Skip to content

Commit

Permalink
fix: error message when package is not found in workspace
Browse files Browse the repository at this point in the history
ref #4477
  • Loading branch information
zkochan committed May 27, 2023
1 parent a9e0b7c commit 267c93a
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 23 deletions.
6 changes: 6 additions & 0 deletions .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).
2 changes: 1 addition & 1 deletion pkg-manager/core/test/install/multipleImporters.ts
Expand Up @@ -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 () => {
Expand Down
62 changes: 40 additions & 22 deletions resolving/npm-resolver/src/index.ts
Expand Up @@ -163,25 +163,33 @@ 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
}
const pickedPackage = pickResult.pickedPackage
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 })
}
Expand Down Expand Up @@ -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)
}

Expand Down
33 changes: 33 additions & 0 deletions resolving/npm-resolver/test/index.ts
Expand Up @@ -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`)
Expand Down

0 comments on commit 267c93a

Please sign in to comment.