import fs from 'fs' import path from 'path' import { type PnpmError } from '@pnpm/error' import { filterPackagesFromDir } from '@pnpm/workspace.filter-packages-from-dir' import { install } from '@pnpm/plugin-commands-installation' import { list, why } from '@pnpm/plugin-commands-listing' import { prepare, preparePackages } from '@pnpm/prepare' import { addDistTag } from '@pnpm/registry-mock' import { stripVTControlCharacters as stripAnsi } from 'util' import { sync as writeYamlFile } from 'write-yaml-file' import { DEFAULT_OPTS } from './utils' test('recursive list', async () => { preparePackages([ { name: 'project-1', version: '1.0.0', dependencies: { 'is-positive': '1.0.0', }, }, { name: 'project-2', version: '1.0.0', dependencies: { 'is-negative': '1.0.0', }, }, { name: 'project-3', version: '1.0.0', }, ]) const { allProjects, selectedProjectsGraph } = await filterPackagesFromDir(process.cwd(), []) await install.handler({ ...DEFAULT_OPTS, allProjects, cacheDir: path.resolve('cache'), dir: process.cwd(), recursive: true, selectedProjectsGraph, workspaceDir: process.cwd(), }) const output = await list.handler({ ...DEFAULT_OPTS, allProjects, dir: process.cwd(), recursive: true, selectedProjectsGraph, }, []) expect(stripAnsi(output as unknown as string)).toBe(`Legend: production dependency, optional only, dev only project-1@1.0.0 ${path.resolve('project-1')} dependencies: is-positive 1.0.0 Legend: production dependency, optional only, dev only project-2@1.0.0 ${path.resolve('project-2')} dependencies: is-negative 1.0.0`) }) test('recursive list with shared-workspace-lockfile', async () => { await addDistTag({ package: '@pnpm.e2e/dep-of-pkg-with-1-dep', version: '100.1.0', distTag: 'latest' }) preparePackages([ { name: 'project-1', version: '1.0.0', dependencies: { '@pnpm.e2e/pkg-with-1-dep': '100.0.0', }, }, { name: 'project-2', version: '1.0.0', dependencies: { 'is-negative': '1.0.0', }, }, { name: 'project-3', version: '1.0.0', }, ]) writeYamlFile('pnpm-workspace.yaml', { packages: ['**', '!store/**'] }) fs.writeFileSync('.npmrc', 'shared-workspace-lockfile = true', 'utf8') const { allProjects, selectedProjectsGraph } = await filterPackagesFromDir(process.cwd(), []) await install.handler({ ...DEFAULT_OPTS, allProjects, cacheDir: path.resolve('cache'), dir: process.cwd(), recursive: true, selectedProjectsGraph, workspaceDir: process.cwd(), }) const output = await list.handler({ ...DEFAULT_OPTS, allProjects, cliOptions: { depth: 2 }, dir: process.cwd(), recursive: true, selectedProjectsGraph, }, []) expect(stripAnsi(output as unknown as string)).toBe(`Legend: production dependency, optional only, dev only project-1@1.0.0 ${path.resolve('project-1')} dependencies: @pnpm.e2e/pkg-with-1-dep 100.0.0 └── @pnpm.e2e/dep-of-pkg-with-1-dep 100.1.0 Legend: production dependency, optional only, dev only project-2@1.0.0 ${path.resolve('project-2')} dependencies: is-negative 1.0.0`) }) test('recursive list --filter', async () => { preparePackages([ { name: 'project-1', version: '1.0.0', dependencies: { 'is-positive': '1.0.0', 'project-2': '1.0.0', }, }, { name: 'project-2', version: '1.0.0', dependencies: { 'is-negative': '1.0.0', }, }, { name: 'project-3', version: '1.0.0', dependencies: { 'is-negative': '1.0.0', 'is-positive': '1.0.0', }, }, ]) await install.handler({ ...DEFAULT_OPTS, ...await filterPackagesFromDir(process.cwd(), []), cacheDir: path.resolve('cache'), dir: process.cwd(), recursive: true, workspaceDir: process.cwd(), }) const output = await list.handler({ ...DEFAULT_OPTS, dir: process.cwd(), recursive: true, ...await filterPackagesFromDir(process.cwd(), [ { includeDependencies: true, namePattern: 'project-1' }, ]), }, []) expect(stripAnsi(output as unknown as string)).toBe(`Legend: production dependency, optional only, dev only project-1@1.0.0 ${path.resolve('project-1')} dependencies: is-positive 1.0.0 project-2 link:../project-2 Legend: production dependency, optional only, dev only project-2@1.0.0 ${path.resolve('project-2')} dependencies: is-negative 1.0.0`) }) test('recursive list --filter link-workspace-packages=false', async () => { preparePackages([ { dependencies: { 'is-positive': '1.0.0', 'project-2': 'workspace:*', }, name: 'project-1', version: '1.0.0', }, { name: 'project-2', version: '1.0.0', }, { name: 'is-positive', version: '1.0.0', }, ]) await install.handler({ ...DEFAULT_OPTS, ...await filterPackagesFromDir(process.cwd(), [], { linkWorkspacePackages: false }), cacheDir: path.resolve('cache'), dir: process.cwd(), linkWorkspacePackages: false, recursive: true, workspaceDir: process.cwd(), }) const output = await list.handler({ ...DEFAULT_OPTS, dir: process.cwd(), recursive: true, ...await filterPackagesFromDir(process.cwd(), [ { includeDependencies: true, namePattern: 'project-1' }, ], { linkWorkspacePackages: false }), }, []) expect(stripAnsi(output as unknown as string)).toBe(`Legend: production dependency, optional only, dev only project-1@1.0.0 ${path.resolve('project-1')} dependencies: is-positive 1.0.0 project-2 link:../project-2`) }) test('`pnpm recursive why` should fail if no package name was provided', async () => { prepare() let err!: PnpmError try { await why.handler({ ...DEFAULT_OPTS, ...await filterPackagesFromDir(process.cwd(), []), dir: process.cwd(), recursive: true, }, []) } catch (_err: any) { // eslint-disable-line err = _err } expect(err.code).toBe('ERR_PNPM_MISSING_PACKAGE_NAME') expect(err.message).toBe('`pnpm why` requires the package name') })