eslint-plugin-unicorn 64.0.0 → 65.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 (100) hide show
  1. package/index.js +14 -0
  2. package/package.json +7 -3
  3. package/readme.md +183 -151
  4. package/rules/better-dom-traversing.js +291 -0
  5. package/rules/consistent-compound-words.js +452 -0
  6. package/rules/consistent-destructuring.js +97 -9
  7. package/rules/consistent-function-scoping.js +20 -0
  8. package/rules/consistent-json-file-read.js +245 -0
  9. package/rules/custom-error-definition.js +89 -4
  10. package/rules/dom-node-dataset.js +431 -0
  11. package/rules/escape-case.js +1 -1
  12. package/rules/expiring-todo-comments.js +42 -81
  13. package/rules/explicit-length-check.js +139 -6
  14. package/rules/filename-case.js +95 -21
  15. package/rules/import-style.js +21 -1
  16. package/rules/index.js +33 -3
  17. package/rules/isolated-functions.js +7 -5
  18. package/rules/no-anonymous-default-export.js +6 -6
  19. package/rules/no-array-callback-reference.js +89 -23
  20. package/rules/no-array-fill-with-reference-type.js +127 -0
  21. package/rules/no-array-for-each.js +17 -1
  22. package/rules/no-array-from-fill.js +76 -0
  23. package/rules/no-array-reduce.js +508 -2
  24. package/rules/no-blob-to-file.js +299 -0
  25. package/rules/no-canvas-to-image.js +152 -0
  26. package/rules/no-confusing-array-splice.js +164 -0
  27. package/rules/no-duplicate-set-values.js +57 -0
  28. package/rules/no-empty-file.js +31 -2
  29. package/rules/no-exports-in-scripts.js +34 -0
  30. package/rules/no-hex-escape.js +1 -1
  31. package/rules/no-incorrect-query-selector.js +347 -0
  32. package/rules/no-invalid-file-input-accept.js +475 -0
  33. package/rules/no-keyword-prefix.js +20 -5
  34. package/rules/no-late-current-target-access.js +166 -0
  35. package/rules/no-lonely-if.js +151 -50
  36. package/rules/no-manually-wrapped-comments.js +151 -0
  37. package/rules/no-null.js +14 -3
  38. package/rules/no-this-outside-of-class.js +75 -0
  39. package/rules/no-typeof-undefined.js +6 -4
  40. package/rules/no-unnecessary-nested-ternary.js +132 -0
  41. package/rules/no-unnecessary-polyfills.js +66 -20
  42. package/rules/no-unreadable-iife.js +33 -3
  43. package/rules/no-unused-array-method-return.js +301 -0
  44. package/rules/no-useless-promise-resolve-reject.js +5 -5
  45. package/rules/no-useless-spread.js +53 -4
  46. package/rules/no-useless-undefined.js +52 -45
  47. package/rules/numeric-separators-style.js +13 -4
  48. package/rules/prefer-array-last-methods.js +93 -0
  49. package/rules/prefer-array-some.js +66 -5
  50. package/rules/prefer-at.js +114 -55
  51. package/rules/prefer-dom-node-append.js +2 -2
  52. package/rules/prefer-dom-node-remove.js +24 -18
  53. package/rules/prefer-export-from.js +6 -6
  54. package/rules/prefer-get-or-insert-computed.js +159 -0
  55. package/rules/prefer-global-this.js +7 -46
  56. package/rules/prefer-https.js +83 -0
  57. package/rules/prefer-includes-over-repeated-comparisons.js +199 -0
  58. package/rules/prefer-iterator-concat.js +174 -0
  59. package/rules/prefer-iterator-to-array-at-end.js +123 -0
  60. package/rules/prefer-keyboard-event-key.js +202 -76
  61. package/rules/prefer-math-abs.js +397 -0
  62. package/rules/prefer-math-min-max.js +5 -3
  63. package/rules/prefer-node-protocol.js +6 -4
  64. package/rules/prefer-query-selector.js +119 -7
  65. package/rules/prefer-queue-microtask.js +204 -0
  66. package/rules/prefer-regexp-test.js +164 -18
  67. package/rules/prefer-set-has.js +411 -22
  68. package/rules/prefer-single-call.js +128 -38
  69. package/rules/prefer-split-limit.js +107 -0
  70. package/rules/prefer-spread.js +34 -4
  71. package/rules/prefer-string-match-all.js +352 -0
  72. package/rules/prefer-string-pad-start-end.js +380 -0
  73. package/rules/prefer-string-raw.js +90 -19
  74. package/rules/prefer-string-repeat.js +173 -0
  75. package/rules/prefer-string-replace-all.js +180 -12
  76. package/rules/prefer-string-slice.js +54 -3
  77. package/rules/prefer-top-level-await.js +129 -1
  78. package/rules/prevent-abbreviations.js +126 -134
  79. package/rules/require-css-escape.js +141 -0
  80. package/rules/require-module-specifiers.js +62 -0
  81. package/rules/require-passive-events.js +292 -0
  82. package/rules/shared/dom-events.js +7 -7
  83. package/rules/shared/identifier-checks.js +205 -0
  84. package/rules/shared/package-json.js +1 -1
  85. package/rules/string-content.js +34 -5
  86. package/rules/template-indent.js +52 -3
  87. package/rules/throw-new-error.js +4 -0
  88. package/rules/try-complexity.js +184 -0
  89. package/rules/utils/boolean.js +12 -12
  90. package/rules/utils/get-duplicate-array-elements.js +77 -0
  91. package/rules/utils/index.js +1 -0
  92. package/rules/utils/is-same-reference.js +6 -4
  93. package/rules/utils/should-add-parentheses-to-await-expression-argument.js +9 -9
  94. package/rules/utils/should-add-parentheses-to-call-expression-callee.js +12 -10
  95. package/rules/utils/should-add-parentheses-to-conditional-expression-child.js +9 -7
  96. package/rules/utils/should-add-parentheses-to-logical-expression-child.js +12 -8
  97. package/rules/utils/should-add-parentheses-to-unary-expression.js +10 -10
  98. package/rules/better-regex.js +0 -155
  99. package/rules/prefer-dom-node-dataset.js +0 -135
  100. package/rules/prefer-json-parse-buffer.js +0 -161
@@ -6,6 +6,7 @@ import {
6
6
  isBooleanExpression,
7
7
  isControlFlowTest,
8
8
  getBooleanAncestor,
9
+ isSameReference,
9
10
  } from './utils/index.js';
10
11
  import {fixSpaceAroundKeyword} from './fix/index.js';
11
12
  import {isLiteral, isMemberExpression} from './ast/index.js';
@@ -48,8 +49,107 @@ const zeroStyle = {
48
49
  test: node => isCompareRight(node, '===', 0),
49
50
  };
50
51
 
51
- function getLengthCheckNode(node) {
52
+ const shapeProperties = new Set(['depth', 'height', 'width']);
53
+
54
+ function isLengthOrSizeMemberExpression(node) {
55
+ return isMemberExpression(node, {
56
+ properties: ['length', 'size'],
57
+ optional: false,
58
+ });
59
+ }
60
+
61
+ function isTypeScriptExpression(node) {
62
+ return node?.type === 'TSAsExpression'
63
+ || node?.type === 'TSSatisfiesExpression'
64
+ || node?.type === 'TSTypeAssertion'
65
+ || node?.type === 'TSNonNullExpression';
66
+ }
67
+
68
+ function unwrapTypeScriptExpression(node) {
69
+ if (isTypeScriptExpression(node)) {
70
+ return unwrapTypeScriptExpression(node.expression);
71
+ }
72
+
73
+ return node;
74
+ }
75
+
76
+ function getLengthCheckParent(node, allowTypeScriptExpression) {
52
77
  node = node.parent;
78
+ if (allowTypeScriptExpression) {
79
+ while (isTypeScriptExpression(node)) {
80
+ node = node.parent;
81
+ }
82
+ }
83
+
84
+ return node;
85
+ }
86
+
87
+ function getLogicalExpressionRoot(node) {
88
+ while (
89
+ isLogicalExpression(node.parent)
90
+ && node.parent.operator === '&&'
91
+ ) {
92
+ node = node.parent;
93
+ }
94
+
95
+ return node;
96
+ }
97
+
98
+ function getLogicalExpressionOperands(node) {
99
+ return [node.left, node.right].flatMap(child =>
100
+ child.type === 'LogicalExpression' && child.operator === node.operator
101
+ ? getLogicalExpressionOperands(child)
102
+ : [child]);
103
+ }
104
+
105
+ function hasSameObjectShapePropertyCheck({node, lengthNode}) {
106
+ const root = getLogicalExpressionRoot(node);
107
+ if (
108
+ root.type !== 'LogicalExpression'
109
+ || root.operator !== '&&'
110
+ ) {
111
+ return false;
112
+ }
113
+
114
+ return getLogicalExpressionOperands(root).some(operand =>
115
+ operand !== node
116
+ && isMemberExpression(operand, {computed: false, optional: false})
117
+ && operand.property.type === 'Identifier'
118
+ && shapeProperties.has(operand.property.name)
119
+ && isSameReference(operand.object, lengthNode.object));
120
+ }
121
+
122
+ function getLengthCheckMemberExpression(node) {
123
+ if (node.type === 'UnaryExpression' && node.operator === '!') {
124
+ return getLengthCheckMemberExpression(node.argument);
125
+ }
126
+
127
+ if (
128
+ node.type === 'CallExpression'
129
+ && node.callee.type === 'Identifier'
130
+ && node.callee.name === 'Boolean'
131
+ && node.arguments.length === 1
132
+ ) {
133
+ return getLengthCheckMemberExpression(node.arguments[0]);
134
+ }
135
+
136
+ if (node.type !== 'BinaryExpression') {
137
+ return;
138
+ }
139
+
140
+ const left = unwrapTypeScriptExpression(node.left);
141
+ if (isLengthOrSizeMemberExpression(left)) {
142
+ return left;
143
+ }
144
+
145
+ const right = unwrapTypeScriptExpression(node.right);
146
+ if (isLengthOrSizeMemberExpression(right)) {
147
+ return right;
148
+ }
149
+ }
150
+
151
+ function getLengthCheckNode(node, {allowTypeScriptExpression = false} = {}) {
152
+ node = getLengthCheckParent(node, allowTypeScriptExpression);
53
153
 
54
154
  // Zero length check
55
155
  if (
@@ -81,7 +181,7 @@ function getLengthCheckNode(node) {
81
181
  || isCompareRight(node, '>=', 1)
82
182
  // `0 !== foo.length`
83
183
  || isCompareLeft(node, '!==', 0)
84
- // `0 !== foo.length`
184
+ // `0 != foo.length`
85
185
  || isCompareLeft(node, '!=', 0)
86
186
  // `0 < foo.length`
87
187
  || isCompareLeft(node, '<', 0)
@@ -94,6 +194,35 @@ function getLengthCheckNode(node) {
94
194
  return {};
95
195
  }
96
196
 
197
+ function isSameLengthNonZeroCheck(node, lengthNode) {
198
+ const comparisonLengthNode = getLengthCheckMemberExpression(node);
199
+ if (!comparisonLengthNode || !isSameReference(comparisonLengthNode, lengthNode)) {
200
+ return false;
201
+ }
202
+
203
+ const {isZeroLengthCheck, node: lengthCheckNode} = getLengthCheckNode(comparisonLengthNode, {allowTypeScriptExpression: true});
204
+ if (!lengthCheckNode) {
205
+ return false;
206
+ }
207
+
208
+ const {isNegative, node: ancestor} = getBooleanAncestor(lengthCheckNode);
209
+ return ancestor === node && isNegative === isZeroLengthCheck;
210
+ }
211
+
212
+ function isLengthGuardedByNonZeroCheck(lengthNode) {
213
+ const root = getLogicalExpressionRoot(lengthNode);
214
+ if (
215
+ root.type !== 'LogicalExpression'
216
+ || root.operator !== '&&'
217
+ ) {
218
+ return false;
219
+ }
220
+
221
+ return getLogicalExpressionOperands(root).some(operand =>
222
+ operand !== lengthNode
223
+ && isSameLengthNonZeroCheck(operand, lengthNode));
224
+ }
225
+
97
226
  function create(context) {
98
227
  const options = context.options[0];
99
228
  const nonZeroStyle = nonZeroStyles.get(options['non-zero']);
@@ -141,10 +270,7 @@ function create(context) {
141
270
 
142
271
  context.on('MemberExpression', memberExpression => {
143
272
  if (
144
- !isMemberExpression(memberExpression, {
145
- properties: ['length', 'size'],
146
- optional: false,
147
- })
273
+ !isLengthOrSizeMemberExpression(memberExpression)
148
274
  || memberExpression.object.type === 'ThisExpression'
149
275
  ) {
150
276
  return;
@@ -179,6 +305,13 @@ function create(context) {
179
305
  }
180
306
 
181
307
  if (node) {
308
+ if (
309
+ (node === lengthNode && isLengthGuardedByNonZeroCheck(lengthNode))
310
+ || hasSameObjectShapePropertyCheck({node, lengthNode})
311
+ ) {
312
+ return;
313
+ }
314
+
182
315
  const isUnsafeNegationInBinaryExpression = node.type === 'UnaryExpression'
183
316
  && node.operator === '!'
184
317
  && node.parent.type === 'BinaryExpression'
@@ -9,9 +9,11 @@ import {
9
9
  import cartesianProductSamples from './utils/cartesian-product-samples.js';
10
10
 
11
11
  const MESSAGE_ID = 'filename-case';
12
+ const MESSAGE_ID_DIRECTORY = 'directory-case';
12
13
  const MESSAGE_ID_EXTENSION = 'filename-extension';
13
14
  const messages = {
14
15
  [MESSAGE_ID]: 'Filename is not in {{chosenCases}}. Rename it to {{renamedFilenames}}.',
16
+ [MESSAGE_ID_DIRECTORY]: 'Directory name `{{directory}}` is not in {{chosenCases}}. Rename it to {{renamedDirectories}}.',
15
17
  [MESSAGE_ID_EXTENSION]: 'File extension `{{extension}}` is not in lowercase. Rename it to `{{filename}}`.',
16
18
  };
17
19
 
@@ -59,13 +61,13 @@ function getChosenCases(options) {
59
61
  return ['kebabCase'];
60
62
  }
61
63
 
62
- function validateFilename(words, caseFunctions) {
64
+ function validateName(words, caseFunctions) {
63
65
  return words
64
66
  .filter(({ignored}) => !ignored)
65
67
  .every(({word}) => caseFunctions.some(caseFunction => caseFunction(word) === word));
66
68
  }
67
69
 
68
- function fixFilename(words, caseFunctions, {leading, trailing}) {
70
+ function fixName(words, caseFunctions, {leading, trailing}) {
69
71
  const replacements = words
70
72
  .map(({word, ignored}) => ignored ? [word] : caseFunctions.map(caseFunction => caseFunction(word)));
71
73
 
@@ -99,10 +101,29 @@ function getFilenameParts(filenameWithExtension, {multipleFileExtensions}) {
99
101
  return parts;
100
102
  }
101
103
 
104
+ function isInsideCwd(relativePath) {
105
+ return relativePath !== ''
106
+ && relativePath !== '..'
107
+ && !relativePath.startsWith(`..${path.sep}`)
108
+ && !path.isAbsolute(relativePath);
109
+ }
110
+
111
+ function getPathSegments(filenameWithExtension, cwd) {
112
+ const relativePath = path.relative(cwd, path.resolve(cwd, filenameWithExtension));
113
+
114
+ if (!isInsideCwd(relativePath)) {
115
+ return [path.basename(filenameWithExtension)];
116
+ }
117
+
118
+ return relativePath
119
+ .split(path.sep)
120
+ .filter(segment => segment !== '.');
121
+ }
122
+
102
123
  const leadingUnderscoresRegex = /^(?<leading>_+)(?<tailing>.*)$/;
103
- function splitFilename(filename) {
104
- const result = leadingUnderscoresRegex.exec(filename) || {groups: {}};
105
- const {leading = '', tailing = filename} = result.groups;
124
+ function splitName(name) {
125
+ const result = leadingUnderscoresRegex.exec(name) || {groups: {}};
126
+ const {leading = '', tailing = name} = result.groups;
106
127
 
107
128
  const words = [];
108
129
 
@@ -135,6 +156,33 @@ Turns `[a, b, c]` into `a, b, or c`.
135
156
  */
136
157
  const englishishJoinWords = words => new Intl.ListFormat('en-US', {type: 'disjunction'}).format(words);
137
158
 
159
+ function getCaseNames(chosenCases) {
160
+ return englishishJoinWords(chosenCases.map(x => cases[x].name));
161
+ }
162
+
163
+ function getInvalidDirectoryReport(directory, chosenCases, chosenCasesFunctions) {
164
+ const {leading, words} = splitName(directory);
165
+
166
+ if (directory.startsWith('$') || validateName(words, chosenCasesFunctions)) {
167
+ return;
168
+ }
169
+
170
+ const renamedDirectories = fixName(words, chosenCasesFunctions, {
171
+ leading,
172
+ trailing: '',
173
+ });
174
+
175
+ return {
176
+ loc: {column: 0, line: 1},
177
+ messageId: MESSAGE_ID_DIRECTORY,
178
+ data: {
179
+ directory,
180
+ chosenCases: getCaseNames(chosenCases),
181
+ renamedDirectories: englishishJoinWords(renamedDirectories.map(x => `\`${x}\``)),
182
+ },
183
+ };
184
+ }
185
+
138
186
  /** @param {import('eslint').Rule.RuleContext} context */
139
187
  const create = context => {
140
188
  const options = context.options[0] || {};
@@ -147,6 +195,7 @@ const create = context => {
147
195
  return new RegExp(item, 'u');
148
196
  });
149
197
  const multipleFileExtensions = options.multipleFileExtensions !== false;
198
+ const checkDirectories = options.checkDirectories !== false;
150
199
  const chosenCasesFunctions = chosenCases.map(case_ => cases[case_].fn);
151
200
  const filenameWithExtension = context.physicalFilename;
152
201
 
@@ -155,19 +204,35 @@ const create = context => {
155
204
  }
156
205
 
157
206
  context.on('Program', () => {
207
+ const pathSegments = getPathSegments(filenameWithExtension, context.cwd);
208
+ const basenameWithExtension = pathSegments.at(-1);
158
209
  const {
159
210
  basename,
160
211
  filename,
161
212
  middle,
162
213
  extension,
163
- } = getFilenameParts(filenameWithExtension, {multipleFileExtensions});
214
+ } = getFilenameParts(basenameWithExtension, {multipleFileExtensions});
215
+
216
+ if (pathSegments.some(segment => ignore.some(regexp => regexp.test(segment)))) {
217
+ return;
218
+ }
164
219
 
165
- if (ignoredByDefault.has(basename) || ignore.some(regexp => regexp.test(basename))) {
220
+ if (checkDirectories) {
221
+ for (const directory of pathSegments.slice(0, -1)) {
222
+ const report = getInvalidDirectoryReport(directory, chosenCases, chosenCasesFunctions);
223
+
224
+ if (report) {
225
+ return report;
226
+ }
227
+ }
228
+ }
229
+
230
+ if (ignoredByDefault.has(basename)) {
166
231
  return;
167
232
  }
168
233
 
169
- const {leading, words} = splitFilename(filename);
170
- const isValid = validateFilename(words, chosenCasesFunctions);
234
+ const {leading, words} = splitName(filename);
235
+ const isValid = filename.startsWith('$') || validateName(words, chosenCasesFunctions);
171
236
 
172
237
  if (isValid) {
173
238
  if (!isLowerCase(extension)) {
@@ -181,7 +246,7 @@ const create = context => {
181
246
  return;
182
247
  }
183
248
 
184
- const renamedFilenames = fixFilename(words, chosenCasesFunctions, {
249
+ const renamedFilenames = fixName(words, chosenCasesFunctions, {
185
250
  leading,
186
251
  trailing: middle + extension.toLowerCase(),
187
252
  });
@@ -192,7 +257,7 @@ const create = context => {
192
257
  loc: {column: 0, line: 1},
193
258
  messageId: MESSAGE_ID,
194
259
  data: {
195
- chosenCases: englishishJoinWords(chosenCases.map(x => cases[x].name)),
260
+ chosenCases: getCaseNames(chosenCases),
196
261
  renamedFilenames: englishishJoinWords(renamedFilenames.map(x => `\`${x}\``)),
197
262
  },
198
263
  };
@@ -201,7 +266,8 @@ const create = context => {
201
266
 
202
267
  const schema = [
203
268
  {
204
- oneOf: [
269
+ description: 'The rule options.',
270
+ anyOf: [
205
271
  {
206
272
  properties: {
207
273
  case: {
@@ -211,17 +277,21 @@ const schema = [
211
277
  'kebabCase',
212
278
  'pascalCase',
213
279
  ],
214
- description: 'The filename case style.',
280
+ description: 'The filename and directory name case style.',
215
281
  },
216
282
  ignore: {
217
283
  type: 'array',
218
284
  uniqueItems: true,
219
- description: 'Patterns to ignore.',
285
+ description: 'Path segment patterns to ignore.',
220
286
  },
221
287
  multipleFileExtensions: {
222
288
  type: 'boolean',
223
289
  description: 'Whether to treat additional, dot-separated parts of a filename as file extensions.',
224
290
  },
291
+ checkDirectories: {
292
+ type: 'boolean',
293
+ description: 'Whether to check directory names.',
294
+ },
225
295
  },
226
296
  additionalProperties: false,
227
297
  },
@@ -231,33 +301,37 @@ const schema = [
231
301
  properties: {
232
302
  camelCase: {
233
303
  type: 'boolean',
234
- description: 'Whether to allow camelCase filenames.',
304
+ description: 'Whether to allow camelCase filenames and directory names.',
235
305
  },
236
306
  snakeCase: {
237
307
  type: 'boolean',
238
- description: 'Whether to allow snake_case filenames.',
308
+ description: 'Whether to allow snake_case filenames and directory names.',
239
309
  },
240
310
  kebabCase: {
241
311
  type: 'boolean',
242
- description: 'Whether to allow kebab-case filenames.',
312
+ description: 'Whether to allow kebab-case filenames and directory names.',
243
313
  },
244
314
  pascalCase: {
245
315
  type: 'boolean',
246
- description: 'Whether to allow PascalCase filenames.',
316
+ description: 'Whether to allow PascalCase filenames and directory names.',
247
317
  },
248
318
  },
249
319
  additionalProperties: false,
250
- description: 'The allowed filename case styles.',
320
+ description: 'The allowed filename and directory name case styles.',
251
321
  },
252
322
  ignore: {
253
323
  type: 'array',
254
324
  uniqueItems: true,
255
- description: 'Patterns to ignore.',
325
+ description: 'Path segment patterns to ignore.',
256
326
  },
257
327
  multipleFileExtensions: {
258
328
  type: 'boolean',
259
329
  description: 'Whether to treat additional, dot-separated parts of a filename as file extensions.',
260
330
  },
331
+ checkDirectories: {
332
+ type: 'boolean',
333
+ description: 'Whether to check directory names.',
334
+ },
261
335
  },
262
336
  additionalProperties: false,
263
337
  },
@@ -271,7 +345,7 @@ const config = {
271
345
  meta: {
272
346
  type: 'suggestion',
273
347
  docs: {
274
- description: 'Enforce a case style for filenames.',
348
+ description: 'Enforce a case style for filenames and directory names.',
275
349
  recommended: true,
276
350
  },
277
351
  schema,
@@ -2,8 +2,10 @@ import {getStringIfConstant} from '@eslint-community/eslint-utils';
2
2
  import {isCallExpression} from './ast/index.js';
3
3
 
4
4
  const MESSAGE_ID = 'importStyle';
5
+ const MESSAGE_ID_BANNED = 'importStyleBanned';
5
6
  const messages = {
6
7
  [MESSAGE_ID]: 'Use {{allowedStyles}} import for module `{{moduleName}}`.',
8
+ [MESSAGE_ID_BANNED]: 'All import styles are disabled for module `{{moduleName}}`. Use the `no-restricted-imports` rule to disallow a module.',
7
9
  };
8
10
 
9
11
  const getActualImportDeclarationStyles = importDeclaration => {
@@ -144,6 +146,12 @@ const create = context => {
144
146
  .map(name => [name, styles[name] === false ? {} : {...defaultStyles[name], ...styles[name]}]))
145
147
  : styles;
146
148
 
149
+ const bannedModules = new Set(
150
+ Object.entries(styles)
151
+ .filter(([, moduleStyles]) => ['unassigned', 'default', 'namespace', 'named'].every(key => moduleStyles[key] === false))
152
+ .map(([name]) => name),
153
+ );
154
+
147
155
  styles = new Map(Object.entries(styles).map(([moduleName, styles]) =>
148
156
  [moduleName, new Set(Object.entries(styles).filter(([, isAllowed]) => isAllowed).map(([style]) => style))]));
149
157
 
@@ -151,7 +159,19 @@ const create = context => {
151
159
 
152
160
  // eslint-disable-next-line max-params
153
161
  const report = (node, moduleName, actualImportStyles, allowedImportStyles, isRequire = false) => {
154
- if (!allowedImportStyles || allowedImportStyles.size === 0) {
162
+ if (!allowedImportStyles) {
163
+ return;
164
+ }
165
+
166
+ if (allowedImportStyles.size === 0) {
167
+ if (bannedModules.has(moduleName)) {
168
+ context.report({
169
+ node,
170
+ messageId: MESSAGE_ID_BANNED,
171
+ data: {moduleName},
172
+ });
173
+ }
174
+
155
175
  return;
156
176
  }
157
177
 
package/rules/index.js CHANGED
@@ -1,15 +1,18 @@
1
1
  // Generated file, DO NOT edit
2
2
 
3
- export {default as 'better-regex'} from './better-regex.js';
3
+ export {default as 'better-dom-traversing'} from './better-dom-traversing.js';
4
4
  export {default as 'catch-error-name'} from './catch-error-name.js';
5
5
  export {default as 'consistent-assert'} from './consistent-assert.js';
6
+ export {default as 'consistent-compound-words'} from './consistent-compound-words.js';
6
7
  export {default as 'consistent-date-clone'} from './consistent-date-clone.js';
7
8
  export {default as 'consistent-destructuring'} from './consistent-destructuring.js';
8
9
  export {default as 'consistent-empty-array-spread'} from './consistent-empty-array-spread.js';
9
10
  export {default as 'consistent-existence-index-check'} from './consistent-existence-index-check.js';
10
11
  export {default as 'consistent-function-scoping'} from './consistent-function-scoping.js';
12
+ export {default as 'consistent-json-file-read'} from './consistent-json-file-read.js';
11
13
  export {default as 'consistent-template-literal-escape'} from './consistent-template-literal-escape.js';
12
14
  export {default as 'custom-error-definition'} from './custom-error-definition.js';
15
+ export {default as 'dom-node-dataset'} from './dom-node-dataset.js';
13
16
  export {default as 'empty-brace-spaces'} from './empty-brace-spaces.js';
14
17
  export {default as 'error-message'} from './error-message.js';
15
18
  export {default as 'escape-case'} from './escape-case.js';
@@ -23,25 +26,36 @@ export {default as 'no-abusive-eslint-disable'} from './no-abusive-eslint-disabl
23
26
  export {default as 'no-accessor-recursion'} from './no-accessor-recursion.js';
24
27
  export {default as 'no-anonymous-default-export'} from './no-anonymous-default-export.js';
25
28
  export {default as 'no-array-callback-reference'} from './no-array-callback-reference.js';
29
+ export {default as 'no-array-fill-with-reference-type'} from './no-array-fill-with-reference-type.js';
26
30
  export {default as 'no-array-for-each'} from './no-array-for-each.js';
31
+ export {default as 'no-array-from-fill'} from './no-array-from-fill.js';
27
32
  export {default as 'no-array-method-this-argument'} from './no-array-method-this-argument.js';
28
33
  export {default as 'no-array-reduce'} from './no-array-reduce.js';
29
34
  export {default as 'no-array-reverse'} from './no-array-reverse.js';
30
35
  export {default as 'no-array-sort'} from './no-array-sort.js';
31
36
  export {default as 'no-await-expression-member'} from './no-await-expression-member.js';
32
37
  export {default as 'no-await-in-promise-methods'} from './no-await-in-promise-methods.js';
38
+ export {default as 'no-blob-to-file'} from './no-blob-to-file.js';
39
+ export {default as 'no-canvas-to-image'} from './no-canvas-to-image.js';
40
+ export {default as 'no-confusing-array-splice'} from './no-confusing-array-splice.js';
33
41
  export {default as 'no-console-spaces'} from './no-console-spaces.js';
34
42
  export {default as 'no-document-cookie'} from './no-document-cookie.js';
43
+ export {default as 'no-duplicate-set-values'} from './no-duplicate-set-values.js';
35
44
  export {default as 'no-empty-file'} from './no-empty-file.js';
45
+ export {default as 'no-exports-in-scripts'} from './no-exports-in-scripts.js';
36
46
  export {default as 'no-for-loop'} from './no-for-loop.js';
37
47
  export {default as 'no-hex-escape'} from './no-hex-escape.js';
38
48
  export {default as 'no-immediate-mutation'} from './no-immediate-mutation.js';
49
+ export {default as 'no-incorrect-query-selector'} from './no-incorrect-query-selector.js';
39
50
  export {default as 'no-instanceof-builtins'} from './no-instanceof-builtins.js';
40
51
  export {default as 'no-invalid-fetch-options'} from './no-invalid-fetch-options.js';
52
+ export {default as 'no-invalid-file-input-accept'} from './no-invalid-file-input-accept.js';
41
53
  export {default as 'no-invalid-remove-event-listener'} from './no-invalid-remove-event-listener.js';
42
54
  export {default as 'no-keyword-prefix'} from './no-keyword-prefix.js';
55
+ export {default as 'no-late-current-target-access'} from './no-late-current-target-access.js';
43
56
  export {default as 'no-lonely-if'} from './no-lonely-if.js';
44
57
  export {default as 'no-magic-array-flat-depth'} from './no-magic-array-flat-depth.js';
58
+ export {default as 'no-manually-wrapped-comments'} from './no-manually-wrapped-comments.js';
45
59
  export {default as 'no-named-default'} from './no-named-default.js';
46
60
  export {default as 'no-negated-condition'} from './no-negated-condition.js';
47
61
  export {default as 'no-negation-in-equality-check'} from './no-negation-in-equality-check.js';
@@ -55,14 +69,17 @@ export {default as 'no-single-promise-in-promise-methods'} from './no-single-pro
55
69
  export {default as 'no-static-only-class'} from './no-static-only-class.js';
56
70
  export {default as 'no-thenable'} from './no-thenable.js';
57
71
  export {default as 'no-this-assignment'} from './no-this-assignment.js';
72
+ export {default as 'no-this-outside-of-class'} from './no-this-outside-of-class.js';
58
73
  export {default as 'no-typeof-undefined'} from './no-typeof-undefined.js';
59
74
  export {default as 'no-unnecessary-array-flat-depth'} from './no-unnecessary-array-flat-depth.js';
60
75
  export {default as 'no-unnecessary-array-splice-count'} from './no-unnecessary-array-splice-count.js';
61
76
  export {default as 'no-unnecessary-await'} from './no-unnecessary-await.js';
77
+ export {default as 'no-unnecessary-nested-ternary'} from './no-unnecessary-nested-ternary.js';
62
78
  export {default as 'no-unnecessary-polyfills'} from './no-unnecessary-polyfills.js';
63
79
  export {default as 'no-unnecessary-slice-end'} from './no-unnecessary-slice-end.js';
64
80
  export {default as 'no-unreadable-array-destructuring'} from './no-unreadable-array-destructuring.js';
65
81
  export {default as 'no-unreadable-iife'} from './no-unreadable-iife.js';
82
+ export {default as 'no-unused-array-method-return'} from './no-unused-array-method-return.js';
66
83
  export {default as 'no-unused-properties'} from './no-unused-properties.js';
67
84
  export {default as 'no-useless-collection-argument'} from './no-useless-collection-argument.js';
68
85
  export {default as 'no-useless-error-capture-stack-trace'} from './no-useless-error-capture-stack-trace.js';
@@ -81,6 +98,7 @@ export {default as 'prefer-array-find'} from './prefer-array-find.js';
81
98
  export {default as 'prefer-array-flat-map'} from './prefer-array-flat-map.js';
82
99
  export {default as 'prefer-array-flat'} from './prefer-array-flat.js';
83
100
  export {default as 'prefer-array-index-of'} from './prefer-array-index-of.js';
101
+ export {default as 'prefer-array-last-methods'} from './prefer-array-last-methods.js';
84
102
  export {default as 'prefer-array-some'} from './prefer-array-some.js';
85
103
  export {default as 'prefer-at'} from './prefer-at.js';
86
104
  export {default as 'prefer-bigint-literals'} from './prefer-bigint-literals.js';
@@ -91,17 +109,21 @@ export {default as 'prefer-code-point'} from './prefer-code-point.js';
91
109
  export {default as 'prefer-date-now'} from './prefer-date-now.js';
92
110
  export {default as 'prefer-default-parameters'} from './prefer-default-parameters.js';
93
111
  export {default as 'prefer-dom-node-append'} from './prefer-dom-node-append.js';
94
- export {default as 'prefer-dom-node-dataset'} from './prefer-dom-node-dataset.js';
95
112
  export {default as 'prefer-dom-node-remove'} from './prefer-dom-node-remove.js';
96
113
  export {default as 'prefer-dom-node-text-content'} from './prefer-dom-node-text-content.js';
97
114
  export {default as 'prefer-event-target'} from './prefer-event-target.js';
98
115
  export {default as 'prefer-export-from'} from './prefer-export-from.js';
116
+ export {default as 'prefer-get-or-insert-computed'} from './prefer-get-or-insert-computed.js';
99
117
  export {default as 'prefer-global-this'} from './prefer-global-this.js';
118
+ export {default as 'prefer-https'} from './prefer-https.js';
100
119
  export {default as 'prefer-import-meta-properties'} from './prefer-import-meta-properties.js';
120
+ export {default as 'prefer-includes-over-repeated-comparisons'} from './prefer-includes-over-repeated-comparisons.js';
101
121
  export {default as 'prefer-includes'} from './prefer-includes.js';
102
- export {default as 'prefer-json-parse-buffer'} from './prefer-json-parse-buffer.js';
122
+ export {default as 'prefer-iterator-concat'} from './prefer-iterator-concat.js';
123
+ export {default as 'prefer-iterator-to-array-at-end'} from './prefer-iterator-to-array-at-end.js';
103
124
  export {default as 'prefer-keyboard-event-key'} from './prefer-keyboard-event-key.js';
104
125
  export {default as 'prefer-logical-operator-over-ternary'} from './prefer-logical-operator-over-ternary.js';
126
+ export {default as 'prefer-math-abs'} from './prefer-math-abs.js';
105
127
  export {default as 'prefer-math-min-max'} from './prefer-math-min-max.js';
106
128
  export {default as 'prefer-math-trunc'} from './prefer-math-trunc.js';
107
129
  export {default as 'prefer-modern-dom-apis'} from './prefer-modern-dom-apis.js';
@@ -115,6 +137,7 @@ export {default as 'prefer-object-from-entries'} from './prefer-object-from-entr
115
137
  export {default as 'prefer-optional-catch-binding'} from './prefer-optional-catch-binding.js';
116
138
  export {default as 'prefer-prototype-methods'} from './prefer-prototype-methods.js';
117
139
  export {default as 'prefer-query-selector'} from './prefer-query-selector.js';
140
+ export {default as 'prefer-queue-microtask'} from './prefer-queue-microtask.js';
118
141
  export {default as 'prefer-reflect-apply'} from './prefer-reflect-apply.js';
119
142
  export {default as 'prefer-regexp-test'} from './prefer-regexp-test.js';
120
143
  export {default as 'prefer-response-static-json'} from './prefer-response-static-json.js';
@@ -122,8 +145,12 @@ export {default as 'prefer-set-has'} from './prefer-set-has.js';
122
145
  export {default as 'prefer-set-size'} from './prefer-set-size.js';
123
146
  export {default as 'prefer-simple-condition-first'} from './prefer-simple-condition-first.js';
124
147
  export {default as 'prefer-single-call'} from './prefer-single-call.js';
148
+ export {default as 'prefer-split-limit'} from './prefer-split-limit.js';
125
149
  export {default as 'prefer-spread'} from './prefer-spread.js';
150
+ export {default as 'prefer-string-match-all'} from './prefer-string-match-all.js';
151
+ export {default as 'prefer-string-pad-start-end'} from './prefer-string-pad-start-end.js';
126
152
  export {default as 'prefer-string-raw'} from './prefer-string-raw.js';
153
+ export {default as 'prefer-string-repeat'} from './prefer-string-repeat.js';
127
154
  export {default as 'prefer-string-replace-all'} from './prefer-string-replace-all.js';
128
155
  export {default as 'prefer-string-slice'} from './prefer-string-slice.js';
129
156
  export {default as 'prefer-string-starts-ends-with'} from './prefer-string-starts-ends-with.js';
@@ -136,9 +163,11 @@ export {default as 'prefer-type-error'} from './prefer-type-error.js';
136
163
  export {default as 'prevent-abbreviations'} from './prevent-abbreviations.js';
137
164
  export {default as 'relative-url-style'} from './relative-url-style.js';
138
165
  export {default as 'require-array-join-separator'} from './require-array-join-separator.js';
166
+ export {default as 'require-css-escape'} from './require-css-escape.js';
139
167
  export {default as 'require-module-attributes'} from './require-module-attributes.js';
140
168
  export {default as 'require-module-specifiers'} from './require-module-specifiers.js';
141
169
  export {default as 'require-number-to-fixed-digits-argument'} from './require-number-to-fixed-digits-argument.js';
170
+ export {default as 'require-passive-events'} from './require-passive-events.js';
142
171
  export {default as 'require-post-message-target-origin'} from './require-post-message-target-origin.js';
143
172
  export {default as 'string-content'} from './string-content.js';
144
173
  export {default as 'switch-case-braces'} from './switch-case-braces.js';
@@ -146,3 +175,4 @@ export {default as 'switch-case-break-position'} from './switch-case-break-posit
146
175
  export {default as 'template-indent'} from './template-indent.js';
147
176
  export {default as 'text-encoding-identifier-case'} from './text-encoding-identifier-case.js';
148
177
  export {default as 'throw-new-error'} from './throw-new-error.js';
178
+ export {default as 'try-complexity'} from './try-complexity.js';
@@ -53,7 +53,7 @@ const create = context => {
53
53
  }
54
54
 
55
55
  const globalsValue = allowedGlobals[identifier.name];
56
- const isGlobalWritable = globalsValue === true || globalsValue === 'writable' || globalsValue === 'writeable';
56
+ const isGlobalWritable = [true, 'writable', 'writeable'].includes(globalsValue);
57
57
  if (isGlobalWritable) {
58
58
  continue;
59
59
  }
@@ -82,10 +82,12 @@ const create = context => {
82
82
  let commentableNode = node;
83
83
  while (
84
84
  !isComment(previousToken)
85
- && (commentableNode.parent.type === 'VariableDeclarator'
86
- || commentableNode.parent.type === 'VariableDeclaration'
87
- || commentableNode.parent.type === 'ExportNamedDeclaration'
88
- || commentableNode.parent.type === 'ExportDefaultDeclaration')
85
+ && [
86
+ 'VariableDeclarator',
87
+ 'VariableDeclaration',
88
+ 'ExportNamedDeclaration',
89
+ 'ExportDefaultDeclaration',
90
+ ].includes(commentableNode.parent.type)
89
91
  ) {
90
92
  commentableNode = commentableNode.parent;
91
93
  previousToken = sourceCode.getTokenBefore(commentableNode, {includeComments: true});
@@ -23,12 +23,12 @@ const messages = {
23
23
  const isClassKeywordToken = token => token.type === 'Keyword' && token.value === 'class';
24
24
  const isAnonymousClassOrFunction = node =>
25
25
  (
26
- (
27
- node.type === 'FunctionDeclaration'
28
- || node.type === 'FunctionExpression'
29
- || node.type === 'ClassDeclaration'
30
- || node.type === 'ClassExpression'
31
- )
26
+ [
27
+ 'FunctionDeclaration',
28
+ 'FunctionExpression',
29
+ 'ClassDeclaration',
30
+ 'ClassExpression',
31
+ ].includes(node.type)
32
32
  && !node.id
33
33
  )
34
34
  || node.type === 'ArrowFunctionExpression';