#!/usr/bin/env node /* Restauración v3: TODAS las funciones/globales que el parche borró de inventory.js (comparando HEAD vs actual por referencias de templates + exposiciones window). */ const fs = require('fs'); const { execSync } = require('child_process'); const old = execSync('git show HEAD:pos/static/js/inventory.js', { maxBuffer: 20 * 1024 * 1024 }).toString(); let cur = fs.readFileSync('pos/static/js/inventory.js', 'utf8'); // 1. Identificadores referenciados por templates (onclick/onchange/oninput/onkeydown) const tpl = fs.readFileSync('pos/templates/inventory.html', 'utf8'); const handlers = new Set(); const reH = /on(?:click|change|input|keydown|keyup|blur|focus)="([^"]+)"/g; let m; while ((m = reH.exec(tpl))) { const body = m[1]; const reId = /([A-Za-z_$][\w$]*)\s*\(/g; let mm; while ((mm = reId.exec(body))) { const fn = mm[1]; if (!['if', 'event', 'this', 'return', 'parseInt', 'parseFloat', 'String', 'Number', 'confirm', 'alert'].includes(fn)) { handlers.add(fn); } } } // 2. window.X = X sin definición en el archivo actual const exposeRe = /window\.([A-Za-z_$][\w$]*)\s*=\s*\1\b/g; const exposed = new Set(); while ((m = exposeRe.exec(cur))) exposed.add(m[1]); // 3. Referencias directas dentro del JS (llamadas sin definición) const calledMissing = []; for (const name of handlers) { const defined = new RegExp('function\\s+' + name + '\\b').test(cur) || new RegExp('\\b' + name + '\\s*=\\s*function').test(cur) || cur.includes('window.' + name + ' '); if (!defined) calledMissing.push(name); } console.log('handlers de template SIN definición:', calledMissing); console.log('exposiciones window sin función:', [...exposed].filter(n => !new RegExp('function\\s+' + n + '\\b').test(cur) && !new RegExp('\\b' + n + '\\s*=\\s*function').test(cur))); // 4. extraer de HEAD cada función faltante (por marcadores de 4 espacios) function extractFrom(src, name) { const start = src.indexOf('\n function ' + name + '('); if (start === -1) return null; let end = src.length; const nf = src.indexOf('\n function ', start + 30); const nm = src.indexOf('\n // =====================================================================', start + 30); if (nf !== -1) end = Math.min(end, nf); if (nm !== -1) end = Math.min(end, nm); return src.slice(start + 1, end); } const need = new Set([...calledMissing]); for (const n of exposed) { if (!new RegExp('function\\s+' + n + '\\b').test(cur)) need.add(n); } const blocks = []; for (const name of need) { const b = extractFrom(old, name); if (b) blocks.push(b.trimEnd()); else console.log(' (no está en HEAD: ' + name + ')'); } if (blocks.length) { const anchor = '\n // =====================================================================\n // EXPOSE GLOBALS (for onclick handlers in HTML)'; const idx = cur.indexOf(anchor); if (idx === -1) { console.log('ERROR: anchor no encontrado'); process.exit(1); } cur = cur.slice(0, idx) + '\n // ==== RESTAURADAS v3 ====\n\n' + blocks.join('\n\n') + '\n' + cur.slice(idx); fs.writeFileSync('pos/static/js/inventory.js', cur); console.log('restauradas ' + blocks.length + ' funciones'); }