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,101 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ @param {
5
+ {
6
+ property?: string,
7
+ properties?: string[],
8
+ object?: string,
9
+ objects?: string[],
10
+ optional?: boolean,
11
+ computed?: boolean
12
+ } | string | string[]
13
+ } [options]
14
+ @returns {string}
15
+ */
16
+ function isMemberExpression(node, options) {
17
+ if (node?.type !== 'MemberExpression') {
18
+ return false;
19
+ }
20
+
21
+ if (typeof options === 'string') {
22
+ options = {properties: [options]};
23
+ }
24
+
25
+ if (Array.isArray(options)) {
26
+ options = {properties: options};
27
+ }
28
+
29
+ let {
30
+ property,
31
+ properties,
32
+ object,
33
+ objects,
34
+ optional,
35
+ computed,
36
+ } = {
37
+ property: '',
38
+ properties: [],
39
+ object: '',
40
+ ...options,
41
+ };
42
+
43
+ if (property) {
44
+ properties = [property];
45
+ }
46
+
47
+ if (object) {
48
+ objects = [object];
49
+ }
50
+
51
+ if (
52
+ (optional === true && (node.optional !== optional))
53
+ || (
54
+ optional === false
55
+ // `node.optional` can be `undefined` in some parsers
56
+ && node.optional
57
+ )
58
+ ) {
59
+ return false;
60
+ }
61
+
62
+ if (
63
+ Array.isArray(properties)
64
+ && properties.length > 0
65
+ ) {
66
+ if (
67
+ node.property.type !== 'Identifier'
68
+ || !properties.includes(node.property.name)
69
+ ) {
70
+ return false;
71
+ }
72
+
73
+ computed ??= false;
74
+ }
75
+
76
+ if (
77
+ (computed === true && (node.computed !== computed))
78
+ || (
79
+ computed === false
80
+ // `node.computed` can be `undefined` in some parsers
81
+ && node.computed
82
+ )
83
+ ) {
84
+ return false;
85
+ }
86
+
87
+ if (
88
+ Array.isArray(objects)
89
+ && objects.length > 0
90
+ && (
91
+ node.object.type !== 'Identifier'
92
+ || !objects.includes(node.object.name)
93
+ )
94
+ ) {
95
+ return false;
96
+ }
97
+
98
+ return true;
99
+ }
100
+
101
+ module.exports = isMemberExpression;
@@ -0,0 +1,65 @@
1
+ 'use strict';
2
+ const isMemberExpression = require('./is-member-expression.js');
3
+ const {isCallExpression} = require('./call-or-new-expression.js');
4
+
5
+ /**
6
+ @param {
7
+ {
8
+ // `isCallExpression` options
9
+ argumentsLength?: number,
10
+ minimumArguments?: number,
11
+ maximumArguments?: number,
12
+ optionalCall?: boolean,
13
+ allowSpreadElement?: boolean,
14
+
15
+ // `isMemberExpression` options
16
+ method?: string,
17
+ methods?: string[],
18
+ object?: string,
19
+ objects?: string[],
20
+ optionalMember?: boolean,
21
+ computed?: boolean
22
+ } | string | string[]
23
+ } [options]
24
+ @returns {string}
25
+ */
26
+ function isMethodCall(node, options) {
27
+ if (typeof options === 'string') {
28
+ options = {methods: [options]};
29
+ }
30
+
31
+ if (Array.isArray(options)) {
32
+ options = {methods: options};
33
+ }
34
+
35
+ const {
36
+ optionalCall,
37
+ optionalMember,
38
+ method,
39
+ methods,
40
+ } = {
41
+ method: '',
42
+ methods: [],
43
+ ...options,
44
+ };
45
+
46
+ return (
47
+ isCallExpression(node, {
48
+ argumentsLength: options.argumentsLength,
49
+ minimumArguments: options.minimumArguments,
50
+ maximumArguments: options.maximumArguments,
51
+ allowSpreadElement: options.allowSpreadElement,
52
+ optional: optionalCall,
53
+ })
54
+ && isMemberExpression(node.callee, {
55
+ object: options.object,
56
+ objects: options.objects,
57
+ computed: options.computed,
58
+ property: method,
59
+ properties: methods,
60
+ optional: optionalMember,
61
+ })
62
+ );
63
+ }
64
+
65
+ module.exports = isMethodCall;
@@ -0,0 +1,156 @@
1
+ 'use strict';
2
+
3
+ // eslint-disable-next-line complexity
4
+ function isNotReference(node) {
5
+ const {parent} = node;
6
+
7
+ switch (parent.type) {
8
+ // `foo.Identifier`
9
+ case 'MemberExpression': {
10
+ return !parent.computed && parent.property === node;
11
+ }
12
+
13
+ case 'FunctionDeclaration':
14
+ case 'FunctionExpression': {
15
+ return (
16
+ // `function foo(Identifier) {}`
17
+ // `const foo = function(Identifier) {}`
18
+ parent.params.includes(node)
19
+ // `function Identifier() {}`
20
+ // `const foo = function Identifier() {}`
21
+ || parent.id === node
22
+ );
23
+ }
24
+
25
+ case 'ArrowFunctionExpression': {
26
+ // `const foo = (Identifier) => {}`
27
+ return parent.params.includes(node);
28
+ }
29
+
30
+ // `class Identifier() {}`
31
+ // `const foo = class Identifier() {}`
32
+ // `const Identifier = 1`
33
+ case 'ClassDeclaration':
34
+ case 'ClassExpression':
35
+ case 'VariableDeclarator': {
36
+ return parent.id === node;
37
+ }
38
+
39
+ // `class Foo {Identifier = 1}`
40
+ // `class Foo {Identifier() {}}`
41
+ case 'PropertyDefinition':
42
+ case 'MethodDefinition': {
43
+ return !parent.computed && parent.key === node;
44
+ }
45
+
46
+ // `const foo = {Identifier: 1}`
47
+ // `const {Identifier} = {}`
48
+ // `const {Identifier: foo} = {}`
49
+ // `const {Identifier} = {}`
50
+ // `const {foo: Identifier} = {}`
51
+ case 'Property': {
52
+ return (
53
+ (
54
+ !parent.computed
55
+ && parent.key === node
56
+ && (
57
+ (parent.parent.type === 'ObjectExpression' || parent.parent.type === 'ObjectPattern')
58
+ && parent.parent.properties.includes(parent)
59
+ )
60
+ )
61
+ || (
62
+ parent.value === node
63
+ && parent.parent.type === 'ObjectPattern'
64
+ && parent.parent.properties.includes(parent)
65
+ )
66
+ );
67
+ }
68
+
69
+ // `const [Identifier] = []`
70
+ case 'ArrayPattern': {
71
+ return parent.elements.includes(node);
72
+ }
73
+
74
+ /*
75
+ ```
76
+ Identifier: for (const foo of bar) {
77
+ continue Identifier;
78
+ break Identifier;
79
+ }
80
+ ```
81
+ */
82
+ case 'LabeledStatement':
83
+ case 'ContinueStatement':
84
+ case 'BreakStatement': {
85
+ return parent.label === node;
86
+ }
87
+
88
+ // `import * as Identifier from 'foo'`
89
+ // `import Identifier from 'foo'`
90
+ case 'ImportDefaultSpecifier':
91
+ case 'ImportNamespaceSpecifier': {
92
+ return parent.local === node;
93
+ }
94
+
95
+ // `export * as Identifier from 'foo'`
96
+ case 'ExportAllDeclaration': {
97
+ return parent.exported === node;
98
+ }
99
+
100
+ // `import {foo as Identifier} from 'foo'`
101
+ // `import {Identifier as foo} from 'foo'`
102
+ case 'ImportSpecifier': {
103
+ return (parent.local === node || parent.imported === node);
104
+ }
105
+
106
+ // `export {foo as Identifier}`
107
+ // `export {Identifier as foo}`
108
+ case 'ExportSpecifier': {
109
+ return (parent.local === node || parent.exported === node);
110
+ }
111
+
112
+ // TypeScript
113
+ case 'TSDeclareFunction':
114
+ case 'TSEnumMember': {
115
+ return parent.id === node;
116
+ }
117
+
118
+ // `type Foo = { [Identifier: string]: string }`
119
+ case 'TSIndexSignature': {
120
+ return parent.parameters.includes(node);
121
+ }
122
+
123
+ // `type Foo = { [Identifier in keyof string]: number; };`
124
+ case 'TSTypeParameter': {
125
+ return parent.name === node;
126
+ }
127
+
128
+ // `type Identifier = Foo`
129
+ case 'TSTypeAliasDeclaration': {
130
+ return parent.id === node;
131
+ }
132
+
133
+ case 'TSPropertySignature': {
134
+ return parent.key === node;
135
+ }
136
+
137
+ // No default
138
+ }
139
+
140
+ return false;
141
+ }
142
+
143
+ function isReferenceIdentifier(node, nameOrNames = []) {
144
+ if (node.type !== 'Identifier') {
145
+ return false;
146
+ }
147
+
148
+ const names = Array.isArray(nameOrNames) ? nameOrNames : [nameOrNames];
149
+ if (names.length > 0 && !names.includes(node.name)) {
150
+ return false;
151
+ }
152
+
153
+ return !isNotReference(node);
154
+ }
155
+
156
+ module.exports = isReferenceIdentifier;
@@ -0,0 +1,14 @@
1
+ 'use strict';
2
+
3
+ const {isStringLiteral} = require('./literal.js');
4
+ const {isCallExpression} = require('./call-or-new-expression.js');
5
+
6
+ const isStaticRequire = node =>
7
+ isCallExpression(node, {
8
+ name: 'require',
9
+ argumentsLength: 1,
10
+ optional: false,
11
+ })
12
+ && isStringLiteral(node.arguments[0]);
13
+
14
+ module.exports = isStaticRequire;
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ function isUndefined(node) {
4
+ return node.type === 'Identifier' && node.name === 'undefined';
5
+ }
6
+
7
+ module.exports = isUndefined;
@@ -0,0 +1,29 @@
1
+ 'use strict';
2
+
3
+ function isLiteral(node, value) {
4
+ if (node?.type !== 'Literal') {
5
+ return false;
6
+ }
7
+
8
+ if (value === null) {
9
+ return node.raw === 'null';
10
+ }
11
+
12
+ return node.value === value;
13
+ }
14
+
15
+ const isStringLiteral = node => node?.type === 'Literal' && typeof node.value === 'string';
16
+ const isNumberLiteral = node => node.type === 'Literal' && typeof node.value === 'number';
17
+ const isRegexLiteral = node => node.type === 'Literal' && Boolean(node.regex);
18
+ // eslint-disable-next-line unicorn/no-null
19
+ const isNullLiteral = node => isLiteral(node, null);
20
+ const isBigIntLiteral = node => node.type === 'Literal' && Boolean(node.bigint);
21
+
22
+ module.exports = {
23
+ isLiteral,
24
+ isStringLiteral,
25
+ isNumberLiteral,
26
+ isBigIntLiteral,
27
+ isNullLiteral,
28
+ isRegexLiteral,
29
+ };
@@ -0,0 +1,144 @@
1
+ 'use strict';
2
+ const cleanRegexp = require('clean-regexp');
3
+ const {optimize} = require('regexp-tree');
4
+ const escapeString = require('./utils/escape-string.js');
5
+ const {isStringLiteral, isNewExpression, isRegexLiteral} = require('./ast/index.js');
6
+
7
+ const MESSAGE_ID = 'better-regex';
8
+ const MESSAGE_ID_PARSE_ERROR = 'better-regex/parse-error';
9
+ const messages = {
10
+ [MESSAGE_ID]: '{{original}} can be optimized to {{optimized}}.',
11
+ [MESSAGE_ID_PARSE_ERROR]: 'Problem parsing {{original}}: {{error}}',
12
+ };
13
+
14
+ /** @param {import('eslint').Rule.RuleContext} context */
15
+ const create = context => {
16
+ const {sortCharacterClasses} = context.options[0] || {};
17
+
18
+ const ignoreList = [];
19
+
20
+ if (sortCharacterClasses === false) {
21
+ ignoreList.push('charClassClassrangesMerge');
22
+ }
23
+
24
+ return {
25
+ Literal(node) {
26
+ if (!isRegexLiteral(node)) {
27
+ return;
28
+ }
29
+
30
+ const {raw: original, regex} = node;
31
+ // Regular Expressions with `u` and `v` flag are not well handled by `regexp-tree`
32
+ // https://github.com/DmitrySoshnikov/regexp-tree/issues/162
33
+ if (regex.flags.includes('u') || regex.flags.includes('v')) {
34
+ return;
35
+ }
36
+
37
+ let optimized = original;
38
+
39
+ try {
40
+ optimized = optimize(original, undefined, {blacklist: ignoreList}).toString();
41
+ } catch (error) {
42
+ return {
43
+ node,
44
+ messageId: MESSAGE_ID_PARSE_ERROR,
45
+ data: {
46
+ original,
47
+ error: error.message,
48
+ },
49
+ };
50
+ }
51
+
52
+ if (original === optimized) {
53
+ return;
54
+ }
55
+
56
+ const problem = {
57
+ node,
58
+ messageId: MESSAGE_ID,
59
+ data: {
60
+ original,
61
+ optimized,
62
+ },
63
+ };
64
+
65
+ if (
66
+ node.parent.type === 'MemberExpression'
67
+ && node.parent.object === node
68
+ && !node.parent.optional
69
+ && !node.parent.computed
70
+ && node.parent.property.type === 'Identifier'
71
+ && (
72
+ node.parent.property.name === 'toString'
73
+ || node.parent.property.name === 'source'
74
+ )
75
+ ) {
76
+ return problem;
77
+ }
78
+
79
+ return Object.assign(problem, {
80
+ fix: fixer => fixer.replaceText(node, optimized),
81
+ });
82
+ },
83
+ NewExpression(node) {
84
+ if (!isNewExpression(node, {name: 'RegExp', minimumArguments: 1})) {
85
+ return;
86
+ }
87
+
88
+ const [patternNode, flagsNode] = node.arguments;
89
+
90
+ if (!isStringLiteral(patternNode)) {
91
+ return;
92
+ }
93
+
94
+ const oldPattern = patternNode.value;
95
+ const flags = isStringLiteral(flagsNode)
96
+ ? flagsNode.value
97
+ : '';
98
+
99
+ const newPattern = cleanRegexp(oldPattern, flags);
100
+
101
+ if (oldPattern !== newPattern) {
102
+ return {
103
+ node,
104
+ messageId: MESSAGE_ID,
105
+ data: {
106
+ original: oldPattern,
107
+ optimized: newPattern,
108
+ },
109
+ fix: fixer => fixer.replaceText(
110
+ patternNode,
111
+ escapeString(newPattern, patternNode.raw.charAt(0)),
112
+ ),
113
+ };
114
+ }
115
+ },
116
+ };
117
+ };
118
+
119
+ const schema = [
120
+ {
121
+ type: 'object',
122
+ additionalProperties: false,
123
+ properties: {
124
+ sortCharacterClasses: {
125
+ type: 'boolean',
126
+ default: true,
127
+ },
128
+ },
129
+ },
130
+ ];
131
+
132
+ /** @type {import('eslint').Rule.RuleModule} */
133
+ module.exports = {
134
+ create,
135
+ meta: {
136
+ type: 'suggestion',
137
+ docs: {
138
+ description: 'Improve regexes by making them shorter, consistent, and safer.',
139
+ },
140
+ fixable: 'code',
141
+ schema,
142
+ messages,
143
+ },
144
+ };
@@ -0,0 +1,136 @@
1
+ 'use strict';
2
+ const {findVariable} = require('@eslint-community/eslint-utils');
3
+ const avoidCapture = require('./utils/avoid-capture.js');
4
+ const {renameVariable} = require('./fix/index.js');
5
+ const {isMethodCall} = require('./ast/index.js');
6
+
7
+ const MESSAGE_ID = 'catch-error-name';
8
+ const messages = {
9
+ [MESSAGE_ID]: 'The catch parameter `{{originalName}}` should be named `{{fixedName}}`.',
10
+ };
11
+
12
+ // - `promise.then(…, foo => {})`
13
+ // - `promise.then(…, function(foo) {})`
14
+ // - `promise.catch(foo => {})`
15
+ // - `promise.catch(function(foo) {})`
16
+ const isPromiseCatchParameter = node =>
17
+ (node.parent.type === 'FunctionExpression' || node.parent.type === 'ArrowFunctionExpression')
18
+ && node.parent.params[0] === node
19
+ && (
20
+ isMethodCall(node.parent.parent, {
21
+ method: 'then',
22
+ argumentsLength: 2,
23
+ optionalCall: false,
24
+ optionalMember: false,
25
+ })
26
+ || isMethodCall(node.parent.parent, {
27
+ method: 'catch',
28
+ argumentsLength: 1,
29
+ optionalCall: false,
30
+ optionalMember: false,
31
+ })
32
+ )
33
+ && node.parent.parent.arguments.at(-1) === node.parent;
34
+
35
+ /** @param {import('eslint').Rule.RuleContext} context */
36
+ const create = context => {
37
+ const options = {
38
+ name: 'error',
39
+ ignore: [],
40
+ ...context.options[0],
41
+ };
42
+ const {name: expectedName} = options;
43
+ const ignore = options.ignore.map(
44
+ pattern => pattern instanceof RegExp ? pattern : new RegExp(pattern, 'u'),
45
+ );
46
+ const isNameAllowed = name =>
47
+ name === expectedName
48
+ || ignore.some(regexp => regexp.test(name))
49
+ || name.endsWith(expectedName)
50
+ || name.endsWith(expectedName.charAt(0).toUpperCase() + expectedName.slice(1));
51
+
52
+ return {
53
+ Identifier(node) {
54
+ if (
55
+ !(node.parent.type === 'CatchClause' && node.parent.param === node)
56
+ && !isPromiseCatchParameter(node)
57
+ ) {
58
+ return;
59
+ }
60
+
61
+ const originalName = node.name;
62
+
63
+ if (
64
+ isNameAllowed(originalName)
65
+ || isNameAllowed(originalName.replaceAll(/_+$/g, ''))
66
+ ) {
67
+ return;
68
+ }
69
+
70
+ const scope = context.sourceCode.getScope(node);
71
+ const variable = findVariable(scope, node);
72
+
73
+ // This was reported https://github.com/sindresorhus/eslint-plugin-unicorn/issues/1075#issuecomment-768072967
74
+ // But can't reproduce, just ignore this case
75
+ /* c8 ignore next 3 */
76
+ if (!variable) {
77
+ return;
78
+ }
79
+
80
+ if (originalName === '_' && variable.references.length === 0) {
81
+ return;
82
+ }
83
+
84
+ const scopes = [
85
+ variable.scope,
86
+ ...variable.references.map(({from}) => from),
87
+ ];
88
+ const fixedName = avoidCapture(expectedName, scopes);
89
+
90
+ const problem = {
91
+ node,
92
+ messageId: MESSAGE_ID,
93
+ data: {
94
+ originalName,
95
+ fixedName: fixedName || expectedName,
96
+ },
97
+ };
98
+
99
+ if (fixedName) {
100
+ problem.fix = fixer => renameVariable(variable, fixedName, fixer);
101
+ }
102
+
103
+ return problem;
104
+ },
105
+ };
106
+ };
107
+
108
+ const schema = [
109
+ {
110
+ type: 'object',
111
+ additionalProperties: false,
112
+ properties: {
113
+ name: {
114
+ type: 'string',
115
+ },
116
+ ignore: {
117
+ type: 'array',
118
+ uniqueItems: true,
119
+ },
120
+ },
121
+ },
122
+ ];
123
+
124
+ /** @type {import('eslint').Rule.RuleModule} */
125
+ module.exports = {
126
+ create,
127
+ meta: {
128
+ type: 'suggestion',
129
+ docs: {
130
+ description: 'Enforce a specific parameter name in catch clauses.',
131
+ },
132
+ fixable: 'code',
133
+ schema,
134
+ messages,
135
+ },
136
+ };