fix: command parsing
This commit is contained in:
parent
c315e0643b
commit
d1ea04c442
|
|
@ -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++;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue