Skip to content

Commit 398472c

Browse files
authored
feat: handle workspace protocol with any semver range specifier (#7633)
close #7578
1 parent 5d1ed94 commit 398472c

File tree

3 files changed

+67
-20
lines changed

3 files changed

+67
-20
lines changed

.changeset/slimy-geese-knock.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@pnpm/exportable-manifest": minor
3+
"pnpm": patch
4+
---
5+
6+
Handle workspace protocol with any semver range specifier, when used in peer dependencies [#7578](https://github.com/pnpm/pnpm/issues/7578).

pkg-manifest/exportable-manifest/src/index.ts

Lines changed: 53 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,18 @@ export async function createExportableManifest (
2929
if (originalManifest.scripts != null) {
3030
publishManifest.scripts = omit(PREPUBLISH_SCRIPTS, originalManifest.scripts)
3131
}
32-
await Promise.all((['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies'] as const).map(async (depsField) => {
33-
const deps = await makePublishDependencies(dir, originalManifest[depsField], opts?.modulesDir)
32+
await Promise.all((['dependencies', 'devDependencies', 'optionalDependencies'] as const).map(async (depsField) => {
33+
const deps = await makePublishDependencies(dir, originalManifest[depsField], { modulesDir: opts?.modulesDir })
3434
if (deps != null) {
3535
publishManifest[depsField] = deps
3636
}
3737
}))
3838

39+
const peerDependencies = originalManifest.peerDependencies
40+
if (peerDependencies) {
41+
publishManifest.peerDependencies = await makePublishDependencies(dir, peerDependencies, { modulesDir: opts?.modulesDir, convertDependencyForPublish: makePublishPeerDependency })
42+
}
43+
3944
overridePublishConfig(publishManifest)
4045

4146
if (opts?.readmeFile) {
@@ -48,16 +53,32 @@ export async function createExportableManifest (
4853
async function makePublishDependencies (
4954
dir: string,
5055
dependencies: Dependencies | undefined,
51-
modulesDir?: string
56+
{ modulesDir, convertDependencyForPublish = makePublishDependency }: {
57+
modulesDir?: string
58+
convertDependencyForPublish?: (depName: string, depSpec: string, dir: string, modulesDir?: string) => Promise<string>
59+
} = {}
5260
): Promise<Dependencies | undefined> {
5361
if (dependencies == null) return dependencies
5462
const publishDependencies = await pMapValues(
55-
(depSpec, depName) => makePublishDependency(depName, depSpec, dir, modulesDir),
63+
(depSpec, depName) => convertDependencyForPublish(depName, depSpec, dir, modulesDir),
5664
dependencies
5765
)
5866
return publishDependencies
5967
}
6068

69+
async function resolveManifest (depName: string, modulesDir: string): Promise<ProjectManifest> {
70+
const { manifest } = await tryReadProjectManifest(path.join(modulesDir, depName))
71+
if (!manifest?.name || !manifest?.version) {
72+
throw new PnpmError(
73+
'CANNOT_RESOLVE_WORKSPACE_PROTOCOL',
74+
`Cannot resolve workspace protocol of dependency "${depName}" ` +
75+
'because this dependency is not installed. Try running "pnpm install".'
76+
)
77+
}
78+
79+
return manifest
80+
}
81+
6182
async function makePublishDependency (depName: string, depSpec: string, dir: string, modulesDir?: string): Promise<string> {
6283
if (!depSpec.startsWith('workspace:')) {
6384
return depSpec
@@ -67,14 +88,7 @@ async function makePublishDependency (depName: string, depSpec: string, dir: str
6788
const versionAliasSpecParts = /^workspace:(.*?)@?([\^~*])$/.exec(depSpec)
6889
if (versionAliasSpecParts != null) {
6990
modulesDir = modulesDir ?? path.join(dir, 'node_modules')
70-
const { manifest } = await tryReadProjectManifest(path.join(modulesDir, depName))
71-
if (!manifest?.version) {
72-
throw new PnpmError(
73-
'CANNOT_RESOLVE_WORKSPACE_PROTOCOL',
74-
`Cannot resolve workspace protocol of dependency "${depName}" ` +
75-
'because this dependency is not installed. Try running "pnpm install".'
76-
)
77-
}
91+
const manifest = await resolveManifest(depName, modulesDir)
7892

7993
const semverRangeToken = versionAliasSpecParts[2] !== '*' ? versionAliasSpecParts[2] : ''
8094
if (depName !== manifest.name) {
@@ -83,14 +97,8 @@ async function makePublishDependency (depName: string, depSpec: string, dir: str
8397
return `${semverRangeToken}${manifest.version}`
8498
}
8599
if (depSpec.startsWith('workspace:./') || depSpec.startsWith('workspace:../')) {
86-
const { manifest } = await tryReadProjectManifest(path.join(dir, depSpec.slice(10)))
87-
if (!manifest?.name || !manifest?.version) {
88-
throw new PnpmError(
89-
'CANNOT_RESOLVE_WORKSPACE_PROTOCOL',
90-
`Cannot resolve workspace protocol of dependency "${depName}" ` +
91-
'because this dependency is not installed. Try running "pnpm install".'
92-
)
93-
}
100+
const manifest = await resolveManifest(depName, path.join(dir, depSpec.slice(10)))
101+
94102
if (manifest.name === depName) return `${manifest.version}`
95103
return `npm:${manifest.name}@${manifest.version}`
96104
}
@@ -100,3 +108,28 @@ async function makePublishDependency (depName: string, depSpec: string, dir: str
100108
}
101109
return depSpec
102110
}
111+
112+
async function makePublishPeerDependency (depName: string, depSpec: string, dir: string, modulesDir?: string) {
113+
if (!depSpec.includes('workspace:')) {
114+
return depSpec
115+
}
116+
117+
// Dependencies with bare "*", "^", "~",">=",">","<=",< versions
118+
const workspaceSemverRegex = /workspace:([\^~*]|>=|>|<=|<)/
119+
const versionAliasSpecParts = workspaceSemverRegex.exec(depSpec)
120+
121+
if (versionAliasSpecParts != null) {
122+
modulesDir = modulesDir ?? path.join(dir, 'node_modules')
123+
const manifest = await resolveManifest(depName, modulesDir)
124+
125+
const [,semverRangGroup] = versionAliasSpecParts
126+
127+
const semverRangeToken = semverRangGroup !== '*' ? semverRangGroup : ''
128+
129+
return depSpec.replace(workspaceSemverRegex, `${semverRangeToken}${manifest.version}`)
130+
}
131+
132+
depSpec = depSpec.replace('workspace:', '')
133+
134+
return depSpec
135+
}

pkg-manifest/exportable-manifest/test/index.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ test('workspace deps are replaced', async () => {
9191
baz: 'workspace:baz@^',
9292
foo: 'workspace:*',
9393
},
94+
peerDependencies: {
95+
foo: 'workspace:>= || ^3.9.0',
96+
baz: '^1.0.0 || workspace:>',
97+
},
9498
}
9599

96100
preparePackages([
@@ -123,5 +127,9 @@ test('workspace deps are replaced', async () => {
123127
baz: '^1.2.3',
124128
foo: '4.5.6',
125129
},
130+
peerDependencies: {
131+
baz: '^1.0.0 || >1.2.3',
132+
foo: '>=4.5.6 || ^3.9.0',
133+
},
126134
})
127135
})

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy