@hypersoniclabs/helix-cli 0.1.25-helix3.476 → 0.1.25-helix3.478
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/city/source/canonical.d.ts +21 -0
- package/dist/city/source/canonical.js +140 -0
- package/dist/city/source/canonical.js.map +1 -0
- package/dist/city/source/commands.d.ts +2 -0
- package/dist/city/source/commands.js +71 -0
- package/dist/city/source/commands.js.map +1 -0
- package/dist/city/source/fixtures.d.ts +13 -0
- package/dist/city/source/fixtures.js +499 -0
- package/dist/city/source/fixtures.js.map +1 -0
- package/dist/city/source/geometry.d.ts +30 -0
- package/dist/city/source/geometry.js +203 -0
- package/dist/city/source/geometry.js.map +1 -0
- package/dist/city/source/index.d.ts +12 -0
- package/dist/city/source/index.js +73 -0
- package/dist/city/source/index.js.map +1 -0
- package/dist/city/source/inspect.d.ts +79 -0
- package/dist/city/source/inspect.js +261 -0
- package/dist/city/source/inspect.js.map +1 -0
- package/dist/city/source/io.d.ts +50 -0
- package/dist/city/source/io.js +327 -0
- package/dist/city/source/io.js.map +1 -0
- package/dist/city/source/overrides.d.ts +9 -0
- package/dist/city/source/overrides.js +55 -0
- package/dist/city/source/overrides.js.map +1 -0
- package/dist/city/source/preview.d.ts +15 -0
- package/dist/city/source/preview.js +226 -0
- package/dist/city/source/preview.js.map +1 -0
- package/dist/city/source/raster.d.ts +23 -0
- package/dist/city/source/raster.js +228 -0
- package/dist/city/source/raster.js.map +1 -0
- package/dist/city/source/schema.json +1095 -0
- package/dist/city/source/types.d.ts +372 -0
- package/dist/city/source/types.js +67 -0
- package/dist/city/source/types.js.map +1 -0
- package/dist/city/source/validate.d.ts +27 -0
- package/dist/city/source/validate.js +832 -0
- package/dist/city/source/validate.js.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/placements/attachFoliageLods.js +7 -2
- package/dist/placements/attachFoliageLods.js.map +1 -1
- package/dist/placements/foliageLods.d.ts +7 -0
- package/dist/placements/foliageLods.js +150 -5
- package/dist/placements/foliageLods.js.map +1 -1
- package/dist/placements/source.d.ts +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/plugins/beamng-vehicle/bin/__pycache__/beamng_abs.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/beamng_audio.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/beamng_engine.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/beamng_expression.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/beamng_jbeam.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/beamng_materials.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/beamng_stock_events.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/fmod_studio.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/fsb5.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/sim_audio.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/sim_audio_ac.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/sim_audio_beamng.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/sim_audio_fixtures.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/test_beamng_engine.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/test_sim_audio.cpython-312.pyc +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare function sha256Hex(bytes: Uint8Array | string): string;
|
|
2
|
+
/** Round to 1 mm. Idempotent: rounding an already rounded value returns it unchanged. */
|
|
3
|
+
export declare function roundMm(value: number): number;
|
|
4
|
+
export interface CanonicalOptions {
|
|
5
|
+
/** Round every number to 1 mm. Rows yes; manifest no (a longitude needs more digits). */
|
|
6
|
+
quantise?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/** Compact canonical JSON of any JSON-shaped value. */
|
|
9
|
+
export declare function canonicalJson(value: unknown, options?: CanonicalOptions): string;
|
|
10
|
+
/** Human-readable canonical JSON for small documents (manifest, dem.json, overrides). */
|
|
11
|
+
export declare function prettyCanonicalJson(value: unknown): string;
|
|
12
|
+
/** A document of row arrays, one row per line: roads.json and areas.json. A non-array section is written inline. */
|
|
13
|
+
export declare function rowsDocument(sections: Array<[name: string, rows: unknown[] | Record<string, unknown> | undefined]>): string;
|
|
14
|
+
export declare function ndjsonDocument(rows: unknown[]): string;
|
|
15
|
+
export declare function sortById<T extends {
|
|
16
|
+
id: string;
|
|
17
|
+
}>(rows: readonly T[]): T[];
|
|
18
|
+
/** gzip with a fixed header (no mtime, OS = unix), so the same bytes in give the same bytes out on every machine zlib agrees on. */
|
|
19
|
+
export declare function gzipStable(bytes: Uint8Array): Buffer;
|
|
20
|
+
export declare function gunzipBytes(bytes: Uint8Array): Buffer;
|
|
21
|
+
export declare function isGzipUri(uri: string): boolean;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Canonical serialisation: the single place that decides which bytes a city-source layer is. Two sources with the same
|
|
3
|
+
// content produce the same bytes, so a layer's sha256 is its identity and a re-import of unchanged data is a no-op.
|
|
4
|
+
//
|
|
5
|
+
// Rules (docs/city-source.md "Canonical form"): UTF-8, LF, no BOM, a trailing newline; object keys in code-unit order with
|
|
6
|
+
// `schema` and `id` first; undefined fields omitted; numbers in layer rows rounded to 1 mm; -0 written as 0; non-finite
|
|
7
|
+
// numbers refused; rows sorted by id; one row per line in NDJSON and in the row arrays of roads.json / areas.json.
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.sha256Hex = sha256Hex;
|
|
10
|
+
exports.roundMm = roundMm;
|
|
11
|
+
exports.canonicalJson = canonicalJson;
|
|
12
|
+
exports.prettyCanonicalJson = prettyCanonicalJson;
|
|
13
|
+
exports.rowsDocument = rowsDocument;
|
|
14
|
+
exports.ndjsonDocument = ndjsonDocument;
|
|
15
|
+
exports.sortById = sortById;
|
|
16
|
+
exports.gzipStable = gzipStable;
|
|
17
|
+
exports.gunzipBytes = gunzipBytes;
|
|
18
|
+
exports.isGzipUri = isGzipUri;
|
|
19
|
+
const node_crypto_1 = require("node:crypto");
|
|
20
|
+
const node_zlib_1 = require("node:zlib");
|
|
21
|
+
const types_1 = require("./types");
|
|
22
|
+
function sha256Hex(bytes) {
|
|
23
|
+
return (0, node_crypto_1.createHash)('sha256').update(bytes).digest('hex');
|
|
24
|
+
}
|
|
25
|
+
/** Round to 1 mm. Idempotent: rounding an already rounded value returns it unchanged. */
|
|
26
|
+
function roundMm(value) {
|
|
27
|
+
if (!Number.isFinite(value))
|
|
28
|
+
throw new Error(`city-source: cannot write a non-finite number (${value})`);
|
|
29
|
+
const rounded = Number(value.toFixed(types_1.CITY_SOURCE_DECIMALS));
|
|
30
|
+
return rounded === 0 ? 0 : rounded;
|
|
31
|
+
}
|
|
32
|
+
function compareKeys(a, b) {
|
|
33
|
+
const rank = (key) => (key === 'schema' ? 0 : key === 'id' ? 1 : 2);
|
|
34
|
+
const ra = rank(a);
|
|
35
|
+
const rb = rank(b);
|
|
36
|
+
if (ra !== rb)
|
|
37
|
+
return ra - rb;
|
|
38
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
39
|
+
}
|
|
40
|
+
/** Compact canonical JSON of any JSON-shaped value. */
|
|
41
|
+
function canonicalJson(value, options = {}) {
|
|
42
|
+
const quantise = options.quantise === true;
|
|
43
|
+
const walk = (v, path) => {
|
|
44
|
+
if (v === null)
|
|
45
|
+
return 'null';
|
|
46
|
+
switch (typeof v) {
|
|
47
|
+
case 'number':
|
|
48
|
+
if (!Number.isFinite(v))
|
|
49
|
+
throw new Error(`city-source: non-finite number at ${path}`);
|
|
50
|
+
return String(quantise ? roundMm(v) : v === 0 ? 0 : v);
|
|
51
|
+
case 'string':
|
|
52
|
+
return JSON.stringify(v);
|
|
53
|
+
case 'boolean':
|
|
54
|
+
return v ? 'true' : 'false';
|
|
55
|
+
case 'object': {
|
|
56
|
+
if (Array.isArray(v)) {
|
|
57
|
+
let out = '[';
|
|
58
|
+
for (let i = 0; i < v.length; i += 1)
|
|
59
|
+
out += (i === 0 ? '' : ',') + (v[i] === undefined ? 'null' : walk(v[i], `${path}[${i}]`));
|
|
60
|
+
return `${out}]`;
|
|
61
|
+
}
|
|
62
|
+
const record = v;
|
|
63
|
+
const keys = Object.keys(record).filter((key) => record[key] !== undefined).sort(compareKeys);
|
|
64
|
+
let out = '{';
|
|
65
|
+
for (let i = 0; i < keys.length; i += 1)
|
|
66
|
+
out += `${i === 0 ? '' : ','}${JSON.stringify(keys[i])}:${walk(record[keys[i]], `${path}.${keys[i]}`)}`;
|
|
67
|
+
return `${out}}`;
|
|
68
|
+
}
|
|
69
|
+
default:
|
|
70
|
+
throw new Error(`city-source: cannot serialise ${typeof v} at ${path}`);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
return walk(value, '$');
|
|
74
|
+
}
|
|
75
|
+
function isFlat(value) {
|
|
76
|
+
if (value === null || typeof value !== 'object')
|
|
77
|
+
return true;
|
|
78
|
+
return Array.isArray(value) && value.every((item) => item === null || typeof item !== 'object' || (Array.isArray(item) && item.every((leaf) => leaf === null || typeof leaf !== 'object')));
|
|
79
|
+
}
|
|
80
|
+
function inlineArray(value) {
|
|
81
|
+
return `[${value.map((item) => (Array.isArray(item) ? inlineArray(item) : canonicalJson(item, {}))).join(', ')}]`;
|
|
82
|
+
}
|
|
83
|
+
/** Human-readable canonical JSON for small documents (manifest, dem.json, overrides). */
|
|
84
|
+
function prettyCanonicalJson(value) {
|
|
85
|
+
const walk = (v, depth, path) => {
|
|
86
|
+
if (v === null || typeof v !== 'object')
|
|
87
|
+
return canonicalJson(v, {});
|
|
88
|
+
const pad = ' '.repeat(depth + 1);
|
|
89
|
+
const close = ' '.repeat(depth);
|
|
90
|
+
if (Array.isArray(v)) {
|
|
91
|
+
if (v.length === 0)
|
|
92
|
+
return '[]';
|
|
93
|
+
if (isFlat(v))
|
|
94
|
+
return inlineArray(v);
|
|
95
|
+
return `[\n${v.map((item, i) => pad + walk(item, depth + 1, `${path}[${i}]`)).join(',\n')}\n${close}]`;
|
|
96
|
+
}
|
|
97
|
+
const record = v;
|
|
98
|
+
const keys = Object.keys(record).filter((key) => record[key] !== undefined).sort(compareKeys);
|
|
99
|
+
if (keys.length === 0)
|
|
100
|
+
return '{}';
|
|
101
|
+
return `{\n${keys.map((key) => `${pad}${JSON.stringify(key)}: ${walk(record[key], depth + 1, `${path}.${key}`)}`).join(',\n')}\n${close}}`;
|
|
102
|
+
};
|
|
103
|
+
return `${walk(value, 0, '$')}\n`;
|
|
104
|
+
}
|
|
105
|
+
/** A document of row arrays, one row per line: roads.json and areas.json. A non-array section is written inline. */
|
|
106
|
+
function rowsDocument(sections) {
|
|
107
|
+
const parts = [];
|
|
108
|
+
for (const [name, rows] of sections) {
|
|
109
|
+
if (rows === undefined)
|
|
110
|
+
continue;
|
|
111
|
+
if (Array.isArray(rows)) {
|
|
112
|
+
parts.push(rows.length === 0 ? `"${name}": []` : `"${name}": [\n${rows.map((row) => canonicalJson(row, { quantise: true })).join(',\n')}\n]`);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
parts.push(`"${name}": ${canonicalJson(rows, { quantise: true })}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return `{\n${parts.join(',\n')}\n}\n`;
|
|
119
|
+
}
|
|
120
|
+
function ndjsonDocument(rows) {
|
|
121
|
+
return rows.map((row) => `${canonicalJson(row, { quantise: true })}\n`).join('');
|
|
122
|
+
}
|
|
123
|
+
function sortById(rows) {
|
|
124
|
+
return [...rows].sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
125
|
+
}
|
|
126
|
+
/** gzip with a fixed header (no mtime, OS = unix), so the same bytes in give the same bytes out on every machine zlib agrees on. */
|
|
127
|
+
function gzipStable(bytes) {
|
|
128
|
+
const out = (0, node_zlib_1.gzipSync)(bytes, { level: 9 });
|
|
129
|
+
out.writeUInt32LE(0, 4); // mtime
|
|
130
|
+
out[8] = 0; // xfl
|
|
131
|
+
out[9] = 3; // OS: unix
|
|
132
|
+
return out;
|
|
133
|
+
}
|
|
134
|
+
function gunzipBytes(bytes) {
|
|
135
|
+
return (0, node_zlib_1.gunzipSync)(bytes);
|
|
136
|
+
}
|
|
137
|
+
function isGzipUri(uri) {
|
|
138
|
+
return uri.endsWith('.gz');
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=canonical.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical.js","sourceRoot":"","sources":["../../../src/city/source/canonical.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// `helix city source validate|inspect`: how an agent hands the CLI a city-source folder and gets a verdict and a picture.
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.registerCitySourceCommands = registerCitySourceCommands;
|
|
5
|
+
const promises_1 = require("node:fs/promises");
|
|
6
|
+
const node_path_1 = require("node:path");
|
|
7
|
+
const inspect_1 = require("./inspect");
|
|
8
|
+
const io_1 = require("./io");
|
|
9
|
+
const preview_1 = require("./preview");
|
|
10
|
+
const validate_1 = require("./validate");
|
|
11
|
+
function registerCitySourceCommands(city, fail) {
|
|
12
|
+
const source = city
|
|
13
|
+
.command('source')
|
|
14
|
+
.description('The neutral city format helix.city-source/1 (docs/city-source.md): check a folder, read its numbers, draw its plan');
|
|
15
|
+
source
|
|
16
|
+
.command('validate')
|
|
17
|
+
.description('Check a city-source folder: files and hashes, then rings, road graph, extents, projection. Exits 1 on any error.')
|
|
18
|
+
.argument('<dir>', 'folder holding city-source.json')
|
|
19
|
+
.option('--json', 'print the report as JSON')
|
|
20
|
+
.option('--max-issues <n>', 'issues listed per code (the rest are counted)', '25')
|
|
21
|
+
.action(async (dir, opts) => {
|
|
22
|
+
try {
|
|
23
|
+
const max = Number(opts.maxIssues);
|
|
24
|
+
if (!Number.isInteger(max) || max < 1)
|
|
25
|
+
fail('✖ --max-issues must be a whole number >= 1');
|
|
26
|
+
const report = await (0, io_1.validateCitySourceFolder)((0, node_path_1.resolve)(dir), { maxIssuesPerCode: max });
|
|
27
|
+
console.log(opts.json ? JSON.stringify(report, null, 2) : (0, validate_1.formatValidationReport)(report));
|
|
28
|
+
if (!report.ok)
|
|
29
|
+
process.exitCode = 1;
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
fail(`✖ ${err instanceof Error ? err.message : String(err)}`);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
source
|
|
36
|
+
.command('inspect')
|
|
37
|
+
.description('Counts, lengths, areas and hashes of a city-source folder; with --preview, a PNG plan of roads, footprints, water and land use')
|
|
38
|
+
.argument('<dir>', 'folder holding city-source.json')
|
|
39
|
+
.option('--json', 'print the numbers as JSON')
|
|
40
|
+
.option('--preview <png>', 'also write a north-up plan image (at most 1000 px)')
|
|
41
|
+
.option('--size <px>', 'longest edge of the preview, 200 to 1000', '1000')
|
|
42
|
+
.action(async (dir, opts) => {
|
|
43
|
+
try {
|
|
44
|
+
const size = Number(opts.size);
|
|
45
|
+
if (!Number.isInteger(size) || size < 200 || size > 1000)
|
|
46
|
+
fail('✖ --size must be a whole number from 200 to 1000');
|
|
47
|
+
const loaded = await (0, io_1.loadCitySource)((0, node_path_1.resolve)(dir));
|
|
48
|
+
if (loaded.sink.totals['manifest.missing'] || loaded.sink.totals['manifest.parse']) {
|
|
49
|
+
fail(`✖ ${loaded.sink.issues.map((issue) => issue.message).join('\n')}`);
|
|
50
|
+
}
|
|
51
|
+
const verdict = (0, validate_1.validateCitySource)(loaded.source, { sink: loaded.sink, layerFacts: loaded.layerFacts });
|
|
52
|
+
const report = (0, inspect_1.inspectCitySource)(loaded.source, loaded.layerFacts);
|
|
53
|
+
const lines = [];
|
|
54
|
+
if (!verdict.ok)
|
|
55
|
+
lines.push(`✖ ${verdict.errors} error${verdict.errors === 1 ? '' : 's'} in this source (numbers below are as found); run: helix city source validate ${dir}`);
|
|
56
|
+
lines.push(opts.json ? JSON.stringify({ valid: verdict.ok, errors: verdict.errors, warnings: verdict.warnings, ...report }, null, 2) : (0, inspect_1.formatCitySourceInspection)(report));
|
|
57
|
+
if (opts.preview) {
|
|
58
|
+
const preview = (0, preview_1.renderCitySourcePreview)(loaded.source, { size });
|
|
59
|
+
const out = (0, node_path_1.resolve)(opts.preview);
|
|
60
|
+
await (0, promises_1.mkdir)((0, node_path_1.dirname)(out), { recursive: true });
|
|
61
|
+
await (0, promises_1.writeFile)(out, preview.png);
|
|
62
|
+
lines.push(`✔ preview ${out} (${preview.width} x ${preview.height} px, ${preview.scale.toFixed(3)} px per metre)`);
|
|
63
|
+
}
|
|
64
|
+
console.log(lines.join('\n'));
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
fail(`✖ ${err instanceof Error ? err.message : String(err)}`);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../../../src/city/source/commands.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CitySource, CitySourceDraft } from './types';
|
|
2
|
+
export declare function buildSyntheticFixture(): CitySourceDraft;
|
|
3
|
+
export declare function buildOsmSliceFixture(): CitySourceDraft;
|
|
4
|
+
export declare function buildCs2SliceFixture(): CitySourceDraft;
|
|
5
|
+
export declare const CITY_SOURCE_FIXTURES: {
|
|
6
|
+
readonly 'osm-slice': typeof buildOsmSliceFixture;
|
|
7
|
+
readonly 'cs2-slice': typeof buildCs2SliceFixture;
|
|
8
|
+
readonly synthetic: typeof buildSyntheticFixture;
|
|
9
|
+
};
|
|
10
|
+
export type CitySourceFixtureName = keyof typeof CITY_SOURCE_FIXTURES;
|
|
11
|
+
/** The schema string, re-exported for specs that build variants by hand. */
|
|
12
|
+
export declare const FIXTURE_SCHEMA: "helix.city-source/1";
|
|
13
|
+
export type { CitySource };
|