eslint-plugin-unicorn-ts 0.0.1-security → 50.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.

Potentially problematic release.


This version of eslint-plugin-unicorn-ts might be problematic. Click here for more details.

Files changed (214) hide show
  1. package/configs/all.js +6 -0
  2. package/configs/flat-config-base.js +10 -0
  3. package/configs/legacy-config-base.js +10 -0
  4. package/configs/recommended.js +117 -0
  5. package/index.js +91 -0
  6. package/license +9 -0
  7. package/package.json +186 -4
  8. package/readme.md +356 -0
  9. package/rules/ast/call-or-new-expression.js +127 -0
  10. package/rules/ast/function-types.js +5 -0
  11. package/rules/ast/index.js +39 -0
  12. package/rules/ast/is-arrow-function-body.js +7 -0
  13. package/rules/ast/is-empty-node.js +20 -0
  14. package/rules/ast/is-expression-statement.js +11 -0
  15. package/rules/ast/is-function.js +8 -0
  16. package/rules/ast/is-member-expression.js +101 -0
  17. package/rules/ast/is-method-call.js +65 -0
  18. package/rules/ast/is-reference-identifier.js +156 -0
  19. package/rules/ast/is-static-require.js +14 -0
  20. package/rules/ast/is-undefined.js +7 -0
  21. package/rules/ast/literal.js +29 -0
  22. package/rules/better-regex.js +144 -0
  23. package/rules/catch-error-name.js +136 -0
  24. package/rules/consistent-destructuring.js +168 -0
  25. package/rules/consistent-function-scoping.js +223 -0
  26. package/rules/custom-error-definition.js +215 -0
  27. package/rules/empty-brace-spaces.js +72 -0
  28. package/rules/error-message.js +104 -0
  29. package/rules/escape-case.js +63 -0
  30. package/rules/expiring-todo-comments.js +580 -0
  31. package/rules/explicit-length-check.js +229 -0
  32. package/rules/filename-case.js +258 -0
  33. package/rules/fix/add-parenthesizes-to-return-or-throw-expression.js +21 -0
  34. package/rules/fix/append-argument.js +20 -0
  35. package/rules/fix/extend-fix-range.js +15 -0
  36. package/rules/fix/fix-space-around-keywords.js +35 -0
  37. package/rules/fix/index.js +23 -0
  38. package/rules/fix/remove-argument.js +32 -0
  39. package/rules/fix/remove-member-expression-property.js +11 -0
  40. package/rules/fix/remove-method-call.js +20 -0
  41. package/rules/fix/remove-parentheses.js +11 -0
  42. package/rules/fix/remove-spaces-after.js +14 -0
  43. package/rules/fix/rename-variable.js +9 -0
  44. package/rules/fix/replace-argument.js +8 -0
  45. package/rules/fix/replace-node-or-token-and-spaces-before.js +21 -0
  46. package/rules/fix/replace-reference-identifier.js +35 -0
  47. package/rules/fix/replace-string-literal.js +11 -0
  48. package/rules/fix/replace-string-raw.js +14 -0
  49. package/rules/fix/replace-template-element.js +11 -0
  50. package/rules/fix/switch-call-expression-to-new-expression.js +18 -0
  51. package/rules/fix/switch-new-expression-to-call-expression.js +34 -0
  52. package/rules/import-style.js +364 -0
  53. package/rules/new-for-builtins.js +85 -0
  54. package/rules/no-abusive-eslint-disable.js +48 -0
  55. package/rules/no-array-callback-reference.js +256 -0
  56. package/rules/no-array-for-each.js +473 -0
  57. package/rules/no-array-method-this-argument.js +188 -0
  58. package/rules/no-array-push-push.js +144 -0
  59. package/rules/no-array-reduce.js +126 -0
  60. package/rules/no-await-expression-member.js +90 -0
  61. package/rules/no-console-spaces.js +86 -0
  62. package/rules/no-document-cookie.js +25 -0
  63. package/rules/no-empty-file.js +57 -0
  64. package/rules/no-for-loop.js +427 -0
  65. package/rules/no-hex-escape.js +46 -0
  66. package/rules/no-instanceof-array.js +65 -0
  67. package/rules/no-invalid-remove-event-listener.js +60 -0
  68. package/rules/no-keyword-prefix.js +199 -0
  69. package/rules/no-lonely-if.js +151 -0
  70. package/rules/no-negated-condition.js +144 -0
  71. package/rules/no-nested-ternary.js +58 -0
  72. package/rules/no-new-array.js +104 -0
  73. package/rules/no-new-buffer.js +98 -0
  74. package/rules/no-null.js +153 -0
  75. package/rules/no-object-as-default-parameter.js +50 -0
  76. package/rules/no-process-exit.js +104 -0
  77. package/rules/no-static-only-class.js +224 -0
  78. package/rules/no-thenable.js +198 -0
  79. package/rules/no-this-assignment.js +38 -0
  80. package/rules/no-typeof-undefined.js +143 -0
  81. package/rules/no-unnecessary-await.js +107 -0
  82. package/rules/no-unnecessary-polyfills.js +176 -0
  83. package/rules/no-unreadable-array-destructuring.js +83 -0
  84. package/rules/no-unreadable-iife.js +45 -0
  85. package/rules/no-unused-properties.js +238 -0
  86. package/rules/no-useless-fallback-in-spread.js +68 -0
  87. package/rules/no-useless-length-check.js +152 -0
  88. package/rules/no-useless-promise-resolve-reject.js +212 -0
  89. package/rules/no-useless-spread.js +381 -0
  90. package/rules/no-useless-switch-case.js +71 -0
  91. package/rules/no-useless-undefined.js +301 -0
  92. package/rules/no-zero-fractions.js +79 -0
  93. package/rules/number-literal-case.js +52 -0
  94. package/rules/numeric-separators-style.js +181 -0
  95. package/rules/prefer-add-event-listener.js +188 -0
  96. package/rules/prefer-array-find.js +423 -0
  97. package/rules/prefer-array-flat-map.js +82 -0
  98. package/rules/prefer-array-flat.js +279 -0
  99. package/rules/prefer-array-index-of.js +32 -0
  100. package/rules/prefer-array-some.js +157 -0
  101. package/rules/prefer-at.js +374 -0
  102. package/rules/prefer-blob-reading-methods.js +45 -0
  103. package/rules/prefer-code-point.js +67 -0
  104. package/rules/prefer-date-now.js +135 -0
  105. package/rules/prefer-default-parameters.js +219 -0
  106. package/rules/prefer-dom-node-append.js +48 -0
  107. package/rules/prefer-dom-node-dataset.js +120 -0
  108. package/rules/prefer-dom-node-remove.js +122 -0
  109. package/rules/prefer-dom-node-text-content.js +75 -0
  110. package/rules/prefer-event-target.js +117 -0
  111. package/rules/prefer-export-from.js +413 -0
  112. package/rules/prefer-includes.js +98 -0
  113. package/rules/prefer-json-parse-buffer.js +159 -0
  114. package/rules/prefer-keyboard-event-key.js +186 -0
  115. package/rules/prefer-logical-operator-over-ternary.js +159 -0
  116. package/rules/prefer-math-trunc.js +109 -0
  117. package/rules/prefer-modern-dom-apis.js +141 -0
  118. package/rules/prefer-modern-math-apis.js +212 -0
  119. package/rules/prefer-module.js +349 -0
  120. package/rules/prefer-native-coercion-functions.js +185 -0
  121. package/rules/prefer-negative-index.js +213 -0
  122. package/rules/prefer-node-protocol.js +61 -0
  123. package/rules/prefer-number-properties.js +126 -0
  124. package/rules/prefer-object-from-entries.js +252 -0
  125. package/rules/prefer-optional-catch-binding.js +75 -0
  126. package/rules/prefer-prototype-methods.js +88 -0
  127. package/rules/prefer-query-selector.js +135 -0
  128. package/rules/prefer-reflect-apply.js +97 -0
  129. package/rules/prefer-regexp-test.js +156 -0
  130. package/rules/prefer-set-has.js +186 -0
  131. package/rules/prefer-set-size.js +103 -0
  132. package/rules/prefer-spread.js +529 -0
  133. package/rules/prefer-string-replace-all.js +145 -0
  134. package/rules/prefer-string-slice.js +182 -0
  135. package/rules/prefer-string-starts-ends-with.js +199 -0
  136. package/rules/prefer-string-trim-start-end.js +44 -0
  137. package/rules/prefer-switch.js +344 -0
  138. package/rules/prefer-ternary.js +282 -0
  139. package/rules/prefer-top-level-await.js +152 -0
  140. package/rules/prefer-type-error.js +151 -0
  141. package/rules/prevent-abbreviations.js +645 -0
  142. package/rules/relative-url-style.js +168 -0
  143. package/rules/require-array-join-separator.js +63 -0
  144. package/rules/require-number-to-fixed-digits-argument.js +54 -0
  145. package/rules/require-post-message-target-origin.js +71 -0
  146. package/rules/shared/abbreviations.js +262 -0
  147. package/rules/shared/dom-events.js +275 -0
  148. package/rules/shared/event-keys.js +52 -0
  149. package/rules/shared/negative-index.js +46 -0
  150. package/rules/shared/simple-array-search-rule.js +128 -0
  151. package/rules/shared/typed-array.js +16 -0
  152. package/rules/string-content.js +187 -0
  153. package/rules/switch-case-braces.js +109 -0
  154. package/rules/template-indent.js +219 -0
  155. package/rules/text-encoding-identifier-case.js +108 -0
  156. package/rules/throw-new-error.js +53 -0
  157. package/rules/utils/array-or-object-prototype-property.js +63 -0
  158. package/rules/utils/assert-token.js +32 -0
  159. package/rules/utils/avoid-capture.js +146 -0
  160. package/rules/utils/boolean.js +92 -0
  161. package/rules/utils/builtins.js +36 -0
  162. package/rules/utils/cartesian-product-samples.js +24 -0
  163. package/rules/utils/create-deprecated-rules.js +25 -0
  164. package/rules/utils/escape-string.js +26 -0
  165. package/rules/utils/escape-template-element-raw.js +6 -0
  166. package/rules/utils/get-ancestor.js +20 -0
  167. package/rules/utils/get-builtin-rule.js +7 -0
  168. package/rules/utils/get-call-expression-arguments-text.js +21 -0
  169. package/rules/utils/get-class-head-location.js +22 -0
  170. package/rules/utils/get-documentation-url.js +10 -0
  171. package/rules/utils/get-indent-string.js +11 -0
  172. package/rules/utils/get-previous-node.js +24 -0
  173. package/rules/utils/get-references.js +9 -0
  174. package/rules/utils/get-scopes.js +14 -0
  175. package/rules/utils/get-switch-case-head-location.js +21 -0
  176. package/rules/utils/get-variable-identifiers.js +7 -0
  177. package/rules/utils/global-reference-tracker.js +72 -0
  178. package/rules/utils/has-optional-chain-element.js +21 -0
  179. package/rules/utils/has-same-range.js +7 -0
  180. package/rules/utils/index.js +53 -0
  181. package/rules/utils/is-function-self-used-inside.js +43 -0
  182. package/rules/utils/is-left-hand-side.js +22 -0
  183. package/rules/utils/is-logical-expression.js +16 -0
  184. package/rules/utils/is-method-named.js +9 -0
  185. package/rules/utils/is-new-expression-with-parentheses.js +26 -0
  186. package/rules/utils/is-node-matches.js +53 -0
  187. package/rules/utils/is-node-value-not-dom-node.js +21 -0
  188. package/rules/utils/is-node-value-not-function.js +42 -0
  189. package/rules/utils/is-number.js +224 -0
  190. package/rules/utils/is-object-method.js +11 -0
  191. package/rules/utils/is-on-same-line.js +7 -0
  192. package/rules/utils/is-same-identifier.js +8 -0
  193. package/rules/utils/is-same-reference.js +173 -0
  194. package/rules/utils/is-shadowed.js +33 -0
  195. package/rules/utils/is-shorthand-export-local.js +9 -0
  196. package/rules/utils/is-shorthand-import-local.js +9 -0
  197. package/rules/utils/is-shorthand-property-assignment-pattern-left.js +10 -0
  198. package/rules/utils/is-shorthand-property-value.js +8 -0
  199. package/rules/utils/is-value-not-usable.js +5 -0
  200. package/rules/utils/lodash.js +1589 -0
  201. package/rules/utils/needs-semicolon.js +114 -0
  202. package/rules/utils/numeric.js +53 -0
  203. package/rules/utils/parentheses.js +73 -0
  204. package/rules/utils/resolve-variable-name.js +20 -0
  205. package/rules/utils/rule.js +190 -0
  206. package/rules/utils/should-add-parentheses-to-conditional-expression-child.js +17 -0
  207. package/rules/utils/should-add-parentheses-to-expression-statement-expression.js +26 -0
  208. package/rules/utils/should-add-parentheses-to-logical-expression-child.js +47 -0
  209. package/rules/utils/should-add-parentheses-to-member-expression-object.js +47 -0
  210. package/rules/utils/should-add-parentheses-to-new-expression-callee.js +32 -0
  211. package/rules/utils/should-add-parentheses-to-spread-element-argument.js +22 -0
  212. package/rules/utils/singular.js +18 -0
  213. package/rules/utils/to-location.js +21 -0
  214. package/README.md +0 -5
@@ -0,0 +1,645 @@
1
+ 'use strict';
2
+ const path = require('node:path');
3
+ const {defaultsDeep, upperFirst, lowerFirst} = require('./utils/lodash.js');
4
+ const avoidCapture = require('./utils/avoid-capture.js');
5
+ const cartesianProductSamples = require('./utils/cartesian-product-samples.js');
6
+ const isShorthandPropertyValue = require('./utils/is-shorthand-property-value.js');
7
+ const isShorthandImportLocal = require('./utils/is-shorthand-import-local.js');
8
+ const getVariableIdentifiers = require('./utils/get-variable-identifiers.js');
9
+ const {defaultReplacements, defaultAllowList, defaultIgnore} = require('./shared/abbreviations.js');
10
+ const {renameVariable} = require('./fix/index.js');
11
+ const getScopes = require('./utils/get-scopes.js');
12
+ const {isStaticRequire} = require('./ast/index.js');
13
+
14
+ const MESSAGE_ID_REPLACE = 'replace';
15
+ const MESSAGE_ID_SUGGESTION = 'suggestion';
16
+ const anotherNameMessage = 'A more descriptive name will do too.';
17
+ const messages = {
18
+ [MESSAGE_ID_REPLACE]: `The {{nameTypeText}} \`{{discouragedName}}\` should be named \`{{replacement}}\`. ${anotherNameMessage}`,
19
+ [MESSAGE_ID_SUGGESTION]: `Please rename the {{nameTypeText}} \`{{discouragedName}}\`. Suggested names are: {{replacementsText}}. ${anotherNameMessage}`,
20
+ };
21
+
22
+ const isUpperCase = string => string === string.toUpperCase();
23
+ const isUpperFirst = string => isUpperCase(string[0]);
24
+
25
+ const prepareOptions = ({
26
+ checkProperties = false,
27
+ checkVariables = true,
28
+
29
+ checkDefaultAndNamespaceImports = 'internal',
30
+ checkShorthandImports = 'internal',
31
+ checkShorthandProperties = false,
32
+
33
+ checkFilenames = true,
34
+
35
+ extendDefaultReplacements = true,
36
+ replacements = {},
37
+
38
+ extendDefaultAllowList = true,
39
+ allowList = {},
40
+
41
+ ignore = [],
42
+ } = {}) => {
43
+ const mergedReplacements = extendDefaultReplacements
44
+ ? defaultsDeep({}, replacements, defaultReplacements)
45
+ : replacements;
46
+
47
+ const mergedAllowList = extendDefaultAllowList
48
+ ? defaultsDeep({}, allowList, defaultAllowList)
49
+ : allowList;
50
+
51
+ ignore = [...defaultIgnore, ...ignore];
52
+
53
+ ignore = ignore.map(
54
+ pattern => pattern instanceof RegExp ? pattern : new RegExp(pattern, 'u'),
55
+ );
56
+
57
+ return {
58
+ checkProperties,
59
+ checkVariables,
60
+
61
+ checkDefaultAndNamespaceImports,
62
+ checkShorthandImports,
63
+ checkShorthandProperties,
64
+
65
+ checkFilenames,
66
+
67
+ replacements: new Map(
68
+ Object.entries(mergedReplacements).map(
69
+ ([discouragedName, replacements]) =>
70
+ [discouragedName, new Map(Object.entries(replacements))],
71
+ ),
72
+ ),
73
+ allowList: new Map(Object.entries(mergedAllowList)),
74
+
75
+ ignore,
76
+ };
77
+ };
78
+
79
+ const getWordReplacements = (word, {replacements, allowList}) => {
80
+ // Skip constants and allowList
81
+ if (isUpperCase(word) || allowList.get(word)) {
82
+ return [];
83
+ }
84
+
85
+ const replacement = replacements.get(lowerFirst(word))
86
+ || replacements.get(word)
87
+ || replacements.get(upperFirst(word));
88
+
89
+ let wordReplacement = [];
90
+ if (replacement) {
91
+ const transform = isUpperFirst(word) ? upperFirst : lowerFirst;
92
+ wordReplacement = [...replacement.keys()]
93
+ .filter(name => replacement.get(name))
94
+ .map(name => transform(name));
95
+ }
96
+
97
+ return wordReplacement.length > 0 ? wordReplacement.sort() : [];
98
+ };
99
+
100
+ const getNameReplacements = (name, options, limit = 3) => {
101
+ const {allowList, ignore} = options;
102
+
103
+ // Skip constants and allowList
104
+ if (isUpperCase(name) || allowList.get(name) || ignore.some(regexp => regexp.test(name))) {
105
+ return {total: 0};
106
+ }
107
+
108
+ // Find exact replacements
109
+ const exactReplacements = getWordReplacements(name, options);
110
+
111
+ if (exactReplacements.length > 0) {
112
+ return {
113
+ total: exactReplacements.length,
114
+ samples: exactReplacements.slice(0, limit),
115
+ };
116
+ }
117
+
118
+ // Split words
119
+ const words = name.split(/(?=[^a-z])|(?<=[^A-Za-z])/).filter(Boolean);
120
+
121
+ let hasReplacements = false;
122
+ const combinations = words.map(word => {
123
+ const wordReplacements = getWordReplacements(word, options);
124
+
125
+ if (wordReplacements.length > 0) {
126
+ hasReplacements = true;
127
+ return wordReplacements;
128
+ }
129
+
130
+ return [word];
131
+ });
132
+
133
+ // No replacements for any word
134
+ if (!hasReplacements) {
135
+ return {total: 0};
136
+ }
137
+
138
+ const {
139
+ total,
140
+ samples,
141
+ } = cartesianProductSamples(combinations, limit);
142
+
143
+ // `retVal` -> `['returnValue', 'Value']` -> `['returnValue']`
144
+ for (const parts of samples) {
145
+ for (let index = parts.length - 1; index > 0; index--) {
146
+ const word = parts[index];
147
+ if (/^[A-Za-z]+$/.test(word) && parts[index - 1].endsWith(parts[index])) {
148
+ parts.splice(index, 1);
149
+ }
150
+ }
151
+ }
152
+
153
+ return {
154
+ total,
155
+ samples: samples.map(words => words.join('')),
156
+ };
157
+ };
158
+
159
+ const getMessage = (discouragedName, replacements, nameTypeText) => {
160
+ const {total, samples = []} = replacements;
161
+
162
+ if (total === 1) {
163
+ return {
164
+ messageId: MESSAGE_ID_REPLACE,
165
+ data: {
166
+ nameTypeText,
167
+ discouragedName,
168
+ replacement: samples[0],
169
+ },
170
+ };
171
+ }
172
+
173
+ let replacementsText = samples
174
+ .map(replacement => `\`${replacement}\``)
175
+ .join(', ');
176
+
177
+ const omittedReplacementsCount = total - samples.length;
178
+ if (omittedReplacementsCount > 0) {
179
+ replacementsText += `, ... (${omittedReplacementsCount > 99 ? '99+' : omittedReplacementsCount} more omitted)`;
180
+ }
181
+
182
+ return {
183
+ messageId: MESSAGE_ID_SUGGESTION,
184
+ data: {
185
+ nameTypeText,
186
+ discouragedName,
187
+ replacementsText,
188
+ },
189
+ };
190
+ };
191
+
192
+ const isExportedIdentifier = identifier => {
193
+ if (
194
+ identifier.parent.type === 'VariableDeclarator'
195
+ && identifier.parent.id === identifier
196
+ ) {
197
+ return (
198
+ identifier.parent.parent.type === 'VariableDeclaration'
199
+ && identifier.parent.parent.parent.type === 'ExportNamedDeclaration'
200
+ );
201
+ }
202
+
203
+ if (
204
+ identifier.parent.type === 'FunctionDeclaration'
205
+ && identifier.parent.id === identifier
206
+ ) {
207
+ return identifier.parent.parent.type === 'ExportNamedDeclaration';
208
+ }
209
+
210
+ if (
211
+ identifier.parent.type === 'ClassDeclaration'
212
+ && identifier.parent.id === identifier
213
+ ) {
214
+ return identifier.parent.parent.type === 'ExportNamedDeclaration';
215
+ }
216
+
217
+ if (
218
+ identifier.parent.type === 'TSTypeAliasDeclaration'
219
+ && identifier.parent.id === identifier
220
+ ) {
221
+ return identifier.parent.parent.type === 'ExportNamedDeclaration';
222
+ }
223
+
224
+ return false;
225
+ };
226
+
227
+ const shouldFix = variable => getVariableIdentifiers(variable)
228
+ .every(identifier =>
229
+ !isExportedIdentifier(identifier)
230
+ // In typescript parser, only `JSXOpeningElement` is added to variable
231
+ // `<foo></foo>` -> `<bar></foo>` will cause parse error
232
+ && identifier.type !== 'JSXIdentifier',
233
+ );
234
+
235
+ const isDefaultOrNamespaceImportName = identifier => {
236
+ if (
237
+ identifier.parent.type === 'ImportDefaultSpecifier'
238
+ && identifier.parent.local === identifier
239
+ ) {
240
+ return true;
241
+ }
242
+
243
+ if (
244
+ identifier.parent.type === 'ImportNamespaceSpecifier'
245
+ && identifier.parent.local === identifier
246
+ ) {
247
+ return true;
248
+ }
249
+
250
+ if (
251
+ identifier.parent.type === 'ImportSpecifier'
252
+ && identifier.parent.local === identifier
253
+ && identifier.parent.imported.type === 'Identifier'
254
+ && identifier.parent.imported.name === 'default'
255
+ ) {
256
+ return true;
257
+ }
258
+
259
+ if (
260
+ identifier.parent.type === 'VariableDeclarator'
261
+ && identifier.parent.id === identifier
262
+ && isStaticRequire(identifier.parent.init)
263
+ ) {
264
+ return true;
265
+ }
266
+
267
+ return false;
268
+ };
269
+
270
+ const isClassVariable = variable => {
271
+ if (variable.defs.length !== 1) {
272
+ return false;
273
+ }
274
+
275
+ const [definition] = variable.defs;
276
+
277
+ return definition.type === 'ClassName';
278
+ };
279
+
280
+ const shouldReportIdentifierAsProperty = identifier => {
281
+ if (
282
+ identifier.parent.type === 'MemberExpression'
283
+ && identifier.parent.property === identifier
284
+ && !identifier.parent.computed
285
+ && identifier.parent.parent.type === 'AssignmentExpression'
286
+ && identifier.parent.parent.left === identifier.parent
287
+ ) {
288
+ return true;
289
+ }
290
+
291
+ if (
292
+ identifier.parent.type === 'Property'
293
+ && identifier.parent.key === identifier
294
+ && !identifier.parent.computed
295
+ && !identifier.parent.shorthand // Shorthand properties are reported and fixed as variables
296
+ && identifier.parent.parent.type === 'ObjectExpression'
297
+ ) {
298
+ return true;
299
+ }
300
+
301
+ if (
302
+ identifier.parent.type === 'ExportSpecifier'
303
+ && identifier.parent.exported === identifier
304
+ && identifier.parent.local !== identifier // Same as shorthand properties above
305
+ ) {
306
+ return true;
307
+ }
308
+
309
+ if (
310
+ (
311
+ identifier.parent.type === 'MethodDefinition'
312
+ || identifier.parent.type === 'PropertyDefinition'
313
+ )
314
+ && identifier.parent.key === identifier
315
+ && !identifier.parent.computed
316
+ ) {
317
+ return true;
318
+ }
319
+
320
+ return false;
321
+ };
322
+
323
+ const isInternalImport = node => {
324
+ let source = '';
325
+
326
+ if (node.type === 'Variable') {
327
+ source = node.node.init.arguments[0].value;
328
+ } else if (node.type === 'ImportBinding') {
329
+ source = node.parent.source.value;
330
+ }
331
+
332
+ return (
333
+ !source.includes('node_modules')
334
+ && (source.startsWith('.') || source.startsWith('/'))
335
+ );
336
+ };
337
+
338
+ /** @param {import('eslint').Rule.RuleContext} context */
339
+ const create = context => {
340
+ const options = prepareOptions(context.options[0]);
341
+ const filenameWithExtension = context.physicalFilename;
342
+
343
+ // A `class` declaration produces two variables in two scopes:
344
+ // the inner class scope, and the outer one (wherever the class is declared).
345
+ // This map holds the outer ones to be later processed when the inner one is encountered.
346
+ // For why this is not a eslint issue see https://github.com/eslint/eslint-scope/issues/48#issuecomment-464358754
347
+ const identifierToOuterClassVariable = new WeakMap();
348
+
349
+ const checkPossiblyWeirdClassVariable = variable => {
350
+ if (isClassVariable(variable)) {
351
+ if (variable.scope.type === 'class') { // The inner class variable
352
+ const [definition] = variable.defs;
353
+ const outerClassVariable = identifierToOuterClassVariable.get(definition.name);
354
+
355
+ if (!outerClassVariable) {
356
+ return checkVariable(variable);
357
+ }
358
+
359
+ // Create a normal-looking variable (like a `var` or a `function`)
360
+ // For which a single `variable` holds all references, unlike with a `class`
361
+ const combinedReferencesVariable = {
362
+ name: variable.name,
363
+ scope: variable.scope,
364
+ defs: variable.defs,
365
+ identifiers: variable.identifiers,
366
+ references: [...variable.references, ...outerClassVariable.references],
367
+ };
368
+
369
+ // Call the common checker with the newly forged normalized class variable
370
+ return checkVariable(combinedReferencesVariable);
371
+ }
372
+
373
+ // The outer class variable, we save it for later, when it's inner counterpart is encountered
374
+ const [definition] = variable.defs;
375
+ identifierToOuterClassVariable.set(definition.name, variable);
376
+
377
+ return;
378
+ }
379
+
380
+ return checkVariable(variable);
381
+ };
382
+
383
+ // Holds a map from a `Scope` to a `Set` of new variable names generated by our fixer.
384
+ // Used to avoid generating duplicate names, see for instance `let errCb, errorCb` test.
385
+ const scopeToNamesGeneratedByFixer = new WeakMap();
386
+ const isSafeName = (name, scopes) => scopes.every(scope => {
387
+ const generatedNames = scopeToNamesGeneratedByFixer.get(scope);
388
+ return !generatedNames || !generatedNames.has(name);
389
+ });
390
+
391
+ const checkVariable = variable => {
392
+ if (variable.defs.length === 0) {
393
+ return;
394
+ }
395
+
396
+ const [definition] = variable.defs;
397
+
398
+ if (isDefaultOrNamespaceImportName(definition.name)) {
399
+ if (!options.checkDefaultAndNamespaceImports) {
400
+ return;
401
+ }
402
+
403
+ if (
404
+ options.checkDefaultAndNamespaceImports === 'internal'
405
+ && !isInternalImport(definition)
406
+ ) {
407
+ return;
408
+ }
409
+ }
410
+
411
+ if (isShorthandImportLocal(definition.name)) {
412
+ if (!options.checkShorthandImports) {
413
+ return;
414
+ }
415
+
416
+ if (
417
+ options.checkShorthandImports === 'internal'
418
+ && !isInternalImport(definition)
419
+ ) {
420
+ return;
421
+ }
422
+ }
423
+
424
+ if (
425
+ !options.checkShorthandProperties
426
+ && isShorthandPropertyValue(definition.name)
427
+ ) {
428
+ return;
429
+ }
430
+
431
+ const variableReplacements = getNameReplacements(variable.name, options);
432
+
433
+ if (variableReplacements.total === 0) {
434
+ return;
435
+ }
436
+
437
+ const scopes = [
438
+ ...variable.references.map(reference => reference.from),
439
+ variable.scope,
440
+ ];
441
+ variableReplacements.samples = variableReplacements.samples.map(
442
+ name => avoidCapture(name, scopes, isSafeName),
443
+ );
444
+
445
+ const problem = {
446
+ ...getMessage(definition.name.name, variableReplacements, 'variable'),
447
+ node: definition.name,
448
+ };
449
+
450
+ if (
451
+ variableReplacements.total === 1
452
+ && shouldFix(variable)
453
+ && variableReplacements.samples[0]
454
+ && !variable.references.some(reference => reference.vueUsedInTemplate)
455
+ ) {
456
+ const [replacement] = variableReplacements.samples;
457
+
458
+ for (const scope of scopes) {
459
+ if (!scopeToNamesGeneratedByFixer.has(scope)) {
460
+ scopeToNamesGeneratedByFixer.set(scope, new Set());
461
+ }
462
+
463
+ const generatedNames = scopeToNamesGeneratedByFixer.get(scope);
464
+ generatedNames.add(replacement);
465
+ }
466
+
467
+ problem.fix = fixer => renameVariable(variable, replacement, fixer);
468
+ }
469
+
470
+ context.report(problem);
471
+ };
472
+
473
+ const checkVariables = scope => {
474
+ for (const variable of scope.variables) {
475
+ checkPossiblyWeirdClassVariable(variable);
476
+ }
477
+ };
478
+
479
+ const checkScope = scope => {
480
+ const scopes = getScopes(scope);
481
+ for (const scope of scopes) {
482
+ checkVariables(scope);
483
+ }
484
+ };
485
+
486
+ return {
487
+ Identifier(node) {
488
+ if (!options.checkProperties) {
489
+ return;
490
+ }
491
+
492
+ if (node.name === '__proto__') {
493
+ return;
494
+ }
495
+
496
+ const identifierReplacements = getNameReplacements(node.name, options);
497
+
498
+ if (identifierReplacements.total === 0) {
499
+ return;
500
+ }
501
+
502
+ if (!shouldReportIdentifierAsProperty(node)) {
503
+ return;
504
+ }
505
+
506
+ const problem = {
507
+ ...getMessage(node.name, identifierReplacements, 'property'),
508
+ node,
509
+ };
510
+
511
+ context.report(problem);
512
+ },
513
+
514
+ Program(node) {
515
+ if (!options.checkFilenames) {
516
+ return;
517
+ }
518
+
519
+ if (
520
+ filenameWithExtension === '<input>'
521
+ || filenameWithExtension === '<text>'
522
+ ) {
523
+ return;
524
+ }
525
+
526
+ const filename = path.basename(filenameWithExtension);
527
+ const extension = path.extname(filename);
528
+ const filenameReplacements = getNameReplacements(path.basename(filename, extension), options);
529
+
530
+ if (filenameReplacements.total === 0) {
531
+ return;
532
+ }
533
+
534
+ filenameReplacements.samples = filenameReplacements.samples.map(replacement => `${replacement}${extension}`);
535
+
536
+ context.report({
537
+ ...getMessage(filename, filenameReplacements, 'filename'),
538
+ node,
539
+ });
540
+ },
541
+
542
+ 'Program:exit'(program) {
543
+ if (!options.checkVariables) {
544
+ return;
545
+ }
546
+
547
+ checkScope(context.sourceCode.getScope(program));
548
+ },
549
+ };
550
+ };
551
+
552
+ const schema = {
553
+ type: 'array',
554
+ additionalItems: false,
555
+ items: [
556
+ {
557
+ type: 'object',
558
+ additionalProperties: false,
559
+ properties: {
560
+ checkProperties: {
561
+ type: 'boolean',
562
+ },
563
+ checkVariables: {
564
+ type: 'boolean',
565
+ },
566
+ checkDefaultAndNamespaceImports: {
567
+ type: [
568
+ 'boolean',
569
+ 'string',
570
+ ],
571
+ pattern: 'internal',
572
+ },
573
+ checkShorthandImports: {
574
+ type: [
575
+ 'boolean',
576
+ 'string',
577
+ ],
578
+ pattern: 'internal',
579
+ },
580
+ checkShorthandProperties: {
581
+ type: 'boolean',
582
+ },
583
+ checkFilenames: {
584
+ type: 'boolean',
585
+ },
586
+ extendDefaultReplacements: {
587
+ type: 'boolean',
588
+ },
589
+ replacements: {
590
+ $ref: '#/definitions/abbreviations',
591
+ },
592
+ extendDefaultAllowList: {
593
+ type: 'boolean',
594
+ },
595
+ allowList: {
596
+ $ref: '#/definitions/booleanObject',
597
+ },
598
+ ignore: {
599
+ type: 'array',
600
+ uniqueItems: true,
601
+ },
602
+ },
603
+ },
604
+ ],
605
+ definitions: {
606
+ abbreviations: {
607
+ type: 'object',
608
+ additionalProperties: {
609
+ $ref: '#/definitions/replacements',
610
+ },
611
+ },
612
+ replacements: {
613
+ anyOf: [
614
+ {
615
+ enum: [
616
+ false,
617
+ ],
618
+ },
619
+ {
620
+ $ref: '#/definitions/booleanObject',
621
+ },
622
+ ],
623
+ },
624
+ booleanObject: {
625
+ type: 'object',
626
+ additionalProperties: {
627
+ type: 'boolean',
628
+ },
629
+ },
630
+ },
631
+ };
632
+
633
+ /** @type {import('eslint').Rule.RuleModule} */
634
+ module.exports = {
635
+ create,
636
+ meta: {
637
+ type: 'suggestion',
638
+ docs: {
639
+ description: 'Prevent abbreviations.',
640
+ },
641
+ fixable: 'code',
642
+ schema,
643
+ messages,
644
+ },
645
+ };