boardgame-core/src/utils/command/command-apply.ts

80 lines
3.0 KiB
TypeScript

import { type ParseError } from 'inline-schema';
import type { Command, CommandSchema } from './types';
function validateCommandCore(command: Command, schema: CommandSchema): string[] {
const errors: string[] = [];
if (schema.name !== '' && command.name !== schema.name) {
errors.push(`命令名称不匹配:期望 "${schema.name}",实际 "${command.name}"`);
}
const requiredParams = schema.params.filter(p => p.required);
const variadicParam = schema.params.find(p => p.variadic);
if (command.params.length < requiredParams.length) {
errors.push(`参数不足:至少需要 ${requiredParams.length} 个参数,实际 ${command.params.length}`);
}
if (!variadicParam && command.params.length > schema.params.length) {
errors.push(`参数过多:最多 ${schema.params.length} 个参数,实际 ${command.params.length}`);
}
const requiredOptions = Object.values(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) {
errors.push(`缺少必需选项:--${opt.name}${opt.short ? ` 或 -${opt.short}` : ''}`);
}
}
return errors;
}
export function applyCommandSchema(
command: Command,
schema: CommandSchema
): { command: Command; valid: true } | { command: Command; valid: false; errors: string[] } {
const errors = validateCommandCore(command, schema);
if (errors.length > 0) {
return { command, valid: false, errors };
}
const parseErrors: string[] = [];
const parsedParams: unknown[] = [...command.params];
for (let i = 0; i < command.params.length; i++) {
const paramValue = command.params[i];
const paramSchema = schema.params[i]?.schema;
if (paramSchema && typeof paramValue === 'string') {
try {
parsedParams[i] = paramSchema.parse(paramValue);
} catch (e) {
const err = e as ParseError;
parseErrors.push(`参数 "${schema.params[i]?.name}" 解析失败:${err.message}`);
}
}
}
const parsedOptions: Record<string, unknown> = { ...command.options };
for (const [key, value] of Object.entries(command.options)) {
const optSchema = schema.options[key] ?? (key.length === 1 ? Object.values(schema.options).find(o => o.short === key) : undefined);
if (optSchema?.schema && typeof value === 'string') {
try {
parsedOptions[key] = optSchema.schema.parse(value);
} catch (e) {
const err = e as ParseError;
parseErrors.push(`选项 "--${key}" 解析失败:${err.message}`);
}
}
}
const result = { ...command, params: parsedParams, options: parsedOptions };
if (parseErrors.length > 0) {
return { command: result, valid: false, errors: parseErrors };
}
return { command: result, valid: true };
}