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']; // hub footer check const hub = fs.readFileSync(path.join(dir,'geometry_10_hub.html'),'utf8'); const footerMatch = hub.match(//); console.log('HUB FOOTER:'); if (footerMatch) console.log(footerMatch[0].slice(0,400)); else console.log(' NOT FOUND'); // g3d.js usage console.log('\\n3D ENGINE / g3d.js usage:'); for (const f of files) { const txt = fs.readFileSync(path.join(dir, f), 'utf8'); const has3d = /g3d/i.test(txt); const hasProj = /(project|perspective|3d|threejs|three\.)/i.test(txt); const hasViewBox = (txt.match(/viewBox/g) || []).length; console.log(' ' + f + ' g3d:'+has3d+' proj/3d:'+hasProj+' viewBox count:'+hasViewBox); } // Structure: count §, finals, "Я прочитал" buttons console.log('\\nSTRUCTURE:'); for (const f of files) { if (f.includes('hub')) continue; const txt = fs.readFileSync(path.join(dir, f), 'utf8'); // sections: pattern in TOC const sectionIds = []; const re = /id:\s*['"]([^'"]+)['"]\s*,\s*num:\s*['"]([^'"]*)['"]/g; let mm; while ((mm = re.exec(txt)) !== null) sectionIds.push({id:mm[1], num:mm[2]}); // theory blocks const theoryCount = (txt.match(/theory|teor|Теори/g) || []).length; // interactive: int1/int2/int3/int4 or class const intCount = (txt.match(/data-int|intCanvas|interactive/g) || []).length; // "Я прочитал" const yaProch = (txt.match(/Я прочитал/g) || []).length; // markRead const markRead = (txt.match(/markRead|markAsRead|читал/g) || []).length; console.log(' ' + f + ':'); console.log(' sections in TOC:', sectionIds.map(s=>s.num+':'+s.id).join(' ')); console.log(' theoryCount mentions:', theoryCount, 'interactive mentions:', intCount, '"Я прочитал":', yaProch); } // Look for slider px ranges 40..150, R=120 etc. console.log('\\nSLIDER PIXEL CHECK (range/value hints):'); for (const f of files) { if (f.includes('hub')) continue; const txt = fs.readFileSync(path.join(dir, f), 'utf8'); // Find input range with suspicious min/max const ranges = [...txt.matchAll(/]*type=["']range["'][^>]*>/g)]; let suspicious = 0; for (const r of ranges) { const tag = r[0]; const min = (tag.match(/min=["']?(\d+)/)||[])[1]; const max = (tag.match(/max=["']?(\d+)/)||[])[1]; if (min && max) { const lo=+min, hi=+max; if ((lo>=30 && hi>=120) || (hi-lo>=60 && hi>=100)) { suspicious++; if (suspicious<=5) { const idx = r.index; const line = (txt.slice(0,idx).match(/\n/g)||[]).length+1; console.log(' ' + f + ' line '+line+': '+tag.slice(0,140)); } } } } console.log(' ' + f + ': total ranges=' + ranges.length + ' suspicious(px-like)=' + suspicious); } // Check "px" usage near labels (R = , a =, etc.) console.log('\\nLABEL "R=" / "a=" PATTERNS:'); for (const f of files) { if (f.includes('hub')) continue; const txt = fs.readFileSync(path.join(dir, f), 'utf8'); // Find patterns like 'R = ${...}' or text="R = ${r}" where r might be px const pat = /['"`][^'"`]*\b(R|a|h|d|l|r|b|c)\s*=\s*\$\{[^}]+\}/g; const matches = []; let mm; while ((mm = pat.exec(txt)) !== null) { if (matches.length < 6) { const idx = mm.index; const line = (txt.slice(0,idx).match(/\n/g)||[]).length+1; matches.push({line, snip: mm[0].slice(0,80)}); } } if (matches.length) { console.log(' ' + f + ':'); for (const x of matches) console.log(' line '+x.line+': '+x.snip); } }