esupgrade 2025.0.0 → 2025.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.pre-commit-config.yaml +7 -6
- package/README.md +57 -48
- package/bin/esupgrade.js +7 -21
- package/images/logo-dark.svg +3 -4
- package/images/logo-light.svg +1 -2
- package/package.json +1 -1
- package/src/index.js +18 -689
- package/src/newlyAvailable.js +154 -0
- package/src/widelyAvailable.js +265 -0
- package/tests/cli.test.js +358 -0
- package/tests/index.test.js +274 -0
- package/tests/newlyAvailable.test.js +221 -0
- package/tests/widelyAvailable.test.js +428 -0
- package/.idea/copilot.data.migration.ask2agent.xml +0 -6
- package/.idea/esupgrade.iml +0 -8
- package/.idea/inspectionProfiles/Project_Default.xml +0 -28
- package/.idea/inspectionProfiles/profiles_settings.xml +0 -6
- package/.idea/misc.xml +0 -7
- package/.idea/modules.xml +0 -8
- package/.idea/vcs.xml +0 -7
- package/tests/transform.test.js +0 -322
package/.idea/misc.xml
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<project version="4">
|
|
3
|
-
<component name="Black">
|
|
4
|
-
<option name="sdkName" value="Python 3.9" />
|
|
5
|
-
</component>
|
|
6
|
-
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9" project-jdk-type="Python SDK" />
|
|
7
|
-
</project>
|
package/.idea/modules.xml
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<project version="4">
|
|
3
|
-
<component name="ProjectModuleManager">
|
|
4
|
-
<modules>
|
|
5
|
-
<module fileurl="file://$PROJECT_DIR$/.idea/esupgrade.iml" filepath="$PROJECT_DIR$/.idea/esupgrade.iml" />
|
|
6
|
-
</modules>
|
|
7
|
-
</component>
|
|
8
|
-
</project>
|
package/.idea/vcs.xml
DELETED
package/tests/transform.test.js
DELETED
|
@@ -1,322 +0,0 @@
|
|
|
1
|
-
import { test } from "node:test"
|
|
2
|
-
import assert from "node:assert"
|
|
3
|
-
import { transform } from "../src/index.js"
|
|
4
|
-
|
|
5
|
-
test("Array.from().forEach() to for...of", () => {
|
|
6
|
-
const input = `
|
|
7
|
-
Array.from(items).forEach(item => {
|
|
8
|
-
console.log(item);
|
|
9
|
-
});
|
|
10
|
-
`
|
|
11
|
-
|
|
12
|
-
const result = transform(input)
|
|
13
|
-
|
|
14
|
-
assert.strictEqual(result.modified, true)
|
|
15
|
-
assert.match(result.code, /for \(const item of items\)/)
|
|
16
|
-
assert.match(result.code, /console\.log\(item\)/)
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
test("Array.from().forEach() with arrow function expression", () => {
|
|
20
|
-
const input = `Array.from(numbers).forEach(n => console.log(n));`
|
|
21
|
-
|
|
22
|
-
const result = transform(input)
|
|
23
|
-
|
|
24
|
-
assert.strictEqual(result.modified, true)
|
|
25
|
-
assert.match(result.code, /for \(const n of numbers\)/)
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
test("var to const when not reassigned", () => {
|
|
29
|
-
const input = `
|
|
30
|
-
var x = 1;
|
|
31
|
-
`
|
|
32
|
-
|
|
33
|
-
const result = transform(input)
|
|
34
|
-
|
|
35
|
-
assert.strictEqual(result.modified, true)
|
|
36
|
-
assert.match(result.code, /const x = 1/)
|
|
37
|
-
assert.doesNotMatch(result.code, /var x/)
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
test("var to const (simplified version)", () => {
|
|
41
|
-
const input = `
|
|
42
|
-
var x = 1;
|
|
43
|
-
x = 2;
|
|
44
|
-
`
|
|
45
|
-
|
|
46
|
-
const result = transform(input)
|
|
47
|
-
|
|
48
|
-
assert.strictEqual(result.modified, true)
|
|
49
|
-
assert.match(result.code, /const x = 1/)
|
|
50
|
-
assert.doesNotMatch(result.code, /var x/)
|
|
51
|
-
// Note: This will cause a runtime error due to const reassignment
|
|
52
|
-
// A more sophisticated version would detect reassignments and use 'let'
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
test("string concatenation to template literal", () => {
|
|
56
|
-
const input = `const greeting = 'Hello ' + name + '!';`
|
|
57
|
-
|
|
58
|
-
const result = transform(input)
|
|
59
|
-
|
|
60
|
-
assert.strictEqual(result.modified, true)
|
|
61
|
-
assert.match(result.code, /`Hello \$\{name\}!`/)
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
test("multiple string concatenations", () => {
|
|
65
|
-
const input = `const msg = 'Hello ' + firstName + ' ' + lastName + '!';`
|
|
66
|
-
|
|
67
|
-
const result = transform(input)
|
|
68
|
-
|
|
69
|
-
assert.strictEqual(result.modified, true)
|
|
70
|
-
assert.match(result.code, /`Hello \$\{firstName\} \$\{lastName\}!`/)
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
test("Object.assign to object spread", () => {
|
|
74
|
-
const input = `const obj = Object.assign({}, obj1, obj2);`
|
|
75
|
-
|
|
76
|
-
const result = transform(input)
|
|
77
|
-
|
|
78
|
-
assert.strictEqual(result.modified, true)
|
|
79
|
-
assert.match(result.code, /\.\.\.obj1/)
|
|
80
|
-
assert.match(result.code, /\.\.\.obj2/)
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
test("no changes needed", () => {
|
|
84
|
-
const input = `
|
|
85
|
-
const x = 1;
|
|
86
|
-
const y = 2;
|
|
87
|
-
`
|
|
88
|
-
|
|
89
|
-
const result = transform(input)
|
|
90
|
-
|
|
91
|
-
assert.strictEqual(result.modified, false)
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
test("complex transformation", () => {
|
|
95
|
-
const input = `
|
|
96
|
-
var userName = 'Alice';
|
|
97
|
-
var greeting = 'Hello ' + userName;
|
|
98
|
-
`
|
|
99
|
-
|
|
100
|
-
const result = transform(input)
|
|
101
|
-
|
|
102
|
-
assert.strictEqual(result.modified, true)
|
|
103
|
-
assert.match(result.code, /const userName/)
|
|
104
|
-
assert.match(result.code, /`Hello \$\{userName\}`/)
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
test("baseline option - widely-available", () => {
|
|
108
|
-
const input = `var x = 1;`
|
|
109
|
-
|
|
110
|
-
const result = transform(input, { baseline: "widely-available" })
|
|
111
|
-
|
|
112
|
-
assert.strictEqual(result.modified, true)
|
|
113
|
-
assert.match(result.code, /const x = 1/)
|
|
114
|
-
})
|
|
115
|
-
|
|
116
|
-
test("baseline option - newly-available", () => {
|
|
117
|
-
const input = `var x = 1;`
|
|
118
|
-
|
|
119
|
-
const result = transform(input, { baseline: "newly-available" })
|
|
120
|
-
|
|
121
|
-
assert.strictEqual(result.modified, true)
|
|
122
|
-
assert.match(result.code, /const x = 1/)
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
test("forEach should NOT transform plain identifiers (cannot confirm iterable)", () => {
|
|
126
|
-
const input = `
|
|
127
|
-
items.forEach(item => {
|
|
128
|
-
console.log(item);
|
|
129
|
-
});
|
|
130
|
-
`
|
|
131
|
-
|
|
132
|
-
const result = transform(input)
|
|
133
|
-
|
|
134
|
-
// Should not transform because we can't statically confirm 'items' is iterable
|
|
135
|
-
// It could be a jscodeshift Collection or other object with forEach but not Symbol.iterator
|
|
136
|
-
assert.strictEqual(result.modified, false)
|
|
137
|
-
assert.match(result.code, /items\.forEach/)
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
test("forEach should NOT transform plain identifiers with function expression", () => {
|
|
141
|
-
const input = `numbers.forEach(function(n) { console.log(n); });`
|
|
142
|
-
|
|
143
|
-
const result = transform(input)
|
|
144
|
-
|
|
145
|
-
// Should not transform because we can't statically confirm 'numbers' is iterable
|
|
146
|
-
assert.strictEqual(result.modified, false)
|
|
147
|
-
assert.match(result.code, /numbers\.forEach/)
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
test("forEach DOES transform array literals", () => {
|
|
151
|
-
const input = `[1, 2, 3].forEach(n => console.log(n));`
|
|
152
|
-
|
|
153
|
-
const result = transform(input)
|
|
154
|
-
|
|
155
|
-
// Should transform because array literals are definitely iterable
|
|
156
|
-
assert.strictEqual(result.modified, true)
|
|
157
|
-
assert.match(result.code, /for \(const n of \[1, 2, 3\]\)/)
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
test("for...of Object.keys() to for...in", () => {
|
|
161
|
-
const input = `
|
|
162
|
-
for (const key of Object.keys(obj)) {
|
|
163
|
-
console.log(key);
|
|
164
|
-
}
|
|
165
|
-
`
|
|
166
|
-
|
|
167
|
-
const result = transform(input)
|
|
168
|
-
|
|
169
|
-
assert.strictEqual(result.modified, true)
|
|
170
|
-
assert.match(result.code, /for \(const key in obj\)/)
|
|
171
|
-
})
|
|
172
|
-
|
|
173
|
-
test("Promise.try transformation - newly-available", () => {
|
|
174
|
-
const input = `const p = new Promise((resolve) => resolve(getData()));`
|
|
175
|
-
|
|
176
|
-
const result = transform(input, { baseline: "newly-available" })
|
|
177
|
-
|
|
178
|
-
assert.strictEqual(result.modified, true)
|
|
179
|
-
assert.match(result.code, /Promise\.try/)
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
test("Promise.try not in widely-available", () => {
|
|
183
|
-
const input = `const p = new Promise((resolve) => resolve(getData()));`
|
|
184
|
-
|
|
185
|
-
const result = transform(input, { baseline: "widely-available" })
|
|
186
|
-
|
|
187
|
-
// Should not transform Promise with widely-available baseline
|
|
188
|
-
assert.doesNotMatch(result.code, /Promise\.try/)
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
test("Promise.try with function passed to resolve", () => {
|
|
192
|
-
const input = `const p = new Promise((resolve) => setTimeout(resolve));`
|
|
193
|
-
|
|
194
|
-
const result = transform(input, { baseline: "newly-available" })
|
|
195
|
-
|
|
196
|
-
assert.strictEqual(result.modified, true)
|
|
197
|
-
// Should transform to Promise.try(setTimeout) not Promise.try(() => setTimeout(resolve))
|
|
198
|
-
assert.match(result.code, /Promise\.try\(setTimeout\)/)
|
|
199
|
-
assert.doesNotMatch(result.code, /resolve/)
|
|
200
|
-
})
|
|
201
|
-
|
|
202
|
-
test("Promise.try should not transform when awaited", () => {
|
|
203
|
-
const input = `async function foo() {
|
|
204
|
-
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
205
|
-
}`
|
|
206
|
-
|
|
207
|
-
const result = transform(input, { baseline: "newly-available" })
|
|
208
|
-
|
|
209
|
-
// Should NOT transform awaited Promises
|
|
210
|
-
assert.strictEqual(result.modified, false)
|
|
211
|
-
assert.match(result.code, /await new Promise/)
|
|
212
|
-
assert.doesNotMatch(result.code, /Promise\.try/)
|
|
213
|
-
})
|
|
214
|
-
|
|
215
|
-
test("Array.from().forEach() with array destructuring", () => {
|
|
216
|
-
const input = `
|
|
217
|
-
Array.from(Object.entries(obj)).forEach(([key, value]) => {
|
|
218
|
-
console.log(key, value);
|
|
219
|
-
});
|
|
220
|
-
`
|
|
221
|
-
|
|
222
|
-
const result = transform(input)
|
|
223
|
-
|
|
224
|
-
assert.strictEqual(result.modified, true)
|
|
225
|
-
assert.match(result.code, /for \(const \[key, value\] of Object\.entries\(obj\)\)/)
|
|
226
|
-
})
|
|
227
|
-
|
|
228
|
-
test("Array.from().forEach() should NOT transform with index parameter", () => {
|
|
229
|
-
const input = `
|
|
230
|
-
Array.from(items).forEach((item, index) => {
|
|
231
|
-
console.log(item, index);
|
|
232
|
-
});
|
|
233
|
-
`
|
|
234
|
-
|
|
235
|
-
const result = transform(input)
|
|
236
|
-
|
|
237
|
-
// Should not transform because callback uses index parameter
|
|
238
|
-
assert.strictEqual(result.modified, false)
|
|
239
|
-
assert.match(result.code, /forEach\(\(item, index\)/)
|
|
240
|
-
})
|
|
241
|
-
|
|
242
|
-
test("forEach should NOT transform with index parameter", () => {
|
|
243
|
-
const input = `
|
|
244
|
-
items.forEach((item, index) => {
|
|
245
|
-
console.log(item, index);
|
|
246
|
-
});
|
|
247
|
-
`
|
|
248
|
-
|
|
249
|
-
const result = transform(input)
|
|
250
|
-
|
|
251
|
-
// Should not transform because callback uses index parameter
|
|
252
|
-
assert.strictEqual(result.modified, false)
|
|
253
|
-
assert.match(result.code, /forEach\(\(item, index\)/)
|
|
254
|
-
})
|
|
255
|
-
|
|
256
|
-
test("forEach transforms array methods that return arrays", () => {
|
|
257
|
-
const input = `
|
|
258
|
-
items.filter(x => x > 0).forEach(item => {
|
|
259
|
-
console.log(item);
|
|
260
|
-
});
|
|
261
|
-
`
|
|
262
|
-
|
|
263
|
-
const result = transform(input)
|
|
264
|
-
|
|
265
|
-
assert.strictEqual(result.modified, true)
|
|
266
|
-
assert.match(result.code, /for \(const item of items\.filter/)
|
|
267
|
-
})
|
|
268
|
-
|
|
269
|
-
test("forEach transforms Object.keys/values/entries", () => {
|
|
270
|
-
const input = `
|
|
271
|
-
Object.keys(obj).forEach(key => {
|
|
272
|
-
console.log(key);
|
|
273
|
-
});
|
|
274
|
-
`
|
|
275
|
-
|
|
276
|
-
const result = transform(input)
|
|
277
|
-
|
|
278
|
-
assert.strictEqual(result.modified, true)
|
|
279
|
-
// Object.keys().forEach() -> for...of Object.keys() -> for...in
|
|
280
|
-
assert.match(result.code, /for \(const key in obj\)/)
|
|
281
|
-
})
|
|
282
|
-
|
|
283
|
-
test("forEach transforms Set iteration", () => {
|
|
284
|
-
const input = `
|
|
285
|
-
new Set([1, 2, 3]).forEach(value => {
|
|
286
|
-
console.log(value);
|
|
287
|
-
});
|
|
288
|
-
`
|
|
289
|
-
|
|
290
|
-
const result = transform(input)
|
|
291
|
-
|
|
292
|
-
assert.strictEqual(result.modified, true)
|
|
293
|
-
assert.match(result.code, /for \(const value of new Set/)
|
|
294
|
-
})
|
|
295
|
-
|
|
296
|
-
test("forEach should NOT transform unknown objects", () => {
|
|
297
|
-
const input = `
|
|
298
|
-
myCustomObject.forEach(item => {
|
|
299
|
-
console.log(item);
|
|
300
|
-
});
|
|
301
|
-
`
|
|
302
|
-
|
|
303
|
-
const result = transform(input)
|
|
304
|
-
|
|
305
|
-
// Should not transform because we can't be sure myCustomObject is iterable
|
|
306
|
-
assert.strictEqual(result.modified, false)
|
|
307
|
-
assert.match(result.code, /myCustomObject\.forEach/)
|
|
308
|
-
})
|
|
309
|
-
|
|
310
|
-
test("forEach should NOT transform Map (uses different signature)", () => {
|
|
311
|
-
const input = `
|
|
312
|
-
myMap.forEach((value, key) => {
|
|
313
|
-
console.log(key, value);
|
|
314
|
-
});
|
|
315
|
-
`
|
|
316
|
-
|
|
317
|
-
const result = transform(input)
|
|
318
|
-
|
|
319
|
-
// Should not transform Map.forEach because it has 2 parameters (value, key)
|
|
320
|
-
assert.strictEqual(result.modified, false)
|
|
321
|
-
assert.match(result.code, /myMap\.forEach/)
|
|
322
|
-
})
|