Introduce parser error codes - #13033
Conversation
|
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/45001/ |
|
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. Latest deployment of this branch, based on commit f07223d:
|
| // These errors have a different error code than the key | ||
| export const SourceTypeModuleErrorMessages: ErrorTemplates = Object.freeze({ | ||
| ImportMetaOutsideModule: { | ||
| code: "BABEL_PARSER_SOURCETYPE_MODULE_REQUIRED", |
| AccessorIsGenerator: { | ||
| code: "AccessorIsGenerator", | ||
| template: "A %0ter cannot be a generator", | ||
| }, |
There was a problem hiding this comment.
It's just a stylistic preference, but I don't really like that we have to repeat so much boilerplate (duplicating every code, and the code/template keys for every message).
Maybe we could do something like this?
export const ErrorMessages = makeErrorTemplates({
AccessorIsGenerator: "A %0ter cannot be a generator",
...
});
export function makeErrorTemplates(messages) {
Object.keys(messages).forEach(code => {
messages[code] = { code, template: messages[code] };
});
}it's a one-time cost only paid when importing @babel/parser.
|
|
||
| // 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: ErrorTemplates = makeErrorTemplates({ |
There was a problem hiding this comment.
Nit: This is probably not needed anymore, since it's inferred from makeErrorTemplates's return type.
| export const ErrorMessages: ErrorTemplates = makeErrorTemplates({ | |
| export const ErrorMessages = makeErrorTemplates({ |
| throw this.raise(pos != null ? pos : this.state.start, { | ||
| code: "UnexpectedToken", | ||
| template: messageOrType, | ||
| }); |
There was a problem hiding this comment.
I think here it would be better if the signature was
unexpected(pos: ?number, messageOrType: TokenType | ErrorTemplate)and if we get an error template we use the correct code rather than UnexpectedToken.
0a70716 to
874ddd6
Compare
|
Should this wait for a minor? |
|
Note that the |
| `Unexpected token \`${char}\`. Did you mean \`${htmlEntity}\` or \`{'${char}'}\`?`, | ||
| ); | ||
| this.raise(this.state.pos, { | ||
| code: "UnexpectedToken", |
There was a problem hiding this comment.
Should we prefix error code with BABEL_PARSER like we did in BABEL_PARSER_SOURCETYPE_MODULE_REQUIRED? Should we use SNAKE_CASE instead?
There was a problem hiding this comment.
Or maybe we could always set code to BABEL_PARSER_ERROR, and add a new property (like errorCode, or parserError) using these new codes we are introducing.
There was a problem hiding this comment.
I prefer a prefixed error code but don't have a strong opinion. The Node.js recommends error.code to be the identifier of the error. Conventionally they use SNAKE_CASE. I don't have strong opinion between camelCase and SNAKE_CASE, as long as we have consensus.
https://nodejs.org/api/errors.html#errors_error_code
I would like to maintain the same stability policy as Node.js: The error.code thrown from @babel/parser is considered stable: It will only be changed in a major release, but not for error.message which we will keep polishing between patches/minors.
There was a problem hiding this comment.
Yeah but I wonder how useful these specific error messages are.
Except for a few (and they already have specific codes), I think often I would want do do something like this:
try {
somethingThatCallsBabel();
} catch (e) {
if (e.code === "BABEL_PARSER_ERROR") {
console.warn("The file contains invalid syntax!");
} else if (e.code === "BABEL_PARSER_MISSING_PLUGIN") {
console.warn("You might want to enable a parser plugin!");
} else if (e.code === "BABEL_PARSER_SOURCETYPE_MODULE_REQUIRED") {
console.warn("You are parsing a module as a script!");
} else if (e.code === "ENOENT") {
console.warn("You are trying to parse a non-existing file!");
} else {
throw e;
}
}Imho the specific syntax error is a detail at a deeper leverl.
I would like to maintain the same stability policy as Node.js: The
error.codethrown from@babel/parseris considered stable
+1
There was a problem hiding this comment.
The new example looks good to me. In that case we may consider place current detailed error code to syntaxError or reasonCode.
I think BABEL_PARSER_ERROR is too general, maybe BABEL_PARSER_INVALID_SYNTAX or BABEL_PARSER_SYNTAX_ERROR?
There was a problem hiding this comment.
Yeah I like that (I don't have a preference about the exact names).
There was a problem hiding this comment.
I would like to maintain the same stability policy as Node.js: The error.code thrown from @babel/parser is considered stable
👍
To summarize, the interface will look like this?:
{
code: "BABEL_PARSER_SYNTAX_ERROR",
reasonCode: "ArgumentsInClass",
message: "'arguments' is only allowed in functions and class methods"
}Dismissing my approval for now, since there will be more changes.
|
Also, |
9413b1f to
59f07f7
Compare
|
Wow this PR is getting huge! 🚀😂 Could you also run |
9828d62 to
2a737a1
Compare
|
Maybe we could add a new test file (
|
| } | ||
| } | ||
| return this._raise({ loc, pos }, message); | ||
| return this._raise({ code, loc, pos }, message); |
There was a problem hiding this comment.
It'd be good to add params as a property.
Use case: in Prettier, Unexpected reserved word 'yield' should be suppressed, Unexpected reserved word 'for' should be rethrown. prettier/prettier#10603
There was a problem hiding this comment.
I'd prefer to split the error between UnexpectedKeyword and UnexpectedContextualKeyword if that works too, and avoid exposing too much internal details about how we build errors.
There was a problem hiding this comment.
Yes, that's a better solution for that use case.
There was a problem hiding this comment.
@thorn0 I was going to implement this, but I noticed that we already have two different errors:
UnexpectedKeywordfor things likefor,if,while, ...UnexpectedReservedWordfor things likeyield,await,enum, ...
2a737a1 to
f07223d
Compare
I added simple tests! f07223d |
nicolo-ribaudo
left a comment
There was a problem hiding this comment.
Thanks!
I'll merge this to a feature branch (since we don't merge "New feature" PRs until we are ready for a minor version), so that you or someone else can work on #13033 (comment) on top of this one.
If you have an idea for better interface, please comment!