eslint-plugin-unicorn 40.0.0 → 41.0.1

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 (75) hide show
  1. package/configs/all.js +5 -13
  2. package/configs/recommended.js +11 -2
  3. package/index.js +2 -2
  4. package/package.json +43 -10
  5. package/readme.md +18 -123
  6. package/rules/better-regex.js +2 -2
  7. package/rules/catch-error-name.js +2 -2
  8. package/rules/consistent-destructuring.js +2 -2
  9. package/rules/consistent-function-scoping.js +10 -9
  10. package/rules/expiring-todo-comments.js +20 -11
  11. package/rules/filename-case.js +1 -11
  12. package/rules/fix/append-argument.js +1 -1
  13. package/rules/fix/remove-argument.js +2 -1
  14. package/rules/import-style.js +1 -1
  15. package/rules/new-for-builtins.js +2 -2
  16. package/rules/no-array-callback-reference.js +2 -3
  17. package/rules/no-array-for-each.js +2 -1
  18. package/rules/no-array-push-push.js +1 -1
  19. package/rules/no-await-expression-member.js +0 -1
  20. package/rules/no-document-cookie.js +2 -2
  21. package/rules/no-empty-file.js +0 -1
  22. package/rules/no-hex-escape.js +1 -1
  23. package/rules/no-invalid-remove-event-listener.js +1 -2
  24. package/rules/no-keyword-prefix.js +2 -2
  25. package/rules/no-nested-ternary.js +1 -1
  26. package/rules/no-new-buffer.js +1 -1
  27. package/rules/no-null.js +1 -1
  28. package/rules/no-object-as-default-parameter.js +1 -1
  29. package/rules/no-process-exit.js +4 -4
  30. package/rules/no-static-only-class.js +1 -1
  31. package/rules/no-thenable.js +4 -6
  32. package/rules/no-unsafe-regex.js +2 -2
  33. package/rules/no-useless-fallback-in-spread.js +0 -3
  34. package/rules/no-useless-promise-resolve-reject.js +1 -4
  35. package/rules/no-useless-undefined.js +4 -2
  36. package/rules/no-zero-fractions.js +1 -1
  37. package/rules/number-literal-case.js +1 -1
  38. package/rules/numeric-separators-style.js +1 -1
  39. package/rules/prefer-array-find.js +2 -2
  40. package/rules/prefer-array-flat.js +2 -2
  41. package/rules/prefer-at.js +42 -27
  42. package/rules/prefer-code-point.js +0 -1
  43. package/rules/prefer-default-parameters.js +5 -5
  44. package/rules/prefer-export-from.js +28 -6
  45. package/rules/prefer-includes.js +2 -2
  46. package/rules/prefer-json-parse-buffer.js +3 -4
  47. package/rules/prefer-keyboard-event-key.js +1 -1
  48. package/rules/prefer-math-trunc.js +1 -1
  49. package/rules/prefer-negative-index.js +1 -1
  50. package/rules/prefer-number-properties.js +2 -2
  51. package/rules/prefer-optional-catch-binding.js +1 -1
  52. package/rules/prefer-prototype-methods.js +3 -3
  53. package/rules/prefer-reflect-apply.js +6 -6
  54. package/rules/prefer-set-has.js +3 -3
  55. package/rules/prefer-string-replace-all.js +1 -1
  56. package/rules/prefer-ternary.js +1 -1
  57. package/rules/prefer-type-error.js +1 -1
  58. package/rules/relative-url-style.js +92 -34
  59. package/rules/selectors/not-dom-node.js +2 -1
  60. package/rules/string-content.js +1 -1
  61. package/rules/template-indent.js +3 -3
  62. package/rules/text-encoding-identifier-case.js +69 -0
  63. package/rules/throw-new-error.js +1 -1
  64. package/rules/utils/create-deprecated-rules.js +0 -1
  65. package/rules/utils/get-builtin-rule.js +0 -7
  66. package/rules/utils/get-references.js +3 -3
  67. package/rules/utils/get-variable-identifiers.js +2 -3
  68. package/rules/utils/is-function-self-used-inside.js +1 -1
  69. package/rules/utils/is-same-reference.js +4 -4
  70. package/rules/utils/rule.js +1 -1
  71. package/rules/utils/should-add-parentheses-to-logical-expression-child.js +2 -1
  72. package/rules/utils/should-add-parentheses-to-member-expression-object.js +1 -1
  73. package/configs/base.js +0 -13
  74. package/configs/conflicting-rules.js +0 -6
  75. package/rules/utils/get-key-name.js +0 -38
package/configs/all.js CHANGED
@@ -1,17 +1,9 @@
1
1
  'use strict';
2
- const conflictingRules = require('./conflicting-rules.js');
2
+ const {rules, ...baseConfigs} = require('./recommended.js');
3
3
 
4
4
  module.exports = {
5
- ...require('./base.js'),
6
- rules: {
7
- ...Object.fromEntries(
8
- Object.entries(require('./recommended.js').rules)
9
- .filter(
10
- ruleEntry =>
11
- !Object.keys(conflictingRules.rules).includes(ruleEntry[0]),
12
- )
13
- .map(ruleEntry => [ruleEntry[0], 'error']),
14
- ),
15
- ...conflictingRules.rules,
16
- },
5
+ ...baseConfigs,
6
+ rules: Object.fromEntries(Object.entries(rules).map(
7
+ ([ruleId, severity]) => [ruleId, ruleId.startsWith('unicorn/') ? 'error' : severity],
8
+ )),
17
9
  };
@@ -1,6 +1,15 @@
1
1
  'use strict';
2
2
  module.exports = {
3
- ...require('./base.js'),
3
+ env: {
4
+ es2022: true,
5
+ },
6
+ parserOptions: {
7
+ ecmaVersion: 'latest',
8
+ sourceType: 'module',
9
+ },
10
+ plugins: [
11
+ 'unicorn',
12
+ ],
4
13
  rules: {
5
14
  'unicorn/better-regex': 'error',
6
15
  'unicorn/catch-error-name': 'error',
@@ -105,7 +114,7 @@ module.exports = {
105
114
  'unicorn/require-post-message-target-origin': 'off',
106
115
  'unicorn/string-content': 'off',
107
116
  'unicorn/template-indent': 'warn',
117
+ 'unicorn/text-encoding-identifier-case': 'error',
108
118
  'unicorn/throw-new-error': 'error',
109
- ...require('./conflicting-rules.js').rules,
110
119
  },
111
120
  };
package/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  const createDeprecatedRules = require('./rules/utils/create-deprecated-rules.js');
3
3
  const {loadRules} = require('./rules/utils/rule.js');
4
4
  const recommendedConfig = require('./configs/recommended.js');
5
- const all = require('./configs/all.js');
5
+ const allRulesEnabledConfig = require('./configs/all.js');
6
6
 
7
7
  const deprecatedRules = createDeprecatedRules({
8
8
  // {ruleId: ReplacementRuleId | ReplacementRuleId[]}, if no replacement, use `{ruleId: []}`
@@ -30,6 +30,6 @@ module.exports = {
30
30
  },
31
31
  configs: {
32
32
  recommended: recommendedConfig,
33
- all,
33
+ all: allRulesEnabledConfig,
34
34
  },
35
35
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-unicorn",
3
- "version": "40.0.0",
3
+ "version": "41.0.1",
4
4
  "description": "Various awesome ESLint rules",
5
5
  "license": "MIT",
6
6
  "repository": "sindresorhus/eslint-plugin-unicorn",
@@ -14,12 +14,12 @@
14
14
  "node": ">=12"
15
15
  },
16
16
  "scripts": {
17
- "create-rule": "node ./scripts/create-rule.mjs && npm run generate-rules-table && npm run generate-usage-example",
17
+ "create-rule": "node ./scripts/create-rule.mjs && npm run generate-rule-notices && npm run generate-rules-table",
18
18
  "fix": "run-p --continue-on-error fix:*",
19
19
  "fix:js": "npm run lint:js -- --fix",
20
20
  "fix:md": "npm run lint:md -- --fix",
21
+ "generate-rule-notices": "node ./scripts/generate-rule-notices.mjs",
21
22
  "generate-rules-table": "node ./scripts/generate-rules-table.mjs",
22
- "generate-usage-example": "node ./scripts/generate-usage-example.mjs",
23
23
  "integration": "node ./test/integration/test.mjs",
24
24
  "lint": "run-p --continue-on-error lint:*",
25
25
  "lint:js": "xo",
@@ -28,7 +28,7 @@
28
28
  "run-rules-on-codebase": "node ./test/run-rules-on-codebase/lint.mjs",
29
29
  "smoke": "eslint-remote-tester --config ./test/smoke/eslint-remote-tester.config.js",
30
30
  "test": "npm-run-all --continue-on-error lint test:*",
31
- "test:js": "nyc ava"
31
+ "test:js": "c8 ava"
32
32
  },
33
33
  "files": [
34
34
  "index.js",
@@ -68,11 +68,13 @@
68
68
  "@lubien/fixture-beta-package": "^1.0.0-beta.1",
69
69
  "@typescript-eslint/parser": "^5.7.0",
70
70
  "ava": "^3.15.0",
71
+ "c8": "^7.11.0",
71
72
  "chalk": "^5.0.0",
72
73
  "enquirer": "^2.3.6",
73
- "eslint": "^8.5.0",
74
+ "eslint": "^8.8.0",
74
75
  "eslint-ava-rule-tester": "^4.0.0",
75
76
  "eslint-plugin-eslint-plugin": "^4.1.0",
77
+ "eslint-plugin-internal-rules": "file:./scripts/internal-rules/",
76
78
  "eslint-remote-tester": "^2.0.1",
77
79
  "eslint-remote-tester-repositories": "^0.0.3",
78
80
  "execa": "^6.0.0",
@@ -82,14 +84,13 @@
82
84
  "mem": "^9.0.1",
83
85
  "npm-package-json-lint": "^5.4.2",
84
86
  "npm-run-all": "^4.1.5",
85
- "nyc": "^15.1.0",
86
87
  "outdent": "^0.8.0",
87
88
  "typescript": "^4.5.4",
88
89
  "vue-eslint-parser": "^8.0.1",
89
- "xo": "^0.47.0"
90
+ "xo": "^0.48.0"
90
91
  },
91
92
  "peerDependencies": {
92
- "eslint": ">=7.32.0"
93
+ "eslint": ">=8.8.0"
93
94
  },
94
95
  "ava": {
95
96
  "files": [
@@ -97,7 +98,7 @@
97
98
  "test/unit/*.mjs"
98
99
  ]
99
100
  },
100
- "nyc": {
101
+ "c8": {
101
102
  "reporter": [
102
103
  "text",
103
104
  "lcov"
@@ -110,7 +111,16 @@
110
111
  "test/integration/{fixtures,fixtures-local}/**"
111
112
  ],
112
113
  "rules": {
113
- "unicorn/no-null": "error"
114
+ "unicorn/no-null": "error",
115
+ "unicorn/prefer-array-flat": [
116
+ "error",
117
+ {
118
+ "functions": [
119
+ "flat",
120
+ "flatten"
121
+ ]
122
+ }
123
+ ]
114
124
  },
115
125
  "overrides": [
116
126
  {
@@ -146,7 +156,30 @@
146
156
  "eslint-plugin/require-meta-has-suggestions": "off",
147
157
  "eslint-plugin/require-meta-schema": "off"
148
158
  }
159
+ },
160
+ {
161
+ "files": [
162
+ "rules/**/*.js"
163
+ ],
164
+ "plugins": [
165
+ "internal-rules"
166
+ ],
167
+ "rules": {
168
+ "internal-rules/prefer-negative-boolean-attribute": "error"
169
+ }
149
170
  }
150
171
  ]
172
+ },
173
+ "npmpackagejsonlint": {
174
+ "rules": {
175
+ "prefer-caret-version-devDependencies": [
176
+ "error",
177
+ {
178
+ "exceptions": [
179
+ "eslint-plugin-internal-rules"
180
+ ]
181
+ }
182
+ ]
183
+ }
151
184
  }
152
185
  }
package/readme.md CHANGED
@@ -17,16 +17,14 @@ npm install --save-dev eslint eslint-plugin-unicorn
17
17
 
18
18
  ## Usage
19
19
 
20
- Configure it in `package.json`.
20
+ Use a [preset config](#preset-configs) or configure each rules in `package.json`.
21
21
 
22
- <!-- Do not manually modify this table. Run: `npm run generate-usage-example` -->
23
- <!-- USAGE_EXAMPLE_START -->
24
22
  ```json
25
23
  {
26
24
  "name": "my-awesome-project",
27
25
  "eslintConfig": {
28
26
  "env": {
29
- "es6": true
27
+ "es2022": true
30
28
  },
31
29
  "parserOptions": {
32
30
  "ecmaVersion": "latest",
@@ -37,109 +35,11 @@ Configure it in `package.json`.
37
35
  ],
38
36
  "rules": {
39
37
  "unicorn/better-regex": "error",
40
- "unicorn/catch-error-name": "error",
41
- "unicorn/consistent-destructuring": "error",
42
- "unicorn/consistent-function-scoping": "error",
43
- "unicorn/custom-error-definition": "off",
44
- "unicorn/empty-brace-spaces": "error",
45
- "unicorn/error-message": "error",
46
- "unicorn/escape-case": "error",
47
- "unicorn/expiring-todo-comments": "error",
48
- "unicorn/explicit-length-check": "error",
49
- "unicorn/filename-case": "error",
50
- "unicorn/import-index": "off",
51
- "unicorn/import-style": "error",
52
- "unicorn/new-for-builtins": "error",
53
- "unicorn/no-abusive-eslint-disable": "error",
54
- "unicorn/no-array-callback-reference": "error",
55
- "unicorn/no-array-for-each": "error",
56
- "unicorn/no-array-method-this-argument": "error",
57
- "unicorn/no-array-push-push": "error",
58
- "unicorn/no-array-reduce": "error",
59
- "unicorn/no-await-expression-member": "error",
60
- "unicorn/no-console-spaces": "error",
61
- "unicorn/no-document-cookie": "error",
62
- "unicorn/no-empty-file": "error",
63
- "unicorn/no-for-loop": "error",
64
- "unicorn/no-hex-escape": "error",
65
- "unicorn/no-instanceof-array": "error",
66
- "unicorn/no-invalid-remove-event-listener": "error",
67
- "unicorn/no-keyword-prefix": "off",
68
- "unicorn/no-lonely-if": "error",
69
- "no-nested-ternary": "off",
70
- "unicorn/no-nested-ternary": "error",
71
- "unicorn/no-new-array": "error",
72
- "unicorn/no-new-buffer": "error",
73
- "unicorn/no-null": "error",
74
- "unicorn/no-object-as-default-parameter": "error",
75
- "unicorn/no-process-exit": "error",
76
- "unicorn/no-static-only-class": "error",
77
- "unicorn/no-thenable": "error",
78
- "unicorn/no-this-assignment": "error",
79
- "unicorn/no-unreadable-array-destructuring": "error",
80
- "unicorn/no-unsafe-regex": "off",
81
- "unicorn/no-unused-properties": "off",
82
- "unicorn/no-useless-fallback-in-spread": "error",
83
- "unicorn/no-useless-length-check": "error",
84
- "unicorn/no-useless-promise-resolve-reject": "error",
85
- "unicorn/no-useless-spread": "error",
86
- "unicorn/no-useless-undefined": "error",
87
- "unicorn/no-zero-fractions": "error",
88
- "unicorn/number-literal-case": "error",
89
- "unicorn/numeric-separators-style": "error",
90
- "unicorn/prefer-add-event-listener": "error",
91
- "unicorn/prefer-array-find": "error",
92
- "unicorn/prefer-array-flat": "error",
93
- "unicorn/prefer-array-flat-map": "error",
94
- "unicorn/prefer-array-index-of": "error",
95
- "unicorn/prefer-array-some": "error",
96
- "unicorn/prefer-at": "off",
97
- "unicorn/prefer-code-point": "error",
98
- "unicorn/prefer-date-now": "error",
99
- "unicorn/prefer-default-parameters": "error",
100
- "unicorn/prefer-dom-node-append": "error",
101
- "unicorn/prefer-dom-node-dataset": "error",
102
- "unicorn/prefer-dom-node-remove": "error",
103
- "unicorn/prefer-dom-node-text-content": "error",
104
- "unicorn/prefer-export-from": "error",
105
- "unicorn/prefer-includes": "error",
106
- "unicorn/prefer-json-parse-buffer": "error",
107
- "unicorn/prefer-keyboard-event-key": "error",
108
- "unicorn/prefer-math-trunc": "error",
109
- "unicorn/prefer-modern-dom-apis": "error",
110
- "unicorn/prefer-module": "error",
111
- "unicorn/prefer-negative-index": "error",
112
- "unicorn/prefer-node-protocol": "error",
113
- "unicorn/prefer-number-properties": "error",
114
- "unicorn/prefer-object-from-entries": "error",
115
- "unicorn/prefer-optional-catch-binding": "error",
116
- "unicorn/prefer-prototype-methods": "error",
117
- "unicorn/prefer-query-selector": "error",
118
- "unicorn/prefer-reflect-apply": "error",
119
- "unicorn/prefer-regexp-test": "error",
120
- "unicorn/prefer-set-has": "error",
121
- "unicorn/prefer-spread": "error",
122
- "unicorn/prefer-string-replace-all": "off",
123
- "unicorn/prefer-string-slice": "error",
124
- "unicorn/prefer-string-starts-ends-with": "error",
125
- "unicorn/prefer-string-trim-start-end": "error",
126
- "unicorn/prefer-switch": "error",
127
- "unicorn/prefer-ternary": "error",
128
- "unicorn/prefer-top-level-await": "off",
129
- "unicorn/prefer-type-error": "error",
130
- "unicorn/prevent-abbreviations": "error",
131
- "unicorn/relative-url-style": "error",
132
- "unicorn/require-array-join-separator": "error",
133
- "unicorn/require-number-to-fixed-digits-argument": "error",
134
- "unicorn/require-post-message-target-origin": "off",
135
- "unicorn/string-content": "off",
136
- "unicorn/template-indent": "warn",
137
- "unicorn/throw-new-error": "error"
38
+ "unicorn/…": "error"
138
39
  }
139
40
  }
140
41
  }
141
42
  ```
142
- <!-- USAGE_EXAMPLE_END -->
143
43
 
144
44
  ## Rules
145
45
 
@@ -149,9 +49,8 @@ Each rule has emojis denoting:
149
49
  - 🔧 if some problems reported by the rule are automatically fixable by the `--fix` [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) option
150
50
  - 💡 if some problems reported by the rule are manually fixable by editor [suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions)
151
51
 
152
- <!-- Do not manually modify this table. Run: `npm run generate-rules-table` -->
153
- <!-- RULES_TABLE_START -->
154
-
52
+ <!-- Do not manually modify RULES_TABLE part. Run: `npm run generate-rules-table` -->
53
+ <!-- RULES_TABLE -->
155
54
  | Name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Description | ✅ | 🔧 | 💡 |
156
55
  | :-- | :-- | :-- | :-- | :-- |
157
56
  | [better-regex](docs/rules/better-regex.md) | Improve regexes by making them shorter, consistent, and safer. | ✅ | 🔧 | |
@@ -245,25 +144,29 @@ Each rule has emojis denoting:
245
144
  | [prefer-top-level-await](docs/rules/prefer-top-level-await.md) | Prefer top-level await over top-level promises and async function calls. | | | 💡 |
246
145
  | [prefer-type-error](docs/rules/prefer-type-error.md) | Enforce throwing `TypeError` in type checking conditions. | ✅ | 🔧 | |
247
146
  | [prevent-abbreviations](docs/rules/prevent-abbreviations.md) | Prevent abbreviations. | ✅ | 🔧 | |
248
- | [relative-url-style](docs/rules/relative-url-style.md) | Enforce consistent relative URL style. | ✅ | 🔧 | |
147
+ | [relative-url-style](docs/rules/relative-url-style.md) | Enforce consistent relative URL style. | ✅ | 🔧 | 💡 |
249
148
  | [require-array-join-separator](docs/rules/require-array-join-separator.md) | Enforce using the separator argument with `Array#join()`. | ✅ | 🔧 | |
250
149
  | [require-number-to-fixed-digits-argument](docs/rules/require-number-to-fixed-digits-argument.md) | Enforce using the digits argument with `Number#toFixed()`. | ✅ | 🔧 | |
251
150
  | [require-post-message-target-origin](docs/rules/require-post-message-target-origin.md) | Enforce using the `targetOrigin` argument with `window.postMessage()`. | | | 💡 |
252
151
  | [string-content](docs/rules/string-content.md) | Enforce better string content. | | 🔧 | 💡 |
253
- | [template-indent](docs/rules/template-indent.md) | Fix whitespace-insensitive template indentation. | | 🔧 | |
152
+ | [template-indent](docs/rules/template-indent.md) | Fix whitespace-insensitive template indentation. || 🔧 | |
153
+ | [text-encoding-identifier-case](docs/rules/text-encoding-identifier-case.md) | Enforce consistent case for text encoding identifiers. | ✅ | | 💡 |
254
154
  | [throw-new-error](docs/rules/throw-new-error.md) | Require `new` when throwing an error. | ✅ | 🔧 | |
155
+ <!-- /RULES_TABLE -->
255
156
 
256
- <!-- RULES_TABLE_END -->
257
-
258
- ## Deprecated Rules
157
+ ### Deprecated Rules
259
158
 
260
159
  See [docs/deprecated-rules.md](docs/deprecated-rules.md)
261
160
 
262
- ## Recommended config
161
+ ## Preset configs
263
162
 
264
- This plugin exports a [`recommended` config](configs/recommended.js) that enforces good practices.
163
+ See the [ESLint docs](https://eslint.org/docs/user-guide/configuring/configuration-files#extending-configuration-files) for more information about extending config files.
265
164
 
266
- Enable it in your `package.json` with the `extends` option:
165
+ **Note**: Preset configs will also enable the correct [parser options](https://eslint.org/docs/user-guide/configuring/language-options#specifying-parser-options) and [environment](https://eslint.org/docs/user-guide/configuring/language-options#specifying-environments).
166
+
167
+ ### Recommended config
168
+
169
+ This plugin exports a [`recommended` config](configs/recommended.js) that enforces good practices.
267
170
 
268
171
  ```json
269
172
  {
@@ -274,16 +177,10 @@ Enable it in your `package.json` with the `extends` option:
274
177
  }
275
178
  ```
276
179
 
277
- See the [ESLint docs](https://eslint.org/docs/user-guide/configuring/configuration-files#extending-configuration-files) for more information about extending config files.
278
-
279
- **Note**: This config will also enable the correct [parser options](https://eslint.org/docs/user-guide/configuring/language-options#specifying-parser-options) and [environment](https://eslint.org/docs/user-guide/configuring/language-options#specifying-environments).
280
-
281
- ## All config
180
+ ### All config
282
181
 
283
182
  This plugin exports an [`all` config](configs/all.js) that makes use of all rules (except for deprecated ones).
284
183
 
285
- Enable it in your `package.json` with the `extends` option:
286
-
287
184
  ```json
288
185
  {
289
186
  "name": "my-awesome-project",
@@ -293,8 +190,6 @@ Enable it in your `package.json` with the `extends` option:
293
190
  }
294
191
  ```
295
192
 
296
- See the [ESLint docs](https://eslint.org/docs/user-guide/configuring/configuration-files#extending-configuration-files) for more information about extending config files.
297
-
298
193
  ## Maintainers
299
194
 
300
195
  - [Sindre Sorhus](https://github.com/sindresorhus)
@@ -25,7 +25,7 @@ const create = context => {
25
25
  }
26
26
 
27
27
  return {
28
- 'Literal[regex]': node => {
28
+ 'Literal[regex]'(node) {
29
29
  const {raw: original, regex} = node;
30
30
 
31
31
  // Regular Expressions with `u` flag are not well handled by `regexp-tree`
@@ -63,7 +63,7 @@ const create = context => {
63
63
  fix: fixer => fixer.replaceText(node, optimized),
64
64
  };
65
65
  },
66
- [newRegExp]: node => {
66
+ [newRegExp](node) {
67
67
  const [patternNode, flagsNode] = node.arguments;
68
68
 
69
69
  if (typeof patternNode.value !== 'string') {
@@ -50,7 +50,7 @@ const create = context => {
50
50
  || name.endsWith(expectedName.charAt(0).toUpperCase() + expectedName.slice(1));
51
51
 
52
52
  return {
53
- [selector]: node => {
53
+ [selector](node) {
54
54
  const originalName = node.name;
55
55
 
56
56
  if (
@@ -65,7 +65,7 @@ const create = context => {
65
65
 
66
66
  // This was reported https://github.com/sindresorhus/eslint-plugin-unicorn/issues/1075#issuecomment-768072967
67
67
  // But can't reproduce, just ignore this case
68
- /* istanbul ignore next */
68
+ /* c8 ignore next 3 */
69
69
  if (!variable) {
70
70
  return;
71
71
  }
@@ -57,7 +57,7 @@ const create = context => {
57
57
  const declarations = new Map();
58
58
 
59
59
  return {
60
- [declaratorSelector]: node => {
60
+ [declaratorSelector](node) {
61
61
  // Ignore any complex expressions (e.g. arrays, functions)
62
62
  if (!isSimpleExpression(node.init)) {
63
63
  return;
@@ -69,7 +69,7 @@ const create = context => {
69
69
  objectPattern: node.id,
70
70
  });
71
71
  },
72
- [memberSelector]: node => {
72
+ [memberSelector](node) {
73
73
  const declaration = declarations.get(source.getText(node.object));
74
74
 
75
75
  if (!declaration) {
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
  const {getFunctionHeadLocation, getFunctionNameWithKind} = require('eslint-utils');
3
3
  const getReferences = require('./utils/get-references.js');
4
+ const {isNodeMatches} = require('./utils/is-node-matches.js');
4
5
 
5
6
  const MESSAGE_ID = 'consistent-function-scoping';
6
7
  const messages = {
@@ -45,13 +46,13 @@ function checkReferences(scope, parent, scopeManager) {
45
46
  const identifierScope = scopeManager.acquire(identifier);
46
47
 
47
48
  // If we have a scope, the earlier checks should have worked so ignore them here
48
- /* istanbul ignore next: Hard to test */
49
+ /* c8 ignore next 3 */
49
50
  if (identifierScope) {
50
51
  return false;
51
52
  }
52
53
 
53
54
  const identifierParentScope = scopeManager.acquire(identifier.parent);
54
- /* istanbul ignore next: Hard to test */
55
+ /* c8 ignore next 3 */
55
56
  if (!identifierParentScope) {
56
57
  return false;
57
58
  }
@@ -77,7 +78,7 @@ function checkReferences(scope, parent, scopeManager) {
77
78
  }
78
79
 
79
80
  // https://reactjs.org/docs/hooks-reference.html
80
- const reactHooks = new Set([
81
+ const reactHooks = [
81
82
  'useState',
82
83
  'useEffect',
83
84
  'useContext',
@@ -88,13 +89,13 @@ const reactHooks = new Set([
88
89
  'useImperativeHandle',
89
90
  'useLayoutEffect',
90
91
  'useDebugValue',
91
- ]);
92
+ ].flatMap(hookName => [hookName, `React.${hookName}`]);
93
+
92
94
  const isReactHook = scope =>
93
95
  scope.block
94
96
  && scope.block.parent
95
97
  && scope.block.parent.callee
96
- && scope.block.parent.callee.type === 'Identifier'
97
- && reactHooks.has(scope.block.parent.callee.name);
98
+ && isNodeMatches(scope.block.parent.callee, reactHooks);
98
99
 
99
100
  const isArrowFunctionWithThis = scope =>
100
101
  scope.type === 'function'
@@ -158,17 +159,17 @@ const create = context => {
158
159
  const functions = [];
159
160
 
160
161
  return {
161
- ':function': () => {
162
+ ':function'() {
162
163
  functions.push(false);
163
164
  },
164
- JSXElement: () => {
165
+ JSXElement() {
165
166
  // Turn off this rule if we see a JSX element because scope
166
167
  // references does not include JSXElement nodes.
167
168
  if (functions.length > 0) {
168
169
  functions[functions.length - 1] = true;
169
170
  }
170
171
  },
171
- ':function:exit': node => {
172
+ ':function:exit'(node) {
172
173
  const currentFunctionHasJsx = functions.pop();
173
174
  if (currentFunctionHasJsx) {
174
175
  return;
@@ -186,13 +186,13 @@ function parseTodoMessage(todoString) {
186
186
  return afterArguments;
187
187
  }
188
188
 
189
- function reachedDate(past) {
190
- const now = new Date().toISOString().slice(0, 10);
189
+ function reachedDate(past, now) {
191
190
  return Date.parse(past) < Date.parse(now);
192
191
  }
193
192
 
194
193
  function tryToCoerceVersion(rawVersion) {
195
- /* istanbul ignore if: version in `package.json` and comment can't be empty */
194
+ // `version` in `package.json` and comment can't be empty
195
+ /* c8 ignore next 3 */
196
196
  if (!rawVersion) {
197
197
  return false;
198
198
  }
@@ -215,12 +215,14 @@ function tryToCoerceVersion(rawVersion) {
215
215
 
216
216
  // Get only the first member for cases such as `1.0.0 - 2.9999.9999`
217
217
  const parts = version.split(' ');
218
- /* istanbul ignore if: We don't have this `package.json` to test */
218
+ // We don't have this `package.json` to test
219
+ /* c8 ignore next 3 */
219
220
  if (parts.length > 1) {
220
221
  version = parts[0];
221
222
  }
222
223
 
223
- /* istanbul ignore if: We don't have this `package.json` to test */
224
+ // We don't have this `package.json` to test
225
+ /* c8 ignore next 3 */
224
226
  if (semver.valid(version)) {
225
227
  return version;
226
228
  }
@@ -230,7 +232,8 @@ function tryToCoerceVersion(rawVersion) {
230
232
  // But coerce can't parse pre-releases.
231
233
  return semver.parse(version) || semver.coerce(version);
232
234
  } catch {
233
- /* istanbul ignore next: We don't have this `package.json` to test */
235
+ // We don't have this `package.json` to test
236
+ /* c8 ignore next 3 */
234
237
  return false;
235
238
  }
236
239
  }
@@ -249,6 +252,7 @@ const create = context => {
249
252
  ignore: [],
250
253
  ignoreDatesOnPullRequests: true,
251
254
  allowWarningComments: true,
255
+ date: new Date().toISOString().slice(0, 10),
252
256
  ...context.options[0],
253
257
  };
254
258
 
@@ -325,15 +329,15 @@ const create = context => {
325
329
  });
326
330
  } else if (dates.length === 1) {
327
331
  uses++;
328
- const [date] = dates;
332
+ const [expirationDate] = dates;
329
333
 
330
334
  const shouldIgnore = options.ignoreDatesOnPullRequests && ci.isPR;
331
- if (!shouldIgnore && reachedDate(date)) {
335
+ if (!shouldIgnore && reachedDate(expirationDate, options.date)) {
332
336
  context.report({
333
337
  loc: comment.loc,
334
338
  messageId: MESSAGE_ID_EXPIRED_TODO,
335
339
  data: {
336
- expirationDate: date,
340
+ expirationDate,
337
341
  message: parseTodoMessage(comment.value),
338
342
  },
339
343
  });
@@ -403,11 +407,12 @@ const create = context => {
403
407
  const todoVersion = tryToCoerceVersion(dependency.version);
404
408
  const targetPackageVersion = tryToCoerceVersion(targetPackageRawVersion);
405
409
 
406
- /* istanbul ignore if: Can't test in Node.js */
410
+ /* c8 ignore start */
407
411
  if (!hasTargetPackage || !targetPackageVersion) {
408
412
  // Can't compare `¯\_(ツ)_/¯`
409
413
  continue;
410
414
  }
415
+ /* c8 ignore end */
411
416
 
412
417
  const compare = semverComparisonForOperator(dependency.condition);
413
418
 
@@ -431,7 +436,7 @@ const create = context => {
431
436
  const targetPackageRawEngineVersion = packageEngines.node;
432
437
  const hasTargetEngine = Boolean(targetPackageRawEngineVersion);
433
438
 
434
- /* istanbul ignore if: Can't test in this repo */
439
+ /* c8 ignore next 3 */
435
440
  if (!hasTargetEngine) {
436
441
  continue;
437
442
  }
@@ -531,6 +536,10 @@ const schema = [
531
536
  type: 'boolean',
532
537
  default: false,
533
538
  },
539
+ date: {
540
+ type: 'string',
541
+ format: 'date',
542
+ },
534
543
  },
535
544
  },
536
545
  ];
@@ -130,17 +130,7 @@ Turns `[a, b, c]` into `a, b, or c`.
130
130
  @param {string[]} words
131
131
  @returns {string}
132
132
  */
133
- function englishishJoinWords(words) {
134
- if (words.length === 1) {
135
- return words[0];
136
- }
137
-
138
- if (words.length === 2) {
139
- return `${words[0]} or ${words[1]}`;
140
- }
141
-
142
- return `${words.slice(0, -1).join(', ')}, or ${words[words.length - 1]}`;
143
- }
133
+ const englishishJoinWords = words => new Intl.ListFormat('en-US', {type: 'disjunction'}).format(words);
144
134
 
145
135
  /** @param {import('eslint').Rule.RuleContext} context */
146
136
  const create = context => {
@@ -4,7 +4,7 @@ const {isCommaToken} = require('eslint-utils');
4
4
  function appendArgument(fixer, node, text, sourceCode) {
5
5
  // This function should also work for `NewExpression`
6
6
  // But parentheses of `NewExpression` could be omitted, add this check to prevent accident use on it
7
- /* istanbul ignore next */
7
+ /* c8 ignore next 3 */
8
8
  if (node.type !== 'CallExpression') {
9
9
  throw new Error(`Unexpected node "${node.type}".`);
10
10
  }
@@ -17,13 +17,14 @@ function removeArgument(fixer, node, sourceCode) {
17
17
  }
18
18
 
19
19
  // If the removed argument is the only argument, the trailing comma must be removed too
20
- /* istanbul ignore next: Not reachable for now */
20
+ /* c8 ignore start */
21
21
  if (callExpression.arguments.length === 1) {
22
22
  const tokenAfter = sourceCode.getTokenBefore(lastToken);
23
23
  if (isCommaToken(tokenAfter)) {
24
24
  end = tokenAfter[1];
25
25
  }
26
26
  }
27
+ /* c8 ignore end */
27
28
 
28
29
  return fixer.replaceTextRange([start, end], '');
29
30
  }