From 1d78576d41323e35c2d2a2ecc92f6ee76ed61d57 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Mon, 13 Mar 2023 08:50:14 +0800 Subject: [PATCH] feat(typescript-estree): throw errors for object methods without function bodies (#6589) --- .../_error_/missing-getter-body/fixture.ts | 1 + .../snapshots/1-TSESTree-Error.shot | 8 ++++ .../snapshots/2-Babel-Error.shot | 3 ++ .../snapshots/3-Alignment-Error.shot | 3 ++ .../_error_/missing-method-body/fixture.ts | 1 + .../snapshots/1-TSESTree-Error.shot | 8 ++++ .../snapshots/2-Babel-Error.shot | 3 ++ .../snapshots/3-Alignment-Error.shot | 3 ++ .../_error_/missing-setter-body/fixture.ts | 1 + .../snapshots/1-TSESTree-Error.shot | 8 ++++ .../snapshots/2-Babel-Error.shot | 3 ++ .../snapshots/3-Alignment-Error.shot | 3 ++ .../tests/rules/no-unsafe-assignment.test.ts | 2 +- .../prefer-readonly-parameter-types.test.ts | 4 +- packages/typescript-estree/src/convert.ts | 39 +++++++++++++++---- 15 files changed, 79 insertions(+), 11 deletions(-) create mode 100644 packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-getter-body/fixture.ts create mode 100644 packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-getter-body/snapshots/1-TSESTree-Error.shot create mode 100644 packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-getter-body/snapshots/2-Babel-Error.shot create mode 100644 packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-getter-body/snapshots/3-Alignment-Error.shot create mode 100644 packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-method-body/fixture.ts create mode 100644 packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-method-body/snapshots/1-TSESTree-Error.shot create mode 100644 packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-method-body/snapshots/2-Babel-Error.shot create mode 100644 packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-method-body/snapshots/3-Alignment-Error.shot create mode 100644 packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-setter-body/fixture.ts create mode 100644 packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-setter-body/snapshots/1-TSESTree-Error.shot create mode 100644 packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-setter-body/snapshots/2-Babel-Error.shot create mode 100644 packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-setter-body/snapshots/3-Alignment-Error.shot diff --git a/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-getter-body/fixture.ts b/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-getter-body/fixture.ts new file mode 100644 index 00000000000..876119b3990 --- /dev/null +++ b/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-getter-body/fixture.ts @@ -0,0 +1 @@ +({get foo();}) diff --git a/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-getter-body/snapshots/1-TSESTree-Error.shot b/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-getter-body/snapshots/1-TSESTree-Error.shot new file mode 100644 index 00000000000..16431b24f4d --- /dev/null +++ b/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-getter-body/snapshots/1-TSESTree-Error.shot @@ -0,0 +1,8 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AST Fixtures expression ObjectExpression _error_ missing-getter-body TSESTree - Error 1`] = ` +"TSError +> 1 | ({get foo();}) + | ^ '{' expected. + 2 |" +`; diff --git a/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-getter-body/snapshots/2-Babel-Error.shot b/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-getter-body/snapshots/2-Babel-Error.shot new file mode 100644 index 00000000000..71aabcc7954 --- /dev/null +++ b/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-getter-body/snapshots/2-Babel-Error.shot @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AST Fixtures expression ObjectExpression _error_ missing-getter-body Babel - Error 1`] = `[SyntaxError: Unexpected token, expected "{" (1:11)]`; diff --git a/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-getter-body/snapshots/3-Alignment-Error.shot b/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-getter-body/snapshots/3-Alignment-Error.shot new file mode 100644 index 00000000000..bc5201f9cee --- /dev/null +++ b/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-getter-body/snapshots/3-Alignment-Error.shot @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AST Fixtures expression ObjectExpression _error_ missing-getter-body Error Alignment 1`] = `"Both errored"`; diff --git a/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-method-body/fixture.ts b/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-method-body/fixture.ts new file mode 100644 index 00000000000..433743dbdf0 --- /dev/null +++ b/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-method-body/fixture.ts @@ -0,0 +1 @@ +({method();}) diff --git a/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-method-body/snapshots/1-TSESTree-Error.shot b/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-method-body/snapshots/1-TSESTree-Error.shot new file mode 100644 index 00000000000..d5072a95357 --- /dev/null +++ b/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-method-body/snapshots/1-TSESTree-Error.shot @@ -0,0 +1,8 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AST Fixtures expression ObjectExpression _error_ missing-method-body TSESTree - Error 1`] = ` +"TSError +> 1 | ({method();}) + | ^ '{' expected. + 2 |" +`; diff --git a/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-method-body/snapshots/2-Babel-Error.shot b/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-method-body/snapshots/2-Babel-Error.shot new file mode 100644 index 00000000000..83750d60313 --- /dev/null +++ b/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-method-body/snapshots/2-Babel-Error.shot @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AST Fixtures expression ObjectExpression _error_ missing-method-body Babel - Error 1`] = `[SyntaxError: Unexpected token, expected "{" (1:10)]`; diff --git a/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-method-body/snapshots/3-Alignment-Error.shot b/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-method-body/snapshots/3-Alignment-Error.shot new file mode 100644 index 00000000000..37626ca0238 --- /dev/null +++ b/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-method-body/snapshots/3-Alignment-Error.shot @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AST Fixtures expression ObjectExpression _error_ missing-method-body Error Alignment 1`] = `"Both errored"`; diff --git a/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-setter-body/fixture.ts b/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-setter-body/fixture.ts new file mode 100644 index 00000000000..7f9318e62fd --- /dev/null +++ b/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-setter-body/fixture.ts @@ -0,0 +1 @@ +({set foo(value);}) diff --git a/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-setter-body/snapshots/1-TSESTree-Error.shot b/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-setter-body/snapshots/1-TSESTree-Error.shot new file mode 100644 index 00000000000..b775e8717cb --- /dev/null +++ b/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-setter-body/snapshots/1-TSESTree-Error.shot @@ -0,0 +1,8 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AST Fixtures expression ObjectExpression _error_ missing-setter-body TSESTree - Error 1`] = ` +"TSError +> 1 | ({set foo(value);}) + | ^ '{' expected. + 2 |" +`; diff --git a/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-setter-body/snapshots/2-Babel-Error.shot b/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-setter-body/snapshots/2-Babel-Error.shot new file mode 100644 index 00000000000..340728334fd --- /dev/null +++ b/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-setter-body/snapshots/2-Babel-Error.shot @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AST Fixtures expression ObjectExpression _error_ missing-setter-body Babel - Error 1`] = `[SyntaxError: Unexpected token, expected "{" (1:16)]`; diff --git a/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-setter-body/snapshots/3-Alignment-Error.shot b/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-setter-body/snapshots/3-Alignment-Error.shot new file mode 100644 index 00000000000..21d1ea67346 --- /dev/null +++ b/packages/ast-spec/src/expression/ObjectExpression/fixtures/_error_/missing-setter-body/snapshots/3-Alignment-Error.shot @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AST Fixtures expression ObjectExpression _error_ missing-setter-body Error Alignment 1`] = `"Both errored"`; diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-assignment.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-assignment.test.ts index 8b08ec79ff9..f0d32d2ed47 100644 --- a/packages/eslint-plugin/tests/rules/no-unsafe-assignment.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unsafe-assignment.test.ts @@ -113,7 +113,7 @@ class Foo { 'const x = new Set();', 'const x = { y: 1 };', 'const x = { y = 1 };', - noFormat`const x = { y(); };`, + noFormat`const x = { y(){} };`, 'const x: { y: number } = { y: 1 };', 'const x = [...[1, 2, 3]];', 'const [{ [`x${1}`]: x }] = [{ [`x`]: 1 }] as [{ [`x`]: any }];', diff --git a/packages/eslint-plugin/tests/rules/prefer-readonly-parameter-types.test.ts b/packages/eslint-plugin/tests/rules/prefer-readonly-parameter-types.test.ts index 44919f60d79..649b4970050 100644 --- a/packages/eslint-plugin/tests/rules/prefer-readonly-parameter-types.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-readonly-parameter-types.test.ts @@ -290,7 +290,7 @@ ruleTester.run('prefer-readonly-parameter-types', rule, { new (arg: readonly string[]): void; } `, // TSConstructSignatureDeclaration - noFormat`const x = { foo(arg: readonly string[]): void; };`, // TSEmptyBodyFunctionExpression + noFormat`class Foo { foo(arg: readonly string[]): void; };`, // TSEmptyBodyFunctionExpression 'function foo(arg: readonly string[]);', // TSDeclareFunction 'type Foo = (arg: readonly string[]) => void;', // TSFunctionType ` @@ -667,7 +667,7 @@ ruleTester.run('prefer-readonly-parameter-types', rule, { }, { // TSEmptyBodyFunctionExpression - code: noFormat`const x = { foo(arg: string[]): void; };`, + code: noFormat`class Foo { foo(arg: string[]): void; };`, errors: [ { messageId: 'shouldBeReadonly', diff --git a/packages/typescript-estree/src/convert.ts b/packages/typescript-estree/src/convert.ts index 416171c2dbd..d9b05c86960 100644 --- a/packages/typescript-estree/src/convert.ts +++ b/packages/typescript-estree/src/convert.ts @@ -1029,12 +1029,26 @@ export class Converter { properties: node.properties.map(el => this.convertPattern(el)), typeAnnotation: undefined, }); - } else { - return this.createNode(node, { - type: AST_NODE_TYPES.ObjectExpression, - properties: node.properties.map(el => this.convertChild(el)), - }); } + + const properties: TSESTree.Property[] = []; + for (const property of node.properties) { + if ( + (property.kind === SyntaxKind.GetAccessor || + property.kind === SyntaxKind.SetAccessor || + property.kind === SyntaxKind.MethodDeclaration) && + !property.body + ) { + this.#throwUnlessAllowInvalidAST(property.end - 1, "'{' expected."); + } + + properties.push(this.convertChild(property) as TSESTree.Property); + } + + return this.createNode(node, { + type: AST_NODE_TYPES.ObjectExpression, + properties, + }); } case SyntaxKind.PropertyAssignment: { @@ -3077,7 +3091,7 @@ export class Converter { } #throwUnlessAllowInvalidAST( - node: ts.Node, + node: ts.Node | number, message: string, ): asserts node is never { if (!this.options.allowInvalidAST) { @@ -3085,7 +3099,16 @@ export class Converter { } } - #throwError(node: ts.Node, message: string): asserts node is never { - throw createError(message, this.ast, node.getStart(), node.getEnd()); + #throwError(node: ts.Node | number, message: string): asserts node is never { + let start; + let end; + if (typeof node === 'number') { + start = end = node; + } else { + start = node.getStart(this.ast); + end = node.getEnd(); + } + + throw createError(message, this.ast, start, end); } }