From 41d1458d8e5ae0dbd58b11af0147a16bc01395e9 Mon Sep 17 00:00:00 2001 From: AquilaXk Date: Wed, 23 Sep 2026 21:58:07 +0900 Subject: [PATCH] feat(datapack): sort transfer links and transfer rules in ascending duration order --- tools/datapack/build-datapack.mjs | 12 +++++-- ...out-of-station-transfer-asymmetry.test.mjs | 35 +++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/tools/datapack/build-datapack.mjs b/tools/datapack/build-datapack.mjs index 32631dee..61f6ac85 100644 --- a/tools/datapack/build-datapack.mjs +++ b/tools/datapack/build-datapack.mjs @@ -4240,7 +4240,11 @@ function buildSqlitePack(sqlitePath, schema, pack, officialOdFareAdmissions) { "last_field_verified_at", "evidence_hash", ], - pack.outOfStationTransferLinks ?? [], + [...(pack.outOfStationTransferLinks ?? [])].sort( + (a, b) => + (a.durationSeconds ?? 0) - (b.durationSeconds ?? 0) || + codepointCompare(String(a.id), String(b.id)), + ), (row) => [ requiredString(row.id, "outOfStationTransferLinks.id"), requiredString(row.fromStationId, "outOfStationTransferLinks.fromStationId"), @@ -4705,7 +4709,11 @@ function buildSqlitePack(sqlitePath, schema, pack, officialOdFareAdmissions) { "source_id", "verification_status", ], - pack.transferRules ?? [], + [...(pack.transferRules ?? [])].sort( + (a, b) => + (a.minTransferSeconds ?? 0) - (b.minTransferSeconds ?? 0) || + codepointCompare(String(a.id), String(b.id)), + ), (row) => [ requiredString(row.id, "transferRules.id"), requiredString(row.fromStationId, "transferRules.fromStationId"), diff --git a/tools/datapack/build-out-of-station-transfer-asymmetry.test.mjs b/tools/datapack/build-out-of-station-transfer-asymmetry.test.mjs index c3b79e09..22186265 100644 --- a/tools/datapack/build-out-of-station-transfer-asymmetry.test.mjs +++ b/tools/datapack/build-out-of-station-transfer-asymmetry.test.mjs @@ -197,3 +197,38 @@ test("out-of-station transfer SQLite bundle: forces bidirectional=0 for slope_le db.close(); }); +test("out-of-station transfer links and transfer rules are serialized in ascending duration order", async () => { + const { codepointCompare } = await import("../lib/codepoint-compare.mjs"); + const links = [ + { id: "link-long", durationSeconds: 600 }, + { id: "link-short", durationSeconds: 120 }, + { id: "link-mid", durationSeconds: 300 }, + { id: "link-same-b", durationSeconds: 120 }, + { id: "link-same-a", durationSeconds: 120 }, + ]; + const sortedLinks = [...links].sort( + (a, b) => + (a.durationSeconds ?? 0) - (b.durationSeconds ?? 0) || + codepointCompare(String(a.id), String(b.id)), + ); + assert.deepEqual( + sortedLinks.map((l) => l.id), + ["link-same-a", "link-same-b", "link-short", "link-mid", "link-long"], + ); + + const rules = [ + { id: "rule-c", minTransferSeconds: 300 }, + { id: "rule-a", minTransferSeconds: 90 }, + { id: "rule-b", minTransferSeconds: 180 }, + ]; + const sortedRules = [...rules].sort( + (a, b) => + (a.minTransferSeconds ?? 0) - (b.minTransferSeconds ?? 0) || + codepointCompare(String(a.id), String(b.id)), + ); + assert.deepEqual( + sortedRules.map((r) => r.id), + ["rule-a", "rule-b", "rule-c"], + ); +}); +