eslint-plugin-unicorn 70.0.0 → 71.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/package.json +26 -25
- package/readme.md +5 -1
- package/rules/ast/call-or-new-expression.js +2 -8
- package/rules/ast/is-member-expression.js +2 -8
- package/rules/comment-content.js +4 -4
- package/rules/consistent-boolean-name.js +94 -10
- package/rules/consistent-compound-words.js +1 -2
- package/rules/consistent-json-file-read.js +2 -5
- package/rules/dom-node-dataset.js +3 -7
- package/rules/escape-case.js +4 -4
- package/rules/expiring-todo-comments.js +2 -2
- package/rules/explicit-length-check.js +3 -3
- package/rules/filename-case.js +4 -4
- package/rules/fix/remove-argument.js +34 -8
- package/rules/fix/remove-statement.js +1 -3
- package/rules/id-match.js +2 -2
- package/rules/isolated-functions.js +47 -7
- package/rules/name-replacements.js +1 -2
- package/rules/no-anonymous-default-export.js +1 -3
- package/rules/no-array-callback-reference.js +2 -10
- package/rules/no-chained-comparison.js +1 -1
- package/rules/no-computed-property-existence-check.js +1 -4
- package/rules/no-declarations-before-early-exit.js +6 -5
- package/rules/no-error-property-assignment.js +3 -3
- package/rules/no-for-loop.js +4 -4
- package/rules/no-keyword-prefix.js +2 -2
- package/rules/no-mismatched-map-key.js +13 -20
- package/rules/no-named-default.js +2 -5
- package/rules/no-negated-array-predicate.js +4 -11
- package/rules/no-negated-comparison.js +7 -10
- package/rules/no-negation-in-equality-check.js +2 -5
- package/rules/no-process-exit.js +6 -6
- package/rules/no-static-only-class.js +2 -8
- package/rules/no-thenable.js +9 -15
- package/rules/no-undeclared-class-members.js +1 -5
- package/rules/no-unnecessary-array-flat-map.js +6 -5
- package/rules/no-unnecessary-global-this.js +5 -9
- package/rules/no-unused-properties.js +0 -1
- package/rules/no-useless-coercion.js +1 -2
- package/rules/no-useless-undefined.js +2 -2
- package/rules/prefer-array-find.js +2 -5
- package/rules/prefer-bigint-literals.js +1 -0
- package/rules/prefer-boolean-return.js +20 -3
- package/rules/prefer-default-parameters.js +2 -2
- package/rules/prefer-else-if.js +5 -9
- package/rules/prefer-has-check.js +6 -3
- package/rules/prefer-https.js +3 -3
- package/rules/prefer-identifier-import-export-specifiers.js +1 -3
- package/rules/prefer-minimal-ternary.js +4 -4
- package/rules/prefer-object-define-properties.js +1 -3
- package/rules/prefer-observer-apis.js +2 -5
- package/rules/prefer-private-class-fields.js +1 -3
- package/rules/prefer-simple-sort-comparator.js +6 -6
- package/rules/prefer-single-object-destructuring.js +2 -5
- package/rules/prefer-single-replace.js +2 -2
- package/rules/prefer-spread.js +22 -32
- package/rules/prefer-string-pad-start-end.js +1 -6
- package/rules/prefer-string-repeat.js +16 -9
- package/rules/prefer-string-replace-all.js +1 -1
- package/rules/prefer-ternary.js +5 -5
- package/rules/prefer-toggle-attribute.js +3 -3
- package/rules/prefer-top-level-await.js +6 -1
- package/rules/prefer-uint8array-base64.js +3 -1
- package/rules/require-proxy-trap-boolean-return.js +2 -2
- package/rules/rule/to-eslint-create.js +1 -2
- package/rules/rule/to-eslint-listener.js +1 -3
- package/rules/rule/to-eslint-problem.js +1 -3
- package/rules/rule/to-eslint-rule-fixer.js +1 -3
- package/rules/rule/to-eslint-rule.js +1 -3
- package/rules/rule/to-eslint-rules.js +1 -3
- package/rules/rule/unicorn-context.js +1 -3
- package/rules/rule/unicorn-listeners.js +1 -3
- package/rules/shared/no-array-mutate-rule.js +1 -3
- package/rules/shared/regexp-escape.js +4 -4
- package/rules/utils/can-tokens-be-adjacent.js +95 -0
- package/rules/utils/escape-string.js +2 -8
- package/rules/utils/get-available-variable-name.js +2 -13
- package/rules/utils/get-precedence.js +112 -0
- package/rules/utils/get-token-store.js +1 -3
- package/rules/utils/global-reference-tracker.js +3 -6
- package/rules/utils/index.js +4 -0
- package/rules/utils/is-boolean.js +90 -32
- package/rules/utils/is-identifier-name.js +5 -0
- package/rules/utils/is-promise-type.js +1 -3
- package/rules/utils/is-react-hook-name.js +5 -0
- package/rules/utils/parentheses/get-parent-syntax-opening-parenthesis.js +1 -3
- package/rules/utils/parentheses/iterate-surrounding-parentheses.js +1 -1
- package/rules/utils/should-add-parentheses-to-await-expression-argument.js +4 -9
- package/rules/utils/should-add-parentheses-to-call-expression-callee.js +6 -12
- package/rules/utils/should-add-parentheses-to-unary-expression.js +7 -14
- package/rules/utils/to-location.js +1 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-unicorn",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "71.0.0",
|
|
4
4
|
"description": "More than 300 powerful ESLint rules",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -62,58 +62,59 @@
|
|
|
62
62
|
"xo"
|
|
63
63
|
],
|
|
64
64
|
"dependencies": {
|
|
65
|
-
"@babel/helper-validator-identifier": "^7.29.7",
|
|
66
65
|
"@eslint-community/eslint-utils": "^4.9.1",
|
|
67
|
-
"browserslist": "^4.28.
|
|
66
|
+
"browserslist": "^4.28.4",
|
|
68
67
|
"change-case": "^5.4.4",
|
|
69
68
|
"ci-info": "^4.4.0",
|
|
70
69
|
"core-js-compat": "^3.49.0",
|
|
71
70
|
"detect-indent": "^7.0.2",
|
|
72
71
|
"find-up-simple": "^1.0.1",
|
|
73
|
-
"globals": "^17.
|
|
72
|
+
"globals": "^17.7.0",
|
|
74
73
|
"indent-string": "^5.0.0",
|
|
75
74
|
"is-builtin-module": "^5.0.0",
|
|
76
|
-
"
|
|
75
|
+
"is-identifier": "^1.1.0",
|
|
77
76
|
"pluralize": "^8.0.0",
|
|
78
|
-
"
|
|
79
|
-
"
|
|
77
|
+
"quote-js-string": "^0.1.0",
|
|
78
|
+
"regjsparser": "^0.13.2",
|
|
79
|
+
"reserved-identifiers": "^1.2.0",
|
|
80
|
+
"semver": "^7.8.5",
|
|
80
81
|
"strip-indent": "^4.1.1"
|
|
81
82
|
},
|
|
82
83
|
"devDependencies": {
|
|
83
|
-
"@babel/code-frame": "^8.0.0
|
|
84
|
-
"@eslint/css": "^1.
|
|
84
|
+
"@babel/code-frame": "^8.0.0",
|
|
85
|
+
"@eslint/css": "^1.4.0",
|
|
85
86
|
"@eslint/eslintrc": "^3.3.5",
|
|
86
|
-
"@eslint/json": "^2.0.
|
|
87
|
-
"@eslint/markdown": "^8.0.
|
|
88
|
-
"@html-eslint/eslint-plugin": "^0.
|
|
89
|
-
"@html-eslint/parser": "^0.
|
|
87
|
+
"@eslint/json": "^2.0.1",
|
|
88
|
+
"@eslint/markdown": "^8.0.3",
|
|
89
|
+
"@html-eslint/eslint-plugin": "^0.63.0",
|
|
90
|
+
"@html-eslint/parser": "^0.63.0",
|
|
90
91
|
"@lubien/fixture-beta-package": "^1.0.0-beta.1",
|
|
91
|
-
"@typescript-eslint/parser": "^8.
|
|
92
|
-
"@typescript-eslint/types": "^8.
|
|
92
|
+
"@typescript-eslint/parser": "^8.62.1",
|
|
93
|
+
"@typescript-eslint/types": "^8.62.1",
|
|
93
94
|
"ava": "^8.0.1",
|
|
94
95
|
"c8": "^11.0.0",
|
|
95
96
|
"enquirer": "^2.4.1",
|
|
96
|
-
"eslint": "^10.
|
|
97
|
+
"eslint": "^10.6.0",
|
|
97
98
|
"eslint-ava-rule-tester": "^5.0.1",
|
|
98
|
-
"eslint-config-xo": "^0.
|
|
99
|
+
"eslint-config-xo": "^0.56.0",
|
|
99
100
|
"eslint-doc-generator": "^3.6.0",
|
|
100
|
-
"eslint-plugin-eslint-plugin": "^7.4.
|
|
101
|
-
"eslint-plugin-jsdoc": "^63.0.
|
|
102
|
-
"eslint-plugin-unicorn": "^
|
|
101
|
+
"eslint-plugin-eslint-plugin": "^7.4.1",
|
|
102
|
+
"eslint-plugin-jsdoc": "^63.0.11",
|
|
103
|
+
"eslint-plugin-unicorn": "^70.0.0",
|
|
103
104
|
"eslint-remote-tester": "^4.0.4",
|
|
104
105
|
"eslint-remote-tester-repositories": "^2.0.2",
|
|
105
106
|
"eslint-scope": "^9.1.2",
|
|
106
107
|
"espree": "^11.2.0",
|
|
107
|
-
"listr2": "^10.2.
|
|
108
|
-
"markdownlint-cli": "^0.
|
|
108
|
+
"listr2": "^10.2.2",
|
|
109
|
+
"markdownlint-cli": "^0.49.0",
|
|
109
110
|
"nano-spawn": "^2.1.0",
|
|
110
111
|
"node-style-text": "^2.1.2",
|
|
111
|
-
"npm-package-json-lint": "^10.4.
|
|
112
|
-
"npm-run-all2": "^9.0.
|
|
112
|
+
"npm-package-json-lint": "^10.4.1",
|
|
113
|
+
"npm-run-all2": "^9.0.2",
|
|
113
114
|
"open-editor": "^6.0.0",
|
|
114
115
|
"outdent": "^0.8.0",
|
|
115
116
|
"pretty-ms": "^9.3.0",
|
|
116
|
-
"svelte": "^5.56.
|
|
117
|
+
"svelte": "^5.56.4",
|
|
117
118
|
"svelte-eslint-parser": "^1.8.0",
|
|
118
119
|
"typescript": "^6.0.3",
|
|
119
120
|
"vue-eslint-parser": "^10.4.1",
|
package/readme.md
CHANGED
|
@@ -391,7 +391,7 @@ export default defineConfig([
|
|
|
391
391
|
| [prefer-top-level-await](docs/rules/prefer-top-level-await.md) | Prefer top-level await over top-level promises and async function calls. | ✅ ☑️ | | 💡 | |
|
|
392
392
|
| [prefer-type-error](docs/rules/prefer-type-error.md) | Enforce throwing `TypeError` in type checking conditions. | ✅ ☑️ | 🔧 | | |
|
|
393
393
|
| [prefer-type-literal-last](docs/rules/prefer-type-literal-last.md) | Require type literals to be last in union types. | ✅ | 🔧 | | |
|
|
394
|
-
| [prefer-uint8array-base64](docs/rules/prefer-uint8array-base64.md) | Prefer `Uint8Array#toBase64()` and `Uint8Array.fromBase64()` over `atob()`, `btoa()`, and `Buffer` base64 conversions. |
|
|
394
|
+
| [prefer-uint8array-base64](docs/rules/prefer-uint8array-base64.md) | Prefer `Uint8Array#toBase64()` and `Uint8Array.fromBase64()` over `atob()`, `btoa()`, and `Buffer` base64 conversions. | | | 💡 | |
|
|
395
395
|
| [prefer-unary-minus](docs/rules/prefer-unary-minus.md) | Prefer the unary minus operator over multiplying or dividing by `-1`. | ✅ ☑️ | 🔧 | | |
|
|
396
396
|
| [prefer-unicode-code-point-escapes](docs/rules/prefer-unicode-code-point-escapes.md) | Prefer Unicode code point escapes over legacy escape sequences. | ✅ ☑️ | 🔧 | 💡 | |
|
|
397
397
|
| [prefer-url-can-parse](docs/rules/prefer-url-can-parse.md) | Prefer `URL.canParse()` over constructing a `URL` in a try/catch for validation. | ✅ ☑️ | 🔧 | | |
|
|
@@ -566,3 +566,7 @@ export default defineConfig([
|
|
|
566
566
|
|
|
567
567
|
- [Sindre Sorhus](https://github.com/sindresorhus)
|
|
568
568
|
- [Fisker Cheung](https://github.com/fisker)
|
|
569
|
+
|
|
570
|
+
## Related
|
|
571
|
+
|
|
572
|
+
- [eslint-node-test](https://github.com/sindresorhus/eslint-node-test) — ESLint rules for the Node.js built-in test runner.
|
|
@@ -79,18 +79,12 @@ function create(node, options, types) {
|
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
Array.isArray(names)
|
|
82
|
+
return !(Array.isArray(names)
|
|
84
83
|
&& names.length > 0
|
|
85
84
|
&& (
|
|
86
85
|
node.callee.type !== 'Identifier'
|
|
87
86
|
|| !names.includes(node.callee.name)
|
|
88
|
-
)
|
|
89
|
-
) {
|
|
90
|
-
return false;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return true;
|
|
87
|
+
));
|
|
94
88
|
}
|
|
95
89
|
|
|
96
90
|
/**
|
|
@@ -83,16 +83,10 @@ export default function isMemberExpression(node, options) {
|
|
|
83
83
|
return false;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
Array.isArray(objects)
|
|
86
|
+
return !(Array.isArray(objects)
|
|
88
87
|
&& objects.length > 0
|
|
89
88
|
&& (
|
|
90
89
|
node.object.type !== 'Identifier'
|
|
91
90
|
|| !objects.includes(node.object.name)
|
|
92
|
-
)
|
|
93
|
-
) {
|
|
94
|
-
return false;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return true;
|
|
91
|
+
));
|
|
98
92
|
}
|
package/rules/comment-content.js
CHANGED
|
@@ -346,7 +346,7 @@ const pathTerminatorCharacters = '"\'`<>';
|
|
|
346
346
|
const packageSpecifierTerminatorCharacters = '"\'`()[]{}<>,';
|
|
347
347
|
const domainLeadingPunctuation = '([{<';
|
|
348
348
|
const domainTrailingPunctuation = '.,;:!?)]}>';
|
|
349
|
-
const maskCharacter = '\
|
|
349
|
+
const maskCharacter = '\u{FFFF}';
|
|
350
350
|
const openBrackets = '([{';
|
|
351
351
|
const closeBrackets = ')]}';
|
|
352
352
|
const quoteCharacters = '"\'`';
|
|
@@ -1062,14 +1062,14 @@ const create = context => {
|
|
|
1062
1062
|
return;
|
|
1063
1063
|
}
|
|
1064
1064
|
|
|
1065
|
-
let
|
|
1065
|
+
let isChecked = false;
|
|
1066
1066
|
|
|
1067
1067
|
onRoot(context, function * (node) {
|
|
1068
|
-
if (
|
|
1068
|
+
if (isChecked) {
|
|
1069
1069
|
return;
|
|
1070
1070
|
}
|
|
1071
1071
|
|
|
1072
|
-
|
|
1072
|
+
isChecked = true;
|
|
1073
1073
|
|
|
1074
1074
|
const {sourceCode} = context;
|
|
1075
1075
|
const comments = getRuleComments(context);
|
|
@@ -6,9 +6,11 @@ import {
|
|
|
6
6
|
getAvailableVariableName,
|
|
7
7
|
getScopes,
|
|
8
8
|
getVariableIdentifiers,
|
|
9
|
+
isReactHookName,
|
|
9
10
|
isNullishType,
|
|
10
11
|
isTypeParameterType,
|
|
11
12
|
isUnknownType,
|
|
13
|
+
lowerFirst,
|
|
12
14
|
upperFirst,
|
|
13
15
|
} from './utils/index.js';
|
|
14
16
|
import {
|
|
@@ -17,6 +19,7 @@ import {
|
|
|
17
19
|
isBooleanFunctionReference,
|
|
18
20
|
isBooleanFunctionTypeAnnotation,
|
|
19
21
|
isBooleanTypeAnnotation,
|
|
22
|
+
isFunctionTypeAnnotation,
|
|
20
23
|
} from './utils/is-boolean.js';
|
|
21
24
|
|
|
22
25
|
const MESSAGE_ID = 'consistent-boolean-name';
|
|
@@ -98,6 +101,7 @@ const typeScriptExpressionWrapperTypes = new Set([
|
|
|
98
101
|
]);
|
|
99
102
|
const isUpperCase = string => string === string.toUpperCase();
|
|
100
103
|
const stripLeadingUnderscores = name => name.replace(/^_+/, '');
|
|
104
|
+
const isScreamingCase = name => /^[A-Z][\dA-Z_]*$/.test(stripLeadingUnderscores(name));
|
|
101
105
|
|
|
102
106
|
const isFunction = node => [
|
|
103
107
|
'ArrowFunctionExpression',
|
|
@@ -180,6 +184,18 @@ function getReplacementName(name, prefix) {
|
|
|
180
184
|
: `${leadingUnderscores}${prefix}${upperFirst(nameWithoutLeadingUnderscores)}`;
|
|
181
185
|
}
|
|
182
186
|
|
|
187
|
+
function getReactHookReplacementName({name, nameForPrefixCheck}, prefix) {
|
|
188
|
+
if (name === nameForPrefixCheck) {
|
|
189
|
+
return getReplacementName(name, prefix);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const hookName = isScreamingCase(nameForPrefixCheck)
|
|
193
|
+
? getReplacementName(nameForPrefixCheck, prefix)
|
|
194
|
+
: `${prefix}${upperFirst(nameForPrefixCheck)}`;
|
|
195
|
+
|
|
196
|
+
return `use${upperFirst(hookName)}`;
|
|
197
|
+
}
|
|
198
|
+
|
|
183
199
|
const isExportedIdentifier = identifier => {
|
|
184
200
|
if (
|
|
185
201
|
identifier.parent.type === 'VariableDeclarator'
|
|
@@ -223,6 +239,23 @@ const shouldSuggestRename = variable => getVariableIdentifiers(variable)
|
|
|
223
239
|
&& identifier.type !== 'JSXIdentifier',
|
|
224
240
|
);
|
|
225
241
|
|
|
242
|
+
function isDestructuredDefinition(definition) {
|
|
243
|
+
for (let node = definition.name; node && node !== definition.node; node = node.parent) {
|
|
244
|
+
if (
|
|
245
|
+
node.type === 'ObjectPattern'
|
|
246
|
+
|| node.type === 'ArrayPattern'
|
|
247
|
+
) {
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const isDestructuredVariable = variable =>
|
|
256
|
+
variable.defs.length > 0
|
|
257
|
+
&& variable.defs.every(definition => isDestructuredDefinition(definition));
|
|
258
|
+
|
|
226
259
|
const isBooleanFunctionDefinition = (definition, context) =>
|
|
227
260
|
definition.type === 'FunctionName'
|
|
228
261
|
&& isFunction(definition.node)
|
|
@@ -264,6 +297,41 @@ function getFunctionDefinitions(variable) {
|
|
|
264
297
|
return overloadDefinitions.length > 0 ? overloadDefinitions : variable.defs;
|
|
265
298
|
}
|
|
266
299
|
|
|
300
|
+
function isReactHookFunctionBinding(variable, context) {
|
|
301
|
+
if (
|
|
302
|
+
variable.name === 'use'
|
|
303
|
+
|| !isReactHookName(variable.name)
|
|
304
|
+
) {
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (getFunctionDefinitions(variable)) {
|
|
309
|
+
return true;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const definition = getSupportedVariableDefinition(variable);
|
|
313
|
+
|
|
314
|
+
if (definition?.type === 'FunctionName') {
|
|
315
|
+
return isFunction(definition.node);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return definition?.type === 'Variable'
|
|
319
|
+
&& (
|
|
320
|
+
isFunction(definition.node.init)
|
|
321
|
+
|| isFunctionTypeAnnotation(definition.name.typeAnnotation, context, context.sourceCode.getScope(definition.name))
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function getNameForPrefixCheck(variable, context) {
|
|
326
|
+
if (!isReactHookFunctionBinding(variable, context)) {
|
|
327
|
+
return variable.name;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const hookName = variable.name.slice(3);
|
|
331
|
+
|
|
332
|
+
return isScreamingCase(hookName) ? hookName : lowerFirst(hookName);
|
|
333
|
+
}
|
|
334
|
+
|
|
267
335
|
function combineBooleanStates(states) {
|
|
268
336
|
if (
|
|
269
337
|
states.length === 0
|
|
@@ -888,7 +956,7 @@ function getPropertyBooleanState(node, context) {
|
|
|
888
956
|
return state === unknown && isBooleanProperty(node, context) ? boolean : state;
|
|
889
957
|
}
|
|
890
958
|
|
|
891
|
-
function getSuggestions(variable, prefixes, context) {
|
|
959
|
+
function getSuggestions(variable, prefixes, context, nameForPrefixCheck) {
|
|
892
960
|
if (
|
|
893
961
|
!shouldSuggestRename(variable)
|
|
894
962
|
|| variable.references.some(reference => reference.vueUsedInTemplate)
|
|
@@ -904,7 +972,7 @@ function getSuggestions(variable, prefixes, context) {
|
|
|
904
972
|
const suggestions = [];
|
|
905
973
|
|
|
906
974
|
for (const prefix of prefixes) {
|
|
907
|
-
const replacement = getAvailableVariableName(
|
|
975
|
+
const replacement = getAvailableVariableName(getReactHookReplacementName({name: variable.name, nameForPrefixCheck}, prefix), scopes);
|
|
908
976
|
|
|
909
977
|
if (!replacement || usedReplacements.has(replacement)) {
|
|
910
978
|
continue;
|
|
@@ -954,7 +1022,13 @@ function isInDeclareContext(node) {
|
|
|
954
1022
|
return false;
|
|
955
1023
|
}
|
|
956
1024
|
|
|
957
|
-
function getAutofix(
|
|
1025
|
+
function getAutofix({
|
|
1026
|
+
variable,
|
|
1027
|
+
prefixes,
|
|
1028
|
+
context,
|
|
1029
|
+
suggestions,
|
|
1030
|
+
nameForPrefixCheck,
|
|
1031
|
+
}) {
|
|
958
1032
|
if (
|
|
959
1033
|
!suggestions
|
|
960
1034
|
|| !isAutofixableVariable(variable, context)
|
|
@@ -963,7 +1037,7 @@ function getAutofix(variable, prefixes, context, suggestions) {
|
|
|
963
1037
|
}
|
|
964
1038
|
|
|
965
1039
|
const [prefix] = prefixes;
|
|
966
|
-
const replacement =
|
|
1040
|
+
const replacement = getReactHookReplacementName({name: variable.name, nameForPrefixCheck}, prefix);
|
|
967
1041
|
const suggestion = suggestions.find(suggestion => suggestion.data.replacement === replacement);
|
|
968
1042
|
|
|
969
1043
|
return suggestion?.fix;
|
|
@@ -978,11 +1052,15 @@ const create = context => {
|
|
|
978
1052
|
}
|
|
979
1053
|
|
|
980
1054
|
const checkVariable = variable => {
|
|
981
|
-
if (
|
|
1055
|
+
if (
|
|
1056
|
+
isIgnoredName(variable.name, ignore)
|
|
1057
|
+
|| isDestructuredVariable(variable)
|
|
1058
|
+
) {
|
|
982
1059
|
return;
|
|
983
1060
|
}
|
|
984
1061
|
|
|
985
|
-
const
|
|
1062
|
+
const nameForPrefixCheck = getNameForPrefixCheck(variable, context);
|
|
1063
|
+
const booleanPrefix = getBooleanPrefix(nameForPrefixCheck, prefixes);
|
|
986
1064
|
if (booleanPrefix) {
|
|
987
1065
|
if (getVariableBooleanState(variable, context) === nonBoolean) {
|
|
988
1066
|
const [definition] = variable.defs;
|
|
@@ -991,7 +1069,7 @@ const create = context => {
|
|
|
991
1069
|
node: definition.name,
|
|
992
1070
|
messageId: MESSAGE_ID_NON_BOOLEAN_PREFIX,
|
|
993
1071
|
data: {
|
|
994
|
-
name:
|
|
1072
|
+
name: nameForPrefixCheck,
|
|
995
1073
|
prefix: booleanPrefix,
|
|
996
1074
|
},
|
|
997
1075
|
});
|
|
@@ -1008,16 +1086,22 @@ const create = context => {
|
|
|
1008
1086
|
}
|
|
1009
1087
|
|
|
1010
1088
|
const [definition] = variable.defs;
|
|
1011
|
-
const suggest = getSuggestions(variable, prefixes, context);
|
|
1089
|
+
const suggest = getSuggestions(variable, prefixes, context, nameForPrefixCheck);
|
|
1012
1090
|
|
|
1013
1091
|
context.report({
|
|
1014
1092
|
node: definition.name,
|
|
1015
1093
|
messageId: MESSAGE_ID,
|
|
1016
1094
|
data: {
|
|
1017
|
-
name:
|
|
1095
|
+
name: nameForPrefixCheck,
|
|
1018
1096
|
prefixes: formatPrefixes(prefixes),
|
|
1019
1097
|
},
|
|
1020
|
-
fix: getAutofix(
|
|
1098
|
+
fix: getAutofix({
|
|
1099
|
+
variable,
|
|
1100
|
+
prefixes,
|
|
1101
|
+
context,
|
|
1102
|
+
suggestions: suggest,
|
|
1103
|
+
nameForPrefixCheck,
|
|
1104
|
+
}),
|
|
1021
1105
|
suggest,
|
|
1022
1106
|
});
|
|
1023
1107
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import helperValidatorIdentifier from '@babel/helper-validator-identifier';
|
|
2
1
|
import {
|
|
3
2
|
getAvailableVariableName,
|
|
4
3
|
getScopes,
|
|
5
4
|
isShorthandPropertyValue,
|
|
6
5
|
lowerFirst,
|
|
7
6
|
upperFirst,
|
|
7
|
+
isIdentifierName,
|
|
8
8
|
} from './utils/index.js';
|
|
9
9
|
import {
|
|
10
10
|
isClassVariable,
|
|
@@ -17,7 +17,6 @@ import {renameVariable} from './fix/index.js';
|
|
|
17
17
|
|
|
18
18
|
const MESSAGE_ID_ERROR = 'consistent-compound-words/error';
|
|
19
19
|
const MESSAGE_ID_RENAME = 'consistent-compound-words/rename';
|
|
20
|
-
const {isIdentifierName} = helperValidatorIdentifier;
|
|
21
20
|
|
|
22
21
|
const messages = {
|
|
23
22
|
[MESSAGE_ID_ERROR]: 'Prefer `{{replacement}}` over `{{name}}`.',
|
|
@@ -113,15 +113,12 @@ function isBufferEncoding(node, scope) {
|
|
|
113
113
|
|
|
114
114
|
function isJsonReadFileCall(node, scope) {
|
|
115
115
|
if (
|
|
116
|
-
!(
|
|
117
|
-
node
|
|
116
|
+
!(node
|
|
118
117
|
&& node.type === 'CallExpression'
|
|
119
118
|
&& !node.optional
|
|
120
119
|
&& (node.arguments.length === 1 || node.arguments.length === 2)
|
|
121
120
|
&& node.arguments.every(node => node.type !== 'SpreadElement')
|
|
122
|
-
&& node.callee.type === 'MemberExpression'
|
|
123
|
-
&& !node.callee.optional
|
|
124
|
-
)
|
|
121
|
+
&& node.callee.type === 'MemberExpression') || node.callee.optional
|
|
125
122
|
) {
|
|
126
123
|
return false;
|
|
127
124
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import helperValidatorIdentifier from '@babel/helper-validator-identifier';
|
|
2
1
|
import {findVariable} from '@eslint-community/eslint-utils';
|
|
3
2
|
import {
|
|
4
3
|
escapeString,
|
|
@@ -12,6 +11,7 @@ import {
|
|
|
12
11
|
needsSemicolon,
|
|
13
12
|
shouldAddParenthesesToMemberExpressionObject,
|
|
14
13
|
wouldRemoveComments,
|
|
14
|
+
isIdentifierName,
|
|
15
15
|
} from './utils/index.js';
|
|
16
16
|
import {removeStatement} from './fix/index.js';
|
|
17
17
|
import {
|
|
@@ -21,7 +21,6 @@ import {
|
|
|
21
21
|
isExpressionStatement,
|
|
22
22
|
} from './ast/index.js';
|
|
23
23
|
|
|
24
|
-
const {isIdentifierName} = helperValidatorIdentifier;
|
|
25
24
|
const MESSAGE_ID = 'prefer-dataset';
|
|
26
25
|
const INVERSE_MESSAGE_ID = 'prefer-attributes';
|
|
27
26
|
const messages = {
|
|
@@ -106,11 +105,8 @@ function getDatasetVariableReadMembers(variable) {
|
|
|
106
105
|
|
|
107
106
|
const {identifier} = reference;
|
|
108
107
|
const member = identifier.parent;
|
|
109
|
-
if (!(
|
|
110
|
-
member.
|
|
111
|
-
&& member.object === identifier
|
|
112
|
-
&& !member.optional
|
|
113
|
-
)) {
|
|
108
|
+
if (!(member.type === 'MemberExpression'
|
|
109
|
+
&& member.object === identifier) || member.optional) {
|
|
114
110
|
return;
|
|
115
111
|
}
|
|
116
112
|
|
package/rules/escape-case.js
CHANGED
|
@@ -24,14 +24,14 @@ const getProblem = ({node, original, regex = escapeCase, lowercase, fix}) => {
|
|
|
24
24
|
|
|
25
25
|
/** @param {import('eslint').Rule.RuleContext} context */
|
|
26
26
|
const create = context => {
|
|
27
|
-
const
|
|
27
|
+
const isLowercase = context.options[0] === 'lowercase';
|
|
28
28
|
|
|
29
29
|
context.on('Literal', node => {
|
|
30
30
|
if (isStringLiteral(node)) {
|
|
31
31
|
return getProblem({
|
|
32
32
|
node,
|
|
33
33
|
original: node.raw,
|
|
34
|
-
lowercase,
|
|
34
|
+
lowercase: isLowercase,
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
37
|
});
|
|
@@ -42,7 +42,7 @@ const create = context => {
|
|
|
42
42
|
node,
|
|
43
43
|
original: node.raw,
|
|
44
44
|
regex: escapePatternCase,
|
|
45
|
-
lowercase,
|
|
45
|
+
lowercase: isLowercase,
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
});
|
|
@@ -55,7 +55,7 @@ const create = context => {
|
|
|
55
55
|
return getProblem({
|
|
56
56
|
node,
|
|
57
57
|
original: node.value.raw,
|
|
58
|
-
lowercase,
|
|
58
|
+
lowercase: isLowercase,
|
|
59
59
|
fix: (fixer, fixed) => replaceTemplateElement(node, fixed, context, fixer),
|
|
60
60
|
});
|
|
61
61
|
});
|
|
@@ -191,8 +191,8 @@ function getPackageHelpers(dirname) {
|
|
|
191
191
|
|
|
192
192
|
// Check if have to skip colon
|
|
193
193
|
// @example "TODO [...]: message here"
|
|
194
|
-
const
|
|
195
|
-
if (
|
|
194
|
+
const isDropColon = afterArguments[0] === ':';
|
|
195
|
+
if (isDropColon) {
|
|
196
196
|
return afterArguments.slice(1).trim();
|
|
197
197
|
}
|
|
198
198
|
|
|
@@ -250,7 +250,7 @@ function create(context) {
|
|
|
250
250
|
}
|
|
251
251
|
|
|
252
252
|
let node;
|
|
253
|
-
let
|
|
253
|
+
let isAutoFix = true;
|
|
254
254
|
let {isZeroLengthCheck, node: lengthCheckNode} = getLengthCheckNode(lengthNode);
|
|
255
255
|
if (lengthCheckNode) {
|
|
256
256
|
const {isNegative, node: ancestor} = getBooleanAncestor(lengthCheckNode, context);
|
|
@@ -266,7 +266,7 @@ function create(context) {
|
|
|
266
266
|
} else if (isLogicalExpression(lengthNode.parent) && lengthNode.parent.operator === '&&') {
|
|
267
267
|
isZeroLengthCheck = isNegative;
|
|
268
268
|
node = lengthNode;
|
|
269
|
-
|
|
269
|
+
isAutoFix = false;
|
|
270
270
|
}
|
|
271
271
|
}
|
|
272
272
|
|
|
@@ -287,7 +287,7 @@ function create(context) {
|
|
|
287
287
|
node,
|
|
288
288
|
isZeroLengthCheck,
|
|
289
289
|
lengthNode,
|
|
290
|
-
autoFix:
|
|
290
|
+
autoFix: isAutoFix && !isUnsafeNegationInBinaryExpression,
|
|
291
291
|
shouldSuggest: !isUnsafeNegationInBinaryExpression,
|
|
292
292
|
});
|
|
293
293
|
}
|
package/rules/filename-case.js
CHANGED
|
@@ -280,8 +280,8 @@ const create = context => {
|
|
|
280
280
|
|
|
281
281
|
return new RegExp(item, 'u');
|
|
282
282
|
});
|
|
283
|
-
const
|
|
284
|
-
const
|
|
283
|
+
const isMultipleFileExtensions = options.multipleFileExtensions !== false;
|
|
284
|
+
const isCheckDirectories = options.checkDirectories !== false;
|
|
285
285
|
const chosenCasesFunctions = chosenCases.map(case_ => cases[case_].fn);
|
|
286
286
|
|
|
287
287
|
onRoot(context, () => {
|
|
@@ -292,13 +292,13 @@ const create = context => {
|
|
|
292
292
|
filename,
|
|
293
293
|
middle,
|
|
294
294
|
extension,
|
|
295
|
-
} = getFilenameParts(basenameWithExtension, {multipleFileExtensions});
|
|
295
|
+
} = getFilenameParts(basenameWithExtension, {multipleFileExtensions: isMultipleFileExtensions});
|
|
296
296
|
|
|
297
297
|
if (pathSegments.some(segment => ignore.some(regexp => regexp.test(segment)))) {
|
|
298
298
|
return;
|
|
299
299
|
}
|
|
300
300
|
|
|
301
|
-
if (
|
|
301
|
+
if (isCheckDirectories) {
|
|
302
302
|
for (const directory of pathSegments.slice(0, -1)) {
|
|
303
303
|
const report = getInvalidDirectoryReport(directory, chosenCases, chosenCasesFunctions);
|
|
304
304
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {isCommaToken} from '@eslint-community/eslint-utils';
|
|
2
|
-
import {getParentheses} from '../utils/index.js';
|
|
2
|
+
import {getParentheses, hasCommentInRange} from '../utils/index.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
@import {TSESTree as ESTree} from '@typescript-eslint/types';
|
|
@@ -22,17 +22,22 @@ function getArgumentRemovalRange(node, context) {
|
|
|
22
22
|
let [start] = sourceCode.getRange(firstToken);
|
|
23
23
|
let [, end] = sourceCode.getRange(lastToken);
|
|
24
24
|
|
|
25
|
-
if (index !== 0) {
|
|
26
|
-
const commaToken = sourceCode.getTokenBefore(firstToken);
|
|
27
|
-
[start] = sourceCode.getRange(commaToken);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// If the removed argument is the only argument, the trailing comma must be removed too
|
|
31
25
|
if (callOrNewExpression.arguments.length === 1) {
|
|
26
|
+
// The only argument: also drop a dangling trailing comma if present (`fn(a,)`).
|
|
32
27
|
const tokenAfter = sourceCode.getTokenAfter(lastToken);
|
|
33
28
|
if (isCommaToken(tokenAfter)) {
|
|
34
29
|
[, end] = sourceCode.getRange(tokenAfter);
|
|
35
30
|
}
|
|
31
|
+
} else if (index === 0) {
|
|
32
|
+
// First of several: remove it through the following comma and the gap after it, so
|
|
33
|
+
// `fn(a, b)` becomes `fn(b)` rather than `fn( b)`.
|
|
34
|
+
const commaToken = sourceCode.getTokenAfter(lastToken);
|
|
35
|
+
const tokenAfterComma = sourceCode.getTokenAfter(commaToken, {includeComments: true});
|
|
36
|
+
[end] = sourceCode.getRange(tokenAfterComma);
|
|
37
|
+
} else {
|
|
38
|
+
// Otherwise remove the comma that precedes it.
|
|
39
|
+
const commaToken = sourceCode.getTokenBefore(firstToken);
|
|
40
|
+
[start] = sourceCode.getRange(commaToken);
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
return [start, end];
|
|
@@ -45,7 +50,28 @@ function getArgumentRemovalRange(node, context) {
|
|
|
45
50
|
@returns {ESLint.Rule.Fix}
|
|
46
51
|
*/
|
|
47
52
|
export default function removeArgument(fixer, node, context) {
|
|
48
|
-
|
|
53
|
+
const removalRange = getArgumentRemovalRange(node, context);
|
|
54
|
+
const callOrNewExpression = node.parent;
|
|
55
|
+
const index = callOrNewExpression.arguments.indexOf(node);
|
|
56
|
+
|
|
57
|
+
if (
|
|
58
|
+
index === 0
|
|
59
|
+
&& callOrNewExpression.arguments.length > 1
|
|
60
|
+
&& hasCommentInRange(context, removalRange)
|
|
61
|
+
) {
|
|
62
|
+
const {sourceCode} = context;
|
|
63
|
+
const parentheses = getParentheses(node, context);
|
|
64
|
+
const lastToken = parentheses.at(-1) || node;
|
|
65
|
+
const [, argumentEnd] = sourceCode.getRange(lastToken);
|
|
66
|
+
const commaToken = sourceCode.getTokenAfter(lastToken);
|
|
67
|
+
const [commaStart, commaEnd] = sourceCode.getRange(commaToken);
|
|
68
|
+
const rangeText = sourceCode.text.slice(...removalRange);
|
|
69
|
+
const replacement = rangeText.slice(argumentEnd - removalRange[0], commaStart - removalRange[0]) + rangeText.slice(commaEnd - removalRange[0]);
|
|
70
|
+
|
|
71
|
+
return fixer.replaceTextRange(removalRange, replacement);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return fixer.removeRange(removalRange);
|
|
49
75
|
}
|
|
50
76
|
|
|
51
77
|
export {
|
|
@@ -3,7 +3,7 @@ import {isSemicolonToken} from '@eslint-community/eslint-utils';
|
|
|
3
3
|
const isWhitespaceOnly = text => /^\s*$/.test(text);
|
|
4
4
|
|
|
5
5
|
// Removes a statement node along with its surrounding whitespace, while preserving comments.
|
|
6
|
-
function removeStatement(statement, context, fixer, preserveSemiColon = false) {
|
|
6
|
+
export default function removeStatement(statement, context, fixer, preserveSemiColon = false) {
|
|
7
7
|
const {sourceCode} = context;
|
|
8
8
|
const {lines} = sourceCode;
|
|
9
9
|
let endToken = statement;
|
|
@@ -44,5 +44,3 @@ function removeStatement(statement, context, fixer, preserveSemiColon = false) {
|
|
|
44
44
|
|
|
45
45
|
return fixer.removeRange([start, end]);
|
|
46
46
|
}
|
|
47
|
-
|
|
48
|
-
export default removeStatement;
|
package/rules/id-match.js
CHANGED
|
@@ -26,11 +26,11 @@ const shouldIgnoreNamedSpecifierReport = (problem, checkNamedSpecifiers) =>
|
|
|
26
26
|
@param {import('eslint').Rule.RuleContext} context
|
|
27
27
|
*/
|
|
28
28
|
const create = context => {
|
|
29
|
-
const
|
|
29
|
+
const isCheckNamedSpecifiers = context.options[1]?.checkNamedSpecifiers !== false;
|
|
30
30
|
const fakeContext = Object.create(context, {
|
|
31
31
|
report: {
|
|
32
32
|
value(problem) {
|
|
33
|
-
if (shouldIgnoreNamedSpecifierReport(problem,
|
|
33
|
+
if (shouldIgnoreNamedSpecifierReport(problem, isCheckNamedSpecifiers)) {
|
|
34
34
|
return;
|
|
35
35
|
}
|
|
36
36
|
|