Skip to content

Commit

Permalink
Add internal ESLint rule for consistent parser error messages (#13130)
Browse files Browse the repository at this point in the history
  • Loading branch information
sosukesuzuki authored and JLHwung committed Apr 17, 2021
1 parent f950f8c commit b7f84ed
Show file tree
Hide file tree
Showing 1,398 changed files with 3,596 additions and 3,312 deletions.
1 change: 1 addition & 0 deletions .eslintrc.cjs
Expand Up @@ -109,6 +109,7 @@ module.exports = {
),
},
],
"@babel/development-internal/report-error-message-format": "error",
},
},
{
Expand Down
39 changes: 39 additions & 0 deletions eslint/babel-eslint-plugin-development-internal/README.md
Expand Up @@ -68,3 +68,42 @@ and
}
}
```

### `@babel/development-internal/report-error-message-format`

This rule is inspired by https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/blob/master/docs/rules/report-message-format.md.

Intended for use in `packages/babel-parser/src/**/*`. When enabled, this rule warns for inconsistently error messages format in arguments of `makeErrorTemplates` function calls.

Basically, it starts with an uppercase Latin letter(A~Z) and ends with a period(.) or a question(?). But it can start with `'keyword'` or `` `code` `` to include JavaScript keywords or code in error messages.

valid:

```js
makeErrorTemplates({ ThisIsAnError: "This is an error." });
makeErrorTemplates({ ThisIsAnError: "'this' is an error." });
makeErrorTemplates({ ThisIsAnError: "`this` is an error." });
makeErrorTemplates({ ThisIsAnError: "This is an error?" });
makeErrorTemplates({ ThisIsAnError: "'this' is an error?" });
makeErrorTemplates({ ThisIsAnError: "`this` is an error?" });
```

invalid:

```js
makeErrorTemplates({ ThisIsAnError: 'this is an error.' });
makeErrorTemplates({ ThisIsAnError: 'This is an error' });
makeErrorTemplates({ ThisIsAnError: 'this is an error?' });
makeErrorTemplates({ ThisIsAnError: '`this` is an error' });
makeErrorTemplates({ ThisIsAnError: "'this' is an error" });
```

Example configuration:

```js
{
rules: {
"@babel/development-internal/report-error-message-format": "error"
}
}
```
2 changes: 2 additions & 0 deletions eslint/babel-eslint-plugin-development-internal/src/index.js
@@ -1,7 +1,9 @@
import dryErrorMessages from "./rules/dry-error-messages";
import reportErrorMessageFormat from "./rules/report-error-message-format";

export const rules = {
"dry-error-messages": dryErrorMessages,
"report-error-message-format": reportErrorMessageFormat,
};

export default { rules };
@@ -0,0 +1,31 @@
const messageId = "mustMatchPattern";

const pattern = /(('.*')|(`.*`)|[A-Z]).*(\.|\?)$/s;

export default {
meta: {
type: "suggestion",
docs: {
description: "enforce @babel/parser's error message formatting.",
},
messages: {
[messageId]: `Report message does not match the pattern ${pattern.toString()}.`,
},
},
create({ report }) {
return {
"CallExpression[callee.type='Identifier'][callee.name='makeErrorTemplates'] > ObjectExpression > Property[value.type='Literal']"(
node,
) {
const { value } = node;
if (typeof value.value === "string" && pattern.test(value.value)) {
return;
}
report({
node: value,
messageId,
});
},
};
},
};
@@ -0,0 +1,44 @@
import RuleTester from "../../../babel-eslint-shared-fixtures/utils/RuleTester";
import rule from "../../src/rules/report-error-message-format";

const ruleTester = new RuleTester();

ruleTester.run("report-error-message-format", rule, {
valid: [
"makeErrorTemplates({});",
'makeErrorTemplates({ ThisIsAnError: "This is an error." });',
`makeErrorTemplates({ ThisIsAnError: "'this' is an error." });`,
`makeErrorTemplates({ ThisIsAnError: "\`this\` is an error." });`,
`makeErrorTemplates({ ThisIsAnError: "This is an error?" });`,
`makeErrorTemplates({ ThisIsAnError: "'this' is an error?" });`,
`makeErrorTemplates({ ThisIsAnError: "\`this\` is an error?" });`,
'makeErrorTemplates({ ThisIsAnError: "This is\\nan error." });',
`makeErrorTemplates({ ThisIsAnError: "'this' is\\nan error." });`,
`makeErrorTemplates({ ThisIsAnError: "\`this\` is\\nan error." });`,
`makeErrorTemplates({ ThisIsAnError: "This is\\nan error?" });`,
`makeErrorTemplates({ ThisIsAnError: "'this' is\\nan error?" });`,
`makeErrorTemplates({ ThisIsAnError: "\`this\` is\\nan error?" });`,
],
invalid: [
{
code: "makeErrorTemplates({ ThisIsAnError: 'this is an error.' });",
errors: [{ messageId: "mustMatchPattern" }],
},
{
code: "makeErrorTemplates({ ThisIsAnError: 'This is an error' });",
errors: [{ messageId: "mustMatchPattern" }],
},
{
code: "makeErrorTemplates({ ThisIsAnError: 'this is an error?' });",
errors: [{ messageId: "mustMatchPattern" }],
},
{
code: "makeErrorTemplates({ ThisIsAnError: '`this` is an error' });",
errors: [{ messageId: "mustMatchPattern" }],
},
{
code: `makeErrorTemplates({ ThisIsAnError: "'this' is an error" });`,
errors: [{ messageId: "mustMatchPattern" }],
},
],
});
@@ -1 +1 @@
SyntaxError: <CWD>\test.js: Missing semicolon (2:10)
SyntaxError: <CWD>\test.js: Missing semicolon. (2:10)
@@ -1 +1 @@
SyntaxError: <CWD>/test.js: Missing semicolon (2:10)
SyntaxError: <CWD>/test.js: Missing semicolon. (2:10)
@@ -1,3 +1,3 @@
{
"throws": "Missing semicolon (2:10)"
"throws": "Missing semicolon. (2:10)"
}

0 comments on commit b7f84ed

Please sign in to comment.