chore: консолидация незакоммиченной работы (биохимия + System Health + lab/textbooks)
Зафиксирована накопленная незакоммиченная работа рабочего дерева, КРОМЕ файлов учебника «Химия 7» (migration 046, chemistry_7_*.html, chem7_svg.js, тест — оставлены незакоммиченными по запросу). Включает: модуль биохимии (ядро BIO, 3D VSEPR, химдвижок, баланс, challenges, пути из БД), System Health Level 1 (вердикт/мониторинг), а также frontend- страницы и lab/textbooks-правки параллельной сессии. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const dir = path.join(__dirname, '..', '..', 'frontend', 'textbooks');
|
||||
const files = ['geometry_10_hub.html','geometry_10_r1.html','geometry_10_r2.html','geometry_10_r3.html','geometry_10_r4.html'];
|
||||
|
||||
const cmds = ['dfrac','sqrt','sin','cos','tan','angle','vec','triangle','Rightarrow','cdot','ne','le','ge','pi','alpha','beta','gamma','delta','varphi','circ','perp','parallel','frac','tfrac','overline','left','right','begin','end','boxed','cot','arcsin','arccos','arctan','log','ln','lim','sum','int','infty','Delta','theta','lambda','mu','rho','sigma','tau','omega','Omega','phi','psi','xi','zeta','eta','epsilon','varepsilon','Pi','Sigma','approx','equiv','pm','mp','times','div','leq','geq','neq','sim','cong','subset','supset','cup','cap','forall','exists','overrightarrow','overleftarrow','widehat','widetilde','mathbf','mathrm','mathbb','mathcal','quad','qquad','hline','cline','displaystyle','textstyle','scriptstyle','underline','operatorname','land','lor','lnot','mapsto','Leftrightarrow','Leftarrow','leftarrow','rightarrow','uparrow','downarrow','prime','colon'];
|
||||
|
||||
for (const f of files) {
|
||||
const fp = path.join(dir, f);
|
||||
if (!fs.existsSync(fp)) { console.log('MISSING', f); continue; }
|
||||
const txt = fs.readFileSync(fp, 'utf8');
|
||||
|
||||
const scriptRe = /<script(?![^>]*\bsrc=)[^>]*>([\s\S]*?)<\/script>/g;
|
||||
let m;
|
||||
let totalKatexErrs = 0;
|
||||
const errSamples = [];
|
||||
let scriptBlocks = 0;
|
||||
let combinedJs = '';
|
||||
|
||||
while ((m = scriptRe.exec(txt)) !== null) {
|
||||
scriptBlocks++;
|
||||
const body = m[1];
|
||||
combinedJs += body + ';\n';
|
||||
const cmdRe = /(^|[^\\])\\([a-zA-Z]+)/g;
|
||||
let cm;
|
||||
while ((cm = cmdRe.exec(body)) !== null) {
|
||||
const cmd = cm[2];
|
||||
if (cmds.includes(cmd)) {
|
||||
totalKatexErrs++;
|
||||
const idxAbs = m.index + cm.index + cm[1].length;
|
||||
const before = txt.slice(0, idxAbs);
|
||||
const line = (before.match(/\n/g) || []).length + 1;
|
||||
if (errSamples.length < 10) errSamples.push({line, cmd, ctx: body.slice(Math.max(0,cm.index-30), cm.index+50).replace(/\n/g,' ')});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// <option> raw KaTeX
|
||||
const optRe = /<option[^>]*>([\s\S]*?)<\/option>/g;
|
||||
let om;
|
||||
let optionRaw = 0;
|
||||
const optionSamples = [];
|
||||
while ((om = optRe.exec(txt)) !== null) {
|
||||
const content = om[1];
|
||||
if (/\$[^\$]+\$/.test(content) || /\\(dfrac|sqrt|frac|angle|vec|sin|cos|alpha|beta|pi|circ|triangle|Rightarrow)/.test(content)) {
|
||||
optionRaw++;
|
||||
const before = txt.slice(0, om.index);
|
||||
const line = (before.match(/\n/g) || []).length + 1;
|
||||
if (optionSamples.length < 8) optionSamples.push({line, content: content.slice(0,90)});
|
||||
}
|
||||
}
|
||||
|
||||
// Emoji
|
||||
const emojiRe = /[\u{1F300}-\u{1FAFF}\u{1F000}-\u{1F02F}\u{2700}-\u{27BF}\u{2600}-\u{26FF}]/gu;
|
||||
let em;
|
||||
let emoji = 0;
|
||||
const emojiSamples = [];
|
||||
while ((em = emojiRe.exec(txt)) !== null) {
|
||||
emoji++;
|
||||
const before = txt.slice(0, em.index);
|
||||
const line = (before.match(/\n/g) || []).length + 1;
|
||||
if (emojiSamples.length < 10) emojiSamples.push({line, ch: em[0], cp: em[0].codePointAt(0).toString(16), ctx: txt.slice(Math.max(0,em.index-25), em.index+25).replace(/\n/g,' ')});
|
||||
}
|
||||
|
||||
let authors = [];
|
||||
if (f.includes('hub')) {
|
||||
for (const a of ['Латотин','Чеботаревский','Горбунова','Шлыков']) {
|
||||
if (txt.includes(a)) authors.push(a);
|
||||
}
|
||||
}
|
||||
|
||||
let parseErr = null;
|
||||
try { new Function(combinedJs); } catch(e) { parseErr = e.message.slice(0,200); }
|
||||
|
||||
console.log('=== ' + f + ' ===');
|
||||
console.log(' size:', txt.length, 'scripts:', scriptBlocks);
|
||||
console.log(' KaTeX single-backslash errors:', totalKatexErrs);
|
||||
for (const s of errSamples) console.log(' line ' + s.line + ' \\' + s.cmd + ' ctx: ' + s.ctx);
|
||||
console.log(' <option> raw KaTeX:', optionRaw);
|
||||
for (const s of optionSamples) console.log(' line ' + s.line + ': ' + s.content);
|
||||
console.log(' Emoji symbols:', emoji);
|
||||
for (const s of emojiSamples) console.log(' line ' + s.line + ' U+' + s.cp + ' ctx: ' + s.ctx);
|
||||
if (authors.length) console.log(' Authors in hub:', authors.join(', '));
|
||||
console.log(' JS parse:', parseErr ? 'ERROR: ' + parseErr : 'OK');
|
||||
}
|
||||
Reference in New Issue
Block a user