esupgrade 2025.3.3 → 2025.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/copilot-instructions.md +18 -0
- package/README.md +42 -0
- package/bin/esupgrade.js +30 -13
- package/package.json +1 -1
- package/src/widelyAvailable.js +559 -9
- package/tests/cli.test.js +55 -2
- package/tests/newlyAvailable.test.js +2 -2
- package/tests/widelyAvailable.test.js +1937 -948
- package/AGENTS.md +0 -5
- package/tests/index.test.js +0 -291
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
When writing code, you MUST ALWAYS follow the [naming-things](https://raw.githubusercontent.com/codingjoe/naming-things/refs/heads/main/README.md) guidelines.
|
|
2
|
+
|
|
3
|
+
All code must be fully tested with a 100% coverage. Unreachable code must be removed.
|
|
4
|
+
|
|
5
|
+
All transformers must be documented in the README.md.
|
|
6
|
+
|
|
7
|
+
Use class syntax for all object-oriented code.
|
|
8
|
+
Use named functions instead of anonymous functions whenever possible.
|
|
9
|
+
Use `#` for private methods.
|
|
10
|
+
|
|
11
|
+
Avoid overly complex functions. Break them into smaller functions if necessary.
|
|
12
|
+
|
|
13
|
+
Write docstrings with jsdoc type annotations for all functions, classes, and methods.
|
|
14
|
+
Docstrings should be written in present tense imperative mood.
|
|
15
|
+
Docstrings must describe the external behavior of the function, class, or method.
|
|
16
|
+
Docstrings should avoid redundant phrases like "This function" or "This method".
|
|
17
|
+
Class docstrings must not repeat the class name or start with a verb since they don't do anything themselves.
|
|
18
|
+
Avoid code comments unless they describe behavior of 3rd party code or complex algorithms.
|
package/README.md
CHANGED
|
@@ -212,6 +212,47 @@ Supports:
|
|
|
212
212
|
> [!NOTE]
|
|
213
213
|
> Functions using `this`, `arguments`, or `super` are not converted to preserve semantics.
|
|
214
214
|
|
|
215
|
+
#### Constructor functions → [Classes][mdn-classes]
|
|
216
|
+
|
|
217
|
+
```diff
|
|
218
|
+
-function Person(name, age) {
|
|
219
|
+
- this.name = name;
|
|
220
|
+
- this.age = age;
|
|
221
|
+
-}
|
|
222
|
+
-
|
|
223
|
+
-Person.prototype.greet = function() {
|
|
224
|
+
- return 'Hello, I am ' + this.name;
|
|
225
|
+
-};
|
|
226
|
+
-
|
|
227
|
+
-Person.prototype.getAge = function() {
|
|
228
|
+
- return this.age;
|
|
229
|
+
-};
|
|
230
|
+
+class Person {
|
|
231
|
+
+ constructor(name, age) {
|
|
232
|
+
+ this.name = name;
|
|
233
|
+
+ this.age = age;
|
|
234
|
+
+ }
|
|
235
|
+
+
|
|
236
|
+
+ greet() {
|
|
237
|
+
+ return 'Hello, I am ' + this.name;
|
|
238
|
+
+ }
|
|
239
|
+
+
|
|
240
|
+
+ getAge() {
|
|
241
|
+
+ return this.age;
|
|
242
|
+
+ }
|
|
243
|
+
+}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
> [!NOTE]
|
|
247
|
+
> Transforms constructor functions (both function declarations and variable declarations) that meet these criteria:
|
|
248
|
+
>
|
|
249
|
+
> - Function name starts with an uppercase letter
|
|
250
|
+
> - Constructor bodies are limited to simple statements (variable declarations and expression statements)
|
|
251
|
+
> - No control flow statements (`if`, `for`, `while`, `return`, `throw`, etc.) in constructor body
|
|
252
|
+
> - At least one prototype method is defined
|
|
253
|
+
> - Prototype methods must be function expressions (not arrow functions)
|
|
254
|
+
> - Prototype object literals with getters, setters, or computed properties are skipped
|
|
255
|
+
|
|
215
256
|
<picture>
|
|
216
257
|
<source media="(prefers-color-scheme: dark)" srcset="https://web-platform-dx.github.io/web-features/assets/img/baseline-newly-word-dark.svg">
|
|
217
258
|
<source media="(prefers-color-scheme: light)" srcset="https://web-platform-dx.github.io/web-features/assets/img/baseline-newly-word.svg">
|
|
@@ -258,6 +299,7 @@ Furthermore, esupgrade supports JavaScript, TypeScript, and more, while lebab is
|
|
|
258
299
|
[calver]: https://calver.org/
|
|
259
300
|
[django-upgrade]: https://github.com/adamchainz/django-upgrade
|
|
260
301
|
[mdn-arrow-functions]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
|
|
302
|
+
[mdn-classes]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
|
|
261
303
|
[mdn-const]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
|
|
262
304
|
[mdn-exponentiation]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Exponentiation
|
|
263
305
|
[mdn-for-in]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in
|
package/bin/esupgrade.js
CHANGED
|
@@ -74,7 +74,8 @@ class FileProcessor {
|
|
|
74
74
|
const result = workerResult.result
|
|
75
75
|
|
|
76
76
|
if (result.modified) {
|
|
77
|
-
if (
|
|
77
|
+
// Report changes if check mode or if not writing (dry-run)
|
|
78
|
+
if (options.check || !options.write) {
|
|
78
79
|
this.#reportChanges(filePath, result.changes)
|
|
79
80
|
}
|
|
80
81
|
|
|
@@ -89,6 +90,7 @@ class FileProcessor {
|
|
|
89
90
|
|
|
90
91
|
return { modified: true, changes: result.changes, error: false }
|
|
91
92
|
} else {
|
|
93
|
+
// Show unmodified files unless in check-only mode
|
|
92
94
|
if (!options.check) {
|
|
93
95
|
console.log(` ${filePath}`)
|
|
94
96
|
}
|
|
@@ -237,6 +239,14 @@ class CLIRunner {
|
|
|
237
239
|
this.#reportSummary(results, options)
|
|
238
240
|
}
|
|
239
241
|
|
|
242
|
+
#formatDetailedSummary(modifiedCount, allChanges, actionVerb) {
|
|
243
|
+
const transformTypes = new Set(allChanges.map((c) => c.type))
|
|
244
|
+
const typeCount = transformTypes.size
|
|
245
|
+
const totalChanges = allChanges.length
|
|
246
|
+
|
|
247
|
+
return `${modifiedCount} file${modifiedCount !== 1 ? "s" : ""} ${actionVerb} (${totalChanges} change${totalChanges !== 1 ? "s" : ""}, ${typeCount} type${typeCount !== 1 ? "s" : ""})`
|
|
248
|
+
}
|
|
249
|
+
|
|
240
250
|
#reportSummary(results, options) {
|
|
241
251
|
let modifiedCount = 0
|
|
242
252
|
const allChanges = results.flatMap((result) =>
|
|
@@ -249,12 +259,12 @@ class CLIRunner {
|
|
|
249
259
|
|
|
250
260
|
if (options.check) {
|
|
251
261
|
if (modifiedCount > 0) {
|
|
252
|
-
const transformTypes = new Set(allChanges.map((c) => c.type))
|
|
253
|
-
const typeCount = transformTypes.size
|
|
254
|
-
const totalChanges = allChanges.length
|
|
255
|
-
|
|
256
262
|
console.log(
|
|
257
|
-
|
|
263
|
+
this.#formatDetailedSummary(
|
|
264
|
+
modifiedCount,
|
|
265
|
+
allChanges,
|
|
266
|
+
`need${modifiedCount === 1 ? "s" : ""} upgrading`,
|
|
267
|
+
),
|
|
258
268
|
)
|
|
259
269
|
if (options.write) {
|
|
260
270
|
console.log("Changes have been written")
|
|
@@ -262,12 +272,22 @@ class CLIRunner {
|
|
|
262
272
|
} else {
|
|
263
273
|
console.log("All files are up to date")
|
|
264
274
|
}
|
|
265
|
-
} else {
|
|
275
|
+
} else if (options.write) {
|
|
276
|
+
// --write without --check
|
|
266
277
|
if (modifiedCount > 0) {
|
|
267
278
|
console.log(`✓ ${modifiedCount} file${modifiedCount !== 1 ? "s" : ""} upgraded`)
|
|
268
279
|
} else {
|
|
269
280
|
console.log("All files are up to date")
|
|
270
281
|
}
|
|
282
|
+
} else {
|
|
283
|
+
// Dry-run mode (no --check, no --write)
|
|
284
|
+
if (modifiedCount > 0) {
|
|
285
|
+
console.log(
|
|
286
|
+
this.#formatDetailedSummary(modifiedCount, allChanges, "would be upgraded"),
|
|
287
|
+
)
|
|
288
|
+
} else {
|
|
289
|
+
console.log("All files are up to date")
|
|
290
|
+
}
|
|
271
291
|
}
|
|
272
292
|
|
|
273
293
|
// Errors take precedence over --check flag.
|
|
@@ -296,14 +316,11 @@ program
|
|
|
296
316
|
.default("widely-available"),
|
|
297
317
|
)
|
|
298
318
|
.option("--check", "Report which files need upgrading and exit with code 1 if any do")
|
|
299
|
-
.option(
|
|
300
|
-
"--write",
|
|
301
|
-
"Write changes to files (default: true unless only --check is specified)",
|
|
302
|
-
)
|
|
319
|
+
.option("--write", "Write changes to files")
|
|
303
320
|
.action(async (files, options) => {
|
|
304
321
|
// Handle check/write options - they are not mutually exclusive
|
|
305
|
-
// Default: write is
|
|
306
|
-
const shouldWrite = options.write
|
|
322
|
+
// Default: write is false (read-only mode unless --write is specified)
|
|
323
|
+
const shouldWrite = options.write || false
|
|
307
324
|
const shouldCheck = options.check || false
|
|
308
325
|
|
|
309
326
|
const processingOptions = {
|