refactor: prompt validation
This commit is contained in:
parent
af9254603a
commit
9e2947a8d6
|
|
@ -10,6 +10,7 @@ import {
|
||||||
registerCommand
|
registerCommand
|
||||||
} from "@/utils/command";
|
} from "@/utils/command";
|
||||||
import type { GameModule } from './game-host';
|
import type { GameModule } from './game-host';
|
||||||
|
import {PromptValidator} from "@/utils/command/command-runner";
|
||||||
|
|
||||||
export interface IGameContext<TState extends Record<string, unknown> = {} > {
|
export interface IGameContext<TState extends Record<string, unknown> = {} > {
|
||||||
get value(): TState;
|
get value(): TState;
|
||||||
|
|
@ -17,7 +18,7 @@ export interface IGameContext<TState extends Record<string, unknown> = {} > {
|
||||||
produceAsync(fn: (draft: TState) => void): Promise<void>;
|
produceAsync(fn: (draft: TState) => void): Promise<void>;
|
||||||
run<T>(input: string): Promise<CommandResult<T>>;
|
run<T>(input: string): Promise<CommandResult<T>>;
|
||||||
runParsed<T>(command: Command): Promise<CommandResult<T>>;
|
runParsed<T>(command: Command): Promise<CommandResult<T>>;
|
||||||
prompt(schema: CommandSchema | string, validator?: (command: Command) => string | null, currentPlayer?: string | null): Promise<Command>;
|
prompt<T>(schema: CommandSchema | string, validator: PromptValidator<T>, currentPlayer?: string | null): Promise<T>;
|
||||||
addInterruption(promise: Promise<void>): void;
|
addInterruption(promise: Promise<void>): void;
|
||||||
|
|
||||||
// test only
|
// test only
|
||||||
|
|
@ -82,32 +83,6 @@ export function createGameCommandRegistry<TState extends Record<string, unknown>
|
||||||
return createCommandRegistry<IGameContext<TState>>();
|
return createCommandRegistry<IGameContext<TState>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
type CmdFunc<TState extends Record<string, unknown> = {}> = (this: IGameContext<TState>, ...args: any[]) => Promise<unknown>;
|
|
||||||
|
|
||||||
export function registerGameCommand<TState extends Record<string, unknown> = {}, TFunc extends CmdFunc<TState> = CmdFunc<TState>>(
|
|
||||||
registry: CommandRegistry<IGameContext<TState>>,
|
|
||||||
schema: CommandSchema | string,
|
|
||||||
run: TFunc
|
|
||||||
) {
|
|
||||||
const parsedSchema = typeof schema === 'string' ? parseCommandSchema(schema) : schema;
|
|
||||||
registerCommand(registry, {
|
|
||||||
schema: parsedSchema,
|
|
||||||
async run(this: CommandRunnerContext<IGameContext<TState>>, command: Command){
|
|
||||||
const params = command.params;
|
|
||||||
return await run.call(this.context, ...params);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return function(game: IGameContext<TState>, ...args: Parameters<TFunc>){
|
|
||||||
return game.runParsed({
|
|
||||||
options: {},
|
|
||||||
params: args,
|
|
||||||
flags: {},
|
|
||||||
name: parsedSchema.name,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export { GameHost, createGameHost } from './game-host';
|
export { GameHost, createGameHost } from './game-host';
|
||||||
export type { GameHostStatus, GameModule } from './game-host';
|
export type { GameHostStatus, GameModule } from './game-host';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
// Core types
|
// Core types
|
||||||
export type { IGameContext } from './core/game';
|
export type { IGameContext } from './core/game';
|
||||||
export { createGameContext, createGameCommandRegistry, registerGameCommand } from './core/game';
|
export { createGameContext, createGameCommandRegistry } from './core/game';
|
||||||
|
|
||||||
export type { GameHost, GameHostStatus, GameModule } from './core/game';
|
export type { GameHost, GameHostStatus, GameModule } from './core/game';
|
||||||
export { createGameHost, createGameModule } from './core/game';
|
export { createGameHost, createGameModule } from './core/game';
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,12 @@
|
||||||
import type { Command, CommandSchema } from './types';
|
import type { Command, CommandSchema } from './types';
|
||||||
import type {CommandResult, CommandRunner, CommandRunnerContext, CommandRunnerEvents, PromptEvent} from './command-runner';
|
import type {
|
||||||
|
CommandResult,
|
||||||
|
CommandRunner,
|
||||||
|
CommandRunnerContext,
|
||||||
|
CommandRunnerEvents,
|
||||||
|
PromptEvent,
|
||||||
|
PromptValidator
|
||||||
|
} from './command-runner';
|
||||||
import { parseCommand } from './command-parse';
|
import { parseCommand } from './command-parse';
|
||||||
import { applyCommandSchema } from './command-validate';
|
import { applyCommandSchema } from './command-validate';
|
||||||
import { parseCommandSchema } from './schema-parse';
|
import { parseCommandSchema } from './schema-parse';
|
||||||
|
|
@ -129,11 +136,11 @@ export function createCommandRunnerContext<TContext>(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const prompt = (
|
const prompt = <T>(
|
||||||
schema: CommandSchema | string,
|
schema: CommandSchema | string,
|
||||||
validator?: (command: Command) => string | null,
|
validator: PromptValidator<T>,
|
||||||
currentPlayer?: string | null
|
currentPlayer?: string | null
|
||||||
): Promise<Command> => {
|
): Promise<T> => {
|
||||||
const resolvedSchema = typeof schema === 'string' ? parseCommandSchema(schema) : schema;
|
const resolvedSchema = typeof schema === 'string' ? parseCommandSchema(schema) : schema;
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const tryCommit = (commandOrInput: Command | string) => {
|
const tryCommit = (commandOrInput: Command | string) => {
|
||||||
|
|
@ -142,10 +149,16 @@ export function createCommandRunnerContext<TContext>(
|
||||||
if (!schemaResult.valid) {
|
if (!schemaResult.valid) {
|
||||||
return schemaResult.errors.join('; ');
|
return schemaResult.errors.join('; ');
|
||||||
}
|
}
|
||||||
const error = validator?.(schemaResult.command);
|
try{
|
||||||
if (error) return error;
|
const result = validator(schemaResult.command);
|
||||||
resolve(schemaResult.command);
|
resolve(result);
|
||||||
return null;
|
return null;
|
||||||
|
}catch(e){
|
||||||
|
if(e instanceof Error)
|
||||||
|
return e.message;
|
||||||
|
else
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
const cancel = (reason?: string) => {
|
const cancel = (reason?: string) => {
|
||||||
activePrompt = null;
|
activePrompt = null;
|
||||||
|
|
|
||||||
|
|
@ -31,11 +31,13 @@ export type CommandResult<T=unknown> = {
|
||||||
error: string;
|
error: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type PromptValidator<T> = (command: Command) => T;
|
||||||
|
|
||||||
export type CommandRunnerContext<TContext> = {
|
export type CommandRunnerContext<TContext> = {
|
||||||
context: TContext;
|
context: TContext;
|
||||||
run: <T=unknown>(input: string) => Promise<CommandResult<T>>;
|
run: <T=unknown>(input: string) => Promise<CommandResult<T>>;
|
||||||
runParsed: <T=unknown>(command: Command) => Promise<CommandResult<T>>;
|
runParsed: <T=unknown>(command: Command) => Promise<CommandResult<T>>;
|
||||||
prompt: (schema: CommandSchema | string, validator?: (command: Command) => string | null, currentPlayer?: string | null) => Promise<Command>;
|
prompt: <T>(schema: CommandSchema | string, validator: PromptValidator<T>, currentPlayer?: string | null) => Promise<T>;
|
||||||
on: <T extends keyof CommandRunnerEvents>(event: T, listener: (e: CommandRunnerEvents[T]) => void) => void;
|
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;
|
off: <T extends keyof CommandRunnerEvents>(event: T, listener: (e: CommandRunnerEvents[T]) => void) => void;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue