diff --git a/.changeset/sixty-oranges-jam.md b/.changeset/sixty-oranges-jam.md new file mode 100644 index 0000000000..8932fb5db0 --- /dev/null +++ b/.changeset/sixty-oranges-jam.md @@ -0,0 +1,7 @@ +--- +"@pnpm/exportable-manifest": minor +"@pnpm/npm-resolver": minor +"@pnpm/plugin-commands-publishing": minor +--- + +Support aliases to workspace packages. For instance, `"foo": "workspace:bar@*"` will link bar from the repository but aliased to foo. Before publish, these specs are converted to regular aliased versions. diff --git a/packages/exportable-manifest/src/index.ts b/packages/exportable-manifest/src/index.ts index 98d9ba305c..00eaaa2600 100644 --- a/packages/exportable-manifest/src/index.ts +++ b/packages/exportable-manifest/src/index.ts @@ -62,7 +62,7 @@ async function makePublishDependency (depName: string, depSpec: string, dir: str if (!depSpec.startsWith('workspace:')) { return depSpec } - if (depSpec === 'workspace:*') { + if (depSpec === 'workspace:*' || depSpec.endsWith('@*')) { const { manifest } = await tryReadProjectManifest(path.join(dir, 'node_modules', depName)) if (!manifest || !manifest.version) { throw new PnpmError( @@ -71,7 +71,14 @@ async function makePublishDependency (depName: string, depSpec: string, dir: str 'because this dependency is not installed. Try running "pnpm install".' ) } + if (depName !== manifest.name) { + return `npm:${manifest.name!}@${manifest.version}` + } return manifest.version } - return depSpec.substr(10) + depSpec = depSpec.substr(10) + if (depSpec.includes('@')) { + return `npm:${depSpec}` + } + return depSpec } diff --git a/packages/npm-resolver/src/index.ts b/packages/npm-resolver/src/index.ts index 5b6d64ea72..f4c9d037d6 100644 --- a/packages/npm-resolver/src/index.ts +++ b/packages/npm-resolver/src/index.ts @@ -199,7 +199,10 @@ function tryResolveFromWorkspace ( if (!wantedDependency.pref?.startsWith('workspace:')) { return null } - const pref = wantedDependency.pref.substr(10) + let pref = wantedDependency.pref.substr(10) + if (pref.includes('@', 1)) { + pref = `npm:${pref}` + } const spec = parsePref(pref, wantedDependency.alias, opts.defaultTag, opts.registry) if (!spec) throw new Error(`Invalid workspace: spec (${wantedDependency.pref})`) if (!opts.workspacePackages) { diff --git a/packages/npm-resolver/test/index.ts b/packages/npm-resolver/test/index.ts index f2ed8acf55..01e7750b96 100644 --- a/packages/npm-resolver/test/index.ts +++ b/packages/npm-resolver/test/index.ts @@ -964,6 +964,39 @@ test('resolve from local directory when alwaysTryWorkspacePackages is false but expect(resolveResult!.manifest!.version).toBe('1.0.0') }) +test('resolve from local directory when alwaysTryWorkspacePackages is false but workspace: is used with a different package name', async () => { + const storeDir = tempy.directory() + const resolve = createResolveFromNpm({ + storeDir, + }) + const resolveResult = await resolve({ alias: 'positive', pref: 'workspace:is-positive@*' }, { + alwaysTryWorkspacePackages: false, + projectDir: '/home/istvan/src', + registry, + workspacePackages: { + 'is-positive': { + '1.0.0': { + dir: '/home/istvan/src/is-positive', + manifest: { + name: 'is-positive', + version: '1.0.0', + }, + }, + }, + }, + }) + + expect(resolveResult!.resolvedVia).toBe('local-filesystem') + expect(resolveResult!.id).toBe('link:is-positive') + expect(resolveResult!.resolution).toStrictEqual({ + directory: '/home/istvan/src/is-positive', + type: 'directory', + }) + expect(resolveResult!.manifest).toBeTruthy() + expect(resolveResult!.manifest!.name).toBe('is-positive') + expect(resolveResult!.manifest!.version).toBe('1.0.0') +}) + test('use version from the registry if it is newer than the local one', async () => { nock(registry) .get('/is-positive') diff --git a/packages/plugin-commands-publishing/test/publish.ts b/packages/plugin-commands-publishing/test/publish.ts index c9649a13e8..34d8fdbcf2 100644 --- a/packages/plugin-commands-publishing/test/publish.ts +++ b/packages/plugin-commands-publishing/test/publish.ts @@ -9,7 +9,7 @@ import fs = require('mz/fs') import exists = require('path-exists') import writeYamlFile = require('write-yaml-file') -jest.setTimeout(10000) +jest.setTimeout(60000) const CREDENTIALS = [ `--registry=http://localhost:${REGISTRY_MOCK_PORT}/`, @@ -341,10 +341,12 @@ test('convert specs with workspace protocols to regular version ranges', async ( version: '1.0.0', dependencies: { + even: 'workspace:is-even@^1.0.0', 'file-type': 'workspace:12.0.1', 'is-negative': 'workspace:*', 'is-positive': '1.0.0', 'lodash.delay': '~4.1.0', + odd: 'workspace:is-odd@*', }, devDependencies: { 'random-package': 'workspace:^1.2.3', @@ -356,6 +358,14 @@ test('convert specs with workspace protocols to regular version ranges', async ( 'random-package': 'workspace:*', }, }, + { + name: 'is-even', + version: '1.0.0', + }, + { + name: 'is-odd', + version: '1.0.0', + }, { name: 'is-negative', version: '1.0.0', @@ -420,6 +430,8 @@ because this dependency is not installed. Try running "pnpm install".' 'is-negative': '1.0.0', 'is-positive': '1.0.0', 'lodash.delay': '~4.1.0', + even: 'npm:is-even@^1.0.0', + odd: 'npm:is-odd@1.0.0', }) expect(publishedManifest.devDependencies).toStrictEqual({ 'random-package': '^1.2.3',