eslint-plugin-unicorn 61.0.2 → 62.0.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/index.js +1 -1
- package/package.json +28 -26
- package/readme.md +3 -0
- package/rules/ast/index.js +2 -0
- package/rules/ast/is-empty-array-expression.js +5 -0
- package/rules/ast/is-undefined.js +1 -1
- package/rules/ast/literal.js +1 -0
- package/rules/catch-error-name.js +1 -1
- package/rules/consistent-date-clone.js +1 -1
- package/rules/consistent-existence-index-check.js +1 -1
- package/rules/consistent-function-scoping.js +46 -1
- package/rules/escape-case.js +1 -1
- package/rules/explicit-length-check.js +1 -1
- package/rules/fix/add-parenthesizes-to-return-or-throw-expression.js +13 -1
- package/rules/fix/append-argument.js +14 -1
- package/rules/fix/fix-space-around-keywords.js +13 -2
- package/rules/fix/index.js +5 -4
- package/rules/fix/remove-argument.js +18 -8
- package/rules/fix/remove-expression-statement.js +34 -0
- package/rules/fix/remove-method-call.js +15 -4
- package/rules/fix/remove-parentheses.js +13 -2
- package/rules/fix/remove-spaces-after.js +15 -3
- package/rules/fix/remove-specifier.js +14 -1
- package/rules/fix/rename-variable.js +3 -2
- package/rules/fix/replace-argument.js +14 -2
- package/rules/fix/replace-member-expression-property.js +20 -4
- package/rules/fix/replace-node-or-token-and-spaces-before.js +16 -4
- package/rules/fix/replace-reference-identifier.js +5 -5
- package/rules/fix/replace-string-raw.js +3 -5
- package/rules/fix/replace-template-element.js +3 -3
- package/rules/fix/switch-call-expression-to-new-expression.js +15 -3
- package/rules/fix/switch-new-expression-to-call-expression.js +17 -6
- package/rules/index.js +3 -0
- package/rules/new-for-builtins.js +19 -28
- package/rules/no-anonymous-default-export.js +5 -4
- package/rules/no-array-callback-reference.js +3 -4
- package/rules/no-array-for-each.js +11 -9
- package/rules/no-array-method-this-argument.js +15 -17
- package/rules/no-await-expression-member.js +50 -54
- package/rules/no-await-in-promise-methods.js +1 -2
- package/rules/no-console-spaces.js +1 -1
- package/rules/no-document-cookie.js +1 -1
- package/rules/no-for-loop.js +1 -1
- package/rules/no-hex-escape.js +1 -1
- package/rules/no-immediate-mutation.js +778 -0
- package/rules/no-instanceof-builtins.js +7 -8
- package/rules/no-lonely-if.js +13 -11
- package/rules/no-magic-array-flat-depth.js +1 -1
- package/rules/no-named-default.js +6 -5
- package/rules/no-negated-condition.js +13 -11
- package/rules/no-negation-in-equality-check.js +4 -4
- package/rules/no-new-array.js +1 -1
- package/rules/no-new-buffer.js +4 -4
- package/rules/no-single-promise-in-promise-methods.js +9 -7
- package/rules/no-static-only-class.js +9 -9
- package/rules/no-typeof-undefined.js +4 -4
- package/rules/no-unnecessary-array-flat-depth.js +1 -1
- package/rules/no-unnecessary-await.js +4 -4
- package/rules/no-unreadable-array-destructuring.js +2 -2
- package/rules/no-unreadable-iife.js +1 -1
- package/rules/no-useless-collection-argument.js +101 -0
- package/rules/no-useless-fallback-in-spread.js +2 -2
- package/rules/no-useless-length-check.js +2 -2
- package/rules/no-useless-promise-resolve-reject.js +37 -41
- package/rules/no-useless-spread.js +20 -7
- package/rules/no-useless-switch-case.js +1 -1
- package/rules/no-useless-undefined.js +9 -46
- package/rules/no-zero-fractions.js +3 -3
- package/rules/prefer-array-find.js +11 -11
- package/rules/prefer-array-flat-map.js +1 -1
- package/rules/prefer-array-flat.js +8 -11
- package/rules/prefer-array-some.js +3 -3
- package/rules/prefer-at.js +12 -12
- package/rules/prefer-class-fields.js +1 -1
- package/rules/prefer-classlist-toggle.js +10 -9
- package/rules/prefer-code-point.js +25 -37
- package/rules/prefer-date-now.js +3 -3
- package/rules/prefer-dom-node-remove.js +3 -3
- package/rules/prefer-export-from.js +11 -10
- package/rules/prefer-global-this.js +1 -0
- package/rules/prefer-import-meta-properties.js +3 -3
- package/rules/prefer-json-parse-buffer.js +1 -1
- package/rules/prefer-logical-operator-over-ternary.js +8 -7
- package/rules/prefer-math-min-max.js +1 -1
- package/rules/prefer-math-trunc.js +2 -2
- package/rules/prefer-modern-math-apis.js +5 -5
- package/rules/prefer-module.js +27 -26
- package/rules/prefer-negative-index.js +1 -2
- package/rules/prefer-node-protocol.js +9 -0
- package/rules/prefer-number-properties.js +7 -9
- package/rules/prefer-object-from-entries.js +9 -8
- package/rules/prefer-prototype-methods.js +7 -7
- package/rules/prefer-query-selector.js +1 -1
- package/rules/prefer-regexp-test.js +5 -5
- package/rules/prefer-response-static-json.js +85 -0
- package/rules/prefer-set-size.js +4 -3
- package/rules/prefer-single-call.js +35 -26
- package/rules/prefer-spread.js +27 -24
- package/rules/prefer-string-raw.js +90 -24
- package/rules/prefer-string-replace-all.js +2 -2
- package/rules/prefer-string-slice.js +8 -9
- package/rules/prefer-string-starts-ends-with.js +3 -3
- package/rules/prefer-structured-clone.js +2 -2
- package/rules/prefer-switch.js +15 -12
- package/rules/prefer-ternary.js +7 -7
- package/rules/prevent-abbreviations.js +2 -2
- package/rules/require-array-join-separator.js +1 -1
- package/rules/require-module-attributes.js +1 -1
- package/rules/require-number-to-fixed-digits-argument.js +1 -1
- package/rules/require-post-message-target-origin.js +1 -1
- package/rules/rule/get-documentation-url.js +9 -0
- package/rules/rule/index.js +9 -0
- package/rules/rule/to-eslint-create.js +51 -0
- package/rules/rule/to-eslint-listener.js +40 -0
- package/rules/rule/to-eslint-problem.js +38 -0
- package/rules/rule/to-eslint-rule-fixer.js +49 -0
- package/rules/rule/to-eslint-rule.js +38 -0
- package/rules/rule/to-eslint-rules.js +13 -0
- package/rules/rule/unicorn-context.js +36 -0
- package/rules/rule/unicorn-listeners.js +65 -0
- package/rules/rule/utilities.js +27 -0
- package/rules/shared/negative-index.js +13 -3
- package/rules/shared/no-array-mutate-rule.js +1 -2
- package/rules/shared/no-unnecessary-length-or-infinity-rule.js +1 -1
- package/rules/string-content.js +2 -1
- package/rules/switch-case-braces.js +10 -8
- package/rules/template-indent.js +1 -1
- package/rules/text-encoding-identifier-case.js +44 -23
- package/rules/throw-new-error.js +1 -1
- package/rules/utils/get-call-expression-arguments-text.js +21 -8
- package/rules/utils/get-call-or-new-expression-tokens.js +67 -0
- package/rules/utils/get-class-head-location.js +9 -5
- package/rules/utils/get-indent-string.js +12 -1
- package/rules/utils/get-sibling-node.js +38 -0
- package/rules/utils/get-switch-case-head-location.js +9 -3
- package/rules/utils/global-reference-tracker.js +18 -17
- package/rules/utils/has-same-range.js +3 -5
- package/rules/utils/index.js +3 -2
- package/rules/utils/is-new-expression-with-parentheses.js +9 -3
- package/rules/utils/is-node-matches.js +19 -7
- package/rules/utils/is-on-same-line.js +6 -3
- package/rules/utils/is-shorthand-export-local.js +2 -2
- package/rules/utils/is-shorthand-import-local.js +2 -2
- package/rules/utils/needs-semicolon.js +10 -3
- package/rules/utils/parentheses.js +26 -21
- package/rules/utils/rule.js +5 -153
- package/rules/utils/should-add-parentheses-to-member-expression-object.js +8 -4
- package/rules/utils/to-location.js +10 -4
- package/rules/utils/get-call-expression-tokens.js +0 -30
- package/rules/utils/get-previous-node.js +0 -20
package/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import createDeprecatedRules from './rules/utils/create-deprecated-rules.js';
|
|
2
2
|
import flatConfigBase from './configs/flat-config-base.js';
|
|
3
3
|
import * as rawRules from './rules/index.js';
|
|
4
|
-
import {createRules} from './rules/
|
|
4
|
+
import {createRules} from './rules/rule/index.js';
|
|
5
5
|
import packageJson from './package.json' with {type: 'json'};
|
|
6
6
|
|
|
7
7
|
const rules = createRules(rawRules);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-unicorn",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "62.0.0",
|
|
4
4
|
"description": "More than 100 powerful ESLint rules",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "sindresorhus/eslint-plugin-unicorn",
|
|
@@ -56,60 +56,62 @@
|
|
|
56
56
|
"xo"
|
|
57
57
|
],
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@babel/helper-validator-identifier": "^7.
|
|
60
|
-
"@eslint-community/eslint-utils": "^4.
|
|
61
|
-
"@eslint/plugin-kit": "^0.
|
|
59
|
+
"@babel/helper-validator-identifier": "^7.28.5",
|
|
60
|
+
"@eslint-community/eslint-utils": "^4.9.0",
|
|
61
|
+
"@eslint/plugin-kit": "^0.4.0",
|
|
62
62
|
"change-case": "^5.4.4",
|
|
63
|
-
"ci-info": "^4.3.
|
|
63
|
+
"ci-info": "^4.3.1",
|
|
64
64
|
"clean-regexp": "^1.0.0",
|
|
65
|
-
"core-js-compat": "^3.
|
|
65
|
+
"core-js-compat": "^3.46.0",
|
|
66
66
|
"esquery": "^1.6.0",
|
|
67
67
|
"find-up-simple": "^1.0.1",
|
|
68
|
-
"globals": "^16.
|
|
68
|
+
"globals": "^16.4.0",
|
|
69
69
|
"indent-string": "^5.0.0",
|
|
70
70
|
"is-builtin-module": "^5.0.0",
|
|
71
71
|
"jsesc": "^3.1.0",
|
|
72
72
|
"pluralize": "^8.0.0",
|
|
73
73
|
"regexp-tree": "^0.1.27",
|
|
74
|
-
"regjsparser": "^0.
|
|
75
|
-
"semver": "^7.7.
|
|
76
|
-
"strip-indent": "^4.
|
|
74
|
+
"regjsparser": "^0.13.0",
|
|
75
|
+
"semver": "^7.7.3",
|
|
76
|
+
"strip-indent": "^4.1.1"
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
79
|
"@babel/code-frame": "^7.27.1",
|
|
80
|
-
"@babel/core": "^7.28.
|
|
81
|
-
"@babel/eslint-parser": "^7.28.
|
|
80
|
+
"@babel/core": "^7.28.5",
|
|
81
|
+
"@babel/eslint-parser": "^7.28.5",
|
|
82
82
|
"@eslint/eslintrc": "^3.3.1",
|
|
83
83
|
"@lubien/fixture-beta-package": "^1.0.0-beta.1",
|
|
84
|
-
"@typescript-eslint/parser": "^8.
|
|
84
|
+
"@typescript-eslint/parser": "^8.46.2",
|
|
85
|
+
"@typescript-eslint/types": "^8.46.2",
|
|
85
86
|
"ava": "^6.4.1",
|
|
86
87
|
"c8": "^10.1.3",
|
|
87
88
|
"enquirer": "^2.4.1",
|
|
88
|
-
"eslint": "^9.
|
|
89
|
+
"eslint": "^9.38.0",
|
|
89
90
|
"eslint-ava-rule-tester": "^5.0.1",
|
|
90
|
-
"eslint-config-xo": "^0.
|
|
91
|
-
"eslint-doc-generator": "^2.
|
|
92
|
-
"eslint-plugin-eslint-plugin": "^
|
|
93
|
-
"eslint-plugin-jsdoc": "^
|
|
94
|
-
"eslint-
|
|
91
|
+
"eslint-config-xo": "^0.49.0",
|
|
92
|
+
"eslint-doc-generator": "^2.3.0",
|
|
93
|
+
"eslint-plugin-eslint-plugin": "^7.1.0",
|
|
94
|
+
"eslint-plugin-jsdoc": "^61.1.6",
|
|
95
|
+
"eslint-plugin-unicorn": "^61.0.2",
|
|
96
|
+
"eslint-remote-tester": "^4.0.3",
|
|
95
97
|
"eslint-remote-tester-repositories": "^2.0.2",
|
|
96
98
|
"espree": "^10.4.0",
|
|
97
|
-
"listr2": "^9.0.
|
|
99
|
+
"listr2": "^9.0.5",
|
|
98
100
|
"lodash-es": "^4.17.21",
|
|
99
101
|
"markdownlint-cli": "^0.45.0",
|
|
100
|
-
"nano-spawn": "^
|
|
101
|
-
"node-style-text": "^1.
|
|
102
|
+
"nano-spawn": "^2.0.0",
|
|
103
|
+
"node-style-text": "^2.1.2",
|
|
102
104
|
"npm-package-json-lint": "^9.0.0",
|
|
103
105
|
"npm-run-all2": "^8.0.4",
|
|
104
106
|
"open-editor": "^5.1.0",
|
|
105
107
|
"outdent": "^0.8.0",
|
|
106
|
-
"pretty-ms": "^9.
|
|
107
|
-
"typescript": "^5.
|
|
108
|
+
"pretty-ms": "^9.3.0",
|
|
109
|
+
"typescript": "^5.9.3",
|
|
108
110
|
"vue-eslint-parser": "^10.2.0",
|
|
109
|
-
"yaml": "^2.8.
|
|
111
|
+
"yaml": "^2.8.1"
|
|
110
112
|
},
|
|
111
113
|
"peerDependencies": {
|
|
112
|
-
"eslint": ">=9.
|
|
114
|
+
"eslint": ">=9.38.0"
|
|
113
115
|
},
|
|
114
116
|
"ava": {
|
|
115
117
|
"files": [
|
package/readme.md
CHANGED
|
@@ -90,6 +90,7 @@ export default [
|
|
|
90
90
|
| [no-empty-file](docs/rules/no-empty-file.md) | Disallow empty files. | ✅ ☑️ | | |
|
|
91
91
|
| [no-for-loop](docs/rules/no-for-loop.md) | Do not use a `for` loop that can be replaced with a `for-of` loop. | ✅ | 🔧 | 💡 |
|
|
92
92
|
| [no-hex-escape](docs/rules/no-hex-escape.md) | Enforce the use of Unicode escapes instead of hexadecimal escapes. | ✅ ☑️ | 🔧 | |
|
|
93
|
+
| [no-immediate-mutation](docs/rules/no-immediate-mutation.md) | Disallow immediate mutation after variable assignment. | ✅ | 🔧 | 💡 |
|
|
93
94
|
| [no-instanceof-builtins](docs/rules/no-instanceof-builtins.md) | Disallow `instanceof` with built-in objects | ✅ ☑️ | 🔧 | 💡 |
|
|
94
95
|
| [no-invalid-fetch-options](docs/rules/no-invalid-fetch-options.md) | Disallow invalid options in `fetch()` and `new Request()`. | ✅ ☑️ | | |
|
|
95
96
|
| [no-invalid-remove-event-listener](docs/rules/no-invalid-remove-event-listener.md) | Prevent calling `EventTarget#removeEventListener()` with the result of an expression. | ✅ ☑️ | | |
|
|
@@ -118,6 +119,7 @@ export default [
|
|
|
118
119
|
| [no-unreadable-array-destructuring](docs/rules/no-unreadable-array-destructuring.md) | Disallow unreadable array destructuring. | ✅ ☑️ | 🔧 | |
|
|
119
120
|
| [no-unreadable-iife](docs/rules/no-unreadable-iife.md) | Disallow unreadable IIFEs. | ✅ ☑️ | | |
|
|
120
121
|
| [no-unused-properties](docs/rules/no-unused-properties.md) | Disallow unused object properties. | | | |
|
|
122
|
+
| [no-useless-collection-argument](docs/rules/no-useless-collection-argument.md) | Disallow useless values or fallbacks in `Set`, `Map`, `WeakSet`, or `WeakMap`. | ✅ ☑️ | 🔧 | |
|
|
121
123
|
| [no-useless-error-capture-stack-trace](docs/rules/no-useless-error-capture-stack-trace.md) | Disallow unnecessary `Error.captureStackTrace(…)`. | ✅ ☑️ | 🔧 | |
|
|
122
124
|
| [no-useless-fallback-in-spread](docs/rules/no-useless-fallback-in-spread.md) | Disallow useless fallback when spreading in object literals. | ✅ ☑️ | 🔧 | |
|
|
123
125
|
| [no-useless-length-check](docs/rules/no-useless-length-check.md) | Disallow useless array length check. | ✅ ☑️ | 🔧 | |
|
|
@@ -169,6 +171,7 @@ export default [
|
|
|
169
171
|
| [prefer-query-selector](docs/rules/prefer-query-selector.md) | Prefer `.querySelector()` over `.getElementById()`, `.querySelectorAll()` over `.getElementsByClassName()` and `.getElementsByTagName()` and `.getElementsByName()`. | ✅ | 🔧 | |
|
|
170
172
|
| [prefer-reflect-apply](docs/rules/prefer-reflect-apply.md) | Prefer `Reflect.apply()` over `Function#apply()`. | ✅ ☑️ | 🔧 | |
|
|
171
173
|
| [prefer-regexp-test](docs/rules/prefer-regexp-test.md) | Prefer `RegExp#test()` over `String#match()` and `RegExp#exec()`. | ✅ ☑️ | 🔧 | 💡 |
|
|
174
|
+
| [prefer-response-static-json](docs/rules/prefer-response-static-json.md) | Prefer `Response.json()` over `new Response(JSON.stringify())`. | ✅ ☑️ | 🔧 | |
|
|
172
175
|
| [prefer-set-has](docs/rules/prefer-set-has.md) | Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence. | ✅ ☑️ | 🔧 | 💡 |
|
|
173
176
|
| [prefer-set-size](docs/rules/prefer-set-size.md) | Prefer using `Set#size` instead of `Array#length`. | ✅ ☑️ | 🔧 | |
|
|
174
177
|
| [prefer-single-call](docs/rules/prefer-single-call.md) | Enforce combining multiple `Array#push()`, `Element#classList.{add,remove}()`, and `importScripts()` into one call. | ✅ ☑️ | 🔧 | 💡 |
|
package/rules/ast/index.js
CHANGED
|
@@ -5,6 +5,7 @@ export {
|
|
|
5
5
|
isBigIntLiteral,
|
|
6
6
|
isNullLiteral,
|
|
7
7
|
isRegexLiteral,
|
|
8
|
+
isEmptyStringLiteral,
|
|
8
9
|
} from './literal.js';
|
|
9
10
|
|
|
10
11
|
export {
|
|
@@ -16,6 +17,7 @@ export {
|
|
|
16
17
|
export {default as isArrowFunctionBody} from './is-arrow-function-body.js';
|
|
17
18
|
export {default as isDirective} from './is-directive.js';
|
|
18
19
|
export {default as isEmptyNode} from './is-empty-node.js';
|
|
20
|
+
export {default as isEmptyArrayExpression} from './is-empty-array-expression.js';
|
|
19
21
|
export {default as isExpressionStatement} from './is-expression-statement.js';
|
|
20
22
|
export {default as isFunction} from './is-function.js';
|
|
21
23
|
export {default as isMemberExpression} from './is-member-expression.js';
|
package/rules/ast/literal.js
CHANGED
|
@@ -32,7 +32,7 @@ const create = context => ({
|
|
|
32
32
|
end: sourceCode.getLoc(callExpression).end,
|
|
33
33
|
},
|
|
34
34
|
messageId: MESSAGE_ID_ERROR,
|
|
35
|
-
fix: fixer => removeMethodCall(fixer, callExpression,
|
|
35
|
+
fix: fixer => removeMethodCall(fixer, callExpression, context),
|
|
36
36
|
};
|
|
37
37
|
},
|
|
38
38
|
});
|
|
@@ -108,6 +108,43 @@ const isIife = node =>
|
|
|
108
108
|
&& node.parent.type === 'CallExpression'
|
|
109
109
|
&& node.parent.callee === node;
|
|
110
110
|
|
|
111
|
+
// Helper to walk up the chain to find the first non-arrow ancestor
|
|
112
|
+
function getNonArrowAncestor(node) {
|
|
113
|
+
let ancestor = node;
|
|
114
|
+
while (ancestor && ancestor.type === 'ArrowFunctionExpression') {
|
|
115
|
+
ancestor = ancestor.parent;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return ancestor;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Helper to skip over a chain of ArrowFunctionExpression nodes
|
|
122
|
+
function skipArrowFunctionChain(node) {
|
|
123
|
+
let current = node;
|
|
124
|
+
while (current.type === 'ArrowFunctionExpression') {
|
|
125
|
+
current = current.parent;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return current;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function handleNestedArrowFunctions(parentNode, node) {
|
|
132
|
+
// Skip over arrow function expressions when they are parents and we came from a ReturnStatement
|
|
133
|
+
// This handles nested arrow functions: return next => action => { ... }
|
|
134
|
+
// But only when we're in a return statement context
|
|
135
|
+
if (parentNode.type === 'ArrowFunctionExpression' && node.type === 'ArrowFunctionExpression') {
|
|
136
|
+
const ancestor = getNonArrowAncestor(parentNode);
|
|
137
|
+
if (ancestor && ancestor.type === 'ReturnStatement') {
|
|
138
|
+
parentNode = skipArrowFunctionChain(parentNode);
|
|
139
|
+
if (parentNode.type === 'ReturnStatement') {
|
|
140
|
+
parentNode = parentNode.parent;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return parentNode;
|
|
146
|
+
}
|
|
147
|
+
|
|
111
148
|
function checkNode(node, scopeManager) {
|
|
112
149
|
const scope = scopeManager.acquire(node);
|
|
113
150
|
|
|
@@ -128,7 +165,15 @@ function checkNode(node, scopeManager) {
|
|
|
128
165
|
parentNode = parentNode.parent;
|
|
129
166
|
}
|
|
130
167
|
|
|
131
|
-
|
|
168
|
+
// Only skip ReturnStatement for arrow functions
|
|
169
|
+
// Regular function expressions have different semantics and shouldn't be moved
|
|
170
|
+
if (parentNode?.type === 'ReturnStatement' && node.type === 'ArrowFunctionExpression') {
|
|
171
|
+
parentNode = parentNode.parent;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
parentNode = handleNestedArrowFunctions(parentNode, node);
|
|
175
|
+
|
|
176
|
+
if (parentNode?.type === 'BlockStatement') {
|
|
132
177
|
parentNode = parentNode.parent;
|
|
133
178
|
}
|
|
134
179
|
|
package/rules/escape-case.js
CHANGED
|
@@ -123,7 +123,7 @@ function create(context) {
|
|
|
123
123
|
|
|
124
124
|
const fix = function * (fixer) {
|
|
125
125
|
yield fixer.replaceText(node, fixed);
|
|
126
|
-
yield
|
|
126
|
+
yield fixSpaceAroundKeyword(fixer, node, context);
|
|
127
127
|
};
|
|
128
128
|
|
|
129
129
|
const problem = {
|
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
import {isSemicolonToken} from '@eslint-community/eslint-utils';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
@import {TSESTree as ESTree} from '@typescript-eslint/types';
|
|
5
|
+
@import * as ESLint from 'eslint';
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
@param {ESLint.Rule.RuleFixer} fixer
|
|
10
|
+
@param {ESTree.ReturnStatement | ESTree.ThrowStatement} node
|
|
11
|
+
@param {ESLint.Rule.RuleContext} context - The ESLint rule context object.
|
|
12
|
+
@returns {ESLint.Rule.ReportFixer}
|
|
13
|
+
*/
|
|
14
|
+
export default function * addParenthesizesToReturnOrThrowExpression(fixer, node, context) {
|
|
4
15
|
if (node.type !== 'ReturnStatement' && node.type !== 'ThrowStatement') {
|
|
5
16
|
return;
|
|
6
17
|
}
|
|
7
18
|
|
|
19
|
+
const {sourceCode} = context;
|
|
8
20
|
const returnOrThrowToken = sourceCode.getFirstToken(node);
|
|
9
21
|
yield fixer.insertTextAfter(returnOrThrowToken, ' (');
|
|
10
22
|
const lastToken = sourceCode.getLastToken(node);
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import {isCommaToken} from '@eslint-community/eslint-utils';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
@import {TSESTree as ESTree} from '@typescript-eslint/types';
|
|
5
|
+
@import * as ESLint from 'eslint';
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
@param {ESLint.Rule.RuleFixer} fixer
|
|
10
|
+
@param {ESTree.CallExpression} node
|
|
11
|
+
@param {string} text
|
|
12
|
+
@param {ESLint.Rule.RuleContext} context - The ESLint rule context object.
|
|
13
|
+
@returns {ESLint.Rule.ReportFixer}
|
|
14
|
+
*/
|
|
15
|
+
export default function appendArgument(fixer, node, text, context) {
|
|
4
16
|
// This function should also work for `NewExpression`
|
|
5
17
|
// But parentheses of `NewExpression` could be omitted, add this check to prevent accident use on it
|
|
6
18
|
/* c8 ignore next 3 */
|
|
@@ -8,6 +20,7 @@ export default function appendArgument(fixer, node, text, sourceCode) {
|
|
|
8
20
|
throw new Error(`Unexpected node "${node.type}".`);
|
|
9
21
|
}
|
|
10
22
|
|
|
23
|
+
const {sourceCode} = context;
|
|
11
24
|
const [penultimateToken, lastToken] = sourceCode.getLastTokens(node, 2);
|
|
12
25
|
if (node.arguments.length > 0) {
|
|
13
26
|
text = isCommaToken(penultimateToken) ? ` ${text},` : `, ${text}`;
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import {getParenthesizedRange} from '../utils/parentheses.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
@import {TSESTree as ESTree} from '@typescript-eslint/types';
|
|
5
|
+
@import * as ESLint from 'eslint';
|
|
6
|
+
*/
|
|
7
|
+
|
|
3
8
|
const isProblematicToken = ({type, value}) => (
|
|
4
9
|
(type === 'Keyword' && /^[a-z]*$/.test(value))
|
|
5
10
|
// ForOfStatement
|
|
@@ -8,8 +13,14 @@ const isProblematicToken = ({type, value}) => (
|
|
|
8
13
|
|| (type === 'Identifier' && value === 'await')
|
|
9
14
|
);
|
|
10
15
|
|
|
11
|
-
|
|
12
|
-
|
|
16
|
+
/**
|
|
17
|
+
@param {ESLint.Rule.RuleFixer} fixer
|
|
18
|
+
@param {ESTree.Node} node
|
|
19
|
+
@param {ESLint.Rule.RuleContext} context - The ESLint rule context object.
|
|
20
|
+
*/
|
|
21
|
+
export default function * fixSpaceAroundKeyword(fixer, node, context) {
|
|
22
|
+
const {sourceCode} = context;
|
|
23
|
+
const range = getParenthesizedRange(node, context);
|
|
13
24
|
const tokenBefore = sourceCode.getTokenBefore({range}, {includeComments: true});
|
|
14
25
|
|
|
15
26
|
if (
|
package/rules/fix/index.js
CHANGED
|
@@ -10,13 +10,14 @@ export {
|
|
|
10
10
|
removeMemberExpressionProperty,
|
|
11
11
|
} from './replace-member-expression-property.js';
|
|
12
12
|
export {default as removeMethodCall} from './remove-method-call.js';
|
|
13
|
-
export {default as
|
|
14
|
-
export {default as replaceReferenceIdentifier} from './replace-reference-identifier.js';
|
|
15
|
-
export {default as renameVariable} from './rename-variable.js';
|
|
16
|
-
export {default as replaceNodeOrTokenAndSpacesBefore} from './replace-node-or-token-and-spaces-before.js';
|
|
13
|
+
export {default as removeExpressionStatement} from './remove-expression-statement.js';
|
|
17
14
|
export {default as removeSpacesAfter} from './remove-spaces-after.js';
|
|
18
15
|
export {default as removeSpecifier} from './remove-specifier.js';
|
|
19
16
|
export {default as removeObjectProperty} from './remove-object-property.js';
|
|
17
|
+
export {default as renameVariable} from './rename-variable.js';
|
|
18
|
+
export {default as replaceTemplateElement} from './replace-template-element.js';
|
|
19
|
+
export {default as replaceReferenceIdentifier} from './replace-reference-identifier.js';
|
|
20
|
+
export {default as replaceNodeOrTokenAndSpacesBefore} from './replace-node-or-token-and-spaces-before.js';
|
|
20
21
|
export {default as fixSpaceAroundKeyword} from './fix-space-around-keywords.js';
|
|
21
22
|
export {default as replaceStringRaw} from './replace-string-raw.js';
|
|
22
23
|
export {default as addParenthesizesToReturnOrThrowExpression} from './add-parenthesizes-to-return-or-throw-expression.js';
|
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
import {isCommaToken} from '@eslint-community/eslint-utils';
|
|
2
2
|
import {getParentheses} from '../utils/parentheses.js';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
/**
|
|
5
|
+
@import {TSESTree as ESTree} from '@typescript-eslint/types';
|
|
6
|
+
@import * as ESLint from 'eslint';
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
@param {ESLint.Rule.RuleFixer} fixer
|
|
11
|
+
@param {ESTree.NewExpression | ESTree.CallExpression} node
|
|
12
|
+
@param {ESLint.Rule.RuleContext} context - The ESLint rule context object.
|
|
13
|
+
@returns {ESLint.Rule.ReportFixer}
|
|
14
|
+
*/
|
|
15
|
+
export default function removeArgument(fixer, node, context) {
|
|
16
|
+
const callOrNewExpression = node.parent;
|
|
17
|
+
const index = callOrNewExpression.arguments.indexOf(node);
|
|
18
|
+
const parentheses = getParentheses(node, context);
|
|
8
19
|
const firstToken = parentheses[0] || node;
|
|
9
20
|
const lastToken = parentheses.at(-1) || node;
|
|
21
|
+
const {sourceCode} = context;
|
|
10
22
|
|
|
11
23
|
let [start] = sourceCode.getRange(firstToken);
|
|
12
24
|
let [, end] = sourceCode.getRange(lastToken);
|
|
@@ -17,14 +29,12 @@ export default function removeArgument(fixer, node, sourceCode) {
|
|
|
17
29
|
}
|
|
18
30
|
|
|
19
31
|
// If the removed argument is the only argument, the trailing comma must be removed too
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const tokenAfter = sourceCode.getTokenBefore(lastToken);
|
|
32
|
+
if (callOrNewExpression.arguments.length === 1) {
|
|
33
|
+
const tokenAfter = sourceCode.getTokenAfter(lastToken);
|
|
23
34
|
if (isCommaToken(tokenAfter)) {
|
|
24
35
|
[, end] = sourceCode.getRange(tokenAfter);
|
|
25
36
|
}
|
|
26
37
|
}
|
|
27
|
-
/* c8 ignore end */
|
|
28
38
|
|
|
29
39
|
return fixer.removeRange([start, end]);
|
|
30
40
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import {isSemicolonToken} from '@eslint-community/eslint-utils';
|
|
2
|
+
const isWhitespaceOnly = text => /^\s*$/.test(text);
|
|
3
|
+
|
|
4
|
+
function removeExpressionStatement(expressionStatement, context, fixer, preserveSemiColon = false) {
|
|
5
|
+
const {sourceCode} = context;
|
|
6
|
+
const {lines} = sourceCode;
|
|
7
|
+
let endToken = expressionStatement;
|
|
8
|
+
|
|
9
|
+
if (preserveSemiColon) {
|
|
10
|
+
const [penultimateToken, lastToken] = sourceCode.getLastTokens(expressionStatement, 2);
|
|
11
|
+
|
|
12
|
+
if (isSemicolonToken(lastToken)) {
|
|
13
|
+
endToken = penultimateToken;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const startLocation = sourceCode.getLoc(expressionStatement).start;
|
|
18
|
+
const endLocation = sourceCode.getLoc(endToken).end;
|
|
19
|
+
|
|
20
|
+
const textBefore = lines[startLocation.line - 1].slice(0, startLocation.column);
|
|
21
|
+
const textAfter = lines[endLocation.line - 1].slice(endLocation.column);
|
|
22
|
+
|
|
23
|
+
let [start] = sourceCode.getRange(expressionStatement);
|
|
24
|
+
let [, end] = sourceCode.getRange(endToken);
|
|
25
|
+
|
|
26
|
+
if (isWhitespaceOnly(textBefore) && isWhitespaceOnly(textAfter)) {
|
|
27
|
+
start = Math.max(0, start - textBefore.length - 1);
|
|
28
|
+
end += textAfter.length;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return fixer.removeRange([start, end]);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default removeExpressionStatement;
|
|
@@ -1,17 +1,28 @@
|
|
|
1
1
|
import {getParenthesizedRange} from '../utils/parentheses.js';
|
|
2
2
|
import {removeMemberExpressionProperty} from './replace-member-expression-property.js';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
@import {TSESTree as ESTree} from '@typescript-eslint/types';
|
|
6
|
+
@import * as ESLint from 'eslint';
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
@param {ESLint.Rule.RuleFixer} fixer
|
|
11
|
+
@param {ESTree.CallExpression} callExpression
|
|
12
|
+
@param {ESLint.Rule.RuleContext} context - The ESLint rule context object.
|
|
13
|
+
@returns {ESLint.Rule.ReportFixer}
|
|
14
|
+
*/
|
|
15
|
+
export default function * removeMethodCall(fixer, callExpression, context) {
|
|
5
16
|
const memberExpression = callExpression.callee;
|
|
6
17
|
|
|
7
18
|
// `(( (( foo )).bar ))()`
|
|
8
19
|
// ^^^^
|
|
9
|
-
yield removeMemberExpressionProperty(fixer, memberExpression,
|
|
20
|
+
yield removeMemberExpressionProperty(fixer, memberExpression, context);
|
|
10
21
|
|
|
11
22
|
// `(( (( foo )).bar ))()`
|
|
12
23
|
// ^^
|
|
13
|
-
const [, start] = getParenthesizedRange(memberExpression,
|
|
14
|
-
const [, end] = sourceCode.getRange(callExpression);
|
|
24
|
+
const [, start] = getParenthesizedRange(memberExpression, context);
|
|
25
|
+
const [, end] = context.sourceCode.getRange(callExpression);
|
|
15
26
|
|
|
16
27
|
yield fixer.removeRange([start, end]);
|
|
17
28
|
}
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
import {getParentheses} from '../utils/parentheses.js';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
@import {TSESTree as ESTree} from '@typescript-eslint/types';
|
|
5
|
+
@import * as ESLint from 'eslint';
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
@param {ESTree.Node} node
|
|
10
|
+
@param {ESLint.Rule.RuleFixer} fixer
|
|
11
|
+
@param {ESLint.Rule.RuleContext} context - The ESLint rule context object.
|
|
12
|
+
@returns {ESLint.Rule.ReportFixer}
|
|
13
|
+
*/
|
|
14
|
+
export default function * removeParentheses(node, fixer, context) {
|
|
15
|
+
const parentheses = getParentheses(node, context);
|
|
5
16
|
for (const token of parentheses) {
|
|
6
17
|
yield fixer.remove(token);
|
|
7
18
|
}
|
|
@@ -1,10 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
@import {TSESTree as ESTree} from '@typescript-eslint/types';
|
|
3
|
+
@import * as ESLint from 'eslint';
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
@param {ESTree.Node | ESTree.Token | number} indexOrNodeOrToken
|
|
8
|
+
@param {ESLint.Rule.RuleContext} context - The ESLint rule context object.
|
|
9
|
+
@param {ESLint.Rule.RuleFixer} fixer
|
|
10
|
+
@returns {ESLint.Rule.ReportFixer}
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export default function removeSpacesAfter(indexOrNodeOrToken, context, fixer) {
|
|
2
14
|
let index = indexOrNodeOrToken;
|
|
3
15
|
if (typeof indexOrNodeOrToken === 'object') {
|
|
4
|
-
index = sourceCode.getRange(indexOrNodeOrToken)[1];
|
|
16
|
+
index = context.sourceCode.getRange(indexOrNodeOrToken)[1];
|
|
5
17
|
}
|
|
6
18
|
|
|
7
|
-
const textAfter = sourceCode.text.slice(index);
|
|
19
|
+
const textAfter = context.sourceCode.text.slice(index);
|
|
8
20
|
const [leadingSpaces] = textAfter.match(/^\s*/);
|
|
9
21
|
return fixer.removeRange([index, index + leadingSpaces.length]);
|
|
10
22
|
}
|
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import {isCommaToken, isOpeningBraceToken} from '@eslint-community/eslint-utils';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
@import {TSESTree as ESTree} from '@typescript-eslint/types';
|
|
5
|
+
@import * as ESLint from 'eslint';
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
@param {ESTree.ImportSpecifier | ESTree.ExportSpecifier | ESTree.ImportDefaultSpecifier | ESTree.ImportNamespaceSpecifier} specifier
|
|
10
|
+
@param {ESLint.Rule.RuleFixer} fixer
|
|
11
|
+
@param {ESLint.Rule.RuleContext} context - The ESLint rule context object.
|
|
12
|
+
@param {boolean} [keepDeclaration = false]
|
|
13
|
+
@returns {ESLint.Rule.ReportFixer}
|
|
14
|
+
*/
|
|
15
|
+
export default function * removeSpecifier(specifier, fixer, context, keepDeclaration = false) {
|
|
4
16
|
const declaration = specifier.parent;
|
|
5
17
|
const {specifiers} = declaration;
|
|
6
18
|
|
|
@@ -9,6 +21,7 @@ export default function * removeSpecifier(specifier, fixer, sourceCode, keepDecl
|
|
|
9
21
|
return;
|
|
10
22
|
}
|
|
11
23
|
|
|
24
|
+
const {sourceCode} = context;
|
|
12
25
|
switch (specifier.type) {
|
|
13
26
|
case 'ImportSpecifier': {
|
|
14
27
|
const isTheOnlyNamedImport = specifiers.every(node => specifier === node || specifier.type !== node.type);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import getVariableIdentifiers from '../utils/get-variable-identifiers.js';
|
|
2
2
|
import replaceReferenceIdentifier from './replace-reference-identifier.js';
|
|
3
3
|
|
|
4
|
-
const renameVariable = (variable, name, fixer) =>
|
|
5
|
-
|
|
4
|
+
const renameVariable = (variable, name, context, fixer) =>
|
|
5
|
+
getVariableIdentifiers(variable)
|
|
6
|
+
.map(identifier => replaceReferenceIdentifier(identifier, name, context, fixer));
|
|
6
7
|
|
|
7
8
|
export default renameVariable;
|
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import {getParenthesizedRange} from '../utils/parentheses.js';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
@import {TSESTree as ESTree} from '@typescript-eslint/types';
|
|
5
|
+
@import * as ESLint from 'eslint';
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
@param {ESLint.Rule.RuleFixer} fixer
|
|
10
|
+
@param {ESTree.CallExpression | ESTree.NewExpression} node
|
|
11
|
+
@param {string} text
|
|
12
|
+
@param {ESLint.Rule.RuleContext} context - The ESLint rule context object.
|
|
13
|
+
@returns {ESLint.Rule.ReportFixer}
|
|
14
|
+
*/
|
|
15
|
+
export default function replaceArgument(fixer, node, text, context) {
|
|
16
|
+
return fixer.replaceTextRange(getParenthesizedRange(node, context), text);
|
|
5
17
|
}
|
|
@@ -1,9 +1,25 @@
|
|
|
1
1
|
import {getParenthesizedRange} from '../utils/parentheses.js';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
/**
|
|
4
|
+
@import {TSESTree as ESTree} from '@typescript-eslint/types';
|
|
5
|
+
@import * as ESLint from 'eslint';
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
@param {ESTree.MemberExpression} memberExpression - The `MemberExpression` to fix.
|
|
10
|
+
@param {ESLint.Rule.RuleContext} context - The ESLint rule context object.
|
|
11
|
+
@param {string} text
|
|
12
|
+
@returns {ESLint.Rule.ReportFixer}
|
|
13
|
+
*/
|
|
14
|
+
export function replaceMemberExpressionProperty(fixer, memberExpression, context, text) {
|
|
15
|
+
const [, start] = getParenthesizedRange(memberExpression.object, context);
|
|
16
|
+
const [, end] = context.sourceCode.getRange(memberExpression);
|
|
6
17
|
return fixer.replaceTextRange([start, end], text);
|
|
7
18
|
}
|
|
8
19
|
|
|
9
|
-
|
|
20
|
+
/**
|
|
21
|
+
@param {ESTree.MemberExpression} memberExpression - The `MemberExpression` to fix.
|
|
22
|
+
@param {ESLint.Rule.RuleContext} context - The ESLint rule context object.
|
|
23
|
+
@returns {ESLint.Rule.ReportFixer}
|
|
24
|
+
*/
|
|
25
|
+
export const removeMemberExpressionProperty = (fixer, memberExpression, context) => replaceMemberExpressionProperty(fixer, memberExpression, context, '');
|