feat: make road compiler standalone

This commit is contained in:
2026-08-25 17:53:49 +08:00
parent aadd45bcad
commit 6cb4b995e3
8 changed files with 588 additions and 2 deletions

11
README.md Normal file
View File

@@ -0,0 +1,11 @@
# Road Compiler
Compiles a `native-road-package/v1` `RoadCompilerInput` JSON file into native-road GeoJSON, diagnostics, traffic-signal runtime assets, and a deterministic completion marker.
```bash
npx road-compiler --input /absolute/path/road-compiler.input.json
```
The compiler does not read host area configuration. The caller owns configuration normalization and creates the input JSON. Successful compilation writes exactly one `NATIVE_ROAD_COMPILE_DONE` JSON marker to stdout.
Run `npm test` and `npm run test:road-parity` after `npm ci` to validate the package without the host repository.

16
bin/road-compiler.js Executable file
View File

@@ -0,0 +1,16 @@
#!/usr/bin/env node
"use strict";
const fs = require("fs");
const path = require("path");
const { compiler } = require("../src");
const args = process.argv.slice(2);
const index = args.indexOf("--input");
if (index < 0 || !args[index + 1] || index + 2 !== args.length) {
throw new Error("Usage: road-compiler --input <RoadCompilerInput.json>");
}
const inputFile = path.resolve(args[index + 1]);
const input = JSON.parse(fs.readFileSync(inputFile, "utf8"));
const { result, comparison } = compiler.compileInput(input);
console.log(`NATIVE_ROAD_COMPILE_DONE ${JSON.stringify({ areaId: input.areaId, roads: result.model.roads.length, endpoints: result.model.endpoints.length, diagnostics: result.diagnostics.length, output: input.outDir, comparison })}`);

14
bin/road-workbench.js Executable file
View File

@@ -0,0 +1,14 @@
#!/usr/bin/env node
"use strict";
const path = require("path");
const { startWorkbench } = require("../workbench/server");
const args = process.argv.slice(2);
const index = args.indexOf("--input");
if (index < 0 || !args[index + 1]) throw new Error("Usage: road-workbench --input <RoadCompilerInput.json> [--port <port>]");
const inputFile = path.resolve(args[index + 1]);
const input = require(inputFile);
const portIndex = args.indexOf("--port");
const port = portIndex >= 0 ? Number(args[portIndex + 1]) : 8787;
startWorkbench({ input, inputFile, port });

View File

@@ -0,0 +1,98 @@
# Native Road Package v1
`native-road-package/v1` defines the boundary between the host area pipeline
and the native road compiler. The compiler accepts only the input below; it
does not read `config/areas/*.json` or derive host paths.
## Input
```js
{
areaId: string,
osmFile: string,
outDir: string,
stagingDir: string,
overridesFile: string,
trafficSignalsFile: string,
comparisonDir?: string,
options: {
edgeLines: boolean,
junctionTemplates: {
enabled: boolean,
references: [],
clusters: []
}
}
}
```
All paths are absolute at the process boundary. `stagingDir` is the parent for
the compiler's temporary output and `outDir` is promoted atomically only after
all files are written. The host maps normalized area configuration to this
shape and owns all path derivation.
## Output
`outDir` contains these JSON documents:
- `compiled.json`: top-level keys are `schema`, `areaId`, `source`, `model`,
`movements`, `trafficSignals`, `diagnostics`, and `layers`. `source` has
`osm`, `overrides`, and `trafficSignals` paths.
- `diagnostics.json`: `{ schema: "native-road-diagnostics/v1", diagnostics: [] }`.
Each diagnostic has `id`, `severity`, `subjectId`, `sourceIds`, `rule`,
`message`, and `geometry` (a GeoJSON geometry or `null`).
- `comparison.json`: coverage counts for the road workbench.
- `traffic-signal-assemblies.json` and `traffic-signals.json`: compiler-owned
signal assembly and runtime views.
`layers/` always contains these twelve GeoJSON FeatureCollections:
1. `road_surface.geojson`
2. `intersection_surface.geojson`
3. `sidewalk_surface.geojson`
4. `edge_lines.geojson`
5. `lane_separators.geojson`
6. `center_lines.geojson`
7. `crosswalks.geojson`
8. `vehicle_stop_lines.geojson`
9. `direction_arrows.geojson`
10. `turn_arrows.geojson`
11. `lane_centerlines.geojson` (semantic, not rendered)
12. `connectors.geojson` (semantic, not rendered)
The editable signal source at `trafficSignalsFile` is a sibling of `outDir`.
It is included in the parity baseline because regeneration must be stable.
Successful CLI execution prints exactly one completion marker:
```text
NATIVE_ROAD_COMPILE_DONE {"areaId":...,"roads":N,"endpoints":N,"diagnostics":N,"output":...,"comparison":...}
```
Consumers use the CLI process plus files in `outDir` and parse this marker.
An in-process import may be an optimization, never the sole contract.
## Comparison Input Decision
`comparison.json` remains part of v1. The road workbench currently reads it,
so removing it would break a real consumer. `comparisonDir` is therefore an
optional compiler input for a future standalone package: when absent, the
compiler emits native-only counts and marks osm2streets coverage unavailable.
## Parity Rules
`scripts/road-parity.js` snapshots every file below `outDir` plus the sibling
editable signal document. JSON object keys are recursively sorted before
hashing. GeoJSON records both a sorted-feature `contentHash` and original-order
`orderHash`; either difference is reported.
The only normalization is intentional volatility removal:
- absolute paths below this repository become `<repo>/...`;
- other absolute paths become `<external>/<basename>`;
- `native-road-*` temporary directory names become `<staging>`.
No coordinates are rounded and no feature order changes are ignored. Control
experiments on 2026-08-25 compiled `fengshu-er-road` and
`nantaizi-lake-innovation-valley` twice, then regenerated their editable
signal documents. All 18 tracked files per area matched.

223
package-lock.json generated Normal file
View File

@@ -0,0 +1,223 @@
{
"name": "@osm-asset/road-compiler",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@osm-asset/road-compiler",
"version": "0.1.0",
"dependencies": {
"ol": "10.10.0"
},
"bin": {
"road-compiler": "bin/road-compiler.js"
}
},
"node_modules/@petamoriken/float16": {
"version": "3.9.3",
"resolved": "http://172.16.1.86:4873/@petamoriken/float16/-/float16-3.9.3.tgz",
"integrity": "sha512-8awtpHXCx/bNpFt4mt2xdkgtgVvKqty8VbjHI/WWWQuEw+KLzFot3f4+LkQY9YmOtq7A5GdOnqoIC8Pdygjk2g==",
"license": "MIT"
},
"node_modules/@types/rbush": {
"version": "4.0.0",
"resolved": "http://172.16.1.86:4873/@types/rbush/-/rbush-4.0.0.tgz",
"integrity": "sha512-+N+2H39P8X+Hy1I5mC6awlTX54k3FhiUmvt7HWzGJZvF+syUAAxP/stwppS8JE84YHqFgRMv6fCy31202CMFxQ==",
"license": "MIT"
},
"node_modules/@zarrita/storage": {
"version": "0.2.0",
"resolved": "http://172.16.1.86:4873/@zarrita/storage/-/storage-0.2.0.tgz",
"integrity": "sha512-855ZXqtnds7spnT8vNvD+MXa3QExP1m2GqShe8yt7uZXHnQLgJHgkpVwFjE1B0KDDRO0ki09hmk6OboTaIfPsQ==",
"license": "MIT",
"dependencies": {
"reference-spec-reader": "^0.2.0",
"unzipit": "2.0.0"
}
},
"node_modules/earcut": {
"version": "3.2.3",
"resolved": "http://172.16.1.86:4873/earcut/-/earcut-3.2.3.tgz",
"integrity": "sha512-vnS4AVwp1KHAF13i1vp1/2D5evWy3k5u/iW/B81QVsUZtV8cv2tU0b2VNFlqvh4kYwrFMDdjPCfAmfyJW9y14Q==",
"license": "ISC"
},
"node_modules/fflate": {
"version": "0.8.3",
"resolved": "http://172.16.1.86:4873/fflate/-/fflate-0.8.3.tgz",
"integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==",
"license": "MIT"
},
"node_modules/geotiff": {
"version": "3.1.0-beta.0",
"resolved": "http://172.16.1.86:4873/geotiff/-/geotiff-3.1.0-beta.0.tgz",
"integrity": "sha512-wbVwOaQYuN+ywly5NoMXn37nHslwkQg5EFHqMeUTtjDACrSag0EEVlFsc+2DK3Pzmmp6XzJW2RTZOamPsBM6ng==",
"license": "MIT",
"dependencies": {
"@petamoriken/float16": "^3.9.3",
"lerc": "^3.0.0",
"pako": "^2.0.4",
"parse-headers": "^2.0.2",
"quick-lru": "^6.1.1",
"web-worker": "^1.5.0",
"xml-utils": "^1.10.2",
"zstddec": "^0.2.0"
},
"engines": {
"node": ">=10.19"
}
},
"node_modules/lerc": {
"version": "3.0.0",
"resolved": "http://172.16.1.86:4873/lerc/-/lerc-3.0.0.tgz",
"integrity": "sha512-Rm4J/WaHhRa93nCN2mwWDZFoRVF18G1f47C+kvQWyHGEZxFpTUi73p7lMVSAndyxGt6lJ2/CFbOcf9ra5p8aww==",
"license": "Apache-2.0"
},
"node_modules/numcodecs": {
"version": "0.3.2",
"resolved": "http://172.16.1.86:4873/numcodecs/-/numcodecs-0.3.2.tgz",
"integrity": "sha512-6YSPnmZgg0P87jnNhi3s+FVLOcIn3y+1CTIgUulA3IdASzK9fJM87sUFkpyA+be9GibGRaST2wCgkD+6U+fWKw==",
"license": "MIT",
"dependencies": {
"fflate": "^0.8.0"
}
},
"node_modules/ol": {
"version": "10.10.0",
"resolved": "http://172.16.1.86:4873/ol/-/ol-10.10.0.tgz",
"integrity": "sha512-tLPKn6zl+6uWdPufYlqG/lQzuVUTVmfwahQqVr5+wZNyZecyAtIhMTyOtKpu7ooNDLY2sEjKZNXw9HL+sOjC1A==",
"license": "BSD-2-Clause",
"dependencies": {
"@types/rbush": "4.0.0",
"earcut": "^3.0.0",
"geotiff": "^3.1.0-beta.0",
"pbf": "5.1.2",
"rbush": "^4.0.0",
"zarrita": "^0.7.1"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/openlayers"
}
},
"node_modules/pako": {
"version": "2.2.0",
"resolved": "http://172.16.1.86:4873/pako/-/pako-2.2.0.tgz",
"integrity": "sha512-zJq6RP/5q+TO2OpFV3FHzlPnFjmkb7Nc99a5SNjJE+uu/PkpChs+NIZSSzbBoD+6kjiISXjfYdwj1ZRQ81dz/w==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/puzrin"
},
{
"type": "github",
"url": "https://github.com/sponsors/nodeca"
}
],
"license": "(MIT AND Zlib)"
},
"node_modules/parse-headers": {
"version": "2.0.6",
"resolved": "http://172.16.1.86:4873/parse-headers/-/parse-headers-2.0.6.tgz",
"integrity": "sha512-Tz11t3uKztEW5FEVZnj1ox8GKblWn+PvHY9TmJV5Mll2uHEwRdR/5Li1OlXoECjLYkApdhWy44ocONwXLiKO5A==",
"license": "MIT"
},
"node_modules/pbf": {
"version": "5.1.2",
"resolved": "http://172.16.1.86:4873/pbf/-/pbf-5.1.2.tgz",
"integrity": "sha512-mnvGdvOrIvJOBGUEdGkrVXjN8E/VkIJCkf2eS1DH2yv82ORUlLttmDt0rWY38yYZmVwciZwBUvHM20qxBZf40w==",
"license": "BSD-3-Clause",
"dependencies": {
"resolve-protobuf-schema": "^2.1.0"
},
"bin": {
"pbf": "bin/pbf"
}
},
"node_modules/protocol-buffers-schema": {
"version": "3.6.1",
"resolved": "http://172.16.1.86:4873/protocol-buffers-schema/-/protocol-buffers-schema-3.6.1.tgz",
"integrity": "sha512-VG2K63Igkiv9p76tk1lilczEK1cT+kCjKtkdhw1dQZV3k3IXJbd3o6Ho8b9zJZaHSnT2hKe4I+ObmX9w6m5SmQ==",
"license": "MIT"
},
"node_modules/quick-lru": {
"version": "6.1.2",
"resolved": "http://172.16.1.86:4873/quick-lru/-/quick-lru-6.1.2.tgz",
"integrity": "sha512-AAFUA5O1d83pIHEhJwWCq/RQcRukCkn/NSm2QsTEMle5f2hP0ChI2+3Xb051PZCkLryI/Ir1MVKviT2FIloaTQ==",
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/quickselect": {
"version": "3.0.0",
"resolved": "http://172.16.1.86:4873/quickselect/-/quickselect-3.0.0.tgz",
"integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==",
"license": "ISC"
},
"node_modules/rbush": {
"version": "4.0.1",
"resolved": "http://172.16.1.86:4873/rbush/-/rbush-4.0.1.tgz",
"integrity": "sha512-IP0UpfeWQujYC8Jg162rMNc01Rf0gWMMAb2Uxus/Q0qOFw4lCcq6ZnQEZwUoJqWyUGJ9th7JjwI4yIWo+uvoAQ==",
"license": "MIT",
"dependencies": {
"quickselect": "^3.0.0"
}
},
"node_modules/reference-spec-reader": {
"version": "0.2.0",
"resolved": "http://172.16.1.86:4873/reference-spec-reader/-/reference-spec-reader-0.2.0.tgz",
"integrity": "sha512-q0mfCi5yZSSHXpCyxjgQeaORq3tvDsxDyzaadA/5+AbAUwRyRuuTh0aRQuE/vAOt/qzzxidJ5iDeu1cLHaNBlQ==",
"license": "MIT"
},
"node_modules/resolve-protobuf-schema": {
"version": "2.1.0",
"resolved": "http://172.16.1.86:4873/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz",
"integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==",
"license": "MIT",
"dependencies": {
"protocol-buffers-schema": "^3.3.1"
}
},
"node_modules/unzipit": {
"version": "2.0.0",
"resolved": "http://172.16.1.86:4873/unzipit/-/unzipit-2.0.0.tgz",
"integrity": "sha512-DVeVIWUZCAQPNzm5sB0hpsG1GygTTdBnzNtYYEpInkttx5evkyqRgZi6rTczoySqp8hO5jHVKzrH0f23X8FZLg==",
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/web-worker": {
"version": "1.5.0",
"resolved": "http://172.16.1.86:4873/web-worker/-/web-worker-1.5.0.tgz",
"integrity": "sha512-RiMReJrTAiA+mBjGONMnjVDP2u3p9R1vkcGz6gDIrOMT3oGuYwX2WRMYI9ipkphSuE5XKEhydbhNEJh4NY9mlw==",
"license": "Apache-2.0"
},
"node_modules/xml-utils": {
"version": "1.10.2",
"resolved": "http://172.16.1.86:4873/xml-utils/-/xml-utils-1.10.2.tgz",
"integrity": "sha512-RqM+2o1RYs6T8+3DzDSoTRAUfrvaejbVHcp3+thnAtDKo8LskR+HomLajEy5UjTz24rpka7AxVBRR3g2wTUkJA==",
"license": "CC0-1.0"
},
"node_modules/zarrita": {
"version": "0.7.4",
"resolved": "http://172.16.1.86:4873/zarrita/-/zarrita-0.7.4.tgz",
"integrity": "sha512-NChufj86SceFj45z4CYjndmI98dphaG7hU8Wj0UGpMyT21o0V3HTY6zo87aSobYWts1tNFivSXzH2AR1AkaWjA==",
"license": "MIT",
"dependencies": {
"@zarrita/storage": "^0.2.0",
"numcodecs": "^0.3.2"
}
},
"node_modules/zstddec": {
"version": "0.2.0",
"resolved": "http://172.16.1.86:4873/zstddec/-/zstddec-0.2.0.tgz",
"integrity": "sha512-oyPnDa1X5c13+Y7mA/FDMNJrn4S8UNBe0KCqtDmor40Re7ALrPN6npFwyYVRRh+PqozZQdeg23QtbcamZnG5rA==",
"license": "MIT AND BSD-3-Clause"
}
}
}

View File

@@ -1,10 +1,18 @@
{
"name": "@osm-asset/road-compiler",
"version": "0.1.0",
"private": true,
"private": false,
"type": "commonjs",
"main": "src/index.js",
"bin": {
"road-compiler": "bin/road-compiler.js"
},
"scripts": {
"test": "node test/index.js"
"test": "node test/index.js",
"test:road-parity": "node test/road-parity.js",
"road:workbench": "node bin/road-workbench.js"
},
"dependencies": {
"ol": "10.10.0"
}
}

View File

@@ -0,0 +1,108 @@
{
"contract": "native-road-package/v1",
"areaId": "fengshu-er-road",
"files": {
"../native-traffic-signals.json": {
"contentHash": "88e7f0ef4fc7bdb9ef202af018b3fb3179035ffc8ed5eeba03276c263e1f0476",
"bytes": 5886
},
"comparison.json": {
"contentHash": "651eb4000a44a7521a79c3e1429795b83d20f8899e0c67c4bb25b56cf4a6f75d",
"bytes": 1295
},
"compiled.json": {
"contentHash": "2ab82eafcdab70155078fae3559692ef1fde0645a52c6decbaea762a9ffeb24a",
"bytes": 159230
},
"diagnostics.json": {
"contentHash": "1d9fdae06ddcbc19b5262b797a4a35c494fc30a98a66dbfa111533b12c5fdfc7",
"bytes": 6862
},
"layers/center_lines.geojson": {
"contentHash": "04db66df5821b319d59297b8515502fabcad95faf083cae19edb338be2f6024b",
"orderHash": "04db66df5821b319d59297b8515502fabcad95faf083cae19edb338be2f6024b",
"features": 5,
"bytes": 6909
},
"layers/connectors.geojson": {
"contentHash": "e7979d4642c7c10f33fb23e92721f22533a851ae1a2b4d35f224d50927bf2fe9",
"orderHash": "c327b7b154d4d9ca04cd895523eb0d8ad67c37051ef1d2135b2b46c51e12df58",
"features": 90,
"bytes": 197885
},
"layers/crosswalks.geojson": {
"contentHash": "354cd4d7ed105a11b95904b44848dce567b3a3383f76755936d8c00691fe29af",
"orderHash": "d24376438ac956bde52fcbfa955dd72c2ba31a97995608aaed1c79f6fd3633ab",
"features": 152,
"bytes": 219286
},
"layers/direction_arrows.geojson": {
"contentHash": "7b8362ad4912c997a7661befde55ddfe58757c3c8d139c15867e1938ea8f6918",
"orderHash": "5274e8b433946410a7cdffdaa452c1750e04f53e73a86bf81d034cfb26d4c254",
"features": 686,
"bytes": 1053308
},
"layers/edge_lines.geojson": {
"contentHash": "ad37fe6278e0c7caf3b77c1c5068a56e18a6c87b78ed5a840ee22a0f961ea7a8",
"orderHash": "ad37fe6278e0c7caf3b77c1c5068a56e18a6c87b78ed5a840ee22a0f961ea7a8",
"features": 0,
"bytes": 52
},
"layers/intersection_surface.geojson": {
"contentHash": "b2022ca70339aa470f3be451bf3ba2f55b59c3900645c864538372173811309f",
"orderHash": "b2022ca70339aa470f3be451bf3ba2f55b59c3900645c864538372173811309f",
"features": 5,
"bytes": 13048
},
"layers/lane_centerlines.geojson": {
"contentHash": "19c550c794810c1071de55dee158295235106a56e3877a2ba10da920ee214593",
"orderHash": "67f8e7d33ec578644416e4837dd4aafef62a55aaeb4d438d07ab07eddfbb1df1",
"features": 84,
"bytes": 73294
},
"layers/lane_separators.geojson": {
"contentHash": "02fdf2c7b6e89c2850a60ea2ac72b9f62910259bdb2949681fcaa7e67d2b51f0",
"orderHash": "81782a059c4ff9f69fdf7de9107d20a8d6cf55d34bb0620ec28a9a8c5106c982",
"features": 3596,
"bytes": 4164106
},
"layers/road_surface.geojson": {
"contentHash": "5a2936a705e64338d0d79b395a13d761f1893dd72330a9b9ee4696ae75eab295",
"orderHash": "d8402ae6e772e0778b862b190abfa291de1b02a15537d455f7dcd8596245dfd8",
"features": 30,
"bytes": 49554
},
"layers/sidewalk_surface.geojson": {
"contentHash": "b6f8f876e9f18fd2ef6749125a09d654c73d986e916bd262ceb9967bca1a54c6",
"orderHash": "3fd42a67e18e3b8743fa538428e039ef66a1f44150a6881a7aaa18326607b5cb",
"features": 26,
"bytes": 54997
},
"layers/turn_arrows.geojson": {
"contentHash": "ad37fe6278e0c7caf3b77c1c5068a56e18a6c87b78ed5a840ee22a0f961ea7a8",
"orderHash": "ad37fe6278e0c7caf3b77c1c5068a56e18a6c87b78ed5a840ee22a0f961ea7a8",
"features": 0,
"bytes": 52
},
"layers/vehicle_stop_lines.geojson": {
"contentHash": "cb904550ab8eec011cf33e5edfa81044de6dfca0280dbfe488e77229055ed590",
"orderHash": "8a4b877a17a5af60adc8656465afad6756944736291664139e878d46c5a4f363",
"features": 4,
"bytes": 4191
},
"traffic-signal-assemblies.json": {
"contentHash": "1788026a0c8c531b2fc7dd49628f7fbadd809c7b2f7f8819cffb3ac7d30689ca",
"orderHash": "b409ea6b77b6c8639f63c33a156581f9b184a84fde34d265b5deb05705828251",
"features": 7,
"bytes": 5411
},
"traffic-signals.json": {
"contentHash": "625b79b6eb82b41f2099ba51960717c7f794fdfbd87310eb12e99da966540d89",
"bytes": 15491
}
},
"volatileExcluded": [
"absolute paths -> <repo> or <external>",
"native-road-* staging directory -> <staging>"
]
}

View File

@@ -0,0 +1,108 @@
{
"contract": "native-road-package/v1",
"areaId": "nantaizi-lake-innovation-valley",
"files": {
"../native-traffic-signals.json": {
"contentHash": "36cb9f069fb44a6e24f0af0d130ef8cb5b4a93250dc9fb0891191d1ba039a5b2",
"bytes": 28329
},
"comparison.json": {
"contentHash": "5aa11da443221a48288641ac6950c6e4d75d834713a93110bbf265859202a265",
"bytes": 1153
},
"compiled.json": {
"contentHash": "ea5ae4a04f1259b1ccec9fc1cca7ef8ba81426a77584a447480b6047b37f5e01",
"bytes": 184985
},
"diagnostics.json": {
"contentHash": "7e9327f0424dd612f389c560c114a4cafee1349bbfa36f49b2b4eab846e5ca91",
"bytes": 9755
},
"layers/center_lines.geojson": {
"contentHash": "2b2710fce06e75b0a3e4941c2da6119cea7b8bb7834345607bbee384de20ee6b",
"orderHash": "ea71a8841370689d6fc2b75d0b30ec7104638fb2904da6d707dc82ff3131e065",
"features": 511,
"bytes": 694102
},
"layers/connectors.geojson": {
"contentHash": "901a86bc6c536d38bb73ae4654ec1ce7d1c0790c2d6eba92543c48f584cd15ac",
"orderHash": "4df882ad59b65a97d892df64de0156b35beaf071b04eed671ef7b535e9e2a7b9",
"features": 76,
"bytes": 160866
},
"layers/crosswalks.geojson": {
"contentHash": "53fda76182c0d1db5f9e7ac284337ece62655d7fee8bb446fe170ea26abe8bbc",
"orderHash": "53fda76182c0d1db5f9e7ac284337ece62655d7fee8bb446fe170ea26abe8bbc",
"features": 48,
"bytes": 50536
},
"layers/direction_arrows.geojson": {
"contentHash": "38e80bbfe02d4f12ce40e7d0c8342e3bef6b602c64f81dd320b366b6a6b3d205",
"orderHash": "579aa6c37585bf4edf9d6b6b1e120f976b93ec2d0c303d82a154b75c114a45f5",
"features": 324,
"bytes": 493431
},
"layers/edge_lines.geojson": {
"contentHash": "ad37fe6278e0c7caf3b77c1c5068a56e18a6c87b78ed5a840ee22a0f961ea7a8",
"orderHash": "ad37fe6278e0c7caf3b77c1c5068a56e18a6c87b78ed5a840ee22a0f961ea7a8",
"features": 0,
"bytes": 52
},
"layers/intersection_surface.geojson": {
"contentHash": "7f79e57215e3fd07c5c0f703c71e516873db770cb869efdf18925a3184059ca3",
"orderHash": "d69df8d92d0fce8f7ee172959b978d941fd011e094857e9ab7304b3d1e98bf92",
"features": 12,
"bytes": 38528
},
"layers/lane_centerlines.geojson": {
"contentHash": "3fea4ebfe62e0d720c6977e2289f4e6517ed7b3c5ab361270d03378971aec780",
"orderHash": "69a8ebaa42a74da4f7d5940c5a81bd82ceb104efd3f858723dccfadbae12121e",
"features": 50,
"bytes": 43582
},
"layers/lane_separators.geojson": {
"contentHash": "dc0b50b53da191e65f3dba01162acb7561966d1796a9c0789527cebfd6ed06a4",
"orderHash": "0bfd873e5698869fb4855783fe30bb6db29456958e4d154b7264374a5fdb4a10",
"features": 731,
"bytes": 835933
},
"layers/road_surface.geojson": {
"contentHash": "81af19c71cf6fc8a3884488c00cfb590e1a7fe9ed9e4351fce65825ceadd50fa",
"orderHash": "f2ddec5258411fbdbc050b7ecefbb157b59e00b8226afcc30d2b772e1859e357",
"features": 25,
"bytes": 38275
},
"layers/sidewalk_surface.geojson": {
"contentHash": "bb8f4516e27b16238d753b112d18b8acfa5cfad2cea522a65b7972a609be9563",
"orderHash": "4fa773a6f39c5b6d23551e1338c6d99ef8a5ecd9ebfcafa16154c9765fef8c6e",
"features": 73,
"bytes": 122432
},
"layers/turn_arrows.geojson": {
"contentHash": "a65bb8fe079f27e00bf2e6208148fc6b73d2d07e76d48b1cd1bf8a610d7e2d66",
"orderHash": "66966ac2c65464f9c6715ca9cda5a3620520bf1d066cba2dee36114dc46af936",
"features": 108,
"bytes": 132536
},
"layers/vehicle_stop_lines.geojson": {
"contentHash": "4f45caf3c0bf13bbf10d9cac15fa80b1a9be3969ed84803ba48e56c4a0080992",
"orderHash": "4f45caf3c0bf13bbf10d9cac15fa80b1a9be3969ed84803ba48e56c4a0080992",
"features": 8,
"bytes": 8475
},
"traffic-signal-assemblies.json": {
"contentHash": "9f8d032c00784bb72bb1322238cd7b0a80e621d435b43c728da86f1e77ca352a",
"orderHash": "0b9cae13094dba1994faca4bf1d4d80e8bc5497daa46df5899bf5e6fc7f26d61",
"features": 35,
"bytes": 26398
},
"traffic-signals.json": {
"contentHash": "c4b68cc1cefeb0d393a18eef6c7eb79933fba28630826745165ed433c25779d0",
"bytes": 74151
}
},
"volatileExcluded": [
"absolute paths -> <repo> or <external>",
"native-road-* staging directory -> <staging>"
]
}