refactor: various improvements
This commit is contained in:
+29
-58
@@ -284,10 +284,12 @@ export function parseCommandSchema(schemaStr: string): CommandSchema {
|
||||
let parsedSchema: ParsedSchema | undefined;
|
||||
|
||||
if (paramContent.includes(':')) {
|
||||
const [name, typeStr] = paramContent.split(':').map(s => s.trim());
|
||||
const colonIndex = paramContent.indexOf(':');
|
||||
const name = paramContent.slice(0, colonIndex).trim();
|
||||
const typeStr = paramContent.slice(colonIndex + 1).trim();
|
||||
try {
|
||||
parsedSchema = defineSchema(typeStr);
|
||||
} catch {
|
||||
} catch (e) {
|
||||
// 不是有效的 schema
|
||||
}
|
||||
paramContent = name;
|
||||
@@ -331,7 +333,10 @@ export function parseCommandSchema(schemaStr: string): CommandSchema {
|
||||
i++;
|
||||
} else if (token.startsWith('<') && token.endsWith('>')) {
|
||||
const isVariadic = token.endsWith('...>');
|
||||
let paramContent = token.replace(/^[<]+|[>.>]+$/g, '');
|
||||
let paramContent = token.replace(/^<+|>+$/g, '');
|
||||
if (isVariadic) {
|
||||
paramContent = paramContent.replace(/\.\.\.$/, '');
|
||||
}
|
||||
let parsedSchema: ParsedSchema | undefined;
|
||||
|
||||
if (paramContent.includes(':')) {
|
||||
@@ -541,14 +546,25 @@ 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);
|
||||
|
||||
@@ -556,30 +572,19 @@ export function validateCommand(
|
||||
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}` : ''}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 验证标志(标志都是可选的,除非未来扩展支持必需标志)
|
||||
// 目前只检查是否有未定义的标志(可选的严格模式)
|
||||
|
||||
if (errors.length > 0) {
|
||||
return { valid: false, errors };
|
||||
}
|
||||
|
||||
return { valid: true };
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -605,45 +610,13 @@ export function parseCommandWithSchema(
|
||||
const schema = parseCommandSchema(schemaStr);
|
||||
const command = parseCommand(input);
|
||||
|
||||
// 验证命令名称
|
||||
if (command.name !== schema.name) {
|
||||
return {
|
||||
command,
|
||||
valid: false,
|
||||
errors: [`命令名称不匹配:期望 "${schema.name}",实际 "${command.name}"`],
|
||||
};
|
||||
}
|
||||
|
||||
const errors: string[] = [];
|
||||
|
||||
// 验证参数数量
|
||||
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} 个`);
|
||||
return { command, valid: false, errors };
|
||||
}
|
||||
|
||||
if (!variadicParam && command.params.length > schema.params.length) {
|
||||
errors.push(`参数过多:最多 ${schema.params.length} 个参数,实际 ${command.params.length} 个`);
|
||||
return { command, valid: false, errors };
|
||||
}
|
||||
|
||||
// 验证必需的选项
|
||||
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}` : ''}`);
|
||||
}
|
||||
}
|
||||
|
||||
const errors = validateCommandCore(command, schema);
|
||||
if (errors.length > 0) {
|
||||
return { command, valid: false, errors };
|
||||
}
|
||||
|
||||
// 使用 schema 解析参数值
|
||||
const parseErrors: string[] = [];
|
||||
|
||||
const parsedParams: unknown[] = [];
|
||||
for (let i = 0; i < command.params.length; i++) {
|
||||
const paramValue = command.params[i];
|
||||
@@ -651,21 +624,19 @@ export function parseCommandWithSchema(
|
||||
|
||||
if (paramSchema) {
|
||||
try {
|
||||
// 如果是字符串值,使用 schema 解析
|
||||
const parsed = typeof paramValue === 'string'
|
||||
? paramSchema.parse(paramValue)
|
||||
: paramValue;
|
||||
parsedParams.push(parsed);
|
||||
} catch (e) {
|
||||
const err = e as ParseError;
|
||||
errors.push(`参数 "${schema.params[i]?.name}" 解析失败:${err.message}`);
|
||||
parseErrors.push(`参数 "${schema.params[i]?.name}" 解析失败:${err.message}`);
|
||||
}
|
||||
} else {
|
||||
parsedParams.push(paramValue);
|
||||
}
|
||||
}
|
||||
|
||||
// 使用 schema 解析选项值
|
||||
const parsedOptions: Record<string, unknown> = { ...command.options };
|
||||
for (const [key, value] of Object.entries(command.options)) {
|
||||
const optSchema = schema.options.find(o => o.name === key || o.short === key);
|
||||
@@ -674,13 +645,13 @@ export function parseCommandWithSchema(
|
||||
parsedOptions[key] = optSchema.schema.parse(value);
|
||||
} catch (e) {
|
||||
const err = e as ParseError;
|
||||
errors.push(`选项 "--${key}" 解析失败:${err.message}`);
|
||||
parseErrors.push(`选项 "--${key}" 解析失败:${err.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
return { command: { ...command, params: parsedParams, options: parsedOptions }, valid: false, errors };
|
||||
if (parseErrors.length > 0) {
|
||||
return { command: { ...command, params: parsedParams, options: parsedOptions }, valid: false, errors: parseErrors };
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
+3
-8
@@ -1,4 +1,4 @@
|
||||
export interface RNG {
|
||||
export interface RNG {
|
||||
/** 设置随机数种子 */
|
||||
setSeed(seed: number): void;
|
||||
|
||||
@@ -20,7 +20,7 @@ export function createRNG(seed?: number): RNG {
|
||||
}
|
||||
|
||||
/** Mulberry32RNG 类实现(用于类型兼容) */
|
||||
export class Mulberry32RNG {
|
||||
export class Mulberry32RNG implements RNG {
|
||||
private seed: number = 1;
|
||||
|
||||
constructor(seed?: number) {
|
||||
@@ -30,7 +30,7 @@ export class Mulberry32RNG {
|
||||
}
|
||||
|
||||
/** 设置随机数种子 */
|
||||
call(seed: number): void {
|
||||
setSeed(seed: number): void {
|
||||
this.seed = seed;
|
||||
}
|
||||
|
||||
@@ -48,11 +48,6 @@ export class Mulberry32RNG {
|
||||
return Math.floor(this.next(max));
|
||||
}
|
||||
|
||||
/** 重新设置种子 */
|
||||
setSeed(seed: number): void {
|
||||
this.seed = seed;
|
||||
}
|
||||
|
||||
/** 获取当前种子 */
|
||||
getSeed(): number {
|
||||
return this.seed;
|
||||
|
||||
Reference in New Issue
Block a user