oxlint-plugin-eslint 1.52.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +36 -0
- package/common/ast-utils.cjs +5843 -0
- package/common/chunk.cjs +9 -0
- package/common/eslint-utils.cjs +1633 -0
- package/common/fix-tracker.cjs +89 -0
- package/common/ignore.cjs +123 -0
- package/common/keywords.cjs +15 -0
- package/common/regexpp.cjs +1720 -0
- package/common/regular-expressions.cjs +40 -0
- package/common/string-utils.cjs +39 -0
- package/index.js +7477 -0
- package/package.json +34 -0
- package/rules/accessor-pairs.cjs +233 -0
- package/rules/array-bracket-newline.cjs +172 -0
- package/rules/array-bracket-spacing.cjs +184 -0
- package/rules/array-callback-return.cjs +262 -0
- package/rules/array-element-newline.cjs +178 -0
- package/rules/arrow-body-style.cjs +135 -0
- package/rules/arrow-parens.cjs +130 -0
- package/rules/arrow-spacing.cjs +129 -0
- package/rules/block-scoped-var.cjs +101 -0
- package/rules/block-spacing.cjs +125 -0
- package/rules/brace-style.cjs +141 -0
- package/rules/callback-return.cjs +117 -0
- package/rules/camelcase.cjs +194 -0
- package/rules/capitalized-comments.cjs +168 -0
- package/rules/class-methods-use-this.cjs +155 -0
- package/rules/comma-dangle.cjs +274 -0
- package/rules/comma-spacing.cjs +111 -0
- package/rules/comma-style.cjs +180 -0
- package/rules/complexity.cjs +100 -0
- package/rules/computed-property-spacing.cjs +155 -0
- package/rules/consistent-return.cjs +113 -0
- package/rules/consistent-this.cjs +109 -0
- package/rules/constructor-super.cjs +207 -0
- package/rules/curly.cjs +173 -0
- package/rules/default-case-last.cjs +36 -0
- package/rules/default-case.cjs +50 -0
- package/rules/default-param-last.cjs +61 -0
- package/rules/dot-location.cjs +87 -0
- package/rules/dot-notation.cjs +77 -0
- package/rules/eol-last.cjs +91 -0
- package/rules/eqeqeq.cjs +127 -0
- package/rules/for-direction.cjs +94 -0
- package/rules/func-call-spacing.cjs +127 -0
- package/rules/func-name-matching.cjs +138 -0
- package/rules/func-names.cjs +121 -0
- package/rules/func-style.cjs +103 -0
- package/rules/function-call-argument-newline.cjs +109 -0
- package/rules/function-paren-newline.cjs +173 -0
- package/rules/generator-star-spacing.cjs +174 -0
- package/rules/getter-return.cjs +129 -0
- package/rules/global-require.cjs +84 -0
- package/rules/grouped-accessor-pairs.cjs +146 -0
- package/rules/guard-for-in.cjs +39 -0
- package/rules/handle-callback-err.cjs +86 -0
- package/rules/id-blacklist.cjs +135 -0
- package/rules/id-denylist.cjs +126 -0
- package/rules/id-length.cjs +119 -0
- package/rules/id-match.cjs +139 -0
- package/rules/implicit-arrow-linebreak.cjs +76 -0
- package/rules/indent-legacy.cjs +520 -0
- package/rules/indent.cjs +842 -0
- package/rules/init-declarations.cjs +88 -0
- package/rules/jsx-quotes.cjs +84 -0
- package/rules/key-spacing.cjs +399 -0
- package/rules/keyword-spacing.cjs +464 -0
- package/rules/line-comment-position.cjs +75 -0
- package/rules/linebreak-style.cjs +89 -0
- package/rules/lines-around-comment.cjs +290 -0
- package/rules/lines-around-directive.cjs +129 -0
- package/rules/lines-between-class-members.cjs +212 -0
- package/rules/logical-assignment-operators.cjs +305 -0
- package/rules/max-classes-per-file.cjs +61 -0
- package/rules/max-depth.cjs +117 -0
- package/rules/max-len.cjs +256 -0
- package/rules/max-lines-per-function.cjs +116 -0
- package/rules/max-lines.cjs +109 -0
- package/rules/max-nested-callbacks.cjs +78 -0
- package/rules/max-params.cjs +78 -0
- package/rules/max-statements-per-line.cjs +147 -0
- package/rules/max-statements.cjs +119 -0
- package/rules/multiline-comment-style.cjs +319 -0
- package/rules/multiline-ternary.cjs +106 -0
- package/rules/new-cap.cjs +139 -0
- package/rules/new-parens.cjs +70 -0
- package/rules/newline-after-var.cjs +159 -0
- package/rules/newline-before-return.cjs +128 -0
- package/rules/newline-per-chained-call.cjs +100 -0
- package/rules/no-alert.cjs +84 -0
- package/rules/no-array-constructor.cjs +91 -0
- package/rules/no-async-promise-executor.cjs +33 -0
- package/rules/no-await-in-loop.cjs +75 -0
- package/rules/no-bitwise.cjs +106 -0
- package/rules/no-buffer-constructor.cjs +51 -0
- package/rules/no-caller.cjs +34 -0
- package/rules/no-case-declarations.cjs +56 -0
- package/rules/no-catch-shadow.cjs +57 -0
- package/rules/no-class-assign.cjs +55 -0
- package/rules/no-compare-neg-zero.cjs +52 -0
- package/rules/no-cond-assign.cjs +104 -0
- package/rules/no-confusing-arrow.cjs +87 -0
- package/rules/no-console.cjs +138 -0
- package/rules/no-const-assign.cjs +50 -0
- package/rules/no-constant-binary-expression.cjs +284 -0
- package/rules/no-constant-condition.cjs +119 -0
- package/rules/no-constructor-return.cjs +43 -0
- package/rules/no-continue.cjs +33 -0
- package/rules/no-control-regex.cjs +74 -0
- package/rules/no-debugger.cjs +33 -0
- package/rules/no-delete-var.cjs +32 -0
- package/rules/no-div-regex.cjs +39 -0
- package/rules/no-dupe-args.cjs +61 -0
- package/rules/no-dupe-class-members.cjs +77 -0
- package/rules/no-dupe-else-if.cjs +74 -0
- package/rules/no-dupe-keys.cjs +88 -0
- package/rules/no-duplicate-case.cjs +49 -0
- package/rules/no-duplicate-imports.cjs +166 -0
- package/rules/no-else-return.cjs +182 -0
- package/rules/no-empty-character-class.cjs +47 -0
- package/rules/no-empty-function.cjs +141 -0
- package/rules/no-empty-pattern.cjs +50 -0
- package/rules/no-empty-static-block.cjs +50 -0
- package/rules/no-empty.cjs +78 -0
- package/rules/no-eq-null.cjs +34 -0
- package/rules/no-eval.cjs +165 -0
- package/rules/no-ex-assign.cjs +45 -0
- package/rules/no-extend-native.cjs +103 -0
- package/rules/no-extra-bind.cjs +127 -0
- package/rules/no-extra-boolean-cast.cjs +159 -0
- package/rules/no-extra-label.cjs +116 -0
- package/rules/no-extra-parens.cjs +665 -0
- package/rules/no-extra-semi.cjs +103 -0
- package/rules/no-fallthrough.cjs +136 -0
- package/rules/no-floating-decimal.cjs +66 -0
- package/rules/no-func-assign.cjs +63 -0
- package/rules/no-global-assign.cjs +62 -0
- package/rules/no-implicit-coercion.cjs +219 -0
- package/rules/no-implicit-globals.cjs +77 -0
- package/rules/no-implied-eval.cjs +87 -0
- package/rules/no-import-assign.cjs +123 -0
- package/rules/no-inline-comments.cjs +57 -0
- package/rules/no-inner-declarations.cjs +82 -0
- package/rules/no-invalid-regexp.cjs +130 -0
- package/rules/no-invalid-this.cjs +90 -0
- package/rules/no-irregular-whitespace.cjs +157 -0
- package/rules/no-iterator.cjs +34 -0
- package/rules/no-label-var.cjs +46 -0
- package/rules/no-labels.cjs +106 -0
- package/rules/no-lone-blocks.cjs +75 -0
- package/rules/no-lonely-if.cjs +42 -0
- package/rules/no-loop-func.cjs +143 -0
- package/rules/no-loss-of-precision.cjs +160 -0
- package/rules/no-magic-numbers.cjs +222 -0
- package/rules/no-misleading-character-class.cjs +500 -0
- package/rules/no-mixed-operators.cjs +197 -0
- package/rules/no-mixed-requires.cjs +117 -0
- package/rules/no-mixed-spaces-and-tabs.cjs +87 -0
- package/rules/no-multi-assign.cjs +38 -0
- package/rules/no-multi-spaces.cjs +95 -0
- package/rules/no-multi-str.cjs +44 -0
- package/rules/no-multiple-empty-lines.cjs +112 -0
- package/rules/no-native-reassign.cjs +72 -0
- package/rules/no-negated-condition.cjs +77 -0
- package/rules/no-negated-in-lhs.cjs +43 -0
- package/rules/no-nested-ternary.cjs +33 -0
- package/rules/no-new-func.cjs +50 -0
- package/rules/no-new-native-nonconstructor.cjs +42 -0
- package/rules/no-new-object.cjs +47 -0
- package/rules/no-new-require.cjs +50 -0
- package/rules/no-new-symbol.cjs +48 -0
- package/rules/no-new-wrappers.cjs +44 -0
- package/rules/no-new.cjs +33 -0
- package/rules/no-nonoctal-decimal-escape.cjs +80 -0
- package/rules/no-obj-calls.cjs +64 -0
- package/rules/no-object-constructor.cjs +69 -0
- package/rules/no-octal-escape.cjs +35 -0
- package/rules/no-octal.cjs +32 -0
- package/rules/no-param-reassign.cjs +135 -0
- package/rules/no-path-concat.cjs +52 -0
- package/rules/no-plusplus.cjs +64 -0
- package/rules/no-process-env.cjs +51 -0
- package/rules/no-process-exit.cjs +50 -0
- package/rules/no-promise-executor-return.cjs +131 -0
- package/rules/no-proto.cjs +34 -0
- package/rules/no-prototype-builtins.cjs +85 -0
- package/rules/no-redeclare.cjs +103 -0
- package/rules/no-regex-spaces.cjs +115 -0
- package/rules/no-restricted-exports.cjs +117 -0
- package/rules/no-restricted-globals.cjs +147 -0
- package/rules/no-restricted-imports.cjs +421 -0
- package/rules/no-restricted-modules.cjs +144 -0
- package/rules/no-restricted-properties.cjs +123 -0
- package/rules/no-restricted-syntax.cjs +49 -0
- package/rules/no-return-assign.cjs +45 -0
- package/rules/no-return-await.cjs +88 -0
- package/rules/no-script-url.cjs +49 -0
- package/rules/no-self-assign.cjs +88 -0
- package/rules/no-self-compare.cjs +53 -0
- package/rules/no-sequences.cjs +81 -0
- package/rules/no-setter-return.cjs +110 -0
- package/rules/no-shadow-restricted-names.cjs +60 -0
- package/rules/no-shadow.cjs +302 -0
- package/rules/no-spaced-func.cjs +69 -0
- package/rules/no-sparse-arrays.cjs +40 -0
- package/rules/no-sync.cjs +58 -0
- package/rules/no-tabs.cjs +73 -0
- package/rules/no-template-curly-in-string.cjs +33 -0
- package/rules/no-ternary.cjs +33 -0
- package/rules/no-this-before-super.cjs +177 -0
- package/rules/no-throw-literal.cjs +40 -0
- package/rules/no-trailing-spaces.cjs +123 -0
- package/rules/no-unassigned-vars.cjs +54 -0
- package/rules/no-undef-init.cjs +46 -0
- package/rules/no-undef.cjs +51 -0
- package/rules/no-undefined.cjs +58 -0
- package/rules/no-underscore-dangle.cjs +211 -0
- package/rules/no-unexpected-multiline.cjs +76 -0
- package/rules/no-unmodified-loop-condition.cjs +849 -0
- package/rules/no-unneeded-ternary.cjs +112 -0
- package/rules/no-unreachable-loop.cjs +128 -0
- package/rules/no-unreachable.cjs +195 -0
- package/rules/no-unsafe-finally.cjs +67 -0
- package/rules/no-unsafe-negation.cjs +86 -0
- package/rules/no-unsafe-optional-chaining.cjs +164 -0
- package/rules/no-unused-expressions.cjs +163 -0
- package/rules/no-unused-labels.cjs +97 -0
- package/rules/no-unused-private-class-members.cjs +69 -0
- package/rules/no-unused-vars.cjs +639 -0
- package/rules/no-use-before-define.cjs +245 -0
- package/rules/no-useless-assignment.cjs +250 -0
- package/rules/no-useless-backreference.cjs +137 -0
- package/rules/no-useless-call.cjs +57 -0
- package/rules/no-useless-catch.cjs +38 -0
- package/rules/no-useless-computed-key.cjs +106 -0
- package/rules/no-useless-concat.cjs +78 -0
- package/rules/no-useless-constructor.cjs +152 -0
- package/rules/no-useless-escape.cjs +164 -0
- package/rules/no-useless-rename.cjs +94 -0
- package/rules/no-useless-return.cjs +229 -0
- package/rules/no-var.cjs +235 -0
- package/rules/no-void.cjs +39 -0
- package/rules/no-warning-comments.cjs +112 -0
- package/rules/no-whitespace-before-property.cjs +72 -0
- package/rules/no-with.cjs +32 -0
- package/rules/nonblock-statement-body-position.cjs +107 -0
- package/rules/object-curly-newline.cjs +194 -0
- package/rules/object-curly-spacing.cjs +225 -0
- package/rules/object-property-newline.cjs +81 -0
- package/rules/object-shorthand.cjs +284 -0
- package/rules/one-var-declaration-per-line.cjs +75 -0
- package/rules/one-var.cjs +378 -0
- package/rules/operator-assignment.cjs +146 -0
- package/rules/operator-linebreak.cjs +150 -0
- package/rules/padded-blocks.cjs +192 -0
- package/rules/padding-line-between-statements.cjs +377 -0
- package/rules/prefer-arrow-callback.cjs +185 -0
- package/rules/prefer-const.cjs +240 -0
- package/rules/prefer-destructuring.cjs +188 -0
- package/rules/prefer-exponentiation-operator.cjs +100 -0
- package/rules/prefer-named-capture-group.cjs +111 -0
- package/rules/prefer-numeric-literals.cjs +75 -0
- package/rules/prefer-object-has-own.cjs +54 -0
- package/rules/prefer-object-spread.cjs +170 -0
- package/rules/prefer-promise-reject-errors.cjs +62 -0
- package/rules/prefer-reflect.cjs +100 -0
- package/rules/prefer-regex-literals.cjs +256 -0
- package/rules/prefer-rest-params.cjs +80 -0
- package/rules/prefer-spread.cjs +57 -0
- package/rules/prefer-template.cjs +147 -0
- package/rules/preserve-caught-error.cjs +196 -0
- package/rules/quote-props.cjs +224 -0
- package/rules/quotes.cjs +187 -0
- package/rules/radix.cjs +124 -0
- package/rules/require-atomic-updates.cjs +197 -0
- package/rules/require-await.cjs +90 -0
- package/rules/require-unicode-regexp.cjs +101 -0
- package/rules/require-yield.cjs +56 -0
- package/rules/rest-spread-spacing.cjs +99 -0
- package/rules/semi-spacing.cjs +215 -0
- package/rules/semi-style.cjs +116 -0
- package/rules/semi.cjs +239 -0
- package/rules/sort-imports.cjs +140 -0
- package/rules/sort-keys.cjs +165 -0
- package/rules/sort-vars.cjs +50 -0
- package/rules/space-before-blocks.cjs +132 -0
- package/rules/space-before-function-paren.cjs +126 -0
- package/rules/space-in-parens.cjs +175 -0
- package/rules/space-infix-ops.cjs +133 -0
- package/rules/space-unary-ops.cjs +237 -0
- package/rules/spaced-comment.cjs +233 -0
- package/rules/strict.cjs +206 -0
- package/rules/switch-colon-spacing.cjs +114 -0
- package/rules/symbol-description.cjs +49 -0
- package/rules/template-curly-spacing.cjs +112 -0
- package/rules/template-tag-spacing.cjs +82 -0
- package/rules/unicode-bom.cjs +52 -0
- package/rules/use-isnan.cjs +144 -0
- package/rules/valid-typeof.cjs +104 -0
- package/rules/vars-on-top.cjs +94 -0
- package/rules/wrap-iife.cjs +131 -0
- package/rules/wrap-regex.cjs +57 -0
- package/rules/yield-star-spacing.cjs +115 -0
- package/rules/yoda.cjs +185 -0
|
@@ -0,0 +1,665 @@
|
|
|
1
|
+
const require_chunk = require("../common/chunk.cjs"), require_ast_utils$1 = require("../common/ast-utils.cjs"), require_eslint_utils$1 = require("../common/eslint-utils.cjs");
|
|
2
|
+
//#region ../../node_modules/.pnpm/eslint@9.39.3_jiti@2.6.1/node_modules/eslint/lib/rules/no-extra-parens.js
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Disallow parenthesising higher precedence subexpressions.
|
|
5
|
+
* @author Michael Ficarra
|
|
6
|
+
* @deprecated in ESLint v8.53.0
|
|
7
|
+
*/
|
|
8
|
+
var require_no_extra_parens = /* @__PURE__ */ require_chunk.t(((exports, module) => {
|
|
9
|
+
let { isParenthesized: isParenthesizedRaw } = require_eslint_utils$1.t(), astUtils = require_ast_utils$1.t();
|
|
10
|
+
/** @type {import('../types').Rule.RuleModule} */
|
|
11
|
+
module.exports = {
|
|
12
|
+
meta: {
|
|
13
|
+
deprecated: {
|
|
14
|
+
message: "Formatting rules are being moved out of ESLint core.",
|
|
15
|
+
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
|
|
16
|
+
deprecatedSince: "8.53.0",
|
|
17
|
+
availableUntil: "11.0.0",
|
|
18
|
+
replacedBy: [{
|
|
19
|
+
message: "ESLint Stylistic now maintains deprecated stylistic core rules.",
|
|
20
|
+
url: "https://eslint.style/guide/migration",
|
|
21
|
+
plugin: {
|
|
22
|
+
name: "@stylistic/eslint-plugin",
|
|
23
|
+
url: "https://eslint.style"
|
|
24
|
+
},
|
|
25
|
+
rule: {
|
|
26
|
+
name: "no-extra-parens",
|
|
27
|
+
url: "https://eslint.style/rules/no-extra-parens"
|
|
28
|
+
}
|
|
29
|
+
}]
|
|
30
|
+
},
|
|
31
|
+
type: "layout",
|
|
32
|
+
docs: {
|
|
33
|
+
description: "Disallow unnecessary parentheses",
|
|
34
|
+
recommended: !1,
|
|
35
|
+
url: "https://eslint.org/docs/latest/rules/no-extra-parens"
|
|
36
|
+
},
|
|
37
|
+
fixable: "code",
|
|
38
|
+
schema: { anyOf: [{
|
|
39
|
+
type: "array",
|
|
40
|
+
items: [{ enum: ["functions"] }],
|
|
41
|
+
minItems: 0,
|
|
42
|
+
maxItems: 1
|
|
43
|
+
}, {
|
|
44
|
+
type: "array",
|
|
45
|
+
items: [{ enum: ["all"] }, {
|
|
46
|
+
type: "object",
|
|
47
|
+
properties: {
|
|
48
|
+
conditionalAssign: { type: "boolean" },
|
|
49
|
+
ternaryOperandBinaryExpressions: { type: "boolean" },
|
|
50
|
+
nestedBinaryExpressions: { type: "boolean" },
|
|
51
|
+
returnAssign: { type: "boolean" },
|
|
52
|
+
ignoreJSX: { enum: [
|
|
53
|
+
"none",
|
|
54
|
+
"all",
|
|
55
|
+
"single-line",
|
|
56
|
+
"multi-line"
|
|
57
|
+
] },
|
|
58
|
+
enforceForArrowConditionals: { type: "boolean" },
|
|
59
|
+
enforceForSequenceExpressions: { type: "boolean" },
|
|
60
|
+
enforceForNewInMemberExpressions: { type: "boolean" },
|
|
61
|
+
enforceForFunctionPrototypeMethods: { type: "boolean" },
|
|
62
|
+
allowParensAfterCommentPattern: { type: "string" }
|
|
63
|
+
},
|
|
64
|
+
additionalProperties: !1
|
|
65
|
+
}],
|
|
66
|
+
minItems: 0,
|
|
67
|
+
maxItems: 2
|
|
68
|
+
}] },
|
|
69
|
+
messages: { unexpected: "Unnecessary parentheses around expression." }
|
|
70
|
+
},
|
|
71
|
+
create(context) {
|
|
72
|
+
let sourceCode = context.sourceCode, tokensToIgnore = /* @__PURE__ */ new WeakSet(), precedence = astUtils.getPrecedence, ALL_NODES = context.options[0] !== "functions", EXCEPT_COND_ASSIGN = ALL_NODES && context.options[1] && context.options[1].conditionalAssign === !1, EXCEPT_COND_TERNARY = ALL_NODES && context.options[1] && context.options[1].ternaryOperandBinaryExpressions === !1, NESTED_BINARY = ALL_NODES && context.options[1] && context.options[1].nestedBinaryExpressions === !1, EXCEPT_RETURN_ASSIGN = ALL_NODES && context.options[1] && context.options[1].returnAssign === !1, IGNORE_JSX = ALL_NODES && context.options[1] && context.options[1].ignoreJSX, IGNORE_ARROW_CONDITIONALS = ALL_NODES && context.options[1] && context.options[1].enforceForArrowConditionals === !1, IGNORE_SEQUENCE_EXPRESSIONS = ALL_NODES && context.options[1] && context.options[1].enforceForSequenceExpressions === !1, IGNORE_NEW_IN_MEMBER_EXPR = ALL_NODES && context.options[1] && context.options[1].enforceForNewInMemberExpressions === !1, IGNORE_FUNCTION_PROTOTYPE_METHODS = ALL_NODES && context.options[1] && context.options[1].enforceForFunctionPrototypeMethods === !1, ALLOW_PARENS_AFTER_COMMENT_PATTERN = ALL_NODES && context.options[1] && context.options[1].allowParensAfterCommentPattern, PRECEDENCE_OF_ASSIGNMENT_EXPR = precedence({ type: "AssignmentExpression" }), PRECEDENCE_OF_UPDATE_EXPR = precedence({ type: "UpdateExpression" }), reportsBuffer;
|
|
73
|
+
/**
|
|
74
|
+
* Determines whether the given node is a `call` or `apply` method call, invoked directly on a `FunctionExpression` node.
|
|
75
|
+
* Example: function(){}.call()
|
|
76
|
+
* @param {ASTNode} node The node to be checked.
|
|
77
|
+
* @returns {boolean} True if the node is an immediate `call` or `apply` method call.
|
|
78
|
+
* @private
|
|
79
|
+
*/
|
|
80
|
+
function isImmediateFunctionPrototypeMethodCall(node) {
|
|
81
|
+
let callNode = astUtils.skipChainExpression(node);
|
|
82
|
+
if (callNode.type !== "CallExpression") return !1;
|
|
83
|
+
let callee = astUtils.skipChainExpression(callNode.callee);
|
|
84
|
+
return callee.type === "MemberExpression" && callee.object.type === "FunctionExpression" && ["call", "apply"].includes(astUtils.getStaticPropertyName(callee));
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Determines if this rule should be enforced for a node given the current configuration.
|
|
88
|
+
* @param {ASTNode} node The node to be checked.
|
|
89
|
+
* @returns {boolean} True if the rule should be enforced for this node.
|
|
90
|
+
* @private
|
|
91
|
+
*/
|
|
92
|
+
function ruleApplies(node) {
|
|
93
|
+
if (node.type === "JSXElement" || node.type === "JSXFragment") {
|
|
94
|
+
let isSingleLine = node.loc.start.line === node.loc.end.line;
|
|
95
|
+
switch (IGNORE_JSX) {
|
|
96
|
+
case "all": return !1;
|
|
97
|
+
case "multi-line": return isSingleLine;
|
|
98
|
+
case "single-line": return !isSingleLine;
|
|
99
|
+
case "none": break;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return node.type === "SequenceExpression" && IGNORE_SEQUENCE_EXPRESSIONS || isImmediateFunctionPrototypeMethodCall(node) && IGNORE_FUNCTION_PROTOTYPE_METHODS ? !1 : ALL_NODES || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression";
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Determines if a node is surrounded by parentheses.
|
|
106
|
+
* @param {ASTNode} node The node to be checked.
|
|
107
|
+
* @returns {boolean} True if the node is parenthesised.
|
|
108
|
+
* @private
|
|
109
|
+
*/
|
|
110
|
+
function isParenthesised(node) {
|
|
111
|
+
return isParenthesizedRaw(1, node, sourceCode);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Determines if a node is surrounded by parentheses twice.
|
|
115
|
+
* @param {ASTNode} node The node to be checked.
|
|
116
|
+
* @returns {boolean} True if the node is doubly parenthesised.
|
|
117
|
+
* @private
|
|
118
|
+
*/
|
|
119
|
+
function isParenthesisedTwice(node) {
|
|
120
|
+
return isParenthesizedRaw(2, node, sourceCode);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Determines if a node is surrounded by (potentially) invalid parentheses.
|
|
124
|
+
* @param {ASTNode} node The node to be checked.
|
|
125
|
+
* @returns {boolean} True if the node is incorrectly parenthesised.
|
|
126
|
+
* @private
|
|
127
|
+
*/
|
|
128
|
+
function hasExcessParens(node) {
|
|
129
|
+
return ruleApplies(node) && isParenthesised(node);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Determines if a node that is expected to be parenthesised is surrounded by
|
|
133
|
+
* (potentially) invalid extra parentheses.
|
|
134
|
+
* @param {ASTNode} node The node to be checked.
|
|
135
|
+
* @returns {boolean} True if the node is has an unexpected extra pair of parentheses.
|
|
136
|
+
* @private
|
|
137
|
+
*/
|
|
138
|
+
function hasDoubleExcessParens(node) {
|
|
139
|
+
return ruleApplies(node) && isParenthesisedTwice(node);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Determines if a node that is expected to be parenthesised is surrounded by
|
|
143
|
+
* (potentially) invalid extra parentheses with considering precedence level of the node.
|
|
144
|
+
* If the preference level of the node is not higher or equal to precedence lower limit, it also checks
|
|
145
|
+
* whether the node is surrounded by parentheses twice or not.
|
|
146
|
+
* @param {ASTNode} node The node to be checked.
|
|
147
|
+
* @param {number} precedenceLowerLimit The lower limit of precedence.
|
|
148
|
+
* @returns {boolean} True if the node is has an unexpected extra pair of parentheses.
|
|
149
|
+
* @private
|
|
150
|
+
*/
|
|
151
|
+
function hasExcessParensWithPrecedence(node, precedenceLowerLimit) {
|
|
152
|
+
return !!(ruleApplies(node) && isParenthesised(node) && (precedence(node) >= precedenceLowerLimit || isParenthesisedTwice(node)));
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Determines if a node test expression is allowed to have a parenthesised assignment
|
|
156
|
+
* @param {ASTNode} node The node to be checked.
|
|
157
|
+
* @returns {boolean} True if the assignment can be parenthesised.
|
|
158
|
+
* @private
|
|
159
|
+
*/
|
|
160
|
+
function isCondAssignException(node) {
|
|
161
|
+
return EXCEPT_COND_ASSIGN && node.test.type === "AssignmentExpression";
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Determines if a node is in a return statement
|
|
165
|
+
* @param {ASTNode} node The node to be checked.
|
|
166
|
+
* @returns {boolean} True if the node is in a return statement.
|
|
167
|
+
* @private
|
|
168
|
+
*/
|
|
169
|
+
function isInReturnStatement(node) {
|
|
170
|
+
for (let currentNode = node; currentNode; currentNode = currentNode.parent) if (currentNode.type === "ReturnStatement" || currentNode.type === "ArrowFunctionExpression" && currentNode.body.type !== "BlockStatement") return !0;
|
|
171
|
+
return !1;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Determines if a constructor function is newed-up with parens
|
|
175
|
+
* @param {ASTNode} newExpression The NewExpression node to be checked.
|
|
176
|
+
* @returns {boolean} True if the constructor is called with parens.
|
|
177
|
+
* @private
|
|
178
|
+
*/
|
|
179
|
+
function isNewExpressionWithParens(newExpression) {
|
|
180
|
+
let lastToken = sourceCode.getLastToken(newExpression), penultimateToken = sourceCode.getTokenBefore(lastToken);
|
|
181
|
+
return newExpression.arguments.length > 0 || astUtils.isOpeningParenToken(penultimateToken) && astUtils.isClosingParenToken(lastToken) && newExpression.callee.range[1] < newExpression.range[1];
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Determines if a node is or contains an assignment expression
|
|
185
|
+
* @param {ASTNode} node The node to be checked.
|
|
186
|
+
* @returns {boolean} True if the node is or contains an assignment expression.
|
|
187
|
+
* @private
|
|
188
|
+
*/
|
|
189
|
+
function containsAssignment(node) {
|
|
190
|
+
return !!(node.type === "AssignmentExpression" || node.type === "ConditionalExpression" && (node.consequent.type === "AssignmentExpression" || node.alternate.type === "AssignmentExpression") || node.left && node.left.type === "AssignmentExpression" || node.right && node.right.type === "AssignmentExpression");
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Determines if a node is contained by or is itself a return statement and is allowed to have a parenthesised assignment
|
|
194
|
+
* @param {ASTNode} node The node to be checked.
|
|
195
|
+
* @returns {boolean} True if the assignment can be parenthesised.
|
|
196
|
+
* @private
|
|
197
|
+
*/
|
|
198
|
+
function isReturnAssignException(node) {
|
|
199
|
+
return !EXCEPT_RETURN_ASSIGN || !isInReturnStatement(node) ? !1 : node.type === "ReturnStatement" ? node.argument && containsAssignment(node.argument) : node.type === "ArrowFunctionExpression" && node.body.type !== "BlockStatement" ? containsAssignment(node.body) : containsAssignment(node);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Determines if a node following a [no LineTerminator here] restriction is
|
|
203
|
+
* surrounded by (potentially) invalid extra parentheses.
|
|
204
|
+
* @param {Token} token The token preceding the [no LineTerminator here] restriction.
|
|
205
|
+
* @param {ASTNode} node The node to be checked.
|
|
206
|
+
* @returns {boolean} True if the node is incorrectly parenthesised.
|
|
207
|
+
* @private
|
|
208
|
+
*/
|
|
209
|
+
function hasExcessParensNoLineTerminator(token, node) {
|
|
210
|
+
return token.loc.end.line === node.loc.start.line ? hasExcessParens(node) : hasDoubleExcessParens(node);
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Determines whether a node should be preceded by an additional space when removing parens
|
|
214
|
+
* @param {ASTNode} node node to evaluate; must be surrounded by parentheses
|
|
215
|
+
* @returns {boolean} `true` if a space should be inserted before the node
|
|
216
|
+
* @private
|
|
217
|
+
*/
|
|
218
|
+
function requiresLeadingSpace(node) {
|
|
219
|
+
let leftParenToken = sourceCode.getTokenBefore(node), tokenBeforeLeftParen = sourceCode.getTokenBefore(leftParenToken, { includeComments: !0 }), tokenAfterLeftParen = sourceCode.getTokenAfter(leftParenToken, { includeComments: !0 });
|
|
220
|
+
return tokenBeforeLeftParen && tokenBeforeLeftParen.range[1] === leftParenToken.range[0] && leftParenToken.range[1] === tokenAfterLeftParen.range[0] && !astUtils.canTokensBeAdjacent(tokenBeforeLeftParen, tokenAfterLeftParen);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Determines whether a node should be followed by an additional space when removing parens
|
|
224
|
+
* @param {ASTNode} node node to evaluate; must be surrounded by parentheses
|
|
225
|
+
* @returns {boolean} `true` if a space should be inserted after the node
|
|
226
|
+
* @private
|
|
227
|
+
*/
|
|
228
|
+
function requiresTrailingSpace(node) {
|
|
229
|
+
let nextTwoTokens = sourceCode.getTokensAfter(node, { count: 2 }), rightParenToken = nextTwoTokens[0], tokenAfterRightParen = nextTwoTokens[1], tokenBeforeRightParen = sourceCode.getLastToken(node);
|
|
230
|
+
return rightParenToken && tokenAfterRightParen && !sourceCode.isSpaceBetweenTokens(rightParenToken, tokenAfterRightParen) && !astUtils.canTokensBeAdjacent(tokenBeforeRightParen, tokenAfterRightParen);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Determines if a given expression node is an IIFE
|
|
234
|
+
* @param {ASTNode} node The node to check
|
|
235
|
+
* @returns {boolean} `true` if the given node is an IIFE
|
|
236
|
+
*/
|
|
237
|
+
function isIIFE(node) {
|
|
238
|
+
let maybeCallNode = astUtils.skipChainExpression(node);
|
|
239
|
+
return maybeCallNode.type === "CallExpression" && maybeCallNode.callee.type === "FunctionExpression";
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Determines if the given node can be the assignment target in destructuring or the LHS of an assignment.
|
|
243
|
+
* This is to avoid an autofix that could change behavior because parsers mistakenly allow invalid syntax,
|
|
244
|
+
* such as `(a = b) = c` and `[(a = b) = c] = []`. Ideally, this function shouldn't be necessary.
|
|
245
|
+
* @param {ASTNode} [node] The node to check
|
|
246
|
+
* @returns {boolean} `true` if the given node can be a valid assignment target
|
|
247
|
+
*/
|
|
248
|
+
function canBeAssignmentTarget(node) {
|
|
249
|
+
return node && (node.type === "Identifier" || node.type === "MemberExpression");
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Checks if a node is fixable.
|
|
253
|
+
* A node is fixable if removing a single pair of surrounding parentheses does not turn it
|
|
254
|
+
* into a directive after fixing other nodes.
|
|
255
|
+
* Almost all nodes are fixable, except if all of the following conditions are met:
|
|
256
|
+
* The node is a string Literal
|
|
257
|
+
* It has a single pair of parentheses
|
|
258
|
+
* It is the only child of an ExpressionStatement
|
|
259
|
+
* @param {ASTNode} node The node to evaluate.
|
|
260
|
+
* @returns {boolean} Whether or not the node is fixable.
|
|
261
|
+
* @private
|
|
262
|
+
*/
|
|
263
|
+
function isFixable(node) {
|
|
264
|
+
return node.type !== "Literal" || typeof node.value != "string" || isParenthesisedTwice(node) ? !0 : !astUtils.isTopLevelExpressionStatement(node.parent);
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Report the node
|
|
268
|
+
* @param {ASTNode} node node to evaluate
|
|
269
|
+
* @returns {void}
|
|
270
|
+
* @private
|
|
271
|
+
*/
|
|
272
|
+
function report(node) {
|
|
273
|
+
let leftParenToken = sourceCode.getTokenBefore(node), rightParenToken = sourceCode.getTokenAfter(node);
|
|
274
|
+
if (!isParenthesisedTwice(node)) {
|
|
275
|
+
if (tokensToIgnore.has(sourceCode.getFirstToken(node)) || isIIFE(node) && !isParenthesised(node.callee)) return;
|
|
276
|
+
if (ALLOW_PARENS_AFTER_COMMENT_PATTERN) {
|
|
277
|
+
let commentsBeforeLeftParenToken = sourceCode.getCommentsBefore(leftParenToken), totalCommentsBeforeLeftParenTokenCount = commentsBeforeLeftParenToken.length, ignorePattern = new RegExp(ALLOW_PARENS_AFTER_COMMENT_PATTERN, "u");
|
|
278
|
+
if (totalCommentsBeforeLeftParenTokenCount > 0 && ignorePattern.test(commentsBeforeLeftParenToken[totalCommentsBeforeLeftParenTokenCount - 1].value)) return;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Finishes reporting
|
|
283
|
+
* @returns {void}
|
|
284
|
+
* @private
|
|
285
|
+
*/
|
|
286
|
+
function finishReport() {
|
|
287
|
+
context.report({
|
|
288
|
+
node,
|
|
289
|
+
loc: leftParenToken.loc,
|
|
290
|
+
messageId: "unexpected",
|
|
291
|
+
fix: isFixable(node) ? (fixer) => {
|
|
292
|
+
let parenthesizedSource = sourceCode.text.slice(leftParenToken.range[1], rightParenToken.range[0]);
|
|
293
|
+
return fixer.replaceTextRange([leftParenToken.range[0], rightParenToken.range[1]], (requiresLeadingSpace(node) ? " " : "") + parenthesizedSource + (requiresTrailingSpace(node) ? " " : ""));
|
|
294
|
+
} : null
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
if (reportsBuffer) {
|
|
298
|
+
reportsBuffer.reports.push({
|
|
299
|
+
node,
|
|
300
|
+
finishReport
|
|
301
|
+
});
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
finishReport();
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Evaluate a argument of the node.
|
|
308
|
+
* @param {ASTNode} node node to evaluate
|
|
309
|
+
* @returns {void}
|
|
310
|
+
* @private
|
|
311
|
+
*/
|
|
312
|
+
function checkArgumentWithPrecedence(node) {
|
|
313
|
+
hasExcessParensWithPrecedence(node.argument, precedence(node)) && report(node.argument);
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Check if a member expression contains a call expression
|
|
317
|
+
* @param {ASTNode} node MemberExpression node to evaluate
|
|
318
|
+
* @returns {boolean} true if found, false if not
|
|
319
|
+
*/
|
|
320
|
+
function doesMemberExpressionContainCallExpression(node) {
|
|
321
|
+
let currentNode = node.object, currentNodeType = node.object.type;
|
|
322
|
+
for (; currentNodeType === "MemberExpression";) currentNode = currentNode.object, currentNodeType = currentNode.type;
|
|
323
|
+
return currentNodeType === "CallExpression";
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Evaluate a new call
|
|
327
|
+
* @param {ASTNode} node node to evaluate
|
|
328
|
+
* @returns {void}
|
|
329
|
+
* @private
|
|
330
|
+
*/
|
|
331
|
+
function checkCallNew(node) {
|
|
332
|
+
let callee = node.callee;
|
|
333
|
+
hasExcessParensWithPrecedence(callee, precedence(node)) && (hasDoubleExcessParens(callee) || !(isIIFE(node) || callee.type === "NewExpression" && !isNewExpressionWithParens(callee) && !(node.type === "NewExpression" && !isNewExpressionWithParens(node)) || node.type === "NewExpression" && callee.type === "MemberExpression" && doesMemberExpressionContainCallExpression(callee) || !node.optional && callee.type === "ChainExpression")) && report(node.callee), node.arguments.filter((arg) => hasExcessParensWithPrecedence(arg, PRECEDENCE_OF_ASSIGNMENT_EXPR)).forEach(report);
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Evaluate binary logicals
|
|
337
|
+
* @param {ASTNode} node node to evaluate
|
|
338
|
+
* @returns {void}
|
|
339
|
+
* @private
|
|
340
|
+
*/
|
|
341
|
+
function checkBinaryLogical(node) {
|
|
342
|
+
let prec = precedence(node), leftPrecedence = precedence(node.left), rightPrecedence = precedence(node.right), isExponentiation = node.operator === "**", shouldSkipLeft = NESTED_BINARY && (node.left.type === "BinaryExpression" || node.left.type === "LogicalExpression"), shouldSkipRight = NESTED_BINARY && (node.right.type === "BinaryExpression" || node.right.type === "LogicalExpression");
|
|
343
|
+
!shouldSkipLeft && hasExcessParens(node.left) && (!(["AwaitExpression", "UnaryExpression"].includes(node.left.type) && isExponentiation) && !astUtils.isMixedLogicalAndCoalesceExpressions(node.left, node) && (leftPrecedence > prec || leftPrecedence === prec && !isExponentiation) || isParenthesisedTwice(node.left)) && report(node.left), !shouldSkipRight && hasExcessParens(node.right) && (!astUtils.isMixedLogicalAndCoalesceExpressions(node.right, node) && (rightPrecedence > prec || rightPrecedence === prec && isExponentiation) || isParenthesisedTwice(node.right)) && report(node.right);
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Check the parentheses around the super class of the given class definition.
|
|
347
|
+
* @param {ASTNode} node The node of class declarations to check.
|
|
348
|
+
* @returns {void}
|
|
349
|
+
*/
|
|
350
|
+
function checkClass(node) {
|
|
351
|
+
node.superClass && (precedence(node.superClass) > PRECEDENCE_OF_UPDATE_EXPR ? hasExcessParens(node.superClass) : hasDoubleExcessParens(node.superClass)) && report(node.superClass);
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Check the parentheses around the argument of the given spread operator.
|
|
355
|
+
* @param {ASTNode} node The node of spread elements/properties to check.
|
|
356
|
+
* @returns {void}
|
|
357
|
+
*/
|
|
358
|
+
function checkSpreadOperator(node) {
|
|
359
|
+
hasExcessParensWithPrecedence(node.argument, PRECEDENCE_OF_ASSIGNMENT_EXPR) && report(node.argument);
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Checks the parentheses for an ExpressionStatement or ExportDefaultDeclaration
|
|
363
|
+
* @param {ASTNode} node The ExpressionStatement.expression or ExportDefaultDeclaration.declaration node
|
|
364
|
+
* @returns {void}
|
|
365
|
+
*/
|
|
366
|
+
function checkExpressionOrExportStatement(node) {
|
|
367
|
+
let firstToken = isParenthesised(node) ? sourceCode.getTokenBefore(node) : sourceCode.getFirstToken(node), secondToken = sourceCode.getTokenAfter(firstToken, astUtils.isNotOpeningParenToken), thirdToken = secondToken ? sourceCode.getTokenAfter(secondToken) : null, tokenAfterClosingParens = secondToken ? sourceCode.getTokenAfter(secondToken, astUtils.isNotClosingParenToken) : null;
|
|
368
|
+
astUtils.isOpeningParenToken(firstToken) && (astUtils.isOpeningBraceToken(secondToken) || secondToken.type === "Keyword" && (secondToken.value === "function" || secondToken.value === "class" || secondToken.value === "let" && tokenAfterClosingParens && (astUtils.isOpeningBracketToken(tokenAfterClosingParens) || tokenAfterClosingParens.type === "Identifier")) || secondToken && secondToken.type === "Identifier" && secondToken.value === "async" && thirdToken && thirdToken.type === "Keyword" && thirdToken.value === "function") && tokensToIgnore.add(secondToken), (node.parent.type === "ExportDefaultDeclaration" ? hasExcessParensWithPrecedence(node, PRECEDENCE_OF_ASSIGNMENT_EXPR) : hasExcessParens(node)) && report(node);
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Finds the path from the given node to the specified ancestor.
|
|
372
|
+
* @param {ASTNode} node First node in the path.
|
|
373
|
+
* @param {ASTNode} ancestor Last node in the path.
|
|
374
|
+
* @returns {ASTNode[]} Path, including both nodes.
|
|
375
|
+
* @throws {Error} If the given node does not have the specified ancestor.
|
|
376
|
+
*/
|
|
377
|
+
function pathToAncestor(node, ancestor) {
|
|
378
|
+
let path = [node], currentNode = node;
|
|
379
|
+
for (; currentNode !== ancestor;) {
|
|
380
|
+
/* c8 ignore start */
|
|
381
|
+
if (currentNode = currentNode.parent, currentNode === null) throw Error("Nodes are not in the ancestor-descendant relationship.");
|
|
382
|
+
path.push(currentNode);
|
|
383
|
+
}
|
|
384
|
+
return path;
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Finds the path from the given node to the specified descendant.
|
|
388
|
+
* @param {ASTNode} node First node in the path.
|
|
389
|
+
* @param {ASTNode} descendant Last node in the path.
|
|
390
|
+
* @returns {ASTNode[]} Path, including both nodes.
|
|
391
|
+
* @throws {Error} If the given node does not have the specified descendant.
|
|
392
|
+
*/
|
|
393
|
+
function pathToDescendant(node, descendant) {
|
|
394
|
+
return pathToAncestor(descendant, node).reverse();
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Checks whether the syntax of the given ancestor of an 'in' expression inside a for-loop initializer
|
|
398
|
+
* is preventing the 'in' keyword from being interpreted as a part of an ill-formed for-in loop.
|
|
399
|
+
* @param {ASTNode} node Ancestor of an 'in' expression.
|
|
400
|
+
* @param {ASTNode} child Child of the node, ancestor of the same 'in' expression or the 'in' expression itself.
|
|
401
|
+
* @returns {boolean} True if the keyword 'in' would be interpreted as the 'in' operator, without any parenthesis.
|
|
402
|
+
*/
|
|
403
|
+
function isSafelyEnclosingInExpression(node, child) {
|
|
404
|
+
switch (node.type) {
|
|
405
|
+
case "ArrayExpression":
|
|
406
|
+
case "ArrayPattern":
|
|
407
|
+
case "BlockStatement":
|
|
408
|
+
case "ObjectExpression":
|
|
409
|
+
case "ObjectPattern":
|
|
410
|
+
case "TemplateLiteral": return !0;
|
|
411
|
+
case "ArrowFunctionExpression":
|
|
412
|
+
case "FunctionExpression": return node.params.includes(child);
|
|
413
|
+
case "CallExpression":
|
|
414
|
+
case "NewExpression": return node.arguments.includes(child);
|
|
415
|
+
case "MemberExpression": return node.computed && node.property === child;
|
|
416
|
+
case "ConditionalExpression": return node.consequent === child;
|
|
417
|
+
default: return !1;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Starts a new reports buffering. Warnings will be stored in a buffer instead of being reported immediately.
|
|
422
|
+
* An additional logic that requires multiple nodes (e.g. a whole subtree) may dismiss some of the stored warnings.
|
|
423
|
+
* @returns {void}
|
|
424
|
+
*/
|
|
425
|
+
function startNewReportsBuffering() {
|
|
426
|
+
reportsBuffer = {
|
|
427
|
+
upper: reportsBuffer,
|
|
428
|
+
inExpressionNodes: [],
|
|
429
|
+
reports: []
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Ends the current reports buffering.
|
|
434
|
+
* @returns {void}
|
|
435
|
+
*/
|
|
436
|
+
function endCurrentReportsBuffering() {
|
|
437
|
+
let { upper, inExpressionNodes, reports } = reportsBuffer;
|
|
438
|
+
upper ? (upper.inExpressionNodes.push(...inExpressionNodes), upper.reports.push(...reports)) : reports.forEach(({ finishReport }) => finishReport()), reportsBuffer = upper;
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Checks whether the given node is in the current reports buffer.
|
|
442
|
+
* @param {ASTNode} node Node to check.
|
|
443
|
+
* @returns {boolean} True if the node is in the current buffer, false otherwise.
|
|
444
|
+
*/
|
|
445
|
+
function isInCurrentReportsBuffer(node) {
|
|
446
|
+
return reportsBuffer.reports.some((r) => r.node === node);
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Removes the given node from the current reports buffer.
|
|
450
|
+
* @param {ASTNode} node Node to remove.
|
|
451
|
+
* @returns {void}
|
|
452
|
+
*/
|
|
453
|
+
function removeFromCurrentReportsBuffer(node) {
|
|
454
|
+
reportsBuffer.reports = reportsBuffer.reports.filter((r) => r.node !== node);
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Checks whether a node is a MemberExpression at NewExpression's callee.
|
|
458
|
+
* @param {ASTNode} node node to check.
|
|
459
|
+
* @returns {boolean} True if the node is a MemberExpression at NewExpression's callee. false otherwise.
|
|
460
|
+
*/
|
|
461
|
+
function isMemberExpInNewCallee(node) {
|
|
462
|
+
return node.type === "MemberExpression" ? node.parent.type === "NewExpression" && node.parent.callee === node ? !0 : node.parent.object === node && isMemberExpInNewCallee(node.parent) : !1;
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Checks if the left-hand side of an assignment is an identifier, the operator is one of
|
|
466
|
+
* `=`, `&&=`, `||=` or `??=` and the right-hand side is an anonymous class or function.
|
|
467
|
+
*
|
|
468
|
+
* As per https://tc39.es/ecma262/#sec-assignment-operators-runtime-semantics-evaluation, an
|
|
469
|
+
* assignment involving one of the operators `=`, `&&=`, `||=` or `??=` where the right-hand
|
|
470
|
+
* side is an anonymous class or function and the left-hand side is an *unparenthesized*
|
|
471
|
+
* identifier has different semantics than other assignments.
|
|
472
|
+
* Specifically, when an expression like `foo = function () {}` is evaluated, `foo.name`
|
|
473
|
+
* will be set to the string "foo", i.e. the identifier name. The same thing does not happen
|
|
474
|
+
* when evaluating `(foo) = function () {}`.
|
|
475
|
+
* Since the parenthesizing of the identifier in the left-hand side is significant in this
|
|
476
|
+
* special case, the parentheses, if present, should not be flagged as unnecessary.
|
|
477
|
+
* @param {ASTNode} node an AssignmentExpression node.
|
|
478
|
+
* @returns {boolean} `true` if the left-hand side of the assignment is an identifier, the
|
|
479
|
+
* operator is one of `=`, `&&=`, `||=` or `??=` and the right-hand side is an anonymous
|
|
480
|
+
* class or function; otherwise, `false`.
|
|
481
|
+
*/
|
|
482
|
+
function isAnonymousFunctionAssignmentException({ left, operator, right }) {
|
|
483
|
+
if (left.type === "Identifier" && [
|
|
484
|
+
"=",
|
|
485
|
+
"&&=",
|
|
486
|
+
"||=",
|
|
487
|
+
"??="
|
|
488
|
+
].includes(operator)) {
|
|
489
|
+
let rhsType = right.type;
|
|
490
|
+
if (rhsType === "ArrowFunctionExpression" || (rhsType === "FunctionExpression" || rhsType === "ClassExpression") && !right.id) return !0;
|
|
491
|
+
}
|
|
492
|
+
return !1;
|
|
493
|
+
}
|
|
494
|
+
return {
|
|
495
|
+
ArrayExpression(node) {
|
|
496
|
+
node.elements.filter((e) => e && hasExcessParensWithPrecedence(e, PRECEDENCE_OF_ASSIGNMENT_EXPR)).forEach(report);
|
|
497
|
+
},
|
|
498
|
+
ArrayPattern(node) {
|
|
499
|
+
node.elements.filter((e) => canBeAssignmentTarget(e) && hasExcessParens(e)).forEach(report);
|
|
500
|
+
},
|
|
501
|
+
ArrowFunctionExpression(node) {
|
|
502
|
+
if (!isReturnAssignException(node) && !(node.body.type === "ConditionalExpression" && IGNORE_ARROW_CONDITIONALS) && node.body.type !== "BlockStatement") {
|
|
503
|
+
let firstBodyToken = sourceCode.getFirstToken(node.body, astUtils.isNotOpeningParenToken), tokenBeforeFirst = sourceCode.getTokenBefore(firstBodyToken);
|
|
504
|
+
astUtils.isOpeningParenToken(tokenBeforeFirst) && astUtils.isOpeningBraceToken(firstBodyToken) && tokensToIgnore.add(firstBodyToken), hasExcessParensWithPrecedence(node.body, PRECEDENCE_OF_ASSIGNMENT_EXPR) && report(node.body);
|
|
505
|
+
}
|
|
506
|
+
},
|
|
507
|
+
AssignmentExpression(node) {
|
|
508
|
+
canBeAssignmentTarget(node.left) && hasExcessParens(node.left) && (!isAnonymousFunctionAssignmentException(node) || isParenthesisedTwice(node.left)) && report(node.left), !isReturnAssignException(node) && hasExcessParensWithPrecedence(node.right, precedence(node)) && report(node.right);
|
|
509
|
+
},
|
|
510
|
+
BinaryExpression(node) {
|
|
511
|
+
reportsBuffer && node.operator === "in" && reportsBuffer.inExpressionNodes.push(node), checkBinaryLogical(node);
|
|
512
|
+
},
|
|
513
|
+
CallExpression: checkCallNew,
|
|
514
|
+
ConditionalExpression(node) {
|
|
515
|
+
if (isReturnAssignException(node)) return;
|
|
516
|
+
let availableTypes = new Set(["BinaryExpression", "LogicalExpression"]);
|
|
517
|
+
!(EXCEPT_COND_TERNARY && availableTypes.has(node.test.type)) && !isCondAssignException(node) && hasExcessParensWithPrecedence(node.test, precedence({
|
|
518
|
+
type: "LogicalExpression",
|
|
519
|
+
operator: "||"
|
|
520
|
+
})) && report(node.test), !(EXCEPT_COND_TERNARY && availableTypes.has(node.consequent.type)) && hasExcessParensWithPrecedence(node.consequent, PRECEDENCE_OF_ASSIGNMENT_EXPR) && report(node.consequent), !(EXCEPT_COND_TERNARY && availableTypes.has(node.alternate.type)) && hasExcessParensWithPrecedence(node.alternate, PRECEDENCE_OF_ASSIGNMENT_EXPR) && report(node.alternate);
|
|
521
|
+
},
|
|
522
|
+
DoWhileStatement(node) {
|
|
523
|
+
hasExcessParens(node.test) && !isCondAssignException(node) && report(node.test);
|
|
524
|
+
},
|
|
525
|
+
ExportDefaultDeclaration: (node) => checkExpressionOrExportStatement(node.declaration),
|
|
526
|
+
ExpressionStatement: (node) => checkExpressionOrExportStatement(node.expression),
|
|
527
|
+
ForInStatement(node) {
|
|
528
|
+
if (node.left.type !== "VariableDeclaration") {
|
|
529
|
+
let firstLeftToken = sourceCode.getFirstToken(node.left, astUtils.isNotOpeningParenToken);
|
|
530
|
+
firstLeftToken.value === "let" && astUtils.isOpeningBracketToken(sourceCode.getTokenAfter(firstLeftToken, astUtils.isNotClosingParenToken)) && tokensToIgnore.add(firstLeftToken);
|
|
531
|
+
}
|
|
532
|
+
hasExcessParens(node.left) && report(node.left), hasExcessParens(node.right) && report(node.right);
|
|
533
|
+
},
|
|
534
|
+
ForOfStatement(node) {
|
|
535
|
+
if (node.left.type !== "VariableDeclaration") {
|
|
536
|
+
let firstLeftToken = sourceCode.getFirstToken(node.left, astUtils.isNotOpeningParenToken);
|
|
537
|
+
firstLeftToken.value === "let" && tokensToIgnore.add(firstLeftToken);
|
|
538
|
+
}
|
|
539
|
+
hasExcessParens(node.left) && report(node.left), hasExcessParensWithPrecedence(node.right, PRECEDENCE_OF_ASSIGNMENT_EXPR) && report(node.right);
|
|
540
|
+
},
|
|
541
|
+
ForStatement(node) {
|
|
542
|
+
if (node.test && hasExcessParens(node.test) && !isCondAssignException(node) && report(node.test), node.update && hasExcessParens(node.update) && report(node.update), node.init) {
|
|
543
|
+
if (node.init.type !== "VariableDeclaration") {
|
|
544
|
+
let firstToken = sourceCode.getFirstToken(node.init, astUtils.isNotOpeningParenToken);
|
|
545
|
+
firstToken.value === "let" && astUtils.isOpeningBracketToken(sourceCode.getTokenAfter(firstToken, astUtils.isNotClosingParenToken)) && tokensToIgnore.add(firstToken);
|
|
546
|
+
}
|
|
547
|
+
startNewReportsBuffering(), hasExcessParens(node.init) && report(node.init);
|
|
548
|
+
}
|
|
549
|
+
},
|
|
550
|
+
"ForStatement > *.init:exit"(node) {
|
|
551
|
+
reportsBuffer.reports.length && reportsBuffer.inExpressionNodes.forEach((inExpressionNode) => {
|
|
552
|
+
let path = pathToDescendant(node, inExpressionNode), nodeToExclude;
|
|
553
|
+
for (let i = 0; i < path.length; i++) {
|
|
554
|
+
let pathNode = path[i];
|
|
555
|
+
if (i < path.length - 1) {
|
|
556
|
+
let nextPathNode = path[i + 1];
|
|
557
|
+
if (isSafelyEnclosingInExpression(pathNode, nextPathNode)) return;
|
|
558
|
+
}
|
|
559
|
+
if (isParenthesised(pathNode)) if (isInCurrentReportsBuffer(pathNode)) {
|
|
560
|
+
if (isParenthesisedTwice(pathNode)) return;
|
|
561
|
+
nodeToExclude ||= pathNode;
|
|
562
|
+
} else return;
|
|
563
|
+
}
|
|
564
|
+
removeFromCurrentReportsBuffer(nodeToExclude);
|
|
565
|
+
}), endCurrentReportsBuffering();
|
|
566
|
+
},
|
|
567
|
+
IfStatement(node) {
|
|
568
|
+
hasExcessParens(node.test) && !isCondAssignException(node) && report(node.test);
|
|
569
|
+
},
|
|
570
|
+
ImportExpression(node) {
|
|
571
|
+
let { source } = node;
|
|
572
|
+
source.type === "SequenceExpression" ? hasDoubleExcessParens(source) && report(source) : hasExcessParens(source) && report(source);
|
|
573
|
+
},
|
|
574
|
+
LogicalExpression: checkBinaryLogical,
|
|
575
|
+
MemberExpression(node) {
|
|
576
|
+
let nodeObjHasExcessParens = isMemberExpInNewCallee(node) && doesMemberExpressionContainCallExpression(node) ? hasDoubleExcessParens(node.object) : hasExcessParens(node.object) && !(isImmediateFunctionPrototypeMethodCall(node.parent) && node.parent.callee === node && IGNORE_FUNCTION_PROTOTYPE_METHODS);
|
|
577
|
+
nodeObjHasExcessParens && precedence(node.object) >= precedence(node) && (node.computed || !(astUtils.isDecimalInteger(node.object) || node.object.type === "Literal" && node.object.regex)) && report(node.object), nodeObjHasExcessParens && node.object.type === "CallExpression" && report(node.object), nodeObjHasExcessParens && !IGNORE_NEW_IN_MEMBER_EXPR && node.object.type === "NewExpression" && isNewExpressionWithParens(node.object) && report(node.object), nodeObjHasExcessParens && node.optional && node.object.type === "ChainExpression" && report(node.object), node.computed && hasExcessParens(node.property) && report(node.property);
|
|
578
|
+
},
|
|
579
|
+
"MethodDefinition[computed=true]"(node) {
|
|
580
|
+
hasExcessParensWithPrecedence(node.key, PRECEDENCE_OF_ASSIGNMENT_EXPR) && report(node.key);
|
|
581
|
+
},
|
|
582
|
+
NewExpression: checkCallNew,
|
|
583
|
+
ObjectExpression(node) {
|
|
584
|
+
node.properties.filter((property) => property.value && hasExcessParensWithPrecedence(property.value, PRECEDENCE_OF_ASSIGNMENT_EXPR)).forEach((property) => report(property.value));
|
|
585
|
+
},
|
|
586
|
+
ObjectPattern(node) {
|
|
587
|
+
node.properties.filter((property) => {
|
|
588
|
+
let value = property.value;
|
|
589
|
+
return canBeAssignmentTarget(value) && hasExcessParens(value);
|
|
590
|
+
}).forEach((property) => report(property.value));
|
|
591
|
+
},
|
|
592
|
+
Property(node) {
|
|
593
|
+
if (node.computed) {
|
|
594
|
+
let { key } = node;
|
|
595
|
+
key && hasExcessParensWithPrecedence(key, PRECEDENCE_OF_ASSIGNMENT_EXPR) && report(key);
|
|
596
|
+
}
|
|
597
|
+
},
|
|
598
|
+
PropertyDefinition(node) {
|
|
599
|
+
node.computed && hasExcessParensWithPrecedence(node.key, PRECEDENCE_OF_ASSIGNMENT_EXPR) && report(node.key), node.value && hasExcessParensWithPrecedence(node.value, PRECEDENCE_OF_ASSIGNMENT_EXPR) && report(node.value);
|
|
600
|
+
},
|
|
601
|
+
RestElement(node) {
|
|
602
|
+
let argument = node.argument;
|
|
603
|
+
canBeAssignmentTarget(argument) && hasExcessParens(argument) && report(argument);
|
|
604
|
+
},
|
|
605
|
+
ReturnStatement(node) {
|
|
606
|
+
let returnToken = sourceCode.getFirstToken(node);
|
|
607
|
+
isReturnAssignException(node) || node.argument && hasExcessParensNoLineTerminator(returnToken, node.argument) && !(node.argument.type === "Literal" && node.argument.regex) && report(node.argument);
|
|
608
|
+
},
|
|
609
|
+
SequenceExpression(node) {
|
|
610
|
+
let precedenceOfNode = precedence(node);
|
|
611
|
+
node.expressions.filter((e) => hasExcessParensWithPrecedence(e, precedenceOfNode)).forEach(report);
|
|
612
|
+
},
|
|
613
|
+
SwitchCase(node) {
|
|
614
|
+
node.test && hasExcessParens(node.test) && report(node.test);
|
|
615
|
+
},
|
|
616
|
+
SwitchStatement(node) {
|
|
617
|
+
hasExcessParens(node.discriminant) && report(node.discriminant);
|
|
618
|
+
},
|
|
619
|
+
ThrowStatement(node) {
|
|
620
|
+
hasExcessParensNoLineTerminator(sourceCode.getFirstToken(node), node.argument) && report(node.argument);
|
|
621
|
+
},
|
|
622
|
+
UnaryExpression: checkArgumentWithPrecedence,
|
|
623
|
+
UpdateExpression(node) {
|
|
624
|
+
if (node.prefix) checkArgumentWithPrecedence(node);
|
|
625
|
+
else {
|
|
626
|
+
let { argument } = node, operatorToken = sourceCode.getLastToken(node);
|
|
627
|
+
argument.loc.end.line === operatorToken.loc.start.line ? checkArgumentWithPrecedence(node) : hasDoubleExcessParens(argument) && report(argument);
|
|
628
|
+
}
|
|
629
|
+
},
|
|
630
|
+
AwaitExpression: checkArgumentWithPrecedence,
|
|
631
|
+
VariableDeclarator(node) {
|
|
632
|
+
node.init && hasExcessParensWithPrecedence(node.init, PRECEDENCE_OF_ASSIGNMENT_EXPR) && !(node.init.type === "Literal" && node.init.regex) && report(node.init);
|
|
633
|
+
},
|
|
634
|
+
WhileStatement(node) {
|
|
635
|
+
hasExcessParens(node.test) && !isCondAssignException(node) && report(node.test);
|
|
636
|
+
},
|
|
637
|
+
WithStatement(node) {
|
|
638
|
+
hasExcessParens(node.object) && report(node.object);
|
|
639
|
+
},
|
|
640
|
+
YieldExpression(node) {
|
|
641
|
+
if (node.argument) {
|
|
642
|
+
let yieldToken = sourceCode.getFirstToken(node);
|
|
643
|
+
(precedence(node.argument) >= precedence(node) && hasExcessParensNoLineTerminator(yieldToken, node.argument) || hasDoubleExcessParens(node.argument)) && report(node.argument);
|
|
644
|
+
}
|
|
645
|
+
},
|
|
646
|
+
ClassDeclaration: checkClass,
|
|
647
|
+
ClassExpression: checkClass,
|
|
648
|
+
SpreadElement: checkSpreadOperator,
|
|
649
|
+
SpreadProperty: checkSpreadOperator,
|
|
650
|
+
ExperimentalSpreadProperty: checkSpreadOperator,
|
|
651
|
+
TemplateLiteral(node) {
|
|
652
|
+
node.expressions.filter((e) => e && hasExcessParens(e)).forEach(report);
|
|
653
|
+
},
|
|
654
|
+
AssignmentPattern(node) {
|
|
655
|
+
let { left, right } = node;
|
|
656
|
+
canBeAssignmentTarget(left) && hasExcessParens(left) && report(left), right && hasExcessParensWithPrecedence(right, PRECEDENCE_OF_ASSIGNMENT_EXPR) && report(right);
|
|
657
|
+
}
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
}));
|
|
662
|
+
//#endregion
|
|
663
|
+
//#region src-js/generated/plugin-eslint/rules/no-extra-parens.cjs
|
|
664
|
+
module.exports = require_no_extra_parens().create;
|
|
665
|
+
//#endregion
|