mirror of
https://github.com/pnpm/pnpm.git
synced 2026-05-19 14:20:36 -04:00
5
.changeset/lucky-moons-drum.md
Normal file
5
.changeset/lucky-moons-drum.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@pnpm/workspace.spec-parser": major
|
||||||
|
---
|
||||||
|
|
||||||
|
Initial release.
|
||||||
7
.changeset/wicked-queens-bow.md
Normal file
7
.changeset/wicked-queens-bow.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
"@pnpm/resolve-dependencies": patch
|
||||||
|
"@pnpm/npm-resolver": patch
|
||||||
|
"pnpm": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
`pnpm update` should not fail when there's an aliased local workspace dependency [#7975](https://github.com/pnpm/pnpm/issues/7975).
|
||||||
@@ -4,6 +4,7 @@ import { type Lockfile } from '@pnpm/lockfile-types'
|
|||||||
import { readModulesManifest } from '@pnpm/modules-yaml'
|
import { readModulesManifest } from '@pnpm/modules-yaml'
|
||||||
import { install, update } from '@pnpm/plugin-commands-installation'
|
import { install, update } from '@pnpm/plugin-commands-installation'
|
||||||
import { preparePackages } from '@pnpm/prepare'
|
import { preparePackages } from '@pnpm/prepare'
|
||||||
|
import { readProjectManifestOnly } from '@pnpm/read-project-manifest'
|
||||||
import { addDistTag } from '@pnpm/registry-mock'
|
import { addDistTag } from '@pnpm/registry-mock'
|
||||||
import { sync as readYamlFile } from 'read-yaml-file'
|
import { sync as readYamlFile } from 'read-yaml-file'
|
||||||
import { DEFAULT_OPTS } from '../utils'
|
import { DEFAULT_OPTS } from '../utils'
|
||||||
@@ -415,3 +416,33 @@ test('recursive update in workspace should not add new dependencies', async () =
|
|||||||
projects['project-1'].hasNot('is-positive')
|
projects['project-1'].hasNot('is-positive')
|
||||||
projects['project-2'].hasNot('is-positive')
|
projects['project-2'].hasNot('is-positive')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('recursive update with aliased workspace dependency (#7975)', async () => {
|
||||||
|
const projects = preparePackages([
|
||||||
|
{
|
||||||
|
name: 'project-1',
|
||||||
|
version: '1.0.0',
|
||||||
|
dependencies: {
|
||||||
|
pkg: 'workspace:project-2@^',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'project-2',
|
||||||
|
version: '1.0.0',
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
await update.handler({
|
||||||
|
...DEFAULT_OPTS,
|
||||||
|
...await readProjects(process.cwd(), []),
|
||||||
|
depth: 0,
|
||||||
|
dir: process.cwd(),
|
||||||
|
recursive: true,
|
||||||
|
workspaceDir: process.cwd(),
|
||||||
|
})
|
||||||
|
|
||||||
|
projects['project-1'].has('pkg')
|
||||||
|
|
||||||
|
const manifest = await readProjectManifestOnly('project-1')
|
||||||
|
expect(manifest).toHaveProperty(['dependencies', 'pkg'], 'workspace:project-2@^')
|
||||||
|
})
|
||||||
|
|||||||
@@ -46,6 +46,7 @@
|
|||||||
"@pnpm/store-controller-types": "workspace:*",
|
"@pnpm/store-controller-types": "workspace:*",
|
||||||
"@pnpm/types": "workspace:*",
|
"@pnpm/types": "workspace:*",
|
||||||
"@pnpm/which-version-is-pinned": "workspace:*",
|
"@pnpm/which-version-is-pinned": "workspace:*",
|
||||||
|
"@pnpm/workspace.spec-parser": "workspace:*",
|
||||||
"@yarnpkg/core": "4.0.3",
|
"@yarnpkg/core": "4.0.3",
|
||||||
"filenamify": "^4.3.0",
|
"filenamify": "^4.3.0",
|
||||||
"get-npm-tarball-url": "^2.1.0",
|
"get-npm-tarball-url": "^2.1.0",
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
type ProjectManifest,
|
type ProjectManifest,
|
||||||
} from '@pnpm/types'
|
} from '@pnpm/types'
|
||||||
import { whichVersionIsPinned } from '@pnpm/which-version-is-pinned'
|
import { whichVersionIsPinned } from '@pnpm/which-version-is-pinned'
|
||||||
|
import { WorkspaceSpec } from '@pnpm/workspace.spec-parser'
|
||||||
|
|
||||||
export type PinnedVersion = 'major' | 'minor' | 'patch' | 'none'
|
export type PinnedVersion = 'major' | 'minor' | 'patch' | 'none'
|
||||||
|
|
||||||
@@ -54,7 +55,10 @@ export function getWantedDependencies (
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateWorkspacePref (pref: string): string {
|
function updateWorkspacePref (pref: string): string {
|
||||||
return pref.startsWith('workspace:') ? 'workspace:*' : pref
|
const spec = WorkspaceSpec.parse(pref)
|
||||||
|
if (!spec) return pref
|
||||||
|
spec.version = '*'
|
||||||
|
return spec.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWantedDependenciesFromGivenSet (
|
function getWantedDependenciesFromGivenSet (
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ function resolvedDirectDepToSpecObject (
|
|||||||
shouldUseWorkspaceProtocol &&
|
shouldUseWorkspaceProtocol &&
|
||||||
!pref.startsWith('workspace:')
|
!pref.startsWith('workspace:')
|
||||||
) {
|
) {
|
||||||
|
pref = pref.replace(/^npm:/, '')
|
||||||
pref = `workspace:${pref}`
|
pref = `workspace:${pref}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,9 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "../../store/store-controller-types"
|
"path": "../../store/store-controller-types"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../../workspace/spec-parser"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"composite": true
|
"composite": true
|
||||||
|
|||||||
12
pnpm-lock.yaml
generated
12
pnpm-lock.yaml
generated
@@ -4289,6 +4289,9 @@ importers:
|
|||||||
'@pnpm/which-version-is-pinned':
|
'@pnpm/which-version-is-pinned':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/which-version-is-pinned
|
version: link:../../packages/which-version-is-pinned
|
||||||
|
'@pnpm/workspace.spec-parser':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../../workspace/spec-parser
|
||||||
'@yarnpkg/core':
|
'@yarnpkg/core':
|
||||||
specifier: 4.0.3
|
specifier: 4.0.3
|
||||||
version: 4.0.3(typanion@3.14.0)
|
version: 4.0.3(typanion@3.14.0)
|
||||||
@@ -5191,6 +5194,9 @@ importers:
|
|||||||
'@pnpm/types':
|
'@pnpm/types':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/types
|
version: link:../../packages/types
|
||||||
|
'@pnpm/workspace.spec-parser':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../../workspace/spec-parser
|
||||||
'@zkochan/retry':
|
'@zkochan/retry':
|
||||||
specifier: ^0.2.0
|
specifier: ^0.2.0
|
||||||
version: 0.2.0
|
version: 0.2.0
|
||||||
@@ -6556,6 +6562,12 @@ importers:
|
|||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: 'link:'
|
version: 'link:'
|
||||||
|
|
||||||
|
workspace/spec-parser:
|
||||||
|
devDependencies:
|
||||||
|
'@pnpm/workspace.spec-parser':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: 'link:'
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
'@aashutoshrathi/word-wrap@1.2.6':
|
'@aashutoshrathi/word-wrap@1.2.6':
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
"@pnpm/resolve-workspace-range": "workspace:*",
|
"@pnpm/resolve-workspace-range": "workspace:*",
|
||||||
"@pnpm/resolver-base": "workspace:*",
|
"@pnpm/resolver-base": "workspace:*",
|
||||||
"@pnpm/types": "workspace:*",
|
"@pnpm/types": "workspace:*",
|
||||||
|
"@pnpm/workspace.spec-parser": "workspace:*",
|
||||||
"@zkochan/retry": "^0.2.0",
|
"@zkochan/retry": "^0.2.0",
|
||||||
"encode-registry": "^3.0.1",
|
"encode-registry": "^3.0.1",
|
||||||
"load-json-file": "^6.2.0",
|
"load-json-file": "^6.2.0",
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
export function workspacePrefToNpm (workspacePref: string): string {
|
import { WorkspaceSpec } from '@pnpm/workspace.spec-parser'
|
||||||
const prefParts = /^workspace:([^._/][^@]*@)?(.*)$/.exec(workspacePref)
|
|
||||||
|
|
||||||
if (prefParts == null) {
|
export function workspacePrefToNpm (workspacePref: string): string {
|
||||||
|
const parseResult = WorkspaceSpec.parse(workspacePref)
|
||||||
|
if (parseResult == null) {
|
||||||
throw new Error(`Invalid workspace spec: ${workspacePref}`)
|
throw new Error(`Invalid workspace spec: ${workspacePref}`)
|
||||||
}
|
}
|
||||||
const [workspacePkgAlias, workspaceVersion] = prefParts.slice(1)
|
|
||||||
|
|
||||||
const pkgAliasPart = workspacePkgAlias != null && workspacePkgAlias
|
const { alias, version } = parseResult
|
||||||
? `npm:${workspacePkgAlias}`
|
const versionPart = version === '^' || version === '~' ? '*' : version
|
||||||
: ''
|
return alias
|
||||||
const versionPart = workspaceVersion === '^' || workspaceVersion === '~'
|
? `npm:${alias}@${versionPart}`
|
||||||
? '*'
|
: versionPart
|
||||||
: workspaceVersion
|
|
||||||
|
|
||||||
return `${pkgAliasPart}${versionPart}`
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,9 @@
|
|||||||
{
|
{
|
||||||
"path": "../../workspace/resolve-workspace-range"
|
"path": "../../workspace/resolve-workspace-range"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "../../workspace/spec-parser"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "../resolver-base"
|
"path": "../resolver-base"
|
||||||
}
|
}
|
||||||
|
|||||||
15
workspace/spec-parser/README.md
Normal file
15
workspace/spec-parser/README.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# @pnpm/workspace.spec-parser
|
||||||
|
|
||||||
|
> Parse and stringify workspace specs
|
||||||
|
|
||||||
|
[](https://www.npmjs.com/package/@pnpm/workspace.spec-parser)
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pnpm add @pnpm/workspace.spec-parser
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
3
workspace/spec-parser/jest.config.js
Normal file
3
workspace/spec-parser/jest.config.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
const config = require('../../jest.config.js');
|
||||||
|
|
||||||
|
module.exports = config
|
||||||
38
workspace/spec-parser/package.json
Normal file
38
workspace/spec-parser/package.json
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"name": "@pnpm/workspace.spec-parser",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "Parse and stringify workspace pref",
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"types": "lib/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"lib",
|
||||||
|
"!*.map"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.12"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\"",
|
||||||
|
"_test": "jest",
|
||||||
|
"test": "pnpm run compile && pnpm run _test",
|
||||||
|
"prepublishOnly": "pnpm run compile",
|
||||||
|
"compile": "tsc --build && pnpm run lint --fix"
|
||||||
|
},
|
||||||
|
"repository": "https://github.com/pnpm/pnpm/blob/main/workspace/spec-parser",
|
||||||
|
"keywords": [
|
||||||
|
"pnpm9",
|
||||||
|
"pnpm"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/pnpm/pnpm/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/pnpm/pnpm/blob/main/workspace/spec-parser#readme",
|
||||||
|
"funding": "https://opencollective.com/pnpm",
|
||||||
|
"devDependencies": {
|
||||||
|
"@pnpm/workspace.spec-parser": "workspace:*"
|
||||||
|
},
|
||||||
|
"exports": {
|
||||||
|
".": "./lib/index.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
22
workspace/spec-parser/src/index.ts
Normal file
22
workspace/spec-parser/src/index.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
const WORKSPACE_PREF_REGEX = /^workspace:((?<alias>[^._/][^@]*)@)?(?<version>.*)$/
|
||||||
|
|
||||||
|
export class WorkspaceSpec {
|
||||||
|
alias?: string
|
||||||
|
version: string
|
||||||
|
|
||||||
|
constructor (version: string, alias?: string) {
|
||||||
|
this.version = version
|
||||||
|
this.alias = alias
|
||||||
|
}
|
||||||
|
|
||||||
|
static parse (pref: string): WorkspaceSpec | null {
|
||||||
|
const parts = WORKSPACE_PREF_REGEX.exec(pref)
|
||||||
|
if (!parts?.groups) return null
|
||||||
|
return new WorkspaceSpec(parts.groups.version, parts.groups.alias)
|
||||||
|
}
|
||||||
|
|
||||||
|
toString (): `workspace:${string}` {
|
||||||
|
const { alias, version } = this
|
||||||
|
return alias ? `workspace:${alias}@${version}` : `workspace:${version}`
|
||||||
|
}
|
||||||
|
}
|
||||||
47
workspace/spec-parser/test/workspace-spec.test.ts
Normal file
47
workspace/spec-parser/test/workspace-spec.test.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import { WorkspaceSpec } from '../src/index'
|
||||||
|
|
||||||
|
test('parse valid workspace spec', () => {
|
||||||
|
expect(WorkspaceSpec.parse('workspace:*')).toStrictEqual(new WorkspaceSpec('*'))
|
||||||
|
expect(WorkspaceSpec.parse('workspace:^')).toStrictEqual(new WorkspaceSpec('^'))
|
||||||
|
expect(WorkspaceSpec.parse('workspace:~')).toStrictEqual(new WorkspaceSpec('~'))
|
||||||
|
expect(WorkspaceSpec.parse('workspace:0.1.2')).toStrictEqual(new WorkspaceSpec('0.1.2'))
|
||||||
|
expect(WorkspaceSpec.parse('workspace:foo@*')).toStrictEqual(new WorkspaceSpec('*', 'foo'))
|
||||||
|
expect(WorkspaceSpec.parse('workspace:foo@^')).toStrictEqual(new WorkspaceSpec('^', 'foo'))
|
||||||
|
expect(WorkspaceSpec.parse('workspace:foo@~')).toStrictEqual(new WorkspaceSpec('~', 'foo'))
|
||||||
|
expect(WorkspaceSpec.parse('workspace:foo@0.1.2')).toStrictEqual(new WorkspaceSpec('0.1.2', 'foo'))
|
||||||
|
expect(WorkspaceSpec.parse('workspace:@foo/bar@*')).toStrictEqual(new WorkspaceSpec('*', '@foo/bar'))
|
||||||
|
expect(WorkspaceSpec.parse('workspace:@foo/bar@^')).toStrictEqual(new WorkspaceSpec('^', '@foo/bar'))
|
||||||
|
expect(WorkspaceSpec.parse('workspace:@foo/bar@~')).toStrictEqual(new WorkspaceSpec('~', '@foo/bar'))
|
||||||
|
expect(WorkspaceSpec.parse('workspace:@foo/bar@0.1.2')).toStrictEqual(new WorkspaceSpec('0.1.2', '@foo/bar'))
|
||||||
|
})
|
||||||
|
|
||||||
|
test('parse invalid workspace spec', () => {
|
||||||
|
expect(WorkspaceSpec.parse('npm:foo@0.1.2')).toBe(null)
|
||||||
|
expect(WorkspaceSpec.parse('*')).toBe(null)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('to string', () => {
|
||||||
|
expect(new WorkspaceSpec('*').toString()).toBe('workspace:*')
|
||||||
|
expect(new WorkspaceSpec('^').toString()).toBe('workspace:^')
|
||||||
|
expect(new WorkspaceSpec('~').toString()).toBe('workspace:~')
|
||||||
|
expect(new WorkspaceSpec('0.1.2').toString()).toBe('workspace:0.1.2')
|
||||||
|
expect(new WorkspaceSpec('*', 'foo').toString()).toBe('workspace:foo@*')
|
||||||
|
expect(new WorkspaceSpec('^', 'foo').toString()).toBe('workspace:foo@^')
|
||||||
|
expect(new WorkspaceSpec('~', 'foo').toString()).toBe('workspace:foo@~')
|
||||||
|
expect(new WorkspaceSpec('0.1.2', 'foo').toString()).toBe('workspace:foo@0.1.2')
|
||||||
|
expect(new WorkspaceSpec('*', '@foo/bar').toString()).toBe('workspace:@foo/bar@*')
|
||||||
|
expect(new WorkspaceSpec('^', '@foo/bar').toString()).toBe('workspace:@foo/bar@^')
|
||||||
|
expect(new WorkspaceSpec('~', '@foo/bar').toString()).toBe('workspace:@foo/bar@~')
|
||||||
|
expect(new WorkspaceSpec('0.1.2', '@foo/bar').toString()).toBe('workspace:@foo/bar@0.1.2')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('mutate alias and version', () => {
|
||||||
|
const spec = WorkspaceSpec.parse('workspace:*')!
|
||||||
|
expect(spec.toString()).toBe('workspace:*')
|
||||||
|
spec.version = '^'
|
||||||
|
expect(spec.toString()).toBe('workspace:^')
|
||||||
|
spec.alias = 'foo'
|
||||||
|
expect(spec.toString()).toBe('workspace:foo@^')
|
||||||
|
delete spec.alias
|
||||||
|
expect(spec.toString()).toBe('workspace:^')
|
||||||
|
})
|
||||||
13
workspace/spec-parser/tsconfig.json
Normal file
13
workspace/spec-parser/tsconfig.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"extends": "@pnpm/tsconfig",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "lib",
|
||||||
|
"rootDir": "src"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
"../../__typings__/**/*.d.ts"
|
||||||
|
],
|
||||||
|
"references": [],
|
||||||
|
"composite": true
|
||||||
|
}
|
||||||
8
workspace/spec-parser/tsconfig.lint.json
Normal file
8
workspace/spec-parser/tsconfig.lint.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
"test/**/*.ts",
|
||||||
|
"../../__typings__/**/*.d.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user