World airport dataset + distance cap on generated jobs (ISS-079, v0.44.0)
CI / build + unit + e2e (pull_request) Successful in 11m2s
CI / build + unit + e2e (pull_request) Successful in 11m2s
This commit is contained in:
+20
-5
@@ -52,11 +52,13 @@ export function parseCsv(text: string): CsvRow[] {
|
||||
// The 2026 schema splits "airport" into small/medium/large_airport (older dumps used a
|
||||
// single "airport" type + category column) — both spellings are accepted. Heliports are
|
||||
// excluded — no fixed-wing transport ops; other types (closed, balloonport, ...) are
|
||||
// irrelevant to an airline-ops game.
|
||||
// irrelevant to an airline-ops game. The committed dataset is pre-curated to large_airport
|
||||
// only (scripts/build-world-airports.mjs); this check stays as a cheap guard against an
|
||||
// uncurated dump being swapped in.
|
||||
const INCLUDED_TYPES = new Set(['airport', 'small_airport', 'medium_airport', 'large_airport', 'seaplane_base']);
|
||||
|
||||
export function filterEuAirports(rows: CsvRow[]): CsvRow[] {
|
||||
return rows.filter((r) => r.continent === 'EU' && INCLUDED_TYPES.has(r.type));
|
||||
export function filterWorldAirports(rows: CsvRow[]): CsvRow[] {
|
||||
return rows.filter((r) => INCLUDED_TYPES.has(r.type));
|
||||
}
|
||||
|
||||
export interface AirportProperties {
|
||||
@@ -93,13 +95,26 @@ export function toGeoJson(rows: CsvRow[]): GeoJsonFeatureCollection {
|
||||
return { type: 'FeatureCollection', features };
|
||||
}
|
||||
|
||||
// Three consumers key features by ICAO with silent-overwrite semantics (the map's airport
|
||||
// index, the route/queue GeoJSON builders and the sim's airport lookups) — a duplicate would
|
||||
// corrupt state without any error, so fail loud at load instead.
|
||||
export function assertUniqueIcaos(fc: GeoJsonFeatureCollection): void {
|
||||
const seen = new Set<string>();
|
||||
for (const f of fc.features) {
|
||||
if (seen.has(f.properties.icao)) throw new Error(`duplicate ICAO in airport dataset: ${f.properties.icao}`);
|
||||
seen.add(f.properties.icao);
|
||||
}
|
||||
}
|
||||
|
||||
let cached: GeoJsonFeatureCollection | null = null;
|
||||
|
||||
export async function loadAirportsGeoJson(): Promise<GeoJsonFeatureCollection> {
|
||||
if (cached) return cached;
|
||||
const file = path.join(process.cwd(), 'data', 'airports_eu.csv');
|
||||
const file = path.join(process.cwd(), 'data', 'airports_world.csv');
|
||||
const text = await fs.readFile(file, 'utf8');
|
||||
cached = toGeoJson(filterEuAirports(parseCsv(text)));
|
||||
const fc = toGeoJson(filterWorldAirports(parseCsv(text)));
|
||||
assertUniqueIcaos(fc);
|
||||
cached = fc;
|
||||
return cached;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user