eslint-plugin-unicorn 52.0.0 → 54.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 +33 -11
- package/package.json +29 -38
- package/readme.md +12 -6
- package/rules/ast/index.js +2 -0
- package/rules/ast/is-directive.js +7 -0
- package/rules/ast/is-reference-identifier.js +7 -0
- package/rules/ast/is-tagged-template-literal.js +28 -0
- package/rules/better-regex.js +1 -0
- package/rules/catch-error-name.js +1 -0
- package/rules/consistent-destructuring.js +1 -0
- package/rules/consistent-empty-array-spread.js +126 -0
- package/rules/consistent-function-scoping.js +1 -0
- package/rules/custom-error-definition.js +1 -0
- package/rules/empty-brace-spaces.js +1 -0
- package/rules/error-message.js +1 -0
- package/rules/escape-case.js +17 -6
- package/rules/expiring-todo-comments.js +11 -2
- package/rules/explicit-length-check.js +7 -1
- package/rules/filename-case.js +1 -0
- package/rules/fix/switch-call-expression-to-new-expression.js +2 -0
- package/rules/import-style.js +1 -0
- package/rules/new-for-builtins.js +1 -0
- package/rules/no-abusive-eslint-disable.js +1 -0
- package/rules/no-anonymous-default-export.js +1 -0
- package/rules/no-array-callback-reference.js +1 -0
- package/rules/no-array-for-each.js +13 -2
- package/rules/no-array-method-this-argument.js +3 -2
- package/rules/no-array-push-push.js +15 -7
- package/rules/no-array-reduce.js +1 -0
- package/rules/no-await-expression-member.js +1 -0
- package/rules/no-await-in-promise-methods.js +1 -0
- package/rules/no-console-spaces.js +1 -0
- package/rules/no-document-cookie.js +1 -0
- package/rules/no-empty-file.js +2 -2
- package/rules/no-for-loop.js +1 -0
- package/rules/no-hex-escape.js +13 -2
- package/rules/no-instanceof-array.js +1 -0
- package/rules/no-invalid-fetch-options.js +111 -0
- package/rules/no-invalid-remove-event-listener.js +1 -0
- package/rules/no-keyword-prefix.js +1 -0
- package/rules/no-lonely-if.js +1 -0
- package/rules/no-magic-array-flat-depth.js +54 -0
- package/rules/no-negated-condition.js +1 -0
- package/rules/no-negation-in-equality-check.js +104 -0
- package/rules/no-nested-ternary.js +1 -0
- package/rules/no-new-array.js +1 -0
- package/rules/no-new-buffer.js +1 -0
- package/rules/no-null.js +1 -0
- package/rules/no-object-as-default-parameter.js +1 -0
- package/rules/no-process-exit.js +1 -0
- package/rules/no-single-promise-in-promise-methods.js +1 -0
- package/rules/no-static-only-class.js +1 -0
- package/rules/no-thenable.js +1 -0
- package/rules/no-this-assignment.js +1 -0
- package/rules/no-typeof-undefined.js +1 -0
- package/rules/no-unnecessary-await.js +1 -0
- package/rules/no-unnecessary-polyfills.js +3 -2
- package/rules/no-unreadable-array-destructuring.js +1 -0
- package/rules/no-unreadable-iife.js +1 -0
- package/rules/no-unused-properties.js +1 -0
- package/rules/no-useless-fallback-in-spread.js +1 -0
- package/rules/no-useless-length-check.js +1 -0
- package/rules/no-useless-promise-resolve-reject.js +3 -2
- package/rules/no-useless-spread.js +1 -0
- package/rules/no-useless-switch-case.js +3 -16
- package/rules/no-useless-undefined.js +1 -0
- package/rules/no-zero-fractions.js +1 -0
- package/rules/number-literal-case.js +1 -0
- package/rules/numeric-separators-style.js +1 -0
- package/rules/prefer-add-event-listener.js +2 -1
- package/rules/prefer-array-find.js +4 -3
- package/rules/prefer-array-flat-map.js +1 -0
- package/rules/prefer-array-flat.js +1 -0
- package/rules/prefer-array-index-of.js +1 -0
- package/rules/prefer-array-some.js +65 -7
- package/rules/prefer-at.js +1 -0
- package/rules/prefer-blob-reading-methods.js +1 -0
- package/rules/prefer-code-point.js +1 -0
- package/rules/prefer-date-now.js +1 -0
- package/rules/prefer-default-parameters.js +1 -0
- package/rules/prefer-dom-node-append.js +1 -0
- package/rules/prefer-dom-node-dataset.js +12 -0
- package/rules/prefer-dom-node-remove.js +1 -0
- package/rules/prefer-dom-node-text-content.js +1 -0
- package/rules/prefer-event-target.js +1 -0
- package/rules/prefer-export-from.js +2 -3
- package/rules/prefer-includes.js +8 -4
- package/rules/prefer-json-parse-buffer.js +1 -0
- package/rules/prefer-keyboard-event-key.js +1 -0
- package/rules/prefer-logical-operator-over-ternary.js +1 -0
- package/rules/prefer-math-trunc.js +1 -0
- package/rules/prefer-modern-dom-apis.js +1 -0
- package/rules/prefer-modern-math-apis.js +1 -0
- package/rules/prefer-module.js +13 -12
- package/rules/prefer-native-coercion-functions.js +1 -0
- package/rules/prefer-negative-index.js +1 -0
- package/rules/prefer-node-protocol.js +1 -0
- package/rules/prefer-number-properties.js +19 -5
- package/rules/prefer-object-from-entries.js +1 -0
- package/rules/prefer-optional-catch-binding.js +1 -0
- package/rules/prefer-prototype-methods.js +1 -0
- package/rules/prefer-query-selector.js +1 -0
- package/rules/prefer-reflect-apply.js +1 -0
- package/rules/prefer-regexp-test.js +1 -0
- package/rules/prefer-set-has.js +1 -0
- package/rules/prefer-set-size.js +1 -0
- package/rules/prefer-spread.js +1 -0
- package/rules/prefer-string-raw.js +94 -0
- package/rules/prefer-string-replace-all.js +1 -0
- package/rules/prefer-string-slice.js +7 -1
- package/rules/prefer-string-starts-ends-with.js +1 -0
- package/rules/prefer-string-trim-start-end.js +1 -0
- package/rules/prefer-structured-clone.js +151 -0
- package/rules/prefer-switch.js +1 -0
- package/rules/prefer-ternary.js +1 -0
- package/rules/prefer-top-level-await.js +1 -0
- package/rules/prefer-type-error.js +1 -0
- package/rules/prevent-abbreviations.js +2 -1
- package/rules/relative-url-style.js +1 -0
- package/rules/require-array-join-separator.js +1 -0
- package/rules/require-number-to-fixed-digits-argument.js +1 -0
- package/rules/require-post-message-target-origin.js +3 -0
- package/rules/string-content.js +3 -1
- package/rules/switch-case-braces.js +1 -0
- package/rules/template-indent.js +9 -7
- package/rules/text-encoding-identifier-case.js +1 -0
- package/rules/throw-new-error.js +3 -9
- package/rules/utils/escape-template-element-raw.js +1 -1
- package/rules/utils/get-call-expression-arguments-text.js +11 -6
- package/rules/utils/get-call-expression-tokens.js +37 -0
- package/rules/utils/index.js +2 -0
- package/rules/utils/numeric.js +6 -1
- package/rules/utils/rule.js +2 -6
- package/configs/all.js +0 -6
- package/configs/recommended.js +0 -120
package/index.js
CHANGED
|
@@ -3,8 +3,6 @@ const createDeprecatedRules = require('./rules/utils/create-deprecated-rules.js'
|
|
|
3
3
|
const {loadRules} = require('./rules/utils/rule.js');
|
|
4
4
|
const legacyConfigBase = require('./configs/legacy-config-base.js');
|
|
5
5
|
const flatConfigBase = require('./configs/flat-config-base.js');
|
|
6
|
-
const recommendedRules = require('./configs/recommended.js');
|
|
7
|
-
const allRules = require('./configs/all.js');
|
|
8
6
|
const {name, version} = require('./package.json');
|
|
9
7
|
|
|
10
8
|
const deprecatedRules = createDeprecatedRules({
|
|
@@ -28,10 +26,34 @@ const deprecatedRules = createDeprecatedRules({
|
|
|
28
26
|
'regex-shorthand': 'unicorn/better-regex',
|
|
29
27
|
});
|
|
30
28
|
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
29
|
+
const externalRules = {
|
|
30
|
+
// Covered by `unicorn/no-negated-condition`
|
|
31
|
+
'no-negated-condition': 'off',
|
|
32
|
+
// Covered by `unicorn/no-nested-ternary`
|
|
33
|
+
'no-nested-ternary': 'off',
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const rules = loadRules();
|
|
37
|
+
const recommendedRules = Object.fromEntries(
|
|
38
|
+
Object.entries(rules).map(([id, rule]) => [
|
|
39
|
+
`unicorn/${id}`,
|
|
40
|
+
rule.meta.docs.recommended ? 'error' : 'off',
|
|
41
|
+
]),
|
|
42
|
+
);
|
|
43
|
+
const allRules = Object.fromEntries(
|
|
44
|
+
Object.keys(rules).map(id => [
|
|
45
|
+
`unicorn/${id}`,
|
|
46
|
+
'error',
|
|
47
|
+
]),
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const createConfig = (rules, flatConfigName = false) => ({
|
|
51
|
+
...(
|
|
52
|
+
flatConfigName
|
|
53
|
+
? {...flatConfigBase, name: flatConfigName, plugins: {unicorn}}
|
|
54
|
+
: {...legacyConfigBase, plugins: ['unicorn']}
|
|
55
|
+
),
|
|
56
|
+
rules: {...externalRules, ...rules},
|
|
35
57
|
});
|
|
36
58
|
|
|
37
59
|
const unicorn = {
|
|
@@ -40,16 +62,16 @@ const unicorn = {
|
|
|
40
62
|
version,
|
|
41
63
|
},
|
|
42
64
|
rules: {
|
|
43
|
-
...
|
|
65
|
+
...rules,
|
|
44
66
|
...deprecatedRules,
|
|
45
67
|
},
|
|
46
68
|
};
|
|
47
69
|
|
|
48
70
|
const configs = {
|
|
49
|
-
recommended: createConfig(recommendedRules
|
|
50
|
-
all: createConfig(allRules
|
|
51
|
-
'flat/recommended': createConfig(recommendedRules),
|
|
52
|
-
'flat/all': createConfig(allRules),
|
|
71
|
+
recommended: createConfig(recommendedRules),
|
|
72
|
+
all: createConfig(allRules),
|
|
73
|
+
'flat/recommended': createConfig(recommendedRules, 'unicorn/flat/recommended'),
|
|
74
|
+
'flat/all': createConfig(allRules, 'unicorn/flat/all'),
|
|
53
75
|
};
|
|
54
76
|
|
|
55
77
|
module.exports = {...unicorn, configs};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-unicorn",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "54.0.0",
|
|
4
4
|
"description": "More than 100 powerful ESLint rules",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "sindresorhus/eslint-plugin-unicorn",
|
|
@@ -13,9 +13,10 @@
|
|
|
13
13
|
"main": "index.js",
|
|
14
14
|
"sideEffects": false,
|
|
15
15
|
"engines": {
|
|
16
|
-
"node": ">=
|
|
16
|
+
"node": ">=18.18"
|
|
17
17
|
},
|
|
18
18
|
"scripts": {
|
|
19
|
+
"bundle-lodash": "echo \"export {defaultsDeep, camelCase, kebabCase, snakeCase, upperFirst, lowerFirst} from 'lodash-es';\" | npx esbuild --bundle --outfile=rules/utils/lodash.js --format=cjs",
|
|
19
20
|
"create-rule": "node ./scripts/create-rule.mjs && npm run fix:eslint-docs",
|
|
20
21
|
"fix": "run-p --continue-on-error fix:*",
|
|
21
22
|
"fix:eslint-docs": "eslint-doc-generator",
|
|
@@ -28,8 +29,7 @@
|
|
|
28
29
|
"lint:markdown": "markdownlint \"**/*.md\"",
|
|
29
30
|
"lint:package-json": "npmPkgJsonLint .",
|
|
30
31
|
"run-rules-on-codebase": "node ./test/run-rules-on-codebase/lint.mjs",
|
|
31
|
-
"
|
|
32
|
-
"smoke": "eslint-remote-tester --config ./test/smoke/eslint-remote-tester.config.js",
|
|
32
|
+
"smoke": "eslint-remote-tester --config ./test/smoke/eslint-remote-tester.config.mjs",
|
|
33
33
|
"test": "npm-run-all --continue-on-error lint test:*",
|
|
34
34
|
"test:js": "c8 ava"
|
|
35
35
|
},
|
|
@@ -49,12 +49,12 @@
|
|
|
49
49
|
"xo"
|
|
50
50
|
],
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@babel/helper-validator-identifier": "^7.
|
|
52
|
+
"@babel/helper-validator-identifier": "^7.24.5",
|
|
53
53
|
"@eslint-community/eslint-utils": "^4.4.0",
|
|
54
|
-
"@eslint/eslintrc": "^
|
|
54
|
+
"@eslint/eslintrc": "^3.0.2",
|
|
55
55
|
"ci-info": "^4.0.0",
|
|
56
56
|
"clean-regexp": "^1.0.0",
|
|
57
|
-
"core-js-compat": "^3.
|
|
57
|
+
"core-js-compat": "^3.37.0",
|
|
58
58
|
"esquery": "^1.5.0",
|
|
59
59
|
"indent-string": "^4.0.0",
|
|
60
60
|
"is-builtin-module": "^3.2.1",
|
|
@@ -63,39 +63,40 @@
|
|
|
63
63
|
"read-pkg-up": "^7.0.1",
|
|
64
64
|
"regexp-tree": "^0.1.27",
|
|
65
65
|
"regjsparser": "^0.10.0",
|
|
66
|
-
"semver": "^7.
|
|
66
|
+
"semver": "^7.6.1",
|
|
67
67
|
"strip-indent": "^3.0.0"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
|
-
"@babel/code-frame": "^7.
|
|
71
|
-
"@babel/core": "^7.
|
|
72
|
-
"@babel/eslint-parser": "^7.
|
|
70
|
+
"@babel/code-frame": "^7.24.2",
|
|
71
|
+
"@babel/core": "^7.24.5",
|
|
72
|
+
"@babel/eslint-parser": "^7.24.5",
|
|
73
73
|
"@lubien/fixture-beta-package": "^1.0.0-beta.1",
|
|
74
|
-
"@typescript-eslint/parser": "^
|
|
75
|
-
"ava": "^6.
|
|
76
|
-
"c8": "^
|
|
74
|
+
"@typescript-eslint/parser": "^8.0.0-alpha.12",
|
|
75
|
+
"ava": "^6.1.3",
|
|
76
|
+
"c8": "^9.1.0",
|
|
77
77
|
"chalk": "^5.3.0",
|
|
78
78
|
"enquirer": "^2.4.1",
|
|
79
|
-
"eslint": "^
|
|
79
|
+
"eslint": "^9.2.0",
|
|
80
80
|
"eslint-ava-rule-tester": "^5.0.1",
|
|
81
|
-
"eslint-doc-generator": "
|
|
82
|
-
"eslint-plugin-eslint-plugin": "^
|
|
81
|
+
"eslint-doc-generator": "1.7.0",
|
|
82
|
+
"eslint-plugin-eslint-plugin": "^6.1.0",
|
|
83
83
|
"eslint-plugin-internal-rules": "file:./scripts/internal-rules/",
|
|
84
|
-
"eslint-remote-tester": "^
|
|
85
|
-
"eslint-remote-tester-repositories": "^
|
|
84
|
+
"eslint-remote-tester": "^4.0.0",
|
|
85
|
+
"eslint-remote-tester-repositories": "^2.0.0",
|
|
86
|
+
"espree": "^10.0.1",
|
|
86
87
|
"execa": "^8.0.1",
|
|
87
88
|
"listr": "^0.14.3",
|
|
88
89
|
"lodash-es": "^4.17.21",
|
|
89
|
-
"markdownlint-cli": "^0.
|
|
90
|
+
"markdownlint-cli": "^0.40.0",
|
|
90
91
|
"memoize": "^10.0.0",
|
|
91
92
|
"npm-package-json-lint": "^7.1.0",
|
|
92
|
-
"npm-run-all2": "^6.1.
|
|
93
|
+
"npm-run-all2": "^6.1.2",
|
|
93
94
|
"outdent": "^0.8.0",
|
|
94
|
-
"pretty-ms": "^
|
|
95
|
-
"typescript": "^5.
|
|
96
|
-
"vue-eslint-parser": "^9.
|
|
97
|
-
"xo": "^0.
|
|
98
|
-
"yaml": "^2.
|
|
95
|
+
"pretty-ms": "^9.0.0",
|
|
96
|
+
"typescript": "^5.4.5",
|
|
97
|
+
"vue-eslint-parser": "^9.4.2",
|
|
98
|
+
"xo": "^0.58.0",
|
|
99
|
+
"yaml": "^2.4.2"
|
|
99
100
|
},
|
|
100
101
|
"peerDependencies": {
|
|
101
102
|
"eslint": ">=8.56.0"
|
|
@@ -123,7 +124,9 @@
|
|
|
123
124
|
"test/integration/{fixtures,fixtures-local}/**"
|
|
124
125
|
],
|
|
125
126
|
"rules": {
|
|
127
|
+
"unicorn/escape-case": "off",
|
|
126
128
|
"unicorn/expiring-todo-comments": "off",
|
|
129
|
+
"unicorn/no-hex-escape": "off",
|
|
127
130
|
"unicorn/no-null": "error",
|
|
128
131
|
"unicorn/prefer-array-flat": [
|
|
129
132
|
"error",
|
|
@@ -173,17 +176,5 @@
|
|
|
173
176
|
}
|
|
174
177
|
}
|
|
175
178
|
]
|
|
176
|
-
},
|
|
177
|
-
"npmpackagejsonlint": {
|
|
178
|
-
"rules": {
|
|
179
|
-
"prefer-caret-version-devDependencies": [
|
|
180
|
-
"error",
|
|
181
|
-
{
|
|
182
|
-
"exceptions": [
|
|
183
|
-
"eslint-plugin-internal-rules"
|
|
184
|
-
]
|
|
185
|
-
}
|
|
186
|
-
]
|
|
187
|
-
}
|
|
188
179
|
}
|
|
189
180
|
}
|
package/readme.md
CHANGED
|
@@ -17,7 +17,7 @@ npm install --save-dev eslint eslint-plugin-unicorn
|
|
|
17
17
|
|
|
18
18
|
## Usage (`eslint.config.js`)
|
|
19
19
|
|
|
20
|
-
**Requires ESLint `>=8.
|
|
20
|
+
**Requires ESLint `>=8.56.0`.**
|
|
21
21
|
|
|
22
22
|
Use a [preset config](#preset-configs-eslintconfigjs) or configure each rule in `eslint.config.js`.
|
|
23
23
|
|
|
@@ -103,8 +103,8 @@ If you don't use the preset, ensure you use the same `env` and `parserOptions` c
|
|
|
103
103
|
<!-- Do not manually modify this list. Run: `npm run fix:eslint-docs` -->
|
|
104
104
|
<!-- begin auto-generated rules list -->
|
|
105
105
|
|
|
106
|
-
💼 [Configurations](https://github.com/sindresorhus/eslint-plugin-unicorn#preset-configs) enabled in.\
|
|
107
|
-
✅ Set in the `recommended` [configuration](https://github.com/sindresorhus/eslint-plugin-unicorn#preset-configs).\
|
|
106
|
+
💼 [Configurations](https://github.com/sindresorhus/eslint-plugin-unicorn#preset-configs-eslintconfigjs) enabled in.\
|
|
107
|
+
✅ Set in the `recommended` [configuration](https://github.com/sindresorhus/eslint-plugin-unicorn#preset-configs-eslintconfigjs).\
|
|
108
108
|
🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\
|
|
109
109
|
💡 Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
|
|
110
110
|
|
|
@@ -113,6 +113,7 @@ If you don't use the preset, ensure you use the same `env` and `parserOptions` c
|
|
|
113
113
|
| [better-regex](docs/rules/better-regex.md) | Improve regexes by making them shorter, consistent, and safer. | ✅ | 🔧 | |
|
|
114
114
|
| [catch-error-name](docs/rules/catch-error-name.md) | Enforce a specific parameter name in catch clauses. | ✅ | 🔧 | |
|
|
115
115
|
| [consistent-destructuring](docs/rules/consistent-destructuring.md) | Use destructured variables over properties. | | 🔧 | 💡 |
|
|
116
|
+
| [consistent-empty-array-spread](docs/rules/consistent-empty-array-spread.md) | Prefer consistent types when spreading a ternary in an array literal. | ✅ | 🔧 | |
|
|
116
117
|
| [consistent-function-scoping](docs/rules/consistent-function-scoping.md) | Move function definitions to the highest possible scope. | ✅ | | |
|
|
117
118
|
| [custom-error-definition](docs/rules/custom-error-definition.md) | Enforce correct `Error` subclassing. | | 🔧 | |
|
|
118
119
|
| [empty-brace-spaces](docs/rules/empty-brace-spaces.md) | Enforce no spaces between braces. | ✅ | 🔧 | |
|
|
@@ -138,10 +139,13 @@ If you don't use the preset, ensure you use the same `env` and `parserOptions` c
|
|
|
138
139
|
| [no-for-loop](docs/rules/no-for-loop.md) | Do not use a `for` loop that can be replaced with a `for-of` loop. | ✅ | 🔧 | 💡 |
|
|
139
140
|
| [no-hex-escape](docs/rules/no-hex-escape.md) | Enforce the use of Unicode escapes instead of hexadecimal escapes. | ✅ | 🔧 | |
|
|
140
141
|
| [no-instanceof-array](docs/rules/no-instanceof-array.md) | Require `Array.isArray()` instead of `instanceof Array`. | ✅ | 🔧 | |
|
|
142
|
+
| [no-invalid-fetch-options](docs/rules/no-invalid-fetch-options.md) | Disallow invalid options in `fetch()` and `new Request()`. | ✅ | | |
|
|
141
143
|
| [no-invalid-remove-event-listener](docs/rules/no-invalid-remove-event-listener.md) | Prevent calling `EventTarget#removeEventListener()` with the result of an expression. | ✅ | | |
|
|
142
144
|
| [no-keyword-prefix](docs/rules/no-keyword-prefix.md) | Disallow identifiers starting with `new` or `class`. | | | |
|
|
143
145
|
| [no-lonely-if](docs/rules/no-lonely-if.md) | Disallow `if` statements as the only statement in `if` blocks without `else`. | ✅ | 🔧 | |
|
|
146
|
+
| [no-magic-array-flat-depth](docs/rules/no-magic-array-flat-depth.md) | Disallow a magic number as the `depth` argument in `Array#flat(…).` | ✅ | | |
|
|
144
147
|
| [no-negated-condition](docs/rules/no-negated-condition.md) | Disallow negated conditions. | ✅ | 🔧 | |
|
|
148
|
+
| [no-negation-in-equality-check](docs/rules/no-negation-in-equality-check.md) | Disallow negated expression in equality check. | ✅ | | 💡 |
|
|
145
149
|
| [no-nested-ternary](docs/rules/no-nested-ternary.md) | Disallow nested ternary expressions. | ✅ | 🔧 | |
|
|
146
150
|
| [no-new-array](docs/rules/no-new-array.md) | Disallow `new Array()`. | ✅ | 🔧 | 💡 |
|
|
147
151
|
| [no-new-buffer](docs/rules/no-new-buffer.md) | Enforce the use of `Buffer.from()` and `Buffer.alloc()` instead of the deprecated `new Buffer()`. | ✅ | 🔧 | 💡 |
|
|
@@ -172,7 +176,7 @@ If you don't use the preset, ensure you use the same `env` and `parserOptions` c
|
|
|
172
176
|
| [prefer-array-flat](docs/rules/prefer-array-flat.md) | Prefer `Array#flat()` over legacy techniques to flatten arrays. | ✅ | 🔧 | |
|
|
173
177
|
| [prefer-array-flat-map](docs/rules/prefer-array-flat-map.md) | Prefer `.flatMap(…)` over `.map(…).flat()`. | ✅ | 🔧 | |
|
|
174
178
|
| [prefer-array-index-of](docs/rules/prefer-array-index-of.md) | Prefer `Array#{indexOf,lastIndexOf}()` over `Array#{findIndex,findLastIndex}()` when looking for the index of an item. | ✅ | 🔧 | 💡 |
|
|
175
|
-
| [prefer-array-some](docs/rules/prefer-array-some.md) | Prefer `.some(…)` over `.filter(…).length` check and `.{find,findLast}(…)`.
|
|
179
|
+
| [prefer-array-some](docs/rules/prefer-array-some.md) | Prefer `.some(…)` over `.filter(…).length` check and `.{find,findLast,findIndex,findLastIndex}(…)`. | ✅ | 🔧 | 💡 |
|
|
176
180
|
| [prefer-at](docs/rules/prefer-at.md) | Prefer `.at()` method for index access and `String#charAt()`. | ✅ | 🔧 | 💡 |
|
|
177
181
|
| [prefer-blob-reading-methods](docs/rules/prefer-blob-reading-methods.md) | Prefer `Blob#arrayBuffer()` over `FileReader#readAsArrayBuffer(…)` and `Blob#text()` over `FileReader#readAsText(…)`. | ✅ | | |
|
|
178
182
|
| [prefer-code-point](docs/rules/prefer-code-point.md) | Prefer `String#codePointAt(…)` over `String#charCodeAt(…)` and `String.fromCodePoint(…)` over `String.fromCharCode(…)`. | ✅ | | 💡 |
|
|
@@ -184,7 +188,7 @@ If you don't use the preset, ensure you use the same `env` and `parserOptions` c
|
|
|
184
188
|
| [prefer-dom-node-text-content](docs/rules/prefer-dom-node-text-content.md) | Prefer `.textContent` over `.innerText`. | ✅ | | 💡 |
|
|
185
189
|
| [prefer-event-target](docs/rules/prefer-event-target.md) | Prefer `EventTarget` over `EventEmitter`. | ✅ | | |
|
|
186
190
|
| [prefer-export-from](docs/rules/prefer-export-from.md) | Prefer `export…from` when re-exporting. | ✅ | 🔧 | 💡 |
|
|
187
|
-
| [prefer-includes](docs/rules/prefer-includes.md) | Prefer `.includes()` over `.indexOf()
|
|
191
|
+
| [prefer-includes](docs/rules/prefer-includes.md) | Prefer `.includes()` over `.indexOf()`, `.lastIndexOf()`, and `Array#some()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 |
|
|
188
192
|
| [prefer-json-parse-buffer](docs/rules/prefer-json-parse-buffer.md) | Prefer reading a JSON file as a buffer. | | 🔧 | |
|
|
189
193
|
| [prefer-keyboard-event-key](docs/rules/prefer-keyboard-event-key.md) | Prefer `KeyboardEvent#key` over `KeyboardEvent#keyCode`. | ✅ | 🔧 | |
|
|
190
194
|
| [prefer-logical-operator-over-ternary](docs/rules/prefer-logical-operator-over-ternary.md) | Prefer using a logical operator over a ternary. | ✅ | | 💡 |
|
|
@@ -205,10 +209,12 @@ If you don't use the preset, ensure you use the same `env` and `parserOptions` c
|
|
|
205
209
|
| [prefer-set-has](docs/rules/prefer-set-has.md) | Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 |
|
|
206
210
|
| [prefer-set-size](docs/rules/prefer-set-size.md) | Prefer using `Set#size` instead of `Array#length`. | ✅ | 🔧 | |
|
|
207
211
|
| [prefer-spread](docs/rules/prefer-spread.md) | Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#{slice,toSpliced}()` and `String#split('')`. | ✅ | 🔧 | 💡 |
|
|
212
|
+
| [prefer-string-raw](docs/rules/prefer-string-raw.md) | Prefer using the `String.raw` tag to avoid escaping `\`. | ✅ | 🔧 | |
|
|
208
213
|
| [prefer-string-replace-all](docs/rules/prefer-string-replace-all.md) | Prefer `String#replaceAll()` over regex searches with the global flag. | ✅ | 🔧 | |
|
|
209
214
|
| [prefer-string-slice](docs/rules/prefer-string-slice.md) | Prefer `String#slice()` over `String#substr()` and `String#substring()`. | ✅ | 🔧 | |
|
|
210
215
|
| [prefer-string-starts-ends-with](docs/rules/prefer-string-starts-ends-with.md) | Prefer `String#startsWith()` & `String#endsWith()` over `RegExp#test()`. | ✅ | 🔧 | 💡 |
|
|
211
216
|
| [prefer-string-trim-start-end](docs/rules/prefer-string-trim-start-end.md) | Prefer `String#trimStart()` / `String#trimEnd()` over `String#trimLeft()` / `String#trimRight()`. | ✅ | 🔧 | |
|
|
217
|
+
| [prefer-structured-clone](docs/rules/prefer-structured-clone.md) | Prefer using `structuredClone` to create a deep clone. | ✅ | | 💡 |
|
|
212
218
|
| [prefer-switch](docs/rules/prefer-switch.md) | Prefer `switch` over multiple `else-if`. | ✅ | 🔧 | |
|
|
213
219
|
| [prefer-ternary](docs/rules/prefer-ternary.md) | Prefer ternary expressions over simple `if-else` statements. | ✅ | 🔧 | |
|
|
214
220
|
| [prefer-top-level-await](docs/rules/prefer-top-level-await.md) | Prefer top-level await over top-level promises and async function calls. | ✅ | | 💡 |
|
|
@@ -222,7 +228,7 @@ If you don't use the preset, ensure you use the same `env` and `parserOptions` c
|
|
|
222
228
|
| [switch-case-braces](docs/rules/switch-case-braces.md) | Enforce consistent brace style for `case` clauses. | ✅ | 🔧 | |
|
|
223
229
|
| [template-indent](docs/rules/template-indent.md) | Fix whitespace-insensitive template indentation. | ✅ | 🔧 | |
|
|
224
230
|
| [text-encoding-identifier-case](docs/rules/text-encoding-identifier-case.md) | Enforce consistent case for text encoding identifiers. | ✅ | 🔧 | 💡 |
|
|
225
|
-
| [throw-new-error](docs/rules/throw-new-error.md) | Require `new` when
|
|
231
|
+
| [throw-new-error](docs/rules/throw-new-error.md) | Require `new` when creating an error. | ✅ | 🔧 | |
|
|
226
232
|
|
|
227
233
|
<!-- end auto-generated rules list -->
|
|
228
234
|
|
package/rules/ast/index.js
CHANGED
|
@@ -25,6 +25,7 @@ module.exports = {
|
|
|
25
25
|
isArrowFunctionBody: require('./is-arrow-function-body.js'),
|
|
26
26
|
isCallExpression,
|
|
27
27
|
isCallOrNewExpression,
|
|
28
|
+
isDirective: require('./is-directive.js'),
|
|
28
29
|
isEmptyNode: require('./is-empty-node.js'),
|
|
29
30
|
isExpressionStatement: require('./is-expression-statement.js'),
|
|
30
31
|
isFunction: require('./is-function.js'),
|
|
@@ -33,6 +34,7 @@ module.exports = {
|
|
|
33
34
|
isNewExpression,
|
|
34
35
|
isReferenceIdentifier: require('./is-reference-identifier.js'),
|
|
35
36
|
isStaticRequire: require('./is-static-require.js'),
|
|
37
|
+
isTaggedTemplateLiteral: require('./is-tagged-template-literal.js'),
|
|
36
38
|
isUndefined: require('./is-undefined.js'),
|
|
37
39
|
|
|
38
40
|
functionTypes: require('./function-types.js'),
|
|
@@ -120,11 +120,18 @@ function isNotReference(node) {
|
|
|
120
120
|
return parent.parameters.includes(node);
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
// `@typescript-eslint/parse` v7
|
|
123
124
|
// `type Foo = { [Identifier in keyof string]: number; };`
|
|
124
125
|
case 'TSTypeParameter': {
|
|
125
126
|
return parent.name === node;
|
|
126
127
|
}
|
|
127
128
|
|
|
129
|
+
// `@typescript-eslint/parse` v8
|
|
130
|
+
// `type Foo = { [Identifier in keyof string]: number; };`
|
|
131
|
+
case 'TSMappedType': {
|
|
132
|
+
return parent.key === node;
|
|
133
|
+
}
|
|
134
|
+
|
|
128
135
|
// `type Identifier = Foo`
|
|
129
136
|
case 'TSTypeAliasDeclaration': {
|
|
130
137
|
return parent.id === node;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {isNodeMatches} = require('../utils/is-node-matches.js');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
Check if the given node is a tagged template literal.
|
|
7
|
+
|
|
8
|
+
@param {Node} node - The AST node to check.
|
|
9
|
+
@param {string[]} tags - The object name or key paths.
|
|
10
|
+
@returns {boolean}
|
|
11
|
+
*/
|
|
12
|
+
function isTaggedTemplateLiteral(node, tags) {
|
|
13
|
+
if (
|
|
14
|
+
node.type !== 'TemplateLiteral'
|
|
15
|
+
|| node.parent.type !== 'TaggedTemplateExpression'
|
|
16
|
+
|| node.parent.quasi !== node
|
|
17
|
+
) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (tags) {
|
|
22
|
+
return isNodeMatches(node.parent.tag, tags);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = isTaggedTemplateLiteral;
|
package/rules/better-regex.js
CHANGED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const {getStaticValue} = require('@eslint-community/eslint-utils');
|
|
3
|
+
|
|
4
|
+
const MESSAGE_ID = 'consistent-empty-array-spread';
|
|
5
|
+
const messages = {
|
|
6
|
+
[MESSAGE_ID]: 'Prefer using empty {{replacementDescription}} since the {{anotherNodePosition}} is {{anotherNodeDescription}}.',
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const isEmptyArrayExpression = node =>
|
|
10
|
+
node.type === 'ArrayExpression'
|
|
11
|
+
&& node.elements.length === 0;
|
|
12
|
+
|
|
13
|
+
const isEmptyStringLiteral = node =>
|
|
14
|
+
node.type === 'Literal'
|
|
15
|
+
&& node.value === '';
|
|
16
|
+
|
|
17
|
+
const isString = (node, context) => {
|
|
18
|
+
const staticValueResult = getStaticValue(node, context.sourceCode.getScope(node));
|
|
19
|
+
return typeof staticValueResult?.value === 'string';
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const isArray = (node, context) => {
|
|
23
|
+
if (node.type === 'ArrayExpression') {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const staticValueResult = getStaticValue(node, context.sourceCode.getScope(node));
|
|
28
|
+
return Array.isArray(staticValueResult?.value);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const cases = [
|
|
32
|
+
{
|
|
33
|
+
oneSidePredicate: isEmptyStringLiteral,
|
|
34
|
+
anotherSidePredicate: isArray,
|
|
35
|
+
anotherNodeDescription: 'an array',
|
|
36
|
+
replacementDescription: 'array',
|
|
37
|
+
replacementCode: '[]',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
oneSidePredicate: isEmptyArrayExpression,
|
|
41
|
+
anotherSidePredicate: isString,
|
|
42
|
+
anotherNodeDescription: 'a string',
|
|
43
|
+
replacementDescription: 'string',
|
|
44
|
+
replacementCode: '\'\'',
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
function createProblem({
|
|
49
|
+
problemNode,
|
|
50
|
+
anotherNodePosition,
|
|
51
|
+
anotherNodeDescription,
|
|
52
|
+
replacementDescription,
|
|
53
|
+
replacementCode,
|
|
54
|
+
}) {
|
|
55
|
+
return {
|
|
56
|
+
node: problemNode,
|
|
57
|
+
messageId: MESSAGE_ID,
|
|
58
|
+
data: {
|
|
59
|
+
replacementDescription,
|
|
60
|
+
anotherNodePosition,
|
|
61
|
+
anotherNodeDescription,
|
|
62
|
+
},
|
|
63
|
+
fix: fixer => fixer.replaceText(problemNode, replacementCode),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function getProblem(conditionalExpression, context) {
|
|
68
|
+
const {
|
|
69
|
+
consequent,
|
|
70
|
+
alternate,
|
|
71
|
+
} = conditionalExpression;
|
|
72
|
+
|
|
73
|
+
for (const problemCase of cases) {
|
|
74
|
+
const {
|
|
75
|
+
oneSidePredicate,
|
|
76
|
+
anotherSidePredicate,
|
|
77
|
+
} = problemCase;
|
|
78
|
+
|
|
79
|
+
if (oneSidePredicate(consequent, context) && anotherSidePredicate(alternate, context)) {
|
|
80
|
+
return createProblem({
|
|
81
|
+
...problemCase,
|
|
82
|
+
problemNode: consequent,
|
|
83
|
+
anotherNodePosition: 'alternate',
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (oneSidePredicate(alternate, context) && anotherSidePredicate(consequent, context)) {
|
|
88
|
+
return createProblem({
|
|
89
|
+
...problemCase,
|
|
90
|
+
problemNode: alternate,
|
|
91
|
+
anotherNodePosition: 'consequent',
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** @param {import('eslint').Rule.RuleContext} context */
|
|
98
|
+
const create = context => ({
|
|
99
|
+
* ArrayExpression(arrayExpression) {
|
|
100
|
+
for (const element of arrayExpression.elements) {
|
|
101
|
+
if (
|
|
102
|
+
element?.type !== 'SpreadElement'
|
|
103
|
+
|| element.argument.type !== 'ConditionalExpression'
|
|
104
|
+
) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
yield getProblem(element.argument, context);
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
/** @type {import('eslint').Rule.RuleModule} */
|
|
114
|
+
module.exports = {
|
|
115
|
+
create,
|
|
116
|
+
meta: {
|
|
117
|
+
type: 'suggestion',
|
|
118
|
+
docs: {
|
|
119
|
+
description: 'Prefer consistent types when spreading a ternary in an array literal.',
|
|
120
|
+
recommended: true,
|
|
121
|
+
},
|
|
122
|
+
fixable: 'code',
|
|
123
|
+
|
|
124
|
+
messages,
|
|
125
|
+
},
|
|
126
|
+
};
|
package/rules/error-message.js
CHANGED
package/rules/escape-case.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
const {replaceTemplateElement} = require('./fix/index.js');
|
|
3
|
-
const {
|
|
3
|
+
const {
|
|
4
|
+
isRegexLiteral,
|
|
5
|
+
isStringLiteral,
|
|
6
|
+
isTaggedTemplateLiteral,
|
|
7
|
+
} = require('./ast/index.js');
|
|
4
8
|
|
|
5
9
|
const MESSAGE_ID = 'escape-case';
|
|
6
10
|
const messages = {
|
|
@@ -42,11 +46,17 @@ const create = context => {
|
|
|
42
46
|
}
|
|
43
47
|
});
|
|
44
48
|
|
|
45
|
-
context.on('TemplateElement', node =>
|
|
46
|
-
node,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
context.on('TemplateElement', node => {
|
|
50
|
+
if (isTaggedTemplateLiteral(node.parent, ['String.raw'])) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return getProblem({
|
|
55
|
+
node,
|
|
56
|
+
original: node.value.raw,
|
|
57
|
+
fix: (fixer, fixed) => replaceTemplateElement(fixer, node, fixed),
|
|
58
|
+
});
|
|
59
|
+
});
|
|
50
60
|
};
|
|
51
61
|
|
|
52
62
|
/** @type {import('eslint').Rule.RuleModule} */
|
|
@@ -56,6 +66,7 @@ module.exports = {
|
|
|
56
66
|
type: 'suggestion',
|
|
57
67
|
docs: {
|
|
58
68
|
description: 'Require escape sequences to use uppercase values.',
|
|
69
|
+
recommended: true,
|
|
59
70
|
},
|
|
60
71
|
fixable: 'code',
|
|
61
72
|
messages,
|
|
@@ -186,7 +186,15 @@ function getPackageHelpers(dirname) {
|
|
|
186
186
|
return afterArguments;
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
return {
|
|
189
|
+
return {
|
|
190
|
+
packageResult,
|
|
191
|
+
hasPackage,
|
|
192
|
+
packageJson,
|
|
193
|
+
packageDependencies,
|
|
194
|
+
parseArgument,
|
|
195
|
+
parseTodoMessage,
|
|
196
|
+
parseTodoWithArguments,
|
|
197
|
+
};
|
|
190
198
|
}
|
|
191
199
|
|
|
192
200
|
const DEPENDENCY_INCLUSION_RE = /^[+-]\s*@?\S+\/?\S+/;
|
|
@@ -197,7 +205,7 @@ const ISO8601_DATE = /\d{4}-\d{2}-\d{2}/;
|
|
|
197
205
|
function createArgumentGroup(arguments_) {
|
|
198
206
|
const groups = {};
|
|
199
207
|
for (const {value, type} of arguments_) {
|
|
200
|
-
groups[type]
|
|
208
|
+
groups[type] ??= [];
|
|
201
209
|
groups[type].push(value);
|
|
202
210
|
}
|
|
203
211
|
|
|
@@ -573,6 +581,7 @@ module.exports = {
|
|
|
573
581
|
type: 'suggestion',
|
|
574
582
|
docs: {
|
|
575
583
|
description: 'Add expiration conditions to TODO comments.',
|
|
584
|
+
recommended: true,
|
|
576
585
|
},
|
|
577
586
|
schema,
|
|
578
587
|
messages,
|