diff --git a/packages/babel-parser/src/parser/error.js b/packages/babel-parser/src/parser/error.js index aa68465b618f..4dc30ba98925 100644 --- a/packages/babel-parser/src/parser/error.js +++ b/packages/babel-parser/src/parser/error.js @@ -28,17 +28,30 @@ export type ErrorTemplates = { [key: string]: ErrorTemplate, }; +type SyntaxPlugin = "flow" | "typescript" | "jsx" | typeof undefined; + +function keepReasonCodeCompat(reasonCode: string, syntaxPlugin: SyntaxPlugin) { + if (!process.env.BABEL_8_BREAKING) { + // For consistency in TypeScript and Flow error codes + if (syntaxPlugin === "flow" && reasonCode === "PatternIsOptional") { + return "OptionalBindingPattern"; + } + } + return reasonCode; +} + export function makeErrorTemplates( messages: { [key: string]: string, }, code: ErrorCode, + syntaxPlugin?: SyntaxPlugin, ): ErrorTemplates { const templates: ErrorTemplates = {}; Object.keys(messages).forEach(reasonCode => { templates[reasonCode] = Object.freeze({ code, - reasonCode, + reasonCode: keepReasonCodeCompat(reasonCode, syntaxPlugin), template: messages[reasonCode], }); }); diff --git a/packages/babel-parser/src/plugins/flow/index.js b/packages/babel-parser/src/plugins/flow/index.js index 2a29bae384c3..272cbe70e908 100644 --- a/packages/babel-parser/src/plugins/flow/index.js +++ b/packages/babel-parser/src/plugins/flow/index.js @@ -99,7 +99,7 @@ const FlowErrors = makeErrorTemplates( "`declare module` cannot be used inside another `declare module`.", NestedFlowComment: "Cannot have a flow comment inside another flow comment.", - OptionalBindingPattern: + PatternIsOptional: "A binding pattern parameter cannot be optional in an implementation signature.", SetterMayNotHaveThisParam: "A setter cannot have a `this` parameter.", SpreadVariance: "Spread properties cannot have variance.", @@ -137,6 +137,7 @@ const FlowErrors = makeErrorTemplates( UnterminatedFlowComment: "Unterminated flow-comment.", }, /* code */ ErrorCodes.SyntaxError, + /* syntaxPlugin */ "flow", ); /* eslint-disable sort-keys */ @@ -2532,7 +2533,7 @@ export default (superClass: Class): Class => parseAssignableListItemTypes(param: N.Pattern): N.Pattern { if (this.eat(tt.question)) { if (param.type !== "Identifier") { - this.raise(param.start, FlowErrors.OptionalBindingPattern); + this.raise(param.start, FlowErrors.PatternIsOptional); } if (this.isThisParam(param)) { this.raise(param.start, FlowErrors.ThisParamMayNotBeOptional); diff --git a/packages/babel-parser/src/plugins/jsx/index.js b/packages/babel-parser/src/plugins/jsx/index.js index df3dbcbd0663..35d2047b8c4c 100644 --- a/packages/babel-parser/src/plugins/jsx/index.js +++ b/packages/babel-parser/src/plugins/jsx/index.js @@ -40,6 +40,7 @@ const JsxErrors = makeErrorTemplates( "Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...?", }, /* code */ ErrorCodes.SyntaxError, + /* syntaxPlugin */ "jsx", ); /* eslint-disable sort-keys */ diff --git a/packages/babel-parser/src/plugins/typescript/index.js b/packages/babel-parser/src/plugins/typescript/index.js index 5fde51cb9b0a..71ed89592cba 100644 --- a/packages/babel-parser/src/plugins/typescript/index.js +++ b/packages/babel-parser/src/plugins/typescript/index.js @@ -156,6 +156,7 @@ const TSErrors = makeErrorTemplates( "Name in a signature must be an Identifier, ObjectPattern or ArrayPattern, instead got %0.", }, /* code */ ErrorCodes.SyntaxError, + /* syntaxPlugin */ "typescript", ); /* eslint-disable sort-keys */ diff --git a/packages/babel-parser/test/error-codes.js b/packages/babel-parser/test/error-codes.js index 58bb5e411a6c..a072b0d7821a 100644 --- a/packages/babel-parser/test/error-codes.js +++ b/packages/babel-parser/test/error-codes.js @@ -18,4 +18,25 @@ describe("error codes", function () { expect(error.code).toBe("BABEL_PARSER_SYNTAX_ERROR"); expect(error.reasonCode).toBe("MissingSemicolon"); }); + it("consistent reasonCode between Flow and TypeScript in Babel 8", () => { + const code = `function f([]?) {}`; + const { + errors: [tsError], + } = parse(code, { + errorRecovery: true, + plugins: ["typescript"], + }); + const { + errors: [flowError], + } = parse(code, { + errorRecovery: true, + plugins: ["flow"], + }); + expect(flowError.reasonCode).toBe( + process.env.BABEL_8_BREAKING + ? tsError.reasonCode + : "OptionalBindingPattern", + ); + expect(flowError.message).toBe(tsError.message); + }); });