Skip to content

Commit

Permalink
refactor: use error message template in typescript plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
JLHwung committed Mar 3, 2020
1 parent 0b8d5ca commit 5ededb5
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 61 deletions.
1 change: 1 addition & 0 deletions packages/babel-parser/src/plugins/flow.js
Expand Up @@ -44,6 +44,7 @@ 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 = Object.freeze({
AmbiguousConditionalArrow:
"Ambiguous expression: wrap the arrow functions in parentheses to disambiguate.",
Expand Down
123 changes: 62 additions & 61 deletions packages/babel-parser/src/plugins/typescript/index.js
Expand Up @@ -27,6 +27,7 @@ import TypeScriptScopeHandler from "./scope";
import * as charCodes from "charcodes";
import type { ExpressionErrors } from "../../parser/util";
import { PARAM } from "../../util/production-parameter";
import { Errors } from "../../parser/location";

type TsModifier =
| "readonly"
Expand Down Expand Up @@ -58,6 +59,42 @@ type ParsingContext =
| "TypeMembers"
| "TypeParametersOrArguments";

const tsErrors = Object.freeze({
ClassMethodHasDeclare: "Class methods cannot have the 'declare' modifier",
ClassMethodHasReadonly: "Class methods cannot have the 'readonly' modifier",
DeclareClassFieldHasInitializer:
"'declare' class fields cannot have an initializer",
DuplicateModifier: "Duplicate modifier: '%0'",
EmptyHeritageClauseType: "'%0' list cannot be empty.",
IndexSignatureHasAbstract:
"Index signatures cannot have the 'abstract' modifier",
IndexSignatureHasAccessibility:
"Index signatures cannot have an accessibility modifier ('%0')",
IndexSignatureHasStatic: "Index signatures cannot have the 'static' modifier",
OptionalTypeBeforeRequired:
"A required element cannot follow an optional element.",
PatternIsOptional:
"A binding pattern parameter cannot be optional in an implementation signature.",
PrivateElementHasAbstract:
"Private elements cannot have the 'abstract' modifier.",
PrivateElementHasAccessibility:
"Private elements cannot have an accessibility modifier ('%0')",
TemplateTypeHasSubstitution:
"Template literal types cannot have any substitution",
TypeAnnotationAfterAssign:
"Type annotations must come before default assignments, e.g. instead of `age = 25: number` use `age: number = 25`",
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:
"Name in a signature must be an Identifier, ObjectPattern or ArrayPattern, instead got %0",
});

// Doesn't handle "void" or "null" because those are keywords, not identifiers.
function keywordTypeFromName(
value: string,
Expand Down Expand Up @@ -149,7 +186,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
if (!modifier) break;

if (Object.hasOwnProperty.call(modified, modifier)) {
this.raise(startPos, `Duplicate modifier: '${modifier}'`);
this.raise(startPos, tsErrors.DuplicateModifier, modifier);
}
modified[modifier] = true;
}
Expand Down Expand Up @@ -263,10 +300,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
this.expect(tt._import);
this.expect(tt.parenL);
if (!this.match(tt.string)) {
this.raise(
this.state.start,
"Argument in a type import must be a string literal",
);
this.raise(this.state.start, tsErrors.UnsupportedImportTypeArgument);
}

// For compatibility to estree we cannot call parseLiteral directly here
Expand Down Expand Up @@ -402,8 +436,8 @@ export default (superClass: Class<Parser>): Class<Parser> =>
) {
this.raise(
pattern.start,
"Name in a signature must be an Identifier, ObjectPattern or ArrayPattern," +
`instead got ${pattern.type}`,
tsErrors.UnsupportedSignatureParameterKind,
pattern.type,
);
}
return (pattern: any);
Expand Down Expand Up @@ -601,10 +635,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
if (elementNode.type === "TSOptionalType") {
seenOptionalElement = true;
} else if (seenOptionalElement && elementNode.type !== "TSRestType") {
this.raise(
elementNode.start,
"A required element cannot follow an optional element.",
);
this.raise(elementNode.start, tsErrors.OptionalTypeBeforeRequired);
}
});

Expand Down Expand Up @@ -678,7 +709,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
if (templateNode.expressions.length > 0) {
this.raise(
templateNode.expressions[0].start,
"Template literal types cannot have any substitution",
tsErrors.TemplateTypeHasSubstitution,
);
}
node.literal = templateNode;
Expand Down Expand Up @@ -790,10 +821,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
case "TSArrayType":
return;
default:
this.raise(
node.start,
"'readonly' type modifier is only permitted on array and tuple literal types.",
);
this.raise(node.start, tsErrors.UnexpectedReadonly);
}
}

Expand Down Expand Up @@ -1031,7 +1059,8 @@ export default (superClass: Class<Parser>): Class<Parser> =>
if (containsEsc) {
this.raise(
this.state.lastTokStart,
"Escape sequence in keyword asserts",
Errors.InvalidEscapedReservedWord,
"asserts",
);
}

Expand Down Expand Up @@ -1098,7 +1127,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
);

if (!delimitedList.length) {
this.raise(originalStart, `'${descriptor}' list cannot be empty.`);
this.raise(originalStart, tsErrors.EmptyHeritageClauseType, descriptor);
}

return delimitedList;
Expand Down Expand Up @@ -1639,10 +1668,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
if (accessibility) pp.accessibility = accessibility;
if (readonly) pp.readonly = readonly;
if (elt.type !== "Identifier" && elt.type !== "AssignmentPattern") {
this.raise(
pp.start,
"A parameter property may not be declared using a binding pattern.",
);
this.raise(pp.start, tsErrors.UnsupportedParameterPropertyKind);
}
pp.parameter = ((elt: any): N.Identifier | N.AssignmentPattern);
return this.finishNode(pp, "TSParameterProperty");
Expand Down Expand Up @@ -1941,23 +1967,16 @@ export default (superClass: Class<Parser>): Class<Parser> =>
classBody.body.push(idx);

if ((member: any).abstract) {
this.raise(
member.start,
"Index signatures cannot have the 'abstract' modifier",
);
this.raise(member.start, tsErrors.IndexSignatureHasAbstract);
}
if (isStatic) {
this.raise(
member.start,
"Index signatures cannot have the 'static' modifier",
);
this.raise(member.start, tsErrors.IndexSignatureHasStatic);
}
if ((member: any).accessibility) {
this.raise(
member.start,
`Index signatures cannot have an accessibility modifier ('${
(member: any).accessibility
}')`,
tsErrors.IndexSignatureHasAccessibility,
(member: any).accessibility,
);
}

Expand All @@ -1982,17 +2001,11 @@ export default (superClass: Class<Parser>): Class<Parser> =>
if (optional) methodOrProp.optional = true;

if ((methodOrProp: any).readonly && this.match(tt.parenL)) {
this.raise(
methodOrProp.start,
"Class methods cannot have the 'readonly' modifier",
);
this.raise(methodOrProp.start, tsErrors.ClassMethodHasReadonly);
}

if ((methodOrProp: any).declare && this.match(tt.parenL)) {
this.raise(
methodOrProp.start,
"Class methods cannot have the 'declare' modifier",
);
this.raise(methodOrProp.start, tsErrors.ClassMethodHasDeclare);
}
}

Expand Down Expand Up @@ -2142,10 +2155,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
this.parseClassPropertyAnnotation(node);

if (node.declare && this.match(tt.equal)) {
this.raise(
this.state.start,
"'declare' class fields cannot have an initializer",
);
this.raise(this.state.start, tsErrors.DeclareClassFieldHasInitializer);
}

return super.parseClassProperty(node);
Expand All @@ -2156,17 +2166,15 @@ export default (superClass: Class<Parser>): Class<Parser> =>
): N.ClassPrivateProperty {
// $FlowIgnore
if (node.abstract) {
this.raise(
node.start,
"Private elements cannot have the 'abstract' modifier.",
);
this.raise(node.start, tsErrors.PrivateElementHasAbstract);
}

// $FlowIgnore
if (node.accessibility) {
this.raise(
node.start,
`Private elements cannot have an accessibility modifier ('${node.accessibility}')`,
tsErrors.PrivateElementHasAccessibility,
node.accessibility,
);
}

Expand Down Expand Up @@ -2389,10 +2397,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
parseAssignableListItemTypes(param: N.Pattern) {
if (this.eat(tt.question)) {
if (param.type !== "Identifier") {
this.raise(
param.start,
"A binding pattern parameter cannot be optional in an implementation signature.",
);
this.raise(param.start, tsErrors.PatternIsOptional);
}

((param: any): N.Identifier).optional = true;
Expand Down Expand Up @@ -2507,8 +2512,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
) {
this.raise(
node.typeAnnotation.start,
"Type annotations must come before default assignments, " +
"e.g. instead of `age = 25: number` use `age: number = 25`",
tsErrors.TypeAnnotationAfterAssign,
);
}

Expand Down Expand Up @@ -2537,10 +2541,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
if (!this.state.maybeInArrowParameters) {
exprList[i] = this.typeCastToParameter(expr);
} else {
this.raise(
expr.start,
"Unexpected type cast in parameter position.",
);
this.raise(expr.start, tsErrors.UnexpectedTypeCastInParameter);
}
break;
}
Expand All @@ -2567,7 +2568,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
for (let i = 0; i < exprList.length; i++) {
const expr = exprList[i];
if (expr && expr.type === "TSTypeCastExpression") {
this.raise(expr.start, "Did not expect a type annotation here.");
this.raise(expr.start, tsErrors.UnexpectedTypeAnnotation);
}
}

Expand Down

0 comments on commit 5ededb5

Please sign in to comment.