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,146 @@
1
+ 'use strict';
2
+ const {
3
+ isIdentifierName,
4
+ isStrictReservedWord,
5
+ isKeyword,
6
+ } = require('@babel/helper-validator-identifier');
7
+ const resolveVariableName = require('./resolve-variable-name.js');
8
+ const getReferences = require('./get-references.js');
9
+
10
+ // https://github.com/microsoft/TypeScript/issues/2536#issuecomment-87194347
11
+ const typescriptReservedWords = new Set([
12
+ 'break',
13
+ 'case',
14
+ 'catch',
15
+ 'class',
16
+ 'const',
17
+ 'continue',
18
+ 'debugger',
19
+ 'default',
20
+ 'delete',
21
+ 'do',
22
+ 'else',
23
+ 'enum',
24
+ 'export',
25
+ 'extends',
26
+ 'false',
27
+ 'finally',
28
+ 'for',
29
+ 'function',
30
+ 'if',
31
+ 'import',
32
+ 'in',
33
+ 'instanceof',
34
+ 'new',
35
+ 'null',
36
+ 'return',
37
+ 'super',
38
+ 'switch',
39
+ 'this',
40
+ 'throw',
41
+ 'true',
42
+ 'try',
43
+ 'typeof',
44
+ 'var',
45
+ 'void',
46
+ 'while',
47
+ 'with',
48
+ 'as',
49
+ 'implements',
50
+ 'interface',
51
+ 'let',
52
+ 'package',
53
+ 'private',
54
+ 'protected',
55
+ 'public',
56
+ 'static',
57
+ 'yield',
58
+ 'any',
59
+ 'boolean',
60
+ 'constructor',
61
+ 'declare',
62
+ 'get',
63
+ 'module',
64
+ 'require',
65
+ 'number',
66
+ 'set',
67
+ 'string',
68
+ 'symbol',
69
+ 'type',
70
+ 'from',
71
+ 'of',
72
+ ]);
73
+
74
+ // Copied from https://github.com/babel/babel/blob/fce35af69101c6b316557e28abf60bdbf77d6a36/packages/babel-types/src/validators/isValidIdentifier.ts#L7
75
+ // Use this function instead of `require('@babel/types').isIdentifier`, since `@babel/helper-validator-identifier` package is much smaller
76
+ const isValidIdentifier = name =>
77
+ typeof name === 'string'
78
+ && !isKeyword(name)
79
+ && !isStrictReservedWord(name, true)
80
+ && isIdentifierName(name)
81
+ && name !== 'arguments'
82
+ && !typescriptReservedWords.has(name);
83
+
84
+ /*
85
+ Unresolved reference is probably from the global scope. We should avoid using that name.
86
+
87
+ For example, like `foo` and `bar` below.
88
+
89
+ ```
90
+ function unicorn() {
91
+ return foo;
92
+ }
93
+
94
+ function unicorn() {
95
+ return function() {
96
+ return bar;
97
+ };
98
+ }
99
+ ```
100
+ */
101
+ const isUnresolvedName = (name, scope) =>
102
+ getReferences(scope).some(({identifier, resolved}) => identifier?.name === name && !resolved);
103
+
104
+ const isSafeName = (name, scopes) =>
105
+ !scopes.some(scope => resolveVariableName(name, scope) || isUnresolvedName(name, scope));
106
+
107
+ const alwaysTrue = () => true;
108
+
109
+ /**
110
+ Rule-specific name check function.
111
+
112
+ @callback isSafe
113
+ @param {string} name - The generated candidate name.
114
+ @param {Scope[]} scopes - The same list of scopes you pass to `avoidCapture`.
115
+ @returns {boolean} - `true` if the `name` is ok.
116
+ */
117
+
118
+ /**
119
+ Generates a unique name prefixed with `name` such that:
120
+ - it is not defined in any of the `scopes`,
121
+ - it is not a reserved word,
122
+ - it is not `arguments` in strict scopes (where `arguments` is not allowed),
123
+ - it does not collide with the actual `arguments` (which is always defined in function scopes).
124
+
125
+ Useful when you want to rename a variable (or create a new variable) while being sure not to shadow any other variables in the code.
126
+
127
+ @param {string} name - The desired name for a new variable.
128
+ @param {Scope[]} scopes - The list of scopes the new variable will be referenced in.
129
+ @param {isSafe} [isSafe] - Rule-specific name check function.
130
+ @returns {string} - Either `name` as is, or a string like `${name}_` suffixed with underscores to make the name unique.
131
+ */
132
+ module.exports = (name, scopes, isSafe = alwaysTrue) => {
133
+ if (!isValidIdentifier(name)) {
134
+ name += '_';
135
+
136
+ if (!isValidIdentifier(name)) {
137
+ return;
138
+ }
139
+ }
140
+
141
+ while (!isSafeName(name, scopes) || !isSafe(name, scopes)) {
142
+ name += '_';
143
+ }
144
+
145
+ return name;
146
+ };
@@ -0,0 +1,92 @@
1
+ 'use strict';
2
+
3
+ const isLogicalExpression = require('./is-logical-expression.js');
4
+
5
+ const isLogicNot = node => node?.type === 'UnaryExpression' && node.operator === '!';
6
+ const isLogicNotArgument = node => isLogicNot(node.parent) && node.parent.argument === node;
7
+ const isBooleanCallArgument = node => isBooleanCall(node.parent) && node.parent.arguments[0] === node;
8
+ const isBooleanCall = node =>
9
+ node?.type === 'CallExpression'
10
+ && node.callee.type === 'Identifier'
11
+ && node.callee.name === 'Boolean'
12
+ && node.arguments.length === 1;
13
+ const isVueBooleanAttributeValue = node =>
14
+ node?.type === 'VExpressionContainer'
15
+ && node.parent.type === 'VAttribute'
16
+ && node.parent.directive
17
+ && node.parent.value === node
18
+ && node.parent.key.type === 'VDirectiveKey'
19
+ && node.parent.key.name.type === 'VIdentifier'
20
+ && (
21
+ node.parent.key.name.rawName === 'if'
22
+ || node.parent.key.name.rawName === 'else-if'
23
+ || node.parent.key.name.rawName === 'show'
24
+ );
25
+
26
+ /**
27
+ Check if the value of node is a `boolean`.
28
+
29
+ @param {Node} node
30
+ @returns {boolean}
31
+ */
32
+ function isBooleanNode(node) {
33
+ if (
34
+ isLogicNot(node)
35
+ || isLogicNotArgument(node)
36
+ || isBooleanCall(node)
37
+ || isBooleanCallArgument(node)
38
+ ) {
39
+ return true;
40
+ }
41
+
42
+ const {parent} = node;
43
+ if (isVueBooleanAttributeValue(parent)) {
44
+ return true;
45
+ }
46
+
47
+ if (
48
+ (
49
+ parent.type === 'IfStatement'
50
+ || parent.type === 'ConditionalExpression'
51
+ || parent.type === 'WhileStatement'
52
+ || parent.type === 'DoWhileStatement'
53
+ || parent.type === 'ForStatement'
54
+ )
55
+ && parent.test === node
56
+ ) {
57
+ return true;
58
+ }
59
+
60
+ if (isLogicalExpression(parent)) {
61
+ return isBooleanNode(parent);
62
+ }
63
+
64
+ return false;
65
+ }
66
+
67
+ /**
68
+ Get the boolean type-casting ancestor.
69
+
70
+ @typedef {{ node: Node, isNegative: boolean }} Result
71
+
72
+ @param {Node} node
73
+ @returns {Result}
74
+ */
75
+ function getBooleanAncestor(node) {
76
+ let isNegative = false;
77
+ // eslint-disable-next-line no-constant-condition
78
+ while (true) {
79
+ if (isLogicNotArgument(node)) {
80
+ isNegative = !isNegative;
81
+ node = node.parent;
82
+ } else if (isBooleanCallArgument(node)) {
83
+ node = node.parent;
84
+ } else {
85
+ break;
86
+ }
87
+ }
88
+
89
+ return {node, isNegative};
90
+ }
91
+
92
+ module.exports = {isBooleanNode, getBooleanAncestor};
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+ const typedArray = require('../shared/typed-array.js');
3
+
4
+ const enforceNew = [
5
+ 'Object',
6
+ 'Array',
7
+ 'ArrayBuffer',
8
+ 'DataView',
9
+ 'Date',
10
+ 'Error',
11
+ 'Function',
12
+ 'Map',
13
+ 'WeakMap',
14
+ 'Set',
15
+ 'WeakSet',
16
+ 'Promise',
17
+ 'RegExp',
18
+ 'SharedArrayBuffer',
19
+ 'Proxy',
20
+ 'WeakRef',
21
+ 'FinalizationRegistry',
22
+ ...typedArray,
23
+ ];
24
+
25
+ const disallowNew = [
26
+ 'BigInt',
27
+ 'Boolean',
28
+ 'Number',
29
+ 'String',
30
+ 'Symbol',
31
+ ];
32
+
33
+ module.exports = {
34
+ enforceNew,
35
+ disallowNew,
36
+ };
@@ -0,0 +1,24 @@
1
+ 'use strict';
2
+
3
+ module.exports = (combinations, length = Number.POSITIVE_INFINITY) => {
4
+ const total = combinations.reduce((total, {length}) => total * length, 1);
5
+
6
+ const samples = Array.from({length: Math.min(total, length)}, (_, sampleIndex) => {
7
+ let indexRemaining = sampleIndex;
8
+ const combination = [];
9
+ for (let combinationIndex = combinations.length - 1; combinationIndex >= 0; combinationIndex--) {
10
+ const items = combinations[combinationIndex];
11
+ const {length} = items;
12
+ const index = indexRemaining % length;
13
+ indexRemaining = (indexRemaining - index) / length;
14
+ combination.unshift(items[index]);
15
+ }
16
+
17
+ return combination;
18
+ });
19
+
20
+ return {
21
+ total,
22
+ samples,
23
+ };
24
+ };
@@ -0,0 +1,25 @@
1
+ 'use strict';
2
+ const packageJson = require('../../package.json');
3
+
4
+ const repoUrl = 'https://github.com/sindresorhus/eslint-plugin-unicorn';
5
+
6
+ /** @returns {{ [ruleName: string]: import('eslint').Rule.RuleModule }} */
7
+ function createDeprecatedRules(data) {
8
+ return Object.fromEntries(
9
+ Object.entries(data).map(([ruleId, replacedBy = []]) => [
10
+ ruleId,
11
+ {
12
+ create: () => ({}),
13
+ meta: {
14
+ docs: {
15
+ url: `${repoUrl}/blob/v${packageJson.version}/docs/deprecated-rules.md#${ruleId}`,
16
+ },
17
+ deprecated: true,
18
+ replacedBy: Array.isArray(replacedBy) ? replacedBy : [replacedBy],
19
+ },
20
+ },
21
+ ]),
22
+ );
23
+ }
24
+
25
+ module.exports = createDeprecatedRules;
@@ -0,0 +1,26 @@
1
+ 'use strict';
2
+
3
+ const jsesc = require('jsesc');
4
+
5
+ /**
6
+ Escape string and wrap the result in quotes.
7
+
8
+ @param {string} string - The string to be quoted.
9
+ @param {string} [quote] - The quote character.
10
+ @returns {string} - The quoted and escaped string.
11
+ */
12
+ module.exports = (string, quote = '\'') => {
13
+ /* c8 ignore start */
14
+ if (typeof string !== 'string') {
15
+ throw new TypeError('Unexpected string.');
16
+ }
17
+ /* c8 ignore end */
18
+
19
+ return jsesc(string, {
20
+ quotes: quote === '"' ? 'double' : 'single',
21
+ wrap: true,
22
+ es6: true,
23
+ minimal: true,
24
+ lowercaseHex: false,
25
+ });
26
+ };
@@ -0,0 +1,6 @@
1
+ 'use strict';
2
+
3
+ module.exports = string => string.replaceAll(
4
+ /(?<=(?:^|[^\\])(?:\\\\)*)(?<symbol>(?:`|\$(?={)))/g,
5
+ '\\$<symbol>',
6
+ );
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+
3
+ // TODO: Support more types
4
+ function getPredicate(options) {
5
+ if (typeof options === 'string') {
6
+ return node => node.type === options;
7
+ }
8
+ }
9
+
10
+ function getAncestor(node, options) {
11
+ const predicate = getPredicate(options);
12
+
13
+ for (;node.parent; node = node.parent) {
14
+ if (predicate(node)) {
15
+ return node;
16
+ }
17
+ }
18
+ }
19
+
20
+ module.exports = getAncestor;
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ function getBuiltinRule(id) {
4
+ return require('eslint/use-at-your-own-risk').builtinRules.get(id);
5
+ }
6
+
7
+ module.exports = getBuiltinRule;
@@ -0,0 +1,21 @@
1
+ 'use strict';
2
+ const {isOpeningParenToken} = require('@eslint-community/eslint-utils');
3
+
4
+ /**
5
+ Get the text of the arguments list of `CallExpression`.
6
+
7
+ @param {Node} node - The `CallExpression` node.
8
+ @param {SourceCode} sourceCode - The source code object.
9
+ @returns {string}
10
+ */
11
+ const getCallExpressionArgumentsText = (node, sourceCode) => {
12
+ const openingParenthesisToken = sourceCode.getTokenAfter(node.callee, isOpeningParenToken);
13
+ const closingParenthesisToken = sourceCode.getLastToken(node);
14
+
15
+ return sourceCode.text.slice(
16
+ openingParenthesisToken.range[1],
17
+ closingParenthesisToken.range[0],
18
+ );
19
+ };
20
+
21
+ module.exports = getCallExpressionArgumentsText;
@@ -0,0 +1,22 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ @typedef {line: number, column: number} Position
5
+
6
+ Get the location of the given class node for reporting.
7
+
8
+ @param {Node} node - The class node to get.
9
+ @param {SourceCode} sourceCode - The source code object to get tokens.
10
+ @returns {{start: Position, end: Position}} The location of the class node for reporting.
11
+ */
12
+ function getClassHeadLocation(node, sourceCode) {
13
+ const {loc, body} = node;
14
+ const tokenBeforeBody = sourceCode.getTokenBefore(body);
15
+
16
+ const {start} = loc;
17
+ const {end} = tokenBeforeBody.loc;
18
+
19
+ return {start, end};
20
+ }
21
+
22
+ module.exports = getClassHeadLocation;
@@ -0,0 +1,10 @@
1
+ 'use strict';
2
+ const path = require('node:path');
3
+ const packageJson = require('../../package.json');
4
+
5
+ const repoUrl = 'https://github.com/sindresorhus/eslint-plugin-unicorn';
6
+
7
+ module.exports = filename => {
8
+ const ruleName = path.basename(filename, '.js');
9
+ return `${repoUrl}/blob/v${packageJson.version}/docs/rules/${ruleName}.md`;
10
+ };
@@ -0,0 +1,11 @@
1
+ 'use strict';
2
+
3
+ function getIndentString(node, sourceCode) {
4
+ const {line, column} = sourceCode.getLocFromIndex(node.range[0]);
5
+ const lines = sourceCode.getLines();
6
+ const before = lines[line - 1].slice(0, column);
7
+
8
+ return before.match(/\s*$/)[0];
9
+ }
10
+
11
+ module.exports = getIndentString;
@@ -0,0 +1,24 @@
1
+ 'use strict';
2
+
3
+ function getPreviousNode(node, sourceCode) {
4
+ const {parent} = node;
5
+ const visitorKeys = sourceCode.visitorKeys[parent.type] || Object.keys(parent);
6
+
7
+ for (const property of visitorKeys) {
8
+ const value = parent[property];
9
+
10
+ if (value === node) {
11
+ return;
12
+ }
13
+
14
+ if (Array.isArray(value)) {
15
+ const index = value.indexOf(node);
16
+
17
+ if (index !== -1) {
18
+ return value[index - 1];
19
+ }
20
+ }
21
+ }
22
+ }
23
+
24
+ module.exports = getPreviousNode;
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ const getScopes = require('./get-scopes.js');
4
+
5
+ const getReferences = scope => [...new Set(
6
+ getScopes(scope).flatMap(({references}) => references),
7
+ )];
8
+
9
+ module.exports = getReferences;
@@ -0,0 +1,14 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ Gather a list of all Scopes starting recursively from the input Scope.
5
+
6
+ @param {Scope} scope - The Scope to start checking from.
7
+ @returns {Scope[]} - The resulting Scopes.
8
+ */
9
+ const getScopes = scope => [
10
+ scope,
11
+ ...scope.childScopes.flatMap(scope => getScopes(scope)),
12
+ ];
13
+
14
+ module.exports = getScopes;
@@ -0,0 +1,21 @@
1
+ 'use strict';
2
+
3
+ const {isColonToken} = require('@eslint-community/eslint-utils');
4
+
5
+ /**
6
+ @typedef {line: number, column: number} Position
7
+
8
+ Get the location of the given `SwitchCase` node for reporting.
9
+
10
+ @param {Node} node - The `SwitchCase` node to get.
11
+ @param {SourceCode} sourceCode - The source code object to get tokens from.
12
+ @returns {{start: Position, end: Position}} The location of the class node for reporting.
13
+ */
14
+ function getSwitchCaseHeadLocation(node, sourceCode) {
15
+ const startToken = node.test || sourceCode.getFirstToken(node);
16
+ const colonToken = sourceCode.getTokenAfter(startToken, isColonToken);
17
+
18
+ return {start: node.loc.start, end: colonToken.loc.end};
19
+ }
20
+
21
+ module.exports = getSwitchCaseHeadLocation;
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ // Get identifiers of given variable
4
+ module.exports = ({identifiers, references}) => [...new Set([
5
+ ...identifiers,
6
+ ...references.map(({identifier}) => identifier),
7
+ ])];
@@ -0,0 +1,72 @@
1
+ 'use strict';
2
+ const {ReferenceTracker} = require('@eslint-community/eslint-utils');
3
+
4
+ const createTraceMap = (object, type) => {
5
+ let map = {[type]: true};
6
+
7
+ const path = object.split('.').reverse();
8
+ for (const name of path) {
9
+ map = {[name]: map};
10
+ }
11
+
12
+ return map;
13
+ };
14
+
15
+ class GlobalReferenceTracker {
16
+ #traceMap = {};
17
+ #filter;
18
+ #handle;
19
+
20
+ constructor({
21
+ object,
22
+ objects = [object],
23
+ filter,
24
+ handle,
25
+ type = ReferenceTracker.READ,
26
+ }) {
27
+ for (const object of objects) {
28
+ Object.assign(this.#traceMap, createTraceMap(object, type));
29
+ }
30
+
31
+ this.#filter = filter;
32
+ this.#handle = handle;
33
+ }
34
+
35
+ * track(globalScope) {
36
+ const tracker = new ReferenceTracker(globalScope);
37
+
38
+ for (const reference of tracker.iterateGlobalReferences(this.#traceMap)) {
39
+ if (this.#filter && !this.#filter(reference)) {
40
+ continue;
41
+ }
42
+
43
+ const problems = this.#handle(reference);
44
+
45
+ if (!problems) {
46
+ continue;
47
+ }
48
+
49
+ if (problems[Symbol.iterator]) {
50
+ yield * problems;
51
+ } else {
52
+ yield problems;
53
+ }
54
+ }
55
+ }
56
+
57
+ createListeners(context) {
58
+ return {
59
+ 'Program:exit': program => this.track(context.sourceCode.getScope(program)),
60
+ };
61
+ }
62
+ }
63
+
64
+ Object.assign(GlobalReferenceTracker, {
65
+ READ: ReferenceTracker.READ,
66
+ CALL: ReferenceTracker.CALL,
67
+ CONSTRUCT: ReferenceTracker.CONSTRUCT,
68
+ });
69
+
70
+ module.exports = {
71
+ GlobalReferenceTracker,
72
+ };
@@ -0,0 +1,21 @@
1
+ 'use strict';
2
+
3
+ const isChainElement = node => node.type === 'MemberExpression' || node.type === 'CallExpression';
4
+
5
+ function hasOptionalChainElement(node) {
6
+ if (!isChainElement(node)) {
7
+ return false;
8
+ }
9
+
10
+ if (node.optional) {
11
+ return true;
12
+ }
13
+
14
+ if (node.type === 'MemberExpression') {
15
+ return hasOptionalChainElement(node.object);
16
+ }
17
+
18
+ return false;
19
+ }
20
+
21
+ module.exports = hasOptionalChainElement;
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ module.exports = (node1, node2) =>
4
+ node1
5
+ && node2
6
+ && node1.range[0] === node2.range[0]
7
+ && node1.range[1] === node2.range[1];