@openrewrite/rewrite 8.83.4 → 8.83.5
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/index.d.ts.map +1 -1
- package/dist/index.js +1 -5
- package/dist/index.js.map +1 -1
- package/dist/java/rpc.d.ts.map +1 -1
- package/dist/java/rpc.js +2 -0
- package/dist/java/rpc.js.map +1 -1
- package/dist/java/tree.d.ts +1 -0
- package/dist/java/tree.d.ts.map +1 -1
- package/dist/java/tree.js.map +1 -1
- package/dist/java/visitor.d.ts.map +1 -1
- package/dist/java/visitor.js +1 -0
- package/dist/java/visitor.js.map +1 -1
- package/dist/javascript/parser.d.ts.map +1 -1
- package/dist/javascript/parser.js +8 -0
- package/dist/javascript/parser.js.map +1 -1
- package/dist/javascript/recipes/dependencies.d.ts +63 -0
- package/dist/javascript/recipes/dependencies.d.ts.map +1 -0
- package/dist/javascript/recipes/dependencies.js +49 -0
- package/dist/javascript/recipes/dependencies.js.map +1 -0
- package/dist/javascript/recipes/index.d.ts +1 -4
- package/dist/javascript/recipes/index.d.ts.map +1 -1
- package/dist/javascript/recipes/index.js +1 -4
- package/dist/javascript/recipes/index.js.map +1 -1
- package/dist/rewrite-javascript-version.txt +1 -1
- package/package.json +1 -1
- package/src/index.ts +0 -8
- package/src/java/rpc.ts +2 -0
- package/src/java/tree.ts +1 -0
- package/src/java/visitor.ts +1 -0
- package/src/javascript/parser.ts +8 -0
- package/src/javascript/recipes/dependencies.ts +108 -0
- package/src/javascript/recipes/index.ts +1 -4
- package/dist/javascript/recipes/add-dependency.d.ts +0 -61
- package/dist/javascript/recipes/add-dependency.d.ts.map +0 -1
- package/dist/javascript/recipes/add-dependency.js +0 -430
- package/dist/javascript/recipes/add-dependency.js.map +0 -1
- package/dist/javascript/recipes/remove-dependency.d.ts +0 -29
- package/dist/javascript/recipes/remove-dependency.d.ts.map +0 -1
- package/dist/javascript/recipes/remove-dependency.js +0 -261
- package/dist/javascript/recipes/remove-dependency.js.map +0 -1
- package/dist/javascript/recipes/upgrade-dependency-version.d.ts +0 -74
- package/dist/javascript/recipes/upgrade-dependency-version.d.ts.map +0 -1
- package/dist/javascript/recipes/upgrade-dependency-version.js +0 -387
- package/dist/javascript/recipes/upgrade-dependency-version.js.map +0 -1
- package/dist/javascript/recipes/upgrade-transitive-dependency-version.d.ts +0 -68
- package/dist/javascript/recipes/upgrade-transitive-dependency-version.d.ts.map +0 -1
- package/dist/javascript/recipes/upgrade-transitive-dependency-version.js +0 -307
- package/dist/javascript/recipes/upgrade-transitive-dependency-version.js.map +0 -1
- package/src/javascript/recipes/add-dependency.ts +0 -549
- package/src/javascript/recipes/remove-dependency.ts +0 -345
- package/src/javascript/recipes/upgrade-dependency-version.ts +0 -486
- package/src/javascript/recipes/upgrade-transitive-dependency-version.ts +0 -403
|
@@ -1,486 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright 2025 the original author or authors.
|
|
3
|
-
* <p>
|
|
4
|
-
* Licensed under the Moderne Source Available License (the "License");
|
|
5
|
-
* you may not use this file except in compliance with the License.
|
|
6
|
-
* You may obtain a copy of the License at
|
|
7
|
-
* <p>
|
|
8
|
-
* https://docs.moderne.io/licensing/moderne-source-available-license
|
|
9
|
-
* <p>
|
|
10
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
* See the License for the specific language governing permissions and
|
|
14
|
-
* limitations under the License.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import {Option, ScanningRecipe} from "../../recipe";
|
|
18
|
-
import {ExecutionContext} from "../../execution";
|
|
19
|
-
import {TreeVisitor} from "../../visitor";
|
|
20
|
-
import {Tree} from "../../tree";
|
|
21
|
-
import {getMemberKeyName, isJson, isLiteral, Json, JsonVisitor} from "../../json";
|
|
22
|
-
import {isDocuments, isYaml, Yaml} from "../../yaml";
|
|
23
|
-
import {isPlainText, PlainText} from "../../text";
|
|
24
|
-
import {
|
|
25
|
-
allDependencyScopes,
|
|
26
|
-
DependencyScope,
|
|
27
|
-
findNodeResolutionResult,
|
|
28
|
-
PackageManager,
|
|
29
|
-
serializeNpmrcConfigs
|
|
30
|
-
} from "../node-resolution-result";
|
|
31
|
-
import * as path from "path";
|
|
32
|
-
import * as semver from "semver";
|
|
33
|
-
import * as picomatch from "picomatch";
|
|
34
|
-
import {markupWarn, replaceMarkerByKind} from "../../markers";
|
|
35
|
-
import {TreePrinters} from "../../print";
|
|
36
|
-
import {
|
|
37
|
-
createDependencyRecipeAccumulator,
|
|
38
|
-
createLockFileEditor,
|
|
39
|
-
DependencyRecipeAccumulator,
|
|
40
|
-
getAllLockFileNames,
|
|
41
|
-
getLockFileName,
|
|
42
|
-
parseLockFileContent,
|
|
43
|
-
runInstallIfNeeded,
|
|
44
|
-
runInstallInTempDir,
|
|
45
|
-
storeInstallResult,
|
|
46
|
-
updateNodeResolutionMarker
|
|
47
|
-
} from "../package-manager";
|
|
48
|
-
|
|
49
|
-
interface MatchedDependency {
|
|
50
|
-
packageName: string;
|
|
51
|
-
dependencyScope: DependencyScope;
|
|
52
|
-
currentVersion: string;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
interface ProjectUpdateInfo {
|
|
56
|
-
packageJsonPath: string;
|
|
57
|
-
originalPackageJson: string;
|
|
58
|
-
matchedDependencies: MatchedDependency[];
|
|
59
|
-
newVersion: string;
|
|
60
|
-
packageManager: PackageManager;
|
|
61
|
-
skipInstall: boolean;
|
|
62
|
-
configFiles?: Record<string, string>;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
interface Accumulator extends DependencyRecipeAccumulator<ProjectUpdateInfo> {
|
|
66
|
-
/** Original lock file content, keyed by lock file path */
|
|
67
|
-
originalLockFiles: Map<string, string>;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Upgrades the version of a direct dependency in package.json and updates the lock file.
|
|
72
|
-
*
|
|
73
|
-
* This recipe:
|
|
74
|
-
* 1. Finds package.json files containing the specified dependency
|
|
75
|
-
* 2. Updates the version constraint to the new version
|
|
76
|
-
* 3. Runs the package manager to update the lock file
|
|
77
|
-
* 4. Updates the NodeResolutionResult marker with new dependency info
|
|
78
|
-
*
|
|
79
|
-
* For upgrading transitive dependencies (those pulled in indirectly by your direct
|
|
80
|
-
* dependencies), use `UpgradeTransitiveDependencyVersion` instead.
|
|
81
|
-
*
|
|
82
|
-
* @see UpgradeTransitiveDependencyVersion for transitive dependencies
|
|
83
|
-
*/
|
|
84
|
-
export class UpgradeDependencyVersion extends ScanningRecipe<Accumulator> {
|
|
85
|
-
readonly name = "org.openrewrite.javascript.dependencies.upgrade-dependency-version";
|
|
86
|
-
readonly displayName = "Upgrade npm dependency version";
|
|
87
|
-
readonly description = "Upgrades the version of a direct dependency in `package.json` and updates the lock file by running the package manager. Either `packageName` or `packagePattern` must be specified.";
|
|
88
|
-
|
|
89
|
-
@Option({
|
|
90
|
-
displayName: "Package name",
|
|
91
|
-
description: "The exact name of the npm package to upgrade (e.g., `lodash`, `@types/node`). Either this or `packagePattern` must be specified.",
|
|
92
|
-
required: false,
|
|
93
|
-
example: "lodash"
|
|
94
|
-
})
|
|
95
|
-
packageName?: string;
|
|
96
|
-
|
|
97
|
-
@Option({
|
|
98
|
-
displayName: "Package pattern",
|
|
99
|
-
description: "A glob expression to match package names (e.g., `@angular/*`, `@types/*`). Either this or `packageName` must be specified.",
|
|
100
|
-
required: false,
|
|
101
|
-
example: "@angular/*"
|
|
102
|
-
})
|
|
103
|
-
packagePattern?: string;
|
|
104
|
-
|
|
105
|
-
@Option({
|
|
106
|
-
displayName: "Version",
|
|
107
|
-
description: "The version constraint to set (e.g., `^5.0.0`, `~2.1.0`, `3.0.0`)",
|
|
108
|
-
example: "^5.0.0"
|
|
109
|
-
})
|
|
110
|
-
newVersion!: string;
|
|
111
|
-
|
|
112
|
-
private _matcher?: picomatch.Matcher;
|
|
113
|
-
|
|
114
|
-
private get matcher(): picomatch.Matcher | undefined {
|
|
115
|
-
if (this.packagePattern && !this._matcher) {
|
|
116
|
-
this._matcher = picomatch.default
|
|
117
|
-
? picomatch.default(this.packagePattern)
|
|
118
|
-
: (picomatch as any)(this.packagePattern);
|
|
119
|
-
}
|
|
120
|
-
return this._matcher;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
matchesPackage(name: string): boolean {
|
|
124
|
-
if (this.packageName && name === this.packageName) {
|
|
125
|
-
return true;
|
|
126
|
-
}
|
|
127
|
-
if (this.matcher) {
|
|
128
|
-
return this.matcher(name);
|
|
129
|
-
}
|
|
130
|
-
return false;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
initialValue(_ctx: ExecutionContext): Accumulator {
|
|
134
|
-
if (!this.packageName && !this.packagePattern) {
|
|
135
|
-
throw new Error("Either packageName or packagePattern must be specified");
|
|
136
|
-
}
|
|
137
|
-
return {
|
|
138
|
-
...createDependencyRecipeAccumulator<ProjectUpdateInfo>(),
|
|
139
|
-
originalLockFiles: new Map()
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Determines if the dependency should be upgraded from currentVersion to newVersion.
|
|
145
|
-
* Returns true only if the new version constraint represents a strictly newer version.
|
|
146
|
-
*
|
|
147
|
-
* This prevents:
|
|
148
|
-
* - Re-applying the same version (idempotency)
|
|
149
|
-
* - Downgrading to an older version
|
|
150
|
-
*
|
|
151
|
-
* @param currentVersion Current version constraint (e.g., "^4.17.20")
|
|
152
|
-
* @param newVersion New version constraint to apply (e.g., "^4.17.21")
|
|
153
|
-
* @returns true if upgrade should proceed, false otherwise
|
|
154
|
-
*/
|
|
155
|
-
shouldUpgrade(currentVersion: string, newVersion: string): boolean {
|
|
156
|
-
// If they're identical strings, no upgrade needed
|
|
157
|
-
if (currentVersion === newVersion) {
|
|
158
|
-
return false;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Extract the minimum version from each constraint
|
|
162
|
-
// semver.minVersion returns the lowest version that could match the range
|
|
163
|
-
const currentMin = semver.minVersion(currentVersion);
|
|
164
|
-
const newMin = semver.minVersion(newVersion);
|
|
165
|
-
|
|
166
|
-
// If either constraint is invalid, fall back to string comparison
|
|
167
|
-
// (will upgrade if strings differ)
|
|
168
|
-
if (!currentMin || !newMin) {
|
|
169
|
-
return currentVersion !== newVersion;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Only upgrade if new minimum version is strictly greater than current
|
|
173
|
-
return semver.gt(newMin, currentMin);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
async scanner(acc: Accumulator): Promise<TreeVisitor<any, ExecutionContext>> {
|
|
177
|
-
const recipe = this;
|
|
178
|
-
const LOCK_FILE_NAMES = getAllLockFileNames();
|
|
179
|
-
|
|
180
|
-
return new class extends TreeVisitor<Tree, ExecutionContext> {
|
|
181
|
-
protected async accept(tree: Tree, ctx: ExecutionContext): Promise<Tree | undefined> {
|
|
182
|
-
// Handle JSON documents (package.json and JSON lock files)
|
|
183
|
-
if (isJson(tree) && tree.kind === Json.Kind.Document) {
|
|
184
|
-
return this.handleJsonDocument(tree as Json.Document, ctx);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Handle YAML documents (pnpm-lock.yaml)
|
|
188
|
-
if (isYaml(tree) && isDocuments(tree)) {
|
|
189
|
-
return this.handleYamlDocument(tree, ctx);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
// Handle PlainText files (yarn.lock for Yarn Classic)
|
|
193
|
-
if (isPlainText(tree)) {
|
|
194
|
-
return this.handlePlainTextDocument(tree as PlainText, ctx);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return tree;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
private async handleJsonDocument(doc: Json.Document, _ctx: ExecutionContext): Promise<Json | undefined> {
|
|
201
|
-
const basename = path.basename(doc.sourcePath);
|
|
202
|
-
|
|
203
|
-
// Capture JSON lock file content (package-lock.json, bun.lock)
|
|
204
|
-
if (LOCK_FILE_NAMES.includes(basename)) {
|
|
205
|
-
acc.originalLockFiles.set(doc.sourcePath, await TreePrinters.print(doc));
|
|
206
|
-
return doc;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Only process package.json files for dependency analysis
|
|
210
|
-
if (!doc.sourcePath.endsWith('package.json')) {
|
|
211
|
-
return doc;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
const marker = findNodeResolutionResult(doc);
|
|
215
|
-
if (!marker) {
|
|
216
|
-
return doc;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
const pm = marker.packageManager ?? PackageManager.Npm;
|
|
220
|
-
|
|
221
|
-
const matchedDeps: MatchedDependency[] = [];
|
|
222
|
-
for (const scope of allDependencyScopes) {
|
|
223
|
-
const deps = marker[scope];
|
|
224
|
-
if (!deps) continue;
|
|
225
|
-
for (const dep of deps) {
|
|
226
|
-
if (recipe.matchesPackage(dep.name) && recipe.shouldUpgrade(dep.versionConstraint, recipe.newVersion)) {
|
|
227
|
-
matchedDeps.push({
|
|
228
|
-
packageName: dep.name,
|
|
229
|
-
dependencyScope: scope,
|
|
230
|
-
currentVersion: dep.versionConstraint
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
if (matchedDeps.length === 0) {
|
|
237
|
-
return doc;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
const skipInstall = matchedDeps.every(md => {
|
|
241
|
-
const resolvedDep = marker.resolvedDependencies?.find(rd => rd.name === md.packageName);
|
|
242
|
-
return resolvedDep !== undefined && semver.satisfies(resolvedDep.version, recipe.newVersion);
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
const configFiles: Record<string, string> = {};
|
|
246
|
-
const npmrcContent = serializeNpmrcConfigs(marker.npmrcConfigs);
|
|
247
|
-
if (npmrcContent) {
|
|
248
|
-
configFiles['.npmrc'] = npmrcContent;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
acc.projectsToUpdate.set(doc.sourcePath, {
|
|
252
|
-
packageJsonPath: doc.sourcePath,
|
|
253
|
-
originalPackageJson: await TreePrinters.print(doc),
|
|
254
|
-
matchedDependencies: matchedDeps,
|
|
255
|
-
newVersion: recipe.newVersion,
|
|
256
|
-
packageManager: pm,
|
|
257
|
-
skipInstall,
|
|
258
|
-
configFiles: Object.keys(configFiles).length > 0 ? configFiles : undefined
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
return doc;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
private async handleYamlDocument(docs: Yaml.Documents, _ctx: ExecutionContext): Promise<Yaml.Documents | undefined> {
|
|
265
|
-
const basename = path.basename(docs.sourcePath);
|
|
266
|
-
if (LOCK_FILE_NAMES.includes(basename)) {
|
|
267
|
-
acc.originalLockFiles.set(docs.sourcePath, await TreePrinters.print(docs));
|
|
268
|
-
}
|
|
269
|
-
return docs;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
private async handlePlainTextDocument(text: PlainText, _ctx: ExecutionContext): Promise<PlainText | undefined> {
|
|
273
|
-
const basename = path.basename(text.sourcePath);
|
|
274
|
-
if (LOCK_FILE_NAMES.includes(basename)) {
|
|
275
|
-
acc.originalLockFiles.set(text.sourcePath, await TreePrinters.print(text));
|
|
276
|
-
}
|
|
277
|
-
return text;
|
|
278
|
-
}
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
async editorWithData(acc: Accumulator): Promise<TreeVisitor<any, ExecutionContext>> {
|
|
283
|
-
const recipe = this;
|
|
284
|
-
|
|
285
|
-
// Create JSON visitor that handles both package.json and JSON lock files
|
|
286
|
-
const jsonEditor = new class extends JsonVisitor<ExecutionContext> {
|
|
287
|
-
protected async visitDocument(doc: Json.Document, ctx: ExecutionContext): Promise<Json | undefined> {
|
|
288
|
-
const sourcePath = doc.sourcePath;
|
|
289
|
-
|
|
290
|
-
// Handle package.json files
|
|
291
|
-
if (sourcePath.endsWith('package.json')) {
|
|
292
|
-
const updateInfo = acc.projectsToUpdate.get(sourcePath);
|
|
293
|
-
if (!updateInfo) {
|
|
294
|
-
return doc; // This package.json doesn't need updating
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
const failureMessage = updateInfo.skipInstall
|
|
298
|
-
? undefined
|
|
299
|
-
: await runInstallIfNeeded(sourcePath, acc, () =>
|
|
300
|
-
recipe.runPackageManagerInstall(acc, updateInfo, ctx)
|
|
301
|
-
);
|
|
302
|
-
if (failureMessage) {
|
|
303
|
-
const names = updateInfo.matchedDependencies.map(d => d.packageName).join(', ');
|
|
304
|
-
return markupWarn(doc, `Failed to upgrade ${names} to ${recipe.newVersion}`, failureMessage);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
let modifiedDoc = doc;
|
|
308
|
-
for (const md of updateInfo.matchedDependencies) {
|
|
309
|
-
const visitor = new UpdateVersionVisitor(
|
|
310
|
-
md.packageName,
|
|
311
|
-
updateInfo.newVersion,
|
|
312
|
-
md.dependencyScope
|
|
313
|
-
);
|
|
314
|
-
modifiedDoc = await visitor.visit(modifiedDoc, undefined) as Json.Document;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
if (updateInfo.skipInstall) {
|
|
318
|
-
return recipe.updateMarkerVersionConstraint(modifiedDoc, updateInfo);
|
|
319
|
-
}
|
|
320
|
-
return updateNodeResolutionMarker(modifiedDoc, updateInfo, acc);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
// Handle JSON lock files (package-lock.json, bun.lock)
|
|
324
|
-
const lockFileName = path.basename(sourcePath);
|
|
325
|
-
if (getAllLockFileNames().includes(lockFileName)) {
|
|
326
|
-
const updatedLockContent = acc.updatedLockFiles.get(sourcePath);
|
|
327
|
-
if (updatedLockContent) {
|
|
328
|
-
const parsed = await parseLockFileContent(updatedLockContent, sourcePath, lockFileName) as Json.Document;
|
|
329
|
-
// Preserve original ID for RPC compatibility
|
|
330
|
-
return {
|
|
331
|
-
...doc,
|
|
332
|
-
value: parsed.value,
|
|
333
|
-
eof: parsed.eof
|
|
334
|
-
} as Json.Document;
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
return doc;
|
|
339
|
-
}
|
|
340
|
-
};
|
|
341
|
-
|
|
342
|
-
// Return composite visitor that handles both JSON and YAML lock files
|
|
343
|
-
return createLockFileEditor(jsonEditor, acc);
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
/**
|
|
347
|
-
* Runs the package manager in a temporary directory to update the lock file.
|
|
348
|
-
* Writes a modified package.json with the new version, then runs install to update the lock file.
|
|
349
|
-
* All file contents are provided from in-memory sources (SourceFiles), not read from disk.
|
|
350
|
-
*/
|
|
351
|
-
private async runPackageManagerInstall(
|
|
352
|
-
acc: Accumulator,
|
|
353
|
-
updateInfo: ProjectUpdateInfo,
|
|
354
|
-
_ctx: ExecutionContext
|
|
355
|
-
): Promise<void> {
|
|
356
|
-
const modifiedPackageJson = this.createModifiedPackageJson(
|
|
357
|
-
updateInfo.originalPackageJson,
|
|
358
|
-
updateInfo.matchedDependencies,
|
|
359
|
-
updateInfo.newVersion
|
|
360
|
-
);
|
|
361
|
-
|
|
362
|
-
// Get the lock file path based on package manager
|
|
363
|
-
const lockFileName = getLockFileName(updateInfo.packageManager);
|
|
364
|
-
const packageJsonDir = path.dirname(updateInfo.packageJsonPath);
|
|
365
|
-
const lockFilePath = packageJsonDir === '.'
|
|
366
|
-
? lockFileName
|
|
367
|
-
: path.join(packageJsonDir, lockFileName);
|
|
368
|
-
|
|
369
|
-
// Look up the original lock file content from captured SourceFiles
|
|
370
|
-
const originalLockFileContent = acc.originalLockFiles.get(lockFilePath);
|
|
371
|
-
|
|
372
|
-
const result = await runInstallInTempDir(
|
|
373
|
-
updateInfo.packageManager,
|
|
374
|
-
modifiedPackageJson,
|
|
375
|
-
{
|
|
376
|
-
originalLockFileContent,
|
|
377
|
-
configFiles: updateInfo.configFiles
|
|
378
|
-
}
|
|
379
|
-
);
|
|
380
|
-
|
|
381
|
-
storeInstallResult(result, acc, updateInfo, modifiedPackageJson);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
private createModifiedPackageJson(
|
|
385
|
-
originalContent: string,
|
|
386
|
-
matchedDependencies: MatchedDependency[],
|
|
387
|
-
newVersion: string
|
|
388
|
-
): string {
|
|
389
|
-
const packageJson = JSON.parse(originalContent);
|
|
390
|
-
|
|
391
|
-
for (const md of matchedDependencies) {
|
|
392
|
-
if (packageJson[md.dependencyScope]?.[md.packageName]) {
|
|
393
|
-
packageJson[md.dependencyScope][md.packageName] = newVersion;
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
return JSON.stringify(packageJson, null, 2);
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
private updateMarkerVersionConstraint(
|
|
401
|
-
doc: Json.Document,
|
|
402
|
-
updateInfo: ProjectUpdateInfo
|
|
403
|
-
): Json.Document {
|
|
404
|
-
const existingMarker = findNodeResolutionResult(doc);
|
|
405
|
-
if (!existingMarker) {
|
|
406
|
-
return doc;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
const matchedNames = new Set(updateInfo.matchedDependencies.map(md => md.packageName));
|
|
410
|
-
let newMarker = {...existingMarker};
|
|
411
|
-
for (const md of updateInfo.matchedDependencies) {
|
|
412
|
-
const deps = newMarker[md.dependencyScope];
|
|
413
|
-
newMarker = {
|
|
414
|
-
...newMarker,
|
|
415
|
-
[md.dependencyScope]: deps?.map(dep =>
|
|
416
|
-
matchedNames.has(dep.name)
|
|
417
|
-
? {...dep, versionConstraint: updateInfo.newVersion}
|
|
418
|
-
: dep
|
|
419
|
-
)
|
|
420
|
-
};
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
return {
|
|
424
|
-
...doc,
|
|
425
|
-
markers: replaceMarkerByKind(doc.markers, newMarker)
|
|
426
|
-
};
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
/**
|
|
431
|
-
* Visitor that updates the version of a specific dependency in a specific scope.
|
|
432
|
-
*/
|
|
433
|
-
class UpdateVersionVisitor extends JsonVisitor<void> {
|
|
434
|
-
private readonly packageName: string;
|
|
435
|
-
private readonly newVersion: string;
|
|
436
|
-
private readonly targetScope: DependencyScope;
|
|
437
|
-
private inTargetScope = false;
|
|
438
|
-
|
|
439
|
-
constructor(packageName: string, newVersion: string, targetScope: DependencyScope) {
|
|
440
|
-
super();
|
|
441
|
-
this.packageName = packageName;
|
|
442
|
-
this.newVersion = newVersion;
|
|
443
|
-
this.targetScope = targetScope;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
protected async visitMember(member: Json.Member, p: void): Promise<Json | undefined> {
|
|
447
|
-
// Check if we're entering the target scope
|
|
448
|
-
const keyName = getMemberKeyName(member);
|
|
449
|
-
|
|
450
|
-
if (keyName === this.targetScope) {
|
|
451
|
-
// We're entering the dependencies scope
|
|
452
|
-
this.inTargetScope = true;
|
|
453
|
-
const result = await super.visitMember(member, p);
|
|
454
|
-
this.inTargetScope = false;
|
|
455
|
-
return result;
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
// Check if this is the dependency we're looking for
|
|
459
|
-
if (this.inTargetScope && keyName === this.packageName) {
|
|
460
|
-
// Update the version value
|
|
461
|
-
return this.updateVersion(member);
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
return super.visitMember(member, p);
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
private updateVersion(member: Json.Member): Json.Member {
|
|
468
|
-
const value = member.value;
|
|
469
|
-
|
|
470
|
-
if (!isLiteral(value)) {
|
|
471
|
-
return member; // Not a literal value, can't update
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
// Create new literal with updated version
|
|
475
|
-
const newLiteral: Json.Literal = {
|
|
476
|
-
...value,
|
|
477
|
-
source: `"${this.newVersion}"`,
|
|
478
|
-
value: this.newVersion
|
|
479
|
-
};
|
|
480
|
-
|
|
481
|
-
return {
|
|
482
|
-
...member,
|
|
483
|
-
value: newLiteral
|
|
484
|
-
};
|
|
485
|
-
}
|
|
486
|
-
}
|