Remove jieba wasm and update parser

This commit is contained in:
2026-02-02 00:00:53 +08:00
parent c3cc86160b
commit 618b2ca442
5 changed files with 2665 additions and 406 deletions

View File

@@ -108,6 +108,152 @@ export function computeStateSignature(text) {
return chunks.join('\n---\n');
}
/**
* Parse $schema block
*/
function parseSchemaBlock(basePath, schemaLines) {
const rules = [];
const nonEmpty = schemaLines.filter(l => l.trim());
if (!nonEmpty.length) return rules;
const minIndent = Math.min(...nonEmpty.map(l => l.search(/\S/)));
const yamlText = schemaLines
.map(l => (l.trim() ? l.slice(minIndent) : ''))
.join('\n');
let schemaObj;
try {
schemaObj = jsyaml.load(yamlText);
} catch (e) {
console.warn('[parser] $schema YAML parse failed:', e.message);
return rules;
}
if (!schemaObj || typeof schemaObj !== 'object') return rules;
function walk(obj, curPath) {
if (obj === null || obj === undefined) return;
if (Array.isArray(obj)) {
if (obj.length === 0) {
rules.push({
path: curPath,
rule: { typeLock: 'array', arrayGrow: true },
});
} else {
rules.push({
path: curPath,
rule: { typeLock: 'array', arrayGrow: true },
});
walk(obj[0], curPath ? `${curPath}.[*]` : '[*]');
}
return;
}
if (typeof obj !== 'object') {
const t = typeof obj;
if (t === 'string' || t === 'number' || t === 'boolean') {
rules.push({
path: curPath,
rule: { typeLock: t },
});
}
return;
}
const keys = Object.keys(obj);
if (keys.length === 0) {
rules.push({
path: curPath,
rule: { typeLock: 'object', objectExt: true },
});
return;
}
const hasWildcard = keys.includes('*');
if (hasWildcard) {
rules.push({
path: curPath,
rule: { typeLock: 'object', objectExt: true, hasWildcard: true },
});
const wildcardTemplate = obj['*'];
if (wildcardTemplate !== undefined) {
walk(wildcardTemplate, curPath ? `${curPath}.*` : '*');
}
for (const k of keys) {
if (k === '*') continue;
const childPath = curPath ? `${curPath}.${k}` : k;
walk(obj[k], childPath);
}
return;
}
rules.push({
path: curPath,
rule: { typeLock: 'object', allowedKeys: keys },
});
for (const k of keys) {
const childPath = curPath ? `${curPath}.${k}` : k;
walk(obj[k], childPath);
}
}
walk(schemaObj, basePath);
return rules;
}
/**
* Parse rule line ($ro, $range, $step, $enum)
*/
function parseRuleLine(line) {
const tokens = line.trim().split(/\s+/);
const directives = [];
let pathStart = 0;
for (let i = 0; i < tokens.length; i++) {
if (tokens[i].startsWith('$')) {
directives.push(tokens[i]);
pathStart = i + 1;
} else {
break;
}
}
const path = tokens.slice(pathStart).join(' ').trim();
if (!path || !directives.length) return null;
const rule = {};
for (const tok of directives) {
if (tok === '$ro') { rule.ro = true; continue; }
const rangeMatch = tok.match(/^\$range=\[\s*(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)\s*\]$/);
if (rangeMatch) {
rule.min = Math.min(Number(rangeMatch[1]), Number(rangeMatch[2]));
rule.max = Math.max(Number(rangeMatch[1]), Number(rangeMatch[2]));
continue;
}
const stepMatch = tok.match(/^\$step=(\d+(?:\.\d+)?)$/);
if (stepMatch) { rule.step = Math.abs(Number(stepMatch[1])); continue; }
const enumMatch = tok.match(/^\$enum=\{([^}]+)\}$/);
if (enumMatch) {
rule.enum = enumMatch[1].split(/[,、;]/).map(s => s.trim()).filter(Boolean);
continue;
}
}
return { path, rule };
}
export function parseStateBlock(content) {
const lines = String(content ?? '').split(/\r?\n/);