115 lines
2.8 KiB
TypeScript
115 lines
2.8 KiB
TypeScript
import type { TrackerAttribute } from "../types";
|
|
|
|
export interface ParsedEmmet {
|
|
tag: string;
|
|
id?: string;
|
|
classes: string[];
|
|
attributes: Record<string, TrackerAttribute>;
|
|
}
|
|
|
|
/**
|
|
* 解析 Emmet 风格的 tracker 语法
|
|
* 格式:tag#id.class1.class2[attr1=value1 attr2=value2]
|
|
* 示例:npc#john.dwarf.warrior[hp=4/4 ac=15 name="John the Dwarf"]
|
|
*/
|
|
export function parseEmmet(input: string): ParsedEmmet {
|
|
const result: ParsedEmmet = {
|
|
tag: "",
|
|
classes: [],
|
|
attributes: {},
|
|
};
|
|
|
|
if (!input) return result;
|
|
|
|
// 匹配属性部分 [...]
|
|
const attrMatch = input.match(/\[(.+)\]$/);
|
|
let attrString: string | undefined;
|
|
let mainPart: string;
|
|
|
|
if (attrMatch) {
|
|
attrString = attrMatch[1];
|
|
mainPart = input.slice(0, attrMatch.index);
|
|
} else {
|
|
mainPart = input;
|
|
}
|
|
|
|
// 解析 tag、id 和 classes
|
|
// 格式:tag#id.class1.class2.class3
|
|
const tagClassMatch = mainPart.match(/^([^#.\s]+)?(?:#([^.\s]+))?(?:\.([^.]+(?:\.[^.]+)*))?/);
|
|
|
|
if (tagClassMatch) {
|
|
if (tagClassMatch[1]) {
|
|
result.tag = tagClassMatch[1];
|
|
}
|
|
if (tagClassMatch[2]) {
|
|
// # 后面的是 ID,不是 class
|
|
result.id = tagClassMatch[2];
|
|
}
|
|
if (tagClassMatch[3]) {
|
|
result.classes.push(...tagClassMatch[3].split("."));
|
|
}
|
|
}
|
|
|
|
// 解析属性
|
|
if (attrString) {
|
|
result.attributes = parseAttributes(attrString);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* 解析属性字符串
|
|
* 支持格式:
|
|
* - hp=4/4 (progress 类型,自动检测)
|
|
* - count=5 (count 类型,纯数字)
|
|
* - name="John" (string 类型,带引号)
|
|
* - name=John (string 类型,不带引号)
|
|
*/
|
|
function parseAttributes(attrString: string): Record<string, TrackerAttribute> {
|
|
const attributes: Record<string, TrackerAttribute> = {};
|
|
|
|
// 匹配键值对:使用,分隔
|
|
const regex = /(\w+)=(?:"([^"]*)"|'([^']*)'|([^,]+))/g;
|
|
let match: RegExpExecArray | null;
|
|
|
|
while ((match = regex.exec(attrString)) !== null) {
|
|
const key = match[1];
|
|
// 匹配的值可能是第 2、3 或 4 组(取决于引号类型)
|
|
const value = match[2] ?? match[3] ?? match[4] ?? "";
|
|
|
|
// 自动检测类型
|
|
let attr: TrackerAttribute;
|
|
|
|
// 检查是否是 progress 格式 (x/y)
|
|
const progressMatch = value.match(/^(\d+)\/(\d+)$/);
|
|
if (progressMatch) {
|
|
attr = {
|
|
name: key,
|
|
type: "progress",
|
|
value: { x: parseInt(progressMatch[1]), y: parseInt(progressMatch[2]) },
|
|
};
|
|
}
|
|
// 检查是否是纯数字(count 类型)
|
|
else if (/^\d+$/.test(value)) {
|
|
attr = {
|
|
name: key,
|
|
type: "count",
|
|
value: parseInt(value),
|
|
};
|
|
}
|
|
// 默认 string 类型
|
|
else {
|
|
attr = {
|
|
name: key,
|
|
type: "string",
|
|
value: value.replace(/^["']|["']$/g, ""), // 移除可能的引号
|
|
};
|
|
}
|
|
|
|
attributes[key] = attr;
|
|
}
|
|
|
|
return attributes;
|
|
}
|