esupgrade 2025.19.0 → 2025.20.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.
- package/.gitattributes +0 -1
- package/.github/agents/superjoe.agent.md +1 -2
- package/.pre-commit-config.yaml +2 -2
- package/AGENTS.md +10 -0
- package/CONTRIBUTING.md +5 -0
- package/README.md +105 -188
- package/SKILL.md +14 -0
- 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 +239 -172
- 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/constructor-to-class.test.js +331 -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
|
@@ -5,12 +5,12 @@ name: SuperJoe
|
|
|
5
5
|
description: CodingJoe's digital clone following his coding guidelines and best practices.
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
|
|
9
8
|
# SuperJoe
|
|
10
9
|
|
|
11
10
|
## Planning
|
|
12
11
|
|
|
13
12
|
You MUST ALWAYS follow the `naming-things` guidelines. Use the following command to access the guidelines:
|
|
13
|
+
|
|
14
14
|
```console
|
|
15
15
|
curl -sSL https://raw.githubusercontent.com/codingjoe/naming-things/refs/heads/main/README.md | head -n 500
|
|
16
16
|
```
|
|
@@ -44,7 +44,6 @@ Avoid functions or other code inside functions.
|
|
|
44
44
|
Avoid if-statements in favor of switch/match-statements or polymorphism.
|
|
45
45
|
Do not assign names to objects which are returned in the next line.
|
|
46
46
|
|
|
47
|
-
|
|
48
47
|
## Python
|
|
49
48
|
|
|
50
49
|
Follow PEP 8 guidelines for code style.
|
package/.pre-commit-config.yaml
CHANGED
|
@@ -18,10 +18,10 @@ repos:
|
|
|
18
18
|
hooks:
|
|
19
19
|
- id: mdformat
|
|
20
20
|
additional_dependencies:
|
|
21
|
+
- mdformat-front-matters
|
|
21
22
|
- mdformat-footnote
|
|
22
23
|
- mdformat-gfm
|
|
23
24
|
- mdformat-gfm-alerts
|
|
24
|
-
exclude: '.github/agents/'
|
|
25
25
|
- repo: https://github.com/google/yamlfmt
|
|
26
26
|
rev: v0.21.0
|
|
27
27
|
hooks:
|
|
@@ -32,7 +32,7 @@ repos:
|
|
|
32
32
|
- id: write-good
|
|
33
33
|
args: [--no-passive]
|
|
34
34
|
- repo: https://github.com/pre-commit/mirrors-eslint
|
|
35
|
-
rev: v10.4.
|
|
35
|
+
rev: v10.4.1
|
|
36
36
|
hooks:
|
|
37
37
|
- id: eslint
|
|
38
38
|
args: ["--fix"]
|
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
|
@@ -13,7 +13,7 @@ Keeping your JavaScript and TypeScript code up to date with full browser compati
|
|
|
13
13
|
## Usage
|
|
14
14
|
|
|
15
15
|
esupgrade is safe and meant to be used automatically on your codebase.
|
|
16
|
-
We recommend integrating it into your development workflow using [pre-commit].
|
|
16
|
+
We recommend integrating it into your development workflow using [pre-commit] or [husky].
|
|
17
17
|
|
|
18
18
|
To try it out on a repository without writing changes, run:
|
|
19
19
|
|
|
@@ -40,6 +40,15 @@ repos:
|
|
|
40
40
|
pre-commit run esupgrade --all-files
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
+
### Husky
|
|
44
|
+
|
|
45
|
+
Assuming Husky is already initialized and `.husky/pre-commit` already contains `set -e`, append:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
echo "git diff --cached --name-only --diff-filter=ACMR -z -- '*.js' '*.jsx' '*.ts' '*.tsx' '*.mjs' '*.cjs' | xargs -0 sh -c 'test \"\$#\" -eq 0 && exit 0; npx esupgrade -- \"\$@\"' sh" >> .husky/pre-commit
|
|
49
|
+
echo "git diff --cached --name-only --diff-filter=ACMR -z -- '*.js' '*.jsx' '*.ts' '*.tsx' '*.mjs' '*.cjs' | xargs -0 sh -c 'test \"\$#\" -eq 0 && exit 0; git add -- \"\$@\"' sh" >> .husky/pre-commit
|
|
50
|
+
```
|
|
51
|
+
|
|
43
52
|
### CLI
|
|
44
53
|
|
|
45
54
|
```bash
|
|
@@ -215,6 +224,18 @@ Supports:
|
|
|
215
224
|
+const withItem = [...array, item];
|
|
216
225
|
```
|
|
217
226
|
|
|
227
|
+
#### `1000000` → [Numeric separators][mdn-numeric-separators]
|
|
228
|
+
|
|
229
|
+
```diff
|
|
230
|
+
-const budget = 1000000;
|
|
231
|
+
-const maxUsers = 1000000n;
|
|
232
|
+
+const budget = 1_000_000;
|
|
233
|
+
+const maxUsers = 1_000_000n;
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
esupgrade transforms decimal integer and bigint literals with at least five digits.
|
|
237
|
+
Fractional, exponential, hexadecimal, octal, binary, and already formatted literals are left unchanged.
|
|
238
|
+
|
|
218
239
|
#### `Array.slice(0)` → [Array spread [...]][mdn-spread]
|
|
219
240
|
|
|
220
241
|
```diff
|
|
@@ -231,9 +252,16 @@ Supports:
|
|
|
231
252
|
+const first = [1, 2, 3].find(n => n > 1);
|
|
232
253
|
```
|
|
233
254
|
|
|
234
|
-
|
|
255
|
+
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.
|
|
235
256
|
|
|
236
|
-
|
|
257
|
+
#### `arr[arr.length - n]` → [`Array.at()`][mdn-at]
|
|
258
|
+
|
|
259
|
+
```diff
|
|
260
|
+
-const last = arr[arr.length - 1];
|
|
261
|
+
-const item = arr[arr.length - n];
|
|
262
|
+
+const last = arr.at(-1);
|
|
263
|
+
+const item = arr.at(-n);
|
|
264
|
+
```
|
|
237
265
|
|
|
238
266
|
#### `Math.pow()` → [Exponentiation operator \*\*][mdn-exponentiation]
|
|
239
267
|
|
|
@@ -244,6 +272,31 @@ Transformations are limited to when the receiver can be verified as an array (ar
|
|
|
244
272
|
+const area = Math.PI * radius ** 2;
|
|
245
273
|
```
|
|
246
274
|
|
|
275
|
+
#### Verbose arithmetic assignments → [Compound assignment operators (+=, -=, …)][mdn-compound-assignment]
|
|
276
|
+
|
|
277
|
+
```diff
|
|
278
|
+
-x = x + y
|
|
279
|
+
+x += y
|
|
280
|
+
-x = x - y
|
|
281
|
+
+x -= y
|
|
282
|
+
-x = x * y
|
|
283
|
+
+x *= y
|
|
284
|
+
-x = x / y
|
|
285
|
+
+x /= y
|
|
286
|
+
-x = x % y
|
|
287
|
+
+x %= y
|
|
288
|
+
-x = x ** y
|
|
289
|
+
+x **= y
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
> [!NOTE]
|
|
293
|
+
> When the assignment target is a member expression with potential side effects
|
|
294
|
+
> (e.g., `getObj().prop = getObj().prop + y` or `obj[f()] = obj[f()] + y`), the
|
|
295
|
+
> transformation evaluates the target expression once instead of twice.
|
|
296
|
+
> If `getObj()` or `f()` have observable side effects or return different values
|
|
297
|
+
> on each call, `getObj().prop += y` may produce different results than the
|
|
298
|
+
> original `getObj().prop = getObj().prop + y`.
|
|
299
|
+
|
|
247
300
|
#### Named function assignments → [Function declarations][mdn-functions]
|
|
248
301
|
|
|
249
302
|
```diff
|
|
@@ -336,6 +389,7 @@ Transforms constructor functions (both function declarations and variable declar
|
|
|
336
389
|
|
|
337
390
|
- Function name starts with an uppercase letter
|
|
338
391
|
- At least one prototype method is defined
|
|
392
|
+
- Prototype methods are matched only to constructors declared in the current or an ancestor lexical scope (never sibling or child scopes)
|
|
339
393
|
- Prototype methods using `this` in arrow functions are skipped
|
|
340
394
|
- Prototype object literals with getters, setters, or computed properties are skipped
|
|
341
395
|
|
|
@@ -397,6 +451,32 @@ ES6 modules are automatically in strict mode, making explicit `'use strict'` dir
|
|
|
397
451
|
+const result = obj.prop ?? 0;
|
|
398
452
|
```
|
|
399
453
|
|
|
454
|
+
#### Logical assignment patterns → [Logical assignment operators (??=, ||=, &&=)][mdn-logical-assignment]
|
|
455
|
+
|
|
456
|
+
```diff
|
|
457
|
+
-x = x ?? y
|
|
458
|
+
+x ??= y
|
|
459
|
+
-x = x || y
|
|
460
|
+
+x ||= y
|
|
461
|
+
-x = x && y
|
|
462
|
+
+x &&= y
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
```diff
|
|
466
|
+
-if (x === null || x === undefined) x = y
|
|
467
|
+
+x ??= y
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
> [!NOTE]
|
|
471
|
+
> For member expression targets (e.g., `obj.prop ||= y`), the original
|
|
472
|
+
> unconditional assignment always invokes property setters, while the logical
|
|
473
|
+
> assignment operator skips the setter when the condition is not met. This
|
|
474
|
+
> generally improves performance by avoiding unnecessary setter calls.
|
|
475
|
+
>
|
|
476
|
+
> Similarly, for `if (obj.prop === null || obj.prop === undefined) obj.prop = y`,
|
|
477
|
+
> the transformation to `obj.prop ??= y` reads `obj.prop` once instead of twice
|
|
478
|
+
> before assigning, which improves performance for getter-backed properties.
|
|
479
|
+
|
|
400
480
|
#### `indexOf()` → [includes()][mdn-includes]
|
|
401
481
|
|
|
402
482
|
```diff
|
|
@@ -437,6 +517,15 @@ Transforms the deprecated `substr()` method to `slice()`:
|
|
|
437
517
|
|
|
438
518
|
Transformations are limited to when the receiver can be verified as a string (string literals, template literals, or string method chains).
|
|
439
519
|
|
|
520
|
+
#### `split().join()` / `replace(/literal/g)` → [String.replaceAll()][mdn-replaceall]
|
|
521
|
+
|
|
522
|
+
```diff
|
|
523
|
+
-const value = "a,b,c".split(",").join(".");
|
|
524
|
+
-const label = "foo".replace(/o/g, "a");
|
|
525
|
+
+const value = "a,b,c".replaceAll(",", ".");
|
|
526
|
+
+const label = "foo".replaceAll("o", "a");
|
|
527
|
+
```
|
|
528
|
+
|
|
440
529
|
#### `Object.keys().forEach()` → [Object.entries()][mdn-object-entries]
|
|
441
530
|
|
|
442
531
|
```diff
|
|
@@ -449,8 +538,6 @@ Transformations are limited to when the receiver can be verified as a string (st
|
|
|
449
538
|
+});
|
|
450
539
|
```
|
|
451
540
|
|
|
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
541
|
Transforms when:
|
|
455
542
|
|
|
456
543
|
- The callback has one parameter (the key)
|
|
@@ -464,11 +551,9 @@ Transforms when:
|
|
|
464
551
|
+Object.values(obj)
|
|
465
552
|
```
|
|
466
553
|
|
|
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
554
|
Transforms when:
|
|
470
555
|
|
|
471
|
-
- The callback has
|
|
556
|
+
- The callback has one parameter (the key)
|
|
472
557
|
- The callback body returns `obj[key]` (expression or block with a single return statement)
|
|
473
558
|
- The object being accessed matches the object passed to Object.keys()
|
|
474
559
|
|
|
@@ -628,187 +713,13 @@ These transformations are mainly to harden code for future releases and should b
|
|
|
628
713
|
+});
|
|
629
714
|
```
|
|
630
715
|
|
|
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
|
|
716
|
+
#### `Object.prototype.hasOwnProperty.call()` → [Object.hasOwn()][mdn-object-has-own]
|
|
802
717
|
|
|
803
718
|
```diff
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
+array.forEach(fn);
|
|
809
|
-
+array.map(fn);
|
|
810
|
-
+array.includes(val);
|
|
811
|
-
+str.trim();
|
|
719
|
+
-Object.prototype.hasOwnProperty.call(obj, prop);
|
|
720
|
+
-({}).hasOwnProperty.call(obj, prop);
|
|
721
|
+
+Object.hasOwn(obj, prop);
|
|
722
|
+
+Object.hasOwn(obj, prop);
|
|
812
723
|
```
|
|
813
724
|
|
|
814
725
|
## Versioning
|
|
@@ -833,10 +744,12 @@ Furthermore, esupgrade supports JavaScript, TypeScript, and more, while lebab is
|
|
|
833
744
|
[baseline]: https://web.dev/baseline/
|
|
834
745
|
[calver]: https://calver.org/
|
|
835
746
|
[django-upgrade]: https://github.com/adamchainz/django-upgrade
|
|
836
|
-
[
|
|
747
|
+
[husky]: https://typicode.github.io/husky/
|
|
837
748
|
[mdn-arrow-functions]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
|
|
838
749
|
[mdn-async-await]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
|
|
750
|
+
[mdn-at]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at
|
|
839
751
|
[mdn-classes]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
|
|
752
|
+
[mdn-compound-assignment]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Addition_assignment
|
|
840
753
|
[mdn-console]: https://developer.mozilla.org/en-US/docs/Web/API/console
|
|
841
754
|
[mdn-const]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
|
|
842
755
|
[mdn-default-parameters]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters
|
|
@@ -849,10 +762,14 @@ Furthermore, esupgrade supports JavaScript, TypeScript, and more, while lebab is
|
|
|
849
762
|
[mdn-globalthis]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis
|
|
850
763
|
[mdn-includes]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes
|
|
851
764
|
[mdn-let]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
|
|
765
|
+
[mdn-logical-assignment]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_OR_assignment
|
|
852
766
|
[mdn-nullish-coalescing]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing
|
|
767
|
+
[mdn-numeric-separators]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#numeric_separators
|
|
853
768
|
[mdn-object-entries]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries
|
|
769
|
+
[mdn-object-has-own]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn
|
|
854
770
|
[mdn-object-values]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values
|
|
855
771
|
[mdn-promise-try]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/try
|
|
772
|
+
[mdn-replaceall]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replaceAll
|
|
856
773
|
[mdn-rest-parameters]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters
|
|
857
774
|
[mdn-slice]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice
|
|
858
775
|
[mdn-spread]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: esupgrade
|
|
3
|
+
description: Auto-update JavaScript and TypeScript syntax to new ECMAScript features based on browser support.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Use the CLI with `npx` on files or directories:
|
|
7
|
+
|
|
8
|
+
```console
|
|
9
|
+
npx esupgrade [--baseline <newly-available|widely-available>] [--check] [--write] <files-or-directories>
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
- Use `--check` to preview changes and fail when updates are needed.
|
|
13
|
+
- Use `--write` to apply updates in place.
|
|
14
|
+
- Use `--baseline` to choose `newly-available` or `widely-available` (default).
|
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))
|