@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/LICENSE +22 -0
- package/README.md +15 -0
- package/lib/buildCommandNotFoundHint.d.ts +10 -0
- package/lib/buildCommandNotFoundHint.js +46 -0
- package/lib/create.d.ts +8 -0
- package/lib/create.js +94 -0
- package/lib/dlx.d.ts +24 -0
- package/lib/dlx.js +290 -0
- package/lib/exec.d.ts +34 -0
- package/lib/exec.js +328 -0
- package/lib/existsInDir.d.ts +1 -0
- package/lib/existsInDir.js +9 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.js +7 -0
- package/lib/makeEnv.d.ts +10 -0
- package/lib/makeEnv.js +20 -0
- package/lib/regexpCommand.d.ts +1 -0
- package/lib/regexpCommand.js +21 -0
- package/lib/restart.d.ts +6 -0
- package/lib/restart.js +35 -0
- package/lib/run.d.ts +50 -0
- package/lib/run.js +336 -0
- package/lib/runDepsStatusCheck.d.ts +8 -0
- package/lib/runDepsStatusCheck.js +74 -0
- package/lib/runRecursive.d.ts +9 -0
- package/lib/runRecursive.js +173 -0
- package/package.json +97 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015-2016 Rico Sta. Cruz and other contributors
|
|
4
|
+
Copyright (c) 2016-2026 Zoltan Kochan and other contributors
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# @pnpm/plugin-commands-script-runners
|
|
2
|
+
|
|
3
|
+
> Commands for running scripts
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@pnpm/plugin-commands-script-runners)
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pnpm add @pnpm/plugin-commands-script-runners
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## License
|
|
14
|
+
|
|
15
|
+
MIT
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PackageScripts } from '@pnpm/types';
|
|
2
|
+
export declare function getNearestProgram({ dir, modulesDir, programName, workspaceDir }: {
|
|
3
|
+
dir: string;
|
|
4
|
+
modulesDir: string;
|
|
5
|
+
programName: string;
|
|
6
|
+
workspaceDir: string | undefined;
|
|
7
|
+
}): string | null;
|
|
8
|
+
export declare function buildCommandNotFoundHint(scriptName: string, scripts?: PackageScripts | undefined): string;
|
|
9
|
+
export declare function getNearestScript(scriptName: string, scripts?: PackageScripts | undefined): string | null;
|
|
10
|
+
export declare function getNearest(name: string, list: readonly string[]): string | null;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { readdirSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import didYouMean, { ReturnTypeEnums } from 'didyoumean2';
|
|
4
|
+
export function getNearestProgram({ dir, modulesDir, programName, workspaceDir, }) {
|
|
5
|
+
try {
|
|
6
|
+
const binDir = path.join(dir, modulesDir, '.bin');
|
|
7
|
+
const programList = readProgramsFromDir(binDir);
|
|
8
|
+
if (workspaceDir && workspaceDir !== dir) {
|
|
9
|
+
const workspaceBinDir = path.join(workspaceDir, modulesDir, '.bin');
|
|
10
|
+
programList.push(...readProgramsFromDir(workspaceBinDir));
|
|
11
|
+
}
|
|
12
|
+
return getNearest(programName, programList);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function readProgramsFromDir(binDir) {
|
|
19
|
+
const files = readdirSync(binDir);
|
|
20
|
+
if (process.platform !== 'win32')
|
|
21
|
+
return files;
|
|
22
|
+
const executableExtensions = ['.cmd', '.bat', '.ps1', '.exe', '.com'];
|
|
23
|
+
return files.map((fullName) => {
|
|
24
|
+
const { name, ext } = path.parse(fullName);
|
|
25
|
+
return executableExtensions.includes(ext.toLowerCase()) ? name : fullName;
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
export function buildCommandNotFoundHint(scriptName, scripts) {
|
|
29
|
+
let hint = `Command "${scriptName}" not found.`;
|
|
30
|
+
const nearestCommand = getNearestScript(scriptName, scripts);
|
|
31
|
+
if (nearestCommand) {
|
|
32
|
+
hint += ` Did you mean "pnpm run ${nearestCommand}"?`;
|
|
33
|
+
}
|
|
34
|
+
return hint;
|
|
35
|
+
}
|
|
36
|
+
export function getNearestScript(scriptName, scripts) {
|
|
37
|
+
return getNearest(scriptName, Object.keys(scripts ?? []));
|
|
38
|
+
}
|
|
39
|
+
export function getNearest(name, list) {
|
|
40
|
+
if (list == null || list.length === 0)
|
|
41
|
+
return null;
|
|
42
|
+
return didYouMean(name, list, {
|
|
43
|
+
returnType: ReturnTypeEnums.FIRST_CLOSEST_MATCH,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=buildCommandNotFoundHint.js.map
|
package/lib/create.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as dlx from './dlx.js';
|
|
2
|
+
export declare const commandNames: string[];
|
|
3
|
+
export declare function handler(_opts: dlx.DlxCommandOptions, params: string[]): Promise<{
|
|
4
|
+
exitCode: number;
|
|
5
|
+
} | string>;
|
|
6
|
+
export declare function rcOptionsTypes(): Record<string, unknown>;
|
|
7
|
+
export declare function cliOptionsTypes(): Record<string, unknown>;
|
|
8
|
+
export declare function help(): string;
|
package/lib/create.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { docsUrl } from '@pnpm/cli.utils';
|
|
2
|
+
import { PnpmError } from '@pnpm/error';
|
|
3
|
+
import { renderHelp } from 'render-help';
|
|
4
|
+
import * as dlx from './dlx.js';
|
|
5
|
+
export const commandNames = ['create'];
|
|
6
|
+
export async function handler(_opts, params) {
|
|
7
|
+
// If the first argument is --help or -h, we show the help message.
|
|
8
|
+
if (params[0] === '--help' || params[0] === '-h') {
|
|
9
|
+
return help();
|
|
10
|
+
}
|
|
11
|
+
const [packageName, ...packageArgs] = params;
|
|
12
|
+
if (packageName === undefined) {
|
|
13
|
+
throw new PnpmError('MISSING_ARGS', 'Missing the template package name.\n' +
|
|
14
|
+
'The correct usage is `pnpm create <name>` ' +
|
|
15
|
+
'with <name> substituted for a package name.');
|
|
16
|
+
}
|
|
17
|
+
const createPackageName = convertToCreateName(packageName);
|
|
18
|
+
return dlx.handler(_opts, [createPackageName, ...packageArgs]);
|
|
19
|
+
}
|
|
20
|
+
export function rcOptionsTypes() {
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
export function cliOptionsTypes() {
|
|
24
|
+
return {
|
|
25
|
+
...rcOptionsTypes(),
|
|
26
|
+
'allow-build': [String, Array],
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export function help() {
|
|
30
|
+
return renderHelp({
|
|
31
|
+
description: 'Creates a project from a `create-*` starter kit.',
|
|
32
|
+
descriptionLists: [
|
|
33
|
+
{
|
|
34
|
+
title: 'Options',
|
|
35
|
+
list: [
|
|
36
|
+
{
|
|
37
|
+
description: 'A list of package names that are allowed to run postinstall scripts during installation',
|
|
38
|
+
name: '--allow-build',
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
url: docsUrl('create'),
|
|
44
|
+
usages: [
|
|
45
|
+
'pnpm create <name>',
|
|
46
|
+
'pnpm create <name-without-create>',
|
|
47
|
+
'pnpm create <@scope>',
|
|
48
|
+
],
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
const CREATE_PREFIX = 'create-';
|
|
52
|
+
/**
|
|
53
|
+
* Defines the npm's algorithm for resolving a package name
|
|
54
|
+
* for create-* packages.
|
|
55
|
+
*
|
|
56
|
+
* Example:
|
|
57
|
+
* - `foo` -> `create-foo`
|
|
58
|
+
* - `@usr/foo` -> `@usr/create-foo`
|
|
59
|
+
* - `@usr` -> `@usr/create`
|
|
60
|
+
* - `@usr@2.0.0` -> `@usr/create@2.0.0`
|
|
61
|
+
* - `@usr/foo@2.0.0` -> `@usr/create-foo@2.0.0`
|
|
62
|
+
* - `@usr@latest` -> `@user/create@latest`
|
|
63
|
+
*
|
|
64
|
+
* For more info, see https://docs.npmjs.com/cli/v9/commands/npm-init#description
|
|
65
|
+
*/
|
|
66
|
+
function convertToCreateName(packageName) {
|
|
67
|
+
if (packageName[0] === '@') {
|
|
68
|
+
const preferredVersionPosition = packageName.indexOf('@', 1);
|
|
69
|
+
let preferredVersion = '';
|
|
70
|
+
if (preferredVersionPosition > -1) {
|
|
71
|
+
preferredVersion = packageName.substring(preferredVersionPosition);
|
|
72
|
+
packageName = packageName.substring(0, preferredVersionPosition);
|
|
73
|
+
}
|
|
74
|
+
const [scope, scopedPackage = ''] = packageName.split('/');
|
|
75
|
+
if (scopedPackage === '') {
|
|
76
|
+
return `${scope}/create${preferredVersion}`;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
return `${scope}/${ensureCreatePrefixed(scopedPackage)}${preferredVersion}`;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
return ensureCreatePrefixed(packageName);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function ensureCreatePrefixed(packageName) {
|
|
87
|
+
if (packageName.startsWith(CREATE_PREFIX)) {
|
|
88
|
+
return packageName;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
return `${CREATE_PREFIX}${packageName}`;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=create.js.map
|
package/lib/dlx.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type Config } from '@pnpm/config.reader';
|
|
2
|
+
import { add } from '@pnpm/installing.commands';
|
|
3
|
+
import type { PnpmSettings, SupportedArchitectures } from '@pnpm/types';
|
|
4
|
+
export declare const skipPackageManagerCheck = true;
|
|
5
|
+
export declare const commandNames: string[];
|
|
6
|
+
export declare const shorthands: Record<string, string>;
|
|
7
|
+
export declare function rcOptionsTypes(): Record<string, unknown>;
|
|
8
|
+
export declare const cliOptionsTypes: () => Record<string, unknown>;
|
|
9
|
+
export declare function help(): string;
|
|
10
|
+
export type DlxCommandOptions = {
|
|
11
|
+
package?: string[];
|
|
12
|
+
shellMode?: boolean;
|
|
13
|
+
allowBuild?: string[];
|
|
14
|
+
} & Pick<Config, 'extraBinPaths' | 'minimumReleaseAgeExclude' | 'registries' | 'reporter' | 'userAgent' | 'cacheDir' | 'dlxCacheMaxAge' | 'symlink'> & Omit<add.AddCommandOptions, 'rootProjectManifestDir'> & PnpmSettings;
|
|
15
|
+
export declare function handler(opts: DlxCommandOptions, [command, ...args]: string[]): Promise<{
|
|
16
|
+
exitCode: number;
|
|
17
|
+
output?: string;
|
|
18
|
+
}>;
|
|
19
|
+
export declare function createCacheKey(opts: {
|
|
20
|
+
packages: string[];
|
|
21
|
+
registries: Record<string, string>;
|
|
22
|
+
allowBuild?: string[];
|
|
23
|
+
supportedArchitectures?: SupportedArchitectures;
|
|
24
|
+
}): string;
|
package/lib/dlx.js
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import fs, {} from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import util from 'node:util';
|
|
4
|
+
import { getBinsFromPackageManifest } from '@pnpm/bins.resolver';
|
|
5
|
+
import { resolveFromCatalog, } from '@pnpm/catalogs.resolver';
|
|
6
|
+
import { OUTPUT_OPTIONS } from '@pnpm/cli.common-cli-options-help';
|
|
7
|
+
import { docsUrl, readProjectManifestOnly } from '@pnpm/cli.utils';
|
|
8
|
+
import { types } from '@pnpm/config.reader';
|
|
9
|
+
import { createPackageVersionPolicy } from '@pnpm/config.version-policy';
|
|
10
|
+
import { createHexHash } from '@pnpm/crypto.hash';
|
|
11
|
+
import { PnpmError } from '@pnpm/error';
|
|
12
|
+
import { createResolver } from '@pnpm/installing.client';
|
|
13
|
+
import { add } from '@pnpm/installing.commands';
|
|
14
|
+
import { readPackageJsonFromDir } from '@pnpm/pkg-manifest.reader';
|
|
15
|
+
import { parseWantedDependency } from '@pnpm/resolving.parse-wanted-dependency';
|
|
16
|
+
import { lexCompare } from '@pnpm/util.lex-comparator';
|
|
17
|
+
import { safeExeca as execa } from 'execa';
|
|
18
|
+
import { pick } from 'ramda';
|
|
19
|
+
import { renderHelp } from 'render-help';
|
|
20
|
+
import symlinkDir from 'symlink-dir';
|
|
21
|
+
import { makeEnv } from './makeEnv.js';
|
|
22
|
+
export const skipPackageManagerCheck = true;
|
|
23
|
+
export const commandNames = ['dlx'];
|
|
24
|
+
export const shorthands = {
|
|
25
|
+
c: '--shell-mode',
|
|
26
|
+
};
|
|
27
|
+
export function rcOptionsTypes() {
|
|
28
|
+
return {
|
|
29
|
+
...pick([
|
|
30
|
+
'cpu',
|
|
31
|
+
'libc',
|
|
32
|
+
'os',
|
|
33
|
+
], types),
|
|
34
|
+
'shell-mode': Boolean,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export const cliOptionsTypes = () => ({
|
|
38
|
+
...rcOptionsTypes(),
|
|
39
|
+
package: [String, Array],
|
|
40
|
+
'allow-build': [String, Array],
|
|
41
|
+
});
|
|
42
|
+
export function help() {
|
|
43
|
+
return renderHelp({
|
|
44
|
+
description: 'Run a package in a temporary environment.',
|
|
45
|
+
descriptionLists: [
|
|
46
|
+
{
|
|
47
|
+
title: 'Options',
|
|
48
|
+
list: [
|
|
49
|
+
{
|
|
50
|
+
description: 'The package to install before running the command',
|
|
51
|
+
name: '--package',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
description: 'A list of package names that are allowed to run postinstall scripts during installation',
|
|
55
|
+
name: '--allow-build',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
description: 'Runs the script inside of a shell. Uses /bin/sh on UNIX and \\cmd.exe on Windows.',
|
|
59
|
+
name: '--shell-mode',
|
|
60
|
+
shortAlias: '-c',
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
OUTPUT_OPTIONS,
|
|
65
|
+
],
|
|
66
|
+
url: docsUrl('dlx'),
|
|
67
|
+
usages: ['pnpm dlx <command> [args...]'],
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
export async function handler(opts, [command, ...args]) {
|
|
71
|
+
if (!command && (!opts.package || opts.package.length === 0)) {
|
|
72
|
+
return { exitCode: 1, output: help() };
|
|
73
|
+
}
|
|
74
|
+
const pkgs = opts.package ?? [command];
|
|
75
|
+
const fullMetadata = ((opts.resolutionMode === 'time-based' ||
|
|
76
|
+
Boolean(opts.minimumReleaseAge) ||
|
|
77
|
+
opts.trustPolicy === 'no-downgrade') && !opts.registrySupportsTimeField);
|
|
78
|
+
const catalogResolver = resolveFromCatalog.bind(null, opts.catalogs ?? {});
|
|
79
|
+
const { resolve } = createResolver({
|
|
80
|
+
...opts,
|
|
81
|
+
authConfig: opts.rawConfig,
|
|
82
|
+
fullMetadata,
|
|
83
|
+
filterMetadata: fullMetadata,
|
|
84
|
+
retry: {
|
|
85
|
+
factor: opts.fetchRetryFactor,
|
|
86
|
+
maxTimeout: opts.fetchRetryMaxtimeout,
|
|
87
|
+
minTimeout: opts.fetchRetryMintimeout,
|
|
88
|
+
retries: opts.fetchRetries,
|
|
89
|
+
},
|
|
90
|
+
timeout: opts.fetchTimeout,
|
|
91
|
+
});
|
|
92
|
+
const resolvedPkgAliases = [];
|
|
93
|
+
const publishedBy = opts.minimumReleaseAge ? new Date(Date.now() - opts.minimumReleaseAge * 60 * 1000) : undefined;
|
|
94
|
+
const publishedByExclude = opts.minimumReleaseAgeExclude
|
|
95
|
+
? createPackageVersionPolicy(opts.minimumReleaseAgeExclude)
|
|
96
|
+
: undefined;
|
|
97
|
+
const resolvedPkgs = await Promise.all(pkgs.map(async (pkg) => {
|
|
98
|
+
const { alias, bareSpecifier } = parseWantedDependency(pkg) || {};
|
|
99
|
+
if (alias == null)
|
|
100
|
+
return pkg;
|
|
101
|
+
const resolvedBareSpecifier = bareSpecifier != null
|
|
102
|
+
? resolveCatalogProtocol(catalogResolver, alias, bareSpecifier)
|
|
103
|
+
: bareSpecifier;
|
|
104
|
+
resolvedPkgAliases.push(alias);
|
|
105
|
+
const resolved = await resolve({ alias, bareSpecifier: resolvedBareSpecifier }, {
|
|
106
|
+
lockfileDir: opts.lockfileDir ?? opts.dir,
|
|
107
|
+
preferredVersions: {},
|
|
108
|
+
projectDir: opts.dir,
|
|
109
|
+
publishedBy,
|
|
110
|
+
publishedByExclude,
|
|
111
|
+
});
|
|
112
|
+
return resolved.id;
|
|
113
|
+
}));
|
|
114
|
+
const { cacheLink, cacheExists, cachedDir } = findCache({
|
|
115
|
+
packages: resolvedPkgs,
|
|
116
|
+
dlxCacheMaxAge: opts.dlxCacheMaxAge,
|
|
117
|
+
cacheDir: opts.cacheDir,
|
|
118
|
+
registries: opts.registries,
|
|
119
|
+
allowBuild: opts.allowBuild,
|
|
120
|
+
supportedArchitectures: opts.supportedArchitectures,
|
|
121
|
+
});
|
|
122
|
+
if (!cacheExists) {
|
|
123
|
+
fs.mkdirSync(cachedDir, { recursive: true });
|
|
124
|
+
await add.handler({
|
|
125
|
+
...opts,
|
|
126
|
+
enableGlobalVirtualStore: opts.enableGlobalVirtualStore ?? true,
|
|
127
|
+
bin: path.join(cachedDir, 'node_modules/.bin'),
|
|
128
|
+
dir: cachedDir,
|
|
129
|
+
lockfileDir: cachedDir,
|
|
130
|
+
allowBuilds: Object.fromEntries([...resolvedPkgAliases, ...(opts.allowBuild ?? [])].map(pkg => [pkg, true])),
|
|
131
|
+
rootProjectManifestDir: cachedDir,
|
|
132
|
+
saveProd: true, // dlx will be looking for the package in the "dependencies" field!
|
|
133
|
+
saveDev: false,
|
|
134
|
+
saveOptional: false,
|
|
135
|
+
savePeer: false,
|
|
136
|
+
symlink: true,
|
|
137
|
+
workspaceDir: undefined,
|
|
138
|
+
}, resolvedPkgs);
|
|
139
|
+
try {
|
|
140
|
+
await symlinkDir(cachedDir, cacheLink, { overwrite: true });
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
// EBUSY/EEXIST/EPERM means that there is another dlx process running in parallel that has acquired the cache link first.
|
|
144
|
+
// EPERM can happen on Windows when another process has the symlink open while this process tries to unlink it.
|
|
145
|
+
// The link created by the other process is just as up-to-date as the link the current process was attempting
|
|
146
|
+
// to create. Therefore, instead of re-attempting to create the current link again, it is just as good to let
|
|
147
|
+
// the other link stay. The current process should yield.
|
|
148
|
+
if (!util.types.isNativeError(error) || !('code' in error) || (error.code !== 'EBUSY' && error.code !== 'EEXIST' && error.code !== 'EPERM')) {
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
const binsDir = path.join(cachedDir, 'node_modules/.bin');
|
|
154
|
+
const env = makeEnv({
|
|
155
|
+
userAgent: opts.userAgent,
|
|
156
|
+
prependPaths: [binsDir, ...opts.extraBinPaths],
|
|
157
|
+
});
|
|
158
|
+
const binName = opts.package
|
|
159
|
+
? command
|
|
160
|
+
: await getBinName(cachedDir, opts);
|
|
161
|
+
try {
|
|
162
|
+
await execa(binName, args, {
|
|
163
|
+
cwd: process.cwd(),
|
|
164
|
+
env,
|
|
165
|
+
stdio: 'inherit',
|
|
166
|
+
shell: opts.shellMode ?? false,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
if (util.types.isNativeError(err) && 'exitCode' in err && err.exitCode != null) {
|
|
171
|
+
return {
|
|
172
|
+
exitCode: err.exitCode,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
throw err;
|
|
176
|
+
}
|
|
177
|
+
return { exitCode: 0 };
|
|
178
|
+
}
|
|
179
|
+
async function getPkgName(pkgDir) {
|
|
180
|
+
const manifest = await readPackageJsonFromDir(pkgDir);
|
|
181
|
+
const dependencyNames = Object.keys(manifest.dependencies ?? {});
|
|
182
|
+
if (dependencyNames.length === 0) {
|
|
183
|
+
throw new PnpmError('DLX_NO_DEP', 'dlx was unable to find the installed dependency in "dependencies"');
|
|
184
|
+
}
|
|
185
|
+
return dependencyNames[0];
|
|
186
|
+
}
|
|
187
|
+
async function getBinName(cachedDir, opts) {
|
|
188
|
+
const pkgName = await getPkgName(cachedDir);
|
|
189
|
+
const pkgDir = path.join(cachedDir, 'node_modules', pkgName);
|
|
190
|
+
const manifest = await readProjectManifestOnly(pkgDir, opts);
|
|
191
|
+
const bins = await getBinsFromPackageManifest(manifest, pkgDir);
|
|
192
|
+
if (bins.length === 0) {
|
|
193
|
+
throw new PnpmError('DLX_NO_BIN', `No binaries found in ${pkgName}`);
|
|
194
|
+
}
|
|
195
|
+
if (bins.length === 1) {
|
|
196
|
+
return bins[0].name;
|
|
197
|
+
}
|
|
198
|
+
const scopelessPkgName = scopeless(manifest.name);
|
|
199
|
+
const defaultBin = bins.find(({ name }) => name === scopelessPkgName);
|
|
200
|
+
if (defaultBin)
|
|
201
|
+
return defaultBin.name;
|
|
202
|
+
const binNames = bins.map(({ name }) => name);
|
|
203
|
+
throw new PnpmError('DLX_MULTIPLE_BINS', `Could not determine executable to run. ${pkgName} has multiple binaries: ${binNames.join(', ')}`, {
|
|
204
|
+
hint: `Try one of the following:
|
|
205
|
+
${binNames.map(name => `pnpm --package=${pkgName} dlx ${name}`).join('\n')}
|
|
206
|
+
`,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
function scopeless(pkgName) {
|
|
210
|
+
if (pkgName[0] === '@') {
|
|
211
|
+
return pkgName.split('/')[1];
|
|
212
|
+
}
|
|
213
|
+
return pkgName;
|
|
214
|
+
}
|
|
215
|
+
function findCache(opts) {
|
|
216
|
+
const dlxCommandCacheDir = createDlxCommandCacheDir(opts);
|
|
217
|
+
const cacheLink = path.join(dlxCommandCacheDir, 'pkg');
|
|
218
|
+
const cachedDir = getValidCacheDir(cacheLink, opts.dlxCacheMaxAge);
|
|
219
|
+
return {
|
|
220
|
+
cacheLink,
|
|
221
|
+
cachedDir: cachedDir ?? getPrepareDir(dlxCommandCacheDir),
|
|
222
|
+
cacheExists: cachedDir != null,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
function createDlxCommandCacheDir(opts) {
|
|
226
|
+
const dlxCacheDir = path.resolve(opts.cacheDir, 'dlx');
|
|
227
|
+
const cacheKey = createCacheKey(opts);
|
|
228
|
+
const cachePath = path.join(dlxCacheDir, cacheKey);
|
|
229
|
+
fs.mkdirSync(cachePath, { recursive: true });
|
|
230
|
+
return cachePath;
|
|
231
|
+
}
|
|
232
|
+
export function createCacheKey(opts) {
|
|
233
|
+
const sortedPkgs = [...opts.packages].sort(lexCompare);
|
|
234
|
+
const sortedRegistries = Object.entries(opts.registries).sort(([k1], [k2]) => lexCompare(k1, k2));
|
|
235
|
+
const args = [sortedPkgs, sortedRegistries];
|
|
236
|
+
if (opts.allowBuild?.length) {
|
|
237
|
+
args.push({ allowBuild: opts.allowBuild.sort(lexCompare) });
|
|
238
|
+
}
|
|
239
|
+
if (opts.supportedArchitectures) {
|
|
240
|
+
const supportedArchitecturesKeys = ['cpu', 'libc', 'os'];
|
|
241
|
+
for (const key of supportedArchitecturesKeys) {
|
|
242
|
+
const value = opts.supportedArchitectures[key];
|
|
243
|
+
if (!value?.length)
|
|
244
|
+
continue;
|
|
245
|
+
args.push({
|
|
246
|
+
supportedArchitectures: {
|
|
247
|
+
[key]: [...new Set(value)].sort(lexCompare),
|
|
248
|
+
},
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
const hashStr = JSON.stringify(args);
|
|
253
|
+
return createHexHash(hashStr);
|
|
254
|
+
}
|
|
255
|
+
function getValidCacheDir(cacheLink, dlxCacheMaxAge) {
|
|
256
|
+
let stats;
|
|
257
|
+
let target;
|
|
258
|
+
try {
|
|
259
|
+
stats = fs.lstatSync(cacheLink);
|
|
260
|
+
if (stats.isSymbolicLink()) {
|
|
261
|
+
target = fs.realpathSync(cacheLink);
|
|
262
|
+
if (!target)
|
|
263
|
+
return undefined;
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
return undefined;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
catch (err) {
|
|
270
|
+
if (util.types.isNativeError(err) && 'code' in err && err.code === 'ENOENT') {
|
|
271
|
+
return undefined;
|
|
272
|
+
}
|
|
273
|
+
throw err;
|
|
274
|
+
}
|
|
275
|
+
const isValid = stats.mtime.getTime() + dlxCacheMaxAge * 60_000 >= new Date().getTime();
|
|
276
|
+
return isValid ? target : undefined;
|
|
277
|
+
}
|
|
278
|
+
function getPrepareDir(cachePath) {
|
|
279
|
+
const name = `${new Date().getTime().toString(16)}-${process.pid.toString(16)}`;
|
|
280
|
+
return path.join(cachePath, name);
|
|
281
|
+
}
|
|
282
|
+
function resolveCatalogProtocol(catalogResolver, alias, bareSpecifier) {
|
|
283
|
+
const result = catalogResolver({ alias, bareSpecifier });
|
|
284
|
+
switch (result.type) {
|
|
285
|
+
case 'found': return result.resolution.specifier;
|
|
286
|
+
case 'unused': return bareSpecifier;
|
|
287
|
+
case 'misconfiguration': throw result.error;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
//# sourceMappingURL=dlx.js.map
|
package/lib/exec.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type RecursiveSummary } from '@pnpm/cli.utils';
|
|
2
|
+
import { type Config } from '@pnpm/config.reader';
|
|
3
|
+
import type { CheckDepsStatusOptions } from '@pnpm/deps.status';
|
|
4
|
+
import type { ProjectRootDir, ProjectsGraph } from '@pnpm/types';
|
|
5
|
+
export declare const shorthands: Record<string, string | string[]>;
|
|
6
|
+
export declare const commandNames: string[];
|
|
7
|
+
export declare function rcOptionsTypes(): Record<string, unknown>;
|
|
8
|
+
export declare const cliOptionsTypes: () => Record<string, unknown>;
|
|
9
|
+
export declare function help(): string;
|
|
10
|
+
export declare function getResumedPackageChunks({ resumeFrom, chunks, selectedProjectsGraph }: {
|
|
11
|
+
resumeFrom: string;
|
|
12
|
+
chunks: ProjectRootDir[][];
|
|
13
|
+
selectedProjectsGraph: ProjectsGraph;
|
|
14
|
+
}): ProjectRootDir[][];
|
|
15
|
+
export declare function writeRecursiveSummary(opts: {
|
|
16
|
+
dir: string;
|
|
17
|
+
summary: RecursiveSummary;
|
|
18
|
+
}): Promise<void>;
|
|
19
|
+
export declare function createEmptyRecursiveSummary(chunks: string[][]): RecursiveSummary;
|
|
20
|
+
export declare function getExecutionDuration(start: [number, number]): number;
|
|
21
|
+
export type ExecOpts = Required<Pick<Config, 'selectedProjectsGraph'>> & {
|
|
22
|
+
bail?: boolean;
|
|
23
|
+
unsafePerm?: boolean;
|
|
24
|
+
reverse?: boolean;
|
|
25
|
+
sort?: boolean;
|
|
26
|
+
workspaceConcurrency?: number;
|
|
27
|
+
shellMode?: boolean;
|
|
28
|
+
resumeFrom?: string;
|
|
29
|
+
reportSummary?: boolean;
|
|
30
|
+
implicitlyFellbackFromRun?: boolean;
|
|
31
|
+
} & Pick<Config, 'bin' | 'cliOptions' | 'dir' | 'extraBinPaths' | 'extraEnv' | 'lockfileDir' | 'modulesDir' | 'nodeOptions' | 'pnpmHomeDir' | 'rawConfig' | 'recursive' | 'reporterHidePrefix' | 'userAgent' | 'verifyDepsBeforeRun' | 'workspaceDir'> & CheckDepsStatusOptions;
|
|
32
|
+
export declare function handler(opts: ExecOpts, params: string[]): Promise<{
|
|
33
|
+
exitCode: number;
|
|
34
|
+
}>;
|