Skip to content

Commit

Permalink
Simplify parser errors creation
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolo-ribaudo committed Aug 24, 2023
1 parent c3f03f6 commit 602a7a1
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 117 deletions.
108 changes: 59 additions & 49 deletions packages/babel-parser/src/parse-error.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { Position } from "./util/location";
import {
instantiate,
ParseErrorCode,
type ParseErrorCredentials,
type ToMessage,
type SyntaxPlugin,
} from "./parse-error/credentials";
import type { Undone } from "./parser/node";
import type { Node } from "./types";

type SyntaxPlugin =
| "flow"
| "typescript"
| "jsx"
| "pipelineOperator"
| "placeholders";

// Babel uses "normal" SyntaxErrors for it's errors, but adds some extra
// functionality. This functionality is defined in the
// `ParseErrorSpecification` interface below. We may choose to change to someday
Expand All @@ -22,7 +22,7 @@ interface ParseErrorSpecification<ErrorDetails> {
// readonly for when we create the error, then cast it to the readonly
// interface for public use, but the previous implementation didn't have them
// as readonly, so let's just not worry about it for now.
code: ParseErrorCode;
code: string;
reasonCode: string;
syntaxPlugin?: SyntaxPlugin;
missingPlugin?: string | string[];
Expand All @@ -47,6 +47,23 @@ export type ParseErrorConstructor<ErrorDetails> = (a: {
details: ErrorDetails;
}) => ParseError<ErrorDetails>;

type ToMessage<ErrorDetails> = (self: ErrorDetails) => string;

type ParseErrorCredentials<ErrorDetails> = {
code: string;
reasonCode: string;
syntaxPlugin?: SyntaxPlugin;
toMessage: ToMessage<ErrorDetails>;
};

function defineHidden(obj: object, key: string, value: unknown) {
Object.defineProperty(obj, key, {
enumerable: false,
configurable: true,
value,
});
}

function toParseErrorConstructor<ErrorDetails extends object>({
toMessage,
...properties
Expand All @@ -57,44 +74,39 @@ function toParseErrorConstructor<ErrorDetails extends object>({
};

return function constructor({ loc, details }: ConstructorArgument) {
return instantiate(
SyntaxError,
{ ...properties, loc },
{
clone(
overrides: {
loc?: Position;
details?: ErrorDetails;
} = {},
) {
const loc = (overrides.loc || {}) as Partial<Position>;
return constructor({
loc: new Position(
"line" in loc ? loc.line : this.loc.line,
"column" in loc ? loc.column : this.loc.column,
"index" in loc ? loc.index : this.loc.index,
),
details: { ...this.details, ...overrides.details },
});
},
details: { value: details, enumerable: false },
message: {
get(this: ConstructorArgument): string {
return `${toMessage(this.details)} (${this.loc.line}:${
this.loc.column
})`;
},
set(value: string) {
Object.defineProperty(this, "message", { value });
},
},
pos: { reflect: "loc.index", enumerable: true },
missingPlugin: "missingPlugin" in details && {
reflect: "details.missingPlugin",
enumerable: true,
},
const error = new SyntaxError();
Object.assign(error, properties, { loc, pos: loc.index });
if ("missingPlugin" in details) {
Object.assign(error, { missingPlugin: details.missingPlugin });
}

type Overrides = {
loc?: Position;
details?: ErrorDetails;
};
defineHidden(error, "clone", function clone(overrides: Overrides = {}) {
const { line, column, index } = overrides.loc ?? loc;
return constructor({
loc: new Position(line, column, index),
details: { ...details, ...overrides.details },
});
});

defineHidden(error, "details", details);

Object.defineProperty(error, "message", {
configurable: true,
get(this: ParseError<ErrorDetails>): string {
const message = `${toMessage(details)} (${loc.line}:${loc.column})`;
this.message = message;
return message;
},
set(value: string) {
Object.defineProperty(this, "message", { value, writable: true });
},
) as ParseError<ErrorDetails>;
});

return error as ParseError<ErrorDetails>;
};
}

Expand Down Expand Up @@ -156,7 +168,7 @@ export function ParseErrorEnum<T extends ParseErrorTemplates>(
// ErrorWithDynamicMessage: ({ type } : { type: string }) => `${type}`),
// ErrorWithOverriddenCodeAndOrReasonCode: {
// message: ({ type }: { type: string }) => `${type}`),
// code: ParseErrorCode.SourceTypeModuleError,
// code: "AN_ERROR_CODE",
// ...(BABEL_8_BREAKING ? { } : { reasonCode: "CustomErrorReasonCode" })
// }
// });
Expand Down Expand Up @@ -189,7 +201,7 @@ export function ParseErrorEnum(
const toMessage = typeof message === "string" ? () => message : message;

ParseErrorConstructors[reasonCode] = toParseErrorConstructor({
code: ParseErrorCode.SyntaxError,
code: "BABEL_PARSER_SYNTAX_ERROR",
reasonCode,
toMessage,
...(syntaxPlugin ? { syntaxPlugin } : {}),
Expand Down Expand Up @@ -217,5 +229,3 @@ export const Errors = {
};

export type { LValAncestor } from "./parse-error/standard-errors";

export * from "./parse-error/credentials";
65 changes: 0 additions & 65 deletions packages/babel-parser/src/parse-error/credentials.ts

This file was deleted.

6 changes: 3 additions & 3 deletions packages/babel-parser/src/parse-error/module-errors.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { ParseErrorCode } from "../parse-error";
const code = "BABEL_PARSER_SOURCETYPE_MODULE_REQUIRED";

export default {
ImportMetaOutsideModule: {
message: `import.meta may appear only with 'sourceType: "module"'`,
code: ParseErrorCode.SourceTypeModuleError,
code,
},
ImportOutsideModule: {
message: `'import' and 'export' may appear only with 'sourceType: "module"'`,
code: ParseErrorCode.SourceTypeModuleError,
code,
},
};

0 comments on commit 602a7a1

Please sign in to comment.