feat: export portable native road packages
This commit is contained in:
56
src/export/native-road-package.js
Normal file
56
src/export/native-road-package.js
Normal file
@@ -0,0 +1,56 @@
|
||||
"use strict";
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const { zipSync } = require("fflate");
|
||||
const { LAYER_REGISTRY, validatePublishedLayers } = require("../compile/layer-manifest");
|
||||
|
||||
const ROOT_FILES = [
|
||||
"manifest.json",
|
||||
"compiled.json",
|
||||
"diagnostics.json",
|
||||
"comparison.json",
|
||||
"traffic-signal-assemblies.json",
|
||||
"traffic-signals.json",
|
||||
];
|
||||
|
||||
const GENERATOR = Object.freeze({ name: "road-compiler", version: "0.3.0" });
|
||||
|
||||
function packageEntries(directory) {
|
||||
const manifestPath = path.join(directory, "manifest.json");
|
||||
if (!fs.existsSync(manifestPath)) throw new Error(`Native road package manifest is missing: ${manifestPath}`);
|
||||
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
||||
if (manifest.contract !== "native-road-package/v1.1") throw new Error("Native road package requires native-road-package/v1.1.");
|
||||
if (!manifest.areaId || typeof manifest.areaId !== "string") throw new Error("Native road package manifest areaId is required.");
|
||||
validatePublishedLayers(directory, manifest);
|
||||
const files = [];
|
||||
for (const relative of ROOT_FILES) files.push(relative);
|
||||
for (const layer of LAYER_REGISTRY) files.push(`layers/${layer.source}.geojson`);
|
||||
for (const relative of files) {
|
||||
const file = path.join(directory, relative);
|
||||
if (!fs.existsSync(file) || !fs.statSync(file).isFile()) throw new Error(`Native road package file is missing: ${relative}`);
|
||||
}
|
||||
return { manifest, files: [...new Set(files)].sort() };
|
||||
}
|
||||
|
||||
function exportNativeRoadPackage(directory, destination = null) {
|
||||
const { manifest, files } = packageEntries(directory);
|
||||
const entries = Object.fromEntries(files.map((relative) => [relative, fs.readFileSync(path.join(directory, relative))]));
|
||||
// The model/movements remain needed by host preview generation, but absolute
|
||||
// compiler-workspace paths are not part of the exported package contract.
|
||||
const compiled = JSON.parse(entries["compiled.json"].toString("utf8"));
|
||||
delete compiled.source;
|
||||
entries["compiled.json"] = Buffer.from(`${JSON.stringify(compiled, null, 2)}\n`);
|
||||
entries["manifest.json"] = Buffer.from(`${JSON.stringify({ ...manifest, generator: GENERATOR }, null, 2)}\n`);
|
||||
// ZIP timestamps start at 1980; a fixed value keeps repeated exports byte-stable.
|
||||
const bytes = zipSync(entries, { level: 6, mtime: new Date("1980-01-01T00:00:00Z") });
|
||||
if (destination) {
|
||||
fs.mkdirSync(path.dirname(destination), { recursive: true });
|
||||
const temporary = `${destination}.tmp-${process.pid}`;
|
||||
fs.writeFileSync(temporary, bytes);
|
||||
fs.renameSync(temporary, destination);
|
||||
}
|
||||
return { bytes, manifest, files };
|
||||
}
|
||||
|
||||
module.exports = { ROOT_FILES, GENERATOR, packageEntries, exportNativeRoadPackage };
|
||||
@@ -10,6 +10,7 @@ module.exports = {
|
||||
nativeTrafficSignals: require("./native-traffic-signals"),
|
||||
nativeRoad: require("./compile/native-road"),
|
||||
layerManifest: require("./compile/layer-manifest"),
|
||||
nativeRoadPackage: require("./export/native-road-package"),
|
||||
compiler: require("./compile/compiler"),
|
||||
check: require("./check"),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user