esupgrade 2025.3.0 → 2025.3.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/package.json +1 -1
- package/src/widelyAvailable.js +30 -70
- package/tests/cli.test.js +150 -110
- package/tests/index.test.js +230 -213
- package/tests/newlyAvailable.test.js +325 -167
- package/tests/widelyAvailable.test.js +1073 -1400
package/package.json
CHANGED
package/src/widelyAvailable.js
CHANGED
|
@@ -68,17 +68,32 @@ export function concatToTemplateLiteral(j, root) {
|
|
|
68
68
|
return false
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
// Helper to get the raw value of a string literal (preserving escape sequences)
|
|
72
|
+
const getRawStringValue = (node) => {
|
|
73
|
+
// In string literals, backslashes are used for escape sequences
|
|
74
|
+
// In template literals, backslashes in the raw value also need escaping
|
|
75
|
+
// So we need to double the backslashes: \\ -> \\\\
|
|
76
|
+
// Note: node.extra.rawValue is always defined for string literals with the current parser
|
|
77
|
+
return node.extra.rawValue.replace(/\\/g, "\\\\")
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const addStringPart = (stringNode) => {
|
|
81
|
+
// Store both the raw and cooked values
|
|
82
|
+
const rawValue = getRawStringValue(stringNode)
|
|
83
|
+
const cookedValue = stringNode.value
|
|
84
|
+
|
|
72
85
|
if (parts.length === 0 || expressions.length >= parts.length) {
|
|
73
|
-
parts.push(
|
|
86
|
+
parts.push({ raw: rawValue, cooked: cookedValue })
|
|
74
87
|
} else {
|
|
75
|
-
parts[parts.length - 1]
|
|
88
|
+
const lastPart = parts[parts.length - 1]
|
|
89
|
+
lastPart.raw += rawValue
|
|
90
|
+
lastPart.cooked += cookedValue
|
|
76
91
|
}
|
|
77
92
|
}
|
|
78
93
|
|
|
79
94
|
const addExpression = (expr) => {
|
|
80
95
|
if (parts.length === 0) {
|
|
81
|
-
parts.push("")
|
|
96
|
+
parts.push({ raw: "", cooked: "" })
|
|
82
97
|
}
|
|
83
98
|
expressions.push(expr)
|
|
84
99
|
}
|
|
@@ -103,8 +118,8 @@ export function concatToTemplateLiteral(j, root) {
|
|
|
103
118
|
// Left is also a + expression - recurse
|
|
104
119
|
flatten(node.left, stringContext)
|
|
105
120
|
} else if (isStringLiteral(node.left)) {
|
|
106
|
-
// Left is a string literal
|
|
107
|
-
addStringPart(node.left
|
|
121
|
+
// Left is a string literal - use raw value to preserve escape sequences
|
|
122
|
+
addStringPart(node.left)
|
|
108
123
|
} else {
|
|
109
124
|
// Left is some other expression
|
|
110
125
|
addExpression(node.left)
|
|
@@ -121,8 +136,8 @@ export function concatToTemplateLiteral(j, root) {
|
|
|
121
136
|
flatten(node.right, rightInStringContext)
|
|
122
137
|
}
|
|
123
138
|
} else if (isStringLiteral(node.right)) {
|
|
124
|
-
// Right is a string literal
|
|
125
|
-
addStringPart(node.right
|
|
139
|
+
// Right is a string literal - use raw value to preserve escape sequences
|
|
140
|
+
addStringPart(node.right)
|
|
126
141
|
} else {
|
|
127
142
|
// Right is some other expression
|
|
128
143
|
addExpression(node.right)
|
|
@@ -135,12 +150,15 @@ export function concatToTemplateLiteral(j, root) {
|
|
|
135
150
|
|
|
136
151
|
// Ensure we have the right number of quasis (one more than expressions)
|
|
137
152
|
while (parts.length <= expressions.length) {
|
|
138
|
-
parts.push("")
|
|
153
|
+
parts.push({ raw: "", cooked: "" })
|
|
139
154
|
}
|
|
140
155
|
|
|
141
156
|
// Create template literal
|
|
142
157
|
const quasis = parts.map((part, i) =>
|
|
143
|
-
j.templateElement(
|
|
158
|
+
j.templateElement(
|
|
159
|
+
{ raw: part.raw, cooked: part.cooked },
|
|
160
|
+
i === parts.length - 1,
|
|
161
|
+
),
|
|
144
162
|
)
|
|
145
163
|
|
|
146
164
|
const templateLiteral = j.templateLiteral(quasis, expressions)
|
|
@@ -913,62 +931,6 @@ export function anonymousFunctionToArrow(j, root) {
|
|
|
913
931
|
return found
|
|
914
932
|
}
|
|
915
933
|
|
|
916
|
-
// Helper to check if a node or its descendants use 'super'
|
|
917
|
-
const usesSuper = (node) => {
|
|
918
|
-
let found = false
|
|
919
|
-
|
|
920
|
-
const visit = (n) => {
|
|
921
|
-
if (!n || typeof n !== "object" || found) return
|
|
922
|
-
|
|
923
|
-
// If we encounter a nested function, don't traverse into it
|
|
924
|
-
// as it has its own 'super' binding context
|
|
925
|
-
if (n.type === "FunctionExpression" || n.type === "FunctionDeclaration") {
|
|
926
|
-
return
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
// Check if this is a 'super' node
|
|
930
|
-
if (n.type === "Super") {
|
|
931
|
-
found = true
|
|
932
|
-
return
|
|
933
|
-
}
|
|
934
|
-
|
|
935
|
-
// Traverse all child nodes
|
|
936
|
-
for (const key in n) {
|
|
937
|
-
if (
|
|
938
|
-
key === "loc" ||
|
|
939
|
-
key === "start" ||
|
|
940
|
-
key === "end" ||
|
|
941
|
-
key === "tokens" ||
|
|
942
|
-
key === "comments" ||
|
|
943
|
-
key === "type"
|
|
944
|
-
) {
|
|
945
|
-
continue
|
|
946
|
-
}
|
|
947
|
-
const value = n[key]
|
|
948
|
-
if (Array.isArray(value)) {
|
|
949
|
-
for (const item of value) {
|
|
950
|
-
visit(item)
|
|
951
|
-
if (found) return
|
|
952
|
-
}
|
|
953
|
-
} else if (value && typeof value === "object") {
|
|
954
|
-
visit(value)
|
|
955
|
-
}
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
// Start visiting from the function body's child nodes
|
|
960
|
-
// Don't check the body node itself, check its contents
|
|
961
|
-
// Note: FunctionExpression.body is always a BlockStatement
|
|
962
|
-
if (node.type === "BlockStatement" && node.body) {
|
|
963
|
-
for (const statement of node.body) {
|
|
964
|
-
visit(statement)
|
|
965
|
-
if (found) break
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
|
|
969
|
-
return found
|
|
970
|
-
}
|
|
971
|
-
|
|
972
934
|
root
|
|
973
935
|
.find(j.FunctionExpression)
|
|
974
936
|
.filter((path) => {
|
|
@@ -996,10 +958,8 @@ export function anonymousFunctionToArrow(j, root) {
|
|
|
996
958
|
return false
|
|
997
959
|
}
|
|
998
960
|
|
|
999
|
-
//
|
|
1000
|
-
|
|
1001
|
-
return false
|
|
1002
|
-
}
|
|
961
|
+
// Note: We don't need to check for 'super' because using super in a
|
|
962
|
+
// function expression is a syntax error and will never parse successfully
|
|
1003
963
|
|
|
1004
964
|
return true
|
|
1005
965
|
})
|
package/tests/cli.test.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import assert from "node:assert"
|
|
3
|
-
import {
|
|
1
|
+
import { afterEach, beforeEach, describe, test } from "node:test"
|
|
2
|
+
import assert from "node:assert/strict"
|
|
3
|
+
import { spawnSync } from "node:child_process"
|
|
4
4
|
import fs from "node:fs"
|
|
5
5
|
import path from "node:path"
|
|
6
6
|
import os from "node:os"
|
|
@@ -20,50 +20,63 @@ describe("CLI", () => {
|
|
|
20
20
|
}
|
|
21
21
|
})
|
|
22
22
|
|
|
23
|
-
test("
|
|
23
|
+
test("display help when no files specified", () => {
|
|
24
24
|
const result = spawnSync(process.execPath, [CLI_PATH], {
|
|
25
25
|
encoding: "utf8",
|
|
26
26
|
})
|
|
27
27
|
|
|
28
|
-
assert.match(
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
assert.match(
|
|
29
|
+
result.stderr,
|
|
30
|
+
/Error: No files specified/,
|
|
31
|
+
"displays error for no files",
|
|
32
|
+
)
|
|
33
|
+
assert.equal(result.status, 0, "exits with 0 when showing help")
|
|
31
34
|
})
|
|
32
35
|
|
|
33
|
-
test("
|
|
36
|
+
test("transform a single file with --write", () => {
|
|
34
37
|
const testFile = path.join(tempDir, "test.js")
|
|
35
|
-
|
|
36
|
-
fs.writeFileSync(testFile, originalCode)
|
|
38
|
+
fs.writeFileSync(testFile, `var x = 1;`)
|
|
37
39
|
|
|
38
40
|
const result = spawnSync(process.execPath, [CLI_PATH, testFile, "--write"], {
|
|
39
41
|
encoding: "utf8",
|
|
40
42
|
})
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
assert.match(
|
|
45
|
+
fs.readFileSync(testFile, "utf8"),
|
|
46
|
+
/const x = 1/,
|
|
47
|
+
"transforms var to const",
|
|
48
|
+
)
|
|
49
|
+
assert.match(result.stdout, /✓ 1 file\(s\) upgraded/, "reports 1 file upgraded")
|
|
50
|
+
assert.equal(result.status, 0, "exits successfully")
|
|
46
51
|
})
|
|
47
52
|
|
|
48
|
-
test("
|
|
53
|
+
test("transform files with widely-available baseline by default", () => {
|
|
49
54
|
const testFile = path.join(tempDir, "test.js")
|
|
50
|
-
|
|
51
|
-
|
|
55
|
+
fs.writeFileSync(
|
|
56
|
+
testFile,
|
|
57
|
+
`var x = 1;\nconst p = new Promise((resolve) => resolve(getData()));`,
|
|
58
|
+
)
|
|
52
59
|
|
|
53
60
|
const result = spawnSync(process.execPath, [CLI_PATH, testFile, "--write"], {
|
|
54
61
|
encoding: "utf8",
|
|
55
62
|
})
|
|
56
63
|
|
|
57
64
|
const transformedCode = fs.readFileSync(testFile, "utf8")
|
|
58
|
-
assert.match(transformedCode, /const x = 1
|
|
59
|
-
assert.doesNotMatch(
|
|
60
|
-
|
|
65
|
+
assert.match(transformedCode, /const x = 1/, "transforms var to const")
|
|
66
|
+
assert.doesNotMatch(
|
|
67
|
+
transformedCode,
|
|
68
|
+
/Promise\.try/,
|
|
69
|
+
"excludes Promise.try for widely-available baseline",
|
|
70
|
+
)
|
|
71
|
+
assert.equal(result.status, 0, "exits successfully")
|
|
61
72
|
})
|
|
62
73
|
|
|
63
|
-
test("
|
|
74
|
+
test("transform files with newly-available baseline", () => {
|
|
64
75
|
const testFile = path.join(tempDir, "test.js")
|
|
65
|
-
|
|
66
|
-
|
|
76
|
+
fs.writeFileSync(
|
|
77
|
+
testFile,
|
|
78
|
+
`var x = 1;\nconst p = new Promise((resolve) => resolve(getData()));`,
|
|
79
|
+
)
|
|
67
80
|
|
|
68
81
|
const result = spawnSync(
|
|
69
82
|
process.execPath,
|
|
@@ -74,12 +87,16 @@ describe("CLI", () => {
|
|
|
74
87
|
)
|
|
75
88
|
|
|
76
89
|
const transformedCode = fs.readFileSync(testFile, "utf8")
|
|
77
|
-
assert.match(transformedCode, /const x = 1
|
|
78
|
-
assert.match(
|
|
79
|
-
|
|
90
|
+
assert.match(transformedCode, /const x = 1/, "transforms var to const")
|
|
91
|
+
assert.match(
|
|
92
|
+
transformedCode,
|
|
93
|
+
/Promise\.try/,
|
|
94
|
+
"includes Promise.try for newly-available baseline",
|
|
95
|
+
)
|
|
96
|
+
assert.equal(result.status, 0, "exits successfully")
|
|
80
97
|
})
|
|
81
98
|
|
|
82
|
-
test("
|
|
99
|
+
test("check files without writing with --check", () => {
|
|
83
100
|
const testFile = path.join(tempDir, "test.js")
|
|
84
101
|
const originalCode = `var x = 1;`
|
|
85
102
|
fs.writeFileSync(testFile, originalCode)
|
|
@@ -88,14 +105,21 @@ describe("CLI", () => {
|
|
|
88
105
|
encoding: "utf8",
|
|
89
106
|
})
|
|
90
107
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
108
|
+
assert.equal(
|
|
109
|
+
fs.readFileSync(testFile, "utf8"),
|
|
110
|
+
originalCode,
|
|
111
|
+
"leaves file unchanged",
|
|
112
|
+
)
|
|
113
|
+
assert.match(result.stdout, /✗/, "indicates changes needed")
|
|
114
|
+
assert.match(
|
|
115
|
+
result.stdout,
|
|
116
|
+
/1 file\(s\) need upgrading/,
|
|
117
|
+
"reports 1 file needs upgrading",
|
|
118
|
+
)
|
|
119
|
+
assert.equal(result.status, 1, "exits with 1 when changes needed")
|
|
96
120
|
})
|
|
97
121
|
|
|
98
|
-
test("
|
|
122
|
+
test("exit with 0 when --check and no changes needed", () => {
|
|
99
123
|
const testFile = path.join(tempDir, "test.js")
|
|
100
124
|
const originalCode = `const x = 1;`
|
|
101
125
|
fs.writeFileSync(testFile, originalCode)
|
|
@@ -104,16 +128,22 @@ describe("CLI", () => {
|
|
|
104
128
|
encoding: "utf8",
|
|
105
129
|
})
|
|
106
130
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
131
|
+
assert.equal(
|
|
132
|
+
fs.readFileSync(testFile, "utf8"),
|
|
133
|
+
originalCode,
|
|
134
|
+
"leaves file unchanged",
|
|
135
|
+
)
|
|
136
|
+
assert.match(
|
|
137
|
+
result.stdout,
|
|
138
|
+
/All files are up to date/,
|
|
139
|
+
"reports all files up to date",
|
|
140
|
+
)
|
|
141
|
+
assert.equal(result.status, 0, "exits with 0")
|
|
111
142
|
})
|
|
112
143
|
|
|
113
|
-
test("
|
|
144
|
+
test("support both --check and --write together", () => {
|
|
114
145
|
const testFile = path.join(tempDir, "test.js")
|
|
115
|
-
|
|
116
|
-
fs.writeFileSync(testFile, originalCode)
|
|
146
|
+
fs.writeFileSync(testFile, `var x = 1;`)
|
|
117
147
|
|
|
118
148
|
const result = spawnSync(
|
|
119
149
|
process.execPath,
|
|
@@ -123,14 +153,17 @@ describe("CLI", () => {
|
|
|
123
153
|
},
|
|
124
154
|
)
|
|
125
155
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
156
|
+
assert.match(
|
|
157
|
+
fs.readFileSync(testFile, "utf8"),
|
|
158
|
+
/const x = 1/,
|
|
159
|
+
"transforms var to const",
|
|
160
|
+
)
|
|
161
|
+
assert.match(result.stdout, /✗/, "indicates changes needed")
|
|
162
|
+
assert.match(result.stdout, /Changes have been written/, "reports changes written")
|
|
163
|
+
assert.equal(result.status, 1, "exits with 1 with --check")
|
|
131
164
|
})
|
|
132
165
|
|
|
133
|
-
test("
|
|
166
|
+
test("process directory recursively", () => {
|
|
134
167
|
const subDir = path.join(tempDir, "src")
|
|
135
168
|
fs.mkdirSync(subDir)
|
|
136
169
|
|
|
@@ -143,36 +176,31 @@ describe("CLI", () => {
|
|
|
143
176
|
encoding: "utf8",
|
|
144
177
|
})
|
|
145
178
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
assert.match(
|
|
149
|
-
assert.
|
|
150
|
-
assert.match(result.stdout, /2 file\(s\) upgraded/)
|
|
151
|
-
assert.strictEqual(result.status, 0)
|
|
179
|
+
assert.match(fs.readFileSync(file1, "utf8"), /const x = 1/, "transforms file1")
|
|
180
|
+
assert.match(fs.readFileSync(file2, "utf8"), /const y = 2/, "transforms file2")
|
|
181
|
+
assert.match(result.stdout, /2 file\(s\) upgraded/, "reports 2 files upgraded")
|
|
182
|
+
assert.equal(result.status, 0, "exits successfully")
|
|
152
183
|
})
|
|
153
184
|
|
|
154
|
-
test("
|
|
185
|
+
test("skip node_modules and .git directories", () => {
|
|
155
186
|
const nodeModules = path.join(tempDir, "node_modules")
|
|
156
187
|
const gitDir = path.join(tempDir, ".git")
|
|
157
188
|
fs.mkdirSync(nodeModules)
|
|
158
189
|
fs.mkdirSync(gitDir)
|
|
159
190
|
|
|
160
191
|
const file1 = path.join(tempDir, "test.js")
|
|
161
|
-
const file2 = path.join(nodeModules, "test.js")
|
|
162
|
-
const file3 = path.join(gitDir, "test.js")
|
|
163
192
|
fs.writeFileSync(file1, `var x = 1;`)
|
|
164
|
-
fs.writeFileSync(
|
|
165
|
-
fs.writeFileSync(
|
|
193
|
+
fs.writeFileSync(path.join(nodeModules, "test.js"), `var y = 2;`)
|
|
194
|
+
fs.writeFileSync(path.join(gitDir, "test.js"), `var z = 3;`)
|
|
166
195
|
|
|
167
196
|
const result = spawnSync(process.execPath, [CLI_PATH, tempDir, "--write"], {
|
|
168
197
|
encoding: "utf8",
|
|
169
198
|
})
|
|
170
199
|
|
|
171
|
-
|
|
172
|
-
assert.strictEqual(result.status, 0)
|
|
200
|
+
assert.equal(result.status, 0, "exits successfully skipping ignored dirs")
|
|
173
201
|
})
|
|
174
202
|
|
|
175
|
-
test("
|
|
203
|
+
test("process multiple file extensions", () => {
|
|
176
204
|
const jsFile = path.join(tempDir, "test.js")
|
|
177
205
|
const mjsFile = path.join(tempDir, "test.mjs")
|
|
178
206
|
const cjsFile = path.join(tempDir, "test.cjs")
|
|
@@ -187,11 +215,11 @@ describe("CLI", () => {
|
|
|
187
215
|
encoding: "utf8",
|
|
188
216
|
})
|
|
189
217
|
|
|
190
|
-
assert.match(result.stdout, /4 file\(s\) upgraded
|
|
191
|
-
assert.
|
|
218
|
+
assert.match(result.stdout, /4 file\(s\) upgraded/, "reports 4 files upgraded")
|
|
219
|
+
assert.equal(result.status, 0, "exits successfully")
|
|
192
220
|
})
|
|
193
221
|
|
|
194
|
-
test("
|
|
222
|
+
test("handle TypeScript file extensions", () => {
|
|
195
223
|
const tsFile = path.join(tempDir, "test.ts")
|
|
196
224
|
const tsxFile = path.join(tempDir, "test.tsx")
|
|
197
225
|
|
|
@@ -202,10 +230,10 @@ describe("CLI", () => {
|
|
|
202
230
|
encoding: "utf8",
|
|
203
231
|
})
|
|
204
232
|
|
|
205
|
-
assert.
|
|
233
|
+
assert.equal(result.status, 0, "exits successfully for TS files")
|
|
206
234
|
})
|
|
207
235
|
|
|
208
|
-
test("
|
|
236
|
+
test("error on invalid baseline", () => {
|
|
209
237
|
const testFile = path.join(tempDir, "test.js")
|
|
210
238
|
fs.writeFileSync(testFile, `var x = 1;`)
|
|
211
239
|
|
|
@@ -217,11 +245,11 @@ describe("CLI", () => {
|
|
|
217
245
|
},
|
|
218
246
|
)
|
|
219
247
|
|
|
220
|
-
assert.match(result.stderr, /error
|
|
221
|
-
assert.
|
|
248
|
+
assert.match(result.stderr, /error/, "displays error for invalid baseline")
|
|
249
|
+
assert.equal(result.status, 1, "exits with 1")
|
|
222
250
|
})
|
|
223
251
|
|
|
224
|
-
test("
|
|
252
|
+
test("error on non-existent file", () => {
|
|
225
253
|
const result = spawnSync(
|
|
226
254
|
process.execPath,
|
|
227
255
|
[CLI_PATH, path.join(tempDir, "nonexistent.js")],
|
|
@@ -230,24 +258,27 @@ describe("CLI", () => {
|
|
|
230
258
|
},
|
|
231
259
|
)
|
|
232
260
|
|
|
233
|
-
assert.match(
|
|
234
|
-
|
|
261
|
+
assert.match(
|
|
262
|
+
result.stderr,
|
|
263
|
+
/Error: Cannot access/,
|
|
264
|
+
"displays error for non-existent file",
|
|
265
|
+
)
|
|
266
|
+
assert.equal(result.status, 1, "exits with 1")
|
|
235
267
|
})
|
|
236
268
|
|
|
237
|
-
test("
|
|
269
|
+
test("show detailed changes with --check", () => {
|
|
238
270
|
const testFile = path.join(tempDir, "test.js")
|
|
239
|
-
|
|
240
|
-
fs.writeFileSync(testFile, originalCode)
|
|
271
|
+
fs.writeFileSync(testFile, `var x = 1;\nvar y = 2;`)
|
|
241
272
|
|
|
242
273
|
const result = spawnSync(process.execPath, [CLI_PATH, testFile, "--check"], {
|
|
243
274
|
encoding: "utf8",
|
|
244
275
|
})
|
|
245
276
|
|
|
246
|
-
assert.match(result.stdout, /var to const
|
|
247
|
-
assert.
|
|
277
|
+
assert.match(result.stdout, /var to const/, "shows var to const changes")
|
|
278
|
+
assert.equal(result.status, 1, "exits with 1")
|
|
248
279
|
})
|
|
249
280
|
|
|
250
|
-
test("
|
|
281
|
+
test("process multiple files specified as arguments", () => {
|
|
251
282
|
const file1 = path.join(tempDir, "test1.js")
|
|
252
283
|
const file2 = path.join(tempDir, "test2.js")
|
|
253
284
|
fs.writeFileSync(file1, `var x = 1;`)
|
|
@@ -257,15 +288,13 @@ describe("CLI", () => {
|
|
|
257
288
|
encoding: "utf8",
|
|
258
289
|
})
|
|
259
290
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
assert.match(
|
|
263
|
-
assert.
|
|
264
|
-
assert.match(result.stdout, /2 file\(s\) upgraded/)
|
|
265
|
-
assert.strictEqual(result.status, 0)
|
|
291
|
+
assert.match(fs.readFileSync(file1, "utf8"), /const x = 1/, "transforms file1")
|
|
292
|
+
assert.match(fs.readFileSync(file2, "utf8"), /const y = 2/, "transforms file2")
|
|
293
|
+
assert.match(result.stdout, /2 file\(s\) upgraded/, "reports 2 files upgraded")
|
|
294
|
+
assert.equal(result.status, 0, "exits successfully")
|
|
266
295
|
})
|
|
267
296
|
|
|
268
|
-
test("
|
|
297
|
+
test("handle files with no changes needed", () => {
|
|
269
298
|
const testFile = path.join(tempDir, "test.js")
|
|
270
299
|
const originalCode = `const x = 1;`
|
|
271
300
|
fs.writeFileSync(testFile, originalCode)
|
|
@@ -274,13 +303,20 @@ describe("CLI", () => {
|
|
|
274
303
|
encoding: "utf8",
|
|
275
304
|
})
|
|
276
305
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
306
|
+
assert.equal(
|
|
307
|
+
fs.readFileSync(testFile, "utf8"),
|
|
308
|
+
originalCode,
|
|
309
|
+
"leaves file unchanged",
|
|
310
|
+
)
|
|
311
|
+
assert.match(
|
|
312
|
+
result.stdout,
|
|
313
|
+
/All files are up to date/,
|
|
314
|
+
"reports all files up to date",
|
|
315
|
+
)
|
|
316
|
+
assert.equal(result.status, 0, "exits successfully")
|
|
281
317
|
})
|
|
282
318
|
|
|
283
|
-
test("
|
|
319
|
+
test("show no changes message for individual files", () => {
|
|
284
320
|
const testFile = path.join(tempDir, "test.js")
|
|
285
321
|
const originalCode = `const x = 1;`
|
|
286
322
|
fs.writeFileSync(testFile, originalCode)
|
|
@@ -289,11 +325,15 @@ describe("CLI", () => {
|
|
|
289
325
|
encoding: "utf8",
|
|
290
326
|
})
|
|
291
327
|
|
|
292
|
-
assert.match(
|
|
293
|
-
|
|
328
|
+
assert.match(
|
|
329
|
+
result.stdout,
|
|
330
|
+
/All files are up to date/,
|
|
331
|
+
"reports all files up to date",
|
|
332
|
+
)
|
|
333
|
+
assert.equal(result.status, 0, "exits successfully")
|
|
294
334
|
})
|
|
295
335
|
|
|
296
|
-
test("
|
|
336
|
+
test("handle empty directory", () => {
|
|
297
337
|
const emptyDir = path.join(tempDir, "empty")
|
|
298
338
|
fs.mkdirSync(emptyDir)
|
|
299
339
|
|
|
@@ -301,37 +341,39 @@ describe("CLI", () => {
|
|
|
301
341
|
encoding: "utf8",
|
|
302
342
|
})
|
|
303
343
|
|
|
304
|
-
assert.match(
|
|
305
|
-
|
|
344
|
+
assert.match(
|
|
345
|
+
result.stdout,
|
|
346
|
+
/No JavaScript files found/,
|
|
347
|
+
"reports no JS files found",
|
|
348
|
+
)
|
|
349
|
+
assert.equal(result.status, 0, "exits successfully")
|
|
306
350
|
})
|
|
307
351
|
|
|
308
|
-
test("
|
|
352
|
+
test("group changes by type in --check output", () => {
|
|
309
353
|
const testFile = path.join(tempDir, "test.js")
|
|
310
|
-
|
|
311
|
-
fs.writeFileSync(testFile, originalCode)
|
|
354
|
+
fs.writeFileSync(testFile, `var x = 1;\nvar y = 2;\nvar z = 3;`)
|
|
312
355
|
|
|
313
356
|
const result = spawnSync(process.execPath, [CLI_PATH, testFile, "--check"], {
|
|
314
357
|
encoding: "utf8",
|
|
315
358
|
})
|
|
316
359
|
|
|
317
|
-
assert.match(result.stdout, /var to const
|
|
318
|
-
assert.
|
|
360
|
+
assert.match(result.stdout, /var to const/, "shows var to const changes")
|
|
361
|
+
assert.equal(result.status, 1, "exits with 1")
|
|
319
362
|
})
|
|
320
363
|
|
|
321
|
-
test("
|
|
364
|
+
test("handle syntax errors gracefully", () => {
|
|
322
365
|
const testFile = path.join(tempDir, "test.js")
|
|
323
|
-
|
|
324
|
-
fs.writeFileSync(testFile, invalidCode)
|
|
366
|
+
fs.writeFileSync(testFile, `var x = {{{;`)
|
|
325
367
|
|
|
326
368
|
const result = spawnSync(process.execPath, [CLI_PATH, testFile, "--write"], {
|
|
327
369
|
encoding: "utf8",
|
|
328
370
|
})
|
|
329
371
|
|
|
330
|
-
assert.match(result.stderr, /✗ Error
|
|
331
|
-
assert.
|
|
372
|
+
assert.match(result.stderr, /✗ Error:/, "displays error for syntax issues")
|
|
373
|
+
assert.equal(result.status, 0, "continues despite errors")
|
|
332
374
|
})
|
|
333
375
|
|
|
334
|
-
test("
|
|
376
|
+
test("handle mixed directory and file arguments", () => {
|
|
335
377
|
const subDir = path.join(tempDir, "src")
|
|
336
378
|
fs.mkdirSync(subDir)
|
|
337
379
|
|
|
@@ -344,11 +386,9 @@ describe("CLI", () => {
|
|
|
344
386
|
encoding: "utf8",
|
|
345
387
|
})
|
|
346
388
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
assert.match(
|
|
350
|
-
assert.
|
|
351
|
-
assert.match(result.stdout, /2 file\(s\) upgraded/)
|
|
352
|
-
assert.strictEqual(result.status, 0)
|
|
389
|
+
assert.match(fs.readFileSync(file1, "utf8"), /const x = 1/, "transforms file1")
|
|
390
|
+
assert.match(fs.readFileSync(file2, "utf8"), /const y = 2/, "transforms file2")
|
|
391
|
+
assert.match(result.stdout, /2 file\(s\) upgraded/, "reports 2 files upgraded")
|
|
392
|
+
assert.equal(result.status, 0, "exits successfully")
|
|
353
393
|
})
|
|
354
394
|
})
|