diff --git a/packages/babel-parser/src/parse-error.ts b/packages/babel-parser/src/parse-error.ts index f3d13ff91b54..2c0b85f1fcf9 100644 --- a/packages/babel-parser/src/parse-error.ts +++ b/packages/babel-parser/src/parse-error.ts @@ -2,9 +2,10 @@ import { Position } from "./util/location"; import type { NodeBase } from "./types"; import { instantiate, - type ParseErrorCode, - ParseErrorCodes, + ParseErrorCode, type ParseErrorCredentials, + type ToMessage, + type SyntaxPlugin, } from "./parse-error/credentials"; import type { Undone } from "../src/parser/node"; @@ -23,7 +24,7 @@ interface ParseErrorSpecification { // as readonly, so let's just not worry about it for now. code: ParseErrorCode; reasonCode: string; - syntaxPlugin?: string; + syntaxPlugin?: SyntaxPlugin; missingPlugin?: string | string[]; loc: Position; details: ErrorDetails; @@ -56,7 +57,7 @@ function toParseErrorConstructor({ }; return function constructor({ loc, details }: ConstructorArgument) { - return instantiate>( + return instantiate( SyntaxError, { ...properties, loc }, { @@ -66,14 +67,11 @@ function toParseErrorConstructor({ details?: ErrorDetails; } = {}, ) { - const loc = overrides.loc || {}; + const loc = (overrides.loc || {}) as Partial; return constructor({ loc: new Position( - // @ts-expect-error line has been guarded "line" in loc ? loc.line : this.loc.line, - // @ts-expect-error column has been guarded "column" in loc ? loc.column : this.loc.column, - // @ts-expect-error index has been guarded "index" in loc ? loc.index : this.loc.index, ), details: { ...this.details, ...overrides.details }, @@ -96,82 +94,106 @@ function toParseErrorConstructor({ enumerable: true, }, }, - ); + ) as ParseError; }; } -// This part is tricky. You'll probably notice from the name of this function -// that it is supposed to return `ParseErrorCredentials`, but instead these. -// declarations seem to instead imply that they return -// `ParseErrorConstructor` instead. This is because in Flow we -// can't easily extract parameter types (either from functions, like with -// Typescript's Parameters utility type, or from generic types either). As -// such, this function does double duty: packaging up the credentials during -// its actual runtime operation, but pretending to return the -// `ParseErrorConstructor` that we won't actually have until later -// to the type system, avoiding the need to do so with $ObjMap (which doesn't -// work) in `ParseErrorEnum`. This hack won't be necessary when we switch to -// Typescript. -export function toParseErrorCredentials( - message: string, - credentials?: { code?: ParseErrorCode; reasonCode?: string }, -): ParseErrorConstructor<{}>; - -export function toParseErrorCredentials( - toMessage: (details: ErrorDetails) => string, - credentials?: { code?: ParseErrorCode; reasonCode?: string }, -): ParseErrorConstructor; - -export function toParseErrorCredentials( - toMessageOrMessage: string | ((details: unknown) => string), - credentials?: any, -) { - return { - toMessage: - typeof toMessageOrMessage === "string" - ? () => toMessageOrMessage - : toMessageOrMessage, - ...credentials, - }; -} +type ParseErrorTemplate = + | string + | ToMessage + | { message: string | ToMessage }; -// This is the templated form. -export function ParseErrorEnum(a: TemplateStringsArray): typeof ParseErrorEnum; +type ParseErrorTemplates = { [reasonCode: string]: ParseErrorTemplate }; + +// This is the templated form of `ParseErrorEnum`. +// +// Note: We could factor out the return type calculation into something like +// `ParseErrorConstructor`, 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 } + ? T[K]["message"] extends ToMessage + ? Parameters[0] + : {} + : T[K] extends ToMessage + ? Parameters[0] + : {} + >; +}; -export function ParseErrorEnum< - T extends (a: typeof toParseErrorCredentials) => unknown, ->(toParseErrorCredentials: T, syntaxPlugin?: string): ReturnType; +export function ParseErrorEnum( + parseErrorTemplates: T, + syntaxPlugin?: SyntaxPlugin, +): { + [K in keyof T]: ParseErrorConstructor< + T[K] extends { message: string | ToMessage } + ? T[K]["message"] extends ToMessage + ? Parameters[0] + : {} + : T[K] extends ToMessage + ? Parameters[0] + : {} + >; +}; -// You call `ParseErrorEnum` with a mapping from `ReasonCode`'s to either error -// messages, or `toMessage` functions that define additional necessary `details` -// needed by the `ParseError`: +// You call `ParseErrorEnum` with a mapping from `ReasonCode`'s to either: // -// ParseErrorEnum`optionalSyntaxPlugin` (_ => ({ -// ErrorWithStaticMessage: _("message"), -// ErrorWithDynamicMessage: _<{ type: string }>(({ type }) => `${type}`), +// 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: ParseErrorCode.SourceTypeModuleError, +// ...(BABEL_8_BREAKING ? { } : { reasonCode: "CustomErrorReasonCode" }) +// } // }); // -export function ParseErrorEnum(argument: any, syntaxPlugin?: string) { +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 (toParseErrorCredentialsMap: any) => - ParseErrorEnum(toParseErrorCredentialsMap, argument[0]); + return (parseErrorTemplates: ParseErrorTemplates) => + ParseErrorEnum(parseErrorTemplates, argument[0]); } - const partialCredentials = argument(toParseErrorCredentials); const ParseErrorConstructors = {} as Record< string, ParseErrorConstructor >; - for (const reasonCode of Object.keys(partialCredentials)) { + 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: ParseErrorCodes.SyntaxError, + code: ParseErrorCode.SyntaxError, reasonCode, + toMessage, ...(syntaxPlugin ? { syntaxPlugin } : {}), - ...partialCredentials[reasonCode], + ...rest, }); } diff --git a/packages/babel-parser/src/parse-error/credentials.ts b/packages/babel-parser/src/parse-error/credentials.ts index cfca66fedfd7..bb3bafa27693 100644 --- a/packages/babel-parser/src/parse-error/credentials.ts +++ b/packages/babel-parser/src/parse-error/credentials.ts @@ -1,10 +1,7 @@ -export const ParseErrorCodes = Object.freeze({ - SyntaxError: "BABEL_PARSER_SYNTAX_ERROR", - SourceTypeModuleError: "BABEL_PARSER_SOURCETYPE_MODULE_REQUIRED", -}); - -export type ParseErrorCode = - typeof ParseErrorCodes[keyof typeof ParseErrorCodes]; +export const enum ParseErrorCode { + SyntaxError = "BABEL_PARSER_SYNTAX_ERROR", + SourceTypeModuleError = "BABEL_PARSER_SOURCETYPE_MODULE_REQUIRED", +} export type SyntaxPlugin = | "flow" @@ -40,7 +37,7 @@ const reflect = (keys: string[], last = keys.length - 1) => ({ }, }); -const instantiate = ( +const instantiate = ( constructor: new () => T, properties: any, descriptors: any, @@ -62,7 +59,7 @@ const instantiate = ( configurable: true, ...descriptor, }), - Object.assign(new constructor() as U, properties), + Object.assign(new constructor(), properties), ); export { instantiate }; diff --git a/packages/babel-parser/src/parse-error/module-errors.ts b/packages/babel-parser/src/parse-error/module-errors.ts index 465d8018b572..e901d2ac85c1 100644 --- a/packages/babel-parser/src/parse-error/module-errors.ts +++ b/packages/babel-parser/src/parse-error/module-errors.ts @@ -1,12 +1,12 @@ -import { ParseErrorCodes, toParseErrorCredentials } from "../parse-error"; +import { ParseErrorCode } from "../parse-error"; -export default (_: typeof toParseErrorCredentials) => ({ - ImportMetaOutsideModule: _( - `import.meta may appear only with 'sourceType: "module"'`, - { code: ParseErrorCodes.SourceTypeModuleError }, - ), - ImportOutsideModule: _( - `'import' and 'export' may appear only with 'sourceType: "module"'`, - { code: ParseErrorCodes.SourceTypeModuleError }, - ), -}); +export default { + ImportMetaOutsideModule: { + message: `import.meta may appear only with 'sourceType: "module"'`, + code: ParseErrorCode.SourceTypeModuleError, + }, + ImportOutsideModule: { + message: `'import' and 'export' may appear only with 'sourceType: "module"'`, + code: ParseErrorCode.SourceTypeModuleError, + }, +}; diff --git a/packages/babel-parser/src/parse-error/pipeline-operator-errors.ts b/packages/babel-parser/src/parse-error/pipeline-operator-errors.ts index 26aaca6f4659..ffaae410a55d 100644 --- a/packages/babel-parser/src/parse-error/pipeline-operator-errors.ts +++ b/packages/babel-parser/src/parse-error/pipeline-operator-errors.ts @@ -1,63 +1,51 @@ -import { toParseErrorCredentials } from "../parse-error"; import toNodeDescription from "./to-node-description"; -const UnparenthesizedPipeBodyDescriptionsList = [ +export const UnparenthesizedPipeBodyDescriptions = new Set([ "ArrowFunctionExpression", "AssignmentExpression", "ConditionalExpression", "YieldExpression", -] as const; -export const UnparenthesizedPipeBodyDescriptions = new Set( - UnparenthesizedPipeBodyDescriptionsList, -); +] as const); -export default (_: typeof toParseErrorCredentials) => ({ +type GetSetMemberType> = T extends Set + ? M + : unknown; + +type UnparanthesizedPipeBodyTypes = GetSetMemberType< + typeof UnparenthesizedPipeBodyDescriptions +>; + +export default { // This error is only used by the smart-mix proposal - PipeBodyIsTighter: _( + PipeBodyIsTighter: "Unexpected yield after pipeline body; any yield expression acting as Hack-style pipe body must be parenthesized due to its loose operator precedence.", - ), - PipeTopicRequiresHackPipes: _( + PipeTopicRequiresHackPipes: 'Topic reference is used, but the pipelineOperator plugin was not passed a "proposal": "hack" or "smart" option.', - ), - PipeTopicUnbound: _( + PipeTopicUnbound: "Topic reference is unbound; it must be inside a pipe body.", - ), - PipeTopicUnconfiguredToken: _<{ token: string }>( - ({ token }) => - `Invalid topic token ${token}. In order to use ${token} as a topic reference, the pipelineOperator plugin must be configured with { "proposal": "hack", "topicToken": "${token}" }.`, - ), - PipeTopicUnused: _( + PipeTopicUnconfiguredToken: ({ token }: { token: string }) => + `Invalid topic token ${token}. In order to use ${token} as a topic reference, the pipelineOperator plugin must be configured with { "proposal": "hack", "topicToken": "${token}" }.`, + PipeTopicUnused: "Hack-style pipe body does not contain a topic reference; Hack-style pipes must use topic at least once.", - ), - PipeUnparenthesizedBody: _<{ - type: typeof UnparenthesizedPipeBodyDescriptionsList[number]; - }>( - ({ type }) => - `Hack-style pipe body cannot be an unparenthesized ${toNodeDescription({ - type, - })}; please wrap it in parentheses.`, - ), + PipeUnparenthesizedBody: ({ type }: { type: UnparanthesizedPipeBodyTypes }) => + `Hack-style pipe body cannot be an unparenthesized ${toNodeDescription({ + type, + })}; please wrap it in parentheses.`, // Messages whose codes start with “Pipeline” or “PrimaryTopic” // are retained for backwards compatibility // with the deprecated smart-mix pipe operator proposal plugin. // They are subject to removal in a future major version. - PipelineBodyNoArrow: _( + PipelineBodyNoArrow: 'Unexpected arrow "=>" after pipeline body; arrow function in pipeline body must be parenthesized.', - ), - PipelineBodySequenceExpression: _( + PipelineBodySequenceExpression: "Pipeline body may not be a comma-separated sequence expression.", - ), - PipelineHeadSequenceExpression: _( + PipelineHeadSequenceExpression: "Pipeline head should not be a comma-separated sequence expression.", - ), - PipelineTopicUnused: _( + PipelineTopicUnused: "Pipeline is in topic style but does not use topic reference.", - ), - PrimaryTopicNotAllowed: _( + PrimaryTopicNotAllowed: "Topic reference was used in a lexical context without topic binding.", - ), - PrimaryTopicRequiresSmartPipeline: _( + PrimaryTopicRequiresSmartPipeline: 'Topic reference is used, but the pipelineOperator plugin was not passed a "proposal": "hack" or "smart" option.', - ), -}); +}; diff --git a/packages/babel-parser/src/parse-error/standard-errors.ts b/packages/babel-parser/src/parse-error/standard-errors.ts index 1dae5fcec9e8..a4087dfcc718 100644 --- a/packages/babel-parser/src/parse-error/standard-errors.ts +++ b/packages/babel-parser/src/parse-error/standard-errors.ts @@ -1,4 +1,3 @@ -import { toParseErrorCredentials } from "../parse-error"; import toNodeDescription from "./to-node-description"; export type LValAncestor = @@ -20,342 +19,278 @@ export type LValAncestor = | "VariableDeclarator"; }; -export default (_: typeof toParseErrorCredentials) => ({ - AccessorIsGenerator: _<{ kind: "get" | "set" }>( - ({ kind }) => `A ${kind}ter cannot be a generator.`, - ), - - ArgumentsInClass: _( +export default { + AccessorIsGenerator: ({ kind }: { kind: "get" | "set" }) => + `A ${kind}ter cannot be a generator.`, + ArgumentsInClass: "'arguments' is only allowed in functions and class methods.", - ), - AsyncFunctionInSingleStatementContext: _( + AsyncFunctionInSingleStatementContext: "Async functions can only be declared at the top level or inside a block.", - ), - AwaitBindingIdentifier: _( + AwaitBindingIdentifier: "Can not use 'await' as identifier inside an async function.", - ), - AwaitBindingIdentifierInStaticBlock: _( + AwaitBindingIdentifierInStaticBlock: "Can not use 'await' as identifier inside a static block.", - ), - AwaitExpressionFormalParameter: _( + AwaitExpressionFormalParameter: "'await' is not allowed in async function parameters.", - ), - AwaitNotInAsyncContext: _( + AwaitNotInAsyncContext: "'await' is only allowed within async functions and at the top levels of modules.", - ), - AwaitNotInAsyncFunction: _("'await' is only allowed within async functions."), - BadGetterArity: _("A 'get' accesor must not have any formal parameters."), - BadSetterArity: _("A 'set' accesor must have exactly one formal parameter."), - BadSetterRestParameter: _( + AwaitNotInAsyncFunction: "'await' is only allowed within async functions.", + BadGetterArity: "A 'get' accesor must not have any formal parameters.", + BadSetterArity: "A 'set' accesor must have exactly one formal parameter.", + BadSetterRestParameter: "A 'set' accesor function argument must not be a rest parameter.", - ), - ConstructorClassField: _("Classes may not have a field named 'constructor'."), - ConstructorClassPrivateField: _( + ConstructorClassField: "Classes may not have a field named 'constructor'.", + ConstructorClassPrivateField: "Classes may not have a private field named '#constructor'.", - ), - ConstructorIsAccessor: _("Class constructor may not be an accessor."), - ConstructorIsAsync: _("Constructor can't be an async function."), - ConstructorIsGenerator: _("Constructor can't be a generator."), - DeclarationMissingInitializer: _<{ kind: "const" | "destructuring" }>( - ({ kind }) => `Missing initializer in ${kind} declaration.`, - ), - DecoratorBeforeExport: _( + ConstructorIsAccessor: "Class constructor may not be an accessor.", + ConstructorIsAsync: "Constructor can't be an async function.", + ConstructorIsGenerator: "Constructor can't be a generator.", + DeclarationMissingInitializer: ({ + kind, + }: { + kind: "const" | "destructuring"; + }) => `Missing initializer in ${kind} declaration.`, + DecoratorBeforeExport: "Decorators must be placed *before* the 'export' keyword. You can set the 'decoratorsBeforeExport' option to false to use the 'export @decorator class {}' syntax.", - ), - DecoratorConstructor: _( + DecoratorConstructor: "Decorators can't be used with a constructor. Did you mean '@dec class { ... }'?", - ), - DecoratorExportClass: _( + DecoratorExportClass: "Using the export keyword between a decorator and a class is not allowed. Please use `export @dec class` instead.", - ), - DecoratorSemicolon: _("Decorators must not be followed by a semicolon."), - DecoratorStaticBlock: _("Decorators can't be used with a static block."), - DeletePrivateField: _("Deleting a private field is not allowed."), - DestructureNamedImport: _( + DecoratorSemicolon: "Decorators must not be followed by a semicolon.", + DecoratorStaticBlock: "Decorators can't be used with a static block.", + DeletePrivateField: "Deleting a private field is not allowed.", + DestructureNamedImport: "ES2015 named imports do not destructure. Use another statement for destructuring after the import.", - ), - DuplicateConstructor: _("Duplicate constructor in the same class."), - DuplicateDefaultExport: _("Only one default export allowed per module."), - DuplicateExport: _<{ exportName: string }>( - ({ exportName }) => - `\`${exportName}\` has already been exported. Exported identifiers must be unique.`, - ), - DuplicateProto: _("Redefinition of __proto__ property."), - DuplicateRegExpFlags: _("Duplicate regular expression flag."), - ElementAfterRest: _("Rest element must be last element."), - EscapedCharNotAnIdentifier: _("Invalid Unicode escape."), - ExportBindingIsString: _<{ localName: string; exportName: string }>( - ({ localName, exportName }) => - `A string literal cannot be used as an exported binding without \`from\`.\n- Did you mean \`export { '${localName}' as '${exportName}' } from 'some-module'\`?`, - ), - ExportDefaultFromAsIdentifier: _( + DuplicateConstructor: "Duplicate constructor in the same class.", + DuplicateDefaultExport: "Only one default export allowed per module.", + DuplicateExport: ({ exportName }: { exportName: string }) => + `\`${exportName}\` has already been exported. Exported identifiers must be unique.`, + DuplicateProto: "Redefinition of __proto__ property.", + DuplicateRegExpFlags: "Duplicate regular expression flag.", + ElementAfterRest: "Rest element must be last element.", + EscapedCharNotAnIdentifier: "Invalid Unicode escape.", + ExportBindingIsString: ({ + localName, + exportName, + }: { + localName: string; + exportName: string; + }) => + `A string literal cannot be used as an exported binding without \`from\`.\n- Did you mean \`export { '${localName}' as '${exportName}' } from 'some-module'\`?`, + ExportDefaultFromAsIdentifier: "'from' is not allowed as an identifier after 'export default'.", - ), - ForInOfLoopInitializer: _<{ type: "ForInStatement" | "ForOfStatement" }>( - ({ type }) => - `'${ - type === "ForInStatement" ? "for-in" : "for-of" - }' loop variable declaration may not have an initializer.`, - ), + ForInOfLoopInitializer: ({ + type, + }: { + type: "ForInStatement" | "ForOfStatement"; + }) => + `'${ + type === "ForInStatement" ? "for-in" : "for-of" + }' loop variable declaration may not have an initializer.`, - ForOfAsync: _("The left-hand side of a for-of loop may not be 'async'."), - ForOfLet: _("The left-hand side of a for-of loop may not start with 'let'."), - GeneratorInSingleStatementContext: _( + ForOfAsync: "The left-hand side of a for-of loop may not be 'async'.", + ForOfLet: "The left-hand side of a for-of loop may not start with 'let'.", + GeneratorInSingleStatementContext: "Generators can only be declared at the top level or inside a block.", - ), - IllegalBreakContinue: _<{ type: "BreakStatement" | "ContinueStatement" }>( - ({ type }) => - `Unsyntactic ${type === "BreakStatement" ? "break" : "continue"}.`, - ), + IllegalBreakContinue: ({ + type, + }: { + type: "BreakStatement" | "ContinueStatement"; + }) => `Unsyntactic ${type === "BreakStatement" ? "break" : "continue"}.`, - IllegalLanguageModeDirective: _( + IllegalLanguageModeDirective: "Illegal 'use strict' directive in function with non-simple parameter list.", - ), - IllegalReturn: _("'return' outside of function."), - ImportBindingIsString: _<{ importName: string }>( - ({ importName }) => - `A string literal cannot be used as an imported binding.\n- Did you mean \`import { "${importName}" as foo }\`?`, - ), - ImportCallArgumentTrailingComma: _( + IllegalReturn: "'return' outside of function.", + ImportBindingIsString: ({ importName }: { importName: string }) => + `A string literal cannot be used as an imported binding.\n- Did you mean \`import { "${importName}" as foo }\`?`, + ImportCallArgumentTrailingComma: "Trailing comma is disallowed inside import(...) arguments.", - ), - ImportCallArity: _<{ maxArgumentCount: 1 | 2 }>( - ({ maxArgumentCount }) => - `\`import()\` requires exactly ${ - maxArgumentCount === 1 ? "one argument" : "one or two arguments" - }.`, - ), - ImportCallNotNewExpression: _("Cannot use new with import(...)."), - ImportCallSpreadArgument: _("`...` is not allowed in `import()`."), - ImportJSONBindingNotDefault: _( + ImportCallArity: ({ maxArgumentCount }: { maxArgumentCount: 1 | 2 }) => + `\`import()\` requires exactly ${ + maxArgumentCount === 1 ? "one argument" : "one or two arguments" + }.`, + ImportCallNotNewExpression: "Cannot use new with import(...).", + ImportCallSpreadArgument: "`...` is not allowed in `import()`.", + ImportJSONBindingNotDefault: "A JSON module can only be imported with `default`.", - ), - IncompatibleRegExpUVFlags: _( + IncompatibleRegExpUVFlags: "The 'u' and 'v' regular expression flags cannot be enabled at the same time.", - ), - InvalidBigIntLiteral: _("Invalid BigIntLiteral."), - InvalidCodePoint: _("Code point out of bounds."), - InvalidCoverInitializedName: _("Invalid shorthand property initializer."), - InvalidDecimal: _("Invalid decimal."), - InvalidDigit: _<{ radix: number }>( - ({ radix }) => `Expected number in radix ${radix}.`, - ), - InvalidEscapeSequence: _("Bad character escape sequence."), - InvalidEscapeSequenceTemplate: _("Invalid escape sequence in template."), - InvalidEscapedReservedWord: _<{ reservedWord: string }>( - ({ reservedWord }) => `Escape sequence in keyword ${reservedWord}.`, - ), - InvalidIdentifier: _<{ identifierName: string }>( - ({ identifierName }) => `Invalid identifier ${identifierName}.`, - ), - InvalidLhs: _<{ ancestor: LValAncestor }>( - ({ ancestor }) => - `Invalid left-hand side in ${toNodeDescription(ancestor)}.`, - ), - InvalidLhsBinding: _<{ ancestor: LValAncestor }>( - ({ ancestor }) => - `Binding invalid left-hand side in ${toNodeDescription(ancestor)}.`, - ), - InvalidNumber: _("Invalid number."), - InvalidOrMissingExponent: _( + InvalidBigIntLiteral: "Invalid BigIntLiteral.", + InvalidCodePoint: "Code point out of bounds.", + InvalidCoverInitializedName: "Invalid shorthand property initializer.", + InvalidDecimal: "Invalid decimal.", + InvalidDigit: ({ radix }: { radix: number }) => + `Expected number in radix ${radix}.`, + InvalidEscapeSequence: "Bad character escape sequence.", + InvalidEscapeSequenceTemplate: "Invalid escape sequence in template.", + InvalidEscapedReservedWord: ({ reservedWord }: { reservedWord: string }) => + `Escape sequence in keyword ${reservedWord}.`, + InvalidIdentifier: ({ identifierName }: { identifierName: string }) => + `Invalid identifier ${identifierName}.`, + InvalidLhs: ({ ancestor }: { ancestor: LValAncestor }) => + `Invalid left-hand side in ${toNodeDescription(ancestor)}.`, + InvalidLhsBinding: ({ ancestor }: { ancestor: LValAncestor }) => + `Binding invalid left-hand side in ${toNodeDescription(ancestor)}.`, + InvalidNumber: "Invalid number.", + InvalidOrMissingExponent: "Floating-point numbers require a valid exponent after the 'e'.", - ), - InvalidOrUnexpectedToken: _<{ unexpected: string }>( - ({ unexpected }) => `Unexpected character '${unexpected}'.`, - ), - InvalidParenthesizedAssignment: _( - "Invalid parenthesized assignment pattern.", - ), - InvalidPrivateFieldResolution: _<{ identifierName: string }>( - ({ identifierName }) => `Private name #${identifierName} is not defined.`, - ), - InvalidPropertyBindingPattern: _("Binding member expression."), - InvalidRecordProperty: _( + InvalidOrUnexpectedToken: ({ unexpected }: { unexpected: string }) => + `Unexpected character '${unexpected}'.`, + InvalidParenthesizedAssignment: "Invalid parenthesized assignment pattern.", + InvalidPrivateFieldResolution: ({ + identifierName, + }: { + identifierName: string; + }) => `Private name #${identifierName} is not defined.`, + InvalidPropertyBindingPattern: "Binding member expression.", + InvalidRecordProperty: "Only properties and spread elements are allowed in record definitions.", - ), - InvalidRestAssignmentPattern: _("Invalid rest operator's argument."), - LabelRedeclaration: _<{ labelName: string }>( - ({ labelName }) => `Label '${labelName}' is already declared.`, - ), - LetInLexicalBinding: _( + InvalidRestAssignmentPattern: "Invalid rest operator's argument.", + LabelRedeclaration: ({ labelName }: { labelName: string }) => + `Label '${labelName}' is already declared.`, + LetInLexicalBinding: "'let' is not allowed to be used as a name in 'let' or 'const' declarations.", - ), - LineTerminatorBeforeArrow: _("No line break is allowed before '=>'."), - MalformedRegExpFlags: _("Invalid regular expression flag."), - MissingClassName: _("A class name is required."), - MissingEqInAssignment: _( + LineTerminatorBeforeArrow: "No line break is allowed before '=>'.", + MalformedRegExpFlags: "Invalid regular expression flag.", + MissingClassName: "A class name is required.", + MissingEqInAssignment: "Only '=' operator can be used for specifying default value.", - ), - MissingSemicolon: _("Missing semicolon."), - MissingPlugin: _<{ missingPlugin: [string] }>( - ({ missingPlugin }) => - `This experimental syntax requires enabling the parser plugin: ${missingPlugin - .map(name => JSON.stringify(name)) - .join(", ")}.`, - ), + MissingSemicolon: "Missing semicolon.", + MissingPlugin: ({ missingPlugin }: { missingPlugin: [string] }) => + `This experimental syntax requires enabling the parser plugin: ${missingPlugin + .map(name => JSON.stringify(name)) + .join(", ")}.`, // FIXME: Would be nice to make this "missingPlugins" instead. - // Also), seems like we can drop the "(s)" from the message and just make it "s". - MissingOneOfPlugins: _<{ missingPlugin: string[] }>( - ({ missingPlugin }) => - `This experimental syntax requires enabling one of the following parser plugin(s): ${missingPlugin - .map(name => JSON.stringify(name)) - .join(", ")}.`, - ), - MissingUnicodeEscape: _("Expecting Unicode escape sequence \\uXXXX."), - MixingCoalesceWithLogical: _( + // Also, seems like we can drop the "(s)" from the message and just make it "s". + MissingOneOfPlugins: ({ missingPlugin }: { missingPlugin: string[] }) => + `This experimental syntax requires enabling one of the following parser plugin(s): ${missingPlugin + .map(name => JSON.stringify(name)) + .join(", ")}.`, + MissingUnicodeEscape: "Expecting Unicode escape sequence \\uXXXX.", + MixingCoalesceWithLogical: "Nullish coalescing operator(??) requires parens when mixing with logical operators.", - ), - ModuleAttributeDifferentFromType: _( + ModuleAttributeDifferentFromType: "The only accepted module attribute is `type`.", - ), - ModuleAttributeInvalidValue: _( + ModuleAttributeInvalidValue: "Only string literals are allowed as module attribute values.", - ), - ModuleAttributesWithDuplicateKeys: _<{ key: string }>( - ({ key }) => `Duplicate key "${key}" is not allowed in module attributes.`, - ), - ModuleExportNameHasLoneSurrogate: _<{ surrogateCharCode: number }>( - ({ surrogateCharCode }) => - `An export name cannot include a lone surrogate, found '\\u${surrogateCharCode.toString( - 16, - )}'.`, - ), - ModuleExportUndefined: _<{ localName: string }>( - ({ localName }) => `Export '${localName}' is not defined.`, - ), - MultipleDefaultsInSwitch: _("Multiple default clauses."), - NewlineAfterThrow: _("Illegal newline after throw."), - NoCatchOrFinally: _("Missing catch or finally clause."), - NumberIdentifier: _("Identifier directly after number."), - NumericSeparatorInEscapeSequence: _( + ModuleAttributesWithDuplicateKeys: ({ key }: { key: string }) => + `Duplicate key "${key}" is not allowed in module attributes.`, + ModuleExportNameHasLoneSurrogate: ({ + surrogateCharCode, + }: { + surrogateCharCode: number; + }) => + `An export name cannot include a lone surrogate, found '\\u${surrogateCharCode.toString( + 16, + )}'.`, + ModuleExportUndefined: ({ localName }: { localName: string }) => + `Export '${localName}' is not defined.`, + MultipleDefaultsInSwitch: "Multiple default clauses.", + NewlineAfterThrow: "Illegal newline after throw.", + NoCatchOrFinally: "Missing catch or finally clause.", + NumberIdentifier: "Identifier directly after number.", + NumericSeparatorInEscapeSequence: "Numeric separators are not allowed inside unicode escape sequences or hex escape sequences.", - ), - ObsoleteAwaitStar: _( + ObsoleteAwaitStar: "'await*' has been removed from the async functions proposal. Use Promise.all() instead.", - ), - OptionalChainingNoNew: _( + OptionalChainingNoNew: "Constructors in/after an Optional Chain are not allowed.", - ), - OptionalChainingNoTemplate: _( + OptionalChainingNoTemplate: "Tagged Template Literals are not allowed in optionalChain.", - ), - OverrideOnConstructor: _( + OverrideOnConstructor: "'override' modifier cannot appear on a constructor declaration.", - ), - ParamDupe: _("Argument name clash."), - PatternHasAccessor: _("Object pattern can't contain getter or setter."), - PatternHasMethod: _("Object pattern can't contain methods."), - PrivateInExpectedIn: _<{ identifierName: string }>( - ({ identifierName }) => - `Private names are only allowed in property accesses (\`obj.#${identifierName}\`) or in \`in\` expressions (\`#${identifierName} in obj\`).`, - ), - PrivateNameRedeclaration: _<{ identifierName: string }>( - ({ identifierName }) => `Duplicate private name #${identifierName}.`, - ), - RecordExpressionBarIncorrectEndSyntaxType: _( + ParamDupe: "Argument name clash.", + PatternHasAccessor: "Object pattern can't contain getter or setter.", + PatternHasMethod: "Object pattern can't contain methods.", + PrivateInExpectedIn: ({ identifierName }: { identifierName: string }) => + `Private names are only allowed in property accesses (\`obj.#${identifierName}\`) or in \`in\` expressions (\`#${identifierName} in obj\`).`, + PrivateNameRedeclaration: ({ identifierName }: { identifierName: string }) => + `Duplicate private name #${identifierName}.`, + RecordExpressionBarIncorrectEndSyntaxType: "Record expressions ending with '|}' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'bar'.", - ), - RecordExpressionBarIncorrectStartSyntaxType: _( + RecordExpressionBarIncorrectStartSyntaxType: "Record expressions starting with '{|' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'bar'.", - ), - RecordExpressionHashIncorrectStartSyntaxType: _( + RecordExpressionHashIncorrectStartSyntaxType: "Record expressions starting with '#{' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'hash'.", - ), - RecordNoProto: _("'__proto__' is not allowed in Record expressions."), - RestTrailingComma: _("Unexpected trailing comma after rest element."), - SloppyFunction: _( + RecordNoProto: "'__proto__' is not allowed in Record expressions.", + RestTrailingComma: "Unexpected trailing comma after rest element.", + SloppyFunction: "In non-strict mode code, functions can only be declared at top level, inside a block, or as the body of an if statement.", - ), - StaticPrototype: _("Classes may not have static property named prototype."), - SuperNotAllowed: _( + StaticPrototype: "Classes may not have static property named prototype.", + SuperNotAllowed: "`super()` is only valid inside a class constructor of a subclass. Maybe a typo in the method name ('constructor') or not extending another class?", - ), - SuperPrivateField: _("Private fields can't be accessed on super."), - TrailingDecorator: _("Decorators must be attached to a class element."), - TupleExpressionBarIncorrectEndSyntaxType: _( + SuperPrivateField: "Private fields can't be accessed on super.", + TrailingDecorator: "Decorators must be attached to a class element.", + TupleExpressionBarIncorrectEndSyntaxType: "Tuple expressions ending with '|]' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'bar'.", - ), - TupleExpressionBarIncorrectStartSyntaxType: _( + TupleExpressionBarIncorrectStartSyntaxType: "Tuple expressions starting with '[|' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'bar'.", - ), - TupleExpressionHashIncorrectStartSyntaxType: _( + TupleExpressionHashIncorrectStartSyntaxType: "Tuple expressions starting with '#[' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'hash'.", - ), - UnexpectedArgumentPlaceholder: _("Unexpected argument placeholder."), - UnexpectedAwaitAfterPipelineBody: _( + UnexpectedArgumentPlaceholder: "Unexpected argument placeholder.", + UnexpectedAwaitAfterPipelineBody: 'Unexpected "await" after pipeline body; await must have parentheses in minimal proposal.', - ), - UnexpectedDigitAfterHash: _("Unexpected digit after hash token."), - UnexpectedImportExport: _( + UnexpectedDigitAfterHash: "Unexpected digit after hash token.", + UnexpectedImportExport: "'import' and 'export' may only appear at the top level.", - ), - UnexpectedKeyword: _<{ keyword: string }>( - ({ keyword }) => `Unexpected keyword '${keyword}'.`, - ), - UnexpectedLeadingDecorator: _( + UnexpectedKeyword: ({ keyword }: { keyword: string }) => + `Unexpected keyword '${keyword}'.`, + UnexpectedLeadingDecorator: "Leading decorators must be attached to a class declaration.", - ), - UnexpectedLexicalDeclaration: _( + UnexpectedLexicalDeclaration: "Lexical declaration cannot appear in a single-statement context.", - ), - UnexpectedNewTarget: _( + UnexpectedNewTarget: "`new.target` can only be used in functions or class properties.", - ), - UnexpectedNumericSeparator: _( + UnexpectedNumericSeparator: "A numeric separator is only allowed between two digits.", - ), - UnexpectedPrivateField: _("Unexpected private name."), - UnexpectedReservedWord: _<{ reservedWord: string }>( - ({ reservedWord }) => `Unexpected reserved word '${reservedWord}'.`, - ), - UnexpectedSuper: _("'super' is only allowed in object methods and classes."), - UnexpectedToken: _<{ expected?: string | null; unexpected?: string | null }>( - ({ expected, unexpected }) => - `Unexpected token${unexpected ? ` '${unexpected}'.` : ""}${ - expected ? `, expected "${expected}"` : "" - }`, - ), - UnexpectedTokenUnaryExponentiation: _( + UnexpectedPrivateField: "Unexpected private name.", + UnexpectedReservedWord: ({ reservedWord }: { reservedWord: string }) => + `Unexpected reserved word '${reservedWord}'.`, + UnexpectedSuper: "'super' is only allowed in object methods and classes.", + UnexpectedToken: ({ + expected, + unexpected, + }: { + expected?: string | null; + unexpected?: string | null; + }) => + `Unexpected token${unexpected ? ` '${unexpected}'.` : ""}${ + expected ? `, expected "${expected}"` : "" + }`, + UnexpectedTokenUnaryExponentiation: "Illegal expression. Wrap left hand side or entire exponentiation in parentheses.", - ), - UnsupportedBind: _("Binding should be performed on object property."), - UnsupportedDecoratorExport: _( + UnsupportedBind: "Binding should be performed on object property.", + UnsupportedDecoratorExport: "A decorated export must export a class declaration.", - ), - UnsupportedDefaultExport: _( + UnsupportedDefaultExport: "Only expressions, functions or classes are allowed as the `default` export.", - ), - UnsupportedImport: _( + UnsupportedImport: "`import` can only be used in `import()` or `import.meta`.", - ), - UnsupportedMetaProperty: _<{ target: string; onlyValidPropertyName: string }>( - ({ target, onlyValidPropertyName }) => - `The only valid meta property for ${target} is ${target}.${onlyValidPropertyName}.`, - ), - UnsupportedParameterDecorator: _( + UnsupportedMetaProperty: ({ + target, + onlyValidPropertyName, + }: { + target: string; + onlyValidPropertyName: string; + }) => + `The only valid meta property for ${target} is ${target}.${onlyValidPropertyName}.`, + UnsupportedParameterDecorator: "Decorators cannot be used to decorate parameters.", - ), - UnsupportedPropertyDecorator: _( + UnsupportedPropertyDecorator: "Decorators cannot be used to decorate object literal properties.", - ), - UnsupportedSuper: _( + UnsupportedSuper: "'super' can only be used with function calls (i.e. super()) or in property accesses (i.e. super.prop or super[prop]).", - ), - UnterminatedComment: _("Unterminated comment."), - UnterminatedRegExp: _("Unterminated regular expression."), - UnterminatedString: _("Unterminated string constant."), - UnterminatedTemplate: _("Unterminated template."), - VarRedeclaration: _<{ identifierName: string }>( - ({ identifierName }) => - `Identifier '${identifierName}' has already been declared.`, - ), - YieldBindingIdentifier: _( + UnterminatedComment: "Unterminated comment.", + UnterminatedRegExp: "Unterminated regular expression.", + UnterminatedString: "Unterminated string constant.", + UnterminatedTemplate: "Unterminated template.", + VarRedeclaration: ({ identifierName }: { identifierName: string }) => + `Identifier '${identifierName}' has already been declared.`, + YieldBindingIdentifier: "Can not use 'yield' as identifier inside a generator.", - ), - YieldInParameter: _("Yield expression is not allowed in formal parameters."), - ZeroDigitNumericSeparator: _( + YieldInParameter: "Yield expression is not allowed in formal parameters.", + ZeroDigitNumericSeparator: "Numeric separator can not be used after leading 0.", - ), -}); +}; diff --git a/packages/babel-parser/src/parse-error/strict-mode-errors.ts b/packages/babel-parser/src/parse-error/strict-mode-errors.ts index 1a6da37ac225..b419dc9fa331 100644 --- a/packages/babel-parser/src/parse-error/strict-mode-errors.ts +++ b/packages/babel-parser/src/parse-error/strict-mode-errors.ts @@ -1,33 +1,28 @@ -import { toParseErrorCredentials } from "../parse-error"; - -export default (_: typeof toParseErrorCredentials) => ({ - StrictDelete: _("Deleting local variable in strict mode."), +export default { + StrictDelete: "Deleting local variable in strict mode.", // `referenceName` is the StringValue[1] of an IdentifierReference[2], which // is represented as just an `Identifier`[3] in the Babel AST. // 1. https://tc39.es/ecma262/#sec-static-semantics-stringvalue // 2. https://tc39.es/ecma262/#prod-IdentifierReference // 3. https://github.com/babel/babel/blob/main/packages/babel-parser/ast/spec.md#identifier - StrictEvalArguments: _<{ - referenceName: string; - }>(({ referenceName }) => `Assigning to '${referenceName}' in strict mode.`), + StrictEvalArguments: ({ referenceName }: { referenceName: string }) => + `Assigning to '${referenceName}' in strict mode.`, + // `bindingName` is the StringValue[1] of a BindingIdentifier[2], which is // represented as just an `Identifier`[3] in the Babel AST. // 1. https://tc39.es/ecma262/#sec-static-semantics-stringvalue // 2. https://tc39.es/ecma262/#prod-BindingIdentifier // 3. https://github.com/babel/babel/blob/main/packages/babel-parser/ast/spec.md#identifier - StrictEvalArgumentsBinding: _<{ - bindingName: string; - }>(({ bindingName }) => `Binding '${bindingName}' in strict mode.`), + StrictEvalArgumentsBinding: ({ bindingName }: { bindingName: string }) => + `Binding '${bindingName}' in strict mode.`, - StrictFunction: _( + StrictFunction: "In strict mode code, functions can only be declared at top level or inside a block.", - ), - StrictNumericEscape: _( - "The only valid numeric escape in strict mode is '\\0'.", - ), - StrictOctalLiteral: _( - "Legacy octal literals are not allowed in strict mode.", - ), - StrictWith: _("'with' in strict mode."), -}); + + StrictNumericEscape: "The only valid numeric escape in strict mode is '\\0'.", + + StrictOctalLiteral: "Legacy octal literals are not allowed in strict mode.", + + StrictWith: "'with' in strict mode.", +}; diff --git a/packages/babel-parser/src/plugins/flow/index.ts b/packages/babel-parser/src/plugins/flow/index.ts index 52536024f696..861187aa21d4 100644 --- a/packages/babel-parser/src/plugins/flow/index.ts +++ b/packages/babel-parser/src/plugins/flow/index.ts @@ -28,11 +28,7 @@ import { type BindingTypes, } from "../../util/scopeflags"; import type { ExpressionErrors } from "../../parser/util"; -import { - Errors, - ParseErrorEnum, - toParseErrorCredentials, -} from "../../parse-error"; +import { Errors, ParseErrorEnum } from "../../parse-error"; import { cloneIdentifier, type Undone } from "../../parser/node"; const reservedTypes = new Set([ @@ -56,204 +52,182 @@ const reservedTypes = new Set([ /* eslint sort-keys: "error" */ // The Errors key follows https://github.com/facebook/flow/blob/master/src/parser/parse_error.ml unless it does not exist -const FlowErrors = ParseErrorEnum`flow`( - (_: typeof toParseErrorCredentials) => ({ - AmbiguousConditionalArrow: _( - "Ambiguous expression: wrap the arrow functions in parentheses to disambiguate.", - ), - AmbiguousDeclareModuleKind: _( - "Found both `declare module.exports` and `declare export` in the same module. Modules can only have 1 since they are either an ES module or they are a CommonJS module.", - ), - // TODO: When we get proper string enums in typescript make this ReservedType. - // Not really worth it to do the whole $Values dance with reservedTypes set. - AssignReservedType: _<{ - reservedType: string; - }>(({ reservedType }) => `Cannot overwrite reserved type ${reservedType}.`), - DeclareClassElement: _( - "The `declare` modifier can only appear on class fields.", - ), - DeclareClassFieldInitializer: _( - "Initializers are not allowed in fields with the `declare` modifier.", - ), - DuplicateDeclareModuleExports: _( - "Duplicate `declare module.exports` statement.", - ), - EnumBooleanMemberNotInitialized: _<{ - memberName: string; - enumName: string; - }>( - ({ memberName, enumName }) => - `Boolean enum members need to be initialized. Use either \`${memberName} = true,\` or \`${memberName} = false,\` in enum \`${enumName}\`.`, - ), - EnumDuplicateMemberName: _<{ - memberName: string; - enumName: string; - }>( - ({ memberName, enumName }) => - `Enum member names need to be unique, but the name \`${memberName}\` has already been used before in enum \`${enumName}\`.`, - ), - EnumInconsistentMemberValues: _<{ - enumName: string; - }>( - ({ enumName }) => - `Enum \`${enumName}\` has inconsistent member initializers. Either use no initializers, or consistently use literals (either booleans, numbers, or strings) for all member initializers.`, - ), - EnumInvalidExplicitType: _<{ - invalidEnumType: string; - enumName: string; - }>( - ({ invalidEnumType, enumName }) => - `Enum type \`${invalidEnumType}\` is not valid. Use one of \`boolean\`, \`number\`, \`string\`, or \`symbol\` in enum \`${enumName}\`.`, - ), - EnumInvalidExplicitTypeUnknownSupplied: _<{ - enumName: string; - }>( - ({ enumName }) => - `Supplied enum type is not valid. Use one of \`boolean\`, \`number\`, \`string\`, or \`symbol\` in enum \`${enumName}\`.`, - ), - - // TODO: When moving to typescript, we should either have each of the - // following errors only accept the specific strings they want: - // - // ...PrimaryType: explicitType: "string" | "number" | "boolean" - // ...SymbolType: explicitType: "symbol" - // ...UnknownType: explicitType: null - // - // Or, alternatively, merge these three errors together into one - // `EnumInvalidMemberInitializer` error that can accept `EnumExplicitType` - // without alteration, and then just have its message change based on the - // explicitType. - EnumInvalidMemberInitializerPrimaryType: _<{ - enumName: string; - memberName: string; - explicitType: EnumExplicitType; - }>( - ({ enumName, memberName, explicitType }) => - `Enum \`${enumName}\` has type \`${explicitType}\`, so the initializer of \`${memberName}\` needs to be a ${explicitType} literal.`, - ), - EnumInvalidMemberInitializerSymbolType: _<{ - enumName: string; - memberName: string; - explicitType: EnumExplicitType; - }>( - ({ enumName, memberName }) => - `Symbol enum members cannot be initialized. Use \`${memberName},\` in enum \`${enumName}\`.`, - ), - EnumInvalidMemberInitializerUnknownType: _<{ - enumName: string; - memberName: string; - explicitType: EnumExplicitType; - }>( - ({ enumName, memberName }) => - `The enum member initializer for \`${memberName}\` needs to be a literal (either a boolean, number, or string) in enum \`${enumName}\`.`, - ), - EnumInvalidMemberName: _<{ - enumName: string; - memberName: string; - suggestion: string; - }>( - ({ enumName, memberName, suggestion }) => - `Enum member names cannot start with lowercase 'a' through 'z'. Instead of using \`${memberName}\`, consider using \`${suggestion}\`, in enum \`${enumName}\`.`, - ), - EnumNumberMemberNotInitialized: _<{ - enumName: string; - memberName: string; - }>( - ({ enumName, memberName }) => - `Number enum members need to be initialized, e.g. \`${memberName} = 1\` in enum \`${enumName}\`.`, - ), - EnumStringMemberInconsistentlyInitailized: _<{ - enumName: string; - }>( - ({ enumName }) => - `String enum members need to consistently either all use initializers, or use no initializers, in enum \`${enumName}\`.`, - ), - GetterMayNotHaveThisParam: _("A getter cannot have a `this` parameter."), - ImportTypeShorthandOnlyInPureImport: _( - "The `type` and `typeof` keywords on named imports can only be used on regular `import` statements. It cannot be used with `import type` or `import typeof` statements.", - ), - InexactInsideExact: _( - "Explicit inexact syntax cannot appear inside an explicit exact object type.", - ), - InexactInsideNonObject: _( - "Explicit inexact syntax cannot appear in class or interface definitions.", - ), - InexactVariance: _("Explicit inexact syntax cannot have variance."), - InvalidNonTypeImportInDeclareModule: _( - "Imports within a `declare module` body must always be `import type` or `import typeof`.", - ), - MissingTypeParamDefault: _( - "Type parameter declaration needs a default, since a preceding type parameter declaration has a default.", - ), - NestedDeclareModule: _( - "`declare module` cannot be used inside another `declare module`.", - ), - NestedFlowComment: _( - "Cannot have a flow comment inside another flow comment.", - ), - PatternIsOptional: _( +const FlowErrors = ParseErrorEnum`flow`({ + AmbiguousConditionalArrow: + "Ambiguous expression: wrap the arrow functions in parentheses to disambiguate.", + AmbiguousDeclareModuleKind: + "Found both `declare module.exports` and `declare export` in the same module. Modules can only have 1 since they are either an ES module or they are a CommonJS module.", + // TODO: When we get proper string enums in typescript make this ReservedType. + // Not really worth it to do the whole $Values dance with reservedTypes set. + AssignReservedType: ({ reservedType }: { reservedType: string }) => + `Cannot overwrite reserved type ${reservedType}.`, + DeclareClassElement: + "The `declare` modifier can only appear on class fields.", + DeclareClassFieldInitializer: + "Initializers are not allowed in fields with the `declare` modifier.", + DuplicateDeclareModuleExports: + "Duplicate `declare module.exports` statement.", + EnumBooleanMemberNotInitialized: ({ + memberName, + enumName, + }: { + memberName: string; + enumName: string; + }) => + `Boolean enum members need to be initialized. Use either \`${memberName} = true,\` or \`${memberName} = false,\` in enum \`${enumName}\`.`, + EnumDuplicateMemberName: ({ + memberName, + enumName, + }: { + memberName: string; + enumName: string; + }) => + `Enum member names need to be unique, but the name \`${memberName}\` has already been used before in enum \`${enumName}\`.`, + EnumInconsistentMemberValues: ({ enumName }: { enumName: string }) => + `Enum \`${enumName}\` has inconsistent member initializers. Either use no initializers, or consistently use literals (either booleans, numbers, or strings) for all member initializers.`, + EnumInvalidExplicitType: ({ + invalidEnumType, + enumName, + }: { + invalidEnumType: string; + enumName: string; + }) => + `Enum type \`${invalidEnumType}\` is not valid. Use one of \`boolean\`, \`number\`, \`string\`, or \`symbol\` in enum \`${enumName}\`.`, + EnumInvalidExplicitTypeUnknownSupplied: ({ + enumName, + }: { + enumName: string; + }) => + `Supplied enum type is not valid. Use one of \`boolean\`, \`number\`, \`string\`, or \`symbol\` in enum \`${enumName}\`.`, + + // TODO: When moving to typescript, we should either have each of the + // following errors only accept the specific strings they want: + // + // ...PrimaryType: explicitType: "string" | "number" | "boolean" + // ...SymbolType: explicitType: "symbol" + // ...UnknownType: explicitType: null + // + // Or, alternatively, merge these three errors together into one + // `EnumInvalidMemberInitializer` error that can accept `EnumExplicitType` + // without alteration, and then just have its message change based on the + // explicitType. + EnumInvalidMemberInitializerPrimaryType: ({ + enumName, + memberName, + explicitType, + }: { + enumName: string; + memberName: string; + explicitType: EnumExplicitType; + }) => + `Enum \`${enumName}\` has type \`${explicitType}\`, so the initializer of \`${memberName}\` needs to be a ${explicitType} literal.`, + EnumInvalidMemberInitializerSymbolType: ({ + enumName, + memberName, + }: { + enumName: string; + memberName: string; + explicitType: EnumExplicitType; + }) => + `Symbol enum members cannot be initialized. Use \`${memberName},\` in enum \`${enumName}\`.`, + EnumInvalidMemberInitializerUnknownType: ({ + enumName, + memberName, + }: { + enumName: string; + memberName: string; + explicitType: EnumExplicitType; + }) => + `The enum member initializer for \`${memberName}\` needs to be a literal (either a boolean, number, or string) in enum \`${enumName}\`.`, + EnumInvalidMemberName: ({ + enumName, + memberName, + suggestion, + }: { + enumName: string; + memberName: string; + suggestion: string; + }) => + `Enum member names cannot start with lowercase 'a' through 'z'. Instead of using \`${memberName}\`, consider using \`${suggestion}\`, in enum \`${enumName}\`.`, + EnumNumberMemberNotInitialized: ({ + enumName, + memberName, + }: { + enumName: string; + memberName: string; + }) => + `Number enum members need to be initialized, e.g. \`${memberName} = 1\` in enum \`${enumName}\`.`, + EnumStringMemberInconsistentlyInitailized: ({ + enumName, + }: { + enumName: string; + }) => + `String enum members need to consistently either all use initializers, or use no initializers, in enum \`${enumName}\`.`, + GetterMayNotHaveThisParam: "A getter cannot have a `this` parameter.", + ImportTypeShorthandOnlyInPureImport: + "The `type` and `typeof` keywords on named imports can only be used on regular `import` statements. It cannot be used with `import type` or `import typeof` statements.", + InexactInsideExact: + "Explicit inexact syntax cannot appear inside an explicit exact object type.", + InexactInsideNonObject: + "Explicit inexact syntax cannot appear in class or interface definitions.", + InexactVariance: "Explicit inexact syntax cannot have variance.", + InvalidNonTypeImportInDeclareModule: + "Imports within a `declare module` body must always be `import type` or `import typeof`.", + MissingTypeParamDefault: + "Type parameter declaration needs a default, since a preceding type parameter declaration has a default.", + NestedDeclareModule: + "`declare module` cannot be used inside another `declare module`.", + NestedFlowComment: "Cannot have a flow comment inside another flow comment.", + PatternIsOptional: { + message: "A binding pattern parameter cannot be optional in an implementation signature.", - // For consistency in TypeScript and Flow error codes - !process.env.BABEL_8_BREAKING - ? { reasonCode: "OptionalBindingPattern" } - : {}, - ), - SetterMayNotHaveThisParam: _("A setter cannot have a `this` parameter."), - SpreadVariance: _("Spread properties cannot have variance."), - ThisParamAnnotationRequired: _( - "A type annotation is required for the `this` parameter.", - ), - ThisParamBannedInConstructor: _( - "Constructors cannot have a `this` parameter; constructors don't bind `this` like other functions.", - ), - ThisParamMayNotBeOptional: _("The `this` parameter cannot be optional."), - ThisParamMustBeFirst: _( - "The `this` parameter must be the first function parameter.", - ), - ThisParamNoDefault: _("The `this` parameter may not have a default value."), - TypeBeforeInitializer: _( - "Type annotations must come before default assignments, e.g. instead of `age = 25: number` use `age: number = 25`.", - ), - TypeCastInPattern: _( - "The type cast expression is expected to be wrapped with parenthesis.", - ), - UnexpectedExplicitInexactInObject: _( - "Explicit inexact syntax must appear at the end of an inexact object.", - ), - UnexpectedReservedType: _<{ - reservedType: string; - }>(({ reservedType }) => `Unexpected reserved type ${reservedType}.`), - UnexpectedReservedUnderscore: _( - "`_` is only allowed as a type argument to call or new.", - ), - UnexpectedSpaceBetweenModuloChecks: _( - "Spaces between `%` and `checks` are not allowed here.", - ), - UnexpectedSpreadType: _( - "Spread operator cannot appear in class or interface definitions.", - ), - UnexpectedSubtractionOperand: _( - 'Unexpected token, expected "number" or "bigint".', - ), - UnexpectedTokenAfterTypeParameter: _( - "Expected an arrow function after this type parameter declaration.", - ), - UnexpectedTypeParameterBeforeAsyncArrowFunction: _( - "Type parameters must come after the async keyword, e.g. instead of ` async () => {}`, use `async () => {}`.", - ), - UnsupportedDeclareExportKind: _<{ - unsupportedExportKind: string; - suggestion: string; - }>( - ({ unsupportedExportKind, suggestion }) => - `\`declare export ${unsupportedExportKind}\` is not supported. Use \`${suggestion}\` instead.`, - ), - UnsupportedStatementInDeclareModule: _( - "Only declares and type imports are allowed inside declare module.", - ), - UnterminatedFlowComment: _("Unterminated flow-comment."), - }), -); + // For consistency in TypeScript and Flow error codes + ...(!process.env.BABEL_8_BREAKING + ? { reasonCode: "OptionalBindingPattern" } + : {}), + }, + SetterMayNotHaveThisParam: "A setter cannot have a `this` parameter.", + SpreadVariance: "Spread properties cannot have variance.", + ThisParamAnnotationRequired: + "A type annotation is required for the `this` parameter.", + ThisParamBannedInConstructor: + "Constructors cannot have a `this` parameter; constructors don't bind `this` like other functions.", + ThisParamMayNotBeOptional: "The `this` parameter cannot be optional.", + ThisParamMustBeFirst: + "The `this` parameter must be the first function parameter.", + ThisParamNoDefault: "The `this` parameter may not have a default value.", + TypeBeforeInitializer: + "Type annotations must come before default assignments, e.g. instead of `age = 25: number` use `age: number = 25`.", + TypeCastInPattern: + "The type cast expression is expected to be wrapped with parenthesis.", + UnexpectedExplicitInexactInObject: + "Explicit inexact syntax must appear at the end of an inexact object.", + UnexpectedReservedType: ({ reservedType }: { reservedType: string }) => + `Unexpected reserved type ${reservedType}.`, + UnexpectedReservedUnderscore: + "`_` is only allowed as a type argument to call or new.", + UnexpectedSpaceBetweenModuloChecks: + "Spaces between `%` and `checks` are not allowed here.", + UnexpectedSpreadType: + "Spread operator cannot appear in class or interface definitions.", + UnexpectedSubtractionOperand: + 'Unexpected token, expected "number" or "bigint".', + UnexpectedTokenAfterTypeParameter: + "Expected an arrow function after this type parameter declaration.", + UnexpectedTypeParameterBeforeAsyncArrowFunction: + "Type parameters must come after the async keyword, e.g. instead of ` async () => {}`, use `async () => {}`.", + UnsupportedDeclareExportKind: ({ + unsupportedExportKind, + suggestion, + }: { + unsupportedExportKind: string; + suggestion: string; + }) => + `\`declare export ${unsupportedExportKind}\` is not supported. Use \`${suggestion}\` instead.`, + UnsupportedStatementInDeclareModule: + "Only declares and type imports are allowed inside declare module.", + UnterminatedFlowComment: "Unterminated flow-comment.", +}); /* eslint-disable sort-keys */ function isEsModuleType(bodyElement: N.Node): boolean { diff --git a/packages/babel-parser/src/plugins/jsx/index.ts b/packages/babel-parser/src/plugins/jsx/index.ts index 6629ae6d0041..c4e42fecf9c4 100644 --- a/packages/babel-parser/src/plugins/jsx/index.ts +++ b/packages/babel-parser/src/plugins/jsx/index.ts @@ -15,46 +15,33 @@ import * as N from "../../types"; import { isIdentifierChar, isIdentifierStart } from "../../util/identifier"; import type { Position } from "../../util/location"; import { isNewLine } from "../../util/whitespace"; -import { - Errors, - ParseErrorEnum, - toParseErrorCredentials, -} from "../../parse-error"; +import { Errors, ParseErrorEnum } from "../../parse-error"; import { type Undone } from "../../parser/node"; /* eslint sort-keys: "error" */ -const JsxErrors = ParseErrorEnum`jsx`((_: typeof toParseErrorCredentials) => ({ - AttributeIsEmpty: _( +const JsxErrors = ParseErrorEnum`jsx`({ + AttributeIsEmpty: "JSX attributes must only be assigned a non-empty expression.", - ), - MissingClosingTagElement: _<{ - openingTagName: string; - }>( - ({ openingTagName }) => - `Expected corresponding JSX closing tag for <${openingTagName}>.`, - ), - MissingClosingTagFragment: _( - "Expected corresponding JSX closing tag for <>.", - ), - UnexpectedSequenceExpression: _( + MissingClosingTagElement: ({ openingTagName }: { openingTagName: string }) => + `Expected corresponding JSX closing tag for <${openingTagName}>.`, + MissingClosingTagFragment: "Expected corresponding JSX closing tag for <>.", + UnexpectedSequenceExpression: "Sequence expressions cannot be directly nested inside JSX. Did you mean to wrap it in parentheses (...)?", - ), // FIXME: Unify with Errors.UnexpectedToken - UnexpectedToken: _<{ + UnexpectedToken: ({ + unexpected, + HTMLEntity, + }: { unexpected: string; HTMLEntity: string; - }>( - ({ unexpected, HTMLEntity }) => - `Unexpected token \`${unexpected}\`. Did you mean \`${HTMLEntity}\` or \`{'${unexpected}'}\`?`, - ), - UnsupportedJsxValue: _( + }) => + `Unexpected token \`${unexpected}\`. Did you mean \`${HTMLEntity}\` or \`{'${unexpected}'}\`?`, + UnsupportedJsxValue: "JSX value should be either an expression or a quoted JSX text.", - ), - UnterminatedJsxContent: _("Unterminated JSX contents."), - UnwrappedAdjacentJSXElements: _( + UnterminatedJsxContent: "Unterminated JSX contents.", + UnwrappedAdjacentJSXElements: "Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...?", - ), -})); +}); /* eslint-disable sort-keys */ diff --git a/packages/babel-parser/src/plugins/placeholders.ts b/packages/babel-parser/src/plugins/placeholders.ts index 486bebe64975..bee82d3e16a0 100644 --- a/packages/babel-parser/src/plugins/placeholders.ts +++ b/packages/babel-parser/src/plugins/placeholders.ts @@ -3,7 +3,7 @@ import * as charCodes from "charcodes"; import { tokenLabelName, tt } from "../tokenizer/types"; import type Parser from "../parser"; import * as N from "../types"; -import { ParseErrorEnum, toParseErrorCredentials } from "../parse-error"; +import { ParseErrorEnum } from "../parse-error"; import type { Undone } from "../parser/node"; import type { Position } from "../util/location"; @@ -53,12 +53,11 @@ type NodeOf = $Switch< type MaybePlaceholder = NodeOf; // | Placeholder /* eslint sort-keys: "error" */ -const PlaceholderErrors = ParseErrorEnum`placeholders`( - (_: typeof toParseErrorCredentials) => ({ - ClassNameIsRequired: _("A class name is required."), - UnexpectedSpace: _("Unexpected space in placeholder."), - }), -); +const PlaceholderErrors = ParseErrorEnum`placeholders`({ + ClassNameIsRequired: "A class name is required.", + UnexpectedSpace: "Unexpected space in placeholder.", +}); + /* eslint-disable sort-keys */ export default (superClass: { diff --git a/packages/babel-parser/src/plugins/typescript/index.ts b/packages/babel-parser/src/plugins/typescript/index.ts index f226c9a619c3..731eb3c07fc2 100644 --- a/packages/babel-parser/src/plugins/typescript/index.ts +++ b/packages/babel-parser/src/plugins/typescript/index.ts @@ -34,11 +34,7 @@ import TypeScriptScopeHandler from "./scope"; import * as charCodes from "charcodes"; import type { ExpressionErrors } from "../../parser/util"; import { PARAM } from "../../util/production-parameter"; -import { - Errors, - ParseErrorEnum, - toParseErrorCredentials, -} from "../../parse-error"; +import { Errors, ParseErrorEnum } from "../../parse-error"; import { cloneIdentifier, type Undone } from "../../parser/node"; const getOwn = (object: T, key: keyof T) => @@ -80,222 +76,153 @@ type ModifierBase = { }; /* eslint sort-keys: "error" */ -const TSErrors = ParseErrorEnum`typescript`( - (_: typeof toParseErrorCredentials) => ({ - AbstractMethodHasImplementation: _<{ - methodName: string; - }>( - ({ methodName }) => - `Method '${methodName}' cannot have an implementation because it is marked abstract.`, - ), - AbstractPropertyHasInitializer: _<{ - propertyName: string; - }>( - ({ propertyName }) => - `Property '${propertyName}' cannot have an initializer because it is marked abstract.`, - ), - AccesorCannotDeclareThisParameter: _( - "'get' and 'set' accessors cannot declare 'this' parameters.", - ), - AccesorCannotHaveTypeParameters: _( - "An accessor cannot have type parameters.", - ), - CannotFindName: _<{ - name: string; - }>(({ name }) => `Cannot find name '${name}'.`), - ClassMethodHasDeclare: _( - "Class methods cannot have the 'declare' modifier.", - ), - ClassMethodHasReadonly: _( - "Class methods cannot have the 'readonly' modifier.", - ), - ConstInitiailizerMustBeStringOrNumericLiteralOrLiteralEnumReference: _( - "A 'const' initializer in an ambient context must be a string or numeric literal or literal enum reference.", - ), - ConstructorHasTypeParameters: _( - "Type parameters cannot appear on a constructor declaration.", - ), - DeclareAccessor: _<{ - kind: "get" | "set"; - }>(({ kind }) => `'declare' is not allowed in ${kind}ters.`), - DeclareClassFieldHasInitializer: _( - "Initializers are not allowed in ambient contexts.", - ), - DeclareFunctionHasImplementation: _( - "An implementation cannot be declared in ambient contexts.", - ), - DuplicateAccessibilityModifier: _<{ - modifier: N.Accessibility; - }>( - // `Accessibility modifier already seen: ${modifier}` would be more helpful. - // eslint-disable-next-line @typescript-eslint/no-unused-vars - ({ modifier }) => `Accessibility modifier already seen.`, - ), - DuplicateModifier: _<{ - modifier: TsModifier; - }>(({ modifier }) => `Duplicate modifier: '${modifier}'.`), - // `token` matches the terminology used by typescript: - // https://github.com/microsoft/TypeScript/blob/main/src/compiler/types.ts#L2915 - EmptyHeritageClauseType: _<{ - token: "extends" | "implements"; - }>(({ token }) => `'${token}' list cannot be empty.`), - EmptyTypeArguments: _("Type argument list cannot be empty."), - EmptyTypeParameters: _("Type parameter list cannot be empty."), - ExpectedAmbientAfterExportDeclare: _( - "'export declare' must be followed by an ambient declaration.", - ), - ImportAliasHasImportType: _("An import alias can not use 'import type'."), - IncompatibleModifiers: _<{ - modifiers: [TsModifier, TsModifier]; - }>( - ({ modifiers }) => - `'${modifiers[0]}' modifier cannot be used with '${modifiers[1]}' modifier.`, - ), - IndexSignatureHasAbstract: _( - "Index signatures cannot have the 'abstract' modifier.", - ), - IndexSignatureHasAccessibility: _<{ - modifier: N.Accessibility; - }>( - ({ modifier }) => - `Index signatures cannot have an accessibility modifier ('${modifier}').`, - ), - IndexSignatureHasDeclare: _( - "Index signatures cannot have the 'declare' modifier.", - ), - IndexSignatureHasOverride: _( - "'override' modifier cannot appear on an index signature.", - ), - IndexSignatureHasStatic: _( - "Index signatures cannot have the 'static' modifier.", - ), - InitializerNotAllowedInAmbientContext: _( - "Initializers are not allowed in ambient contexts.", - ), - InvalidModifierOnTypeMember: _<{ - modifier: TsModifier; - }>( - ({ modifier }) => - `'${modifier}' modifier cannot appear on a type member.`, - ), - InvalidModifierOnTypeParameter: _<{ - modifier: TsModifier; - }>( - ({ modifier }) => - `'${modifier}' modifier cannot appear on a type parameter.`, - ), - InvalidModifierOnTypeParameterPositions: _<{ - modifier: TsModifier; - }>( - ({ modifier }) => - `'${modifier}' modifier can only appear on a type parameter of a class, interface or type alias.`, - ), - InvalidModifiersOrder: _<{ - orderedModifiers: [TsModifier, TsModifier]; - }>( - ({ orderedModifiers }) => - `'${orderedModifiers[0]}' modifier must precede '${orderedModifiers[1]}' modifier.`, - ), - InvalidPropertyAccessAfterInstantiationExpression: _( - "Invalid property access after an instantiation expression. " + - "You can either wrap the instantiation expression in parentheses, or delete the type arguments.", - ), - InvalidTupleMemberLabel: _( - "Tuple members must be labeled with a simple identifier.", - ), - MissingInterfaceName: _( - "'interface' declarations must be followed by an identifier.", - ), - MixedLabeledAndUnlabeledElements: _( - "Tuple members must all have names or all not have names.", - ), - NonAbstractClassHasAbstractMethod: _( - "Abstract methods can only appear within an abstract class.", - ), - NonClassMethodPropertyHasAbstractModifer: _( - "'abstract' modifier can only appear on a class, method, or property declaration.", - ), - OptionalTypeBeforeRequired: _( - "A required element cannot follow an optional element.", - ), - OverrideNotInSubClass: _( - "This member cannot have an 'override' modifier because its containing class does not extend another class.", - ), - PatternIsOptional: _( - "A binding pattern parameter cannot be optional in an implementation signature.", - ), - PrivateElementHasAbstract: _( - "Private elements cannot have the 'abstract' modifier.", - ), - PrivateElementHasAccessibility: _<{ - modifier: N.Accessibility; - }>( - ({ modifier }) => - `Private elements cannot have an accessibility modifier ('${modifier}').`, - ), - ReadonlyForMethodSignature: _( - "'readonly' modifier can only appear on a property declaration or index signature.", - ), - ReservedArrowTypeParam: _( - "This syntax is reserved in files with the .mts or .cts extension. Add a trailing comma, as in `() => ...`.", - ), - ReservedTypeAssertion: _( - "This syntax is reserved in files with the .mts or .cts extension. Use an `as` expression instead.", - ), - SetAccesorCannotHaveOptionalParameter: _( - "A 'set' accessor cannot have an optional parameter.", - ), - SetAccesorCannotHaveRestParameter: _( - "A 'set' accessor cannot have rest parameter.", - ), - SetAccesorCannotHaveReturnType: _( - "A 'set' accessor cannot have a return type annotation.", - ), - SingleTypeParameterWithoutTrailingComma: _<{ - typeParameterName: string; - }>( - ({ typeParameterName }) => - `Single type parameter ${typeParameterName} should have a trailing comma. Example usage: <${typeParameterName},>.`, - ), - StaticBlockCannotHaveModifier: _( - "Static class blocks cannot have any modifier.", - ), - TypeAnnotationAfterAssign: _( - "Type annotations must come before default assignments, e.g. instead of `age = 25: number` use `age: number = 25`.", - ), - TypeImportCannotSpecifyDefaultAndNamed: _( - "A type-only import can specify a default import or named bindings, but not both.", - ), - TypeModifierIsUsedInTypeExports: _( - "The 'type' modifier cannot be used on a named export when 'export type' is used on its export statement.", - ), - TypeModifierIsUsedInTypeImports: _( - "The 'type' modifier cannot be used on a named import when 'import type' is used on its import statement.", - ), - UnexpectedParameterModifier: _( - "A parameter property is only allowed in a constructor implementation.", - ), - UnexpectedReadonly: _( - "'readonly' type modifier is only permitted on array and tuple literal types.", - ), - UnexpectedTypeAnnotation: _("Did not expect a type annotation here."), - UnexpectedTypeCastInParameter: _( - "Unexpected type cast in parameter position.", - ), - UnsupportedImportTypeArgument: _( - "Argument in a type import must be a string literal.", - ), - UnsupportedParameterPropertyKind: _( - "A parameter property may not be declared using a binding pattern.", - ), - UnsupportedSignatureParameterKind: _<{ - type: string; - }>( - ({ type }) => - `Name in a signature must be an Identifier, ObjectPattern or ArrayPattern, instead got ${type}.`, - ), - }), -); +const TSErrors = ParseErrorEnum`typescript`({ + AbstractMethodHasImplementation: ({ methodName }: { methodName: string }) => + `Method '${methodName}' cannot have an implementation because it is marked abstract.`, + AbstractPropertyHasInitializer: ({ + propertyName, + }: { + propertyName: string; + }) => + `Property '${propertyName}' cannot have an initializer because it is marked abstract.`, + AccesorCannotDeclareThisParameter: + "'get' and 'set' accessors cannot declare 'this' parameters.", + AccesorCannotHaveTypeParameters: "An accessor cannot have type parameters.", + CannotFindName: ({ name }: { name: string }) => `Cannot find name '${name}'.`, + ClassMethodHasDeclare: "Class methods cannot have the 'declare' modifier.", + ClassMethodHasReadonly: "Class methods cannot have the 'readonly' modifier.", + ConstInitiailizerMustBeStringOrNumericLiteralOrLiteralEnumReference: + "A 'const' initializer in an ambient context must be a string or numeric literal or literal enum reference.", + ConstructorHasTypeParameters: + "Type parameters cannot appear on a constructor declaration.", + DeclareAccessor: ({ kind }: { kind: "get" | "set" }) => + `'declare' is not allowed in ${kind}ters.`, + DeclareClassFieldHasInitializer: + "Initializers are not allowed in ambient contexts.", + DeclareFunctionHasImplementation: + "An implementation cannot be declared in ambient contexts.", + DuplicateAccessibilityModifier: + // `Accessibility modifier already seen: ${modifier}` would be more helpful. + // eslint-disable-next-line @typescript-eslint/no-unused-vars + ({ modifier }: { modifier: N.Accessibility }) => + `Accessibility modifier already seen.`, + DuplicateModifier: ({ modifier }: { modifier: TsModifier }) => + `Duplicate modifier: '${modifier}'.`, + // `token` matches the terminology used by typescript: + // https://github.com/microsoft/TypeScript/blob/main/src/compiler/types.ts#L2915 + EmptyHeritageClauseType: ({ token }: { token: "extends" | "implements" }) => + `'${token}' list cannot be empty.`, + EmptyTypeArguments: "Type argument list cannot be empty.", + EmptyTypeParameters: "Type parameter list cannot be empty.", + ExpectedAmbientAfterExportDeclare: + "'export declare' must be followed by an ambient declaration.", + ImportAliasHasImportType: "An import alias can not use 'import type'.", + IncompatibleModifiers: ({ + modifiers, + }: { + modifiers: [TsModifier, TsModifier]; + }) => + `'${modifiers[0]}' modifier cannot be used with '${modifiers[1]}' modifier.`, + IndexSignatureHasAbstract: + "Index signatures cannot have the 'abstract' modifier.", + IndexSignatureHasAccessibility: ({ + modifier, + }: { + modifier: N.Accessibility; + }) => + `Index signatures cannot have an accessibility modifier ('${modifier}').`, + IndexSignatureHasDeclare: + "Index signatures cannot have the 'declare' modifier.", + IndexSignatureHasOverride: + "'override' modifier cannot appear on an index signature.", + IndexSignatureHasStatic: + "Index signatures cannot have the 'static' modifier.", + InitializerNotAllowedInAmbientContext: + "Initializers are not allowed in ambient contexts.", + InvalidModifierOnTypeMember: ({ modifier }: { modifier: TsModifier }) => + `'${modifier}' modifier cannot appear on a type member.`, + InvalidModifierOnTypeParameter: ({ modifier }: { modifier: TsModifier }) => + `'${modifier}' modifier cannot appear on a type parameter.`, + InvalidModifierOnTypeParameterPositions: ({ + modifier, + }: { + modifier: TsModifier; + }) => + `'${modifier}' modifier can only appear on a type parameter of a class, interface or type alias.`, + InvalidModifiersOrder: ({ + orderedModifiers, + }: { + orderedModifiers: [TsModifier, TsModifier]; + }) => + `'${orderedModifiers[0]}' modifier must precede '${orderedModifiers[1]}' modifier.`, + InvalidPropertyAccessAfterInstantiationExpression: + "Invalid property access after an instantiation expression. " + + "You can either wrap the instantiation expression in parentheses, or delete the type arguments.", + InvalidTupleMemberLabel: + "Tuple members must be labeled with a simple identifier.", + MissingInterfaceName: + "'interface' declarations must be followed by an identifier.", + MixedLabeledAndUnlabeledElements: + "Tuple members must all have names or all not have names.", + NonAbstractClassHasAbstractMethod: + "Abstract methods can only appear within an abstract class.", + NonClassMethodPropertyHasAbstractModifer: + "'abstract' modifier can only appear on a class, method, or property declaration.", + OptionalTypeBeforeRequired: + "A required element cannot follow an optional element.", + OverrideNotInSubClass: + "This member cannot have an 'override' modifier because its containing class does not extend another class.", + PatternIsOptional: + "A binding pattern parameter cannot be optional in an implementation signature.", + PrivateElementHasAbstract: + "Private elements cannot have the 'abstract' modifier.", + PrivateElementHasAccessibility: ({ + modifier, + }: { + modifier: N.Accessibility; + }) => + `Private elements cannot have an accessibility modifier ('${modifier}').`, + ReadonlyForMethodSignature: + "'readonly' modifier can only appear on a property declaration or index signature.", + ReservedArrowTypeParam: + "This syntax is reserved in files with the .mts or .cts extension. Add a trailing comma, as in `() => ...`.", + ReservedTypeAssertion: + "This syntax is reserved in files with the .mts or .cts extension. Use an `as` expression instead.", + SetAccesorCannotHaveOptionalParameter: + "A 'set' accessor cannot have an optional parameter.", + SetAccesorCannotHaveRestParameter: + "A 'set' accessor cannot have rest parameter.", + SetAccesorCannotHaveReturnType: + "A 'set' accessor cannot have a return type annotation.", + SingleTypeParameterWithoutTrailingComma: ({ + typeParameterName, + }: { + typeParameterName: string; + }) => + `Single type parameter ${typeParameterName} should have a trailing comma. Example usage: <${typeParameterName},>.`, + StaticBlockCannotHaveModifier: + "Static class blocks cannot have any modifier.", + TypeAnnotationAfterAssign: + "Type annotations must come before default assignments, e.g. instead of `age = 25: number` use `age: number = 25`.", + TypeImportCannotSpecifyDefaultAndNamed: + "A type-only import can specify a default import or named bindings, but not both.", + TypeModifierIsUsedInTypeExports: + "The 'type' modifier cannot be used on a named export when 'export type' is used on its export statement.", + TypeModifierIsUsedInTypeImports: + "The 'type' modifier cannot be used on a named import when 'import type' is used on its import statement.", + UnexpectedParameterModifier: + "A parameter property is only allowed in a constructor implementation.", + UnexpectedReadonly: + "'readonly' type modifier is only permitted on array and tuple literal types.", + UnexpectedTypeAnnotation: "Did not expect a type annotation here.", + UnexpectedTypeCastInParameter: "Unexpected type cast in parameter position.", + UnsupportedImportTypeArgument: + "Argument in a type import must be a string literal.", + UnsupportedParameterPropertyKind: + "A parameter property may not be declared using a binding pattern.", + UnsupportedSignatureParameterKind: ({ type }: { type: string }) => + `Name in a signature must be an Identifier, ObjectPattern or ArrayPattern, instead got ${type}.`, +}); /* eslint-disable sort-keys */