@optique/discover 1.1.0-dev.2160 → 1.2.0-dev.2167
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 +4 -0
- 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 +366 -45
- package/dist/index.d.cts +27 -4
- package/dist/index.d.ts +27 -4
- package/dist/index.js +367 -46
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -117,6 +117,10 @@ By default, Deno and Bun discover `.ts`, `.mts`, `.js`, and `.mjs` files.
|
|
|
117
117
|
Node.js discovers `.js`, `.mjs`, and `.cjs` files, plus `.ts`, `.mts`, and
|
|
118
118
|
`.cts` when it reports native TypeScript support or runs with a recognized
|
|
119
119
|
TypeScript loader. TypeScript declaration files such as `.d.ts` are ignored.
|
|
120
|
+
Entry files named `index` map to their containing command path, so
|
|
121
|
+
`commands/index.ts` defines the root command and `commands/user/index.ts`
|
|
122
|
+
defines `user`. Use `entryFileName` to choose another entry name or disable
|
|
123
|
+
this rule.
|
|
120
124
|
|
|
121
125
|
For more resources, see the [docs] and the [*examples/*](/examples/)
|
|
122
126
|
directory.
|
|
@@ -21,10 +21,10 @@ function isCommand(value) {
|
|
|
21
21
|
return value != null && typeof value === "object" && value[commandBrand] === true && (value.path == null || isCommandPath(value.path)) && isParser(value.parser) && typeof value.handler === "function";
|
|
22
22
|
}
|
|
23
23
|
function validateCommandPath(path) {
|
|
24
|
-
if (!isCommandPath(path)) throw new TypeError("Command path must be
|
|
24
|
+
if (!isCommandPath(path)) throw new TypeError("Command path must be an array of non-empty strings.");
|
|
25
25
|
}
|
|
26
26
|
function isCommandPath(path) {
|
|
27
|
-
return Array.isArray(path) && path.
|
|
27
|
+
return Array.isArray(path) && path.every((segment) => typeof segment === "string" && segment.length > 0);
|
|
28
28
|
}
|
|
29
29
|
function isParser(value) {
|
|
30
30
|
return value != null && typeof value === "object" && typeof value.parse === "function" && typeof value.complete === "function" && typeof value.suggest === "function" && typeof value.getDocFragments === "function" && (value.mode === "sync" || value.mode === "async");
|
|
@@ -20,10 +20,10 @@ function isCommand(value) {
|
|
|
20
20
|
return value != null && typeof value === "object" && value[commandBrand] === true && (value.path == null || isCommandPath(value.path)) && isParser(value.parser) && typeof value.handler === "function";
|
|
21
21
|
}
|
|
22
22
|
function validateCommandPath(path) {
|
|
23
|
-
if (!isCommandPath(path)) throw new TypeError("Command path must be
|
|
23
|
+
if (!isCommandPath(path)) throw new TypeError("Command path must be an array of non-empty strings.");
|
|
24
24
|
}
|
|
25
25
|
function isCommandPath(path) {
|
|
26
|
-
return Array.isArray(path) && path.
|
|
26
|
+
return Array.isArray(path) && path.every((segment) => typeof segment === "string" && segment.length > 0);
|
|
27
27
|
}
|
|
28
28
|
function isParser(value) {
|
|
29
29
|
return value != null && typeof value === "object" && typeof value.parse === "function" && typeof value.complete === "function" && typeof value.suggest === "function" && typeof value.getDocFragments === "function" && (value.mode === "sync" || value.mode === "async");
|
|
@@ -14,11 +14,13 @@ declare const commandBrand: unique symbol;
|
|
|
14
14
|
*/
|
|
15
15
|
type CommandMetadata = CommandOptions;
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
17
|
+
* Command path used by static command registration.
|
|
18
|
+
*
|
|
19
|
+
* An empty path represents the root command.
|
|
18
20
|
*
|
|
19
21
|
* @since 1.1.0
|
|
20
22
|
*/
|
|
21
|
-
type CommandPath = readonly
|
|
23
|
+
type CommandPath = readonly string[];
|
|
22
24
|
/**
|
|
23
25
|
* Input accepted by {@link defineCommand}.
|
|
24
26
|
*
|
|
@@ -29,6 +31,7 @@ type CommandPath = readonly [string, ...string[]];
|
|
|
29
31
|
interface CommandDefinition<M extends Mode, T> {
|
|
30
32
|
/**
|
|
31
33
|
* Command path used when commands are passed directly to `runProgram()`.
|
|
34
|
+
* Use an empty path (`[]`) to register the root command.
|
|
32
35
|
*
|
|
33
36
|
* File-based discovery derives the command path from the file name and uses
|
|
34
37
|
* this field only to validate that the declared path matches.
|
|
@@ -14,11 +14,13 @@ declare const commandBrand: unique symbol;
|
|
|
14
14
|
*/
|
|
15
15
|
type CommandMetadata = CommandOptions;
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
17
|
+
* Command path used by static command registration.
|
|
18
|
+
*
|
|
19
|
+
* An empty path represents the root command.
|
|
18
20
|
*
|
|
19
21
|
* @since 1.1.0
|
|
20
22
|
*/
|
|
21
|
-
type CommandPath = readonly
|
|
23
|
+
type CommandPath = readonly string[];
|
|
22
24
|
/**
|
|
23
25
|
* Input accepted by {@link defineCommand}.
|
|
24
26
|
*
|
|
@@ -29,6 +31,7 @@ type CommandPath = readonly [string, ...string[]];
|
|
|
29
31
|
interface CommandDefinition<M extends Mode, T> {
|
|
30
32
|
/**
|
|
31
33
|
* Command path used when commands are passed directly to `runProgram()`.
|
|
34
|
+
* Use an empty path (`[]`) to register the root command.
|
|
32
35
|
*
|
|
33
36
|
* File-based discovery derives the command path from the file name and uses
|
|
34
37
|
* this field only to validate that the declared path matches.
|
package/dist/command.cjs
CHANGED
package/dist/command.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { AnyCommand, AnyStaticCommand, Command, CommandDefinition, CommandMetadata, CommandPath, StaticCommand, defineCommand, isCommand } from "./command-
|
|
1
|
+
import { AnyCommand, AnyStaticCommand, Command, CommandDefinition, CommandMetadata, CommandPath, StaticCommand, defineCommand, isCommand } from "./command-DSHBTa5c.cjs";
|
|
2
2
|
export { AnyCommand, AnyStaticCommand, Command, CommandDefinition, CommandMetadata, CommandPath, StaticCommand, defineCommand, isCommand };
|
package/dist/command.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { AnyCommand, AnyStaticCommand, Command, CommandDefinition, CommandMetadata, CommandPath, StaticCommand, defineCommand, isCommand } from "./command-
|
|
1
|
+
import { AnyCommand, AnyStaticCommand, Command, CommandDefinition, CommandMetadata, CommandPath, StaticCommand, defineCommand, isCommand } from "./command-DyiVIMUh.js";
|
|
2
2
|
export { AnyCommand, AnyStaticCommand, Command, CommandDefinition, CommandMetadata, CommandPath, StaticCommand, defineCommand, isCommand };
|
package/dist/command.js
CHANGED
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,37 @@ 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
88
|
const commandDefinition = unwrapCommandExport(mod.default);
|
|
86
89
|
if (commandDefinition == null) throw new TypeError(`Module ${filePath} default export must be created with defineCommand().`);
|
|
87
|
-
if (commandDefinition.path != null && commandPathKey(commandDefinition.path) !== commandPathKey(path)) throw new TypeError(`Module ${filePath} declares command path "${commandDefinition.path
|
|
90
|
+
if (commandDefinition.path != null && commandPathKey(commandDefinition.path) !== commandPathKey(path)) throw new TypeError(`Module ${filePath} declares command path "${displayCommandPath(commandDefinition.path)}" but file path defines "${displayCommandPath(path)}".`);
|
|
88
91
|
discovered.push({
|
|
89
92
|
path,
|
|
90
93
|
filePath,
|
|
91
94
|
command: commandDefinition
|
|
92
95
|
});
|
|
93
96
|
}
|
|
94
|
-
rejectPathConflicts(discovered);
|
|
95
97
|
return sortCommands(discovered);
|
|
96
98
|
}
|
|
97
99
|
/**
|
|
@@ -100,7 +102,8 @@ async function discoverCommands(options) {
|
|
|
100
102
|
* @param commands Commands to compose.
|
|
101
103
|
* @param metadata Optional root documentation metadata.
|
|
102
104
|
* @returns A parser that resolves to an internal command invocation.
|
|
103
|
-
* @throws {TypeError} If no commands are provided or command paths
|
|
105
|
+
* @throws {TypeError} If no commands are provided or command paths are
|
|
106
|
+
* duplicated.
|
|
104
107
|
* @since 1.1.0
|
|
105
108
|
*/
|
|
106
109
|
function createProgramParser(commands, metadata = {}) {
|
|
@@ -108,11 +111,7 @@ function createProgramParser(commands, metadata = {}) {
|
|
|
108
111
|
const sortedCommands = sortCommands(commands);
|
|
109
112
|
rejectDuplicatePaths(sortedCommands.map((entry) => ({
|
|
110
113
|
path: entry.path,
|
|
111
|
-
filePath: entry.path
|
|
112
|
-
})));
|
|
113
|
-
rejectPathConflicts(sortedCommands.map((entry) => ({
|
|
114
|
-
path: entry.path,
|
|
115
|
-
filePath: entry.path.join("/")
|
|
114
|
+
filePath: displayCommandPath(entry.path)
|
|
116
115
|
})));
|
|
117
116
|
const rootNode = buildCommandTree(sortedCommands);
|
|
118
117
|
const parser = buildNodeParser(rootNode);
|
|
@@ -132,7 +131,8 @@ async function runProgram(options) {
|
|
|
132
131
|
if (isStaticRunProgramOptions(options)) commands = staticCommandsToEntries(options.commands);
|
|
133
132
|
else commands = await discoverCommands({
|
|
134
133
|
dir: options.dir,
|
|
135
|
-
extensions: options.extensions
|
|
134
|
+
extensions: options.extensions,
|
|
135
|
+
entryFileName: options.entryFileName
|
|
136
136
|
});
|
|
137
137
|
const parser = createProgramParser(commands, options.metadata);
|
|
138
138
|
const invocation = await (0, __optique_run.runAsync)(parser, buildRunOptions(options));
|
|
@@ -163,6 +163,14 @@ function normalizeExtensions(extensions) {
|
|
|
163
163
|
}
|
|
164
164
|
return normalized.toSorted((a, b) => b.length - a.length || a.localeCompare(b));
|
|
165
165
|
}
|
|
166
|
+
function normalizeEntryFileName(entryFileName) {
|
|
167
|
+
if (entryFileName === void 0) return "index";
|
|
168
|
+
if (entryFileName === false) return false;
|
|
169
|
+
if (typeof entryFileName !== "string") throw new TypeError(`Command entry file name must be a non-empty file name: ${entryFileName}`);
|
|
170
|
+
const normalized = entryFileName;
|
|
171
|
+
if (normalized.length < 1 || normalized.includes("/") || normalized.includes("\\")) throw new TypeError(`Command entry file name must be a non-empty file name: ${normalized}`);
|
|
172
|
+
return normalized;
|
|
173
|
+
}
|
|
166
174
|
async function collectCommandFiles(dir, extensions, activeDirs = /* @__PURE__ */ new Set()) {
|
|
167
175
|
const canonicalDir = await (0, node_fs_promises.realpath)(dir);
|
|
168
176
|
if (activeDirs.has(canonicalDir)) return [];
|
|
@@ -194,29 +202,24 @@ async function getCommandFileEntryType(path, entry) {
|
|
|
194
202
|
function isDeclarationFile(fileName) {
|
|
195
203
|
return /\.d\.[cm]?ts$/.test(fileName);
|
|
196
204
|
}
|
|
197
|
-
function commandPathFromFile(rootDir, filePath, extensions) {
|
|
205
|
+
function commandPathFromFile(rootDir, filePath, extensions, entryFileName) {
|
|
198
206
|
const matchedExtension = extensions.find((ext) => filePath.endsWith(ext));
|
|
199
207
|
if (matchedExtension == null) throw new TypeError(`No configured extension matches ${filePath}.`);
|
|
200
208
|
const withoutExtension = filePath.slice(0, -matchedExtension.length);
|
|
201
209
|
const relativePath = (0, node_path.relative)(rootDir, withoutExtension);
|
|
202
210
|
const path = relativePath.split(node_path.sep).filter((segment) => segment.length > 0);
|
|
203
|
-
|
|
204
|
-
if (
|
|
205
|
-
return
|
|
211
|
+
if (path.length < 1) throw new TypeError(`Command file ${filePath} does not define a path.`);
|
|
212
|
+
if (entryFileName !== false && path[path.length - 1] === entryFileName) return path.slice(0, -1);
|
|
213
|
+
return path;
|
|
206
214
|
}
|
|
207
215
|
function commandPathKey(path) {
|
|
208
216
|
return path.join("\0");
|
|
209
217
|
}
|
|
218
|
+
function displayCommandPath(path) {
|
|
219
|
+
return path.length < 1 ? "<root>" : path.join(" ");
|
|
220
|
+
}
|
|
210
221
|
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
|
-
}
|
|
222
|
+
return Array.isArray(path) && path.every((segment) => typeof segment === "string" && segment.length > 0);
|
|
220
223
|
}
|
|
221
224
|
function rejectDuplicatePaths(commands) {
|
|
222
225
|
const seen = /* @__PURE__ */ new Map();
|
|
@@ -224,7 +227,7 @@ function rejectDuplicatePaths(commands) {
|
|
|
224
227
|
const key = commandPathKey(entry.path);
|
|
225
228
|
const previous = seen.get(key);
|
|
226
229
|
if (previous != null) {
|
|
227
|
-
const displayPath = entry.path
|
|
230
|
+
const displayPath = displayCommandPath(entry.path);
|
|
228
231
|
throw new TypeError(`Duplicate command path "${displayPath}" from ${previous} and ${entry.filePath}.`);
|
|
229
232
|
}
|
|
230
233
|
seen.set(key, entry.filePath);
|
|
@@ -242,7 +245,7 @@ function isStaticRunProgramOptions(options) {
|
|
|
242
245
|
function staticCommandsToEntries(commands) {
|
|
243
246
|
return commands.map((command$1) => {
|
|
244
247
|
if (!require_command.isCommand(command$1)) throw new TypeError("Static command entries must be created with defineCommand().");
|
|
245
|
-
if (!isCommandPath(command$1.path)) throw new TypeError("Static command entries must declare a
|
|
248
|
+
if (!isCommandPath(command$1.path)) throw new TypeError("Static command entries must declare a path.");
|
|
246
249
|
return {
|
|
247
250
|
path: command$1.path,
|
|
248
251
|
command: command$1
|
|
@@ -273,41 +276,354 @@ function buildCommandTree(commands) {
|
|
|
273
276
|
}
|
|
274
277
|
return root;
|
|
275
278
|
}
|
|
276
|
-
function buildNodeParser(node) {
|
|
279
|
+
function buildNodeParser(node, inheritedHidden) {
|
|
280
|
+
const childParser = buildChildrenParser(node, inheritedHidden);
|
|
281
|
+
if (childParser != null && node.command != null) return createExecutableNodeParser(childParser, node.command);
|
|
282
|
+
if (childParser != null) return childParser;
|
|
283
|
+
if (node.command != null) return createLeafParser(node.command);
|
|
284
|
+
throw new TypeError("Command tree node must contain a command.");
|
|
285
|
+
}
|
|
286
|
+
function createExecutableNodeParser(childParser, commandDefinition) {
|
|
287
|
+
const leafParser = createLeafParser(commandDefinition, true);
|
|
288
|
+
const branchParsers = [childParser, leafParser];
|
|
289
|
+
const parser = (0, __optique_core_constructs.longestMatch)(childParser, leafParser);
|
|
290
|
+
const phase2SeedHook = findPhase2SeedHook(parser);
|
|
291
|
+
const executableParser = {
|
|
292
|
+
...parser,
|
|
293
|
+
$valueType: [],
|
|
294
|
+
$stateType: [],
|
|
295
|
+
initialState: void 0,
|
|
296
|
+
parse(context) {
|
|
297
|
+
const activeState = normalizeExecutableNodeState(context.state);
|
|
298
|
+
if (activeState?.committed === true && activeState.result.success) {
|
|
299
|
+
const branchParser = branchParsers[activeState.branch];
|
|
300
|
+
const result$1 = branchParser.parse(withExecutableNodeChildContext(context, activeState.branch, (0, __optique_core_extension.inheritAnnotations)(context.state, activeState.result.next.state), branchParser));
|
|
301
|
+
return (0, __optique_core_extension.mapModeValue)(parser.mode, (0, __optique_core_extension.wrapForMode)(parser.mode, result$1), (resolved) => wrapBranchParseResult(context, activeState, resolved));
|
|
302
|
+
}
|
|
303
|
+
const result = parser.parse({
|
|
304
|
+
...context,
|
|
305
|
+
state: toExclusiveState(activeState, context.state)
|
|
306
|
+
});
|
|
307
|
+
return (0, __optique_core_extension.mapModeValue)(parser.mode, (0, __optique_core_extension.wrapForMode)(parser.mode, result), (resolved) => wrapInitialParseResult(context, resolved));
|
|
308
|
+
},
|
|
309
|
+
complete(state, exec) {
|
|
310
|
+
const activeState = normalizeExecutableNodeState(state);
|
|
311
|
+
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)));
|
|
312
|
+
if (activeState == null) return (0, __optique_core_extension.wrapForMode)(parser.mode, completeExecutableNodeLeaf(state, exec, leafParser));
|
|
313
|
+
return (0, __optique_core_extension.wrapForMode)(parser.mode, parser.complete(toExclusiveState(activeState, state), exec));
|
|
314
|
+
},
|
|
315
|
+
suggest(context, prefix) {
|
|
316
|
+
const activeState = normalizeExecutableNodeState(context.state);
|
|
317
|
+
if (activeState?.committed === true && activeState.result.success) {
|
|
318
|
+
const branchParser = branchParsers[activeState.branch];
|
|
319
|
+
return branchParser.suggest(withExecutableNodeChildContext(context, activeState.branch, (0, __optique_core_extension.inheritAnnotations)(context.state, activeState.result.next.state), branchParser), prefix);
|
|
320
|
+
}
|
|
321
|
+
return parser.suggest({
|
|
322
|
+
...context,
|
|
323
|
+
state: toExclusiveState(activeState, context.state)
|
|
324
|
+
}, prefix);
|
|
325
|
+
},
|
|
326
|
+
getSuggestRuntimeNodes(state, path) {
|
|
327
|
+
const activeState = normalizeExecutableNodeState(state);
|
|
328
|
+
if (activeState == null) {
|
|
329
|
+
const branchPath$1 = [...path, 1];
|
|
330
|
+
const branchState$1 = (0, __optique_core_extension.inheritAnnotations)(state, leafParser.initialState);
|
|
331
|
+
return getExecutableNodeBranchSuggestRuntimeNodes(leafParser, branchState$1, branchPath$1);
|
|
332
|
+
}
|
|
333
|
+
if (activeState?.result.success !== true) return parser.getSuggestRuntimeNodes?.(toExclusiveState(activeState, state), path) ?? [];
|
|
334
|
+
const branchParser = branchParsers[activeState.branch];
|
|
335
|
+
const branchPath = [...path, activeState.branch];
|
|
336
|
+
const branchState = (0, __optique_core_extension.inheritAnnotations)(state, activeState.result.next.state);
|
|
337
|
+
return getExecutableNodeBranchSuggestRuntimeNodes(branchParser, branchState, branchPath);
|
|
338
|
+
},
|
|
339
|
+
getDocFragments(state, defaultValue) {
|
|
340
|
+
const activeState = state.kind === "available" ? normalizeExecutableNodeState(state.state) : void 0;
|
|
341
|
+
const fragments = parser.getDocFragments(state.kind === "available" ? {
|
|
342
|
+
kind: "available",
|
|
343
|
+
state: toExclusiveState(activeState, state.state)
|
|
344
|
+
} : state, defaultValue);
|
|
345
|
+
if (activeState == null) return withCommandDocMetadata(fragments, commandDefinition.metadata);
|
|
346
|
+
return fragments;
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
if (phase2SeedHook != null) Object.defineProperty(executableParser, phase2SeedHook.key, {
|
|
350
|
+
value(state, exec) {
|
|
351
|
+
return extractExecutableNodePhase2Seed(state, exec, leafParser, phase2SeedHook);
|
|
352
|
+
},
|
|
353
|
+
configurable: true,
|
|
354
|
+
enumerable: true
|
|
355
|
+
});
|
|
356
|
+
return executableParser;
|
|
357
|
+
}
|
|
358
|
+
function getExecutableNodeBranchSuggestRuntimeNodes(parser, state, path) {
|
|
359
|
+
return parser.getSuggestRuntimeNodes?.(state, path) ?? (parser.dependencyMetadata?.source != null ? [{
|
|
360
|
+
path,
|
|
361
|
+
parser,
|
|
362
|
+
state
|
|
363
|
+
}] : []);
|
|
364
|
+
}
|
|
365
|
+
const phase2SeedSymbolDescription = "@optique/core/extractPhase2Seed";
|
|
366
|
+
function findPhase2SeedHook(parser) {
|
|
367
|
+
for (const key of Object.getOwnPropertySymbols(parser)) {
|
|
368
|
+
if (key.description !== phase2SeedSymbolDescription) continue;
|
|
369
|
+
const value = Reflect.get(parser, key);
|
|
370
|
+
if (typeof value !== "function") continue;
|
|
371
|
+
return {
|
|
372
|
+
key,
|
|
373
|
+
extract(state, exec) {
|
|
374
|
+
const seed = Reflect.apply(value, parser, [state, exec]);
|
|
375
|
+
return seed;
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
return void 0;
|
|
380
|
+
}
|
|
381
|
+
function completeExecutableNodeLeaf(state, exec, leafParser) {
|
|
382
|
+
const result = parseExecutableNodeLeaf(state, exec, leafParser);
|
|
383
|
+
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))));
|
|
384
|
+
}
|
|
385
|
+
function completeParsedExecutableNodeLeaf(state, exec, leafParser, result) {
|
|
386
|
+
const childExec = withExecutableNodeChildExecPath(exec, 1);
|
|
387
|
+
const nextExec = result.success ? mergeExecutableNodeChildExec(childExec, result.next.exec) : childExec;
|
|
388
|
+
const nextState = result.success ? (0, __optique_core_extension.inheritAnnotations)(state, result.next.state) : (0, __optique_core_extension.inheritAnnotations)(state, leafParser.initialState);
|
|
389
|
+
return leafParser.complete(nextState, nextExec);
|
|
390
|
+
}
|
|
391
|
+
function extractExecutableNodePhase2Seed(state, exec, leafParser, phase2SeedHook) {
|
|
392
|
+
const activeState = normalizeExecutableNodeState(state);
|
|
393
|
+
if (activeState != null) return phase2SeedHook.extract(toExclusiveState(activeState, state), exec);
|
|
394
|
+
const result = parseExecutableNodeLeaf(state, exec, leafParser);
|
|
395
|
+
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)));
|
|
396
|
+
}
|
|
397
|
+
function extractParsedExecutableNodePhase2Seed(state, exec, result, phase2SeedHook) {
|
|
398
|
+
if (!result.success) return phase2SeedHook.extract(toExclusiveState(void 0, state), exec);
|
|
399
|
+
const executableState = (0, __optique_core_extension.inheritAnnotations)(state, {
|
|
400
|
+
branch: 1,
|
|
401
|
+
result,
|
|
402
|
+
committed: false
|
|
403
|
+
});
|
|
404
|
+
return phase2SeedHook.extract(toExclusiveState(executableState, state), exec);
|
|
405
|
+
}
|
|
406
|
+
function parseExecutableNodeLeaf(state, exec, leafParser) {
|
|
407
|
+
const childExec = withExecutableNodeChildExecPath(exec, 1);
|
|
408
|
+
const childContext = {
|
|
409
|
+
buffer: [],
|
|
410
|
+
optionsTerminated: false,
|
|
411
|
+
usage: leafParser.usage,
|
|
412
|
+
state: (0, __optique_core_extension.inheritAnnotations)(state, leafParser.initialState),
|
|
413
|
+
...childExec != null ? {
|
|
414
|
+
exec: childExec,
|
|
415
|
+
dependencyRegistry: childExec.dependencyRegistry
|
|
416
|
+
} : {}
|
|
417
|
+
};
|
|
418
|
+
return leafParser.parse(childContext);
|
|
419
|
+
}
|
|
420
|
+
function normalizeExecutableNodeState(state) {
|
|
421
|
+
if (state == null || typeof state !== "object" || !("branch" in state) || !("result" in state)) return void 0;
|
|
422
|
+
const branch = state.branch;
|
|
423
|
+
if (branch !== 0 && branch !== 1) return void 0;
|
|
424
|
+
const result = state.result;
|
|
425
|
+
if (result == null || typeof result !== "object" || typeof result.success !== "boolean") return void 0;
|
|
426
|
+
return (0, __optique_core_extension.inheritAnnotations)(state, {
|
|
427
|
+
branch,
|
|
428
|
+
result,
|
|
429
|
+
committed: state.committed === true
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
function toExclusiveState(state, sourceState = state) {
|
|
433
|
+
const exclusiveState = state == null ? void 0 : [state.branch, state.result];
|
|
434
|
+
return (0, __optique_core_extension.inheritAnnotations)(sourceState, exclusiveState);
|
|
435
|
+
}
|
|
436
|
+
function fromExclusiveState(state) {
|
|
437
|
+
if (!Array.isArray(state) || state.length !== 2 || state[0] !== 0 && state[0] !== 1) return void 0;
|
|
438
|
+
return (0, __optique_core_extension.inheritAnnotations)(state, {
|
|
439
|
+
branch: state[0],
|
|
440
|
+
result: state[1],
|
|
441
|
+
committed: isCommittedResult(state[1])
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
function isCommittedResult(result) {
|
|
445
|
+
return result != null && typeof result === "object" && result.success === true && Array.isArray(result.consumed) && result.consumed.length > 0;
|
|
446
|
+
}
|
|
447
|
+
function wrapInitialParseResult(_context, result) {
|
|
448
|
+
if (!result.success) return result;
|
|
449
|
+
return {
|
|
450
|
+
success: true,
|
|
451
|
+
consumed: result.consumed,
|
|
452
|
+
provisional: result.provisional,
|
|
453
|
+
next: {
|
|
454
|
+
...result.next,
|
|
455
|
+
state: fromExclusiveState(result.next.state)
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
function wrapBranchParseResult(context, activeState, result) {
|
|
460
|
+
if (!result.success) return result;
|
|
461
|
+
const mergedExec = mergeExecutableNodeChildExec(context.exec, result.next.exec);
|
|
462
|
+
const dependencyRegistry = mergedExec?.dependencyRegistry ?? result.next.dependencyRegistry ?? context.dependencyRegistry;
|
|
463
|
+
const nextState = (0, __optique_core_extension.inheritAnnotations)(result.next.state, {
|
|
464
|
+
branch: activeState.branch,
|
|
465
|
+
result,
|
|
466
|
+
committed: activeState.committed || result.consumed.length > 0
|
|
467
|
+
});
|
|
468
|
+
return {
|
|
469
|
+
success: true,
|
|
470
|
+
consumed: result.consumed,
|
|
471
|
+
provisional: result.provisional,
|
|
472
|
+
next: {
|
|
473
|
+
...context,
|
|
474
|
+
buffer: result.next.buffer,
|
|
475
|
+
optionsTerminated: result.next.optionsTerminated,
|
|
476
|
+
state: (0, __optique_core_extension.inheritAnnotations)(context.state, nextState),
|
|
477
|
+
...mergedExec != null ? {
|
|
478
|
+
exec: mergedExec,
|
|
479
|
+
trace: mergedExec.trace
|
|
480
|
+
} : {},
|
|
481
|
+
...dependencyRegistry != null ? { dependencyRegistry } : {}
|
|
482
|
+
}
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
function withExecutableNodeChildContext(context, branch, state, parser) {
|
|
486
|
+
const exec = withExecutableNodeChildExecPath(context.exec, branch);
|
|
487
|
+
const dependencyRegistry = context.dependencyRegistry ?? exec?.dependencyRegistry;
|
|
488
|
+
return {
|
|
489
|
+
...context,
|
|
490
|
+
state,
|
|
491
|
+
usage: parser.usage,
|
|
492
|
+
...exec != null ? {
|
|
493
|
+
exec: dependencyRegistry === exec.dependencyRegistry ? exec : {
|
|
494
|
+
...exec,
|
|
495
|
+
dependencyRegistry
|
|
496
|
+
},
|
|
497
|
+
dependencyRegistry
|
|
498
|
+
} : {}
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
function withExecutableNodeChildExecPath(exec, branch) {
|
|
502
|
+
if (exec == null) return void 0;
|
|
503
|
+
return {
|
|
504
|
+
...exec,
|
|
505
|
+
path: [...exec.path ?? [], branch]
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
function mergeExecutableNodeChildExec(parent, child) {
|
|
509
|
+
if (parent == null) return child;
|
|
510
|
+
if (child == null) return parent;
|
|
511
|
+
return {
|
|
512
|
+
...parent,
|
|
513
|
+
trace: child.trace ?? parent.trace,
|
|
514
|
+
dependencyRuntime: child.dependencyRuntime ?? parent.dependencyRuntime,
|
|
515
|
+
dependencyRegistry: child.dependencyRegistry ?? parent.dependencyRegistry,
|
|
516
|
+
commandPath: child.commandPath ?? parent.commandPath,
|
|
517
|
+
preCompletedByParser: child.preCompletedByParser ?? parent.preCompletedByParser,
|
|
518
|
+
excludedSourceFields: child.excludedSourceFields ?? parent.excludedSourceFields
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
function withCommandDocMetadata(fragments, metadata) {
|
|
522
|
+
if (metadata == null) return fragments;
|
|
523
|
+
return {
|
|
524
|
+
...fragments,
|
|
525
|
+
brief: fragments.brief ?? metadata.brief,
|
|
526
|
+
description: fragments.description ?? metadata.description,
|
|
527
|
+
footer: fragments.footer ?? metadata.footer
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
function buildChildrenParser(node, inheritedHidden) {
|
|
277
531
|
const parsers = [];
|
|
278
532
|
for (const [name, child] of node.children) {
|
|
279
|
-
const
|
|
280
|
-
const
|
|
281
|
-
parsers.push((
|
|
533
|
+
const childHidden = (0, __optique_core_usage.mergeHidden)(inheritedHidden, child.command?.metadata?.hidden);
|
|
534
|
+
const childParser = buildNodeParser(child, childHidden);
|
|
535
|
+
if (child.children.size > 0) parsers.push(createNamespaceCommandParser(name, childParser, child.command, inheritedHidden));
|
|
536
|
+
else parsers.push((0, __optique_core_primitives.command)(name, childParser, commandMetadataWithInheritedHidden(child.command?.metadata, inheritedHidden)));
|
|
282
537
|
}
|
|
538
|
+
if (parsers.length < 1) return void 0;
|
|
283
539
|
if (parsers.length === 1) return parsers[0];
|
|
284
540
|
return (0, __optique_core_constructs.or)(...parsers);
|
|
285
541
|
}
|
|
286
|
-
function
|
|
287
|
-
|
|
542
|
+
function createNamespaceCommandParser(name, childParser, commandDefinition, inheritedHidden) {
|
|
543
|
+
const metadata = commandDefinition?.metadata;
|
|
544
|
+
const parser = (0, __optique_core_primitives.command)(name, childParser, namespaceCommandMetadata(metadata, inheritedHidden));
|
|
545
|
+
const description = metadata?.brief ?? metadata?.description;
|
|
546
|
+
if (description == null) return parser;
|
|
547
|
+
return {
|
|
548
|
+
...parser,
|
|
549
|
+
getDocFragments(state, defaultValue) {
|
|
550
|
+
const fragments = parser.getDocFragments(state, defaultValue);
|
|
551
|
+
if (state.kind !== "unavailable" && (state.kind !== "available" || !Object.is(state.state, parser.initialState))) return fragments;
|
|
552
|
+
return withNamespaceListDocDescription(fragments, name, description);
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
function withNamespaceListDocDescription(fragments, name, description) {
|
|
557
|
+
return {
|
|
558
|
+
...fragments,
|
|
559
|
+
fragments: fragments.fragments.map((fragment) => {
|
|
560
|
+
if (fragment.type !== "entry" || fragment.term.type !== "command" || fragment.term.name !== name) return fragment;
|
|
561
|
+
return {
|
|
562
|
+
...fragment,
|
|
563
|
+
description: fragment.description ?? description
|
|
564
|
+
};
|
|
565
|
+
})
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
function namespaceCommandMetadata(metadata, inheritedHidden) {
|
|
569
|
+
const hidden = (0, __optique_core_usage.mergeHidden)(inheritedHidden, metadata?.hidden);
|
|
570
|
+
if (metadata?.aliases == null && metadata?.errors == null && hidden == null && metadata?.usageLine == null) return void 0;
|
|
571
|
+
return {
|
|
572
|
+
...metadata?.aliases != null && { aliases: metadata.aliases },
|
|
573
|
+
...metadata?.errors != null && { errors: metadata.errors },
|
|
574
|
+
...hidden != null && { hidden },
|
|
575
|
+
...metadata?.usageLine != null && { usageLine: metadata.usageLine }
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
function commandMetadataWithInheritedHidden(metadata, inheritedHidden) {
|
|
579
|
+
const hidden = (0, __optique_core_usage.mergeHidden)(inheritedHidden, metadata?.hidden);
|
|
580
|
+
if (metadata == null) return hidden == null ? void 0 : { hidden };
|
|
581
|
+
if (hidden === metadata.hidden) return metadata;
|
|
582
|
+
return {
|
|
583
|
+
...metadata,
|
|
584
|
+
...hidden != null && { hidden }
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
function createLeafParser(commandDefinition, includeMetadata = false) {
|
|
588
|
+
const parser = (0, __optique_core_modifiers.map)(commandDefinition.parser, (value) => ({
|
|
288
589
|
command: commandDefinition,
|
|
289
590
|
value,
|
|
290
591
|
handler: commandDefinition.handler
|
|
291
592
|
}));
|
|
593
|
+
if (!includeMetadata) return parser;
|
|
594
|
+
return {
|
|
595
|
+
...parser,
|
|
596
|
+
getDocFragments(state, defaultValue) {
|
|
597
|
+
const fragments = parser.getDocFragments(state, defaultValue);
|
|
598
|
+
return withCommandDocMetadata(fragments, commandDefinition.metadata);
|
|
599
|
+
}
|
|
600
|
+
};
|
|
292
601
|
}
|
|
293
602
|
function withRootDocs(parser, commands, metadata) {
|
|
294
603
|
const rootState = parser.initialState;
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
fragments: [
|
|
604
|
+
const rootCommand = commands.find((entry) => entry.path.length < 1);
|
|
605
|
+
const listedCommands = commands.filter((entry) => entry.path.length > 0);
|
|
606
|
+
const commandsByPath = new Map(commands.map((entry) => [commandPathKey(entry.path), entry.command]));
|
|
607
|
+
const rootDocs = () => {
|
|
608
|
+
const fragments = [...rootCommand?.command.parser.getDocFragments({ kind: "unavailable" }).fragments ?? []];
|
|
609
|
+
if (listedCommands.length > 0) fragments.push({
|
|
300
610
|
type: "section",
|
|
301
|
-
entries:
|
|
611
|
+
entries: listedCommands.map((entry) => ({
|
|
302
612
|
term: {
|
|
303
613
|
type: "command",
|
|
304
614
|
name: entry.path.join(" "),
|
|
305
|
-
hidden: entry.
|
|
615
|
+
hidden: commandPathHidden(entry.path, commandsByPath)
|
|
306
616
|
},
|
|
307
617
|
description: entry.command.metadata?.brief ?? entry.command.metadata?.description
|
|
308
618
|
}))
|
|
309
|
-
}
|
|
310
|
-
|
|
619
|
+
});
|
|
620
|
+
return {
|
|
621
|
+
brief: metadata.brief,
|
|
622
|
+
description: metadata.description,
|
|
623
|
+
footer: metadata.footer,
|
|
624
|
+
fragments
|
|
625
|
+
};
|
|
626
|
+
};
|
|
311
627
|
return {
|
|
312
628
|
...parser,
|
|
313
629
|
getDocFragments(state, defaultValue) {
|
|
@@ -316,9 +632,14 @@ function withRootDocs(parser, commands, metadata) {
|
|
|
316
632
|
}
|
|
317
633
|
};
|
|
318
634
|
}
|
|
635
|
+
function commandPathHidden(path, commandsByPath) {
|
|
636
|
+
let hidden;
|
|
637
|
+
for (let length = 1; length <= path.length; length++) hidden = (0, __optique_core_usage.mergeHidden)(hidden, commandsByPath.get(commandPathKey(path.slice(0, length)))?.metadata?.hidden);
|
|
638
|
+
return hidden;
|
|
639
|
+
}
|
|
319
640
|
function buildRunOptions(options) {
|
|
320
641
|
const metadata = options.metadata;
|
|
321
|
-
const { dir: _dir, commands: _commands, extensions: _extensions, metadata: _metadata, help, version, completion,...rest } = options;
|
|
642
|
+
const { dir: _dir, commands: _commands, extensions: _extensions, entryFileName: _entryFileName, metadata: _metadata, help, version, completion,...rest } = options;
|
|
322
643
|
const runOptions = {
|
|
323
644
|
...rest,
|
|
324
645
|
contexts: unwrapProgramContexts(rest.contexts),
|