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,275 @@
1
+ 'use strict';
2
+
3
+ const getVendorPrefixedName = eventName => [
4
+ `webkit${eventName}`,
5
+ `o${eventName.toLowerCase()}`,
6
+ eventName.toLowerCase(),
7
+ ];
8
+
9
+ // https://github.com/google/closure-library/blob/8782d8ba16ef2dd4a508d2081a6938f054fc60e8/closure/goog/events/eventtype.js#L44
10
+ module.exports = new Set([
11
+ // Mouse events
12
+ 'click',
13
+ 'rightclick',
14
+ 'dblclick',
15
+ 'auxclick',
16
+ 'mousedown',
17
+ 'mouseup',
18
+ 'mouseover',
19
+ 'mouseout',
20
+ 'mousemove',
21
+ 'mouseenter',
22
+ 'mouseleave',
23
+
24
+ // Non-existent event; will never fire. This exists as a mouse counterpart to
25
+ // POINTERCANCEL.
26
+ 'mousecancel',
27
+
28
+ // Selection events.
29
+ // https://www.w3.org/TR/selection-api/
30
+ 'selectionchange',
31
+ 'selectstart', // IE, Safari, Chrome
32
+
33
+ // Wheel events
34
+ // http://www.w3.org/TR/DOM-Level-3-Events/#events-wheelevents
35
+ 'wheel',
36
+
37
+ // Key events
38
+ 'keypress',
39
+ 'keydown',
40
+ 'keyup',
41
+
42
+ // Focus
43
+ 'blur',
44
+ 'focus',
45
+ 'deactivate', // IE only
46
+ 'focusin',
47
+ 'focusout',
48
+
49
+ // Forms
50
+ 'change',
51
+ 'reset',
52
+ 'select',
53
+ 'submit',
54
+ 'input',
55
+ 'propertychange', // IE only
56
+
57
+ // Drag and drop
58
+ 'dragstart',
59
+ 'drag',
60
+ 'dragenter',
61
+ 'dragover',
62
+ 'dragleave',
63
+ 'drop',
64
+ 'dragend',
65
+
66
+ // Touch events
67
+ // Note that other touch events exist, but we should follow the W3C list here.
68
+ // http://www.w3.org/TR/touch-events/#list-of-touchevent-types
69
+ 'touchstart',
70
+ 'touchmove',
71
+ 'touchend',
72
+ 'touchcancel',
73
+
74
+ // Misc
75
+ 'beforeunload',
76
+ 'consolemessage',
77
+ 'contextmenu',
78
+ 'devicechange',
79
+ 'devicemotion',
80
+ 'deviceorientation',
81
+ 'DOMContentLoaded',
82
+ 'error',
83
+ 'help',
84
+ 'load',
85
+ 'losecapture',
86
+ 'orientationchange',
87
+ 'readystatechange',
88
+ 'resize',
89
+ 'scroll',
90
+ 'unload',
91
+
92
+ // Media events
93
+ 'canplay',
94
+ 'canplaythrough',
95
+ 'durationchange',
96
+ 'emptied',
97
+ 'ended',
98
+ 'loadeddata',
99
+ 'loadedmetadata',
100
+ 'pause',
101
+ 'play',
102
+ 'playing',
103
+ 'progress',
104
+ 'ratechange',
105
+ 'seeked',
106
+ 'seeking',
107
+ 'stalled',
108
+ 'suspend',
109
+ 'timeupdate',
110
+ 'volumechange',
111
+ 'waiting',
112
+
113
+ // Media Source Extensions events
114
+ // https://www.w3.org/TR/media-source/#mediasource-events
115
+ 'sourceopen',
116
+ 'sourceended',
117
+ 'sourceclosed',
118
+ // https://www.w3.org/TR/media-source/#sourcebuffer-events
119
+ 'abort',
120
+ 'update',
121
+ 'updatestart',
122
+ 'updateend',
123
+
124
+ // HTML 5 History events
125
+ // See http://www.w3.org/TR/html5/browsers.html#event-definitions-0
126
+ 'hashchange',
127
+ 'pagehide',
128
+ 'pageshow',
129
+ 'popstate',
130
+
131
+ // Copy and Paste
132
+ // Support is limited. Make sure it works on your favorite browser
133
+ // before using.
134
+ // http://www.quirksmode.org/dom/events/cutcopypaste.html
135
+ 'copy',
136
+ 'paste',
137
+ 'cut',
138
+ 'beforecopy',
139
+ 'beforecut',
140
+ 'beforepaste',
141
+
142
+ // HTML5 online/offline events.
143
+ // http://www.w3.org/TR/offline-webapps/#related
144
+ 'online',
145
+ 'offline',
146
+
147
+ // HTML 5 worker events
148
+ 'message',
149
+ 'connect',
150
+
151
+ // Service Worker Events - ServiceWorkerGlobalScope context
152
+ // See https://w3c.github.io/ServiceWorker/#execution-context-events
153
+ // message event defined in worker events section
154
+ 'install',
155
+ 'activate',
156
+ 'fetch',
157
+ 'foreignfetch',
158
+ 'messageerror',
159
+
160
+ // Service Worker Events - Document context
161
+ // See https://w3c.github.io/ServiceWorker/#document-context-events
162
+ 'statechange',
163
+ 'updatefound',
164
+ 'controllerchange',
165
+
166
+ // CSS animation events.
167
+ ...getVendorPrefixedName('AnimationStart'),
168
+ ...getVendorPrefixedName('AnimationEnd'),
169
+ ...getVendorPrefixedName('AnimationIteration'),
170
+
171
+ // CSS transition events. Based on the browser support described at:
172
+ // https://developer.mozilla.org/en/css/css_transitions#Browser_compatibility
173
+ ...getVendorPrefixedName('TransitionEnd'),
174
+
175
+ // W3C Pointer Events
176
+ // http://www.w3.org/TR/pointerevents/
177
+ 'pointerdown',
178
+ 'pointerup',
179
+ 'pointercancel',
180
+ 'pointermove',
181
+ 'pointerover',
182
+ 'pointerout',
183
+ 'pointerenter',
184
+ 'pointerleave',
185
+ 'gotpointercapture',
186
+ 'lostpointercapture',
187
+
188
+ // IE specific events.
189
+ // See http://msdn.microsoft.com/en-us/library/ie/hh772103(v=vs.85).aspx
190
+ // these events will be supplanted in IE11.
191
+ 'MSGestureChange',
192
+ 'MSGestureEnd',
193
+ 'MSGestureHold',
194
+ 'MSGestureStart',
195
+ 'MSGestureTap',
196
+ 'MSGotPointerCapture',
197
+ 'MSInertiaStart',
198
+ 'MSLostPointerCapture',
199
+ 'MSPointerCancel',
200
+ 'MSPointerDown',
201
+ 'MSPointerEnter',
202
+ 'MSPointerHover',
203
+ 'MSPointerLeave',
204
+ 'MSPointerMove',
205
+ 'MSPointerOut',
206
+ 'MSPointerOver',
207
+ 'MSPointerUp',
208
+
209
+ // Native IMEs/input tools events.
210
+ 'text',
211
+ // The textInput event is supported in IE9+, but only in lower case. All other
212
+ // browsers use the camel-case event name.
213
+ 'textinput',
214
+ 'textInput',
215
+ 'compositionstart',
216
+ 'compositionupdate',
217
+ 'compositionend',
218
+
219
+ // The beforeinput event is initially only supported in Safari. See
220
+ // https://bugs.chromium.org/p/chromium/issues/detail?id=342670 for Chrome
221
+ // implementation tracking.
222
+ 'beforeinput',
223
+
224
+ // Webview tag events
225
+ // See https://developer.chrome.com/apps/tags/webview
226
+ 'exit',
227
+ 'loadabort',
228
+ 'loadcommit',
229
+ 'loadredirect',
230
+ 'loadstart',
231
+ 'loadstop',
232
+ 'responsive',
233
+ 'sizechanged',
234
+ 'unresponsive',
235
+
236
+ // HTML5 Page Visibility API. See details at
237
+ // `goog.labs.dom.PageVisibilityMonitor`.
238
+ 'visibilitychange',
239
+
240
+ // LocalStorage event.
241
+ 'storage',
242
+
243
+ // DOM Level 2 mutation events (deprecated).
244
+ 'DOMSubtreeModified',
245
+ 'DOMNodeInserted',
246
+ 'DOMNodeRemoved',
247
+ 'DOMNodeRemovedFromDocument',
248
+ 'DOMNodeInsertedIntoDocument',
249
+ 'DOMAttrModified',
250
+ 'DOMCharacterDataModified',
251
+
252
+ // Print events.
253
+ 'beforeprint',
254
+ 'afterprint',
255
+
256
+ // Web app manifest events.
257
+ 'beforeinstallprompt',
258
+ 'appinstalled',
259
+
260
+ // https://github.com/facebook/react/blob/cae635054e17a6f107a39d328649137b83f25972/packages/react-dom/src/events/DOMEventNames.js#L12
261
+ 'afterblur',
262
+ 'beforeblur',
263
+ 'cancel',
264
+ 'close',
265
+ 'dragexit',
266
+ 'encrypted',
267
+ 'fullscreenchange',
268
+ 'invalid',
269
+ 'toggle',
270
+
271
+ // https://github.com/sindresorhus/eslint-plugin-unicorn/pull/147
272
+ 'search',
273
+ 'open',
274
+ 'show',
275
+ ]);
@@ -0,0 +1,52 @@
1
+ /* eslint sort-keys: ["error", "asc", {natural: true}] */
2
+ 'use strict';
3
+ // https://github.com/facebook/react/blob/b87aabd/packages/react-dom/src/events/getEventKey.js#L36
4
+ // Only meta characters which can't be deciphered from `String.fromCharCode()`
5
+ module.exports = {
6
+ 8: 'Backspace',
7
+ 9: 'Tab',
8
+ 12: 'Clear',
9
+ 13: 'Enter',
10
+ 16: 'Shift',
11
+ 17: 'Control',
12
+ 18: 'Alt',
13
+ 19: 'Pause',
14
+ 20: 'CapsLock',
15
+ 27: 'Escape',
16
+ 32: ' ',
17
+ 33: 'PageUp',
18
+ 34: 'PageDown',
19
+ 35: 'End',
20
+ 36: 'Home',
21
+ 37: 'ArrowLeft',
22
+ 38: 'ArrowUp',
23
+ 39: 'ArrowRight',
24
+ 40: 'ArrowDown',
25
+ 45: 'Insert',
26
+ 46: 'Delete',
27
+ 112: 'F1',
28
+ 113: 'F2',
29
+ 114: 'F3',
30
+ 115: 'F4',
31
+ 116: 'F5',
32
+ 117: 'F6',
33
+ 118: 'F7',
34
+ 119: 'F8',
35
+ 120: 'F9',
36
+ 121: 'F10',
37
+ 122: 'F11',
38
+ 123: 'F12',
39
+ 144: 'NumLock',
40
+ 145: 'ScrollLock',
41
+ 186: ';',
42
+ 187: '=',
43
+ 188: ',',
44
+ 189: '-',
45
+ 190: '.',
46
+ 191: '/',
47
+ 219: '[',
48
+ 220: '\\',
49
+ 221: ']',
50
+ 222: '\'',
51
+ 224: 'Meta',
52
+ };
@@ -0,0 +1,46 @@
1
+ 'use strict';
2
+ const isSameReference = require('../utils/is-same-reference.js');
3
+ const {getParenthesizedRange} = require('../utils/parentheses.js');
4
+ const {isNumberLiteral} = require('../ast/index.js');
5
+
6
+ const isLengthMemberExpression = node =>
7
+ node.type === 'MemberExpression'
8
+ && !node.computed
9
+ && !node.optional
10
+ && node.property.type === 'Identifier'
11
+ && node.property.name === 'length';
12
+ const isLiteralPositiveNumber = node =>
13
+ isNumberLiteral(node)
14
+ && node.value > 0;
15
+
16
+ function getNegativeIndexLengthNode(node, objectNode) {
17
+ if (!node) {
18
+ return;
19
+ }
20
+
21
+ const {type, operator, left, right} = node;
22
+
23
+ if (type !== 'BinaryExpression' || operator !== '-' || !isLiteralPositiveNumber(right)) {
24
+ return;
25
+ }
26
+
27
+ if (isLengthMemberExpression(left) && isSameReference(left.object, objectNode)) {
28
+ return left;
29
+ }
30
+
31
+ // Nested BinaryExpression
32
+ return getNegativeIndexLengthNode(left, objectNode);
33
+ }
34
+
35
+ function removeLengthNode(node, fixer, sourceCode) {
36
+ const [start, end] = getParenthesizedRange(node, sourceCode);
37
+ return fixer.removeRange([
38
+ start,
39
+ end + sourceCode.text.slice(end).match(/\S|$/).index,
40
+ ]);
41
+ }
42
+
43
+ module.exports = {
44
+ getNegativeIndexLengthNode,
45
+ removeLengthNode,
46
+ };
@@ -0,0 +1,128 @@
1
+ 'use strict';
2
+
3
+ const {hasSideEffect, isParenthesized, findVariable} = require('@eslint-community/eslint-utils');
4
+ const {isMethodCall} = require('../ast/index.js');
5
+ const {isSameIdentifier, isFunctionSelfUsedInside} = require('../utils/index.js');
6
+
7
+ const isSimpleCompare = (node, compareNode) =>
8
+ node.type === 'BinaryExpression'
9
+ && node.operator === '==='
10
+ && (
11
+ isSameIdentifier(node.left, compareNode)
12
+ || isSameIdentifier(node.right, compareNode)
13
+ );
14
+ const isSimpleCompareCallbackFunction = node =>
15
+ // Matches `foo.findIndex(bar => bar === baz)`
16
+ (
17
+ node.type === 'ArrowFunctionExpression'
18
+ && !node.async
19
+ && node.params.length === 1
20
+ && isSimpleCompare(node.body, node.params[0])
21
+ )
22
+ // Matches `foo.findIndex(bar => {return bar === baz})`
23
+ // Matches `foo.findIndex(function (bar) {return bar === baz})`
24
+ || (
25
+ (node.type === 'ArrowFunctionExpression' || node.type === 'FunctionExpression')
26
+ && !node.async
27
+ && !node.generator
28
+ && node.params.length === 1
29
+ && node.body.type === 'BlockStatement'
30
+ && node.body.body.length === 1
31
+ && node.body.body[0].type === 'ReturnStatement'
32
+ && isSimpleCompare(node.body.body[0].argument, node.params[0])
33
+ );
34
+ const isIdentifierNamed = ({type, name}, expectName) => type === 'Identifier' && name === expectName;
35
+
36
+ function simpleArraySearchRule({method, replacement}) {
37
+ // Add prefix to avoid conflicts in `prefer-includes` rule
38
+ const MESSAGE_ID_PREFIX = `prefer-${replacement}-over-${method}/`;
39
+ const ERROR = `${MESSAGE_ID_PREFIX}error`;
40
+ const SUGGESTION = `${MESSAGE_ID_PREFIX}suggestion`;
41
+ const ERROR_MESSAGES = {
42
+ findIndex: 'Use `.indexOf()` instead of `.findIndex()` when looking for the index of an item.',
43
+ findLastIndex: 'Use `.lastIndexOf()` instead of `findLastIndex() when looking for the index of an item.`',
44
+ some: `Use \`.${replacement}()\` instead of \`.${method}()\` when checking value existence.`,
45
+ };
46
+
47
+ const messages = {
48
+ [ERROR]: ERROR_MESSAGES[method],
49
+ [SUGGESTION]: `Replace \`.${method}()\` with \`.${replacement}()\`.`,
50
+ };
51
+
52
+ function listen(context) {
53
+ const {sourceCode} = context;
54
+ const {scopeManager} = sourceCode;
55
+
56
+ context.on('CallExpression', callExpression => {
57
+ if (
58
+ !isMethodCall(callExpression, {
59
+ method,
60
+ argumentsLength: 1,
61
+ optionalCall: false,
62
+ optionalMember: false,
63
+ })
64
+ || !isSimpleCompareCallbackFunction(callExpression.arguments[0])
65
+ ) {
66
+ return;
67
+ }
68
+
69
+ const [callback] = callExpression.arguments;
70
+ const binaryExpression = callback.body.type === 'BinaryExpression'
71
+ ? callback.body
72
+ : callback.body.body[0].argument;
73
+ const [parameter] = callback.params;
74
+ const {left, right} = binaryExpression;
75
+ const {name} = parameter;
76
+
77
+ let searchValueNode;
78
+ let parameterInBinaryExpression;
79
+ if (isIdentifierNamed(left, name)) {
80
+ searchValueNode = right;
81
+ parameterInBinaryExpression = left;
82
+ } else if (isIdentifierNamed(right, name)) {
83
+ searchValueNode = left;
84
+ parameterInBinaryExpression = right;
85
+ } else {
86
+ return;
87
+ }
88
+
89
+ const callbackScope = scopeManager.acquire(callback);
90
+ if (
91
+ // `parameter` is used somewhere else
92
+ findVariable(callbackScope, parameter).references.some(({identifier}) => identifier !== parameterInBinaryExpression)
93
+ || isFunctionSelfUsedInside(callback, callbackScope)
94
+ ) {
95
+ return;
96
+ }
97
+
98
+ const methodNode = callExpression.callee.property;
99
+ const problem = {
100
+ node: methodNode,
101
+ messageId: ERROR,
102
+ suggest: [],
103
+ };
104
+
105
+ const fix = function * (fixer) {
106
+ let text = sourceCode.getText(searchValueNode);
107
+ if (isParenthesized(searchValueNode, sourceCode) && !isParenthesized(callback, sourceCode)) {
108
+ text = `(${text})`;
109
+ }
110
+
111
+ yield fixer.replaceText(methodNode, replacement);
112
+ yield fixer.replaceText(callback, text);
113
+ };
114
+
115
+ if (hasSideEffect(searchValueNode, sourceCode)) {
116
+ problem.suggest.push({messageId: SUGGESTION, fix});
117
+ } else {
118
+ problem.fix = fix;
119
+ }
120
+
121
+ return problem;
122
+ });
123
+ }
124
+
125
+ return {messages, listen};
126
+ }
127
+
128
+ module.exports = simpleArraySearchRule;
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+
3
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray#description
4
+ module.exports = [
5
+ 'Int8Array',
6
+ 'Uint8Array',
7
+ 'Uint8ClampedArray',
8
+ 'Int16Array',
9
+ 'Uint16Array',
10
+ 'Int32Array',
11
+ 'Uint32Array',
12
+ 'Float32Array',
13
+ 'Float64Array',
14
+ 'BigInt64Array',
15
+ 'BigUint64Array',
16
+ ];
@@ -0,0 +1,187 @@
1
+ 'use strict';
2
+ const escapeString = require('./utils/escape-string.js');
3
+ const escapeTemplateElementRaw = require('./utils/escape-template-element-raw.js');
4
+ const {replaceTemplateElement} = require('./fix/index.js');
5
+
6
+ const defaultMessage = 'Prefer `{{suggest}}` over `{{match}}`.';
7
+ const SUGGESTION_MESSAGE_ID = 'replace';
8
+ const messages = {
9
+ [SUGGESTION_MESSAGE_ID]: 'Replace `{{match}}` with `{{suggest}}`.',
10
+ };
11
+
12
+ const ignoredIdentifier = new Set([
13
+ 'gql',
14
+ 'html',
15
+ 'svg',
16
+ ]);
17
+
18
+ const ignoredMemberExpressionObject = new Set([
19
+ 'styled',
20
+ ]);
21
+
22
+ const isIgnoredTag = node => {
23
+ if (!node.parent || !node.parent.parent || !node.parent.parent.tag) {
24
+ return false;
25
+ }
26
+
27
+ const {tag} = node.parent.parent;
28
+
29
+ if (tag.type === 'Identifier' && ignoredIdentifier.has(tag.name)) {
30
+ return true;
31
+ }
32
+
33
+ if (tag.type === 'MemberExpression') {
34
+ const {object} = tag;
35
+ if (
36
+ object.type === 'Identifier'
37
+ && ignoredMemberExpressionObject.has(object.name)
38
+ ) {
39
+ return true;
40
+ }
41
+ }
42
+
43
+ return false;
44
+ };
45
+
46
+ function getReplacements(patterns) {
47
+ return Object.entries(patterns)
48
+ .map(([match, options]) => {
49
+ if (typeof options === 'string') {
50
+ options = {
51
+ suggest: options,
52
+ };
53
+ }
54
+
55
+ return {
56
+ match,
57
+ regex: new RegExp(match, 'gu'),
58
+ fix: true,
59
+ ...options,
60
+ };
61
+ });
62
+ }
63
+
64
+ /** @param {import('eslint').Rule.RuleContext} context */
65
+ const create = context => {
66
+ const {patterns} = {
67
+ patterns: {},
68
+ ...context.options[0],
69
+ };
70
+ const replacements = getReplacements(patterns);
71
+
72
+ if (replacements.length === 0) {
73
+ return;
74
+ }
75
+
76
+ context.on(['Literal', 'TemplateElement'], node => {
77
+ const {type, value, raw} = node;
78
+
79
+ let string;
80
+ if (type === 'Literal') {
81
+ string = value;
82
+ } else if (!isIgnoredTag(node)) {
83
+ string = value.raw;
84
+ }
85
+
86
+ if (!string || typeof string !== 'string') {
87
+ return;
88
+ }
89
+
90
+ const replacement = replacements.find(({regex}) => regex.test(string));
91
+
92
+ if (!replacement) {
93
+ return;
94
+ }
95
+
96
+ const {fix: autoFix, message = defaultMessage, match, suggest, regex} = replacement;
97
+ const problem = {
98
+ node,
99
+ message,
100
+ data: {
101
+ match,
102
+ suggest,
103
+ },
104
+ };
105
+
106
+ const fixed = string.replace(regex, suggest);
107
+ const fix = type === 'Literal'
108
+ ? fixer => {
109
+ const [quote] = raw;
110
+ return fixer.replaceText(
111
+ node,
112
+ node.parent.type === 'JSXAttribute' ? quote + fixed + quote : escapeString(fixed, quote),
113
+ );
114
+ }
115
+ : fixer => replaceTemplateElement(
116
+ fixer,
117
+ node,
118
+ escapeTemplateElementRaw(fixed),
119
+ );
120
+
121
+ if (autoFix) {
122
+ problem.fix = fix;
123
+ } else {
124
+ problem.suggest = [
125
+ {
126
+ messageId: SUGGESTION_MESSAGE_ID,
127
+ fix,
128
+ },
129
+ ];
130
+ }
131
+
132
+ return problem;
133
+ });
134
+ };
135
+
136
+ const schema = [
137
+ {
138
+ type: 'object',
139
+ additionalProperties: false,
140
+ properties: {
141
+ patterns: {
142
+ type: 'object',
143
+ additionalProperties: {
144
+ anyOf: [
145
+ {
146
+ type: 'string',
147
+ },
148
+ {
149
+ type: 'object',
150
+ required: [
151
+ 'suggest',
152
+ ],
153
+ properties: {
154
+ suggest: {
155
+ type: 'string',
156
+ },
157
+ fix: {
158
+ type: 'boolean',
159
+ // Default: true
160
+ },
161
+ message: {
162
+ type: 'string',
163
+ // Default: ''
164
+ },
165
+ },
166
+ additionalProperties: false,
167
+ },
168
+ ],
169
+ }},
170
+ },
171
+ },
172
+ ];
173
+
174
+ /** @type {import('eslint').Rule.RuleModule} */
175
+ module.exports = {
176
+ create,
177
+ meta: {
178
+ type: 'suggestion',
179
+ docs: {
180
+ description: 'Enforce better string content.',
181
+ },
182
+ fixable: 'code',
183
+ hasSuggestions: true,
184
+ schema,
185
+ messages,
186
+ },
187
+ };