From 267c93aa5b15dad1714c3bb1c8377afeb302de6c Mon Sep 17 00:00:00 2001 From: Zoltan Kochan Date: Sat, 27 May 2023 17:00:13 +0300 Subject: [PATCH] fix: error message when package is not found in workspace ref #4477 --- .changeset/dirty-spoons-report.md | 6 ++ .../core/test/install/multipleImporters.ts | 2 +- resolving/npm-resolver/src/index.ts | 62 ++++++++++++------- resolving/npm-resolver/test/index.ts | 33 ++++++++++ 4 files changed, 80 insertions(+), 23 deletions(-) create mode 100644 .changeset/dirty-spoons-report.md diff --git a/.changeset/dirty-spoons-report.md b/.changeset/dirty-spoons-report.md new file mode 100644 index 00000000000..e4f31cf9690 --- /dev/null +++ b/.changeset/dirty-spoons-report.md @@ -0,0 +1,6 @@ +--- +"@pnpm/npm-resolver": patch +"pnpm": patch +--- + +Print a meaningful error when a project referenced by the `workspace:` protocol is not found in the workspace [#4477](https://github.com/pnpm/pnpm/issues/4477). diff --git a/pkg-manager/core/test/install/multipleImporters.ts b/pkg-manager/core/test/install/multipleImporters.ts index 4cdb2160666..a94ce64753c 100644 --- a/pkg-manager/core/test/install/multipleImporters.ts +++ b/pkg-manager/core/test/install/multipleImporters.ts @@ -233,7 +233,7 @@ test('some projects were removed from the workspace and the ones that are left d pruneLockfileImporters: true, workspacePackages: pick(['project-1'], workspacePackages), } as any)) // eslint-disable-line - ).rejects.toThrow(/No matching version found for/) + ).rejects.toThrow(/"project-2@workspace:1.0.0" is in the dependencies but no package named "project-2" is present in the workspace/) }) test('dependencies of other importers are not pruned when installing for a subset of importers', async () => { diff --git a/resolving/npm-resolver/src/index.ts b/resolving/npm-resolver/src/index.ts index 76defc27ba3..e18f5642db7 100644 --- a/resolving/npm-resolver/src/index.ts +++ b/resolving/npm-resolver/src/index.ts @@ -163,12 +163,16 @@ async function resolveNpm ( }) } catch (err: any) { // eslint-disable-line if ((workspacePackages != null) && opts.projectDir) { - const resolvedFromLocal = tryResolveFromWorkspacePackages(workspacePackages, spec, { - projectDir: opts.projectDir, - lockfileDir: opts.lockfileDir, - hardLinkLocalPackages: wantedDependency.injected, - }) - if (resolvedFromLocal != null) return resolvedFromLocal + try { + return tryResolveFromWorkspacePackages(workspacePackages, spec, { + wantedDependency, + projectDir: opts.projectDir, + lockfileDir: opts.lockfileDir, + hardLinkLocalPackages: wantedDependency.injected, + }) + } catch { + // ignore + } } throw err } @@ -176,12 +180,16 @@ async function resolveNpm ( const meta = pickResult.meta if (pickedPackage == null) { if ((workspacePackages != null) && opts.projectDir) { - const resolvedFromLocal = tryResolveFromWorkspacePackages(workspacePackages, spec, { - projectDir: opts.projectDir, - lockfileDir: opts.lockfileDir, - hardLinkLocalPackages: wantedDependency.injected, - }) - if (resolvedFromLocal != null) return resolvedFromLocal + try { + return tryResolveFromWorkspacePackages(workspacePackages, spec, { + wantedDependency, + projectDir: opts.projectDir, + lockfileDir: opts.lockfileDir, + hardLinkLocalPackages: wantedDependency.injected, + }) + } catch { + // ignore + } } throw new NoMatchingVersionError({ wantedDependency, packageMeta: meta }) } @@ -250,32 +258,42 @@ function tryResolveFromWorkspace ( if (!opts.projectDir) { throw new Error('Cannot resolve package from workspace because opts.projectDir is not defined') } - const resolvedFromLocal = tryResolveFromWorkspacePackages(opts.workspacePackages, spec, { + return tryResolveFromWorkspacePackages(opts.workspacePackages, spec, { + wantedDependency, + pref, projectDir: opts.projectDir, hardLinkLocalPackages: wantedDependency.injected, lockfileDir: opts.lockfileDir, }) - if (resolvedFromLocal == null) { - throw new PnpmError( - 'NO_MATCHING_VERSION_INSIDE_WORKSPACE', - `In ${path.relative(process.cwd(), opts.projectDir)}: No matching version found for ${wantedDependency.alias ?? ''}@${pref} inside the workspace` - ) - } - return resolvedFromLocal } function tryResolveFromWorkspacePackages ( workspacePackages: WorkspacePackages, spec: RegistryPackageSpec, opts: { + wantedDependency: WantedDependency hardLinkLocalPackages?: boolean + pref?: string projectDir: string lockfileDir?: string } ) { - if (!workspacePackages[spec.name]) return null + if (!workspacePackages[spec.name]) { + throw new PnpmError( + 'NO_MATCHING_PKG_INSIDE_WORKSPACE', + `In ${path.relative(process.cwd(), opts.projectDir)}: "${spec.name}@${opts.wantedDependency.pref ?? ''}" is in the dependencies but no package named "${spec.name}" is present in the workspace`, + { + hint: 'Packages found in the workspace: ' + Object.keys(workspacePackages).join(', '), + } + ) + } const localVersion = pickMatchingLocalVersionOrNull(workspacePackages[spec.name], spec) - if (!localVersion) return null + if (!localVersion) { + throw new PnpmError( + 'NO_MATCHING_VERSION_INSIDE_WORKSPACE', + `In ${path.relative(process.cwd(), opts.projectDir)}: No matching version found for ${opts.wantedDependency.alias ?? ''}@${opts.pref ?? spec.normalizedPref ?? ''} inside the workspace` + ) + } return resolveFromLocalPackage(workspacePackages[spec.name][localVersion], spec.normalizedPref, opts) } diff --git a/resolving/npm-resolver/test/index.ts b/resolving/npm-resolver/test/index.ts index 5a98f034e1e..6b8ae46f67b 100644 --- a/resolving/npm-resolver/test/index.ts +++ b/resolving/npm-resolver/test/index.ts @@ -1621,6 +1621,39 @@ test('workspace protocol: resolution fails if there is no matching local package err = _err } + expect(err).toBeTruthy() + expect(err.code).toBe('ERR_PNPM_NO_MATCHING_PKG_INSIDE_WORKSPACE') + expect(err.message).toBe(`In ${path.relative(process.cwd(), projectDir)}: "is-positive@workspace:^3.0.0" is in the dependencies but no package named "is-positive" is present in the workspace`) +}) + +test('workspace protocol: resolution fails if there is no matching local package version', async () => { + const cacheDir = tempy.directory() + const resolve = createResolveFromNpm({ + cacheDir, + }) + + const projectDir = '/home/istvan/src' + let err!: Error & { code: string } + try { + await resolve({ alias: 'is-positive', pref: 'workspace:^3.0.0' }, { + projectDir, + registry, + workspacePackages: { + 'is-positive': { + '2.0.0': { + dir: '/home/istvan/src/is-positive', + manifest: { + name: 'is-positive', + version: '2.0.0', + }, + }, + }, + }, + }) + } catch (_err: any) { // eslint-disable-line + err = _err + } + expect(err).toBeTruthy() expect(err.code).toBe('ERR_PNPM_NO_MATCHING_VERSION_INSIDE_WORKSPACE') expect(err.message).toBe(`In ${path.relative(process.cwd(), projectDir)}: No matching version found for is-positive@^3.0.0 inside the workspace`)