esupgrade 2025.0.2 → 2025.2.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/AGENTS.md ADDED
@@ -0,0 +1,3 @@
1
+ When writing code, you MUST ALWAYS follow the [naming-things](https://raw.githubusercontent.com/codingjoe/naming-things/refs/heads/main/README.md) guidlines.
2
+
3
+ All code must be fully tested with a 100% coverage. Unreachable code must be removed.
package/README.md CHANGED
@@ -73,7 +73,7 @@ For more information about Baseline browser support, visit [web.dev/baseline][ba
73
73
 
74
74
  ### Widely available
75
75
 
76
- #### `var` → `let`/`const`
76
+ #### `var` → [const][mdn-const] & [let][mdn-let]
77
77
 
78
78
  ```diff
79
79
  -var x = 1;
@@ -84,7 +84,7 @@ For more information about Baseline browser support, visit [web.dev/baseline][ba
84
84
  +y = 3;
85
85
  ```
86
86
 
87
- #### String concatenation → Template literals
87
+ #### String concatenation → [Template literals][mdn-template-literals]
88
88
 
89
89
  ```diff
90
90
  -const greeting = 'Hello ' + name + '!';
@@ -93,7 +93,22 @@ For more information about Baseline browser support, visit [web.dev/baseline][ba
93
93
  +const message = `You have ${count} items`;
94
94
  ```
95
95
 
96
- #### `Array.from().forEach()` → `for...of` loops
96
+ #### Traditional `for` loops [`for...of` loops][mdn-for-of]
97
+
98
+ ```diff
99
+ -for (let i = 0; i < items.length; i++) {
100
+ - const item = items[i];
101
+ - console.log(item);
102
+ -}
103
+ +for (const item of items) {
104
+ + console.log(item);
105
+ +}
106
+ ```
107
+
108
+ > [!NOTE]
109
+ > Transformations are limited to loops that start at 0, increment by 1, and where the index variable is not used in the loop body.
110
+
111
+ #### `Array.from().forEach()` → [`for...of` loops][mdn-for-of]
97
112
 
98
113
  ```diff
99
114
  -Array.from(items).forEach(item => {
@@ -104,7 +119,44 @@ For more information about Baseline browser support, visit [web.dev/baseline][ba
104
119
  +}
105
120
  ```
106
121
 
107
- #### `Object.assign({}, ...)` → Object spread
122
+ #### DOM `forEach()` → [`for...of` loops][mdn-for-of]
123
+
124
+ ```diff
125
+ -document.querySelectorAll('.item').forEach(item => {
126
+ - item.classList.add('active');
127
+ -});
128
+ +for (const item of document.querySelectorAll('.item')) {
129
+ + item.classList.add('active');
130
+ +}
131
+ ```
132
+
133
+ Supports:
134
+
135
+ - `document.querySelectorAll()`
136
+ - `document.getElementsByTagName()`
137
+ - `document.getElementsByClassName()`
138
+ - `document.getElementsByName()`
139
+ - `window.frames`
140
+
141
+ > [!NOTE]
142
+ > Transformations limited to inline arrow or function expressions with block statement bodies.
143
+ > Callbacks with index parameters or expression bodies are not transformed.
144
+
145
+ #### `Array.from()` → [Array spread [...]][mdn-spread]
146
+
147
+ ```diff
148
+ -const doubled = Array.from(numbers).map(n => n * 2);
149
+ -const filtered = Array.from(items).filter(x => x > 5);
150
+ -const arr = Array.from(iterable);
151
+ +const doubled = [...numbers].map(n => n * 2);
152
+ +const filtered = [...items].filter(x => x > 5);
153
+ +const arr = [...iterable];
154
+ ```
155
+
156
+ > [!NOTE]
157
+ > `Array.from()` with a mapping function or thisArg is not converted.
158
+
159
+ #### `Object.assign({}, ...)` → [Object spread {...}][mdn-spread]
108
160
 
109
161
  ```diff
110
162
  -const obj = Object.assign({}, obj1, obj2);
@@ -113,7 +165,7 @@ For more information about Baseline browser support, visit [web.dev/baseline][ba
113
165
  +const copy = { ...original };
114
166
  ```
115
167
 
116
- #### `.concat()` → Array spread
168
+ #### `.concat()` → [Array spread [...]][mdn-spread]
117
169
 
118
170
  ```diff
119
171
  -const combined = arr1.concat(arr2, arr3);
@@ -122,7 +174,16 @@ For more information about Baseline browser support, visit [web.dev/baseline][ba
122
174
  +const withItem = [...array, item];
123
175
  ```
124
176
 
125
- #### Function expressions Arrow functions
177
+ #### `Math.pow()`[Exponentiation operator \*\*][mdn-exponentiation]
178
+
179
+ ```diff
180
+ -const result = Math.pow(2, 3);
181
+ -const area = Math.PI * Math.pow(radius, 2);
182
+ +const result = 2 ** 3;
183
+ +const area = Math.PI * radius ** 2;
184
+ ```
185
+
186
+ #### Function expressions → [Arrow functions][mdn-arrow-functions]
126
187
 
127
188
  ```diff
128
189
  -const fn = function(x) { return x * 2; };
@@ -145,7 +206,7 @@ For more information about Baseline browser support, visit [web.dev/baseline][ba
145
206
  > [!CAUTION]
146
207
  > These transformations are mainly to harden code for future releases and should be used with caution.
147
208
 
148
- #### `new Promise((resolve) => { ... })` → `Promise.try(() => { ... })`
209
+ #### `new Promise((resolve) => { ... })` → [Promise.try][mdn-promise-try]
149
210
 
150
211
  ```diff
151
212
  -new Promise((resolve) => {
@@ -158,4 +219,12 @@ For more information about Baseline browser support, visit [web.dev/baseline][ba
158
219
  ```
159
220
 
160
221
  [baseline]: https://web.dev/baseline/
222
+ [mdn-arrow-functions]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
223
+ [mdn-const]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
224
+ [mdn-exponentiation]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Exponentiation
225
+ [mdn-for-of]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of
226
+ [mdn-let]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
227
+ [mdn-promise-try]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/try
228
+ [mdn-spread]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
229
+ [mdn-template-literals]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
161
230
  [pre-commit]: https://pre-commit.com/
package/bin/esupgrade.js CHANGED
@@ -98,50 +98,52 @@ function processFile(filePath, options) {
98
98
 
99
99
  if (result.modified) {
100
100
  if (options.check) {
101
- console.log(`✗ ${filePath}`)
101
+ // Group changes by type for summary
102
+ const changesByType = {}
102
103
  if (result.changes && result.changes.length > 0) {
103
- // Group changes by type
104
- const changesByType = {}
105
-
106
104
  for (const change of result.changes) {
107
105
  if (!changesByType[change.type]) {
108
- changesByType[change.type] = []
106
+ changesByType[change.type] = 0
109
107
  }
110
- changesByType[change.type].push(change.line)
108
+ changesByType[change.type]++
111
109
  }
110
+ }
112
111
 
113
- for (const [type, lines] of Object.entries(changesByType)) {
114
- const uniqueLines = [...new Set(lines)].sort((a, b) => a - b)
112
+ const transformations = Object.keys(changesByType)
113
+ .map((type) => {
115
114
  const displayName = type
116
115
  .replace(/([A-Z])/g, " $1")
117
116
  .trim()
118
117
  .toLowerCase()
119
- console.log(
120
- ` - ${displayName} (line${uniqueLines.length > 1 ? "s" : ""}: ${uniqueLines.join(", ")})`,
121
- )
122
- }
118
+ return displayName
119
+ })
120
+ .join(", ")
121
+
122
+ console.log(`✗ ${filePath}`)
123
+ if (transformations) {
124
+ console.log(` ${transformations}`)
123
125
  }
124
126
  }
125
127
 
126
128
  if (options.write) {
127
129
  fs.writeFileSync(filePath, result.code, "utf8")
128
130
  if (!options.check) {
129
- console.log(`✓ Upgraded: ${filePath}`)
131
+ console.log(`✓ ${filePath}`)
130
132
  } else {
131
- console.log(` ✓ Changes written to file`)
133
+ console.log(` ✓ written`)
132
134
  }
133
135
  }
134
136
 
135
- return true
137
+ return { modified: true, changes: result.changes }
136
138
  } else {
137
139
  if (!options.check) {
138
- console.log(` No changes: ${filePath}`)
140
+ console.log(` ${filePath}`)
139
141
  }
140
- return false
142
+ return { modified: false, changes: [] }
141
143
  }
142
144
  } catch (error) {
143
- console.error(`Error processing ${filePath}: ${error.message}`)
144
- return false
145
+ console.error(`✗ Error: ${filePath}: ${error.message}`)
146
+ return { modified: false, changes: [] }
145
147
  }
146
148
  }
147
149
 
@@ -153,27 +155,42 @@ function processFiles(patterns, options) {
153
155
  process.exit(0)
154
156
  }
155
157
 
156
- console.log(`Processing ${files.length} file(s) with baseline: ${options.baseline}\n`)
157
-
158
158
  let modifiedCount = 0
159
+ const allChanges = []
160
+
159
161
  for (const file of files) {
160
- if (processFile(file, options)) {
162
+ const result = processFile(file, options)
163
+ if (result.modified) {
161
164
  modifiedCount++
165
+ allChanges.push(...result.changes)
162
166
  }
163
167
  }
164
168
 
165
169
  // Summary
166
- console.log("")
167
- if (modifiedCount > 0) {
168
- if (options.write && options.check) {
169
- console.log(`Summary: ${modifiedCount} file(s) upgraded`)
170
- } else if (options.write) {
171
- console.log(`Summary: ${modifiedCount} file(s) upgraded`)
170
+ if (options.check) {
171
+ console.log("")
172
+ if (modifiedCount > 0) {
173
+ // Count unique transformation types
174
+ const transformTypes = new Set(allChanges.map((c) => c.type))
175
+ const typeCount = transformTypes.size
176
+ const totalChanges = allChanges.length
177
+
178
+ console.log(
179
+ `${modifiedCount} file(s) need upgrading (${totalChanges} change${totalChanges !== 1 ? "s" : ""}, ${typeCount} type${typeCount !== 1 ? "s" : ""})`,
180
+ )
181
+ if (options.write) {
182
+ console.log("Changes have been written")
183
+ }
172
184
  } else {
173
- console.log(`Summary: ${modifiedCount} file(s) need upgrading`)
185
+ console.log("All files are up to date")
174
186
  }
175
187
  } else {
176
- console.log("Summary: All files are already modern")
188
+ console.log("")
189
+ if (modifiedCount > 0) {
190
+ console.log(`✓ ${modifiedCount} file(s) upgraded`)
191
+ } else {
192
+ console.log("All files are up to date")
193
+ }
177
194
  }
178
195
 
179
196
  // Exit with code 1 if --check specified and there were changes
@@ -1,10 +1,10 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" width="640" height="320" font-family="Segoe UI, system-ui, sans-serif" viewBox="0 0 1280 640">
2
2
  <circle cx="260" cy="320" r="200" fill="#f7df1e"/>
3
3
  <path fill="none" stroke="#191919" stroke-width="48" d="m167 409 95-95 95 95m-190 -95 95-95 95 95m415 50"/>
4
- <text x="241" y="148" fill="#c9d1d9" font-size="92" font-weight="bold" transform="matrix(1.6 0 0 1.6 120 120)">
4
+ <text x="241" y="148" fill="#c9d1d9" font-size="90" font-weight="bold" transform="matrix(1.6 0 0 1.6 120 120)">
5
5
  esupgrade
6
6
  </text>
7
- <text x="241" y="192" fill="#c9d1d9" font-size="28" font-style="italic" transform="matrix(1.6 0 0 1.6 120 120)">
7
+ <text x="241" y="192" fill="#c9d1d9" font-size="27" font-style="italic" transform="matrix(1.6 0 0 1.6 120 120)">
8
8
  Auto-upgrade your JavaScript syntax
9
9
  </text>
10
10
  </svg>
@@ -1,10 +1,10 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" width="640" height="320" font-family="Segoe UI, system-ui, sans-serif" viewBox="0 0 1280 640">
2
2
  <circle cx="260" cy="320" r="200" fill="#f7df1e"/>
3
3
  <path fill="none" stroke="#191919" stroke-width="48" d="m167 409 95-95 95 95m-190 -95 95-95 95 95m415 50"/>
4
- <text x="241" y="148" font-size="92" font-weight="bold" transform="matrix(1.6 0 0 1.6 120 120)">
4
+ <text x="241" y="148" font-size="90" font-weight="bold" transform="matrix(1.6 0 0 1.6 120 120)">
5
5
  esupgrade
6
6
  </text>
7
- <text x="241" y="192" font-size="28" font-style="italic" transform="matrix(1.6 0 0 1.6 120 120)">
7
+ <text x="241" y="192" font-size="27" font-style="italic" transform="matrix(1.6 0 0 1.6 120 120)">
8
8
  Auto-upgrade your JavaScript syntax
9
9
  </text>
10
10
  </svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "esupgrade",
3
- "version": "2025.0.2",
3
+ "version": "2025.2.0",
4
4
  "description": "Auto-upgrade your JavaScript syntax",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * Transform new Promise((resolve, reject) => { resolve(fn()) }) to Promise.try(fn)
3
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/try
3
4
  */
4
5
  export function promiseTry(j, root) {
5
6
  let modified = false