diff --git a/packages/filter-lockfile/src/filterLockfileByImporters.ts b/packages/filter-lockfile/src/filterLockfileByImporters.ts index f4f01b4730..29bf231e6c 100644 --- a/packages/filter-lockfile/src/filterLockfileByImporters.ts +++ b/packages/filter-lockfile/src/filterLockfileByImporters.ts @@ -33,7 +33,7 @@ export default function filterByImporters ( lockfile, importerIds, { include: opts.include, skipped: opts.skipped }, - ), + ).step, packages, { failOnMissingDependencies: opts.failOnMissingDependencies, diff --git a/packages/hoist/src/index.ts b/packages/hoist/src/index.ts index 0c5fdc0974..2622856a24 100644 --- a/packages/hoist/src/index.ts +++ b/packages/hoist/src/index.ts @@ -27,19 +27,33 @@ export default async function hoistByLockfile ( ) { if (!opts.lockfile.packages) return {} - const deps = await getDependencies( - lockfileWalker( - opts.lockfile, - Object.keys(opts.lockfile.importers), - ), - 0, - { - getIndependentPackageLocation: opts.getIndependentPackageLocation, - lockfileDir: opts.lockfileDir, - registries: opts.registries, - virtualStoreDir: opts.virtualStoreDir, - }, + const { directDeps, step } = lockfileWalker( + opts.lockfile, + Object.keys(opts.lockfile.importers), ) + const deps = [ + { + absolutePath: '', + children: directDeps + .reduce((acc, dep) => { + if (acc[dep.alias]) return acc + acc[dep.alias] = dp.resolve(opts.registries, dep.relDepPath) + return acc + }, {}), + depth: -1, + location: '', + }, + ...await getDependencies( + step, + 0, + { + getIndependentPackageLocation: opts.getIndependentPackageLocation, + lockfileDir: opts.lockfileDir, + registries: opts.registries, + virtualStoreDir: opts.virtualStoreDir, + }, + ), + ] const aliasesByDependencyPath = await hoistGraph(deps, opts.lockfile.importers['.'].specifiers, { dryRun: false, @@ -92,7 +106,6 @@ async function getDependencies ( location: !independent ? path.join(modules, pkgName) : await opts.getIndependentPackageLocation!(pkgSnapshot.id || absolutePath, pkgName), - name: pkgName, }) nextSteps.push(next()) @@ -112,7 +125,6 @@ async function getDependencies ( } export interface Dependency { - name: string, location: string, children: {[alias: string]: string}, depth: number, @@ -135,7 +147,7 @@ async function hoistGraph ( // sort by depth and then alphabetically .sort((a, b) => { const depthDiff = a.depth - b.depth - return depthDiff === 0 ? a.name.localeCompare(b.name) : depthDiff + return depthDiff === 0 ? a.absolutePath.localeCompare(b.absolutePath) : depthDiff }) // build the alias map and the id map .map((depNode) => { diff --git a/packages/lockfile-walker/src/index.ts b/packages/lockfile-walker/src/index.ts index c9ff761cf9..b15a9f2ae8 100644 --- a/packages/lockfile-walker/src/index.ts +++ b/packages/lockfile-walker/src/index.ts @@ -55,6 +55,7 @@ export default function lockfileWalker ( ) { const walked = new Set(opts?.skipped ? Array.from(opts?.skipped) : []) const entryNodes = [] as string[] + const directDeps = [] as Array<{ alias: string, relDepPath: string }> importerIds.forEach((importerId) => { const projectSnapshot = lockfile.importers[importerId] @@ -63,17 +64,21 @@ export default function lockfileWalker ( ...(opts?.include?.dependencies === false ? {} : projectSnapshot.dependencies), ...(opts?.include?.optionalDependencies === false ? {} : projectSnapshot.optionalDependencies), }) - .map(([ pkgName, reference ]) => dp.refToRelative(reference, pkgName)) - .filter((nodeId) => nodeId !== null) - .forEach((relDepPath) => { + .forEach(([ pkgName, reference ]) => { + const relDepPath = dp.refToRelative(reference, pkgName) + if (relDepPath === null) return entryNodes.push(relDepPath as string) + directDeps.push({ alias: pkgName, relDepPath }) }) }) - return step({ - includeOptionalDependencies: opts?.include?.optionalDependencies !== false, - lockfile, - walked, - }, entryNodes) + return { + directDeps, + step: step({ + includeOptionalDependencies: opts?.include?.optionalDependencies !== false, + lockfile, + walked, + }, entryNodes), + } } function step ( diff --git a/packages/plugin-commands-rebuild/src/implementation/index.ts b/packages/plugin-commands-rebuild/src/implementation/index.ts index b343ac7c20..5265b6a135 100644 --- a/packages/plugin-commands-rebuild/src/implementation/index.ts +++ b/packages/plugin-commands-rebuild/src/implementation/index.ts @@ -245,7 +245,7 @@ async function _rebuild ( optionalDependencies: opts.optional, }, }, - ), + ).step, nodesToBuildAndTransitive, { pkgsToRebuild: ctx.pkgsToRebuild }, ) diff --git a/packages/supi/test/install/hoist.ts b/packages/supi/test/install/hoist.ts index 21a96f3ab6..dbfe76c2ea 100644 --- a/packages/supi/test/install/hoist.ts +++ b/packages/supi/test/install/hoist.ts @@ -311,7 +311,7 @@ test('should uninstall correctly peer dependencies', async (t) => { t.throws(() => fs.lstatSync('node_modules/ajv-keywords'), Error, 'symlink to peer dependency is deleted') }) -test('hoist-pattern: only hoists the dependencies of the root workspace package', async (t) => { +test('hoist-pattern: hoist all dependencies to the virtual store node_modules', async (t) => { const workspaceRootManifest = { name: 'root', @@ -355,6 +355,9 @@ test('hoist-pattern: only hoists the dependencies of the root workspace package' await projects['root'].has('pkg-with-1-dep') await projects['root'].has('.pnpm/node_modules/dep-of-pkg-with-1-dep') + await projects['root'].has('.pnpm/node_modules/foobar') + await projects['root'].has('.pnpm/node_modules/foo') + await projects['root'].has('.pnpm/node_modules/bar') await projects['root'].hasNot('foobar') await projects['root'].hasNot('foo') await projects['root'].hasNot('bar') @@ -370,6 +373,9 @@ test('hoist-pattern: only hoists the dependencies of the root workspace package' await projects['root'].has('pkg-with-1-dep') await projects['root'].has('.pnpm/node_modules/dep-of-pkg-with-1-dep') + await projects['root'].has('.pnpm/node_modules/foobar') + await projects['root'].has('.pnpm/node_modules/foo') + await projects['root'].has('.pnpm/node_modules/bar') await projects['root'].hasNot('foobar') await projects['root'].hasNot('foo') await projects['root'].hasNot('bar')