@optique/discover 1.1.0 → 1.2.0-dev.2169
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/README.md +21 -19
- package/dist/{command-DZA06E08.cjs → command-B0lV6NBO.cjs} +2 -2
- package/dist/{command-y_A3hG0g.js → command-DO5zgkvS.js} +2 -2
- package/dist/{command-2HtR3-TV.d.cts → command-DSHBTa5c.d.cts} +5 -2
- package/dist/{command-BAVhIzfI.d.ts → command-DyiVIMUh.d.ts} +5 -2
- package/dist/command.cjs +1 -1
- package/dist/command.d.cts +1 -1
- package/dist/command.d.ts +1 -1
- package/dist/command.js +1 -1
- package/dist/index.cjs +465 -58
- package/dist/index.d.cts +119 -8
- package/dist/index.d.ts +119 -8
- package/dist/index.js +467 -61
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -21,10 +21,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
21
21
|
}) : target, mod));
|
|
22
22
|
|
|
23
23
|
//#endregion
|
|
24
|
-
const require_command = require('./command-
|
|
24
|
+
const require_command = require('./command-B0lV6NBO.cjs');
|
|
25
25
|
const __optique_core_constructs = __toESM(require("@optique/core/constructs"));
|
|
26
|
+
const __optique_core_extension = __toESM(require("@optique/core/extension"));
|
|
26
27
|
const __optique_core_modifiers = __toESM(require("@optique/core/modifiers"));
|
|
27
28
|
const __optique_core_primitives = __toESM(require("@optique/core/primitives"));
|
|
29
|
+
const __optique_core_usage = __toESM(require("@optique/core/usage"));
|
|
28
30
|
const __optique_run = __toESM(require("@optique/run"));
|
|
29
31
|
const node_fs_promises = __toESM(require("node:fs/promises"));
|
|
30
32
|
const node_path = __toESM(require("node:path"));
|
|
@@ -61,37 +63,81 @@ function getDefaultExtensions(options = {}) {
|
|
|
61
63
|
* @param options Discovery options.
|
|
62
64
|
* @returns Discovered commands sorted by command path.
|
|
63
65
|
* @throws {TypeError} If options are invalid, discovery finds no commands,
|
|
64
|
-
* command paths
|
|
65
|
-
* command created with `defineCommand()`.
|
|
66
|
+
* command paths are duplicated, or a module does not default-export
|
|
67
|
+
* a command created with `defineCommand()`.
|
|
66
68
|
* @since 1.1.0
|
|
67
69
|
*/
|
|
68
70
|
async function discoverCommands(options) {
|
|
69
71
|
const dir = pathFromDir(options.dir);
|
|
70
72
|
const extensions = normalizeExtensions(options.extensions ?? getDefaultExtensions());
|
|
73
|
+
const entryFileName = normalizeEntryFileName(options.entryFileName);
|
|
71
74
|
const files = await collectCommandFiles(dir, extensions);
|
|
72
75
|
if (files.length < 1) throw new TypeError(`No command modules found in ${dir}.`);
|
|
73
76
|
const seen = /* @__PURE__ */ new Map();
|
|
74
77
|
const discovered = [];
|
|
75
78
|
for (const filePath of files) {
|
|
76
|
-
const path = commandPathFromFile(dir, filePath, extensions);
|
|
79
|
+
const path = commandPathFromFile(dir, filePath, extensions, entryFileName);
|
|
77
80
|
const key = commandPathKey(path);
|
|
78
81
|
const previous = seen.get(key);
|
|
79
82
|
if (previous != null) {
|
|
80
|
-
const displayPath = path
|
|
83
|
+
const displayPath = displayCommandPath(path);
|
|
81
84
|
throw new TypeError(`Duplicate command path "${displayPath}" from ${previous} and ${filePath}.`);
|
|
82
85
|
}
|
|
83
86
|
seen.set(key, filePath);
|
|
84
87
|
const mod = await import((0, node_url.pathToFileURL)(filePath).href);
|
|
85
|
-
const commandDefinition =
|
|
86
|
-
|
|
87
|
-
if (commandDefinition.path != null && commandPathKey(commandDefinition.path) !== commandPathKey(path)) throw new TypeError(`Module ${filePath} declares command path "${commandDefinition.path.join(" ")}" but file path defines "${path.join(" ")}".`);
|
|
88
|
+
const commandDefinition = commandFromModuleExport(filePath, mod.default);
|
|
89
|
+
validateDeclaredCommandPath(commandDefinition, path, filePath, "file path");
|
|
88
90
|
discovered.push({
|
|
89
91
|
path,
|
|
90
92
|
filePath,
|
|
91
93
|
command: commandDefinition
|
|
92
94
|
});
|
|
93
95
|
}
|
|
94
|
-
|
|
96
|
+
return sortCommands(discovered);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Converts a static module map into command entries.
|
|
100
|
+
*
|
|
101
|
+
* This is useful for bundlers and single-file packagers that can statically
|
|
102
|
+
* see module maps, such as `import.meta.glob(..., { eager: true })`, while
|
|
103
|
+
* still deriving command paths from file-like module keys.
|
|
104
|
+
*
|
|
105
|
+
* @param modules Static module map keyed by module path.
|
|
106
|
+
* @param options Module path derivation options.
|
|
107
|
+
* @returns Command entries sorted by command path.
|
|
108
|
+
* @throws {TypeError} If options are invalid, no command modules are found,
|
|
109
|
+
* command paths are duplicated, a module does not default-export a
|
|
110
|
+
* command created with `defineCommand()`, or an explicit command
|
|
111
|
+
* `path` does not match the module-derived path.
|
|
112
|
+
* @since 1.2.0
|
|
113
|
+
*/
|
|
114
|
+
function commandsFromModules(modules, options = {}) {
|
|
115
|
+
if (modules == null || typeof modules !== "object") throw new TypeError("commandsFromModules() requires a module map object.");
|
|
116
|
+
const base = normalizeModuleBase(options.base);
|
|
117
|
+
const extensions = normalizeExtensions(options.extensions ?? getDefaultExtensions());
|
|
118
|
+
const entryFileName = normalizeEntryFileName(options.entryFileName);
|
|
119
|
+
const modulePaths = Object.keys(modules).toSorted((a, b) => a.localeCompare(b));
|
|
120
|
+
const seen = /* @__PURE__ */ new Map();
|
|
121
|
+
const discovered = [];
|
|
122
|
+
for (const modulePath of modulePaths) {
|
|
123
|
+
if (isDeclarationFile(node_path.posix.basename(modulePath)) || !extensions.some((ext) => modulePath.endsWith(ext))) continue;
|
|
124
|
+
const path = commandPathFromModulePath(base, modulePath, extensions, entryFileName);
|
|
125
|
+
const key = commandPathKey(path);
|
|
126
|
+
const previous = seen.get(key);
|
|
127
|
+
if (previous != null) {
|
|
128
|
+
const displayPath = displayCommandPath(path);
|
|
129
|
+
throw new TypeError(`Duplicate command path "${displayPath}" from ${previous} and ${modulePath}.`);
|
|
130
|
+
}
|
|
131
|
+
seen.set(key, modulePath);
|
|
132
|
+
const commandDefinition = commandFromModuleExport(modulePath, modules[modulePath]);
|
|
133
|
+
validateDeclaredCommandPath(commandDefinition, path, modulePath, "module path");
|
|
134
|
+
discovered.push({
|
|
135
|
+
path,
|
|
136
|
+
modulePath,
|
|
137
|
+
command: commandDefinition
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
if (discovered.length < 1) throw new TypeError("No command modules found in module map.");
|
|
95
141
|
return sortCommands(discovered);
|
|
96
142
|
}
|
|
97
143
|
/**
|
|
@@ -100,7 +146,8 @@ async function discoverCommands(options) {
|
|
|
100
146
|
* @param commands Commands to compose.
|
|
101
147
|
* @param metadata Optional root documentation metadata.
|
|
102
148
|
* @returns A parser that resolves to an internal command invocation.
|
|
103
|
-
* @throws {TypeError} If no commands are provided or command paths
|
|
149
|
+
* @throws {TypeError} If no commands are provided or command paths are
|
|
150
|
+
* duplicated.
|
|
104
151
|
* @since 1.1.0
|
|
105
152
|
*/
|
|
106
153
|
function createProgramParser(commands, metadata = {}) {
|
|
@@ -108,11 +155,7 @@ function createProgramParser(commands, metadata = {}) {
|
|
|
108
155
|
const sortedCommands = sortCommands(commands);
|
|
109
156
|
rejectDuplicatePaths(sortedCommands.map((entry) => ({
|
|
110
157
|
path: entry.path,
|
|
111
|
-
filePath: entry.path
|
|
112
|
-
})));
|
|
113
|
-
rejectPathConflicts(sortedCommands.map((entry) => ({
|
|
114
|
-
path: entry.path,
|
|
115
|
-
filePath: entry.path.join("/")
|
|
158
|
+
filePath: displayCommandPath(entry.path)
|
|
116
159
|
})));
|
|
117
160
|
const rootNode = buildCommandTree(sortedCommands);
|
|
118
161
|
const parser = buildNodeParser(rootNode);
|
|
@@ -132,7 +175,8 @@ async function runProgram(options) {
|
|
|
132
175
|
if (isStaticRunProgramOptions(options)) commands = staticCommandsToEntries(options.commands);
|
|
133
176
|
else commands = await discoverCommands({
|
|
134
177
|
dir: options.dir,
|
|
135
|
-
extensions: options.extensions
|
|
178
|
+
extensions: options.extensions,
|
|
179
|
+
entryFileName: options.entryFileName
|
|
136
180
|
});
|
|
137
181
|
const parser = createProgramParser(commands, options.metadata);
|
|
138
182
|
const invocation = await (0, __optique_run.runAsync)(parser, buildRunOptions(options));
|
|
@@ -163,6 +207,19 @@ function normalizeExtensions(extensions) {
|
|
|
163
207
|
}
|
|
164
208
|
return normalized.toSorted((a, b) => b.length - a.length || a.localeCompare(b));
|
|
165
209
|
}
|
|
210
|
+
function normalizeEntryFileName(entryFileName) {
|
|
211
|
+
if (entryFileName === void 0) return "index";
|
|
212
|
+
if (entryFileName === false) return false;
|
|
213
|
+
if (typeof entryFileName !== "string") throw new TypeError(`Command entry file name must be a non-empty file name: ${entryFileName}`);
|
|
214
|
+
const normalized = entryFileName;
|
|
215
|
+
if (normalized.length < 1 || normalized.includes("/") || normalized.includes("\\")) throw new TypeError(`Command entry file name must be a non-empty file name: ${normalized}`);
|
|
216
|
+
return normalized;
|
|
217
|
+
}
|
|
218
|
+
function normalizeModuleBase(base) {
|
|
219
|
+
if (base === void 0) return ".";
|
|
220
|
+
if (typeof base !== "string" || base.length < 1) throw new TypeError(`Module base path must be a non-empty string: ${base}`);
|
|
221
|
+
return normalizeModulePath(base);
|
|
222
|
+
}
|
|
166
223
|
async function collectCommandFiles(dir, extensions, activeDirs = /* @__PURE__ */ new Set()) {
|
|
167
224
|
const canonicalDir = await (0, node_fs_promises.realpath)(dir);
|
|
168
225
|
if (activeDirs.has(canonicalDir)) return [];
|
|
@@ -194,29 +251,45 @@ async function getCommandFileEntryType(path, entry) {
|
|
|
194
251
|
function isDeclarationFile(fileName) {
|
|
195
252
|
return /\.d\.[cm]?ts$/.test(fileName);
|
|
196
253
|
}
|
|
197
|
-
function commandPathFromFile(rootDir, filePath, extensions) {
|
|
198
|
-
const
|
|
199
|
-
if (matchedExtension == null) throw new TypeError(`No configured extension matches ${filePath}.`);
|
|
200
|
-
const withoutExtension = filePath.slice(0, -matchedExtension.length);
|
|
254
|
+
function commandPathFromFile(rootDir, filePath, extensions, entryFileName) {
|
|
255
|
+
const withoutExtension = stripCommandExtension(filePath, extensions);
|
|
201
256
|
const relativePath = (0, node_path.relative)(rootDir, withoutExtension);
|
|
202
257
|
const path = relativePath.split(node_path.sep).filter((segment) => segment.length > 0);
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
258
|
+
return commandPathFromSegments(path, filePath, entryFileName);
|
|
259
|
+
}
|
|
260
|
+
function commandPathFromModulePath(base, modulePath, extensions, entryFileName) {
|
|
261
|
+
const withoutExtension = stripCommandExtension(modulePath, extensions);
|
|
262
|
+
const relativePath = relativeModulePath(base, withoutExtension, modulePath);
|
|
263
|
+
const path = relativePath.split("/").filter((segment) => segment.length > 0);
|
|
264
|
+
return commandPathFromSegments(path, modulePath, entryFileName);
|
|
265
|
+
}
|
|
266
|
+
function stripCommandExtension(path, extensions) {
|
|
267
|
+
const matchedExtension = extensions.find((ext) => path.endsWith(ext));
|
|
268
|
+
if (matchedExtension == null) throw new TypeError(`No configured extension matches ${path}.`);
|
|
269
|
+
return path.slice(0, -matchedExtension.length);
|
|
270
|
+
}
|
|
271
|
+
function relativeModulePath(base, modulePath, originalModulePath) {
|
|
272
|
+
const normalizedPath = normalizeModulePath(modulePath);
|
|
273
|
+
const relativePath = node_path.posix.relative(base, normalizedPath);
|
|
274
|
+
if (relativePath.length < 1 || relativePath === ".." || relativePath.startsWith("../") || node_path.posix.isAbsolute(relativePath)) throw new TypeError(`Module path ${originalModulePath} is not under base path ${base}.`);
|
|
275
|
+
return relativePath;
|
|
276
|
+
}
|
|
277
|
+
function normalizeModulePath(path) {
|
|
278
|
+
return node_path.posix.normalize(path.replaceAll("\\", "/"));
|
|
279
|
+
}
|
|
280
|
+
function commandPathFromSegments(path, source, entryFileName) {
|
|
281
|
+
if (path.length < 1) throw new TypeError(`Command module ${source} does not define a path.`);
|
|
282
|
+
if (entryFileName !== false && path[path.length - 1] === entryFileName) return path.slice(0, -1);
|
|
283
|
+
return path;
|
|
206
284
|
}
|
|
207
285
|
function commandPathKey(path) {
|
|
208
286
|
return path.join("\0");
|
|
209
287
|
}
|
|
288
|
+
function displayCommandPath(path) {
|
|
289
|
+
return path.length < 1 ? "<root>" : path.join(" ");
|
|
290
|
+
}
|
|
210
291
|
function isCommandPath(path) {
|
|
211
|
-
return Array.isArray(path) && path.
|
|
212
|
-
}
|
|
213
|
-
function rejectPathConflicts(commands) {
|
|
214
|
-
const paths = new Map(commands.map((entry) => [commandPathKey(entry.path), entry]));
|
|
215
|
-
for (const entry of commands) for (let i = 1; i < entry.path.length; i++) {
|
|
216
|
-
const parent = entry.path.slice(0, i);
|
|
217
|
-
const parentEntry = paths.get(commandPathKey(parent));
|
|
218
|
-
if (parentEntry != null) throw new TypeError(`Command path "${parent.join(" ")}" conflicts with nested command "${entry.path.join(" ")}".`);
|
|
219
|
-
}
|
|
292
|
+
return Array.isArray(path) && path.every((segment) => typeof segment === "string" && segment.length > 0);
|
|
220
293
|
}
|
|
221
294
|
function rejectDuplicatePaths(commands) {
|
|
222
295
|
const seen = /* @__PURE__ */ new Map();
|
|
@@ -224,7 +297,7 @@ function rejectDuplicatePaths(commands) {
|
|
|
224
297
|
const key = commandPathKey(entry.path);
|
|
225
298
|
const previous = seen.get(key);
|
|
226
299
|
if (previous != null) {
|
|
227
|
-
const displayPath = entry.path
|
|
300
|
+
const displayPath = displayCommandPath(entry.path);
|
|
228
301
|
throw new TypeError(`Duplicate command path "${displayPath}" from ${previous} and ${entry.filePath}.`);
|
|
229
302
|
}
|
|
230
303
|
seen.set(key, entry.filePath);
|
|
@@ -240,23 +313,38 @@ function isStaticRunProgramOptions(options) {
|
|
|
240
313
|
return hasCommands;
|
|
241
314
|
}
|
|
242
315
|
function staticCommandsToEntries(commands) {
|
|
243
|
-
return commands.map((
|
|
244
|
-
if (
|
|
245
|
-
if (!
|
|
316
|
+
return commands.map((entry) => {
|
|
317
|
+
if (isCommandEntry(entry)) return entry;
|
|
318
|
+
if (!require_command.isCommand(entry)) throw new TypeError("Static command entries must be created with defineCommand().");
|
|
319
|
+
if (!isCommandPath(entry.path)) throw new TypeError("Static command entries must declare a path.");
|
|
246
320
|
return {
|
|
247
|
-
path:
|
|
248
|
-
command:
|
|
321
|
+
path: entry.path,
|
|
322
|
+
command: entry
|
|
249
323
|
};
|
|
250
324
|
});
|
|
251
325
|
}
|
|
326
|
+
function isCommandEntry(value) {
|
|
327
|
+
return value != null && typeof value === "object" && isCommandPath(value.path) && require_command.isCommand(value.command);
|
|
328
|
+
}
|
|
252
329
|
function unwrapCommandExport(value) {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if (
|
|
330
|
+
let current = value;
|
|
331
|
+
for (let depth = 0; depth < 3; depth++) {
|
|
332
|
+
if (require_command.isCommand(current)) return current;
|
|
333
|
+
if (current == null || typeof current !== "object") return void 0;
|
|
334
|
+
const nestedDefault = current.default;
|
|
335
|
+
if (Object.is(nestedDefault, current)) return void 0;
|
|
336
|
+
current = nestedDefault;
|
|
257
337
|
}
|
|
258
338
|
return void 0;
|
|
259
339
|
}
|
|
340
|
+
function commandFromModuleExport(source, value) {
|
|
341
|
+
const commandDefinition = unwrapCommandExport(value);
|
|
342
|
+
if (commandDefinition == null) throw new TypeError(`Module ${source} default export must be created with defineCommand().`);
|
|
343
|
+
return commandDefinition;
|
|
344
|
+
}
|
|
345
|
+
function validateDeclaredCommandPath(commandDefinition, path, source, sourcePathLabel) {
|
|
346
|
+
if (commandDefinition.path != null && commandPathKey(commandDefinition.path) !== commandPathKey(path)) throw new TypeError(`Module ${source} declares command path "${displayCommandPath(commandDefinition.path)}" but ${sourcePathLabel} defines "${displayCommandPath(path)}".`);
|
|
347
|
+
}
|
|
260
348
|
function buildCommandTree(commands) {
|
|
261
349
|
const root = { children: /* @__PURE__ */ new Map() };
|
|
262
350
|
for (const entry of commands) {
|
|
@@ -273,41 +361,354 @@ function buildCommandTree(commands) {
|
|
|
273
361
|
}
|
|
274
362
|
return root;
|
|
275
363
|
}
|
|
276
|
-
function buildNodeParser(node) {
|
|
364
|
+
function buildNodeParser(node, inheritedHidden) {
|
|
365
|
+
const childParser = buildChildrenParser(node, inheritedHidden);
|
|
366
|
+
if (childParser != null && node.command != null) return createExecutableNodeParser(childParser, node.command);
|
|
367
|
+
if (childParser != null) return childParser;
|
|
368
|
+
if (node.command != null) return createLeafParser(node.command);
|
|
369
|
+
throw new TypeError("Command tree node must contain a command.");
|
|
370
|
+
}
|
|
371
|
+
function createExecutableNodeParser(childParser, commandDefinition) {
|
|
372
|
+
const leafParser = createLeafParser(commandDefinition, true);
|
|
373
|
+
const branchParsers = [childParser, leafParser];
|
|
374
|
+
const parser = (0, __optique_core_constructs.longestMatch)(childParser, leafParser);
|
|
375
|
+
const phase2SeedHook = findPhase2SeedHook(parser);
|
|
376
|
+
const executableParser = {
|
|
377
|
+
...parser,
|
|
378
|
+
$valueType: [],
|
|
379
|
+
$stateType: [],
|
|
380
|
+
initialState: void 0,
|
|
381
|
+
parse(context) {
|
|
382
|
+
const activeState = normalizeExecutableNodeState(context.state);
|
|
383
|
+
if (activeState?.committed === true && activeState.result.success) {
|
|
384
|
+
const branchParser = branchParsers[activeState.branch];
|
|
385
|
+
const result$1 = branchParser.parse(withExecutableNodeChildContext(context, activeState.branch, (0, __optique_core_extension.inheritAnnotations)(context.state, activeState.result.next.state), branchParser));
|
|
386
|
+
return (0, __optique_core_extension.mapModeValue)(parser.mode, (0, __optique_core_extension.wrapForMode)(parser.mode, result$1), (resolved) => wrapBranchParseResult(context, activeState, resolved));
|
|
387
|
+
}
|
|
388
|
+
const result = parser.parse({
|
|
389
|
+
...context,
|
|
390
|
+
state: toExclusiveState(activeState, context.state)
|
|
391
|
+
});
|
|
392
|
+
return (0, __optique_core_extension.mapModeValue)(parser.mode, (0, __optique_core_extension.wrapForMode)(parser.mode, result), (resolved) => wrapInitialParseResult(context, resolved));
|
|
393
|
+
},
|
|
394
|
+
complete(state, exec) {
|
|
395
|
+
const activeState = normalizeExecutableNodeState(state);
|
|
396
|
+
if (activeState?.result.success === true) return (0, __optique_core_extension.wrapForMode)(parser.mode, branchParsers[activeState.branch].complete((0, __optique_core_extension.inheritAnnotations)(state, activeState.result.next.state), withExecutableNodeChildExecPath(exec, activeState.branch)));
|
|
397
|
+
if (activeState == null) return (0, __optique_core_extension.wrapForMode)(parser.mode, completeExecutableNodeLeaf(state, exec, leafParser));
|
|
398
|
+
return (0, __optique_core_extension.wrapForMode)(parser.mode, parser.complete(toExclusiveState(activeState, state), exec));
|
|
399
|
+
},
|
|
400
|
+
suggest(context, prefix) {
|
|
401
|
+
const activeState = normalizeExecutableNodeState(context.state);
|
|
402
|
+
if (activeState?.committed === true && activeState.result.success) {
|
|
403
|
+
const branchParser = branchParsers[activeState.branch];
|
|
404
|
+
return branchParser.suggest(withExecutableNodeChildContext(context, activeState.branch, (0, __optique_core_extension.inheritAnnotations)(context.state, activeState.result.next.state), branchParser), prefix);
|
|
405
|
+
}
|
|
406
|
+
return parser.suggest({
|
|
407
|
+
...context,
|
|
408
|
+
state: toExclusiveState(activeState, context.state)
|
|
409
|
+
}, prefix);
|
|
410
|
+
},
|
|
411
|
+
getSuggestRuntimeNodes(state, path) {
|
|
412
|
+
const activeState = normalizeExecutableNodeState(state);
|
|
413
|
+
if (activeState == null) {
|
|
414
|
+
const branchPath$1 = [...path, 1];
|
|
415
|
+
const branchState$1 = (0, __optique_core_extension.inheritAnnotations)(state, leafParser.initialState);
|
|
416
|
+
return getExecutableNodeBranchSuggestRuntimeNodes(leafParser, branchState$1, branchPath$1);
|
|
417
|
+
}
|
|
418
|
+
if (activeState?.result.success !== true) return parser.getSuggestRuntimeNodes?.(toExclusiveState(activeState, state), path) ?? [];
|
|
419
|
+
const branchParser = branchParsers[activeState.branch];
|
|
420
|
+
const branchPath = [...path, activeState.branch];
|
|
421
|
+
const branchState = (0, __optique_core_extension.inheritAnnotations)(state, activeState.result.next.state);
|
|
422
|
+
return getExecutableNodeBranchSuggestRuntimeNodes(branchParser, branchState, branchPath);
|
|
423
|
+
},
|
|
424
|
+
getDocFragments(state, defaultValue) {
|
|
425
|
+
const activeState = state.kind === "available" ? normalizeExecutableNodeState(state.state) : void 0;
|
|
426
|
+
const fragments = parser.getDocFragments(state.kind === "available" ? {
|
|
427
|
+
kind: "available",
|
|
428
|
+
state: toExclusiveState(activeState, state.state)
|
|
429
|
+
} : state, defaultValue);
|
|
430
|
+
if (activeState == null) return withCommandDocMetadata(fragments, commandDefinition.metadata);
|
|
431
|
+
return fragments;
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
if (phase2SeedHook != null) Object.defineProperty(executableParser, phase2SeedHook.key, {
|
|
435
|
+
value(state, exec) {
|
|
436
|
+
return extractExecutableNodePhase2Seed(state, exec, leafParser, phase2SeedHook);
|
|
437
|
+
},
|
|
438
|
+
configurable: true,
|
|
439
|
+
enumerable: true
|
|
440
|
+
});
|
|
441
|
+
return executableParser;
|
|
442
|
+
}
|
|
443
|
+
function getExecutableNodeBranchSuggestRuntimeNodes(parser, state, path) {
|
|
444
|
+
return parser.getSuggestRuntimeNodes?.(state, path) ?? (parser.dependencyMetadata?.source != null ? [{
|
|
445
|
+
path,
|
|
446
|
+
parser,
|
|
447
|
+
state
|
|
448
|
+
}] : []);
|
|
449
|
+
}
|
|
450
|
+
const phase2SeedSymbolDescription = "@optique/core/extractPhase2Seed";
|
|
451
|
+
function findPhase2SeedHook(parser) {
|
|
452
|
+
for (const key of Object.getOwnPropertySymbols(parser)) {
|
|
453
|
+
if (key.description !== phase2SeedSymbolDescription) continue;
|
|
454
|
+
const value = Reflect.get(parser, key);
|
|
455
|
+
if (typeof value !== "function") continue;
|
|
456
|
+
return {
|
|
457
|
+
key,
|
|
458
|
+
extract(state, exec) {
|
|
459
|
+
const seed = Reflect.apply(value, parser, [state, exec]);
|
|
460
|
+
return seed;
|
|
461
|
+
}
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
return void 0;
|
|
465
|
+
}
|
|
466
|
+
function completeExecutableNodeLeaf(state, exec, leafParser) {
|
|
467
|
+
const result = parseExecutableNodeLeaf(state, exec, leafParser);
|
|
468
|
+
return (0, __optique_core_extension.dispatchByMode)(leafParser.mode, () => (0, __optique_core_extension.wrapForMode)("sync", completeParsedExecutableNodeLeaf(state, exec, leafParser, (0, __optique_core_extension.wrapForMode)("sync", result))), () => Promise.resolve((0, __optique_core_extension.wrapForMode)("async", result)).then((resolved) => (0, __optique_core_extension.wrapForMode)("async", completeParsedExecutableNodeLeaf(state, exec, leafParser, resolved))));
|
|
469
|
+
}
|
|
470
|
+
function completeParsedExecutableNodeLeaf(state, exec, leafParser, result) {
|
|
471
|
+
const childExec = withExecutableNodeChildExecPath(exec, 1);
|
|
472
|
+
const nextExec = result.success ? mergeExecutableNodeChildExec(childExec, result.next.exec) : childExec;
|
|
473
|
+
const nextState = result.success ? (0, __optique_core_extension.inheritAnnotations)(state, result.next.state) : (0, __optique_core_extension.inheritAnnotations)(state, leafParser.initialState);
|
|
474
|
+
return leafParser.complete(nextState, nextExec);
|
|
475
|
+
}
|
|
476
|
+
function extractExecutableNodePhase2Seed(state, exec, leafParser, phase2SeedHook) {
|
|
477
|
+
const activeState = normalizeExecutableNodeState(state);
|
|
478
|
+
if (activeState != null) return phase2SeedHook.extract(toExclusiveState(activeState, state), exec);
|
|
479
|
+
const result = parseExecutableNodeLeaf(state, exec, leafParser);
|
|
480
|
+
return (0, __optique_core_extension.dispatchByMode)(leafParser.mode, () => extractParsedExecutableNodePhase2Seed(state, exec, (0, __optique_core_extension.wrapForMode)("sync", result), phase2SeedHook), () => Promise.resolve((0, __optique_core_extension.wrapForMode)("async", result)).then((resolved) => extractParsedExecutableNodePhase2Seed(state, exec, resolved, phase2SeedHook)));
|
|
481
|
+
}
|
|
482
|
+
function extractParsedExecutableNodePhase2Seed(state, exec, result, phase2SeedHook) {
|
|
483
|
+
if (!result.success) return phase2SeedHook.extract(toExclusiveState(void 0, state), exec);
|
|
484
|
+
const executableState = (0, __optique_core_extension.inheritAnnotations)(state, {
|
|
485
|
+
branch: 1,
|
|
486
|
+
result,
|
|
487
|
+
committed: false
|
|
488
|
+
});
|
|
489
|
+
return phase2SeedHook.extract(toExclusiveState(executableState, state), exec);
|
|
490
|
+
}
|
|
491
|
+
function parseExecutableNodeLeaf(state, exec, leafParser) {
|
|
492
|
+
const childExec = withExecutableNodeChildExecPath(exec, 1);
|
|
493
|
+
const childContext = {
|
|
494
|
+
buffer: [],
|
|
495
|
+
optionsTerminated: false,
|
|
496
|
+
usage: leafParser.usage,
|
|
497
|
+
state: (0, __optique_core_extension.inheritAnnotations)(state, leafParser.initialState),
|
|
498
|
+
...childExec != null ? {
|
|
499
|
+
exec: childExec,
|
|
500
|
+
dependencyRegistry: childExec.dependencyRegistry
|
|
501
|
+
} : {}
|
|
502
|
+
};
|
|
503
|
+
return leafParser.parse(childContext);
|
|
504
|
+
}
|
|
505
|
+
function normalizeExecutableNodeState(state) {
|
|
506
|
+
if (state == null || typeof state !== "object" || !("branch" in state) || !("result" in state)) return void 0;
|
|
507
|
+
const branch = state.branch;
|
|
508
|
+
if (branch !== 0 && branch !== 1) return void 0;
|
|
509
|
+
const result = state.result;
|
|
510
|
+
if (result == null || typeof result !== "object" || typeof result.success !== "boolean") return void 0;
|
|
511
|
+
return (0, __optique_core_extension.inheritAnnotations)(state, {
|
|
512
|
+
branch,
|
|
513
|
+
result,
|
|
514
|
+
committed: state.committed === true
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
function toExclusiveState(state, sourceState = state) {
|
|
518
|
+
const exclusiveState = state == null ? void 0 : [state.branch, state.result];
|
|
519
|
+
return (0, __optique_core_extension.inheritAnnotations)(sourceState, exclusiveState);
|
|
520
|
+
}
|
|
521
|
+
function fromExclusiveState(state) {
|
|
522
|
+
if (!Array.isArray(state) || state.length !== 2 || state[0] !== 0 && state[0] !== 1) return void 0;
|
|
523
|
+
return (0, __optique_core_extension.inheritAnnotations)(state, {
|
|
524
|
+
branch: state[0],
|
|
525
|
+
result: state[1],
|
|
526
|
+
committed: isCommittedResult(state[1])
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
function isCommittedResult(result) {
|
|
530
|
+
return result != null && typeof result === "object" && result.success === true && Array.isArray(result.consumed) && result.consumed.length > 0;
|
|
531
|
+
}
|
|
532
|
+
function wrapInitialParseResult(_context, result) {
|
|
533
|
+
if (!result.success) return result;
|
|
534
|
+
return {
|
|
535
|
+
success: true,
|
|
536
|
+
consumed: result.consumed,
|
|
537
|
+
provisional: result.provisional,
|
|
538
|
+
next: {
|
|
539
|
+
...result.next,
|
|
540
|
+
state: fromExclusiveState(result.next.state)
|
|
541
|
+
}
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
function wrapBranchParseResult(context, activeState, result) {
|
|
545
|
+
if (!result.success) return result;
|
|
546
|
+
const mergedExec = mergeExecutableNodeChildExec(context.exec, result.next.exec);
|
|
547
|
+
const dependencyRegistry = mergedExec?.dependencyRegistry ?? result.next.dependencyRegistry ?? context.dependencyRegistry;
|
|
548
|
+
const nextState = (0, __optique_core_extension.inheritAnnotations)(result.next.state, {
|
|
549
|
+
branch: activeState.branch,
|
|
550
|
+
result,
|
|
551
|
+
committed: activeState.committed || result.consumed.length > 0
|
|
552
|
+
});
|
|
553
|
+
return {
|
|
554
|
+
success: true,
|
|
555
|
+
consumed: result.consumed,
|
|
556
|
+
provisional: result.provisional,
|
|
557
|
+
next: {
|
|
558
|
+
...context,
|
|
559
|
+
buffer: result.next.buffer,
|
|
560
|
+
optionsTerminated: result.next.optionsTerminated,
|
|
561
|
+
state: (0, __optique_core_extension.inheritAnnotations)(context.state, nextState),
|
|
562
|
+
...mergedExec != null ? {
|
|
563
|
+
exec: mergedExec,
|
|
564
|
+
trace: mergedExec.trace
|
|
565
|
+
} : {},
|
|
566
|
+
...dependencyRegistry != null ? { dependencyRegistry } : {}
|
|
567
|
+
}
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
function withExecutableNodeChildContext(context, branch, state, parser) {
|
|
571
|
+
const exec = withExecutableNodeChildExecPath(context.exec, branch);
|
|
572
|
+
const dependencyRegistry = context.dependencyRegistry ?? exec?.dependencyRegistry;
|
|
573
|
+
return {
|
|
574
|
+
...context,
|
|
575
|
+
state,
|
|
576
|
+
usage: parser.usage,
|
|
577
|
+
...exec != null ? {
|
|
578
|
+
exec: dependencyRegistry === exec.dependencyRegistry ? exec : {
|
|
579
|
+
...exec,
|
|
580
|
+
dependencyRegistry
|
|
581
|
+
},
|
|
582
|
+
dependencyRegistry
|
|
583
|
+
} : {}
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
function withExecutableNodeChildExecPath(exec, branch) {
|
|
587
|
+
if (exec == null) return void 0;
|
|
588
|
+
return {
|
|
589
|
+
...exec,
|
|
590
|
+
path: [...exec.path ?? [], branch]
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
function mergeExecutableNodeChildExec(parent, child) {
|
|
594
|
+
if (parent == null) return child;
|
|
595
|
+
if (child == null) return parent;
|
|
596
|
+
return {
|
|
597
|
+
...parent,
|
|
598
|
+
trace: child.trace ?? parent.trace,
|
|
599
|
+
dependencyRuntime: child.dependencyRuntime ?? parent.dependencyRuntime,
|
|
600
|
+
dependencyRegistry: child.dependencyRegistry ?? parent.dependencyRegistry,
|
|
601
|
+
commandPath: child.commandPath ?? parent.commandPath,
|
|
602
|
+
preCompletedByParser: child.preCompletedByParser ?? parent.preCompletedByParser,
|
|
603
|
+
excludedSourceFields: child.excludedSourceFields ?? parent.excludedSourceFields
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
function withCommandDocMetadata(fragments, metadata) {
|
|
607
|
+
if (metadata == null) return fragments;
|
|
608
|
+
return {
|
|
609
|
+
...fragments,
|
|
610
|
+
brief: fragments.brief ?? metadata.brief,
|
|
611
|
+
description: fragments.description ?? metadata.description,
|
|
612
|
+
footer: fragments.footer ?? metadata.footer
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
function buildChildrenParser(node, inheritedHidden) {
|
|
277
616
|
const parsers = [];
|
|
278
617
|
for (const [name, child] of node.children) {
|
|
279
|
-
const
|
|
280
|
-
const
|
|
281
|
-
parsers.push((
|
|
618
|
+
const childHidden = (0, __optique_core_usage.mergeHidden)(inheritedHidden, child.command?.metadata?.hidden);
|
|
619
|
+
const childParser = buildNodeParser(child, childHidden);
|
|
620
|
+
if (child.children.size > 0) parsers.push(createNamespaceCommandParser(name, childParser, child.command, inheritedHidden));
|
|
621
|
+
else parsers.push((0, __optique_core_primitives.command)(name, childParser, commandMetadataWithInheritedHidden(child.command?.metadata, inheritedHidden)));
|
|
282
622
|
}
|
|
623
|
+
if (parsers.length < 1) return void 0;
|
|
283
624
|
if (parsers.length === 1) return parsers[0];
|
|
284
625
|
return (0, __optique_core_constructs.or)(...parsers);
|
|
285
626
|
}
|
|
286
|
-
function
|
|
287
|
-
|
|
627
|
+
function createNamespaceCommandParser(name, childParser, commandDefinition, inheritedHidden) {
|
|
628
|
+
const metadata = commandDefinition?.metadata;
|
|
629
|
+
const parser = (0, __optique_core_primitives.command)(name, childParser, namespaceCommandMetadata(metadata, inheritedHidden));
|
|
630
|
+
const description = metadata?.brief ?? metadata?.description;
|
|
631
|
+
if (description == null) return parser;
|
|
632
|
+
return {
|
|
633
|
+
...parser,
|
|
634
|
+
getDocFragments(state, defaultValue) {
|
|
635
|
+
const fragments = parser.getDocFragments(state, defaultValue);
|
|
636
|
+
if (state.kind !== "unavailable" && (state.kind !== "available" || !Object.is(state.state, parser.initialState))) return fragments;
|
|
637
|
+
return withNamespaceListDocDescription(fragments, name, description);
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
function withNamespaceListDocDescription(fragments, name, description) {
|
|
642
|
+
return {
|
|
643
|
+
...fragments,
|
|
644
|
+
fragments: fragments.fragments.map((fragment) => {
|
|
645
|
+
if (fragment.type !== "entry" || fragment.term.type !== "command" || fragment.term.name !== name) return fragment;
|
|
646
|
+
return {
|
|
647
|
+
...fragment,
|
|
648
|
+
description: fragment.description ?? description
|
|
649
|
+
};
|
|
650
|
+
})
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
function namespaceCommandMetadata(metadata, inheritedHidden) {
|
|
654
|
+
const hidden = (0, __optique_core_usage.mergeHidden)(inheritedHidden, metadata?.hidden);
|
|
655
|
+
if (metadata?.aliases == null && metadata?.errors == null && hidden == null && metadata?.usageLine == null) return void 0;
|
|
656
|
+
return {
|
|
657
|
+
...metadata?.aliases != null && { aliases: metadata.aliases },
|
|
658
|
+
...metadata?.errors != null && { errors: metadata.errors },
|
|
659
|
+
...hidden != null && { hidden },
|
|
660
|
+
...metadata?.usageLine != null && { usageLine: metadata.usageLine }
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
function commandMetadataWithInheritedHidden(metadata, inheritedHidden) {
|
|
664
|
+
const hidden = (0, __optique_core_usage.mergeHidden)(inheritedHidden, metadata?.hidden);
|
|
665
|
+
if (metadata == null) return hidden == null ? void 0 : { hidden };
|
|
666
|
+
if (hidden === metadata.hidden) return metadata;
|
|
667
|
+
return {
|
|
668
|
+
...metadata,
|
|
669
|
+
...hidden != null && { hidden }
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
function createLeafParser(commandDefinition, includeMetadata = false) {
|
|
673
|
+
const parser = (0, __optique_core_modifiers.map)(commandDefinition.parser, (value) => ({
|
|
288
674
|
command: commandDefinition,
|
|
289
675
|
value,
|
|
290
676
|
handler: commandDefinition.handler
|
|
291
677
|
}));
|
|
678
|
+
if (!includeMetadata) return parser;
|
|
679
|
+
return {
|
|
680
|
+
...parser,
|
|
681
|
+
getDocFragments(state, defaultValue) {
|
|
682
|
+
const fragments = parser.getDocFragments(state, defaultValue);
|
|
683
|
+
return withCommandDocMetadata(fragments, commandDefinition.metadata);
|
|
684
|
+
}
|
|
685
|
+
};
|
|
292
686
|
}
|
|
293
687
|
function withRootDocs(parser, commands, metadata) {
|
|
294
688
|
const rootState = parser.initialState;
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
fragments: [
|
|
689
|
+
const rootCommand = commands.find((entry) => entry.path.length < 1);
|
|
690
|
+
const listedCommands = commands.filter((entry) => entry.path.length > 0);
|
|
691
|
+
const commandsByPath = new Map(commands.map((entry) => [commandPathKey(entry.path), entry.command]));
|
|
692
|
+
const rootDocs = () => {
|
|
693
|
+
const fragments = [...rootCommand?.command.parser.getDocFragments({ kind: "unavailable" }).fragments ?? []];
|
|
694
|
+
if (listedCommands.length > 0) fragments.push({
|
|
300
695
|
type: "section",
|
|
301
|
-
entries:
|
|
696
|
+
entries: listedCommands.map((entry) => ({
|
|
302
697
|
term: {
|
|
303
698
|
type: "command",
|
|
304
699
|
name: entry.path.join(" "),
|
|
305
|
-
hidden: entry.
|
|
700
|
+
hidden: commandPathHidden(entry.path, commandsByPath)
|
|
306
701
|
},
|
|
307
702
|
description: entry.command.metadata?.brief ?? entry.command.metadata?.description
|
|
308
703
|
}))
|
|
309
|
-
}
|
|
310
|
-
|
|
704
|
+
});
|
|
705
|
+
return {
|
|
706
|
+
brief: metadata.brief,
|
|
707
|
+
description: metadata.description,
|
|
708
|
+
footer: metadata.footer,
|
|
709
|
+
fragments
|
|
710
|
+
};
|
|
711
|
+
};
|
|
311
712
|
return {
|
|
312
713
|
...parser,
|
|
313
714
|
getDocFragments(state, defaultValue) {
|
|
@@ -316,9 +717,14 @@ function withRootDocs(parser, commands, metadata) {
|
|
|
316
717
|
}
|
|
317
718
|
};
|
|
318
719
|
}
|
|
720
|
+
function commandPathHidden(path, commandsByPath) {
|
|
721
|
+
let hidden;
|
|
722
|
+
for (let length = 1; length <= path.length; length++) hidden = (0, __optique_core_usage.mergeHidden)(hidden, commandsByPath.get(commandPathKey(path.slice(0, length)))?.metadata?.hidden);
|
|
723
|
+
return hidden;
|
|
724
|
+
}
|
|
319
725
|
function buildRunOptions(options) {
|
|
320
726
|
const metadata = options.metadata;
|
|
321
|
-
const { dir: _dir, commands: _commands, extensions: _extensions, metadata: _metadata, help, version, completion,...rest } = options;
|
|
727
|
+
const { dir: _dir, commands: _commands, extensions: _extensions, entryFileName: _entryFileName, metadata: _metadata, help, version, completion,...rest } = options;
|
|
322
728
|
const runOptions = {
|
|
323
729
|
...rest,
|
|
324
730
|
contexts: unwrapProgramContexts(rest.contexts),
|
|
@@ -368,6 +774,7 @@ function isProgramInvocation(value) {
|
|
|
368
774
|
}
|
|
369
775
|
|
|
370
776
|
//#endregion
|
|
777
|
+
exports.commandsFromModules = commandsFromModules;
|
|
371
778
|
exports.createProgramParser = createProgramParser;
|
|
372
779
|
exports.defineCommand = require_command.defineCommand;
|
|
373
780
|
exports.discoverCommands = discoverCommands;
|