eslint-plugin-unicorn 51.0.1 → 53.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.
Files changed (145) hide show
  1. package/index.js +23 -4
  2. package/package.json +28 -36
  3. package/readme.md +13 -5
  4. package/rules/ast/index.js +2 -0
  5. package/rules/ast/is-directive.js +7 -0
  6. package/rules/ast/is-tagged-template-literal.js +28 -0
  7. package/rules/better-regex.js +1 -0
  8. package/rules/catch-error-name.js +1 -0
  9. package/rules/consistent-destructuring.js +1 -0
  10. package/rules/consistent-empty-array-spread.js +126 -0
  11. package/rules/consistent-function-scoping.js +1 -0
  12. package/rules/custom-error-definition.js +1 -0
  13. package/rules/empty-brace-spaces.js +1 -0
  14. package/rules/error-message.js +1 -0
  15. package/rules/escape-case.js +17 -6
  16. package/rules/expiring-todo-comments.js +11 -2
  17. package/rules/explicit-length-check.js +7 -1
  18. package/rules/filename-case.js +42 -8
  19. package/rules/import-style.js +7 -0
  20. package/rules/new-for-builtins.js +1 -0
  21. package/rules/no-abusive-eslint-disable.js +1 -0
  22. package/rules/no-anonymous-default-export.js +213 -0
  23. package/rules/no-array-callback-reference.js +72 -42
  24. package/rules/no-array-for-each.js +13 -2
  25. package/rules/no-array-method-this-argument.js +3 -2
  26. package/rules/no-array-push-push.js +15 -7
  27. package/rules/no-array-reduce.js +1 -0
  28. package/rules/no-await-expression-member.js +1 -0
  29. package/rules/no-await-in-promise-methods.js +69 -0
  30. package/rules/no-console-spaces.js +1 -0
  31. package/rules/no-document-cookie.js +1 -0
  32. package/rules/no-empty-file.js +2 -2
  33. package/rules/no-for-loop.js +1 -0
  34. package/rules/no-hex-escape.js +13 -2
  35. package/rules/no-instanceof-array.js +1 -0
  36. package/rules/no-invalid-fetch-options.js +111 -0
  37. package/rules/no-invalid-remove-event-listener.js +1 -0
  38. package/rules/no-keyword-prefix.js +1 -0
  39. package/rules/no-lonely-if.js +1 -0
  40. package/rules/no-magic-array-flat-depth.js +54 -0
  41. package/rules/no-negated-condition.js +1 -0
  42. package/rules/no-nested-ternary.js +1 -0
  43. package/rules/no-new-array.js +1 -0
  44. package/rules/no-new-buffer.js +1 -0
  45. package/rules/no-null.js +1 -0
  46. package/rules/no-object-as-default-parameter.js +1 -0
  47. package/rules/no-process-exit.js +1 -0
  48. package/rules/no-single-promise-in-promise-methods.js +168 -0
  49. package/rules/no-static-only-class.js +1 -0
  50. package/rules/no-thenable.js +1 -0
  51. package/rules/no-this-assignment.js +1 -0
  52. package/rules/no-typeof-undefined.js +1 -0
  53. package/rules/no-unnecessary-await.js +1 -0
  54. package/rules/no-unnecessary-polyfills.js +3 -2
  55. package/rules/no-unreadable-array-destructuring.js +1 -0
  56. package/rules/no-unreadable-iife.js +1 -0
  57. package/rules/no-unused-properties.js +1 -0
  58. package/rules/no-useless-fallback-in-spread.js +2 -2
  59. package/rules/no-useless-length-check.js +1 -0
  60. package/rules/no-useless-promise-resolve-reject.js +3 -2
  61. package/rules/no-useless-spread.js +1 -0
  62. package/rules/no-useless-switch-case.js +3 -16
  63. package/rules/no-useless-undefined.js +1 -0
  64. package/rules/no-zero-fractions.js +1 -0
  65. package/rules/number-literal-case.js +1 -0
  66. package/rules/numeric-separators-style.js +1 -0
  67. package/rules/prefer-add-event-listener.js +2 -1
  68. package/rules/prefer-array-find.js +29 -0
  69. package/rules/prefer-array-flat-map.js +1 -0
  70. package/rules/prefer-array-flat.js +5 -0
  71. package/rules/prefer-array-index-of.js +1 -0
  72. package/rules/prefer-array-some.js +1 -0
  73. package/rules/prefer-at.js +1 -0
  74. package/rules/prefer-blob-reading-methods.js +1 -0
  75. package/rules/prefer-code-point.js +1 -0
  76. package/rules/prefer-date-now.js +1 -0
  77. package/rules/prefer-default-parameters.js +1 -0
  78. package/rules/prefer-dom-node-append.js +1 -0
  79. package/rules/prefer-dom-node-dataset.js +12 -0
  80. package/rules/prefer-dom-node-remove.js +1 -0
  81. package/rules/prefer-dom-node-text-content.js +1 -0
  82. package/rules/prefer-event-target.js +1 -0
  83. package/rules/prefer-export-from.js +2 -3
  84. package/rules/prefer-includes.js +1 -0
  85. package/rules/prefer-json-parse-buffer.js +1 -0
  86. package/rules/prefer-keyboard-event-key.js +1 -0
  87. package/rules/prefer-logical-operator-over-ternary.js +1 -0
  88. package/rules/prefer-math-trunc.js +1 -0
  89. package/rules/prefer-modern-dom-apis.js +1 -0
  90. package/rules/prefer-modern-math-apis.js +2 -0
  91. package/rules/prefer-module.js +13 -12
  92. package/rules/prefer-native-coercion-functions.js +1 -0
  93. package/rules/prefer-negative-index.js +1 -0
  94. package/rules/prefer-node-protocol.js +1 -0
  95. package/rules/prefer-number-properties.js +19 -5
  96. package/rules/prefer-object-from-entries.js +1 -0
  97. package/rules/prefer-optional-catch-binding.js +1 -0
  98. package/rules/prefer-prototype-methods.js +129 -56
  99. package/rules/prefer-query-selector.js +1 -0
  100. package/rules/prefer-reflect-apply.js +1 -0
  101. package/rules/prefer-regexp-test.js +1 -0
  102. package/rules/prefer-set-has.js +1 -0
  103. package/rules/prefer-set-size.js +1 -0
  104. package/rules/prefer-spread.js +7 -19
  105. package/rules/prefer-string-raw.js +93 -0
  106. package/rules/prefer-string-replace-all.js +1 -0
  107. package/rules/prefer-string-slice.js +7 -1
  108. package/rules/prefer-string-starts-ends-with.js +1 -0
  109. package/rules/prefer-string-trim-start-end.js +1 -0
  110. package/rules/prefer-structured-clone.js +152 -0
  111. package/rules/prefer-switch.js +1 -0
  112. package/rules/prefer-ternary.js +1 -0
  113. package/rules/prefer-top-level-await.js +1 -0
  114. package/rules/prefer-type-error.js +1 -0
  115. package/rules/prevent-abbreviations.js +2 -1
  116. package/rules/relative-url-style.js +1 -0
  117. package/rules/require-array-join-separator.js +1 -0
  118. package/rules/require-number-to-fixed-digits-argument.js +1 -0
  119. package/rules/require-post-message-target-origin.js +3 -0
  120. package/rules/string-content.js +3 -1
  121. package/rules/switch-case-braces.js +1 -0
  122. package/rules/template-indent.js +9 -7
  123. package/rules/text-encoding-identifier-case.js +1 -0
  124. package/rules/throw-new-error.js +3 -9
  125. package/rules/utils/avoid-capture.js +2 -1
  126. package/rules/utils/cartesian-product-samples.js +1 -1
  127. package/rules/utils/escape-string.js +1 -1
  128. package/rules/utils/escape-template-element-raw.js +3 -2
  129. package/rules/utils/get-call-expression-arguments-text.js +11 -6
  130. package/rules/utils/get-call-expression-tokens.js +37 -0
  131. package/rules/utils/get-documentation-url.js +1 -1
  132. package/rules/utils/get-variable-identifiers.js +2 -1
  133. package/rules/utils/has-same-range.js +2 -1
  134. package/rules/utils/index.js +4 -1
  135. package/rules/utils/is-node-value-not-function.js +0 -1
  136. package/rules/utils/is-object-method.js +1 -1
  137. package/rules/utils/is-value-not-usable.js +2 -1
  138. package/rules/utils/numeric.js +6 -1
  139. package/rules/utils/resolve-variable-name.js +1 -1
  140. package/rules/utils/rule.js +5 -5
  141. package/rules/utils/should-add-parentheses-to-await-expression-argument.js +21 -0
  142. package/rules/utils/should-add-parentheses-to-call-expression-callee.js +22 -0
  143. package/configs/all.js +0 -6
  144. package/configs/recommended.js +0 -117
  145. package/rules/utils/should-add-parentheses-to-spread-element-argument.js +0 -22
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,31 @@ const deprecatedRules = createDeprecatedRules({
28
26
  'regex-shorthand': 'unicorn/better-regex',
29
27
  });
30
28
 
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
+
31
50
  const createConfig = (rules, isLegacyConfig = false) => ({
32
51
  ...(isLegacyConfig ? legacyConfigBase : flatConfigBase),
33
52
  plugins: isLegacyConfig ? ['unicorn'] : {unicorn},
34
- rules,
53
+ rules: {...externalRules, ...rules},
35
54
  });
36
55
 
37
56
  const unicorn = {
@@ -40,7 +59,7 @@ const unicorn = {
40
59
  version,
41
60
  },
42
61
  rules: {
43
- ...loadRules(),
62
+ ...rules,
44
63
  ...deprecatedRules,
45
64
  },
46
65
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-unicorn",
3
- "version": "51.0.1",
3
+ "version": "53.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"
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,7 +29,6 @@
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
- "bundle-lodash": "echo \"export {defaultsDeep, camelCase, kebabCase, snakeCase, upperFirst, lowerFirst} from 'lodash-es';\" | npx esbuild --bundle --outfile=rules/utils/lodash.js --format=cjs",
32
32
  "smoke": "eslint-remote-tester --config ./test/smoke/eslint-remote-tester.config.js",
33
33
  "test": "npm-run-all --continue-on-error lint test:*",
34
34
  "test:js": "c8 ava"
@@ -49,12 +49,12 @@
49
49
  "xo"
50
50
  ],
51
51
  "dependencies": {
52
- "@babel/helper-validator-identifier": "^7.22.20",
52
+ "@babel/helper-validator-identifier": "^7.24.5",
53
53
  "@eslint-community/eslint-utils": "^4.4.0",
54
- "@eslint/eslintrc": "^2.1.4",
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.34.0",
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.5.4",
66
+ "semver": "^7.6.1",
67
67
  "strip-indent": "^3.0.0"
68
68
  },
69
69
  "devDependencies": {
70
- "@babel/code-frame": "^7.23.5",
71
- "@babel/core": "^7.23.6",
72
- "@babel/eslint-parser": "^7.23.3",
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": "^6.15.0",
75
- "ava": "^6.0.1",
76
- "c8": "^8.0.1",
74
+ "@typescript-eslint/parser": "^7.8.0",
75
+ "ava": "^6.1.3",
76
+ "c8": "^9.1.0",
77
77
  "chalk": "^5.3.0",
78
78
  "enquirer": "^2.4.1",
79
- "eslint": "^8.56.0",
79
+ "eslint": "^9.2.0",
80
80
  "eslint-ava-rule-tester": "^5.0.1",
81
- "eslint-doc-generator": "^1.6.1",
82
- "eslint-plugin-eslint-plugin": "^5.2.1",
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
84
  "eslint-remote-tester": "^3.0.1",
85
85
  "eslint-remote-tester-repositories": "^1.0.1",
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.38.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.1",
93
+ "npm-run-all2": "^6.1.2",
93
94
  "outdent": "^0.8.0",
94
- "pretty-ms": "^8.0.0",
95
- "typescript": "^5.3.3",
96
- "vue-eslint-parser": "^9.3.2",
97
- "xo": "^0.56.0",
98
- "yaml": "^2.3.4"
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",
@@ -134,7 +137,8 @@
134
137
  ]
135
138
  }
136
139
  ],
137
- "import/order": "off"
140
+ "import/order": "off",
141
+ "func-names": "off"
138
142
  },
139
143
  "overrides": [
140
144
  {
@@ -172,17 +176,5 @@
172
176
  }
173
177
  }
174
178
  ]
175
- },
176
- "npmpackagejsonlint": {
177
- "rules": {
178
- "prefer-caret-version-devDependencies": [
179
- "error",
180
- {
181
- "exceptions": [
182
- "eslint-plugin-internal-rules"
183
- ]
184
- }
185
- ]
186
- }
187
179
  }
188
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.23.0`.**
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,16 +103,17 @@ 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
- 💡 Manually fixable by [editor suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions).
109
+ 💡 Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
110
110
 
111
111
  | Name                                    | Description | 💼 | 🔧 | 💡 |
112
112
  | :----------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :- | :- | :- |
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. | ✅ | 🔧 | |
@@ -124,21 +125,25 @@ If you don't use the preset, ensure you use the same `env` and `parserOptions` c
124
125
  | [import-style](docs/rules/import-style.md) | Enforce specific import styles per module. | ✅ | | |
125
126
  | [new-for-builtins](docs/rules/new-for-builtins.md) | Enforce the use of `new` for all builtins, except `String`, `Number`, `Boolean`, `Symbol` and `BigInt`. | ✅ | 🔧 | |
126
127
  | [no-abusive-eslint-disable](docs/rules/no-abusive-eslint-disable.md) | Enforce specifying rules to disable in `eslint-disable` comments. | ✅ | | |
128
+ | [no-anonymous-default-export](docs/rules/no-anonymous-default-export.md) | Disallow anonymous functions and classes as the default export. | ✅ | | 💡 |
127
129
  | [no-array-callback-reference](docs/rules/no-array-callback-reference.md) | Prevent passing a function reference directly to iterator methods. | ✅ | | 💡 |
128
130
  | [no-array-for-each](docs/rules/no-array-for-each.md) | Prefer `for…of` over the `forEach` method. | ✅ | 🔧 | 💡 |
129
131
  | [no-array-method-this-argument](docs/rules/no-array-method-this-argument.md) | Disallow using the `this` argument in array methods. | ✅ | 🔧 | 💡 |
130
132
  | [no-array-push-push](docs/rules/no-array-push-push.md) | Enforce combining multiple `Array#push()` into one call. | ✅ | 🔧 | 💡 |
131
133
  | [no-array-reduce](docs/rules/no-array-reduce.md) | Disallow `Array#reduce()` and `Array#reduceRight()`. | ✅ | | |
132
134
  | [no-await-expression-member](docs/rules/no-await-expression-member.md) | Disallow member access from await expression. | ✅ | 🔧 | |
135
+ | [no-await-in-promise-methods](docs/rules/no-await-in-promise-methods.md) | Disallow using `await` in `Promise` method parameters. | ✅ | | 💡 |
133
136
  | [no-console-spaces](docs/rules/no-console-spaces.md) | Do not use leading/trailing space between `console.log` parameters. | ✅ | 🔧 | |
134
137
  | [no-document-cookie](docs/rules/no-document-cookie.md) | Do not use `document.cookie` directly. | ✅ | | |
135
138
  | [no-empty-file](docs/rules/no-empty-file.md) | Disallow empty files. | ✅ | | |
136
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. | ✅ | 🔧 | 💡 |
137
140
  | [no-hex-escape](docs/rules/no-hex-escape.md) | Enforce the use of Unicode escapes instead of hexadecimal escapes. | ✅ | 🔧 | |
138
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()`. | ✅ | | |
139
143
  | [no-invalid-remove-event-listener](docs/rules/no-invalid-remove-event-listener.md) | Prevent calling `EventTarget#removeEventListener()` with the result of an expression. | ✅ | | |
140
144
  | [no-keyword-prefix](docs/rules/no-keyword-prefix.md) | Disallow identifiers starting with `new` or `class`. | | | |
141
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(…).` | ✅ | | |
142
147
  | [no-negated-condition](docs/rules/no-negated-condition.md) | Disallow negated conditions. | ✅ | 🔧 | |
143
148
  | [no-nested-ternary](docs/rules/no-nested-ternary.md) | Disallow nested ternary expressions. | ✅ | 🔧 | |
144
149
  | [no-new-array](docs/rules/no-new-array.md) | Disallow `new Array()`. | ✅ | 🔧 | 💡 |
@@ -146,6 +151,7 @@ If you don't use the preset, ensure you use the same `env` and `parserOptions` c
146
151
  | [no-null](docs/rules/no-null.md) | Disallow the use of the `null` literal. | ✅ | 🔧 | 💡 |
147
152
  | [no-object-as-default-parameter](docs/rules/no-object-as-default-parameter.md) | Disallow the use of objects as default parameters. | ✅ | | |
148
153
  | [no-process-exit](docs/rules/no-process-exit.md) | Disallow `process.exit()`. | ✅ | | |
154
+ | [no-single-promise-in-promise-methods](docs/rules/no-single-promise-in-promise-methods.md) | Disallow passing single-element arrays to `Promise` methods. | ✅ | 🔧 | 💡 |
149
155
  | [no-static-only-class](docs/rules/no-static-only-class.md) | Disallow classes that only have static members. | ✅ | 🔧 | |
150
156
  | [no-thenable](docs/rules/no-thenable.md) | Disallow `then` property. | ✅ | | |
151
157
  | [no-this-assignment](docs/rules/no-this-assignment.md) | Disallow assigning `this` to a variable. | ✅ | | |
@@ -202,10 +208,12 @@ If you don't use the preset, ensure you use the same `env` and `parserOptions` c
202
208
  | [prefer-set-has](docs/rules/prefer-set-has.md) | Prefer `Set#has()` over `Array#includes()` when checking for existence or non-existence. | ✅ | 🔧 | 💡 |
203
209
  | [prefer-set-size](docs/rules/prefer-set-size.md) | Prefer using `Set#size` instead of `Array#length`. | ✅ | 🔧 | |
204
210
  | [prefer-spread](docs/rules/prefer-spread.md) | Prefer the spread operator over `Array.from(…)`, `Array#concat(…)`, `Array#{slice,toSpliced}()` and `String#split('')`. | ✅ | 🔧 | 💡 |
211
+ | [prefer-string-raw](docs/rules/prefer-string-raw.md) | Prefer using the `String.raw` tag to avoid escaping `\`. | ✅ | 🔧 | |
205
212
  | [prefer-string-replace-all](docs/rules/prefer-string-replace-all.md) | Prefer `String#replaceAll()` over regex searches with the global flag. | ✅ | 🔧 | |
206
213
  | [prefer-string-slice](docs/rules/prefer-string-slice.md) | Prefer `String#slice()` over `String#substr()` and `String#substring()`. | ✅ | 🔧 | |
207
214
  | [prefer-string-starts-ends-with](docs/rules/prefer-string-starts-ends-with.md) | Prefer `String#startsWith()` & `String#endsWith()` over `RegExp#test()`. | ✅ | 🔧 | 💡 |
208
215
  | [prefer-string-trim-start-end](docs/rules/prefer-string-trim-start-end.md) | Prefer `String#trimStart()` / `String#trimEnd()` over `String#trimLeft()` / `String#trimRight()`. | ✅ | 🔧 | |
216
+ | [prefer-structured-clone](docs/rules/prefer-structured-clone.md) | Prefer using `structuredClone` to create a deep clone. | ✅ | | 💡 |
209
217
  | [prefer-switch](docs/rules/prefer-switch.md) | Prefer `switch` over multiple `else-if`. | ✅ | 🔧 | |
210
218
  | [prefer-ternary](docs/rules/prefer-ternary.md) | Prefer ternary expressions over simple `if-else` statements. | ✅ | 🔧 | |
211
219
  | [prefer-top-level-await](docs/rules/prefer-top-level-await.md) | Prefer top-level await over top-level promises and async function calls. | ✅ | | 💡 |
@@ -219,7 +227,7 @@ If you don't use the preset, ensure you use the same `env` and `parserOptions` c
219
227
  | [switch-case-braces](docs/rules/switch-case-braces.md) | Enforce consistent brace style for `case` clauses. | ✅ | 🔧 | |
220
228
  | [template-indent](docs/rules/template-indent.md) | Fix whitespace-insensitive template indentation. | ✅ | 🔧 | |
221
229
  | [text-encoding-identifier-case](docs/rules/text-encoding-identifier-case.md) | Enforce consistent case for text encoding identifiers. | ✅ | 🔧 | 💡 |
222
- | [throw-new-error](docs/rules/throw-new-error.md) | Require `new` when throwing an error. | ✅ | 🔧 | |
230
+ | [throw-new-error](docs/rules/throw-new-error.md) | Require `new` when creating an error. | ✅ | 🔧 | |
223
231
 
224
232
  <!-- end auto-generated rules list -->
225
233
 
@@ -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'),
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ const isDirective = node =>
4
+ node.type === 'ExpressionStatement'
5
+ && typeof node.directive === 'string';
6
+
7
+ module.exports = isDirective;
@@ -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;
@@ -136,6 +136,7 @@ module.exports = {
136
136
  type: 'suggestion',
137
137
  docs: {
138
138
  description: 'Improve regexes by making them shorter, consistent, and safer.',
139
+ recommended: true,
139
140
  },
140
141
  fixable: 'code',
141
142
  schema,
@@ -128,6 +128,7 @@ module.exports = {
128
128
  type: 'suggestion',
129
129
  docs: {
130
130
  description: 'Enforce a specific parameter name in catch clauses.',
131
+ recommended: true,
131
132
  },
132
133
  fixable: 'code',
133
134
  schema,
@@ -157,6 +157,7 @@ module.exports = {
157
157
  type: 'suggestion',
158
158
  docs: {
159
159
  description: 'Use destructured variables over properties.',
160
+ recommended: false,
160
161
  },
161
162
  fixable: 'code',
162
163
  hasSuggestions: true,
@@ -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
+ };
@@ -216,6 +216,7 @@ module.exports = {
216
216
  type: 'suggestion',
217
217
  docs: {
218
218
  description: 'Move function definitions to the highest possible scope.',
219
+ recommended: true,
219
220
  },
220
221
  schema,
221
222
  messages,
@@ -208,6 +208,7 @@ module.exports = {
208
208
  type: 'problem',
209
209
  docs: {
210
210
  description: 'Enforce correct `Error` subclassing.',
211
+ recommended: false,
211
212
  },
212
213
  fixable: 'code',
213
214
  messages,
@@ -65,6 +65,7 @@ module.exports = {
65
65
  type: 'layout',
66
66
  docs: {
67
67
  description: 'Enforce no spaces between braces.',
68
+ recommended: true,
68
69
  },
69
70
  fixable: 'whitespace',
70
71
  messages,
@@ -98,6 +98,7 @@ module.exports = {
98
98
  type: 'problem',
99
99
  docs: {
100
100
  description: 'Enforce passing a `message` value when creating a built-in error.',
101
+ recommended: true,
101
102
  },
102
103
  messages,
103
104
  },
@@ -1,6 +1,10 @@
1
1
  'use strict';
2
2
  const {replaceTemplateElement} = require('./fix/index.js');
3
- const {isRegexLiteral, isStringLiteral} = require('./ast/index.js');
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 => getProblem({
46
- node,
47
- original: node.value.raw,
48
- fix: (fixer, fixed) => replaceTemplateElement(fixer, node, fixed),
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 {packageResult, hasPackage, packageJson, packageDependencies, parseArgument, parseTodoMessage, parseTodoWithArguments};
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] = 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,
@@ -194,7 +194,12 @@ function create(context) {
194
194
  }
195
195
 
196
196
  if (node) {
197
- return getProblem({node, isZeroLengthCheck, lengthNode, autoFix});
197
+ return getProblem({
198
+ node,
199
+ isZeroLengthCheck,
200
+ lengthNode,
201
+ autoFix,
202
+ });
198
203
  }
199
204
  },
200
205
  };
@@ -220,6 +225,7 @@ module.exports = {
220
225
  type: 'problem',
221
226
  docs: {
222
227
  description: 'Enforce explicitly comparing the `length` or `size` property of a value.',
228
+ recommended: true,
223
229
  },
224
230
  fixable: 'code',
225
231
  schema,