2026-07-30 15:13:53 +09:00
'use strict' ;
const fs = require ( 'fs' ) ;
const path = require ( 'path' ) ;
const vm = require ( 'vm' ) ;
const root = path . resolve ( _ _dirname , '../..' ) ;
const read = name => fs . readFileSync ( path . join ( root , name ) , 'utf8' ) ;
2026-07-31 12:54:46 +09:00
const app = read ( 'app.js' ) , html = read ( 'index.html' ) , css = ` ${ read ( 'style.css' ) } \n ${ read ( 'client/styles/tokens.css' ) } \n ${ read ( 'client/styles/base.css' ) } \n ${ read ( 'client/ui/cursor.css' ) } \n ${ read ( 'client/styles/accessibility.css' ) } ` , worker = read ( 'puzzle-worker.js' ) , appLogicSource = read ( 'app-logic.js' ) , buildMetaSource = read ( 'build-meta.js' ) ;
const buildMeta = require ( path . join ( root , 'build-meta.js' ) ) ;
2026-07-30 15:13:53 +09:00
function assert ( value , message ) { if ( ! value ) throw new Error ( message ) }
function functionSource ( name , source = app ) {
let start = source . indexOf ( ` async function ${ name } ( ` ) ; if ( start < 0 ) start = source . indexOf ( ` function* ${ name } ( ` ) ; if ( start < 0 ) start = source . indexOf ( ` function ${ name } ( ` ) ;
assert ( start >= 0 , ` Missing ${ name } ` ) ;
let paren = source . indexOf ( '(' , start ) , parenDepth = 0 , body = - 1 ;
for ( let i = paren ; i < source . length ; i ++ ) {
if ( source [ i ] === '(' ) parenDepth ++ ;
else if ( source [ i ] === ')' && -- parenDepth === 0 ) { body = source . indexOf ( '{' , i ) ; break }
}
assert ( body >= 0 , ` Missing body for ${ name } ` ) ; let depth = 0 ;
for ( let i = body ; i < source . length ; i ++ ) {
if ( source [ i ] === '{' ) depth ++ ;
else if ( source [ i ] === '}' && -- depth === 0 ) return source . slice ( start , i + 1 ) ;
}
throw new Error ( ` Unclosed ${ name } ` ) ;
}
function createContext ( context = { } ) { vm . createContext ( context ) ; return context }
function runFunctions ( names , context , expose = names ) {
createContext ( context ) ;
const sources = names . map ( name => functionSource ( name ) ) . join ( '\n' ) ;
vm . runInContext ( ` ${ sources } \n this.logic={ ${ expose . join ( ',' ) } }; ` , context ) ;
return context . logic ;
}
function loadBendPuzzle ( ) {
delete global . BendPuzzle ;
delete require . cache [ require . resolve ( path . join ( root , 'puzzle-core.js' ) ) ] ;
require ( path . join ( root , 'puzzle-core.js' ) ) ;
return global . BendPuzzle ;
}
function loadAppLogic ( ) {
delete require . cache [ require . resolve ( path . join ( root , 'app-logic.js' ) ) ] ;
return require ( path . join ( root , 'app-logic.js' ) ) ;
}
function starterPuzzle ( ) {
const match = app . match ( / c o n s t S T A R T E R _ P U Z Z L E = O b j e c t \ . f r e e z e \ ( ( \ { . * \ } ) \ ) ; \ n c o n s t S C O R E _ V E R S I O N / s ) ;
assert ( match , 'Bundled origin puzzle missing' ) ;
return JSON . parse ( match [ 1 ] ) ;
}
2026-07-31 12:54:46 +09:00
module . exports = { root , read , app , html , css , worker , appLogicSource , buildMetaSource , buildMeta , assert , functionSource , createContext , runFunctions , loadBendPuzzle , loadAppLogic , starterPuzzle , vm , path , fs } ;