@vltpkg/cli-sdk 1.0.0-rc.22 → 1.0.0-rc.24
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/dist/commands/bugs.d.ts +17 -0
- package/dist/commands/bugs.js +163 -0
- package/dist/commands/build.d.ts +24 -0
- package/dist/commands/build.js +101 -0
- package/dist/commands/cache.d.ts +64 -0
- package/dist/commands/cache.js +256 -0
- package/dist/commands/ci.d.ts +10 -0
- package/dist/commands/ci.js +40 -0
- package/dist/commands/config.d.ts +5 -0
- package/dist/commands/config.js +429 -0
- package/dist/commands/create.d.ts +8 -0
- package/dist/commands/create.js +102 -0
- package/dist/commands/docs.d.ts +17 -0
- package/dist/commands/docs.js +153 -0
- package/dist/commands/exec-cache.d.ts +48 -0
- package/dist/commands/exec-cache.js +145 -0
- package/dist/commands/exec-local.d.ts +5 -0
- package/dist/commands/exec-local.js +46 -0
- package/dist/commands/exec.d.ts +8 -0
- package/dist/commands/exec.js +161 -0
- package/dist/commands/help.d.ts +3 -0
- package/dist/commands/help.js +43 -0
- package/dist/commands/init.d.ts +7 -0
- package/dist/commands/init.js +116 -0
- package/dist/commands/install/reporter.d.ts +10 -0
- package/dist/commands/install/reporter.js +93 -0
- package/dist/commands/install.d.ts +27 -0
- package/dist/commands/install.js +80 -0
- package/dist/commands/list.d.ts +17 -0
- package/dist/commands/list.js +197 -0
- package/dist/commands/login.d.ts +3 -0
- package/dist/commands/login.js +22 -0
- package/dist/commands/logout.d.ts +3 -0
- package/dist/commands/logout.js +22 -0
- package/dist/commands/pack.d.ts +31 -0
- package/dist/commands/pack.js +205 -0
- package/dist/commands/ping.d.ts +17 -0
- package/dist/commands/ping.js +114 -0
- package/dist/commands/pkg.d.ts +6 -0
- package/dist/commands/pkg.js +232 -0
- package/dist/commands/publish.d.ts +21 -0
- package/dist/commands/publish.js +282 -0
- package/dist/commands/query.d.ts +18 -0
- package/dist/commands/query.js +216 -0
- package/dist/commands/repo.d.ts +17 -0
- package/dist/commands/repo.js +157 -0
- package/dist/commands/run-exec.d.ts +5 -0
- package/dist/commands/run-exec.js +40 -0
- package/dist/commands/run.d.ts +5 -0
- package/dist/commands/run.js +62 -0
- package/dist/commands/token.d.ts +3 -0
- package/dist/commands/token.js +39 -0
- package/dist/commands/uninstall.d.ts +15 -0
- package/dist/commands/uninstall.js +39 -0
- package/dist/commands/update.d.ts +13 -0
- package/dist/commands/update.js +46 -0
- package/dist/commands/version.d.ts +25 -0
- package/dist/commands/version.js +252 -0
- package/dist/commands/view.d.ts +22 -0
- package/dist/commands/view.js +334 -0
- package/dist/commands/whoami.d.ts +12 -0
- package/dist/commands/whoami.js +28 -0
- package/dist/config/definition.d.ts +407 -0
- package/dist/config/definition.js +684 -0
- package/dist/config/index.d.ts +218 -0
- package/dist/config/index.js +488 -0
- package/dist/config/merge.d.ts +3 -0
- package/dist/config/merge.js +27 -0
- package/dist/config/usage.d.ts +18 -0
- package/dist/config/usage.js +39 -0
- package/dist/custom-help.d.ts +8 -0
- package/dist/custom-help.js +419 -0
- package/dist/exec-command.d.ts +52 -0
- package/dist/exec-command.js +313 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +72 -0
- package/dist/load-command.d.ts +15 -0
- package/dist/load-command.js +20 -0
- package/dist/mermaid-image-view.d.ts +18 -0
- package/dist/mermaid-image-view.js +36 -0
- package/dist/output.d.ts +20 -0
- package/dist/output.js +125 -0
- package/dist/pack-tarball.d.ts +23 -0
- package/dist/pack-tarball.js +256 -0
- package/dist/parse-add-remove-args.d.ts +28 -0
- package/dist/parse-add-remove-args.js +103 -0
- package/dist/print-err.d.ts +13 -0
- package/dist/print-err.js +193 -0
- package/dist/query-diff-files.d.ts +17 -0
- package/dist/query-diff-files.js +63 -0
- package/dist/query-host-contexts.d.ts +15 -0
- package/dist/query-host-contexts.js +136 -0
- package/dist/read-password.d.ts +7 -0
- package/dist/read-password.js +32 -0
- package/dist/read-project-folders.d.ts +17 -0
- package/dist/read-project-folders.js +100 -0
- package/dist/reload-config.d.ts +2 -0
- package/dist/reload-config.js +11 -0
- package/dist/render-mermaid.d.ts +22 -0
- package/dist/render-mermaid.js +68 -0
- package/dist/view.d.ts +29 -0
- package/dist/view.js +30 -0
- package/package.json +30 -30
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { mkdirSync } from 'node:fs';
|
|
2
|
+
import { relative, resolve } from 'node:path';
|
|
3
|
+
import { minimatch } from 'minimatch';
|
|
4
|
+
import { init } from '@vltpkg/init';
|
|
5
|
+
import { load, save } from '@vltpkg/vlt-json';
|
|
6
|
+
import { assertWSConfig, asWSConfig } from '@vltpkg/workspaces';
|
|
7
|
+
import { commandUsage } from "../config/usage.js";
|
|
8
|
+
export const usage = () => commandUsage({
|
|
9
|
+
command: 'init',
|
|
10
|
+
usage: '',
|
|
11
|
+
description: `Create a new package.json file in the current directory.`,
|
|
12
|
+
options: {
|
|
13
|
+
workspace: {
|
|
14
|
+
value: '<path|glob>',
|
|
15
|
+
description: 'Create package.json files in matching workspaces.',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
// TODO: colorize the JSON if config.options.color
|
|
20
|
+
export const views = {
|
|
21
|
+
human: (results) => {
|
|
22
|
+
const output = [];
|
|
23
|
+
// if results is an array, it means multiple workspaces were initialized
|
|
24
|
+
if (Array.isArray(results)) {
|
|
25
|
+
for (const result of results) {
|
|
26
|
+
for (const [type, { path }] of Object.entries(result)) {
|
|
27
|
+
output.push(`Wrote ${type} to ${path}:`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
// otherwise, it's a single result
|
|
33
|
+
for (const [type, { path, data }] of Object.entries(results)) {
|
|
34
|
+
output.push(`Wrote ${type} to ${path}:
|
|
35
|
+
|
|
36
|
+
${JSON.stringify(data, null, 2)}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
output.push(`\nModify/add properties using \`vlt pkg\`. For example:
|
|
40
|
+
|
|
41
|
+
vlt pkg set "description=My new project"`);
|
|
42
|
+
return output.join('\n');
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
export const command = async (conf) => {
|
|
46
|
+
if (conf.values.workspace?.length) {
|
|
47
|
+
const workspacesConfig = load('workspaces', assertWSConfig);
|
|
48
|
+
const parsedWSConfig = asWSConfig(workspacesConfig ?? {});
|
|
49
|
+
const results = [];
|
|
50
|
+
const addToConfig = [];
|
|
51
|
+
// create a new package.json file for every workspace
|
|
52
|
+
// defined as cli --workspace options
|
|
53
|
+
for (const workspace of conf.values.workspace) {
|
|
54
|
+
// cwd is the resolved location of the workspace
|
|
55
|
+
const cwd = resolve(conf.options.projectRoot, workspace);
|
|
56
|
+
// create the folder in case it's missing
|
|
57
|
+
mkdirSync(cwd, { recursive: true });
|
|
58
|
+
// run the initialization script and collect results
|
|
59
|
+
results.push(await init({ cwd }));
|
|
60
|
+
// Check if this workspace path is covered by existing workspace patterns
|
|
61
|
+
const isMatched = Object.values(parsedWSConfig).some((patterns) => {
|
|
62
|
+
return patterns.some(pattern => minimatch(workspace, pattern));
|
|
63
|
+
});
|
|
64
|
+
// When a workspace is not matched we track it for insertion later
|
|
65
|
+
if (!isMatched) {
|
|
66
|
+
addToConfig.push(relative(conf.options.projectRoot, cwd).replace(/\\/g, '/'));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// if there are workspaces that were not matched by existing
|
|
70
|
+
// patterns, we add them to the workspaces config
|
|
71
|
+
if (addToConfig.length > 0) {
|
|
72
|
+
let workspaces = workspacesConfig;
|
|
73
|
+
// if the original workspaces config is a string, we'll need
|
|
74
|
+
// to convert it to an array in order to append the recently
|
|
75
|
+
// added workspaces
|
|
76
|
+
if (typeof workspacesConfig === 'string') {
|
|
77
|
+
workspaces = [workspacesConfig, ...addToConfig];
|
|
78
|
+
}
|
|
79
|
+
else if (Array.isArray(workspacesConfig)) {
|
|
80
|
+
// if the original workspaces config is an array, we simply
|
|
81
|
+
// append the missing items to it
|
|
82
|
+
workspaces = [...workspacesConfig, ...addToConfig];
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
// otherwise we assume it's an Record<string, string[]> object
|
|
86
|
+
// and we'll add the new workspaces to the `packages` keys
|
|
87
|
+
workspaces = (workspacesConfig ?? {});
|
|
88
|
+
// if the `packages` key is not being used
|
|
89
|
+
if (!workspaces.packages) {
|
|
90
|
+
workspaces.packages = addToConfig;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
// if the `packages` key is defined as a string, we
|
|
94
|
+
// convert it to an array to append the new items
|
|
95
|
+
if (typeof workspaces.packages === 'string') {
|
|
96
|
+
workspaces.packages = [
|
|
97
|
+
workspaces.packages,
|
|
98
|
+
...addToConfig,
|
|
99
|
+
];
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
// if it is, we simply append the new workspaces
|
|
103
|
+
workspaces.packages = [
|
|
104
|
+
...workspaces.packages,
|
|
105
|
+
...addToConfig,
|
|
106
|
+
];
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// finally, we add the new workspaces to the config file
|
|
111
|
+
save('workspaces', workspaces);
|
|
112
|
+
}
|
|
113
|
+
return results;
|
|
114
|
+
}
|
|
115
|
+
return init({ cwd: process.cwd() });
|
|
116
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ViewClass } from '../../view.ts';
|
|
2
|
+
import type { InstallResult } from '../install.ts';
|
|
3
|
+
export declare class InstallReporter extends ViewClass {
|
|
4
|
+
#private;
|
|
5
|
+
start(): void;
|
|
6
|
+
done(_result: InstallResult, { time }: {
|
|
7
|
+
time: number;
|
|
8
|
+
}): Promise<undefined>;
|
|
9
|
+
error(err: unknown): void;
|
|
10
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { emitter } from '@vltpkg/output';
|
|
2
|
+
import { Box, render, Text } from 'ink';
|
|
3
|
+
import Spinner from 'ink-spinner';
|
|
4
|
+
import { createElement as $, Fragment, useEffect, useState, } from 'react';
|
|
5
|
+
import { ViewClass } from "../../view.js";
|
|
6
|
+
import { asError } from '@vltpkg/types';
|
|
7
|
+
const labels = {
|
|
8
|
+
build: 'resolving dependencies',
|
|
9
|
+
actual: '',
|
|
10
|
+
reify: 'extracting files',
|
|
11
|
+
};
|
|
12
|
+
const GraphStep = ({ text, step }) => {
|
|
13
|
+
if (step.state === 'waiting') {
|
|
14
|
+
return $(Text, { color: 'gray' }, text);
|
|
15
|
+
}
|
|
16
|
+
if (step.state === 'in_progress') {
|
|
17
|
+
return $(Text, { color: 'yellow' }, text + ' ', $(Spinner, { type: 'dots' }));
|
|
18
|
+
}
|
|
19
|
+
return $(Text, { color: 'green' }, text, ' ✓');
|
|
20
|
+
};
|
|
21
|
+
const App = ({ trailer }) => {
|
|
22
|
+
const [requests, setRequests] = useState(0);
|
|
23
|
+
const [cacheHit, setCacheHit] = useState(0);
|
|
24
|
+
const [steps, setSteps] = useState({
|
|
25
|
+
build: {
|
|
26
|
+
state: 'waiting',
|
|
27
|
+
},
|
|
28
|
+
actual: {
|
|
29
|
+
state: 'waiting',
|
|
30
|
+
},
|
|
31
|
+
reify: {
|
|
32
|
+
state: 'waiting',
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
const updateRequests = ({ state }) => {
|
|
37
|
+
if (state === 'start') {
|
|
38
|
+
setRequests(p => p + 1);
|
|
39
|
+
}
|
|
40
|
+
else if (state === 'cache' || state === 'stale') {
|
|
41
|
+
setCacheHit(p => p + 1);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
emitter.on('request', updateRequests);
|
|
45
|
+
return () => emitter.off('request', updateRequests);
|
|
46
|
+
}, []);
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
const update = ({ step, state }) => {
|
|
49
|
+
setSteps(p => ({
|
|
50
|
+
...p,
|
|
51
|
+
[step]: {
|
|
52
|
+
...p[step],
|
|
53
|
+
state: state === 'start' ? 'in_progress' : 'completed',
|
|
54
|
+
},
|
|
55
|
+
}));
|
|
56
|
+
};
|
|
57
|
+
emitter.on('graphStep', update);
|
|
58
|
+
return () => emitter.off('graphStep', update);
|
|
59
|
+
}, []);
|
|
60
|
+
return $(Fragment, null, $(Box, null, ...['build', 'actual', 'reify'].map((step, idx, list) => {
|
|
61
|
+
const separator = idx === list.length - 1 ? '' : ' > ';
|
|
62
|
+
const label = labels[step];
|
|
63
|
+
if (!label)
|
|
64
|
+
return null;
|
|
65
|
+
return $(Text, { key: step }, $(GraphStep, { text: label, step: steps[step] }), $(Text, { color: 'gray' }, separator));
|
|
66
|
+
})), cacheHit > 0 ?
|
|
67
|
+
$(Text, null, `${cacheHit} cache hit${cacheHit > 1 ? 's' : ''}`)
|
|
68
|
+
: null, requests > 0 ?
|
|
69
|
+
$(Text, null, `${requests} request${requests > 1 ? 's' : ''}`)
|
|
70
|
+
: null, trailer ? $(Text, null, trailer) : null);
|
|
71
|
+
};
|
|
72
|
+
export class InstallReporter extends ViewClass {
|
|
73
|
+
#instance = null;
|
|
74
|
+
start() {
|
|
75
|
+
this.#instance = render($(App));
|
|
76
|
+
}
|
|
77
|
+
async done(_result, { time }) {
|
|
78
|
+
let out = `Done in ${time}ms`;
|
|
79
|
+
// prints a very complete message explaining users the next steps
|
|
80
|
+
// in case there are packages to be built
|
|
81
|
+
if (_result.buildQueue?.length) {
|
|
82
|
+
out += `\n\n📦 ${_result.buildQueue.length} packages have install scripts defined & were not fully built\n`;
|
|
83
|
+
out += '🔎 Run `vlt query :scripts` to list them\n';
|
|
84
|
+
out +=
|
|
85
|
+
'🔨 Run `vlt build` to run all required scripts to build installed packages.\n';
|
|
86
|
+
}
|
|
87
|
+
this.#instance?.rerender($(App, { trailer: out }));
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
error(err) {
|
|
91
|
+
this.#instance?.unmount(asError(err));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { InstallReporter } from './install/reporter.ts';
|
|
2
|
+
import type { DepID } from '@vltpkg/dep-id';
|
|
3
|
+
import type { Graph } from '@vltpkg/graph';
|
|
4
|
+
import type { CommandFn, CommandUsage } from '../index.ts';
|
|
5
|
+
/**
|
|
6
|
+
* The resulting object of an install operation. To be used by the view impl.
|
|
7
|
+
*/
|
|
8
|
+
export type InstallResult = {
|
|
9
|
+
/**
|
|
10
|
+
* A queue of package IDs that need to be built after the install is complete.
|
|
11
|
+
*/
|
|
12
|
+
buildQueue?: DepID[];
|
|
13
|
+
/**
|
|
14
|
+
* The resulting graph structure at the end of an install.
|
|
15
|
+
*/
|
|
16
|
+
graph: Graph;
|
|
17
|
+
};
|
|
18
|
+
export declare const usage: CommandUsage;
|
|
19
|
+
export declare const views: {
|
|
20
|
+
readonly json: (i: InstallResult) => {
|
|
21
|
+
graph: import("@vltpkg/graph").LockfileData;
|
|
22
|
+
buildQueue?: DepID[] | undefined;
|
|
23
|
+
message?: string | undefined;
|
|
24
|
+
};
|
|
25
|
+
readonly human: typeof InstallReporter;
|
|
26
|
+
};
|
|
27
|
+
export declare const command: CommandFn<InstallResult>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { commandUsage } from "../config/usage.js";
|
|
2
|
+
import { install } from '@vltpkg/graph';
|
|
3
|
+
import { parseAddArgs } from "../parse-add-remove-args.js";
|
|
4
|
+
import { InstallReporter } from "./install/reporter.js";
|
|
5
|
+
export const usage = () => commandUsage({
|
|
6
|
+
command: 'install',
|
|
7
|
+
usage: '[packages ...]',
|
|
8
|
+
description: `Install the specified packages, updating package.json and
|
|
9
|
+
vlt-lock.json appropriately.`,
|
|
10
|
+
options: {
|
|
11
|
+
'save-dev': {
|
|
12
|
+
description: 'Save installed packages to package.json as devDependencies.',
|
|
13
|
+
},
|
|
14
|
+
'save-optional': {
|
|
15
|
+
description: 'Save installed packages to package.json as optionalDependencies.',
|
|
16
|
+
},
|
|
17
|
+
'save-peer': {
|
|
18
|
+
description: 'Save installed packages to package.json as peerDependencies.',
|
|
19
|
+
},
|
|
20
|
+
'save-prod': {
|
|
21
|
+
description: 'Save installed packages to package.json as dependencies.',
|
|
22
|
+
},
|
|
23
|
+
workspace: {
|
|
24
|
+
value: '<path|glob>',
|
|
25
|
+
description: 'Limit installation targets to matching workspaces.',
|
|
26
|
+
},
|
|
27
|
+
'workspace-group': {
|
|
28
|
+
value: '<name>',
|
|
29
|
+
description: 'Limit installation targets to workspace groups.',
|
|
30
|
+
},
|
|
31
|
+
'expect-lockfile': {
|
|
32
|
+
description: 'Fail if lockfile is missing or out of date.',
|
|
33
|
+
},
|
|
34
|
+
'frozen-lockfile': {
|
|
35
|
+
description: 'Fail if lockfile is missing or out of sync with package.json.',
|
|
36
|
+
},
|
|
37
|
+
'lockfile-only': {
|
|
38
|
+
description: 'Only update lockfile and package.json files; skip node_modules operations.',
|
|
39
|
+
},
|
|
40
|
+
'allow-scripts': {
|
|
41
|
+
value: '<query>',
|
|
42
|
+
description: 'Filter which packages are allowed to run lifecycle scripts using DSS query syntax.',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
export const views = {
|
|
47
|
+
json: i => ({
|
|
48
|
+
...(i.buildQueue?.length ?
|
|
49
|
+
{
|
|
50
|
+
buildQueue: i.buildQueue,
|
|
51
|
+
message: `${i.buildQueue.length} packages that will need to be built, run "vlt build" to complete the install.`,
|
|
52
|
+
}
|
|
53
|
+
: null),
|
|
54
|
+
graph: i.graph.toJSON(),
|
|
55
|
+
}),
|
|
56
|
+
human: InstallReporter,
|
|
57
|
+
};
|
|
58
|
+
export const command = async (conf) => {
|
|
59
|
+
// TODO: we should probably throw an error if the user
|
|
60
|
+
// tries to install using view=mermaid
|
|
61
|
+
const monorepo = conf.options.monorepo;
|
|
62
|
+
const scurry = conf.options.scurry;
|
|
63
|
+
const { add } = parseAddArgs(conf, scurry, monorepo);
|
|
64
|
+
const frozenLockfile = conf.options['frozen-lockfile'];
|
|
65
|
+
const expectLockfile = conf.options['expect-lockfile'];
|
|
66
|
+
const lockfileOnly = conf.options['lockfile-only'];
|
|
67
|
+
/* c8 ignore start */
|
|
68
|
+
const allowScripts = conf.get('allow-scripts') ?
|
|
69
|
+
String(conf.get('allow-scripts'))
|
|
70
|
+
: ':not(*)';
|
|
71
|
+
/* c8 ignore stop */
|
|
72
|
+
const { buildQueue, graph } = await install({
|
|
73
|
+
...conf.options,
|
|
74
|
+
frozenLockfile,
|
|
75
|
+
expectLockfile,
|
|
76
|
+
allowScripts,
|
|
77
|
+
lockfileOnly,
|
|
78
|
+
}, add);
|
|
79
|
+
return { buildQueue, graph };
|
|
80
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { humanReadableOutput, jsonOutput, mermaidOutput } from '@vltpkg/graph';
|
|
2
|
+
import type { HumanReadableOutputGraph, JSONOutputGraph, MermaidOutputGraph } from '@vltpkg/graph';
|
|
3
|
+
import { MermaidImageView } from '../mermaid-image-view.ts';
|
|
4
|
+
import type { CommandFn, CommandUsage } from '../index.ts';
|
|
5
|
+
export declare const usage: CommandUsage;
|
|
6
|
+
export type ListResult = JSONOutputGraph & MermaidOutputGraph & HumanReadableOutputGraph & {
|
|
7
|
+
queryString: string;
|
|
8
|
+
};
|
|
9
|
+
export declare const views: {
|
|
10
|
+
readonly json: typeof jsonOutput;
|
|
11
|
+
readonly mermaid: typeof mermaidOutput;
|
|
12
|
+
readonly human: typeof humanReadableOutput;
|
|
13
|
+
readonly count: (result: ListResult) => number;
|
|
14
|
+
readonly svg: typeof MermaidImageView;
|
|
15
|
+
readonly png: typeof MermaidImageView;
|
|
16
|
+
};
|
|
17
|
+
export declare const command: CommandFn<ListResult>;
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { actual, asNode, humanReadableOutput, jsonOutput, mermaidOutput, GraphModifier, } from '@vltpkg/graph';
|
|
2
|
+
import { Query } from '@vltpkg/query';
|
|
3
|
+
import { SecurityArchive } from '@vltpkg/security-archive';
|
|
4
|
+
import { error } from '@vltpkg/error-cause';
|
|
5
|
+
import { commandUsage } from "../config/usage.js";
|
|
6
|
+
import { createHostContextsMap } from "../query-host-contexts.js";
|
|
7
|
+
import { MermaidImageView } from "../mermaid-image-view.js";
|
|
8
|
+
export const usage = () => commandUsage({
|
|
9
|
+
command: 'ls',
|
|
10
|
+
usage: [
|
|
11
|
+
'',
|
|
12
|
+
'[package-names...] [--view=human | json | mermaid | svg | png | count]',
|
|
13
|
+
'[--scope=<query>] [--target=<query>] [--view=human | json | mermaid | svg | png | count]',
|
|
14
|
+
],
|
|
15
|
+
description: `List installed dependencies matching given package names or query selectors.
|
|
16
|
+
|
|
17
|
+
Package names provided as positional arguments will be used to filter
|
|
18
|
+
the results to show only dependencies with those names.
|
|
19
|
+
|
|
20
|
+
The --scope and --target options accepts DSS query selectors to filter
|
|
21
|
+
packages. Using --scope, you can specify which packages to treat as the
|
|
22
|
+
top-level items in the output graph. The --target option allows you to
|
|
23
|
+
filter what dependencies to include in the output. Using both options
|
|
24
|
+
allows you to render subgraphs of the dependency graph.
|
|
25
|
+
|
|
26
|
+
Defaults to listing direct dependencies of a project and any configured
|
|
27
|
+
workspace.`,
|
|
28
|
+
examples: {
|
|
29
|
+
'': {
|
|
30
|
+
description: 'List direct dependencies of the current project / workspace',
|
|
31
|
+
},
|
|
32
|
+
'foo bar baz': {
|
|
33
|
+
description: `List all dependencies named 'foo', 'bar', or 'baz'`,
|
|
34
|
+
},
|
|
35
|
+
'--scope=":root > #dependency-name"': {
|
|
36
|
+
description: 'Defines a direct dependency as the output top-level scope',
|
|
37
|
+
},
|
|
38
|
+
'--target="*"': {
|
|
39
|
+
description: 'List all dependencies using a query selector',
|
|
40
|
+
},
|
|
41
|
+
'--target=":workspace > *:peer"': {
|
|
42
|
+
description: 'List all peer dependencies of all workspaces',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
options: {
|
|
46
|
+
scope: {
|
|
47
|
+
value: '<query>',
|
|
48
|
+
description: 'Query selector to select top-level packages using the DSS query language syntax.',
|
|
49
|
+
},
|
|
50
|
+
target: {
|
|
51
|
+
value: '<query>',
|
|
52
|
+
description: 'Query selector to filter packages using the DSS query language syntax.',
|
|
53
|
+
},
|
|
54
|
+
view: {
|
|
55
|
+
value: '[human | json | mermaid | svg | png | count]',
|
|
56
|
+
description: 'Output format. Defaults to human-readable or json if no tty. Use svg or png to render the dependency graph as an image and open it. Count outputs the number of dependency relationships in the result.',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
export const views = {
|
|
61
|
+
json: jsonOutput,
|
|
62
|
+
mermaid: mermaidOutput,
|
|
63
|
+
human: humanReadableOutput,
|
|
64
|
+
count: (result) => result.edges.length,
|
|
65
|
+
svg: MermaidImageView,
|
|
66
|
+
png: MermaidImageView,
|
|
67
|
+
};
|
|
68
|
+
export const command = async (conf) => {
|
|
69
|
+
const modifiers = GraphModifier.maybeLoad(conf.options);
|
|
70
|
+
const monorepo = conf.options.monorepo;
|
|
71
|
+
const mainManifest = conf.options.packageJson.maybeRead(conf.options.projectRoot);
|
|
72
|
+
let graph;
|
|
73
|
+
let securityArchive;
|
|
74
|
+
// optionally load the cwd graph if we found a package.json file
|
|
75
|
+
if (mainManifest) {
|
|
76
|
+
graph = actual.load({
|
|
77
|
+
...conf.options,
|
|
78
|
+
mainManifest,
|
|
79
|
+
modifiers,
|
|
80
|
+
monorepo,
|
|
81
|
+
loadManifests: true,
|
|
82
|
+
});
|
|
83
|
+
securityArchive = await SecurityArchive.start({
|
|
84
|
+
nodes: [...graph.nodes.values()],
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
// Validate positional arguments - only allow package names, not direct queries
|
|
88
|
+
for (const arg of conf.positionals) {
|
|
89
|
+
if (!/^[@\w-]/.test(arg)) {
|
|
90
|
+
throw error(`Direct queries are not supported as positional arguments. Use package names only.`, {
|
|
91
|
+
code: 'EUSAGE',
|
|
92
|
+
cause: `Argument '${arg}' appears to be a query syntax. Only package names are allowed as positional arguments.`,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// retrieve default values and set up host contexts
|
|
97
|
+
const positionalQueryString = conf.positionals
|
|
98
|
+
.map(k => `#${k.replace(/\//, '\\/')}`)
|
|
99
|
+
.join(', ');
|
|
100
|
+
const targetQueryString = conf.get('target');
|
|
101
|
+
const scopeQueryString = conf.get('scope');
|
|
102
|
+
const queryString = targetQueryString || positionalQueryString;
|
|
103
|
+
const projectQueryString = ':workspace, :project > *';
|
|
104
|
+
const selectImporters = [];
|
|
105
|
+
const hostContexts = await createHostContextsMap(conf);
|
|
106
|
+
const importers = new Set();
|
|
107
|
+
const scopeIDs = [];
|
|
108
|
+
// handle --scope option to add scope nodes as importers
|
|
109
|
+
let scopeNodes;
|
|
110
|
+
if (scopeQueryString) {
|
|
111
|
+
// run scope query to get all matching nodes
|
|
112
|
+
/* c8 ignore start */
|
|
113
|
+
const edges = graph?.edges ?? new Set();
|
|
114
|
+
const nodes = graph?.nodes ?
|
|
115
|
+
new Set(graph.nodes.values())
|
|
116
|
+
: new Set();
|
|
117
|
+
const importers = graph?.importers ?? new Set();
|
|
118
|
+
/* c8 ignore stop */
|
|
119
|
+
const scopeQuery = new Query({
|
|
120
|
+
nodes,
|
|
121
|
+
edges,
|
|
122
|
+
importers,
|
|
123
|
+
securityArchive,
|
|
124
|
+
hostContexts,
|
|
125
|
+
});
|
|
126
|
+
const { nodes: resultNodes } = await scopeQuery.search(scopeQueryString, {
|
|
127
|
+
signal: new AbortController().signal,
|
|
128
|
+
});
|
|
129
|
+
scopeNodes = resultNodes;
|
|
130
|
+
}
|
|
131
|
+
if (scopeQueryString && scopeNodes) {
|
|
132
|
+
// Add all scope nodes to importers Set (treat them as top-level items)
|
|
133
|
+
for (const queryNode of scopeNodes) {
|
|
134
|
+
importers.add(asNode(queryNode));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else if ('workspace' in conf.values) {
|
|
138
|
+
// if in a workspace environment, select only the specified
|
|
139
|
+
// workspaces as top-level items
|
|
140
|
+
if (monorepo && graph) {
|
|
141
|
+
for (const workspace of monorepo.filter(conf.values)) {
|
|
142
|
+
const w = graph.nodes.get(workspace.id);
|
|
143
|
+
if (w) {
|
|
144
|
+
importers.add(w);
|
|
145
|
+
selectImporters.push(`[name="${w.name}"]`);
|
|
146
|
+
selectImporters.push(`[name="${w.name}"] > *`);
|
|
147
|
+
scopeIDs.push(workspace.id);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// build a default query string to use in the target search
|
|
153
|
+
const selectImportersQueryString = selectImporters.join(', ');
|
|
154
|
+
const defaultProjectQueryString = (graph &&
|
|
155
|
+
selectImporters.length &&
|
|
156
|
+
selectImporters.length < graph.importers.size) ?
|
|
157
|
+
selectImportersQueryString
|
|
158
|
+
: projectQueryString;
|
|
159
|
+
const defaultLocalScopeQueryString = ':host(local) :root > *';
|
|
160
|
+
// retrieve the selected nodes and edges
|
|
161
|
+
/* c8 ignore start */
|
|
162
|
+
const edges_ = graph?.edges ?? new Set();
|
|
163
|
+
const nodes_ = graph?.nodes ?
|
|
164
|
+
new Set(graph.nodes.values())
|
|
165
|
+
: new Set();
|
|
166
|
+
const importers_ = importers.size === 0 && graph ?
|
|
167
|
+
new Set([graph.mainImporter])
|
|
168
|
+
: importers;
|
|
169
|
+
/* c8 ignore stop */
|
|
170
|
+
const q = new Query({
|
|
171
|
+
nodes: nodes_,
|
|
172
|
+
edges: edges_,
|
|
173
|
+
importers: importers_,
|
|
174
|
+
securityArchive,
|
|
175
|
+
hostContexts,
|
|
176
|
+
});
|
|
177
|
+
const query = queryString ||
|
|
178
|
+
/* c8 ignore next */
|
|
179
|
+
(graph ? defaultProjectQueryString : defaultLocalScopeQueryString);
|
|
180
|
+
const { edges, nodes, importers: queryResultImporters, } = await q.search(query, {
|
|
181
|
+
signal: new AbortController().signal,
|
|
182
|
+
scopeIDs: scopeIDs.length > 0 ? scopeIDs : undefined,
|
|
183
|
+
});
|
|
184
|
+
return {
|
|
185
|
+
importers: importers.size === 0 ?
|
|
186
|
+
new Set(queryResultImporters)
|
|
187
|
+
: importers,
|
|
188
|
+
edges,
|
|
189
|
+
nodes,
|
|
190
|
+
highlightSelection: !!(targetQueryString || positionalQueryString),
|
|
191
|
+
queryString: queryString ||
|
|
192
|
+
(graph ?
|
|
193
|
+
/* c8 ignore next 2 */
|
|
194
|
+
defaultProjectQueryString
|
|
195
|
+
: defaultLocalScopeQueryString),
|
|
196
|
+
};
|
|
197
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { RegistryClient } from '@vltpkg/registry-client';
|
|
2
|
+
import { commandUsage } from "../config/usage.js";
|
|
3
|
+
export const usage = () => commandUsage({
|
|
4
|
+
command: 'login',
|
|
5
|
+
usage: [''],
|
|
6
|
+
description: `Authenticate against a registry, and store the token in
|
|
7
|
+
the appropriate config file for later use.`,
|
|
8
|
+
options: {
|
|
9
|
+
registry: {
|
|
10
|
+
value: '<url>',
|
|
11
|
+
description: 'Registry URL to authenticate against.',
|
|
12
|
+
},
|
|
13
|
+
identity: {
|
|
14
|
+
value: '<name>',
|
|
15
|
+
description: 'Identity namespace used to store auth tokens.',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
export const command = async (conf) => {
|
|
20
|
+
const rc = new RegistryClient(conf.options);
|
|
21
|
+
await rc.login(conf.options.registry);
|
|
22
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { RegistryClient } from '@vltpkg/registry-client';
|
|
2
|
+
import { commandUsage } from "../config/usage.js";
|
|
3
|
+
export const usage = () => commandUsage({
|
|
4
|
+
command: 'logout',
|
|
5
|
+
usage: [''],
|
|
6
|
+
description: `Log out of the default registry, deleting the token from
|
|
7
|
+
the local keychain, as well as destroying it on the server.`,
|
|
8
|
+
options: {
|
|
9
|
+
registry: {
|
|
10
|
+
value: '<url>',
|
|
11
|
+
description: 'Registry URL to log out from.',
|
|
12
|
+
},
|
|
13
|
+
identity: {
|
|
14
|
+
value: '<name>',
|
|
15
|
+
description: 'Identity namespace used to look up auth tokens.',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
export const command = async (conf) => {
|
|
20
|
+
const rc = new RegistryClient(conf.options);
|
|
21
|
+
await rc.logout(conf.options.registry);
|
|
22
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { CommandFn, CommandUsage } from '../index.ts';
|
|
2
|
+
import type { LoadedConfig } from '../config/index.ts';
|
|
3
|
+
export declare const usage: CommandUsage;
|
|
4
|
+
export type CommandResultSingle = {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
version: string;
|
|
8
|
+
filename: string;
|
|
9
|
+
files: string[];
|
|
10
|
+
size: number;
|
|
11
|
+
unpackedSize: number;
|
|
12
|
+
shasum?: string;
|
|
13
|
+
integrity?: string;
|
|
14
|
+
};
|
|
15
|
+
export type CommandResult = CommandResultSingle | CommandResultSingle[];
|
|
16
|
+
export declare const views: {
|
|
17
|
+
readonly human: (results: CommandResult) => string;
|
|
18
|
+
readonly json: (r: CommandResult) => CommandResult;
|
|
19
|
+
};
|
|
20
|
+
export declare const command: CommandFn<CommandResult>;
|
|
21
|
+
export declare const commandSingle: (location: string, conf: LoadedConfig) => Promise<{
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
version: string;
|
|
25
|
+
filename: string;
|
|
26
|
+
files: string[];
|
|
27
|
+
size: number;
|
|
28
|
+
unpackedSize: number;
|
|
29
|
+
shasum: string | undefined;
|
|
30
|
+
integrity: string | undefined;
|
|
31
|
+
}>;
|