From ddb32d640da5aeaec4dc692aa41b0b5403c6c28e Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Thu, 22 Jun 2023 15:25:59 +0930 Subject: [PATCH 1/5] feat: treat unknown nodes as having the lowest precedence --- lib/rules/utils/ast-utils.js | 12 +- .../boolean-cast-with-assertion.js | 333 ++++++++++++++++ .../exponentiation-with-assertion.js | 322 +++++++++++++++ .../logical-assignment-with-assertion.js | 209 ++++++++++ .../member-call-expr-with-assertion.js | 366 ++++++++++++++++++ .../typescript-parsers/unneeded-ternary-1.js | 239 ++++++++++++ .../typescript-parsers/unneeded-ternary-2.js | 240 ++++++++++++ .../lib/rules/logical-assignment-operators.js | 15 +- tests/lib/rules/no-extra-boolean-cast.js | 13 +- tests/lib/rules/no-extra-parens.js | 9 +- tests/lib/rules/no-unneeded-ternary.js | 26 +- .../rules/prefer-exponentiation-operator.js | 16 +- 12 files changed, 1793 insertions(+), 7 deletions(-) create mode 100644 tests/fixtures/parsers/typescript-parsers/boolean-cast-with-assertion.js create mode 100644 tests/fixtures/parsers/typescript-parsers/exponentiation-with-assertion.js create mode 100644 tests/fixtures/parsers/typescript-parsers/logical-assignment-with-assertion.js create mode 100644 tests/fixtures/parsers/typescript-parsers/member-call-expr-with-assertion.js create mode 100644 tests/fixtures/parsers/typescript-parsers/unneeded-ternary-1.js create mode 100644 tests/fixtures/parsers/typescript-parsers/unneeded-ternary-2.js diff --git a/lib/rules/utils/ast-utils.js b/lib/rules/utils/ast-utils.js index aed2c42f9a3..39e53b1057d 100644 --- a/lib/rules/utils/ast-utils.js +++ b/lib/rules/utils/ast-utils.js @@ -9,6 +9,7 @@ // Requirements //------------------------------------------------------------------------------ +const { KEYS: eslintVisitorKeys } = require("eslint-visitor-keys"); const esutils = require("esutils"); const espree = require("espree"); const escapeRegExp = require("escape-string-regexp"); @@ -1461,7 +1462,16 @@ module.exports = { return 19; default: - return 20; + if (node.type in eslintVisitorKeys) { + return 20; + } + + /* + * if the node is not a standard node that we know about, then assume it has the lowest precedence + * this will mean that rules will wrap unknown nodes in parentheses where applicable instead of + * unwrapping them and potentially changing the meaning of the code or introducing a syntax error. + */ + return -1; } }, diff --git a/tests/fixtures/parsers/typescript-parsers/boolean-cast-with-assertion.js b/tests/fixtures/parsers/typescript-parsers/boolean-cast-with-assertion.js new file mode 100644 index 00000000000..b58ace5c008 --- /dev/null +++ b/tests/fixtures/parsers/typescript-parsers/boolean-cast-with-assertion.js @@ -0,0 +1,333 @@ +"use strict"; + +/** + * Parser: @typescript-eslint/parser 5.59.11 (TS 5.1.3) + * Source code: + * if (!Boolean(a as any)) {} + */ + +exports.parse = () => ({ + type: "Program", + body: [ + { + type: "IfStatement", + test: { + type: "UnaryExpression", + operator: "!", + prefix: true, + argument: { + type: "CallExpression", + callee: { + type: "Identifier", + decorators: [], + name: "Boolean", + optional: false, + range: [5, 12], + loc: { + start: { + line: 1, + column: 5, + }, + end: { + line: 1, + column: 12, + }, + }, + }, + arguments: [ + { + type: "TSAsExpression", + expression: { + type: "Identifier", + decorators: [], + name: "a", + optional: false, + range: [13, 14], + loc: { + start: { + line: 1, + column: 13, + }, + end: { + line: 1, + column: 14, + }, + }, + }, + typeAnnotation: { + type: "TSAnyKeyword", + range: [18, 21], + loc: { + start: { + line: 1, + column: 18, + }, + end: { + line: 1, + column: 21, + }, + }, + }, + range: [13, 21], + loc: { + start: { + line: 1, + column: 13, + }, + end: { + line: 1, + column: 21, + }, + }, + }, + ], + optional: false, + range: [5, 22], + loc: { + start: { + line: 1, + column: 5, + }, + end: { + line: 1, + column: 22, + }, + }, + }, + range: [4, 22], + loc: { + start: { + line: 1, + column: 4, + }, + end: { + line: 1, + column: 22, + }, + }, + }, + consequent: { + type: "BlockStatement", + body: [], + range: [24, 27], + loc: { + start: { + line: 1, + column: 24, + }, + end: { + line: 1, + column: 27, + }, + }, + }, + alternate: null, + range: [0, 27], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 27, + }, + }, + }, + ], + comments: [], + range: [0, 28], + sourceType: "script", + tokens: [ + { + type: "Keyword", + value: "if", + range: [0, 2], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 2, + }, + }, + }, + { + type: "Punctuator", + value: "(", + range: [3, 4], + loc: { + start: { + line: 1, + column: 3, + }, + end: { + line: 1, + column: 4, + }, + }, + }, + { + type: "Punctuator", + value: "!", + range: [4, 5], + loc: { + start: { + line: 1, + column: 4, + }, + end: { + line: 1, + column: 5, + }, + }, + }, + { + type: "Identifier", + value: "Boolean", + range: [5, 12], + loc: { + start: { + line: 1, + column: 5, + }, + end: { + line: 1, + column: 12, + }, + }, + }, + { + type: "Punctuator", + value: "(", + range: [12, 13], + loc: { + start: { + line: 1, + column: 12, + }, + end: { + line: 1, + column: 13, + }, + }, + }, + { + type: "Identifier", + value: "a", + range: [13, 14], + loc: { + start: { + line: 1, + column: 13, + }, + end: { + line: 1, + column: 14, + }, + }, + }, + { + type: "Identifier", + value: "as", + range: [15, 17], + loc: { + start: { + line: 1, + column: 15, + }, + end: { + line: 1, + column: 17, + }, + }, + }, + { + type: "Identifier", + value: "any", + range: [18, 21], + loc: { + start: { + line: 1, + column: 18, + }, + end: { + line: 1, + column: 21, + }, + }, + }, + { + type: "Punctuator", + value: ")", + range: [21, 22], + loc: { + start: { + line: 1, + column: 21, + }, + end: { + line: 1, + column: 22, + }, + }, + }, + { + type: "Punctuator", + value: ")", + range: [22, 23], + loc: { + start: { + line: 1, + column: 22, + }, + end: { + line: 1, + column: 23, + }, + }, + }, + { + type: "Punctuator", + value: "{", + range: [24, 25], + loc: { + start: { + line: 1, + column: 24, + }, + end: { + line: 1, + column: 25, + }, + }, + }, + { + type: "Punctuator", + value: "}", + range: [26, 27], + loc: { + start: { + line: 1, + column: 26, + }, + end: { + line: 1, + column: 27, + }, + }, + }, + ], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 2, + column: 0, + }, + }, +}); diff --git a/tests/fixtures/parsers/typescript-parsers/exponentiation-with-assertion.js b/tests/fixtures/parsers/typescript-parsers/exponentiation-with-assertion.js new file mode 100644 index 00000000000..713c40864f2 --- /dev/null +++ b/tests/fixtures/parsers/typescript-parsers/exponentiation-with-assertion.js @@ -0,0 +1,322 @@ +"use strict"; + +/** + * Parser: @typescript-eslint/parser 5.59.11 (TS 5.1.3) + * Source code: + * Math.pow(a, b as any) + */ + +exports.parse = () => ({ + type: "Program", + body: [ + { + type: "ExpressionStatement", + expression: { + type: "CallExpression", + callee: { + type: "MemberExpression", + object: { + type: "Identifier", + decorators: [], + name: "Math", + optional: false, + range: [0, 4], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 4, + }, + }, + }, + property: { + type: "Identifier", + decorators: [], + name: "pow", + optional: false, + range: [5, 8], + loc: { + start: { + line: 1, + column: 5, + }, + end: { + line: 1, + column: 8, + }, + }, + }, + computed: false, + optional: false, + range: [0, 8], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 8, + }, + }, + }, + arguments: [ + { + type: "Identifier", + decorators: [], + name: "a", + optional: false, + range: [9, 10], + loc: { + start: { + line: 1, + column: 9, + }, + end: { + line: 1, + column: 10, + }, + }, + }, + { + type: "TSAsExpression", + expression: { + type: "Identifier", + decorators: [], + name: "b", + optional: false, + range: [12, 13], + loc: { + start: { + line: 1, + column: 12, + }, + end: { + line: 1, + column: 13, + }, + }, + }, + typeAnnotation: { + type: "TSAnyKeyword", + range: [17, 20], + loc: { + start: { + line: 1, + column: 17, + }, + end: { + line: 1, + column: 20, + }, + }, + }, + range: [12, 20], + loc: { + start: { + line: 1, + column: 12, + }, + end: { + line: 1, + column: 20, + }, + }, + }, + ], + optional: false, + range: [0, 21], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 21, + }, + }, + }, + range: [0, 21], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 21, + }, + }, + }, + ], + comments: [], + range: [0, 21], + sourceType: "script", + tokens: [ + { + type: "Identifier", + value: "Math", + range: [0, 4], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 4, + }, + }, + }, + { + type: "Punctuator", + value: ".", + range: [4, 5], + loc: { + start: { + line: 1, + column: 4, + }, + end: { + line: 1, + column: 5, + }, + }, + }, + { + type: "Identifier", + value: "pow", + range: [5, 8], + loc: { + start: { + line: 1, + column: 5, + }, + end: { + line: 1, + column: 8, + }, + }, + }, + { + type: "Punctuator", + value: "(", + range: [8, 9], + loc: { + start: { + line: 1, + column: 8, + }, + end: { + line: 1, + column: 9, + }, + }, + }, + { + type: "Identifier", + value: "a", + range: [9, 10], + loc: { + start: { + line: 1, + column: 9, + }, + end: { + line: 1, + column: 10, + }, + }, + }, + { + type: "Punctuator", + value: ",", + range: [10, 11], + loc: { + start: { + line: 1, + column: 10, + }, + end: { + line: 1, + column: 11, + }, + }, + }, + { + type: "Identifier", + value: "b", + range: [12, 13], + loc: { + start: { + line: 1, + column: 12, + }, + end: { + line: 1, + column: 13, + }, + }, + }, + { + type: "Identifier", + value: "as", + range: [14, 16], + loc: { + start: { + line: 1, + column: 14, + }, + end: { + line: 1, + column: 16, + }, + }, + }, + { + type: "Identifier", + value: "any", + range: [17, 20], + loc: { + start: { + line: 1, + column: 17, + }, + end: { + line: 1, + column: 20, + }, + }, + }, + { + type: "Punctuator", + value: ")", + range: [20, 21], + loc: { + start: { + line: 1, + column: 20, + }, + end: { + line: 1, + column: 21, + }, + }, + }, + ], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 21, + }, + }, + parent: null, +}); diff --git a/tests/fixtures/parsers/typescript-parsers/logical-assignment-with-assertion.js b/tests/fixtures/parsers/typescript-parsers/logical-assignment-with-assertion.js new file mode 100644 index 00000000000..27337cf1982 --- /dev/null +++ b/tests/fixtures/parsers/typescript-parsers/logical-assignment-with-assertion.js @@ -0,0 +1,209 @@ +"use strict"; + +/** + * Parser: @typescript-eslint/parser 5.59.11 (TS 5.1.3) + * Source code: + * a ||= (b as number); + */ + +exports.parse = () => ({ + type: "Program", + body: [ + { + type: "ExpressionStatement", + expression: { + type: "AssignmentExpression", + operator: "||=", + left: { + type: "Identifier", + decorators: [], + name: "a", + optional: false, + range: [0, 1], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 1, + }, + }, + }, + right: { + type: "TSAsExpression", + expression: { + type: "Identifier", + decorators: [], + name: "b", + optional: false, + range: [6, 7], + loc: { + start: { + line: 1, + column: 6, + }, + end: { + line: 1, + column: 7, + }, + }, + }, + typeAnnotation: { + type: "TSNumberKeyword", + range: [11, 17], + loc: { + start: { + line: 1, + column: 11, + }, + end: { + line: 1, + column: 17, + }, + }, + }, + range: [6, 17], + loc: { + start: { + line: 1, + column: 6, + }, + end: { + line: 1, + column: 17, + }, + }, + }, + range: [0, 17], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 17, + }, + }, + }, + range: [0, 18], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 18, + }, + }, + }, + ], + comments: [], + range: [0, 19], + sourceType: "script", + tokens: [ + { + type: "Identifier", + value: "a", + range: [0, 1], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 1, + }, + }, + }, + { + type: "Punctuator", + value: "||=", + range: [2, 5], + loc: { + start: { + line: 1, + column: 2, + }, + end: { + line: 1, + column: 5, + }, + }, + }, + { + type: "Identifier", + value: "b", + range: [6, 7], + loc: { + start: { + line: 1, + column: 6, + }, + end: { + line: 1, + column: 7, + }, + }, + }, + { + type: "Identifier", + value: "as", + range: [8, 10], + loc: { + start: { + line: 1, + column: 8, + }, + end: { + line: 1, + column: 10, + }, + }, + }, + { + type: "Identifier", + value: "number", + range: [11, 17], + loc: { + start: { + line: 1, + column: 11, + }, + end: { + line: 1, + column: 17, + }, + }, + }, + { + type: "Punctuator", + value: ";", + range: [17, 18], + loc: { + start: { + line: 1, + column: 17, + }, + end: { + line: 1, + column: 18, + }, + }, + }, + ], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 2, + column: 0, + }, + }, +}); diff --git a/tests/fixtures/parsers/typescript-parsers/member-call-expr-with-assertion.js b/tests/fixtures/parsers/typescript-parsers/member-call-expr-with-assertion.js new file mode 100644 index 00000000000..14f679d2f79 --- /dev/null +++ b/tests/fixtures/parsers/typescript-parsers/member-call-expr-with-assertion.js @@ -0,0 +1,366 @@ +"use strict"; + +/** + * Parser: @typescript-eslint/parser 5.59.11 (TS 5.1.3) + * Source code: + * const x = (1 satisfies number).toFixed(); + */ + +exports.parse = () => ({ + type: "Program", + body: [ + { + type: "VariableDeclaration", + declarations: [ + { + type: "VariableDeclarator", + definite: false, + id: { + type: "Identifier", + decorators: [], + name: "x", + optional: false, + range: [6, 7], + loc: { + start: { + line: 1, + column: 6, + }, + end: { + line: 1, + column: 7, + }, + }, + }, + init: { + type: "CallExpression", + callee: { + type: "MemberExpression", + object: { + type: "TSSatisfiesExpression", + expression: { + type: "Literal", + value: 1, + raw: "1", + range: [11, 12], + loc: { + start: { + line: 1, + column: 11, + }, + end: { + line: 1, + column: 12, + }, + }, + }, + typeAnnotation: { + type: "TSNumberKeyword", + range: [23, 29], + loc: { + start: { + line: 1, + column: 23, + }, + end: { + line: 1, + column: 29, + }, + }, + }, + range: [11, 29], + loc: { + start: { + line: 1, + column: 11, + }, + end: { + line: 1, + column: 29, + }, + }, + }, + property: { + type: "Identifier", + decorators: [], + name: "toFixed", + optional: false, + range: [31, 38], + loc: { + start: { + line: 1, + column: 31, + }, + end: { + line: 1, + column: 38, + }, + }, + }, + computed: false, + optional: false, + range: [10, 38], + loc: { + start: { + line: 1, + column: 10, + }, + end: { + line: 1, + column: 38, + }, + }, + }, + arguments: [], + optional: false, + range: [10, 40], + loc: { + start: { + line: 1, + column: 10, + }, + end: { + line: 1, + column: 40, + }, + }, + }, + range: [6, 40], + loc: { + start: { + line: 1, + column: 6, + }, + end: { + line: 1, + column: 40, + }, + }, + }, + ], + declare: false, + kind: "const", + range: [0, 41], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 41, + }, + }, + }, + ], + comments: [], + range: [0, 42], + sourceType: "script", + tokens: [ + { + type: "Keyword", + value: "const", + range: [0, 5], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 5, + }, + }, + }, + { + type: "Identifier", + value: "x", + range: [6, 7], + loc: { + start: { + line: 1, + column: 6, + }, + end: { + line: 1, + column: 7, + }, + }, + }, + { + type: "Punctuator", + value: "=", + range: [8, 9], + loc: { + start: { + line: 1, + column: 8, + }, + end: { + line: 1, + column: 9, + }, + }, + }, + { + type: "Punctuator", + value: "(", + range: [10, 11], + loc: { + start: { + line: 1, + column: 10, + }, + end: { + line: 1, + column: 11, + }, + }, + }, + { + type: "Numeric", + value: "1", + range: [11, 12], + loc: { + start: { + line: 1, + column: 11, + }, + end: { + line: 1, + column: 12, + }, + }, + }, + { + type: "Identifier", + value: "satisfies", + range: [13, 22], + loc: { + start: { + line: 1, + column: 13, + }, + end: { + line: 1, + column: 22, + }, + }, + }, + { + type: "Identifier", + value: "number", + range: [23, 29], + loc: { + start: { + line: 1, + column: 23, + }, + end: { + line: 1, + column: 29, + }, + }, + }, + { + type: "Punctuator", + value: ")", + range: [29, 30], + loc: { + start: { + line: 1, + column: 29, + }, + end: { + line: 1, + column: 30, + }, + }, + }, + { + type: "Punctuator", + value: ".", + range: [30, 31], + loc: { + start: { + line: 1, + column: 30, + }, + end: { + line: 1, + column: 31, + }, + }, + }, + { + type: "Identifier", + value: "toFixed", + range: [31, 38], + loc: { + start: { + line: 1, + column: 31, + }, + end: { + line: 1, + column: 38, + }, + }, + }, + { + type: "Punctuator", + value: "(", + range: [38, 39], + loc: { + start: { + line: 1, + column: 38, + }, + end: { + line: 1, + column: 39, + }, + }, + }, + { + type: "Punctuator", + value: ")", + range: [39, 40], + loc: { + start: { + line: 1, + column: 39, + }, + end: { + line: 1, + column: 40, + }, + }, + }, + { + type: "Punctuator", + value: ";", + range: [40, 41], + loc: { + start: { + line: 1, + column: 40, + }, + end: { + line: 1, + column: 41, + }, + }, + }, + ], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 2, + column: 0, + }, + }, +}); diff --git a/tests/fixtures/parsers/typescript-parsers/unneeded-ternary-1.js b/tests/fixtures/parsers/typescript-parsers/unneeded-ternary-1.js new file mode 100644 index 00000000000..cfeb1ce7a76 --- /dev/null +++ b/tests/fixtures/parsers/typescript-parsers/unneeded-ternary-1.js @@ -0,0 +1,239 @@ +"use strict"; + +/** + * Parser: @typescript-eslint/parser 5.59.11 (TS 5.1.3) + * Source code: + * foo as any ? false : true + */ + +exports.parse = () => ({ + type: "Program", + body: [ + { + type: "ExpressionStatement", + expression: { + type: "ConditionalExpression", + test: { + type: "TSAsExpression", + expression: { + type: "Identifier", + decorators: [], + name: "foo", + optional: false, + range: [0, 3], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 3, + }, + }, + }, + typeAnnotation: { + type: "TSAnyKeyword", + range: [7, 10], + loc: { + start: { + line: 1, + column: 7, + }, + end: { + line: 1, + column: 10, + }, + }, + }, + range: [0, 10], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 10, + }, + }, + }, + consequent: { + type: "Literal", + value: false, + raw: "false", + range: [13, 18], + loc: { + start: { + line: 1, + column: 13, + }, + end: { + line: 1, + column: 18, + }, + }, + }, + alternate: { + type: "Literal", + value: true, + raw: "true", + range: [21, 25], + loc: { + start: { + line: 1, + column: 21, + }, + end: { + line: 1, + column: 25, + }, + }, + }, + range: [0, 25], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 25, + }, + }, + }, + range: [0, 25], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 25, + }, + }, + }, + ], + comments: [], + range: [0, 25], + sourceType: "script", + tokens: [ + { + type: "Identifier", + value: "foo", + range: [0, 3], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 3, + }, + }, + }, + { + type: "Identifier", + value: "as", + range: [4, 6], + loc: { + start: { + line: 1, + column: 4, + }, + end: { + line: 1, + column: 6, + }, + }, + }, + { + type: "Identifier", + value: "any", + range: [7, 10], + loc: { + start: { + line: 1, + column: 7, + }, + end: { + line: 1, + column: 10, + }, + }, + }, + { + type: "Punctuator", + value: "?", + range: [11, 12], + loc: { + start: { + line: 1, + column: 11, + }, + end: { + line: 1, + column: 12, + }, + }, + }, + { + type: "Boolean", + value: "false", + range: [13, 18], + loc: { + start: { + line: 1, + column: 13, + }, + end: { + line: 1, + column: 18, + }, + }, + }, + { + type: "Punctuator", + value: ":", + range: [19, 20], + loc: { + start: { + line: 1, + column: 19, + }, + end: { + line: 1, + column: 20, + }, + }, + }, + { + type: "Boolean", + value: "true", + range: [21, 25], + loc: { + start: { + line: 1, + column: 21, + }, + end: { + line: 1, + column: 25, + }, + }, + }, + ], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 25, + }, + }, + parent: null, +}); diff --git a/tests/fixtures/parsers/typescript-parsers/unneeded-ternary-2.js b/tests/fixtures/parsers/typescript-parsers/unneeded-ternary-2.js new file mode 100644 index 00000000000..eaac150cf1a --- /dev/null +++ b/tests/fixtures/parsers/typescript-parsers/unneeded-ternary-2.js @@ -0,0 +1,240 @@ +"use strict"; + +/** + * Parser: @typescript-eslint/parser 5.59.11 (TS 5.1.3) + * Source code: + * foo ? foo : bar as any + */ + +exports.parse = () => ({ + type: "Program", + body: [ + { + type: "ExpressionStatement", + expression: { + type: "ConditionalExpression", + test: { + type: "Identifier", + decorators: [], + name: "foo", + optional: false, + range: [0, 3], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 3, + }, + }, + }, + consequent: { + type: "Identifier", + decorators: [], + name: "foo", + optional: false, + range: [6, 9], + loc: { + start: { + line: 1, + column: 6, + }, + end: { + line: 1, + column: 9, + }, + }, + }, + alternate: { + type: "TSAsExpression", + expression: { + type: "Identifier", + decorators: [], + name: "bar", + optional: false, + range: [12, 15], + loc: { + start: { + line: 1, + column: 12, + }, + end: { + line: 1, + column: 15, + }, + }, + }, + typeAnnotation: { + type: "TSAnyKeyword", + range: [19, 22], + loc: { + start: { + line: 1, + column: 19, + }, + end: { + line: 1, + column: 22, + }, + }, + }, + range: [12, 22], + loc: { + start: { + line: 1, + column: 12, + }, + end: { + line: 1, + column: 22, + }, + }, + }, + range: [0, 22], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 22, + }, + }, + }, + range: [0, 22], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 22, + }, + }, + }, + ], + comments: [], + range: [0, 22], + sourceType: "script", + tokens: [ + { + type: "Identifier", + value: "foo", + range: [0, 3], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 3, + }, + }, + }, + { + type: "Punctuator", + value: "?", + range: [4, 5], + loc: { + start: { + line: 1, + column: 4, + }, + end: { + line: 1, + column: 5, + }, + }, + }, + { + type: "Identifier", + value: "foo", + range: [6, 9], + loc: { + start: { + line: 1, + column: 6, + }, + end: { + line: 1, + column: 9, + }, + }, + }, + { + type: "Punctuator", + value: ":", + range: [10, 11], + loc: { + start: { + line: 1, + column: 10, + }, + end: { + line: 1, + column: 11, + }, + }, + }, + { + type: "Identifier", + value: "bar", + range: [12, 15], + loc: { + start: { + line: 1, + column: 12, + }, + end: { + line: 1, + column: 15, + }, + }, + }, + { + type: "Identifier", + value: "as", + range: [16, 18], + loc: { + start: { + line: 1, + column: 16, + }, + end: { + line: 1, + column: 18, + }, + }, + }, + { + type: "Identifier", + value: "any", + range: [19, 22], + loc: { + start: { + line: 1, + column: 19, + }, + end: { + line: 1, + column: 22, + }, + }, + }, + ], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 22, + }, + }, +}); diff --git a/tests/lib/rules/logical-assignment-operators.js b/tests/lib/rules/logical-assignment-operators.js index ba839b5c6a8..ddf7ef1649d 100644 --- a/tests/lib/rules/logical-assignment-operators.js +++ b/tests/lib/rules/logical-assignment-operators.js @@ -9,7 +9,8 @@ //------------------------------------------------------------------------------ const rule = require("../../../lib/rules/logical-assignment-operators"), - { RuleTester } = require("../../../lib/rule-tester"); + { RuleTester } = require("../../../lib/rule-tester"), + parser = require("../../fixtures/fixture-parser"); //------------------------------------------------------------------------------ // Tests @@ -1456,5 +1457,15 @@ ruleTester.run("logical-assignment-operators", rule, { output: "a = a ?? b + c", options: ["never"], errors: [{ messageId: "unexpected", type: "AssignmentExpression", data: { operator: "??=" } }] - }] + }, + + // https://github.com/eslint/eslint/issues/17173 + { + code: "a ||= b as number;", + output: "a = a || (b as number);", + options: ["never"], + parser: parser("typescript-parsers/logical-assignment-with-assertion"), + errors: [{ messageId: "unexpected", type: "AssignmentExpression", data: { operator: "||=" } }] + } + ] }); diff --git a/tests/lib/rules/no-extra-boolean-cast.js b/tests/lib/rules/no-extra-boolean-cast.js index 8aecb4ca37f..69f34faaf76 100644 --- a/tests/lib/rules/no-extra-boolean-cast.js +++ b/tests/lib/rules/no-extra-boolean-cast.js @@ -10,7 +10,8 @@ //------------------------------------------------------------------------------ const rule = require("../../../lib/rules/no-extra-boolean-cast"), - { RuleTester } = require("../../../lib/rule-tester"); + { RuleTester } = require("../../../lib/rule-tester"), + parser = require("../../fixtures/fixture-parser"); //------------------------------------------------------------------------------ // Tests @@ -2423,6 +2424,16 @@ ruleTester.run("no-extra-boolean-cast", rule, { options: [{ enforceForLogicalOperands: true }], parserOptions: { ecmaVersion: 2020 }, errors: [{ messageId: "unexpectedCall" }] + }, + + // https://github.com/eslint/eslint/issues/17173 + { + code: "if (!Boolean(a as any)) {}", + output: "if (!(a as any)) {}", + options: [{ enforceForLogicalOperands: true }], + parser: parser("typescript-parsers/boolean-cast-with-assertion"), + parserOptions: { ecmaVersion: 2020 }, + errors: [{ messageId: "unexpectedCall" }] } ] }); diff --git a/tests/lib/rules/no-extra-parens.js b/tests/lib/rules/no-extra-parens.js index 71e1e2e9845..ca1c530c787 100644 --- a/tests/lib/rules/no-extra-parens.js +++ b/tests/lib/rules/no-extra-parens.js @@ -10,7 +10,8 @@ //------------------------------------------------------------------------------ const rule = require("../../../lib/rules/no-extra-parens"), - { RuleTester } = require("../../../lib/rule-tester"); + { RuleTester } = require("../../../lib/rule-tester"), + parser = require("../../fixtures/fixture-parser"); //------------------------------------------------------------------------------ // Helpers @@ -783,6 +784,12 @@ ruleTester.run("no-extra-parens", rule, { { code: "((a)) = function () {};", options: ["functions"] + }, + + // https://github.com/eslint/eslint/issues/17173 + { + code: "const x = (1 satisfies number).toFixed();", + parser: parser("typescript-parsers/keyword-with-arrow-function") } ], diff --git a/tests/lib/rules/no-unneeded-ternary.js b/tests/lib/rules/no-unneeded-ternary.js index 7ad11d2b2e5..3714e70bec8 100644 --- a/tests/lib/rules/no-unneeded-ternary.js +++ b/tests/lib/rules/no-unneeded-ternary.js @@ -10,7 +10,8 @@ //------------------------------------------------------------------------------ const rule = require("../../../lib/rules/no-unneeded-ternary"), - { RuleTester } = require("../../../lib/rule-tester"); + { RuleTester } = require("../../../lib/rule-tester"), + parser = require("../../fixtures/fixture-parser"); //------------------------------------------------------------------------------ // Tests @@ -427,6 +428,29 @@ ruleTester.run("no-unneeded-ternary", rule, { endLine: 1, endColumn: 27 }] + }, + + // https://github.com/eslint/eslint/issues/17173 + { + code: "foo as any ? false : true", + output: "!(foo as any)", + parser: parser("typescript-parsers/unneeded-ternary-1"), + parserOptions: { ecmaVersion: 6 }, + errors: [{ + messageId: "unnecessaryConditionalExpression", + type: "ConditionalExpression" + }] + }, + { + code: "foo ? foo : bar as any", + output: "foo || (bar as any)", + options: [{ defaultAssignment: false }], + parser: parser("typescript-parsers/unneeded-ternary-2"), + parserOptions: { ecmaVersion: 6 }, + errors: [{ + messageId: "unnecessaryConditionalAssignment", + type: "ConditionalExpression" + }] } ] }); diff --git a/tests/lib/rules/prefer-exponentiation-operator.js b/tests/lib/rules/prefer-exponentiation-operator.js index 2de358e2c8f..6c8ec1d9c24 100644 --- a/tests/lib/rules/prefer-exponentiation-operator.js +++ b/tests/lib/rules/prefer-exponentiation-operator.js @@ -11,6 +11,7 @@ const rule = require("../../../lib/rules/prefer-exponentiation-operator"); const { RuleTester } = require("../../../lib/rule-tester"); +const parser = require("../../fixtures/fixture-parser"); //------------------------------------------------------------------------------ // Helpers @@ -357,6 +358,19 @@ ruleTester.run("prefer-exponentiation-operator", rule, { invalid("Math?.pow(a, b)", "a**b"), invalid("Math?.pow?.(a, b)", "a**b"), invalid("(Math?.pow)(a, b)", "a**b"), - invalid("(Math?.pow)?.(a, b)", "a**b") + invalid("(Math?.pow)?.(a, b)", "a**b"), + + // https://github.com/eslint/eslint/issues/17173 + { + code: "Math.pow(a, b as any)", + output: "a**(b as any)", + parser: parser("typescript-parsers/exponentiation-with-assertion"), + errors: [ + { + messageId: "useExponentiation", + type: "CallExpression" + } + ] + } ] }); From 6f34f65b02e04ff1b333ae3884b1d6d35c45ef9e Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sat, 24 Jun 2023 12:44:15 +0930 Subject: [PATCH 2/5] fix test typo --- tests/lib/rules/no-extra-parens.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lib/rules/no-extra-parens.js b/tests/lib/rules/no-extra-parens.js index ca1c530c787..c160ace3c36 100644 --- a/tests/lib/rules/no-extra-parens.js +++ b/tests/lib/rules/no-extra-parens.js @@ -789,7 +789,7 @@ ruleTester.run("no-extra-parens", rule, { // https://github.com/eslint/eslint/issues/17173 { code: "const x = (1 satisfies number).toFixed();", - parser: parser("typescript-parsers/keyword-with-arrow-function") + parser: parser("typescript-parsers/member-call-expr-with-assertion") } ], From fbaf67a3941b4efe7c55729ed939f50ac48375c8 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sat, 24 Jun 2023 13:08:31 +0930 Subject: [PATCH 3/5] more tests and handle prefer-exponentiation case --- lib/rules/prefer-exponentiation-operator.js | 3 +- ....js => exponentiation-with-assertion-1.js} | 1 - .../exponentiation-with-assertion-2.js | 321 ++++++++++ .../exponentiation-with-assertion-3.js | 321 ++++++++++ ...ogical-with-assignment-with-assertion-1.js | 538 +++++++++++++++++ ...ogical-with-assignment-with-assertion-2.js | 568 ++++++++++++++++++ .../typescript-parsers/unneeded-ternary-1.js | 1 - .../lib/rules/logical-assignment-operators.js | 30 + .../rules/prefer-exponentiation-operator.js | 24 +- 9 files changed, 1803 insertions(+), 4 deletions(-) rename tests/fixtures/parsers/typescript-parsers/{exponentiation-with-assertion.js => exponentiation-with-assertion-1.js} (99%) create mode 100644 tests/fixtures/parsers/typescript-parsers/exponentiation-with-assertion-2.js create mode 100644 tests/fixtures/parsers/typescript-parsers/exponentiation-with-assertion-3.js create mode 100644 tests/fixtures/parsers/typescript-parsers/logical-with-assignment-with-assertion-1.js create mode 100644 tests/fixtures/parsers/typescript-parsers/logical-with-assignment-with-assertion-2.js diff --git a/lib/rules/prefer-exponentiation-operator.js b/lib/rules/prefer-exponentiation-operator.js index dd4ba2c8e04..8dcb828f4f5 100644 --- a/lib/rules/prefer-exponentiation-operator.js +++ b/lib/rules/prefer-exponentiation-operator.js @@ -55,11 +55,12 @@ function doesExponentNeedParens(exponent) { function doesExponentiationExpressionNeedParens(node, sourceCode) { const parent = node.parent.type === "ChainExpression" ? node.parent.parent : node.parent; + const parentPrecedence = astUtils.getPrecedence(parent); const needsParens = ( parent.type === "ClassDeclaration" || ( parent.type.endsWith("Expression") && - astUtils.getPrecedence(parent) >= PRECEDENCE_OF_EXPONENTIATION_EXPR && + (parentPrecedence === -1 || astUtils.getPrecedence(parent) >= PRECEDENCE_OF_EXPONENTIATION_EXPR) && !(parent.type === "BinaryExpression" && parent.operator === "**" && parent.right === node) && !((parent.type === "CallExpression" || parent.type === "NewExpression") && parent.arguments.includes(node)) && !(parent.type === "MemberExpression" && parent.computed && parent.property === node) && diff --git a/tests/fixtures/parsers/typescript-parsers/exponentiation-with-assertion.js b/tests/fixtures/parsers/typescript-parsers/exponentiation-with-assertion-1.js similarity index 99% rename from tests/fixtures/parsers/typescript-parsers/exponentiation-with-assertion.js rename to tests/fixtures/parsers/typescript-parsers/exponentiation-with-assertion-1.js index 713c40864f2..7921af52872 100644 --- a/tests/fixtures/parsers/typescript-parsers/exponentiation-with-assertion.js +++ b/tests/fixtures/parsers/typescript-parsers/exponentiation-with-assertion-1.js @@ -318,5 +318,4 @@ exports.parse = () => ({ column: 21, }, }, - parent: null, }); diff --git a/tests/fixtures/parsers/typescript-parsers/exponentiation-with-assertion-2.js b/tests/fixtures/parsers/typescript-parsers/exponentiation-with-assertion-2.js new file mode 100644 index 00000000000..cbdfa49e142 --- /dev/null +++ b/tests/fixtures/parsers/typescript-parsers/exponentiation-with-assertion-2.js @@ -0,0 +1,321 @@ +"use strict"; + +/** + * Parser: @typescript-eslint/parser 5.59.11 (TS 5.1.3) + * Source code: + * Math.pow(a as any, b) + */ + +exports.parse = () => ({ + type: "Program", + body: [ + { + type: "ExpressionStatement", + expression: { + type: "CallExpression", + callee: { + type: "MemberExpression", + object: { + type: "Identifier", + decorators: [], + name: "Math", + optional: false, + range: [0, 4], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 4, + }, + }, + }, + property: { + type: "Identifier", + decorators: [], + name: "pow", + optional: false, + range: [5, 8], + loc: { + start: { + line: 1, + column: 5, + }, + end: { + line: 1, + column: 8, + }, + }, + }, + computed: false, + optional: false, + range: [0, 8], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 8, + }, + }, + }, + arguments: [ + { + type: "TSAsExpression", + expression: { + type: "Identifier", + decorators: [], + name: "a", + optional: false, + range: [9, 10], + loc: { + start: { + line: 1, + column: 9, + }, + end: { + line: 1, + column: 10, + }, + }, + }, + typeAnnotation: { + type: "TSAnyKeyword", + range: [14, 17], + loc: { + start: { + line: 1, + column: 14, + }, + end: { + line: 1, + column: 17, + }, + }, + }, + range: [9, 17], + loc: { + start: { + line: 1, + column: 9, + }, + end: { + line: 1, + column: 17, + }, + }, + }, + { + type: "Identifier", + decorators: [], + name: "b", + optional: false, + range: [19, 20], + loc: { + start: { + line: 1, + column: 19, + }, + end: { + line: 1, + column: 20, + }, + }, + }, + ], + optional: false, + range: [0, 21], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 21, + }, + }, + }, + range: [0, 21], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 21, + }, + }, + }, + ], + comments: [], + range: [0, 21], + sourceType: "script", + tokens: [ + { + type: "Identifier", + value: "Math", + range: [0, 4], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 4, + }, + }, + }, + { + type: "Punctuator", + value: ".", + range: [4, 5], + loc: { + start: { + line: 1, + column: 4, + }, + end: { + line: 1, + column: 5, + }, + }, + }, + { + type: "Identifier", + value: "pow", + range: [5, 8], + loc: { + start: { + line: 1, + column: 5, + }, + end: { + line: 1, + column: 8, + }, + }, + }, + { + type: "Punctuator", + value: "(", + range: [8, 9], + loc: { + start: { + line: 1, + column: 8, + }, + end: { + line: 1, + column: 9, + }, + }, + }, + { + type: "Identifier", + value: "a", + range: [9, 10], + loc: { + start: { + line: 1, + column: 9, + }, + end: { + line: 1, + column: 10, + }, + }, + }, + { + type: "Identifier", + value: "as", + range: [11, 13], + loc: { + start: { + line: 1, + column: 11, + }, + end: { + line: 1, + column: 13, + }, + }, + }, + { + type: "Identifier", + value: "any", + range: [14, 17], + loc: { + start: { + line: 1, + column: 14, + }, + end: { + line: 1, + column: 17, + }, + }, + }, + { + type: "Punctuator", + value: ",", + range: [17, 18], + loc: { + start: { + line: 1, + column: 17, + }, + end: { + line: 1, + column: 18, + }, + }, + }, + { + type: "Identifier", + value: "b", + range: [19, 20], + loc: { + start: { + line: 1, + column: 19, + }, + end: { + line: 1, + column: 20, + }, + }, + }, + { + type: "Punctuator", + value: ")", + range: [20, 21], + loc: { + start: { + line: 1, + column: 20, + }, + end: { + line: 1, + column: 21, + }, + }, + }, + ], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 21, + }, + }, +}); diff --git a/tests/fixtures/parsers/typescript-parsers/exponentiation-with-assertion-3.js b/tests/fixtures/parsers/typescript-parsers/exponentiation-with-assertion-3.js new file mode 100644 index 00000000000..422d8736ff3 --- /dev/null +++ b/tests/fixtures/parsers/typescript-parsers/exponentiation-with-assertion-3.js @@ -0,0 +1,321 @@ +"use strict"; + +/** + * Parser: @typescript-eslint/parser 5.59.11 (TS 5.1.3) + * Source code: + * Math.pow(a, b) as any + */ + +exports.parse = () => ({ + type: "Program", + body: [ + { + type: "ExpressionStatement", + expression: { + type: "TSAsExpression", + expression: { + type: "CallExpression", + callee: { + type: "MemberExpression", + object: { + type: "Identifier", + decorators: [], + name: "Math", + optional: false, + range: [0, 4], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 4, + }, + }, + }, + property: { + type: "Identifier", + decorators: [], + name: "pow", + optional: false, + range: [5, 8], + loc: { + start: { + line: 1, + column: 5, + }, + end: { + line: 1, + column: 8, + }, + }, + }, + computed: false, + optional: false, + range: [0, 8], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 8, + }, + }, + }, + arguments: [ + { + type: "Identifier", + decorators: [], + name: "a", + optional: false, + range: [9, 10], + loc: { + start: { + line: 1, + column: 9, + }, + end: { + line: 1, + column: 10, + }, + }, + }, + { + type: "Identifier", + decorators: [], + name: "b", + optional: false, + range: [12, 13], + loc: { + start: { + line: 1, + column: 12, + }, + end: { + line: 1, + column: 13, + }, + }, + }, + ], + optional: false, + range: [0, 14], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 14, + }, + }, + }, + typeAnnotation: { + type: "TSAnyKeyword", + range: [18, 21], + loc: { + start: { + line: 1, + column: 18, + }, + end: { + line: 1, + column: 21, + }, + }, + }, + range: [0, 21], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 21, + }, + }, + }, + range: [0, 21], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 21, + }, + }, + }, + ], + comments: [], + range: [0, 21], + sourceType: "script", + tokens: [ + { + type: "Identifier", + value: "Math", + range: [0, 4], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 4, + }, + }, + }, + { + type: "Punctuator", + value: ".", + range: [4, 5], + loc: { + start: { + line: 1, + column: 4, + }, + end: { + line: 1, + column: 5, + }, + }, + }, + { + type: "Identifier", + value: "pow", + range: [5, 8], + loc: { + start: { + line: 1, + column: 5, + }, + end: { + line: 1, + column: 8, + }, + }, + }, + { + type: "Punctuator", + value: "(", + range: [8, 9], + loc: { + start: { + line: 1, + column: 8, + }, + end: { + line: 1, + column: 9, + }, + }, + }, + { + type: "Identifier", + value: "a", + range: [9, 10], + loc: { + start: { + line: 1, + column: 9, + }, + end: { + line: 1, + column: 10, + }, + }, + }, + { + type: "Punctuator", + value: ",", + range: [10, 11], + loc: { + start: { + line: 1, + column: 10, + }, + end: { + line: 1, + column: 11, + }, + }, + }, + { + type: "Identifier", + value: "b", + range: [12, 13], + loc: { + start: { + line: 1, + column: 12, + }, + end: { + line: 1, + column: 13, + }, + }, + }, + { + type: "Punctuator", + value: ")", + range: [13, 14], + loc: { + start: { + line: 1, + column: 13, + }, + end: { + line: 1, + column: 14, + }, + }, + }, + { + type: "Identifier", + value: "as", + range: [15, 17], + loc: { + start: { + line: 1, + column: 15, + }, + end: { + line: 1, + column: 17, + }, + }, + }, + { + type: "Identifier", + value: "any", + range: [18, 21], + loc: { + start: { + line: 1, + column: 18, + }, + end: { + line: 1, + column: 21, + }, + }, + }, + ], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 21, + }, + }, +}); diff --git a/tests/fixtures/parsers/typescript-parsers/logical-with-assignment-with-assertion-1.js b/tests/fixtures/parsers/typescript-parsers/logical-with-assignment-with-assertion-1.js new file mode 100644 index 00000000000..914ff4d0c24 --- /dev/null +++ b/tests/fixtures/parsers/typescript-parsers/logical-with-assignment-with-assertion-1.js @@ -0,0 +1,538 @@ +"use strict"; + +/** + * Parser: @typescript-eslint/parser 5.59.11 (TS 5.1.3) + * Source code: + * a.b.c || (a.b.c = d as number) + */ + +exports.parse = () => ({ + type: "Program", + body: [ + { + type: "ExpressionStatement", + expression: { + type: "LogicalExpression", + operator: "||", + left: { + type: "MemberExpression", + object: { + type: "MemberExpression", + object: { + type: "Identifier", + decorators: [], + name: "a", + optional: false, + range: [0, 1], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 1, + }, + }, + }, + property: { + type: "Identifier", + decorators: [], + name: "b", + optional: false, + range: [2, 3], + loc: { + start: { + line: 1, + column: 2, + }, + end: { + line: 1, + column: 3, + }, + }, + }, + computed: false, + optional: false, + range: [0, 3], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 3, + }, + }, + }, + property: { + type: "Identifier", + decorators: [], + name: "c", + optional: false, + range: [4, 5], + loc: { + start: { + line: 1, + column: 4, + }, + end: { + line: 1, + column: 5, + }, + }, + }, + computed: false, + optional: false, + range: [0, 5], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 5, + }, + }, + }, + right: { + type: "AssignmentExpression", + operator: "=", + left: { + type: "MemberExpression", + object: { + type: "MemberExpression", + object: { + type: "Identifier", + decorators: [], + name: "a", + optional: false, + range: [10, 11], + loc: { + start: { + line: 1, + column: 10, + }, + end: { + line: 1, + column: 11, + }, + }, + }, + property: { + type: "Identifier", + decorators: [], + name: "b", + optional: false, + range: [12, 13], + loc: { + start: { + line: 1, + column: 12, + }, + end: { + line: 1, + column: 13, + }, + }, + }, + computed: false, + optional: false, + range: [10, 13], + loc: { + start: { + line: 1, + column: 10, + }, + end: { + line: 1, + column: 13, + }, + }, + }, + property: { + type: "Identifier", + decorators: [], + name: "c", + optional: false, + range: [14, 15], + loc: { + start: { + line: 1, + column: 14, + }, + end: { + line: 1, + column: 15, + }, + }, + }, + computed: false, + optional: false, + range: [10, 15], + loc: { + start: { + line: 1, + column: 10, + }, + end: { + line: 1, + column: 15, + }, + }, + }, + right: { + type: "TSAsExpression", + expression: { + type: "Identifier", + decorators: [], + name: "d", + optional: false, + range: [18, 19], + loc: { + start: { + line: 1, + column: 18, + }, + end: { + line: 1, + column: 19, + }, + }, + }, + typeAnnotation: { + type: "TSNumberKeyword", + range: [23, 29], + loc: { + start: { + line: 1, + column: 23, + }, + end: { + line: 1, + column: 29, + }, + }, + }, + range: [18, 29], + loc: { + start: { + line: 1, + column: 18, + }, + end: { + line: 1, + column: 29, + }, + }, + }, + range: [10, 29], + loc: { + start: { + line: 1, + column: 10, + }, + end: { + line: 1, + column: 29, + }, + }, + }, + range: [0, 30], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 30, + }, + }, + }, + range: [0, 30], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 30, + }, + }, + }, + ], + comments: [], + range: [0, 30], + sourceType: "script", + tokens: [ + { + type: "Identifier", + value: "a", + range: [0, 1], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 1, + }, + }, + }, + { + type: "Punctuator", + value: ".", + range: [1, 2], + loc: { + start: { + line: 1, + column: 1, + }, + end: { + line: 1, + column: 2, + }, + }, + }, + { + type: "Identifier", + value: "b", + range: [2, 3], + loc: { + start: { + line: 1, + column: 2, + }, + end: { + line: 1, + column: 3, + }, + }, + }, + { + type: "Punctuator", + value: ".", + range: [3, 4], + loc: { + start: { + line: 1, + column: 3, + }, + end: { + line: 1, + column: 4, + }, + }, + }, + { + type: "Identifier", + value: "c", + range: [4, 5], + loc: { + start: { + line: 1, + column: 4, + }, + end: { + line: 1, + column: 5, + }, + }, + }, + { + type: "Punctuator", + value: "||", + range: [6, 8], + loc: { + start: { + line: 1, + column: 6, + }, + end: { + line: 1, + column: 8, + }, + }, + }, + { + type: "Punctuator", + value: "(", + range: [9, 10], + loc: { + start: { + line: 1, + column: 9, + }, + end: { + line: 1, + column: 10, + }, + }, + }, + { + type: "Identifier", + value: "a", + range: [10, 11], + loc: { + start: { + line: 1, + column: 10, + }, + end: { + line: 1, + column: 11, + }, + }, + }, + { + type: "Punctuator", + value: ".", + range: [11, 12], + loc: { + start: { + line: 1, + column: 11, + }, + end: { + line: 1, + column: 12, + }, + }, + }, + { + type: "Identifier", + value: "b", + range: [12, 13], + loc: { + start: { + line: 1, + column: 12, + }, + end: { + line: 1, + column: 13, + }, + }, + }, + { + type: "Punctuator", + value: ".", + range: [13, 14], + loc: { + start: { + line: 1, + column: 13, + }, + end: { + line: 1, + column: 14, + }, + }, + }, + { + type: "Identifier", + value: "c", + range: [14, 15], + loc: { + start: { + line: 1, + column: 14, + }, + end: { + line: 1, + column: 15, + }, + }, + }, + { + type: "Punctuator", + value: "=", + range: [16, 17], + loc: { + start: { + line: 1, + column: 16, + }, + end: { + line: 1, + column: 17, + }, + }, + }, + { + type: "Identifier", + value: "d", + range: [18, 19], + loc: { + start: { + line: 1, + column: 18, + }, + end: { + line: 1, + column: 19, + }, + }, + }, + { + type: "Identifier", + value: "as", + range: [20, 22], + loc: { + start: { + line: 1, + column: 20, + }, + end: { + line: 1, + column: 22, + }, + }, + }, + { + type: "Identifier", + value: "number", + range: [23, 29], + loc: { + start: { + line: 1, + column: 23, + }, + end: { + line: 1, + column: 29, + }, + }, + }, + { + type: "Punctuator", + value: ")", + range: [29, 30], + loc: { + start: { + line: 1, + column: 29, + }, + end: { + line: 1, + column: 30, + }, + }, + }, + ], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 30, + }, + }, +}); diff --git a/tests/fixtures/parsers/typescript-parsers/logical-with-assignment-with-assertion-2.js b/tests/fixtures/parsers/typescript-parsers/logical-with-assignment-with-assertion-2.js new file mode 100644 index 00000000000..644060ab1d7 --- /dev/null +++ b/tests/fixtures/parsers/typescript-parsers/logical-with-assignment-with-assertion-2.js @@ -0,0 +1,568 @@ +"use strict"; + +/** + * Parser: @typescript-eslint/parser 5.59.11 (TS 5.1.3) + * Source code: + * a.b.c || (a.b.c = (d as number)) + */ + +exports.parse = () => ({ + type: "Program", + body: [ + { + type: "ExpressionStatement", + expression: { + type: "LogicalExpression", + operator: "||", + left: { + type: "MemberExpression", + object: { + type: "MemberExpression", + object: { + type: "Identifier", + decorators: [], + name: "a", + optional: false, + range: [0, 1], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 1, + }, + }, + }, + property: { + type: "Identifier", + decorators: [], + name: "b", + optional: false, + range: [2, 3], + loc: { + start: { + line: 1, + column: 2, + }, + end: { + line: 1, + column: 3, + }, + }, + }, + computed: false, + optional: false, + range: [0, 3], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 3, + }, + }, + }, + property: { + type: "Identifier", + decorators: [], + name: "c", + optional: false, + range: [4, 5], + loc: { + start: { + line: 1, + column: 4, + }, + end: { + line: 1, + column: 5, + }, + }, + }, + computed: false, + optional: false, + range: [0, 5], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 5, + }, + }, + }, + right: { + type: "AssignmentExpression", + operator: "=", + left: { + type: "MemberExpression", + object: { + type: "MemberExpression", + object: { + type: "Identifier", + decorators: [], + name: "a", + optional: false, + range: [10, 11], + loc: { + start: { + line: 1, + column: 10, + }, + end: { + line: 1, + column: 11, + }, + }, + }, + property: { + type: "Identifier", + decorators: [], + name: "b", + optional: false, + range: [12, 13], + loc: { + start: { + line: 1, + column: 12, + }, + end: { + line: 1, + column: 13, + }, + }, + }, + computed: false, + optional: false, + range: [10, 13], + loc: { + start: { + line: 1, + column: 10, + }, + end: { + line: 1, + column: 13, + }, + }, + }, + property: { + type: "Identifier", + decorators: [], + name: "c", + optional: false, + range: [14, 15], + loc: { + start: { + line: 1, + column: 14, + }, + end: { + line: 1, + column: 15, + }, + }, + }, + computed: false, + optional: false, + range: [10, 15], + loc: { + start: { + line: 1, + column: 10, + }, + end: { + line: 1, + column: 15, + }, + }, + }, + right: { + type: "TSAsExpression", + expression: { + type: "Identifier", + decorators: [], + name: "d", + optional: false, + range: [19, 20], + loc: { + start: { + line: 1, + column: 19, + }, + end: { + line: 1, + column: 20, + }, + }, + }, + typeAnnotation: { + type: "TSNumberKeyword", + range: [24, 30], + loc: { + start: { + line: 1, + column: 24, + }, + end: { + line: 1, + column: 30, + }, + }, + }, + range: [19, 30], + loc: { + start: { + line: 1, + column: 19, + }, + end: { + line: 1, + column: 30, + }, + }, + }, + range: [10, 31], + loc: { + start: { + line: 1, + column: 10, + }, + end: { + line: 1, + column: 31, + }, + }, + }, + range: [0, 32], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 32, + }, + }, + }, + range: [0, 32], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 32, + }, + }, + }, + ], + comments: [], + range: [0, 32], + sourceType: "script", + tokens: [ + { + type: "Identifier", + value: "a", + range: [0, 1], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 1, + }, + }, + }, + { + type: "Punctuator", + value: ".", + range: [1, 2], + loc: { + start: { + line: 1, + column: 1, + }, + end: { + line: 1, + column: 2, + }, + }, + }, + { + type: "Identifier", + value: "b", + range: [2, 3], + loc: { + start: { + line: 1, + column: 2, + }, + end: { + line: 1, + column: 3, + }, + }, + }, + { + type: "Punctuator", + value: ".", + range: [3, 4], + loc: { + start: { + line: 1, + column: 3, + }, + end: { + line: 1, + column: 4, + }, + }, + }, + { + type: "Identifier", + value: "c", + range: [4, 5], + loc: { + start: { + line: 1, + column: 4, + }, + end: { + line: 1, + column: 5, + }, + }, + }, + { + type: "Punctuator", + value: "||", + range: [6, 8], + loc: { + start: { + line: 1, + column: 6, + }, + end: { + line: 1, + column: 8, + }, + }, + }, + { + type: "Punctuator", + value: "(", + range: [9, 10], + loc: { + start: { + line: 1, + column: 9, + }, + end: { + line: 1, + column: 10, + }, + }, + }, + { + type: "Identifier", + value: "a", + range: [10, 11], + loc: { + start: { + line: 1, + column: 10, + }, + end: { + line: 1, + column: 11, + }, + }, + }, + { + type: "Punctuator", + value: ".", + range: [11, 12], + loc: { + start: { + line: 1, + column: 11, + }, + end: { + line: 1, + column: 12, + }, + }, + }, + { + type: "Identifier", + value: "b", + range: [12, 13], + loc: { + start: { + line: 1, + column: 12, + }, + end: { + line: 1, + column: 13, + }, + }, + }, + { + type: "Punctuator", + value: ".", + range: [13, 14], + loc: { + start: { + line: 1, + column: 13, + }, + end: { + line: 1, + column: 14, + }, + }, + }, + { + type: "Identifier", + value: "c", + range: [14, 15], + loc: { + start: { + line: 1, + column: 14, + }, + end: { + line: 1, + column: 15, + }, + }, + }, + { + type: "Punctuator", + value: "=", + range: [16, 17], + loc: { + start: { + line: 1, + column: 16, + }, + end: { + line: 1, + column: 17, + }, + }, + }, + { + type: "Punctuator", + value: "(", + range: [18, 19], + loc: { + start: { + line: 1, + column: 18, + }, + end: { + line: 1, + column: 19, + }, + }, + }, + { + type: "Identifier", + value: "d", + range: [19, 20], + loc: { + start: { + line: 1, + column: 19, + }, + end: { + line: 1, + column: 20, + }, + }, + }, + { + type: "Identifier", + value: "as", + range: [21, 23], + loc: { + start: { + line: 1, + column: 21, + }, + end: { + line: 1, + column: 23, + }, + }, + }, + { + type: "Identifier", + value: "number", + range: [24, 30], + loc: { + start: { + line: 1, + column: 24, + }, + end: { + line: 1, + column: 30, + }, + }, + }, + { + type: "Punctuator", + value: ")", + range: [30, 31], + loc: { + start: { + line: 1, + column: 30, + }, + end: { + line: 1, + column: 31, + }, + }, + }, + { + type: "Punctuator", + value: ")", + range: [31, 32], + loc: { + start: { + line: 1, + column: 31, + }, + end: { + line: 1, + column: 32, + }, + }, + }, + ], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 32, + }, + }, +}); diff --git a/tests/fixtures/parsers/typescript-parsers/unneeded-ternary-1.js b/tests/fixtures/parsers/typescript-parsers/unneeded-ternary-1.js index cfeb1ce7a76..2b44484d892 100644 --- a/tests/fixtures/parsers/typescript-parsers/unneeded-ternary-1.js +++ b/tests/fixtures/parsers/typescript-parsers/unneeded-ternary-1.js @@ -235,5 +235,4 @@ exports.parse = () => ({ column: 25, }, }, - parent: null, }); diff --git a/tests/lib/rules/logical-assignment-operators.js b/tests/lib/rules/logical-assignment-operators.js index ddf7ef1649d..39c773d5378 100644 --- a/tests/lib/rules/logical-assignment-operators.js +++ b/tests/lib/rules/logical-assignment-operators.js @@ -1466,6 +1466,36 @@ ruleTester.run("logical-assignment-operators", rule, { options: ["never"], parser: parser("typescript-parsers/logical-assignment-with-assertion"), errors: [{ messageId: "unexpected", type: "AssignmentExpression", data: { operator: "||=" } }] + }, + { + code: "a.b.c || (a.b.c = d as number)", + output: null, + parser: parser("typescript-parsers/logical-with-assignment-with-assertion-1"), + errors: [{ + messageId: "logical", + type: "LogicalExpression", + data: { operator: "||=" }, + suggestions: [{ + messageId: "convertLogical", + data: { operator: "||=" }, + output: "a.b.c ||= d as number" + }] + }] + }, + { + code: "a.b.c || (a.b.c = (d as number))", + output: null, + parser: parser("typescript-parsers/logical-with-assignment-with-assertion-2"), + errors: [{ + messageId: "logical", + type: "LogicalExpression", + data: { operator: "||=" }, + suggestions: [{ + messageId: "convertLogical", + data: { operator: "||=" }, + output: "a.b.c ||= (d as number)" + }] + }] } ] }); diff --git a/tests/lib/rules/prefer-exponentiation-operator.js b/tests/lib/rules/prefer-exponentiation-operator.js index 6c8ec1d9c24..8765330c00f 100644 --- a/tests/lib/rules/prefer-exponentiation-operator.js +++ b/tests/lib/rules/prefer-exponentiation-operator.js @@ -364,7 +364,29 @@ ruleTester.run("prefer-exponentiation-operator", rule, { { code: "Math.pow(a, b as any)", output: "a**(b as any)", - parser: parser("typescript-parsers/exponentiation-with-assertion"), + parser: parser("typescript-parsers/exponentiation-with-assertion-1"), + errors: [ + { + messageId: "useExponentiation", + type: "CallExpression" + } + ] + }, + { + code: "Math.pow(a as any, b)", + output: "(a as any)**b", + parser: parser("typescript-parsers/exponentiation-with-assertion-2"), + errors: [ + { + messageId: "useExponentiation", + type: "CallExpression" + } + ] + }, + { + code: "Math.pow(a, b) as any", + output: "(a**b) as any", + parser: parser("typescript-parsers/exponentiation-with-assertion-3"), errors: [ { messageId: "useExponentiation", From fc5e78e97a70ba280d481375112c278b8fa3c705 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Mon, 26 Jun 2023 10:04:56 +0930 Subject: [PATCH 4/5] review fixes and more cases --- lib/rules/logical-assignment-operators.js | 7 +- lib/rules/prefer-exponentiation-operator.js | 2 +- .../boolean-cast-with-assertion.js | 6 +- .../logical-assignment-with-assertion.js | 364 +++++----- ...ogical-with-assignment-with-assertion-3.js | 568 +++++++++++++++ .../member-call-expr-with-assertion.js | 644 +++++++++--------- .../lib/rules/logical-assignment-operators.js | 15 + tests/lib/rules/no-extra-boolean-cast.js | 1 - 8 files changed, 1096 insertions(+), 511 deletions(-) create mode 100644 tests/fixtures/parsers/typescript-parsers/logical-with-assignment-with-assertion-3.js diff --git a/lib/rules/logical-assignment-operators.js b/lib/rules/logical-assignment-operators.js index cb1cbe5a16b..27ca585e995 100644 --- a/lib/rules/logical-assignment-operators.js +++ b/lib/rules/logical-assignment-operators.js @@ -370,8 +370,11 @@ module.exports = { return; } - const requiresOuterParenthesis = logical.parent.type !== "ExpressionStatement" && - (astUtils.getPrecedence({ type: "AssignmentExpression" }) < astUtils.getPrecedence(logical.parent)); + const parentPrecedence = astUtils.getPrecedence(logical.parent); + const requiresOuterParenthesis = logical.parent.type !== "ExpressionStatement" && ( + parentPrecedence === -1 || + astUtils.getPrecedence({ type: "AssignmentExpression" }) < parentPrecedence + ); if (!astUtils.isParenthesised(sourceCode, logical) && requiresOuterParenthesis) { yield ruleFixer.insertTextBefore(logical, "("); diff --git a/lib/rules/prefer-exponentiation-operator.js b/lib/rules/prefer-exponentiation-operator.js index 8dcb828f4f5..6d807f9cfea 100644 --- a/lib/rules/prefer-exponentiation-operator.js +++ b/lib/rules/prefer-exponentiation-operator.js @@ -60,7 +60,7 @@ function doesExponentiationExpressionNeedParens(node, sourceCode) { parent.type === "ClassDeclaration" || ( parent.type.endsWith("Expression") && - (parentPrecedence === -1 || astUtils.getPrecedence(parent) >= PRECEDENCE_OF_EXPONENTIATION_EXPR) && + (parentPrecedence === -1 || parentPrecedence >= PRECEDENCE_OF_EXPONENTIATION_EXPR) && !(parent.type === "BinaryExpression" && parent.operator === "**" && parent.right === node) && !((parent.type === "CallExpression" || parent.type === "NewExpression") && parent.arguments.includes(node)) && !(parent.type === "MemberExpression" && parent.computed && parent.property === node) && diff --git a/tests/fixtures/parsers/typescript-parsers/boolean-cast-with-assertion.js b/tests/fixtures/parsers/typescript-parsers/boolean-cast-with-assertion.js index b58ace5c008..57d23df4793 100644 --- a/tests/fixtures/parsers/typescript-parsers/boolean-cast-with-assertion.js +++ b/tests/fixtures/parsers/typescript-parsers/boolean-cast-with-assertion.js @@ -136,7 +136,7 @@ exports.parse = () => ({ }, ], comments: [], - range: [0, 28], + range: [0, 27], sourceType: "script", tokens: [ { @@ -326,8 +326,8 @@ exports.parse = () => ({ column: 0, }, end: { - line: 2, - column: 0, + line: 1, + column: 27, }, }, }); diff --git a/tests/fixtures/parsers/typescript-parsers/logical-assignment-with-assertion.js b/tests/fixtures/parsers/typescript-parsers/logical-assignment-with-assertion.js index 27337cf1982..675559196e1 100644 --- a/tests/fixtures/parsers/typescript-parsers/logical-assignment-with-assertion.js +++ b/tests/fixtures/parsers/typescript-parsers/logical-assignment-with-assertion.js @@ -3,207 +3,207 @@ /** * Parser: @typescript-eslint/parser 5.59.11 (TS 5.1.3) * Source code: - * a ||= (b as number); + * a ||= b as number; */ exports.parse = () => ({ - type: "Program", - body: [ - { - type: "ExpressionStatement", - expression: { - type: "AssignmentExpression", - operator: "||=", - left: { - type: "Identifier", - decorators: [], - name: "a", - optional: false, - range: [0, 1], - loc: { - start: { - line: 1, - column: 0, - }, - end: { - line: 1, - column: 1, - }, - }, - }, - right: { - type: "TSAsExpression", - expression: { - type: "Identifier", - decorators: [], - name: "b", - optional: false, - range: [6, 7], - loc: { - start: { - line: 1, - column: 6, - }, - end: { - line: 1, - column: 7, - }, - }, - }, - typeAnnotation: { - type: "TSNumberKeyword", - range: [11, 17], - loc: { - start: { - line: 1, - column: 11, - }, - end: { - line: 1, - column: 17, - }, - }, - }, - range: [6, 17], - loc: { - start: { - line: 1, - column: 6, - }, - end: { - line: 1, - column: 17, - }, - }, - }, - range: [0, 17], - loc: { - start: { - line: 1, - column: 0, - }, - end: { - line: 1, - column: 17, - }, - }, + type: "Program", + body: [ + { + type: "ExpressionStatement", + expression: { + type: "AssignmentExpression", + operator: "||=", + left: { + type: "Identifier", + decorators: [], + name: "a", + optional: false, + range: [0, 1], + loc: { + start: { + line: 1, + column: 0, }, - range: [0, 18], - loc: { - start: { - line: 1, - column: 0, - }, - end: { - line: 1, - column: 18, - }, - }, - }, - ], - comments: [], - range: [0, 19], - sourceType: "script", - tokens: [ - { - type: "Identifier", - value: "a", - range: [0, 1], - loc: { - start: { - line: 1, - column: 0, - }, - end: { - line: 1, - column: 1, - }, - }, - }, - { - type: "Punctuator", - value: "||=", - range: [2, 5], - loc: { - start: { - line: 1, - column: 2, - }, - end: { - line: 1, - column: 5, - }, + end: { + line: 1, + column: 1, }, + }, }, - { + right: { + type: "TSAsExpression", + expression: { type: "Identifier", - value: "b", + decorators: [], + name: "b", + optional: false, range: [6, 7], loc: { - start: { - line: 1, - column: 6, - }, - end: { - line: 1, - column: 7, - }, + start: { + line: 1, + column: 6, + }, + end: { + line: 1, + column: 7, + }, }, - }, - { - type: "Identifier", - value: "as", - range: [8, 10], - loc: { - start: { - line: 1, - column: 8, - }, - end: { - line: 1, - column: 10, - }, - }, - }, - { - type: "Identifier", - value: "number", + }, + typeAnnotation: { + type: "TSNumberKeyword", range: [11, 17], loc: { - start: { - line: 1, - column: 11, - }, - end: { - line: 1, - column: 17, - }, + start: { + line: 1, + column: 11, + }, + end: { + line: 1, + column: 17, + }, }, - }, - { - type: "Punctuator", - value: ";", - range: [17, 18], - loc: { - start: { - line: 1, - column: 17, - }, - end: { - line: 1, - column: 18, - }, + }, + range: [6, 17], + loc: { + start: { + line: 1, + column: 6, }, + end: { + line: 1, + column: 17, + }, + }, }, - ], - loc: { - start: { + range: [0, 17], + loc: { + start: { line: 1, column: 0, + }, + end: { + line: 1, + column: 17, + }, + }, + }, + range: [0, 18], + loc: { + start: { + line: 1, + column: 0, }, end: { - line: 2, - column: 0, + line: 1, + column: 18, + }, + }, + }, + ], + comments: [], + range: [0, 18], + sourceType: "script", + tokens: [ + { + type: "Identifier", + value: "a", + range: [0, 1], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 1, }, + }, + }, + { + type: "Punctuator", + value: "||=", + range: [2, 5], + loc: { + start: { + line: 1, + column: 2, + }, + end: { + line: 1, + column: 5, + }, + }, + }, + { + type: "Identifier", + value: "b", + range: [6, 7], + loc: { + start: { + line: 1, + column: 6, + }, + end: { + line: 1, + column: 7, + }, + }, + }, + { + type: "Identifier", + value: "as", + range: [8, 10], + loc: { + start: { + line: 1, + column: 8, + }, + end: { + line: 1, + column: 10, + }, + }, + }, + { + type: "Identifier", + value: "number", + range: [11, 17], + loc: { + start: { + line: 1, + column: 11, + }, + end: { + line: 1, + column: 17, + }, + }, + }, + { + type: "Punctuator", + value: ";", + range: [17, 18], + loc: { + start: { + line: 1, + column: 17, + }, + end: { + line: 1, + column: 18, + }, + }, + }, + ], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 18, }, + }, }); diff --git a/tests/fixtures/parsers/typescript-parsers/logical-with-assignment-with-assertion-3.js b/tests/fixtures/parsers/typescript-parsers/logical-with-assignment-with-assertion-3.js new file mode 100644 index 00000000000..8824fc2f609 --- /dev/null +++ b/tests/fixtures/parsers/typescript-parsers/logical-with-assignment-with-assertion-3.js @@ -0,0 +1,568 @@ +"use strict"; + +/** + * Parser: @typescript-eslint/parser 5.59.11 (TS 5.1.3) + * Source code: + * (a.b.c || (a.b.c = d)) as number + */ + +exports.parse = () => ({ + type: "Program", + body: [ + { + type: "ExpressionStatement", + expression: { + type: "TSAsExpression", + expression: { + type: "LogicalExpression", + operator: "||", + left: { + type: "MemberExpression", + object: { + type: "MemberExpression", + object: { + type: "Identifier", + decorators: [], + name: "a", + optional: false, + range: [1, 2], + loc: { + start: { + line: 1, + column: 1, + }, + end: { + line: 1, + column: 2, + }, + }, + }, + property: { + type: "Identifier", + decorators: [], + name: "b", + optional: false, + range: [3, 4], + loc: { + start: { + line: 1, + column: 3, + }, + end: { + line: 1, + column: 4, + }, + }, + }, + computed: false, + optional: false, + range: [1, 4], + loc: { + start: { + line: 1, + column: 1, + }, + end: { + line: 1, + column: 4, + }, + }, + }, + property: { + type: "Identifier", + decorators: [], + name: "c", + optional: false, + range: [5, 6], + loc: { + start: { + line: 1, + column: 5, + }, + end: { + line: 1, + column: 6, + }, + }, + }, + computed: false, + optional: false, + range: [1, 6], + loc: { + start: { + line: 1, + column: 1, + }, + end: { + line: 1, + column: 6, + }, + }, + }, + right: { + type: "AssignmentExpression", + operator: "=", + left: { + type: "MemberExpression", + object: { + type: "MemberExpression", + object: { + type: "Identifier", + decorators: [], + name: "a", + optional: false, + range: [11, 12], + loc: { + start: { + line: 1, + column: 11, + }, + end: { + line: 1, + column: 12, + }, + }, + }, + property: { + type: "Identifier", + decorators: [], + name: "b", + optional: false, + range: [13, 14], + loc: { + start: { + line: 1, + column: 13, + }, + end: { + line: 1, + column: 14, + }, + }, + }, + computed: false, + optional: false, + range: [11, 14], + loc: { + start: { + line: 1, + column: 11, + }, + end: { + line: 1, + column: 14, + }, + }, + }, + property: { + type: "Identifier", + decorators: [], + name: "c", + optional: false, + range: [15, 16], + loc: { + start: { + line: 1, + column: 15, + }, + end: { + line: 1, + column: 16, + }, + }, + }, + computed: false, + optional: false, + range: [11, 16], + loc: { + start: { + line: 1, + column: 11, + }, + end: { + line: 1, + column: 16, + }, + }, + }, + right: { + type: "Identifier", + decorators: [], + name: "d", + optional: false, + range: [19, 20], + loc: { + start: { + line: 1, + column: 19, + }, + end: { + line: 1, + column: 20, + }, + }, + }, + range: [11, 20], + loc: { + start: { + line: 1, + column: 11, + }, + end: { + line: 1, + column: 20, + }, + }, + }, + range: [1, 21], + loc: { + start: { + line: 1, + column: 1, + }, + end: { + line: 1, + column: 21, + }, + }, + }, + typeAnnotation: { + type: "TSNumberKeyword", + range: [26, 32], + loc: { + start: { + line: 1, + column: 26, + }, + end: { + line: 1, + column: 32, + }, + }, + }, + range: [0, 32], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 32, + }, + }, + }, + range: [0, 32], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 32, + }, + }, + }, + ], + comments: [], + range: [0, 32], + sourceType: "script", + tokens: [ + { + type: "Punctuator", + value: "(", + range: [0, 1], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 1, + }, + }, + }, + { + type: "Identifier", + value: "a", + range: [1, 2], + loc: { + start: { + line: 1, + column: 1, + }, + end: { + line: 1, + column: 2, + }, + }, + }, + { + type: "Punctuator", + value: ".", + range: [2, 3], + loc: { + start: { + line: 1, + column: 2, + }, + end: { + line: 1, + column: 3, + }, + }, + }, + { + type: "Identifier", + value: "b", + range: [3, 4], + loc: { + start: { + line: 1, + column: 3, + }, + end: { + line: 1, + column: 4, + }, + }, + }, + { + type: "Punctuator", + value: ".", + range: [4, 5], + loc: { + start: { + line: 1, + column: 4, + }, + end: { + line: 1, + column: 5, + }, + }, + }, + { + type: "Identifier", + value: "c", + range: [5, 6], + loc: { + start: { + line: 1, + column: 5, + }, + end: { + line: 1, + column: 6, + }, + }, + }, + { + type: "Punctuator", + value: "||", + range: [7, 9], + loc: { + start: { + line: 1, + column: 7, + }, + end: { + line: 1, + column: 9, + }, + }, + }, + { + type: "Punctuator", + value: "(", + range: [10, 11], + loc: { + start: { + line: 1, + column: 10, + }, + end: { + line: 1, + column: 11, + }, + }, + }, + { + type: "Identifier", + value: "a", + range: [11, 12], + loc: { + start: { + line: 1, + column: 11, + }, + end: { + line: 1, + column: 12, + }, + }, + }, + { + type: "Punctuator", + value: ".", + range: [12, 13], + loc: { + start: { + line: 1, + column: 12, + }, + end: { + line: 1, + column: 13, + }, + }, + }, + { + type: "Identifier", + value: "b", + range: [13, 14], + loc: { + start: { + line: 1, + column: 13, + }, + end: { + line: 1, + column: 14, + }, + }, + }, + { + type: "Punctuator", + value: ".", + range: [14, 15], + loc: { + start: { + line: 1, + column: 14, + }, + end: { + line: 1, + column: 15, + }, + }, + }, + { + type: "Identifier", + value: "c", + range: [15, 16], + loc: { + start: { + line: 1, + column: 15, + }, + end: { + line: 1, + column: 16, + }, + }, + }, + { + type: "Punctuator", + value: "=", + range: [17, 18], + loc: { + start: { + line: 1, + column: 17, + }, + end: { + line: 1, + column: 18, + }, + }, + }, + { + type: "Identifier", + value: "d", + range: [19, 20], + loc: { + start: { + line: 1, + column: 19, + }, + end: { + line: 1, + column: 20, + }, + }, + }, + { + type: "Punctuator", + value: ")", + range: [20, 21], + loc: { + start: { + line: 1, + column: 20, + }, + end: { + line: 1, + column: 21, + }, + }, + }, + { + type: "Punctuator", + value: ")", + range: [21, 22], + loc: { + start: { + line: 1, + column: 21, + }, + end: { + line: 1, + column: 22, + }, + }, + }, + { + type: "Identifier", + value: "as", + range: [23, 25], + loc: { + start: { + line: 1, + column: 23, + }, + end: { + line: 1, + column: 25, + }, + }, + }, + { + type: "Identifier", + value: "number", + range: [26, 32], + loc: { + start: { + line: 1, + column: 26, + }, + end: { + line: 1, + column: 32, + }, + }, + }, + ], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 32, + }, + }, +}); diff --git a/tests/fixtures/parsers/typescript-parsers/member-call-expr-with-assertion.js b/tests/fixtures/parsers/typescript-parsers/member-call-expr-with-assertion.js index 14f679d2f79..e26e115e94e 100644 --- a/tests/fixtures/parsers/typescript-parsers/member-call-expr-with-assertion.js +++ b/tests/fixtures/parsers/typescript-parsers/member-call-expr-with-assertion.js @@ -7,360 +7,360 @@ */ exports.parse = () => ({ - type: "Program", - body: [ + type: "Program", + body: [ + { + type: "VariableDeclaration", + declarations: [ { - type: "VariableDeclaration", - declarations: [ - { - type: "VariableDeclarator", - definite: false, - id: { - type: "Identifier", - decorators: [], - name: "x", - optional: false, - range: [6, 7], - loc: { - start: { - line: 1, - column: 6, - }, - end: { - line: 1, - column: 7, - }, - }, + type: "VariableDeclarator", + definite: false, + id: { + type: "Identifier", + decorators: [], + name: "x", + optional: false, + range: [6, 7], + loc: { + start: { + line: 1, + column: 6, + }, + end: { + line: 1, + column: 7, + }, + }, + }, + init: { + type: "CallExpression", + callee: { + type: "MemberExpression", + object: { + type: "TSSatisfiesExpression", + expression: { + type: "Literal", + value: 1, + raw: "1", + range: [11, 12], + loc: { + start: { + line: 1, + column: 11, }, - init: { - type: "CallExpression", - callee: { - type: "MemberExpression", - object: { - type: "TSSatisfiesExpression", - expression: { - type: "Literal", - value: 1, - raw: "1", - range: [11, 12], - loc: { - start: { - line: 1, - column: 11, - }, - end: { - line: 1, - column: 12, - }, - }, - }, - typeAnnotation: { - type: "TSNumberKeyword", - range: [23, 29], - loc: { - start: { - line: 1, - column: 23, - }, - end: { - line: 1, - column: 29, - }, - }, - }, - range: [11, 29], - loc: { - start: { - line: 1, - column: 11, - }, - end: { - line: 1, - column: 29, - }, - }, - }, - property: { - type: "Identifier", - decorators: [], - name: "toFixed", - optional: false, - range: [31, 38], - loc: { - start: { - line: 1, - column: 31, - }, - end: { - line: 1, - column: 38, - }, - }, - }, - computed: false, - optional: false, - range: [10, 38], - loc: { - start: { - line: 1, - column: 10, - }, - end: { - line: 1, - column: 38, - }, - }, - }, - arguments: [], - optional: false, - range: [10, 40], - loc: { - start: { - line: 1, - column: 10, - }, - end: { - line: 1, - column: 40, - }, - }, + end: { + line: 1, + column: 12, }, - range: [6, 40], - loc: { - start: { - line: 1, - column: 6, - }, - end: { - line: 1, - column: 40, - }, + }, + }, + typeAnnotation: { + type: "TSNumberKeyword", + range: [23, 29], + loc: { + start: { + line: 1, + column: 23, + }, + end: { + line: 1, + column: 29, }, + }, }, - ], - declare: false, - kind: "const", - range: [0, 41], - loc: { - start: { + range: [11, 29], + loc: { + start: { line: 1, - column: 0, - }, - end: { + column: 11, + }, + end: { line: 1, - column: 41, + column: 29, + }, }, - }, - }, - ], - comments: [], - range: [0, 42], - sourceType: "script", - tokens: [ - { - type: "Keyword", - value: "const", - range: [0, 5], - loc: { - start: { + }, + property: { + type: "Identifier", + decorators: [], + name: "toFixed", + optional: false, + range: [31, 38], + loc: { + start: { line: 1, - column: 0, - }, - end: { + column: 31, + }, + end: { line: 1, - column: 5, + column: 38, + }, }, - }, - }, - { - type: "Identifier", - value: "x", - range: [6, 7], - loc: { + }, + computed: false, + optional: false, + range: [10, 38], + loc: { start: { - line: 1, - column: 6, + line: 1, + column: 10, }, end: { - line: 1, - column: 7, + line: 1, + column: 38, }, + }, }, - }, - { - type: "Punctuator", - value: "=", - range: [8, 9], + arguments: [], + optional: false, + range: [10, 40], loc: { - start: { - line: 1, - column: 8, - }, - end: { - line: 1, - column: 9, - }, + start: { + line: 1, + column: 10, + }, + end: { + line: 1, + column: 40, + }, }, - }, - { - type: "Punctuator", - value: "(", - range: [10, 11], - loc: { - start: { - line: 1, - column: 10, - }, - end: { - line: 1, - column: 11, - }, + }, + range: [6, 40], + loc: { + start: { + line: 1, + column: 6, }, - }, - { - type: "Numeric", - value: "1", - range: [11, 12], - loc: { - start: { - line: 1, - column: 11, - }, - end: { - line: 1, - column: 12, - }, + end: { + line: 1, + column: 40, }, + }, }, - { - type: "Identifier", - value: "satisfies", - range: [13, 22], - loc: { - start: { - line: 1, - column: 13, - }, - end: { - line: 1, - column: 22, - }, - }, + ], + declare: false, + kind: "const", + range: [0, 41], + loc: { + start: { + line: 1, + column: 0, }, - { - type: "Identifier", - value: "number", - range: [23, 29], - loc: { - start: { - line: 1, - column: 23, - }, - end: { - line: 1, - column: 29, - }, - }, + end: { + line: 1, + column: 41, }, - { - type: "Punctuator", - value: ")", - range: [29, 30], - loc: { - start: { - line: 1, - column: 29, - }, - end: { - line: 1, - column: 30, - }, - }, + }, + }, + ], + comments: [], + range: [0, 41], + sourceType: "script", + tokens: [ + { + type: "Keyword", + value: "const", + range: [0, 5], + loc: { + start: { + line: 1, + column: 0, }, - { - type: "Punctuator", - value: ".", - range: [30, 31], - loc: { - start: { - line: 1, - column: 30, - }, - end: { - line: 1, - column: 31, - }, - }, + end: { + line: 1, + column: 5, }, - { - type: "Identifier", - value: "toFixed", - range: [31, 38], - loc: { - start: { - line: 1, - column: 31, - }, - end: { - line: 1, - column: 38, - }, - }, + }, + }, + { + type: "Identifier", + value: "x", + range: [6, 7], + loc: { + start: { + line: 1, + column: 6, }, - { - type: "Punctuator", - value: "(", - range: [38, 39], - loc: { - start: { - line: 1, - column: 38, - }, - end: { - line: 1, - column: 39, - }, - }, + end: { + line: 1, + column: 7, }, - { - type: "Punctuator", - value: ")", - range: [39, 40], - loc: { - start: { - line: 1, - column: 39, - }, - end: { - line: 1, - column: 40, - }, - }, + }, + }, + { + type: "Punctuator", + value: "=", + range: [8, 9], + loc: { + start: { + line: 1, + column: 8, }, - { - type: "Punctuator", - value: ";", - range: [40, 41], - loc: { - start: { - line: 1, - column: 40, - }, - end: { - line: 1, - column: 41, - }, - }, + end: { + line: 1, + column: 9, + }, + }, + }, + { + type: "Punctuator", + value: "(", + range: [10, 11], + loc: { + start: { + line: 1, + column: 10, }, - ], - loc: { + end: { + line: 1, + column: 11, + }, + }, + }, + { + type: "Numeric", + value: "1", + range: [11, 12], + loc: { start: { - line: 1, - column: 0, + line: 1, + column: 11, }, end: { - line: 2, - column: 0, + line: 1, + column: 12, + }, + }, + }, + { + type: "Identifier", + value: "satisfies", + range: [13, 22], + loc: { + start: { + line: 1, + column: 13, + }, + end: { + line: 1, + column: 22, + }, + }, + }, + { + type: "Identifier", + value: "number", + range: [23, 29], + loc: { + start: { + line: 1, + column: 23, + }, + end: { + line: 1, + column: 29, + }, + }, + }, + { + type: "Punctuator", + value: ")", + range: [29, 30], + loc: { + start: { + line: 1, + column: 29, + }, + end: { + line: 1, + column: 30, + }, + }, + }, + { + type: "Punctuator", + value: ".", + range: [30, 31], + loc: { + start: { + line: 1, + column: 30, }, + end: { + line: 1, + column: 31, + }, + }, + }, + { + type: "Identifier", + value: "toFixed", + range: [31, 38], + loc: { + start: { + line: 1, + column: 31, + }, + end: { + line: 1, + column: 38, + }, + }, + }, + { + type: "Punctuator", + value: "(", + range: [38, 39], + loc: { + start: { + line: 1, + column: 38, + }, + end: { + line: 1, + column: 39, + }, + }, + }, + { + type: "Punctuator", + value: ")", + range: [39, 40], + loc: { + start: { + line: 1, + column: 39, + }, + end: { + line: 1, + column: 40, + }, + }, + }, + { + type: "Punctuator", + value: ";", + range: [40, 41], + loc: { + start: { + line: 1, + column: 40, + }, + end: { + line: 1, + column: 41, + }, + }, + }, + ], + loc: { + start: { + line: 1, + column: 0, + }, + end: { + line: 1, + column: 41, }, + }, }); diff --git a/tests/lib/rules/logical-assignment-operators.js b/tests/lib/rules/logical-assignment-operators.js index 39c773d5378..36756815a90 100644 --- a/tests/lib/rules/logical-assignment-operators.js +++ b/tests/lib/rules/logical-assignment-operators.js @@ -1496,6 +1496,21 @@ ruleTester.run("logical-assignment-operators", rule, { output: "a.b.c ||= (d as number)" }] }] + }, + { + code: "(a.b.c || (a.b.c = d)) as number", + output: null, + parser: parser("typescript-parsers/logical-with-assignment-with-assertion-3"), + errors: [{ + messageId: "logical", + type: "LogicalExpression", + data: { operator: "||=" }, + suggestions: [{ + messageId: "convertLogical", + data: { operator: "||=" }, + output: "(a.b.c ||= d) as number" + }] + }] } ] }); diff --git a/tests/lib/rules/no-extra-boolean-cast.js b/tests/lib/rules/no-extra-boolean-cast.js index 69f34faaf76..5a6a9cd2140 100644 --- a/tests/lib/rules/no-extra-boolean-cast.js +++ b/tests/lib/rules/no-extra-boolean-cast.js @@ -2430,7 +2430,6 @@ ruleTester.run("no-extra-boolean-cast", rule, { { code: "if (!Boolean(a as any)) {}", output: "if (!(a as any)) {}", - options: [{ enforceForLogicalOperands: true }], parser: parser("typescript-parsers/boolean-cast-with-assertion"), parserOptions: { ecmaVersion: 2020 }, errors: [{ messageId: "unexpectedCall" }] From 36b2621d90757fa83868f3b0986ef369eefe4050 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Tue, 27 Jun 2023 11:08:48 +0930 Subject: [PATCH 5/5] Apply suggestions from code review Co-authored-by: Milos Djermanovic --- .../parsers/typescript-parsers/boolean-cast-with-assertion.js | 2 +- tests/lib/rules/no-extra-boolean-cast.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/fixtures/parsers/typescript-parsers/boolean-cast-with-assertion.js b/tests/fixtures/parsers/typescript-parsers/boolean-cast-with-assertion.js index 57d23df4793..caecf5c9191 100644 --- a/tests/fixtures/parsers/typescript-parsers/boolean-cast-with-assertion.js +++ b/tests/fixtures/parsers/typescript-parsers/boolean-cast-with-assertion.js @@ -3,7 +3,7 @@ /** * Parser: @typescript-eslint/parser 5.59.11 (TS 5.1.3) * Source code: - * if (!Boolean(a as any)) {} + * if (!Boolean(a as any)) { } */ exports.parse = () => ({ diff --git a/tests/lib/rules/no-extra-boolean-cast.js b/tests/lib/rules/no-extra-boolean-cast.js index 5a6a9cd2140..2e95cb740bb 100644 --- a/tests/lib/rules/no-extra-boolean-cast.js +++ b/tests/lib/rules/no-extra-boolean-cast.js @@ -2428,8 +2428,8 @@ ruleTester.run("no-extra-boolean-cast", rule, { // https://github.com/eslint/eslint/issues/17173 { - code: "if (!Boolean(a as any)) {}", - output: "if (!(a as any)) {}", + code: "if (!Boolean(a as any)) { }", + output: "if (!(a as any)) { }", parser: parser("typescript-parsers/boolean-cast-with-assertion"), parserOptions: { ecmaVersion: 2020 }, errors: [{ messageId: "unexpectedCall" }]