feat: details
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
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> = {};
|
||||
|
||||
// 匹配键值对:key=value 或 key="value with spaces"
|
||||
const regex = /(\w+)=(?:"([^"]*)"|'([^']*)'|([^\s]+))/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;
|
||||
}
|
||||
Reference in New Issue
Block a user