Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114#!/usr/bin/env node// embed-objects.mjs — carry the object compiler (xbox/live/object-lisp.mjs)// and the objects the game draws (xbox/live/objects/*.lisp) into oskiewar.js.//// The game is one global script every platform loads as-is, so it can't// import the compiler the object lab uses. This writes it into a sealed block// between markers, in its own scope, with each object's source as a string,// and exposes one global, `gameObjects`: each object compiled — and so baked// — once, the first time the game asks for it. The lab and the game run the same compiler// on the same source.//// node xbox/tools/embed-objects.mjs rewrite the block// node xbox/tools/embed-objects.mjs --check exit 1 if the block is stale
import { readFileSync, writeFileSync } from "node:fs";import { fileURLToPath } from "node:url";
const live = new URL("../live/", import.meta.url);const read = (name) => readFileSync(new URL(name, live), "utf8");export const gamePath = fileURLToPath(new URL("oskiewar.js", live));export const start = "// <objects>";export const end = "// </objects>";
// What the game draws, by the name it asks for: the source file each is// compiled from. The monowheel is drawn flat, and figures are, behind a flag// (OBJECT-DIALECT.md).export const objects = { monowheel: "monowheel-flat", figure: "figure-flat" };
// A module's source with its `export` keywords taken off, and the names it// exported.function unexport(source) { const names = []; const body = source.replace(/^export (async function\*?|function\*?|const|let|class) (\w+)/gm, (_, kind, name) => { names.push(name); return `${kind} ${name}`; }); return { body, names };}
export function generate() { const lisp = unexport(read("object-lisp.mjs")); if (/^import /m.test(lisp.body)) throw new Error("object-lisp.mjs: the game can't carry imports"); // The .ow package reader rides along (xbox/OW-FORMAT.md): a level and its // objects arrive as one text, and the game reads it with the same reader. const ow = unexport(read("ow.mjs")); if (/^import /m.test(ow.body)) throw new Error("ow.mjs: the game can't carry imports"); const indent = (text) => text.trimEnd().split("\n").map((line) => (line ? " " + line : line)).join("\n"); const sources = Object.entries(objects).map(([name, file]) => ` ${name}: ${JSON.stringify(read(`objects/${file}.lisp`))},`); return [ start, "// Generated from xbox/live/object-lisp.mjs and xbox/live/objects/*.lisp by", "// xbox/tools/embed-objects.mjs. Don't edit here: edit those, try them in", "// xbox/live/object-lab.html, then rerun the tool.", "const gameObjects = (() => {", " const objectLisp = (() => {", indent(lisp.body), ` return { ${lisp.names.join(", ")} };`, " })();", " const owLisp = (() => {", indent(ow.body), ` return { ${ow.names.join(", ")} };`, " })();", " const sources = {", ...sources, " };", " // Each compiled (and baked) the first time it is asked for, not at load:", " // an object the game never draws costs nothing.", " const objects = { light: objectLisp.objectLight, drawFigureShapes: objectLisp.drawFigureShapes, read: objectLisp.read, ow: owLisp };", " const compiled = {};", " const ask = (name) => Object.defineProperty(objects, name, { configurable: true,", " get: () => compiled[name] || (compiled[name] = objectLisp.compile(sources[name], name)) });", " for (const name in sources) ask(name);", " // A .ow package can bring its own object by a name the game draws: the", " // next ask compiles the new source. `sources()` lists what it carries.", " objects.define = (name, source) => { sources[name] = source; delete compiled[name]; ask(name); };", " objects.sources = () => Object.keys(sources);", " return objects;", "})();", end, ].join("\n");}
// Where the block goes the first time: just before the monowheel it draws.const anchor = "function drawMonowheel(";
export function embedded(source = readFileSync(gamePath, "utf8")) { const a = source.indexOf(start), b = source.indexOf(end); return a < 0 || b < 0 ? null : source.slice(a, b + end.length);}
function write() { const source = readFileSync(gamePath, "utf8"), block = generate(); const current = embedded(source); let next; if (current) next = source.replace(current, () => block); else { const at = source.indexOf(anchor); if (at < 0) throw new Error("oskiewar.js: can't find where the objects go"); next = source.slice(0, at) + block + "\n" + source.slice(at); } if (next !== source) writeFileSync(gamePath, next); return next !== source;}
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) { if (process.argv.includes("--check")) { const fresh = embedded() === generate(); console.log(fresh ? "objects in oskiewar.js are current" : "objects in oskiewar.js are stale: run node xbox/tools/embed-objects.mjs"); process.exit(fresh ? 0 : 1); } console.log(write() ? "embedded the objects into oskiewar.js" : "objects already current");}