feat(map): add functional sector grid v2
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import test from "node:test";
|
||||
import vm from "node:vm";
|
||||
import { DEFAULT_GRID_LOD_PROFILES } from "../apps/catalog/src/mapGridPolicy.mjs";
|
||||
|
||||
const seed = JSON.parse(await readFile(new URL("../runtime-seed/page-layouts/map.json", import.meta.url), "utf8"));
|
||||
const serverSource = await readFile(new URL("./catalog-server.mjs", import.meta.url), "utf8");
|
||||
const mcpSource = await readFile(new URL("./foundry-mcp.mjs", import.meta.url), "utf8");
|
||||
const extensionKeys = [
|
||||
"majorLinesEnabled",
|
||||
"majorLabelsEnabled",
|
||||
"majorLineWidthMultiplier",
|
||||
"volumeEnabled",
|
||||
"volumeMinimumHeightMeters",
|
||||
"volumeMaximumHeightMeters",
|
||||
"volumeBandHeightMeters",
|
||||
];
|
||||
|
||||
function applicationError(code, statusCode = 400) {
|
||||
const error = new Error(code);
|
||||
error.statusCode = statusCode;
|
||||
return error;
|
||||
}
|
||||
|
||||
const validators = {
|
||||
applicationError,
|
||||
isObject: (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value),
|
||||
requireNumber(value, minimum, maximum, code) {
|
||||
if (typeof value !== "number" || !Number.isFinite(value) || value < minimum || value > maximum) {
|
||||
throw applicationError(code);
|
||||
}
|
||||
return value;
|
||||
},
|
||||
requireBoolean(value, code) {
|
||||
if (typeof value !== "boolean") throw applicationError(code);
|
||||
return value;
|
||||
},
|
||||
requireHex(value, code) {
|
||||
const normalized = String(value || "");
|
||||
if (!/^#[0-9a-f]{6}$/i.test(normalized)) throw applicationError(code);
|
||||
return normalized.toLowerCase();
|
||||
},
|
||||
};
|
||||
|
||||
function loadServerGridContract() {
|
||||
const start = serverSource.indexOf("const GRID_LOD_PROFILE_KEYS");
|
||||
const end = serverSource.indexOf("function validateMapPageSettingsPatch");
|
||||
assert.ok(start >= 0 && end > start, "server grid contract source boundaries");
|
||||
const context = vm.createContext({ ...validators });
|
||||
const source = `${serverSource.slice(start, end)}\n;globalThis.gridContract = { DEFAULT_GRID_LOD_PROFILES, promoteLegacyGridLodProfiles, validateGridLodProfiles };`;
|
||||
new vm.Script(source, { filename: "catalog-server.grid-contract.mjs" }).runInContext(context);
|
||||
return context.gridContract;
|
||||
}
|
||||
|
||||
const serverGrid = loadServerGridContract();
|
||||
|
||||
test("seed, client defaults and server promotion keep the sector-v2 profile contract identical", () => {
|
||||
assert.deepEqual(seed.settings.gridLodProfiles, DEFAULT_GRID_LOD_PROFILES);
|
||||
const legacyProfiles = seed.settings.gridLodProfiles.map((profile) => {
|
||||
const legacy = { ...profile };
|
||||
for (const key of extensionKeys) delete legacy[key];
|
||||
return legacy;
|
||||
});
|
||||
assert.deepEqual(
|
||||
structuredClone(serverGrid.validateGridLodProfiles(legacyProfiles)),
|
||||
DEFAULT_GRID_LOD_PROFILES,
|
||||
);
|
||||
});
|
||||
|
||||
test("flat layouts migrate mode-aware extensions while explicit invalid hierarchy is rejected", () => {
|
||||
const flatSettings = {
|
||||
...seed.settings,
|
||||
gridLodProfiles: undefined,
|
||||
gridLod1StepKm: 3,
|
||||
gridTileSizeKm: 10,
|
||||
gridLod2Mode: "graticule",
|
||||
};
|
||||
const migrated = structuredClone(serverGrid.validateGridLodProfiles(
|
||||
serverGrid.promoteLegacyGridLodProfiles(flatSettings),
|
||||
));
|
||||
assert.equal(migrated[0].majorLinesEnabled, false);
|
||||
assert.equal(migrated[0].majorLabelsEnabled, false);
|
||||
assert.equal(migrated[1].mode, "graticule");
|
||||
assert.equal(migrated[1].volumeEnabled, false);
|
||||
|
||||
const invalidExplicit = structuredClone(DEFAULT_GRID_LOD_PROFILES);
|
||||
invalidExplicit[0].stepKm = 3;
|
||||
invalidExplicit[0].tileSizeKm = 10;
|
||||
assert.throws(
|
||||
() => serverGrid.validateGridLodProfiles(invalidExplicit),
|
||||
/invalid_map_grid_lod_profile_1_tileSizeKm_step_ratio/,
|
||||
);
|
||||
});
|
||||
|
||||
test("Foundry MCP exposes every persisted sector-v2 profile field", () => {
|
||||
for (const key of extensionKeys) assert.match(mcpSource, new RegExp(`\\b${key}: \\{`));
|
||||
});
|
||||
Reference in New Issue
Block a user