Skip to content

Commit

Permalink
feat: handle workspace protocol with any semver range specifier (#7633)
Browse files Browse the repository at this point in the history
close #7578
  • Loading branch information
EWhite613 authored Jun 14, 2024
1 parent 5d1ed94 commit 398472c
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 20 deletions.
6 changes: 6 additions & 0 deletions .changeset/slimy-geese-knock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@pnpm/exportable-manifest": minor
"pnpm": patch
---

Handle workspace protocol with any semver range specifier, when used in peer dependencies [#7578](https://github.com/pnpm/pnpm/issues/7578).
73 changes: 53 additions & 20 deletions pkg-manifest/exportable-manifest/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,18 @@ export async function createExportableManifest (
if (originalManifest.scripts != null) {
publishManifest.scripts = omit(PREPUBLISH_SCRIPTS, originalManifest.scripts)
}
await Promise.all((['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies'] as const).map(async (depsField) => {
const deps = await makePublishDependencies(dir, originalManifest[depsField], opts?.modulesDir)
await Promise.all((['dependencies', 'devDependencies', 'optionalDependencies'] as const).map(async (depsField) => {
const deps = await makePublishDependencies(dir, originalManifest[depsField], { modulesDir: opts?.modulesDir })
if (deps != null) {
publishManifest[depsField] = deps
}
}))

const peerDependencies = originalManifest.peerDependencies
if (peerDependencies) {
publishManifest.peerDependencies = await makePublishDependencies(dir, peerDependencies, { modulesDir: opts?.modulesDir, convertDependencyForPublish: makePublishPeerDependency })
}

overridePublishConfig(publishManifest)

if (opts?.readmeFile) {
Expand All @@ -48,16 +53,32 @@ export async function createExportableManifest (
async function makePublishDependencies (
dir: string,
dependencies: Dependencies | undefined,
modulesDir?: string
{ modulesDir, convertDependencyForPublish = makePublishDependency }: {
modulesDir?: string
convertDependencyForPublish?: (depName: string, depSpec: string, dir: string, modulesDir?: string) => Promise<string>
} = {}
): Promise<Dependencies | undefined> {
if (dependencies == null) return dependencies
const publishDependencies = await pMapValues(
(depSpec, depName) => makePublishDependency(depName, depSpec, dir, modulesDir),
(depSpec, depName) => convertDependencyForPublish(depName, depSpec, dir, modulesDir),
dependencies
)
return publishDependencies
}

async function resolveManifest (depName: string, modulesDir: string): Promise<ProjectManifest> {
const { manifest } = await tryReadProjectManifest(path.join(modulesDir, depName))
if (!manifest?.name || !manifest?.version) {
throw new PnpmError(
'CANNOT_RESOLVE_WORKSPACE_PROTOCOL',
`Cannot resolve workspace protocol of dependency "${depName}" ` +
'because this dependency is not installed. Try running "pnpm install".'
)
}

return manifest
}

async function makePublishDependency (depName: string, depSpec: string, dir: string, modulesDir?: string): Promise<string> {
if (!depSpec.startsWith('workspace:')) {
return depSpec
Expand All @@ -67,14 +88,7 @@ async function makePublishDependency (depName: string, depSpec: string, dir: str
const versionAliasSpecParts = /^workspace:(.*?)@?([\^~*])$/.exec(depSpec)
if (versionAliasSpecParts != null) {
modulesDir = modulesDir ?? path.join(dir, 'node_modules')
const { manifest } = await tryReadProjectManifest(path.join(modulesDir, depName))
if (!manifest?.version) {
throw new PnpmError(
'CANNOT_RESOLVE_WORKSPACE_PROTOCOL',
`Cannot resolve workspace protocol of dependency "${depName}" ` +
'because this dependency is not installed. Try running "pnpm install".'
)
}
const manifest = await resolveManifest(depName, modulesDir)

const semverRangeToken = versionAliasSpecParts[2] !== '*' ? versionAliasSpecParts[2] : ''
if (depName !== manifest.name) {
Expand All @@ -83,14 +97,8 @@ async function makePublishDependency (depName: string, depSpec: string, dir: str
return `${semverRangeToken}${manifest.version}`
}
if (depSpec.startsWith('workspace:./') || depSpec.startsWith('workspace:../')) {
const { manifest } = await tryReadProjectManifest(path.join(dir, depSpec.slice(10)))
if (!manifest?.name || !manifest?.version) {
throw new PnpmError(
'CANNOT_RESOLVE_WORKSPACE_PROTOCOL',
`Cannot resolve workspace protocol of dependency "${depName}" ` +
'because this dependency is not installed. Try running "pnpm install".'
)
}
const manifest = await resolveManifest(depName, path.join(dir, depSpec.slice(10)))

if (manifest.name === depName) return `${manifest.version}`
return `npm:${manifest.name}@${manifest.version}`
}
Expand All @@ -100,3 +108,28 @@ async function makePublishDependency (depName: string, depSpec: string, dir: str
}
return depSpec
}

async function makePublishPeerDependency (depName: string, depSpec: string, dir: string, modulesDir?: string) {
if (!depSpec.includes('workspace:')) {
return depSpec
}

// Dependencies with bare "*", "^", "~",">=",">","<=",< versions
const workspaceSemverRegex = /workspace:([\^~*]|>=|>|<=|<)/
const versionAliasSpecParts = workspaceSemverRegex.exec(depSpec)

if (versionAliasSpecParts != null) {
modulesDir = modulesDir ?? path.join(dir, 'node_modules')
const manifest = await resolveManifest(depName, modulesDir)

const [,semverRangGroup] = versionAliasSpecParts

const semverRangeToken = semverRangGroup !== '*' ? semverRangGroup : ''

return depSpec.replace(workspaceSemverRegex, `${semverRangeToken}${manifest.version}`)
}

depSpec = depSpec.replace('workspace:', '')

return depSpec
}
8 changes: 8 additions & 0 deletions pkg-manifest/exportable-manifest/test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ test('workspace deps are replaced', async () => {
baz: 'workspace:baz@^',
foo: 'workspace:*',
},
peerDependencies: {
foo: 'workspace:>= || ^3.9.0',
baz: '^1.0.0 || workspace:>',
},
}

preparePackages([
Expand Down Expand Up @@ -123,5 +127,9 @@ test('workspace deps are replaced', async () => {
baz: '^1.2.3',
foo: '4.5.6',
},
peerDependencies: {
baz: '^1.0.0 || >1.2.3',
foo: '>=4.5.6 || ^3.9.0',
},
})
})

0 comments on commit 398472c

Please sign in to comment.