esupgrade 2025.3.3 → 2025.3.4
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/bin/esupgrade.js +30 -13
- package/package.json +1 -1
- package/src/widelyAvailable.js +256 -9
- package/tests/cli.test.js +55 -2
- package/tests/newlyAvailable.test.js +2 -2
- package/tests/widelyAvailable.test.js +1362 -948
- package/tests/index.test.js +0 -291
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 = {
|
package/package.json
CHANGED
package/src/widelyAvailable.js
CHANGED
|
@@ -1,20 +1,267 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Check if a pattern (identifier, destructuring, etc.) contains a specific variable name
|
|
3
|
+
* @param {import('jscodeshift').JSCodeshift} j - The jscodeshift API
|
|
4
|
+
* @param {import('jscodeshift').ASTNode | null | undefined} node - The AST node to check
|
|
5
|
+
* @param {string} varName - The variable name to search for
|
|
6
|
+
* @returns {boolean} True if the pattern contains the identifier
|
|
7
|
+
*/
|
|
8
|
+
function patternContainsIdentifier(j, node, varName) {
|
|
9
|
+
if (!node) {
|
|
10
|
+
return false
|
|
11
|
+
}
|
|
12
|
+
if (j.Identifier.check(node)) {
|
|
13
|
+
return node.name === varName
|
|
14
|
+
}
|
|
15
|
+
if (j.ObjectPattern.check(node)) {
|
|
16
|
+
return node.properties.some(
|
|
17
|
+
(prop) =>
|
|
18
|
+
((j.Property.check(prop) || j.ObjectProperty.check(prop)) &&
|
|
19
|
+
patternContainsIdentifier(j, prop.value, varName)) ||
|
|
20
|
+
(j.RestElement.check(prop) &&
|
|
21
|
+
patternContainsIdentifier(j, prop.argument, varName)),
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
if (j.ArrayPattern.check(node)) {
|
|
25
|
+
return node.elements.some((element) =>
|
|
26
|
+
patternContainsIdentifier(j, element, varName),
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
if (j.AssignmentPattern.check(node)) {
|
|
30
|
+
return patternContainsIdentifier(j, node.left, varName)
|
|
31
|
+
}
|
|
32
|
+
// RestElement is the only remaining valid pattern type
|
|
33
|
+
return (
|
|
34
|
+
j.RestElement.check(node) && patternContainsIdentifier(j, node.argument, varName)
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Extract all identifier names from a pattern (handles destructuring)
|
|
40
|
+
* @param {import('jscodeshift').JSCodeshift} j - The jscodeshift API
|
|
41
|
+
* @param {import('jscodeshift').ASTNode | null | undefined} pattern - The pattern node to extract identifiers from
|
|
42
|
+
* @yields {string} Identifier names found in the pattern
|
|
43
|
+
* @returns {Generator<string, void, unknown>}
|
|
44
|
+
*/
|
|
45
|
+
function* extractIdentifiersFromPattern(j, pattern) {
|
|
46
|
+
if (!pattern) return
|
|
47
|
+
|
|
48
|
+
if (j.Identifier.check(pattern)) {
|
|
49
|
+
yield pattern.name
|
|
50
|
+
} else if (j.ObjectPattern.check(pattern)) {
|
|
51
|
+
for (const prop of pattern.properties) {
|
|
52
|
+
if (j.Property.check(prop) || j.ObjectProperty.check(prop)) {
|
|
53
|
+
yield* extractIdentifiersFromPattern(j, prop.value)
|
|
54
|
+
} else if (j.RestElement.check(prop)) {
|
|
55
|
+
yield* extractIdentifiersFromPattern(j, prop.argument)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
} else if (j.ArrayPattern.check(pattern)) {
|
|
59
|
+
for (const element of pattern.elements) {
|
|
60
|
+
yield* extractIdentifiersFromPattern(j, element)
|
|
61
|
+
}
|
|
62
|
+
} else if (j.AssignmentPattern.check(pattern)) {
|
|
63
|
+
yield* extractIdentifiersFromPattern(j, pattern.left)
|
|
64
|
+
} else if (j.RestElement.check(pattern)) {
|
|
65
|
+
yield* extractIdentifiersFromPattern(j, pattern.argument)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Check if an assignment/update expression is shadowed by a closer variable declaration
|
|
71
|
+
* @param {import('jscodeshift').JSCodeshift} j - The jscodeshift API
|
|
72
|
+
* @param {string} varName - The variable name to check
|
|
73
|
+
* @param {import('jscodeshift').ASTPath} declarationPath - The path to the original declaration
|
|
74
|
+
* @param {import('jscodeshift').ASTPath} usagePath - The path to the assignment/update expression
|
|
75
|
+
* @returns {boolean} True if the assignment is shadowed by a closer declaration
|
|
76
|
+
*/
|
|
77
|
+
function isAssignmentShadowed(j, varName, declarationPath, usagePath) {
|
|
78
|
+
let current = usagePath.parent
|
|
79
|
+
|
|
80
|
+
while (current) {
|
|
81
|
+
if (
|
|
82
|
+
j.FunctionDeclaration.check(current.node) ||
|
|
83
|
+
j.FunctionExpression.check(current.node) ||
|
|
84
|
+
j.ArrowFunctionExpression.check(current.node)
|
|
85
|
+
) {
|
|
86
|
+
// Check function parameters
|
|
87
|
+
if (current.node.params) {
|
|
88
|
+
for (const param of current.node.params) {
|
|
89
|
+
if (patternContainsIdentifier(j, param, varName)) {
|
|
90
|
+
return true
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Check for var/let/const declarations in this function
|
|
96
|
+
const functionBody = current.node.body
|
|
97
|
+
if (functionBody) {
|
|
98
|
+
let foundOurDeclaration = false
|
|
99
|
+
const hasLocalDecl = j(functionBody)
|
|
100
|
+
.find(j.VariableDeclarator)
|
|
101
|
+
.some((declPath) => {
|
|
102
|
+
const declParent = declPath.parent.node
|
|
103
|
+
if (declParent === declarationPath.node) {
|
|
104
|
+
foundOurDeclaration = true
|
|
105
|
+
return false
|
|
106
|
+
}
|
|
107
|
+
return patternContainsIdentifier(j, declPath.node.id, varName)
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
// If we found a shadowing declaration (not our own), the assignment is shadowed
|
|
111
|
+
if (hasLocalDecl) {
|
|
112
|
+
return true
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// If we found our declaration in this scope, stop traversing -
|
|
116
|
+
// the assignment is not shadowed, it belongs to our declaration
|
|
117
|
+
if (foundOurDeclaration) {
|
|
118
|
+
return false
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
current = current.parent
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return false
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Check if a variable is reassigned after its declaration
|
|
131
|
+
* @param {import('jscodeshift').JSCodeshift} j - The jscodeshift API
|
|
132
|
+
* @param {import('jscodeshift').Collection} root - The root AST collection
|
|
133
|
+
* @param {string} varName - The variable name to check
|
|
134
|
+
* @param {import('jscodeshift').ASTPath} declarationPath - The path to the variable declaration
|
|
135
|
+
* @returns {boolean} True if the variable is reassigned
|
|
136
|
+
*/
|
|
137
|
+
function isVariableReassigned(j, root, varName, declarationPath) {
|
|
138
|
+
let isReassigned = false
|
|
139
|
+
|
|
140
|
+
// Check for AssignmentExpression where left side targets the variable
|
|
141
|
+
root.find(j.AssignmentExpression).forEach((assignPath) => {
|
|
142
|
+
if (!patternContainsIdentifier(j, assignPath.node.left, varName)) {
|
|
143
|
+
return
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (isAssignmentShadowed(j, varName, declarationPath, assignPath)) {
|
|
147
|
+
return
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
isReassigned = true
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
if (isReassigned) return true
|
|
154
|
+
|
|
155
|
+
// Check for UpdateExpression (++, --)
|
|
156
|
+
root.find(j.UpdateExpression).forEach((updatePath) => {
|
|
157
|
+
if (
|
|
158
|
+
!j.Identifier.check(updatePath.node.argument) ||
|
|
159
|
+
updatePath.node.argument.name !== varName
|
|
160
|
+
) {
|
|
161
|
+
return
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (isAssignmentShadowed(j, varName, declarationPath, updatePath)) {
|
|
165
|
+
return
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
isReassigned = true
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
return isReassigned
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Determine the appropriate kind (const or let) for a declarator
|
|
176
|
+
* @param {import('jscodeshift').JSCodeshift} j - The jscodeshift API
|
|
177
|
+
* @param {import('jscodeshift').Collection} root - The root AST collection
|
|
178
|
+
* @param {import('jscodeshift').VariableDeclarator} declarator - The variable declarator
|
|
179
|
+
* @param {import('jscodeshift').ASTPath} declarationPath - The path to the variable declaration
|
|
180
|
+
* @returns {'const' | 'let'} The appropriate variable kind
|
|
181
|
+
*/
|
|
182
|
+
function determineDeclaratorKind(j, root, declarator, declarationPath) {
|
|
183
|
+
if (j.Identifier.check(declarator.id)) {
|
|
184
|
+
return isVariableReassigned(j, root, declarator.id.name, declarationPath)
|
|
185
|
+
? "let"
|
|
186
|
+
: "const"
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Destructuring pattern - check if any identifier is reassigned
|
|
190
|
+
for (const varName of extractIdentifiersFromPattern(j, declarator.id)) {
|
|
191
|
+
if (isVariableReassigned(j, root, varName, declarationPath)) {
|
|
192
|
+
return "let"
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return "const"
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Process a single declarator variable declaration
|
|
201
|
+
* @param {import('jscodeshift').JSCodeshift} j - The jscodeshift API
|
|
202
|
+
* @param {import('jscodeshift').Collection} root - The root AST collection
|
|
203
|
+
* @param {import('jscodeshift').ASTPath} path - The path to the variable declaration
|
|
204
|
+
* @returns {{ modified: boolean, change: { type: string, line: number } | null }}
|
|
205
|
+
*/
|
|
206
|
+
function processSingleDeclarator(j, root, path) {
|
|
207
|
+
const declarator = path.node.declarations[0]
|
|
208
|
+
const kind = determineDeclaratorKind(j, root, declarator, path)
|
|
209
|
+
|
|
210
|
+
path.node.kind = kind
|
|
211
|
+
|
|
212
|
+
const change = path.node.loc
|
|
213
|
+
? { type: "varToLetOrConst", line: path.node.loc.start.line }
|
|
214
|
+
: null
|
|
215
|
+
|
|
216
|
+
return { modified: true, change }
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Process a multiple declarator variable declaration by splitting into separate declarations
|
|
221
|
+
* @param {import('jscodeshift').JSCodeshift} j - The jscodeshift API
|
|
222
|
+
* @param {import('jscodeshift').Collection} root - The root AST collection
|
|
223
|
+
* @param {import('jscodeshift').ASTPath} path - The path to the variable declaration
|
|
224
|
+
* @returns {{ modified: boolean, change: { type: string, line: number } | null }}
|
|
225
|
+
*/
|
|
226
|
+
function processMultipleDeclarators(j, root, path) {
|
|
227
|
+
const declarations = path.node.declarations.map((declarator) => {
|
|
228
|
+
const kind = determineDeclaratorKind(j, root, declarator, path)
|
|
229
|
+
return j.variableDeclaration(kind, [declarator])
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
j(path).replaceWith(declarations)
|
|
233
|
+
|
|
234
|
+
const change = path.node.loc
|
|
235
|
+
? { type: "varToLetOrConst", line: path.node.loc.start.line }
|
|
236
|
+
: null
|
|
237
|
+
|
|
238
|
+
return { modified: true, change }
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Transform var to const or let
|
|
3
243
|
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const
|
|
4
244
|
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
|
|
245
|
+
* @param {import('jscodeshift').JSCodeshift} j - The jscodeshift API
|
|
246
|
+
* @param {import('jscodeshift').Collection} root - The root AST collection
|
|
247
|
+
* @returns {{ modified: boolean, changes: Array<{ type: string, line: number }> }}
|
|
5
248
|
*/
|
|
6
|
-
export function
|
|
249
|
+
export function varToLetOrConst(j, root) {
|
|
7
250
|
let modified = false
|
|
8
251
|
const changes = []
|
|
9
252
|
|
|
10
253
|
root.find(j.VariableDeclaration, { kind: "var" }).forEach((path) => {
|
|
11
|
-
path.node.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
254
|
+
const isSingleDeclarator = path.node.declarations.length === 1
|
|
255
|
+
|
|
256
|
+
const result = isSingleDeclarator
|
|
257
|
+
? processSingleDeclarator(j, root, path)
|
|
258
|
+
: processMultipleDeclarators(j, root, path)
|
|
259
|
+
|
|
260
|
+
if (result.modified) {
|
|
261
|
+
modified = true
|
|
262
|
+
}
|
|
263
|
+
if (result.change) {
|
|
264
|
+
changes.push(result.change)
|
|
18
265
|
}
|
|
19
266
|
})
|
|
20
267
|
|
package/tests/cli.test.js
CHANGED
|
@@ -274,7 +274,11 @@ describe("CLI", () => {
|
|
|
274
274
|
encoding: "utf8",
|
|
275
275
|
})
|
|
276
276
|
|
|
277
|
-
assert.match(
|
|
277
|
+
assert.match(
|
|
278
|
+
result.stdout,
|
|
279
|
+
/var to let or const/,
|
|
280
|
+
"shows var to let or const changes",
|
|
281
|
+
)
|
|
278
282
|
assert.equal(result.status, 1, "exits with 1")
|
|
279
283
|
})
|
|
280
284
|
|
|
@@ -357,7 +361,11 @@ describe("CLI", () => {
|
|
|
357
361
|
encoding: "utf8",
|
|
358
362
|
})
|
|
359
363
|
|
|
360
|
-
assert.match(
|
|
364
|
+
assert.match(
|
|
365
|
+
result.stdout,
|
|
366
|
+
/var to let or const/,
|
|
367
|
+
"shows var to let or const changes",
|
|
368
|
+
)
|
|
361
369
|
assert.equal(result.status, 1, "exits with 1")
|
|
362
370
|
})
|
|
363
371
|
|
|
@@ -397,6 +405,51 @@ describe("CLI", () => {
|
|
|
397
405
|
assert.equal(result.status, 1, "exits with 1 on errors without --check")
|
|
398
406
|
})
|
|
399
407
|
|
|
408
|
+
test("dry-run mode without flags shows changes but doesn't write", () => {
|
|
409
|
+
const testFile = path.join(tempDir, "test.js")
|
|
410
|
+
const originalCode = `var x = 1;`
|
|
411
|
+
fs.writeFileSync(testFile, originalCode)
|
|
412
|
+
|
|
413
|
+
const result = spawnSync(process.execPath, [CLI_PATH, testFile], {
|
|
414
|
+
encoding: "utf8",
|
|
415
|
+
})
|
|
416
|
+
|
|
417
|
+
assert.equal(
|
|
418
|
+
fs.readFileSync(testFile, "utf8"),
|
|
419
|
+
originalCode,
|
|
420
|
+
"leaves file unchanged",
|
|
421
|
+
)
|
|
422
|
+
assert.match(result.stdout, /✗/, "indicates changes would be made")
|
|
423
|
+
assert.match(
|
|
424
|
+
result.stdout,
|
|
425
|
+
/1 file would be upgraded/,
|
|
426
|
+
"reports 1 file would be upgraded",
|
|
427
|
+
)
|
|
428
|
+
assert.equal(result.status, 0, "exits with 0 in dry-run mode")
|
|
429
|
+
})
|
|
430
|
+
|
|
431
|
+
test("dry-run mode exits with 0 when no changes needed", () => {
|
|
432
|
+
const testFile = path.join(tempDir, "test.js")
|
|
433
|
+
const originalCode = `const x = 1;`
|
|
434
|
+
fs.writeFileSync(testFile, originalCode)
|
|
435
|
+
|
|
436
|
+
const result = spawnSync(process.execPath, [CLI_PATH, testFile], {
|
|
437
|
+
encoding: "utf8",
|
|
438
|
+
})
|
|
439
|
+
|
|
440
|
+
assert.equal(
|
|
441
|
+
fs.readFileSync(testFile, "utf8"),
|
|
442
|
+
originalCode,
|
|
443
|
+
"leaves file unchanged",
|
|
444
|
+
)
|
|
445
|
+
assert.match(
|
|
446
|
+
result.stdout,
|
|
447
|
+
/All files are up to date/,
|
|
448
|
+
"reports all files up to date",
|
|
449
|
+
)
|
|
450
|
+
assert.equal(result.status, 0, "exits with 0")
|
|
451
|
+
})
|
|
452
|
+
|
|
400
453
|
test("exit with 1 on errors even with valid files", () => {
|
|
401
454
|
const validFile = path.join(tempDir, "valid.js")
|
|
402
455
|
const invalidFile = path.join(tempDir, "invalid.js")
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { describe, test } from "node:test"
|
|
1
|
+
import { describe, suite, test } from "node:test"
|
|
2
2
|
import assert from "node:assert/strict"
|
|
3
3
|
import { transform } from "../src/index.js"
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
suite("newly-available", () => {
|
|
6
6
|
describe("Promise.try", () => {
|
|
7
7
|
test("transforms resolve call with argument", () => {
|
|
8
8
|
const result = transform(
|