Skip to content

Commit

Permalink
Throw errors for invalid TSEmptyBodyFunctionExpression node (#12982)
Browse files Browse the repository at this point in the history
  • Loading branch information
fisker committed Jun 14, 2022
1 parent 1bec824 commit d2bcaea
Show file tree
Hide file tree
Showing 6 changed files with 195 additions and 10 deletions.
15 changes: 15 additions & 0 deletions changelog_unreleased/typescript/12982.md
@@ -0,0 +1,15 @@
#### Stop parsing invalid code (#12982 by @fisker)

<!-- prettier-ignore -->
```tsx
// Input
const object = ({ methodName() });

// Prettier stable
const object = { methodName(); };

// Prettier main
SyntaxError: Unexpected token. (1:29)
> 1 | const object = ({ methodName() });
| ^^
```
15 changes: 15 additions & 0 deletions src/language-js/parse/postprocess/index.js
Expand Up @@ -6,6 +6,7 @@ const isTypeCastComment = require("../../utils/is-type-cast-comment.js");
const getLast = require("../../../utils/get-last.js");
const visitNode = require("./visit-node.js");
const { throwErrorForInvalidNodes } = require("./typescript.js");
const throwSyntaxError = require("./throw-syntax-error.js");

function postprocess(ast, options) {
if (
Expand Down Expand Up @@ -102,6 +103,20 @@ function postprocess(ast, options) {
};
}
break;
case "ObjectExpression":
// #12963
if (options.parser === "typescript") {
const invalidProperty = node.properties.find(
(property) =>
property.type === "Property" &&
property.value.type === "TSEmptyBodyFunctionExpression"
);
if (invalidProperty) {
throwSyntaxError(invalidProperty.value, "Unexpected token.");
}
}
break;

case "SequenceExpression": {
// Babel (unlike other parsers) includes spaces and comments in the range. Let's unify this.
const lastExpression = getLast(node.expressions);
Expand Down
12 changes: 12 additions & 0 deletions src/language-js/parse/postprocess/throw-syntax-error.js
@@ -0,0 +1,12 @@
"use strict";
const createError = require("../../../common/parser-create-error.js");

function throwSyntaxError(node, message) {
const { start, end } = node.loc;
throw createError(message, {
start: { line: start.line, column: start.column + 1 },
end: { line: end.line, column: end.column + 1 },
});
}

module.exports = throwSyntaxError;
11 changes: 2 additions & 9 deletions src/language-js/parse/postprocess/typescript.js
@@ -1,15 +1,7 @@
"use strict";

const createError = require("../../../common/parser-create-error.js");
const visitNode = require("./visit-node.js");

function throwSyntaxError(node, message) {
const { start, end } = node.loc;
throw createError(message, {
start: { line: start.line, column: start.column + 1 },
end: { line: end.line, column: end.column + 1 },
});
}
const throwSyntaxError = require("./throw-syntax-error.js");

// Invalid decorators are removed since `@typescript-eslint/typescript-estree` v4
// https://github.com/typescript-eslint/typescript-eslint/pull/2375
Expand Down Expand Up @@ -73,6 +65,7 @@ function throwErrorForInvalidNodes(ast, options) {
if (esTreeNode !== node) {
return;
}

throwErrorForInvalidDecorator(tsNode, esTreeNode, tsNodeToESTreeNodeMap);
throwErrorForInvalidAbstractProperty(tsNode, esTreeNode);
});
Expand Down
144 changes: 144 additions & 0 deletions tests/format/misc/errors/invalid/__snapshots__/jsfmt.spec.js.snap
Expand Up @@ -156,92 +156,236 @@ exports[`snippet: #1 [typescript] format 1`] = `
| ^"
`;
exports[`snippet: #2 [acorn] format 1`] = `
"Unexpected token (1:13)
> 1 | ({ method() })
| ^"
`;
exports[`snippet: #2 [babel] format 1`] = `
"Unexpected token, expected "{" (1:13)
> 1 | ({ method() })
| ^"
`;
exports[`snippet: #2 [babel] format 2`] = `
"Invalid parenthesized assignment pattern. (1:1)
> 1 | (a = 1) = 2
| ^"
`;
exports[`snippet: #2 [babel-flow] format 1`] = `
"Unexpected token, expected "{" (1:13)
> 1 | ({ method() })
| ^"
`;
exports[`snippet: #2 [babel-flow] format 2`] = `
"Invalid parenthesized assignment pattern. (1:1)
> 1 | (a = 1) = 2
| ^"
`;
exports[`snippet: #2 [babel-ts] format 1`] = `
"Unexpected token, expected "{" (1:13)
> 1 | ({ method() })
| ^"
`;
exports[`snippet: #2 [babel-ts] format 2`] = `
"Invalid parenthesized assignment pattern. (1:1)
> 1 | (a = 1) = 2
| ^"
`;
exports[`snippet: #2 [espree] format 1`] = `
"Unexpected token } (1:13)
> 1 | ({ method() })
| ^"
`;
exports[`snippet: #2 [flow] format 1`] = `
"Unexpected token \`}\`, expected the token \`{\` (1:13)
> 1 | ({ method() })
| ^"
`;
exports[`snippet: #2 [flow] format 2`] = `
"Invalid left-hand side in assignment (1:2)
> 1 | (a = 1) = 2
| ^^^^^"
`;
exports[`snippet: #2 [meriyah] format 1`] = `
"Expected '{' (1:13)
> 1 | ({ method() })
| ^"
`;
exports[`snippet: #2 [meriyah] format 2`] = `
"Invalid left-hand side in assignment (1:9)
> 1 | (a = 1) = 2
| ^"
`;
exports[`snippet: #2 [typescript] format 1`] = `
"Unexpected token. (1:10)
> 1 | ({ method() })
| ^^"
`;
exports[`snippet: #3 [acorn] format 1`] = `
"Unexpected token (1:15)
> 1 | ({ method({}) })
| ^"
`;
exports[`snippet: #3 [babel] format 1`] = `
"Unexpected token, expected "{" (1:15)
> 1 | ({ method({}) })
| ^"
`;
exports[`snippet: #3 [babel] format 2`] = `
"Invalid parenthesized assignment pattern. (1:1)
> 1 | (a += b) = 1
| ^"
`;
exports[`snippet: #3 [babel-flow] format 1`] = `
"Unexpected token, expected "{" (1:15)
> 1 | ({ method({}) })
| ^"
`;
exports[`snippet: #3 [babel-flow] format 2`] = `
"Invalid parenthesized assignment pattern. (1:1)
> 1 | (a += b) = 1
| ^"
`;
exports[`snippet: #3 [babel-ts] format 1`] = `
"Unexpected token, expected "{" (1:15)
> 1 | ({ method({}) })
| ^"
`;
exports[`snippet: #3 [babel-ts] format 2`] = `
"Invalid parenthesized assignment pattern. (1:1)
> 1 | (a += b) = 1
| ^"
`;
exports[`snippet: #3 [espree] format 1`] = `
"Unexpected token } (1:15)
> 1 | ({ method({}) })
| ^"
`;
exports[`snippet: #3 [flow] format 1`] = `
"Unexpected token \`}\`, expected the token \`{\` (1:15)
> 1 | ({ method({}) })
| ^"
`;
exports[`snippet: #3 [flow] format 2`] = `
"Invalid left-hand side in assignment (1:2)
> 1 | (a += b) = 1
| ^^^^^^"
`;
exports[`snippet: #3 [meriyah] format 1`] = `
"Expected '{' (1:15)
> 1 | ({ method({}) })
| ^"
`;
exports[`snippet: #3 [meriyah] format 2`] = `
"Invalid left-hand side in assignment (1:10)
> 1 | (a += b) = 1
| ^"
`;
exports[`snippet: #3 [typescript] format 1`] = `
"Unexpected token. (1:10)
> 1 | ({ method({}) })
| ^^^^"
`;
exports[`snippet: #4 [acorn] format 1`] = `
"Unexpected token (1:23)
> 1 | ({ method(parameter,) })
| ^"
`;
exports[`snippet: #4 [babel] format 1`] = `
"Unexpected token, expected "{" (1:23)
> 1 | ({ method(parameter,) })
| ^"
`;
exports[`snippet: #4 [babel] format 2`] = `
"Invalid left-hand side in parenthesized expression. (1:2)
> 1 | (a = b) += 1
| ^"
`;
exports[`snippet: #4 [babel-flow] format 1`] = `
"Unexpected token, expected "{" (1:23)
> 1 | ({ method(parameter,) })
| ^"
`;
exports[`snippet: #4 [babel-flow] format 2`] = `
"Invalid left-hand side in parenthesized expression. (1:2)
> 1 | (a = b) += 1
| ^"
`;
exports[`snippet: #4 [babel-ts] format 1`] = `
"Unexpected token, expected "{" (1:23)
> 1 | ({ method(parameter,) })
| ^"
`;
exports[`snippet: #4 [babel-ts] format 2`] = `
"Invalid left-hand side in parenthesized expression. (1:2)
> 1 | (a = b) += 1
| ^"
`;
exports[`snippet: #4 [espree] format 1`] = `
"Unexpected token } (1:23)
> 1 | ({ method(parameter,) })
| ^"
`;
exports[`snippet: #4 [flow] format 1`] = `
"Unexpected token \`}\`, expected the token \`{\` (1:23)
> 1 | ({ method(parameter,) })
| ^"
`;
exports[`snippet: #4 [flow] format 2`] = `
"Invalid left-hand side in assignment (1:2)
> 1 | (a = b) += 1
| ^^^^^"
`;
exports[`snippet: #4 [meriyah] format 1`] = `
"Expected '{' (1:23)
> 1 | ({ method(parameter,) })
| ^"
`;
exports[`snippet: #4 [meriyah] format 2`] = `
"Invalid left-hand side in assignment (1:10)
> 1 | (a = b) += 1
| ^"
`;
exports[`snippet: #4 [typescript] format 1`] = `
"Unexpected token. (1:10)
> 1 | ({ method(parameter,) })
| ^^^^^^^^^^^^"
`;
8 changes: 7 additions & 1 deletion tests/format/misc/errors/invalid/jsfmt.spec.js
@@ -1,7 +1,13 @@
run_spec(
{
dirname: __dirname,
snippets: ["for each (a in b) {}", "class switch() {}"],
snippets: [
"for each (a in b) {}",
"class switch() {}",
"({ method() })",
"({ method({}) })",
"({ method(parameter,) })",
],
},
[
"babel",
Expand Down

0 comments on commit d2bcaea

Please sign in to comment.