esupgrade 2025.19.0 → 2025.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +0 -1
- package/AGENTS.md +10 -0
- package/CONTRIBUTING.md +5 -0
- package/README.md +93 -187
- package/bin/esupgrade.js +3 -11
- package/package.json +1 -1
- package/src/index.js +1 -7
- package/src/newlyAvailable/promiseTry.js +1 -0
- package/src/widelyAvailable/anonymousFunctionToArrow.js +1 -0
- package/src/widelyAvailable/argumentsToRestParameters.js +2 -2
- package/src/widelyAvailable/arrayConcatToSpread.js +1 -0
- package/src/widelyAvailable/arrayFilterToFind.js +1 -0
- package/src/widelyAvailable/arrayFromForEachToForOf.js +1 -0
- package/src/widelyAvailable/arrayFromToSpread.js +1 -0
- package/src/widelyAvailable/arraySliceToSpread.js +1 -0
- package/src/widelyAvailable/compoundAssignment.js +53 -0
- package/src/widelyAvailable/concatToTemplateLiteral.js +2 -1
- package/src/widelyAvailable/consoleLogToInfo.js +1 -0
- package/src/widelyAvailable/constructorToClass.js +1 -0
- package/src/widelyAvailable/defaultParameterValues.js +1 -0
- package/src/widelyAvailable/forLoopToForOf.js +1 -0
- package/src/widelyAvailable/globalContextToGlobalThis.js +1 -0
- package/src/widelyAvailable/indexOfToIncludes.js +1 -0
- package/src/widelyAvailable/indexOfToStartsWith.js +1 -0
- package/src/widelyAvailable/iterableForEachToForOf.js +1 -0
- package/src/widelyAvailable/lastIndexOfToEndsWith.js +1 -0
- package/src/widelyAvailable/logicalAssignment.js +83 -0
- package/src/widelyAvailable/mathPowToExponentiation.js +1 -0
- package/src/widelyAvailable/namedArrowFunctionToNamedFunction.js +1 -0
- package/src/widelyAvailable/negativeIndexToAt.js +76 -0
- package/src/widelyAvailable/nullishCoalescingOperator.js +1 -0
- package/src/widelyAvailable/numericSeparators.js +67 -0
- package/src/widelyAvailable/objectAssignToSpread.js +1 -0
- package/src/widelyAvailable/objectHasOwn.js +72 -0
- package/src/widelyAvailable/objectKeysForEachToEntries.js +1 -0
- package/src/widelyAvailable/objectKeysMapToValues.js +1 -0
- package/src/widelyAvailable/objectPropertyExtractionToDestructuring.js +1 -0
- package/src/widelyAvailable/optionalChaining.js +1 -0
- package/src/widelyAvailable/promiseToAsyncAwait.js +1 -0
- package/src/widelyAvailable/removeUseStrictFromModules.js +1 -0
- package/src/widelyAvailable/replaceAll.js +171 -0
- package/src/widelyAvailable/substrToSlice.js +1 -0
- package/src/widelyAvailable/substringToStartsWith.js +1 -0
- package/src/widelyAvailable/varToLetOrConst.js +1 -0
- package/src/widelyAvailable.js +6 -0
- package/src/worker.js +2 -2
- package/tests/baseline.test.js +51 -0
- package/tests/cli.test.js +0 -61
- package/tests/general.test.js +5 -6
- package/tests/widelyAvailable/compound-assignment.test.js +89 -0
- package/tests/widelyAvailable/default-parameter-values.test.js +1 -1
- package/tests/widelyAvailable/for-loop-to-for-of.test.js +2 -1
- package/tests/widelyAvailable/logical-assignment.test.js +134 -0
- package/tests/widelyAvailable/negative-index-to-at.test.js +95 -0
- package/tests/widelyAvailable/numeric-separators.test.js +62 -0
- package/tests/widelyAvailable/object-has-own.test.js +74 -0
- package/tests/widelyAvailable/replace-all.test.js +156 -0
- package/src/jQuery/HTMLInputElement.json +0 -389
- package/src/jQuery/addClassToClassList.js +0 -49
- package/src/jQuery/afterToAfter.js +0 -54
- package/src/jQuery/appendToAppend.js +0 -55
- package/src/jQuery/attrToGetSetRemove.js +0 -52
- package/src/jQuery/beforeToBefore.js +0 -47
- package/src/jQuery/childrenToChildrenArray.js +0 -48
- package/src/jQuery/clickToAddEventListener.js +0 -52
- package/src/jQuery/closestToClosest.js +0 -43
- package/src/jQuery/cssToStyleAndComputed.js +0 -120
- package/src/jQuery/eachToForOf.js +0 -92
- package/src/jQuery/emptyToReplaceChildren.js +0 -33
- package/src/jQuery/findToQuerySelectorAll.js +0 -57
- package/src/jQuery/hasClassToClassListContains.js +0 -36
- package/src/jQuery/htmlToInnerHTML.js +0 -61
- package/src/jQuery/idSelectorToGetElementById.js +0 -54
- package/src/jQuery/inArrayToIncludes.js +0 -77
- package/src/jQuery/nextToNextElementSibling.js +0 -78
- package/src/jQuery/offToRemoveEventListener.js +0 -36
- package/src/jQuery/onToAddEventListener.js +0 -51
- package/src/jQuery/parentToParentElement.js +0 -60
- package/src/jQuery/prependToPrepend.js +0 -54
- package/src/jQuery/prevToPreviousElementSibling.js +0 -76
- package/src/jQuery/propToDirectProperty.js +0 -175
- package/src/jQuery/readyToDOMContentLoaded.js +0 -78
- package/src/jQuery/removeClassToClassList.js +0 -45
- package/src/jQuery/removeToRemove.js +0 -49
- package/src/jQuery/selectorToQuerySelectorAll.js +0 -68
- package/src/jQuery/showHideToStyleDisplay.js +0 -56
- package/src/jQuery/siblingsToSiblingsArray.js +0 -70
- package/src/jQuery/staticEachToForEach.js +0 -42
- package/src/jQuery/staticGrepToFilter.js +0 -36
- package/src/jQuery/staticMapToMap.js +0 -33
- package/src/jQuery/textToTextContent.js +0 -49
- package/src/jQuery/toggleClassToClassList.js +0 -36
- package/src/jQuery/triggerToDispatchEvent.js +0 -65
- package/src/jQuery/trimToStringTrim.js +0 -30
- package/src/jQuery/unwrapJQueryIdentifier.js +0 -51
- package/src/jQuery/utils.js +0 -384
- package/src/jQuery/valToValue.js +0 -40
- package/src/jQuery/widthHeightToClient.js +0 -49
- package/src/jQuery.js +0 -46
- package/tests/jQuery/addClassToClassList.test.js +0 -34
- package/tests/jQuery/afterToAfter.test.js +0 -38
- package/tests/jQuery/appendToAppend.test.js +0 -44
- package/tests/jQuery/attrToGetSetRemove.test.js +0 -44
- package/tests/jQuery/beforeToBefore.test.js +0 -44
- package/tests/jQuery/childrenToChildrenArray.test.js +0 -32
- package/tests/jQuery/clickToAddEventListener.test.js +0 -44
- package/tests/jQuery/closestToClosest.test.js +0 -38
- package/tests/jQuery/cssToStyleAndComputed.test.js +0 -71
- package/tests/jQuery/eachToForOf.test.js +0 -57
- package/tests/jQuery/emptyToReplaceChildren.test.js +0 -26
- package/tests/jQuery/findToQuerySelectorAll.test.js +0 -47
- package/tests/jQuery/hasClassToClassListContains.test.js +0 -41
- package/tests/jQuery/htmlToInnerHTML.test.js +0 -38
- package/tests/jQuery/idSelectorToGetElementById.test.js +0 -31
- package/tests/jQuery/inArrayToIncludes.test.js +0 -69
- package/tests/jQuery/nextToNextElementSibling.test.js +0 -37
- package/tests/jQuery/offToRemoveEventListener.test.js +0 -43
- package/tests/jQuery/onToAddEventListener.test.js +0 -41
- package/tests/jQuery/parentToParentElement.test.js +0 -34
- package/tests/jQuery/prependToPrepend.test.js +0 -32
- package/tests/jQuery/prevToPreviousElementSibling.test.js +0 -37
- package/tests/jQuery/propToDirectProperty.test.js +0 -65
- package/tests/jQuery/readyToDOMContentLoaded.test.js +0 -40
- package/tests/jQuery/removeClassToClassList.test.js +0 -47
- package/tests/jQuery/removeToRemove.test.js +0 -26
- package/tests/jQuery/selectorToQuerySelectorAll.test.js +0 -36
- package/tests/jQuery/showHideToStyleDisplay.test.js +0 -38
- package/tests/jQuery/siblingsToSiblingsArray.test.js +0 -32
- package/tests/jQuery/staticEachToForEach.test.js +0 -80
- package/tests/jQuery/staticGrepToFilter.test.js +0 -50
- package/tests/jQuery/staticMapToMap.test.js +0 -56
- package/tests/jQuery/textToTextContent.test.js +0 -38
- package/tests/jQuery/toggleClassToClassList.test.js +0 -38
- package/tests/jQuery/triggerToDispatchEvent.test.js +0 -45
- package/tests/jQuery/trimToStringTrim.test.js +0 -32
- package/tests/jQuery/unwrapJQueryIdentifier.test.js +0 -26
- package/tests/jQuery/utils.test.js +0 -283
- package/tests/jQuery/valToValue.test.js +0 -38
- package/tests/jQuery/widthHeightToClient.test.js +0 -38
package/.gitattributes
CHANGED
package/AGENTS.md
CHANGED
|
@@ -31,3 +31,13 @@ console.log('modified:', res.modified);
|
|
|
31
31
|
console.log('code:\n' + res.code);
|
|
32
32
|
EOF
|
|
33
33
|
```
|
|
34
|
+
|
|
35
|
+
## Writing Transformers
|
|
36
|
+
|
|
37
|
+
Transformers must only apply to types that are statically verifiable. Use `NodeTest` from
|
|
38
|
+
`src/types.js` to guard transformations:
|
|
39
|
+
|
|
40
|
+
- `new NodeTest(node).isIterable()` — array literals, `new Array()`, `Array.from()`, and `Array.of()`. Use this when the transformation is array-specific (e.g., index access, `.at()`).
|
|
41
|
+
- `new NodeTest(node).hasIndexOfAndIncludes()` — arrays and strings (includes string literals and array method chains like `.map()`, `.filter()`). Use this when the transformation applies to both arrays and strings.
|
|
42
|
+
|
|
43
|
+
Never apply a transformation based solely on structural shape (e.g., a `.length` property or bracket access) without first verifying the receiver is a known type. An unknown identifier such as `arr` cannot be assumed to be an array and must not be transformed.
|
package/CONTRIBUTING.md
CHANGED
|
@@ -24,3 +24,8 @@ uvx pre-commit run --all-files
|
|
|
24
24
|
## Naming conversions
|
|
25
25
|
|
|
26
26
|
When writing code, please follow the [naming guidelines](https://raw.githubusercontent.com/codingjoe/naming-things/refs/heads/main/README.md).
|
|
27
|
+
|
|
28
|
+
## Baselines release dates
|
|
29
|
+
|
|
30
|
+
The `baselineDate` can be found on
|
|
31
|
+
https://github.com/web-platform-dx/web-features named `baseline_low_date`.
|
package/README.md
CHANGED
|
@@ -215,6 +215,18 @@ Supports:
|
|
|
215
215
|
+const withItem = [...array, item];
|
|
216
216
|
```
|
|
217
217
|
|
|
218
|
+
#### `1000000` → [Numeric separators][mdn-numeric-separators]
|
|
219
|
+
|
|
220
|
+
```diff
|
|
221
|
+
-const budget = 1000000;
|
|
222
|
+
-const maxUsers = 1000000n;
|
|
223
|
+
+const budget = 1_000_000;
|
|
224
|
+
+const maxUsers = 1_000_000n;
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
esupgrade transforms decimal integer and bigint literals with at least five digits.
|
|
228
|
+
Fractional, exponential, hexadecimal, octal, binary, and already formatted literals are left unchanged.
|
|
229
|
+
|
|
218
230
|
#### `Array.slice(0)` → [Array spread [...]][mdn-spread]
|
|
219
231
|
|
|
220
232
|
```diff
|
|
@@ -231,9 +243,16 @@ Supports:
|
|
|
231
243
|
+const first = [1, 2, 3].find(n => n > 1);
|
|
232
244
|
```
|
|
233
245
|
|
|
234
|
-
|
|
246
|
+
Transformations are limited to when the receiver can be verified as an array (array literals, `new Array()`, or known array method chains) and `filter()` is called with one argument.
|
|
247
|
+
|
|
248
|
+
#### `arr[arr.length - n]` → [`Array.at()`][mdn-at]
|
|
235
249
|
|
|
236
|
-
|
|
250
|
+
```diff
|
|
251
|
+
-const last = arr[arr.length - 1];
|
|
252
|
+
-const item = arr[arr.length - n];
|
|
253
|
+
+const last = arr.at(-1);
|
|
254
|
+
+const item = arr.at(-n);
|
|
255
|
+
```
|
|
237
256
|
|
|
238
257
|
#### `Math.pow()` → [Exponentiation operator \*\*][mdn-exponentiation]
|
|
239
258
|
|
|
@@ -244,6 +263,31 @@ Transformations are limited to when the receiver can be verified as an array (ar
|
|
|
244
263
|
+const area = Math.PI * radius ** 2;
|
|
245
264
|
```
|
|
246
265
|
|
|
266
|
+
#### Verbose arithmetic assignments → [Compound assignment operators (+=, -=, …)][mdn-compound-assignment]
|
|
267
|
+
|
|
268
|
+
```diff
|
|
269
|
+
-x = x + y
|
|
270
|
+
+x += y
|
|
271
|
+
-x = x - y
|
|
272
|
+
+x -= y
|
|
273
|
+
-x = x * y
|
|
274
|
+
+x *= y
|
|
275
|
+
-x = x / y
|
|
276
|
+
+x /= y
|
|
277
|
+
-x = x % y
|
|
278
|
+
+x %= y
|
|
279
|
+
-x = x ** y
|
|
280
|
+
+x **= y
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
> [!NOTE]
|
|
284
|
+
> When the assignment target is a member expression with potential side effects
|
|
285
|
+
> (e.g., `getObj().prop = getObj().prop + y` or `obj[f()] = obj[f()] + y`), the
|
|
286
|
+
> transformation evaluates the target expression once instead of twice.
|
|
287
|
+
> If `getObj()` or `f()` have observable side effects or return different values
|
|
288
|
+
> on each call, `getObj().prop += y` may produce different results than the
|
|
289
|
+
> original `getObj().prop = getObj().prop + y`.
|
|
290
|
+
|
|
247
291
|
#### Named function assignments → [Function declarations][mdn-functions]
|
|
248
292
|
|
|
249
293
|
```diff
|
|
@@ -397,6 +441,32 @@ ES6 modules are automatically in strict mode, making explicit `'use strict'` dir
|
|
|
397
441
|
+const result = obj.prop ?? 0;
|
|
398
442
|
```
|
|
399
443
|
|
|
444
|
+
#### Logical assignment patterns → [Logical assignment operators (??=, ||=, &&=)][mdn-logical-assignment]
|
|
445
|
+
|
|
446
|
+
```diff
|
|
447
|
+
-x = x ?? y
|
|
448
|
+
+x ??= y
|
|
449
|
+
-x = x || y
|
|
450
|
+
+x ||= y
|
|
451
|
+
-x = x && y
|
|
452
|
+
+x &&= y
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
```diff
|
|
456
|
+
-if (x === null || x === undefined) x = y
|
|
457
|
+
+x ??= y
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
> [!NOTE]
|
|
461
|
+
> For member expression targets (e.g., `obj.prop ||= y`), the original
|
|
462
|
+
> unconditional assignment always invokes property setters, while the logical
|
|
463
|
+
> assignment operator skips the setter when the condition is not met. This
|
|
464
|
+
> generally improves performance by avoiding unnecessary setter calls.
|
|
465
|
+
>
|
|
466
|
+
> Similarly, for `if (obj.prop === null || obj.prop === undefined) obj.prop = y`,
|
|
467
|
+
> the transformation to `obj.prop ??= y` reads `obj.prop` once instead of twice
|
|
468
|
+
> before assigning, which improves performance for getter-backed properties.
|
|
469
|
+
|
|
400
470
|
#### `indexOf()` → [includes()][mdn-includes]
|
|
401
471
|
|
|
402
472
|
```diff
|
|
@@ -437,6 +507,15 @@ Transforms the deprecated `substr()` method to `slice()`:
|
|
|
437
507
|
|
|
438
508
|
Transformations are limited to when the receiver can be verified as a string (string literals, template literals, or string method chains).
|
|
439
509
|
|
|
510
|
+
#### `split().join()` / `replace(/literal/g)` → [String.replaceAll()][mdn-replaceall]
|
|
511
|
+
|
|
512
|
+
```diff
|
|
513
|
+
-const value = "a,b,c".split(",").join(".");
|
|
514
|
+
-const label = "foo".replace(/o/g, "a");
|
|
515
|
+
+const value = "a,b,c".replaceAll(",", ".");
|
|
516
|
+
+const label = "foo".replaceAll("o", "a");
|
|
517
|
+
```
|
|
518
|
+
|
|
440
519
|
#### `Object.keys().forEach()` → [Object.entries()][mdn-object-entries]
|
|
441
520
|
|
|
442
521
|
```diff
|
|
@@ -449,8 +528,6 @@ Transformations are limited to when the receiver can be verified as a string (st
|
|
|
449
528
|
+});
|
|
450
529
|
```
|
|
451
530
|
|
|
452
|
-
Transforms Object.keys() iteration patterns where the value is accessed from the same object into Object.entries() with array destructuring. This eliminates duplicate property lookups and makes the code more concise.
|
|
453
|
-
|
|
454
531
|
Transforms when:
|
|
455
532
|
|
|
456
533
|
- The callback has one parameter (the key)
|
|
@@ -464,11 +541,9 @@ Transforms when:
|
|
|
464
541
|
+Object.values(obj)
|
|
465
542
|
```
|
|
466
543
|
|
|
467
|
-
Transforms `Object.keys(obj).map(key => obj[key])` patterns to use `Object.values()` directly. This eliminates redundant property lookups and expresses intent more clearly.
|
|
468
|
-
|
|
469
544
|
Transforms when:
|
|
470
545
|
|
|
471
|
-
- The callback has
|
|
546
|
+
- The callback has one parameter (the key)
|
|
472
547
|
- The callback body returns `obj[key]` (expression or block with a single return statement)
|
|
473
548
|
- The object being accessed matches the object passed to Object.keys()
|
|
474
549
|
|
|
@@ -628,187 +703,13 @@ These transformations are mainly to harden code for future releases and should b
|
|
|
628
703
|
+});
|
|
629
704
|
```
|
|
630
705
|
|
|
631
|
-
|
|
632
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://jquery.com/wp-content/themes/jquery/images/logo-jquery@2x.png">
|
|
633
|
-
<source media="(prefers-color-scheme: light)" srcset="https://upload.wikimedia.org/wikipedia/commons/f/fd/JQuery-Logo.svg">
|
|
634
|
-
<img alt="jQuery logo" src="https://upload.wikimedia.org/wikipedia/commons/f/fd/JQuery-Logo.svg" height="32" align="right">
|
|
635
|
-
</picture>
|
|
636
|
-
|
|
637
|
-
## jQuery
|
|
638
|
-
|
|
639
|
-
esupgrade can transform common [jQuery] patterns to modern, standards-based DOM APIs via the `--jQuery` argument.
|
|
640
|
-
For further reading, we recommend: [You Might Not Need jQuery](https://youmightnotneedjquery.com/).
|
|
641
|
-
|
|
642
|
-
```bash
|
|
643
|
-
npx esupgrade --jQuery <files>
|
|
644
|
-
```
|
|
645
|
-
|
|
646
|
-
> [!WARNING]
|
|
647
|
-
> jQuery transformers are experimental and may produce unsafe code in complex scenarios.
|
|
648
|
-
> Review all changes before applying them to your codebase.
|
|
649
|
-
|
|
650
|
-
### Selection
|
|
651
|
-
|
|
652
|
-
#### `$(selector)` → `document.querySelectorAll()` / `document.getElementById()`
|
|
653
|
-
|
|
654
|
-
```diff
|
|
655
|
-
-$('.foo')
|
|
656
|
-
- $('#bar')
|
|
657
|
-
+document.querySelectorAll('.foo')
|
|
658
|
-
+document.getElementById('bar')
|
|
659
|
-
```
|
|
660
|
-
|
|
661
|
-
Skipped when jQuery chaining is present (e.g. `$('.x').css(...).addClass(...)`).
|
|
662
|
-
|
|
663
|
-
### Class and Attributes
|
|
664
|
-
|
|
665
|
-
#### Class helpers
|
|
666
|
-
|
|
667
|
-
```diff
|
|
668
|
-
-$(el).addClass('a b');
|
|
669
|
-
-$(el).removeClass('a');
|
|
670
|
-
-$(el).toggleClass('x');
|
|
671
|
-
-$(el).hasClass('x');
|
|
672
|
-
+el.classList.add('a', 'b');
|
|
673
|
-
+el.classList.remove('a');
|
|
674
|
-
+el.classList.toggle('x');
|
|
675
|
-
+el.classList.contains('x');
|
|
676
|
-
```
|
|
677
|
-
|
|
678
|
-
#### Attribute helpers
|
|
679
|
-
|
|
680
|
-
```diff
|
|
681
|
-
-$(el).attr('data');
|
|
682
|
-
-$(el).attr('data', v);
|
|
683
|
-
-$(el).removeAttr('disabled');
|
|
684
|
-
+el.getAttribute('data');
|
|
685
|
-
+el.setAttribute('data', v);
|
|
686
|
-
+el.removeAttribute('disabled');
|
|
687
|
-
```
|
|
688
|
-
|
|
689
|
-
### Content and Value
|
|
690
|
-
|
|
691
|
-
#### Text and HTML accessors
|
|
692
|
-
|
|
693
|
-
```diff
|
|
694
|
-
-const text = $(el).text();
|
|
695
|
-
-$(el).text('new text');
|
|
696
|
-
-const html = $(el).html();
|
|
697
|
-
-$(el).html('<b>bold</b>');
|
|
698
|
-
+const text = el.textContent;
|
|
699
|
-
+el.textContent = 'new text';
|
|
700
|
-
+const html = el.innerHTML;
|
|
701
|
-
+el.innerHTML = '<b>bold</b>';
|
|
702
|
-
```
|
|
703
|
-
|
|
704
|
-
#### Value accessors
|
|
705
|
-
|
|
706
|
-
```diff
|
|
707
|
-
-const val = $(el).val();
|
|
708
|
-
-$(el).val('new value');
|
|
709
|
-
+const val = el.value;
|
|
710
|
-
+el.value = 'new value';
|
|
711
|
-
```
|
|
712
|
-
|
|
713
|
-
### DOM Manipulation
|
|
714
|
-
|
|
715
|
-
#### Insertion and Removal
|
|
716
|
-
|
|
717
|
-
```diff
|
|
718
|
-
-$(parent).append(child);
|
|
719
|
-
-$(parent).prepend(child);
|
|
720
|
-
-$(el).before(node);
|
|
721
|
-
-$(el).after(node);
|
|
722
|
-
-$(el).remove();
|
|
723
|
-
-$(el).empty();
|
|
724
|
-
+parent.append(child);
|
|
725
|
-
+parent.prepend(child);
|
|
726
|
-
+el.before(node);
|
|
727
|
-
+el.after(node);
|
|
728
|
-
+el.remove();
|
|
729
|
-
+el.replaceChildren();
|
|
730
|
-
```
|
|
731
|
-
|
|
732
|
-
### Events
|
|
733
|
-
|
|
734
|
-
#### Event Listeners
|
|
735
|
-
|
|
736
|
-
```diff
|
|
737
|
-
-$(el).on('click', handler);
|
|
738
|
-
-$(el).off('click', handler);
|
|
739
|
-
-$(el).click(handler);
|
|
740
|
-
+el.addEventListener('click', handler);
|
|
741
|
-
+el.removeEventListener('click', handler);
|
|
742
|
-
+el.addEventListener('click', handler);
|
|
743
|
-
```
|
|
744
|
-
|
|
745
|
-
#### Dispatching and Ready
|
|
746
|
-
|
|
747
|
-
```diff
|
|
748
|
-
-$(el).trigger('custom');
|
|
749
|
-
-$(document).ready(fn);
|
|
750
|
-
+el.dispatchEvent(new CustomEvent('custom'));
|
|
751
|
-
+document.addEventListener('DOMContentLoaded', fn);
|
|
752
|
-
```
|
|
753
|
-
|
|
754
|
-
### Traversal
|
|
755
|
-
|
|
756
|
-
#### Traversal helpers
|
|
757
|
-
|
|
758
|
-
```diff
|
|
759
|
-
-$(el).find('.sel');
|
|
760
|
-
-$(el).parent();
|
|
761
|
-
-$(el).closest('.sel');
|
|
762
|
-
-$(el).next();
|
|
763
|
-
-$(el).prev();
|
|
764
|
-
-$(el).children();
|
|
765
|
-
-$(el).siblings();
|
|
766
|
-
+el.querySelectorAll('.sel');
|
|
767
|
-
+el.parentElement;
|
|
768
|
-
+el.closest('.sel');
|
|
769
|
-
+el.nextElementSibling;
|
|
770
|
-
+el.previousElementSibling;
|
|
771
|
-
+Array.from(el.children);
|
|
772
|
-
+Array.from(el.parentElement.children).filter(c => c !== el);
|
|
773
|
-
```
|
|
774
|
-
|
|
775
|
-
### Style and Sizing
|
|
776
|
-
|
|
777
|
-
#### CSS and Display
|
|
778
|
-
|
|
779
|
-
```diff
|
|
780
|
-
-$(el).css('color');
|
|
781
|
-
-$(el).css('color', 'red');
|
|
782
|
-
-$(el).show();
|
|
783
|
-
-$(el).hide();
|
|
784
|
-
+getComputedStyle(el).color;
|
|
785
|
-
+el.style.color = 'red';
|
|
786
|
-
+el.style.display = '';
|
|
787
|
-
+el.style.display = 'none';
|
|
788
|
-
```
|
|
789
|
-
|
|
790
|
-
#### Dimensions
|
|
791
|
-
|
|
792
|
-
```diff
|
|
793
|
-
-$(el).width();
|
|
794
|
-
-$(el).height();
|
|
795
|
-
+el.clientWidth;
|
|
796
|
-
+el.clientHeight;
|
|
797
|
-
```
|
|
798
|
-
|
|
799
|
-
### Static Utilities
|
|
800
|
-
|
|
801
|
-
#### Collection and String utilities
|
|
706
|
+
#### `Object.prototype.hasOwnProperty.call()` → [Object.hasOwn()][mdn-object-has-own]
|
|
802
707
|
|
|
803
708
|
```diff
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
+array.forEach(fn);
|
|
809
|
-
+array.map(fn);
|
|
810
|
-
+array.includes(val);
|
|
811
|
-
+str.trim();
|
|
709
|
+
-Object.prototype.hasOwnProperty.call(obj, prop);
|
|
710
|
+
-({}).hasOwnProperty.call(obj, prop);
|
|
711
|
+
+Object.hasOwn(obj, prop);
|
|
712
|
+
+Object.hasOwn(obj, prop);
|
|
812
713
|
```
|
|
813
714
|
|
|
814
715
|
## Versioning
|
|
@@ -833,10 +734,11 @@ Furthermore, esupgrade supports JavaScript, TypeScript, and more, while lebab is
|
|
|
833
734
|
[baseline]: https://web.dev/baseline/
|
|
834
735
|
[calver]: https://calver.org/
|
|
835
736
|
[django-upgrade]: https://github.com/adamchainz/django-upgrade
|
|
836
|
-
[jquery]: https://jquery.com/
|
|
837
737
|
[mdn-arrow-functions]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
|
|
838
738
|
[mdn-async-await]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
|
|
739
|
+
[mdn-at]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at
|
|
839
740
|
[mdn-classes]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
|
|
741
|
+
[mdn-compound-assignment]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Addition_assignment
|
|
840
742
|
[mdn-console]: https://developer.mozilla.org/en-US/docs/Web/API/console
|
|
841
743
|
[mdn-const]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
|
|
842
744
|
[mdn-default-parameters]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters
|
|
@@ -849,10 +751,14 @@ Furthermore, esupgrade supports JavaScript, TypeScript, and more, while lebab is
|
|
|
849
751
|
[mdn-globalthis]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis
|
|
850
752
|
[mdn-includes]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes
|
|
851
753
|
[mdn-let]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
|
|
754
|
+
[mdn-logical-assignment]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_OR_assignment
|
|
852
755
|
[mdn-nullish-coalescing]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing
|
|
756
|
+
[mdn-numeric-separators]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#numeric_separators
|
|
853
757
|
[mdn-object-entries]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries
|
|
758
|
+
[mdn-object-has-own]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn
|
|
854
759
|
[mdn-object-values]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values
|
|
855
760
|
[mdn-promise-try]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/try
|
|
761
|
+
[mdn-replaceall]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replaceAll
|
|
856
762
|
[mdn-rest-parameters]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters
|
|
857
763
|
[mdn-slice]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice
|
|
858
764
|
[mdn-spread]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
|
package/bin/esupgrade.js
CHANGED
|
@@ -30,12 +30,11 @@ class WorkerRunner {
|
|
|
30
30
|
* Run a worker thread to process a file.
|
|
31
31
|
* @param {string} filePath - Path to the file to process.
|
|
32
32
|
* @param {string} baseline - Baseline level for transformations.
|
|
33
|
-
* @param {boolean} jQuery - Whether to include jQuery transformers.
|
|
34
33
|
* @returns {Promise<Object>} Worker message result.
|
|
35
34
|
*/
|
|
36
|
-
async run(filePath, baseline
|
|
35
|
+
async run(filePath, baseline) {
|
|
37
36
|
const worker = new Worker(this.workerPath, {
|
|
38
|
-
workerData: { filePath, baseline
|
|
37
|
+
workerData: { filePath, baseline },
|
|
39
38
|
})
|
|
40
39
|
|
|
41
40
|
const [message] = await once(worker, "message")
|
|
@@ -59,7 +58,6 @@ class FileProcessor {
|
|
|
59
58
|
* @param {boolean} options.check - Whether to only check for changes.
|
|
60
59
|
* @param {boolean} options.write - Whether to write changes to file.
|
|
61
60
|
* @param {boolean} options.verbose - The verbosity level for logging.
|
|
62
|
-
* @param {boolean} options.jQuery - Whether to include jQuery transformers.
|
|
63
61
|
* @returns {Promise<{modified: boolean, error: boolean}>} Result of processing.
|
|
64
62
|
*/
|
|
65
63
|
async processFile(filePath, options) {
|
|
@@ -76,11 +74,7 @@ class FileProcessor {
|
|
|
76
74
|
}
|
|
77
75
|
|
|
78
76
|
try {
|
|
79
|
-
const workerResult = await this.workerRunner.run(
|
|
80
|
-
filePath,
|
|
81
|
-
options.baseline,
|
|
82
|
-
options.jQuery,
|
|
83
|
-
)
|
|
77
|
+
const workerResult = await this.workerRunner.run(filePath, options.baseline)
|
|
84
78
|
|
|
85
79
|
if (!workerResult.success) {
|
|
86
80
|
if (options.verbose) console.error(workerResult.error)
|
|
@@ -203,7 +197,6 @@ class CLIRunner {
|
|
|
203
197
|
async run(patterns, options) {
|
|
204
198
|
console.time("Processing")
|
|
205
199
|
// Hand CLI-provided names directly to the worker pool; file validation occurs in processFile.
|
|
206
|
-
// Pass jQuery to worker pool
|
|
207
200
|
const results = await this.workerPool.processFiles(patterns, options)
|
|
208
201
|
console.timeEnd("Processing")
|
|
209
202
|
|
|
@@ -277,7 +270,6 @@ program
|
|
|
277
270
|
false,
|
|
278
271
|
)
|
|
279
272
|
.option("--write", "Write changes to files", false)
|
|
280
|
-
.option("--jquery, --jQuery", "Enable jQuery specific transformers", false)
|
|
281
273
|
.action(async (files, options) => {
|
|
282
274
|
await cliRunner.run(files, options)
|
|
283
275
|
})
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import jscodeshift from "jscodeshift"
|
|
2
2
|
import * as newlyAvailable from "./newlyAvailable.js"
|
|
3
3
|
import * as widelyAvailable from "./widelyAvailable.js"
|
|
4
|
-
import * as jQueryTransformers from "./jQuery.js"
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* Transformer function type.
|
|
@@ -49,10 +48,9 @@ function applyTransformersRecursively(code, j, transformers, globalModified = fa
|
|
|
49
48
|
*
|
|
50
49
|
* @param {string} code - The source code to transform.
|
|
51
50
|
* @param {string} baseline - Baseline level ('widely-available' or 'newly-available').
|
|
52
|
-
* @param {boolean} jQuery - Whether to include jQuery transformers.
|
|
53
51
|
* @returns {TransformResult} Object with transformed code and modification status.
|
|
54
52
|
*/
|
|
55
|
-
export function transform(code, baseline = "widely-available"
|
|
53
|
+
export function transform(code, baseline = "widely-available") {
|
|
56
54
|
const j = jscodeshift.withParser("tsx")
|
|
57
55
|
|
|
58
56
|
let transformers =
|
|
@@ -60,9 +58,5 @@ export function transform(code, baseline = "widely-available", jQuery) {
|
|
|
60
58
|
? { ...widelyAvailable, ...newlyAvailable }
|
|
61
59
|
: widelyAvailable
|
|
62
60
|
|
|
63
|
-
if (jQuery) {
|
|
64
|
-
transformers = { ...transformers, ...jQueryTransformers }
|
|
65
|
-
}
|
|
66
|
-
|
|
67
61
|
return applyTransformersRecursively(code, j, Object.values(transformers))
|
|
68
62
|
}
|
|
@@ -26,8 +26,7 @@ export function argumentsToRestParameters(root) {
|
|
|
26
26
|
|
|
27
27
|
functionNodes.forEach(({ node: func }) => {
|
|
28
28
|
if (
|
|
29
|
-
(func.params.length > 0 &&
|
|
30
|
-
j.RestElement.check(func.params[func.params.length - 1])) ||
|
|
29
|
+
(func.params.length > 0 && j.RestElement.check(func.params.at(-1))) ||
|
|
31
30
|
!j.BlockStatement.check(func.body)
|
|
32
31
|
) {
|
|
33
32
|
return
|
|
@@ -86,3 +85,4 @@ export function argumentsToRestParameters(root) {
|
|
|
86
85
|
|
|
87
86
|
return modified
|
|
88
87
|
}
|
|
88
|
+
argumentsToRestParameters.baselineDate = new Date(Date.UTC(2016, 8, 20))
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { default as j } from "jscodeshift"
|
|
2
|
+
import { NodeTest } from "../types.js"
|
|
3
|
+
|
|
4
|
+
const BINARY_TO_COMPOUND = new Map([
|
|
5
|
+
["+", "+="],
|
|
6
|
+
["-", "-="],
|
|
7
|
+
["*", "*="],
|
|
8
|
+
["/", "/="],
|
|
9
|
+
["%", "%="],
|
|
10
|
+
["**", "**="],
|
|
11
|
+
])
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Transform verbose assignment patterns to compound assignment operators.
|
|
15
|
+
*
|
|
16
|
+
* Transforms:
|
|
17
|
+
* - `x = x + y` → `x += y`
|
|
18
|
+
* - `x = x - y` → `x -= y`
|
|
19
|
+
* - `x = x * y` → `x *= y`
|
|
20
|
+
* - `x = x / y` → `x /= y`
|
|
21
|
+
* - `x = x % y` → `x %= y`
|
|
22
|
+
* - `x = x ** y` → `x **= y`
|
|
23
|
+
*
|
|
24
|
+
* @param {import("jscodeshift").Collection} root - The root AST collection
|
|
25
|
+
* @returns {boolean} True if code was modified
|
|
26
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Addition_assignment
|
|
27
|
+
*/
|
|
28
|
+
export function compoundAssignment(root) {
|
|
29
|
+
let modified = false
|
|
30
|
+
|
|
31
|
+
root
|
|
32
|
+
.find(j.AssignmentExpression, { operator: "=" })
|
|
33
|
+
.filter(({ node }) => {
|
|
34
|
+
if (!j.BinaryExpression.check(node.right)) return false
|
|
35
|
+
const op = node.right.operator
|
|
36
|
+
if (!BINARY_TO_COMPOUND.has(op)) return false
|
|
37
|
+
return new NodeTest(node.left).isEqual(node.right.left)
|
|
38
|
+
})
|
|
39
|
+
.forEach((path) => {
|
|
40
|
+
const { node } = path
|
|
41
|
+
const op = node.right.operator
|
|
42
|
+
const right = node.right.right
|
|
43
|
+
|
|
44
|
+
j(path).replaceWith(
|
|
45
|
+
j.assignmentExpression(BINARY_TO_COMPOUND.get(op), node.left, right),
|
|
46
|
+
)
|
|
47
|
+
modified = true
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
return modified
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
compoundAssignment.baselineDate = new Date(Date.UTC(1997, 5, 1))
|
|
@@ -40,7 +40,7 @@ export function concatToTemplateLiteral(root) {
|
|
|
40
40
|
if (parts.length === 0 || expressions.length >= parts.length) {
|
|
41
41
|
parts.push({ raw: rawValue, cooked: cookedValue })
|
|
42
42
|
} else {
|
|
43
|
-
const lastPart = parts
|
|
43
|
+
const lastPart = parts.at(-1)
|
|
44
44
|
if (needsLineContinuation) {
|
|
45
45
|
// Add backslash and newline for line continuation
|
|
46
46
|
// But if the last part already ends with a newline, don't add another backslash+newline
|
|
@@ -127,3 +127,4 @@ ${rawValue}`
|
|
|
127
127
|
|
|
128
128
|
return modified
|
|
129
129
|
}
|
|
130
|
+
concatToTemplateLiteral.baselineDate = new Date(Date.UTC(2015, 8, 30))
|