import { type ParseError } from 'inline-schema'; import type { Command, CommandSchema } from './types.js'; import { parseCommand } from './command-parse.js'; import { parseCommandSchema } from './schema-parse.js'; export function validateCommand( command: Command, schema: CommandSchema ): { valid: true } | { valid: false; errors: string[] } { const errors = validateCommandCore(command, schema); if (errors.length > 0) { return { valid: false, errors }; } return { valid: true }; } function validateCommandCore(command: Command, schema: CommandSchema): string[] { const errors: string[] = []; if (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 = 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 parseCommandWithSchema( input: string, schemaStr: string ): { command: Command; valid: true } | { command: Command; valid: false; errors: string[] } { const schema = parseCommandSchema(schemaStr); const command = parseCommand(input); const errors = validateCommandCore(command, schema); if (errors.length > 0) { return { command, valid: false, errors }; } const parseErrors: string[] = []; const parsedParams: unknown[] = []; for (let i = 0; i < command.params.length; i++) { const paramValue = command.params[i]; const paramSchema = schema.params[i]?.schema; if (paramSchema) { try { const parsed = typeof paramValue === 'string' ? paramSchema.parse(paramValue) : paramValue; parsedParams.push(parsed); } catch (e) { const err = e as ParseError; parseErrors.push(`参数 "${schema.params[i]?.name}" 解析失败:${err.message}`); } } else { parsedParams.push(paramValue); } } const parsedOptions: Record = { ...command.options }; for (const [key, value] of Object.entries(command.options)) { const optSchema = schema.options.find(o => o.name === key || o.short === key); 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}`); } } } if (parseErrors.length > 0) { return { command: { ...command, params: parsedParams, options: parsedOptions }, valid: false, errors: parseErrors }; } return { command: { ...command, params: parsedParams, options: parsedOptions }, valid: true, }; }