56 lines
3.4 KiB
JavaScript
56 lines
3.4 KiB
JavaScript
#!/usr/bin/env node
|
||
// Exporteert de standaardmodellen van de configurator (HouseModel.MODELS) als house-design-JSON,
|
||
// precies zoals Bestand › Opslaan in de configurator ze wegschrijft.
|
||
// Gebruik: node tools/export-models.js [pad-naar-configurator] [uitvoermap]
|
||
// Standaard: ../configurator → demo/modellen/
|
||
'use strict';
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
const vm = require('vm');
|
||
|
||
const root = path.dirname(__dirname);
|
||
const SRC = path.resolve(process.argv[2] || path.join(root, '..', 'configurator'));
|
||
const OUT = path.resolve(process.argv[3] || path.join(root, 'demo', 'modellen'));
|
||
|
||
// De rekenmodules in de volgorde van light.html; alleen wat nodig is om een model op te bouwen.
|
||
const SCRIPTS = [
|
||
'js/vendor/three.min.js', 'js/core/geometry.js', 'js/core/view-layers.js', 'js/wall/kozijn-model.js',
|
||
'js/core/ui-kit.js', 'js/wall/wall-model.js', 'js/floor/floor-model.js', 'js/roof/roof-model.js', 'js/roof/post-model.js',
|
||
'js/lighting/lighting-model.js', 'js/elektra/elektra-model.js', 'js/sandwich/sandwich-model.js', 'js/wall/wall.js', 'js/floor/floor.js',
|
||
'js/unit/unit-model.js', 'js/room/room-model.js', 'js/interior/fixture-model.js',
|
||
'js/house/chimney-model.js', 'js/house/house-model.js'
|
||
];
|
||
|
||
// Minimale browseromgeving: de modules raken het DOM alleen bij het tekenen, niet bij het opbouwen.
|
||
const noop = () => {};
|
||
const el = () => new Proxy(function () {}, { get: (t, k) => (k === Symbol.toPrimitive ? () => '' : el()), apply: () => el(), construct: () => el() });
|
||
const ctx = { console, Math, JSON, Date, setTimeout, clearTimeout, URL, Blob: function () {}, Image: function () { return el(); } };
|
||
ctx.window = ctx; ctx.self = ctx; ctx.globalThis = ctx;
|
||
ctx.document = { createElement: () => el(), getElementById: () => null, querySelector: () => null, querySelectorAll: () => [], addEventListener: noop, head: el(), body: el(), currentScript: null };
|
||
ctx.navigator = { userAgent: 'node', platform: 'node', maxTouchPoints: 0 };
|
||
ctx.location = { href: 'http://localhost/', search: '' };
|
||
ctx.fetch = () => Promise.reject(new Error('geen fetch'));
|
||
ctx.addEventListener = noop;
|
||
vm.createContext(ctx);
|
||
for (const s of SCRIPTS) {
|
||
const file = path.join(SRC, s);
|
||
// const/let op het hoogste niveau blijven in het script; zet de modulenamen expliciet op het globale object.
|
||
let code = fs.readFileSync(file, 'utf8');
|
||
const names = [...code.matchAll(/^(?:const|let|var|class)\s+([A-Z][A-Za-z0-9_]*)\s*=?/gm)].map(m => m[1]);
|
||
code += '\n' + names.map(n => `try { globalThis.${n} = ${n}; } catch (e) {}`).join('\n');
|
||
vm.runInContext(code, ctx, { filename: file });
|
||
}
|
||
|
||
const version = (fs.readFileSync(path.join(SRC, 'js/app.js'), 'utf8').match(/APP_VERSION\s*=\s*['"]([^'"]+)/) || [])[1] || '';
|
||
fs.mkdirSync(OUT, { recursive: true });
|
||
const index = [];
|
||
for (const [key, def] of Object.entries(ctx.HouseModel.MODELS)) {
|
||
const state = ctx.HouseModel.normalize(ctx.HouseModel.clone(def.create()));
|
||
state.project = Object.assign({}, state.project, { naam: state.project.naam || def.label });
|
||
const design = { type: 'house-design', version: 1, exportedAt: new Date().toISOString(), model: key, configurator: version, ...state };
|
||
fs.writeFileSync(path.join(OUT, `${key}.json`), JSON.stringify(design));
|
||
index.push({ key, label: def.label });
|
||
console.log(`${key}.json ${def.label} (${state.units.length} units)`);
|
||
}
|
||
fs.writeFileSync(path.join(OUT, 'index.json'), JSON.stringify({ configurator: version, models: index }, null, 2) + '\n');
|