const { test } = require('node:test'); const assert = require('node:assert'); const fs = require('node:fs'); const path = require('node:path'); const html = fs.readFileSync(path.join(__dirname, '..', 'index.html'), 'utf8'); function extractConst(src, name) { const m = new RegExp('const\\s+' + name + '\\s*=\\s*([^;]+);').exec(src); if (!m) throw new Error('const ' + name + ' not found'); return 'var ' + name + ' = ' + m[1] + ';\n'; } function extractFunc(src, name) { const re = new RegExp('function\\s+' + name + '\\s*\\([^)]*\\)\\s*\\{'); const m = re.exec(src); if (!m) throw new Error('function ' + name + ' not found'); let i = m.index + m[0].length - 1; let depth = 0; for (; i < src.length; i++) { if (src[i] === '{') depth++; else if (src[i] === '}') { depth--; if (depth === 0) break; } } return src.slice(m.index, i + 1); } let code = ''; for (const fn of ['cardsTarList', 'cardsRoleDefault', 'cardsRoleTar', 'cardsTarEntry', 'cardsTarMsl', 'cardsApplyFields', 'cardsApply', 'spRefreshFromPreset', 'spPorAccepted', 'spNextCntr', 'spPresetIdx', 'spPresetCounterValue', 'spCntrPlaceholder', 'spCntrEffective', 'spCntrAhead', 'spCntrAdjust', 'spKeysetKvnOf', 'spKeysetList', 'spKeysetFor', 'spKeysetCheck', 'spTarOptionsHtml', 'spTarRender', 'spSpi1Seed', 'spTarKeysetGuard', 'cardsTarKeysetCell', 'cardsTarKeysetFromForm', 'cardsTarKeysetRefresh', 'cardsTarRowsRender', 'cardsTarRowHtml', 'cardsTarsFromTable', 'cardsFreeTarsFromForm', 'cardsKeysetRowHtml', 'cardsKeysetRowsRender', 'cardsKeysetAdd', 'cardsKeysetRemove', 'cardsKeysetKvnUpdate', 'cardsKeysetsFromForm', 'spKeysetSync', 'spKeysetApply', 'ramPresetIdx', 'tarPresetIdx', 'spKeysetGuard', 'ramKeysetGuard', 'esc', ]) { code += extractFunc(html, fn) + '\n'; } code = extractConst(html, 'CARDS_TAR_DEFAULTS') + extractConst(html, 'CARDS_TAR_ROLES') + extractConst(html, 'CARDS_MSL_DEFAULT') + code; code = 'var _cardsKeysetCount = 0;\nglobalThis.spPresetWarningRender = function() {};\n' + 'globalThis.spMslWarningRender = function() {};\n' + 'globalThis.pysimApplyAvailability = function() {};\n' + code; code = 'var _genSpBuildStub = function() {};\n' + code; eval(code); globalThis._genSpBuild = () => {}; globalThis.spShowSizeInfo = () => {}; globalThis.spKeysetSync = globalThis.spKeysetSync || (() => {}); globalThis.t = s => s; // The SP form is a working copy: the preset is the source of truth, and // every SCP80/RAM operation re-reads it before starting (v3.6.3). The plain // SCP80 send keeps a hand-edited packet TAR (v3.6.21). function fakeEnv(selValue, selId, presetCntr) { const els = {}; for (const id of ['sp-spi1', 'sp-spi2-hex', 'sp-kic-idx', 'sp-kic-alg', 'sp-kid-idx', 'sp-kid-alg', 'sp-cntr', 'sp-kic-key', 'sp-kid-key']) { els[id] = { value: '' }; } // the TAR is a select (v3.26.0): the stub models the surface the renderer // touches - setting innerHTML parses the option values and selectedIndex // moves the value, like a real