Files
brain/tools/secretary-armor.mjs
T

52 lines
3.3 KiB
JavaScript

// tools/secretary-armor.mjs
// Детерминированный разбор/спасение ответов флэша (принцип В1).
export const normLens = (l) => {
const t = String(l || '').trim().replace(/^л/i, 'Л');
return /^Л\d$/.test(t) ? t : (/^\d$/.test(t) ? 'Л' + t : t || 'Л?');
};
const ОПОРЫ = ['внутр', 'внеш', 'воля', 'догадка'];
const ОП_SYN = {
внутренний: 'внутр', код: 'внутр', файл: 'внутр', проект: 'внутр', обмен: 'внутр', реплика: 'внутр',
ответ: 'внутр', цитата: 'внутр', текст: 'внутр', строка: 'внутр', внешний: 'внеш', url: 'внеш',
веб: 'внеш', док: 'внеш', документация: 'внеш', владелец: 'воля', юзер: 'воля', пользователь: 'воля',
запрос: 'воля', директива: 'воля', гипотеза: 'догадка', предположение: 'догадка', домысел: 'догадка',
незавершённый: 'догадка', неизвестно: 'догадка',
};
/** Паспорт-опора -> ровно одно слово словаря; неизвестное -> честно «догадка». */
export function one(raw) {
const w = String(raw || '').trim().toLowerCase().split(/[\s,;:|]+/)[0].replace(/[.,;:]+$/, '');
if (ОПОРЫ.includes(w)) return w;
return ОП_SYN[w] || 'догадка';
}
/** Спасение по-объектно: лезем В массив […] и парсим КАЖДЫЙ объект; битый пропускаем. */
export function salvageObjects(text) {
const lb = text.indexOf('['), rb = text.lastIndexOf(']');
const body = (lb >= 0 && rb > lb) ? text.slice(lb + 1, rb) : text;
const out = [];
let depth = 0, start = -1, inStr = false, esc = false;
for (let i = 0; i < body.length; i++) {
const c = body[i];
if (inStr) { if (esc) esc = false; else if (c === '\\') esc = true; else if (c === '"') inStr = false; continue; }
if (c === '"') inStr = true;
else if (c === '{') { if (depth === 0) start = i; depth++; }
else if (c === '}') { depth--; if (depth === 0 && start >= 0) { const chunk = body.slice(start, i + 1).replace(/,(\s*[}\]])/g, '$1'); try { out.push(JSON.parse(chunk)); } catch { /* битый — пропустить */ } start = -1; } }
}
return out;
}
/** Толерантный парсер: ```-обёртка, висячая запятая, голый массив/объект; слом -> спасение по-объектно. */
export function parseLoose(text, expectKey) {
let s = String(text || '').trim().replace(/^```(?:json)?\s*\n?/i, '').replace(/\n?```$/, '').trim();
const obj = s.indexOf('{'), arr = s.indexOf('[');
if (obj >= 0 || arr >= 0) { const start = arr < 0 ? obj : obj < 0 ? arr : Math.min(obj, arr); s = s.slice(start); }
s = s.replace(/,(\s*[}\]])/g, '$1');
let p; try { p = JSON.parse(s); }
catch { const salv = salvageObjects(s); return { [expectKey]: salv.length ? salv : [] }; }
if (Array.isArray(p)) return { [expectKey]: p };
if (p && typeof p === 'object') { if (!Array.isArray(p[expectKey])) p[expectKey] = p[expectKey] ? [p[expectKey]] : []; return p; }
return { [expectKey]: [] };
}