The standalone build's source list is explicit, so the two modules the previous commit added were called by validator.js inside XZBT.html without being defined there. Both are now bundled ahead of validator.js and resolution.js, which are their only consumers. visual-validation.js used a local isPlainObject that would have collided with validator.js's own once the bundler strips imports and concatenates into one scope; it uses the shared isRecord of types.js instead. The rebuilt artifact parses and carries validateVisualSubsystem and matchVisualTarget. npm test remains at 131 passing. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_0162Jb1J36judZNT8fHabGVt
69 lines
2.7 KiB
JavaScript
69 lines
2.7 KiB
JavaScript
#!/usr/bin/env node
|
|
import { createHash } from 'node:crypto';
|
|
import { readFileSync, writeFileSync } from 'node:fs';
|
|
import { dirname, resolve } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
const sourceFiles = Object.freeze([
|
|
'src/runtime/constants.js',
|
|
'src/runtime/diagnostics.js',
|
|
'src/runtime/rng.js',
|
|
'src/runtime/types.js',
|
|
'src/runtime/values.js',
|
|
'src/runtime/audio-contract.js',
|
|
'src/runtime/audio-protection.js',
|
|
'src/runtime/audio-automation.js',
|
|
'src/runtime/audio-graph.js',
|
|
'src/runtime/audio-controls.js',
|
|
'src/runtime/visual-contract.js',
|
|
'src/runtime/visual-validation.js',
|
|
'src/runtime/validator.js',
|
|
'src/runtime/persistence.js',
|
|
'src/runtime/library.js',
|
|
'src/runtime/resolution.js',
|
|
'src/runtime/actions.js',
|
|
'src/runtime/performance.js',
|
|
'src/runtime/activation.js',
|
|
'src/runtime/audio-engine.js',
|
|
'src/runtime/app.js'
|
|
]);
|
|
|
|
function normalized(path) {
|
|
return readFileSync(resolve(repositoryRoot, path), 'utf8').replace(/\r\n/g, '\n');
|
|
}
|
|
|
|
function bundleModule(source, path) {
|
|
const withoutImports = source.replace(/^import\s+[\s\S]*?\s+from\s+['"][^'"]+['"];\s*$/gm, '');
|
|
const withoutExports = withoutImports.replace(/\bexport\s+/g, '');
|
|
return `\n/* ${path} */\n${withoutExports.trim()}\n`;
|
|
}
|
|
|
|
export function bundleRuntime(includeApp = true) {
|
|
return sourceFiles.filter(path => includeApp || path !== 'src/runtime/app.js')
|
|
.map(path => bundleModule(normalized(path), path)).join('');
|
|
}
|
|
|
|
export function buildStandalone(outputPath = resolve(repositoryRoot, 'XZBT.html')) {
|
|
const template = normalized('src/XZBT.template.html');
|
|
const styles = normalized('src/styles.css').trim();
|
|
const script = `'use strict';\n(() => {\n${bundleRuntime()}\n})();`;
|
|
if (!template.includes('/*__XZBT_STYLES__*/') || !template.includes('/*__XZBT_SCRIPT__*/')) {
|
|
throw new Error('Standalone template is missing a build placeholder.');
|
|
}
|
|
const artifact = template
|
|
.replace('/*__XZBT_STYLES__*/', () => styles)
|
|
.replace('/*__XZBT_SCRIPT__*/', () => script)
|
|
.replace(/\r\n/g, '\n');
|
|
writeFileSync(outputPath, artifact, 'utf8');
|
|
return { outputPath, bytes: Buffer.byteLength(artifact), sha256: createHash('sha256').update(artifact).digest('hex') };
|
|
}
|
|
|
|
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
const outputIndex = process.argv.indexOf('--output');
|
|
const outputPath = outputIndex >= 0 ? resolve(process.argv[outputIndex + 1]) : resolve(repositoryRoot, 'XZBT.html');
|
|
const result = buildStandalone(outputPath);
|
|
console.log(`Built ${result.outputPath}`);
|
|
console.log(`SHA-256 ${result.sha256} (${result.bytes} bytes)`);
|
|
}
|