Introduce parser error codes (#13033)

This commit is contained in:
Sosuke Suzuki 2021-04-04 02:31:07 +09:00 committed by Nicolò Ribaudo
parent d0fcbfccdd
commit 0ee98139a6
16 changed files with 551 additions and 442 deletions

View File

@ -0,0 +1,8 @@
// @flow
export const ErrorCodes = Object.freeze({
SyntaxError: "BABEL_PARSER_SYNTAX_ERROR",
SourceTypeModuleError: "BABEL_PARSER_SOURCETYPE_MODULE_REQUIRED",
});
export type ErrorCode = $Values<typeof ErrorCodes>;

View File

@ -1,4 +1,7 @@
// @flow // @flow
import { makeErrorTemplates, ErrorCodes } from "./error";
/* eslint sort-keys: "error" */ /* eslint sort-keys: "error" */
/** /**
@ -6,215 +9,225 @@
*/ */
// The Errors key follows https://cs.chromium.org/chromium/src/v8/src/common/message-template.h unless it does not exist // The Errors key follows https://cs.chromium.org/chromium/src/v8/src/common/message-template.h unless it does not exist
export const ErrorMessages = Object.freeze({ export const ErrorMessages = makeErrorTemplates(
AccessorIsGenerator: "A %0ter cannot be a generator", {
ArgumentsInClass: AccessorIsGenerator: "A %0ter cannot be a generator",
"'arguments' is only allowed in functions and class methods", ArgumentsInClass:
AsyncFunctionInSingleStatementContext: "'arguments' is only allowed in functions and class methods",
"Async functions can only be declared at the top level or inside a block", AsyncFunctionInSingleStatementContext:
AwaitBindingIdentifier: "Async functions can only be declared at the top level or inside a block",
"Can not use 'await' as identifier inside an async function", AwaitBindingIdentifier:
AwaitBindingIdentifierInStaticBlock: "Can not use 'await' as identifier inside an async function",
"Can not use 'await' as identifier inside a static block", AwaitBindingIdentifierInStaticBlock:
AwaitExpressionFormalParameter: "Can not use 'await' as identifier inside a static block",
"await is not allowed in async function parameters", AwaitExpressionFormalParameter:
AwaitNotInAsyncContext: "await is not allowed in async function parameters",
"'await' is only allowed within async functions and at the top levels of modules", AwaitNotInAsyncContext:
AwaitNotInAsyncFunction: "'await' is only allowed within async functions", "'await' is only allowed within async functions and at the top levels of modules",
BadGetterArity: "getter must not have any formal parameters", AwaitNotInAsyncFunction: "'await' is only allowed within async functions",
BadSetterArity: "setter must have exactly one formal parameter", BadGetterArity: "getter must not have any formal parameters",
BadSetterRestParameter: BadSetterArity: "setter must have exactly one formal parameter",
"setter function argument must not be a rest parameter", BadSetterRestParameter:
ConstructorClassField: "Classes may not have a field named 'constructor'", "setter function argument must not be a rest parameter",
ConstructorClassPrivateField: ConstructorClassField: "Classes may not have a field named 'constructor'",
"Classes may not have a private field named '#constructor'", ConstructorClassPrivateField:
ConstructorIsAccessor: "Class constructor may not be an accessor", "Classes may not have a private field named '#constructor'",
ConstructorIsAsync: "Constructor can't be an async function", ConstructorIsAccessor: "Class constructor may not be an accessor",
ConstructorIsGenerator: "Constructor can't be a generator", ConstructorIsAsync: "Constructor can't be an async function",
DeclarationMissingInitializer: "%0 require an initialization value", ConstructorIsGenerator: "Constructor can't be a generator",
DecoratorBeforeExport: DeclarationMissingInitializer: "%0 require an initialization value",
"Decorators must be placed *before* the 'export' keyword. You can set the 'decoratorsBeforeExport' option to false to use the 'export @decorator class {}' syntax", DecoratorBeforeExport:
DecoratorConstructor: "Decorators must be placed *before* the 'export' keyword. You can set the 'decoratorsBeforeExport' option to false to use the 'export @decorator class {}' syntax",
"Decorators can't be used with a constructor. Did you mean '@dec class { ... }'?", DecoratorConstructor:
DecoratorExportClass: "Decorators can't be used with a constructor. Did you mean '@dec class { ... }'?",
"Using the export keyword between a decorator and a class is not allowed. Please use `export @dec class` instead.", DecoratorExportClass:
DecoratorSemicolon: "Decorators must not be followed by a semicolon", "Using the export keyword between a decorator and a class is not allowed. Please use `export @dec class` instead.",
DecoratorStaticBlock: "Decorators can't be used with a static block", DecoratorSemicolon: "Decorators must not be followed by a semicolon",
DeletePrivateField: "Deleting a private field is not allowed", DecoratorStaticBlock: "Decorators can't be used with a static block",
DestructureNamedImport: DeletePrivateField: "Deleting a private field is not allowed",
"ES2015 named imports do not destructure. Use another statement for destructuring after the import.", DestructureNamedImport:
DuplicateConstructor: "Duplicate constructor in the same class", "ES2015 named imports do not destructure. Use another statement for destructuring after the import.",
DuplicateDefaultExport: "Only one default export allowed per module.", DuplicateConstructor: "Duplicate constructor in the same class",
DuplicateExport: DuplicateDefaultExport: "Only one default export allowed per module.",
"`%0` has already been exported. Exported identifiers must be unique.", DuplicateExport:
DuplicateProto: "Redefinition of __proto__ property", "`%0` has already been exported. Exported identifiers must be unique.",
DuplicateRegExpFlags: "Duplicate regular expression flag", DuplicateProto: "Redefinition of __proto__ property",
ElementAfterRest: "Rest element must be last element", DuplicateRegExpFlags: "Duplicate regular expression flag",
EscapedCharNotAnIdentifier: "Invalid Unicode escape", ElementAfterRest: "Rest element must be last element",
ExportBindingIsString: EscapedCharNotAnIdentifier: "Invalid Unicode escape",
"A string literal cannot be used as an exported binding without `from`.\n- Did you mean `export { '%0' as '%1' } from 'some-module'`?", ExportBindingIsString:
ExportDefaultFromAsIdentifier: "A string literal cannot be used as an exported binding without `from`.\n- Did you mean `export { '%0' as '%1' } from 'some-module'`?",
"'from' is not allowed as an identifier after 'export default'", ExportDefaultFromAsIdentifier:
ForInOfLoopInitializer: "'from' is not allowed as an identifier after 'export default'",
"%0 loop variable declaration may not have an initializer", ForInOfLoopInitializer:
ForOfLet: "The left-hand side of a for-of loop may not start with 'let'.", "%0 loop variable declaration may not have an initializer",
GeneratorInSingleStatementContext: ForOfLet: "The left-hand side of a for-of loop may not start with 'let'.",
"Generators can only be declared at the top level or inside a block", GeneratorInSingleStatementContext:
IllegalBreakContinue: "Unsyntactic %0", "Generators can only be declared at the top level or inside a block",
IllegalLanguageModeDirective: IllegalBreakContinue: "Unsyntactic %0",
"Illegal 'use strict' directive in function with non-simple parameter list", IllegalLanguageModeDirective:
IllegalReturn: "'return' outside of function", "Illegal 'use strict' directive in function with non-simple parameter list",
ImportBindingIsString: IllegalReturn: "'return' outside of function",
'A string literal cannot be used as an imported binding.\n- Did you mean `import { "%0" as foo }`?', ImportBindingIsString:
ImportCallArgumentTrailingComma: 'A string literal cannot be used as an imported binding.\n- Did you mean `import { "%0" as foo }`?',
"Trailing comma is disallowed inside import(...) arguments", ImportCallArgumentTrailingComma:
ImportCallArity: "import() requires exactly %0", "Trailing comma is disallowed inside import(...) arguments",
ImportCallNotNewExpression: "Cannot use new with import(...)", ImportCallArity: "import() requires exactly %0",
ImportCallSpreadArgument: "... is not allowed in import()", ImportCallNotNewExpression: "Cannot use new with import(...)",
ImportMetaOutsideModule: `import.meta may appear only with 'sourceType: "module"'`, ImportCallSpreadArgument: "... is not allowed in import()",
ImportOutsideModule: `'import' and 'export' may appear only with 'sourceType: "module"'`, InvalidBigIntLiteral: "Invalid BigIntLiteral",
InvalidBigIntLiteral: "Invalid BigIntLiteral", InvalidCodePoint: "Code point out of bounds",
InvalidCodePoint: "Code point out of bounds", InvalidDecimal: "Invalid decimal",
InvalidDecimal: "Invalid decimal", InvalidDigit: "Expected number in radix %0",
InvalidDigit: "Expected number in radix %0", InvalidEscapeSequence: "Bad character escape sequence",
InvalidEscapeSequence: "Bad character escape sequence", InvalidEscapeSequenceTemplate: "Invalid escape sequence in template",
InvalidEscapeSequenceTemplate: "Invalid escape sequence in template", InvalidEscapedReservedWord: "Escape sequence in keyword %0",
InvalidEscapedReservedWord: "Escape sequence in keyword %0", InvalidIdentifier: "Invalid identifier %0",
InvalidIdentifier: "Invalid identifier %0", InvalidLhs: "Invalid left-hand side in %0",
InvalidLhs: "Invalid left-hand side in %0", InvalidLhsBinding: "Binding invalid left-hand side in %0",
InvalidLhsBinding: "Binding invalid left-hand side in %0", InvalidNumber: "Invalid number",
InvalidNumber: "Invalid number", InvalidOrMissingExponent:
InvalidOrMissingExponent: "Floating-point numbers require a valid exponent after the 'e'",
"Floating-point numbers require a valid exponent after the 'e'", InvalidOrUnexpectedToken: "Unexpected character '%0'",
InvalidOrUnexpectedToken: "Unexpected character '%0'", InvalidParenthesizedAssignment: "Invalid parenthesized assignment pattern",
InvalidParenthesizedAssignment: "Invalid parenthesized assignment pattern", InvalidPrivateFieldResolution: "Private name #%0 is not defined",
InvalidPrivateFieldResolution: "Private name #%0 is not defined", InvalidPropertyBindingPattern: "Binding member expression",
InvalidPropertyBindingPattern: "Binding member expression", InvalidRecordProperty:
InvalidRecordProperty: "Only properties and spread elements are allowed in record definitions",
"Only properties and spread elements are allowed in record definitions", InvalidRestAssignmentPattern: "Invalid rest operator's argument",
InvalidRestAssignmentPattern: "Invalid rest operator's argument", LabelRedeclaration: "Label '%0' is already declared",
LabelRedeclaration: "Label '%0' is already declared", LetInLexicalBinding:
LetInLexicalBinding: "'let' is not allowed to be used as a name in 'let' or 'const' declarations.",
"'let' is not allowed to be used as a name in 'let' or 'const' declarations.", LineTerminatorBeforeArrow: "No line break is allowed before '=>'",
LineTerminatorBeforeArrow: "No line break is allowed before '=>'", MalformedRegExpFlags: "Invalid regular expression flag",
MalformedRegExpFlags: "Invalid regular expression flag", MissingClassName: "A class name is required",
MissingClassName: "A class name is required", MissingEqInAssignment:
MissingEqInAssignment: "Only '=' operator can be used for specifying default value.",
"Only '=' operator can be used for specifying default value.", MissingSemicolon: "Missing semicolon",
MissingSemicolon: "Missing semicolon", MissingUnicodeEscape: "Expecting Unicode escape sequence \\uXXXX",
MissingUnicodeEscape: "Expecting Unicode escape sequence \\uXXXX", MixingCoalesceWithLogical:
MixingCoalesceWithLogical: "Nullish coalescing operator(??) requires parens when mixing with logical operators",
"Nullish coalescing operator(??) requires parens when mixing with logical operators", ModuleAttributeDifferentFromType:
ModuleAttributeDifferentFromType: "The only accepted module attribute is `type`",
"The only accepted module attribute is `type`", ModuleAttributeInvalidValue:
ModuleAttributeInvalidValue: "Only string literals are allowed as module attribute values",
"Only string literals are allowed as module attribute values", ModuleAttributesWithDuplicateKeys:
ModuleAttributesWithDuplicateKeys: 'Duplicate key "%0" is not allowed in module attributes',
'Duplicate key "%0" is not allowed in module attributes', ModuleExportNameHasLoneSurrogate:
ModuleExportNameHasLoneSurrogate: "An export name cannot include a lone surrogate, found '\\u%0'",
"An export name cannot include a lone surrogate, found '\\u%0'", ModuleExportUndefined: "Export '%0' is not defined",
ModuleExportUndefined: "Export '%0' is not defined", MultipleDefaultsInSwitch: "Multiple default clauses",
MultipleDefaultsInSwitch: "Multiple default clauses", NewlineAfterThrow: "Illegal newline after throw",
NewlineAfterThrow: "Illegal newline after throw", NoCatchOrFinally: "Missing catch or finally clause",
NoCatchOrFinally: "Missing catch or finally clause", NumberIdentifier: "Identifier directly after number",
NumberIdentifier: "Identifier directly after number", NumericSeparatorInEscapeSequence:
NumericSeparatorInEscapeSequence: "Numeric separators are not allowed inside unicode escape sequences or hex escape sequences",
"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.",
"await* has been removed from the async functions proposal. Use Promise.all() instead.", OptionalChainingNoNew:
OptionalChainingNoNew: "constructors in/after an Optional Chain are not allowed",
"constructors in/after an Optional Chain are not allowed", OptionalChainingNoTemplate:
OptionalChainingNoTemplate: "Tagged Template Literals are not allowed in optionalChain",
"Tagged Template Literals are not allowed in optionalChain", ParamDupe: "Argument name clash",
ParamDupe: "Argument name clash", PatternHasAccessor: "Object pattern can't contain getter or setter",
PatternHasAccessor: "Object pattern can't contain getter or setter", PatternHasMethod: "Object pattern can't contain methods",
PatternHasMethod: "Object pattern can't contain methods", PipelineBodyNoArrow:
PipelineBodyNoArrow: 'Unexpected arrow "=>" after pipeline body; arrow function in pipeline body must be parenthesized',
'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",
"Pipeline body may not be a comma-separated sequence expression", PipelineHeadSequenceExpression:
PipelineHeadSequenceExpression: "Pipeline head should not be a comma-separated sequence expression",
"Pipeline head should not be a comma-separated sequence expression", PipelineTopicUnused:
PipelineTopicUnused: "Pipeline is in topic style but does not use topic reference",
"Pipeline is in topic style but does not use topic reference", PrimaryTopicNotAllowed:
PrimaryTopicNotAllowed: "Topic reference was used in a lexical context without topic binding",
"Topic reference was used in a lexical context without topic binding", PrimaryTopicRequiresSmartPipeline:
PrimaryTopicRequiresSmartPipeline: "Primary Topic Reference found but pipelineOperator not passed 'smart' for 'proposal' option.",
"Primary Topic Reference found but pipelineOperator not passed 'smart' for 'proposal' option.", PrivateInExpectedIn:
PrivateInExpectedIn: "Private names are only allowed in property accesses (`obj.#%0`) or in `in` expressions (`#%0 in obj`)",
"Private names are only allowed in property accesses (`obj.#%0`) or in `in` expressions (`#%0 in obj`)", PrivateNameRedeclaration: "Duplicate private name #%0",
PrivateNameRedeclaration: "Duplicate private name #%0", RecordExpressionBarIncorrectEndSyntaxType:
RecordExpressionBarIncorrectEndSyntaxType: "Record expressions ending with '|}' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'bar'",
"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'",
"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'",
"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",
RecordNoProto: "'__proto__' is not allowed in Record expressions", RestTrailingComma: "Unexpected trailing comma after rest element",
RestTrailingComma: "Unexpected trailing comma after rest element", SloppyFunction:
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",
"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",
StaticPrototype: "Classes may not have static property named prototype", StrictDelete: "Deleting local variable in strict mode",
StrictDelete: "Deleting local variable in strict mode", StrictEvalArguments: "Assigning to '%0' in strict mode",
StrictEvalArguments: "Assigning to '%0' in strict mode", StrictEvalArgumentsBinding: "Binding '%0' in strict mode",
StrictEvalArgumentsBinding: "Binding '%0' in strict mode", StrictFunction:
StrictFunction: "In strict mode code, functions can only be declared at top level or inside a block",
"In strict mode code, functions can only be declared at top level or inside a block", StrictNumericEscape:
StrictNumericEscape: "The only valid numeric escape in strict mode is '\\0'", "The only valid numeric escape in strict mode is '\\0'",
StrictOctalLiteral: "Legacy octal literals are not allowed in strict mode", StrictOctalLiteral: "Legacy octal literals are not allowed in strict mode",
StrictWith: "'with' in strict mode", StrictWith: "'with' in strict mode",
SuperNotAllowed: 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?", "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", SuperPrivateField: "Private fields can't be accessed on super",
TrailingDecorator: "Decorators must be attached to a class element", TrailingDecorator: "Decorators must be attached to a class element",
TupleExpressionBarIncorrectEndSyntaxType: TupleExpressionBarIncorrectEndSyntaxType:
"Tuple expressions ending with '|]' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'bar'", "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'", "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'", "Tuple expressions starting with '#[' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'hash'",
UnexpectedArgumentPlaceholder: "Unexpected argument placeholder", UnexpectedArgumentPlaceholder: "Unexpected argument placeholder",
UnexpectedAwaitAfterPipelineBody: UnexpectedAwaitAfterPipelineBody:
'Unexpected "await" after pipeline body; await must have parentheses in minimal proposal', 'Unexpected "await" after pipeline body; await must have parentheses in minimal proposal',
UnexpectedDigitAfterHash: "Unexpected digit after hash token", UnexpectedDigitAfterHash: "Unexpected digit after hash token",
UnexpectedImportExport: UnexpectedImportExport:
"'import' and 'export' may only appear at the top level", "'import' and 'export' may only appear at the top level",
UnexpectedKeyword: "Unexpected keyword '%0'", UnexpectedKeyword: "Unexpected keyword '%0'",
UnexpectedLeadingDecorator: UnexpectedLeadingDecorator:
"Leading decorators must be attached to a class declaration", "Leading decorators must be attached to a class declaration",
UnexpectedLexicalDeclaration: UnexpectedLexicalDeclaration:
"Lexical declaration cannot appear in a single-statement context", "Lexical declaration cannot appear in a single-statement context",
UnexpectedNewTarget: "new.target can only be used in functions", UnexpectedNewTarget: "new.target can only be used in functions",
UnexpectedNumericSeparator: UnexpectedNumericSeparator:
"A numeric separator is only allowed between two digits", "A numeric separator is only allowed between two digits",
UnexpectedPrivateField: UnexpectedPrivateField:
"Private names can only be used as the name of a class element (i.e. class C { #p = 42; #m() {} } )\n or a property of member expression (i.e. this.#p).", "Private names can only be used as the name of a class element (i.e. class C { #p = 42; #m() {} } )\n or a property of member expression (i.e. this.#p).",
UnexpectedReservedWord: "Unexpected reserved word '%0'", UnexpectedReservedWord: "Unexpected reserved word '%0'",
UnexpectedSuper: "super is only allowed in object methods and classes", UnexpectedSuper: "super is only allowed in object methods and classes",
UnexpectedToken: "Unexpected token '%0'", UnexpectedToken: "Unexpected token '%0'",
UnexpectedTokenUnaryExponentiation: UnexpectedTokenUnaryExponentiation:
"Illegal expression. Wrap left hand side or entire exponentiation in parentheses.", "Illegal expression. Wrap left hand side or entire exponentiation in parentheses.",
UnsupportedBind: "Binding should be performed on object property.", UnsupportedBind: "Binding should be performed on object property.",
UnsupportedDecoratorExport: UnsupportedDecoratorExport:
"A decorated export must export a class declaration", "A decorated export must export a class declaration",
UnsupportedDefaultExport: UnsupportedDefaultExport:
"Only expressions, functions or classes are allowed as the `default` export.", "Only expressions, functions or classes are allowed as the `default` export.",
UnsupportedImport: "import can only be used in import() or import.meta", UnsupportedImport: "import can only be used in import() or import.meta",
UnsupportedMetaProperty: "The only valid meta property for %0 is %0.%1", UnsupportedMetaProperty: "The only valid meta property for %0 is %0.%1",
UnsupportedParameterDecorator: UnsupportedParameterDecorator:
"Decorators cannot be used to decorate parameters", "Decorators cannot be used to decorate parameters",
UnsupportedPropertyDecorator: UnsupportedPropertyDecorator:
"Decorators cannot be used to decorate object literal properties", "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])", "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", UnterminatedComment: "Unterminated comment",
UnterminatedRegExp: "Unterminated regular expression", UnterminatedRegExp: "Unterminated regular expression",
UnterminatedString: "Unterminated string constant", UnterminatedString: "Unterminated string constant",
UnterminatedTemplate: "Unterminated template", UnterminatedTemplate: "Unterminated template",
VarRedeclaration: "Identifier '%0' has already been declared", VarRedeclaration: "Identifier '%0' has already been declared",
YieldBindingIdentifier: YieldBindingIdentifier:
"Can not use 'yield' as identifier inside a generator", "Can not use 'yield' as identifier inside a generator",
YieldInParameter: "Yield expression is not allowed in formal parameters", YieldInParameter: "Yield expression is not allowed in formal parameters",
ZeroDigitNumericSeparator: ZeroDigitNumericSeparator:
"Numeric separator can not be used after leading 0", "Numeric separator can not be used after leading 0",
}); },
/* code */ ErrorCodes.SyntaxError,
);
export const SourceTypeModuleErrorMessages = makeErrorTemplates(
{
ImportMetaOutsideModule: `import.meta may appear only with 'sourceType: "module"'`,
ImportOutsideModule: `'import' and 'export' may appear only with 'sourceType: "module"'`,
},
/* code */ ErrorCodes.SourceTypeModuleError,
);

View File

@ -2,6 +2,7 @@
/* eslint sort-keys: "error" */ /* eslint sort-keys: "error" */
import { getLineInfo, type Position } from "../util/location"; import { getLineInfo, type Position } from "../util/location";
import CommentsParser from "./comments"; import CommentsParser from "./comments";
import { type ErrorCode, ErrorCodes } from "./error-codes";
// This function is used to raise exceptions on parse errors. It // This function is used to raise exceptions on parse errors. It
// takes an offset integer (into the current `input`) to indicate // takes an offset integer (into the current `input`) to indicate
@ -14,11 +15,43 @@ type ErrorContext = {
loc: Position, loc: Position,
missingPlugin?: Array<string>, missingPlugin?: Array<string>,
code?: string, code?: string,
reasonCode?: String,
}; };
export type ParsingError = SyntaxError & ErrorContext; export type ParsingError = SyntaxError & ErrorContext;
export { ErrorMessages as Errors } from "./error-message"; export type ErrorTemplate = {
code: ErrorCode,
template: string,
reasonCode: string,
};
export type ErrorTemplates = {
[key: string]: ErrorTemplate,
};
export function makeErrorTemplates(
messages: {
[key: string]: string,
},
code: ErrorCode,
): ErrorTemplates {
const templates: ErrorTemplates = {};
Object.keys(messages).forEach(reasonCode => {
templates[reasonCode] = {
code,
reasonCode,
template: messages[reasonCode],
};
});
return Object.freeze(templates);
}
export { ErrorCodes };
export {
ErrorMessages as Errors,
SourceTypeModuleErrorMessages as SourceTypeModuleErrors,
} from "./error-message";
export type raiseFunction = (number, ErrorTemplate, ...any) => void;
export default class ParserError extends CommentsParser { export default class ParserError extends CommentsParser {
// Forward-declaration: defined in tokenizer/index.js // Forward-declaration: defined in tokenizer/index.js
@ -37,8 +70,12 @@ export default class ParserError extends CommentsParser {
return loc; return loc;
} }
raise(pos: number, errorTemplate: string, ...params: any): Error | empty { raise(
return this.raiseWithData(pos, undefined, errorTemplate, ...params); pos: number,
{ code, reasonCode, template }: ErrorTemplate,
...params: any
): Error | empty {
return this.raiseWithData(pos, { code, reasonCode }, template, ...params);
} }
/** /**
@ -55,12 +92,12 @@ export default class ParserError extends CommentsParser {
*/ */
raiseOverwrite( raiseOverwrite(
pos: number, pos: number,
errorTemplate: string, { code, template }: ErrorTemplate,
...params: any ...params: any
): Error | empty { ): Error | empty {
const loc = this.getLocationForPosition(pos); const loc = this.getLocationForPosition(pos);
const message = const message =
errorTemplate.replace(/%(\d+)/g, (_, i: number) => params[i]) + template.replace(/%(\d+)/g, (_, i: number) => params[i]) +
` (${loc.line}:${loc.column})`; ` (${loc.line}:${loc.column})`;
if (this.options.errorRecovery) { if (this.options.errorRecovery) {
const errors = this.state.errors; const errors = this.state.errors;
@ -73,7 +110,7 @@ export default class ParserError extends CommentsParser {
} }
} }
} }
return this._raise({ loc, pos }, message); return this._raise({ code, loc, pos }, message);
} }
raiseWithData( raiseWithData(

View File

@ -54,7 +54,7 @@ import {
newAsyncArrowScope, newAsyncArrowScope,
newExpressionScope, newExpressionScope,
} from "../util/expression-scope"; } from "../util/expression-scope";
import { Errors } from "./error"; import { Errors, SourceTypeModuleErrors } from "./error";
/*:: /*::
import type { SourceType } from "../options"; import type { SourceType } from "../options";
@ -1358,11 +1358,7 @@ export default class ExpressionParser extends LValParser {
if (this.isContextual("meta")) { if (this.isContextual("meta")) {
if (!this.inModule) { if (!this.inModule) {
this.raiseWithData( this.raise(id.start, SourceTypeModuleErrors.ImportMetaOutsideModule);
id.start,
{ code: "BABEL_PARSER_SOURCETYPE_MODULE_REQUIRED" },
Errors.ImportMetaOutsideModule,
);
} }
this.sawUnambiguousESM = true; this.sawUnambiguousESM = true;
} }
@ -1524,14 +1520,14 @@ export default class ExpressionParser extends LValParser {
const metaProp = this.parseMetaProperty(node, meta, "target"); const metaProp = this.parseMetaProperty(node, meta, "target");
if (!this.scope.inNonArrowFunction && !this.scope.inClass) { if (!this.scope.inNonArrowFunction && !this.scope.inClass) {
let error = Errors.UnexpectedNewTarget; const errorTemplate = { ...Errors.UnexpectedNewTarget };
if (this.hasPlugin("classProperties")) { if (this.hasPlugin("classProperties")) {
error += " or class properties"; errorTemplate.template += " or class properties";
} }
/* eslint-disable @babel/development-internal/dry-error-messages */ /* eslint-disable @babel/development-internal/dry-error-messages */
this.raise(metaProp.start, error); this.raise(metaProp.start, errorTemplate);
/* eslint-enable @babel/development-internal/dry-error-messages */ /* eslint-enable @babel/development-internal/dry-error-messages */
} }

View File

@ -3,7 +3,7 @@
import * as N from "../types"; import * as N from "../types";
import { types as tt, type TokenType } from "../tokenizer/types"; import { types as tt, type TokenType } from "../tokenizer/types";
import ExpressionParser from "./expression"; import ExpressionParser from "./expression";
import { Errors } from "./error"; import { Errors, SourceTypeModuleErrors } from "./error";
import { import {
isIdentifierChar, isIdentifierChar,
isIdentifierStart, isIdentifierStart,
@ -324,13 +324,7 @@ export default class StatementParser extends ExpressionParser {
assertModuleNodeAllowed(node: N.Node): void { assertModuleNodeAllowed(node: N.Node): void {
if (!this.options.allowImportExportEverywhere && !this.inModule) { if (!this.options.allowImportExportEverywhere && !this.inModule) {
this.raiseWithData( this.raise(node.start, SourceTypeModuleErrors.ImportOutsideModule);
node.start,
{
code: "BABEL_PARSER_SOURCETYPE_MODULE_REQUIRED",
},
Errors.ImportOutsideModule,
);
} }
} }

View File

@ -1,6 +1,6 @@
// @flow // @flow
import { types as tt, type TokenType } from "../tokenizer/types"; import { types as tt, TokenType } from "../tokenizer/types";
import Tokenizer from "../tokenizer"; import Tokenizer from "../tokenizer";
import State from "../tokenizer/state"; import State from "../tokenizer/state";
import type { Node } from "../types"; import type { Node } from "../types";
@ -13,7 +13,7 @@ import ProductionParameterHandler, {
PARAM_AWAIT, PARAM_AWAIT,
PARAM, PARAM,
} from "../util/production-parameter"; } from "../util/production-parameter";
import { Errors } from "./error"; import { Errors, type ErrorTemplate, ErrorCodes } from "./error";
/*:: /*::
import type ScopeHandler from "../util/scope"; import type ScopeHandler from "../util/scope";
*/ */
@ -91,8 +91,8 @@ export default class UtilParser extends Tokenizer {
// Asserts that following token is given contextual keyword. // Asserts that following token is given contextual keyword.
expectContextual(name: string, message?: string): void { expectContextual(name: string, template?: ErrorTemplate): void {
if (!this.eatContextual(name)) this.unexpected(null, message); if (!this.eatContextual(name)) this.unexpected(null, template);
} }
// Test whether a semicolon can be inserted at the current position. // Test whether a semicolon can be inserted at the current position.
@ -142,7 +142,11 @@ export default class UtilParser extends Tokenizer {
assertNoSpace(message: string = "Unexpected space."): void { assertNoSpace(message: string = "Unexpected space."): void {
if (this.state.start > this.state.lastTokEnd) { if (this.state.start > this.state.lastTokEnd) {
/* eslint-disable @babel/development-internal/dry-error-messages */ /* eslint-disable @babel/development-internal/dry-error-messages */
this.raise(this.state.lastTokEnd, message); this.raise(this.state.lastTokEnd, {
code: ErrorCodes.SyntaxError,
reasonCode: "UnexpectedSpace",
template: message,
});
/* eslint-enable @babel/development-internal/dry-error-messages */ /* eslint-enable @babel/development-internal/dry-error-messages */
} }
} }
@ -152,10 +156,18 @@ export default class UtilParser extends Tokenizer {
unexpected( unexpected(
pos: ?number, pos: ?number,
messageOrType: string | TokenType = "Unexpected token", messageOrType: ErrorTemplate | TokenType = {
code: ErrorCodes.SyntaxError,
reasonCode: "UnexpectedToken",
template: "Unexpected token",
},
): empty { ): empty {
if (typeof messageOrType !== "string") { if (messageOrType instanceof TokenType) {
messageOrType = `Unexpected token, expected "${messageOrType.label}"`; messageOrType = {
code: ErrorCodes.SyntaxError,
reasonCode: "UnexpectedToken",
template: `Unexpected token, expected "${messageOrType.label}"`,
};
} }
/* eslint-disable @babel/development-internal/dry-error-messages */ /* eslint-disable @babel/development-internal/dry-error-messages */
throw this.raise(pos != null ? pos : this.state.start, messageOrType); throw this.raise(pos != null ? pos : this.state.start, messageOrType);

View File

@ -25,7 +25,7 @@ import {
SCOPE_OTHER, SCOPE_OTHER,
} from "../../util/scopeflags"; } from "../../util/scopeflags";
import type { ExpressionErrors } from "../../parser/util"; import type { ExpressionErrors } from "../../parser/util";
import { Errors } from "../../parser/error"; import { Errors, makeErrorTemplates, ErrorCodes } from "../../parser/error";
const reservedTypes = new Set([ const reservedTypes = new Set([
"_", "_",
@ -48,91 +48,95 @@ const reservedTypes = new Set([
/* eslint sort-keys: "error" */ /* 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 // The Errors key follows https://github.com/facebook/flow/blob/master/src/parser/parse_error.ml unless it does not exist
const FlowErrors = Object.freeze({ const FlowErrors = makeErrorTemplates(
AmbiguousConditionalArrow: {
"Ambiguous expression: wrap the arrow functions in parentheses to disambiguate.", AmbiguousConditionalArrow:
AmbiguousDeclareModuleKind: "Ambiguous expression: wrap the arrow functions in parentheses to disambiguate.",
"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", AmbiguousDeclareModuleKind:
AssignReservedType: "Cannot overwrite reserved type %0", "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",
DeclareClassElement: AssignReservedType: "Cannot overwrite reserved type %0",
"The `declare` modifier can only appear on class fields.", DeclareClassElement:
DeclareClassFieldInitializer: "The `declare` modifier can only appear on class fields.",
"Initializers are not allowed in fields with the `declare` modifier.", DeclareClassFieldInitializer:
DuplicateDeclareModuleExports: "Duplicate `declare module.exports` statement", "Initializers are not allowed in fields with the `declare` modifier.",
EnumBooleanMemberNotInitialized: DuplicateDeclareModuleExports:
"Boolean enum members need to be initialized. Use either `%0 = true,` or `%0 = false,` in enum `%1`.", "Duplicate `declare module.exports` statement",
EnumDuplicateMemberName: EnumBooleanMemberNotInitialized:
"Enum member names need to be unique, but the name `%0` has already been used before in enum `%1`.", "Boolean enum members need to be initialized. Use either `%0 = true,` or `%0 = false,` in enum `%1`.",
EnumInconsistentMemberValues: EnumDuplicateMemberName:
"Enum `%0` has inconsistent member initializers. Either use no initializers, or consistently use literals (either booleans, numbers, or strings) for all member initializers.", "Enum member names need to be unique, but the name `%0` has already been used before in enum `%1`.",
EnumInvalidExplicitType: EnumInconsistentMemberValues:
"Enum type `%1` is not valid. Use one of `boolean`, `number`, `string`, or `symbol` in enum `%0`.", "Enum `%0` has inconsistent member initializers. Either use no initializers, or consistently use literals (either booleans, numbers, or strings) for all member initializers.",
EnumInvalidExplicitTypeUnknownSupplied: EnumInvalidExplicitType:
"Supplied enum type is not valid. Use one of `boolean`, `number`, `string`, or `symbol` in enum `%0`.", "Enum type `%1` is not valid. Use one of `boolean`, `number`, `string`, or `symbol` in enum `%0`.",
EnumInvalidMemberInitializerPrimaryType: EnumInvalidExplicitTypeUnknownSupplied:
"Enum `%0` has type `%2`, so the initializer of `%1` needs to be a %2 literal.", "Supplied enum type is not valid. Use one of `boolean`, `number`, `string`, or `symbol` in enum `%0`.",
EnumInvalidMemberInitializerSymbolType: EnumInvalidMemberInitializerPrimaryType:
"Symbol enum members cannot be initialized. Use `%1,` in enum `%0`.", "Enum `%0` has type `%2`, so the initializer of `%1` needs to be a %2 literal.",
EnumInvalidMemberInitializerUnknownType: EnumInvalidMemberInitializerSymbolType:
"The enum member initializer for `%1` needs to be a literal (either a boolean, number, or string) in enum `%0`.", "Symbol enum members cannot be initialized. Use `%1,` in enum `%0`.",
EnumInvalidMemberName: EnumInvalidMemberInitializerUnknownType:
"Enum member names cannot start with lowercase 'a' through 'z'. Instead of using `%0`, consider using `%1`, in enum `%2`.", "The enum member initializer for `%1` needs to be a literal (either a boolean, number, or string) in enum `%0`.",
EnumNumberMemberNotInitialized: EnumInvalidMemberName:
"Number enum members need to be initialized, e.g. `%1 = 1` in enum `%0`.", "Enum member names cannot start with lowercase 'a' through 'z'. Instead of using `%0`, consider using `%1`, in enum `%2`.",
EnumStringMemberInconsistentlyInitailized: EnumNumberMemberNotInitialized:
"String enum members need to consistently either all use initializers, or use no initializers, in enum `%0`.", "Number enum members need to be initialized, e.g. `%1 = 1` in enum `%0`.",
GetterMayNotHaveThisParam: "A getter cannot have a `this` parameter.", EnumStringMemberInconsistentlyInitailized:
ImportTypeShorthandOnlyInPureImport: "String enum members need to consistently either all use initializers, or use no initializers, in enum `%0`.",
"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", GetterMayNotHaveThisParam: "A getter cannot have a `this` parameter.",
InexactInsideExact: ImportTypeShorthandOnlyInPureImport:
"Explicit inexact syntax cannot appear inside an explicit exact object type", "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",
InexactInsideNonObject: InexactInsideExact:
"Explicit inexact syntax cannot appear in class or interface definitions", "Explicit inexact syntax cannot appear inside an explicit exact object type",
InexactVariance: "Explicit inexact syntax cannot have variance", InexactInsideNonObject:
InvalidNonTypeImportInDeclareModule: "Explicit inexact syntax cannot appear in class or interface definitions",
"Imports within a `declare module` body must always be `import type` or `import typeof`", InexactVariance: "Explicit inexact syntax cannot have variance",
MissingTypeParamDefault: InvalidNonTypeImportInDeclareModule:
"Type parameter declaration needs a default, since a preceding type parameter declaration has a default.", "Imports within a `declare module` body must always be `import type` or `import typeof`",
NestedDeclareModule: MissingTypeParamDefault:
"`declare module` cannot be used inside another `declare module`", "Type parameter declaration needs a default, since a preceding type parameter declaration has a default.",
NestedFlowComment: "Cannot have a flow comment inside another flow comment", NestedDeclareModule:
OptionalBindingPattern: "`declare module` cannot be used inside another `declare module`",
"A binding pattern parameter cannot be optional in an implementation signature.", NestedFlowComment: "Cannot have a flow comment inside another flow comment",
SetterMayNotHaveThisParam: "A setter cannot have a `this` parameter.", OptionalBindingPattern:
SpreadVariance: "Spread properties cannot have variance", "A binding pattern parameter cannot be optional in an implementation signature.",
ThisParamAnnotationRequired: SetterMayNotHaveThisParam: "A setter cannot have a `this` parameter.",
"A type annotation is required for the `this` parameter.", SpreadVariance: "Spread properties cannot have variance",
ThisParamBannedInConstructor: ThisParamAnnotationRequired:
"Constructors cannot have a `this` parameter; constructors don't bind `this` like other functions.", "A type annotation is required for the `this` parameter.",
ThisParamMayNotBeOptional: "The `this` parameter cannot be optional.", ThisParamBannedInConstructor:
ThisParamMustBeFirst: "Constructors cannot have a `this` parameter; constructors don't bind `this` like other functions.",
"The `this` parameter must be the first function parameter.", ThisParamMayNotBeOptional: "The `this` parameter cannot be optional.",
ThisParamNoDefault: "The `this` parameter may not have a default value.", ThisParamMustBeFirst:
TypeBeforeInitializer: "The `this` parameter must be the first function parameter.",
"Type annotations must come before default assignments, e.g. instead of `age = 25: number` use `age: number = 25`", ThisParamNoDefault: "The `this` parameter may not have a default value.",
TypeCastInPattern: TypeBeforeInitializer:
"The type cast expression is expected to be wrapped with parenthesis", "Type annotations must come before default assignments, e.g. instead of `age = 25: number` use `age: number = 25`",
UnexpectedExplicitInexactInObject: TypeCastInPattern:
"Explicit inexact syntax must appear at the end of an inexact object", "The type cast expression is expected to be wrapped with parenthesis",
UnexpectedReservedType: "Unexpected reserved type %0", UnexpectedExplicitInexactInObject:
UnexpectedReservedUnderscore: "Explicit inexact syntax must appear at the end of an inexact object",
"`_` is only allowed as a type argument to call or new", UnexpectedReservedType: "Unexpected reserved type %0",
UnexpectedSpaceBetweenModuloChecks: UnexpectedReservedUnderscore:
"Spaces between `%` and `checks` are not allowed here.", "`_` is only allowed as a type argument to call or new",
UnexpectedSpreadType: UnexpectedSpaceBetweenModuloChecks:
"Spread operator cannot appear in class or interface definitions", "Spaces between `%` and `checks` are not allowed here.",
UnexpectedSubtractionOperand: UnexpectedSpreadType:
'Unexpected token, expected "number" or "bigint"', "Spread operator cannot appear in class or interface definitions",
UnexpectedTokenAfterTypeParameter: UnexpectedSubtractionOperand:
"Expected an arrow function after this type parameter declaration", 'Unexpected token, expected "number" or "bigint"',
UnexpectedTypeParameterBeforeAsyncArrowFunction: UnexpectedTokenAfterTypeParameter:
"Type parameters must come after the async keyword, e.g. instead of `<T> async () => {}`, use `async <T>() => {}`", "Expected an arrow function after this type parameter declaration",
UnsupportedDeclareExportKind: UnexpectedTypeParameterBeforeAsyncArrowFunction:
"`declare export %0` is not supported. Use `%1` instead", "Type parameters must come after the async keyword, e.g. instead of `<T> async () => {}`, use `async <T>() => {}`",
UnsupportedStatementInDeclareModule: UnsupportedDeclareExportKind:
"Only declares and type imports are allowed inside declare module", "`declare export %0` is not supported. Use `%1` instead",
UnterminatedFlowComment: "Unterminated flow-comment", UnsupportedStatementInDeclareModule:
}); "Only declares and type imports are allowed inside declare module",
UnterminatedFlowComment: "Unterminated flow-comment",
},
/* code */ ErrorCodes.SyntaxError,
);
/* eslint-disable sort-keys */ /* eslint-disable sort-keys */
function isEsModuleType(bodyElement: N.Node): boolean { function isEsModuleType(bodyElement: N.Node): boolean {

View File

@ -14,25 +14,28 @@ import * as N from "../../types";
import { isIdentifierChar, isIdentifierStart } from "../../util/identifier"; import { isIdentifierChar, isIdentifierStart } from "../../util/identifier";
import type { Position } from "../../util/location"; import type { Position } from "../../util/location";
import { isNewLine } from "../../util/whitespace"; import { isNewLine } from "../../util/whitespace";
import { Errors } from "../../parser/error"; import { Errors, makeErrorTemplates, ErrorCodes } from "../../parser/error";
const HEX_NUMBER = /^[\da-fA-F]+$/; const HEX_NUMBER = /^[\da-fA-F]+$/;
const DECIMAL_NUMBER = /^\d+$/; const DECIMAL_NUMBER = /^\d+$/;
/* eslint sort-keys: "error" */ /* eslint sort-keys: "error" */
const JsxErrors = Object.freeze({ const JsxErrors = makeErrorTemplates(
AttributeIsEmpty: {
"JSX attributes must only be assigned a non-empty expression", AttributeIsEmpty:
MissingClosingTagElement: "Expected corresponding JSX closing tag for <%0>", "JSX attributes must only be assigned a non-empty expression",
MissingClosingTagFragment: "Expected corresponding JSX closing tag for <>", MissingClosingTagElement: "Expected corresponding JSX closing tag for <%0>",
UnexpectedSequenceExpression: MissingClosingTagFragment: "Expected corresponding JSX closing tag for <>",
"Sequence expressions cannot be directly nested inside JSX. Did you mean to wrap it in parentheses (...)?", UnexpectedSequenceExpression:
UnsupportedJsxValue: "Sequence expressions cannot be directly nested inside JSX. Did you mean to wrap it in parentheses (...)?",
"JSX value should be either an expression or a quoted JSX text", UnsupportedJsxValue:
UnterminatedJsxContent: "Unterminated JSX contents", "JSX value should be either an expression or a quoted JSX text",
UnwrappedAdjacentJSXElements: UnterminatedJsxContent: "Unterminated JSX contents",
"Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>?", UnwrappedAdjacentJSXElements:
}); "Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>?",
},
/* code */ ErrorCodes.SyntaxError,
);
/* eslint-disable sort-keys */ /* eslint-disable sort-keys */
// Be aware that this file is always executed and not only when the plugin is enabled. // Be aware that this file is always executed and not only when the plugin is enabled.
@ -133,10 +136,11 @@ export default (superClass: Class<Parser>): Class<Parser> =>
const htmlEntity = const htmlEntity =
ch === charCodes.rightCurlyBrace ? "&rbrace;" : "&gt;"; ch === charCodes.rightCurlyBrace ? "&rbrace;" : "&gt;";
const char = this.input[this.state.pos]; const char = this.input[this.state.pos];
this.raise( this.raise(this.state.pos, {
this.state.pos, code: ErrorCodes.SyntaxError,
`Unexpected token \`${char}\`. Did you mean \`${htmlEntity}\` or \`{'${char}'}\`?`, reasonCode: "UnexpectedToken",
); template: `Unexpected token \`${char}\`. Did you mean \`${htmlEntity}\` or \`{'${char}'}\`?`,
});
} }
/* falls through */ /* falls through */

View File

@ -5,6 +5,7 @@ import * as charCodes from "charcodes";
import { types as tt, TokenType } from "../tokenizer/types"; import { types as tt, TokenType } from "../tokenizer/types";
import type Parser from "../parser"; import type Parser from "../parser";
import * as N from "../types"; import * as N from "../types";
import { makeErrorTemplates, ErrorCodes } from "../parser/error";
tt.placeholder = new TokenType("%%", { startsExpr: true }); tt.placeholder = new TokenType("%%", { startsExpr: true });
@ -47,6 +48,13 @@ type NodeOf<T: PlaceholderTypes> = $Switch<
// the substituted nodes. // the substituted nodes.
type MaybePlaceholder<T: PlaceholderTypes> = NodeOf<T>; // | Placeholder<T> type MaybePlaceholder<T: PlaceholderTypes> = NodeOf<T>; // | Placeholder<T>
const PlaceHolderErrors = makeErrorTemplates(
{
ClassNameIsRequired: "A class name is required",
},
/* code */ ErrorCodes.SyntaxError,
);
export default (superClass: Class<Parser>): Class<Parser> => export default (superClass: Class<Parser>): Class<Parser> =>
class extends superClass { class extends superClass {
parsePlaceholder<T: PlaceholderTypes>( parsePlaceholder<T: PlaceholderTypes>(
@ -240,7 +248,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
node.body = this.finishPlaceholder(placeholder, "ClassBody"); node.body = this.finishPlaceholder(placeholder, "ClassBody");
return this.finishNode(node, type); return this.finishNode(node, type);
} else { } else {
this.unexpected(null, "A class name is required"); this.unexpected(null, PlaceHolderErrors.ClassNameIsRequired);
} }
} else { } else {
this.parseClassId(node, isStatement, optionalId); this.parseClassId(node, isStatement, optionalId);

View File

@ -29,7 +29,12 @@ import TypeScriptScopeHandler from "./scope";
import * as charCodes from "charcodes"; import * as charCodes from "charcodes";
import type { ExpressionErrors } from "../../parser/util"; import type { ExpressionErrors } from "../../parser/util";
import { PARAM } from "../../util/production-parameter"; import { PARAM } from "../../util/production-parameter";
import { Errors } from "../../parser/error"; import {
Errors,
makeErrorTemplates,
type ErrorTemplate,
ErrorCodes,
} from "../../parser/error";
type TsModifier = type TsModifier =
| "readonly" | "readonly"
@ -60,67 +65,75 @@ type ParsingContext =
| "TypeParametersOrArguments"; | "TypeParametersOrArguments";
/* eslint sort-keys: "error" */ /* eslint sort-keys: "error" */
const TSErrors = Object.freeze({ const TSErrors = makeErrorTemplates(
AbstractMethodHasImplementation: {
"Method '%0' cannot have an implementation because it is marked abstract.", AbstractMethodHasImplementation:
ClassMethodHasDeclare: "Class methods cannot have the 'declare' modifier", "Method '%0' cannot have an implementation because it is marked abstract.",
ClassMethodHasReadonly: "Class methods cannot have the 'readonly' modifier", ClassMethodHasDeclare: "Class methods cannot have the 'declare' modifier",
ConstructorHasTypeParameters: ClassMethodHasReadonly: "Class methods cannot have the 'readonly' modifier",
"Type parameters cannot appear on a constructor declaration.", ConstructorHasTypeParameters:
"Type parameters cannot appear on a constructor declaration.",
DeclareAccessor: "'declare' is not allowed in %0ters.", DeclareAccessor: "'declare' is not allowed in %0ters.",
DeclareClassFieldHasInitializer: DeclareClassFieldHasInitializer:
"Initializers are not allowed in ambient contexts.", "Initializers are not allowed in ambient contexts.",
DeclareFunctionHasImplementation: DeclareFunctionHasImplementation:
"An implementation cannot be declared in ambient contexts.", "An implementation cannot be declared in ambient contexts.",
DuplicateAccessibilityModifier: "Accessibility modifier already seen.", DuplicateAccessibilityModifier: "Accessibility modifier already seen.",
DuplicateModifier: "Duplicate modifier: '%0'", DuplicateModifier: "Duplicate modifier: '%0'",
EmptyHeritageClauseType: "'%0' list cannot be empty.", EmptyHeritageClauseType: "'%0' list cannot be empty.",
EmptyTypeArguments: "Type argument list cannot be empty.", EmptyTypeArguments: "Type argument list cannot be empty.",
EmptyTypeParameters: "Type parameter list cannot be empty.", EmptyTypeParameters: "Type parameter list cannot be empty.",
ExpectedAmbientAfterExportDeclare: ExpectedAmbientAfterExportDeclare:
"'export declare' must be followed by an ambient declaration.", "'export declare' must be followed by an ambient declaration.",
ImportAliasHasImportType: "An import alias can not use 'import type'", ImportAliasHasImportType: "An import alias can not use 'import type'",
IndexSignatureHasAbstract: IndexSignatureHasAbstract:
"Index signatures cannot have the 'abstract' modifier", "Index signatures cannot have the 'abstract' modifier",
IndexSignatureHasAccessibility: IndexSignatureHasAccessibility:
"Index signatures cannot have an accessibility modifier ('%0')", "Index signatures cannot have an accessibility modifier ('%0')",
IndexSignatureHasDeclare: IndexSignatureHasDeclare:
"Index signatures cannot have the 'declare' modifier", "Index signatures cannot have the 'declare' modifier",
IndexSignatureHasStatic: "Index signatures cannot have the 'static' modifier", IndexSignatureHasStatic:
InvalidModifierOnTypeMember: "'%0' modifier cannot appear on a type member.", "Index signatures cannot have the 'static' modifier",
InvalidTupleMemberLabel: InvalidModifierOnTypeMember:
"Tuple members must be labeled with a simple identifier.", "'%0' modifier cannot appear on a type member.",
MixedLabeledAndUnlabeledElements: InvalidTupleMemberLabel:
"Tuple members must all have names or all not have names.", "Tuple members must be labeled with a simple identifier.",
NonAbstractClassHasAbstractMethod: MixedLabeledAndUnlabeledElements:
"Abstract methods can only appear within an abstract class.", "Tuple members must all have names or all not have names.",
NonClassMethodPropertyHasAbstractModifer: NonAbstractClassHasAbstractMethod:
"'abstract' modifier can only appear on a class, method, or property declaration.", "Abstract methods can only appear within an abstract class.",
OptionalTypeBeforeRequired: NonClassMethodPropertyHasAbstractModifer:
"A required element cannot follow an optional element.", "'abstract' modifier can only appear on a class, method, or property declaration.",
PatternIsOptional: OptionalTypeBeforeRequired:
"A binding pattern parameter cannot be optional in an implementation signature.", "A required element cannot follow an optional element.",
PrivateElementHasAbstract: PatternIsOptional:
"Private elements cannot have the 'abstract' modifier.", "A binding pattern parameter cannot be optional in an implementation signature.",
PrivateElementHasAccessibility: PrivateElementHasAbstract:
"Private elements cannot have an accessibility modifier ('%0')", "Private elements cannot have the 'abstract' modifier.",
ReadonlyForMethodSignature: PrivateElementHasAccessibility:
"'readonly' modifier can only appear on a property declaration or index signature.", "Private elements cannot have an accessibility modifier ('%0')",
TypeAnnotationAfterAssign: ReadonlyForMethodSignature:
"Type annotations must come before default assignments, e.g. instead of `age = 25: number` use `age: number = 25`", "'readonly' modifier can only appear on a property declaration or index signature.",
UnexpectedParameterModifier: TypeAnnotationAfterAssign:
"A parameter property is only allowed in a constructor implementation.", "Type annotations must come before default assignments, e.g. instead of `age = 25: number` use `age: number = 25`",
UnexpectedReadonly: TypeImportCannotSpecifyDefaultAndNamed:
"'readonly' type modifier is only permitted on array and tuple literal types.", "A type-only import can specify a default import or named bindings, but not both.",
UnexpectedTypeAnnotation: "Did not expect a type annotation here.", UnexpectedParameterModifier:
UnexpectedTypeCastInParameter: "Unexpected type cast in parameter position.", "A parameter property is only allowed in a constructor implementation.",
UnsupportedImportTypeArgument: UnexpectedReadonly:
"Argument in a type import must be a string literal", "'readonly' type modifier is only permitted on array and tuple literal types.",
UnsupportedParameterPropertyKind: UnexpectedTypeAnnotation: "Did not expect a type annotation here.",
"A parameter property may not be declared using a binding pattern.", UnexpectedTypeCastInParameter:
UnsupportedSignatureParameterKind: "Unexpected type cast in parameter position.",
"Name in a signature must be an Identifier, ObjectPattern or ArrayPattern, instead got %0", UnsupportedImportTypeArgument:
}); "Argument in a type import must be a string literal",
UnsupportedParameterPropertyKind:
"A parameter property may not be declared using a binding pattern.",
UnsupportedSignatureParameterKind:
"Name in a signature must be an Identifier, ObjectPattern or ArrayPattern, instead got %0",
},
/* code */ ErrorCodes.SyntaxError,
);
/* eslint-disable sort-keys */ /* eslint-disable sort-keys */
// Doesn't handle "void" or "null" because those are keywords, not identifiers. // Doesn't handle "void" or "null" because those are keywords, not identifiers.
@ -217,7 +230,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}, },
allowedModifiers: TsModifier[], allowedModifiers: TsModifier[],
disallowedModifiers?: TsModifier[], disallowedModifiers?: TsModifier[],
errorTemplate?: string, errorTemplate?: ErrorTemplate,
): void { ): void {
for (;;) { for (;;) {
const startPos = this.state.start; const startPos = this.state.start;
@ -2098,7 +2111,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
) { ) {
this.raise( this.raise(
importNode.start, importNode.start,
"A type-only import can specify a default import or named bindings, but not both.", TSErrors.TypeImportCannotSpecifyDefaultAndNamed,
); );
} }

View File

@ -9,7 +9,7 @@ import * as charCodes from "charcodes";
import { isIdentifierStart, isIdentifierChar } from "../util/identifier"; import { isIdentifierStart, isIdentifierChar } from "../util/identifier";
import { types as tt, keywords as keywordTypes, type TokenType } from "./types"; import { types as tt, keywords as keywordTypes, type TokenType } from "./types";
import { type TokContext, types as ct } from "./context"; import { type TokContext, types as ct } from "./context";
import ParserErrors, { Errors } from "../parser/error"; import ParserErrors, { Errors, type ErrorTemplate } from "../parser/error";
import { SourceLocation } from "../util/location"; import { SourceLocation } from "../util/location";
import { import {
lineBreak, lineBreak,
@ -115,7 +115,7 @@ export default class Tokenizer extends ParserErrors {
// parser/util.js // parser/util.js
/*:: /*::
+hasPrecedingLineBreak: () => boolean; +hasPrecedingLineBreak: () => boolean;
+unexpected: (pos?: ?number, messageOrType?: string | TokenType) => empty; +unexpected: (pos?: ?number, messageOrType?: ErrorTemplate | TokenType) => empty;
+expectPlugin: (name: string, pos?: ?number) => true; +expectPlugin: (name: string, pos?: ?number) => true;
*/ */
@ -1321,7 +1321,7 @@ export default class Tokenizer extends ParserErrors {
} }
} }
recordStrictModeErrors(pos: number, message: string) { recordStrictModeErrors(pos: number, message: ErrorTemplate) {
if (this.state.strict && !this.state.strictErrors.has(pos)) { if (this.state.strict && !this.state.strictErrors.has(pos)) {
this.raise(pos, message); this.raise(pos, message);
} else { } else {

View File

@ -6,7 +6,7 @@ import { Position } from "../util/location";
import { types as ct, type TokContext } from "./context"; import { types as ct, type TokContext } from "./context";
import { types as tt, type TokenType } from "./types"; import { types as tt, type TokenType } from "./types";
import type { ParsingError } from "../parser/error"; import type { ParsingError, ErrorTemplate } from "../parser/error";
type TopicContextState = { type TopicContextState = {
// When a topic binding has been currently established, // When a topic binding has been currently established,
@ -147,7 +147,7 @@ export default class State {
// todo(JLHwung): set strictErrors to null and avoid recording string errors // todo(JLHwung): set strictErrors to null and avoid recording string errors
// after a non-directive is parsed // after a non-directive is parsed
strictErrors: Map<number, string> = new Map(); strictErrors: Map<number, ErrorTemplate> = new Map();
// Names of exports store. `default` is stored as a name for both // Names of exports store. `default` is stored as a name for both
// `export default foo;` and `export { foo as default };`. // `export default foo;` and `export { foo as default };`.

View File

@ -5,7 +5,7 @@ import {
CLASS_ELEMENT_FLAG_STATIC, CLASS_ELEMENT_FLAG_STATIC,
type ClassElementTypes, type ClassElementTypes,
} from "./scopeflags"; } from "./scopeflags";
import { Errors } from "../parser/error"; import { Errors, type raiseFunction } from "../parser/error";
export class ClassScope { export class ClassScope {
// A list of private named declared in the current class // A list of private named declared in the current class
@ -19,8 +19,6 @@ export class ClassScope {
undefinedPrivateNames: Map<string, number> = new Map(); undefinedPrivateNames: Map<string, number> = new Map();
} }
type raiseFunction = (number, string, ...any) => void;
export default class ClassScopeHandler { export default class ClassScopeHandler {
stack: Array<ClassScope> = []; stack: Array<ClassScope> = [];
declare raise: raiseFunction; declare raise: raiseFunction;

View File

@ -1,5 +1,7 @@
// @flow // @flow
import type { ErrorTemplate, raiseFunction } from "../parser/error";
/*:: declare var invariant; */ /*:: declare var invariant; */
/** /**
* @module util/expression-scope * @module util/expression-scope
@ -52,8 +54,6 @@ const kExpression = 0,
type ExpressionScopeType = 0 | 1 | 2 | 3; type ExpressionScopeType = 0 | 1 | 2 | 3;
type raiseFunction = (number, string, ...any) => void;
class ExpressionScope { class ExpressionScope {
type: ExpressionScopeType; type: ExpressionScopeType;
@ -74,17 +74,17 @@ class ExpressionScope {
} }
class ArrowHeadParsingScope extends ExpressionScope { class ArrowHeadParsingScope extends ExpressionScope {
errors: Map</* pos */ number, /* message */ string> = new Map(); errors: Map</* pos */ number, /* message */ ErrorTemplate> = new Map();
constructor(type: 1 | 2) { constructor(type: 1 | 2) {
super(type); super(type);
} }
recordDeclarationError(pos: number, message: string) { recordDeclarationError(pos: number, template: ErrorTemplate) {
this.errors.set(pos, message); this.errors.set(pos, template);
} }
clearDeclarationError(pos: number) { clearDeclarationError(pos: number) {
this.errors.delete(pos); this.errors.delete(pos);
} }
iterateErrors(iterator: (message: string, pos: number) => void) { iterateErrors(iterator: (template: ErrorTemplate, pos: number) => void) {
this.errors.forEach(iterator); this.errors.forEach(iterator);
} }
} }
@ -110,17 +110,17 @@ export default class ExpressionScopeHandler {
* otherwise it will be recorded to any ancestry MaybeArrowParameterDeclaration and * otherwise it will be recorded to any ancestry MaybeArrowParameterDeclaration and
* MaybeAsyncArrowParameterDeclaration scope until an Expression scope is seen. * MaybeAsyncArrowParameterDeclaration scope until an Expression scope is seen.
* @param {number} pos Error position * @param {number} pos Error position
* @param {string} message Error message * @param {ErrorTemplate} template Error template
* @memberof ExpressionScopeHandler * @memberof ExpressionScopeHandler
*/ */
recordParameterInitializerError(pos: number, message: string): void { recordParameterInitializerError(pos: number, template: ErrorTemplate): void {
const { stack } = this; const { stack } = this;
let i = stack.length - 1; let i = stack.length - 1;
let scope: ExpressionScope = stack[i]; let scope: ExpressionScope = stack[i];
while (!scope.isCertainlyParameterDeclaration()) { while (!scope.isCertainlyParameterDeclaration()) {
if (scope.canBeArrowParameterDeclaration()) { if (scope.canBeArrowParameterDeclaration()) {
/*:: invariant(scope instanceof ArrowHeadParsingScope) */ /*:: invariant(scope instanceof ArrowHeadParsingScope) */
scope.recordDeclarationError(pos, message); scope.recordDeclarationError(pos, template);
} else { } else {
/*:: invariant(scope.type == kExpression) */ /*:: invariant(scope.type == kExpression) */
// Type-Expression is the boundary where initializer error can populate to // Type-Expression is the boundary where initializer error can populate to
@ -129,7 +129,7 @@ export default class ExpressionScopeHandler {
scope = stack[--i]; scope = stack[--i];
} }
/* eslint-disable @babel/development-internal/dry-error-messages */ /* eslint-disable @babel/development-internal/dry-error-messages */
this.raise(pos, message); this.raise(pos, template);
} }
/** /**
@ -149,18 +149,21 @@ export default class ExpressionScopeHandler {
* arrow scope because when we finish parsing `( [(a) = []] = [] )`, it is an unambiguous assignment * arrow scope because when we finish parsing `( [(a) = []] = [] )`, it is an unambiguous assignment
* expression and can not be cast to pattern * expression and can not be cast to pattern
* @param {number} pos * @param {number} pos
* @param {string} message * @param {ErrorTemplate} template
* @returns {void} * @returns {void}
* @memberof ExpressionScopeHandler * @memberof ExpressionScopeHandler
*/ */
recordParenthesizedIdentifierError(pos: number, message: string): void { recordParenthesizedIdentifierError(
pos: number,
template: ErrorTemplate,
): void {
const { stack } = this; const { stack } = this;
const scope: ExpressionScope = stack[stack.length - 1]; const scope: ExpressionScope = stack[stack.length - 1];
if (scope.isCertainlyParameterDeclaration()) { if (scope.isCertainlyParameterDeclaration()) {
this.raise(pos, message); this.raise(pos, template);
} else if (scope.canBeArrowParameterDeclaration()) { } else if (scope.canBeArrowParameterDeclaration()) {
/*:: invariant(scope instanceof ArrowHeadParsingScope) */ /*:: invariant(scope instanceof ArrowHeadParsingScope) */
scope.recordDeclarationError(pos, message); scope.recordDeclarationError(pos, template);
} else { } else {
return; return;
} }
@ -172,17 +175,17 @@ export default class ExpressionScopeHandler {
* Errors will be recorded to any ancestry MaybeAsyncArrowParameterDeclaration * Errors will be recorded to any ancestry MaybeAsyncArrowParameterDeclaration
* scope until an Expression scope is seen. * scope until an Expression scope is seen.
* @param {number} pos * @param {number} pos
* @param {string} message * @param {ErrorTemplate} template
* @memberof ExpressionScopeHandler * @memberof ExpressionScopeHandler
*/ */
recordAsyncArrowParametersError(pos: number, message: string): void { recordAsyncArrowParametersError(pos: number, template: ErrorTemplate): void {
const { stack } = this; const { stack } = this;
let i = stack.length - 1; let i = stack.length - 1;
let scope: ExpressionScope = stack[i]; let scope: ExpressionScope = stack[i];
while (scope.canBeArrowParameterDeclaration()) { while (scope.canBeArrowParameterDeclaration()) {
if (scope.type === kMaybeAsyncArrowParameterDeclaration) { if (scope.type === kMaybeAsyncArrowParameterDeclaration) {
/*:: invariant(scope instanceof ArrowHeadParsingScope) */ /*:: invariant(scope instanceof ArrowHeadParsingScope) */
scope.recordDeclarationError(pos, message); scope.recordDeclarationError(pos, template);
} }
scope = stack[--i]; scope = stack[--i];
} }
@ -193,9 +196,9 @@ export default class ExpressionScopeHandler {
const currentScope = stack[stack.length - 1]; const currentScope = stack[stack.length - 1];
if (!currentScope.canBeArrowParameterDeclaration()) return; if (!currentScope.canBeArrowParameterDeclaration()) return;
/*:: invariant(currentScope instanceof ArrowHeadParsingScope) */ /*:: invariant(currentScope instanceof ArrowHeadParsingScope) */
currentScope.iterateErrors((message, pos) => { currentScope.iterateErrors((template, pos) => {
/* eslint-disable @babel/development-internal/dry-error-messages */ /* eslint-disable @babel/development-internal/dry-error-messages */
this.raise(pos, message); this.raise(pos, template);
// iterate from parent scope // iterate from parent scope
let i = stack.length - 2; let i = stack.length - 2;
let scope = stack[i]; let scope = stack[i];

View File

@ -17,7 +17,7 @@ import {
type BindingTypes, type BindingTypes,
} from "./scopeflags"; } from "./scopeflags";
import * as N from "../types"; import * as N from "../types";
import { Errors } from "../parser/error"; import { Errors, type raiseFunction } from "../parser/error";
// Start an AST node, attaching a start offset. // Start an AST node, attaching a start offset.
export class Scope { export class Scope {
@ -34,8 +34,6 @@ export class Scope {
} }
} }
type raiseFunction = (number, string, ...any) => void;
// The functions in this module keep track of declared variables in the // The functions in this module keep track of declared variables in the
// current scope in order to detect duplicate variable names. // current scope in order to detect duplicate variable names.
export default class ScopeHandler<IScope: Scope = Scope> { export default class ScopeHandler<IScope: Scope = Scope> {

View File

@ -0,0 +1,21 @@
import { parse } from "../lib";
describe("error codes", function () {
it("raises an error with BABEL_PARSER_SOURCETYPE_MODULE_REQUIRED and reasonCode", function () {
const code = `import "foo"`;
const { errors } = parse(code, {
errorRecovery: true,
sourceType: "script",
});
const error = errors[0];
expect(error.code).toBe("BABEL_PARSER_SOURCETYPE_MODULE_REQUIRED");
expect(error.reasonCode).toBe("ImportOutsideModule");
});
it("raises an error with BABEL_PARSER_SYNTAX_ERROR and reasonCode", function () {
const code = `a b`;
const { errors } = parse(code, { errorRecovery: true });
const error = errors[0];
expect(error.code).toBe("BABEL_PARSER_SYNTAX_ERROR");
expect(error.reasonCode).toBe("MissingSemicolon");
});
});