refactor: destroying the plugin-commands-recursive package

PR #2237
This commit is contained in:
Zoltan Kochan
2019-12-29 18:45:20 +02:00
committed by GitHub
parent c5ae0acb12
commit 9c9a3849d9
85 changed files with 2123 additions and 1650 deletions

View File

@@ -40,6 +40,7 @@
"dependencies": {
"@pnpm/config": "workspace:6.0.0",
"@pnpm/default-resolver": "workspace:6.0.3",
"@pnpm/error": "workspace:1.0.0",
"@pnpm/package-is-installable": "workspace:4.0.1",
"@pnpm/read-importer-manifest": "workspace:2.0.1",
"@pnpm/utils": "workspace:0.12.2",

View File

@@ -8,6 +8,7 @@ export * from './createLatestManifestGetter'
export * from './getPinnedVersion'
export * from './packageIsInstallable'
export * from './readImporterManifest'
export * from './recursiveSummary'
export * from './style'
export * from './updateToLatestSpecsFromManifest'

View File

@@ -6,13 +6,11 @@ interface ActionFailure {
error: Error,
}
interface RecursiveSummary {
export interface RecursiveSummary {
fails: ActionFailure[],
passes: number,
}
export default RecursiveSummary
class RecursiveFailError extends PnpmError {
public readonly fails: ActionFailure[]
public readonly passes: number

View File

@@ -5,7 +5,7 @@ export type UniversalOptions = Pick<Config, 'color' | 'dir' | 'rawConfig' | 'raw
export type WsPkg = {
dir: string,
manifest: ImporterManifest,
writeImporterManifest: (manifest: ImporterManifest) => Promise<void>,
writeImporterManifest (manifest: ImporterManifest, force?: boolean | undefined): Promise<void>
}
export type WsPkgsGraph = Record<string, { dependencies: string[], package: WsPkg }>

View File

@@ -28,6 +28,7 @@
"homepage": "https://pnpm.js.org",
"dependencies": {
"@pnpm/error": "workspace:1.0.0",
"@pnpm/find-workspace-packages": "workspace:2.0.8",
"@pnpm/matcher": "workspace:1.0.0",
"execa": "4.0.0",
"find-up": "4.1.0",

View File

@@ -1,3 +1,4 @@
import findWorkspacePackages, { WsPkg } from '@pnpm/find-workspace-packages'
import matcher from '@pnpm/matcher'
import isSubdir = require('is-subdir')
import createPkgGraph, { Package, PackageNode } from 'pkgs-graph'
@@ -15,6 +16,21 @@ interface Graph {
[nodeId: string]: string[],
}
export async function readWsPkgs (
workspaceDir: string,
pkgSelectors: PackageSelector[],
) {
const allWsPkgs = await findWorkspacePackages(workspaceDir, {})
const selectedWsPkgsGraph = await filterPkgsBySelectorObjects(
allWsPkgs,
pkgSelectors,
{
workspaceDir,
},
)
return { allWsPkgs, selectedWsPkgsGraph }
}
export async function filterPackages<T> (
pkgs: Array<Package & T>,
filter: string[],

View File

@@ -32,6 +32,7 @@
},
"dependencies": {
"@pnpm/cli-utils": "workspace:0.2.5",
"@pnpm/config": "workspace:6.0.0",
"@pnpm/constants": "workspace:3.0.0",
"@pnpm/types": "workspace:4.0.0",
"find-packages": "workspace:7.0.1",

View File

@@ -1,15 +1,11 @@
import { packageIsInstallable } from '@pnpm/cli-utils'
import { WsPkg } from '@pnpm/config'
import { WORKSPACE_MANIFEST_FILENAME } from '@pnpm/constants'
import { ImporterManifest } from '@pnpm/types'
import findPackages from 'find-packages'
import path = require('path')
import readYamlFile from 'read-yaml-file'
interface WorkspaceDependencyPackage {
dir: string
manifest: ImporterManifest
writeImporterManifest (manifest: ImporterManifest, force?: boolean | undefined): Promise<void>
}
export { WsPkg }
export default async (
workspaceRoot: string,
@@ -29,7 +25,7 @@ export default async (
packageIsInstallable(pkg.dir, pkg.manifest, opts)
}
return pkgs as WorkspaceDependencyPackage[]
return pkgs as WsPkg[]
}
async function requirePackagesManifest (dir: string): Promise<{packages?: string[]} | null> {
@@ -44,7 +40,7 @@ async function requirePackagesManifest (dir: string): Promise<{packages?: string
}
export function arrayOfWorkspacePackagesToMap (
pkgs: WorkspaceDependencyPackage[],
pkgs: WsPkg[],
) {
return pkgs.reduce((acc, pkg) => {
if (!pkg.manifest.name || !pkg.manifest.version) return acc

View File

@@ -1,6 +1,8 @@
import findWorkspaceDir from '@pnpm/find-workspace-dir'
import nopt = require('nopt')
const RECURSIVE_CMDS = new Set(['recursive', 'multi', 'm'])
export default async function parseCliArgs (
opts: {
getCommandLongName: (commandName: string) => string,
@@ -40,28 +42,16 @@ export default async function parseCliArgs (
}
}
const types = (() => {
if (opts.getCommandLongName(noptExploratoryResults.argv.remain[0]) === 'recursive') {
return {
...opts.globalOptionsTypes,
...opts.getTypesByCommandName('recursive'),
...opts.getTypesByCommandName(getCommandName(noptExploratoryResults.argv.remain.slice(1))),
}
}
if (noptExploratoryResults['filter'] || noptExploratoryResults['recursive'] === true) {
return {
...opts.globalOptionsTypes,
...opts.getTypesByCommandName('recursive'),
...opts.getTypesByCommandName(getCommandName(noptExploratoryResults.argv.remain)),
}
}
return {
...opts.globalOptionsTypes,
...opts.getTypesByCommandName(getCommandName(noptExploratoryResults.argv.remain)),
}
})() as any // tslint:disable-line:no-any
const types = {
'recursive': Boolean,
...opts.globalOptionsTypes,
...opts.getTypesByCommandName(getCommandName(noptExploratoryResults.argv.remain)),
} as any // tslint:disable-line:no-any
function getCommandName (cliArgs: string[]) {
if (RECURSIVE_CMDS.has(cliArgs[0])) {
cliArgs = cliArgs.slice(1)
}
if (opts.getCommandLongName(cliArgs[0]) !== 'install' || cliArgs.length === 1) return cliArgs[0]
return 'add'
}
@@ -77,9 +67,8 @@ export default async function parseCliArgs (
}
}
let cmd = opts.getCommandLongName(argv.remain[0])
|| 'help'
if (!opts.isKnownCommand(cmd)) {
let cmd = opts.getCommandLongName(argv.remain[0]) ?? 'help'
if (!opts.isKnownCommand(cmd) && !RECURSIVE_CMDS.has(cmd)) {
cmd = 'help'
}
@@ -88,10 +77,14 @@ export default async function parseCliArgs (
// `pnpm install ""` is going to be just `pnpm install`
const cliArgs = argv.remain.slice(1).filter(Boolean)
if (cmd !== 'recursive' && (cliConf['filter'] || cliConf['recursive'] === true)) {
subCmd = cmd
cmd = 'recursive'
cliArgs.unshift(subCmd)
if (cliConf['recursive'] !== true && (cliConf['filter'] || RECURSIVE_CMDS.has(cmd))) {
cliConf['recursive'] = true
if (subCmd && RECURSIVE_CMDS.has(cmd)) {
cliArgs.shift()
argv.remain.shift()
cmd = subCmd
subCmd = null
}
} else if (subCmd && !opts.isKnownCommand(subCmd)) {
subCmd = null
}
@@ -105,15 +98,13 @@ export default async function parseCliArgs (
typeof workspaceDir === 'string' &&
cliArgs.length === 0
) {
subCmd = cmd
cmd = 'recursive'
cliArgs.unshift(subCmd)
cliConf['recursive'] = true
}
if (cmd === 'install' && cliArgs.length > 0) {
cmd = 'add'
} else if (subCmd === 'install' && cliArgs.length > 1) {
subCmd = 'add'
cmd = 'add'
}
const allowedOptions = new Set(Object.keys(types))

View File

@@ -13,59 +13,69 @@ const DEFAULT_OPTS = {
}
test('a command is recursive if it has a --filter option', async (t) => {
const { cmd, subCmd } = await parseCliArgs({
const { cliConf, cmd } = await parseCliArgs({
...DEFAULT_OPTS,
globalOptionsTypes: { filter: [String, Array] },
}, ['--filter', 'foo', 'update'])
t.equal(cmd, 'recursive')
t.equal(subCmd, 'update')
t.equal(cmd, 'update')
t.ok(cliConf['recursive'])
t.end()
})
test('a command is recursive if -r option is used', async (t) => {
const { cmd, subCmd } = await parseCliArgs({
const { cliConf, cmd } = await parseCliArgs({
...DEFAULT_OPTS,
globalOptionsTypes: { recursive: Boolean },
shortHands: { 'r': ['--recursive'] },
}, ['-r', 'update'])
t.equal(cmd, 'recursive')
t.equal(subCmd, 'update')
t.equal(cmd, 'update')
t.ok(cliConf['recursive'])
t.end()
})
test('a command is recursive if --recursive option is used', async (t) => {
const { cmd, subCmd } = await parseCliArgs({
const { cliConf, cmd } = await parseCliArgs({
...DEFAULT_OPTS,
globalOptionsTypes: { recursive: Boolean },
}, ['-r', 'update'])
t.equal(cmd, 'recursive')
t.equal(subCmd, 'update')
t.equal(cmd, 'update')
t.ok(cliConf['recursive'])
t.end()
})
test('the install command is recursive when executed in a subdir of a workspace', async (t) => {
const { cmd, subCmd, workspaceDir } = await parseCliArgs({
const { cliConf, cmd, workspaceDir } = await parseCliArgs({
...DEFAULT_OPTS,
globalOptionsTypes: { dir: String },
}, ['--dir', __dirname, 'install'])
t.equal(cmd, 'recursive')
t.equal(subCmd, 'install')
t.equal(cmd, 'install')
t.ok(cliConf['recursive'])
t.equal(workspaceDir, path.join(__dirname, '../../..'))
t.end()
})
test('the install command is recursive when executed in the root of a workspace', async (t) => {
const expectedWorkspaceDir = path.join(__dirname, '../../..')
const { cmd, subCmd, workspaceDir } = await parseCliArgs({
const { cliConf, cmd, workspaceDir } = await parseCliArgs({
...DEFAULT_OPTS,
globalOptionsTypes: { dir: String },
}, ['--dir', expectedWorkspaceDir, 'install'])
t.equal(cmd, 'recursive')
t.equal(subCmd, 'install')
t.equal(cmd, 'install')
t.ok(cliConf['recursive'])
t.equal(workspaceDir, expectedWorkspaceDir)
t.end()
})
test('recursive is returned as the command name if no subcommand passed', async (t) => {
const { cliConf, cmd } = await parseCliArgs({
...DEFAULT_OPTS,
globalOptionsTypes: { filter: [String, Array] },
}, ['recursive'])
t.equal(cmd, 'recursive')
t.ok(cliConf['recursive'])
t.end()
})
test('when runnning a global command inside a workspace, the workspace should be ignored', async (t) => {
const { workspaceDir } = await parseCliArgs({
...DEFAULT_OPTS,
@@ -112,6 +122,7 @@ test('detect unknown options', async (t) => {
getTypesByCommandName: (commandName: string) => {
if (commandName === 'install') {
return {
recursive: Boolean,
registry: String,
}
}
@@ -124,24 +135,6 @@ test('detect unknown options', async (t) => {
t.end()
})
test('merge option types of recursive and subcommand', async (t) => {
const { unknownOptions } = await parseCliArgs({
...DEFAULT_OPTS,
getTypesByCommandName: (commandName: string) => {
switch (commandName) {
case 'install': return { recursive: Boolean, registry: String }
case 'recursive': return { sort: Boolean }
default: return {}
}
},
globalOptionsTypes: { filter: [String, Array] },
isKnownCommand: (commandName) => commandName === 'install',
shortHands: { 'r': ['--recursive'] },
}, ['-r', 'install', '--registry=https://example.com', '--sort'])
t.deepEqual(unknownOptions, [])
t.end()
})
test('do not incorrectly change "install" command to "add"', async (t) => {
const { cmd } = await parseCliArgs({
...DEFAULT_OPTS,

View File

@@ -13,7 +13,11 @@
"scripts": {
"lint": "tslint -c tslint.json src/**/*.ts test/**/*.ts",
"tsc": "rimraf lib && tsc",
"test": "pnpm run tsc && pnpm run lint && ts-node test",
"registry-mock": "registry-mock",
"test:tap": "ts-node test --type-check",
"pretest:e2e": "registry-mock prepare",
"test:e2e": "run-p -r registry-mock test:tap",
"test": "pnpm run tsc && pnpm run lint && cross-env PNPM_REGISTRY_MOCK_PORT=7777 pnpm run test:e2e",
"prepublishOnly": "pnpm run tsc"
},
"repository": "https://github.com/pnpm/pnpm/blob/master/packages/plugin-commands-installation",
@@ -27,33 +31,54 @@
},
"homepage": "https://pnpm.js.org",
"devDependencies": {
"@pnpm/lockfile-types": "workspace:1.1.0",
"@pnpm/logger": "^3.1.0",
"@pnpm/plugin-commands-installation": "link:",
"@pnpm/prepare": "workspace:0.0.0",
"@pnpm/registry-mock": "1.11.1",
"@pnpm/test-fixtures": "workspace:0.0.0",
"@types/common-tags": "^1.8.0",
"@types/mz": "^2.7.0",
"@types/ramda": "^0.26.38",
"rimraf": "3.0.0"
"make-dir": "3.0.0",
"read-yaml-file": "1.1.0",
"rimraf": "3.0.0",
"write-json-file": "4.2.1",
"write-yaml-file": "3.0.1"
},
"dependencies": {
"@pnpm/cli-utils": "workspace:0.2.5",
"@pnpm/common-cli-options-help": "workspace:0.1.2",
"@pnpm/config": "workspace:6.0.0",
"@pnpm/constants": "workspace:3.0.0",
"@pnpm/core-loggers": "workspace:4.0.0",
"@pnpm/error": "workspace:1.0.0",
"@pnpm/filter-workspace-packages": "workspace:1.0.1",
"@pnpm/find-workspace-dir": "workspace:1.0.0",
"@pnpm/find-workspace-packages": "workspace:2.0.8",
"@pnpm/package-store": "workspace:7.0.2",
"@pnpm/plugin-commands-rebuild": "workspace:0.0.0",
"@pnpm/plugin-commands-recursive": "workspace:0.1.10",
"@pnpm/pnpmfile": "workspace:0.1.0",
"@pnpm/resolver-base": "workspace:6.0.0",
"@pnpm/sort-packages": "workspace:0.0.0",
"@pnpm/store-connection-manager": "workspace:0.2.5",
"@pnpm/types": "workspace:4.0.0",
"@pnpm/utils": "workspace:0.12.2",
"camelcase-keys": "6.1.1",
"common-tags": "1.8.0",
"is-subdir": "1.1.1",
"mem": "6.0.1",
"mz": "2.7.0",
"p-filter": "2.1.0",
"p-limit": "2.2.1",
"path-absolute": "1.0.1",
"path-exists": "4.0.0",
"ramda": "0.26.1",
"read-ini-file": "2.0.0",
"render-help": "0.0.0",
"supi": "workspace:0.37.6"
},
"peerDependencies": {
"@pnpm/logger": "^3.1.0"
}
}

View File

@@ -151,6 +151,7 @@ export async function handler (
input: string[],
opts: InstallCommandOptions & {
allowNew?: boolean,
ignoreWorkspaceRootCheck?: boolean,
save?: boolean,
update?: boolean,
useBetaCli?: boolean,
@@ -160,5 +161,20 @@ export async function handler (
if (opts.cliOptions['save'] === false) {
throw new PnpmError('OPTION_NOT_SUPPORTED', 'The "add" command currently does not support the no-save option')
}
return install(input, opts, invocation)
if (!input || !input.length) {
throw new PnpmError('MISSING_PACKAGE_NAME', '`pnpm add` requires the package name')
}
if (
!opts.recursive &&
opts.workspaceDir === opts.dir &&
!opts.ignoreWorkspaceRootCheck
) {
throw new PnpmError('ADDING_TO_ROOT',
'Running this command will add the dependency to the workspace root, ' +
'which might not be what you want - if you really meant it, ' +
'make it explicit by running this command again with the -W flag (or --ignore-workspace-root-check).',
)
}
return install(input, opts, invocation ?? 'add')
}

View File

@@ -14,8 +14,6 @@ import PnpmError from '@pnpm/error'
import { filterPkgsBySelectorObjects } from '@pnpm/filter-workspace-packages'
import findWorkspacePackages, { arrayOfWorkspacePackagesToMap } from '@pnpm/find-workspace-packages'
import { rebuild } from '@pnpm/plugin-commands-rebuild/lib/implementation'
import { recursive } from '@pnpm/plugin-commands-recursive/lib/recursive'
import { createWorkspaceSpecs, updateToWorkspacePackagesFromManifest } from '@pnpm/plugin-commands-recursive/lib/updateWorkspaceDependencies'
import { requireHooks } from '@pnpm/pnpmfile'
import { createOrConnectStoreController, CreateStoreControllerOptions } from '@pnpm/store-connection-manager'
import { oneLine } from 'common-tags'
@@ -25,6 +23,8 @@ import {
install,
mutateModules,
} from 'supi'
import recursive from './recursive'
import { createWorkspaceSpecs, updateToWorkspacePackagesFromManifest } from './updateWorkspaceDependencies'
const OVERWRITE_UPDATE_OPTIONS = {
allowNew: true,
@@ -256,6 +256,7 @@ export function help () {
}
export type InstallCommandOptions = Pick<Config,
'allWsPkgs' |
'bail' |
'bin' |
'cliOptions' |
@@ -277,7 +278,9 @@ export type InstallCommandOptions = Pick<Config,
'savePrefix' |
'saveProd' |
'saveWorkspaceProtocol' |
'selectedWsPkgsGraph' |
'sort' |
'sharedWorkspaceLockfile' |
'workspaceConcurrency' |
'workspaceDir'
> & CreateStoreControllerOptions & {
@@ -288,13 +291,14 @@ export type InstallCommandOptions = Pick<Config,
latest?: boolean,
update?: boolean,
useBetaCli?: boolean,
recursive?: boolean,
workspace?: boolean,
}
export async function handler (
input: string[],
opts: InstallCommandOptions,
invocation?: string,
invocation: string,
) {
if (opts.workspace) {
if (opts.latest) {
@@ -315,6 +319,10 @@ export async function handler (
}
opts['preserveWorkspaceProtocol'] = !opts.linkWorkspacePackages
}
if (opts.recursive && opts.allWsPkgs && opts.selectedWsPkgsGraph && opts.workspaceDir) {
await recursive(opts.allWsPkgs, input, { ...opts, selectedWsPkgsGraph: opts.selectedWsPkgsGraph!, workspaceDir: opts.workspaceDir! }, invocation)
return
}
// `pnpm install ""` is going to be just `pnpm install`
input = input.filter(Boolean)
@@ -369,9 +377,6 @@ export async function handler (
}
}
if (!input || !input.length) {
if (invocation === 'add') {
throw new PnpmError('MISSING_PACKAGE_NAME', '`pnpm add` requires the package name')
}
const updatedManifest = await install(manifest, installOpts)
if (opts.update === true && opts.save !== false) {
await writeImporterManifest(updatedManifest)
@@ -401,6 +406,7 @@ export async function handler (
const allWsPkgs = await findWorkspacePackages(opts.workspaceDir, opts)
const selectedWsPkgsGraph = await filterPkgsBySelectorObjects(allWsPkgs, [
{
excludeSelf: true,
includeDependencies: true,
parentDir: dir,
},
@@ -410,10 +416,9 @@ export async function handler (
await recursive(allWsPkgs, [], {
...opts,
...OVERWRITE_UPDATE_OPTIONS,
ignoredPackages: new Set([dir]),
selectedWsPkgsGraph,
workspaceDir: opts.workspaceDir, // Otherwise TypeScript doesn't understant that is is not undefined
}, 'install', 'install')
}, 'install')
if (opts.ignoreScripts) return

View File

@@ -25,6 +25,7 @@ import {
WorkspacePackages,
} from 'supi'
import * as installCommand from './install'
import recursive from './recursive'
const installLimit = pLimit(4)

View File

@@ -0,0 +1,406 @@
import {
createLatestSpecs,
getPinnedVersion,
getSaveType,
RecursiveSummary,
throwOnCommandFail,
updateToLatestSpecsFromManifest,
} from '@pnpm/cli-utils'
import { Config, WsPkg, WsPkgsGraph } from '@pnpm/config'
import { scopeLogger } from '@pnpm/core-loggers'
import { arrayOfWorkspacePackagesToMap } from '@pnpm/find-workspace-packages'
import logger from '@pnpm/logger'
import { rebuild } from '@pnpm/plugin-commands-rebuild'
import { requireHooks } from '@pnpm/pnpmfile'
import sortPackages from '@pnpm/sort-packages'
import { createOrConnectStoreController, CreateStoreControllerOptions } from '@pnpm/store-connection-manager'
import { ImporterManifest, PackageManifest } from '@pnpm/types'
import camelcaseKeys = require('camelcase-keys')
import isSubdir = require('is-subdir')
import mem = require('mem')
import fs = require('mz/fs')
import pFilter = require('p-filter')
import pLimit from 'p-limit'
import path = require('path')
import R = require('ramda')
import readIniFile = require('read-ini-file')
import {
addDependenciesToPackage,
install,
InstallOptions,
MutatedImporter,
mutateModules,
} from 'supi'
import { createWorkspaceSpecs, updateToWorkspacePackagesFromManifest } from './updateWorkspaceDependencies'
type RecursiveOptions = CreateStoreControllerOptions & Pick<Config,
'bail' |
'globalPnpmfile' |
'hoistPattern' |
'ignorePnpmfile' |
'ignoreScripts' |
'include' |
'linkWorkspacePackages' |
'lockfileDir' |
'lockfileOnly' |
'pnpmfile' |
'rawLocalConfig' |
'registries' |
'save' |
'saveDev' |
'saveExact' |
'saveOptional' |
'savePeer' |
'savePrefix' |
'saveProd' |
'saveWorkspaceProtocol' |
'sharedWorkspaceLockfile' |
'tag'
> & {
latest?: boolean,
pending?: boolean,
workspace?: boolean,
} & Partial<Pick<Config, 'sort' | 'workspaceConcurrency'>>
export default async function recursive (
allWsPkgs: WsPkg[],
input: string[],
opts: RecursiveOptions & {
allowNew?: boolean,
ignoredPackages?: Set<string>,
update?: boolean,
useBetaCli?: boolean,
selectedWsPkgsGraph: WsPkgsGraph,
} & Required<Pick<Config, 'workspaceDir'>>,
cmdFullName: string,
): Promise<boolean | string> {
if (allWsPkgs.length === 0) {
// It might make sense to throw an exception in this case
return false
}
const pkgs = Object.values(opts.selectedWsPkgsGraph).map((wsPkg) => wsPkg.package)
if (pkgs.length === 0) {
return false
}
const manifestsByPath: { [dir: string]: Omit<WsPkg, 'dir'> } = {}
for (const { dir, manifest, writeImporterManifest } of pkgs) {
manifestsByPath[dir] = { manifest, writeImporterManifest }
}
scopeLogger.debug({
selected: pkgs.length,
total: allWsPkgs.length,
workspacePrefix: opts.workspaceDir,
})
const throwOnFail = throwOnCommandFail.bind(null, `pnpm recursive ${cmdFullName}`)
const chunks = opts.sort !== false
? sortPackages(opts.selectedWsPkgsGraph)
: [Object.keys(opts.selectedWsPkgsGraph).sort()]
const store = await createOrConnectStoreController(opts)
// It is enough to save the store.json file once,
// once all installations are done.
// That's why saveState that is passed to the install engine
// does nothing.
const saveState = store.ctrl.saveState
const storeController = {
...store.ctrl,
saveState: async () => undefined,
}
const workspacePackages = cmdFullName !== 'unlink'
? arrayOfWorkspacePackagesToMap(allWsPkgs)
: {}
const installOpts = Object.assign(opts, {
ownLifecycleHooksStdio: 'pipe',
peer: opts.savePeer,
pruneLockfileImporters: (!opts.ignoredPackages || opts.ignoredPackages.size === 0)
&& pkgs.length === allWsPkgs.length,
storeController,
storeDir: store.dir,
workspacePackages,
forceHoistPattern: typeof opts.rawLocalConfig['hoist-pattern'] !== 'undefined' || typeof opts.rawLocalConfig['hoist'] !== 'undefined',
forceIndependentLeaves: typeof opts.rawLocalConfig['independent-leaves'] !== 'undefined',
forceShamefullyHoist: typeof opts.rawLocalConfig['shamefully-hoist'] !== 'undefined',
}) as InstallOptions
const result = {
fails: [],
passes: 0,
} as RecursiveSummary
const memReadLocalConfig = mem(readLocalConfig)
async function getImporters () {
const importers = [] as Array<{ buildIndex: number, manifest: ImporterManifest, rootDir: string }>
await Promise.all(chunks.map((prefixes: string[], buildIndex) => {
if (opts.ignoredPackages) {
prefixes = prefixes.filter((prefix) => !opts.ignoredPackages!.has(prefix))
}
return Promise.all(
prefixes.map(async (prefix) => {
importers.push({
buildIndex,
manifest: manifestsByPath[prefix].manifest,
rootDir: prefix,
})
})
)
}))
return importers
}
const updateToLatest = opts.update && opts.latest
const include = opts.include
if (updateToLatest) {
delete opts.include
}
// For a workspace with shared lockfile
if (opts.lockfileDir && ['add', 'install', 'remove', 'update'].includes(cmdFullName)) {
if (opts.hoistPattern) {
logger.info({ message: 'Only the root workspace package is going to have hoisted dependencies in node_modules', prefix: opts.lockfileDir })
}
let importers = await getImporters()
const isFromWorkspace = isSubdir.bind(null, opts.lockfileDir)
importers = await pFilter(importers, async ({ rootDir }: { rootDir: string }) => isFromWorkspace(await fs.realpath(rootDir)))
if (importers.length === 0) return true
const hooks = opts.ignorePnpmfile ? {} : requireHooks(opts.lockfileDir, opts)
const mutation = cmdFullName === 'remove' ? 'uninstallSome' : (input.length === 0 && !updateToLatest ? 'install' : 'installSome')
const writeImporterManifests = [] as Array<(manifest: ImporterManifest) => Promise<void>>
const mutatedImporters = [] as MutatedImporter[]
await Promise.all(importers.map(async ({ buildIndex, rootDir }) => {
const localConfig = await memReadLocalConfig(rootDir)
const { manifest, writeImporterManifest } = manifestsByPath[rootDir]
let currentInput = [...input]
if (updateToLatest) {
if (!currentInput || !currentInput.length) {
currentInput = updateToLatestSpecsFromManifest(manifest, include)
} else {
currentInput = createLatestSpecs(currentInput, manifest)
if (!currentInput.length) {
installOpts.pruneLockfileImporters = false
return
}
}
}
if (opts.workspace) {
if (!currentInput || !currentInput.length) {
currentInput = updateToWorkspacePackagesFromManifest(manifest, opts.include, workspacePackages!)
} else {
currentInput = createWorkspaceSpecs(currentInput, workspacePackages!)
}
}
writeImporterManifests.push(writeImporterManifest)
switch (mutation) {
case 'uninstallSome':
mutatedImporters.push({
dependencyNames: currentInput,
manifest,
mutation,
rootDir,
targetDependenciesField: getSaveType(opts),
} as MutatedImporter)
return
case 'installSome':
mutatedImporters.push({
allowNew: cmdFullName === 'install' || cmdFullName === 'add',
dependencySelectors: currentInput,
manifest,
mutation,
peer: opts.savePeer,
pinnedVersion: getPinnedVersion({
saveExact: typeof localConfig.saveExact === 'boolean' ? localConfig.saveExact : opts.saveExact,
savePrefix: typeof localConfig.savePrefix === 'string' ? localConfig.savePrefix : opts.savePrefix,
}),
rootDir,
targetDependenciesField: getSaveType(opts),
} as MutatedImporter)
return
case 'install':
mutatedImporters.push({
buildIndex,
manifest,
mutation,
rootDir,
} as MutatedImporter)
return
}
}))
const mutatedPkgs = await mutateModules(mutatedImporters, {
...installOpts,
hooks,
storeController: store.ctrl,
})
if (opts.save !== false) {
await Promise.all(
mutatedPkgs
.map(({ manifest }, index) => writeImporterManifests[index](manifest))
)
}
return true
}
let pkgPaths = chunks.length === 0
? chunks[0]
: Object.keys(opts.selectedWsPkgsGraph).sort()
const limitInstallation = pLimit(opts.workspaceConcurrency ?? 4)
await Promise.all(pkgPaths.map((rootDir: string) =>
limitInstallation(async () => {
const hooks = opts.ignorePnpmfile ? {} : requireHooks(rootDir, opts)
try {
if (opts.ignoredPackages && opts.ignoredPackages.has(rootDir)) {
return
}
const { manifest, writeImporterManifest } = manifestsByPath[rootDir]
let currentInput = [...input]
if (updateToLatest) {
if (!currentInput || !currentInput.length) {
currentInput = updateToLatestSpecsFromManifest(manifest, include)
} else {
currentInput = createLatestSpecs(currentInput, manifest)
if (!currentInput.length) return
}
}
let action!: any // tslint:disable-line:no-any
switch (cmdFullName) {
case 'unlink':
action = (currentInput.length === 0 ? unlink : unlinkPkgs.bind(null, currentInput))
break
case 'remove':
action = (manifest: PackageManifest, opts: any) => mutateModules([ // tslint:disable-line:no-any
{
dependencyNames: currentInput,
manifest,
mutation: 'uninstallSome',
rootDir,
},
], opts)
break
default:
action = currentInput.length === 0
? install
: (manifest: PackageManifest, opts: any) => addDependenciesToPackage(manifest, currentInput, opts) // tslint:disable-line:no-any
break
}
const localConfig = await memReadLocalConfig(rootDir)
const newManifest = await action(
manifest,
{
...installOpts,
...localConfig,
bin: path.join(rootDir, 'node_modules', '.bin'),
dir: rootDir,
hooks,
ignoreScripts: true,
pinnedVersion: getPinnedVersion({
saveExact: typeof localConfig.saveExact === 'boolean' ? localConfig.saveExact : opts.saveExact,
savePrefix: typeof localConfig.savePrefix === 'string' ? localConfig.savePrefix : opts.savePrefix,
}),
rawConfig: {
...installOpts.rawConfig,
...localConfig,
},
storeController,
},
)
if (opts.save !== false) {
await writeImporterManifest(newManifest)
}
result.passes++
} catch (err) {
logger.info(err)
if (!opts.bail) {
result.fails.push({
error: err,
message: err.message,
prefix: rootDir,
})
return
}
err['prefix'] = rootDir // tslint:disable-line:no-string-literal
throw err
}
}),
))
await saveState()
// The store should be unlocked because otherwise rebuild will not be able
// to access it
await storeController.close()
if (
!opts.lockfileOnly && !opts.ignoreScripts && (
cmdFullName === 'add' ||
cmdFullName === 'install' ||
cmdFullName === 'update' ||
cmdFullName === 'unlink'
)
) {
await rebuild.handler([], {
...opts,
pending: opts.pending === true,
})
}
throwOnFail(result)
return true
}
async function unlink (manifest: ImporterManifest, opts: any) { // tslint:disable-line:no-any
return mutateModules(
[
{
manifest,
mutation: 'unlink',
rootDir: opts.dir,
},
],
opts,
)
}
async function unlinkPkgs (dependencyNames: string[], manifest: ImporterManifest, opts: any) { // tslint:disable-line:no-any
return mutateModules(
[
{
dependencyNames,
manifest,
mutation: 'unlinkSome',
rootDir: opts.dir,
},
],
opts,
)
}
async function readLocalConfig (prefix: string) {
try {
const ini = await readIniFile(path.join(prefix, '.npmrc')) as { [key: string]: string }
const config = camelcaseKeys(ini) as ({ [key: string]: string } & { hoist?: boolean })
if (config.shamefullyFlatten) {
config.hoistPattern = '*'
// TODO: print a warning
}
if (config.hoist === false) {
config.hoistPattern = ''
}
return config
} catch (err) {
if (err.code !== 'ENOENT') throw err
return {}
}
}

View File

@@ -10,6 +10,7 @@ import renderHelp = require('render-help')
import {
mutateModules,
} from 'supi'
import recursive from './recursive'
export const rcOptionsTypes = cliOptionsTypes
@@ -68,8 +69,29 @@ export const commandNames = ['remove', 'uninstall', 'r', 'rm', 'un']
export async function handler (
input: string[],
opts: CreateStoreControllerOptions & Pick<Config, 'ignorePnpmfile' | 'engineStrict' | 'lockfileDir' | 'linkWorkspacePackages' | 'workspaceDir' | 'bin' | 'globalPnpmfile' | 'pnpmfile'>,
opts: CreateStoreControllerOptions & Pick<Config,
'allWsPkgs' |
'bail' |
'bin' |
'engineStrict' |
'globalPnpmfile' |
'ignorePnpmfile' |
'include' |
'lockfileDir' |
'linkWorkspacePackages' |
'pnpmfile' |
'rawLocalConfig' |
'registries' |
'selectedWsPkgsGraph' |
'workspaceDir'
> & {
recursive?: boolean,
},
) {
if (opts.recursive && opts.allWsPkgs && opts.selectedWsPkgsGraph && opts.workspaceDir) {
await recursive(opts.allWsPkgs, input, { ...opts, selectedWsPkgsGraph: opts.selectedWsPkgsGraph!, workspaceDir: opts.workspaceDir! }, 'remove')
return
}
const store = await createOrConnectStoreController(opts)
const removeOpts = Object.assign(opts, {
storeController: store.ctrl,

View File

@@ -6,6 +6,7 @@ import { oneLine } from 'common-tags'
import renderHelp = require('render-help')
import { mutateModules } from 'supi'
import { cliOptionsTypes, rcOptionsTypes } from './install'
import recursive from './recursive'
export { cliOptionsTypes, rcOptionsTypes }
@@ -40,7 +41,28 @@ export function help () {
})
}
export async function handler (input: string[], opts: CreateStoreControllerOptions & Pick<Config, 'engineStrict'>) {
export async function handler (
input: string[],
opts: CreateStoreControllerOptions &
Pick<Config,
'allWsPkgs' |
'bail' |
'engineStrict' |
'include' |
'linkWorkspacePackages' |
'selectedWsPkgsGraph' |
'rawLocalConfig' |
'registries' |
'pnpmfile' |
'workspaceDir'
> & {
recursive?: boolean,
},
) {
if (opts.recursive && opts.allWsPkgs && opts.selectedWsPkgsGraph && opts.workspaceDir) {
await recursive(opts.allWsPkgs, input, { ...opts, selectedWsPkgsGraph: opts.selectedWsPkgsGraph!, workspaceDir: opts.workspaceDir! }, 'unlink')
return
}
const store = await createOrConnectStoreController(opts)
const unlinkOpts = Object.assign(opts, {
storeController: store.ctrl,

View File

@@ -106,5 +106,5 @@ export async function handler (
input: string[],
opts: InstallCommandOptions,
) {
return install(input, { ...opts, update: true, allowNew: false })
return install(input, { ...opts, update: true, allowNew: false }, 'update')
}

View File

@@ -1,3 +1,7 @@
///<reference path="../../../typings/index.d.ts" />
import './add'
import './linkRecursive'
import './miscRecursive'
import './prune'
import './updateRecursive'
import './updateWorkspaceDependencies.spec'

View File

@@ -1,10 +1,11 @@
import { WANTED_LOCKFILE } from '@pnpm/constants'
import { recursive } from '@pnpm/plugin-commands-recursive'
import { readWsPkgs } from '@pnpm/filter-workspace-packages'
import { install, link, unlink } from '@pnpm/plugin-commands-installation'
import { preparePackages } from '@pnpm/prepare'
import path = require('path')
import exists = require('path-exists')
import test = require('tape')
import { DEFAULT_OPTS, readWsPkgs } from './utils'
import { DEFAULT_OPTS } from './utils'
test('recursive linking/unlinking', async (t) => {
const projects = preparePackages(t, [
@@ -27,12 +28,14 @@ test('recursive linking/unlinking', async (t) => {
])
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
await install.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
})
workspaceDir: process.cwd(),
}, 'install')
t.ok(projects['is-positive'].requireModule('is-negative'))
t.notOk(projects['project-1'].requireModule('is-positive/package.json').author, 'local package is linked')
@@ -42,11 +45,13 @@ test('recursive linking/unlinking', async (t) => {
t.equal(project1Lockfile.devDependencies['is-positive'], 'link:../is-positive')
}
await recursive.handler(['unlink'], {
await unlink.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
workspaceDir: process.cwd(),
})
process.chdir('project-1')
@@ -86,12 +91,14 @@ test('recursive unlink specific package', async (t) => {
])
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
await install.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
})
workspaceDir: process.cwd(),
}, 'install')
t.ok(projects['is-positive'].requireModule('is-negative'))
t.notOk(projects['project-1'].requireModule('is-positive/package.json').author, 'local package is linked')
@@ -101,11 +108,13 @@ test('recursive unlink specific package', async (t) => {
t.equal(project1Lockfile.devDependencies['is-positive'], 'link:../is-positive')
}
await recursive.handler(['unlink', 'is-positive'], {
await unlink.handler(['is-positive'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
workspaceDir: process.cwd(),
})
process.chdir('project-1')

View File

@@ -1,5 +1,6 @@
import PnpmError from '@pnpm/error'
import { recursive } from '@pnpm/plugin-commands-recursive'
import { readWsPkgs } from '@pnpm/filter-workspace-packages'
import { add, install, remove, update } from '@pnpm/plugin-commands-installation'
import { preparePackages } from '@pnpm/prepare'
import makeDir = require('make-dir')
import fs = require('mz/fs')
@@ -7,7 +8,7 @@ import path = require('path')
import test = require('tape')
import writeJsonFile = require('write-json-file')
import writeYamlFile = require('write-yaml-file')
import { DEFAULT_OPTS, readWsPkgs } from './utils'
import { DEFAULT_OPTS } from './utils'
test('recursive install/uninstall', async (t) => {
const projects = preparePackages(t, [
@@ -30,32 +31,38 @@ test('recursive install/uninstall', async (t) => {
])
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
await install.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
})
workspaceDir: process.cwd(),
}, 'install')
t.ok(projects['project-1'].requireModule('is-positive'))
t.ok(projects['project-2'].requireModule('is-negative'))
await projects['project-2'].has('is-negative')
await recursive.handler(['add', 'noop'], {
await add.handler(['noop'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
})
workspaceDir: process.cwd(),
}, 'add')
t.ok(projects['project-1'].requireModule('noop'))
t.ok(projects['project-2'].requireModule('noop'))
await recursive.handler(['remove', 'is-negative'], {
await remove.handler(['is-negative'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
workspaceDir: process.cwd(),
})
await projects['project-2'].hasNot('is-negative')
@@ -85,11 +92,13 @@ test('recursive install with package that has link', async (t) => {
},
])
await recursive.handler(['install'], {
await install.handler([], {
...DEFAULT_OPTS,
...await readWsPkgs(process.cwd(), []),
dir: process.cwd(),
})
recursive: true,
workspaceDir: process.cwd(),
}, 'install')
t.ok(projects['project-1'].requireModule('is-positive'))
t.ok(projects['project-1'].requireModule('project-2/package.json'))
@@ -119,11 +128,13 @@ test('running `pnpm recursive` on a subset of packages', async t => {
await writeYamlFile('pnpm-workspace.yaml', { packages: ['project-1'] })
await recursive.handler(['install'], {
await install.handler([], {
...DEFAULT_OPTS,
...await readWsPkgs(process.cwd(), []),
dir: process.cwd(),
})
recursive: true,
workspaceDir: process.cwd(),
}, 'install')
await projects['project-1'].has('is-positive')
await projects['project-2'].hasNot('is-negative')
@@ -170,11 +181,13 @@ test('running `pnpm recursive` only for packages in subdirectories of cwd', asyn
await makeDir('node_modules')
process.chdir('packages')
await recursive.handler(['install'], {
await install.handler([], {
...DEFAULT_OPTS,
...await readWsPkgs(process.cwd(), []),
dir: process.cwd(),
})
recursive: true,
workspaceDir: process.cwd(),
}, 'install')
await projects['project-1'].has('is-positive')
await projects['project-2'].has('is-negative')
@@ -204,15 +217,17 @@ test('recursive installation fails when installation in one of the packages fail
let err!: PnpmError
try {
await recursive.handler(['install'], {
await install.handler([], {
...DEFAULT_OPTS,
...await readWsPkgs(process.cwd(), []),
dir: process.cwd(),
})
recursive: true,
workspaceDir: process.cwd(),
}, 'install')
} catch (_err) {
err = _err
}
t.equal(err.code, 'ERR_PNPM_RECURSIVE_FAIL')
t.equal(err.code, 'ERR_PNPM_REGISTRY_META_RESPONSE_404')
t.end()
})
@@ -233,12 +248,14 @@ test('second run of `recursive install` after package.json has been edited manua
])
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
await install.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
})
workspaceDir: process.cwd(),
}, 'install')
await writeJsonFile('is-negative/package.json', {
name: 'is-negative',
@@ -249,12 +266,14 @@ test('second run of `recursive install` after package.json has been edited manua
},
})
await recursive.handler(['install'], {
await install.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
})
workspaceDir: process.cwd(),
}, 'install')
t.ok(projects['is-negative'].requireModule('is-positive/package.json'))
t.end()
@@ -296,13 +315,15 @@ test('recursive --filter ignore excluded packages', async (t) => {
],
})
await recursive.handler(['install'], {
await install.handler([], {
...DEFAULT_OPTS,
...await readWsPkgs(process.cwd(), [
{ includeDependencies: true, namePattern: 'project-1' },
]),
dir: process.cwd(),
})
recursive: true,
workspaceDir: process.cwd(),
}, 'install')
projects['project-1'].hasNot('is-positive')
projects['project-2'].hasNot('is-negative')
@@ -339,14 +360,16 @@ test('recursive filter multiple times', async (t) => {
},
])
await recursive.handler(['install'], {
await install.handler([], {
...DEFAULT_OPTS,
...await readWsPkgs(process.cwd(), [
{ namePattern: 'project-1' },
{ namePattern: 'project-2' },
]),
dir: process.cwd(),
})
recursive: true,
workspaceDir: process.cwd(),
}, 'install')
projects['project-1'].has('is-positive')
projects['project-2'].has('is-negative')
@@ -376,12 +399,14 @@ test('recursive install --no-bail', async (t) => {
let err!: PnpmError
try {
await recursive.handler(['install'], {
await install.handler([], {
...DEFAULT_OPTS,
...await readWsPkgs(process.cwd(), []),
bail: false,
dir: process.cwd(),
})
recursive: true,
workspaceDir: process.cwd(),
}, 'install')
} catch (_err) {
err = _err
}
@@ -408,12 +433,13 @@ test('installing with "workspace=true" should work even if link-workspace-packag
},
])
await recursive.handler(['update', 'project-2'], {
await update.handler(['project-2'], {
...DEFAULT_OPTS,
...await readWsPkgs(process.cwd(), []),
dir: process.cwd(),
linkWorkspacePackages: false,
lockfileDir: process.cwd(),
recursive: true,
saveWorkspaceProtocol: false,
sharedWorkspaceLockfile: true,
workspace: true,

View File

@@ -1,10 +1,11 @@
import { readWsPkgs } from '@pnpm/filter-workspace-packages'
import { Lockfile } from '@pnpm/lockfile-types'
import { recursive } from '@pnpm/plugin-commands-recursive'
import { install, update } from '@pnpm/plugin-commands-installation'
import { preparePackages } from '@pnpm/prepare'
import { addDistTag } from '@pnpm/registry-mock'
import readYamlFile from 'read-yaml-file'
import test = require('tape')
import { DEFAULT_OPTS, readWsPkgs } from './utils'
import { DEFAULT_OPTS } from './utils'
test('recursive update', async (t) => {
const projects = preparePackages(t, [
@@ -27,18 +28,22 @@ test('recursive update', async (t) => {
])
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
await install.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
})
workspaceDir: process.cwd(),
}, 'install')
await recursive.handler(['update', 'is-positive@2.0.0'], {
await update.handler(['is-positive@2.0.0'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
workspaceDir: process.cwd(),
})
t.equal(projects['project-1'].requireModule('is-positive/package.json').version, '2.0.0')
@@ -75,24 +80,28 @@ test('recursive update --latest foo should only update workspace packages that h
const lockfileDir = process.cwd()
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
await install.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
lockfileDir,
recursive: true,
selectedWsPkgsGraph,
})
workspaceDir: process.cwd(),
}, 'install')
await addDistTag({ package: 'foo', version: '100.1.0', distTag: 'latest' })
await addDistTag({ package: 'bar', version: '100.1.0', distTag: 'latest' })
await recursive.handler(['update', '@zkochan/async-regex-replace', 'foo', 'qar@100.1.0'], {
await update.handler(['@zkochan/async-regex-replace', 'foo', 'qar@100.1.0'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
latest: true,
lockfileDir,
recursive: true,
selectedWsPkgsGraph,
workspaceDir: process.cwd(),
})
const lockfile = await readYamlFile<Lockfile>('./pnpm-lock.yaml')
@@ -127,22 +136,26 @@ test('recursive update --latest foo should only update packages that have foo',
])
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
await install.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
})
workspaceDir: process.cwd(),
}, 'install')
await addDistTag({ package: 'foo', version: '100.1.0', distTag: 'latest' })
await addDistTag({ package: 'bar', version: '100.1.0', distTag: 'latest' })
await recursive.handler(['update', 'foo', 'qar@100.1.0'], {
await update.handler(['foo', 'qar@100.1.0'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
latest: true,
recursive: true,
selectedWsPkgsGraph,
workspaceDir: process.cwd(),
})
{
@@ -171,10 +184,12 @@ test('recursive update in workspace should not add new dependencies', async (t)
},
])
await recursive.handler(['update', 'is-positive'], {
await update.handler(['is-positive'], {
...DEFAULT_OPTS,
...await readWsPkgs(process.cwd(), []),
dir: process.cwd(),
recursive: true,
workspaceDir: process.cwd(),
})
projects['project-1'].hasNot('is-positive')
@@ -194,10 +209,12 @@ test('recursive update should not add new dependencies', async (t) => {
},
])
await recursive.handler(['update', 'is-positive'], {
await update.handler(['is-positive'], {
...DEFAULT_OPTS,
...await readWsPkgs(process.cwd(), []),
dir: process.cwd(),
recursive: true,
workspaceDir: process.cwd(),
})
projects['project-1'].hasNot('is-positive')

View File

@@ -2,7 +2,7 @@ import PnpmError from '@pnpm/error'
import {
createWorkspaceSpecs,
updateToWorkspacePackagesFromManifest,
} from '@pnpm/plugin-commands-recursive/lib/updateWorkspaceDependencies'
} from '@pnpm/plugin-commands-installation/lib/updateWorkspaceDependencies'
import test = require('tape')
const INCLUDE_ALL = {

View File

@@ -0,0 +1,46 @@
import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
const REGISTRY = `http://localhost:${REGISTRY_MOCK_PORT}`
export const DEFAULT_OPTS = {
alwaysAuth: false,
argv: {
original: [],
},
bail: true,
ca: undefined,
cert: undefined,
cliOptions: {},
fetchRetries: 2,
fetchRetryFactor: 90,
fetchRetryMaxtimeout: 90,
fetchRetryMintimeout: 10,
filter: [] as string[],
httpsProxy: undefined,
include: {
dependencies: true,
devDependencies: true,
optionalDependencies: true,
},
key: undefined,
linkWorkspacePackages: true,
localAddress: undefined,
lock: false,
lockStaleDuration: 90,
networkConcurrency: 16,
offline: false,
pending: false,
pnpmfile: './pnpmfile.js',
proxy: undefined,
rawConfig: { registry: REGISTRY },
rawLocalConfig: {},
registries: { default: REGISTRY },
registry: REGISTRY,
sort: true,
storeDir: '../store',
strictSsl: false,
userAgent: 'pnpm',
useRunningStoreServer: false,
useStoreServer: false,
workspaceConcurrency: 4,
}

View File

@@ -16,15 +16,13 @@
"registry-mock": "registry-mock",
"test:tap": "ts-node test --type-check",
"pretest:e2e": "registry-mock prepare",
"test:e2e": "cross-env PNPM_REGISTRY_MOCK_PORT=7775 run-p -r registry-mock test:tap",
"test": "pnpm run tsc && pnpm run lint && pnpm run test:e2e",
"test:e2e": "run-p -r registry-mock test:tap",
"test": "pnpm run tsc && pnpm run lint && cross-env PNPM_REGISTRY_MOCK_PORT=7773 pnpm run test:e2e",
"prepublishOnly": "pnpm run tsc"
},
"repository": "https://github.com/pnpm/pnpm/blob/master/packages/plugin-commands-listing",
"keywords": [
"pnpm",
"pack",
"publish"
"pnpm"
],
"author": "Zoltan Kochan <z@kochan.io> (https://www.kochan.io/)",
"license": "MIT",
@@ -34,6 +32,9 @@
"homepage": "https://pnpm.js.org",
"devDependencies": {
"@pnpm/constants": "workspace:3.0.0",
"@pnpm/filter-workspace-packages": "workspace:1.0.1",
"@pnpm/logger": "^3.1.0",
"@pnpm/plugin-commands-installation": "workspace:*",
"@pnpm/plugin-commands-listing": "link:",
"@pnpm/prepare": "workspace:0.0.0",
"@types/common-tags": "1.8.0",
@@ -54,5 +55,8 @@
"common-tags": "1.8.0",
"ramda": "0.26.1",
"render-help": "0.0.0"
},
"peerDependencies": {
"@pnpm/logger": "^3.1.0"
}
}

View File

@@ -6,6 +6,7 @@ import list, { forPackages as listForPackages } from '@pnpm/list'
import { oneLine } from 'common-tags'
import R = require('ramda')
import renderHelp = require('render-help')
import listRecursive from './recursive'
export const rcOptionsTypes = cliOptionsTypes
@@ -97,15 +98,20 @@ export function help () {
export function handler (
args: string[],
opts: Pick<Config, 'dir' | 'include'> & {
opts: Pick<Config, 'allWsPkgs' | 'dir' | 'include' | 'selectedWsPkgsGraph'> & {
alwaysPrintRootPackage?: boolean,
depth?: number,
lockfileDir?: string,
long?: boolean,
parseable?: boolean,
recursive?: boolean,
},
command: string,
) {
if (opts.recursive && opts.selectedWsPkgsGraph) {
const pkgs = Object.values(opts.selectedWsPkgsGraph).map((wsPkg) => wsPkg.package)
return listRecursive(pkgs, args, command, opts)
}
return render([opts.dir], args, {
...opts,
lockfileDir: opts.lockfileDir || opts.dir,

View File

@@ -1,13 +1,12 @@
import { Config } from '@pnpm/config'
import { Config, WsPkg } from '@pnpm/config'
import logger from '@pnpm/logger'
import { list } from '@pnpm/plugin-commands-listing'
import { ImporterManifest } from '@pnpm/types'
import { render } from './list'
export default async (
pkgs: Array<{ dir: string, manifest: ImporterManifest }>,
pkgs: WsPkg[],
args: string[],
cmd: string,
opts: Config & {
opts: Pick<Config, 'lockfileDir' | 'include'> & {
depth?: number,
long?: boolean,
parseable?: boolean,
@@ -16,7 +15,7 @@ export default async (
) => {
const depth = opts.depth ?? 0
if (opts.lockfileDir) {
return list.render(pkgs.map((pkg) => pkg.dir), args, {
return render(pkgs.map((pkg) => pkg.dir), args, {
...opts,
alwaysPrintRootPackage: depth === -1,
lockfileDir: opts.lockfileDir,
@@ -25,7 +24,7 @@ export default async (
const outputs = []
for (const { dir } of pkgs) {
try {
const output = await list.render([dir], args, {
const output = await render([dir], args, {
...opts,
alwaysPrintRootPackage: depth === -1,
lockfileDir: opts.lockfileDir || dir,

View File

@@ -10,6 +10,7 @@ import path = require('path')
import stripAnsi = require('strip-ansi')
import test = require('tape')
import writeYamlFile = require('write-yaml-file')
import './recursive'
test('listing packages', async (t) => {
prepare(t, {

View File

@@ -1,5 +1,7 @@
import PnpmError from '@pnpm/error'
import { recursive } from '@pnpm/plugin-commands-recursive'
import { readWsPkgs } from '@pnpm/filter-workspace-packages'
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 { stripIndent } from 'common-tags'
@@ -8,7 +10,7 @@ import path = require('path')
import stripAnsi = require('strip-ansi')
import test = require('tape')
import writeYamlFile = require('write-yaml-file')
import { DEFAULT_OPTS, readWsPkgs } from './utils'
import { DEFAULT_OPTS } from './utils'
test('recursive list', async (t) => {
const projects = preparePackages(t, [
@@ -35,19 +37,22 @@ test('recursive list', async (t) => {
])
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
await install.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
})
workspaceDir: process.cwd(),
}, 'install')
const output = await recursive.handler(['list'], {
const output = await list.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
})
}, 'list')
t.equal(stripAnsi(output as unknown as string), stripIndent`
Legend: production dependency, optional only, dev only
@@ -97,20 +102,23 @@ test('recursive list with shared-workspace-lockfile', async (t) => {
await fs.writeFile('.npmrc', 'shared-workspace-lockfile = true', 'utf8')
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
await install.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
})
workspaceDir: process.cwd(),
}, 'install')
const output = await recursive.handler(['list'], {
const output = await list.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
depth: 2,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
})
}, 'list')
t.equal(stripAnsi(output as unknown as string), stripIndent`
Legend: production dependency, optional only, dev only
@@ -161,19 +169,22 @@ test('recursive list --filter', async (t) => {
},
])
await recursive.handler(['install'], {
await install.handler([], {
...DEFAULT_OPTS,
...await readWsPkgs(process.cwd(), []),
dir: process.cwd(),
})
recursive: true,
workspaceDir: process.cwd(),
}, 'install')
const output = await recursive.handler(['list'], {
const output = await list.handler([], {
...DEFAULT_OPTS,
dir: process.cwd(),
recursive: true,
...await readWsPkgs(process.cwd(), [
{ includeDependencies: true, namePattern: 'project-1' },
]),
})
}, 'list')
t.equal(stripAnsi(output as unknown as string), stripIndent`
Legend: production dependency, optional only, dev only
@@ -199,11 +210,12 @@ test('`pnpm recursive why` should fail if no package name was provided', async (
let err!: PnpmError
try {
const output = await recursive.handler(['why'], {
await why.handler([], {
...DEFAULT_OPTS,
...await readWsPkgs(process.cwd(), []),
dir: process.cwd(),
})
recursive: true,
}, 'why')
} catch (_err) {
err = _err
}

View File

@@ -1,5 +1,3 @@
import { filterPkgsBySelectorObjects, PackageSelector } from '@pnpm/filter-workspace-packages'
import findWorkspacePackages from '@pnpm/find-workspace-packages'
import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
const REGISTRY = `http://localhost:${REGISTRY_MOCK_PORT}`
@@ -46,18 +44,3 @@ export const DEFAULT_OPTS = {
useStoreServer: false,
workspaceConcurrency: 4,
}
export async function readWsPkgs (
workspaceDir: string,
pkgSelectors: PackageSelector[],
) {
const allWsPkgs = await findWorkspacePackages(workspaceDir, {})
const selectedWsPkgsGraph = await filterPkgsBySelectorObjects(
allWsPkgs,
pkgSelectors,
{
workspaceDir,
},
)
return { allWsPkgs, selectedWsPkgsGraph }
}

View File

@@ -33,6 +33,8 @@
"homepage": "https://pnpm.js.org",
"devDependencies": {
"@pnpm/constants": "workspace:3.0.0",
"@pnpm/filter-workspace-packages": "workspace:1.0.1",
"@pnpm/plugin-commands-installation": "workspace:*",
"@pnpm/plugin-commands-outdated": "link:",
"@pnpm/prepare": "workspace:0.0.0",
"@pnpm/types": "workspace:4.0.0",

View File

@@ -1,6 +1,6 @@
import { createLatestManifestGetter, docsUrl, readImporterManifestOnly, TABLE_OPTIONS } from '@pnpm/cli-utils'
import { FILTERING, OPTIONS, UNIVERSAL_OPTIONS } from '@pnpm/common-cli-options-help'
import { types as allTypes } from '@pnpm/config'
import { Config, types as allTypes } from '@pnpm/config'
import PnpmError from '@pnpm/error'
import {
getLockfileImporterId,
@@ -10,7 +10,7 @@ import {
import matcher from '@pnpm/matcher'
import { read as readModulesManifest } from '@pnpm/modules-yaml'
import outdated, { OutdatedPackage } from '@pnpm/outdated'
import semverDiff, { SEMVER_CHANGE } from '@pnpm/semver-diff'
import semverDiff from '@pnpm/semver-diff'
import storePath from '@pnpm/store-path'
import { ImporterManifest, Registries } from '@pnpm/types'
import chalk = require('chalk')
@@ -21,6 +21,11 @@ import renderHelp = require('render-help')
import stripAnsi = require('strip-ansi')
import { table } from 'table'
import wrapAnsi = require('wrap-ansi')
import outdatedRecursive from './recursive'
import {
DEFAULT_COMPARATORS,
OutdatedWithVersionDiff,
} from './utils'
export const rcOptionsTypes = cliOptionsTypes
@@ -82,17 +87,7 @@ export function help () {
})
}
export type OutdatedWithVersionDiff = OutdatedPackage & { change: SEMVER_CHANGE | null, diff?: [string[], string[]] }
/**
* Default comparators used as the argument to `ramda.sortWith()`.
*/
export const DEFAULT_COMPARATORS = [
sortBySemverChange,
(o1: OutdatedWithVersionDiff, o2: OutdatedWithVersionDiff) => o1.packageName.localeCompare(o2.packageName),
]
export interface OutdatedOptions {
export type OutdatedOptions = {
alwaysAuth: boolean
ca?: string
cert?: string
@@ -112,6 +107,7 @@ export interface OutdatedOptions {
dir: string
proxy?: string
rawConfig: object
recursive?: boolean,
registries: Registries
lockfileDir?: string
store?: string
@@ -119,13 +115,17 @@ export interface OutdatedOptions {
table?: boolean
tag: string
userAgent: string
}
} & Pick<Config, 'allWsPkgs' | 'selectedWsPkgsGraph'>
export async function handler (
args: string[],
opts: OutdatedOptions,
command: string,
command?: string,
) {
if (opts.recursive && opts.selectedWsPkgsGraph) {
const pkgs = Object.values(opts.selectedWsPkgsGraph).map((wsPkg) => wsPkg.package)
return outdatedRecursive(pkgs, args, opts)
}
const packages = [
{
dir: opts.dir,
@@ -274,20 +274,6 @@ function joinVersionTuples (versionTuples: string[], startIndex: number) {
}`
}
export function sortBySemverChange (outdated1: OutdatedWithVersionDiff, outdated2: OutdatedWithVersionDiff) {
return pkgPriority(outdated1) - pkgPriority(outdated2)
}
function pkgPriority (pkg: OutdatedWithVersionDiff) {
switch (pkg.change) {
case null: return 0
case 'fix': return 1
case 'feature': return 2
case 'breaking': return 3
default: return 4
}
}
export function renderDetails ({ latestManifest }: OutdatedPackage) {
if (!latestManifest) return ''
const outputs = []

View File

@@ -1,8 +1,12 @@
import { TABLE_OPTIONS } from '@pnpm/cli-utils'
import { getLockfileImporterId } from '@pnpm/lockfile-file'
import { OutdatedPackage } from '@pnpm/outdated'
import { DependenciesField, ImporterManifest } from '@pnpm/types'
import chalk = require('chalk')
import { stripIndent } from 'common-tags'
import R = require('ramda')
import { table } from 'table'
import {
DEFAULT_COMPARATORS,
getCellWidth,
outdatedDependenciesOfWorkspacePackages,
OutdatedOptions,
@@ -11,12 +15,8 @@ import {
renderLatest,
renderPackageName,
toOutdatedWithVersionDiff,
} from '@pnpm/plugin-commands-outdated/lib/outdated'
import { DependenciesField, ImporterManifest } from '@pnpm/types'
import chalk = require('chalk')
import { stripIndent } from 'common-tags'
import R = require('ramda')
import { table } from 'table'
} from './outdated'
import { DEFAULT_COMPARATORS } from './utils'
const DEP_PRIORITY: Record<DependenciesField, number> = {
dependencies: 1,
@@ -26,7 +26,8 @@ const DEP_PRIORITY: Record<DependenciesField, number> = {
const COMPARATORS = [
...DEFAULT_COMPARATORS,
(o1: OutdatedInWorkspace, o2: OutdatedInWorkspace) => DEP_PRIORITY[o1.belongsTo] - DEP_PRIORITY[o2.belongsTo],
(o1: OutdatedInWorkspace, o2: OutdatedInWorkspace) =>
DEP_PRIORITY[o1.belongsTo] - DEP_PRIORITY[o2.belongsTo],
]
interface OutdatedInWorkspace extends OutdatedPackage {
@@ -41,7 +42,6 @@ interface OutdatedInWorkspace extends OutdatedPackage {
export default async (
pkgs: Array<{ dir: string, manifest: ImporterManifest }>,
args: string[],
cmd: string,
opts: OutdatedOptions,
) => {
const outdatedByNameAndType = {} as Record<string, OutdatedInWorkspace>

View File

@@ -0,0 +1,27 @@
import { OutdatedPackage } from '@pnpm/outdated'
import { SEMVER_CHANGE } from '@pnpm/semver-diff'
export type OutdatedWithVersionDiff = OutdatedPackage & { change: SEMVER_CHANGE | null, diff?: [string[], string[]] }
/**
* Default comparators used as the argument to `ramda.sortWith()`.
*/
export const DEFAULT_COMPARATORS = [
sortBySemverChange,
(o1: OutdatedWithVersionDiff, o2: OutdatedWithVersionDiff) =>
o1.packageName.localeCompare(o2.packageName),
]
export function sortBySemverChange (outdated1: OutdatedWithVersionDiff, outdated2: OutdatedWithVersionDiff) {
return pkgPriority(outdated1) - pkgPriority(outdated2)
}
function pkgPriority (pkg: OutdatedWithVersionDiff) {
switch (pkg.change) {
case null: return 0
case 'fix': return 1
case 'feature': return 2
case 'breaking': return 3
default: return 4
}
}

View File

@@ -11,6 +11,7 @@ import path = require('path')
import stripAnsi = require('strip-ansi')
import test = require('tape')
import { promisify } from 'util'
import './recursive'
const copyFile = promisify(fs.copyFile)
const fixtures = path.join(__dirname, '../../../fixtures')

View File

@@ -1,10 +1,11 @@
import { recursive } from '@pnpm/plugin-commands-recursive'
import { readWsPkgs } from '@pnpm/filter-workspace-packages'
import { install } from '@pnpm/plugin-commands-installation'
import { outdated } from '@pnpm/plugin-commands-outdated'
import { preparePackages } from '@pnpm/prepare'
import { stripIndent } from 'common-tags'
import stripAnsi = require('strip-ansi')
import test = require('tape')
import writeYamlFile = require('write-yaml-file')
import { DEFAULT_OPTS, readWsPkgs } from './utils'
import { DEFAULT_OPTS } from './utils'
test('pnpm recursive outdated', async (t) => {
preparePackages(t, [
@@ -38,18 +39,21 @@ test('pnpm recursive outdated', async (t) => {
])
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
await install.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
})
workspaceDir: process.cwd(),
}, 'install')
{
const output = await recursive.handler(['outdated'], {
const output = await outdated.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
})
@@ -67,11 +71,12 @@ test('pnpm recursive outdated', async (t) => {
}
{
const output = await recursive.handler(['outdated'], {
const output = await outdated.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
long: true,
recursive: true,
selectedWsPkgsGraph,
})
@@ -89,10 +94,11 @@ test('pnpm recursive outdated', async (t) => {
}
{
const output = await recursive.handler(['outdated'], {
const output = await outdated.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
table: false,
})
@@ -113,11 +119,12 @@ test('pnpm recursive outdated', async (t) => {
}
{
const output = await recursive.handler(['outdated'], {
const output = await outdated.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
long: true,
recursive: true,
selectedWsPkgsGraph,
table: false,
})
@@ -141,10 +148,11 @@ test('pnpm recursive outdated', async (t) => {
}
{
const output = await recursive.handler(['outdated', 'is-positive'], {
const output = await outdated.handler(['is-positive'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
})
@@ -190,21 +198,22 @@ test('pnpm recursive outdated in workspace with shared lockfile', async (t) => {
},
])
await writeYamlFile('pnpm-workspace.yaml', { packages: ['**', '!store/**'] })
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
await install.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
})
workspaceDir: process.cwd(),
}, 'install')
{
const output = await recursive.handler(['outdated'], {
const output = await outdated.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
})
@@ -222,10 +231,11 @@ test('pnpm recursive outdated in workspace with shared lockfile', async (t) => {
}
{
const output = await recursive.handler(['outdated', 'is-positive'], {
const output = await outdated.handler(['is-positive'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
})

View File

@@ -0,0 +1,49 @@
import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
const REGISTRY = `http://localhost:${REGISTRY_MOCK_PORT}`
export const DEFAULT_OPTS = {
alwaysAuth: false,
argv: {
original: [],
},
bail: false,
ca: undefined,
cert: undefined,
cliOptions: {},
fetchRetries: 2,
fetchRetryFactor: 90,
fetchRetryMaxtimeout: 90,
fetchRetryMintimeout: 10,
filter: [] as string[],
global: false,
httpsProxy: undefined,
include: {
dependencies: true,
devDependencies: true,
optionalDependencies: true,
},
independentLeaves: false,
key: undefined,
linkWorkspacePackages: true,
localAddress: undefined,
lock: false,
lockStaleDuration: 90,
networkConcurrency: 16,
offline: false,
pending: false,
pnpmfile: './pnpmfile.js',
proxy: undefined,
rawConfig: { registry: REGISTRY },
rawLocalConfig: {},
registries: { default: REGISTRY },
registry: REGISTRY,
sort: true,
storeDir: '../store',
strictSsl: false,
tag: 'latest',
userAgent: 'pnpm',
useRunningStoreServer: false,
useStoreServer: false,
workspaceConcurrency: 4,
}

View File

@@ -17,7 +17,7 @@
"test:tap": "ts-node test --type-check",
"pretest:e2e": "registry-mock prepare",
"test:e2e": "run-p -r registry-mock test:tap",
"test": "pnpm run tsc && pnpm run lint && cross-env PNPM_REGISTRY_MOCK_PORT=7775 pnpm run test:e2e",
"test": "pnpm run tsc && pnpm run lint && cross-env PNPM_REGISTRY_MOCK_PORT=7771 pnpm run test:e2e",
"prepublishOnly": "pnpm run tsc"
},
"repository": "https://github.com/pnpm/pnpm/blob/master/packages/plugin-commands-publishing",
@@ -33,12 +33,15 @@
},
"homepage": "https://pnpm.js.org",
"devDependencies": {
"@pnpm/filter-workspace-packages": "workspace:1.0.1",
"@pnpm/plugin-commands-publishing": "link:",
"@pnpm/prepare": "workspace:0.0.0",
"@types/cross-spawn": "^6.0.1",
"@types/lru-cache": "^5.1.0",
"@types/mz": "^2.7.0",
"@types/ramda": "^0.26.38",
"cross-spawn": "7.0.1",
"execa": "4.0.0",
"path-exists": "4.0.0",
"rimraf": "3.0.0",
"write-yaml-file": "3.0.1"
@@ -47,13 +50,19 @@
"@pnpm/cli-utils": "workspace:0.2.5",
"@pnpm/config": "workspace:6.0.0",
"@pnpm/error": "workspace:1.0.0",
"@pnpm/npm-resolver": "workspace:6.0.2",
"@pnpm/read-importer-manifest": "workspace:2.0.1",
"@pnpm/resolver-base": "workspace:6.0.0",
"@pnpm/run-npm": "workspace:1.0.0",
"@pnpm/store-path": "2.1.1",
"@pnpm/types": "workspace:4.0.0",
"@pnpm/utils": "workspace:0.12.2",
"@zkochan/rimraf": "1.0.0",
"cp-file": "7.0.0",
"fast-glob": "3.1.1",
"lru-cache": "5.1.1",
"mz": "2.7.0",
"p-filter": "2.1.0",
"ramda": "0.26.1",
"render-help": "0.0.0",
"write-json-file": "4.2.1"

View File

@@ -1,5 +1,5 @@
import { docsUrl, readImporterManifest } from '@pnpm/cli-utils'
import { types as allTypes } from '@pnpm/config'
import { Config, types as allTypes } from '@pnpm/config'
import PnpmError from '@pnpm/error'
import { tryReadImporterManifest } from '@pnpm/read-importer-manifest'
import runNpm from '@pnpm/run-npm'
@@ -12,6 +12,7 @@ import path = require('path')
import R = require('ramda')
import renderHelp = require('render-help')
import writeJsonFile = require('write-json-file')
import recursivePublish, { PublishRecursiveOpts } from './recursivePublish'
export const rcOptionsTypes = cliOptionsTypes
@@ -35,15 +36,24 @@ export function help () {
export async function handler (
args: string[],
opts: {
opts: Omit<PublishRecursiveOpts, 'workspaceDir'> & {
argv: {
original: string[],
},
engineStrict?: boolean,
recursive?: boolean,
workspaceDir?: string,
},
command: string,
} & Pick<Config, 'allWsPkgs' | 'selectedWsPkgsGraph'>,
command?: string,
) {
if (opts.recursive && opts.selectedWsPkgsGraph) {
const pkgs = Object.values(opts.selectedWsPkgsGraph).map((wsPkg) => wsPkg.package)
await recursivePublish(pkgs, {
...opts,
workspaceDir: opts.workspaceDir ?? process.cwd(),
})
return
}
if (args.length && args[0].endsWith('.tgz')) {
await runNpm(['publish', ...args])
return

View File

@@ -1,43 +1,49 @@
import { Config } from '@pnpm/config'
import { Config, WsPkg } from '@pnpm/config'
import createResolver from '@pnpm/npm-resolver'
import { publish } from '@pnpm/plugin-commands-publishing'
import { ResolveFunction } from '@pnpm/resolver-base'
import runNpm from '@pnpm/run-npm'
import storePath from '@pnpm/store-path'
import { ImporterManifest, Registries } from '@pnpm/types'
import { Registries } from '@pnpm/types'
import { pickRegistryForPackage } from '@pnpm/utils'
import LRU = require('lru-cache')
import pFilter = require('p-filter')
import { handler as publish } from './publish'
export type PublishRecursiveOpts = Required<Pick<Config,
'cliOptions' |
'dir' |
'rawConfig' |
'registries' |
'workspaceDir'
>> &
Partial<Pick<Config,
'tag' |
'ca' |
'cert' |
'fetchRetries' |
'fetchRetryFactor' |
'fetchRetryMaxtimeout' |
'fetchRetryMintimeout' |
'httpsProxy' |
'key' |
'localAddress' |
'lockfileDir' |
'offline' |
'proxy' |
'storeDir' |
'strictSsl' |
'userAgent' |
'verifyStoreIntegrity'
>> & {
access?: 'public' | 'restricted',
argv: {
original: string[],
},
}
export default async function (
pkgs: Array<{ dir: string, manifest: ImporterManifest }>,
opts: Pick<Config, 'cliOptions'> & {
access?: 'public' | 'restricted',
argv: {
original: string[],
},
tag?: string,
ca?: string,
cert?: string,
fetchRetries?: number,
fetchRetryFactor?: number,
fetchRetryMaxtimeout?: number,
fetchRetryMintimeout?: number,
httpsProxy?: string,
key?: string,
localAddress?: string,
lockfileDir?: string,
offline?: boolean,
dir: string,
proxy?: string,
rawConfig: object,
registries: Registries,
storeDir?: string,
strictSsl?: boolean,
userAgent?: string,
verifyStoreIntegrity?: boolean,
workspaceDir: string,
},
pkgs: WsPkg[],
opts: PublishRecursiveOpts,
) {
const storeDir = await storePath(opts.workspaceDir, opts.storeDir)
const resolve = createResolver(Object.assign(opts, {
@@ -59,7 +65,8 @@ export default async function (
})
const access = opts.cliOptions['access'] ? ['--access', opts.cliOptions['access']] : []
for (const pkg of pkgsToPublish) {
await publish.handler([pkg.dir], {
await publish([pkg.dir], {
...opts,
argv: {
original: [
'publish',
@@ -71,7 +78,7 @@ export default async function (
...access,
],
},
workspaceDir: opts.workspaceDir,
recursive: false,
}, 'publish')
}
const tag = opts.tag || 'latest'

View File

@@ -1,3 +1,4 @@
///<reference path="../../../typings/index.d.ts" />
import './pack'
import './publish'
import './recursivePublish'

View File

@@ -8,6 +8,7 @@ import path = require('path')
import exists = require('path-exists')
import test = require('tape')
import writeYamlFile = require('write-yaml-file')
import { DEFAULT_OPTS } from './utils'
const CREDENTIALS = [
`--registry=http://localhost:${REGISTRY_MOCK_PORT}/`,
@@ -22,7 +23,11 @@ test('publish: package with package.json', async (t) => {
version: '0.0.0',
})
await publish.handler([], { argv: { original: ['publish', ...CREDENTIALS] } }, 'publish')
await publish.handler([], {
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
dir: process.cwd(),
}, 'publish')
t.end()
})
@@ -32,7 +37,11 @@ test('publish: package with package.yaml', async (t) => {
version: '0.0.0',
}, { manifestFormat: 'YAML' })
await publish.handler([], { argv: { original: ['publish', ...CREDENTIALS] } }, 'publish')
await publish.handler([], {
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
dir: process.cwd(),
}, 'publish')
t.ok(await exists('package.yaml'))
t.notOk(await exists('package.json'))
@@ -45,7 +54,11 @@ test('publish: package with package.json5', async (t) => {
version: '0.0.0',
}, { manifestFormat: 'JSON5' })
await publish.handler([], { argv: { original: ['publish', ...CREDENTIALS] } }, 'publish')
await publish.handler([], {
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
dir: process.cwd(),
}, 'publish')
t.ok(await exists('package.json5'))
t.notOk(await exists('package.json'))
@@ -60,7 +73,11 @@ test('publish: package with package.json5 running publish from different folder'
process.chdir('..')
await publish.handler(['project'], { argv: { original: ['publish', ...CREDENTIALS, 'project'] } }, 'publish')
await publish.handler(['project'], {
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS, 'project'] },
dir: process.cwd(),
}, 'publish')
t.ok(await exists('project/package.json5'))
t.notOk(await exists('project/package.json'))
@@ -129,10 +146,20 @@ test('publish packages with workspace LICENSE if no own LICENSE is present', asy
await fs.writeFile('project-200/LICENSE', 'project-200 license', 'utf8')
process.chdir('project-100')
await publish.handler([], { argv: { original: ['publish', ...CREDENTIALS] }, workspaceDir }, 'publish')
await publish.handler([], {
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
dir: process.cwd(),
workspaceDir,
}, 'publish')
process.chdir('../project-200')
await publish.handler([], { argv: { original: ['publish', ...CREDENTIALS] }, workspaceDir }, 'publish')
await publish.handler([], {
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
dir: process.cwd(),
workspaceDir,
}, 'publish')
process.chdir('../target')
@@ -181,7 +208,11 @@ test('publish: package with all possible fields in publishConfig', async (t) =>
process.chdir('test-publish-config')
await fs.writeFile('published-bin.js', `#!/usr/bin/env node`, 'utf8')
await publish.handler([], { argv: { original: ['publish', ...CREDENTIALS] } }, 'publish')
await publish.handler([], {
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
dir: process.cwd(),
}, 'publish')
const originalManifests = await import(path.resolve('package.json'))
t.deepEqual(originalManifests, {
@@ -286,7 +317,12 @@ test.skip('publish package that calls executable from the workspace .bin folder
await writeYamlFile('pnpm-workspace.yaml', { packages: ['**', '!store/**'] })
process.chdir('test-publish-scripts')
await publish.handler([], { argv: { original: ['publish', ...CREDENTIALS] }, workspaceDir }, 'publish')
await publish.handler([], {
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
dir: process.cwd(),
workspaceDir,
}, 'publish')
t.deepEqual(
await import(path.resolve('output.json')),
@@ -353,7 +389,11 @@ test('convert specs with workspace protocols to regular version ranges', async (
let err!: PnpmError
try {
await publish.handler([], { argv: { original: ['publish', ...CREDENTIALS] } }, 'publish')
await publish.handler([], {
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
dir: process.cwd(),
}, 'publish')
} catch (_err) {
err = _err
}
@@ -368,7 +408,11 @@ test('convert specs with workspace protocols to regular version ranges', async (
crossSpawn.sync('pnpm', ['multi', 'install', '--store-dir=store', `--registry=http://localhost:${REGISTRY_MOCK_PORT}`])
process.chdir('workspace-protocol-package')
await publish.handler([], { argv: { original: ['publish', ...CREDENTIALS] } }, 'publish')
await publish.handler([], {
...DEFAULT_OPTS,
argv: { original: ['publish', ...CREDENTIALS] },
dir: process.cwd(),
}, 'publish')
process.chdir('../target')

View File

@@ -1,10 +1,11 @@
import { recursive } from '@pnpm/plugin-commands-recursive'
import { readWsPkgs } from '@pnpm/filter-workspace-packages'
import { publish } from '@pnpm/plugin-commands-publishing'
import { preparePackages } from '@pnpm/prepare'
import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
import execa = require('execa')
import fs = require('mz/fs')
import test = require('tape')
import { DEFAULT_OPTS, readWsPkgs } from './utils'
import { DEFAULT_OPTS } from './utils'
const CREDENTIALS = [
`--registry=http://localhost:${REGISTRY_MOCK_PORT}/`,
@@ -65,10 +66,11 @@ test('recursive publish', async (t) => {
await fs.writeFile('.npmrc', CREDENTIALS, 'utf8')
await recursive.handler(['publish'], {
await publish.handler([], {
...DEFAULT_OPTS,
...await readWsPkgs(process.cwd(), []),
dir: process.cwd(),
recursive: true,
})
{
@@ -82,10 +84,11 @@ test('recursive publish', async (t) => {
await projects[pkg1.name].writePackageJson({ ...pkg1, version: '2.0.0' })
await recursive.handler(['publish'], {
await publish.handler([], {
...DEFAULT_OPTS,
...await readWsPkgs(process.cwd(), []),
dir: process.cwd(),
recursive: true,
tag: 'next',
})

View File

@@ -0,0 +1,46 @@
import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
const REGISTRY = `http://localhost:${REGISTRY_MOCK_PORT}`
export const DEFAULT_OPTS = {
alwaysAuth: false,
argv: {
original: [],
},
bail: false,
ca: undefined,
cert: undefined,
cliOptions: {},
fetchRetries: 2,
fetchRetryFactor: 90,
fetchRetryMaxtimeout: 90,
fetchRetryMintimeout: 10,
filter: [] as string[],
httpsProxy: undefined,
include: {
dependencies: true,
devDependencies: true,
optionalDependencies: true,
},
key: undefined,
linkWorkspacePackages: true,
localAddress: undefined,
lock: false,
lockStaleDuration: 90,
networkConcurrency: 16,
offline: false,
pending: false,
pnpmfile: './pnpmfile.js',
proxy: undefined,
rawConfig: { registry: REGISTRY },
rawLocalConfig: {},
registries: { default: REGISTRY },
registry: REGISTRY,
sort: true,
storeDir: '../store',
strictSsl: false,
userAgent: 'pnpm',
useRunningStoreServer: false,
useStoreServer: false,
workspaceConcurrency: 4,
}

View File

@@ -32,6 +32,7 @@
},
"homepage": "https://pnpm.js.org",
"devDependencies": {
"@pnpm/filter-workspace-packages": "workspace:1.0.1",
"@pnpm/logger": "^3.1.0",
"@pnpm/plugin-commands-rebuild": "link:",
"@pnpm/prepare": "workspace:0.0.0",
@@ -44,7 +45,8 @@
"execa": "4.0.0",
"path-exists": "4.0.0",
"rimraf": "3.0.0",
"sinon": "8.0.0"
"sinon": "8.0.0",
"write-yaml-file": "3.0.1"
},
"dependencies": {
"@pnpm/cli-utils": "workspace:0.2.5",
@@ -52,6 +54,7 @@
"@pnpm/config": "workspace:6.0.0",
"@pnpm/constants": "workspace:3.0.0",
"@pnpm/core-loggers": "workspace:4.0.0",
"@pnpm/find-workspace-packages": "workspace:2.0.8",
"@pnpm/get-context": "workspace:0.0.0",
"@pnpm/lifecycle": "workspace:8.0.1",
"@pnpm/link-bins": "5.0.1",
@@ -59,17 +62,21 @@
"@pnpm/lockfile-walker": "workspace:1.0.1",
"@pnpm/modules-yaml": "workspace:5.0.0",
"@pnpm/pkgid-to-filename": "2.0.0",
"@pnpm/sort-packages": "workspace:0.0.0",
"@pnpm/store-connection-manager": "workspace:0.2.5",
"@pnpm/store-controller-types": "workspace:6.0.0",
"@pnpm/types": "workspace:4.0.0",
"@pnpm/utils": "workspace:0.12.2",
"@zkochan/npm-package-arg": "1.0.2",
"camelcase-keys": "6.1.1",
"common-tags": "1.8.0",
"dependency-path": "workspace:4.0.2",
"graph-sequencer": "2.0.0",
"load-json-file": "6.2.0",
"mem": "6.0.1",
"p-limit": "2.2.1",
"ramda": "0.26.1",
"read-ini-file": "2.0.0",
"render-help": "0.0.0",
"run-groups": "2.0.1",
"semver": "7.1.1"

View File

@@ -34,6 +34,8 @@ import extendOptions, {
StrictRebuildOptions,
} from './extendRebuildOptions'
export { RebuildOptions }
function findPackages (
packages: PackageSnapshots,
searched: PackageSelector[],

View File

@@ -2,7 +2,10 @@ import { docsUrl, readImporterManifestOnly } from '@pnpm/cli-utils'
import { FILTERING, UNIVERSAL_OPTIONS } from '@pnpm/common-cli-options-help'
import { Config, types as allTypes } from '@pnpm/config'
import { LogBase } from '@pnpm/logger'
import { CreateStoreControllerOptions, createOrConnectStoreController } from '@pnpm/store-connection-manager'
import {
createOrConnectStoreController,
CreateStoreControllerOptions,
} from '@pnpm/store-connection-manager'
import { oneLine } from 'common-tags'
import R = require('ramda')
import renderHelp = require('render-help')
@@ -10,6 +13,7 @@ import {
rebuild,
rebuildPkgs,
} from './implementation'
import recursive from './recursive'
export function rcOptionsTypes () {
return {}
@@ -58,10 +62,18 @@ export function help () {
export async function handler (
args: string[],
opts: Pick<Config, 'dir' | 'engineStrict' | 'independentLeaves'> &
opts: Pick<Config, 'allWsPkgs' | 'dir' | 'engineStrict' | 'independentLeaves' | 'rawLocalConfig' | 'registries' | 'selectedWsPkgsGraph' | 'workspaceDir'> &
CreateStoreControllerOptions &
{ reporter?: (logObj: LogBase) => void, pending: boolean },
{
recursive?: boolean,
reporter?: (logObj: LogBase) => void,
pending: boolean,
},
) {
if (opts.recursive && opts.allWsPkgs && opts.selectedWsPkgsGraph && opts.workspaceDir) {
await recursive(opts.allWsPkgs, args, { ...opts, selectedWsPkgsGraph: opts.selectedWsPkgsGraph!, workspaceDir: opts.workspaceDir! })
return
}
const store = await createOrConnectStoreController(opts)
const rebuildOpts = Object.assign(opts, {
storeController: store.ctrl,

View File

@@ -0,0 +1,187 @@
import {
RecursiveSummary,
throwOnCommandFail,
} from '@pnpm/cli-utils'
import { Config, types as allTypes, WsPkg, WsPkgsGraph } from '@pnpm/config'
import { scopeLogger } from '@pnpm/core-loggers'
import { arrayOfWorkspacePackagesToMap } from '@pnpm/find-workspace-packages'
import logger from '@pnpm/logger'
import sortPackages from '@pnpm/sort-packages'
import { createOrConnectStoreController, CreateStoreControllerOptions } from '@pnpm/store-connection-manager'
import { ImporterManifest, PackageManifest } from '@pnpm/types'
import camelcaseKeys = require('camelcase-keys')
import mem = require('mem')
import pLimit from 'p-limit'
import path = require('path')
import readIniFile = require('read-ini-file')
import { rebuild as rebuildAll, RebuildOptions, rebuildPkgs } from './implementation'
type RecursiveRebuildOpts = CreateStoreControllerOptions & Pick<Config,
'hoistPattern' |
'ignorePnpmfile' |
'ignoreScripts' |
'lockfileDir' |
'lockfileOnly' |
'rawLocalConfig' |
'registries' |
'sharedWorkspaceLockfile'
> & {
pending?: boolean,
} & Partial<Pick<Config, 'bail' | 'sort' | 'workspaceConcurrency'>>
export default async function recursive (
allWsPkgs: WsPkg[],
input: string[],
opts: RecursiveRebuildOpts & {
ignoredPackages?: Set<string>,
} & Required<Pick<Config, 'selectedWsPkgsGraph' | 'workspaceDir'>>,
) {
if (allWsPkgs.length === 0) {
// It might make sense to throw an exception in this case
return
}
const pkgs = Object.values(opts.selectedWsPkgsGraph).map((wsPkg) => wsPkg.package)
if (pkgs.length === 0) {
return
}
const manifestsByPath: { [dir: string]: Omit<WsPkg, 'dir'> } = {}
for (const { dir, manifest, writeImporterManifest } of pkgs) {
manifestsByPath[dir] = { manifest, writeImporterManifest }
}
scopeLogger.debug({
selected: pkgs.length,
total: allWsPkgs.length,
workspacePrefix: opts.workspaceDir,
})
const throwOnFail = throwOnCommandFail.bind(null, `pnpm recursive rebuild`)
const chunks = opts.sort !== false
? sortPackages(opts.selectedWsPkgsGraph)
: [Object.keys(opts.selectedWsPkgsGraph).sort()]
const store = await createOrConnectStoreController(opts)
const workspacePackages = arrayOfWorkspacePackagesToMap(allWsPkgs)
const rebuildOpts = Object.assign(opts, {
ownLifecycleHooksStdio: 'pipe',
pruneLockfileImporters: (!opts.ignoredPackages || opts.ignoredPackages.size === 0)
&& pkgs.length === allWsPkgs.length,
storeController: store.ctrl,
storeDir: store.dir,
workspacePackages,
}) as RebuildOptions
const result = {
fails: [],
passes: 0,
} as RecursiveSummary
const memReadLocalConfig = mem(readLocalConfig)
async function getImporters () {
const importers = [] as Array<{ buildIndex: number, manifest: ImporterManifest, rootDir: string }>
await Promise.all(chunks.map((prefixes: string[], buildIndex) => {
if (opts.ignoredPackages) {
prefixes = prefixes.filter((prefix) => !opts.ignoredPackages!.has(prefix))
}
return Promise.all(
prefixes.map(async (prefix) => {
importers.push({
buildIndex,
manifest: manifestsByPath[prefix].manifest,
rootDir: prefix,
})
})
)
}))
return importers
}
const rebuild = (
input.length === 0
? rebuildAll
: (importers: any, opts: any) => rebuildPkgs(importers, input, opts) // tslint:disable-line
)
if (opts.lockfileDir) {
const importers = await getImporters()
await rebuild(
importers,
{
...rebuildOpts,
pending: opts.pending === true,
},
)
return
}
const limitRebuild = pLimit(opts.workspaceConcurrency ?? 4)
for (const chunk of chunks) {
await Promise.all(chunk.map((rootDir: string) =>
limitRebuild(async () => {
try {
if (opts.ignoredPackages && opts.ignoredPackages.has(rootDir)) {
return
}
const localConfig = await memReadLocalConfig(rootDir)
await rebuild(
[
{
buildIndex: 0,
manifest: manifestsByPath[rootDir].manifest,
rootDir,
},
],
{
...rebuildOpts,
...localConfig,
dir: rootDir,
pending: opts.pending === true,
rawConfig: {
...rebuildOpts.rawConfig,
...localConfig,
},
},
)
result.passes++
} catch (err) {
logger.info(err)
if (!opts.bail) {
result.fails.push({
error: err,
message: err.message,
prefix: rootDir,
})
return
}
err['prefix'] = rootDir // tslint:disable-line:no-string-literal
throw err
}
}),
))
}
throwOnFail(result)
}
async function readLocalConfig (prefix: string) {
try {
const ini = await readIniFile(path.join(prefix, '.npmrc')) as { [key: string]: string }
const config = camelcaseKeys(ini) as ({ [key: string]: string } & { hoist?: boolean })
if (config.shamefullyFlatten) {
config.hoistPattern = '*'
// TODO: print a warning
}
if (config.hoist === false) {
config.hoistPattern = ''
}
return config
} catch (err) {
if (err.code !== 'ENOENT') throw err
return {}
}
}

View File

@@ -11,16 +11,10 @@ import exists = require('path-exists')
import sinon = require('sinon')
import test = require('tape')
import { promisify } from 'util'
import './recursive'
import { DEFAULT_OPTS } from './utils'
const REGISTRY = `http://localhost:${REGISTRY_MOCK_PORT}/`
const DEFAULT_OPTS = {
independentLeaves: false,
lock: false,
rawConfig: {
registry: `http://localhost:${REGISTRY_MOCK_PORT}/`,
},
registries: { default: `http://localhost:${REGISTRY_MOCK_PORT}/` },
}
test('rebuilds dependencies', async (t) => {
const project = prepareEmpty(t)

View File

@@ -1,10 +1,12 @@
import { recursive } from '@pnpm/plugin-commands-recursive'
import { readWsPkgs } from '@pnpm/filter-workspace-packages'
import { rebuild } from '@pnpm/plugin-commands-rebuild'
import { preparePackages } from '@pnpm/prepare'
import { PackageManifest } from '@pnpm/types'
import execa = require('execa')
import path = require('path')
import test = require('tape')
import writeYamlFile = require('write-yaml-file')
import { DEFAULT_OPTS, readWsPkgs } from './utils'
import { DEFAULT_OPTS, REGISTRY } from './utils'
test('pnpm recursive rebuild', async (t) => {
const projects = preparePackages(t, [
@@ -27,24 +29,28 @@ test('pnpm recursive rebuild', async (t) => {
])
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
ignoreScripts: true,
selectedWsPkgsGraph,
})
await execa('pnpm', [
'install',
'-r',
'--registry',
REGISTRY,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
'--ignore-scripts',
])
await projects['project-1'].hasNot('pre-and-postinstall-scripts-example/generated-by-preinstall.js')
await projects['project-1'].hasNot('pre-and-postinstall-scripts-example/generated-by-postinstall.js')
await projects['project-2'].hasNot('pre-and-postinstall-scripts-example/generated-by-preinstall.js')
await projects['project-2'].hasNot('pre-and-postinstall-scripts-example/generated-by-postinstall.js')
await recursive.handler(['rebuild'], {
await rebuild.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
workspaceDir: process.cwd(),
})
await projects['project-1'].has('pre-and-postinstall-scripts-example/generated-by-preinstall.js')
@@ -103,19 +109,23 @@ test.skip('rebuild multiple packages in correct order', async (t) => {
await writeYamlFile('pnpm-workspace.yaml', { packages: ['project-1'] })
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
ignoreScripts: true,
selectedWsPkgsGraph,
})
await execa('pnpm', [
'install',
'-r',
'--registry',
REGISTRY,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
'--ignore-scripts',
])
await recursive.handler(['rebuild'], {
await rebuild.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
workspaceDir: process.cwd(),
})
const outputs1 = await import(path.resolve('output1.json')) as string[]

View File

@@ -0,0 +1,46 @@
import { REGISTRY_MOCK_PORT } from '@pnpm/registry-mock'
export const REGISTRY = `http://localhost:${REGISTRY_MOCK_PORT}`
export const DEFAULT_OPTS = {
alwaysAuth: false,
argv: {
original: [],
},
bail: false,
ca: undefined,
cert: undefined,
cliOptions: {},
fetchRetries: 2,
fetchRetryFactor: 90,
fetchRetryMaxtimeout: 90,
fetchRetryMintimeout: 10,
filter: [] as string[],
httpsProxy: undefined,
include: {
dependencies: true,
devDependencies: true,
optionalDependencies: true,
},
key: undefined,
linkWorkspacePackages: true,
localAddress: undefined,
lock: false,
lockStaleDuration: 90,
networkConcurrency: 16,
offline: false,
pending: false,
pnpmfile: './pnpmfile.js',
proxy: undefined,
rawConfig: { registry: REGISTRY },
rawLocalConfig: {},
registries: { default: REGISTRY },
registry: REGISTRY,
sort: true,
storeDir: '../store',
strictSsl: false,
userAgent: 'pnpm',
useRunningStoreServer: false,
useStoreServer: false,
workspaceConcurrency: 4,
}

View File

@@ -1,15 +0,0 @@
# @pnpm/plugin-commands-recursive
> Recursive commands
[![npm version](https://img.shields.io/npm/v/@pnpm/plugin-commands-recursive.svg)](https://www.npmjs.com/package/@pnpm/plugin-commands-recursive)
## Installation
```sh
<pnpm|npm|yarn> add @pnpm/plugin-commands-recursive
```
## License
MIT © [Zoltan Kochan](https://www.kochan.io/)

View File

@@ -1,98 +0,0 @@
{
"name": "@pnpm/plugin-commands-recursive",
"version": "0.1.10",
"description": "Recursive commands",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
"files": [
"lib"
],
"engines": {
"node": ">=10"
},
"scripts": {
"lint": "tslint -c tslint.json src/**/*.ts test/**/*.ts",
"tsc": "rimraf lib && tsc",
"registry-mock": "registry-mock",
"test:tap": "ts-node test --type-check",
"pretest:e2e": "registry-mock prepare",
"test:e2e": "run-p -r registry-mock test:tap",
"test": "pnpm run tsc && pnpm run lint && cross-env PNPM_REGISTRY_MOCK_PORT=7777 pnpm run test:e2e",
"prepublishOnly": "pnpm run tsc"
},
"repository": "https://github.com/pnpm/pnpm/blob/master/packages/plugin-commands-recursive",
"keywords": [
"pnpm"
],
"author": "Zoltan Kochan <z@kochan.io> (https://www.kochan.io/)",
"license": "MIT",
"bugs": {
"url": "https://github.com/pnpm/pnpm/issues"
},
"homepage": "https://pnpm.js.org",
"devDependencies": {
"@pnpm/lockfile-types": "workspace:1.1.0",
"@pnpm/logger": "3.1.0",
"@pnpm/plugin-commands-recursive": "link:",
"@pnpm/prepare": "workspace:0.0.0",
"@types/common-tags": "^1.8.0",
"@types/lru-cache": "^5.1.0",
"@types/mz": "^2.7.0",
"@types/ramda": "^0.26.38",
"@types/table": "^4.0.7",
"@zkochan/rimraf": "1.0.0",
"make-dir": "3.0.0",
"path-exists": "4.0.0",
"read-yaml-file": "1.1.0",
"rimraf": "3.0.0",
"strip-ansi": "6.0.0",
"write-json-file": "4.2.1",
"write-yaml-file": "3.0.1"
},
"dependencies": {
"@pnpm/cli-utils": "workspace:0.2.5",
"@pnpm/common-cli-options-help": "workspace:0.1.2",
"@pnpm/config": "workspace:6.0.0",
"@pnpm/constants": "workspace:3.0.0",
"@pnpm/core-loggers": "workspace:4.0.0",
"@pnpm/error": "workspace:1.0.0",
"@pnpm/filter-workspace-packages": "workspace:1.0.1",
"@pnpm/find-workspace-packages": "workspace:2.0.8",
"@pnpm/lifecycle": "workspace:8.0.1",
"@pnpm/lockfile-file": "workspace:3.0.1",
"@pnpm/matcher": "workspace:1.0.0",
"@pnpm/npm-resolver": "workspace:6.0.2",
"@pnpm/outdated": "workspace:6.0.5",
"@pnpm/plugin-commands-listing": "workspace:0.1.9",
"@pnpm/plugin-commands-outdated": "workspace:0.1.9",
"@pnpm/plugin-commands-publishing": "workspace:0.1.9",
"@pnpm/plugin-commands-rebuild": "workspace:0.0.0",
"@pnpm/pnpmfile": "workspace:0.1.0",
"@pnpm/resolver-base": "workspace:6.0.0",
"@pnpm/run-npm": "workspace:1.0.0",
"@pnpm/store-connection-manager": "workspace:0.2.5",
"@pnpm/store-path": "2.1.1",
"@pnpm/types": "workspace:4.0.0",
"@pnpm/utils": "workspace:0.12.2",
"camelcase-keys": "6.1.1",
"chalk": "3.0.0",
"common-tags": "1.8.0",
"execa": "4.0.0",
"graph-sequencer": "2.0.0",
"is-subdir": "1.1.1",
"lru-cache": "5.1.1",
"mem": "6.0.1",
"mz": "2.7.0",
"p-filter": "2.1.0",
"p-limit": "2.2.1",
"pkgs-graph": "workspace:5.0.1",
"ramda": "0.26.1",
"read-ini-file": "2.0.0",
"render-help": "0.0.0",
"supi": "workspace:0.37.6",
"table": "5.4.6"
},
"peerDependencies": {
"@pnpm/logger": "^3.1.0"
}
}

View File

@@ -1,62 +0,0 @@
import { WsPkgsGraph } from '@pnpm/config'
import logger from '@pnpm/logger'
import execa = require('execa')
import pLimit from 'p-limit'
import RecursiveSummary from './recursiveSummary'
export default async <T> (
packageChunks: string[][],
graph: WsPkgsGraph,
args: string[],
cmd: string,
opts: {
bail: boolean,
workspaceConcurrency: number,
unsafePerm: boolean,
rawConfig: object,
},
): Promise<RecursiveSummary> => {
const limitRun = pLimit(opts.workspaceConcurrency)
const result = {
fails: [],
passes: 0,
} as RecursiveSummary
for (const chunk of packageChunks) {
await Promise.all(chunk.map((prefix: string) =>
limitRun(async () => {
try {
await execa(args[0], args.slice(1), {
cwd: prefix,
env: {
...process.env,
PNPM_PACKAGE_NAME: graph[prefix].package.manifest.name,
},
stdio: 'inherit',
})
result.passes++
} catch (err) {
logger.info(err)
if (!opts.bail) {
result.fails.push({
error: err,
message: err.message,
prefix,
})
return
}
// tslint:disable:no-string-literal
err['code'] = 'ERR_PNPM_RECURSIVE_EXEC_FIRST_FAIL'
err['prefix'] = prefix
// tslint:enable:no-string-literal
throw err
}
},
)))
}
return result
}

View File

@@ -1,3 +0,0 @@
import * as recursive from './recursive'
export { recursive }

View File

@@ -1,811 +0,0 @@
import {
createLatestSpecs,
docsUrl,
getPinnedVersion,
getSaveType,
updateToLatestSpecsFromManifest,
} from '@pnpm/cli-utils'
import { FILTERING } from '@pnpm/common-cli-options-help'
import { Config, types as allTypes, WsPkg, WsPkgsGraph } from '@pnpm/config'
import { WANTED_LOCKFILE } from '@pnpm/constants'
import { scopeLogger } from '@pnpm/core-loggers'
import PnpmError from '@pnpm/error'
import filterGraph, { PackageSelector, parsePackageSelector } from '@pnpm/filter-workspace-packages'
import findWorkspacePackages, { arrayOfWorkspacePackagesToMap } from '@pnpm/find-workspace-packages'
import logger from '@pnpm/logger'
import { rebuild, rebuildPkgs } from '@pnpm/plugin-commands-rebuild/lib/implementation'
import { requireHooks } from '@pnpm/pnpmfile'
import { createOrConnectStoreController, CreateStoreControllerOptions } from '@pnpm/store-connection-manager'
import { DependencyManifest, ImporterManifest, PackageManifest } from '@pnpm/types'
import camelcaseKeys = require('camelcase-keys')
import { oneLine } from 'common-tags'
import graphSequencer = require('graph-sequencer')
import isSubdir = require('is-subdir')
import mem = require('mem')
import fs = require('mz/fs')
import pFilter = require('p-filter')
import pLimit from 'p-limit'
import path = require('path')
import createPkgGraph, { PackageNode } from 'pkgs-graph'
import R = require('ramda')
import readIniFile = require('read-ini-file')
import renderHelp = require('render-help')
import {
addDependenciesToPackage,
install,
InstallOptions,
MutatedImporter,
mutateModules,
} from 'supi'
import exec from './exec'
import list from './list'
import outdated from './outdated'
import publish from './publish'
import RecursiveSummary, { throwOnCommandFail } from './recursiveSummary'
import run from './run'
import { createWorkspaceSpecs, updateToWorkspacePackagesFromManifest } from './updateWorkspaceDependencies'
const supportedRecursiveCommands = new Set([
'add',
'install',
'remove',
'update',
'unlink',
'list',
'why',
'outdated',
'rebuild',
'run',
'test',
'exec',
'publish',
])
function getCommandFullName (commandName: string) {
switch (commandName) {
case 'i':
return 'install'
case 'r':
case 'rm':
case 'un':
case 'uninstall':
return 'remove'
case 'up':
case 'upgrade':
return 'update'
case 'dislink':
return 'unlink'
case 'ls':
case 'la':
case 'll':
return 'list'
case 'rb':
return 'rebuild'
case 'run-script':
return 'run'
case 't':
case 'tst':
return 'test'
}
return commandName
}
export const rcOptionsTypes = cliOptionsTypes
export function cliOptionsTypes () {
return {
access: ['public', 'restricted'],
recursive: Boolean,
table: Boolean,
...R.pick([
'bail',
'link-workspace-packages',
'reporter',
'shared-workspace-lockfile',
'sort',
'tag',
'workspace-concurrency',
], allTypes),
}
}
export const commandNames = ['recursive', 'multi', 'm']
export function help () {
return renderHelp({
description: oneLine`
Concurrently performs some actions in all subdirectories with a \`package.json\` (excluding node_modules).
A \`pnpm-workspace.yaml\` file may be used to control what directories are searched for packages.`,
descriptionLists: [
{
title: 'Commands',
list: [
{
name: 'install',
},
{
name: 'add',
},
{
name: 'update',
},
{
description: 'Uninstall a dependency from each package',
name: 'remove <pkg>...',
},
{
description: 'Removes links to local packages and reinstalls them from the registry.',
name: 'unlink',
},
{
description: 'List dependencies in each package.',
name: 'list [<pkg>...]',
},
{
description: 'List packages that depend on <pkg>.',
name: 'why <pkg>...',
},
{
description: 'Check for outdated dependencies in every package.',
name: 'outdated [<pkg>...]',
},
{
description: oneLine`
This runs an arbitrary command from each package's "scripts" object.
If a package doesn't have the command, it is skipped.
If none of the packages have the command, the command fails.`,
name: 'run <command> [-- <args>...]',
},
{
description: `This runs each package's "test" script, if one was provided.`,
name: 'test [-- <args>...]',
},
{
description: oneLine`
This command runs the "npm build" command on each package.
This is useful when you install a new version of node,
and must recompile all your C++ addons with the new binary.`,
name: 'rebuild [[<@scope>/<name>]...]',
},
{
description: `Run a command in each package.`,
name: 'exec -- <command> [args...]',
},
{
description: 'Publishes packages to the npm registry. Only publishes a package if its version is not taken in the registry.',
name: 'publish [--tag <tag>] [--access <public|restricted>]',
},
],
},
{
title: 'Options',
list: [
{
description: 'Continues executing other tasks even if a task threw an error.',
name: '--no-bail',
},
{
description: 'Set the maximum number of concurrency. Default is 4. For unlimited concurrency use Infinity.',
name: '--workspace-concurrency <number>',
},
{
description: oneLine`
Locally available packages are linked to node_modules instead of being downloaded from the registry.
Convenient to use in a multi-package repository.`,
name: '--link-workspace-packages',
},
{
description: 'Sort packages topologically (dependencies before dependents). Pass --no-sort to disable.',
name: '--sort',
},
{
description: oneLine`
Creates a single ${WANTED_LOCKFILE} file in the root of the workspace.
A shared lockfile also means that all dependencies of all workspace packages will be in a single node_modules.`,
name: '--shared-workspace-lockfile',
},
],
},
FILTERING,
],
url: docsUrl('recursive'),
usages: [
'pnpm recursive [command] [flags] [--filter <package selector>]',
'pnpm multi [command] [flags] [--filter <package selector>]',
'pnpm m [command] [flags] [--filter <package selector>]'
],
})
}
export async function handler (
input: string[],
opts: RecursiveOptions & Pick<Config, 'filter' | 'depth' | 'engineStrict' | 'tag' | 'workspaceDir'> & { long?: boolean, table?: boolean } & Required<Pick<Config, 'allWsPkgs' | 'selectedWsPkgsGraph'>>,
) {
if (opts.workspaceConcurrency < 1) {
throw new PnpmError('INVALID_WORKSPACE_CONCURRENCY', 'Workspace concurrency should be at least 1')
}
const cmd = input.shift()
if (!cmd) {
help()
return undefined
}
const cmdFullName = getCommandFullName(cmd)
if (!supportedRecursiveCommands.has(cmdFullName)) {
help()
throw new PnpmError('INVALID_RECURSIVE_COMMAND',
`"recursive ${cmdFullName}" is not a pnpm command. See "pnpm help recursive".`)
}
const workspaceDir = opts.workspaceDir ?? process.cwd()
const atLeastOnePackageMatched = await recursive(opts.allWsPkgs, input, { ...opts, workspaceDir }, cmdFullName, cmd)
if (typeof atLeastOnePackageMatched === 'string') {
return atLeastOnePackageMatched
}
if (atLeastOnePackageMatched === false) {
logger.info({ message: `No packages matched the filters in "${workspaceDir}"`, prefix: workspaceDir })
}
return undefined
}
type RecursiveOptions = CreateStoreControllerOptions & Pick<Config,
'bail' |
'cliOptions' |
'globalPnpmfile' |
'hoistPattern' |
'ignorePnpmfile' |
'ignoreScripts' |
'include' |
'linkWorkspacePackages' |
'lockfileDir' |
'lockfileOnly' |
'pnpmfile' |
'rawLocalConfig' |
'registries' |
'save' |
'saveDev' |
'saveExact' |
'saveOptional' |
'savePeer' |
'savePrefix' |
'saveProd' |
'saveWorkspaceProtocol' |
'sharedWorkspaceLockfile' |
'sort' |
'tag' |
'workspaceConcurrency'
> & {
access?: 'public' | 'restricted',
argv: {
original: string[],
},
latest?: boolean,
pending?: boolean,
workspace?: boolean,
}
export async function recursive (
allWsPkgs: WsPkg[],
input: string[],
opts: RecursiveOptions & {
allowNew?: boolean,
ignoredPackages?: Set<string>,
update?: boolean,
useBetaCli?: boolean,
selectedWsPkgsGraph: WsPkgsGraph,
} & Required<Pick<Config, 'workspaceDir'>>,
cmdFullName: string,
cmd: string,
): Promise<boolean | string> {
if (allWsPkgs.length === 0) {
// It might make sense to throw an exception in this case
return false
}
const pkgs = Object.values(opts.selectedWsPkgsGraph).map((wsPkg) => wsPkg.package)
const allPackagesAreSelected = pkgs.length === allWsPkgs.length
if (pkgs.length === 0) {
return false
}
const manifestsByPath: { [dir: string]: { manifest: ImporterManifest, writeImporterManifest: (manifest: ImporterManifest) => Promise<void> } } = {}
for (const { dir, manifest, writeImporterManifest } of pkgs) {
manifestsByPath[dir] = { manifest, writeImporterManifest }
}
scopeLogger.debug({
selected: pkgs.length,
total: allWsPkgs.length,
workspacePrefix: opts.workspaceDir,
})
const throwOnFail = throwOnCommandFail.bind(null, `pnpm recursive ${cmd}`)
switch (cmdFullName) {
case 'why':
case 'list':
return list(pkgs, input, cmd, opts as any) // tslint:disable-line:no-any
case 'outdated':
return outdated(pkgs, input, cmd, opts as any) // tslint:disable-line:no-any
case 'add':
if (!input || !input.length) {
throw new PnpmError('MISSING_PACKAGE_NAME', '`pnpm recursive add` requires the package name')
}
break
case 'publish': {
await publish(pkgs, opts)
return true
}
}
const chunks = opts.sort
? sortPackages(opts.selectedWsPkgsGraph)
: [Object.keys(opts.selectedWsPkgsGraph).sort()]
switch (cmdFullName) {
case 'test':
throwOnFail(await run(chunks, opts.selectedWsPkgsGraph, ['test', ...input], cmd, opts as any)) // tslint:disable-line:no-any
return true
case 'run':
throwOnFail(await run(chunks, opts.selectedWsPkgsGraph, input, cmd, { ...opts, allPackagesAreSelected } as any)) // tslint:disable-line:no-any
return true
case 'update':
opts = { ...opts, update: true, allowNew: false } as any // tslint:disable-line:no-any
break
case 'exec':
throwOnFail(await exec(chunks, opts.selectedWsPkgsGraph, input, cmd, opts as any)) // tslint:disable-line:no-any
return true
}
const store = await createOrConnectStoreController(opts)
// It is enough to save the store.json file once,
// once all installations are done.
// That's why saveState that is passed to the install engine
// does nothing.
const saveState = store.ctrl.saveState
const storeController = {
...store.ctrl,
saveState: async () => undefined,
}
const workspacePackages = cmdFullName !== 'unlink'
? arrayOfWorkspacePackagesToMap(allWsPkgs)
: {}
const installOpts = Object.assign(opts, {
ownLifecycleHooksStdio: 'pipe',
peer: opts.savePeer,
pruneLockfileImporters: (!opts.ignoredPackages || opts.ignoredPackages.size === 0)
&& pkgs.length === allWsPkgs.length,
storeController,
storeDir: store.dir,
workspacePackages,
forceHoistPattern: typeof opts.rawLocalConfig['hoist-pattern'] !== 'undefined' || typeof opts.rawLocalConfig['hoist'] !== 'undefined',
forceIndependentLeaves: typeof opts.rawLocalConfig['independent-leaves'] !== 'undefined',
forceShamefullyHoist: typeof opts.rawLocalConfig['shamefully-hoist'] !== 'undefined',
}) as InstallOptions
const result = {
fails: [],
passes: 0,
} as RecursiveSummary
const memReadLocalConfig = mem(readLocalConfig)
async function getImporters () {
const importers = [] as Array<{ buildIndex: number, manifest: ImporterManifest, rootDir: string }>
await Promise.all(chunks.map((prefixes: string[], buildIndex) => {
if (opts.ignoredPackages) {
prefixes = prefixes.filter((prefix) => !opts.ignoredPackages!.has(prefix))
}
return Promise.all(
prefixes.map(async (prefix) => {
importers.push({
buildIndex,
manifest: manifestsByPath[prefix].manifest,
rootDir: prefix,
})
})
)
}))
return importers
}
const updateToLatest = opts.update && opts.latest
const include = opts.include
if (updateToLatest) {
delete opts.include
}
if (opts.workspace && (cmdFullName === 'install' || cmdFullName === 'add')) {
if (opts.latest) {
throw new PnpmError('BAD_OPTIONS', 'Cannot use --latest with --workspace simultaneously')
}
if (!opts.workspaceDir) {
throw new PnpmError('WORKSPACE_OPTION_OUTSIDE_WORKSPACE', '--workspace can only be used inside a workspace')
}
if (!opts.linkWorkspacePackages && !opts.saveWorkspaceProtocol) {
if (opts.rawLocalConfig['save-workspace-protocol'] === false) {
throw new PnpmError('BAD_OPTIONS', oneLine`This workspace has link-workspace-packages turned off,
so dependencies are linked from the workspace only when the workspace protocol is used.
Either set link-workspace-packages to true or don't use the --no-save-workspace-protocol option
when running add/update with the --workspace option`)
} else {
opts.saveWorkspaceProtocol = true
}
}
opts['preserveWorkspaceProtocol'] = !opts.linkWorkspacePackages
}
if (cmdFullName !== 'rebuild') {
// For a workspace with shared lockfile
if (opts.lockfileDir && ['add', 'install', 'remove', 'update'].includes(cmdFullName)) {
if (opts.hoistPattern) {
logger.info({ message: 'Only the root workspace package is going to have hoisted dependencies in node_modules', prefix: opts.lockfileDir })
}
let importers = await getImporters()
const isFromWorkspace = isSubdir.bind(null, opts.lockfileDir)
importers = await pFilter(importers, async ({ rootDir }: { rootDir: string }) => isFromWorkspace(await fs.realpath(rootDir)))
if (importers.length === 0) return true
const hooks = opts.ignorePnpmfile ? {} : requireHooks(opts.lockfileDir, opts)
const mutation = cmdFullName === 'remove' ? 'uninstallSome' : (input.length === 0 && !updateToLatest ? 'install' : 'installSome')
const writeImporterManifests = [] as Array<(manifest: ImporterManifest) => Promise<void>>
const mutatedImporters = [] as MutatedImporter[]
await Promise.all(importers.map(async ({ buildIndex, rootDir }) => {
const localConfig = await memReadLocalConfig(rootDir)
const { manifest, writeImporterManifest } = manifestsByPath[rootDir]
let currentInput = [...input]
if (updateToLatest) {
if (!currentInput || !currentInput.length) {
currentInput = updateToLatestSpecsFromManifest(manifest, include)
} else {
currentInput = createLatestSpecs(currentInput, manifest)
if (!currentInput.length) {
installOpts.pruneLockfileImporters = false
return
}
}
}
if (opts.workspace) {
if (!currentInput || !currentInput.length) {
currentInput = updateToWorkspacePackagesFromManifest(manifest, opts.include, workspacePackages!)
} else {
currentInput = createWorkspaceSpecs(currentInput, workspacePackages!)
}
}
writeImporterManifests.push(writeImporterManifest)
switch (mutation) {
case 'uninstallSome':
mutatedImporters.push({
dependencyNames: currentInput,
manifest,
mutation,
rootDir,
targetDependenciesField: getSaveType(opts),
} as MutatedImporter)
return
case 'installSome':
mutatedImporters.push({
allowNew: cmdFullName === 'install' || cmdFullName === 'add',
dependencySelectors: currentInput,
manifest,
mutation,
peer: opts.savePeer,
pinnedVersion: getPinnedVersion({
saveExact: typeof localConfig.saveExact === 'boolean' ? localConfig.saveExact : opts.saveExact,
savePrefix: typeof localConfig.savePrefix === 'string' ? localConfig.savePrefix : opts.savePrefix,
}),
rootDir,
targetDependenciesField: getSaveType(opts),
} as MutatedImporter)
return
case 'install':
mutatedImporters.push({
buildIndex,
manifest,
mutation,
rootDir,
} as MutatedImporter)
return
}
}))
const mutatedPkgs = await mutateModules(mutatedImporters, {
...installOpts,
hooks,
storeController: store.ctrl,
})
if (opts.save !== false) {
await Promise.all(
mutatedPkgs
.map(({ manifest }, index) => writeImporterManifests[index](manifest))
)
}
return true
}
let pkgPaths = chunks.length === 0
? chunks[0]
: Object.keys(opts.selectedWsPkgsGraph).sort()
const limitInstallation = pLimit(opts.workspaceConcurrency)
await Promise.all(pkgPaths.map((rootDir: string) =>
limitInstallation(async () => {
const hooks = opts.ignorePnpmfile ? {} : requireHooks(rootDir, opts)
try {
if (opts.ignoredPackages && opts.ignoredPackages.has(rootDir)) {
return
}
const { manifest, writeImporterManifest } = manifestsByPath[rootDir]
let currentInput = [...input]
if (updateToLatest) {
if (!currentInput || !currentInput.length) {
currentInput = updateToLatestSpecsFromManifest(manifest, include)
} else {
currentInput = createLatestSpecs(currentInput, manifest)
if (!currentInput.length) return
}
}
let action!: any // tslint:disable-line:no-any
switch (cmdFullName) {
case 'unlink':
action = (currentInput.length === 0 ? unlink : unlinkPkgs.bind(null, currentInput))
break
case 'remove':
action = (manifest: PackageManifest, opts: any) => mutateModules([ // tslint:disable-line:no-any
{
dependencyNames: currentInput,
manifest,
mutation: 'uninstallSome',
rootDir,
},
], opts)
break
default:
action = currentInput.length === 0
? install
: (manifest: PackageManifest, opts: any) => addDependenciesToPackage(manifest, currentInput, opts) // tslint:disable-line:no-any
break
}
const localConfig = await memReadLocalConfig(rootDir)
const newManifest = await action(
manifest,
{
...installOpts,
...localConfig,
bin: path.join(rootDir, 'node_modules', '.bin'),
dir: rootDir,
hooks,
ignoreScripts: true,
pinnedVersion: getPinnedVersion({
saveExact: typeof localConfig.saveExact === 'boolean' ? localConfig.saveExact : opts.saveExact,
savePrefix: typeof localConfig.savePrefix === 'string' ? localConfig.savePrefix : opts.savePrefix,
}),
rawConfig: {
...installOpts.rawConfig,
...localConfig,
},
storeController,
},
)
if (opts.save !== false) {
await writeImporterManifest(newManifest)
}
result.passes++
} catch (err) {
logger.info(err)
if (!opts.bail) {
result.fails.push({
error: err,
message: err.message,
prefix: rootDir,
})
return
}
err['prefix'] = rootDir // tslint:disable-line:no-string-literal
throw err
}
}),
))
await saveState()
}
if (
cmdFullName === 'rebuild' ||
!opts.lockfileOnly && !opts.ignoreScripts && (
cmdFullName === 'add' ||
cmdFullName === 'install' ||
cmdFullName === 'update' ||
cmdFullName === 'unlink'
)
) {
const action = (
cmdFullName !== 'rebuild' || input.length === 0
? rebuild
: (importers: any, opts: any) => rebuildPkgs(importers, input, opts) // tslint:disable-line
)
if (opts.lockfileDir) {
const importers = await getImporters()
await action(
importers,
{
...installOpts,
pending: cmdFullName !== 'rebuild' || opts.pending === true,
},
)
return true
}
const limitRebuild = pLimit(opts.workspaceConcurrency)
for (const chunk of chunks) {
await Promise.all(chunk.map((rootDir: string) =>
limitRebuild(async () => {
try {
if (opts.ignoredPackages && opts.ignoredPackages.has(rootDir)) {
return
}
const localConfig = await memReadLocalConfig(rootDir)
await action(
[
{
buildIndex: 0,
manifest: manifestsByPath[rootDir].manifest,
rootDir,
},
],
{
...installOpts,
...localConfig,
dir: rootDir,
pending: cmdFullName !== 'rebuild' || opts.pending === true,
rawConfig: {
...installOpts.rawConfig,
...localConfig,
},
},
)
result.passes++
} catch (err) {
logger.info(err)
if (!opts.bail) {
result.fails.push({
error: err,
message: err.message,
prefix: rootDir,
})
return
}
err['prefix'] = rootDir // tslint:disable-line:no-string-literal
throw err
}
}),
))
}
}
throwOnFail(result)
return true
}
async function unlink (manifest: ImporterManifest, opts: any) { // tslint:disable-line:no-any
return mutateModules(
[
{
manifest,
mutation: 'unlink',
rootDir: opts.dir,
},
],
opts,
)
}
async function unlinkPkgs (dependencyNames: string[], manifest: ImporterManifest, opts: any) { // tslint:disable-line:no-any
return mutateModules(
[
{
dependencyNames,
manifest,
mutation: 'unlinkSome',
rootDir: opts.dir,
},
],
opts,
)
}
function sortPackages (pkgGraph: WsPkgsGraph): string[][] {
const keys = Object.keys(pkgGraph)
const setOfKeys = new Set(keys)
const graph = new Map(
keys.map((pkgPath) => [
pkgPath,
pkgGraph[pkgPath].dependencies.filter(
/* remove cycles of length 1 (ie., package 'a' depends on 'a'). They
confuse the graph-sequencer, but can be ignored when ordering packages
topologically.
See the following example where 'b' and 'c' depend on themselves:
graphSequencer({graph: new Map([
['a', ['b', 'c']],
['b', ['b']],
['c', ['b', 'c']]]
),
groups: [['a', 'b', 'c']]})
returns chunks:
[['b'],['a'],['c']]
But both 'b' and 'c' should be executed _before_ 'a', because 'a' depends on
them. It works (and is considered 'safe' if we run:)
graphSequencer({graph: new Map([
['a', ['b', 'c']],
['b', []],
['c', ['b']]]
), groups: [['a', 'b', 'c']]})
returning:
[['b'], ['c'], ['a']]
*/
d => d !== pkgPath &&
/* remove unused dependencies that we can ignore due to a filter expression.
Again, the graph sequencer used to behave weirdly in the following edge case:
graphSequencer({graph: new Map([
['a', ['b', 'c']],
['d', ['a']],
['e', ['a', 'b', 'c']]]
),
groups: [['a', 'e', 'e']]})
returns chunks:
[['d'],['a'],['e']]
But we really want 'a' to be executed first.
*/
setOfKeys.has(d))]
) as Array<[string, string[]]>,
)
const graphSequencerResult = graphSequencer({
graph,
groups: [keys],
})
return graphSequencerResult.chunks
}
async function readLocalConfig (prefix: string) {
try {
const ini = await readIniFile(path.join(prefix, '.npmrc')) as { [key: string]: string }
const config = camelcaseKeys(ini) as ({ [key: string]: string } & { hoist?: boolean })
if (config.shamefullyFlatten) {
config.hoistPattern = '*'
// TODO: print a warning
}
if (config.hoist === false) {
config.hoistPattern = ''
}
return config
} catch (err) {
if (err.code !== 'ENOENT') throw err
return {}
}
}

View File

@@ -1,13 +0,0 @@
///<reference path="../../../typings/index.d.ts" />
import './updateWorkspaceDependencies.spec'
import './exec'
import './link'
import './list'
import './misc'
import './outdated'
import './publish'
import './rebuild'
import './run'
import './test'
import './update'

View File

@@ -32,14 +32,18 @@
},
"homepage": "https://pnpm.js.org",
"devDependencies": {
"@pnpm/filter-workspace-packages": "workspace:1.0.1",
"@pnpm/logger": "^3.1.0",
"@pnpm/plugin-commands-script-runners": "link:",
"@pnpm/prepare": "workspace:0.0.0",
"@types/common-tags": "^1.8.0",
"@types/mz": "^2.7.0",
"@types/ramda": "^0.26.38",
"@zkochan/rimraf": "1.0.0",
"execa": "4.0.0",
"mz": "2.7.0",
"rimraf": "3.0.0"
"rimraf": "3.0.0",
"write-yaml-file": "3.0.1"
},
"dependencies": {
"@pnpm/cli-utils": "workspace:0.2.5",
@@ -47,10 +51,15 @@
"@pnpm/config": "workspace:6.0.0",
"@pnpm/error": "workspace:1.0.0",
"@pnpm/lifecycle": "workspace:8.0.1",
"@pnpm/sort-packages": "workspace:0.0.0",
"@pnpm/types": "workspace:4.0.0",
"@pnpm/utils": "workspace:0.12.2",
"common-tags": "1.8.0",
"p-limit": "2.2.1",
"ramda": "0.26.1",
"render-help": "0.0.0"
},
"peerDependencies": {
"@pnpm/logger": "^3.1.0"
}
}

View File

@@ -0,0 +1,86 @@
import { RecursiveSummary, throwOnCommandFail } from '@pnpm/cli-utils'
import { Config, types, WsPkgsGraph } from '@pnpm/config'
import logger from '@pnpm/logger'
import sortPackages from '@pnpm/sort-packages'
import execa = require('execa')
import pLimit from 'p-limit'
import R = require('ramda')
import renderHelp = require('render-help')
export const commandNames = ['exec']
export const rcOptionsTypes = cliOptionsTypes
export function cliOptionsTypes () {
return R.pick([
'bail',
'unsafe-perm',
'workspace-concurrency',
], types)
}
export function help () {
return renderHelp({
description: 'Run a command in each package.',
usages: ['-r exec -- <command> [args...]'],
})
}
export async function handler (
args: string[],
opts: Required<Pick<Config, 'selectedWsPkgsGraph'>> & {
bail?: boolean,
unsafePerm?: boolean,
rawConfig: object,
sort?: boolean,
workspaceConcurrency?: number,
},
) {
const limitRun = pLimit(opts.workspaceConcurrency ?? 4)
const result = {
fails: [],
passes: 0,
} as RecursiveSummary
const chunks = opts.sort
? sortPackages(opts.selectedWsPkgsGraph)
: [Object.keys(opts.selectedWsPkgsGraph).sort()]
for (const chunk of chunks) {
await Promise.all(chunk.map((prefix: string) =>
limitRun(async () => {
try {
await execa(args[0], args.slice(1), {
cwd: prefix,
env: {
...process.env,
PNPM_PACKAGE_NAME: opts.selectedWsPkgsGraph[prefix].package.manifest.name,
},
stdio: 'inherit',
})
result.passes++
} catch (err) {
logger.info(err)
if (!opts.bail) {
result.fails.push({
error: err,
message: err.message,
prefix,
})
return
}
// tslint:disable:no-string-literal
err['code'] = 'ERR_PNPM_RECURSIVE_EXEC_FIRST_FAIL'
err['prefix'] = prefix
// tslint:enable:no-string-literal
throw err
}
},
)))
}
throwOnCommandFail('pnpm recursive exec', result)
}

View File

@@ -1,7 +1,8 @@
import * as exec from './exec'
import * as restart from './restart'
import * as run from './run'
import * as start from './start'
import * as stop from './stop'
import * as test from './test'
export { restart, run, start, stop, test }
export { exec, restart, run, start, stop, test }

View File

@@ -1,5 +1,10 @@
import renderHelp = require('render-help')
import { handler as run, IF_PRESENT_OPTION, IF_PRESENT_OPTION_HELP } from './run'
import {
handler as run,
IF_PRESENT_OPTION,
IF_PRESENT_OPTION_HELP,
RunOpts,
} from './run'
import { handler as start } from './start'
import { handler as stop } from './stop'
@@ -31,11 +36,7 @@ export function help () {
export async function handler (
args: string[],
opts: {
extraBinPaths: string[],
dir: string,
rawConfig: object,
},
opts: RunOpts,
) {
await stop(args, opts)
await run(['restart', ...args], opts)

View File

@@ -1,6 +1,6 @@
import { docsUrl, readImporterManifestOnly } from '@pnpm/cli-utils'
import { FILTERING } from '@pnpm/common-cli-options-help'
import { types as allTypes } from '@pnpm/config'
import { Config, types as allTypes } from '@pnpm/config'
import PnpmError from '@pnpm/error'
import runLifecycleHooks from '@pnpm/lifecycle'
import { ImporterManifest } from '@pnpm/types'
@@ -8,6 +8,7 @@ import { realNodeModulesDir } from '@pnpm/utils'
import { oneLine } from 'common-tags'
import R = require('ramda')
import renderHelp = require('render-help')
import runRecursive, { RecursiveRunOpts } from './runRecursive'
export const IF_PRESENT_OPTION = {
'if-present': Boolean,
@@ -54,16 +55,25 @@ export function help () {
})
}
export type RunOpts = Omit<RecursiveRunOpts, 'allWsPkgs' | 'selectedWsPkgsGraph' | 'workspaceDir'> & {
ifPresent?: boolean,
recursive?: boolean,
} & Pick<Config, 'dir' | 'engineStrict'> & (
{ recursive?: false } &
Partial<Pick<Config, 'allWsPkgs' | 'selectedWsPkgsGraph' | 'workspaceDir'>>
|
{ recursive: true } &
Required<Pick<Config, 'allWsPkgs' | 'selectedWsPkgsGraph' | 'workspaceDir'>>
)
export async function handler (
args: string[],
opts: {
engineStrict?: boolean,
extraBinPaths: string[],
dir: string,
ifPresent?: boolean,
rawConfig: object,
},
opts: RunOpts,
) {
if (opts.recursive) {
await runRecursive(args, opts)
return
}
const dir = opts.dir
const manifest = await readImporterManifestOnly(dir, opts)
const scriptName = args[0]

View File

@@ -1,36 +1,35 @@
import { WsPkgsGraph } from '@pnpm/config'
import { RecursiveSummary, throwOnCommandFail } from '@pnpm/cli-utils'
import { Config, WsPkgsGraph } from '@pnpm/config'
import PnpmError from '@pnpm/error'
import runLifecycleHooks from '@pnpm/lifecycle'
import logger from '@pnpm/logger'
import sortPackages from '@pnpm/sort-packages'
import { PackageManifest } from '@pnpm/types'
import { realNodeModulesDir } from '@pnpm/utils'
import pLimit from 'p-limit'
import RecursiveSummary from './recursiveSummary'
export default async <T> (
packageChunks: string[][],
graph: WsPkgsGraph,
export type RecursiveRunOpts = Pick<Config,
'unsafePerm' |
'rawConfig'
> & Required<Pick<Config, 'allWsPkgs' | 'selectedWsPkgsGraph' | 'workspaceDir'>> &
Partial<Pick<Config, 'extraBinPaths' | 'bail' | 'sort' | 'workspaceConcurrency'>>
export default async (
args: string[],
cmd: string,
opts: {
bail: boolean,
extraBinPaths: string[],
workspaceConcurrency: number,
unsafePerm: boolean,
rawConfig: object,
workspaceDir: string,
allPackagesAreSelected: boolean,
},
opts: RecursiveRunOpts,
) => {
const scriptName = args[0]
let hasCommand = 0
const packageChunks = opts.sort
? sortPackages(opts.selectedWsPkgsGraph)
: [Object.keys(opts.selectedWsPkgsGraph).sort()]
const result = {
fails: [],
passes: 0,
} as RecursiveSummary
const limitRun = pLimit(opts.workspaceConcurrency)
const limitRun = pLimit(opts.workspaceConcurrency ?? 4)
const stdio = (
opts.workspaceConcurrency === 1 ||
packageChunks.length === 1 && packageChunks[0].length === 1
@@ -40,7 +39,7 @@ export default async <T> (
for (const chunk of packageChunks) {
await Promise.all(chunk.map((prefix: string) =>
limitRun(async () => {
const pkg = graph[prefix] as {package: {dir: string, manifest: PackageManifest}}
const pkg = opts.selectedWsPkgsGraph[prefix] as {package: {dir: string, manifest: PackageManifest}}
if (!pkg.package.manifest.scripts || !pkg.package.manifest.scripts[scriptName]) {
return
}
@@ -86,7 +85,8 @@ export default async <T> (
}
if (scriptName !== 'test' && !hasCommand) {
if (opts.allPackagesAreSelected) {
const allPackagesAreSelected = Object.keys(opts.selectedWsPkgsGraph).length === opts.allWsPkgs.length
if (allPackagesAreSelected) {
throw new PnpmError('RECURSIVE_RUN_NO_SCRIPT', `None of the packages has a "${scriptName}" script`)
} else {
logger.info({
@@ -96,5 +96,5 @@ export default async <T> (
}
}
return result
throwOnCommandFail('pnpm recursive run', result)
}

View File

@@ -1,7 +1,12 @@
import { docsUrl } from '@pnpm/cli-utils'
import { oneLine } from 'common-tags'
import renderHelp = require('render-help')
import { handler as run, IF_PRESENT_OPTION, IF_PRESENT_OPTION_HELP } from './run'
import {
handler as run,
IF_PRESENT_OPTION,
IF_PRESENT_OPTION_HELP,
RunOpts,
} from './run'
export function rcOptionsTypes () {
return {}
@@ -34,11 +39,7 @@ export function help () {
export async function handler (
args: string[],
opts: {
extraBinPaths: string[],
dir: string,
rawConfig: object,
},
opts: RunOpts,
) {
return run(['start', ...args], opts)
}

View File

@@ -1,6 +1,11 @@
import { docsUrl } from '@pnpm/cli-utils'
import renderHelp = require('render-help')
import { handler as run, IF_PRESENT_OPTION, IF_PRESENT_OPTION_HELP } from './run'
import {
handler as run,
IF_PRESENT_OPTION,
IF_PRESENT_OPTION_HELP,
RunOpts,
} from './run'
export function rcOptionsTypes () {
return {}
@@ -31,11 +36,7 @@ export function help () {
export async function handler (
args: string[],
opts: {
extraBinPaths: string[],
dir: string,
rawConfig: object,
},
opts: RunOpts,
) {
return run(['stop', ...args], opts)
}

View File

@@ -4,7 +4,7 @@ import { types as allTypes } from '@pnpm/config'
import { oneLine } from 'common-tags'
import R = require('ramda')
import renderHelp = require('render-help')
import { handler as run } from './run'
import { handler as run, RunOpts } from './run'
export function rcOptionsTypes () {
return {}
@@ -46,11 +46,7 @@ export function help () {
export async function handler (
args: string[],
opts: {
extraBinPaths: string[],
dir: string,
rawConfig: object,
},
opts: RunOpts,
) {
return run(['test', ...args], opts)
}

View File

@@ -1,11 +1,13 @@
import PnpmError from '@pnpm/error'
import { recursive } from '@pnpm/plugin-commands-recursive'
import { readWsPkgs } from '@pnpm/filter-workspace-packages'
import { exec } from '@pnpm/plugin-commands-script-runners'
import { preparePackages } from '@pnpm/prepare'
import rimraf = require('@zkochan/rimraf')
import execa = require('execa')
import fs = require('mz/fs')
import path = require('path')
import test = require('tape')
import { DEFAULT_OPTS, readWsPkgs } from './utils'
import { DEFAULT_OPTS, REGISTRY } from './utils'
test('pnpm recursive exec', async (t) => {
const projects = preparePackages(t, [
@@ -48,17 +50,17 @@ test('pnpm recursive exec', async (t) => {
},
])
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
const { selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await execa('pnpm', [
'install',
'-r',
'--registry',
REGISTRY,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
await exec.handler(['npm', 'run', 'build'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
selectedWsPkgsGraph,
})
await recursive.handler(['exec', 'npm', 'run', 'build'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
selectedWsPkgsGraph,
})
@@ -80,10 +82,8 @@ test('pnpm recursive exec sets PNPM_PACKAGE_NAME env var', async (t) => {
])
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['exec', 'node', '-e', `require('fs').writeFileSync('pkgname', process.env.PNPM_PACKAGE_NAME, 'utf8')`], {
await exec.handler(['node', '-e', `require('fs').writeFileSync('pkgname', process.env.PNPM_PACKAGE_NAME, 'utf8')`], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
selectedWsPkgsGraph,
})
@@ -130,21 +130,21 @@ test('testing the bail config with "pnpm recursive exec"', async (t) => {
},
])
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
selectedWsPkgsGraph,
})
const { selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await execa('pnpm', [
'install',
'-r',
'--registry',
REGISTRY,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
let failed = false
let err1!: PnpmError
try {
await recursive.handler(['exec', 'npm', 'run', 'build', '--no-bail'], {
await exec.handler(['npm', 'run', 'build', '--no-bail'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
selectedWsPkgsGraph,
})
} catch (_err) {
@@ -162,10 +162,8 @@ test('testing the bail config with "pnpm recursive exec"', async (t) => {
failed = false
let err2!: PnpmError
try {
await recursive.handler(['exec', 'npm', 'run', 'build'], {
await exec.handler(['npm', 'run', 'build'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
selectedWsPkgsGraph,
})
} catch (_err) {
@@ -205,18 +203,17 @@ test('pnpm recursive exec --no-sort', async (t) => {
},
])
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
const { selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await execa('pnpm', [
'install',
'-r',
'--registry',
REGISTRY,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
await exec.handler(['npm', 'run', 'build'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
linkWorkspacePackages: true,
selectedWsPkgsGraph,
})
await recursive.handler(['exec', 'npm', 'run', 'build'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
selectedWsPkgsGraph,
sort: false,
workspaceConcurrency: 1,

View File

@@ -11,6 +11,9 @@ import execa = require('execa')
import fs = require('mz/fs')
import path = require('path')
import test = require('tape')
import './exec'
import './runRecursive'
import './testRecursive'
test('pnpm run: returns correct exit code', async (t) => {
prepare(t, {

View File

@@ -1,13 +1,14 @@
import PnpmError from '@pnpm/error'
import { filterPkgsBySelectorObjects } from '@pnpm/filter-workspace-packages'
import { recursive } from '@pnpm/plugin-commands-recursive'
import { filterPkgsBySelectorObjects, readWsPkgs } from '@pnpm/filter-workspace-packages'
import { run } from '@pnpm/plugin-commands-script-runners'
import { preparePackages } from '@pnpm/prepare'
import rimraf = require('@zkochan/rimraf')
import execa = require('execa')
import fs = require('mz/fs')
import path = require('path')
import test = require('tape')
import writeYamlFile = require('write-yaml-file')
import { DEFAULT_OPTS, readWsPkgs } from './utils'
import { DEFAULT_OPTS, REGISTRY } from './utils'
test('pnpm recursive run', async (t) => {
const projects = preparePackages(t, [
@@ -57,17 +58,21 @@ test('pnpm recursive run', async (t) => {
])
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
selectedWsPkgsGraph,
})
await recursive.handler(['run', 'build'], {
await execa('pnpm', [
'install',
'-r',
'--registry',
REGISTRY,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
await run.handler(['build'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
workspaceDir: process.cwd(),
})
const outputs1 = await import(path.resolve('output1.json')) as string[]
@@ -105,17 +110,21 @@ test('pnpm recursive run concurrently', async (t) => {
])
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
selectedWsPkgsGraph,
})
await recursive.handler(['run', 'build'], {
await execa('pnpm', [
'install',
'-r',
'--registry',
REGISTRY,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
await run.handler(['build'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
workspaceDir: process.cwd(),
})
const outputs1 = await import(path.resolve('output1.json')) as number[]
@@ -154,20 +163,24 @@ test('`pnpm recursive run` fails when run without filters and no package has the
])
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
selectedWsPkgsGraph,
})
await execa('pnpm', [
'install',
'-r',
'--registry',
REGISTRY,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
let err!: PnpmError
try {
await recursive.handler(['run', 'this-command-does-not-exist'], {
await run.handler(['this-command-does-not-exist'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
workspaceDir: process.cwd(),
})
} catch (_err) {
err = _err
@@ -206,10 +219,12 @@ test('`pnpm recursive run` fails when run with a filter that includes all packag
let err!: PnpmError
try {
await recursive.handler(['run', 'this-command-does-not-exist'], {
await run.handler(['this-command-does-not-exist'], {
...DEFAULT_OPTS,
...await readWsPkgs(process.cwd(), [{ namePattern: '*' }]),
dir: process.cwd(),
recursive: true,
workspaceDir: process.cwd(),
})
} catch (_err) {
err = _err
@@ -246,22 +261,26 @@ test('`pnpm recursive run` succeeds when run against a subset of packages and no
},
])
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
selectedWsPkgsGraph,
})
await recursive.handler(['run', 'this-command-does-not-exist'], {
const { allWsPkgs } = await readWsPkgs(process.cwd(), [])
await execa('pnpm', [
'install',
'-r',
'--registry',
REGISTRY,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
await run.handler(['this-command-does-not-exist'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph: await filterPkgsBySelectorObjects(
allWsPkgs,
[{ namePattern: 'project-1' }],
{ workspaceDir: process.cwd() },
),
workspaceDir: process.cwd(),
})
t.end()
})
@@ -306,20 +325,24 @@ test('testing the bail config with "pnpm recursive run"', async (t) => {
])
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
selectedWsPkgsGraph,
})
await execa('pnpm', [
'install',
'-r',
'--registry',
REGISTRY,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
let err1!: PnpmError
try {
await recursive.handler(['run', 'build', '--no-bail'], {
await run.handler(['build', '--no-bail'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
workspaceDir: process.cwd(),
})
} catch (_err) {
err1 = _err
@@ -333,11 +356,13 @@ test('testing the bail config with "pnpm recursive run"', async (t) => {
let err2!: PnpmError
try {
await recursive.handler(['run', 'build'], {
await run.handler(['build'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
workspaceDir: process.cwd(),
})
} catch (_err) {
err2 = _err
@@ -376,22 +401,26 @@ test('pnpm recursive run with filtering', async (t) => {
},
])
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
selectedWsPkgsGraph,
})
await recursive.handler(['run', 'build'], {
const { allWsPkgs } = await readWsPkgs(process.cwd(), [])
await execa('pnpm', [
'install',
'-r',
'--registry',
REGISTRY,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
await run.handler(['build'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph: await filterPkgsBySelectorObjects(
allWsPkgs,
[{ namePattern: 'project-1' }],
{ workspaceDir: process.cwd() },
),
workspaceDir: process.cwd(),
})
const outputs = await import(path.resolve('output.json')) as string[]
@@ -415,19 +444,23 @@ test('`pnpm recursive run` should always trust the scripts', async (t) => {
},
])
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
selectedWsPkgsGraph,
})
const { allWsPkgs } = await readWsPkgs(process.cwd(), [])
await execa('pnpm', [
'install',
'-r',
'--registry',
REGISTRY,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
process.env['npm_config_unsafe_perm'] = 'false'
await recursive.handler(['run', 'build'], {
await run.handler(['build'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
workspaceDir: process.cwd(),
...await readWsPkgs(process.cwd(), []),
})
delete process.env['npm_config_unsafe_perm']

View File

@@ -1,9 +1,10 @@
import { filterPkgsBySelectorObjects } from '@pnpm/filter-workspace-packages'
import { recursive } from '@pnpm/plugin-commands-recursive'
import { filterPkgsBySelectorObjects, readWsPkgs } from '@pnpm/filter-workspace-packages'
import { test as testCommand } from '@pnpm/plugin-commands-script-runners'
import { preparePackages } from '@pnpm/prepare'
import execa = require('execa')
import path = require('path')
import test = require('tape')
import { DEFAULT_OPTS, readWsPkgs } from './utils'
import { DEFAULT_OPTS, REGISTRY } from './utils'
test('pnpm recursive test', async (t) => {
const projects = preparePackages(t, [
@@ -51,17 +52,21 @@ test('pnpm recursive test', async (t) => {
])
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
selectedWsPkgsGraph,
})
await recursive.handler(['test'], {
await execa('pnpm', [
'install',
'-r',
'--registry',
REGISTRY,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
await testCommand.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
workspaceDir: process.cwd(),
})
const outputs1 = await import(path.resolve('output1.json')) as string[]
@@ -103,18 +108,22 @@ test('`pnpm recursive test` does not fail if none of the packaegs has a test com
])
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
selectedWsPkgsGraph,
})
await execa('pnpm', [
'install',
'-r',
'--registry',
REGISTRY,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
await recursive.handler(['test'], {
await testCommand.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph,
workspaceDir: process.cwd(),
})
t.pass('command did not fail')
@@ -148,22 +157,26 @@ test('pnpm recursive test with filtering', async (t) => {
},
])
const { allWsPkgs, selectedWsPkgsGraph } = await readWsPkgs(process.cwd(), [])
await recursive.handler(['install'], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
selectedWsPkgsGraph,
})
await recursive.handler(['test'], {
const { allWsPkgs } = await readWsPkgs(process.cwd(), [])
await execa('pnpm', [
'install',
'-r',
'--registry',
REGISTRY,
'--store-dir',
path.resolve(DEFAULT_OPTS.storeDir),
])
await testCommand.handler([], {
...DEFAULT_OPTS,
allWsPkgs,
dir: process.cwd(),
recursive: true,
selectedWsPkgsGraph: await filterPkgsBySelectorObjects(
allWsPkgs,
[{ namePattern: 'project-1' }],
{ workspaceDir: process.cwd() },
),
workspaceDir: process.cwd(),
})
const outputs = await import(path.resolve('output.json')) as string[]

View File

@@ -0,0 +1,44 @@
export const REGISTRY = `https://registry.npmjs.org/`
export const DEFAULT_OPTS = {
alwaysAuth: false,
argv: {
original: [],
},
bail: false,
ca: undefined,
cert: undefined,
cliOptions: {},
fetchRetries: 2,
fetchRetryFactor: 90,
fetchRetryMaxtimeout: 90,
fetchRetryMintimeout: 10,
filter: [] as string[],
httpsProxy: undefined,
include: {
dependencies: true,
devDependencies: true,
optionalDependencies: true,
},
key: undefined,
linkWorkspacePackages: true,
localAddress: undefined,
lock: false,
lockStaleDuration: 90,
networkConcurrency: 16,
offline: false,
pending: false,
pnpmfile: './pnpmfile.js',
proxy: undefined,
rawConfig: { registry: REGISTRY },
rawLocalConfig: {},
registries: { default: REGISTRY },
registry: REGISTRY,
sort: true,
storeDir: '../store',
strictSsl: false,
userAgent: 'pnpm',
useRunningStoreServer: false,
useStoreServer: false,
workspaceConcurrency: 4,
}

View File

@@ -22,6 +22,7 @@
],
"dependencies": {
"@pnpm/cli-utils": "workspace:0.2.5",
"@pnpm/common-cli-options-help": "workspace:0.1.2",
"@pnpm/config": "workspace:6.0.0",
"@pnpm/core-loggers": "workspace:4.0.0",
"@pnpm/default-reporter": "workspace:5.0.5",
@@ -37,7 +38,6 @@
"@pnpm/plugin-commands-outdated": "workspace:0.1.9",
"@pnpm/plugin-commands-publishing": "workspace:0.1.9",
"@pnpm/plugin-commands-rebuild": "workspace:0.0.0",
"@pnpm/plugin-commands-recursive": "workspace:0.1.10",
"@pnpm/plugin-commands-script-runners": "workspace:0.1.9",
"@pnpm/plugin-commands-server": "workspace:0.0.0",
"@pnpm/plugin-commands-store": "workspace:0.0.0",

View File

@@ -5,8 +5,8 @@ import { list, why } from '@pnpm/plugin-commands-listing'
import { outdated } from '@pnpm/plugin-commands-outdated'
import { pack, publish } from '@pnpm/plugin-commands-publishing'
import { rebuild } from '@pnpm/plugin-commands-rebuild'
import { recursive } from '@pnpm/plugin-commands-recursive'
import {
exec,
restart,
run,
start,
@@ -18,6 +18,7 @@ import { store } from '@pnpm/plugin-commands-store'
import { PnpmOptions } from '../types'
import createHelp from './help'
import * as installTest from './installTest'
import * as recursive from './recursive'
import * as root from './root'
export type Command = (
@@ -35,6 +36,7 @@ const commands: Array<{
}> = [
add,
audit,
exec,
importCommand,
install,
installTest,

View File

@@ -20,6 +20,6 @@ export function help () {
}
export async function handler (input: string[], opts: PnpmOptions) {
await install.handler(input, opts)
await install.handler(input, opts, 'install')
await test.handler(input, opts)
}

View File

@@ -0,0 +1,123 @@
import { docsUrl } from '@pnpm/cli-utils'
import { FILTERING } from '@pnpm/common-cli-options-help'
import { WANTED_LOCKFILE } from '@pnpm/constants'
import { oneLine } from 'common-tags'
import renderHelp = require('render-help')
export const rcOptionsTypes = () => ({})
export const cliOptionsTypes = () => ({})
export const commandNames = ['recursive', 'multi', 'm']
export function help () {
return renderHelp({
description: oneLine`
Concurrently performs some actions in all subdirectories with a \`package.json\` (excluding node_modules).
A \`pnpm-workspace.yaml\` file may be used to control what directories are searched for packages.`,
descriptionLists: [
{
title: 'Commands',
list: [
{
name: 'install',
},
{
name: 'add',
},
{
name: 'update',
},
{
description: 'Uninstall a dependency from each package',
name: 'remove <pkg>...',
},
{
description: 'Removes links to local packages and reinstalls them from the registry.',
name: 'unlink',
},
{
description: 'List dependencies in each package.',
name: 'list [<pkg>...]',
},
{
description: 'List packages that depend on <pkg>.',
name: 'why <pkg>...',
},
{
description: 'Check for outdated dependencies in every package.',
name: 'outdated [<pkg>...]',
},
{
description: oneLine`
This runs an arbitrary command from each package's "scripts" object.
If a package doesn't have the command, it is skipped.
If none of the packages have the command, the command fails.`,
name: 'run <command> [-- <args>...]',
},
{
description: `This runs each package's "test" script, if one was provided.`,
name: 'test [-- <args>...]',
},
{
description: oneLine`
This command runs the "npm build" command on each package.
This is useful when you install a new version of node,
and must recompile all your C++ addons with the new binary.`,
name: 'rebuild [[<@scope>/<name>]...]',
},
{
description: `Run a command in each package.`,
name: 'exec -- <command> [args...]',
},
{
description: 'Publishes packages to the npm registry. Only publishes a package if its version is not taken in the registry.',
name: 'publish [--tag <tag>] [--access <public|restricted>]',
},
],
},
{
title: 'Options',
list: [
{
description: 'Continues executing other tasks even if a task threw an error.',
name: '--no-bail',
},
{
description: 'Set the maximum number of concurrency. Default is 4. For unlimited concurrency use Infinity.',
name: '--workspace-concurrency <number>',
},
{
description: oneLine`
Locally available packages are linked to node_modules instead of being downloaded from the registry.
Convenient to use in a multi-package repository.`,
name: '--link-workspace-packages',
},
{
description: 'Sort packages topologically (dependencies before dependents). Pass --no-sort to disable.',
name: '--sort',
},
{
description: oneLine`
Creates a single ${WANTED_LOCKFILE} file in the root of the workspace.
A shared lockfile also means that all dependencies of all workspace packages will be in a single node_modules.`,
name: '--shared-workspace-lockfile',
},
],
},
FILTERING,
],
url: docsUrl('recursive'),
usages: [
'pnpm recursive [command] [flags] [--filter <package selector>]',
'pnpm multi [command] [flags] [--filter <package selector>]',
'pnpm m [command] [flags] [--filter <package selector>]'
],
})
}
export function handler () {
console.log(help())
process.exit(1)
}

View File

@@ -130,21 +130,6 @@ export default async function run (inputArgv: string[]) {
process.env['FORCE_COLOR'] = '0'
}
if (
cmd === 'add' &&
workspaceDir === dir &&
!config.ignoreWorkspaceRootCheck
) {
// Reporting is not initialized at this point, so just printing the error
console.error(`${chalk.bgRed.black('\u2009ERROR\u2009')} ${
chalk.red('Running this command will add the dependency to the workspace root, ' +
'which might not be what you want - if you really meant it, ' +
'make it explicit by running this command again with the -W flag (or --ignore-workspace-root-check).')}`)
console.log(`For help, run: pnpm help ${cmd}`)
process.exit(1)
return
}
const selfUpdate = config.global && (cmd === 'add' || cmd === 'update') && argv.remain.includes(packageManager.name)
// Don't check for updates
@@ -172,7 +157,7 @@ export default async function run (inputArgv: string[]) {
await pnpmCmds.server(['stop'], config as any) // tslint:disable-line:no-any
}
if (cmd === 'recursive') {
if (cliConf['recursive']) {
const wsDir = workspaceDir ?? process.cwd()
const allWsPkgs = await findWorkspacePackages(wsDir, config)
@@ -186,6 +171,7 @@ export default async function run (inputArgv: string[]) {
workspaceDir: wsDir,
})
config.allWsPkgs = allWsPkgs
config.workspaceDir = wsDir
}
// NOTE: we defer the next stage, otherwise reporter might not catch all the logs
@@ -198,7 +184,7 @@ export default async function run (inputArgv: string[]) {
})
}
if (cmd !== 'recursive') {
if (!cliConf['recursive']) {
scopeLogger.debug(workspaceDir
? { selected: 1, workspacePrefix: workspaceDir }
: { selected: 1 })

View File

@@ -323,7 +323,7 @@ test('`pnpm recursive add` should fail if no package name was provided', (t: tap
const { status, stdout } = execPnpmSync('recursive', 'add')
t.equal(status, 1)
t.ok(stdout.toString().includes('`pnpm recursive add` requires the package name'))
t.ok(stdout.toString().includes('`pnpm add` requires the package name'))
t.end()
})

View File

@@ -371,12 +371,12 @@ test('adding new dependency in the root should fail if --ignore-workspace-root-c
await fs.writeFile('pnpm-workspace.yaml', '', 'utf8')
{
const { status, stderr } = execPnpmSync('add', 'is-positive')
const { status, stdout } = execPnpmSync('add', 'is-positive')
t.equal(status, 1)
t.ok(
stderr.toString().includes(
stdout.toString().includes(
'Running this command will add the dependency to the workspace root, ' +
'which might not be what you want - if you really meant it, ' +
'make it explicit by running this command again with the -W flag (or --ignore-workspace-root-check).'

View File

@@ -0,0 +1,15 @@
# @pnpm/sort-packages
> Sort packages
[![npm version](https://img.shields.io/npm/v/@pnpm/sort-packages.svg)](https://www.npmjs.com/package/@pnpm/plugin-commands-recursive)
## Installation
```sh
<pnpm|npm|yarn> add @pnpm/sort-packages
```
## License
MIT © [Zoltan Kochan](https://www.kochan.io/)

View File

@@ -0,0 +1,37 @@
{
"name": "@pnpm/sort-packages",
"version": "0.0.0",
"description": "Sort packages",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
"files": [
"lib"
],
"engines": {
"node": ">=10"
},
"scripts": {
"lint": "tslint -c tslint.json src/**/*.ts test/**/*.ts",
"tsc": "rimraf lib && tsc",
"test": "pnpm run tsc && pnpm run lint",
"prepublishOnly": "pnpm run tsc"
},
"repository": "https://github.com/pnpm/pnpm/blob/master/packages/sort-packages",
"keywords": [
"pnpm"
],
"author": "Zoltan Kochan <z@kochan.io> (https://www.kochan.io/)",
"license": "MIT",
"bugs": {
"url": "https://github.com/pnpm/pnpm/issues"
},
"homepage": "https://pnpm.js.org",
"devDependencies": {
"@pnpm/sort-packages": "link:",
"rimraf": "3.0.0"
},
"dependencies": {
"@pnpm/config": "workspace:6.0.0",
"graph-sequencer": "2.0.0"
}
}

View File

@@ -0,0 +1,68 @@
import { WsPkgsGraph } from '@pnpm/config'
import graphSequencer = require('graph-sequencer')
export default function sortPackages (pkgGraph: WsPkgsGraph): string[][] {
const keys = Object.keys(pkgGraph)
const setOfKeys = new Set(keys)
const graph = new Map(
keys.map((pkgPath) => [
pkgPath,
pkgGraph[pkgPath].dependencies.filter(
/* remove cycles of length 1 (ie., package 'a' depends on 'a'). They
confuse the graph-sequencer, but can be ignored when ordering packages
topologically.
See the following example where 'b' and 'c' depend on themselves:
graphSequencer({graph: new Map([
['a', ['b', 'c']],
['b', ['b']],
['c', ['b', 'c']]]
),
groups: [['a', 'b', 'c']]})
returns chunks:
[['b'],['a'],['c']]
But both 'b' and 'c' should be executed _before_ 'a', because 'a' depends on
them. It works (and is considered 'safe' if we run:)
graphSequencer({graph: new Map([
['a', ['b', 'c']],
['b', []],
['c', ['b']]]
), groups: [['a', 'b', 'c']]})
returning:
[['b'], ['c'], ['a']]
*/
d => d !== pkgPath &&
/* remove unused dependencies that we can ignore due to a filter expression.
Again, the graph sequencer used to behave weirdly in the following edge case:
graphSequencer({graph: new Map([
['a', ['b', 'c']],
['d', ['a']],
['e', ['a', 'b', 'c']]]
),
groups: [['a', 'e', 'e']]})
returns chunks:
[['d'],['a'],['e']]
But we really want 'a' to be executed first.
*/
setOfKeys.has(d))]
) as Array<[string, string[]]>,
)
const graphSequencerResult = graphSequencer({
graph,
groups: [keys],
})
return graphSequencerResult.chunks
}

252
pnpm-lock.yaml generated
View File

@@ -86,6 +86,7 @@ importers:
dependencies:
'@pnpm/config': 'link:../config'
'@pnpm/default-resolver': 'link:../default-resolver'
'@pnpm/error': 'link:../error'
'@pnpm/package-is-installable': 'link:../package-is-installable'
'@pnpm/read-importer-manifest': 'link:../read-importer-manifest'
'@pnpm/utils': 'link:../utils'
@@ -107,6 +108,7 @@ importers:
'@pnpm/cli-utils': 'link:'
'@pnpm/config': 'workspace:6.0.0'
'@pnpm/default-resolver': 'workspace:6.0.3'
'@pnpm/error': 'workspace:1.0.0'
'@pnpm/logger': ^3.1.0
'@pnpm/package-is-installable': 'workspace:4.0.1'
'@pnpm/read-importer-manifest': 'workspace:2.0.1'
@@ -404,6 +406,7 @@ importers:
packages/filter-workspace-packages:
dependencies:
'@pnpm/error': 'link:../error'
'@pnpm/find-workspace-packages': 'link:../find-workspace-packages'
'@pnpm/matcher': 'link:../matcher'
execa: 4.0.0
find-up: 4.1.0
@@ -424,6 +427,7 @@ importers:
specifiers:
'@pnpm/error': 'workspace:1.0.0'
'@pnpm/filter-workspace-packages': 'link:'
'@pnpm/find-workspace-packages': 'workspace:2.0.8'
'@pnpm/matcher': 'workspace:1.0.0'
'@types/is-ci': ^2.0.0
'@types/is-windows': ^1.0.0
@@ -464,6 +468,7 @@ importers:
packages/find-workspace-packages:
dependencies:
'@pnpm/cli-utils': 'link:../cli-utils'
'@pnpm/config': 'link:../config'
'@pnpm/constants': 'link:../constants'
'@pnpm/types': 'link:../types'
find-packages: 'link:../find-packages'
@@ -473,6 +478,7 @@ importers:
rimraf: 3.0.0
specifiers:
'@pnpm/cli-utils': 'workspace:0.2.5'
'@pnpm/config': 'workspace:6.0.0'
'@pnpm/constants': 'workspace:3.0.0'
'@pnpm/find-workspace-packages': 'link:'
'@pnpm/types': 'workspace:4.0.0'
@@ -1337,56 +1343,92 @@ importers:
'@pnpm/common-cli-options-help': 'link:../common-cli-options-help'
'@pnpm/config': 'link:../config'
'@pnpm/constants': 'link:../constants'
'@pnpm/core-loggers': 'link:../core-loggers'
'@pnpm/error': 'link:../error'
'@pnpm/filter-workspace-packages': 'link:../filter-workspace-packages'
'@pnpm/find-workspace-dir': 'link:../find-workspace-dir'
'@pnpm/find-workspace-packages': 'link:../find-workspace-packages'
'@pnpm/package-store': 'link:../package-store'
'@pnpm/plugin-commands-rebuild': 'link:../plugin-commands-rebuild'
'@pnpm/plugin-commands-recursive': 'link:../plugin-commands-recursive'
'@pnpm/pnpmfile': 'link:../pnpmfile'
'@pnpm/resolver-base': 'link:../resolver-base'
'@pnpm/sort-packages': 'link:../sort-packages'
'@pnpm/store-connection-manager': 'link:../store-connection-manager'
'@pnpm/types': 'link:../types'
'@pnpm/utils': 'link:../utils'
camelcase-keys: 6.1.1
common-tags: 1.8.0
is-subdir: 1.1.1
mem: 6.0.1
mz: 2.7.0
p-filter: 2.1.0
p-limit: 2.2.1
path-absolute: 1.0.1
path-exists: 4.0.0
ramda: 0.26.1
read-ini-file: 2.0.0
render-help: 0.0.0
supi: 'link:../supi'
devDependencies:
'@pnpm/lockfile-types': 'link:../lockfile-types'
'@pnpm/logger': 3.1.0
'@pnpm/plugin-commands-installation': 'link:'
'@pnpm/prepare': 'link:../../privatePackages/prepare'
'@pnpm/registry-mock': 1.11.1
'@pnpm/test-fixtures': 'link:../../privatePackages/test-fixtures'
'@types/common-tags': 1.8.0
'@types/mz': 2.7.0
'@types/ramda': 0.26.38
make-dir: 3.0.0
read-yaml-file: 1.1.0
rimraf: 3.0.0
write-json-file: 4.2.1
write-yaml-file: 3.0.1
specifiers:
'@pnpm/cli-utils': 'workspace:0.2.5'
'@pnpm/common-cli-options-help': 'workspace:0.1.2'
'@pnpm/config': 'workspace:6.0.0'
'@pnpm/constants': 'workspace:3.0.0'
'@pnpm/core-loggers': 'workspace:4.0.0'
'@pnpm/error': 'workspace:1.0.0'
'@pnpm/filter-workspace-packages': 'workspace:1.0.1'
'@pnpm/find-workspace-dir': 'workspace:1.0.0'
'@pnpm/find-workspace-packages': 'workspace:2.0.8'
'@pnpm/lockfile-types': 'workspace:1.1.0'
'@pnpm/logger': ^3.1.0
'@pnpm/package-store': 'workspace:7.0.2'
'@pnpm/plugin-commands-installation': 'link:'
'@pnpm/plugin-commands-rebuild': 'workspace:0.0.0'
'@pnpm/plugin-commands-recursive': 'workspace:0.1.10'
'@pnpm/pnpmfile': 'workspace:0.1.0'
'@pnpm/prepare': 'workspace:0.0.0'
'@pnpm/registry-mock': 1.11.1
'@pnpm/resolver-base': 'workspace:6.0.0'
'@pnpm/sort-packages': 'workspace:0.0.0'
'@pnpm/store-connection-manager': 'workspace:0.2.5'
'@pnpm/test-fixtures': 'workspace:0.0.0'
'@pnpm/types': 'workspace:4.0.0'
'@pnpm/utils': 'workspace:0.12.2'
'@types/common-tags': ^1.8.0
'@types/mz': ^2.7.0
'@types/ramda': ^0.26.38
camelcase-keys: 6.1.1
common-tags: 1.8.0
is-subdir: 1.1.1
make-dir: 3.0.0
mem: 6.0.1
mz: 2.7.0
p-filter: 2.1.0
p-limit: 2.2.1
path-absolute: 1.0.1
path-exists: 4.0.0
ramda: 0.26.1
read-ini-file: 2.0.0
read-yaml-file: 1.1.0
render-help: 0.0.0
rimraf: 3.0.0
supi: 'workspace:0.37.6'
write-json-file: 4.2.1
write-yaml-file: 3.0.1
packages/plugin-commands-listing:
dependencies:
'@pnpm/cli-utils': 'link:../cli-utils'
@@ -1399,6 +1441,9 @@ importers:
render-help: 0.0.0
devDependencies:
'@pnpm/constants': 'link:../constants'
'@pnpm/filter-workspace-packages': 'link:../filter-workspace-packages'
'@pnpm/logger': 3.1.0
'@pnpm/plugin-commands-installation': 'link:../plugin-commands-installation'
'@pnpm/plugin-commands-listing': 'link:'
'@pnpm/prepare': 'link:../../privatePackages/prepare'
'@types/common-tags': 1.8.0
@@ -1415,7 +1460,10 @@ importers:
'@pnpm/config': 'workspace:6.0.0'
'@pnpm/constants': 'workspace:3.0.0'
'@pnpm/error': 'workspace:1.0.0'
'@pnpm/filter-workspace-packages': 'workspace:1.0.1'
'@pnpm/list': 'workspace:4.0.12'
'@pnpm/logger': ^3.1.0
'@pnpm/plugin-commands-installation': 'workspace:*'
'@pnpm/plugin-commands-listing': 'link:'
'@pnpm/prepare': 'workspace:0.0.0'
'@types/common-tags': 1.8.0
@@ -1449,6 +1497,8 @@ importers:
wrap-ansi: 6.2.0
devDependencies:
'@pnpm/constants': 'link:../constants'
'@pnpm/filter-workspace-packages': 'link:../filter-workspace-packages'
'@pnpm/plugin-commands-installation': 'link:../plugin-commands-installation'
'@pnpm/plugin-commands-outdated': 'link:'
'@pnpm/prepare': 'link:../../privatePackages/prepare'
'@pnpm/types': 'link:../types'
@@ -1467,10 +1517,12 @@ importers:
'@pnpm/config': 'workspace:6.0.0'
'@pnpm/constants': 'workspace:3.0.0'
'@pnpm/error': 'workspace:1.0.0'
'@pnpm/filter-workspace-packages': 'workspace:1.0.1'
'@pnpm/lockfile-file': 'workspace:3.0.1'
'@pnpm/matcher': 'workspace:1.0.0'
'@pnpm/modules-yaml': 'workspace:5.0.0'
'@pnpm/outdated': 'workspace:6.0.5'
'@pnpm/plugin-commands-installation': 'workspace:*'
'@pnpm/plugin-commands-outdated': 'link:'
'@pnpm/prepare': 'workspace:0.0.0'
'@pnpm/semver-diff': 1.0.2
@@ -1496,23 +1548,32 @@ importers:
'@pnpm/cli-utils': 'link:../cli-utils'
'@pnpm/config': 'link:../config'
'@pnpm/error': 'link:../error'
'@pnpm/npm-resolver': 'link:../npm-resolver'
'@pnpm/read-importer-manifest': 'link:../read-importer-manifest'
'@pnpm/resolver-base': 'link:../resolver-base'
'@pnpm/run-npm': 'link:../run-npm'
'@pnpm/store-path': 2.1.1
'@pnpm/types': 'link:../types'
'@pnpm/utils': 'link:../utils'
'@zkochan/rimraf': 1.0.0
cp-file: 7.0.0
fast-glob: 3.1.1
lru-cache: 5.1.1
mz: 2.7.0
p-filter: 2.1.0
ramda: 0.26.1
render-help: 0.0.0
write-json-file: 4.2.1
devDependencies:
'@pnpm/filter-workspace-packages': 'link:../filter-workspace-packages'
'@pnpm/plugin-commands-publishing': 'link:'
'@pnpm/prepare': 'link:../../privatePackages/prepare'
'@types/cross-spawn': 6.0.1
'@types/lru-cache': 5.1.0
'@types/mz': 2.7.0
'@types/ramda': 0.26.38
cross-spawn: 7.0.1
execa: 4.0.0
path-exists: 4.0.0
rimraf: 3.0.0
write-yaml-file: 3.0.1
@@ -1520,19 +1581,28 @@ importers:
'@pnpm/cli-utils': 'workspace:0.2.5'
'@pnpm/config': 'workspace:6.0.0'
'@pnpm/error': 'workspace:1.0.0'
'@pnpm/filter-workspace-packages': 'workspace:1.0.1'
'@pnpm/npm-resolver': 'workspace:6.0.2'
'@pnpm/plugin-commands-publishing': 'link:'
'@pnpm/prepare': 'workspace:0.0.0'
'@pnpm/read-importer-manifest': 'workspace:2.0.1'
'@pnpm/resolver-base': 'workspace:6.0.0'
'@pnpm/run-npm': 'workspace:1.0.0'
'@pnpm/store-path': 2.1.1
'@pnpm/types': 'workspace:4.0.0'
'@pnpm/utils': 'workspace:0.12.2'
'@types/cross-spawn': ^6.0.1
'@types/lru-cache': ^5.1.0
'@types/mz': ^2.7.0
'@types/ramda': ^0.26.38
'@zkochan/rimraf': 1.0.0
cp-file: 7.0.0
cross-spawn: 7.0.1
execa: 4.0.0
fast-glob: 3.1.1
lru-cache: 5.1.1
mz: 2.7.0
p-filter: 2.1.0
path-exists: 4.0.0
ramda: 0.26.1
render-help: 0.0.0
@@ -1546,6 +1616,7 @@ importers:
'@pnpm/config': 'link:../config'
'@pnpm/constants': 'link:../constants'
'@pnpm/core-loggers': 'link:../core-loggers'
'@pnpm/find-workspace-packages': 'link:../find-workspace-packages'
'@pnpm/get-context': 'link:../get-context'
'@pnpm/lifecycle': 'link:../lifecycle'
'@pnpm/link-bins': 5.0.1
@@ -1553,21 +1624,26 @@ importers:
'@pnpm/lockfile-walker': 'link:../lockfile-walker'
'@pnpm/modules-yaml': 'link:../modules-yaml'
'@pnpm/pkgid-to-filename': 2.0.0
'@pnpm/sort-packages': 'link:../sort-packages'
'@pnpm/store-connection-manager': 'link:../store-connection-manager'
'@pnpm/store-controller-types': 'link:../store-controller-types'
'@pnpm/types': 'link:../types'
'@pnpm/utils': 'link:../utils'
'@zkochan/npm-package-arg': 1.0.2
camelcase-keys: 6.1.1
common-tags: 1.8.0
dependency-path: 'link:../dependency-path'
graph-sequencer: 2.0.0
load-json-file: 6.2.0
mem: 6.0.1
p-limit: 2.2.1
ramda: 0.26.1
read-ini-file: 2.0.0
render-help: 0.0.0
run-groups: 2.0.1
semver: 7.1.1
devDependencies:
'@pnpm/filter-workspace-packages': 'link:../filter-workspace-packages'
'@pnpm/logger': 3.1.0
'@pnpm/plugin-commands-rebuild': 'link:'
'@pnpm/prepare': 'link:../../privatePackages/prepare'
@@ -1581,12 +1657,15 @@ importers:
path-exists: 4.0.0
rimraf: 3.0.0
sinon: 8.0.0
write-yaml-file: 3.0.1
specifiers:
'@pnpm/cli-utils': 'workspace:0.2.5'
'@pnpm/common-cli-options-help': 'workspace:0.1.2'
'@pnpm/config': 'workspace:6.0.0'
'@pnpm/constants': 'workspace:3.0.0'
'@pnpm/core-loggers': 'workspace:4.0.0'
'@pnpm/filter-workspace-packages': 'workspace:1.0.1'
'@pnpm/find-workspace-packages': 'workspace:2.0.8'
'@pnpm/get-context': 'workspace:0.0.0'
'@pnpm/lifecycle': 'workspace:8.0.1'
'@pnpm/link-bins': 5.0.1
@@ -1598,6 +1677,7 @@ importers:
'@pnpm/plugin-commands-rebuild': 'link:'
'@pnpm/prepare': 'workspace:0.0.0'
'@pnpm/registry-mock': 1.11.1
'@pnpm/sort-packages': 'workspace:0.0.0'
'@pnpm/store-connection-manager': 'workspace:0.2.5'
'@pnpm/store-controller-types': 'workspace:6.0.0'
'@pnpm/test-fixtures': 'workspace:0.0.0'
@@ -1608,138 +1688,22 @@ importers:
'@types/semver': ^6.2.0
'@types/sinon': ^7.5.1
'@zkochan/npm-package-arg': 1.0.2
camelcase-keys: 6.1.1
common-tags: 1.8.0
dependency-path: 'workspace:4.0.2'
execa: 4.0.0
graph-sequencer: 2.0.0
load-json-file: 6.2.0
mem: 6.0.1
p-limit: 2.2.1
path-exists: 4.0.0
ramda: 0.26.1
read-ini-file: 2.0.0
render-help: 0.0.0
rimraf: 3.0.0
run-groups: 2.0.1
semver: 7.1.1
sinon: 8.0.0
packages/plugin-commands-recursive:
dependencies:
'@pnpm/cli-utils': 'link:../cli-utils'
'@pnpm/common-cli-options-help': 'link:../common-cli-options-help'
'@pnpm/config': 'link:../config'
'@pnpm/constants': 'link:../constants'
'@pnpm/core-loggers': 'link:../core-loggers'
'@pnpm/error': 'link:../error'
'@pnpm/filter-workspace-packages': 'link:../filter-workspace-packages'
'@pnpm/find-workspace-packages': 'link:../find-workspace-packages'
'@pnpm/lifecycle': 'link:../lifecycle'
'@pnpm/lockfile-file': 'link:../lockfile-file'
'@pnpm/matcher': 'link:../matcher'
'@pnpm/npm-resolver': 'link:../npm-resolver'
'@pnpm/outdated': 'link:../outdated'
'@pnpm/plugin-commands-listing': 'link:../plugin-commands-listing'
'@pnpm/plugin-commands-outdated': 'link:../plugin-commands-outdated'
'@pnpm/plugin-commands-publishing': 'link:../plugin-commands-publishing'
'@pnpm/plugin-commands-rebuild': 'link:../plugin-commands-rebuild'
'@pnpm/pnpmfile': 'link:../pnpmfile'
'@pnpm/resolver-base': 'link:../resolver-base'
'@pnpm/run-npm': 'link:../run-npm'
'@pnpm/store-connection-manager': 'link:../store-connection-manager'
'@pnpm/store-path': 2.1.1
'@pnpm/types': 'link:../types'
'@pnpm/utils': 'link:../utils'
camelcase-keys: 6.1.1
chalk: 3.0.0
common-tags: 1.8.0
execa: 4.0.0
graph-sequencer: 2.0.0
is-subdir: 1.1.1
lru-cache: 5.1.1
mem: 6.0.1
mz: 2.7.0
p-filter: 2.1.0
p-limit: 2.2.1
pkgs-graph: 'link:../pkgs-graph'
ramda: 0.26.1
read-ini-file: 2.0.0
render-help: 0.0.0
supi: 'link:../supi'
table: 5.4.6
devDependencies:
'@pnpm/lockfile-types': 'link:../lockfile-types'
'@pnpm/logger': 3.1.0
'@pnpm/plugin-commands-recursive': 'link:'
'@pnpm/prepare': 'link:../../privatePackages/prepare'
'@types/common-tags': 1.8.0
'@types/lru-cache': 5.1.0
'@types/mz': 2.7.0
'@types/ramda': 0.26.38
'@types/table': 4.0.7
'@zkochan/rimraf': 1.0.0
make-dir: 3.0.0
path-exists: 4.0.0
read-yaml-file: 1.1.0
rimraf: 3.0.0
strip-ansi: 6.0.0
write-json-file: 4.2.1
write-yaml-file: 3.0.1
specifiers:
'@pnpm/cli-utils': 'workspace:0.2.5'
'@pnpm/common-cli-options-help': 'workspace:0.1.2'
'@pnpm/config': 'workspace:6.0.0'
'@pnpm/constants': 'workspace:3.0.0'
'@pnpm/core-loggers': 'workspace:4.0.0'
'@pnpm/error': 'workspace:1.0.0'
'@pnpm/filter-workspace-packages': 'workspace:1.0.1'
'@pnpm/find-workspace-packages': 'workspace:2.0.8'
'@pnpm/lifecycle': 'workspace:8.0.1'
'@pnpm/lockfile-file': 'workspace:3.0.1'
'@pnpm/lockfile-types': 'workspace:1.1.0'
'@pnpm/logger': 3.1.0
'@pnpm/matcher': 'workspace:1.0.0'
'@pnpm/npm-resolver': 'workspace:6.0.2'
'@pnpm/outdated': 'workspace:6.0.5'
'@pnpm/plugin-commands-listing': 'workspace:0.1.9'
'@pnpm/plugin-commands-outdated': 'workspace:0.1.9'
'@pnpm/plugin-commands-publishing': 'workspace:0.1.9'
'@pnpm/plugin-commands-rebuild': 'workspace:0.0.0'
'@pnpm/plugin-commands-recursive': 'link:'
'@pnpm/pnpmfile': 'workspace:0.1.0'
'@pnpm/prepare': 'workspace:0.0.0'
'@pnpm/resolver-base': 'workspace:6.0.0'
'@pnpm/run-npm': 'workspace:1.0.0'
'@pnpm/store-connection-manager': 'workspace:0.2.5'
'@pnpm/store-path': 2.1.1
'@pnpm/types': 'workspace:4.0.0'
'@pnpm/utils': 'workspace:0.12.2'
'@types/common-tags': ^1.8.0
'@types/lru-cache': ^5.1.0
'@types/mz': ^2.7.0
'@types/ramda': ^0.26.38
'@types/table': ^4.0.7
'@zkochan/rimraf': 1.0.0
camelcase-keys: 6.1.1
chalk: 3.0.0
common-tags: 1.8.0
execa: 4.0.0
graph-sequencer: 2.0.0
is-subdir: 1.1.1
lru-cache: 5.1.1
make-dir: 3.0.0
mem: 6.0.1
mz: 2.7.0
p-filter: 2.1.0
p-limit: 2.2.1
path-exists: 4.0.0
pkgs-graph: 'workspace:5.0.1'
ramda: 0.26.1
read-ini-file: 2.0.0
read-yaml-file: 1.1.0
render-help: 0.0.0
rimraf: 3.0.0
strip-ansi: 6.0.0
supi: 'workspace:0.37.6'
table: 5.4.6
write-json-file: 4.2.1
write-yaml-file: 3.0.1
packages/plugin-commands-script-runners:
dependencies:
@@ -1748,39 +1712,51 @@ importers:
'@pnpm/config': 'link:../config'
'@pnpm/error': 'link:../error'
'@pnpm/lifecycle': 'link:../lifecycle'
'@pnpm/sort-packages': 'link:../sort-packages'
'@pnpm/types': 'link:../types'
'@pnpm/utils': 'link:../utils'
common-tags: 1.8.0
p-limit: 2.2.1
ramda: 0.26.1
render-help: 0.0.0
devDependencies:
'@pnpm/filter-workspace-packages': 'link:../filter-workspace-packages'
'@pnpm/logger': 3.1.0
'@pnpm/plugin-commands-script-runners': 'link:'
'@pnpm/prepare': 'link:../../privatePackages/prepare'
'@types/common-tags': 1.8.0
'@types/mz': 2.7.0
'@types/ramda': 0.26.38
'@zkochan/rimraf': 1.0.0
execa: 4.0.0
mz: 2.7.0
rimraf: 3.0.0
write-yaml-file: 3.0.1
specifiers:
'@pnpm/cli-utils': 'workspace:0.2.5'
'@pnpm/common-cli-options-help': 'workspace:0.1.2'
'@pnpm/config': 'workspace:6.0.0'
'@pnpm/error': 'workspace:1.0.0'
'@pnpm/filter-workspace-packages': 'workspace:1.0.1'
'@pnpm/lifecycle': 'workspace:8.0.1'
'@pnpm/logger': ^3.1.0
'@pnpm/plugin-commands-script-runners': 'link:'
'@pnpm/prepare': 'workspace:0.0.0'
'@pnpm/sort-packages': 'workspace:0.0.0'
'@pnpm/types': 'workspace:4.0.0'
'@pnpm/utils': 'workspace:0.12.2'
'@types/common-tags': ^1.8.0
'@types/mz': ^2.7.0
'@types/ramda': ^0.26.38
'@zkochan/rimraf': 1.0.0
common-tags: 1.8.0
execa: 4.0.0
mz: 2.7.0
p-limit: 2.2.1
ramda: 0.26.1
render-help: 0.0.0
rimraf: 3.0.0
write-yaml-file: 3.0.1
packages/plugin-commands-server:
dependencies:
'@pnpm/cli-utils': 'link:../cli-utils'
@@ -1908,6 +1884,7 @@ importers:
packages/pnpm:
dependencies:
'@pnpm/cli-utils': 'link:../cli-utils'
'@pnpm/common-cli-options-help': 'link:../common-cli-options-help'
'@pnpm/config': 'link:../config'
'@pnpm/core-loggers': 'link:../core-loggers'
'@pnpm/default-reporter': 'link:../default-reporter'
@@ -1923,7 +1900,6 @@ importers:
'@pnpm/plugin-commands-outdated': 'link:../plugin-commands-outdated'
'@pnpm/plugin-commands-publishing': 'link:../plugin-commands-publishing'
'@pnpm/plugin-commands-rebuild': 'link:../plugin-commands-rebuild'
'@pnpm/plugin-commands-recursive': 'link:../plugin-commands-recursive'
'@pnpm/plugin-commands-script-runners': 'link:../plugin-commands-script-runners'
'@pnpm/plugin-commands-server': 'link:../plugin-commands-server'
'@pnpm/plugin-commands-store': 'link:../plugin-commands-store'
@@ -1995,6 +1971,7 @@ importers:
specifiers:
'@pnpm/assert-project': 'workspace:*'
'@pnpm/cli-utils': 'workspace:0.2.5'
'@pnpm/common-cli-options-help': 'workspace:0.1.2'
'@pnpm/config': 'workspace:6.0.0'
'@pnpm/constants': 'workspace:3.0.0'
'@pnpm/core-loggers': 'workspace:4.0.0'
@@ -2014,7 +1991,6 @@ importers:
'@pnpm/plugin-commands-outdated': 'workspace:0.1.9'
'@pnpm/plugin-commands-publishing': 'workspace:0.1.9'
'@pnpm/plugin-commands-rebuild': 'workspace:0.0.0'
'@pnpm/plugin-commands-recursive': 'workspace:0.1.10'
'@pnpm/plugin-commands-script-runners': 'workspace:0.1.9'
'@pnpm/plugin-commands-server': 'workspace:0.0.0'
'@pnpm/plugin-commands-store': 'workspace:0.0.0'
@@ -2309,6 +2285,18 @@ importers:
promise-share: 1.0.0
rimraf: 3.0.0
uuid: 3.3.3
packages/sort-packages:
dependencies:
'@pnpm/config': 'link:../config'
graph-sequencer: 2.0.0
devDependencies:
'@pnpm/sort-packages': 'link:'
rimraf: 3.0.0
specifiers:
'@pnpm/config': 'workspace:6.0.0'
'@pnpm/sort-packages': 'link:'
graph-sequencer: 2.0.0
rimraf: 3.0.0
packages/store-connection-manager:
dependencies:
'@pnpm/cli-utils': 'link:../cli-utils'
@@ -3281,7 +3269,7 @@ packages:
dependencies:
'@types/events': 3.0.0
'@types/minimatch': 3.0.3
'@types/node': 12.12.21
'@types/node': 13.1.0
resolution:
integrity: sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==
/@types/graceful-fs/4.1.3:
@@ -3338,7 +3326,7 @@ packages:
integrity: sha512-U5icWpv7YnZYGsN4/cmh3WD2onMY0aJIiTE6+51TwJCttdHvtCYmkBNOobHlXwrJRL0nkH9jH4kD+1FAdMN4Tg==
/@types/mz/2.7.0:
dependencies:
'@types/node': 12.12.21
'@types/node': 13.1.1
resolution:
integrity: sha512-Q5TZYMKnH0hdV5fNstmMWL2LLw5eRRtTd73KNtsZxoQ2gtCQyET5X79uERUEwGneuxPglg441I7OSY00+9CkSw==
/@types/ncp/2.0.3:
@@ -3360,6 +3348,12 @@ packages:
/@types/node/12.12.21:
resolution:
integrity: sha512-8sRGhbpU+ck1n0PGAUgVrWrWdjSW2aqNeyC15W88GRsMpSwzv6RJGlLhE7s2RhVSOdyDmxbqlWSeThq4/7xqlA==
/@types/node/13.1.0:
resolution:
integrity: sha512-zwrxviZS08kRX40nqBrmERElF2vpw4IUTd5khkhBTfFH8AOaeoLVx48EC4+ZzS2/Iga7NevncqnsUSYjM4OWYA==
/@types/node/13.1.1:
resolution:
integrity: sha512-hx6zWtudh3Arsbl3cXay+JnkvVgCKzCWKv42C9J01N2T2np4h8w5X8u6Tpz5mj38kE3M9FM0Pazx8vKFFMnjLQ==
/@types/nopt/3.0.29:
dev: true
resolution:
@@ -3623,7 +3617,7 @@ packages:
/@zkochan/rimraf/1.0.0:
dependencies:
'@types/glob': 7.1.1
'@types/node': 12.12.21
'@types/node': 13.1.0
rimraf: 3.0.0
engines:
node: '>=8.15'
@@ -5783,7 +5777,7 @@ packages:
human-signals: 1.1.1
is-stream: 2.0.0
merge-stream: 2.0.0
npm-run-path: 4.0.0
npm-run-path: 4.0.1
onetime: 5.1.0
signal-exit: 3.0.2
strip-final-newline: 2.0.0
@@ -8353,13 +8347,13 @@ packages:
node: '>=4'
resolution:
integrity: sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
/npm-run-path/4.0.0:
/npm-run-path/4.0.1:
dependencies:
path-key: 3.1.1
engines:
node: '>=8'
resolution:
integrity: sha512-8eyAOAH+bYXFPSnNnKr3J+yoybe8O87Is5rtAQ8qRczJz1ajcsjg8l2oZqP+Ppx15Ii3S1vUTjQN2h4YO2tWWQ==
integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
/npm/4.6.1:
bundledDependencies:
- abbrev