refactor: replace rule.ts with a command runner based solution
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import type { Command } from './types.js';
|
||||
import type { Command, CommandSchema } from './types.js';
|
||||
import type { CommandRunner, CommandRunnerContext, PromptEvent } from './command-runner.js';
|
||||
import { parseCommand } from './command-parse.js';
|
||||
import { applyCommandSchema } from './command-apply.js';
|
||||
import { applyCommandSchema } from './command-validate.js';
|
||||
import { parseCommandSchema } from './schema-parse.js';
|
||||
|
||||
export type CommandRegistry<TContext> = Map<string, CommandRunner<TContext, unknown>>;
|
||||
@@ -42,6 +42,10 @@ type Listener = (e: PromptEvent) => void;
|
||||
|
||||
export type CommandRunnerContextExport<TContext> = CommandRunnerContext<TContext> & {
|
||||
registry: CommandRegistry<TContext>;
|
||||
_activePrompt: PromptEvent | null;
|
||||
_resolvePrompt: (command: Command) => void;
|
||||
_rejectPrompt: (error: Error) => void;
|
||||
_pendingInput: string | null;
|
||||
};
|
||||
|
||||
export function createCommandRunnerContext<TContext>(
|
||||
@@ -58,9 +62,26 @@ export function createCommandRunnerContext<TContext>(
|
||||
listeners.delete(listener);
|
||||
};
|
||||
|
||||
let activePrompt: PromptEvent | null = null;
|
||||
|
||||
const resolvePrompt = (command: Command) => {
|
||||
if (activePrompt) {
|
||||
activePrompt.resolve(command);
|
||||
activePrompt = null;
|
||||
}
|
||||
};
|
||||
|
||||
const rejectPrompt = (error: Error) => {
|
||||
if (activePrompt) {
|
||||
activePrompt.reject(error);
|
||||
activePrompt = null;
|
||||
}
|
||||
};
|
||||
|
||||
const prompt = (schema: Parameters<CommandRunnerContext<TContext>['prompt']>[0]): Promise<Command> => {
|
||||
const resolvedSchema = typeof schema === 'string' ? parseCommandSchema(schema) : schema;
|
||||
return new Promise((resolve, reject) => {
|
||||
activePrompt = { schema: resolvedSchema, resolve, reject };
|
||||
const event: PromptEvent = { schema: resolvedSchema, resolve, reject };
|
||||
for (const listener of listeners) {
|
||||
listener(event);
|
||||
@@ -71,13 +92,21 @@ export function createCommandRunnerContext<TContext>(
|
||||
const runnerCtx: CommandRunnerContextExport<TContext> = {
|
||||
registry,
|
||||
context,
|
||||
run: (input: string) => runCommandWithContext(registry, runnerCtx, input),
|
||||
runParsed: (command: Command) => runCommandParsedWithContext(registry, runnerCtx, command),
|
||||
run: (input: string) => runCommandWithContext(runnerCtx, input),
|
||||
runParsed: (command: Command) => runCommandParsedWithContext(runnerCtx, command),
|
||||
prompt,
|
||||
on,
|
||||
off,
|
||||
_activePrompt: null,
|
||||
_resolvePrompt: resolvePrompt,
|
||||
_rejectPrompt: rejectPrompt,
|
||||
_pendingInput: null,
|
||||
};
|
||||
|
||||
Object.defineProperty(runnerCtx, '_activePrompt', {
|
||||
get: () => activePrompt,
|
||||
});
|
||||
|
||||
return runnerCtx;
|
||||
}
|
||||
|
||||
@@ -101,16 +130,15 @@ export async function runCommand<TContext>(
|
||||
input: string
|
||||
): Promise<{ success: true; result: unknown } | { success: false; error: string }> {
|
||||
const runnerCtx = createCommandRunnerContext(registry, context);
|
||||
return await runCommandWithContext(registry, runnerCtx, input);
|
||||
return await runCommandWithContext(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 runCommandParsedWithContext(registry, runnerCtx, command);
|
||||
return await runCommandParsedWithContext(runnerCtx, command);
|
||||
}
|
||||
|
||||
export async function runCommandParsed<TContext>(
|
||||
@@ -119,15 +147,14 @@ export async function runCommandParsed<TContext>(
|
||||
command: Command
|
||||
): Promise<{ success: true; result: unknown } | { success: false; error: string }> {
|
||||
const runnerCtx = createCommandRunnerContext(registry, context);
|
||||
return await runCommandParsedWithContext(registry, runnerCtx, command);
|
||||
return await runCommandParsedWithContext(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);
|
||||
const runner = runnerCtx.registry.get(command.name);
|
||||
if (!runner) {
|
||||
return { success: false, error: `Unknown command: ${command.name}` };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user