@openrewrite/rewrite 8.69.0-20251210-214835 → 8.69.0-20251211-085327
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 +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/version.txt +1 -1
- package/package.json +1 -1
- 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
|
@@ -14,7 +14,16 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
createNodeResolutionResultMarker,
|
|
19
|
+
findNodeResolutionResult,
|
|
20
|
+
PackageJsonContent,
|
|
21
|
+
PackageLockContent,
|
|
22
|
+
PackageManager,
|
|
23
|
+
readNpmrcConfigs
|
|
24
|
+
} from "./node-resolution-result";
|
|
25
|
+
import {replaceMarkerByKind} from "../markers";
|
|
26
|
+
import {Json} from "../json";
|
|
18
27
|
import * as fs from "fs";
|
|
19
28
|
import * as fsp from "fs/promises";
|
|
20
29
|
import * as path from "path";
|
|
@@ -108,7 +117,7 @@ const LOCK_FILE_DETECTION: ReadonlyArray<LockFileDetectionConfig> = [
|
|
|
108
117
|
/**
|
|
109
118
|
* Result of running a package manager command.
|
|
110
119
|
*/
|
|
111
|
-
|
|
120
|
+
interface PackageManagerResult {
|
|
112
121
|
success: boolean;
|
|
113
122
|
stdout?: string;
|
|
114
123
|
stderr?: string;
|
|
@@ -118,7 +127,7 @@ export interface PackageManagerResult {
|
|
|
118
127
|
/**
|
|
119
128
|
* Options for running package manager install.
|
|
120
129
|
*/
|
|
121
|
-
|
|
130
|
+
interface InstallOptions {
|
|
122
131
|
/** Working directory */
|
|
123
132
|
cwd: string;
|
|
124
133
|
|
|
@@ -164,13 +173,6 @@ export function getLockFileDetectionConfig(): ReadonlyArray<LockFileDetectionCon
|
|
|
164
173
|
return LOCK_FILE_DETECTION;
|
|
165
174
|
}
|
|
166
175
|
|
|
167
|
-
/**
|
|
168
|
-
* Gets the configuration for a package manager.
|
|
169
|
-
*/
|
|
170
|
-
export function getPackageManagerConfig(pm: PackageManager): PackageManagerConfig {
|
|
171
|
-
return PACKAGE_MANAGER_CONFIGS[pm];
|
|
172
|
-
}
|
|
173
|
-
|
|
174
176
|
/**
|
|
175
177
|
* Gets the lock file name for a package manager.
|
|
176
178
|
*/
|
|
@@ -185,22 +187,10 @@ export function getAllLockFileNames(): string[] {
|
|
|
185
187
|
return LOCK_FILE_DETECTION.map(c => c.filename);
|
|
186
188
|
}
|
|
187
189
|
|
|
188
|
-
/**
|
|
189
|
-
* Checks if a file path is a lock file.
|
|
190
|
-
*/
|
|
191
|
-
export function isLockFile(filePath: string): boolean {
|
|
192
|
-
const fileName = path.basename(filePath);
|
|
193
|
-
return getAllLockFileNames().includes(fileName);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
190
|
/**
|
|
197
191
|
* Runs the package manager install command.
|
|
198
|
-
*
|
|
199
|
-
* @param pm The package manager to use
|
|
200
|
-
* @param options Install options
|
|
201
|
-
* @returns Result of the install command
|
|
202
192
|
*/
|
|
203
|
-
|
|
193
|
+
function runInstall(pm: PackageManager, options: InstallOptions): PackageManagerResult {
|
|
204
194
|
const config = PACKAGE_MANAGER_CONFIGS[pm];
|
|
205
195
|
const command = options.lockOnly ? config.installLockOnlyCommand : config.installCommand;
|
|
206
196
|
const [cmd, ...args] = command;
|
|
@@ -244,121 +234,6 @@ export function runInstall(pm: PackageManager, options: InstallOptions): Package
|
|
|
244
234
|
}
|
|
245
235
|
}
|
|
246
236
|
|
|
247
|
-
/**
|
|
248
|
-
* Options for adding/upgrading a package.
|
|
249
|
-
*/
|
|
250
|
-
export interface AddPackageOptions {
|
|
251
|
-
/** Working directory */
|
|
252
|
-
cwd: string;
|
|
253
|
-
|
|
254
|
-
/** Package name to add/upgrade */
|
|
255
|
-
packageName: string;
|
|
256
|
-
|
|
257
|
-
/** Version constraint (e.g., "^5.0.0") */
|
|
258
|
-
version: string;
|
|
259
|
-
|
|
260
|
-
/** If true, only update lock file without installing to node_modules */
|
|
261
|
-
lockOnly?: boolean;
|
|
262
|
-
|
|
263
|
-
/** Timeout in milliseconds (default: 120000 = 2 minutes) */
|
|
264
|
-
timeout?: number;
|
|
265
|
-
|
|
266
|
-
/** Additional environment variables */
|
|
267
|
-
env?: Record<string, string>;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Runs a package manager command to add or upgrade a package.
|
|
272
|
-
* This updates both package.json and the lock file.
|
|
273
|
-
*
|
|
274
|
-
* @param pm The package manager to use
|
|
275
|
-
* @param options Add package options
|
|
276
|
-
* @returns Result of the command
|
|
277
|
-
*/
|
|
278
|
-
export function runAddPackage(pm: PackageManager, options: AddPackageOptions): PackageManagerResult {
|
|
279
|
-
const packageSpec = `${options.packageName}@${options.version}`;
|
|
280
|
-
|
|
281
|
-
// Build command based on package manager
|
|
282
|
-
let cmd: string;
|
|
283
|
-
let args: string[];
|
|
284
|
-
|
|
285
|
-
switch (pm) {
|
|
286
|
-
case PackageManager.Npm:
|
|
287
|
-
cmd = 'npm';
|
|
288
|
-
args = ['install', packageSpec];
|
|
289
|
-
if (options.lockOnly) {
|
|
290
|
-
args.push('--package-lock-only');
|
|
291
|
-
}
|
|
292
|
-
break;
|
|
293
|
-
case PackageManager.YarnClassic:
|
|
294
|
-
cmd = 'yarn';
|
|
295
|
-
args = ['add', packageSpec];
|
|
296
|
-
if (options.lockOnly) {
|
|
297
|
-
args.push('--ignore-scripts');
|
|
298
|
-
}
|
|
299
|
-
break;
|
|
300
|
-
case PackageManager.YarnBerry:
|
|
301
|
-
cmd = 'yarn';
|
|
302
|
-
args = ['add', packageSpec];
|
|
303
|
-
if (options.lockOnly) {
|
|
304
|
-
args.push('--mode', 'skip-build');
|
|
305
|
-
}
|
|
306
|
-
break;
|
|
307
|
-
case PackageManager.Pnpm:
|
|
308
|
-
cmd = 'pnpm';
|
|
309
|
-
args = ['add', packageSpec];
|
|
310
|
-
if (options.lockOnly) {
|
|
311
|
-
args.push('--lockfile-only');
|
|
312
|
-
}
|
|
313
|
-
break;
|
|
314
|
-
case PackageManager.Bun:
|
|
315
|
-
cmd = 'bun';
|
|
316
|
-
args = ['add', packageSpec];
|
|
317
|
-
if (options.lockOnly) {
|
|
318
|
-
args.push('--ignore-scripts');
|
|
319
|
-
}
|
|
320
|
-
break;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
try {
|
|
324
|
-
const result = spawnSync(cmd, args, {
|
|
325
|
-
cwd: options.cwd,
|
|
326
|
-
encoding: 'utf-8',
|
|
327
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
328
|
-
timeout: options.timeout ?? 120000,
|
|
329
|
-
env: options.env ? {...process.env, ...options.env} : process.env,
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
if (result.error) {
|
|
333
|
-
return {
|
|
334
|
-
success: false,
|
|
335
|
-
error: result.error.message,
|
|
336
|
-
stderr: result.stderr,
|
|
337
|
-
};
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
if (result.status !== 0) {
|
|
341
|
-
return {
|
|
342
|
-
success: false,
|
|
343
|
-
stdout: result.stdout,
|
|
344
|
-
stderr: result.stderr,
|
|
345
|
-
error: `Command exited with code ${result.status}`,
|
|
346
|
-
};
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
return {
|
|
350
|
-
success: true,
|
|
351
|
-
stdout: result.stdout,
|
|
352
|
-
stderr: result.stderr,
|
|
353
|
-
};
|
|
354
|
-
} catch (error: any) {
|
|
355
|
-
return {
|
|
356
|
-
success: false,
|
|
357
|
-
error: error.message,
|
|
358
|
-
};
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
237
|
/**
|
|
363
238
|
* Runs a package manager list command to get dependency information.
|
|
364
239
|
*
|
|
@@ -390,55 +265,203 @@ export function runList(pm: PackageManager, cwd: string, timeout: number = 30000
|
|
|
390
265
|
}
|
|
391
266
|
|
|
392
267
|
/**
|
|
393
|
-
*
|
|
268
|
+
* Result of running install in a temporary directory.
|
|
269
|
+
*/
|
|
270
|
+
export interface TempInstallResult {
|
|
271
|
+
/** Whether the install succeeded */
|
|
272
|
+
success: boolean;
|
|
273
|
+
/** The updated lock file content (if successful and lock file exists) */
|
|
274
|
+
lockFileContent?: string;
|
|
275
|
+
/** Error message (if failed) */
|
|
276
|
+
error?: string;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Generic accumulator for dependency recipes that run package manager operations.
|
|
281
|
+
* Used by scanning recipes to track state across scanning and editing phases.
|
|
394
282
|
*
|
|
395
|
-
* @
|
|
396
|
-
* @returns True if the package manager is available
|
|
283
|
+
* @typeParam T The recipe-specific project update info type
|
|
397
284
|
*/
|
|
398
|
-
export
|
|
399
|
-
|
|
400
|
-
|
|
285
|
+
export interface DependencyRecipeAccumulator<T> {
|
|
286
|
+
/** Projects that need updating: packageJsonPath -> update info */
|
|
287
|
+
projectsToUpdate: Map<string, T>;
|
|
401
288
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
289
|
+
/** After running package manager, store the updated lock file content */
|
|
290
|
+
updatedLockFiles: Map<string, string>;
|
|
291
|
+
|
|
292
|
+
/** Updated package.json content (after npm install may have modified it) */
|
|
293
|
+
updatedPackageJsons: Map<string, string>;
|
|
294
|
+
|
|
295
|
+
/** Track which projects have been processed (npm install has run) */
|
|
296
|
+
processedProjects: Set<string>;
|
|
297
|
+
|
|
298
|
+
/** Track projects where npm install failed: packageJsonPath -> error message */
|
|
299
|
+
failedProjects: Map<string, string>;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Creates a new empty accumulator for dependency recipes.
|
|
304
|
+
*/
|
|
305
|
+
export function createDependencyRecipeAccumulator<T>(): DependencyRecipeAccumulator<T> {
|
|
306
|
+
return {
|
|
307
|
+
projectsToUpdate: new Map(),
|
|
308
|
+
updatedLockFiles: new Map(),
|
|
309
|
+
updatedPackageJsons: new Map(),
|
|
310
|
+
processedProjects: new Set(),
|
|
311
|
+
failedProjects: new Map()
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Checks if a source path is a lock file and returns the updated content if available.
|
|
317
|
+
* This is a helper for dependency recipes that need to update lock files.
|
|
318
|
+
*
|
|
319
|
+
* @param sourcePath The source path to check
|
|
320
|
+
* @param acc The recipe accumulator containing updated lock file content
|
|
321
|
+
* @returns The updated lock file content if this is a lock file that was updated, undefined otherwise
|
|
322
|
+
*/
|
|
323
|
+
export function getUpdatedLockFileContent<T>(
|
|
324
|
+
sourcePath: string,
|
|
325
|
+
acc: DependencyRecipeAccumulator<T>
|
|
326
|
+
): string | undefined {
|
|
327
|
+
for (const lockFileName of getAllLockFileNames()) {
|
|
328
|
+
if (sourcePath.endsWith(lockFileName)) {
|
|
329
|
+
// Find the corresponding package.json path
|
|
330
|
+
const packageJsonPath = sourcePath.replace(lockFileName, 'package.json');
|
|
331
|
+
const updateInfo = acc.projectsToUpdate.get(packageJsonPath);
|
|
332
|
+
|
|
333
|
+
if (updateInfo && acc.updatedLockFiles.has(sourcePath)) {
|
|
334
|
+
return acc.updatedLockFiles.get(sourcePath);
|
|
335
|
+
}
|
|
336
|
+
break;
|
|
337
|
+
}
|
|
411
338
|
}
|
|
339
|
+
return undefined;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Base interface for project update info used by dependency recipes.
|
|
344
|
+
* Recipes extend this with additional fields specific to their needs.
|
|
345
|
+
*/
|
|
346
|
+
export interface BaseProjectUpdateInfo {
|
|
347
|
+
/** Absolute path to the project directory */
|
|
348
|
+
projectDir: string;
|
|
349
|
+
/** Relative path to package.json (from source root) */
|
|
350
|
+
packageJsonPath: string;
|
|
351
|
+
/** The package manager used by this project */
|
|
352
|
+
packageManager: PackageManager;
|
|
412
353
|
}
|
|
413
354
|
|
|
414
355
|
/**
|
|
415
|
-
*
|
|
356
|
+
* Stores the result of a package manager install into the accumulator.
|
|
357
|
+
* This handles the common pattern of storing updated lock files and tracking failures.
|
|
358
|
+
*
|
|
359
|
+
* @param result The result from runInstallInTempDir
|
|
360
|
+
* @param acc The recipe accumulator
|
|
361
|
+
* @param updateInfo The project update info (must have packageJsonPath and packageManager)
|
|
362
|
+
* @param modifiedPackageJson The modified package.json content that was used for install
|
|
416
363
|
*/
|
|
417
|
-
export function
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
364
|
+
export function storeInstallResult<T extends BaseProjectUpdateInfo>(
|
|
365
|
+
result: TempInstallResult,
|
|
366
|
+
acc: DependencyRecipeAccumulator<T>,
|
|
367
|
+
updateInfo: T,
|
|
368
|
+
modifiedPackageJson: string
|
|
369
|
+
): void {
|
|
370
|
+
if (result.success) {
|
|
371
|
+
acc.updatedPackageJsons.set(updateInfo.packageJsonPath, modifiedPackageJson);
|
|
372
|
+
|
|
373
|
+
if (result.lockFileContent) {
|
|
374
|
+
const lockFileName = getLockFileName(updateInfo.packageManager);
|
|
375
|
+
const lockFilePath = updateInfo.packageJsonPath.replace('package.json', lockFileName);
|
|
376
|
+
acc.updatedLockFiles.set(lockFilePath, result.lockFileContent);
|
|
377
|
+
}
|
|
378
|
+
} else {
|
|
379
|
+
acc.failedProjects.set(updateInfo.packageJsonPath, result.error || 'Unknown error');
|
|
429
380
|
}
|
|
430
381
|
}
|
|
431
382
|
|
|
432
383
|
/**
|
|
433
|
-
*
|
|
384
|
+
* Runs the package manager install for a project if it hasn't been processed yet.
|
|
385
|
+
* Updates the accumulator's processedProjects set after running.
|
|
386
|
+
*
|
|
387
|
+
* @param sourcePath The source path (package.json path) being processed
|
|
388
|
+
* @param acc The recipe accumulator
|
|
389
|
+
* @param runInstall Function that performs the actual install (recipe-specific)
|
|
390
|
+
* @returns The failure message if install failed, undefined otherwise
|
|
434
391
|
*/
|
|
435
|
-
export
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
392
|
+
export async function runInstallIfNeeded<T>(
|
|
393
|
+
sourcePath: string,
|
|
394
|
+
acc: DependencyRecipeAccumulator<T>,
|
|
395
|
+
runInstall: () => Promise<void>
|
|
396
|
+
): Promise<string | undefined> {
|
|
397
|
+
if (!acc.processedProjects.has(sourcePath)) {
|
|
398
|
+
await runInstall();
|
|
399
|
+
acc.processedProjects.add(sourcePath);
|
|
400
|
+
}
|
|
401
|
+
return acc.failedProjects.get(sourcePath);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Updates the NodeResolutionResult marker on a JSON document after a package manager operation.
|
|
406
|
+
* This recreates the marker based on the updated package.json and lock file content.
|
|
407
|
+
*
|
|
408
|
+
* @param doc The JSON document containing the marker
|
|
409
|
+
* @param updateInfo Project update info with paths and package manager
|
|
410
|
+
* @param acc The recipe accumulator containing updated content
|
|
411
|
+
* @returns The document with the updated marker, or unchanged if no existing marker
|
|
412
|
+
*/
|
|
413
|
+
export async function updateNodeResolutionMarker<T extends BaseProjectUpdateInfo>(
|
|
414
|
+
doc: Json.Document,
|
|
415
|
+
updateInfo: T & { originalPackageJson: string },
|
|
416
|
+
acc: DependencyRecipeAccumulator<T>
|
|
417
|
+
): Promise<Json.Document> {
|
|
418
|
+
const existingMarker = findNodeResolutionResult(doc);
|
|
419
|
+
if (!existingMarker) {
|
|
420
|
+
return doc;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Parse the updated package.json and lock file to create new marker
|
|
424
|
+
const updatedPackageJson = acc.updatedPackageJsons.get(updateInfo.packageJsonPath);
|
|
425
|
+
const lockFileName = getLockFileName(updateInfo.packageManager);
|
|
426
|
+
const updatedLockFile = acc.updatedLockFiles.get(
|
|
427
|
+
updateInfo.packageJsonPath.replace('package.json', lockFileName)
|
|
428
|
+
);
|
|
429
|
+
|
|
430
|
+
let packageJsonContent: PackageJsonContent;
|
|
431
|
+
let lockContent: PackageLockContent | undefined;
|
|
432
|
+
|
|
433
|
+
try {
|
|
434
|
+
packageJsonContent = JSON.parse(updatedPackageJson || updateInfo.originalPackageJson);
|
|
435
|
+
} catch {
|
|
436
|
+
return doc; // Failed to parse, keep original marker
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
if (updatedLockFile) {
|
|
440
|
+
try {
|
|
441
|
+
lockContent = JSON.parse(updatedLockFile);
|
|
442
|
+
} catch {
|
|
443
|
+
// Continue without lock file content
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// Read npmrc configs from the project directory
|
|
448
|
+
const npmrcConfigs = await readNpmrcConfigs(updateInfo.projectDir);
|
|
449
|
+
|
|
450
|
+
// Create new marker
|
|
451
|
+
const newMarker = createNodeResolutionResultMarker(
|
|
452
|
+
existingMarker.path,
|
|
453
|
+
packageJsonContent,
|
|
454
|
+
lockContent,
|
|
455
|
+
existingMarker.workspacePackagePaths,
|
|
456
|
+
existingMarker.packageManager,
|
|
457
|
+
npmrcConfigs.length > 0 ? npmrcConfigs : undefined
|
|
458
|
+
);
|
|
459
|
+
|
|
460
|
+
// Replace the marker in the document
|
|
461
|
+
return {
|
|
462
|
+
...doc,
|
|
463
|
+
markers: replaceMarkerByKind(doc.markers, newMarker)
|
|
464
|
+
};
|
|
442
465
|
}
|
|
443
466
|
|
|
444
467
|
/**
|