fix: command parsing

This commit is contained in:
hypercross 2026-04-01 21:12:34 +08:00
parent c315e0643b
commit d1ea04c442
1 changed files with 77 additions and 72 deletions

View File

@ -133,7 +133,9 @@ export function parseCommand(input: string): Command {
function tokenize(input: string): string[] {
const tokens: string[] = [];
let current = '';
let inQuote: string | null = null; // ' 或 " 或 null
let inQuote: string | null = null;
let inBracket = false;
let bracketDepth = 0;
let escaped = false;
let i = 0;
@ -141,38 +143,57 @@ function tokenize(input: string): string[] {
const char = input[i];
if (escaped) {
// 转义字符:直接添加到当前 token
current += char;
escaped = false;
} else if (char === '\\') {
// 开始转义
escaped = true;
} else if (inQuote) {
// 在引号内
if (char === inQuote) {
// 结束引号
inQuote = null;
} else {
current += char;
}
} else if (char === '"' || char === "'") {
// 开始引号
inQuote = char;
} else if (/\s/.test(char)) {
// 空白字符
} else if (char === '[') {
if (inBracket) {
bracketDepth++;
current += char;
} else {
if (current.length > 0) {
tokens.push(current);
current = '';
}
inBracket = true;
bracketDepth = 1;
current = '[';
}
} else if (char === ']') {
if (inBracket) {
bracketDepth--;
current += char;
if (bracketDepth === 0) {
tokens.push(current);
current = '';
inBracket = false;
}
} else {
current += char;
}
} else if (/\s/.test(char)) {
if (inBracket) {
current += char;
} else if (current.length > 0) {
tokens.push(current);
current = '';
}
} else {
// 普通字符
current += char;
}
i++;
}
// 处理未闭合的引号
if (current.length > 0) {
tokens.push(current);
}
@ -231,12 +252,19 @@ export function parseCommandSchema(schemaStr: string): CommandSchema {
const inner = token.slice(1, -1).trim();
if (inner.startsWith('--')) {
// 可选长格式标志或选项
const parts = inner.split(/\s+/);
const name = parts[0].slice(2);
// 检查是否有类型定义(如 --flag: boolean 或 --opt: string[]
if (name.includes(':')) {
if (name.endsWith(':')) {
const optName = name.slice(0, -1).trim();
const typeStr = parts[1] || '';
const parsedSchema = defineSchema(typeStr);
schema.options.push({
name: optName,
required: false,
schema: parsedSchema,
});
} else if (name.includes(':')) {
const [optName, typeStr] = name.split(':').map(s => s.trim());
const parsedSchema = defineSchema(typeStr);
schema.options.push({
@ -245,36 +273,28 @@ export function parseCommandSchema(schemaStr: string): CommandSchema {
schema: parsedSchema,
});
} else if (parts.length > 1) {
// 可选选项(旧语法:--opt <value>
const valueToken = parts[1];
let typeStr = valueToken;
// 如果是 <value> 格式,提取类型
if (valueToken.startsWith('<') && valueToken.endsWith('>')) {
typeStr = valueToken.slice(1, -1);
}
// 尝试解析为 inline-schema 类型
let parsedSchema: ParsedSchema | undefined;
try {
parsedSchema = defineSchema(typeStr);
} catch {
// 不是有效的 schema使用默认字符串
}
schema.options.push({
name,
required: false,
schema: parsedSchema,
});
} else {
// 可选标志
schema.flags.push({ name });
}
} else if (inner.startsWith('-') && inner.length > 1) {
// 可选短格式标志或选项
const parts = inner.split(/\s+/);
const short = parts[0].slice(1);
// 检查是否有类型定义
if (short.includes(':')) {
if (short.endsWith(':')) {
const optName = short.slice(0, -1).trim();
const typeStr = parts[1] || '';
const parsedSchema = defineSchema(typeStr);
schema.options.push({
name: optName,
short: optName,
required: false,
schema: parsedSchema,
});
} else if (short.includes(':')) {
const [optName, typeStr] = short.split(':').map(s => s.trim());
const parsedSchema = defineSchema(typeStr);
schema.options.push({
@ -284,26 +304,12 @@ export function parseCommandSchema(schemaStr: string): CommandSchema {
schema: parsedSchema,
});
} else if (parts.length > 1) {
// 可选选项(旧语法)
const valueToken = parts[1];
let typeStr = valueToken;
if (valueToken.startsWith('<') && valueToken.endsWith('>')) {
typeStr = valueToken.slice(1, -1);
}
let parsedSchema: ParsedSchema | undefined;
try {
parsedSchema = defineSchema(typeStr);
} catch {
// 不是有效的 schema使用默认字符串
}
schema.options.push({
name: short,
short,
required: false,
schema: parsedSchema,
});
} else {
// 可选标志
schema.flags.push({ name: short, short });
}
} else {
@ -336,8 +342,18 @@ export function parseCommandSchema(schemaStr: string): CommandSchema {
const name = token.slice(2);
const nextToken = tokens[i + 1];
// 检查是否有类型定义(如 --flag: boolean
if (name.includes(':')) {
if (name.endsWith(':')) {
const optName = name.slice(0, -1).trim();
const nextPart = tokens[i + 1];
const typeStr = nextPart || '';
const parsedSchema = defineSchema(typeStr);
schema.options.push({
name: optName,
required: true,
schema: parsedSchema,
});
i += 2;
} else if (name.includes(':')) {
const [optName, typeStr] = name.split(':').map(s => s.trim());
const parsedSchema = defineSchema(typeStr);
schema.options.push({
@ -347,23 +363,12 @@ export function parseCommandSchema(schemaStr: string): CommandSchema {
});
i++;
} else if (nextToken && nextToken.startsWith('<') && nextToken.endsWith('>')) {
// 旧语法:--opt <value>
const valueToken = nextToken;
const typeStr = valueToken.slice(1, -1);
let parsedSchema: ParsedSchema | undefined;
try {
parsedSchema = defineSchema(typeStr);
} catch {
// 不是有效的 schema
}
schema.options.push({
name,
required: true,
schema: parsedSchema,
});
i += 2;
} else {
// 否则是标志
schema.flags.push({ name });
i++;
}
@ -372,8 +377,19 @@ export function parseCommandSchema(schemaStr: string): CommandSchema {
const short = token.slice(1);
const nextToken = tokens[i + 1];
// 检查是否有类型定义
if (short.includes(':')) {
if (short.endsWith(':')) {
const optName = short.slice(0, -1).trim();
const nextPart = tokens[i + 1];
const typeStr = nextPart || '';
const parsedSchema = defineSchema(typeStr);
schema.options.push({
name: optName,
short: optName,
required: true,
schema: parsedSchema,
});
i += 2;
} else if (short.includes(':')) {
const [optName, typeStr] = short.split(':').map(s => s.trim());
const parsedSchema = defineSchema(typeStr);
schema.options.push({
@ -384,24 +400,13 @@ export function parseCommandSchema(schemaStr: string): CommandSchema {
});
i++;
} else if (nextToken && nextToken.startsWith('<') && nextToken.endsWith('>')) {
// 旧语法
const valueToken = nextToken;
const typeStr = valueToken.slice(1, -1);
let parsedSchema: ParsedSchema | undefined;
try {
parsedSchema = defineSchema(typeStr);
} catch {
// 不是有效的 schema
}
schema.options.push({
name: short,
short,
required: true,
schema: parsedSchema,
});
i += 2;
} else {
// 否则是标志
schema.flags.push({ name: short, short });
i++;
}