Files
react/compiler/forget/src/CompilerError.ts
T
Lauren Tan 109d7ba980 Refactor CompilerError
This commit repurposes CompilerError to represent an aggregate of error details 
accumulated during HIR lowering. It also fixes the playground to correctly 
render errors again.
2023-01-24 12:44:51 -05:00

100 lines
2.6 KiB
TypeScript

import { Node, NodePath } from "@babel/core";
import { assertExhaustive } from "./Utils/utils";
export enum ErrorSeverity {
InvalidInput = "InvalidInput",
Todo = "Todo",
}
export type CompilerErrorOptions = {
reason: string;
severity: ErrorSeverity;
nodePath: AnyNodePath | null;
};
type AnyNodePath = NodePath<Node | null | undefined>;
type CompilerErrorKind = typeof InvalidInputError | typeof TodoError;
function mapSeverityToErrorCtor(severity: ErrorSeverity): CompilerErrorKind {
switch (severity) {
case ErrorSeverity.InvalidInput:
return InvalidInputError;
case ErrorSeverity.Todo:
return TodoError;
default:
assertExhaustive(severity, `Unhandled severity level: ${severity}`);
}
}
class InvalidInputError extends Error {
constructor(message: string) {
super(message);
this.name = `${ErrorSeverity.InvalidInput}Error`;
}
}
class TodoError extends Error {
constructor(message: string) {
super(message);
this.name = `${ErrorSeverity.Todo}Error`;
}
}
/**
* Each bailout or invariant in HIR lowering creates an {@link CompilerErrorDetail}, which is then
* aggregated into a single {@link CompilerError} later.
*/
export class CompilerErrorDetail {
reason: string;
severity: ErrorSeverity;
/**
* If a NodePath is provided, we will prefer Babel's built in codeframe error generation which
* will print error markers in the correct location.
*/
nodePath: AnyNodePath | null;
constructor(options: CompilerErrorOptions) {
this.reason = options.reason;
this.severity = options.severity;
this.nodePath = options.nodePath;
}
get errorMessage(): string {
const buffer = [`${this.severity}: ${this.reason}`];
if (this.nodePath != null && this.nodePath.node?.loc != null) {
buffer.push(
` (${this.nodePath.node.loc.start.line}:${this.nodePath.node.loc.end.line})`
);
}
return buffer.join("");
}
get codeFrame() {
if (this.nodePath == null) {
return this.errorMessage;
}
try {
return this.nodePath
.buildCodeFrameError(this.reason, mapSeverityToErrorCtor(this.severity))
.toString();
} catch {
return this.errorMessage;
}
}
toString(): string {
return `[ReactForget] ${this.errorMessage}`;
}
}
export class CompilerError extends Error {
details: CompilerErrorDetail[] = [];
constructor(details: CompilerErrorDetail[], ...args: any[]) {
super(...args);
this.details = details;
this.message = this.toString();
}
override toString() {
return this.details.map((detail) => detail.toString()).join("\n\n");
}
}