/
githubmirror
/
babel
Обзор
Документация
Войти
/
githubmirror
/
babel
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
packages/babel-parser/src/parse-error.ts
314 строк
10 KB
liuxingbaoyu
chore: Update prettier v3.9 (#18147)
20 июл 2026, 21:37
Не верифицирован
20 июл 2026, 21:37
61bfda5
Код
Авторство
О чём код?
import { Position } from "./util/location.ts"; type SyntaxPlugin = | "flow" | "typescript" | "jsx" | "functionBind" | "pipelineOperator" | "placeholders"; type ParseErrorCode = "BABEL_PARSER_SYNTAX_ERROR" | "BABEL_PARSER_SOURCETYPE_MODULE_REQUIRED"; // 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 // give our errors their own full-blown class, but until then this allow us to // keep all the desirable properties of SyntaxErrors (like their name in stack // traces, etc.), and also allows us to punt on any publicly facing // class-hierarchy decisions until Babel 8. interface ParseErrorSpecification<ErrorDetails> { // Look, these *could* be readonly, but then Flow complains when we initially // set them. We could do a whole dance and make a special interface that's not // 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; reasonCode: string; syntaxPlugin?: SyntaxPlugin; missingPlugin?: string | string[]; loc: Position; details: ErrorDetails; // We should consider removing this as it now just contains the same // information as `loc.index`. pos: number; } export type ParseErrorGeneric<ErrorDetails> = SyntaxError & ParseErrorSpecification<ErrorDetails>; export type ParseError = SyntaxError & { missingPlugin?: string | string[]; loc: Position; pos: number; } & ErrorInfo; // By `ParseErrorConstructor`, we mean something like the new-less style // `ErrorConstructor`[1], since `ParseError`'s are not themselves actually // separate classes from `SyntaxError`'s. // // 1. https://github.com/microsoft/TypeScript/blob/v4.5.5/lib/lib.es5.d.ts#L1027 export type ParseErrorConstructor<ErrorDetails> = ( loc: Position, pos: number, details: ErrorDetails, ) => ParseError; 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, code, reasonCode, syntaxPlugin, }: ParseErrorCredentials<ErrorDetails>): ParseErrorConstructor<ErrorDetails> { const hasMissingPlugin = reasonCode === "MissingPlugin" || reasonCode === "MissingOneOfPlugins"; return function constructor( loc: Position, pos: number, details: ErrorDetails, ) { const error = new SyntaxError() as ParseErrorGeneric<ErrorDetails>; error.code = code as ParseErrorCode; error.reasonCode = reasonCode; error.loc = loc; error.pos = pos; error.syntaxPlugin = syntaxPlugin; if (hasMissingPlugin) { error.missingPlugin = (details as any).missingPlugin; } type Overrides = { loc?: Position; details?: ErrorDetails; }; defineHidden(error, "clone", function clone(overrides: Overrides = {}) { const { line, column, index = pos } = overrides.loc ?? loc; return constructor(new Position(line, column), index, { ...details, ...overrides.details, }); }); defineHidden(error, "details", details); Object.defineProperty(error, "message", { configurable: true, get(this: ParseErrorGeneric<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 }); }, }); return error as ParseError; }; } type ParseErrorTemplate = | string | ToMessage<any> | { message: string | ToMessage<any>; code?: ParseErrorCode }; export type ParseErrorTemplates = Record<string, ParseErrorTemplate>; // This is the templated form of `ParseErrorEnum`. // // Note: We could factor out the return type calculation into something like // `ParseErrorConstructor<T extends ParseErrorTemplates>`, and then we could // reuse it in the non-templated form of `ParseErrorEnum`, but TypeScript // doesn't seem to drill down that far when showing you the computed type of // an object in an editor, so we'll leave it inlined for now. export function ParseErrorEnum(a: TemplateStringsArray): < T extends ParseErrorTemplates, >( parseErrorTemplates: T, ) => { [K in keyof T]: ParseErrorConstructor< T[K] extends { message: string | ToMessage<any> } ? T[K]["message"] extends ToMessage<any> ? Parameters<T[K]["message"]>[0] : object : T[K] extends ToMessage<any> ? Parameters<T[K]>[0] : object >; }; export function ParseErrorEnum<T extends ParseErrorTemplates>( parseErrorTemplates: T, syntaxPlugin?: SyntaxPlugin, ): { [K in keyof T]: ParseErrorConstructor< T[K] extends { message: string | ToMessage<any> } ? T[K]["message"] extends ToMessage<any> ? Parameters<T[K]["message"]>[0] : object : T[K] extends ToMessage<any> ? Parameters<T[K]>[0] : object >; }; // You call `ParseErrorEnum` with a mapping from `ReasonCode`'s to either: // // 1. a static error message, // 2. `toMessage` functions that define additional necessary `details` needed by // the `ParseError`, or // 3. Objects that contain a `message` of one of the above and overridden `code` // and/or `reasonCode`: // // ParseErrorEnum `optionalSyntaxPlugin` ({ // ErrorWithStaticMessage: "message", // ErrorWithDynamicMessage: ({ type } : { type: string }) => `${type}`), // ErrorWithOverriddenCodeAndOrReasonCode: { // message: ({ type }: { type: string }) => `${type}`), // code: "AN_ERROR_CODE", // ...(BABEL_8_BREAKING ? { } : { reasonCode: "CustomErrorReasonCode" }) // } // }); // export function ParseErrorEnum( argument: TemplateStringsArray | ParseErrorTemplates, syntaxPlugin?: SyntaxPlugin, ) { // If the first parameter is an array, that means we were called with a tagged // template literal. Extract the syntaxPlugin from this, and call again in // the "normalized" form. if (Array.isArray(argument)) { return (parseErrorTemplates: ParseErrorTemplates) => ParseErrorEnum(parseErrorTemplates, argument[0]); } const ParseErrorConstructors = {} as Record< string, ParseErrorConstructor<unknown> >; for (const reasonCode of Object.keys(argument)) { const template = (argument as ParseErrorTemplates)[reasonCode]; const { message, ...rest } = typeof template === "string" ? { message: () => template } : typeof template === "function" ? { message: template } : template; const toMessage = typeof message === "string" ? () => message : message; ParseErrorConstructors[reasonCode] = toParseErrorConstructor({ code: "BABEL_PARSER_SYNTAX_ERROR", reasonCode, toMessage, ...(syntaxPlugin ? { syntaxPlugin } : {}), ...rest, }); } return ParseErrorConstructors; } import ModuleErrors from "./parse-error/module-errors.ts"; import StandardErrors from "./parse-error/standard-errors.ts"; import StrictModeErrors from "./parse-error/strict-mode-errors.ts"; import ParseExpressionErrors from "./parse-error/parse-expression-errors.ts"; import PipelineOperatorErrors from "./parse-error/pipeline-operator-errors.ts"; import FunctionBindErrors from "./parse-error/bind-operator-errors.ts"; import type { TSErrorTemplates } from "./plugins/typescript/index.ts"; import type { FlowErrorTemplates } from "./plugins/flow/index.ts"; import type { JsxErrorTemplates } from "./plugins/jsx/index.ts"; import type { PlaceholderErrorTemplates } from "./plugins/placeholders.ts"; export const Errors = { ...ParseErrorEnum(ModuleErrors), ...ParseErrorEnum(StandardErrors), ...ParseErrorEnum(StrictModeErrors), ...ParseErrorEnum(ParseExpressionErrors), ...ParseErrorEnum`pipelineOperator`(PipelineOperatorErrors), ...ParseErrorEnum`functionBind`(FunctionBindErrors), }; type ErrorToObject<T> = { [K in keyof T]: { code: T[K] extends { code: string } ? T[K]["code"] : "BABEL_PARSER_SYNTAX_ERROR"; reasonCode: K; details: T[K] extends { message: string | ToMessage<any> } ? T[K]["message"] extends ToMessage<any> ? Parameters<T[K]["message"]>[0] : object : T[K] extends ToMessage<any> ? Parameters<T[K]>[0] : object; }; }; type __ExtractMe = typeof ModuleErrors & typeof StandardErrors & typeof StrictModeErrors & typeof ParseExpressionErrors & typeof FunctionBindErrors & typeof PipelineOperatorErrors & typeof TSErrorTemplates & typeof FlowErrorTemplates & typeof JsxErrorTemplates & typeof PlaceholderErrorTemplates; // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents type __PatchMe = never & Decompress<ErrorInfoCompressed>; type ErrorsObjects = ErrorToObject<__ExtractMe>; // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents type ErrorInfo = __PatchMe | ErrorsObjects[keyof ErrorsObjects]; // eslint-disable-next-line @typescript-eslint/no-empty-object-type type ErrorInfoCompressed = {}; type Decompress<T extends object> = { [K in keyof T]: T[K] extends [infer Param, infer Code] ? { code: Code; reasonCode: K; details: Param; } : T[K] extends [infer Param] ? { code: "BABEL_PARSER_SYNTAX_ERROR"; reasonCode: K; details: Param; } : T[K] extends [] ? { code: "BABEL_PARSER_SYNTAX_ERROR"; reasonCode: K; details: object; } : never; }; export type { LValAncestor } from "./parse-error/standard-errors.ts";