esupgrade 2025.22.0 → 2025.22.2
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/.github/workflows/ci.yml +3 -3
- package/.github/workflows/release.yml +2 -2
- package/.pre-commit-config.yaml +1 -1
- package/README.md +3 -3
- package/package.json +1 -1
- package/{SKILL.md → skills/esugprade/SKILL.md} +2 -6
- package/src/widelyAvailable/anonymousFunctionToArrow.js +10 -0
- package/src/widelyAvailable/varToLetOrConst.js +34 -0
- package/tests/widelyAvailable/function-to-arrow.test.js +20 -0
- package/tests/widelyAvailable/var-to-let-or-const.test.js +24 -0
- package/.claude-plugin/marketplace.json +0 -32
package/.github/workflows/ci.yml
CHANGED
|
@@ -10,7 +10,7 @@ jobs:
|
|
|
10
10
|
runs-on: ubuntu-latest
|
|
11
11
|
timeout-minutes: 1
|
|
12
12
|
steps:
|
|
13
|
-
- uses: actions/checkout@
|
|
13
|
+
- uses: actions/checkout@v7
|
|
14
14
|
- id: read_readme
|
|
15
15
|
run: |
|
|
16
16
|
echo "::set-output name=content::$(cat README.md)"
|
|
@@ -21,9 +21,9 @@ jobs:
|
|
|
21
21
|
name: Test
|
|
22
22
|
runs-on: ubuntu-latest
|
|
23
23
|
steps:
|
|
24
|
-
- uses: actions/checkout@
|
|
24
|
+
- uses: actions/checkout@v7
|
|
25
25
|
- name: Set up Node.js
|
|
26
|
-
uses: actions/setup-node@
|
|
26
|
+
uses: actions/setup-node@v7
|
|
27
27
|
with:
|
|
28
28
|
node-version-file: package.json
|
|
29
29
|
- run: npm ci
|
|
@@ -10,8 +10,8 @@ jobs:
|
|
|
10
10
|
name: npmjs.org
|
|
11
11
|
runs-on: ubuntu-latest
|
|
12
12
|
steps:
|
|
13
|
-
- uses: actions/checkout@
|
|
14
|
-
- uses: actions/setup-node@
|
|
13
|
+
- uses: actions/checkout@v7
|
|
14
|
+
- uses: actions/setup-node@v7
|
|
15
15
|
with:
|
|
16
16
|
node-version-file: package.json
|
|
17
17
|
registry-url: 'https://registry.npmjs.org'
|
package/.pre-commit-config.yaml
CHANGED
package/README.md
CHANGED
|
@@ -69,10 +69,10 @@ echo "git diff --cached --name-only --diff-filter=ACMR -z -- '*.js' '*.jsx' '*.t
|
|
|
69
69
|
|
|
70
70
|
### Agent Skill
|
|
71
71
|
|
|
72
|
-
esupgrade is available as a skill in [Claude Code]. To use it:
|
|
72
|
+
esupgrade is available as a skill in [Claude Code]. The plugin is distributed via the [codingjoe/claude-plugins](https://github.com/codingjoe/claude-plugins) marketplace. To use it:
|
|
73
73
|
|
|
74
|
-
1. Run `/plugin marketplace add codingjoe/
|
|
75
|
-
1. Run `/plugin install esupgrade@
|
|
74
|
+
1. Run `/plugin marketplace add codingjoe/claude-plugins`
|
|
75
|
+
1. Run `/plugin install esupgrade@codingjoe`
|
|
76
76
|
|
|
77
77
|
The skill will analyze your selected code and suggest transformations based on the Baseline browser support policy.
|
|
78
78
|
|
package/package.json
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: esupgrade
|
|
3
|
-
description: Auto-update JavaScript and TypeScript syntax to new ECMAScript features based on browser support.
|
|
4
|
-
|
|
5
|
-
metadata:
|
|
6
|
-
author: codingjoe <security@codingjoe.dev>
|
|
7
|
-
allowed-tools: Bash(npx -y esupgrade *) READ
|
|
8
|
-
compatibility: Requires Node.js 24 or later and npx.
|
|
3
|
+
description: Auto-update JavaScript and TypeScript syntax to new ECMAScript features based on browser support. Use when the user asks to modernize, upgrade, or clean up JavaScript or TypeScript syntax.
|
|
4
|
+
allowed-tools: Bash(npx -y esupgrade *) Read
|
|
9
5
|
---
|
|
10
6
|
|
|
11
7
|
Use the CLI with `npx` on files, directories, or standard input:
|
|
@@ -68,6 +68,16 @@ export function anonymousFunctionToArrow(root) {
|
|
|
68
68
|
arrowFunction.async = true
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
// Preserve TypeScript generic type parameters
|
|
72
|
+
if (node.typeParameters) {
|
|
73
|
+
arrowFunction.typeParameters = node.typeParameters
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Preserve TypeScript return type annotation
|
|
77
|
+
if (node.returnType) {
|
|
78
|
+
arrowFunction.returnType = node.returnType
|
|
79
|
+
}
|
|
80
|
+
|
|
71
81
|
j(path).replaceWith(arrowFunction)
|
|
72
82
|
|
|
73
83
|
modified = true
|
|
@@ -1,6 +1,36 @@
|
|
|
1
1
|
import { default as j } from "jscodeshift"
|
|
2
2
|
import { processMultipleDeclarators, processSingleDeclarator } from "../types.js"
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Detect whether a path is nested in a declared TypeScript module.
|
|
6
|
+
*
|
|
7
|
+
* @param {import("ast-types").NodePath} path - The path to check.
|
|
8
|
+
* @returns {boolean} True when the path is inside a declared TypeScript module.
|
|
9
|
+
*/
|
|
10
|
+
function isInDeclaredTypeScriptModule({ parentPath: currentPath }) {
|
|
11
|
+
while (currentPath) {
|
|
12
|
+
const currentNode = currentPath.node
|
|
13
|
+
|
|
14
|
+
if (j.TSModuleDeclaration.check(currentNode) && currentNode.declare === true) {
|
|
15
|
+
return true
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
currentPath = currentPath.parentPath
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return false
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Detect whether a variable declaration is ambient in TypeScript.
|
|
26
|
+
*
|
|
27
|
+
* @param {import("ast-types").NodePath} path - The variable declaration path.
|
|
28
|
+
* @returns {boolean} True when TypeScript ambient syntax requires keeping `var`.
|
|
29
|
+
*/
|
|
30
|
+
function isAmbientTypeScriptVar(path) {
|
|
31
|
+
return path.node.declare === true || isInDeclaredTypeScriptModule(path)
|
|
32
|
+
}
|
|
33
|
+
|
|
4
34
|
/**
|
|
5
35
|
* Transform var to const or let.
|
|
6
36
|
*
|
|
@@ -13,6 +43,10 @@ export function varToLetOrConst(root) {
|
|
|
13
43
|
let modified = false
|
|
14
44
|
|
|
15
45
|
root.find(j.VariableDeclaration, { kind: "var" }).forEach((path) => {
|
|
46
|
+
if (isAmbientTypeScriptVar(path)) {
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
|
|
16
50
|
const isSingleDeclarator = path.node.declarations.length === 1
|
|
17
51
|
|
|
18
52
|
const result = isSingleDeclarator
|
|
@@ -220,5 +220,25 @@ suite("widely-available", () => {
|
|
|
220
220
|
|
|
221
221
|
assert(!result.modified, "skip named function expression")
|
|
222
222
|
})
|
|
223
|
+
|
|
224
|
+
test("generic type parameters are preserved", () => {
|
|
225
|
+
const result = transform(`
|
|
226
|
+
globalThis.Promise.withResolvers = function<T>() {
|
|
227
|
+
return { promise: new Promise<T>(), resolve: null };
|
|
228
|
+
};
|
|
229
|
+
`)
|
|
230
|
+
|
|
231
|
+
assert(result.modified, "transform generic function expression")
|
|
232
|
+
assert.match(result.code, /<T>\(\) =>/)
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
test("generic type parameters with return type are preserved", () => {
|
|
236
|
+
const result = transform(`
|
|
237
|
+
arr.map(function<T>(x: T): T { return x; });
|
|
238
|
+
`)
|
|
239
|
+
|
|
240
|
+
assert(result.modified, "transform generic callback function")
|
|
241
|
+
assert.match(result.code, /<T>\(x: T\): T =>/)
|
|
242
|
+
})
|
|
223
243
|
})
|
|
224
244
|
})
|
|
@@ -505,5 +505,29 @@ suite("widely-available", () => {
|
|
|
505
505
|
assert.doesNotMatch(result.code, /var prop/)
|
|
506
506
|
assert.doesNotMatch(result.code, /let prop/)
|
|
507
507
|
})
|
|
508
|
+
|
|
509
|
+
test("preserve var in declare global", () => {
|
|
510
|
+
const result = transform(`
|
|
511
|
+
declare global {
|
|
512
|
+
var csrftoken: string;
|
|
513
|
+
}
|
|
514
|
+
`)
|
|
515
|
+
|
|
516
|
+
assert(!result.modified, "skip ambient declare global var")
|
|
517
|
+
assert.match(result.code, /var csrftoken: string;/)
|
|
518
|
+
assert.doesNotMatch(result.code, /const csrftoken: string;/)
|
|
519
|
+
assert.doesNotMatch(result.code, /let csrftoken: string;/)
|
|
520
|
+
})
|
|
521
|
+
|
|
522
|
+
test("preserve top-level declare var", () => {
|
|
523
|
+
const result = transform(`
|
|
524
|
+
declare var csrftoken: string;
|
|
525
|
+
`)
|
|
526
|
+
|
|
527
|
+
assert(!result.modified, "skip top-level ambient declare var")
|
|
528
|
+
assert.match(result.code, /declare var csrftoken: string;/)
|
|
529
|
+
assert.doesNotMatch(result.code, /declare const csrftoken: string;/)
|
|
530
|
+
assert.doesNotMatch(result.code, /declare let csrftoken: string;/)
|
|
531
|
+
})
|
|
508
532
|
})
|
|
509
533
|
})
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "esupgrade",
|
|
3
|
-
"description": "Auto-upgrade JavaScript and TypeScript syntax to new ECMAScript features based on browser support.",
|
|
4
|
-
"owner": {
|
|
5
|
-
"name": "codingjoe",
|
|
6
|
-
"email": "security@codingjoe.dev"
|
|
7
|
-
},
|
|
8
|
-
"plugins": [
|
|
9
|
-
{
|
|
10
|
-
"name": "esupgrade",
|
|
11
|
-
"source": "./",
|
|
12
|
-
"description": "Auto-upgrade JavaScript and TypeScript syntax to new ECMAScript features based on browser support.",
|
|
13
|
-
"displayName": "esupgrade",
|
|
14
|
-
"author": {
|
|
15
|
-
"name": "Johannes Maron",
|
|
16
|
-
"email": "security@codingjoe.dev"
|
|
17
|
-
},
|
|
18
|
-
"homepage": "https://github.com/codingjoe/esupgrade",
|
|
19
|
-
"repository": "https://github.com/codingjoe/esupgrade",
|
|
20
|
-
"license": "BSD-2-Clause",
|
|
21
|
-
"keywords": [
|
|
22
|
-
"javascript",
|
|
23
|
-
"ecmascript",
|
|
24
|
-
"modernize",
|
|
25
|
-
"upgrade",
|
|
26
|
-
"codemod",
|
|
27
|
-
"ast",
|
|
28
|
-
"transform"
|
|
29
|
-
]
|
|
30
|
-
}
|
|
31
|
-
]
|
|
32
|
-
}
|