diff --git a/src/utils/command/command-prompt.ts b/src/utils/command/command-prompt.ts new file mode 100644 index 0000000..a60172a --- /dev/null +++ b/src/utils/command/command-prompt.ts @@ -0,0 +1,93 @@ +import { createMiddlewareChain } from "../middleware"; +import { PromptValidator } from "./command-runner"; +import { CommandSchema } from "./types"; + +export interface PromptDef { + schema: CommandSchema; + hint?: string; +} + +export interface PromptCall { + def: PromptDef; + player?: string; + validator: PromptValidator; + + resolve(res: TRes): void; + reject(reason: string): void; + promise: Promise; +} + +export type PromptTryResult = + | { + ok: false; + reason: string; + } + | { + ok: true; + }; + +export function createPromptContext() { + const map = new Map(); + const handleCall = createMiddlewareChain(async (call: PromptCall) => { + const key = call.player ?? "global"; + const existing = map.get(key); + if (existing) { + existing.reject("Prompt cancelled"); + } + + map.set(key, call); + try { + await call.promise; + } finally { + if (map.get(key) === call) map.delete(key); + } + }); + + function tryCommit( + player: string, + ...args: TArgs + ): PromptTryResult { + const call = map.get(player); + if (!call) return { ok: false, reason: "No Prompt" }; + + try { + const res = call.validator(...args); + call.resolve(res); + return { ok: true }; + } catch (reason) { + if (typeof reason === "string") return { ok: false, reason }; + throw reason; + } + } + + function cancel(player: string, reason = "Prompt Cancelled") { + map.get(player)?.reject(reason); + } + + function prompt( + def: PromptDef, + validator: PromptValidator, + player?: string, + ) { + const promise = new Promise((resolve, reject) => { + const call = { + def, + player, + validator, + + resolve, + reject, + promise, + } as PromptCall; + handleCall.execute(call); + }); + return promise; + } + + return { + prompt, + tryCommit, + cancel, + handleCall, + }; +} diff --git a/src/utils/command/index.ts b/src/utils/command/index.ts index 31900c0..3a1d2e4 100644 --- a/src/utils/command/index.ts +++ b/src/utils/command/index.ts @@ -1,22 +1,41 @@ -export { parseCommand } from './command-parse'; -export { parseCommandSchema } from './schema-parse'; -export { validateCommand, parseCommandWithSchema, applyCommandSchema } from './command-validate'; +export { parseCommand } from "./command-parse"; +export { parseCommandSchema } from "./schema-parse"; export { - createCommandRegistry, - registerCommand, - unregisterCommand, - hasCommand, - getCommand, - runCommand, - runCommandParsed, - createCommandRunnerContext, -} from './command-registry'; + validateCommand, + parseCommandWithSchema, + applyCommandSchema, +} from "./command-validate"; +export { + createCommandRegistry, + registerCommand, + unregisterCommand, + hasCommand, + getCommand, + runCommand, + runCommandParsed, + createCommandRunnerContext, +} from "./command-registry"; export type { - Command, - CommandParamSchema, - CommandOptionSchema, - CommandFlagSchema, - CommandSchema, -} from './types'; -export type { CommandRunner, CommandDef, CommandResult, CommandRunnerHandler, CommandRunnerContext, PromptEvent, CommandRunnerEvents } from './command-runner'; -export type { CommandRegistry, CommandRunnerContextExport } from './command-registry'; + Command, + CommandParamSchema, + CommandOptionSchema, + CommandFlagSchema, + CommandSchema, +} from "./types"; +export type { + CommandRunner, + CommandDef, + CommandResult, + CommandRunnerHandler, + CommandRunnerContext, + PromptEvent, + CommandRunnerEvents, +} from "./command-runner"; +export type { + CommandRegistry, + CommandRunnerContextExport, +} from "./command-registry"; + +export type { PromptDef, PromptTryResult, PromptCall } from "./command-prompt"; + +export { createPromptContext } from "./command-prompt";