diff --git a/.changeset/brown-ads-smell.md b/.changeset/brown-ads-smell.md new file mode 100644 index 0000000000..3851e06d00 --- /dev/null +++ b/.changeset/brown-ads-smell.md @@ -0,0 +1,5 @@ +--- +"@pnpm/filter-workspace-packages": minor +--- + +Make the scope of the package optional, when filtering. diff --git a/packages/filter-workspace-packages/src/index.ts b/packages/filter-workspace-packages/src/index.ts index a14d83257e..d6c3fa0499 100644 --- a/packages/filter-workspace-packages/src/index.ts +++ b/packages/filter-workspace-packages/src/index.ts @@ -271,9 +271,14 @@ function reverseGraph (graph: Graph): Graph { function matchPackages ( graph: PackageGraph, pattern: string -) { +): string[] { const match = matcher(pattern) - return Object.keys(graph).filter((id) => graph[id].package.manifest.name && match(graph[id].package.manifest.name!)) + const matches = Object.keys(graph).filter((id) => graph[id].package.manifest.name && match(graph[id].package.manifest.name!)) + if (matches.length === 0 && !pattern.startsWith('@') && !pattern.includes('/')) { + const scopedMatches = matchPackages(graph, `@*/${pattern}`) + return scopedMatches.length !== 1 ? [] : scopedMatches + } + return matches } function matchPackagesByExactPath ( diff --git a/packages/filter-workspace-packages/test/index.ts b/packages/filter-workspace-packages/test/index.ts index 6acfe93431..176d31cd1e 100644 --- a/packages/filter-workspace-packages/test/index.ts +++ b/packages/filter-workspace-packages/test/index.ts @@ -207,6 +207,95 @@ test('select just a package by name', async () => { expect(Object.keys(selectedProjectsGraph)).toStrictEqual(['/project-2']) }) +test('select package without specifying its scope', async () => { + const PKGS_GRAPH: PackageGraph<{}> = { + '/packages/bar': { + dependencies: [], + package: { + dir: '/packages/bar', + manifest: { + name: '@foo/bar', + version: '1.0.0', + }, + }, + }, + } + const { selectedProjectsGraph } = await filterWorkspacePackages(PKGS_GRAPH, [ + { + excludeSelf: false, + namePattern: 'bar', + }, + ], { workspaceDir: process.cwd() }) + + expect(Object.keys(selectedProjectsGraph)).toStrictEqual(['/packages/bar']) +}) + +test('when a scoped package with the same name exists, only pick the exact match', async () => { + const PKGS_GRAPH: PackageGraph<{}> = { + '/packages/@foo/bar': { + dependencies: [], + package: { + dir: '/packages/@foo/bar', + manifest: { + name: '@foo/bar', + version: '1.0.0', + }, + }, + }, + '/packages/bar': { + dependencies: [], + package: { + dir: '/packages/bar', + manifest: { + name: 'bar', + version: '1.0.0', + }, + }, + }, + } + const { selectedProjectsGraph } = await filterWorkspacePackages(PKGS_GRAPH, [ + { + excludeSelf: false, + namePattern: 'bar', + }, + ], { workspaceDir: process.cwd() }) + + expect(Object.keys(selectedProjectsGraph)).toStrictEqual(['/packages/bar']) +}) + +test('when two scoped packages match the searched name, don\'t select any', async () => { + const PKGS_GRAPH: PackageGraph<{}> = { + '/packages/@foo/bar': { + dependencies: [], + package: { + dir: '/packages/@foo/bar', + manifest: { + name: '@foo/bar', + version: '1.0.0', + }, + }, + }, + '/packages/@types/bar': { + dependencies: [], + package: { + dir: '/packages/@types/bar', + manifest: { + name: '@types/bar', + version: '1.0.0', + }, + }, + }, + } + const { selectedProjectsGraph } = await filterWorkspacePackages(PKGS_GRAPH, [ + { + excludeSelf: false, + namePattern: 'bar', + }, + ], { workspaceDir: process.cwd() }) + + expect(Object.keys(selectedProjectsGraph)).toStrictEqual([]) +}) + test('select by parentDir', async () => { const { selectedProjectsGraph } = await filterWorkspacePackages(PKGS_GRAPH, [ {