From 2006c035d9e14e63f8a3942c3d2694988a08f316 Mon Sep 17 00:00:00 2001 From: Sameh Khamis Date: Sun, 25 Oct 2026 17:21:41 -0700 Subject: [PATCH] chore: remove four modules nothing in the app uses (#1403) * chore: remove four modules nothing in the app uses src/app/sourceSlot.js re-exported src/sources/sourceSlot.js, which every caller imports directly. src/data/flowTiles.js and src/data/issPass.js were reached only by their own tests. src/data/localGeojson.js wrapped localGeojsonCore.js with the app's services, which the catalog already passes itself. The local GeoJSON layer tests now build layers the way the catalog does, so they keep covering localGeojsonCore.js; only the test of the wrapper's own default host goes. Boundary lists, format scope and docs drop the removed paths. * docs: changelog for #1403 --- changelog.d/1403-remove-unused-modules.md | 5 + docs/CODE-BOUNDARIES.md | 2 - docs/CURRENT-STATE.md | 2 +- docs/INFRASTRUCTURE-LAYERS.md | 5 +- scripts/check-import-directions.mjs | 8 - scripts/format-scope.json | 2 - scripts/package-boundaries.json | 6 - src/app/sourceSlot.js | 2 - src/app/sourceSlot.test.mjs | 24 --- src/data/flowTiles.js | 6 - src/data/flowTiles.test.mjs | 162 ------------------- src/data/issPass.js | 46 ------ src/data/issPass.test.mjs | 42 ----- src/data/localGeojson.analyst.test.mjs | 13 +- src/data/localGeojson.js | 29 ---- src/data/localGeojson.test.mjs | 23 ++- src/data/localGeojsonLifecycle.test.mjs | 10 +- src/data/localGeojsonLod.js | 8 +- src/data/tomtomTiles.js | 2 +- src/layers/traffic/flowDecode.js | 2 +- src/overlays/worldOverlayAllocation.test.mjs | 2 +- 21 files changed, 46 insertions(+), 355 deletions(-) create mode 100644 changelog.d/1403-remove-unused-modules.md delete mode 100644 src/app/sourceSlot.js delete mode 100644 src/app/sourceSlot.test.mjs delete mode 100644 src/data/flowTiles.js delete mode 100644 src/data/flowTiles.test.mjs delete mode 100644 src/data/issPass.js delete mode 100644 src/data/issPass.test.mjs delete mode 100644 src/data/localGeojson.js diff --git a/changelog.d/1403-remove-unused-modules.md b/changelog.d/1403-remove-unused-modules.md new file mode 100644 index 000000000..da95c7dcd --- /dev/null +++ b/changelog.d/1403-remove-unused-modules.md @@ -0,0 +1,5 @@ +- Remove four modules nothing in the app imports: `src/app/sourceSlot.js`, + `src/data/flowTiles.js`, `src/data/issPass.js` and `src/data/localGeojson.js`. + The local GeoJSON layer tests now build layers the way the catalog does, so + they keep covering `localGeojsonCore.js`. Package exports are unchanged + (samehkhamis, #1403). diff --git a/docs/CODE-BOUNDARIES.md b/docs/CODE-BOUNDARIES.md index 9085a7b72..9f8e0f629 100644 --- a/docs/CODE-BOUNDARIES.md +++ b/docs/CODE-BOUNDARIES.md @@ -81,8 +81,6 @@ moves it. Do not label all ingestion modules platform-independent by filename. | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | | `src/data/manager.js` | Lifecycle/panel compatibility and existing tests; normal assembly constructs lifecycle and presentation separately | | `src/data/.js` | Legacy default instances; new assembly calls layer factories with supplied sources | -| `src/data/localGeojson.js` | Infrastructure compatibility factories; catalog imports services from `src/app/localGeojsonServices.js` directly | -| `src/app/sourceSlot.js` | Re-export for direct callers/tests; portable slot ownership is `src/sources/sourceSlot.js` | | `src/app/sources.js`, `src/services/application.js` | Existing default/override API; current application construction supplies its own instances | | `server/providers/local.js` | Existing Node composition barrel and provider helper re-exports | diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index 8be9af204..3c53c93a2 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -4662,7 +4662,7 @@ current route throughout enabling, enabled, disabling, and uncertain lifecycle renders. Both routes preserve Radio power, playback, station, filter, and volume state. -Bundled datasets live in `src/data/local_data/` with per-folder provenance READMEs; they are lazily loaded via `src/data/localGeojson.js` (Vite `?url` assets) when toggled on. +Bundled datasets live in `src/data/local_data/` with per-folder provenance READMEs; they are lazily loaded via `src/data/localGeojsonCore.js` (Vite `?url` assets) when toggled on. A bundled dataset that fails to load is a broken install, not a blip, so it is never swallowed: `localGeojson.js` guards `response.ok`, reports `error` + diff --git a/docs/INFRASTRUCTURE-LAYERS.md b/docs/INFRASTRUCTURE-LAYERS.md index 76567e605..31d3cb4cb 100644 --- a/docs/INFRASTRUCTURE-LAYERS.md +++ b/docs/INFRASTRUCTURE-LAYERS.md @@ -53,9 +53,8 @@ Cesium installation shared with its viewer; it must not bundle separate copies. `gods-eye-view/infrastructure/geojson` exports the lower-level `createLocalGeoJsonLayer(options, services)` and existing infrastructure overlay helpers. `gods-eye-view/infrastructure/lod` exports the existing LOD policy helpers. -The standalone app's `src/data/localGeojson.js` keeps its original single-argument -factory and supplies its existing functions. Other consumers should use the package -exports, which do not import standalone application globals. +Consumers use the package exports, which do not import standalone application +globals. Dataset files and source/license notices remain under `src/data/local_data/`. Their input counts are 4,351 datacenter features and 704 dam features. Cesium may diff --git a/scripts/check-import-directions.mjs b/scripts/check-import-directions.mjs index 3f4fec617..b6d8dba67 100644 --- a/scripts/check-import-directions.mjs +++ b/scripts/check-import-directions.mjs @@ -153,14 +153,6 @@ export function checkImportDirections(root) { file, 'Actions must consume feed state without the manager facade', ); - if ( - file === 'src/app/constructCatalog.js' && - to === 'src/data/localGeojson.js' - ) - report( - file, - 'Catalog must use the services owner without compatibility layer construction', - ); } return record; } diff --git a/scripts/format-scope.json b/scripts/format-scope.json index f88be2b6b..d62e8bb47 100644 --- a/scripts/format-scope.json +++ b/scripts/format-scope.json @@ -518,7 +518,6 @@ "src/layers/bikeshare/selection.js", "src/data/traffic.js", "src/data/bikeshare.js", - "src/data/flowTiles.js", "src/layers/traffic/source.test.mjs", "src/layers/bikeshare/source.test.mjs", "src/layers/bikeshare/proxyRoute.test.mjs", @@ -651,7 +650,6 @@ "src/agent/worldPacket.test.mjs", "src/voice/layerSummary.js", "build/application-html.js", - "src/app/sourceSlot.js", "src/app/sources.js", "src/ui/composition.js", "src/services/application.js", diff --git a/scripts/package-boundaries.json b/scripts/package-boundaries.json index cddb29c40..89589091a 100644 --- a/scripts/package-boundaries.json +++ b/scripts/package-boundaries.json @@ -1163,7 +1163,6 @@ "satellites-layer": { "exports": ["./layers/satellites"], "modules": [ - "src/data/issPass.js", "src/data/satelliteClass.js", "src/data/satellitePass.js", "src/sources/tle.js", @@ -1853,14 +1852,12 @@ "src/data/iconOrientation.js", "src/data/infrastructure.js", "src/data/installationFeedback.js", - "src/data/issPass.js", "src/data/labelArbiter.js", "src/data/idSwitches.js", "src/data/layerState.js", "src/data/layerStateCoordinator.js", "src/data/layerStateTokenReservations.json", "src/data/lifecycle.js", - "src/data/localGeojson.js", "src/data/localGeojsonCore.js", "src/data/localGeojsonLod.js", "src/data/local_data/natural_earth/marine.json", @@ -2672,13 +2669,11 @@ "src/data/iconOrientation.js", "src/data/infrastructure.js", "src/data/installationFeedback.js", - "src/data/issPass.js", "src/data/satellitePass.js", "src/data/labelArbiter.js", "src/data/idSwitches.js", "src/data/layerState.js", "src/data/layerStateTokenReservations.json", - "src/data/localGeojson.js", "src/data/localGeojsonCore.js", "src/data/localGeojsonLod.js", "src/data/local_data/natural_earth/marine.json", @@ -3663,7 +3658,6 @@ "exports": ["./layers/transit/standalone"], "modules": [ "src/cyberSonar.js", - "src/app/sourceSlot.js", "src/celestialRing.js", "src/data/approxDistance.js", "src/data/cameraSensitivity.js", diff --git a/src/app/sourceSlot.js b/src/app/sourceSlot.js deleted file mode 100644 index fe7590e3b..000000000 --- a/src/app/sourceSlot.js +++ /dev/null @@ -1,2 +0,0 @@ -// Compatibility entry; source contracts are owned by sources/. -export { createSourceSlot } from '../sources/sourceSlot.js'; diff --git a/src/app/sourceSlot.test.mjs b/src/app/sourceSlot.test.mjs deleted file mode 100644 index 1b1face0c..000000000 --- a/src/app/sourceSlot.test.mjs +++ /dev/null @@ -1,24 +0,0 @@ -import test from 'node:test'; -import assert from 'node:assert/strict'; -import { createSourceSlot } from './sourceSlot.js'; - -test('replacing a source rejects its late result and old cleanup cannot clear the new source', async () => { - let finish; - const slot = createSourceSlot({ read: async () => 'default' }, ['read']); - const old = slot.configure({ read: () => new Promise(resolve => { finish = resolve; }) }); - const pending = slot.source.read(); - const stop = slot.configure({ read: async () => 'replacement', attribution: { name: 'Replacement' } }); - old(); - finish('stale'); - await assert.rejects(pending, { name: 'AbortError' }); - assert.equal(await slot.source.read(), 'replacement'); - assert.equal(slot.source.attribution.name, 'Replacement'); - stop(); - assert.throws(() => slot.source.read(), /not configured/); -}); - -test('an invalid replacement leaves the working source intact', async () => { - const slot = createSourceSlot({ read: async () => 42 }, ['read']); - assert.throws(() => slot.configure({}), TypeError); - assert.equal(await slot.source.read(), 42); -}); diff --git a/src/data/flowTiles.js b/src/data/flowTiles.js deleted file mode 100644 index 07efb0d9a..000000000 --- a/src/data/flowTiles.js +++ /dev/null @@ -1,6 +0,0 @@ -import { createFlowTileSource } from '../layers/traffic/flowSource.js'; -export { tilesForBounds } from './tomtomTiles.js'; -export { decodeFlowTile } from '../layers/traffic/flowDecode.js'; -const source = createFlowTileSource(); -export const { fetchFlowForBounds, getFlowSessionStats, resetFlowTileCache } = - source; diff --git a/src/data/flowTiles.test.mjs b/src/data/flowTiles.test.mjs deleted file mode 100644 index 61a7ddb78..000000000 --- a/src/data/flowTiles.test.mjs +++ /dev/null @@ -1,162 +0,0 @@ -// src/data/flowTiles.test.mjs -import { test } from 'node:test'; -import assert from 'node:assert/strict'; -import fs from 'node:fs'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; -import { - decodeFlowTile, - fetchFlowForBounds, - tilesForBounds, - getFlowSessionStats, - resetFlowTileCache, -} from './flowTiles.js'; - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); -// Real TomTom flow tile, downtown Austin z12 x935 y1686 (probed live 2026-07-16). -const FIXTURE = path.join(__dirname, 'fixtures', 'tomtom-flow-austin-12-935-1686.pbf'); -const FIXTURE_TILE = { z: 12, x: 935, y: 1686 }; - -function loadFixture() { - return fs.readFileSync(FIXTURE); -} - -// ── decodeFlowTile against the real fixture ───────────────── - -test('fixture decode: more than 50 flow segments', () => { - const segments = decodeFlowTile(loadFixture(), FIXTURE_TILE.z, FIXTURE_TILE.x, FIXTURE_TILE.y); - assert.ok(segments.length > 50, `got ${segments.length}`); -}); - -test('fixture decode: every trafficLevel is within [0, 1]', () => { - const segments = decodeFlowTile(loadFixture(), FIXTURE_TILE.z, FIXTURE_TILE.x, FIXTURE_TILE.y); - for (const s of segments) { - assert.ok(Number.isFinite(s.trafficLevel), `non-finite level: ${s.trafficLevel}`); - assert.ok(s.trafficLevel >= 0 && s.trafficLevel <= 1, `level out of range: ${s.trafficLevel}`); - } -}); - -test('fixture decode: all coordinates land in downtown Austin', () => { - const segments = decodeFlowTile(loadFixture(), FIXTURE_TILE.z, FIXTURE_TILE.x, FIXTURE_TILE.y); - for (const s of segments) { - assert.ok(Array.isArray(s.coords) && s.coords.length >= 2, 'polyline too short'); - for (const [lon, lat] of s.coords) { - assert.ok(lon >= -98.0 && lon <= -97.5, `lon out of Austin range: ${lon}`); - assert.ok(lat >= 30.0 && lat <= 30.5, `lat out of Austin range: ${lat}`); - } - } -}); - -test('fixture decode: congestion exists (at least one trafficLevel < 1)', () => { - const segments = decodeFlowTile(loadFixture(), FIXTURE_TILE.z, FIXTURE_TILE.x, FIXTURE_TILE.y); - assert.ok(segments.some((s) => s.trafficLevel < 1), 'no congested segment found'); -}); - -test('fixture decode: segment shape is {coords, trafficLevel, roadType, closure}', () => { - const segments = decodeFlowTile(loadFixture(), FIXTURE_TILE.z, FIXTURE_TILE.x, FIXTURE_TILE.y); - for (const s of segments) { - assert.equal(typeof s.roadType, 'string'); - assert.equal(typeof s.closure, 'boolean'); - } - // The fixture carries real closures — closure decoding is exercised, not vacuous. - assert.ok(segments.some((s) => s.closure === true), 'expected at least one closure in fixture'); -}); - -test('decode of a non-MVT buffer returns [] (defensive)', () => { - assert.deepEqual(decodeFlowTile(Buffer.from('not a protobuf tile'), 12, 935, 1686), []); -}); - -// ── tilesForBounds (re-exported slippy math) ──────────────── - -test('tilesForBounds: 30.2672,-97.7431 @ z12 -> covers x935 y1686', () => { - const tiles = tilesForBounds({ - south: 30.2672 - 0.001, north: 30.2672 + 0.001, - west: -97.7431 - 0.001, east: -97.7431 + 0.001, - }, 12); - assert.ok( - tiles.some((t) => t.z === 12 && t.x === 935 && t.y === 1686), - `fixture tile missing: ${JSON.stringify(tiles)}` - ); -}); - -// ── fetchFlowForBounds (stubbed fetch: cache + abort) ─────── - -/** Bounds fully inside the fixture tile. */ -const FIXTURE_BOUNDS = { south: 30.24, north: 30.26, west: -97.76, east: -97.74 }; - -function stubFetch(impl) { - const original = globalThis.fetch; - globalThis.fetch = impl; - return () => { globalThis.fetch = original; }; -} - -test('fetchFlowForBounds: fetches covering tiles via /api/tomtom and decodes', async () => { - resetFlowTileCache(); - const calls = []; - const restore = stubFetch(async (url) => { - calls.push(String(url)); - return new Response(loadFixture(), { - status: 200, - headers: { 'Content-Type': 'application/x-protobuf' }, - }); - }); - try { - const segments = await fetchFlowForBounds(FIXTURE_BOUNDS); - assert.equal(calls.length, 1); - assert.match(calls[0], /^\/api\/tomtom\/flow\/12\/935\/1686\.pbf$/); - assert.ok(segments.length > 50); - assert.ok(getFlowSessionStats().tilesFetched >= 1); - } finally { - restore(); - } -}); - -test('fetchFlowForBounds: decode cache serves repeat calls within TTL (no refetch)', async () => { - resetFlowTileCache(); - let calls = 0; - const restore = stubFetch(async () => { - calls += 1; - return new Response(loadFixture(), { status: 200 }); - }); - try { - const first = await fetchFlowForBounds(FIXTURE_BOUNDS); - const second = await fetchFlowForBounds(FIXTURE_BOUNDS); - assert.equal(calls, 1, 'second call must be served from the decode cache'); - assert.equal(second.length, first.length); - } finally { - restore(); - } -}); - -test('fetchFlowForBounds: aborted signal rejects (AbortSignal-aware)', async () => { - resetFlowTileCache(); - const restore = stubFetch(async (url, opts) => { - // Mimic real fetch abort semantics. - if (opts?.signal?.aborted) { - const err = new Error('aborted'); - err.name = 'AbortError'; - throw err; - } - return new Response(loadFixture(), { status: 200 }); - }); - try { - const controller = new AbortController(); - controller.abort(); - await assert.rejects( - fetchFlowForBounds(FIXTURE_BOUNDS, { signal: controller.signal }), - (err) => err.name === 'AbortError' - ); - } finally { - restore(); - } -}); - -test('fetchFlowForBounds: non-OK tile responses reject when nothing succeeds', async () => { - resetFlowTileCache(); - const restore = stubFetch(async () => new Response(JSON.stringify({ error: 'no_key' }), { status: 503 })); - try { - await assert.rejects(fetchFlowForBounds(FIXTURE_BOUNDS)); - } finally { - restore(); - } -}); diff --git a/src/data/issPass.js b/src/data/issPass.js deleted file mode 100644 index c3807d59f..000000000 --- a/src/data/issPass.js +++ /dev/null @@ -1,46 +0,0 @@ -// src/data/issPass.js -/** - * Next-ISS-pass prediction. Kept as a thin wrapper over satellitePass.js so the - * original findNextIssPass signature and defaults still work. - */ -import { findNextSatellitePass, lookAnglesAt } from './satellitePass.js'; - -export { lookAnglesAt }; - -/** - * Predict the next ISS pass over an observer location. - * @param {Object} options - * @param {Object} options.satrec SGP4 satellite record - * @param {number} options.latDeg Observer latitude in degrees [-90, 90] - * @param {number} options.lonDeg Observer longitude in degrees [-180, 180] - * @param {number} options.fromMs UTC start time in milliseconds - * @param {number} [options.minElevDeg=10] Elevation that defines rise and set, in degrees - * @param {number} [options.horizonHours=24] Maximum search window in hours - * @param {number} [options.coarseStepSec=30] Coarse search step in seconds - * @param {number} [options.fineStepSec=5] Fine transit step in seconds for peak tracking and visibility - * @param {boolean} [options.requireVisible=false] Require a naked-eye-visible pass - * @returns {{ riseMs: number, setMs: number, maxElevDeg: number, maxElevMs: number, riseAzDeg: number, visible: boolean, sunlit: boolean, observerDark: boolean } | null} - */ -export function findNextIssPass({ - satrec, - latDeg, - lonDeg, - fromMs, - minElevDeg = 10, - horizonHours = 24, - coarseStepSec = 30, - fineStepSec = 5, - requireVisible = false, -}) { - return findNextSatellitePass({ - satrec, - latDeg, - lonDeg, - fromMs, - minElevDeg, - horizonHours, - coarseStepSec, - fineStepSec, - requireVisible, - }); -} diff --git a/src/data/issPass.test.mjs b/src/data/issPass.test.mjs deleted file mode 100644 index aaaa87a55..000000000 --- a/src/data/issPass.test.mjs +++ /dev/null @@ -1,42 +0,0 @@ -// src/data/issPass.test.mjs -import { test } from 'node:test'; -import assert from 'node:assert/strict'; -import { twoline2satrec } from 'satellite.js'; -import { findNextIssPass, lookAnglesAt } from './issPass.js'; -import { findNextSatellitePass } from './satellitePass.js'; - -// Canonical archived ISS TLE (valid checksums; epoch 2008-09-20 ~12:25 UTC). -const L1 = '1 25544U 98067A 08264.51782528 -.00002182 00000-0 -11606-4 0 2927'; -const L2 = '2 25544 51.6416 247.4627 0006703 130.5360 325.0288 15.72125391563537'; -const AUSTIN = { latDeg: 30.2672, lonDeg: -97.7431 }; -const FROM_MS = Date.UTC(2008, 8, 20, 12, 30, 0); // just after the TLE epoch - -test('finds a structurally-consistent ISS pass within 24h of the TLE epoch', () => { - const satrec = twoline2satrec(L1, L2); - const pass = findNextIssPass({ satrec, ...AUSTIN, fromMs: FROM_MS, minElevDeg: 10 }); - assert.ok(pass, 'expected a pass within 24h at 30°N for a 51.6° inclination orbit'); - assert.ok(pass.riseMs > FROM_MS); - assert.ok(pass.riseMs < pass.maxElevMs && pass.maxElevMs < pass.setMs); - assert.ok(pass.maxElevDeg >= 10); - assert.ok(pass.riseAzDeg >= 0 && pass.riseAzDeg < 360); - - // Independent re-check: elevation at the reported peak really is the max-ish - // and ≥ threshold; one minute before rise it is below threshold. - const peak = lookAnglesAt(satrec, pass.maxElevMs, AUSTIN.latDeg, AUSTIN.lonDeg); - assert.ok(peak && Math.abs(peak.elevDeg - pass.maxElevDeg) < 1.5); - const before = lookAnglesAt(satrec, pass.riseMs - 60_000, AUSTIN.latDeg, AUSTIN.lonDeg); - assert.ok(before && before.elevDeg < 10); -}); - -test('forwards its original 30 s coarse step and fineStepSec to the pass engine', () => { - const satrec = twoline2satrec(L1, L2); - const opts = { satrec, ...AUSTIN, fromMs: FROM_MS, minElevDeg: 10, fineStepSec: 30 }; - assert.deepEqual(findNextIssPass(opts), findNextSatellitePass({ ...opts, coarseStepSec: 30 })); - assert.notDeepEqual(findNextIssPass(opts), findNextIssPass({ ...opts, fineStepSec: 5 })); -}); - -test('returns null when no pass clears an absurd threshold', () => { - const satrec = twoline2satrec(L1, L2); - const pass = findNextIssPass({ satrec, ...AUSTIN, fromMs: FROM_MS, minElevDeg: 89.9, horizonHours: 2 }); - assert.equal(pass, null); -}); diff --git a/src/data/localGeojson.analyst.test.mjs b/src/data/localGeojson.analyst.test.mjs index 061a7f27c..33d35a039 100644 --- a/src/data/localGeojson.analyst.test.mjs +++ b/src/data/localGeojson.analyst.test.mjs @@ -2,7 +2,18 @@ import { test } from 'node:test'; import assert from 'node:assert/strict'; import * as Cesium from 'cesium'; -import { createLocalGeoJsonLayer, mapAnalystRecord } from './localGeojson.js'; +import { localGeoJsonServices } from '../app/localGeojsonServices.js'; +import { + createLocalGeoJsonLayer as createLayer, + mapAnalystRecord, +} from './localGeojsonCore.js'; + +/** The catalog's services, with the overlay host each test supplies. */ +const createLocalGeoJsonLayer = (options) => + createLayer(options, { + ...localGeoJsonServices, + overlayHost: options.overlayHost, + }); const DC_RAW = { id: '1176042553', diff --git a/src/data/localGeojson.js b/src/data/localGeojson.js deleted file mode 100644 index 61f6c3abf..000000000 --- a/src/data/localGeojson.js +++ /dev/null @@ -1,29 +0,0 @@ -import { localGeoJsonServices } from '../app/localGeojsonServices.js'; -import { - createLocalGeoJsonLayer as createLayer, - createLocalInfrastructureOverlayPublisher as createPublisher, -} from './localGeojsonCore.js'; - -export * from './localGeojsonCore.js'; - -/** Create a layer using the standalone app's operations; retain overlay overrides. */ -export function createLocalGeoJsonLayer(options) { - return createLayer(options, { - ...localGeoJsonServices, - overlayHost: - options.overlayHost === undefined - ? localGeoJsonServices.overlayHost - : options.overlayHost, - }); -} - -/** Create an overlay publisher using the standalone app's host by default. */ -export function createLocalInfrastructureOverlayPublisher(options) { - return createPublisher({ - ...options, - host: - options.host === undefined - ? localGeoJsonServices.overlayHost - : options.host, - }); -} diff --git a/src/data/localGeojson.test.mjs b/src/data/localGeojson.test.mjs index 1c4499914..13cde65a5 100644 --- a/src/data/localGeojson.test.mjs +++ b/src/data/localGeojson.test.mjs @@ -6,13 +6,14 @@ import { GROUND_SAMPLE_MAX_ARMED_RETRIES, LOCAL_OVERLAY_COHORT_LIMIT, LOCAL_STEM_TIP_EPSILON_M, - createLocalGeoJsonLayer, + createLocalGeoJsonLayer as createLayer, createLocalInfrastructureOverlayEntry, createLocalInfrastructureOverlayPublisher, localDatasetError, localInfrastructureOverlayCopy, selectLocalInfrastructureOverlayCohort, -} from './localGeojson.js'; +} from './localGeojsonCore.js'; +import { localGeoJsonServices } from '../app/localGeojsonServices.js'; import { layerFeedState } from './manager.js'; import { INFRA_LOD_ACTIVE_MIN, INFRA_LOD_ACTIVE_MAX } from './localGeojsonLod.js'; import { @@ -21,6 +22,13 @@ import { _resetRenderGovernorForTest, } from '../renderGovernor.js'; +/** The catalog's services, with the overlay host each test supplies. */ +const createLocalGeoJsonLayer = (options) => + createLayer(options, { + ...localGeoJsonServices, + overlayHost: options.overlayHost ?? localGeoJsonServices.overlayHost, + }); + class MockLayerEvent { constructor() { this.listeners = new Set(); @@ -1337,14 +1345,3 @@ test('globe-LOD re-selects during continuous motion, without ever seeing a moveE assert.deepEqual(env.layer.getLodDiagnostics(), parked, 'a parked camera never re-selects'); }); - -test('standalone publisher retains its default host for an undefined override', () => { - const publisher = createLocalInfrastructureOverlayPublisher({ - sourceId: 'local-default-host-test', host: undefined, - }); - assert.doesNotThrow(() => { - publisher.show(); - publisher.hide(); - publisher.destroy(); - }); -}); diff --git a/src/data/localGeojsonLifecycle.test.mjs b/src/data/localGeojsonLifecycle.test.mjs index 245867155..8b5621ec4 100644 --- a/src/data/localGeojsonLifecycle.test.mjs +++ b/src/data/localGeojsonLifecycle.test.mjs @@ -1,9 +1,17 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import * as Cesium from 'cesium'; -import { createLocalGeoJsonLayer } from './localGeojson.js'; +import { localGeoJsonServices } from '../app/localGeojsonServices.js'; +import { createLocalGeoJsonLayer as createLayer } from './localGeojsonCore.js'; import { getContextStore } from './contextStore.js'; +/** The catalog's services, with the overlay host each test supplies. */ +const createLocalGeoJsonLayer = (options) => + createLayer(options, { + ...localGeoJsonServices, + overlayHost: options.overlayHost, + }); + const dataset = JSON.stringify({ type: 'Feature', id: 'dam', properties: { name: 'Test dam' }, geometry: { type: 'Polygon', coordinates: [[[0, 0], [0.01, 0], [0, 0.01], [0, 0]]] }, diff --git a/src/data/localGeojsonLod.js b/src/data/localGeojsonLod.js index cfd082c04..4a2dd92da 100644 --- a/src/data/localGeojsonLod.js +++ b/src/data/localGeojsonLod.js @@ -5,7 +5,7 @@ * Pure selection policy for the bundled local-infrastructure layers * (`local-datacenters`, `local-dams`, and any future `createLocalGeoJsonLayer` * dataset). Cesium-specific projection, occlusion, and stem geometry stay in - * `localGeojson.js`; this module turns the resulting in-view records into a + * `localGeojsonCore.js`; this module turns the resulting in-view records into a * bounded "active" set — the only records that layer should spend per-frame * stem-geometry and ground-sample work on. * @@ -80,7 +80,7 @@ export const INFRA_LOD_INCUMBENT_BONUS = 250; /** * Distance at or beyond which the proximity penalty is fully applied (m). - * Matches LOCAL_OVERLAY_MAX_DISTANCE_M's order of magnitude in localGeojson.js. + * Matches LOCAL_OVERLAY_MAX_DISTANCE_M's order of magnitude in infrastructureOverlayEntry.js. */ export const INFRA_LOD_FAR_M = 12_000_000; @@ -97,7 +97,7 @@ export const INFRA_LOD_MAX_DISTANCE_PENALTY = 200; * (callers only compare it), but every input is normalized so the output is * always a finite number. * - * @param {number} priority Existing label-priority score (localGeojson.js). + * @param {number} priority Existing label-priority score (localGeojsonCore.js). * @param {number} distanceM Camera→feature distance in metres. * @param {boolean} isIncumbent Record currently holds an active stem. * @param {object} [options] @@ -297,7 +297,7 @@ export function applyInfraEvictionGrace({ * ------------------------------------------------------------------ */ /** - * Probe window for the motion fallback. `localGeojson.js` marks its selection + * Probe window for the motion fallback. `localGeojsonCore.js` marks its selection * dirty on `moveEnd`, which covers drags, one-shot `setView`, and voice * `flyTo` — but a tracked-entity follow camera, a Cockpit view, a route * flight, or a continuous orbit never emits one. Without a fallback the diff --git a/src/data/tomtomTiles.js b/src/data/tomtomTiles.js index af4fc95b3..26ec539ab 100644 --- a/src/data/tomtomTiles.js +++ b/src/data/tomtomTiles.js @@ -2,7 +2,7 @@ * @file Pure tile math + budget accounting for the TomTom traffic-flow proxy. * * Shared by the `/api/tomtom` vite plugin (server-side: coordinate validation, - * daily budget governor) and `src/data/flowTiles.js` (client-side: which tiles + * daily budget governor) and `src/layers/traffic/flowSource.js` (client-side: which tiles * cover the current traffic fetch bounds). Zero dependencies, Cesium-free, so * both sides can unit-test against it with node:test. * diff --git a/src/layers/traffic/flowDecode.js b/src/layers/traffic/flowDecode.js index 691496554..9a0c248dd 100644 --- a/src/layers/traffic/flowDecode.js +++ b/src/layers/traffic/flowDecode.js @@ -19,7 +19,7 @@ import { VectorTile } from '@mapbox/vector-tile'; * tree-shakeable; decoding happens client-side so the proxy stays a dumb * binary cache. * - * @module data/flowTiles + * @module layers/traffic/flowDecode */ const FLOW_LAYER_NAME = 'Traffic flow'; diff --git a/src/overlays/worldOverlayAllocation.test.mjs b/src/overlays/worldOverlayAllocation.test.mjs index e29785d48..2ff6d6c8c 100644 --- a/src/overlays/worldOverlayAllocation.test.mjs +++ b/src/overlays/worldOverlayAllocation.test.mjs @@ -2,7 +2,7 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import { spawnSync } from 'node:child_process'; import { fileURLToPath } from 'node:url'; -import { LOCAL_OVERLAY_COHORT_LIMIT } from '../data/localGeojson.js'; +import { LOCAL_OVERLAY_COHORT_LIMIT } from '../data/localGeojsonCore.js'; import { FIRMS_AMBIENT_COHORT_LIMIT } from '../data/firmsLabels.js'; import { vesselOverlayCohortLimit } from '../data/vesselLabels.js'; import { CCTV_AMBIENT_CARD_MAX } from '../data/cctvLod.js';