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[] {
|
function tokenize(input: string): string[] {
|
||||||
const tokens: string[] = [];
|
const tokens: string[] = [];
|
||||||
let current = '';
|
let current = '';
|
||||||
let inQuote: string | null = null; // ' 或 " 或 null
|
let inQuote: string | null = null;
|
||||||
|
let inBracket = false;
|
||||||
|
let bracketDepth = 0;
|
||||||
let escaped = false;
|
let escaped = false;
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
|
||||||
|
|
@ -141,38 +143,57 @@ function tokenize(input: string): string[] {
|
||||||
const char = input[i];
|
const char = input[i];
|
||||||
|
|
||||||
if (escaped) {
|
if (escaped) {
|
||||||
// 转义字符:直接添加到当前 token
|
|
||||||
current += char;
|
current += char;
|
||||||
escaped = false;
|
escaped = false;
|
||||||
} else if (char === '\\') {
|
} else if (char === '\\') {
|
||||||
// 开始转义
|
|
||||||
escaped = true;
|
escaped = true;
|
||||||
} else if (inQuote) {
|
} else if (inQuote) {
|
||||||
// 在引号内
|
|
||||||
if (char === inQuote) {
|
if (char === inQuote) {
|
||||||
// 结束引号
|
|
||||||
inQuote = null;
|
inQuote = null;
|
||||||
} else {
|
} else {
|
||||||
current += char;
|
current += char;
|
||||||
}
|
}
|
||||||
} else if (char === '"' || char === "'") {
|
} else if (char === '"' || char === "'") {
|
||||||
// 开始引号
|
|
||||||
inQuote = char;
|
inQuote = 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)) {
|
} else if (/\s/.test(char)) {
|
||||||
// 空白字符
|
if (inBracket) {
|
||||||
if (current.length > 0) {
|
current += char;
|
||||||
|
} else if (current.length > 0) {
|
||||||
tokens.push(current);
|
tokens.push(current);
|
||||||
current = '';
|
current = '';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 普通字符
|
|
||||||
current += char;
|
current += char;
|
||||||
}
|
}
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理未闭合的引号
|
|
||||||
if (current.length > 0) {
|
if (current.length > 0) {
|
||||||
tokens.push(current);
|
tokens.push(current);
|
||||||
}
|
}
|
||||||
|
|
@ -231,12 +252,19 @@ export function parseCommandSchema(schemaStr: string): CommandSchema {
|
||||||
const inner = token.slice(1, -1).trim();
|
const inner = token.slice(1, -1).trim();
|
||||||
|
|
||||||
if (inner.startsWith('--')) {
|
if (inner.startsWith('--')) {
|
||||||
// 可选长格式标志或选项
|
|
||||||
const parts = inner.split(/\s+/);
|
const parts = inner.split(/\s+/);
|
||||||
const name = parts[0].slice(2);
|
const name = parts[0].slice(2);
|
||||||
|
|
||||||
// 检查是否有类型定义(如 --flag: boolean 或 --opt: string[])
|
if (name.endsWith(':')) {
|
||||||
if (name.includes(':')) {
|
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 [optName, typeStr] = name.split(':').map(s => s.trim());
|
||||||
const parsedSchema = defineSchema(typeStr);
|
const parsedSchema = defineSchema(typeStr);
|
||||||
schema.options.push({
|
schema.options.push({
|
||||||
|
|
@ -245,36 +273,28 @@ export function parseCommandSchema(schemaStr: string): CommandSchema {
|
||||||
schema: parsedSchema,
|
schema: parsedSchema,
|
||||||
});
|
});
|
||||||
} else if (parts.length > 1) {
|
} 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({
|
schema.options.push({
|
||||||
name,
|
name,
|
||||||
required: false,
|
required: false,
|
||||||
schema: parsedSchema,
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// 可选标志
|
|
||||||
schema.flags.push({ name });
|
schema.flags.push({ name });
|
||||||
}
|
}
|
||||||
} else if (inner.startsWith('-') && inner.length > 1) {
|
} else if (inner.startsWith('-') && inner.length > 1) {
|
||||||
// 可选短格式标志或选项
|
|
||||||
const parts = inner.split(/\s+/);
|
const parts = inner.split(/\s+/);
|
||||||
const short = parts[0].slice(1);
|
const short = parts[0].slice(1);
|
||||||
|
|
||||||
// 检查是否有类型定义
|
if (short.endsWith(':')) {
|
||||||
if (short.includes(':')) {
|
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 [optName, typeStr] = short.split(':').map(s => s.trim());
|
||||||
const parsedSchema = defineSchema(typeStr);
|
const parsedSchema = defineSchema(typeStr);
|
||||||
schema.options.push({
|
schema.options.push({
|
||||||
|
|
@ -284,26 +304,12 @@ export function parseCommandSchema(schemaStr: string): CommandSchema {
|
||||||
schema: parsedSchema,
|
schema: parsedSchema,
|
||||||
});
|
});
|
||||||
} else if (parts.length > 1) {
|
} 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({
|
schema.options.push({
|
||||||
name: short,
|
name: short,
|
||||||
short,
|
short,
|
||||||
required: false,
|
required: false,
|
||||||
schema: parsedSchema,
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// 可选标志
|
|
||||||
schema.flags.push({ name: short, short });
|
schema.flags.push({ name: short, short });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -336,8 +342,18 @@ export function parseCommandSchema(schemaStr: string): CommandSchema {
|
||||||
const name = token.slice(2);
|
const name = token.slice(2);
|
||||||
const nextToken = tokens[i + 1];
|
const nextToken = tokens[i + 1];
|
||||||
|
|
||||||
// 检查是否有类型定义(如 --flag: boolean)
|
if (name.endsWith(':')) {
|
||||||
if (name.includes(':')) {
|
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 [optName, typeStr] = name.split(':').map(s => s.trim());
|
||||||
const parsedSchema = defineSchema(typeStr);
|
const parsedSchema = defineSchema(typeStr);
|
||||||
schema.options.push({
|
schema.options.push({
|
||||||
|
|
@ -347,23 +363,12 @@ export function parseCommandSchema(schemaStr: string): CommandSchema {
|
||||||
});
|
});
|
||||||
i++;
|
i++;
|
||||||
} else if (nextToken && nextToken.startsWith('<') && nextToken.endsWith('>')) {
|
} 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({
|
schema.options.push({
|
||||||
name,
|
name,
|
||||||
required: true,
|
required: true,
|
||||||
schema: parsedSchema,
|
|
||||||
});
|
});
|
||||||
i += 2;
|
i += 2;
|
||||||
} else {
|
} else {
|
||||||
// 否则是标志
|
|
||||||
schema.flags.push({ name });
|
schema.flags.push({ name });
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
@ -372,8 +377,19 @@ export function parseCommandSchema(schemaStr: string): CommandSchema {
|
||||||
const short = token.slice(1);
|
const short = token.slice(1);
|
||||||
const nextToken = tokens[i + 1];
|
const nextToken = tokens[i + 1];
|
||||||
|
|
||||||
// 检查是否有类型定义
|
if (short.endsWith(':')) {
|
||||||
if (short.includes(':')) {
|
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 [optName, typeStr] = short.split(':').map(s => s.trim());
|
||||||
const parsedSchema = defineSchema(typeStr);
|
const parsedSchema = defineSchema(typeStr);
|
||||||
schema.options.push({
|
schema.options.push({
|
||||||
|
|
@ -384,24 +400,13 @@ export function parseCommandSchema(schemaStr: string): CommandSchema {
|
||||||
});
|
});
|
||||||
i++;
|
i++;
|
||||||
} else if (nextToken && nextToken.startsWith('<') && nextToken.endsWith('>')) {
|
} 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({
|
schema.options.push({
|
||||||
name: short,
|
name: short,
|
||||||
short,
|
short,
|
||||||
required: true,
|
required: true,
|
||||||
schema: parsedSchema,
|
|
||||||
});
|
});
|
||||||
i += 2;
|
i += 2;
|
||||||
} else {
|
} else {
|
||||||
// 否则是标志
|
|
||||||
schema.flags.push({ name: short, short });
|
schema.flags.push({ name: short, short });
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue