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.
Files changed (139) hide show
  1. package/.gitattributes +0 -1
  2. package/AGENTS.md +10 -0
  3. package/CONTRIBUTING.md +5 -0
  4. package/README.md +93 -187
  5. package/bin/esupgrade.js +3 -11
  6. package/package.json +1 -1
  7. package/src/index.js +1 -7
  8. package/src/newlyAvailable/promiseTry.js +1 -0
  9. package/src/widelyAvailable/anonymousFunctionToArrow.js +1 -0
  10. package/src/widelyAvailable/argumentsToRestParameters.js +2 -2
  11. package/src/widelyAvailable/arrayConcatToSpread.js +1 -0
  12. package/src/widelyAvailable/arrayFilterToFind.js +1 -0
  13. package/src/widelyAvailable/arrayFromForEachToForOf.js +1 -0
  14. package/src/widelyAvailable/arrayFromToSpread.js +1 -0
  15. package/src/widelyAvailable/arraySliceToSpread.js +1 -0
  16. package/src/widelyAvailable/compoundAssignment.js +53 -0
  17. package/src/widelyAvailable/concatToTemplateLiteral.js +2 -1
  18. package/src/widelyAvailable/consoleLogToInfo.js +1 -0
  19. package/src/widelyAvailable/constructorToClass.js +1 -0
  20. package/src/widelyAvailable/defaultParameterValues.js +1 -0
  21. package/src/widelyAvailable/forLoopToForOf.js +1 -0
  22. package/src/widelyAvailable/globalContextToGlobalThis.js +1 -0
  23. package/src/widelyAvailable/indexOfToIncludes.js +1 -0
  24. package/src/widelyAvailable/indexOfToStartsWith.js +1 -0
  25. package/src/widelyAvailable/iterableForEachToForOf.js +1 -0
  26. package/src/widelyAvailable/lastIndexOfToEndsWith.js +1 -0
  27. package/src/widelyAvailable/logicalAssignment.js +83 -0
  28. package/src/widelyAvailable/mathPowToExponentiation.js +1 -0
  29. package/src/widelyAvailable/namedArrowFunctionToNamedFunction.js +1 -0
  30. package/src/widelyAvailable/negativeIndexToAt.js +76 -0
  31. package/src/widelyAvailable/nullishCoalescingOperator.js +1 -0
  32. package/src/widelyAvailable/numericSeparators.js +67 -0
  33. package/src/widelyAvailable/objectAssignToSpread.js +1 -0
  34. package/src/widelyAvailable/objectHasOwn.js +72 -0
  35. package/src/widelyAvailable/objectKeysForEachToEntries.js +1 -0
  36. package/src/widelyAvailable/objectKeysMapToValues.js +1 -0
  37. package/src/widelyAvailable/objectPropertyExtractionToDestructuring.js +1 -0
  38. package/src/widelyAvailable/optionalChaining.js +1 -0
  39. package/src/widelyAvailable/promiseToAsyncAwait.js +1 -0
  40. package/src/widelyAvailable/removeUseStrictFromModules.js +1 -0
  41. package/src/widelyAvailable/replaceAll.js +171 -0
  42. package/src/widelyAvailable/substrToSlice.js +1 -0
  43. package/src/widelyAvailable/substringToStartsWith.js +1 -0
  44. package/src/widelyAvailable/varToLetOrConst.js +1 -0
  45. package/src/widelyAvailable.js +6 -0
  46. package/src/worker.js +2 -2
  47. package/tests/baseline.test.js +51 -0
  48. package/tests/cli.test.js +0 -61
  49. package/tests/general.test.js +5 -6
  50. package/tests/widelyAvailable/compound-assignment.test.js +89 -0
  51. package/tests/widelyAvailable/default-parameter-values.test.js +1 -1
  52. package/tests/widelyAvailable/for-loop-to-for-of.test.js +2 -1
  53. package/tests/widelyAvailable/logical-assignment.test.js +134 -0
  54. package/tests/widelyAvailable/negative-index-to-at.test.js +95 -0
  55. package/tests/widelyAvailable/numeric-separators.test.js +62 -0
  56. package/tests/widelyAvailable/object-has-own.test.js +74 -0
  57. package/tests/widelyAvailable/replace-all.test.js +156 -0
  58. package/src/jQuery/HTMLInputElement.json +0 -389
  59. package/src/jQuery/addClassToClassList.js +0 -49
  60. package/src/jQuery/afterToAfter.js +0 -54
  61. package/src/jQuery/appendToAppend.js +0 -55
  62. package/src/jQuery/attrToGetSetRemove.js +0 -52
  63. package/src/jQuery/beforeToBefore.js +0 -47
  64. package/src/jQuery/childrenToChildrenArray.js +0 -48
  65. package/src/jQuery/clickToAddEventListener.js +0 -52
  66. package/src/jQuery/closestToClosest.js +0 -43
  67. package/src/jQuery/cssToStyleAndComputed.js +0 -120
  68. package/src/jQuery/eachToForOf.js +0 -92
  69. package/src/jQuery/emptyToReplaceChildren.js +0 -33
  70. package/src/jQuery/findToQuerySelectorAll.js +0 -57
  71. package/src/jQuery/hasClassToClassListContains.js +0 -36
  72. package/src/jQuery/htmlToInnerHTML.js +0 -61
  73. package/src/jQuery/idSelectorToGetElementById.js +0 -54
  74. package/src/jQuery/inArrayToIncludes.js +0 -77
  75. package/src/jQuery/nextToNextElementSibling.js +0 -78
  76. package/src/jQuery/offToRemoveEventListener.js +0 -36
  77. package/src/jQuery/onToAddEventListener.js +0 -51
  78. package/src/jQuery/parentToParentElement.js +0 -60
  79. package/src/jQuery/prependToPrepend.js +0 -54
  80. package/src/jQuery/prevToPreviousElementSibling.js +0 -76
  81. package/src/jQuery/propToDirectProperty.js +0 -175
  82. package/src/jQuery/readyToDOMContentLoaded.js +0 -78
  83. package/src/jQuery/removeClassToClassList.js +0 -45
  84. package/src/jQuery/removeToRemove.js +0 -49
  85. package/src/jQuery/selectorToQuerySelectorAll.js +0 -68
  86. package/src/jQuery/showHideToStyleDisplay.js +0 -56
  87. package/src/jQuery/siblingsToSiblingsArray.js +0 -70
  88. package/src/jQuery/staticEachToForEach.js +0 -42
  89. package/src/jQuery/staticGrepToFilter.js +0 -36
  90. package/src/jQuery/staticMapToMap.js +0 -33
  91. package/src/jQuery/textToTextContent.js +0 -49
  92. package/src/jQuery/toggleClassToClassList.js +0 -36
  93. package/src/jQuery/triggerToDispatchEvent.js +0 -65
  94. package/src/jQuery/trimToStringTrim.js +0 -30
  95. package/src/jQuery/unwrapJQueryIdentifier.js +0 -51
  96. package/src/jQuery/utils.js +0 -384
  97. package/src/jQuery/valToValue.js +0 -40
  98. package/src/jQuery/widthHeightToClient.js +0 -49
  99. package/src/jQuery.js +0 -46
  100. package/tests/jQuery/addClassToClassList.test.js +0 -34
  101. package/tests/jQuery/afterToAfter.test.js +0 -38
  102. package/tests/jQuery/appendToAppend.test.js +0 -44
  103. package/tests/jQuery/attrToGetSetRemove.test.js +0 -44
  104. package/tests/jQuery/beforeToBefore.test.js +0 -44
  105. package/tests/jQuery/childrenToChildrenArray.test.js +0 -32
  106. package/tests/jQuery/clickToAddEventListener.test.js +0 -44
  107. package/tests/jQuery/closestToClosest.test.js +0 -38
  108. package/tests/jQuery/cssToStyleAndComputed.test.js +0 -71
  109. package/tests/jQuery/eachToForOf.test.js +0 -57
  110. package/tests/jQuery/emptyToReplaceChildren.test.js +0 -26
  111. package/tests/jQuery/findToQuerySelectorAll.test.js +0 -47
  112. package/tests/jQuery/hasClassToClassListContains.test.js +0 -41
  113. package/tests/jQuery/htmlToInnerHTML.test.js +0 -38
  114. package/tests/jQuery/idSelectorToGetElementById.test.js +0 -31
  115. package/tests/jQuery/inArrayToIncludes.test.js +0 -69
  116. package/tests/jQuery/nextToNextElementSibling.test.js +0 -37
  117. package/tests/jQuery/offToRemoveEventListener.test.js +0 -43
  118. package/tests/jQuery/onToAddEventListener.test.js +0 -41
  119. package/tests/jQuery/parentToParentElement.test.js +0 -34
  120. package/tests/jQuery/prependToPrepend.test.js +0 -32
  121. package/tests/jQuery/prevToPreviousElementSibling.test.js +0 -37
  122. package/tests/jQuery/propToDirectProperty.test.js +0 -65
  123. package/tests/jQuery/readyToDOMContentLoaded.test.js +0 -40
  124. package/tests/jQuery/removeClassToClassList.test.js +0 -47
  125. package/tests/jQuery/removeToRemove.test.js +0 -26
  126. package/tests/jQuery/selectorToQuerySelectorAll.test.js +0 -36
  127. package/tests/jQuery/showHideToStyleDisplay.test.js +0 -38
  128. package/tests/jQuery/siblingsToSiblingsArray.test.js +0 -32
  129. package/tests/jQuery/staticEachToForEach.test.js +0 -80
  130. package/tests/jQuery/staticGrepToFilter.test.js +0 -50
  131. package/tests/jQuery/staticMapToMap.test.js +0 -56
  132. package/tests/jQuery/textToTextContent.test.js +0 -38
  133. package/tests/jQuery/toggleClassToClassList.test.js +0 -38
  134. package/tests/jQuery/triggerToDispatchEvent.test.js +0 -45
  135. package/tests/jQuery/trimToStringTrim.test.js +0 -32
  136. package/tests/jQuery/unwrapJQueryIdentifier.test.js +0 -26
  137. package/tests/jQuery/utils.test.js +0 -283
  138. package/tests/jQuery/valToValue.test.js +0 -38
  139. package/tests/jQuery/widthHeightToClient.test.js +0 -38
package/.gitattributes CHANGED
@@ -1,2 +1 @@
1
1
  package-lock.json linguist-generated
2
- src/jQuery/HTMLInputElement.json linguist-generated
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
- Transforms `filter(predicate)[0]` to the more explicit and performant `find(predicate)`, which stops at the first match instead of filtering the entire array.
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
- 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 exactly one argument.
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 exactly one parameter (the key)
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
- <picture>
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
- -$.each(array, fn);
805
- -$.map(array, fn);
806
- -$.inArray(val, array) !== -1;
807
- -$.trim(str);
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, jQuery) {
35
+ async run(filePath, baseline) {
37
36
  const worker = new Worker(this.workerPath, {
38
- workerData: { filePath, baseline, jQuery },
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "esupgrade",
3
- "version": "2025.19.0",
3
+ "version": "2025.20.0",
4
4
  "description": "Auto-upgrade your JavaScript syntax",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
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", jQuery) {
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
  }
@@ -151,3 +151,4 @@ export function promiseTry(root) {
151
151
 
152
152
  return modified
153
153
  }
154
+ promiseTry.baselineDate = new Date(Date.UTC(2025, 0, 7))
@@ -75,3 +75,4 @@ export function anonymousFunctionToArrow(root) {
75
75
 
76
76
  return modified
77
77
  }
78
+ anonymousFunctionToArrow.baselineDate = new Date(Date.UTC(2016, 8, 20))
@@ -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))
@@ -65,3 +65,4 @@ export function arrayConcatToSpread(root) {
65
65
 
66
66
  return modified
67
67
  }
68
+ arrayConcatToSpread.baselineDate = new Date(Date.UTC(2015, 9, 14))
@@ -76,3 +76,4 @@ export function arrayFilterToFind(root) {
76
76
 
77
77
  return modified
78
78
  }
79
+ arrayFilterToFind.baselineDate = new Date(Date.UTC(2016, 8, 20))
@@ -72,3 +72,4 @@ export function arrayFromForEachToForOf(root) {
72
72
 
73
73
  return modified
74
74
  }
75
+ arrayFromForEachToForOf.baselineDate = new Date(Date.UTC(2016, 8, 20))
@@ -56,3 +56,4 @@ export function arrayFromToSpread(root) {
56
56
 
57
57
  return modified
58
58
  }
59
+ arrayFromToSpread.baselineDate = new Date(Date.UTC(2016, 8, 20))
@@ -54,3 +54,4 @@ export function arraySliceToSpread(root) {
54
54
 
55
55
  return modified
56
56
  }
57
+ arraySliceToSpread.baselineDate = new Date(Date.UTC(2015, 9, 14))
@@ -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[parts.length - 1]
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))
@@ -35,3 +35,4 @@ export function consoleLogToInfo(root) {
35
35
 
36
36
  return modified
37
37
  }
38
+ consoleLogToInfo.baselineDate = new Date(Date.UTC(2015, 6, 29))
@@ -262,3 +262,4 @@ export function constructorToClass(root) {
262
262
  findPrototypeMethods(root, constructors)
263
263
  return transformConstructorsToClasses(root, constructors)
264
264
  }
265
+ constructorToClass.baselineDate = new Date(Date.UTC(2016, 2, 8))
@@ -158,3 +158,4 @@ export function defaultParameterValues(root) {
158
158
 
159
159
  return modified
160
160
  }
161
+ defaultParameterValues.baselineDate = new Date(Date.UTC(2016, 8, 20))
@@ -137,3 +137,4 @@ export function forLoopToForOf(root) {
137
137
 
138
138
  return modified
139
139
  }
140
+ forLoopToForOf.baselineDate = new Date(Date.UTC(2015, 6, 29))
@@ -115,3 +115,4 @@ export function globalContextToGlobalThis(root) {
115
115
 
116
116
  return modified
117
117
  }
118
+ globalContextToGlobalThis.baselineDate = new Date(Date.UTC(2020, 0, 15))
@@ -141,3 +141,4 @@ export function indexOfToIncludes(root) {
141
141
 
142
142
  return modified
143
143
  }
144
+ indexOfToIncludes.baselineDate = new Date(Date.UTC(2016, 8, 20))
@@ -71,3 +71,4 @@ export function indexOfToStartsWith(root) {
71
71
 
72
72
  return modified
73
73
  }
74
+ indexOfToStartsWith.baselineDate = new Date(Date.UTC(2015, 8, 30))
@@ -163,3 +163,4 @@ export function iterableForEachToForOf(root) {
163
163
 
164
164
  return modified
165
165
  }
166
+ iterableForEachToForOf.baselineDate = new Date(Date.UTC(2015, 6, 29))
@@ -138,3 +138,4 @@ export function lastIndexOfToEndsWith(root) {
138
138
 
139
139
  return modified
140
140
  }
141
+ lastIndexOfToEndsWith.baselineDate = new Date(Date.UTC(2015, 8, 30))