Compare commits
1 Commits
asserts-st
...
pr33777
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3fbedc5980 |
@@ -142,7 +142,10 @@ const COMMON_HOOKS: Array<[string, Hook]> = [
|
|||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
function compile(source: string): [CompilerOutput, 'flow' | 'typescript'] {
|
function compile(
|
||||||
|
source: string,
|
||||||
|
mode: 'compiler' | 'linter',
|
||||||
|
): [CompilerOutput, 'flow' | 'typescript'] {
|
||||||
const results = new Map<string, Array<PrintedCompilerPipelineValue>>();
|
const results = new Map<string, Array<PrintedCompilerPipelineValue>>();
|
||||||
const error = new CompilerError();
|
const error = new CompilerError();
|
||||||
const otherErrors: Array<CompilerErrorDetail | CompilerDiagnostic> = [];
|
const otherErrors: Array<CompilerErrorDetail | CompilerDiagnostic> = [];
|
||||||
@@ -204,6 +207,22 @@ function compile(source: string): [CompilerOutput, 'flow' | 'typescript'] {
|
|||||||
};
|
};
|
||||||
const parsedOptions = parseConfigPragmaForTests(pragma, {
|
const parsedOptions = parseConfigPragmaForTests(pragma, {
|
||||||
compilationMode: 'infer',
|
compilationMode: 'infer',
|
||||||
|
environment:
|
||||||
|
mode === 'linter'
|
||||||
|
? {
|
||||||
|
// enabled in compiler
|
||||||
|
validateRefAccessDuringRender: false,
|
||||||
|
// enabled in linter
|
||||||
|
validateNoSetStateInRender: true,
|
||||||
|
validateNoSetStateInEffects: true,
|
||||||
|
validateNoJSXInTryStatements: true,
|
||||||
|
validateNoImpureFunctionsInRender: true,
|
||||||
|
validateStaticComponents: true,
|
||||||
|
validateNoFreezingKnownMutableFunctions: true,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
/* use defaults for compiler mode */
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const opts: PluginOptions = parsePluginOptions({
|
const opts: PluginOptions = parsePluginOptions({
|
||||||
...parsedOptions,
|
...parsedOptions,
|
||||||
@@ -249,9 +268,12 @@ function compile(source: string): [CompilerOutput, 'flow' | 'typescript'] {
|
|||||||
otherErrors.forEach(e => error.details.push(e));
|
otherErrors.forEach(e => error.details.push(e));
|
||||||
}
|
}
|
||||||
if (error.hasErrors()) {
|
if (error.hasErrors()) {
|
||||||
return [{kind: 'err', results, error: error}, language];
|
return [{kind: 'err', results, error}, language];
|
||||||
}
|
}
|
||||||
return [{kind: 'ok', results, transformOutput}, language];
|
return [
|
||||||
|
{kind: 'ok', results, transformOutput, errors: error.details},
|
||||||
|
language,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Editor(): JSX.Element {
|
export default function Editor(): JSX.Element {
|
||||||
@@ -260,7 +282,11 @@ export default function Editor(): JSX.Element {
|
|||||||
const dispatchStore = useStoreDispatch();
|
const dispatchStore = useStoreDispatch();
|
||||||
const {enqueueSnackbar} = useSnackbar();
|
const {enqueueSnackbar} = useSnackbar();
|
||||||
const [compilerOutput, language] = useMemo(
|
const [compilerOutput, language] = useMemo(
|
||||||
() => compile(deferredStore.source),
|
() => compile(deferredStore.source, 'compiler'),
|
||||||
|
[deferredStore.source],
|
||||||
|
);
|
||||||
|
const [linterOutput] = useMemo(
|
||||||
|
() => compile(deferredStore.source, 'linter'),
|
||||||
[deferredStore.source],
|
[deferredStore.source],
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -286,19 +312,26 @@ export default function Editor(): JSX.Element {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let mergedOutput: CompilerOutput;
|
||||||
|
let errors: Array<CompilerErrorDetail | CompilerDiagnostic>;
|
||||||
|
if (compilerOutput.kind === 'ok') {
|
||||||
|
errors = linterOutput.kind === 'ok' ? [] : linterOutput.error.details;
|
||||||
|
mergedOutput = {
|
||||||
|
...compilerOutput,
|
||||||
|
errors,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
mergedOutput = compilerOutput;
|
||||||
|
errors = compilerOutput.error.details;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="relative flex basis top-14">
|
<div className="relative flex basis top-14">
|
||||||
<div className={clsx('relative sm:basis-1/4')}>
|
<div className={clsx('relative sm:basis-1/4')}>
|
||||||
<Input
|
<Input language={language} errors={errors} />
|
||||||
language={language}
|
|
||||||
errors={
|
|
||||||
compilerOutput.kind === 'err' ? compilerOutput.error.details : []
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div className={clsx('flex sm:flex flex-wrap')}>
|
<div className={clsx('flex sm:flex flex-wrap')}>
|
||||||
<Output store={deferredStore} compilerOutput={compilerOutput} />
|
<Output store={deferredStore} compilerOutput={mergedOutput} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -11,7 +11,11 @@ import {
|
|||||||
InformationCircleIcon,
|
InformationCircleIcon,
|
||||||
} from '@heroicons/react/outline';
|
} from '@heroicons/react/outline';
|
||||||
import MonacoEditor, {DiffEditor} from '@monaco-editor/react';
|
import MonacoEditor, {DiffEditor} from '@monaco-editor/react';
|
||||||
import {type CompilerError} from 'babel-plugin-react-compiler';
|
import {
|
||||||
|
CompilerErrorDetail,
|
||||||
|
CompilerDiagnostic,
|
||||||
|
type CompilerError,
|
||||||
|
} from 'babel-plugin-react-compiler';
|
||||||
import parserBabel from 'prettier/plugins/babel';
|
import parserBabel from 'prettier/plugins/babel';
|
||||||
import * as prettierPluginEstree from 'prettier/plugins/estree';
|
import * as prettierPluginEstree from 'prettier/plugins/estree';
|
||||||
import * as prettier from 'prettier/standalone';
|
import * as prettier from 'prettier/standalone';
|
||||||
@@ -44,6 +48,7 @@ export type CompilerOutput =
|
|||||||
kind: 'ok';
|
kind: 'ok';
|
||||||
transformOutput: CompilerTransformOutput;
|
transformOutput: CompilerTransformOutput;
|
||||||
results: Map<string, Array<PrintedCompilerPipelineValue>>;
|
results: Map<string, Array<PrintedCompilerPipelineValue>>;
|
||||||
|
errors: Array<CompilerErrorDetail | CompilerDiagnostic>;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
kind: 'err';
|
kind: 'err';
|
||||||
@@ -123,10 +128,36 @@ async function tabify(
|
|||||||
parser: transformOutput.language === 'flow' ? 'babel-flow' : 'babel-ts',
|
parser: transformOutput.language === 'flow' ? 'babel-flow' : 'babel-ts',
|
||||||
plugins: [parserBabel, prettierPluginEstree],
|
plugins: [parserBabel, prettierPluginEstree],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let output: string;
|
||||||
|
let language: string;
|
||||||
|
if (compilerOutput.errors.length === 0) {
|
||||||
|
output = code;
|
||||||
|
language = 'javascript';
|
||||||
|
} else {
|
||||||
|
language = 'markdown';
|
||||||
|
output = `
|
||||||
|
# Output
|
||||||
|
|
||||||
|
React Compiler compiled this function sucessfully, but there are lint errors that indicate potential issues with the original code.
|
||||||
|
|
||||||
|
## ${compilerOutput.errors.length} Lint Errors
|
||||||
|
|
||||||
|
${compilerOutput.errors.map(e => e.printErrorMessage(source, {eslint: false})).join('\n\n')}
|
||||||
|
|
||||||
|
## Output
|
||||||
|
|
||||||
|
\`\`\`js
|
||||||
|
${code}
|
||||||
|
\`\`\`
|
||||||
|
`.trim();
|
||||||
|
}
|
||||||
|
|
||||||
reorderedTabs.set(
|
reorderedTabs.set(
|
||||||
'JS',
|
'Output',
|
||||||
<TextTabContent
|
<TextTabContent
|
||||||
output={code}
|
output={output}
|
||||||
|
language={language}
|
||||||
diff={null}
|
diff={null}
|
||||||
showInfoPanel={false}></TextTabContent>,
|
showInfoPanel={false}></TextTabContent>,
|
||||||
);
|
);
|
||||||
@@ -147,9 +178,10 @@ async function tabify(
|
|||||||
eslint: false,
|
eslint: false,
|
||||||
});
|
});
|
||||||
reorderedTabs.set(
|
reorderedTabs.set(
|
||||||
'Errors',
|
'Output',
|
||||||
<TextTabContent
|
<TextTabContent
|
||||||
output={errors}
|
output={errors}
|
||||||
|
language="plaintext"
|
||||||
diff={null}
|
diff={null}
|
||||||
showInfoPanel={false}></TextTabContent>,
|
showInfoPanel={false}></TextTabContent>,
|
||||||
);
|
);
|
||||||
@@ -173,7 +205,9 @@ function getSourceMapUrl(code: string, map: string): string | null {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Output({store, compilerOutput}: Props): JSX.Element {
|
function Output({store, compilerOutput}: Props): JSX.Element {
|
||||||
const [tabsOpen, setTabsOpen] = useState<Set<string>>(() => new Set(['JS']));
|
const [tabsOpen, setTabsOpen] = useState<Set<string>>(
|
||||||
|
() => new Set(['Output']),
|
||||||
|
);
|
||||||
const [tabs, setTabs] = useState<Map<string, React.ReactNode>>(
|
const [tabs, setTabs] = useState<Map<string, React.ReactNode>>(
|
||||||
() => new Map(),
|
() => new Map(),
|
||||||
);
|
);
|
||||||
@@ -187,7 +221,7 @@ function Output({store, compilerOutput}: Props): JSX.Element {
|
|||||||
);
|
);
|
||||||
if (compilerOutput.kind !== previousOutputKind) {
|
if (compilerOutput.kind !== previousOutputKind) {
|
||||||
setPreviousOutputKind(compilerOutput.kind);
|
setPreviousOutputKind(compilerOutput.kind);
|
||||||
setTabsOpen(new Set([compilerOutput.kind === 'ok' ? 'JS' : 'Errors']));
|
setTabsOpen(new Set(['Output']));
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -196,7 +230,7 @@ function Output({store, compilerOutput}: Props): JSX.Element {
|
|||||||
});
|
});
|
||||||
}, [store.source, compilerOutput]);
|
}, [store.source, compilerOutput]);
|
||||||
|
|
||||||
const changedPasses: Set<string> = new Set(['JS', 'HIR']); // Initial and final passes should always be bold
|
const changedPasses: Set<string> = new Set(['Output', 'HIR']); // Initial and final passes should always be bold
|
||||||
let lastResult: string = '';
|
let lastResult: string = '';
|
||||||
for (const [passName, results] of compilerOutput.results) {
|
for (const [passName, results] of compilerOutput.results) {
|
||||||
for (const result of results) {
|
for (const result of results) {
|
||||||
@@ -228,10 +262,12 @@ function TextTabContent({
|
|||||||
output,
|
output,
|
||||||
diff,
|
diff,
|
||||||
showInfoPanel,
|
showInfoPanel,
|
||||||
|
language,
|
||||||
}: {
|
}: {
|
||||||
output: string;
|
output: string;
|
||||||
diff: string | null;
|
diff: string | null;
|
||||||
showInfoPanel: boolean;
|
showInfoPanel: boolean;
|
||||||
|
language: string;
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
const [diffMode, setDiffMode] = useState(false);
|
const [diffMode, setDiffMode] = useState(false);
|
||||||
return (
|
return (
|
||||||
@@ -282,7 +318,7 @@ function TextTabContent({
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<MonacoEditor
|
<MonacoEditor
|
||||||
defaultLanguage="javascript"
|
language={language ?? 'javascript'}
|
||||||
value={output}
|
value={output}
|
||||||
options={{
|
options={{
|
||||||
...monacoOptions,
|
...monacoOptions,
|
||||||
|
|||||||
@@ -113,8 +113,13 @@ function* splitPragma(
|
|||||||
*/
|
*/
|
||||||
function parseConfigPragmaEnvironmentForTest(
|
function parseConfigPragmaEnvironmentForTest(
|
||||||
pragma: string,
|
pragma: string,
|
||||||
|
defaultConfig: PartialEnvironmentConfig,
|
||||||
): EnvironmentConfig {
|
): EnvironmentConfig {
|
||||||
const maybeConfig: Partial<Record<keyof EnvironmentConfig, unknown>> = {};
|
// throw early if the defaults are invalid
|
||||||
|
EnvironmentConfigSchema.parse(defaultConfig);
|
||||||
|
|
||||||
|
const maybeConfig: Partial<Record<keyof EnvironmentConfig, unknown>> =
|
||||||
|
defaultConfig;
|
||||||
|
|
||||||
for (const {key, value: val} of splitPragma(pragma)) {
|
for (const {key, value: val} of splitPragma(pragma)) {
|
||||||
if (!hasOwnProperty(EnvironmentConfigSchema.shape, key)) {
|
if (!hasOwnProperty(EnvironmentConfigSchema.shape, key)) {
|
||||||
@@ -174,9 +179,13 @@ export function parseConfigPragmaForTests(
|
|||||||
pragma: string,
|
pragma: string,
|
||||||
defaults: {
|
defaults: {
|
||||||
compilationMode: CompilationMode;
|
compilationMode: CompilationMode;
|
||||||
|
environment?: PartialEnvironmentConfig;
|
||||||
},
|
},
|
||||||
): PluginOptions {
|
): PluginOptions {
|
||||||
const environment = parseConfigPragmaEnvironmentForTest(pragma);
|
const environment = parseConfigPragmaEnvironmentForTest(
|
||||||
|
pragma,
|
||||||
|
defaults.environment ?? {},
|
||||||
|
);
|
||||||
const options: Record<keyof PluginOptions, unknown> = {
|
const options: Record<keyof PluginOptions, unknown> = {
|
||||||
...defaultOptions,
|
...defaultOptions,
|
||||||
panicThreshold: 'all_errors',
|
panicThreshold: 'all_errors',
|
||||||
|
|||||||
Reference in New Issue
Block a user