Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b0fe7612c |
@@ -11,6 +11,7 @@ import * as t from '@babel/types';
|
|||||||
import BabelPluginReactCompiler, {
|
import BabelPluginReactCompiler, {
|
||||||
CompilerError,
|
CompilerError,
|
||||||
CompilerErrorDetail,
|
CompilerErrorDetail,
|
||||||
|
CompilerDiagnostic,
|
||||||
Effect,
|
Effect,
|
||||||
ErrorSeverity,
|
ErrorSeverity,
|
||||||
parseConfigPragmaForTests,
|
parseConfigPragmaForTests,
|
||||||
@@ -144,7 +145,7 @@ const COMMON_HOOKS: Array<[string, Hook]> = [
|
|||||||
function compile(source: string): [CompilerOutput, 'flow' | 'typescript'] {
|
function compile(source: string): [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> = [];
|
const otherErrors: Array<CompilerErrorDetail | CompilerDiagnostic> = [];
|
||||||
const upsert: (result: PrintedCompilerPipelineValue) => void = result => {
|
const upsert: (result: PrintedCompilerPipelineValue) => void = result => {
|
||||||
const entry = results.get(result.name);
|
const entry = results.get(result.name);
|
||||||
if (Array.isArray(entry)) {
|
if (Array.isArray(entry)) {
|
||||||
@@ -214,7 +215,7 @@ function compile(source: string): [CompilerOutput, 'flow' | 'typescript'] {
|
|||||||
debugLogIRs: logIR,
|
debugLogIRs: logIR,
|
||||||
logEvent: (_filename: string | null, event: LoggerEvent) => {
|
logEvent: (_filename: string | null, event: LoggerEvent) => {
|
||||||
if (event.kind === 'CompileError') {
|
if (event.kind === 'CompileError') {
|
||||||
otherErrors.push(new CompilerErrorDetail(event.detail));
|
otherErrors.push(event.detail);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -226,7 +227,7 @@ function compile(source: string): [CompilerOutput, 'flow' | 'typescript'] {
|
|||||||
* (i.e. object shape that is not CompilerError)
|
* (i.e. object shape that is not CompilerError)
|
||||||
*/
|
*/
|
||||||
if (err instanceof CompilerError && err.details.length > 0) {
|
if (err instanceof CompilerError && err.details.length > 0) {
|
||||||
error.details.push(...err.details);
|
error.merge(err);
|
||||||
} else {
|
} else {
|
||||||
/**
|
/**
|
||||||
* Handle unexpected failures by logging (to get a stack trace)
|
* Handle unexpected failures by logging (to get a stack trace)
|
||||||
@@ -245,7 +246,7 @@ function compile(source: string): [CompilerOutput, 'flow' | 'typescript'] {
|
|||||||
}
|
}
|
||||||
// Only include logger errors if there weren't other errors
|
// Only include logger errors if there weren't other errors
|
||||||
if (!error.hasErrors() && otherErrors.length !== 0) {
|
if (!error.hasErrors() && otherErrors.length !== 0) {
|
||||||
otherErrors.forEach(e => error.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: error}, language];
|
||||||
|
|||||||
@@ -36,13 +36,18 @@ export default function Input({errors, language}: Props): JSX.Element {
|
|||||||
const uri = monaco.Uri.parse(`file:///index.js`);
|
const uri = monaco.Uri.parse(`file:///index.js`);
|
||||||
const model = monaco.editor.getModel(uri);
|
const model = monaco.editor.getModel(uri);
|
||||||
invariant(model, 'Model must exist for the selected input file.');
|
invariant(model, 'Model must exist for the selected input file.');
|
||||||
renderReactCompilerMarkers({monaco, model, details: errors});
|
renderReactCompilerMarkers({
|
||||||
|
monaco,
|
||||||
|
model,
|
||||||
|
details: errors,
|
||||||
|
source: store.source,
|
||||||
|
});
|
||||||
/**
|
/**
|
||||||
* N.B. that `tabSize` is a model property, not an editor property.
|
* N.B. that `tabSize` is a model property, not an editor property.
|
||||||
* So, the tab size has to be set per model.
|
* So, the tab size has to be set per model.
|
||||||
*/
|
*/
|
||||||
model.updateOptions({tabSize: 2});
|
model.updateOptions({tabSize: 2});
|
||||||
}, [monaco, errors]);
|
}, [monaco, errors, store.source]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -142,6 +142,17 @@ async function tabify(
|
|||||||
</>,
|
</>,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
} else if (compilerOutput.kind === 'err') {
|
||||||
|
const errors = compilerOutput.error.printErrorMessage(source, {
|
||||||
|
eslint: false,
|
||||||
|
});
|
||||||
|
reorderedTabs.set(
|
||||||
|
'Errors',
|
||||||
|
<TextTabContent
|
||||||
|
output={errors}
|
||||||
|
diff={null}
|
||||||
|
showInfoPanel={false}></TextTabContent>,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
tabs.forEach((tab, name) => {
|
tabs.forEach((tab, name) => {
|
||||||
reorderedTabs.set(name, tab);
|
reorderedTabs.set(name, tab);
|
||||||
@@ -166,6 +177,19 @@ function Output({store, compilerOutput}: Props): JSX.Element {
|
|||||||
const [tabs, setTabs] = useState<Map<string, React.ReactNode>>(
|
const [tabs, setTabs] = useState<Map<string, React.ReactNode>>(
|
||||||
() => new Map(),
|
() => new Map(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update the active tab back to the output or errors tab when the compilation state
|
||||||
|
* changes between success/failure.
|
||||||
|
*/
|
||||||
|
const [previousOutputKind, setPreviousOutputKind] = useState(
|
||||||
|
compilerOutput.kind,
|
||||||
|
);
|
||||||
|
if (compilerOutput.kind !== previousOutputKind) {
|
||||||
|
setPreviousOutputKind(compilerOutput.kind);
|
||||||
|
setTabsOpen(new Set([compilerOutput.kind === 'ok' ? 'JS' : 'Errors']));
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
tabify(store.source, compilerOutput).then(tabs => {
|
tabify(store.source, compilerOutput).then(tabs => {
|
||||||
setTabs(tabs);
|
setTabs(tabs);
|
||||||
@@ -196,20 +220,6 @@ function Output({store, compilerOutput}: Props): JSX.Element {
|
|||||||
tabs={tabs}
|
tabs={tabs}
|
||||||
changedPasses={changedPasses}
|
changedPasses={changedPasses}
|
||||||
/>
|
/>
|
||||||
{compilerOutput.kind === 'err' ? (
|
|
||||||
<div
|
|
||||||
className="flex flex-wrap absolute bottom-0 bg-white grow border-y border-grey-200 transition-all ease-in"
|
|
||||||
style={{width: 'calc(100vw - 650px)'}}>
|
|
||||||
<div className="w-full p-4 basis-full border-b">
|
|
||||||
<h2>COMPILER ERRORS</h2>
|
|
||||||
</div>
|
|
||||||
<pre
|
|
||||||
className="p-4 basis-full text-red-600 overflow-y-scroll whitespace-pre-wrap"
|
|
||||||
style={{width: 'calc(100vw - 650px)', height: '150px'}}>
|
|
||||||
<code>{compilerOutput.error.toString()}</code>
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {Monaco} from '@monaco-editor/react';
|
import {Monaco} from '@monaco-editor/react';
|
||||||
import {CompilerErrorDetail, ErrorSeverity} from 'babel-plugin-react-compiler';
|
import {
|
||||||
|
CompilerDiagnostic,
|
||||||
|
CompilerErrorDetail,
|
||||||
|
ErrorSeverity,
|
||||||
|
} from 'babel-plugin-react-compiler';
|
||||||
import {MarkerSeverity, type editor} from 'monaco-editor';
|
import {MarkerSeverity, type editor} from 'monaco-editor';
|
||||||
|
|
||||||
function mapReactCompilerSeverityToMonaco(
|
function mapReactCompilerSeverityToMonaco(
|
||||||
@@ -22,38 +26,46 @@ function mapReactCompilerSeverityToMonaco(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function mapReactCompilerDiagnosticToMonacoMarker(
|
function mapReactCompilerDiagnosticToMonacoMarker(
|
||||||
detail: CompilerErrorDetail,
|
detail: CompilerErrorDetail | CompilerDiagnostic,
|
||||||
monaco: Monaco,
|
monaco: Monaco,
|
||||||
|
source: string,
|
||||||
): editor.IMarkerData | null {
|
): editor.IMarkerData | null {
|
||||||
if (detail.loc == null || typeof detail.loc === 'symbol') {
|
const loc = detail.primaryLocation();
|
||||||
|
if (loc == null || typeof loc === 'symbol') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const severity = mapReactCompilerSeverityToMonaco(detail.severity, monaco);
|
const severity = mapReactCompilerSeverityToMonaco(detail.severity, monaco);
|
||||||
let message = detail.printErrorMessage();
|
let message = detail.printErrorMessage(source, {eslint: true});
|
||||||
return {
|
return {
|
||||||
severity,
|
severity,
|
||||||
message,
|
message,
|
||||||
startLineNumber: detail.loc.start.line,
|
startLineNumber: loc.start.line,
|
||||||
startColumn: detail.loc.start.column + 1,
|
startColumn: loc.start.column + 1,
|
||||||
endLineNumber: detail.loc.end.line,
|
endLineNumber: loc.end.line,
|
||||||
endColumn: detail.loc.end.column + 1,
|
endColumn: loc.end.column + 1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReactCompilerMarkerConfig = {
|
type ReactCompilerMarkerConfig = {
|
||||||
monaco: Monaco;
|
monaco: Monaco;
|
||||||
model: editor.ITextModel;
|
model: editor.ITextModel;
|
||||||
details: Array<CompilerErrorDetail>;
|
details: Array<CompilerErrorDetail | CompilerDiagnostic>;
|
||||||
|
source: string;
|
||||||
};
|
};
|
||||||
let decorations: Array<string> = [];
|
let decorations: Array<string> = [];
|
||||||
export function renderReactCompilerMarkers({
|
export function renderReactCompilerMarkers({
|
||||||
monaco,
|
monaco,
|
||||||
model,
|
model,
|
||||||
details,
|
details,
|
||||||
|
source,
|
||||||
}: ReactCompilerMarkerConfig): void {
|
}: ReactCompilerMarkerConfig): void {
|
||||||
const markers: Array<editor.IMarkerData> = [];
|
const markers: Array<editor.IMarkerData> = [];
|
||||||
for (const detail of details) {
|
for (const detail of details) {
|
||||||
const marker = mapReactCompilerDiagnosticToMonacoMarker(detail, monaco);
|
const marker = mapReactCompilerDiagnosticToMonacoMarker(
|
||||||
|
detail,
|
||||||
|
monaco,
|
||||||
|
source,
|
||||||
|
);
|
||||||
if (marker == null) {
|
if (marker == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,9 +84,7 @@ export default function BabelPluginReactCompiler(
|
|||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof CompilerError) {
|
if (e instanceof CompilerError) {
|
||||||
throw new Error(
|
throw e.withPrintedMessage(pass.file.code, {eslint: false});
|
||||||
e.printErrorMessage(pass.file.code, {eslint: false}),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -262,6 +262,7 @@ export class CompilerErrorDetail {
|
|||||||
|
|
||||||
export class CompilerError extends Error {
|
export class CompilerError extends Error {
|
||||||
details: Array<CompilerErrorDetail | CompilerDiagnostic> = [];
|
details: Array<CompilerErrorDetail | CompilerDiagnostic> = [];
|
||||||
|
printedMessage: string | null = null;
|
||||||
|
|
||||||
static invariant(
|
static invariant(
|
||||||
condition: unknown,
|
condition: unknown,
|
||||||
@@ -347,18 +348,29 @@ export class CompilerError extends Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override get message(): string {
|
override get message(): string {
|
||||||
return this.toString();
|
return this.printedMessage ?? this.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
override set message(_message: string) {}
|
override set message(_message: string) {}
|
||||||
|
|
||||||
override toString(): string {
|
override toString(): string {
|
||||||
|
if (this.printedMessage) {
|
||||||
|
return this.printedMessage;
|
||||||
|
}
|
||||||
if (Array.isArray(this.details)) {
|
if (Array.isArray(this.details)) {
|
||||||
return this.details.map(detail => detail.toString()).join('\n\n');
|
return this.details.map(detail => detail.toString()).join('\n\n');
|
||||||
}
|
}
|
||||||
return this.name;
|
return this.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
withPrintedMessage(
|
||||||
|
source: string,
|
||||||
|
options: PrintErrorMessageOptions,
|
||||||
|
): CompilerError {
|
||||||
|
this.printedMessage = this.printErrorMessage(source, options);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
printErrorMessage(source: string, options: PrintErrorMessageOptions): string {
|
printErrorMessage(source: string, options: PrintErrorMessageOptions): string {
|
||||||
if (options.eslint && this.details.length === 1) {
|
if (options.eslint && this.details.length === 1) {
|
||||||
return this.details[0].printErrorMessage(source, options);
|
return this.details[0].printErrorMessage(source, options);
|
||||||
|
|||||||
Reference in New Issue
Block a user