@jskit-ai/jskit-cli 0.2.40 → 0.2.41
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/package.json +1 -1
- package/src/server/cliRuntime/packageInstallFlow.js +7 -2
- package/src/server/cliRuntime/packageTemplateResolution.js +23 -2
- package/src/server/commandHandlers/packageCommands/add.js +7 -2
- package/src/server/commandHandlers/packageCommands/generate.js +7 -2
- package/src/server/commandHandlers/shared.js +39 -0
- package/src/server/core/commandCatalog.js +551 -32
- package/src/server/core/createCliRunner.js +6 -0
- package/src/server/core/dispatchCli.js +28 -68
- package/src/server/core/usageHelp.js +8 -331
package/package.json
CHANGED
|
@@ -275,7 +275,8 @@ async function applyPackageInstall({
|
|
|
275
275
|
appPackageJson,
|
|
276
276
|
lock,
|
|
277
277
|
packageRegistry,
|
|
278
|
-
touchedFiles
|
|
278
|
+
touchedFiles,
|
|
279
|
+
reportTemplateFetchStatus = null
|
|
279
280
|
}) {
|
|
280
281
|
const existingInstall = ensureObject(lock.installedPackages[packageEntry.packageId]);
|
|
281
282
|
const existingManaged = ensureObject(existingInstall.managed);
|
|
@@ -292,7 +293,11 @@ async function applyPackageInstall({
|
|
|
292
293
|
const mutationWarnings = [];
|
|
293
294
|
const mutations = ensureObject(packageEntry.descriptor.mutations);
|
|
294
295
|
const fileMutations = ensureArray(mutations.files);
|
|
295
|
-
const templateRoot = await resolvePackageTemplateRoot({
|
|
296
|
+
const templateRoot = await resolvePackageTemplateRoot({
|
|
297
|
+
packageEntry,
|
|
298
|
+
appRoot,
|
|
299
|
+
reportTemplateFetchStatus
|
|
300
|
+
});
|
|
296
301
|
const packageEntryForMutations =
|
|
297
302
|
templateRoot === packageEntry.rootDir
|
|
298
303
|
? packageEntry
|
|
@@ -68,7 +68,10 @@ async function ensureMaterializedInstallWorkspace(installRoot) {
|
|
|
68
68
|
);
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
async function installCatalogPackageIntoCache({
|
|
71
|
+
async function installCatalogPackageIntoCache({
|
|
72
|
+
installRoot,
|
|
73
|
+
packageEntry
|
|
74
|
+
}) {
|
|
72
75
|
const packageId = String(packageEntry?.packageId || "").trim();
|
|
73
76
|
const version = String(packageEntry?.version || "").trim();
|
|
74
77
|
const packageSpec = version ? `${packageId}@${version}` : packageId;
|
|
@@ -124,6 +127,7 @@ async function installCatalogPackageIntoCache({ installRoot, packageEntry }) {
|
|
|
124
127
|
async function materializeCatalogPackageRoot({
|
|
125
128
|
packageEntry,
|
|
126
129
|
appRoot,
|
|
130
|
+
reportTemplateFetchStatus = null,
|
|
127
131
|
installCatalogPackage = installCatalogPackageIntoCache
|
|
128
132
|
} = {}) {
|
|
129
133
|
if (!isInternalCatalogPackageEntry(packageEntry)) {
|
|
@@ -139,12 +143,20 @@ async function materializeCatalogPackageRoot({
|
|
|
139
143
|
const installRoot = buildMaterializedInstallRoot({ appRoot, packageEntry });
|
|
140
144
|
const candidateRoot = path.join(installRoot, "node_modules", ...packageId.split("/"));
|
|
141
145
|
const descriptorPath = path.join(candidateRoot, "package.descriptor.mjs");
|
|
146
|
+
let didInstallPackage = false;
|
|
142
147
|
|
|
143
148
|
if (!(await fileExists(descriptorPath))) {
|
|
149
|
+
if (typeof reportTemplateFetchStatus === "function") {
|
|
150
|
+
reportTemplateFetchStatus({
|
|
151
|
+
packageEntry,
|
|
152
|
+
state: "start"
|
|
153
|
+
});
|
|
154
|
+
}
|
|
144
155
|
await installCatalogPackage({
|
|
145
156
|
installRoot,
|
|
146
157
|
packageEntry
|
|
147
158
|
});
|
|
159
|
+
didInstallPackage = true;
|
|
148
160
|
}
|
|
149
161
|
|
|
150
162
|
if (!(await fileExists(descriptorPath))) {
|
|
@@ -153,6 +165,13 @@ async function materializeCatalogPackageRoot({
|
|
|
153
165
|
);
|
|
154
166
|
}
|
|
155
167
|
|
|
168
|
+
if (didInstallPackage && typeof reportTemplateFetchStatus === "function") {
|
|
169
|
+
reportTemplateFetchStatus({
|
|
170
|
+
packageEntry,
|
|
171
|
+
state: "complete"
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
156
175
|
MATERIALIZED_PACKAGE_ROOTS.set(cacheKey, candidateRoot);
|
|
157
176
|
return candidateRoot;
|
|
158
177
|
}
|
|
@@ -243,6 +262,7 @@ async function resolvePackageRootFromLocalWorkspace({ packageId }) {
|
|
|
243
262
|
async function resolvePackageTemplateRoot({
|
|
244
263
|
packageEntry,
|
|
245
264
|
appRoot,
|
|
265
|
+
reportTemplateFetchStatus = null,
|
|
246
266
|
materializeCatalogRoot = materializeCatalogPackageRoot
|
|
247
267
|
} = {}) {
|
|
248
268
|
const packageRoot = String(packageEntry?.rootDir || "").trim();
|
|
@@ -267,7 +287,8 @@ async function resolvePackageTemplateRoot({
|
|
|
267
287
|
|
|
268
288
|
const materializedCatalogPackageRoot = await materializeCatalogRoot({
|
|
269
289
|
packageEntry,
|
|
270
|
-
appRoot
|
|
290
|
+
appRoot,
|
|
291
|
+
reportTemplateFetchStatus
|
|
271
292
|
});
|
|
272
293
|
if (materializedCatalogPackageRoot) {
|
|
273
294
|
return materializedCatalogPackageRoot;
|
|
@@ -38,7 +38,8 @@ async function runPackageAddCommand(ctx = {}, { positional, options, cwd, io })
|
|
|
38
38
|
adoptAppLocalPackageDependencies,
|
|
39
39
|
writeJsonFile,
|
|
40
40
|
runNpmInstall,
|
|
41
|
-
renderResolvedSummary
|
|
41
|
+
renderResolvedSummary,
|
|
42
|
+
createCatalogFetchStatusReporter = () => () => {}
|
|
42
43
|
} = ctx;
|
|
43
44
|
|
|
44
45
|
const invocationMode = options?.commandMode === "generate" ? "generate" : "add";
|
|
@@ -242,6 +243,9 @@ async function runPackageAddCommand(ctx = {}, { positional, options, cwd, io })
|
|
|
242
243
|
|
|
243
244
|
const packagesToInstall = [];
|
|
244
245
|
const resolvedOptionsByPackage = {};
|
|
246
|
+
const reportTemplateFetchStatus = createCatalogFetchStatusReporter(io, {
|
|
247
|
+
enabled: options.json !== true
|
|
248
|
+
});
|
|
245
249
|
const forceReapplyTarget = options?.forceReapplyTarget === true;
|
|
246
250
|
const hasInlineOptions = Object.keys(ensureObject(options.inlineOptions)).length > 0;
|
|
247
251
|
for (const packageId of resolvedPackageIds) {
|
|
@@ -293,7 +297,8 @@ async function runPackageAddCommand(ctx = {}, { positional, options, cwd, io })
|
|
|
293
297
|
appPackageJson: packageJson,
|
|
294
298
|
lock,
|
|
295
299
|
packageRegistry: combinedPackageRegistry,
|
|
296
|
-
touchedFiles
|
|
300
|
+
touchedFiles,
|
|
301
|
+
reportTemplateFetchStatus
|
|
297
302
|
});
|
|
298
303
|
installedPackageRecords.push(managedRecord);
|
|
299
304
|
}
|
|
@@ -230,7 +230,8 @@ async function runPackageGenerateCommand(
|
|
|
230
230
|
hasGeneratorSubcommandDefinition,
|
|
231
231
|
readdir,
|
|
232
232
|
validateInlineOptionValuesForPackage,
|
|
233
|
-
runGeneratorSubcommand
|
|
233
|
+
runGeneratorSubcommand,
|
|
234
|
+
createCatalogFetchStatusReporter = () => () => {}
|
|
234
235
|
} = ctx;
|
|
235
236
|
|
|
236
237
|
const firstToken = String(positional[0] || "").trim();
|
|
@@ -244,6 +245,9 @@ async function runPackageGenerateCommand(
|
|
|
244
245
|
const targetId = firstToken === "package" ? secondToken : firstToken;
|
|
245
246
|
const subcommandName = firstToken === "package" ? thirdToken : secondToken;
|
|
246
247
|
const subcommandArgs = firstToken === "package" ? positional.slice(3) : positional.slice(2);
|
|
248
|
+
const reportTemplateFetchStatus = createCatalogFetchStatusReporter(io, {
|
|
249
|
+
enabled: options.json !== true
|
|
250
|
+
});
|
|
247
251
|
|
|
248
252
|
async function resolveGeneratorPackageEntry(packageIdInput = "") {
|
|
249
253
|
const appRoot = await resolveAppRootFromCwd(cwd);
|
|
@@ -425,7 +429,8 @@ async function runPackageGenerateCommand(
|
|
|
425
429
|
|
|
426
430
|
const templateRoot = await resolvePackageTemplateRoot({
|
|
427
431
|
packageEntry,
|
|
428
|
-
appRoot
|
|
432
|
+
appRoot,
|
|
433
|
+
reportTemplateFetchStatus
|
|
429
434
|
});
|
|
430
435
|
const executablePackageEntry =
|
|
431
436
|
templateRoot === packageEntry.rootDir
|
|
@@ -39,6 +39,44 @@ function createCommandHandlerShared(ctx = {}) {
|
|
|
39
39
|
return lines.join("\n");
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
function createCatalogFetchStatusReporter(io = {}, { enabled = true } = {}) {
|
|
43
|
+
if (enabled !== true) {
|
|
44
|
+
return () => {};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const stdout = io?.stdout;
|
|
48
|
+
if (!stdout || typeof stdout.write !== "function") {
|
|
49
|
+
return () => {};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const activeFetchLabels = new Set();
|
|
53
|
+
return ({ packageEntry, state } = {}) => {
|
|
54
|
+
const packageId = String(packageEntry?.packageId || "").trim();
|
|
55
|
+
const version = String(packageEntry?.version || "").trim();
|
|
56
|
+
const packageLabel = version ? `${packageId}@${version}` : packageId;
|
|
57
|
+
if (!packageLabel) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (state === "start") {
|
|
62
|
+
if (activeFetchLabels.has(packageLabel)) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
activeFetchLabels.add(packageLabel);
|
|
66
|
+
stdout.write(`Fetching ${packageLabel}...\n`);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (state === "complete") {
|
|
71
|
+
if (!activeFetchLabels.has(packageLabel)) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
activeFetchLabels.delete(packageLabel);
|
|
75
|
+
stdout.write(`Fetching ${packageLabel}... done!\n`);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
42
80
|
async function runNpmInstall(appRoot, stderr) {
|
|
43
81
|
await new Promise((resolve, reject) => {
|
|
44
82
|
const child = spawn("npm", ["install"], {
|
|
@@ -298,6 +336,7 @@ function createCommandHandlerShared(ctx = {}) {
|
|
|
298
336
|
|
|
299
337
|
return {
|
|
300
338
|
renderResolvedSummary,
|
|
339
|
+
createCatalogFetchStatusReporter,
|
|
301
340
|
runNpmInstall,
|
|
302
341
|
getInstalledDependents,
|
|
303
342
|
resolvePackageKind,
|
|
@@ -1,50 +1,569 @@
|
|
|
1
|
-
const
|
|
2
|
-
"
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"position",
|
|
13
|
-
"update",
|
|
14
|
-
"remove",
|
|
15
|
-
"doctor",
|
|
16
|
-
"lint-descriptors"
|
|
17
|
-
]);
|
|
18
|
-
|
|
19
|
-
const KNOWN_COMMANDS = new Set(KNOWN_COMMAND_IDS);
|
|
20
|
-
|
|
21
|
-
const COMMAND_ALIASES = Object.freeze({
|
|
22
|
-
view: "show",
|
|
23
|
-
ls: "list",
|
|
24
|
-
gen: "generate",
|
|
25
|
-
lp: "list-placements",
|
|
26
|
-
lpct: "list-link-items",
|
|
27
|
-
"list-placement-component-tokens": "list-link-items"
|
|
1
|
+
const OPTION_FLAG_LABELS = Object.freeze({
|
|
2
|
+
dryRun: "--dry-run",
|
|
3
|
+
runNpmInstall: "--run-npm-install",
|
|
4
|
+
full: "--full",
|
|
5
|
+
expanded: "--expanded",
|
|
6
|
+
details: "--details",
|
|
7
|
+
debugExports: "--debug-exports",
|
|
8
|
+
checkDiLabels: "--check-di-labels",
|
|
9
|
+
verbose: "--verbose",
|
|
10
|
+
json: "--json",
|
|
11
|
+
all: "--all"
|
|
28
12
|
});
|
|
29
13
|
|
|
14
|
+
const PARSED_BOOLEAN_OPTION_KEYS = Object.freeze(Object.keys(OPTION_FLAG_LABELS));
|
|
15
|
+
|
|
16
|
+
function isHelpToken(value = "") {
|
|
17
|
+
return String(value || "").trim().toLowerCase() === "help";
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function canDelegateAddInlineOptions(positional = []) {
|
|
21
|
+
const [first, second, third] = Array.isArray(positional) ? positional : [];
|
|
22
|
+
const targetType = String(first || "").trim();
|
|
23
|
+
const targetId = String(second || "").trim();
|
|
24
|
+
if (!targetType || !targetId || isHelpToken(targetId) || isHelpToken(third)) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
return targetType === "package" || targetType === "bundle";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function canDelegateGenerateInlineOptions(positional = []) {
|
|
31
|
+
const normalizedPositionals = Array.isArray(positional) ? positional : [];
|
|
32
|
+
const first = String(normalizedPositionals[0] || "").trim();
|
|
33
|
+
const second = String(normalizedPositionals[1] || "").trim();
|
|
34
|
+
const last = String(normalizedPositionals[normalizedPositionals.length - 1] || "").trim();
|
|
35
|
+
if (!first || !second || isHelpToken(first) || isHelpToken(second) || isHelpToken(last)) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function canDelegateMigrationsInlineOptions(positional = []) {
|
|
42
|
+
const [first, second] = Array.isArray(positional) ? positional : [];
|
|
43
|
+
return String(first || "").trim().toLowerCase() === "package" && Boolean(String(second || "").trim());
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function canDelegatePackageTargetInlineOptions(positional = [], expectedTargetType = "") {
|
|
47
|
+
const [first, second] = Array.isArray(positional) ? positional : [];
|
|
48
|
+
const targetType = String(first || "").trim();
|
|
49
|
+
const targetId = String(second || "").trim();
|
|
50
|
+
if (!targetType || !targetId || isHelpToken(targetId)) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
return targetType === String(expectedTargetType || "").trim();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const COMMAND_DESCRIPTORS = Object.freeze({
|
|
57
|
+
help: Object.freeze({
|
|
58
|
+
command: "help",
|
|
59
|
+
aliases: Object.freeze([]),
|
|
60
|
+
showInOverview: false,
|
|
61
|
+
summary: "Show command-specific usage.",
|
|
62
|
+
minimalUse: "jskit help [command]",
|
|
63
|
+
parameters: Object.freeze([
|
|
64
|
+
Object.freeze({
|
|
65
|
+
name: "[command]",
|
|
66
|
+
description: "Optional command name to inspect."
|
|
67
|
+
})
|
|
68
|
+
]),
|
|
69
|
+
defaults: Object.freeze([
|
|
70
|
+
"Without a command, help prints the top-level overview.",
|
|
71
|
+
"Use jskit help <command> for command-specific usage."
|
|
72
|
+
]),
|
|
73
|
+
fullUse: "jskit help [command]",
|
|
74
|
+
showHelpOnBareInvocation: false,
|
|
75
|
+
handlerName: "",
|
|
76
|
+
allowedFlagKeys: Object.freeze([]),
|
|
77
|
+
inlineOptionMode: "none",
|
|
78
|
+
allowedValueOptionNames: Object.freeze([])
|
|
79
|
+
}),
|
|
80
|
+
create: Object.freeze({
|
|
81
|
+
command: "create",
|
|
82
|
+
aliases: Object.freeze([]),
|
|
83
|
+
showInOverview: true,
|
|
84
|
+
summary: "Scaffold an app-local runtime package.",
|
|
85
|
+
minimalUse: "jskit create package <name>",
|
|
86
|
+
parameters: Object.freeze([
|
|
87
|
+
Object.freeze({
|
|
88
|
+
name: "<name>",
|
|
89
|
+
description: "Local package slug used to scaffold packages/<name>."
|
|
90
|
+
})
|
|
91
|
+
]),
|
|
92
|
+
defaults: Object.freeze([
|
|
93
|
+
"No npm install runs unless --run-npm-install is passed.",
|
|
94
|
+
"If --scope is omitted, scope is inferred from app name.",
|
|
95
|
+
"If --package-id is omitted, it is derived from scope + name."
|
|
96
|
+
]),
|
|
97
|
+
fullUse:
|
|
98
|
+
"jskit create package <name> [--scope <scope>] [--package-id <id>] [--description <text>] [--dry-run] [--run-npm-install] [--json]",
|
|
99
|
+
showHelpOnBareInvocation: true,
|
|
100
|
+
handlerName: "commandCreate",
|
|
101
|
+
allowedFlagKeys: Object.freeze(["dryRun", "runNpmInstall", "json"]),
|
|
102
|
+
inlineOptionMode: "enumerated",
|
|
103
|
+
allowedValueOptionNames: Object.freeze(["scope", "package-id", "description"])
|
|
104
|
+
}),
|
|
105
|
+
add: Object.freeze({
|
|
106
|
+
command: "add",
|
|
107
|
+
aliases: Object.freeze([]),
|
|
108
|
+
showInOverview: true,
|
|
109
|
+
summary: "Install a runtime bundle or package into the current app.",
|
|
110
|
+
minimalUse: "jskit add package <packageId>",
|
|
111
|
+
parameters: Object.freeze([
|
|
112
|
+
Object.freeze({
|
|
113
|
+
name: "package | bundle",
|
|
114
|
+
description: "Target type. Use package for one runtime package, bundle for a bundle id."
|
|
115
|
+
}),
|
|
116
|
+
Object.freeze({
|
|
117
|
+
name: "<packageId|bundleId>",
|
|
118
|
+
description: "Catalog id or installed node_modules package id."
|
|
119
|
+
})
|
|
120
|
+
]),
|
|
121
|
+
defaults: Object.freeze([
|
|
122
|
+
"No npm install runs unless --run-npm-install is passed.",
|
|
123
|
+
"Short ids resolve to @jskit-ai/<id> when available.",
|
|
124
|
+
"Running without args lists bundles and runtime packages.",
|
|
125
|
+
"Existing matching version is skipped unless options force reapply."
|
|
126
|
+
]),
|
|
127
|
+
fullUse:
|
|
128
|
+
"jskit add <package|bundle> <id> [--<option> <value>...] [--dry-run] [--run-npm-install] [--json] [--verbose]",
|
|
129
|
+
showHelpOnBareInvocation: false,
|
|
130
|
+
handlerName: "commandAdd",
|
|
131
|
+
allowedFlagKeys: Object.freeze(["dryRun", "runNpmInstall", "json", "verbose"]),
|
|
132
|
+
inlineOptionMode: "delegate",
|
|
133
|
+
allowedValueOptionNames: Object.freeze([]),
|
|
134
|
+
canDelegateInlineOptions: canDelegateAddInlineOptions
|
|
135
|
+
}),
|
|
136
|
+
generate: Object.freeze({
|
|
137
|
+
command: "generate",
|
|
138
|
+
aliases: Object.freeze(["gen"]),
|
|
139
|
+
showInOverview: true,
|
|
140
|
+
summary: "Run a generator package (or generator subcommand).",
|
|
141
|
+
minimalUse: "jskit generate <generatorId>",
|
|
142
|
+
parameters: Object.freeze([
|
|
143
|
+
Object.freeze({
|
|
144
|
+
name: "<generatorId>",
|
|
145
|
+
description: "Generator package id (for example: crud-ui-generator)."
|
|
146
|
+
}),
|
|
147
|
+
Object.freeze({
|
|
148
|
+
name: "[subcommand]",
|
|
149
|
+
description: "Optional generator subcommand (for example: scaffold or scaffold-field)."
|
|
150
|
+
}),
|
|
151
|
+
Object.freeze({
|
|
152
|
+
name: "[subcommand args...]",
|
|
153
|
+
description: "Optional positional args consumed by the chosen subcommand."
|
|
154
|
+
})
|
|
155
|
+
]),
|
|
156
|
+
defaults: Object.freeze([
|
|
157
|
+
"No npm install runs unless --run-npm-install is passed.",
|
|
158
|
+
"Short ids resolve to @jskit-ai/<id> when available.",
|
|
159
|
+
"Running without args lists available generators.",
|
|
160
|
+
"Running with only <generatorId> shows generator help.",
|
|
161
|
+
"Use jskit generate <generatorId> <subcommand> help for subcommand-specific usage."
|
|
162
|
+
]),
|
|
163
|
+
examples: Object.freeze([
|
|
164
|
+
Object.freeze({
|
|
165
|
+
label: "Common usage",
|
|
166
|
+
lines: Object.freeze([
|
|
167
|
+
"npx jskit generate ui-generator page \\",
|
|
168
|
+
" admin/reports/index.vue"
|
|
169
|
+
])
|
|
170
|
+
}),
|
|
171
|
+
Object.freeze({
|
|
172
|
+
label: "More advanced usage",
|
|
173
|
+
lines: Object.freeze([
|
|
174
|
+
"npx jskit generate crud-ui-generator crud \\",
|
|
175
|
+
" admin/catalog/index/products \\",
|
|
176
|
+
" --resource-file packages/products/src/shared/productResource.js"
|
|
177
|
+
])
|
|
178
|
+
})
|
|
179
|
+
]),
|
|
180
|
+
fullUse:
|
|
181
|
+
"jskit generate <generatorId> [subcommand] [subcommand args...] [--<option> <value>...] [--dry-run] [--run-npm-install] [--json] [--verbose]",
|
|
182
|
+
showHelpOnBareInvocation: false,
|
|
183
|
+
handlerName: "commandGenerate",
|
|
184
|
+
allowedFlagKeys: Object.freeze(["dryRun", "runNpmInstall", "json", "verbose"]),
|
|
185
|
+
inlineOptionMode: "delegate",
|
|
186
|
+
allowedValueOptionNames: Object.freeze([]),
|
|
187
|
+
canDelegateInlineOptions: canDelegateGenerateInlineOptions
|
|
188
|
+
}),
|
|
189
|
+
list: Object.freeze({
|
|
190
|
+
command: "list",
|
|
191
|
+
aliases: Object.freeze(["ls"]),
|
|
192
|
+
showInOverview: true,
|
|
193
|
+
summary: "List bundles, runtime packages, or generator packages.",
|
|
194
|
+
minimalUse: "jskit list",
|
|
195
|
+
parameters: Object.freeze([
|
|
196
|
+
Object.freeze({
|
|
197
|
+
name: "[mode]",
|
|
198
|
+
description: "Optional mode: bundles, packages, or generators."
|
|
199
|
+
})
|
|
200
|
+
]),
|
|
201
|
+
defaults: Object.freeze([
|
|
202
|
+
"Without mode, list prints bundles + runtime packages + generators.",
|
|
203
|
+
"placements are listed by the dedicated list-placements command.",
|
|
204
|
+
"--full and --expanded only affect bundle/package listing views."
|
|
205
|
+
]),
|
|
206
|
+
fullUse: "jskit list [bundles|packages|generators] [--full] [--expanded] [--json]",
|
|
207
|
+
showHelpOnBareInvocation: false,
|
|
208
|
+
handlerName: "commandList",
|
|
209
|
+
allowedFlagKeys: Object.freeze(["full", "expanded", "json"]),
|
|
210
|
+
inlineOptionMode: "none",
|
|
211
|
+
allowedValueOptionNames: Object.freeze([])
|
|
212
|
+
}),
|
|
213
|
+
"list-placements": Object.freeze({
|
|
214
|
+
command: "list-placements",
|
|
215
|
+
aliases: Object.freeze(["lp"]),
|
|
216
|
+
showInOverview: true,
|
|
217
|
+
summary: "List discovered UI placement targets.",
|
|
218
|
+
minimalUse: "jskit list-placements",
|
|
219
|
+
parameters: Object.freeze([]),
|
|
220
|
+
defaults: Object.freeze([
|
|
221
|
+
"Discovers placement outlets from app Vue ShellOutlet tags and route meta.",
|
|
222
|
+
"Includes placement outlets contributed by installed package metadata.",
|
|
223
|
+
"Shows plain text by default; use --json for structured output."
|
|
224
|
+
]),
|
|
225
|
+
fullUse: "jskit list-placements [--json]",
|
|
226
|
+
showHelpOnBareInvocation: false,
|
|
227
|
+
handlerName: "commandListPlacements",
|
|
228
|
+
allowedFlagKeys: Object.freeze(["json"]),
|
|
229
|
+
inlineOptionMode: "none",
|
|
230
|
+
allowedValueOptionNames: Object.freeze([])
|
|
231
|
+
}),
|
|
232
|
+
"list-link-items": Object.freeze({
|
|
233
|
+
command: "list-link-items",
|
|
234
|
+
aliases: Object.freeze(["lpct", "list-placement-component-tokens"]),
|
|
235
|
+
showInOverview: true,
|
|
236
|
+
summary: "List available placement link-item component tokens.",
|
|
237
|
+
minimalUse: "jskit list-link-items",
|
|
238
|
+
parameters: Object.freeze([
|
|
239
|
+
Object.freeze({
|
|
240
|
+
name: "[--prefix <value>]",
|
|
241
|
+
description: "Optional token prefix filter (example: local.main. or users.web.shell.)."
|
|
242
|
+
}),
|
|
243
|
+
Object.freeze({
|
|
244
|
+
name: "[--all]",
|
|
245
|
+
description: "Include all discovered tokens (including non-link-item and client container/runtime tokens)."
|
|
246
|
+
})
|
|
247
|
+
]),
|
|
248
|
+
defaults: Object.freeze([
|
|
249
|
+
"Default output shows link-item tokens only (token names ending with link-item).",
|
|
250
|
+
"Default includes app and installed-package placement-linked token sources.",
|
|
251
|
+
"Use --prefix to narrow quickly (recommended: --prefix local.main.).",
|
|
252
|
+
"Use --all when you want the full discovered token set.",
|
|
253
|
+
"Shows plain text by default; use --json for structured output."
|
|
254
|
+
]),
|
|
255
|
+
fullUse: "jskit list-link-items [--prefix <value>] [--all] [--json]",
|
|
256
|
+
showHelpOnBareInvocation: false,
|
|
257
|
+
handlerName: "commandListLinkItems",
|
|
258
|
+
allowedFlagKeys: Object.freeze(["json", "all"]),
|
|
259
|
+
inlineOptionMode: "enumerated",
|
|
260
|
+
allowedValueOptionNames: Object.freeze(["prefix"])
|
|
261
|
+
}),
|
|
262
|
+
show: Object.freeze({
|
|
263
|
+
command: "show",
|
|
264
|
+
aliases: Object.freeze(["view"]),
|
|
265
|
+
showInOverview: true,
|
|
266
|
+
summary: "Show detailed metadata for a bundle or package.",
|
|
267
|
+
minimalUse: "jskit show <id>",
|
|
268
|
+
parameters: Object.freeze([
|
|
269
|
+
Object.freeze({
|
|
270
|
+
name: "<id>",
|
|
271
|
+
description: "Bundle id or package id to inspect."
|
|
272
|
+
})
|
|
273
|
+
]),
|
|
274
|
+
defaults: Object.freeze([
|
|
275
|
+
"view is an alias of show.",
|
|
276
|
+
"Basic output is compact; --details expands capability and runtime sections.",
|
|
277
|
+
"--debug-exports implies --details."
|
|
278
|
+
]),
|
|
279
|
+
fullUse: "jskit show <id> [--details] [--debug-exports] [--json]",
|
|
280
|
+
showHelpOnBareInvocation: true,
|
|
281
|
+
handlerName: "commandShow",
|
|
282
|
+
allowedFlagKeys: Object.freeze(["details", "debugExports", "json"]),
|
|
283
|
+
inlineOptionMode: "none",
|
|
284
|
+
allowedValueOptionNames: Object.freeze([])
|
|
285
|
+
}),
|
|
286
|
+
migrations: Object.freeze({
|
|
287
|
+
command: "migrations",
|
|
288
|
+
aliases: Object.freeze([]),
|
|
289
|
+
showInOverview: true,
|
|
290
|
+
summary: "Generate managed migration files only.",
|
|
291
|
+
minimalUse: "jskit migrations changed",
|
|
292
|
+
parameters: Object.freeze([
|
|
293
|
+
Object.freeze({
|
|
294
|
+
name: "<scope>",
|
|
295
|
+
description: "all | changed | package."
|
|
296
|
+
}),
|
|
297
|
+
Object.freeze({
|
|
298
|
+
name: "[packageId]",
|
|
299
|
+
description: "Required only when scope is package."
|
|
300
|
+
})
|
|
301
|
+
]),
|
|
302
|
+
defaults: Object.freeze([
|
|
303
|
+
"Inline options are accepted only for 'migrations package <packageId>'.",
|
|
304
|
+
"This command only materializes managed migration files; it does not run npm install.",
|
|
305
|
+
"Without --json, output lists touched migration files."
|
|
306
|
+
]),
|
|
307
|
+
fullUse: "jskit migrations <all|changed|package> [packageId] [--<option> <value>...] [--dry-run] [--json] [--verbose]",
|
|
308
|
+
showHelpOnBareInvocation: true,
|
|
309
|
+
handlerName: "commandMigrations",
|
|
310
|
+
allowedFlagKeys: Object.freeze(["dryRun", "json", "verbose"]),
|
|
311
|
+
inlineOptionMode: "delegate",
|
|
312
|
+
allowedValueOptionNames: Object.freeze([]),
|
|
313
|
+
canDelegateInlineOptions: canDelegateMigrationsInlineOptions
|
|
314
|
+
}),
|
|
315
|
+
position: Object.freeze({
|
|
316
|
+
command: "position",
|
|
317
|
+
aliases: Object.freeze([]),
|
|
318
|
+
showInOverview: true,
|
|
319
|
+
summary: "Re-apply positioning-only mutations for an installed package.",
|
|
320
|
+
minimalUse: "jskit position element <packageId>",
|
|
321
|
+
parameters: Object.freeze([
|
|
322
|
+
Object.freeze({
|
|
323
|
+
name: "element",
|
|
324
|
+
description: "Target type for positioning command."
|
|
325
|
+
}),
|
|
326
|
+
Object.freeze({
|
|
327
|
+
name: "<packageId>",
|
|
328
|
+
description: "Installed package id to re-position."
|
|
329
|
+
})
|
|
330
|
+
]),
|
|
331
|
+
defaults: Object.freeze([
|
|
332
|
+
"Only positioning mutations are applied.",
|
|
333
|
+
"This command does not run npm install.",
|
|
334
|
+
"Reads current options from lock unless overridden inline."
|
|
335
|
+
]),
|
|
336
|
+
fullUse: "jskit position element <packageId> [--<option> <value>...] [--dry-run] [--json]",
|
|
337
|
+
showHelpOnBareInvocation: true,
|
|
338
|
+
handlerName: "commandPosition",
|
|
339
|
+
allowedFlagKeys: Object.freeze(["dryRun", "json"]),
|
|
340
|
+
inlineOptionMode: "delegate",
|
|
341
|
+
allowedValueOptionNames: Object.freeze([]),
|
|
342
|
+
canDelegateInlineOptions: (positional = []) => canDelegatePackageTargetInlineOptions(positional, "element")
|
|
343
|
+
}),
|
|
344
|
+
update: Object.freeze({
|
|
345
|
+
command: "update",
|
|
346
|
+
aliases: Object.freeze([]),
|
|
347
|
+
showInOverview: true,
|
|
348
|
+
summary: "Re-apply one installed package.",
|
|
349
|
+
minimalUse: "jskit update package <packageId>",
|
|
350
|
+
parameters: Object.freeze([
|
|
351
|
+
Object.freeze({
|
|
352
|
+
name: "package",
|
|
353
|
+
description: "Target type for update command."
|
|
354
|
+
}),
|
|
355
|
+
Object.freeze({
|
|
356
|
+
name: "<packageId>",
|
|
357
|
+
description: "Installed package id to re-apply."
|
|
358
|
+
})
|
|
359
|
+
]),
|
|
360
|
+
defaults: Object.freeze([
|
|
361
|
+
"No npm install runs unless --run-npm-install is passed.",
|
|
362
|
+
"Existing lock options are reused unless overridden inline.",
|
|
363
|
+
"update reuses add package flow with forced reapply."
|
|
364
|
+
]),
|
|
365
|
+
fullUse: "jskit update package <packageId> [--<option> <value>...] [--dry-run] [--run-npm-install] [--json]",
|
|
366
|
+
showHelpOnBareInvocation: true,
|
|
367
|
+
handlerName: "commandUpdate",
|
|
368
|
+
allowedFlagKeys: Object.freeze(["dryRun", "runNpmInstall", "json"]),
|
|
369
|
+
inlineOptionMode: "delegate",
|
|
370
|
+
allowedValueOptionNames: Object.freeze([]),
|
|
371
|
+
canDelegateInlineOptions: (positional = []) => canDelegatePackageTargetInlineOptions(positional, "package")
|
|
372
|
+
}),
|
|
373
|
+
remove: Object.freeze({
|
|
374
|
+
command: "remove",
|
|
375
|
+
aliases: Object.freeze([]),
|
|
376
|
+
showInOverview: true,
|
|
377
|
+
summary: "Remove one installed package.",
|
|
378
|
+
minimalUse: "jskit remove package <packageId>",
|
|
379
|
+
parameters: Object.freeze([
|
|
380
|
+
Object.freeze({
|
|
381
|
+
name: "package",
|
|
382
|
+
description: "Target type for remove command."
|
|
383
|
+
}),
|
|
384
|
+
Object.freeze({
|
|
385
|
+
name: "<packageId>",
|
|
386
|
+
description: "Installed package id to remove."
|
|
387
|
+
})
|
|
388
|
+
]),
|
|
389
|
+
defaults: Object.freeze([
|
|
390
|
+
"No npm install runs unless --run-npm-install is passed.",
|
|
391
|
+
"Managed files and lock entries are removed for the package.",
|
|
392
|
+
"Local package source directories are not deleted."
|
|
393
|
+
]),
|
|
394
|
+
fullUse: "jskit remove package <packageId> [--dry-run] [--run-npm-install] [--json]",
|
|
395
|
+
showHelpOnBareInvocation: true,
|
|
396
|
+
handlerName: "commandRemove",
|
|
397
|
+
allowedFlagKeys: Object.freeze(["dryRun", "runNpmInstall", "json"]),
|
|
398
|
+
inlineOptionMode: "none",
|
|
399
|
+
allowedValueOptionNames: Object.freeze([])
|
|
400
|
+
}),
|
|
401
|
+
doctor: Object.freeze({
|
|
402
|
+
command: "doctor",
|
|
403
|
+
aliases: Object.freeze([]),
|
|
404
|
+
showInOverview: true,
|
|
405
|
+
summary: "Validate lockfile and managed-file integrity.",
|
|
406
|
+
minimalUse: "jskit doctor",
|
|
407
|
+
parameters: Object.freeze([]),
|
|
408
|
+
defaults: Object.freeze([
|
|
409
|
+
"Validates lock entries, managed files, and registry visibility.",
|
|
410
|
+
"Reports issues as plain text by default.",
|
|
411
|
+
"Use --json for machine-readable diagnostics."
|
|
412
|
+
]),
|
|
413
|
+
fullUse: "jskit doctor [--json]",
|
|
414
|
+
showHelpOnBareInvocation: false,
|
|
415
|
+
handlerName: "commandDoctor",
|
|
416
|
+
allowedFlagKeys: Object.freeze(["json"]),
|
|
417
|
+
inlineOptionMode: "none",
|
|
418
|
+
allowedValueOptionNames: Object.freeze([])
|
|
419
|
+
}),
|
|
420
|
+
"lint-descriptors": Object.freeze({
|
|
421
|
+
command: "lint-descriptors",
|
|
422
|
+
aliases: Object.freeze([]),
|
|
423
|
+
showInOverview: true,
|
|
424
|
+
summary: "Validate bundle and package descriptor contracts.",
|
|
425
|
+
minimalUse: "jskit lint-descriptors",
|
|
426
|
+
parameters: Object.freeze([]),
|
|
427
|
+
defaults: Object.freeze([
|
|
428
|
+
"Runs descriptor consistency checks.",
|
|
429
|
+
"check-di-labels is optional and adds stricter DI token label checks.",
|
|
430
|
+
"Outputs plain text by default and supports --json."
|
|
431
|
+
]),
|
|
432
|
+
fullUse: "jskit lint-descriptors [--check-di-labels] [--json]",
|
|
433
|
+
showHelpOnBareInvocation: false,
|
|
434
|
+
handlerName: "commandLintDescriptors",
|
|
435
|
+
allowedFlagKeys: Object.freeze(["checkDiLabels", "json"]),
|
|
436
|
+
inlineOptionMode: "none",
|
|
437
|
+
allowedValueOptionNames: Object.freeze([])
|
|
438
|
+
})
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
const COMMAND_ALIAS_TO_ID = Object.freeze(
|
|
442
|
+
Object.fromEntries(
|
|
443
|
+
Object.values(COMMAND_DESCRIPTORS)
|
|
444
|
+
.flatMap((descriptor) =>
|
|
445
|
+
Array.isArray(descriptor.aliases)
|
|
446
|
+
? descriptor.aliases.map((alias) => [alias, descriptor.command])
|
|
447
|
+
: [])
|
|
448
|
+
.sort((left, right) => String(left[0] || "").localeCompare(String(right[0] || "")))
|
|
449
|
+
)
|
|
450
|
+
);
|
|
451
|
+
|
|
452
|
+
const COMMAND_IDS = Object.freeze(Object.keys(COMMAND_DESCRIPTORS));
|
|
453
|
+
const KNOWN_COMMANDS = new Set(COMMAND_IDS);
|
|
454
|
+
|
|
30
455
|
function resolveCommandAlias(rawCommand) {
|
|
31
456
|
const command = String(rawCommand || "").trim();
|
|
32
457
|
if (!command) {
|
|
33
458
|
return "";
|
|
34
459
|
}
|
|
35
|
-
return
|
|
460
|
+
return COMMAND_ALIAS_TO_ID[command] || command;
|
|
36
461
|
}
|
|
37
462
|
|
|
38
|
-
function
|
|
463
|
+
function resolveCommandDescriptor(rawCommand) {
|
|
39
464
|
const command = resolveCommandAlias(rawCommand);
|
|
40
465
|
if (!command) {
|
|
466
|
+
return null;
|
|
467
|
+
}
|
|
468
|
+
return COMMAND_DESCRIPTORS[command] || null;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function isKnownCommandName(rawCommand) {
|
|
472
|
+
const descriptor = resolveCommandDescriptor(rawCommand);
|
|
473
|
+
return Boolean(descriptor && KNOWN_COMMANDS.has(descriptor.command));
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
function listOverviewCommandDescriptors() {
|
|
477
|
+
return Object.values(COMMAND_DESCRIPTORS)
|
|
478
|
+
.filter((descriptor) => descriptor.showInOverview !== false)
|
|
479
|
+
.sort((left, right) => left.command.localeCompare(right.command));
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
function shouldShowCommandHelpOnBareInvocation(command = "", positional = []) {
|
|
483
|
+
const descriptor = resolveCommandDescriptor(command);
|
|
484
|
+
if (!descriptor || descriptor.showHelpOnBareInvocation !== true) {
|
|
41
485
|
return false;
|
|
42
486
|
}
|
|
43
|
-
|
|
487
|
+
const argumentList = Array.isArray(positional) ? positional : [];
|
|
488
|
+
return argumentList.length < 1;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function sortOptionLabels(labels = []) {
|
|
492
|
+
return [...new Set((Array.isArray(labels) ? labels : []).filter(Boolean))]
|
|
493
|
+
.sort((left, right) => left.localeCompare(right));
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
function validateCommandOptions(
|
|
497
|
+
{ command = "", positional = [], options = {} } = {},
|
|
498
|
+
{ createCliError, renderUsage = null } = {}
|
|
499
|
+
) {
|
|
500
|
+
if (typeof createCliError !== "function") {
|
|
501
|
+
throw new TypeError("validateCommandOptions requires createCliError.");
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
const descriptor = resolveCommandDescriptor(command);
|
|
505
|
+
if (!descriptor) {
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
const allowedFlagKeys = new Set(Array.isArray(descriptor.allowedFlagKeys) ? descriptor.allowedFlagKeys : []);
|
|
510
|
+
const unsupportedOptionLabels = [];
|
|
511
|
+
for (const flagKey of PARSED_BOOLEAN_OPTION_KEYS) {
|
|
512
|
+
if (options?.[flagKey] !== true) {
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
if (!allowedFlagKeys.has(flagKey)) {
|
|
516
|
+
unsupportedOptionLabels.push(OPTION_FLAG_LABELS[flagKey]);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
const inlineOptions = options && typeof options === "object" ? options.inlineOptions : null;
|
|
521
|
+
const inlineOptionNames = Object.keys(inlineOptions && typeof inlineOptions === "object" ? inlineOptions : {});
|
|
522
|
+
const inlineOptionMode = String(descriptor.inlineOptionMode || "none").trim().toLowerCase() || "none";
|
|
523
|
+
if (inlineOptionMode === "none") {
|
|
524
|
+
for (const optionName of inlineOptionNames) {
|
|
525
|
+
unsupportedOptionLabels.push(`--${optionName}`);
|
|
526
|
+
}
|
|
527
|
+
} else if (inlineOptionMode === "enumerated") {
|
|
528
|
+
const allowedValueOptionNames = new Set(
|
|
529
|
+
Array.isArray(descriptor.allowedValueOptionNames) ? descriptor.allowedValueOptionNames : []
|
|
530
|
+
);
|
|
531
|
+
for (const optionName of inlineOptionNames) {
|
|
532
|
+
if (!allowedValueOptionNames.has(optionName)) {
|
|
533
|
+
unsupportedOptionLabels.push(`--${optionName}`);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
} else if (
|
|
537
|
+
inlineOptionMode === "delegate" &&
|
|
538
|
+
inlineOptionNames.length > 0 &&
|
|
539
|
+
typeof descriptor.canDelegateInlineOptions === "function" &&
|
|
540
|
+
descriptor.canDelegateInlineOptions(positional) !== true
|
|
541
|
+
) {
|
|
542
|
+
for (const optionName of inlineOptionNames) {
|
|
543
|
+
unsupportedOptionLabels.push(`--${optionName}`);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
const normalizedUnsupportedLabels = sortOptionLabels(unsupportedOptionLabels);
|
|
548
|
+
if (normalizedUnsupportedLabels.length < 1) {
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
throw createCliError(
|
|
553
|
+
`Unknown option${normalizedUnsupportedLabels.length === 1 ? "" : "s"} for command ${descriptor.command}: ${normalizedUnsupportedLabels.join(", ")}.`,
|
|
554
|
+
{
|
|
555
|
+
renderUsage: typeof renderUsage === "function" ? renderUsage : null
|
|
556
|
+
}
|
|
557
|
+
);
|
|
44
558
|
}
|
|
45
559
|
|
|
46
560
|
export {
|
|
47
|
-
|
|
561
|
+
COMMAND_IDS,
|
|
562
|
+
OPTION_FLAG_LABELS,
|
|
48
563
|
resolveCommandAlias,
|
|
49
|
-
|
|
564
|
+
resolveCommandDescriptor,
|
|
565
|
+
isKnownCommandName,
|
|
566
|
+
listOverviewCommandDescriptors,
|
|
567
|
+
shouldShowCommandHelpOnBareInvocation,
|
|
568
|
+
validateCommandOptions
|
|
50
569
|
};
|
|
@@ -15,6 +15,10 @@ import {
|
|
|
15
15
|
import { createCommandHandlers } from "./createCommandHandlers.js";
|
|
16
16
|
import { parseArgs } from "./argParser.js";
|
|
17
17
|
import { printUsage, shouldShowCommandHelpOnBareInvocation } from "./usageHelp.js";
|
|
18
|
+
import {
|
|
19
|
+
resolveCommandDescriptor,
|
|
20
|
+
validateCommandOptions
|
|
21
|
+
} from "./commandCatalog.js";
|
|
18
22
|
import { createCommandHandlerDeps } from "./buildCommandDeps.js";
|
|
19
23
|
import { createRunCli } from "./dispatchCli.js";
|
|
20
24
|
import {
|
|
@@ -148,6 +152,8 @@ const runCli = createRunCli({
|
|
|
148
152
|
parseArgs,
|
|
149
153
|
printUsage,
|
|
150
154
|
shouldShowCommandHelpOnBareInvocation,
|
|
155
|
+
validateCommandOptions,
|
|
156
|
+
resolveCommandDescriptor,
|
|
151
157
|
commandHandlers,
|
|
152
158
|
cleanupMaterializedPackageRoots,
|
|
153
159
|
createCliError
|
|
@@ -2,6 +2,8 @@ function createRunCli({
|
|
|
2
2
|
parseArgs,
|
|
3
3
|
printUsage,
|
|
4
4
|
shouldShowCommandHelpOnBareInvocation,
|
|
5
|
+
validateCommandOptions,
|
|
6
|
+
resolveCommandDescriptor,
|
|
5
7
|
commandHandlers,
|
|
6
8
|
cleanupMaterializedPackageRoots,
|
|
7
9
|
createCliError
|
|
@@ -15,6 +17,12 @@ function createRunCli({
|
|
|
15
17
|
if (typeof shouldShowCommandHelpOnBareInvocation !== "function") {
|
|
16
18
|
throw new TypeError("createRunCli requires shouldShowCommandHelpOnBareInvocation.");
|
|
17
19
|
}
|
|
20
|
+
if (typeof validateCommandOptions !== "function") {
|
|
21
|
+
throw new TypeError("createRunCli requires validateCommandOptions.");
|
|
22
|
+
}
|
|
23
|
+
if (typeof resolveCommandDescriptor !== "function") {
|
|
24
|
+
throw new TypeError("createRunCli requires resolveCommandDescriptor.");
|
|
25
|
+
}
|
|
18
26
|
if (!commandHandlers || typeof commandHandlers !== "object") {
|
|
19
27
|
throw new TypeError("createRunCli requires commandHandlers.");
|
|
20
28
|
}
|
|
@@ -33,6 +41,16 @@ function createRunCli({
|
|
|
33
41
|
|
|
34
42
|
try {
|
|
35
43
|
const { command, options, positional } = parseArgs(argv, { createCliError });
|
|
44
|
+
validateCommandOptions(
|
|
45
|
+
{ command, positional, options },
|
|
46
|
+
{
|
|
47
|
+
createCliError,
|
|
48
|
+
renderUsage: () => {
|
|
49
|
+
const helpCommand = command === "help" ? String(positional[0] || "").trim() : command;
|
|
50
|
+
printUsage(stderr, { command: helpCommand });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
);
|
|
36
54
|
if (options.help || command === "help") {
|
|
37
55
|
const helpCommand = command === "help" ? String(positional[0] || "").trim() : command;
|
|
38
56
|
printUsage(stdout, { command: helpCommand });
|
|
@@ -44,80 +62,22 @@ function createRunCli({
|
|
|
44
62
|
return 0;
|
|
45
63
|
}
|
|
46
64
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (command === "list") {
|
|
56
|
-
return await commandHandlers.commandList({ positional, options, cwd, stdout });
|
|
57
|
-
}
|
|
58
|
-
if (command === "list-placements") {
|
|
59
|
-
return await commandHandlers.commandListPlacements({ options, cwd, stdout });
|
|
60
|
-
}
|
|
61
|
-
if (command === "list-link-items") {
|
|
62
|
-
return await commandHandlers.commandListLinkItems({ options, cwd, stdout });
|
|
63
|
-
}
|
|
64
|
-
if (command === "show") {
|
|
65
|
-
return await commandHandlers.commandShow({ positional, options, stdout });
|
|
66
|
-
}
|
|
67
|
-
if (command === "migrations") {
|
|
68
|
-
return await commandHandlers.commandMigrations({
|
|
69
|
-
positional,
|
|
70
|
-
options,
|
|
71
|
-
cwd,
|
|
72
|
-
io: { stdin, stdout, stderr }
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
if (command === "add") {
|
|
76
|
-
return await commandHandlers.commandAdd({
|
|
77
|
-
positional,
|
|
78
|
-
options,
|
|
79
|
-
cwd,
|
|
80
|
-
io: { stdin, stdout, stderr }
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
if (command === "generate") {
|
|
84
|
-
return await commandHandlers.commandGenerate({
|
|
85
|
-
positional,
|
|
86
|
-
options,
|
|
87
|
-
cwd,
|
|
88
|
-
io: { stdin, stdout, stderr }
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
if (command === "position") {
|
|
92
|
-
return await commandHandlers.commandPosition({
|
|
93
|
-
positional,
|
|
94
|
-
options,
|
|
95
|
-
cwd,
|
|
96
|
-
io: { stdin, stdout, stderr }
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
if (command === "update") {
|
|
100
|
-
return await commandHandlers.commandUpdate({
|
|
65
|
+
const commandDescriptor = resolveCommandDescriptor(command);
|
|
66
|
+
const handlerName = String(commandDescriptor?.handlerName || "").trim();
|
|
67
|
+
if (handlerName) {
|
|
68
|
+
const commandHandler = commandHandlers[handlerName];
|
|
69
|
+
if (typeof commandHandler !== "function") {
|
|
70
|
+
throw createCliError(`Unhandled command: ${command}`, { showUsage: true });
|
|
71
|
+
}
|
|
72
|
+
return await commandHandler({
|
|
101
73
|
positional,
|
|
102
74
|
options,
|
|
103
75
|
cwd,
|
|
76
|
+
stdout,
|
|
77
|
+
stderr,
|
|
104
78
|
io: { stdin, stdout, stderr }
|
|
105
79
|
});
|
|
106
80
|
}
|
|
107
|
-
if (command === "remove") {
|
|
108
|
-
return await commandHandlers.commandRemove({
|
|
109
|
-
positional,
|
|
110
|
-
options,
|
|
111
|
-
cwd,
|
|
112
|
-
io: { stdin, stdout, stderr }
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
if (command === "doctor") {
|
|
116
|
-
return await commandHandlers.commandDoctor({ cwd, options, stdout });
|
|
117
|
-
}
|
|
118
|
-
if (command === "lint-descriptors") {
|
|
119
|
-
return await commandHandlers.commandLintDescriptors({ options, stdout });
|
|
120
|
-
}
|
|
121
81
|
|
|
122
82
|
throw createCliError(`Unhandled command: ${command}`, { showUsage: true });
|
|
123
83
|
} catch (error) {
|
|
@@ -1,323 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
listOverviewCommandDescriptors,
|
|
3
|
+
resolveCommandDescriptor,
|
|
4
|
+
shouldShowCommandHelpOnBareInvocation
|
|
5
|
+
} from "./commandCatalog.js";
|
|
2
6
|
import {
|
|
3
7
|
createColorFormatter,
|
|
4
8
|
writeWrappedLines
|
|
5
9
|
} from "../shared/outputFormatting.js";
|
|
6
10
|
|
|
7
|
-
const COMMAND_OVERVIEW = Object.freeze([
|
|
8
|
-
Object.freeze({
|
|
9
|
-
command: "create",
|
|
10
|
-
summary: "Scaffold an app-local runtime package."
|
|
11
|
-
}),
|
|
12
|
-
Object.freeze({
|
|
13
|
-
command: "add",
|
|
14
|
-
summary: "Install a runtime bundle or package into the current app."
|
|
15
|
-
}),
|
|
16
|
-
Object.freeze({
|
|
17
|
-
command: "generate",
|
|
18
|
-
summary: "Run a generator package (or generator subcommand)."
|
|
19
|
-
}),
|
|
20
|
-
Object.freeze({
|
|
21
|
-
command: "list",
|
|
22
|
-
summary: "List bundles, runtime packages, or generator packages."
|
|
23
|
-
}),
|
|
24
|
-
Object.freeze({
|
|
25
|
-
command: "list-placements",
|
|
26
|
-
summary: "List discovered UI placement targets."
|
|
27
|
-
}),
|
|
28
|
-
Object.freeze({
|
|
29
|
-
command: "list-link-items",
|
|
30
|
-
summary: "List available placement link-item component tokens."
|
|
31
|
-
}),
|
|
32
|
-
Object.freeze({
|
|
33
|
-
command: "show",
|
|
34
|
-
summary: "Show detailed metadata for a bundle or package."
|
|
35
|
-
}),
|
|
36
|
-
Object.freeze({
|
|
37
|
-
command: "migrations",
|
|
38
|
-
summary: "Generate managed migration files only."
|
|
39
|
-
}),
|
|
40
|
-
Object.freeze({
|
|
41
|
-
command: "position",
|
|
42
|
-
summary: "Re-apply positioning-only mutations for an installed package."
|
|
43
|
-
}),
|
|
44
|
-
Object.freeze({
|
|
45
|
-
command: "update",
|
|
46
|
-
summary: "Re-apply one installed package."
|
|
47
|
-
}),
|
|
48
|
-
Object.freeze({
|
|
49
|
-
command: "remove",
|
|
50
|
-
summary: "Remove one installed package."
|
|
51
|
-
}),
|
|
52
|
-
Object.freeze({
|
|
53
|
-
command: "doctor",
|
|
54
|
-
summary: "Validate lockfile and managed-file integrity."
|
|
55
|
-
}),
|
|
56
|
-
Object.freeze({
|
|
57
|
-
command: "lint-descriptors",
|
|
58
|
-
summary: "Validate bundle and package descriptor contracts."
|
|
59
|
-
})
|
|
60
|
-
]);
|
|
61
|
-
|
|
62
|
-
const COMMAND_HELP = Object.freeze({
|
|
63
|
-
create: Object.freeze({
|
|
64
|
-
title: "create",
|
|
65
|
-
minimalUse: "jskit create package <name>",
|
|
66
|
-
parameters: Object.freeze([
|
|
67
|
-
Object.freeze({
|
|
68
|
-
name: "<name>",
|
|
69
|
-
description: "Local package slug used to scaffold packages/<name>."
|
|
70
|
-
})
|
|
71
|
-
]),
|
|
72
|
-
defaults: Object.freeze([
|
|
73
|
-
"No npm install runs unless --run-npm-install is passed.",
|
|
74
|
-
"If --scope is omitted, scope is inferred from app name.",
|
|
75
|
-
"If --package-id is omitted, it is derived from scope + name."
|
|
76
|
-
]),
|
|
77
|
-
fullUse: "jskit create package <name> [--scope <scope>] [--package-id <id>] [--description <text>] [--dry-run] [--run-npm-install] [--json]"
|
|
78
|
-
}),
|
|
79
|
-
add: Object.freeze({
|
|
80
|
-
title: "add",
|
|
81
|
-
minimalUse: "jskit add package <packageId>",
|
|
82
|
-
parameters: Object.freeze([
|
|
83
|
-
Object.freeze({
|
|
84
|
-
name: "package | bundle",
|
|
85
|
-
description: "Target type. Use package for one runtime package, bundle for a bundle id."
|
|
86
|
-
}),
|
|
87
|
-
Object.freeze({
|
|
88
|
-
name: "<packageId|bundleId>",
|
|
89
|
-
description: "Catalog id or installed node_modules package id."
|
|
90
|
-
})
|
|
91
|
-
]),
|
|
92
|
-
defaults: Object.freeze([
|
|
93
|
-
"No npm install runs unless --run-npm-install is passed.",
|
|
94
|
-
"Short ids resolve to @jskit-ai/<id> when available.",
|
|
95
|
-
"Running without args lists bundles and runtime packages.",
|
|
96
|
-
"Existing matching version is skipped unless options force reapply."
|
|
97
|
-
]),
|
|
98
|
-
fullUse: "jskit add <package|bundle> <id> [--<option> <value>...] [--dry-run] [--run-npm-install] [--json] [--verbose]"
|
|
99
|
-
}),
|
|
100
|
-
generate: Object.freeze({
|
|
101
|
-
title: "generate",
|
|
102
|
-
minimalUse: "jskit generate <generatorId>",
|
|
103
|
-
parameters: Object.freeze([
|
|
104
|
-
Object.freeze({
|
|
105
|
-
name: "<generatorId>",
|
|
106
|
-
description: "Generator package id (for example: crud-ui-generator)."
|
|
107
|
-
}),
|
|
108
|
-
Object.freeze({
|
|
109
|
-
name: "[subcommand]",
|
|
110
|
-
description: "Optional generator subcommand (for example: scaffold or scaffold-field)."
|
|
111
|
-
}),
|
|
112
|
-
Object.freeze({
|
|
113
|
-
name: "[subcommand args...]",
|
|
114
|
-
description: "Optional positional args consumed by the chosen subcommand."
|
|
115
|
-
})
|
|
116
|
-
]),
|
|
117
|
-
defaults: Object.freeze([
|
|
118
|
-
"No npm install runs unless --run-npm-install is passed.",
|
|
119
|
-
"Short ids resolve to @jskit-ai/<id> when available.",
|
|
120
|
-
"Running without args lists available generators.",
|
|
121
|
-
"Running with only <generatorId> shows generator help.",
|
|
122
|
-
"Use jskit generate <generatorId> <subcommand> help for subcommand-specific usage."
|
|
123
|
-
]),
|
|
124
|
-
examples: Object.freeze([
|
|
125
|
-
Object.freeze({
|
|
126
|
-
label: "Common usage",
|
|
127
|
-
lines: Object.freeze([
|
|
128
|
-
"npx jskit generate ui-generator page \\",
|
|
129
|
-
" admin/reports/index.vue"
|
|
130
|
-
])
|
|
131
|
-
}),
|
|
132
|
-
Object.freeze({
|
|
133
|
-
label: "More advanced usage",
|
|
134
|
-
lines: Object.freeze([
|
|
135
|
-
"npx jskit generate crud-ui-generator crud \\",
|
|
136
|
-
" admin/catalog/index/products \\",
|
|
137
|
-
" --resource-file packages/products/src/shared/productResource.js"
|
|
138
|
-
])
|
|
139
|
-
})
|
|
140
|
-
]),
|
|
141
|
-
fullUse: "jskit generate <generatorId> [subcommand] [subcommand args...] [--<option> <value>...] [--dry-run] [--run-npm-install] [--json] [--verbose]"
|
|
142
|
-
}),
|
|
143
|
-
list: Object.freeze({
|
|
144
|
-
title: "list",
|
|
145
|
-
minimalUse: "jskit list",
|
|
146
|
-
parameters: Object.freeze([
|
|
147
|
-
Object.freeze({
|
|
148
|
-
name: "[mode]",
|
|
149
|
-
description: "Optional mode: bundles, packages, or generators."
|
|
150
|
-
})
|
|
151
|
-
]),
|
|
152
|
-
defaults: Object.freeze([
|
|
153
|
-
"Without mode, list prints bundles + runtime packages + generators.",
|
|
154
|
-
"placements are listed by the dedicated list-placements command.",
|
|
155
|
-
"--full and --expanded only affect bundle/package listing views."
|
|
156
|
-
]),
|
|
157
|
-
fullUse: "jskit list [bundles|packages|generators] [--full] [--expanded] [--json]"
|
|
158
|
-
}),
|
|
159
|
-
"list-placements": Object.freeze({
|
|
160
|
-
title: "list-placements",
|
|
161
|
-
minimalUse: "jskit list-placements",
|
|
162
|
-
parameters: Object.freeze([]),
|
|
163
|
-
defaults: Object.freeze([
|
|
164
|
-
"Discovers placement outlets from app Vue ShellOutlet tags and route meta.",
|
|
165
|
-
"Includes placement outlets contributed by installed package metadata.",
|
|
166
|
-
"Shows plain text by default; use --json for structured output."
|
|
167
|
-
]),
|
|
168
|
-
fullUse: "jskit list-placements [--json]"
|
|
169
|
-
}),
|
|
170
|
-
"list-link-items": Object.freeze({
|
|
171
|
-
title: "list-link-items",
|
|
172
|
-
minimalUse: "jskit list-link-items",
|
|
173
|
-
parameters: Object.freeze([
|
|
174
|
-
Object.freeze({
|
|
175
|
-
name: "[--prefix <value>]",
|
|
176
|
-
description: "Optional token prefix filter (example: local.main. or users.web.shell.)."
|
|
177
|
-
}),
|
|
178
|
-
Object.freeze({
|
|
179
|
-
name: "[--all]",
|
|
180
|
-
description: "Include all discovered tokens (including non-link-item and client container/runtime tokens)."
|
|
181
|
-
})
|
|
182
|
-
]),
|
|
183
|
-
defaults: Object.freeze([
|
|
184
|
-
"Default output shows link-item tokens only (token names ending with link-item).",
|
|
185
|
-
"Default includes app and installed-package placement-linked token sources.",
|
|
186
|
-
"Use --prefix to narrow quickly (recommended: --prefix local.main.).",
|
|
187
|
-
"Use --all when you want the full discovered token set.",
|
|
188
|
-
"Shows plain text by default; use --json for structured output."
|
|
189
|
-
]),
|
|
190
|
-
fullUse: "jskit list-link-items [--prefix <value>] [--all] [--json]"
|
|
191
|
-
}),
|
|
192
|
-
show: Object.freeze({
|
|
193
|
-
title: "show",
|
|
194
|
-
minimalUse: "jskit show <id>",
|
|
195
|
-
parameters: Object.freeze([
|
|
196
|
-
Object.freeze({
|
|
197
|
-
name: "<id>",
|
|
198
|
-
description: "Bundle id or package id to inspect."
|
|
199
|
-
})
|
|
200
|
-
]),
|
|
201
|
-
defaults: Object.freeze([
|
|
202
|
-
"view is an alias of show.",
|
|
203
|
-
"Basic output is compact; --details expands capability and runtime sections.",
|
|
204
|
-
"--debug-exports implies --details."
|
|
205
|
-
]),
|
|
206
|
-
fullUse: "jskit show <id> [--details] [--debug-exports] [--json]"
|
|
207
|
-
}),
|
|
208
|
-
migrations: Object.freeze({
|
|
209
|
-
title: "migrations",
|
|
210
|
-
minimalUse: "jskit migrations changed",
|
|
211
|
-
parameters: Object.freeze([
|
|
212
|
-
Object.freeze({
|
|
213
|
-
name: "<scope>",
|
|
214
|
-
description: "all | changed | package."
|
|
215
|
-
}),
|
|
216
|
-
Object.freeze({
|
|
217
|
-
name: "[packageId]",
|
|
218
|
-
description: "Required only when scope is package."
|
|
219
|
-
})
|
|
220
|
-
]),
|
|
221
|
-
defaults: Object.freeze([
|
|
222
|
-
"No npm install runs unless --run-npm-install is passed.",
|
|
223
|
-
"Inline options are accepted only for 'migrations package <packageId>'.",
|
|
224
|
-
"Without --json, output lists touched migration files."
|
|
225
|
-
]),
|
|
226
|
-
fullUse: "jskit migrations <all|changed|package> [packageId] [--<option> <value>...] [--dry-run] [--json] [--verbose]"
|
|
227
|
-
}),
|
|
228
|
-
position: Object.freeze({
|
|
229
|
-
title: "position",
|
|
230
|
-
minimalUse: "jskit position element <packageId>",
|
|
231
|
-
parameters: Object.freeze([
|
|
232
|
-
Object.freeze({
|
|
233
|
-
name: "element",
|
|
234
|
-
description: "Target type for positioning command."
|
|
235
|
-
}),
|
|
236
|
-
Object.freeze({
|
|
237
|
-
name: "<packageId>",
|
|
238
|
-
description: "Installed package id to re-position."
|
|
239
|
-
})
|
|
240
|
-
]),
|
|
241
|
-
defaults: Object.freeze([
|
|
242
|
-
"Only positioning mutations are applied.",
|
|
243
|
-
"No npm install runs unless --run-npm-install is passed.",
|
|
244
|
-
"Reads current options from lock unless overridden inline."
|
|
245
|
-
]),
|
|
246
|
-
fullUse: "jskit position element <packageId> [--<option> <value>...] [--dry-run] [--json]"
|
|
247
|
-
}),
|
|
248
|
-
update: Object.freeze({
|
|
249
|
-
title: "update",
|
|
250
|
-
minimalUse: "jskit update package <packageId>",
|
|
251
|
-
parameters: Object.freeze([
|
|
252
|
-
Object.freeze({
|
|
253
|
-
name: "package",
|
|
254
|
-
description: "Target type for update command."
|
|
255
|
-
}),
|
|
256
|
-
Object.freeze({
|
|
257
|
-
name: "<packageId>",
|
|
258
|
-
description: "Installed package id to re-apply."
|
|
259
|
-
})
|
|
260
|
-
]),
|
|
261
|
-
defaults: Object.freeze([
|
|
262
|
-
"No npm install runs unless --run-npm-install is passed.",
|
|
263
|
-
"Existing lock options are reused unless overridden inline.",
|
|
264
|
-
"update reuses add package flow with forced reapply."
|
|
265
|
-
]),
|
|
266
|
-
fullUse: "jskit update package <packageId> [--<option> <value>...] [--dry-run] [--run-npm-install] [--json]"
|
|
267
|
-
}),
|
|
268
|
-
remove: Object.freeze({
|
|
269
|
-
title: "remove",
|
|
270
|
-
minimalUse: "jskit remove package <packageId>",
|
|
271
|
-
parameters: Object.freeze([
|
|
272
|
-
Object.freeze({
|
|
273
|
-
name: "package",
|
|
274
|
-
description: "Target type for remove command."
|
|
275
|
-
}),
|
|
276
|
-
Object.freeze({
|
|
277
|
-
name: "<packageId>",
|
|
278
|
-
description: "Installed package id to remove."
|
|
279
|
-
})
|
|
280
|
-
]),
|
|
281
|
-
defaults: Object.freeze([
|
|
282
|
-
"No npm install runs unless --run-npm-install is passed.",
|
|
283
|
-
"Managed files and lock entries are removed for the package.",
|
|
284
|
-
"Local package source directories are not deleted."
|
|
285
|
-
]),
|
|
286
|
-
fullUse: "jskit remove package <packageId> [--dry-run] [--run-npm-install] [--json]"
|
|
287
|
-
}),
|
|
288
|
-
doctor: Object.freeze({
|
|
289
|
-
title: "doctor",
|
|
290
|
-
minimalUse: "jskit doctor",
|
|
291
|
-
parameters: Object.freeze([]),
|
|
292
|
-
defaults: Object.freeze([
|
|
293
|
-
"Validates lock entries, managed files, and registry visibility.",
|
|
294
|
-
"Reports issues as plain text by default.",
|
|
295
|
-
"Use --json for machine-readable diagnostics."
|
|
296
|
-
]),
|
|
297
|
-
fullUse: "jskit doctor [--json]"
|
|
298
|
-
}),
|
|
299
|
-
"lint-descriptors": Object.freeze({
|
|
300
|
-
title: "lint-descriptors",
|
|
301
|
-
minimalUse: "jskit lint-descriptors",
|
|
302
|
-
parameters: Object.freeze([]),
|
|
303
|
-
defaults: Object.freeze([
|
|
304
|
-
"Runs descriptor consistency checks.",
|
|
305
|
-
"check-di-labels is optional and adds stricter DI token label checks.",
|
|
306
|
-
"Outputs plain text by default and supports --json."
|
|
307
|
-
]),
|
|
308
|
-
fullUse: "jskit lint-descriptors [--check-di-labels] [--json]"
|
|
309
|
-
})
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
const BARE_COMMAND_HELP = new Set([
|
|
313
|
-
"create",
|
|
314
|
-
"show",
|
|
315
|
-
"migrations",
|
|
316
|
-
"position",
|
|
317
|
-
"update",
|
|
318
|
-
"remove"
|
|
319
|
-
]);
|
|
320
|
-
|
|
321
11
|
function appendSeparatedBlocks(lines = [], blocks = []) {
|
|
322
12
|
const normalizedBlocks = Array.isArray(blocks) ? blocks : [];
|
|
323
13
|
for (const [index, block] of normalizedBlocks.entries()) {
|
|
@@ -346,18 +36,14 @@ function printTopLevelHelp(stream = process.stderr) {
|
|
|
346
36
|
lines.push("Use: jskit help <command> for command-specific usage.");
|
|
347
37
|
lines.push("");
|
|
348
38
|
lines.push(color.heading("Available commands:"));
|
|
349
|
-
for (const entry of
|
|
39
|
+
for (const entry of listOverviewCommandDescriptors()) {
|
|
350
40
|
lines.push(` ${color.item(entry.command.padEnd(16, " "))} ${entry.summary}`);
|
|
351
41
|
}
|
|
352
|
-
lines.push("");
|
|
353
|
-
lines.push(color.heading("Global flags:"));
|
|
354
|
-
lines.push(" --dry-run --run-npm-install --json --verbose --help");
|
|
355
42
|
writeHelpLines(stream, lines);
|
|
356
43
|
}
|
|
357
44
|
|
|
358
45
|
function printCommandHelp(stream = process.stderr, command = "") {
|
|
359
|
-
const
|
|
360
|
-
const entry = COMMAND_HELP[resolvedCommand];
|
|
46
|
+
const entry = resolveCommandDescriptor(command);
|
|
361
47
|
if (!entry) {
|
|
362
48
|
printTopLevelHelp(stream);
|
|
363
49
|
return;
|
|
@@ -365,7 +51,7 @@ function printCommandHelp(stream = process.stderr, command = "") {
|
|
|
365
51
|
|
|
366
52
|
const color = createColorFormatter(stream);
|
|
367
53
|
const lines = [];
|
|
368
|
-
lines.push(`Command: ${color.emphasis(entry.
|
|
54
|
+
lines.push(`Command: ${color.emphasis(entry.command)}`);
|
|
369
55
|
lines.push("");
|
|
370
56
|
|
|
371
57
|
let sectionNumber = 1;
|
|
@@ -423,15 +109,6 @@ function printUsage(stream = process.stderr, { command = "" } = {}) {
|
|
|
423
109
|
printCommandHelp(stream, normalizedCommand);
|
|
424
110
|
}
|
|
425
111
|
|
|
426
|
-
function shouldShowCommandHelpOnBareInvocation(command = "", positional = []) {
|
|
427
|
-
const resolvedCommand = resolveCommandAlias(command);
|
|
428
|
-
const argumentList = Array.isArray(positional) ? positional : [];
|
|
429
|
-
if (!BARE_COMMAND_HELP.has(resolvedCommand)) {
|
|
430
|
-
return false;
|
|
431
|
-
}
|
|
432
|
-
return argumentList.length < 1;
|
|
433
|
-
}
|
|
434
|
-
|
|
435
112
|
export {
|
|
436
113
|
printUsage,
|
|
437
114
|
shouldShowCommandHelpOnBareInvocation
|