// Build in a private source copy; never writes the installed SGF or dependencies. import fs from 'node:fs'; import path from 'node:path'; import crypto from 'node:crypto'; import {spawnSync} from 'node:child_process'; const host=fs.realpathSync(process.argv[2]||''); if(fs.existsSync(path.join(host,'public/hot')))throw Error('Stop the source frontend watcher before freezing a candidate.'); const work=path.join('C:/laragon/data/sgf-tempo/run','candidate-ui-'+crypto.randomBytes(6).toString('hex')); fs.mkdirSync(work,{recursive:true}); const replace=(text,old,next)=>{if(text.split(old).length!==2)throw Error('Frontend baseline changed: '+old.slice(0,70));return text.replace(old,next);}; fs.cpSync(path.join(host,'resources'),path.join(work,'resources'),{recursive:true}); for(const file of ['package.json','vite.config.js'])fs.copyFileSync(path.join(host,file),path.join(work,file)); fs.mkdirSync(path.join(work,'public/build'),{recursive:true}); fs.symlinkSync(path.join(host,'node_modules'),path.join(work,'node_modules'),'junction'); let app=fs.readFileSync(path.join(work,'resources/js/app.jsx'),'utf8'); app=replace(app,"const options = (unit === null ? ['company.view', 'company.edit', 'unit.create', 'access.manage'] : ['unit.view', 'unit.edit']).filter(p => can(p, unit));", "const options = (list?.catalogue?.[unit === null ? 'company' : 'unit'] ?? []).filter(p => can(p, unit));"); app=replace(app,'{labels[p]}','{list?.catalogue_labels?.[p] ?? labels[p] ?? p}'); app=replace(app,'{labels[g.permission]}','{list?.catalogue_labels?.[g.permission] ?? labels[g.permission] ?? g.permission}'); fs.writeFileSync(path.join(work,'resources/js/app.jsx'),app); let home=fs.readFileSync(path.join(work,'resources/js/PurchasingHome.jsx'),'utf8'); home=replace(home,"const payables=unit!==null&&can('supplier_payables.view',unit);", "const payables=unit!==null&&can('supplier_payables.view',unit);\n const requisitions=unit!==null&&can('purchasing_requisitions.view',unit);"); home=replace(home,'