diff --git a/package.json b/package.json index ca88125..2a7d99e 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "diagnose:area": "node scripts/diagnose-area.js", "preflight:area": "node scripts/preflight-area.js", "road:compile": "node scripts/compile-native-roads.js", + "road:check": "node scripts/check-native-roads.js", "road:workbench": "node scripts/road-workbench.js", "test:native-road": "node scripts/test-native-road.js", "test:preflight": "node scripts/test-area-preflight.js", diff --git a/scripts/check-native-roads.js b/scripts/check-native-roads.js new file mode 100644 index 0000000..67b179e --- /dev/null +++ b/scripts/check-native-roads.js @@ -0,0 +1,43 @@ +#!/usr/bin/env node +"use strict"; + +const fs = require("fs"); +const path = require("path"); +const { readAreaConfig } = require("./lib/area-config"); +const { compileArea, parseArgs } = require("./compile-native-roads"); + +const repoRoot = path.resolve(__dirname, ".."); + +function checkArea(configPath, options = {}) { + if (options.compile) compileArea(configPath); + const area = readAreaConfig(configPath, { repoRoot }); + const root = area.outputs.nativeRoadDir; + const compiledPath = path.join(root, "compiled.json"); + if (!fs.existsSync(compiledPath)) throw new Error(`Native road output is missing: ${compiledPath}`); + const compiled = readJson(compiledPath); + const connectors = readJson(path.join(root, "layers", "connectors.geojson")); + const published = new Set(connectors.features.map((feature) => feature.properties.movement_id)); + const failures = []; + for (const movement of compiled.movements || []) { + if (movement.geometryPublished && !published.has(movement.id)) failures.push(`Published movement has no connector: ${movement.id}`); + if (!movement.geometryPublished && published.has(movement.id)) failures.push(`Non-published movement has a connector: ${movement.id}`); + if (!movement.geometryStatus) failures.push(`Movement has no geometry status: ${movement.id}`); + } + const errors = (compiled.diagnostics || []).filter((item) => item.severity === "error"); + const warnings = (compiled.diagnostics || []).filter((item) => item.severity === "warning"); + return { schema: "native-road-check/v1", areaId: area.id, ok: failures.length === 0 && errors.length === 0, movementCount: (compiled.movements || []).length, connectorCount: connectors.features.length, errors: errors.map((item) => ({ id: item.id, rule: item.rule, message: item.message })), warningCount: warnings.length, failures }; +} + +function readJson(file) { return JSON.parse(fs.readFileSync(file, "utf8")); } + +function main() { + const args = parseArgs(process.argv.slice(2)); + const configPath = path.resolve(args.config || path.join(repoRoot, "config", "areas", "nantaizi-lake-innovation-valley.json")); + const result = checkArea(configPath, { compile: args.compile === "true" }); + console.log(`NATIVE_ROAD_CHECK_DONE ${JSON.stringify(result)}`); + if (!result.ok) process.exitCode = 1; +} + +if (require.main === module) main(); + +module.exports = { checkArea }; diff --git a/scripts/test-native-road.js b/scripts/test-native-road.js index 7d198f5..0b8b48d 100644 --- a/scripts/test-native-road.js +++ b/scripts/test-native-road.js @@ -7,6 +7,7 @@ const os = require("os"); const path = require("path"); const { compileRoadModel, compileGeometry, validateOverrides } = require("./lib/native-road"); const { compileArea } = require("./compile-native-roads"); +const { checkArea } = require("./check-native-roads"); const osm = ``; const empty = { schema: "native-road-overrides/v1", overrides: [] }; @@ -68,6 +69,7 @@ try { assert.equal(compiledArea.comparison.schema, "native-road-comparison/v2"); assert.equal(compiledArea.comparison.nativeRoadCount, compiledArea.result.model.roads.length); assert.equal(compiledArea.comparison.nativePublishedMovementCount, compiledArea.result.movements.filter((movement) => movement.geometryPublished).length); + assert.equal(checkArea(config).ok, true); } finally { fs.rmSync(freshArea, { recursive: true, force: true }); }