@pnpm/exec.commands 1001.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/run.js ADDED
@@ -0,0 +1,336 @@
1
+ import path from 'node:path';
2
+ import { FILTERING, UNIVERSAL_OPTIONS } from '@pnpm/cli.common-cli-options-help';
3
+ import { docsUrl, readProjectManifestOnly, tryReadProjectManifest, } from '@pnpm/cli.utils';
4
+ import { getWorkspaceConcurrency, types as allTypes } from '@pnpm/config.reader';
5
+ import { PnpmError } from '@pnpm/error';
6
+ import { makeNodeRequireOption, runLifecycleHook, } from '@pnpm/exec.lifecycle';
7
+ import { syncInjectedDeps } from '@pnpm/workspace.injected-deps-syncer';
8
+ import pLimit from 'p-limit';
9
+ import { pick } from 'ramda';
10
+ import { realpathMissing } from 'realpath-missing';
11
+ import { renderHelp } from 'render-help';
12
+ import { buildCommandNotFoundHint } from './buildCommandNotFoundHint.js';
13
+ import { handler as exec } from './exec.js';
14
+ import { existsInDir } from './existsInDir.js';
15
+ import { runDepsStatusCheck } from './runDepsStatusCheck.js';
16
+ import { getSpecifiedScripts as getSpecifiedScriptWithoutStartCommand, runRecursive } from './runRecursive.js';
17
+ export const IF_PRESENT_OPTION = {
18
+ 'if-present': Boolean,
19
+ };
20
+ export const IF_PRESENT_OPTION_HELP = {
21
+ description: 'Avoid exiting with a non-zero exit code when the script is undefined',
22
+ name: '--if-present',
23
+ };
24
+ export const PARALLEL_OPTION_HELP = {
25
+ description: 'Completely disregard concurrency and topological sorting, \
26
+ running a given script immediately in all matching packages \
27
+ with prefixed streaming output. This is the preferred flag \
28
+ for long-running processes such as watch run over many packages.',
29
+ name: '--parallel',
30
+ };
31
+ export const RESUME_FROM_OPTION_HELP = {
32
+ description: 'Command executed from given package',
33
+ name: '--resume-from',
34
+ };
35
+ export const SEQUENTIAL_OPTION_HELP = {
36
+ description: 'Run the specified scripts one by one',
37
+ name: '--sequential',
38
+ };
39
+ export const REPORT_SUMMARY_OPTION_HELP = {
40
+ description: 'Save the execution results of every package to "pnpm-exec-summary.json". Useful to inspect the execution time and status of each package.',
41
+ name: '--report-summary',
42
+ };
43
+ export const REPORTER_HIDE_PREFIX_HELP = {
44
+ description: 'Hide project name prefix from output of running scripts. Useful when running in CI like GitHub Actions and the output from a script may create an annotation.',
45
+ name: '--reporter-hide-prefix',
46
+ };
47
+ export const shorthands = {
48
+ parallel: [
49
+ '--workspace-concurrency=Infinity',
50
+ '--no-sort',
51
+ '--stream',
52
+ '--recursive',
53
+ ],
54
+ sequential: [
55
+ '--workspace-concurrency=1',
56
+ ],
57
+ };
58
+ export function rcOptionsTypes() {
59
+ return {
60
+ ...pick([
61
+ 'npm-path',
62
+ ], allTypes),
63
+ };
64
+ }
65
+ export function cliOptionsTypes() {
66
+ return {
67
+ ...pick([
68
+ 'bail',
69
+ 'sort',
70
+ 'unsafe-perm',
71
+ 'workspace-concurrency',
72
+ 'scripts-prepend-node-path',
73
+ ], allTypes),
74
+ ...IF_PRESENT_OPTION,
75
+ recursive: Boolean,
76
+ reverse: Boolean,
77
+ 'resume-from': String,
78
+ 'report-summary': Boolean,
79
+ 'reporter-hide-prefix': Boolean,
80
+ };
81
+ }
82
+ export const completion = async (cliOpts, params) => {
83
+ if (params.length > 0) {
84
+ return [];
85
+ }
86
+ const manifest = await readProjectManifestOnly(cliOpts.dir ?? process.cwd(), cliOpts);
87
+ return Object.keys(manifest.scripts ?? {}).map((name) => ({ name }));
88
+ };
89
+ export const commandNames = ['run', 'run-script'];
90
+ export function help() {
91
+ return renderHelp({
92
+ aliases: ['run-script'],
93
+ description: 'Runs a defined package script.',
94
+ descriptionLists: [
95
+ {
96
+ title: 'Options',
97
+ list: [
98
+ {
99
+ description: 'Run the defined package script in every package found in subdirectories \
100
+ or every workspace package, when executed inside a workspace. \
101
+ For options that may be used with `-r`, see "pnpm help recursive"',
102
+ name: '--recursive',
103
+ shortAlias: '-r',
104
+ },
105
+ {
106
+ description: 'The command will exit with a 0 exit code even if the script fails',
107
+ name: '--no-bail',
108
+ },
109
+ IF_PRESENT_OPTION_HELP,
110
+ PARALLEL_OPTION_HELP,
111
+ RESUME_FROM_OPTION_HELP,
112
+ ...UNIVERSAL_OPTIONS,
113
+ SEQUENTIAL_OPTION_HELP,
114
+ REPORT_SUMMARY_OPTION_HELP,
115
+ REPORTER_HIDE_PREFIX_HELP,
116
+ ],
117
+ },
118
+ FILTERING,
119
+ ],
120
+ url: docsUrl('run'),
121
+ usages: ['pnpm run <command> [<args>...]'],
122
+ });
123
+ }
124
+ export async function handler(opts, params) {
125
+ let dir;
126
+ if (opts.fallbackCommandUsed && (params[0] === 't' || params[0] === 'tst')) {
127
+ params[0] = 'test';
128
+ }
129
+ const [scriptName, ...passedThruArgs] = params;
130
+ if (opts.verifyDepsBeforeRun) {
131
+ await runDepsStatusCheck(opts);
132
+ }
133
+ if (opts.nodeOptions) {
134
+ opts.extraEnv = {
135
+ ...opts.extraEnv,
136
+ NODE_OPTIONS: opts.nodeOptions,
137
+ };
138
+ }
139
+ if (opts.recursive) {
140
+ if (scriptName || Object.keys(opts.selectedProjectsGraph).length > 1) {
141
+ return runRecursive(params, opts);
142
+ }
143
+ dir = Object.keys(opts.selectedProjectsGraph)[0];
144
+ }
145
+ else {
146
+ dir = opts.dir;
147
+ }
148
+ const manifest = await readProjectManifestOnly(dir, opts);
149
+ if (!scriptName) {
150
+ const rootManifest = opts.workspaceDir && opts.workspaceDir !== dir
151
+ ? (await tryReadProjectManifest(opts.workspaceDir, opts)).manifest
152
+ : undefined;
153
+ return printProjectCommands(manifest, rootManifest ?? undefined);
154
+ }
155
+ const specifiedScripts = getSpecifiedScripts(manifest.scripts ?? {}, scriptName);
156
+ if (specifiedScripts.length < 1) {
157
+ if (opts.ifPresent)
158
+ return;
159
+ if (opts.fallbackCommandUsed) {
160
+ if (opts.argv == null)
161
+ throw new Error('Could not fallback because opts.argv.original was not passed to the script runner');
162
+ const params = opts.argv.original.slice(1);
163
+ while (params.length > 0 && params[0][0] === '-' && params[0] !== '--') {
164
+ params.shift();
165
+ }
166
+ if (params.length > 0 && params[0] === '--') {
167
+ params.shift();
168
+ }
169
+ if (params.length === 0) {
170
+ throw new PnpmError('UNEXPECTED_BEHAVIOR', 'Params should not be an empty array', {
171
+ hint: 'This was a bug caused by programmer error. Please report it',
172
+ });
173
+ }
174
+ return exec({
175
+ selectedProjectsGraph: {},
176
+ implicitlyFellbackFromRun: true,
177
+ ...opts,
178
+ }, params);
179
+ }
180
+ if (opts.workspaceDir) {
181
+ const { manifest: rootManifest } = await tryReadProjectManifest(opts.workspaceDir, opts);
182
+ if (getSpecifiedScripts(rootManifest?.scripts ?? {}, scriptName).length > 0 && specifiedScripts.length < 1) {
183
+ throw new PnpmError('NO_SCRIPT', `Missing script: ${scriptName}`, {
184
+ hint: `But script matched with ${scriptName} is present in the root of the workspace,
185
+ so you may run "pnpm -w run ${scriptName}"`,
186
+ });
187
+ }
188
+ }
189
+ throw new PnpmError('NO_SCRIPT', `Missing script: ${scriptName}`, {
190
+ hint: buildCommandNotFoundHint(scriptName, manifest.scripts),
191
+ });
192
+ }
193
+ const concurrency = getWorkspaceConcurrency(opts.workspaceConcurrency);
194
+ const lifecycleOpts = {
195
+ depPath: dir,
196
+ extraBinPaths: opts.extraBinPaths,
197
+ extraEnv: opts.extraEnv,
198
+ pkgRoot: dir,
199
+ rawConfig: opts.rawConfig,
200
+ rootModulesDir: await realpathMissing(path.join(dir, 'node_modules')),
201
+ scriptsPrependNodePath: opts.scriptsPrependNodePath,
202
+ scriptShell: opts.scriptShell,
203
+ silent: opts.reporter === 'silent',
204
+ shellEmulator: opts.shellEmulator,
205
+ stdio: (specifiedScripts.length > 1 && concurrency > 1) ? 'pipe' : 'inherit',
206
+ unsafePerm: true, // when running scripts explicitly, assume that they're trusted.
207
+ };
208
+ const existsPnp = existsInDir.bind(null, '.pnp.cjs');
209
+ const pnpPath = (opts.workspaceDir && existsPnp(opts.workspaceDir)) ?? existsPnp(dir);
210
+ if (pnpPath) {
211
+ lifecycleOpts.extraEnv = {
212
+ ...lifecycleOpts.extraEnv,
213
+ ...makeNodeRequireOption(pnpPath),
214
+ };
215
+ }
216
+ try {
217
+ const limitRun = pLimit(concurrency);
218
+ const runScriptOptions = {
219
+ enablePrePostScripts: opts.enablePrePostScripts ?? false,
220
+ syncInjectedDepsAfterScripts: opts.syncInjectedDepsAfterScripts,
221
+ workspaceDir: opts.workspaceDir,
222
+ };
223
+ const _runScript = runScript.bind(null, { manifest, lifecycleOpts, runScriptOptions, passedThruArgs });
224
+ await Promise.all(specifiedScripts.map(script => limitRun(() => _runScript(script))));
225
+ }
226
+ catch (err) {
227
+ if (opts.bail !== false) {
228
+ throw err;
229
+ }
230
+ }
231
+ return undefined;
232
+ }
233
+ const ALL_LIFECYCLE_SCRIPTS = new Set([
234
+ 'prepublish',
235
+ 'prepare',
236
+ 'prepublishOnly',
237
+ 'prepack',
238
+ 'postpack',
239
+ 'publish',
240
+ 'postpublish',
241
+ 'preinstall',
242
+ 'install',
243
+ 'postinstall',
244
+ 'preuninstall',
245
+ 'uninstall',
246
+ 'postuninstall',
247
+ 'preversion',
248
+ 'version',
249
+ 'postversion',
250
+ 'pretest',
251
+ 'test',
252
+ 'posttest',
253
+ 'prestop',
254
+ 'stop',
255
+ 'poststop',
256
+ 'prestart',
257
+ 'start',
258
+ 'poststart',
259
+ 'prerestart',
260
+ 'restart',
261
+ 'postrestart',
262
+ 'preshrinkwrap',
263
+ 'shrinkwrap',
264
+ 'postshrinkwrap',
265
+ ]);
266
+ function printProjectCommands(manifest, rootManifest) {
267
+ const lifecycleScripts = [];
268
+ const otherScripts = [];
269
+ for (const [scriptName, script] of Object.entries(manifest.scripts ?? {})) {
270
+ if (ALL_LIFECYCLE_SCRIPTS.has(scriptName)) {
271
+ lifecycleScripts.push([scriptName, script]);
272
+ }
273
+ else {
274
+ otherScripts.push([scriptName, script]);
275
+ }
276
+ }
277
+ if (lifecycleScripts.length === 0 && otherScripts.length === 0) {
278
+ return 'There are no scripts specified.';
279
+ }
280
+ let output = '';
281
+ if (lifecycleScripts.length > 0) {
282
+ output += `Lifecycle scripts:\n${renderCommands(lifecycleScripts)}`;
283
+ }
284
+ if (otherScripts.length > 0) {
285
+ if (output !== '')
286
+ output += '\n\n';
287
+ output += `Commands available via "pnpm run":\n${renderCommands(otherScripts)}`;
288
+ }
289
+ if ((rootManifest?.scripts) == null) {
290
+ return output;
291
+ }
292
+ const rootScripts = Object.entries(rootManifest.scripts);
293
+ if (rootScripts.length === 0) {
294
+ return output;
295
+ }
296
+ if (output !== '')
297
+ output += '\n\n';
298
+ output += `Commands of the root workspace project (to run them, use "pnpm -w run"):
299
+ ${renderCommands(rootScripts)}`;
300
+ return output;
301
+ }
302
+ export async function runScript(opts, scriptName) {
303
+ if (opts.runScriptOptions.enablePrePostScripts &&
304
+ opts.manifest.scripts?.[`pre${scriptName}`] &&
305
+ !opts.manifest.scripts[scriptName].includes(`pre${scriptName}`)) {
306
+ await runLifecycleHook(`pre${scriptName}`, opts.manifest, opts.lifecycleOpts);
307
+ }
308
+ await runLifecycleHook(scriptName, opts.manifest, { ...opts.lifecycleOpts, args: opts.passedThruArgs });
309
+ if (opts.runScriptOptions.enablePrePostScripts &&
310
+ opts.manifest.scripts?.[`post${scriptName}`] &&
311
+ !opts.manifest.scripts[scriptName].includes(`post${scriptName}`)) {
312
+ await runLifecycleHook(`post${scriptName}`, opts.manifest, opts.lifecycleOpts);
313
+ }
314
+ if (opts.runScriptOptions.syncInjectedDepsAfterScripts?.includes(scriptName)) {
315
+ await syncInjectedDeps({
316
+ pkgName: opts.manifest.name,
317
+ pkgRootDir: opts.lifecycleOpts.pkgRoot,
318
+ workspaceDir: opts.runScriptOptions.workspaceDir,
319
+ });
320
+ }
321
+ }
322
+ function renderCommands(commands) {
323
+ return commands.map(([scriptName, script]) => ` ${scriptName}\n ${script}`).join('\n');
324
+ }
325
+ function getSpecifiedScripts(scripts, scriptName) {
326
+ const specifiedSelector = getSpecifiedScriptWithoutStartCommand(scripts, scriptName);
327
+ if (specifiedSelector.length > 0) {
328
+ return specifiedSelector;
329
+ }
330
+ // if a user passes start command as scriptName, `node server.js` will be executed as a fallback, so return start command even if start command is not defined in package.json
331
+ if (scriptName === 'start') {
332
+ return [scriptName];
333
+ }
334
+ return [];
335
+ }
336
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1,8 @@
1
+ import type { VerifyDepsBeforeRun } from '@pnpm/config.reader';
2
+ import { type CheckDepsStatusOptions, type WorkspaceStateSettings } from '@pnpm/deps.status';
3
+ export interface RunDepsStatusCheckOptions extends CheckDepsStatusOptions {
4
+ dir: string;
5
+ verifyDepsBeforeRun?: VerifyDepsBeforeRun;
6
+ }
7
+ export declare function runDepsStatusCheck(opts: RunDepsStatusCheckOptions): Promise<void>;
8
+ export declare function createInstallArgs(opts: Pick<WorkspaceStateSettings, 'dev' | 'optional' | 'production'> | undefined): string[];
@@ -0,0 +1,74 @@
1
+ import { checkDepsStatus } from '@pnpm/deps.status';
2
+ import { PnpmError } from '@pnpm/error';
3
+ import { runPnpmCli } from '@pnpm/exec.pnpm-cli-runner';
4
+ import { globalWarn } from '@pnpm/logger';
5
+ import enquirer from 'enquirer';
6
+ export async function runDepsStatusCheck(opts) {
7
+ // the following flags are always the default values during `pnpm run` and `pnpm exec`,
8
+ // so they may not match the workspace state after `pnpm install --production|--no-optional`
9
+ const ignoredWorkspaceStateSettings = ['dev', 'optional', 'production'];
10
+ opts.ignoredWorkspaceStateSettings = ignoredWorkspaceStateSettings;
11
+ const { upToDate, issue, workspaceState } = await checkDepsStatus(opts);
12
+ if (upToDate)
13
+ return;
14
+ const command = ['install', ...createInstallArgs(workspaceState?.settings)];
15
+ const install = runPnpmCli.bind(null, command, { cwd: opts.dir });
16
+ switch (opts.verifyDepsBeforeRun) {
17
+ case 'install':
18
+ install();
19
+ break;
20
+ case 'prompt': {
21
+ // In non-TTY environments (like CI), we can't prompt the user
22
+ // Exit with error to alert users that node_modules are out of sync
23
+ if (!process.stdin.isTTY) {
24
+ throw new PnpmError('VERIFY_DEPS_BEFORE_RUN', issue ?? 'Your node_modules are out of sync with your lockfile', {
25
+ hint: 'Run "pnpm install" before running scripts. The "verifyDepsBeforeRun: prompt" setting cannot prompt for confirmation in non-interactive environments.',
26
+ });
27
+ }
28
+ let confirmed;
29
+ try {
30
+ confirmed = await enquirer.prompt({
31
+ type: 'confirm',
32
+ name: 'runInstall',
33
+ message: `Your "node_modules" directory is out of sync with the "pnpm-lock.yaml" file. This can lead to issues during scripts execution.
34
+
35
+ Would you like to run "pnpm ${command.join(' ')}" to update your "node_modules"?`,
36
+ initial: true,
37
+ });
38
+ }
39
+ catch {
40
+ // User cancelled the prompt (e.g. Ctrl+C) — exit immediately
41
+ // so the caller doesn't proceed to run the script.
42
+ process.exit(1);
43
+ }
44
+ if (confirmed.runInstall) {
45
+ install();
46
+ }
47
+ break;
48
+ }
49
+ case 'error':
50
+ throw new PnpmError('VERIFY_DEPS_BEFORE_RUN', issue ?? 'Your node_modules are out of sync with your lockfile', {
51
+ hint: 'Run "pnpm install"',
52
+ });
53
+ case 'warn':
54
+ globalWarn(`Your node_modules are out of sync with your lockfile. ${issue}`);
55
+ break;
56
+ }
57
+ }
58
+ export function createInstallArgs(opts) {
59
+ const args = [];
60
+ if (!opts)
61
+ return args;
62
+ const { dev, optional, production } = opts;
63
+ if (production && !dev) {
64
+ args.push('--production');
65
+ }
66
+ else if (dev && !production) {
67
+ args.push('--dev');
68
+ }
69
+ if (!optional) {
70
+ args.push('--no-optional');
71
+ }
72
+ return args;
73
+ }
74
+ //# sourceMappingURL=runDepsStatusCheck.js.map
@@ -0,0 +1,9 @@
1
+ import { type Config } from '@pnpm/config.reader';
2
+ import type { PackageScripts } from '@pnpm/types';
3
+ export type RecursiveRunOpts = Pick<Config, 'bin' | 'enablePrePostScripts' | 'unsafePerm' | 'pnpmHomeDir' | 'rawConfig' | 'requiredScripts' | 'rootProjectManifest' | 'scriptsPrependNodePath' | 'scriptShell' | 'shellEmulator' | 'stream' | 'syncInjectedDepsAfterScripts' | 'workspaceDir'> & Required<Pick<Config, 'allProjects' | 'selectedProjectsGraph' | 'workspaceDir' | 'dir'>> & Partial<Pick<Config, 'extraBinPaths' | 'extraEnv' | 'bail' | 'reporter' | 'reverse' | 'sort' | 'workspaceConcurrency'>> & {
4
+ ifPresent?: boolean;
5
+ resumeFrom?: string;
6
+ reportSummary?: boolean;
7
+ };
8
+ export declare function runRecursive(params: string[], opts: RecursiveRunOpts): Promise<void>;
9
+ export declare function getSpecifiedScripts(scripts: PackageScripts, scriptName: string): string[];
@@ -0,0 +1,173 @@
1
+ import assert from 'node:assert';
2
+ import path from 'node:path';
3
+ import util from 'node:util';
4
+ import { throwOnCommandFail } from '@pnpm/cli.utils';
5
+ import { getWorkspaceConcurrency } from '@pnpm/config.reader';
6
+ import { PnpmError } from '@pnpm/error';
7
+ import { makeNodeRequireOption, } from '@pnpm/exec.lifecycle';
8
+ import { groupStart } from '@pnpm/log.group';
9
+ import { sortProjects } from '@pnpm/workspace.projects-sorter';
10
+ import pLimit from 'p-limit';
11
+ import { realpathMissing } from 'realpath-missing';
12
+ import { createEmptyRecursiveSummary, getExecutionDuration, getResumedPackageChunks, writeRecursiveSummary } from './exec.js';
13
+ import { existsInDir } from './existsInDir.js';
14
+ import { tryBuildRegExpFromCommand } from './regexpCommand.js';
15
+ import { runScript } from './run.js';
16
+ export async function runRecursive(params, opts) {
17
+ const [scriptName, ...passedThruArgs] = params;
18
+ if (!scriptName) {
19
+ throw new PnpmError('SCRIPT_NAME_IS_REQUIRED', 'You must specify the script you want to run');
20
+ }
21
+ let hasCommand = 0;
22
+ const sortedPackageChunks = opts.sort
23
+ ? sortProjects(opts.selectedProjectsGraph)
24
+ : [Object.keys(opts.selectedProjectsGraph).sort()];
25
+ let packageChunks = opts.reverse ? sortedPackageChunks.reverse() : sortedPackageChunks;
26
+ if (opts.resumeFrom) {
27
+ packageChunks = getResumedPackageChunks({
28
+ resumeFrom: opts.resumeFrom,
29
+ chunks: packageChunks,
30
+ selectedProjectsGraph: opts.selectedProjectsGraph,
31
+ });
32
+ }
33
+ const limitRun = pLimit(getWorkspaceConcurrency(opts.workspaceConcurrency));
34
+ const stdio = !opts.stream &&
35
+ (opts.workspaceConcurrency === 1 ||
36
+ (packageChunks.length === 1 && packageChunks[0].length === 1))
37
+ ? 'inherit'
38
+ : 'pipe';
39
+ const existsPnp = existsInDir.bind(null, '.pnp.cjs');
40
+ const workspacePnpPath = opts.workspaceDir && existsPnp(opts.workspaceDir);
41
+ const requiredScripts = opts.requiredScripts ?? [];
42
+ if (requiredScripts.includes(scriptName)) {
43
+ const missingScriptPackages = packageChunks
44
+ .flat()
45
+ .map((prefix) => opts.selectedProjectsGraph[prefix])
46
+ .filter((pkg) => getSpecifiedScripts(pkg.package.manifest.scripts ?? {}, scriptName).length < 1)
47
+ .map((pkg) => pkg.package.manifest.name ?? pkg.package.rootDir);
48
+ if (missingScriptPackages.length) {
49
+ throw new PnpmError('RECURSIVE_RUN_NO_SCRIPT', `Missing script "${scriptName}" in packages: ${missingScriptPackages.join(', ')}`);
50
+ }
51
+ }
52
+ const result = createEmptyRecursiveSummary(packageChunks);
53
+ for (const chunk of packageChunks) {
54
+ const selectedScripts = chunk.map(prefix => {
55
+ const pkg = opts.selectedProjectsGraph[prefix];
56
+ const specifiedScripts = getSpecifiedScripts(pkg.package.manifest.scripts ?? {}, scriptName);
57
+ if (!specifiedScripts.length) {
58
+ result[prefix].status = 'skipped';
59
+ }
60
+ return specifiedScripts.map(script => ({ prefix, scriptName: script }));
61
+ }).flat();
62
+ // eslint-disable-next-line no-await-in-loop
63
+ await Promise.all(selectedScripts.map(async ({ prefix, scriptName }) => limitRun(async () => {
64
+ const pkg = opts.selectedProjectsGraph[prefix];
65
+ if (!pkg.package.manifest.scripts?.[scriptName] ||
66
+ process.env.npm_lifecycle_event === scriptName &&
67
+ process.env.PNPM_SCRIPT_SRC_DIR === prefix) {
68
+ return;
69
+ }
70
+ result[prefix].status = 'running';
71
+ const startTime = process.hrtime();
72
+ hasCommand++;
73
+ try {
74
+ const lifecycleOpts = {
75
+ depPath: prefix,
76
+ extraBinPaths: opts.extraBinPaths,
77
+ extraEnv: opts.extraEnv,
78
+ pkgRoot: prefix,
79
+ rawConfig: opts.rawConfig,
80
+ rootModulesDir: await realpathMissing(path.join(prefix, 'node_modules')),
81
+ scriptsPrependNodePath: opts.scriptsPrependNodePath,
82
+ scriptShell: opts.scriptShell,
83
+ silent: opts.reporter === 'silent',
84
+ shellEmulator: opts.shellEmulator,
85
+ stdio,
86
+ unsafePerm: true, // when running scripts explicitly, assume that they're trusted.
87
+ };
88
+ const pnpPath = workspacePnpPath ?? existsPnp(prefix);
89
+ if (pnpPath) {
90
+ lifecycleOpts.extraEnv = {
91
+ ...lifecycleOpts.extraEnv,
92
+ ...makeNodeRequireOption(pnpPath),
93
+ };
94
+ }
95
+ const runScriptOptions = {
96
+ enablePrePostScripts: opts.enablePrePostScripts ?? false,
97
+ syncInjectedDepsAfterScripts: opts.syncInjectedDepsAfterScripts,
98
+ workspaceDir: opts.workspaceDir,
99
+ };
100
+ const _runScript = runScript.bind(null, { manifest: pkg.package.manifest, lifecycleOpts, runScriptOptions, passedThruArgs });
101
+ const groupEnd = Boolean(lifecycleOpts.silent) || getWorkspaceConcurrency(opts.workspaceConcurrency) > 1
102
+ ? undefined
103
+ : groupStart(formatSectionName({
104
+ name: pkg.package.manifest.name,
105
+ script: scriptName,
106
+ version: pkg.package.manifest.version,
107
+ prefix: path.normalize(path.relative(opts.workspaceDir, prefix)),
108
+ }));
109
+ await _runScript(scriptName);
110
+ groupEnd?.();
111
+ result[prefix].status = 'passed';
112
+ result[prefix].duration = getExecutionDuration(startTime);
113
+ }
114
+ catch (err) {
115
+ assert(util.types.isNativeError(err));
116
+ result[prefix] = {
117
+ status: 'failure',
118
+ duration: getExecutionDuration(startTime),
119
+ error: err,
120
+ message: err.message,
121
+ prefix,
122
+ };
123
+ if (!opts.bail) {
124
+ return;
125
+ }
126
+ Object.assign(err, {
127
+ code: 'ERR_PNPM_RECURSIVE_RUN_FIRST_FAIL',
128
+ prefix,
129
+ });
130
+ if (opts.reportSummary) {
131
+ await writeRecursiveSummary({
132
+ dir: opts.workspaceDir ?? opts.dir,
133
+ summary: result,
134
+ });
135
+ }
136
+ throw err;
137
+ }
138
+ })));
139
+ }
140
+ if (scriptName !== 'test' && !hasCommand && !opts.ifPresent) {
141
+ const allPackagesAreSelected = Object.keys(opts.selectedProjectsGraph).length === opts.allProjects.length;
142
+ if (allPackagesAreSelected) {
143
+ throw new PnpmError('RECURSIVE_RUN_NO_SCRIPT', `None of the packages has a "${scriptName}" script`);
144
+ }
145
+ else {
146
+ throw new PnpmError('RECURSIVE_RUN_NO_SCRIPT', `None of the selected packages has a "${scriptName}" script`);
147
+ }
148
+ }
149
+ if (opts.reportSummary) {
150
+ await writeRecursiveSummary({
151
+ dir: opts.workspaceDir ?? opts.dir,
152
+ summary: result,
153
+ });
154
+ }
155
+ throwOnCommandFail('pnpm recursive run', result);
156
+ }
157
+ function formatSectionName({ script, name, version, prefix, }) {
158
+ return `${name ?? 'unknown'}${version ? `@${version}` : ''} ${script ? `: ${script}` : ''} ${prefix}`;
159
+ }
160
+ export function getSpecifiedScripts(scripts, scriptName) {
161
+ // if scripts in package.json has script which is equal to scriptName a user passes, return it.
162
+ if (scripts[scriptName]) {
163
+ return [scriptName];
164
+ }
165
+ const scriptSelector = tryBuildRegExpFromCommand(scriptName);
166
+ // if scriptName which a user passes is RegExp (like /build:.*/), multiple scripts to execute will be selected with RegExp
167
+ if (scriptSelector) {
168
+ const scriptKeys = Object.keys(scripts);
169
+ return scriptKeys.filter(script => script.match(scriptSelector));
170
+ }
171
+ return [];
172
+ }
173
+ //# sourceMappingURL=runRecursive.js.map