From f72b9f22764fd16be6bea6880bb2fcf47792878f Mon Sep 17 00:00:00 2001 From: Zoltan Kochan Date: Sun, 5 May 2019 02:39:28 +0300 Subject: [PATCH] fix: "pnpm run" prints the list of available commands --- packages/pnpm/src/cmd/run.ts | 72 ++++++++++++++++++++++++++++++++++++ packages/pnpm/test/run.ts | 22 +++++++++++ 2 files changed, 94 insertions(+) diff --git a/packages/pnpm/src/cmd/run.ts b/packages/pnpm/src/cmd/run.ts index bd964214f9..7abbc73213 100644 --- a/packages/pnpm/src/cmd/run.ts +++ b/packages/pnpm/src/cmd/run.ts @@ -1,6 +1,8 @@ import runLifecycleHooks from '@pnpm/lifecycle' import { readImporterManifestOnly } from '@pnpm/read-importer-manifest' +import { ImporterManifest } from '@pnpm/types' import { realNodeModulesDir } from '@pnpm/utils' +import R = require('ramda') export default async function run ( args: string[], @@ -16,6 +18,10 @@ export default async function run ( ) { const manifest = await readImporterManifestOnly(opts.prefix) const scriptName = args[0] + if (!scriptName) { + printProjectCommands(manifest) + return + } if (scriptName !== 'start' && (!manifest.scripts || !manifest.scripts[scriptName])) { const err = new Error(`Missing script: ${scriptName}`) err['code'] = 'ERR_PNPM_NO_SCRIPT' @@ -40,6 +46,72 @@ export default async function run ( } } +const ALL_LIFECYCLE_SCRIPTS = new Set([ + 'prepublish', + 'prepare', + 'prepublishOnly', + 'prepack', + 'postpack', + 'publish', + 'postpublish', + 'preinstall', + 'install', + 'postinstall', + 'preuninstall', + 'uninstall', + 'postuninstall', + 'preversion', + 'version', + 'postversion', + 'pretest', + 'test', + 'posttest', + 'prestop', + 'stop', + 'poststop', + 'prestart', + 'start', + 'poststart', + 'prerestart', + 'restart', + 'postrestart', + 'preshrinkwrap', + 'shrinkwrap', + 'postshrinkwrap', +]) + +function printProjectCommands (manifest: ImporterManifest) { + const lifecycleScripts = [] as string[][] + const otherScripts = [] as string[][] + + for (const [scriptName, script] of R.toPairs(manifest.scripts || {})) { + if (ALL_LIFECYCLE_SCRIPTS.has(scriptName)) { + lifecycleScripts.push([scriptName, script]) + } else { + otherScripts.push([scriptName, script]) + } + } + + if (lifecycleScripts.length === 0 && otherScripts.length === 0) { + console.log(`There are no scripts specified.`) + return + } + + let output = '' + if (lifecycleScripts.length > 0) { + output += `Lifecycle scripts:\n${renderCommands(lifecycleScripts)}` + } + if (otherScripts.length > 0) { + if (output !== '') output += '\n\n' + output += `Commands available via "pnpm run":\n${renderCommands(otherScripts)}` + } + console.log(output) +} + +function renderCommands (commands: string[][]) { + return commands.map(([scriptName, script]) => ` ${scriptName}\n ${script}`).join('\n') +} + export async function start ( args: string[], opts: { diff --git a/packages/pnpm/test/run.ts b/packages/pnpm/test/run.ts index 08599a3f92..8f514001bb 100644 --- a/packages/pnpm/test/run.ts +++ b/packages/pnpm/test/run.ts @@ -1,4 +1,5 @@ import prepare from '@pnpm/prepare' +import { stripIndent } from 'common-tags' import fs = require('mz/fs') import path = require('path') import tape = require('tape') @@ -145,3 +146,24 @@ test('install-test: install dependencies and runs tests', async (t: tape.Test) = 'posttest', ]) }) + +test('"pnpm run" prints the list of available commands', async (t: tape.Test) => { + prepare(t, { + scripts: { + test: 'ts-node test', + foo: 'echo hi', + }, + }) + + const result = execPnpmSync('run') + + t.equal((result.stdout as Buffer).toString('utf8'), stripIndent` + Lifecycle scripts: + test + ts-node test + + Commands available via "pnpm run": + foo + echo hi` + '\n', + ) +})