@optique/discover 1.2.0-dev.2254 → 1.2.0-dev.2255
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +4 -4
- package/dist/cli.js +4 -4
- package/dist/{command-CUn2_NIA.cjs → command-C9u5sJZS.cjs} +29 -0
- package/dist/command-DIfnalpt.d.cts +283 -0
- package/dist/{command-DO5zgkvS.js → command-DSHIV50v.js} +24 -1
- package/dist/command-s80EaEXl.d.ts +283 -0
- package/dist/command.cjs +3 -2
- package/dist/command.d.cts +2 -2
- package/dist/command.d.ts +2 -2
- package/dist/command.js +2 -2
- package/dist/{generator-BV1QDOot.cjs → generator-DW4rrPD2.cjs} +1 -1
- package/dist/{generator-B81thoIS.js → generator-HNXr5Vz2.js} +1 -1
- package/dist/generator.cjs +3 -3
- package/dist/generator.js +3 -3
- package/dist/index.cjs +2 -2
- package/dist/index.d.cts +16 -25
- package/dist/index.d.ts +16 -25
- package/dist/index.js +2 -2
- package/dist/{src-kBDpUW2H.js → src-CVATvqru.js} +65 -13
- package/dist/{src-BDObn4mj.cjs → src-CzbbFDmi.cjs} +65 -13
- package/package.json +3 -3
- package/dist/command-DSHBTa5c.d.cts +0 -139
- package/dist/command-DrmNW0HO.d.ts +0 -139
package/dist/command.cjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
const require_command = require('./command-
|
|
1
|
+
const require_command = require('./command-C9u5sJZS.cjs');
|
|
2
2
|
|
|
3
3
|
exports.defineCommand = require_command.defineCommand;
|
|
4
|
-
exports.isCommand = require_command.isCommand;
|
|
4
|
+
exports.isCommand = require_command.isCommand;
|
|
5
|
+
exports.validateHooks = require_command.validateHooks;
|
package/dist/command.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { AnyCommand, AnyStaticCommand, Command, CommandDefinition, CommandMetadata, CommandPath, StaticCommand, defineCommand, isCommand } from "./command-
|
|
2
|
-
export { AnyCommand, AnyStaticCommand, Command, CommandDefinition, CommandMetadata, CommandPath, StaticCommand, defineCommand, isCommand };
|
|
1
|
+
import { AnyCommand, AnyStaticCommand, Command, CommandDefinition, CommandMetadata, CommandPath, ProgramHookContext, ProgramHooks, ProgramInvocation, StaticCommand, defineCommand, isCommand, validateHooks } from "./command-DIfnalpt.cjs";
|
|
2
|
+
export { AnyCommand, AnyStaticCommand, Command, CommandDefinition, CommandMetadata, CommandPath, ProgramHookContext, ProgramHooks, ProgramInvocation, StaticCommand, defineCommand, isCommand, validateHooks };
|
package/dist/command.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { AnyCommand, AnyStaticCommand, Command, CommandDefinition, CommandMetadata, CommandPath, StaticCommand, defineCommand, isCommand } from "./command-
|
|
2
|
-
export { AnyCommand, AnyStaticCommand, Command, CommandDefinition, CommandMetadata, CommandPath, StaticCommand, defineCommand, isCommand };
|
|
1
|
+
import { AnyCommand, AnyStaticCommand, Command, CommandDefinition, CommandMetadata, CommandPath, ProgramHookContext, ProgramHooks, ProgramInvocation, StaticCommand, defineCommand, isCommand, validateHooks } from "./command-s80EaEXl.js";
|
|
2
|
+
export { AnyCommand, AnyStaticCommand, Command, CommandDefinition, CommandMetadata, CommandPath, ProgramHookContext, ProgramHooks, ProgramInvocation, StaticCommand, defineCommand, isCommand, validateHooks };
|
package/dist/command.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { defineCommand, isCommand } from "./command-
|
|
1
|
+
import { defineCommand, isCommand, validateHooks } from "./command-DSHIV50v.js";
|
|
2
2
|
|
|
3
|
-
export { defineCommand, isCommand };
|
|
3
|
+
export { defineCommand, isCommand, validateHooks };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require('./chunk-CUT6urMc.cjs');
|
|
2
|
-
const require_src = require('./src-
|
|
2
|
+
const require_src = require('./src-CzbbFDmi.cjs');
|
|
3
3
|
const node_fs_promises = require_chunk.__toESM(require("node:fs/promises"));
|
|
4
4
|
const node_path = require_chunk.__toESM(require("node:path"));
|
|
5
5
|
const node_url = require_chunk.__toESM(require("node:url"));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getDefaultExtensions } from "./src-
|
|
1
|
+
import { getDefaultExtensions } from "./src-CVATvqru.js";
|
|
2
2
|
import { mkdir, readdir, realpath, stat, writeFile } from "node:fs/promises";
|
|
3
3
|
import { dirname, posix, relative, resolve } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
package/dist/generator.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
require('./command-
|
|
2
|
-
require('./src-
|
|
3
|
-
const require_generator = require('./generator-
|
|
1
|
+
require('./command-C9u5sJZS.cjs');
|
|
2
|
+
require('./src-CzbbFDmi.cjs');
|
|
3
|
+
const require_generator = require('./generator-DW4rrPD2.cjs');
|
|
4
4
|
|
|
5
5
|
exports.generateCommandsModule = require_generator.generateCommandsModule;
|
|
6
6
|
exports.watchCommandsModule = require_generator.watchCommandsModule;
|
package/dist/generator.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import "./command-
|
|
2
|
-
import "./src-
|
|
3
|
-
import { generateCommandsModule, watchCommandsModule, writeCommandsModule } from "./generator-
|
|
1
|
+
import "./command-DSHIV50v.js";
|
|
2
|
+
import "./src-CVATvqru.js";
|
|
3
|
+
import { generateCommandsModule, watchCommandsModule, writeCommandsModule } from "./generator-HNXr5Vz2.js";
|
|
4
4
|
|
|
5
5
|
export { generateCommandsModule, watchCommandsModule, writeCommandsModule };
|
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const require_command = require('./command-
|
|
2
|
-
const require_src = require('./src-
|
|
1
|
+
const require_command = require('./command-C9u5sJZS.cjs');
|
|
2
|
+
const require_src = require('./src-CzbbFDmi.cjs');
|
|
3
3
|
|
|
4
4
|
exports.commandsFromModules = require_src.commandsFromModules;
|
|
5
5
|
exports.createProgramParser = require_src.createProgramParser;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AnyCommand, AnyStaticCommand, Command, CommandDefinition, CommandMetadata, CommandPath, StaticCommand, defineCommand, isCommand } from "./command-
|
|
1
|
+
import { AnyCommand, AnyStaticCommand, Command, CommandDefinition, CommandMetadata, CommandPath, ProgramHookContext, ProgramHooks, ProgramInvocation, StaticCommand, defineCommand, isCommand } from "./command-DIfnalpt.cjs";
|
|
2
2
|
import { Mode } from "@optique/core/parser";
|
|
3
3
|
import { FluentParser } from "@optique/core/fluent";
|
|
4
4
|
import { Message } from "@optique/core/message";
|
|
@@ -7,28 +7,6 @@ import { RunOptions } from "@optique/run";
|
|
|
7
7
|
|
|
8
8
|
//#region src/index.d.ts
|
|
9
9
|
|
|
10
|
-
/**
|
|
11
|
-
* The parsed command selected by a discovered command parser.
|
|
12
|
-
*
|
|
13
|
-
* Most applications receive this only indirectly through {@link runProgram},
|
|
14
|
-
* which calls the handler automatically.
|
|
15
|
-
*
|
|
16
|
-
* @since 1.1.0
|
|
17
|
-
*/
|
|
18
|
-
interface ProgramInvocation {
|
|
19
|
-
/**
|
|
20
|
-
* The command definition that matched the input.
|
|
21
|
-
*/
|
|
22
|
-
readonly command: AnyCommand;
|
|
23
|
-
/**
|
|
24
|
-
* Parsed value produced by the command parser.
|
|
25
|
-
*/
|
|
26
|
-
readonly value: unknown;
|
|
27
|
-
/**
|
|
28
|
-
* Handler to call with {@link ProgramInvocation.value}.
|
|
29
|
-
*/
|
|
30
|
-
readonly handler: (value: unknown) => void | Promise<void>;
|
|
31
|
-
}
|
|
32
10
|
/**
|
|
33
11
|
* A command paired with its command path.
|
|
34
12
|
*
|
|
@@ -198,6 +176,18 @@ interface RunProgramBaseOptions extends Omit<RunOptions, "help" | "version" | "c
|
|
|
198
176
|
* @default `"both"`
|
|
199
177
|
*/
|
|
200
178
|
readonly completion?: RunOptions["completion"] | false;
|
|
179
|
+
/**
|
|
180
|
+
* Lifecycle hooks invoked around each command handler.
|
|
181
|
+
*
|
|
182
|
+
* Use these for cross-cutting concerns such as opening a log scope, starting
|
|
183
|
+
* a tracing span, or reporting handler failures, without duplicating the
|
|
184
|
+
* logic in every command. Hooks are opt-in: omitting this field keeps the
|
|
185
|
+
* exact behavior of a plain `runProgram()` call. Command-level hooks defined
|
|
186
|
+
* on {@link CommandDefinition.hooks} nest inside these.
|
|
187
|
+
*
|
|
188
|
+
* @since 1.2.0
|
|
189
|
+
*/
|
|
190
|
+
readonly hooks?: ProgramHooks;
|
|
201
191
|
}
|
|
202
192
|
/**
|
|
203
193
|
* Options for {@link runProgram} when discovering commands from files.
|
|
@@ -311,7 +301,8 @@ declare function createProgramParser(commands: readonly CommandEntry[], metadata
|
|
|
311
301
|
* @param options Program options.
|
|
312
302
|
* @returns A promise that resolves after the selected command handler
|
|
313
303
|
* completes.
|
|
314
|
-
* @throws {TypeError} If discovery or command loading fails
|
|
304
|
+
* @throws {TypeError} If discovery or command loading fails, or `hooks` is
|
|
305
|
+
* malformed.
|
|
315
306
|
* @since 1.1.0
|
|
316
307
|
*/
|
|
317
308
|
declare function runProgram(options: RunProgramOptions): Promise<void>;
|
|
@@ -335,4 +326,4 @@ interface ProgramHelpMetadata {
|
|
|
335
326
|
readonly footer?: Message;
|
|
336
327
|
}
|
|
337
328
|
//#endregion
|
|
338
|
-
export { type AnyCommand, type AnyStaticCommand, type Command, type CommandDefinition, CommandEntry, type CommandMetadata, type CommandPath, CommandsFromModulesOptions, DiscoverCommandsOptions, DiscoveredCommand, ModuleCommand, ModuleMap, ProgramHelpMetadata, ProgramInvocation, RunProgramDiscoveryOptions, RunProgramOptions, RunProgramStaticOptions, RuntimeExtensionOptions, type StaticCommand, commandsFromModules, createProgramParser, defineCommand, discoverCommands, getDefaultExtensions, isCommand, runProgram };
|
|
329
|
+
export { type AnyCommand, type AnyStaticCommand, type Command, type CommandDefinition, CommandEntry, type CommandMetadata, type CommandPath, CommandsFromModulesOptions, DiscoverCommandsOptions, DiscoveredCommand, ModuleCommand, ModuleMap, ProgramHelpMetadata, type ProgramHookContext, type ProgramHooks, type ProgramInvocation, RunProgramDiscoveryOptions, RunProgramOptions, RunProgramStaticOptions, RuntimeExtensionOptions, type StaticCommand, commandsFromModules, createProgramParser, defineCommand, discoverCommands, getDefaultExtensions, isCommand, runProgram };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AnyCommand, AnyStaticCommand, Command, CommandDefinition, CommandMetadata, CommandPath, StaticCommand, defineCommand, isCommand } from "./command-
|
|
1
|
+
import { AnyCommand, AnyStaticCommand, Command, CommandDefinition, CommandMetadata, CommandPath, ProgramHookContext, ProgramHooks, ProgramInvocation, StaticCommand, defineCommand, isCommand } from "./command-s80EaEXl.js";
|
|
2
2
|
import { Message } from "@optique/core/message";
|
|
3
3
|
import { ProgramMetadata } from "@optique/core/program";
|
|
4
4
|
import { RunOptions } from "@optique/run";
|
|
@@ -7,28 +7,6 @@ import { Mode } from "@optique/core/parser";
|
|
|
7
7
|
|
|
8
8
|
//#region src/index.d.ts
|
|
9
9
|
|
|
10
|
-
/**
|
|
11
|
-
* The parsed command selected by a discovered command parser.
|
|
12
|
-
*
|
|
13
|
-
* Most applications receive this only indirectly through {@link runProgram},
|
|
14
|
-
* which calls the handler automatically.
|
|
15
|
-
*
|
|
16
|
-
* @since 1.1.0
|
|
17
|
-
*/
|
|
18
|
-
interface ProgramInvocation {
|
|
19
|
-
/**
|
|
20
|
-
* The command definition that matched the input.
|
|
21
|
-
*/
|
|
22
|
-
readonly command: AnyCommand;
|
|
23
|
-
/**
|
|
24
|
-
* Parsed value produced by the command parser.
|
|
25
|
-
*/
|
|
26
|
-
readonly value: unknown;
|
|
27
|
-
/**
|
|
28
|
-
* Handler to call with {@link ProgramInvocation.value}.
|
|
29
|
-
*/
|
|
30
|
-
readonly handler: (value: unknown) => void | Promise<void>;
|
|
31
|
-
}
|
|
32
10
|
/**
|
|
33
11
|
* A command paired with its command path.
|
|
34
12
|
*
|
|
@@ -198,6 +176,18 @@ interface RunProgramBaseOptions extends Omit<RunOptions, "help" | "version" | "c
|
|
|
198
176
|
* @default `"both"`
|
|
199
177
|
*/
|
|
200
178
|
readonly completion?: RunOptions["completion"] | false;
|
|
179
|
+
/**
|
|
180
|
+
* Lifecycle hooks invoked around each command handler.
|
|
181
|
+
*
|
|
182
|
+
* Use these for cross-cutting concerns such as opening a log scope, starting
|
|
183
|
+
* a tracing span, or reporting handler failures, without duplicating the
|
|
184
|
+
* logic in every command. Hooks are opt-in: omitting this field keeps the
|
|
185
|
+
* exact behavior of a plain `runProgram()` call. Command-level hooks defined
|
|
186
|
+
* on {@link CommandDefinition.hooks} nest inside these.
|
|
187
|
+
*
|
|
188
|
+
* @since 1.2.0
|
|
189
|
+
*/
|
|
190
|
+
readonly hooks?: ProgramHooks;
|
|
201
191
|
}
|
|
202
192
|
/**
|
|
203
193
|
* Options for {@link runProgram} when discovering commands from files.
|
|
@@ -311,7 +301,8 @@ declare function createProgramParser(commands: readonly CommandEntry[], metadata
|
|
|
311
301
|
* @param options Program options.
|
|
312
302
|
* @returns A promise that resolves after the selected command handler
|
|
313
303
|
* completes.
|
|
314
|
-
* @throws {TypeError} If discovery or command loading fails
|
|
304
|
+
* @throws {TypeError} If discovery or command loading fails, or `hooks` is
|
|
305
|
+
* malformed.
|
|
315
306
|
* @since 1.1.0
|
|
316
307
|
*/
|
|
317
308
|
declare function runProgram(options: RunProgramOptions): Promise<void>;
|
|
@@ -335,4 +326,4 @@ interface ProgramHelpMetadata {
|
|
|
335
326
|
readonly footer?: Message;
|
|
336
327
|
}
|
|
337
328
|
//#endregion
|
|
338
|
-
export { type AnyCommand, type AnyStaticCommand, type Command, type CommandDefinition, CommandEntry, type CommandMetadata, type CommandPath, CommandsFromModulesOptions, DiscoverCommandsOptions, DiscoveredCommand, ModuleCommand, ModuleMap, ProgramHelpMetadata, ProgramInvocation, RunProgramDiscoveryOptions, RunProgramOptions, RunProgramStaticOptions, RuntimeExtensionOptions, type StaticCommand, commandsFromModules, createProgramParser, defineCommand, discoverCommands, getDefaultExtensions, isCommand, runProgram };
|
|
329
|
+
export { type AnyCommand, type AnyStaticCommand, type Command, type CommandDefinition, CommandEntry, type CommandMetadata, type CommandPath, CommandsFromModulesOptions, DiscoverCommandsOptions, DiscoveredCommand, ModuleCommand, ModuleMap, ProgramHelpMetadata, type ProgramHookContext, type ProgramHooks, type ProgramInvocation, RunProgramDiscoveryOptions, RunProgramOptions, RunProgramStaticOptions, RuntimeExtensionOptions, type StaticCommand, commandsFromModules, createProgramParser, defineCommand, discoverCommands, getDefaultExtensions, isCommand, runProgram };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineCommand, isCommand } from "./command-
|
|
2
|
-
import { commandsFromModules, createProgramParser, discoverCommands, getDefaultExtensions, runProgram } from "./src-
|
|
1
|
+
import { defineCommand, isCommand } from "./command-DSHIV50v.js";
|
|
2
|
+
import { commandsFromModules, createProgramParser, discoverCommands, getDefaultExtensions, runProgram } from "./src-CVATvqru.js";
|
|
3
3
|
|
|
4
4
|
export { commandsFromModules, createProgramParser, defineCommand, discoverCommands, getDefaultExtensions, isCommand, runProgram };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isCommand } from "./command-
|
|
1
|
+
import { isCommand, validateHooks } from "./command-DSHIV50v.js";
|
|
2
2
|
import { longestMatch, or } from "@optique/core/constructs";
|
|
3
3
|
import { map } from "@optique/core/modifiers";
|
|
4
4
|
import { command } from "@optique/core/primitives";
|
|
@@ -145,10 +145,12 @@ function createProgramParser(commands, metadata = {}) {
|
|
|
145
145
|
* @param options Program options.
|
|
146
146
|
* @returns A promise that resolves after the selected command handler
|
|
147
147
|
* completes.
|
|
148
|
-
* @throws {TypeError} If discovery or command loading fails
|
|
148
|
+
* @throws {TypeError} If discovery or command loading fails, or `hooks` is
|
|
149
|
+
* malformed.
|
|
149
150
|
* @since 1.1.0
|
|
150
151
|
*/
|
|
151
152
|
async function runProgram(options) {
|
|
153
|
+
if (options.hooks != null) validateHooks(options.hooks, "Program");
|
|
152
154
|
let commands;
|
|
153
155
|
if (isStaticRunProgramOptions(options)) commands = staticCommandsToEntries(options.commands);
|
|
154
156
|
else commands = await discoverCommands({
|
|
@@ -158,7 +160,55 @@ async function runProgram(options) {
|
|
|
158
160
|
});
|
|
159
161
|
const parser = createProgramParser(commands, options.metadata);
|
|
160
162
|
const invocation = await runAsync(parser, buildRunOptions(options));
|
|
161
|
-
await
|
|
163
|
+
await dispatchInvocation(invocation, options.hooks);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Runs a command handler wrapped in the program-level and command-level
|
|
167
|
+
* lifecycle hooks.
|
|
168
|
+
*
|
|
169
|
+
* The hooks nest: the program-level `beforeEach` runs first, then the command's
|
|
170
|
+
* `beforeEach`, then the handler; `afterEach` and `onError` unwind in reverse,
|
|
171
|
+
* with the command-level hook running before the program-level one.
|
|
172
|
+
*
|
|
173
|
+
* @param invocation The selected command invocation.
|
|
174
|
+
* @param programHooks Program-level hooks, if any.
|
|
175
|
+
* @returns A promise that resolves after the handler and matching hooks
|
|
176
|
+
* complete.
|
|
177
|
+
* @throws The original error thrown by `beforeEach`, the handler, or
|
|
178
|
+
* `afterEach`, re-thrown after the `onError` hooks run.
|
|
179
|
+
*/
|
|
180
|
+
async function dispatchInvocation(invocation, programHooks) {
|
|
181
|
+
const commandHooks = invocation.command.hooks;
|
|
182
|
+
await runHookScope(programHooks, invocation, (programContext) => runHookScope(commandHooks, invocation, (commandContext) => {
|
|
183
|
+
if (commandHooks?.beforeEach != null) return invocation.handler(invocation.value, commandContext);
|
|
184
|
+
if (programHooks?.beforeEach != null) return invocation.handler(invocation.value, programContext);
|
|
185
|
+
return invocation.handler(invocation.value);
|
|
186
|
+
}));
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Runs an inner step wrapped in a single set of lifecycle hooks.
|
|
190
|
+
*
|
|
191
|
+
* @param hooks The hooks for this scope, if any.
|
|
192
|
+
* @param invocation The selected command invocation passed to `beforeEach`.
|
|
193
|
+
* @param inner The step to wrap; receives the context from `beforeEach`.
|
|
194
|
+
* @returns The value returned by `inner`.
|
|
195
|
+
* @throws The original error thrown by `beforeEach`, `inner`, or `afterEach`,
|
|
196
|
+
* re-thrown after `onError` runs. An error thrown by `onError` itself
|
|
197
|
+
* is suppressed so it cannot mask the original failure.
|
|
198
|
+
*/
|
|
199
|
+
async function runHookScope(hooks, invocation, inner) {
|
|
200
|
+
let context = {};
|
|
201
|
+
try {
|
|
202
|
+
if (hooks?.beforeEach != null) context = await hooks.beforeEach(invocation);
|
|
203
|
+
const result = await inner(context);
|
|
204
|
+
if (hooks?.afterEach != null) await hooks.afterEach(context, result);
|
|
205
|
+
return result;
|
|
206
|
+
} catch (error) {
|
|
207
|
+
if (hooks?.onError != null) try {
|
|
208
|
+
await hooks.onError(context, error);
|
|
209
|
+
} catch {}
|
|
210
|
+
throw error;
|
|
211
|
+
}
|
|
162
212
|
}
|
|
163
213
|
function getRuntime() {
|
|
164
214
|
if ("Deno" in globalThis) return "deno";
|
|
@@ -336,18 +386,19 @@ function buildCommandTree(commands) {
|
|
|
336
386
|
current = child;
|
|
337
387
|
}
|
|
338
388
|
current.command = entry.command;
|
|
389
|
+
current.path = entry.path;
|
|
339
390
|
}
|
|
340
391
|
return root;
|
|
341
392
|
}
|
|
342
393
|
function buildNodeParser(node, inheritedHidden) {
|
|
343
394
|
const childParser = buildChildrenParser(node, inheritedHidden);
|
|
344
|
-
if (childParser != null && node.command != null) return createExecutableNodeParser(childParser, node.command);
|
|
395
|
+
if (childParser != null && node.command != null) return createExecutableNodeParser(childParser, node.command, node.path ?? []);
|
|
345
396
|
if (childParser != null) return childParser;
|
|
346
|
-
if (node.command != null) return createLeafParser(node.command);
|
|
397
|
+
if (node.command != null) return createLeafParser(node.command, node.path ?? []);
|
|
347
398
|
throw new TypeError("Command tree node must contain a command.");
|
|
348
399
|
}
|
|
349
|
-
function createExecutableNodeParser(childParser, commandDefinition) {
|
|
350
|
-
const leafParser = createLeafParser(commandDefinition, true);
|
|
400
|
+
function createExecutableNodeParser(childParser, commandDefinition, path) {
|
|
401
|
+
const leafParser = createLeafParser(commandDefinition, path, true);
|
|
351
402
|
const branchParsers = [childParser, leafParser];
|
|
352
403
|
const parser = longestMatch(childParser, leafParser);
|
|
353
404
|
const phase2SeedHook = findPhase2SeedHook(parser);
|
|
@@ -386,16 +437,16 @@ function createExecutableNodeParser(childParser, commandDefinition) {
|
|
|
386
437
|
state: toExclusiveState(activeState, context.state)
|
|
387
438
|
}, prefix);
|
|
388
439
|
},
|
|
389
|
-
getSuggestRuntimeNodes(state, path) {
|
|
440
|
+
getSuggestRuntimeNodes(state, path$1) {
|
|
390
441
|
const activeState = normalizeExecutableNodeState(state);
|
|
391
442
|
if (activeState == null) {
|
|
392
|
-
const branchPath$1 = [...path, 1];
|
|
443
|
+
const branchPath$1 = [...path$1, 1];
|
|
393
444
|
const branchState$1 = inheritAnnotations(state, leafParser.initialState);
|
|
394
445
|
return getExecutableNodeBranchSuggestRuntimeNodes(leafParser, branchState$1, branchPath$1);
|
|
395
446
|
}
|
|
396
|
-
if (activeState?.result.success !== true) return parser.getSuggestRuntimeNodes?.(toExclusiveState(activeState, state), path) ?? [];
|
|
447
|
+
if (activeState?.result.success !== true) return parser.getSuggestRuntimeNodes?.(toExclusiveState(activeState, state), path$1) ?? [];
|
|
397
448
|
const branchParser = branchParsers[activeState.branch];
|
|
398
|
-
const branchPath = [...path, activeState.branch];
|
|
449
|
+
const branchPath = [...path$1, activeState.branch];
|
|
399
450
|
const branchState = inheritAnnotations(state, activeState.result.next.state);
|
|
400
451
|
return getExecutableNodeBranchSuggestRuntimeNodes(branchParser, branchState, branchPath);
|
|
401
452
|
},
|
|
@@ -647,9 +698,10 @@ function commandMetadataWithInheritedHidden(metadata, inheritedHidden) {
|
|
|
647
698
|
...hidden != null && { hidden }
|
|
648
699
|
};
|
|
649
700
|
}
|
|
650
|
-
function createLeafParser(commandDefinition, includeMetadata = false) {
|
|
701
|
+
function createLeafParser(commandDefinition, path, includeMetadata = false) {
|
|
651
702
|
const parser = map(commandDefinition.parser, (value) => ({
|
|
652
703
|
command: commandDefinition,
|
|
704
|
+
path,
|
|
653
705
|
value,
|
|
654
706
|
handler: commandDefinition.handler
|
|
655
707
|
}));
|
|
@@ -702,7 +754,7 @@ function commandPathHidden(path, commandsByPath) {
|
|
|
702
754
|
}
|
|
703
755
|
function buildRunOptions(options) {
|
|
704
756
|
const metadata = options.metadata;
|
|
705
|
-
const { dir: _dir, commands: _commands, extensions: _extensions, entryFileName: _entryFileName, metadata: _metadata, help, version, completion,...rest } = options;
|
|
757
|
+
const { dir: _dir, commands: _commands, extensions: _extensions, entryFileName: _entryFileName, metadata: _metadata, hooks: _hooks, help, version, completion,...rest } = options;
|
|
706
758
|
const runOptions = {
|
|
707
759
|
...rest,
|
|
708
760
|
contexts: unwrapProgramContexts(rest.contexts),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require('./chunk-CUT6urMc.cjs');
|
|
2
|
-
const require_command = require('./command-
|
|
2
|
+
const require_command = require('./command-C9u5sJZS.cjs');
|
|
3
3
|
const __optique_core_constructs = require_chunk.__toESM(require("@optique/core/constructs"));
|
|
4
4
|
const __optique_core_modifiers = require_chunk.__toESM(require("@optique/core/modifiers"));
|
|
5
5
|
const __optique_core_primitives = require_chunk.__toESM(require("@optique/core/primitives"));
|
|
@@ -146,10 +146,12 @@ function createProgramParser(commands, metadata = {}) {
|
|
|
146
146
|
* @param options Program options.
|
|
147
147
|
* @returns A promise that resolves after the selected command handler
|
|
148
148
|
* completes.
|
|
149
|
-
* @throws {TypeError} If discovery or command loading fails
|
|
149
|
+
* @throws {TypeError} If discovery or command loading fails, or `hooks` is
|
|
150
|
+
* malformed.
|
|
150
151
|
* @since 1.1.0
|
|
151
152
|
*/
|
|
152
153
|
async function runProgram(options) {
|
|
154
|
+
if (options.hooks != null) require_command.validateHooks(options.hooks, "Program");
|
|
153
155
|
let commands;
|
|
154
156
|
if (isStaticRunProgramOptions(options)) commands = staticCommandsToEntries(options.commands);
|
|
155
157
|
else commands = await discoverCommands({
|
|
@@ -159,7 +161,55 @@ async function runProgram(options) {
|
|
|
159
161
|
});
|
|
160
162
|
const parser = createProgramParser(commands, options.metadata);
|
|
161
163
|
const invocation = await (0, __optique_run.runAsync)(parser, buildRunOptions(options));
|
|
162
|
-
await
|
|
164
|
+
await dispatchInvocation(invocation, options.hooks);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Runs a command handler wrapped in the program-level and command-level
|
|
168
|
+
* lifecycle hooks.
|
|
169
|
+
*
|
|
170
|
+
* The hooks nest: the program-level `beforeEach` runs first, then the command's
|
|
171
|
+
* `beforeEach`, then the handler; `afterEach` and `onError` unwind in reverse,
|
|
172
|
+
* with the command-level hook running before the program-level one.
|
|
173
|
+
*
|
|
174
|
+
* @param invocation The selected command invocation.
|
|
175
|
+
* @param programHooks Program-level hooks, if any.
|
|
176
|
+
* @returns A promise that resolves after the handler and matching hooks
|
|
177
|
+
* complete.
|
|
178
|
+
* @throws The original error thrown by `beforeEach`, the handler, or
|
|
179
|
+
* `afterEach`, re-thrown after the `onError` hooks run.
|
|
180
|
+
*/
|
|
181
|
+
async function dispatchInvocation(invocation, programHooks) {
|
|
182
|
+
const commandHooks = invocation.command.hooks;
|
|
183
|
+
await runHookScope(programHooks, invocation, (programContext) => runHookScope(commandHooks, invocation, (commandContext) => {
|
|
184
|
+
if (commandHooks?.beforeEach != null) return invocation.handler(invocation.value, commandContext);
|
|
185
|
+
if (programHooks?.beforeEach != null) return invocation.handler(invocation.value, programContext);
|
|
186
|
+
return invocation.handler(invocation.value);
|
|
187
|
+
}));
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Runs an inner step wrapped in a single set of lifecycle hooks.
|
|
191
|
+
*
|
|
192
|
+
* @param hooks The hooks for this scope, if any.
|
|
193
|
+
* @param invocation The selected command invocation passed to `beforeEach`.
|
|
194
|
+
* @param inner The step to wrap; receives the context from `beforeEach`.
|
|
195
|
+
* @returns The value returned by `inner`.
|
|
196
|
+
* @throws The original error thrown by `beforeEach`, `inner`, or `afterEach`,
|
|
197
|
+
* re-thrown after `onError` runs. An error thrown by `onError` itself
|
|
198
|
+
* is suppressed so it cannot mask the original failure.
|
|
199
|
+
*/
|
|
200
|
+
async function runHookScope(hooks, invocation, inner) {
|
|
201
|
+
let context = {};
|
|
202
|
+
try {
|
|
203
|
+
if (hooks?.beforeEach != null) context = await hooks.beforeEach(invocation);
|
|
204
|
+
const result = await inner(context);
|
|
205
|
+
if (hooks?.afterEach != null) await hooks.afterEach(context, result);
|
|
206
|
+
return result;
|
|
207
|
+
} catch (error) {
|
|
208
|
+
if (hooks?.onError != null) try {
|
|
209
|
+
await hooks.onError(context, error);
|
|
210
|
+
} catch {}
|
|
211
|
+
throw error;
|
|
212
|
+
}
|
|
163
213
|
}
|
|
164
214
|
function getRuntime() {
|
|
165
215
|
if ("Deno" in globalThis) return "deno";
|
|
@@ -337,18 +387,19 @@ function buildCommandTree(commands) {
|
|
|
337
387
|
current = child;
|
|
338
388
|
}
|
|
339
389
|
current.command = entry.command;
|
|
390
|
+
current.path = entry.path;
|
|
340
391
|
}
|
|
341
392
|
return root;
|
|
342
393
|
}
|
|
343
394
|
function buildNodeParser(node, inheritedHidden) {
|
|
344
395
|
const childParser = buildChildrenParser(node, inheritedHidden);
|
|
345
|
-
if (childParser != null && node.command != null) return createExecutableNodeParser(childParser, node.command);
|
|
396
|
+
if (childParser != null && node.command != null) return createExecutableNodeParser(childParser, node.command, node.path ?? []);
|
|
346
397
|
if (childParser != null) return childParser;
|
|
347
|
-
if (node.command != null) return createLeafParser(node.command);
|
|
398
|
+
if (node.command != null) return createLeafParser(node.command, node.path ?? []);
|
|
348
399
|
throw new TypeError("Command tree node must contain a command.");
|
|
349
400
|
}
|
|
350
|
-
function createExecutableNodeParser(childParser, commandDefinition) {
|
|
351
|
-
const leafParser = createLeafParser(commandDefinition, true);
|
|
401
|
+
function createExecutableNodeParser(childParser, commandDefinition, path) {
|
|
402
|
+
const leafParser = createLeafParser(commandDefinition, path, true);
|
|
352
403
|
const branchParsers = [childParser, leafParser];
|
|
353
404
|
const parser = (0, __optique_core_constructs.longestMatch)(childParser, leafParser);
|
|
354
405
|
const phase2SeedHook = findPhase2SeedHook(parser);
|
|
@@ -387,16 +438,16 @@ function createExecutableNodeParser(childParser, commandDefinition) {
|
|
|
387
438
|
state: toExclusiveState(activeState, context.state)
|
|
388
439
|
}, prefix);
|
|
389
440
|
},
|
|
390
|
-
getSuggestRuntimeNodes(state, path) {
|
|
441
|
+
getSuggestRuntimeNodes(state, path$1) {
|
|
391
442
|
const activeState = normalizeExecutableNodeState(state);
|
|
392
443
|
if (activeState == null) {
|
|
393
|
-
const branchPath$1 = [...path, 1];
|
|
444
|
+
const branchPath$1 = [...path$1, 1];
|
|
394
445
|
const branchState$1 = (0, __optique_core_extension.inheritAnnotations)(state, leafParser.initialState);
|
|
395
446
|
return getExecutableNodeBranchSuggestRuntimeNodes(leafParser, branchState$1, branchPath$1);
|
|
396
447
|
}
|
|
397
|
-
if (activeState?.result.success !== true) return parser.getSuggestRuntimeNodes?.(toExclusiveState(activeState, state), path) ?? [];
|
|
448
|
+
if (activeState?.result.success !== true) return parser.getSuggestRuntimeNodes?.(toExclusiveState(activeState, state), path$1) ?? [];
|
|
398
449
|
const branchParser = branchParsers[activeState.branch];
|
|
399
|
-
const branchPath = [...path, activeState.branch];
|
|
450
|
+
const branchPath = [...path$1, activeState.branch];
|
|
400
451
|
const branchState = (0, __optique_core_extension.inheritAnnotations)(state, activeState.result.next.state);
|
|
401
452
|
return getExecutableNodeBranchSuggestRuntimeNodes(branchParser, branchState, branchPath);
|
|
402
453
|
},
|
|
@@ -648,9 +699,10 @@ function commandMetadataWithInheritedHidden(metadata, inheritedHidden) {
|
|
|
648
699
|
...hidden != null && { hidden }
|
|
649
700
|
};
|
|
650
701
|
}
|
|
651
|
-
function createLeafParser(commandDefinition, includeMetadata = false) {
|
|
702
|
+
function createLeafParser(commandDefinition, path, includeMetadata = false) {
|
|
652
703
|
const parser = (0, __optique_core_modifiers.map)(commandDefinition.parser, (value) => ({
|
|
653
704
|
command: commandDefinition,
|
|
705
|
+
path,
|
|
654
706
|
value,
|
|
655
707
|
handler: commandDefinition.handler
|
|
656
708
|
}));
|
|
@@ -703,7 +755,7 @@ function commandPathHidden(path, commandsByPath) {
|
|
|
703
755
|
}
|
|
704
756
|
function buildRunOptions(options) {
|
|
705
757
|
const metadata = options.metadata;
|
|
706
|
-
const { dir: _dir, commands: _commands, extensions: _extensions, entryFileName: _entryFileName, metadata: _metadata, help, version, completion,...rest } = options;
|
|
758
|
+
const { dir: _dir, commands: _commands, extensions: _extensions, entryFileName: _entryFileName, metadata: _metadata, hooks: _hooks, help, version, completion,...rest } = options;
|
|
707
759
|
const runOptions = {
|
|
708
760
|
...rest,
|
|
709
761
|
contexts: unwrapProgramContexts(rest.contexts),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optique/discover",
|
|
3
|
-
"version": "1.2.0-dev.
|
|
3
|
+
"version": "1.2.0-dev.2255",
|
|
4
4
|
"description": "Runtime-aware command discovery for Optique CLI programs",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"CLI",
|
|
@@ -83,8 +83,8 @@
|
|
|
83
83
|
"optique-discover": "./dist/cli.js"
|
|
84
84
|
},
|
|
85
85
|
"dependencies": {
|
|
86
|
-
"@optique/core": "1.2.0-dev.
|
|
87
|
-
"@optique/run": "1.2.0-dev.
|
|
86
|
+
"@optique/core": "1.2.0-dev.2255+a902c666",
|
|
87
|
+
"@optique/run": "1.2.0-dev.2255+a902c666"
|
|
88
88
|
},
|
|
89
89
|
"devDependencies": {
|
|
90
90
|
"@types/node": "^24.0.0",
|