chore: tests for rule
This commit is contained in:
+41
-6
@@ -1,4 +1,4 @@
|
||||
import {Command, CommandSchema, parseCommand, parseCommandSchema, validateCommand} from "../utils/command";
|
||||
import {Command, CommandSchema, parseCommand, parseCommandSchema} from "../utils/command";
|
||||
|
||||
export type RuleState = 'running' | 'yielded' | 'waiting' | 'done';
|
||||
|
||||
@@ -24,14 +24,14 @@ export function createRule<T>(
|
||||
fn: (cmd: Command) => Generator<string | CommandSchema, T, Command>
|
||||
): RuleDef<T> {
|
||||
return {
|
||||
schema: parseCommandSchema(schemaStr),
|
||||
schema: parseCommandSchema(schemaStr, ''),
|
||||
create: fn as RuleDef<T>['create'],
|
||||
};
|
||||
}
|
||||
|
||||
function parseYieldedSchema(value: string | CommandSchema): CommandSchema {
|
||||
if (typeof value === 'string') {
|
||||
return parseCommandSchema(value);
|
||||
return parseCommandSchema(value, '');
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -57,6 +57,29 @@ function discardChildren(game: GameContextLike, parent: RuleContext<unknown>) {
|
||||
parent.state = 'yielded';
|
||||
}
|
||||
|
||||
function validateYieldedSchema(command: Command, schema: CommandSchema): boolean {
|
||||
const requiredParams = schema.params.filter(p => p.required);
|
||||
const variadicParam = schema.params.find(p => p.variadic);
|
||||
|
||||
if (command.params.length < requiredParams.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!variadicParam && command.params.length > schema.params.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const requiredOptions = schema.options.filter(o => o.required);
|
||||
for (const opt of requiredOptions) {
|
||||
const hasOption = opt.name in command.options || (opt.short && opt.short in command.options);
|
||||
if (!hasOption) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function invokeRule<T>(
|
||||
game: GameContextLike,
|
||||
command: Command,
|
||||
@@ -98,14 +121,16 @@ export function dispatchCommand(game: GameContextLike, input: string): RuleConte
|
||||
|
||||
if (game.rules.has(command.name)) {
|
||||
const ruleDef = game.rules.get(command.name)!;
|
||||
return invokeRule(game, command, ruleDef);
|
||||
|
||||
const parent = findYieldedParent(game);
|
||||
|
||||
return invokeRule(game, command, ruleDef, parent);
|
||||
}
|
||||
|
||||
for (let i = game.ruleContexts.length - 1; i >= 0; i--) {
|
||||
const ctx = game.ruleContexts[i];
|
||||
if (ctx.state === 'yielded' && ctx.schema) {
|
||||
const validation = validateCommand(command, ctx.schema);
|
||||
if (validation.valid) {
|
||||
if (validateYieldedSchema(command, ctx.schema)) {
|
||||
const result = ctx.generator.next(command);
|
||||
if (result.done) {
|
||||
ctx.resolution = result.value;
|
||||
@@ -122,6 +147,16 @@ export function dispatchCommand(game: GameContextLike, input: string): RuleConte
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function findYieldedParent(game: GameContextLike): RuleContext<unknown> | undefined {
|
||||
for (let i = game.ruleContexts.length - 1; i >= 0; i--) {
|
||||
const ctx = game.ruleContexts[i];
|
||||
if (ctx.state === 'yielded') {
|
||||
return ctx;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
type GameContextLike = {
|
||||
rules: RuleRegistry;
|
||||
ruleContexts: RuleContext<unknown>[];
|
||||
|
||||
Reference in New Issue
Block a user