Reads the DSL file, parses to AST, loads all --atlas-dir paths into a registry, runs the builder, and writes pretty-printed JSON. The output filename's basename becomes the map id when the DSL has no 'id' directive. Parser and builder errors are surfaced as '<file>:<line>: <message>'. Also reorders the duplicate-atlas warning so the atlas_id appears before the word 'duplicate'.
95 lines
2.1 KiB
JavaScript
95 lines
2.1 KiB
JavaScript
'use strict';
|
|
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const { parseDsl } = require('../dsl-parser');
|
|
const { loadAtlasDirs } = require('../atlas-loader');
|
|
const { buildMap } = require('../builder');
|
|
|
|
const USAGE = 'usage: sporel-mapper build <spec.txt> <out.json> [--atlas-dir <path> ...]\n';
|
|
|
|
function parseArgs(args) {
|
|
const positional = [];
|
|
const atlasDirs = [];
|
|
let i = 0;
|
|
while (i < args.length) {
|
|
const a = args[i];
|
|
if (a === '--atlas-dir') {
|
|
if (i + 1 >= args.length) {
|
|
throw new Error(`--atlas-dir requires a path`);
|
|
}
|
|
atlasDirs.push(args[i + 1]);
|
|
i += 2;
|
|
} else {
|
|
positional.push(a);
|
|
i += 1;
|
|
}
|
|
}
|
|
return { positional, atlasDirs };
|
|
}
|
|
|
|
function run(args, { out, err }) {
|
|
let parsed;
|
|
try {
|
|
parsed = parseArgs(args);
|
|
} catch (e) {
|
|
err.write(`error: ${e.message}\n${USAGE}`);
|
|
return 1;
|
|
}
|
|
if (parsed.positional.length !== 2) {
|
|
err.write(USAGE);
|
|
return 1;
|
|
}
|
|
const [specPath, outPath] = parsed.positional;
|
|
|
|
let dslText;
|
|
try {
|
|
dslText = fs.readFileSync(specPath, 'utf8');
|
|
} catch (e) {
|
|
err.write(`error: cannot read ${specPath}: ${e.message}\n`);
|
|
return 1;
|
|
}
|
|
|
|
let ast;
|
|
try {
|
|
ast = parseDsl(dslText);
|
|
} catch (e) {
|
|
const line = e.line || '?';
|
|
err.write(`${specPath}:${line}: ${e.message}\n`);
|
|
return 1;
|
|
}
|
|
|
|
let registry;
|
|
try {
|
|
const result = loadAtlasDirs(parsed.atlasDirs);
|
|
registry = result.registry;
|
|
for (const w of result.warnings) {
|
|
err.write(`warning: ${w}\n`);
|
|
}
|
|
} catch (e) {
|
|
err.write(`error: ${e.message}\n`);
|
|
return 1;
|
|
}
|
|
|
|
const defaultId = path.basename(outPath, path.extname(outPath));
|
|
let map;
|
|
try {
|
|
map = buildMap(ast, registry, { defaultId });
|
|
} catch (e) {
|
|
const line = e.line || '?';
|
|
err.write(`${specPath}:${line}: ${e.message}\n`);
|
|
return 1;
|
|
}
|
|
|
|
try {
|
|
fs.writeFileSync(outPath, JSON.stringify(map, null, 2) + '\n');
|
|
} catch (e) {
|
|
err.write(`error: cannot write ${outPath}: ${e.message}\n`);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
module.exports = { run };
|