refactor: move runner context to handler's this
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
import type { Command } from './types.js';
|
||||
import type { CommandRunner, CommandRunnerContext as RunnerContext } from './command-runner.js';
|
||||
import type { CommandRunner, CommandRunnerContext, PromptEvent } from './command-runner.js';
|
||||
import { parseCommand } from './command-parse.js';
|
||||
import { applyCommandSchema } from './command-apply.js';
|
||||
import { parseCommandSchema } from './schema-parse.js';
|
||||
|
||||
export type CommandRegistry<TContext> = Map<string, CommandRunner<TContext, unknown>>;
|
||||
|
||||
@@ -37,17 +38,54 @@ export function getCommand<TContext>(
|
||||
return registry.get(name);
|
||||
}
|
||||
|
||||
async function executeWithRunnerContext<TContext>(
|
||||
type Listener = (e: PromptEvent) => void;
|
||||
|
||||
export type CommandRunnerContextExport<TContext> = CommandRunnerContext<TContext> & {
|
||||
registry: CommandRegistry<TContext>;
|
||||
};
|
||||
|
||||
export function createCommandRunnerContext<TContext>(
|
||||
registry: CommandRegistry<TContext>,
|
||||
context: TContext,
|
||||
context: TContext
|
||||
): CommandRunnerContextExport<TContext> {
|
||||
const listeners = new Set<Listener>();
|
||||
|
||||
const on = (_event: 'prompt', listener: Listener) => {
|
||||
listeners.add(listener);
|
||||
};
|
||||
|
||||
const off = (_event: 'prompt', listener: Listener) => {
|
||||
listeners.delete(listener);
|
||||
};
|
||||
|
||||
const prompt = (schema: Parameters<CommandRunnerContext<TContext>['prompt']>[0]): Promise<Command> => {
|
||||
const resolvedSchema = typeof schema === 'string' ? parseCommandSchema(schema) : schema;
|
||||
return new Promise((resolve, reject) => {
|
||||
const event: PromptEvent = { schema: resolvedSchema, resolve, reject };
|
||||
for (const listener of listeners) {
|
||||
listener(event);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const runnerCtx: CommandRunnerContextExport<TContext> = {
|
||||
registry,
|
||||
context,
|
||||
run: (input: string) => runCommandWithContext(registry, runnerCtx, input),
|
||||
runParsed: (command: Command) => runCommandParsedWithContext(registry, runnerCtx, command),
|
||||
prompt,
|
||||
on,
|
||||
off,
|
||||
};
|
||||
|
||||
return runnerCtx;
|
||||
}
|
||||
|
||||
async function executeWithRunnerContext<TContext>(
|
||||
runnerCtx: CommandRunnerContextExport<TContext>,
|
||||
runner: CommandRunner<TContext, unknown>,
|
||||
command: Command
|
||||
): Promise<{ success: true; result: unknown } | { success: false; error: string }> {
|
||||
const runnerCtx: RunnerContext<TContext> = {
|
||||
context,
|
||||
run: (input: string) => runCommand(registry, context, input),
|
||||
runParsed: (cmd: Command) => runCommandParsed(registry, context, cmd),
|
||||
};
|
||||
try {
|
||||
const result = await runner.run.call(runnerCtx, command);
|
||||
return { success: true, result };
|
||||
@@ -61,15 +99,33 @@ export async function runCommand<TContext>(
|
||||
registry: CommandRegistry<TContext>,
|
||||
context: TContext,
|
||||
input: string
|
||||
): Promise<{ success: true; result: unknown } | { success: false; error: string }> {
|
||||
const runnerCtx = createCommandRunnerContext(registry, context);
|
||||
return await runCommandWithContext(registry, runnerCtx, input);
|
||||
}
|
||||
|
||||
async function runCommandWithContext<TContext>(
|
||||
registry: CommandRegistry<TContext>,
|
||||
runnerCtx: CommandRunnerContextExport<TContext>,
|
||||
input: string
|
||||
): Promise<{ success: true; result: unknown } | { success: false; error: string }> {
|
||||
const command = parseCommand(input);
|
||||
return await runCommandParsed(registry, context, command);
|
||||
return await runCommandParsedWithContext(registry, runnerCtx, command);
|
||||
}
|
||||
|
||||
export async function runCommandParsed<TContext>(
|
||||
registry: CommandRegistry<TContext>,
|
||||
context: TContext,
|
||||
command: Command
|
||||
): Promise<{ success: true; result: unknown } | { success: false; error: string }> {
|
||||
const runnerCtx = createCommandRunnerContext(registry, context);
|
||||
return await runCommandParsedWithContext(registry, runnerCtx, command);
|
||||
}
|
||||
|
||||
async function runCommandParsedWithContext<TContext>(
|
||||
registry: CommandRegistry<TContext>,
|
||||
runnerCtx: CommandRunnerContextExport<TContext>,
|
||||
command: Command
|
||||
): Promise<{ success: true; result: unknown } | { success: false; error: string }> {
|
||||
const runner = registry.get(command.name);
|
||||
if (!runner) {
|
||||
@@ -81,21 +137,5 @@ export async function runCommandParsed<TContext>(
|
||||
return { success: false, error: validationResult.errors.join('; ') };
|
||||
}
|
||||
|
||||
return await executeWithRunnerContext(registry, context, runner, validationResult.command);
|
||||
}
|
||||
|
||||
export type CommandRunnerContext<TContext> = RunnerContext<TContext> & {
|
||||
registry: CommandRegistry<TContext>;
|
||||
};
|
||||
|
||||
export function createCommandRunnerContext<TContext>(
|
||||
registry: CommandRegistry<TContext>,
|
||||
context: TContext
|
||||
): CommandRunnerContext<TContext> {
|
||||
return {
|
||||
registry,
|
||||
context,
|
||||
run: (input: string) => runCommand(registry, context, input),
|
||||
runParsed: (command: Command) => runCommandParsed(registry, context, command),
|
||||
};
|
||||
return await executeWithRunnerContext(runnerCtx, runner, validationResult.command);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,22 @@
|
||||
import type { Command, CommandSchema } from './types.js';
|
||||
|
||||
export type PromptEvent = {
|
||||
schema: CommandSchema;
|
||||
resolve: (command: Command) => void;
|
||||
reject: (error: Error) => void;
|
||||
};
|
||||
|
||||
export type CommandRunnerEvents = {
|
||||
prompt: PromptEvent;
|
||||
};
|
||||
|
||||
export type CommandRunnerContext<TContext> = {
|
||||
context: TContext;
|
||||
run: (input: string) => Promise<{ success: true; result: unknown } | { success: false; error: string }>;
|
||||
runParsed: (command: Command) => Promise<{ success: true; result: unknown } | { success: false; error: string }>;
|
||||
prompt: (schema: CommandSchema | string) => Promise<Command>;
|
||||
on: <T extends keyof CommandRunnerEvents>(event: T, listener: (e: CommandRunnerEvents[T]) => void) => void;
|
||||
off: <T extends keyof CommandRunnerEvents>(event: T, listener: (e: CommandRunnerEvents[T]) => void) => void;
|
||||
};
|
||||
|
||||
export type CommandRunnerHandler<TContext, TResult> = (
|
||||
|
||||
@@ -18,5 +18,5 @@ export type {
|
||||
CommandFlagSchema,
|
||||
CommandSchema,
|
||||
} from './types';
|
||||
export type { CommandRunner, CommandRunnerHandler } from './command-runner';
|
||||
export type { CommandRegistry, CommandRunnerContext } from './command-registry';
|
||||
export type { CommandRunner, CommandRunnerHandler, CommandRunnerContext, PromptEvent, CommandRunnerEvents } from './command-runner';
|
||||
export type { CommandRegistry, CommandRunnerContextExport } from './command-registry';
|
||||
|
||||
Reference in New Issue
Block a user