@openrewrite/rewrite 8.69.0-20251210-214835 → 8.69.0-20251211-110844
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/dist/cli/cli-utils.d.ts.map +1 -1
- package/dist/cli/cli-utils.js +6 -0
- package/dist/cli/cli-utils.js.map +1 -1
- package/dist/cli/rewrite.d.ts.map +1 -1
- package/dist/cli/rewrite.js +55 -23
- package/dist/cli/rewrite.js.map +1 -1
- package/dist/data-table.d.ts +23 -0
- package/dist/data-table.d.ts.map +1 -1
- package/dist/data-table.js +125 -6
- package/dist/data-table.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/javascript/node-resolution-result.d.ts +9 -0
- package/dist/javascript/node-resolution-result.d.ts.map +1 -1
- package/dist/javascript/node-resolution-result.js +10 -1
- package/dist/javascript/node-resolution-result.js.map +1 -1
- package/dist/javascript/package-manager.d.ts +76 -89
- package/dist/javascript/package-manager.d.ts.map +1 -1
- package/dist/javascript/package-manager.js +114 -139
- package/dist/javascript/package-manager.js.map +1 -1
- package/dist/javascript/recipes/add-dependency.d.ts +57 -0
- package/dist/javascript/recipes/add-dependency.d.ts.map +1 -0
- package/dist/javascript/recipes/add-dependency.js +404 -0
- package/dist/javascript/recipes/add-dependency.js.map +1 -0
- package/dist/javascript/recipes/index.d.ts +1 -0
- package/dist/javascript/recipes/index.d.ts.map +1 -1
- package/dist/javascript/recipes/index.js +1 -0
- package/dist/javascript/recipes/index.js.map +1 -1
- package/dist/javascript/recipes/upgrade-dependency-version.d.ts +3 -24
- package/dist/javascript/recipes/upgrade-dependency-version.d.ts.map +1 -1
- package/dist/javascript/recipes/upgrade-dependency-version.js +34 -157
- package/dist/javascript/recipes/upgrade-dependency-version.js.map +1 -1
- package/dist/javascript/recipes/upgrade-transitive-dependency-version.d.ts +2 -19
- package/dist/javascript/recipes/upgrade-transitive-dependency-version.d.ts.map +1 -1
- package/dist/javascript/recipes/upgrade-transitive-dependency-version.js +21 -137
- package/dist/javascript/recipes/upgrade-transitive-dependency-version.js.map +1 -1
- package/dist/javascript/search/find-dependency.d.ts.map +1 -1
- package/dist/javascript/search/find-dependency.js +8 -47
- package/dist/javascript/search/find-dependency.js.map +1 -1
- package/dist/json/tree.d.ts +30 -0
- package/dist/json/tree.d.ts.map +1 -1
- package/dist/json/tree.js +113 -0
- package/dist/json/tree.js.map +1 -1
- package/dist/parser.d.ts +9 -0
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +27 -0
- package/dist/parser.js.map +1 -1
- package/dist/reference.d.ts.map +1 -1
- package/dist/reference.js +1 -1
- package/dist/reference.js.map +1 -1
- package/dist/version.txt +1 -1
- package/dist/visitor.js +1 -1
- package/dist/visitor.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/cli-utils.ts +6 -0
- package/src/cli/rewrite.ts +53 -17
- package/src/data-table.ts +83 -2
- package/src/index.ts +2 -1
- package/src/javascript/node-resolution-result.ts +16 -0
- package/src/javascript/package-manager.ts +197 -174
- package/src/javascript/recipes/add-dependency.ts +467 -0
- package/src/javascript/recipes/index.ts +1 -0
- package/src/javascript/recipes/upgrade-dependency-version.ts +52 -199
- package/src/javascript/recipes/upgrade-transitive-dependency-version.ts +39 -165
- package/src/javascript/search/find-dependency.ts +13 -52
- package/src/json/tree.ts +98 -1
- package/src/parser.ts +17 -0
- package/src/reference.ts +1 -1
- package/src/visitor.ts +1 -1
|
@@ -17,25 +17,26 @@
|
|
|
17
17
|
import {Option, ScanningRecipe} from "../../recipe";
|
|
18
18
|
import {ExecutionContext} from "../../execution";
|
|
19
19
|
import {TreeVisitor} from "../../visitor";
|
|
20
|
-
import {Json, JsonParser, JsonVisitor} from "../../json";
|
|
20
|
+
import {getMemberKeyName, isLiteral, Json, JsonParser, JsonVisitor} from "../../json";
|
|
21
21
|
import {
|
|
22
|
-
|
|
22
|
+
allDependencyScopes,
|
|
23
|
+
DependencyScope,
|
|
23
24
|
findNodeResolutionResult,
|
|
24
|
-
|
|
25
|
-
PackageLockContent,
|
|
26
|
-
PackageManager,
|
|
27
|
-
readNpmrcConfigs
|
|
25
|
+
PackageManager
|
|
28
26
|
} from "../node-resolution-result";
|
|
29
27
|
import * as path from "path";
|
|
30
28
|
import * as semver from "semver";
|
|
31
29
|
import {markupWarn, replaceMarkerByKind} from "../../markers";
|
|
32
30
|
import {TreePrinters} from "../../print";
|
|
33
|
-
import {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
import {
|
|
32
|
+
createDependencyRecipeAccumulator,
|
|
33
|
+
DependencyRecipeAccumulator,
|
|
34
|
+
getUpdatedLockFileContent,
|
|
35
|
+
runInstallIfNeeded,
|
|
36
|
+
runInstallInTempDir,
|
|
37
|
+
storeInstallResult,
|
|
38
|
+
updateNodeResolutionMarker
|
|
39
|
+
} from "../package-manager";
|
|
39
40
|
|
|
40
41
|
/**
|
|
41
42
|
* Information about a project that needs updating
|
|
@@ -62,25 +63,7 @@ interface ProjectUpdateInfo {
|
|
|
62
63
|
skipInstall: boolean;
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
* Accumulator for tracking state across scanning and editing phases
|
|
67
|
-
*/
|
|
68
|
-
interface Accumulator {
|
|
69
|
-
/** Projects that need updating: packageJsonPath -> update info */
|
|
70
|
-
projectsToUpdate: Map<string, ProjectUpdateInfo>;
|
|
71
|
-
|
|
72
|
-
/** After running package manager, store the updated lock file content */
|
|
73
|
-
updatedLockFiles: Map<string, string>;
|
|
74
|
-
|
|
75
|
-
/** Updated package.json content (after npm install may have modified it) */
|
|
76
|
-
updatedPackageJsons: Map<string, string>;
|
|
77
|
-
|
|
78
|
-
/** Track which projects have been processed (npm install has run) */
|
|
79
|
-
processedProjects: Set<string>;
|
|
80
|
-
|
|
81
|
-
/** Track projects where npm install failed: packageJsonPath -> error message */
|
|
82
|
-
failedProjects: Map<string, string>;
|
|
83
|
-
}
|
|
66
|
+
type Accumulator = DependencyRecipeAccumulator<ProjectUpdateInfo>;
|
|
84
67
|
|
|
85
68
|
/**
|
|
86
69
|
* Upgrades the version of a direct dependency in package.json and updates the lock file.
|
|
@@ -103,26 +86,20 @@ export class UpgradeDependencyVersion extends ScanningRecipe<Accumulator> {
|
|
|
103
86
|
|
|
104
87
|
@Option({
|
|
105
88
|
displayName: "Package name",
|
|
106
|
-
description: "The name of the npm package to upgrade (e.g.,
|
|
89
|
+
description: "The name of the npm package to upgrade (e.g., `lodash`, `@types/node`)",
|
|
107
90
|
example: "lodash"
|
|
108
91
|
})
|
|
109
92
|
packageName!: string;
|
|
110
93
|
|
|
111
94
|
@Option({
|
|
112
|
-
displayName: "
|
|
113
|
-
description: "The
|
|
95
|
+
displayName: "Version",
|
|
96
|
+
description: "The version constraint to set (e.g., `^5.0.0`, `~2.1.0`, `3.0.0`)",
|
|
114
97
|
example: "^5.0.0"
|
|
115
98
|
})
|
|
116
99
|
newVersion!: string;
|
|
117
100
|
|
|
118
101
|
initialValue(_ctx: ExecutionContext): Accumulator {
|
|
119
|
-
return
|
|
120
|
-
projectsToUpdate: new Map(),
|
|
121
|
-
updatedLockFiles: new Map(),
|
|
122
|
-
updatedPackageJsons: new Map(),
|
|
123
|
-
processedProjects: new Set(),
|
|
124
|
-
failedProjects: new Map()
|
|
125
|
-
};
|
|
102
|
+
return createDependencyRecipeAccumulator();
|
|
126
103
|
}
|
|
127
104
|
|
|
128
105
|
/**
|
|
@@ -178,7 +155,7 @@ export class UpgradeDependencyVersion extends ScanningRecipe<Accumulator> {
|
|
|
178
155
|
const pm = marker.packageManager ?? PackageManager.Npm;
|
|
179
156
|
|
|
180
157
|
// Check each dependency scope for the target package
|
|
181
|
-
const scopes
|
|
158
|
+
const scopes = allDependencyScopes;
|
|
182
159
|
let foundScope: DependencyScope | undefined;
|
|
183
160
|
let currentVersion: string | undefined;
|
|
184
161
|
|
|
@@ -244,15 +221,13 @@ export class UpgradeDependencyVersion extends ScanningRecipe<Accumulator> {
|
|
|
244
221
|
return doc; // This package.json doesn't need updating
|
|
245
222
|
}
|
|
246
223
|
|
|
247
|
-
// Run package manager install if
|
|
224
|
+
// Run package manager install if needed, check for failure
|
|
248
225
|
// Skip if the resolved version already satisfies the new constraint
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
acc
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
// Check if the install failed - if so, don't update, just add warning
|
|
255
|
-
const failureMessage = acc.failedProjects.get(sourcePath);
|
|
226
|
+
const failureMessage = updateInfo.skipInstall
|
|
227
|
+
? undefined
|
|
228
|
+
: await runInstallIfNeeded(sourcePath, acc, () =>
|
|
229
|
+
recipe.runPackageManagerInstall(acc, updateInfo, ctx)
|
|
230
|
+
);
|
|
256
231
|
if (failureMessage) {
|
|
257
232
|
return markupWarn(
|
|
258
233
|
doc,
|
|
@@ -270,54 +245,24 @@ export class UpgradeDependencyVersion extends ScanningRecipe<Accumulator> {
|
|
|
270
245
|
const modifiedDoc = await visitor.visit(doc, undefined) as Json.Document;
|
|
271
246
|
|
|
272
247
|
// Update the NodeResolutionResult marker
|
|
273
|
-
|
|
248
|
+
if (updateInfo.skipInstall) {
|
|
249
|
+
// Just update the versionConstraint in the marker - resolved version is unchanged
|
|
250
|
+
return recipe.updateMarkerVersionConstraint(modifiedDoc, updateInfo);
|
|
251
|
+
}
|
|
252
|
+
return updateNodeResolutionMarker(modifiedDoc, updateInfo, acc);
|
|
274
253
|
}
|
|
275
254
|
|
|
276
255
|
// Handle lock files for all package managers
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
if (updateInfo && acc.updatedLockFiles.has(sourcePath)) {
|
|
284
|
-
// Parse the updated lock file content and return it
|
|
285
|
-
const updatedContent = acc.updatedLockFiles.get(sourcePath)!;
|
|
286
|
-
return this.parseUpdatedLockFile(doc, updatedContent);
|
|
287
|
-
}
|
|
288
|
-
break;
|
|
289
|
-
}
|
|
256
|
+
const updatedLockContent = getUpdatedLockFileContent(sourcePath, acc);
|
|
257
|
+
if (updatedLockContent) {
|
|
258
|
+
return await new JsonParser({}).parseOne({
|
|
259
|
+
text: updatedLockContent,
|
|
260
|
+
sourcePath: doc.sourcePath
|
|
261
|
+
}) as Json.Document;
|
|
290
262
|
}
|
|
291
263
|
|
|
292
264
|
return doc;
|
|
293
265
|
}
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* Parses updated lock file content and creates a new document.
|
|
297
|
-
*/
|
|
298
|
-
private async parseUpdatedLockFile(
|
|
299
|
-
originalDoc: Json.Document,
|
|
300
|
-
updatedContent: string
|
|
301
|
-
): Promise<Json.Document> {
|
|
302
|
-
// Parse the updated content using JsonParser
|
|
303
|
-
const parser = new JsonParser({});
|
|
304
|
-
const parsed: Json.Document[] = [];
|
|
305
|
-
|
|
306
|
-
for await (const sf of parser.parse({text: updatedContent, sourcePath: originalDoc.sourcePath})) {
|
|
307
|
-
parsed.push(sf as Json.Document);
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
if (parsed.length > 0) {
|
|
311
|
-
// Preserve the original source path and markers
|
|
312
|
-
return {
|
|
313
|
-
...parsed[0],
|
|
314
|
-
sourcePath: originalDoc.sourcePath,
|
|
315
|
-
markers: originalDoc.markers
|
|
316
|
-
};
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
return originalDoc;
|
|
320
|
-
}
|
|
321
266
|
};
|
|
322
267
|
}
|
|
323
268
|
|
|
@@ -343,20 +288,7 @@ export class UpgradeDependencyVersion extends ScanningRecipe<Accumulator> {
|
|
|
343
288
|
modifiedPackageJson
|
|
344
289
|
);
|
|
345
290
|
|
|
346
|
-
|
|
347
|
-
// Store the modified package.json (we'll use our visitor for actual output)
|
|
348
|
-
acc.updatedPackageJsons.set(updateInfo.packageJsonPath, modifiedPackageJson);
|
|
349
|
-
|
|
350
|
-
// Store the updated lock file content
|
|
351
|
-
if (result.lockFileContent) {
|
|
352
|
-
const lockFileName = getLockFileName(updateInfo.packageManager);
|
|
353
|
-
const lockFilePath = updateInfo.packageJsonPath.replace('package.json', lockFileName);
|
|
354
|
-
acc.updatedLockFiles.set(lockFilePath, result.lockFileContent);
|
|
355
|
-
}
|
|
356
|
-
} else {
|
|
357
|
-
// Track the failure - don't update package.json, the version likely doesn't exist
|
|
358
|
-
acc.failedProjects.set(updateInfo.packageJsonPath, result.error || 'Unknown error');
|
|
359
|
-
}
|
|
291
|
+
storeInstallResult(result, acc, updateInfo, modifiedPackageJson);
|
|
360
292
|
}
|
|
361
293
|
|
|
362
294
|
/**
|
|
@@ -378,91 +310,29 @@ export class UpgradeDependencyVersion extends ScanningRecipe<Accumulator> {
|
|
|
378
310
|
}
|
|
379
311
|
|
|
380
312
|
/**
|
|
381
|
-
* Updates the
|
|
313
|
+
* Updates just the versionConstraint in the marker for the target dependency.
|
|
314
|
+
* Used when skipInstall is true - the resolved version is unchanged.
|
|
382
315
|
*/
|
|
383
|
-
private
|
|
316
|
+
private updateMarkerVersionConstraint(
|
|
384
317
|
doc: Json.Document,
|
|
385
|
-
updateInfo: ProjectUpdateInfo
|
|
386
|
-
|
|
387
|
-
): Promise<Json.Document> {
|
|
318
|
+
updateInfo: ProjectUpdateInfo
|
|
319
|
+
): Json.Document {
|
|
388
320
|
const existingMarker = findNodeResolutionResult(doc);
|
|
389
321
|
if (!existingMarker) {
|
|
390
322
|
return doc;
|
|
391
323
|
}
|
|
392
324
|
|
|
393
|
-
//
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
// Parse the updated package.json and lock file to create new marker
|
|
400
|
-
const updatedPackageJson = acc.updatedPackageJsons.get(updateInfo.packageJsonPath);
|
|
401
|
-
const lockFileName = getLockFileName(updateInfo.packageManager);
|
|
402
|
-
const updatedLockFile = acc.updatedLockFiles.get(
|
|
403
|
-
updateInfo.packageJsonPath.replace('package.json', lockFileName)
|
|
325
|
+
// Update the versionConstraint for the target dependency
|
|
326
|
+
const deps = existingMarker[updateInfo.dependencyScope];
|
|
327
|
+
const updatedDeps = deps?.map(dep =>
|
|
328
|
+
dep.name === this.packageName
|
|
329
|
+
? {...dep, versionConstraint: updateInfo.newVersion}
|
|
330
|
+
: dep
|
|
404
331
|
);
|
|
405
332
|
|
|
406
|
-
let packageJsonContent: PackageJsonContent;
|
|
407
|
-
let lockContent: PackageLockContent | undefined;
|
|
408
|
-
|
|
409
|
-
try {
|
|
410
|
-
packageJsonContent = JSON.parse(updatedPackageJson || updateInfo.originalPackageJson);
|
|
411
|
-
} catch {
|
|
412
|
-
return doc; // Failed to parse, keep original marker
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
if (updatedLockFile) {
|
|
416
|
-
try {
|
|
417
|
-
lockContent = JSON.parse(updatedLockFile);
|
|
418
|
-
} catch {
|
|
419
|
-
// Continue without lock file content
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
// Read npmrc configs from the project directory
|
|
424
|
-
const npmrcConfigs = await readNpmrcConfigs(updateInfo.projectDir);
|
|
425
|
-
|
|
426
|
-
// Create new marker
|
|
427
|
-
const newMarker = createNodeResolutionResultMarker(
|
|
428
|
-
existingMarker.path,
|
|
429
|
-
packageJsonContent,
|
|
430
|
-
lockContent,
|
|
431
|
-
existingMarker.workspacePackagePaths,
|
|
432
|
-
existingMarker.packageManager,
|
|
433
|
-
npmrcConfigs.length > 0 ? npmrcConfigs : undefined
|
|
434
|
-
);
|
|
435
|
-
|
|
436
|
-
// Replace the marker in the document
|
|
437
|
-
return {
|
|
438
|
-
...doc,
|
|
439
|
-
markers: replaceMarkerByKind(doc.markers, newMarker)
|
|
440
|
-
};
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
/**
|
|
444
|
-
* Updates just the versionConstraint in the marker for the target dependency.
|
|
445
|
-
* Used when skipInstall is true - the resolved version is unchanged.
|
|
446
|
-
*/
|
|
447
|
-
private updateMarkerVersionConstraint(
|
|
448
|
-
doc: Json.Document,
|
|
449
|
-
existingMarker: any,
|
|
450
|
-
updateInfo: ProjectUpdateInfo
|
|
451
|
-
): Json.Document {
|
|
452
|
-
// Create updated dependency lists with the new versionConstraint
|
|
453
|
-
const updateDeps = (deps: any[] | undefined) => {
|
|
454
|
-
if (!deps) return deps;
|
|
455
|
-
return deps.map(dep => {
|
|
456
|
-
if (dep.name === this.packageName) {
|
|
457
|
-
return {...dep, versionConstraint: updateInfo.newVersion};
|
|
458
|
-
}
|
|
459
|
-
return dep;
|
|
460
|
-
});
|
|
461
|
-
};
|
|
462
|
-
|
|
463
333
|
const newMarker = {
|
|
464
334
|
...existingMarker,
|
|
465
|
-
[updateInfo.dependencyScope]:
|
|
335
|
+
[updateInfo.dependencyScope]: updatedDeps
|
|
466
336
|
};
|
|
467
337
|
|
|
468
338
|
return {
|
|
@@ -490,7 +360,7 @@ class UpdateVersionVisitor extends JsonVisitor<void> {
|
|
|
490
360
|
|
|
491
361
|
protected async visitMember(member: Json.Member, p: void): Promise<Json | undefined> {
|
|
492
362
|
// Check if we're entering the target scope
|
|
493
|
-
const keyName =
|
|
363
|
+
const keyName = getMemberKeyName(member);
|
|
494
364
|
|
|
495
365
|
if (keyName === this.targetScope) {
|
|
496
366
|
// We're entering the dependencies scope
|
|
@@ -509,33 +379,16 @@ class UpdateVersionVisitor extends JsonVisitor<void> {
|
|
|
509
379
|
return super.visitMember(member, p);
|
|
510
380
|
}
|
|
511
381
|
|
|
512
|
-
private getMemberKeyName(member: Json.Member): string | undefined {
|
|
513
|
-
const key = member.key.element;
|
|
514
|
-
if (key.kind === Json.Kind.Literal) {
|
|
515
|
-
// Remove quotes from string literal
|
|
516
|
-
const source = (key as Json.Literal).source;
|
|
517
|
-
if (source.startsWith('"') && source.endsWith('"')) {
|
|
518
|
-
return source.slice(1, -1);
|
|
519
|
-
}
|
|
520
|
-
return source;
|
|
521
|
-
} else if (key.kind === Json.Kind.Identifier) {
|
|
522
|
-
return (key as Json.Identifier).name;
|
|
523
|
-
}
|
|
524
|
-
return undefined;
|
|
525
|
-
}
|
|
526
|
-
|
|
527
382
|
private updateVersion(member: Json.Member): Json.Member {
|
|
528
383
|
const value = member.value;
|
|
529
384
|
|
|
530
|
-
if (value
|
|
385
|
+
if (!isLiteral(value)) {
|
|
531
386
|
return member; // Not a literal value, can't update
|
|
532
387
|
}
|
|
533
388
|
|
|
534
|
-
const literal = value as Json.Literal;
|
|
535
|
-
|
|
536
389
|
// Create new literal with updated version
|
|
537
390
|
const newLiteral: Json.Literal = {
|
|
538
|
-
...
|
|
391
|
+
...value,
|
|
539
392
|
source: `"${this.newVersion}"`,
|
|
540
393
|
value: this.newVersion
|
|
541
394
|
};
|
|
@@ -19,19 +19,24 @@ import {ExecutionContext} from "../../execution";
|
|
|
19
19
|
import {TreeVisitor} from "../../visitor";
|
|
20
20
|
import {Json, JsonParser, JsonVisitor} from "../../json";
|
|
21
21
|
import {
|
|
22
|
-
|
|
22
|
+
allDependencyScopes,
|
|
23
23
|
findNodeResolutionResult,
|
|
24
24
|
NodeResolutionResultQueries,
|
|
25
|
-
|
|
26
|
-
PackageLockContent,
|
|
27
|
-
PackageManager,
|
|
28
|
-
readNpmrcConfigs
|
|
25
|
+
PackageManager
|
|
29
26
|
} from "../node-resolution-result";
|
|
30
27
|
import * as path from "path";
|
|
31
28
|
import * as semver from "semver";
|
|
32
|
-
import {markupWarn
|
|
29
|
+
import {markupWarn} from "../../markers";
|
|
33
30
|
import {TreePrinters} from "../../print";
|
|
34
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
createDependencyRecipeAccumulator,
|
|
33
|
+
DependencyRecipeAccumulator,
|
|
34
|
+
getUpdatedLockFileContent,
|
|
35
|
+
runInstallIfNeeded,
|
|
36
|
+
runInstallInTempDir,
|
|
37
|
+
storeInstallResult,
|
|
38
|
+
updateNodeResolutionMarker
|
|
39
|
+
} from "../package-manager";
|
|
35
40
|
import {applyOverrideToPackageJson, DependencyPathSegment, parseDependencyPath} from "../dependency-manager";
|
|
36
41
|
|
|
37
42
|
/**
|
|
@@ -57,25 +62,7 @@ interface ProjectUpdateInfo {
|
|
|
57
62
|
dependencyPathSegments?: DependencyPathSegment[];
|
|
58
63
|
}
|
|
59
64
|
|
|
60
|
-
|
|
61
|
-
* Accumulator for tracking state across scanning and editing phases
|
|
62
|
-
*/
|
|
63
|
-
interface Accumulator {
|
|
64
|
-
/** Projects that need updating: packageJsonPath -> update info */
|
|
65
|
-
projectsToUpdate: Map<string, ProjectUpdateInfo>;
|
|
66
|
-
|
|
67
|
-
/** After running package manager, store the updated lock file content */
|
|
68
|
-
updatedLockFiles: Map<string, string>;
|
|
69
|
-
|
|
70
|
-
/** Updated package.json content (after npm install may have modified it) */
|
|
71
|
-
updatedPackageJsons: Map<string, string>;
|
|
72
|
-
|
|
73
|
-
/** Track which projects have been processed (npm install has run) */
|
|
74
|
-
processedProjects: Set<string>;
|
|
75
|
-
|
|
76
|
-
/** Track projects where npm install failed: packageJsonPath -> error message */
|
|
77
|
-
failedProjects: Map<string, string>;
|
|
78
|
-
}
|
|
65
|
+
type Accumulator = DependencyRecipeAccumulator<ProjectUpdateInfo>;
|
|
79
66
|
|
|
80
67
|
/**
|
|
81
68
|
* Upgrades the version of a transitive dependency by adding override entries to package.json.
|
|
@@ -98,14 +85,14 @@ export class UpgradeTransitiveDependencyVersion extends ScanningRecipe<Accumulat
|
|
|
98
85
|
|
|
99
86
|
@Option({
|
|
100
87
|
displayName: "Package name",
|
|
101
|
-
description: "The name of the npm package to upgrade (e.g.,
|
|
88
|
+
description: "The name of the npm package to upgrade (e.g., `lodash`, `@types/node`)",
|
|
102
89
|
example: "lodash"
|
|
103
90
|
})
|
|
104
91
|
packageName!: string;
|
|
105
92
|
|
|
106
93
|
@Option({
|
|
107
|
-
displayName: "
|
|
108
|
-
description: "The
|
|
94
|
+
displayName: "Version",
|
|
95
|
+
description: "The version constraint to set (e.g., `^5.0.0`, `~2.1.0`, `3.0.0`)",
|
|
109
96
|
example: "^5.0.0"
|
|
110
97
|
})
|
|
111
98
|
newVersion!: string;
|
|
@@ -119,13 +106,7 @@ export class UpgradeTransitiveDependencyVersion extends ScanningRecipe<Accumulat
|
|
|
119
106
|
dependencyPath?: string;
|
|
120
107
|
|
|
121
108
|
initialValue(_ctx: ExecutionContext): Accumulator {
|
|
122
|
-
return
|
|
123
|
-
projectsToUpdate: new Map(),
|
|
124
|
-
updatedLockFiles: new Map(),
|
|
125
|
-
updatedPackageJsons: new Map(),
|
|
126
|
-
processedProjects: new Set(),
|
|
127
|
-
failedProjects: new Map()
|
|
128
|
-
};
|
|
109
|
+
return createDependencyRecipeAccumulator();
|
|
129
110
|
}
|
|
130
111
|
|
|
131
112
|
async scanner(acc: Accumulator): Promise<TreeVisitor<any, ExecutionContext>> {
|
|
@@ -148,8 +129,7 @@ export class UpgradeTransitiveDependencyVersion extends ScanningRecipe<Accumulat
|
|
|
148
129
|
const pm = marker.packageManager ?? PackageManager.Npm;
|
|
149
130
|
|
|
150
131
|
// Check if package is a direct dependency - if so, skip (use UpgradeDependencyVersion instead)
|
|
151
|
-
const
|
|
152
|
-
for (const scope of scopes) {
|
|
132
|
+
for (const scope of allDependencyScopes) {
|
|
153
133
|
const deps = marker[scope];
|
|
154
134
|
if (deps?.find(d => d.name === recipe.packageName)) {
|
|
155
135
|
// Package is a direct dependency, don't add override
|
|
@@ -218,14 +198,10 @@ export class UpgradeTransitiveDependencyVersion extends ScanningRecipe<Accumulat
|
|
|
218
198
|
return doc; // This package.json doesn't need updating
|
|
219
199
|
}
|
|
220
200
|
|
|
221
|
-
// Run package manager install if
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// Check if the install failed - if so, don't update, just add warning
|
|
228
|
-
const failureMessage = acc.failedProjects.get(sourcePath);
|
|
201
|
+
// Run package manager install if needed, check for failure
|
|
202
|
+
const failureMessage = await runInstallIfNeeded(sourcePath, acc, () =>
|
|
203
|
+
recipe.runPackageManagerInstall(acc, updateInfo, ctx)
|
|
204
|
+
);
|
|
229
205
|
if (failureMessage) {
|
|
230
206
|
return markupWarn(
|
|
231
207
|
doc,
|
|
@@ -238,23 +214,16 @@ export class UpgradeTransitiveDependencyVersion extends ScanningRecipe<Accumulat
|
|
|
238
214
|
const modifiedDoc = await this.addOverrideEntry(doc, updateInfo);
|
|
239
215
|
|
|
240
216
|
// Update the NodeResolutionResult marker
|
|
241
|
-
return
|
|
217
|
+
return updateNodeResolutionMarker(modifiedDoc, updateInfo, acc);
|
|
242
218
|
}
|
|
243
219
|
|
|
244
220
|
// Handle lock files for all package managers
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
if (updateInfo && acc.updatedLockFiles.has(sourcePath)) {
|
|
252
|
-
// Parse the updated lock file content and return it
|
|
253
|
-
const updatedContent = acc.updatedLockFiles.get(sourcePath)!;
|
|
254
|
-
return this.parseUpdatedLockFile(doc, updatedContent);
|
|
255
|
-
}
|
|
256
|
-
break;
|
|
257
|
-
}
|
|
221
|
+
const updatedLockContent = getUpdatedLockFileContent(sourcePath, acc);
|
|
222
|
+
if (updatedLockContent) {
|
|
223
|
+
return await new JsonParser({}).parseOne({
|
|
224
|
+
text: updatedLockContent,
|
|
225
|
+
sourcePath: doc.sourcePath
|
|
226
|
+
}) as Json.Document;
|
|
258
227
|
}
|
|
259
228
|
|
|
260
229
|
return doc;
|
|
@@ -291,46 +260,15 @@ export class UpgradeTransitiveDependencyVersion extends ScanningRecipe<Accumulat
|
|
|
291
260
|
const newContent = JSON.stringify(modifiedPackageJson, null, indent);
|
|
292
261
|
|
|
293
262
|
// Re-parse with JsonParser to get proper AST
|
|
294
|
-
const
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
sourcePath: doc.sourcePath,
|
|
304
|
-
markers: doc.markers
|
|
305
|
-
};
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
return doc;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* Parses updated lock file content and creates a new document.
|
|
313
|
-
*/
|
|
314
|
-
private async parseUpdatedLockFile(
|
|
315
|
-
originalDoc: Json.Document,
|
|
316
|
-
updatedContent: string
|
|
317
|
-
): Promise<Json.Document> {
|
|
318
|
-
const parser = new JsonParser({});
|
|
319
|
-
const parsed: Json.Document[] = [];
|
|
320
|
-
|
|
321
|
-
for await (const sf of parser.parse({text: updatedContent, sourcePath: originalDoc.sourcePath})) {
|
|
322
|
-
parsed.push(sf as Json.Document);
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
if (parsed.length > 0) {
|
|
326
|
-
return {
|
|
327
|
-
...parsed[0],
|
|
328
|
-
sourcePath: originalDoc.sourcePath,
|
|
329
|
-
markers: originalDoc.markers
|
|
330
|
-
};
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
return originalDoc;
|
|
263
|
+
const parsed = await new JsonParser({}).parseOne({
|
|
264
|
+
text: newContent,
|
|
265
|
+
sourcePath: doc.sourcePath
|
|
266
|
+
}) as Json.Document;
|
|
267
|
+
|
|
268
|
+
return {
|
|
269
|
+
...parsed,
|
|
270
|
+
markers: doc.markers
|
|
271
|
+
};
|
|
334
272
|
}
|
|
335
273
|
};
|
|
336
274
|
}
|
|
@@ -355,18 +293,7 @@ export class UpgradeTransitiveDependencyVersion extends ScanningRecipe<Accumulat
|
|
|
355
293
|
modifiedPackageJson
|
|
356
294
|
);
|
|
357
295
|
|
|
358
|
-
|
|
359
|
-
acc.updatedPackageJsons.set(updateInfo.packageJsonPath, modifiedPackageJson);
|
|
360
|
-
|
|
361
|
-
// Store the updated lock file content
|
|
362
|
-
if (result.lockFileContent) {
|
|
363
|
-
const lockFileName = getLockFileName(updateInfo.packageManager);
|
|
364
|
-
const lockFilePath = updateInfo.packageJsonPath.replace('package.json', lockFileName);
|
|
365
|
-
acc.updatedLockFiles.set(lockFilePath, result.lockFileContent);
|
|
366
|
-
}
|
|
367
|
-
} else {
|
|
368
|
-
acc.failedProjects.set(updateInfo.packageJsonPath, result.error || 'Unknown error');
|
|
369
|
-
}
|
|
296
|
+
storeInstallResult(result, acc, updateInfo, modifiedPackageJson);
|
|
370
297
|
}
|
|
371
298
|
|
|
372
299
|
/**
|
|
@@ -389,57 +316,4 @@ export class UpgradeTransitiveDependencyVersion extends ScanningRecipe<Accumulat
|
|
|
389
316
|
return JSON.stringify(packageJson, null, 2);
|
|
390
317
|
}
|
|
391
318
|
|
|
392
|
-
/**
|
|
393
|
-
* Updates the NodeResolutionResult marker with new dependency information.
|
|
394
|
-
*/
|
|
395
|
-
private async updateMarker(
|
|
396
|
-
doc: Json.Document,
|
|
397
|
-
updateInfo: ProjectUpdateInfo,
|
|
398
|
-
acc: Accumulator
|
|
399
|
-
): Promise<Json.Document> {
|
|
400
|
-
const existingMarker = findNodeResolutionResult(doc);
|
|
401
|
-
if (!existingMarker) {
|
|
402
|
-
return doc;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
// Parse the updated package.json and lock file to create new marker
|
|
406
|
-
const updatedPackageJson = acc.updatedPackageJsons.get(updateInfo.packageJsonPath);
|
|
407
|
-
const lockFileName = getLockFileName(updateInfo.packageManager);
|
|
408
|
-
const updatedLockFile = acc.updatedLockFiles.get(
|
|
409
|
-
updateInfo.packageJsonPath.replace('package.json', lockFileName)
|
|
410
|
-
);
|
|
411
|
-
|
|
412
|
-
let packageJsonContent: PackageJsonContent;
|
|
413
|
-
let lockContent: PackageLockContent | undefined;
|
|
414
|
-
|
|
415
|
-
try {
|
|
416
|
-
packageJsonContent = JSON.parse(updatedPackageJson || updateInfo.originalPackageJson);
|
|
417
|
-
} catch {
|
|
418
|
-
return doc;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
if (updatedLockFile) {
|
|
422
|
-
try {
|
|
423
|
-
lockContent = JSON.parse(updatedLockFile);
|
|
424
|
-
} catch {
|
|
425
|
-
// Continue without lock file content
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
const npmrcConfigs = await readNpmrcConfigs(updateInfo.projectDir);
|
|
430
|
-
|
|
431
|
-
const newMarker = createNodeResolutionResultMarker(
|
|
432
|
-
existingMarker.path,
|
|
433
|
-
packageJsonContent,
|
|
434
|
-
lockContent,
|
|
435
|
-
existingMarker.workspacePackagePaths,
|
|
436
|
-
existingMarker.packageManager,
|
|
437
|
-
npmrcConfigs.length > 0 ? npmrcConfigs : undefined
|
|
438
|
-
);
|
|
439
|
-
|
|
440
|
-
return {
|
|
441
|
-
...doc,
|
|
442
|
-
markers: replaceMarkerByKind(doc.markers, newMarker)
|
|
443
|
-
};
|
|
444
|
-
}
|
|
445
319
|
}
|