diff --git a/.changeset/calm-lamps-occur.md b/.changeset/calm-lamps-occur.md new file mode 100644 index 00000000000..2d55f84d7e7 --- /dev/null +++ b/.changeset/calm-lamps-occur.md @@ -0,0 +1,6 @@ +--- +"@pnpm/resolve-dependencies": patch +"pnpm": patch +--- + +It should be possible to use a chain of local file dependencies [#4611](https://github.com/pnpm/pnpm/issues/4611). diff --git a/packages/core/test/install/local.ts b/packages/core/test/install/local.ts index d4535c14dd6..985f93f93ed 100644 --- a/packages/core/test/install/local.ts +++ b/packages/core/test/install/local.ts @@ -1,7 +1,8 @@ import { promises as fs } from 'fs' import path from 'path' import { LOCKFILE_VERSION } from '@pnpm/constants' -import { prepareEmpty } from '@pnpm/prepare' +import { Lockfile } from '@pnpm/lockfile-file' +import { prepareEmpty, preparePackages } from '@pnpm/prepare' import { addDistTag } from '@pnpm/registry-mock' import fixtures from '@pnpm/test-fixtures' import { @@ -11,6 +12,7 @@ import { } from '@pnpm/core' import rimraf from '@zkochan/rimraf' import normalizePath from 'normalize-path' +import readYamlFile from 'read-yaml-file' import symlinkDir from 'symlink-dir' import { testDefaults } from '../utils' @@ -239,3 +241,51 @@ test('frozen-lockfile: installation fails if the integrity of a tarball dependen install(manifest, await testDefaults({ frozenLockfile: true })) ).rejects.toThrow(/Got unexpected checksum/) }) + +test('deep local', async () => { + const manifest1 = { + name: 'project-1', + version: '1.0.0', + dependencies: { + 'project-2': 'file:../project-2', + }, + dependenciesMeta: { + 'project-2': { + injected: true, + }, + }, + } + preparePackages([ + { + location: 'project-1', + package: manifest1, + }, + { + location: 'project-2', + package: { + name: 'project-2', + version: '1.0.0', + dependencies: { + 'project-3': 'file:./project-3', + }, + dependenciesMeta: { + 'project-3': { + injected: true, + }, + }, + }, + }, + { + location: 'project-2/project-3', + package: { + name: 'project-3', + version: '1.0.0', + }, + }, + ]) + process.chdir('../project-1') + await install(manifest1, await testDefaults()) + + const lockfile = await readYamlFile('pnpm-lock.yaml') + expect(Object.keys(lockfile.packages ?? {})).toStrictEqual(['file:../project-2', 'file:../project-2/project-3']) +}) diff --git a/packages/resolve-dependencies/src/resolveDependencies.ts b/packages/resolve-dependencies/src/resolveDependencies.ts index 00eb133e776..d6c6a99dd50 100644 --- a/packages/resolve-dependencies/src/resolveDependencies.ts +++ b/packages/resolve-dependencies/src/resolveDependencies.ts @@ -159,6 +159,7 @@ export type PkgAddress = { pkg: PackageManifest version?: string updated: boolean + rootDir: string } & ({ isLinkedDependency: true version: string @@ -199,7 +200,7 @@ export interface ResolvedPackage { } } -type ParentPkg = Pick +type ParentPkg = Pick interface ResolvedDependenciesOptions { currentDepth: number @@ -625,7 +626,7 @@ async function resolveDependency ( (!wantedDependency.pref.startsWith('file:') || !wantedDependency.injected) ) ? ctx.lockfileDir - : ctx.prefix, + : options.parentPkg.rootDir, registry: wantedDependency.alias && pickRegistryForPackage(ctx.registries, wantedDependency.alias, wantedDependency.pref) || ctx.registries.default, // Unfortunately, even when run with --lockfile-only, we need the *real* package.json // so fetching of the tarball cannot be ever avoided. Related issue: https://github.com/pnpm/pnpm/issues/1176 @@ -823,6 +824,9 @@ async function resolveDependency ( } } + const rootDir = pkgResponse.body.resolution.type === 'directory' + ? path.resolve(ctx.lockfileDir, pkgResponse.body.resolution['directory']) + : ctx.prefix return { alias: wantedDependency.alias || pkg.name, depIsLinked, @@ -831,6 +835,7 @@ async function resolveDependency ( nodeId, normalizedPref: options.currentDepth === 0 ? pkgResponse.body.normalizedPref : undefined, pkgId: pkgResponse.body.id, + rootDir, // Next fields are actually only needed when isNew = true installable, diff --git a/packages/resolve-dependencies/src/resolveDependencyTree.ts b/packages/resolve-dependencies/src/resolveDependencyTree.ts index ed9acc895eb..9a4f480ffda 100644 --- a/packages/resolve-dependencies/src/resolveDependencyTree.ts +++ b/packages/resolve-dependencies/src/resolveDependencyTree.ts @@ -133,6 +133,7 @@ export default async function ( nodeId: `>${importer.id}>`, optional: false, depPath: importer.id, + rootDir: importer.rootDir, }, proceed, resolvedDependencies: {