Skip to content

Commit 3d30ebe

Browse files
committed
modify yarn-cling
1 parent 8e0beb7 commit 3d30ebe

File tree

2 files changed

+33
-9
lines changed

2 files changed

+33
-9
lines changed

packages/@aws-cdk/yarn-cling/lib/index.ts

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,21 @@ export async function generateShrinkwrap(options: ShrinkwrapOptions): Promise<Pa
3636
const yarnLock: YarnLock = lockfile.parse(await fs.readFile(yarnLockLoc, { encoding: 'utf8' }));
3737
const pkgJson = await loadPackageJson(packageJsonFile);
3838

39-
let lock = await generateLockFile(pkgJson, yarnLock, packageJsonDir);
39+
// Load resolutions from root package.json (for monorepo support)
40+
const rootPkgJsonPath = path.join(path.dirname(yarnLockLoc), 'package.json');
41+
let resolutions: Record<string, string> = {};
42+
if (await fileExists(rootPkgJsonPath)) {
43+
const rootPkgJson = await loadPackageJson(rootPkgJsonPath);
44+
resolutions = rootPkgJson.resolutions || {};
45+
}
46+
47+
let lock = await generateLockFile(pkgJson, yarnLock, packageJsonDir, resolutions);
4048

4149
if (options.hoist ?? true) {
4250
lock = hoistDependencies(lock);
4351
}
4452

45-
_validateTree(lock);
53+
_validateTree(lock, resolutions);
4654

4755
if (options.outputFile) {
4856
// Write the shrinkwrap file
@@ -52,7 +60,12 @@ export async function generateShrinkwrap(options: ShrinkwrapOptions): Promise<Pa
5260
return lock;
5361
}
5462

55-
async function generateLockFile(pkgJson: PackageJson, yarnLock: YarnLock, rootDir: string): Promise<PackageLockFile> {
63+
async function generateLockFile(
64+
pkgJson: PackageJson,
65+
yarnLock: YarnLock,
66+
rootDir: string,
67+
resolutions: Record<string, string> = {},
68+
): Promise<PackageLockFile> {
5669
const builder = new PackageGraphBuilder(yarnLock);
5770
const rootKeys = await builder.buildGraph(pkgJson.dependencies || {}, rootDir);
5871

@@ -65,7 +78,7 @@ async function generateLockFile(pkgJson: PackageJson, yarnLock: YarnLock, rootDi
6578
};
6679

6780
try {
68-
checkRequiredVersions(lockFile);
81+
checkRequiredVersions(lockFile, resolutions);
6982
} catch (e: any) {
7083
const tempFile = path.join(os.tmpdir(), 'npm-shrinkwrap.json');
7184
await fs.writeFile(tempFile, JSON.stringify(lockFile, undefined, 2), 'utf-8');
@@ -366,7 +379,7 @@ async function findPackageDir(depName: string, rootDir: string) {
366379
* tell our future selves that is cannot and will not work, and we should find another
367380
* solution.
368381
*/
369-
export function checkRequiredVersions(root: PackageLockFile) {
382+
export function checkRequiredVersions(root: PackageLockFile, resolutions: Record<string, string> = {}) {
370383
recurse(root, [[root.name, root]]);
371384

372385
// rootPath does include 'entry'
@@ -386,8 +399,11 @@ export function checkRequiredVersions(root: PackageLockFile) {
386399
range = range.split('@')[1];
387400
}
388401

402+
// If there's a resolution for this package, use that instead of the required range
403+
const effectiveRange = resolutions[name] || range;
404+
389405
const depPath = [name, ...rootPath.map(x => x[0])];
390-
if (!semver.satisfies(resolvedPackage.version, range)) {
406+
if (!semver.satisfies(resolvedPackage.version, effectiveRange)) {
391407
// Ruh-roh.
392408
throw new Error(`Looks like we're trying to force '${renderRootPath(depPath)}' to version '${resolvedPackage.version}' (found at ${resolvedPath} => ${name}), but `
393409
+ `${depPath[depPath.length - 1]} specifies the dependency as '${range}'. NPM will not respect this shrinkwrap file. Try vendoring a patched `
@@ -421,7 +437,7 @@ export function checkRequiredVersions(root: PackageLockFile) {
421437
* We have manipulated the tree a bunch. Do a sanity check to ensure that all declared
422438
* dependencies are satisfied.
423439
*/
424-
export function _validateTree(lock: PackageLockTree) {
440+
export function _validateTree(lock: PackageLockTree, resolutions: Record<string, string> = {}) {
425441
const errors = new Array<string>();
426442
recurse(lock, [['root', lock]], {});
427443
if (errors.length > 0) {
@@ -452,13 +468,16 @@ export function _validateTree(lock: PackageLockTree) {
452468
declaredRange = declaredRange.split('@')[1];
453469
}
454470

471+
// If there's a resolution for this package, use that instead of the declared range
472+
const effectiveRange = resolutions[name] || declaredRange;
473+
455474
const foundVersion = depsVersions[name];
456475
const newRootPath = [name, ...rootPath.map(x => x[0])];
457476
if (!foundVersion) {
458477
errors.push(`Dependency on ${renderRootPath(newRootPath)} not satisfied: not found`);
459-
} else if (!semver.satisfies(foundVersion, declaredRange)) {
478+
} else if (!semver.satisfies(foundVersion, effectiveRange)) {
460479
// eslint-disable-next-line no-console
461-
errors.push(`Dependency on ${renderRootPath(newRootPath)} not satisfied: declared range '${declaredRange}', found '${foundVersion}'`);
480+
errors.push(`Dependency on ${renderRootPath(newRootPath)} not satisfied: declared range '${effectiveRange}', found '${foundVersion}'`);
462481
}
463482
}
464483
}

packages/@aws-cdk/yarn-cling/lib/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ export interface PackageJson {
66
* Dependency name to version range
77
*/
88
dependencies?: Record<string, string>;
9+
10+
/**
11+
* Yarn resolutions to force specific package versions
12+
*/
13+
resolutions?: Record<string, string>;
914
}
1015

1116
export interface YarnLock {

0 commit comments

Comments
 (0)