Remove jieba wasm and update parser
This commit is contained in:
@@ -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/);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user