mirror of
https://github.com/pnpm/pnpm.git
synced 2026-04-03 15:01:48 -04:00
feat: support -a option in pnpm --help to list all commands (#8628)
close #8624 --------- Co-authored-by: Zoltan Kochan <z@kochan.io>
This commit is contained in:
5
.changeset/popular-suits-repair.md
Normal file
5
.changeset/popular-suits-repair.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"pnpm": minor
|
||||
---
|
||||
|
||||
Support `--all` option in `pnpm --help` to list all commands [#8628](https://github.com/pnpm/pnpm/pull/8628).
|
||||
@@ -1,187 +1,378 @@
|
||||
import { packageManager, detectIfCurrentPkgIsExecutable } from '@pnpm/cli-meta'
|
||||
import { docsUrl } from '@pnpm/cli-utils'
|
||||
import renderHelp from 'render-help'
|
||||
import { type CommandDefinition } from './index.js'
|
||||
|
||||
export function createHelp (helpByCommandName: Record<string, () => string>): (opts: unknown, params: string[]) => string {
|
||||
return function (opts: unknown, params: string[]) {
|
||||
let helpText!: string
|
||||
if (params.length === 0) {
|
||||
helpText = getHelpText()
|
||||
} else if (helpByCommandName[params[0]]) {
|
||||
helpText = helpByCommandName[params[0]]()
|
||||
} else {
|
||||
helpText = `No results for "${params[0]}"`
|
||||
}
|
||||
return `Version ${packageManager.version}\
|
||||
${detectIfCurrentPkgIsExecutable() != null ? ` (compiled to binary; bundled Node.js ${process.version})` : ''}\
|
||||
\n${helpText}\n`
|
||||
type HelpByCommandName = Record<string, () => string>
|
||||
|
||||
export function createHelp (helpByCommandName: HelpByCommandName): CommandDefinition {
|
||||
return {
|
||||
commandNames: ['help'],
|
||||
shorthands: {
|
||||
a: '--all',
|
||||
},
|
||||
cliOptionsTypes: () => ({
|
||||
all: Boolean,
|
||||
}),
|
||||
rcOptionsTypes: () => ({}),
|
||||
help: helpHelp,
|
||||
handler: handler.bind(null, helpByCommandName),
|
||||
}
|
||||
}
|
||||
|
||||
function getHelpText (): string {
|
||||
function helpHelp () {
|
||||
return renderHelp({
|
||||
description: 'Display help information about pnpm',
|
||||
descriptionLists: [
|
||||
{
|
||||
title: 'Manage your dependencies',
|
||||
|
||||
list: [
|
||||
{
|
||||
description: 'Install all dependencies for a project',
|
||||
name: 'install',
|
||||
shortAlias: 'i',
|
||||
},
|
||||
{
|
||||
description: 'Installs a package and any packages that it depends on. By default, any new package is installed as a prod dependency',
|
||||
name: 'add',
|
||||
},
|
||||
{
|
||||
description: 'Updates packages to their latest version based on the specified range',
|
||||
name: 'update',
|
||||
shortAlias: 'up',
|
||||
},
|
||||
{
|
||||
description: 'Removes packages from node_modules and from the project\'s package.json',
|
||||
name: 'remove',
|
||||
shortAlias: 'rm',
|
||||
},
|
||||
{
|
||||
description: 'Connect the local project to another one',
|
||||
name: 'link',
|
||||
shortAlias: 'ln',
|
||||
},
|
||||
{
|
||||
description: 'Unlinks a package. Like yarn unlink but pnpm re-installs the dependency after removing the external link',
|
||||
name: 'unlink',
|
||||
},
|
||||
{
|
||||
description: 'Generates a pnpm-lock.yaml from an npm package-lock.json (or npm-shrinkwrap.json) file',
|
||||
name: 'import',
|
||||
},
|
||||
{
|
||||
description: 'Runs a pnpm install followed immediately by a pnpm test',
|
||||
name: 'install-test',
|
||||
shortAlias: 'it',
|
||||
},
|
||||
{
|
||||
description: 'Rebuild a package',
|
||||
name: 'rebuild',
|
||||
shortAlias: 'rb',
|
||||
},
|
||||
{
|
||||
description: 'Removes extraneous packages',
|
||||
name: 'prune',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Review your dependencies',
|
||||
|
||||
list: [
|
||||
{
|
||||
description: 'Checks for known security issues with the installed packages',
|
||||
name: 'audit',
|
||||
},
|
||||
{
|
||||
description: 'Print all the versions of packages that are installed, as well as their dependencies, in a tree-structure',
|
||||
name: 'list',
|
||||
shortAlias: 'ls',
|
||||
},
|
||||
{
|
||||
description: 'Check for outdated packages',
|
||||
name: 'outdated',
|
||||
},
|
||||
{
|
||||
description: 'Check licenses in consumed packages',
|
||||
name: 'licenses',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Run your scripts',
|
||||
|
||||
list: [
|
||||
{
|
||||
description: 'Executes a shell command in scope of a project',
|
||||
name: 'exec',
|
||||
},
|
||||
{
|
||||
description: 'Runs a defined package script',
|
||||
name: 'run',
|
||||
},
|
||||
{
|
||||
description: 'Runs a package\'s "test" script, if one was provided',
|
||||
name: 'test',
|
||||
shortAlias: 't',
|
||||
},
|
||||
{
|
||||
description: 'Runs an arbitrary command specified in the package\'s "start" property of its "scripts" object',
|
||||
name: 'start',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Other',
|
||||
|
||||
list: [
|
||||
{
|
||||
description: 'Create a tarball from a package',
|
||||
name: 'pack',
|
||||
},
|
||||
{
|
||||
description: 'Publishes a package to the registry',
|
||||
name: 'publish',
|
||||
},
|
||||
{
|
||||
description: 'Prints the effective modules directory',
|
||||
name: 'root',
|
||||
},
|
||||
{
|
||||
description: 'Prints the index file of a specific package from the store',
|
||||
name: 'cat-index',
|
||||
},
|
||||
{
|
||||
description: 'Prints the contents of a file based on the hash value stored in the index file',
|
||||
name: 'cat-file',
|
||||
},
|
||||
{
|
||||
description: 'Experimental! Lists the packages that include the file with the specified hash.',
|
||||
name: 'find-hash',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Manage your store',
|
||||
|
||||
list: [
|
||||
{
|
||||
description: 'Adds new packages to the pnpm store directly. Does not modify any projects or files outside the store',
|
||||
name: 'store add',
|
||||
},
|
||||
{
|
||||
description: 'Prints the path to the active store directory',
|
||||
name: 'store path',
|
||||
},
|
||||
{
|
||||
description: 'Removes unreferenced (extraneous, orphan) packages from the store',
|
||||
name: 'store prune',
|
||||
},
|
||||
{
|
||||
description: 'Checks for modified packages in the store',
|
||||
name: 'store status',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Options',
|
||||
|
||||
list: [
|
||||
{
|
||||
description: 'Run the command for each project in the workspace.',
|
||||
name: '--recursive',
|
||||
shortAlias: '-r',
|
||||
description: 'Print all the available commands',
|
||||
name: '--all',
|
||||
shortAlias: '-a',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
usages: [],
|
||||
url: docsUrl('help'),
|
||||
})
|
||||
}
|
||||
|
||||
function handler (helpByCommandName: HelpByCommandName, opts: { all?: boolean }, params: string[]): string {
|
||||
let helpText!: string
|
||||
if (params.length === 0) {
|
||||
helpText = getHelpText({ all: opts.all ?? false })
|
||||
} else if (helpByCommandName[params[0]]) {
|
||||
helpText = helpByCommandName[params[0]]()
|
||||
} else {
|
||||
helpText = `No results for "${params[0]}"`
|
||||
}
|
||||
return `Version ${packageManager.version}\
|
||||
${detectIfCurrentPkgIsExecutable() != null ? ` (compiled to binary; bundled Node.js ${process.version})` : ''}\
|
||||
\n${helpText}\n`
|
||||
}
|
||||
|
||||
interface DescriptionItem {
|
||||
shortAlias?: string
|
||||
name: string
|
||||
description?: string
|
||||
advanced?: boolean
|
||||
}
|
||||
|
||||
type DescriptionLists = Array<{
|
||||
title: string
|
||||
advanced?: boolean
|
||||
list: DescriptionItem[]
|
||||
}>
|
||||
|
||||
function getHelpText ({ all }: { all: boolean }): string {
|
||||
const descriptionLists: DescriptionLists = [
|
||||
{
|
||||
title: 'Manage your dependencies',
|
||||
|
||||
list: [
|
||||
{
|
||||
description: 'Install all dependencies for a project',
|
||||
name: 'install',
|
||||
shortAlias: 'i',
|
||||
},
|
||||
{
|
||||
description: 'Installs a package and any packages that it depends on. By default, any new package is installed as a prod dependency',
|
||||
name: 'add',
|
||||
},
|
||||
{
|
||||
description: 'Updates packages to their latest version based on the specified range',
|
||||
name: 'update',
|
||||
shortAlias: 'up',
|
||||
},
|
||||
{
|
||||
description: 'Removes packages from node_modules and from the project\'s package.json',
|
||||
name: 'remove',
|
||||
shortAlias: 'rm',
|
||||
},
|
||||
{
|
||||
description: 'Connect the local project to another one',
|
||||
name: 'link',
|
||||
shortAlias: 'ln',
|
||||
},
|
||||
{
|
||||
description: 'Unlinks a package. Like yarn unlink but pnpm re-installs the dependency after removing the external link',
|
||||
name: 'unlink',
|
||||
},
|
||||
{
|
||||
description: 'Generates a pnpm-lock.yaml from an npm package-lock.json (or npm-shrinkwrap.json) file',
|
||||
name: 'import',
|
||||
advanced: true,
|
||||
},
|
||||
{
|
||||
description: 'Runs a pnpm install followed immediately by a pnpm test',
|
||||
name: 'install-test',
|
||||
shortAlias: 'it',
|
||||
advanced: true,
|
||||
},
|
||||
{
|
||||
description: 'Rebuild a package',
|
||||
name: 'rebuild',
|
||||
shortAlias: 'rb',
|
||||
advanced: true,
|
||||
},
|
||||
{
|
||||
description: 'Removes extraneous packages',
|
||||
name: 'prune',
|
||||
advanced: true,
|
||||
},
|
||||
{
|
||||
description: 'Fetch packages from a lockfile into virtual store, package manifest is ignored',
|
||||
name: 'fetch',
|
||||
advanced: true,
|
||||
},
|
||||
{
|
||||
description: 'Perform an install removing older dependencies in the lockfile if a newer version can be used',
|
||||
name: 'dedupe',
|
||||
advanced: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Patch your dependencies',
|
||||
advanced: true,
|
||||
|
||||
list: [
|
||||
{
|
||||
description: 'Prepare a package for patching',
|
||||
name: 'patch',
|
||||
},
|
||||
{
|
||||
description: 'Generate a patch out of a directory',
|
||||
name: 'patch-commit',
|
||||
},
|
||||
{
|
||||
description: 'Remove existing patch files',
|
||||
name: 'patch-remove',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Review your dependencies',
|
||||
|
||||
list: [
|
||||
{
|
||||
description: 'Checks for known security issues with the installed packages',
|
||||
name: 'audit',
|
||||
},
|
||||
{
|
||||
description: 'Print all the versions of packages that are installed, as well as their dependencies, in a tree-structure',
|
||||
name: 'list',
|
||||
shortAlias: 'ls',
|
||||
},
|
||||
{
|
||||
description: 'Check for outdated packages',
|
||||
name: 'outdated',
|
||||
},
|
||||
{
|
||||
description: 'Check licenses in consumed packages',
|
||||
name: 'licenses',
|
||||
advanced: true,
|
||||
},
|
||||
{
|
||||
description: 'Shows all packages that depend on the specified package',
|
||||
name: 'why',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Run your scripts',
|
||||
|
||||
list: [
|
||||
{
|
||||
description: 'Executes a shell command in scope of a project',
|
||||
name: 'exec',
|
||||
},
|
||||
{
|
||||
description: 'Runs a defined package script',
|
||||
name: 'run',
|
||||
},
|
||||
{
|
||||
description: 'Runs a package\'s "test" script, if one was provided',
|
||||
name: 'test',
|
||||
shortAlias: 't',
|
||||
advanced: true,
|
||||
},
|
||||
{
|
||||
description: 'Runs an arbitrary command specified in the package\'s "start" property of its "scripts" object',
|
||||
name: 'start',
|
||||
advanced: true,
|
||||
},
|
||||
{
|
||||
description: 'Fetches a package from the registry without installing it as a dependency, hot loads it, and runs whatever default command binary it exposes',
|
||||
name: 'dlx',
|
||||
},
|
||||
{
|
||||
description: 'Create a project from a "create-*" or "@foo/create-*" starter kit',
|
||||
name: 'create',
|
||||
},
|
||||
{
|
||||
description: 'Approve dependencies for running scripts during installation',
|
||||
name: 'approve-builds',
|
||||
advanced: true,
|
||||
},
|
||||
{
|
||||
description: 'Print the list of packages with blocked build scripts',
|
||||
name: 'ignored-builds',
|
||||
advanced: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Other',
|
||||
|
||||
list: [
|
||||
{
|
||||
description: 'Create a tarball from a package',
|
||||
name: 'pack',
|
||||
advanced: true,
|
||||
},
|
||||
{
|
||||
description: 'Publishes a package to the registry',
|
||||
name: 'publish',
|
||||
},
|
||||
{
|
||||
description: 'Updates pnpm to the latest version',
|
||||
name: 'self-update',
|
||||
},
|
||||
{
|
||||
description: 'Create a package.json file',
|
||||
name: 'init',
|
||||
},
|
||||
{
|
||||
description: 'Manage the pnpm configuration files',
|
||||
name: 'config',
|
||||
shortAlias: 'c',
|
||||
},
|
||||
{
|
||||
description: 'Prints the effective modules directory',
|
||||
name: 'root',
|
||||
advanced: true,
|
||||
},
|
||||
{
|
||||
description: 'Prints the directory into which the executables of dependencies are linked',
|
||||
name: 'bin',
|
||||
advanced: true,
|
||||
},
|
||||
{
|
||||
description: 'Deploy a package from a workspace',
|
||||
name: 'deploy',
|
||||
advanced: true,
|
||||
},
|
||||
{
|
||||
description: 'Checks for known common issues with pnpm configuration',
|
||||
name: 'doctor',
|
||||
advanced: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Manage your environments',
|
||||
advanced: true,
|
||||
|
||||
list: [
|
||||
{
|
||||
description: 'Manage Node.js versions',
|
||||
name: 'env ',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Inspect your store',
|
||||
advanced: true,
|
||||
|
||||
list: [
|
||||
{
|
||||
description: 'Prints the index file of a specific package from the store',
|
||||
name: 'cat-index',
|
||||
},
|
||||
{
|
||||
description: 'Prints the contents of a file based on the hash value stored in the index file',
|
||||
name: 'cat-file',
|
||||
},
|
||||
{
|
||||
description: 'Experimental! Lists the packages that include the file with the specified hash',
|
||||
name: 'find-hash',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Manage your store',
|
||||
advanced: true,
|
||||
|
||||
list: [
|
||||
{
|
||||
description: 'Adds new packages to the pnpm store directly. Does not modify any projects or files outside the store',
|
||||
name: 'store add',
|
||||
},
|
||||
{
|
||||
description: 'Prints the path to the active store directory',
|
||||
name: 'store path',
|
||||
},
|
||||
{
|
||||
description: 'Removes unreferenced (extraneous, orphan) packages from the store',
|
||||
name: 'store prune',
|
||||
},
|
||||
{
|
||||
description: 'Checks for modified packages in the store',
|
||||
name: 'store status',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Manage your cache',
|
||||
advanced: true,
|
||||
|
||||
list: [
|
||||
{
|
||||
description: 'Experimental! Lists the available packages metadata cache. Supports filtering by glob',
|
||||
name: 'cache list',
|
||||
},
|
||||
{
|
||||
description: 'Experimental! Lists all registries that have their metadata cache locally',
|
||||
name: 'cache list-registries',
|
||||
},
|
||||
{
|
||||
description: 'Experimental! Views information from the specified package\'s cache',
|
||||
name: 'cache view',
|
||||
},
|
||||
{
|
||||
description: 'Experimental! Deletes metadata cache for the specified package(s). Supports patterns',
|
||||
name: 'cache delete',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Options',
|
||||
|
||||
list: [
|
||||
{
|
||||
description: 'Run the command for each project in the workspace.',
|
||||
name: '--recursive',
|
||||
shortAlias: '-r',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
const filteredDescriptionLists = []
|
||||
for (const descriptionList of descriptionLists) {
|
||||
if (!descriptionList.advanced || all) {
|
||||
filteredDescriptionLists.push({
|
||||
title: descriptionList.title,
|
||||
list: descriptionList.list.filter((item) => !item.advanced || all),
|
||||
})
|
||||
}
|
||||
}
|
||||
return renderHelp({
|
||||
description: all ? '' : 'These are common pnpm commands used in various situations, use \'pnpm help -a\' to list all commands',
|
||||
descriptionLists: filteredDescriptionLists,
|
||||
usages: ['pnpm [command] [flags]', 'pnpm [ -h | --help | -v | --version ]'],
|
||||
})
|
||||
}
|
||||
|
||||
@@ -108,6 +108,8 @@ export interface CommandDefinition {
|
||||
skipPackageManagerCheck?: boolean
|
||||
}
|
||||
|
||||
const helpByCommandName: Record<string, () => string> = {}
|
||||
|
||||
const commands: CommandDefinition[] = [
|
||||
add,
|
||||
approveBuilds,
|
||||
@@ -159,10 +161,10 @@ const commands: CommandDefinition[] = [
|
||||
unlink,
|
||||
update,
|
||||
why,
|
||||
createHelp(helpByCommandName),
|
||||
]
|
||||
|
||||
const handlerByCommandName: Record<string, Command> = {}
|
||||
const helpByCommandName: Record<string, () => string> = {}
|
||||
const cliOptionsTypesByCommandName: Record<string, () => Record<string, unknown>> = {}
|
||||
const aliasToFullName = new Map<string, string>()
|
||||
const completionByCommandName: Record<string, CompletionFunc> = {}
|
||||
@@ -205,7 +207,6 @@ for (let i = 0; i < commands.length; i++) {
|
||||
}
|
||||
}
|
||||
|
||||
handlerByCommandName.help = createHelp(helpByCommandName)
|
||||
handlerByCommandName['completion-server'] = createCompletionServer({
|
||||
cliOptionsTypesByCommandName,
|
||||
completionByCommandName,
|
||||
|
||||
@@ -2,6 +2,6 @@ import { createHelp } from '../src/cmd/help.js'
|
||||
|
||||
test('print an error when help not found', () => {
|
||||
expect(
|
||||
createHelp({})({}, ['foo']).split('\n')[1]
|
||||
(createHelp({}).handler({}, ['foo']) as string).split('\n')[1]
|
||||
).toBe('No results for "foo"')
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user