corequery-gtfs 0.1.0 → 0.1.2

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.
Files changed (185) hide show
  1. package/README.md +1 -1
  2. package/dist/config/gtfs-config.d.ts +10 -0
  3. package/dist/config/gtfs-config.js +2 -0
  4. package/dist/config/gtfs-config.js.map +1 -0
  5. package/dist/config/ids.d.ts +13 -0
  6. package/dist/config/ids.js +2 -0
  7. package/dist/config/ids.js.map +1 -0
  8. package/dist/config/index.d.ts +4 -0
  9. package/dist/config/index.js +5 -0
  10. package/dist/config/index.js.map +1 -0
  11. package/dist/config/routes.d.ts +16 -0
  12. package/dist/config/routes.js +2 -0
  13. package/dist/config/routes.js.map +1 -0
  14. package/dist/config/timezone-data.d.ts +5 -0
  15. package/dist/config/timezone-data.js +2 -0
  16. package/dist/config/timezone-data.js.map +1 -0
  17. package/dist/corequery-types.d.ts +2 -0
  18. package/dist/corequery-types.js +3 -0
  19. package/dist/corequery-types.js.map +1 -0
  20. package/dist/data/bounded-instant-range.d.ts +10 -0
  21. package/dist/data/bounded-instant-range.js +30 -0
  22. package/dist/data/bounded-instant-range.js.map +1 -0
  23. package/dist/data/gtfs-calendar.d.ts +38 -0
  24. package/dist/data/gtfs-calendar.js +116 -0
  25. package/dist/data/gtfs-calendar.js.map +1 -0
  26. package/dist/data/gtfs-feed.d.ts +16 -0
  27. package/dist/data/gtfs-feed.js +33 -0
  28. package/dist/data/gtfs-feed.js.map +1 -0
  29. package/dist/data/gtfs-realtime-data.d.ts +9 -0
  30. package/dist/data/gtfs-realtime-data.js +20 -0
  31. package/dist/data/gtfs-realtime-data.js.map +1 -0
  32. package/dist/data/gtfs-schedule-data.d.ts +13 -0
  33. package/dist/data/gtfs-schedule-data.js +40 -0
  34. package/dist/data/gtfs-schedule-data.js.map +1 -0
  35. package/dist/data/gtfs-scheduled-trip-movements.d.ts +118 -0
  36. package/dist/data/gtfs-scheduled-trip-movements.js +233 -0
  37. package/dist/data/gtfs-scheduled-trip-movements.js.map +1 -0
  38. package/dist/data/gtfs-scheduled-trip.d.ts +41 -0
  39. package/dist/data/gtfs-scheduled-trip.js +100 -0
  40. package/dist/data/gtfs-scheduled-trip.js.map +1 -0
  41. package/dist/data/gtfs-stop-time.d.ts +38 -0
  42. package/dist/data/gtfs-stop-time.js +105 -0
  43. package/dist/data/gtfs-stop-time.js.map +1 -0
  44. package/dist/data/gtfs-updated-trip-movements.d.ts +124 -0
  45. package/dist/data/gtfs-updated-trip-movements.js +150 -0
  46. package/dist/data/gtfs-updated-trip-movements.js.map +1 -0
  47. package/dist/data/gtfs-updated-trip.d.ts +21 -0
  48. package/dist/data/gtfs-updated-trip.js +55 -0
  49. package/dist/data/gtfs-updated-trip.js.map +1 -0
  50. package/dist/data/ids/index.d.ts +2 -0
  51. package/dist/data/ids/index.js +3 -0
  52. package/dist/data/ids/index.js.map +1 -0
  53. package/dist/data/ids/line-gtfs-id-collection.d.ts +16 -0
  54. package/dist/data/ids/line-gtfs-id-collection.js +47 -0
  55. package/dist/data/ids/line-gtfs-id-collection.js.map +1 -0
  56. package/dist/data/ids/line-gtfs-id-mapping.d.ts +17 -0
  57. package/dist/data/ids/line-gtfs-id-mapping.js +50 -0
  58. package/dist/data/ids/line-gtfs-id-mapping.js.map +1 -0
  59. package/dist/data/ids/line-gtfs-id-metadata.d.ts +17 -0
  60. package/dist/data/ids/line-gtfs-id-metadata.js +2 -0
  61. package/dist/data/ids/line-gtfs-id-metadata.js.map +1 -0
  62. package/dist/data/ids/stop-gtfs-id-collection.d.ts +14 -0
  63. package/dist/data/ids/stop-gtfs-id-collection.js +55 -0
  64. package/dist/data/ids/stop-gtfs-id-collection.js.map +1 -0
  65. package/dist/data/ids/stop-gtfs-id-mapping.d.ts +17 -0
  66. package/dist/data/ids/stop-gtfs-id-mapping.js +50 -0
  67. package/dist/data/ids/stop-gtfs-id-mapping.js.map +1 -0
  68. package/dist/data/ids/stop-gtfs-id-metadata.d.ts +23 -0
  69. package/dist/data/ids/stop-gtfs-id-metadata.js +2 -0
  70. package/dist/data/ids/stop-gtfs-id-metadata.js.map +1 -0
  71. package/dist/data/index.d.ts +3 -0
  72. package/dist/data/index.js +4 -0
  73. package/dist/data/index.js.map +1 -0
  74. package/dist/data/plain-date-range.d.ts +11 -0
  75. package/dist/data/plain-date-range.js +36 -0
  76. package/dist/data/plain-date-range.js.map +1 -0
  77. package/dist/data/raw/realtime-data-json.d.ts +26 -0
  78. package/dist/data/raw/realtime-data-json.js +2 -0
  79. package/dist/data/raw/realtime-data-json.js.map +1 -0
  80. package/dist/data/raw/schedule-csvs.d.ts +69 -0
  81. package/dist/data/raw/schedule-csvs.js +2 -0
  82. package/dist/data/raw/schedule-csvs.js.map +1 -0
  83. package/dist/data/route/bonus-lines-mapping.d.ts +17 -0
  84. package/dist/data/route/bonus-lines-mapping.js +29 -0
  85. package/dist/data/route/bonus-lines-mapping.js.map +1 -0
  86. package/dist/data/route/index.d.ts +1 -0
  87. package/dist/data/route/index.js +2 -0
  88. package/dist/data/route/index.js.map +1 -0
  89. package/dist/data/route/line-routes-mapping.d.ts +8 -0
  90. package/dist/data/route/line-routes-mapping.js +20 -0
  91. package/dist/data/route/line-routes-mapping.js.map +1 -0
  92. package/dist/data/route/route-stop.d.ts +12 -0
  93. package/dist/data/route/route-stop.js +18 -0
  94. package/dist/data/route/route-stop.js.map +1 -0
  95. package/dist/data/route/route.d.ts +19 -0
  96. package/dist/data/route/route.js +43 -0
  97. package/dist/data/route/route.js.map +1 -0
  98. package/dist/data/utils.d.ts +3 -0
  99. package/dist/data/utils.js +2 -0
  100. package/dist/data/utils.js.map +1 -0
  101. package/dist/departures/departures-block-iterator.d.ts +18 -0
  102. package/dist/departures/departures-block-iterator.js +70 -0
  103. package/dist/departures/departures-block-iterator.js.map +1 -0
  104. package/dist/departures/departures-block.d.ts +19 -0
  105. package/dist/departures/departures-block.js +13 -0
  106. package/dist/departures/departures-block.js.map +1 -0
  107. package/dist/departures/departures-iterator.d.ts +16 -0
  108. package/dist/departures/departures-iterator.js +15 -0
  109. package/dist/departures/departures-iterator.js.map +1 -0
  110. package/dist/departures/gtfs-scheduled-movements-index.d.ts +18 -0
  111. package/dist/departures/gtfs-scheduled-movements-index.js +66 -0
  112. package/dist/departures/gtfs-scheduled-movements-index.js.map +1 -0
  113. package/dist/departures/index.d.ts +1 -0
  114. package/dist/departures/index.js +2 -0
  115. package/dist/departures/index.js.map +1 -0
  116. package/dist/departures/multifeed-departures-iterator.d.ts +20 -0
  117. package/dist/departures/multifeed-departures-iterator.js +52 -0
  118. package/dist/departures/multifeed-departures-iterator.js.map +1 -0
  119. package/dist/departures/realtime-departures-block-iterator.d.ts +12 -0
  120. package/dist/departures/realtime-departures-block-iterator.js +38 -0
  121. package/dist/departures/realtime-departures-block-iterator.js.map +1 -0
  122. package/dist/departures/realtime-departures-block.d.ts +16 -0
  123. package/dist/departures/realtime-departures-block.js +43 -0
  124. package/dist/departures/realtime-departures-block.js.map +1 -0
  125. package/dist/departures/scheduled-departures-block-iterator.d.ts +12 -0
  126. package/dist/departures/scheduled-departures-block-iterator.js +55 -0
  127. package/dist/departures/scheduled-departures-block-iterator.js.map +1 -0
  128. package/dist/departures/scheduled-departures-block.d.ts +18 -0
  129. package/dist/departures/scheduled-departures-block.js +54 -0
  130. package/dist/departures/scheduled-departures-block.js.map +1 -0
  131. package/dist/departures/scheduled-departures-blocks-builder.d.ts +20 -0
  132. package/dist/departures/scheduled-departures-blocks-builder.js +222 -0
  133. package/dist/departures/scheduled-departures-blocks-builder.js.map +1 -0
  134. package/dist/departures/scheduled-departures-iterator.d.ts +30 -0
  135. package/dist/departures/scheduled-departures-iterator.js +204 -0
  136. package/dist/departures/scheduled-departures-iterator.js.map +1 -0
  137. package/dist/departures/zipper-departures-iterator.d.ts +18 -0
  138. package/dist/departures/zipper-departures-iterator.js +68 -0
  139. package/dist/departures/zipper-departures-iterator.js.map +1 -0
  140. package/dist/gtfs-system.d.ts +31 -0
  141. package/dist/gtfs-system.js +86 -0
  142. package/dist/gtfs-system.js.map +1 -0
  143. package/dist/index.d.ts +6 -0
  144. package/dist/index.js +7 -0
  145. package/dist/index.js.map +1 -0
  146. package/dist/parser/gtfs-feed-parser.d.ts +18 -0
  147. package/dist/parser/gtfs-feed-parser.js +23 -0
  148. package/dist/parser/gtfs-feed-parser.js.map +1 -0
  149. package/dist/parser/index.d.ts +2 -0
  150. package/dist/parser/index.js +3 -0
  151. package/dist/parser/index.js.map +1 -0
  152. package/dist/parser/realtime/gtfs-realtime-data-parser.d.ts +11 -0
  153. package/dist/parser/realtime/gtfs-realtime-data-parser.js +19 -0
  154. package/dist/parser/realtime/gtfs-realtime-data-parser.js.map +1 -0
  155. package/dist/parser/realtime/gtfs-trip-update-parser.d.ts +99 -0
  156. package/dist/parser/realtime/gtfs-trip-update-parser.js +335 -0
  157. package/dist/parser/realtime/gtfs-trip-update-parser.js.map +1 -0
  158. package/dist/parser/realtime/gtfs-trip-update-trip-identifier.d.ts +35 -0
  159. package/dist/parser/realtime/gtfs-trip-update-trip-identifier.js +95 -0
  160. package/dist/parser/realtime/gtfs-trip-update-trip-identifier.js.map +1 -0
  161. package/dist/parser/realtime/index.d.ts +3 -0
  162. package/dist/parser/realtime/index.js +2 -0
  163. package/dist/parser/realtime/index.js.map +1 -0
  164. package/dist/parser/schedule/gtfs-calendar-parser.d.ts +28 -0
  165. package/dist/parser/schedule/gtfs-calendar-parser.js +113 -0
  166. package/dist/parser/schedule/gtfs-calendar-parser.js.map +1 -0
  167. package/dist/parser/schedule/gtfs-route-matcher.d.ts +48 -0
  168. package/dist/parser/schedule/gtfs-route-matcher.js +199 -0
  169. package/dist/parser/schedule/gtfs-route-matcher.js.map +1 -0
  170. package/dist/parser/schedule/gtfs-schedule-parser.d.ts +15 -0
  171. package/dist/parser/schedule/gtfs-schedule-parser.js +19 -0
  172. package/dist/parser/schedule/gtfs-schedule-parser.js.map +1 -0
  173. package/dist/parser/schedule/gtfs-stop-time-normaliser.d.ts +47 -0
  174. package/dist/parser/schedule/gtfs-stop-time-normaliser.js +119 -0
  175. package/dist/parser/schedule/gtfs-stop-time-normaliser.js.map +1 -0
  176. package/dist/parser/schedule/gtfs-transfer-connector.d.ts +52 -0
  177. package/dist/parser/schedule/gtfs-transfer-connector.js +168 -0
  178. package/dist/parser/schedule/gtfs-transfer-connector.js.map +1 -0
  179. package/dist/parser/schedule/gtfs-trip-parser.d.ts +45 -0
  180. package/dist/parser/schedule/gtfs-trip-parser.js +169 -0
  181. package/dist/parser/schedule/gtfs-trip-parser.js.map +1 -0
  182. package/dist/parser/schedule/index.d.ts +6 -0
  183. package/dist/parser/schedule/index.js +2 -0
  184. package/dist/parser/schedule/index.js.map +1 -0
  185. package/package.json +3 -3
@@ -0,0 +1,2 @@
1
+ export * from "./multifeed-departures-iterator.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/departures/index.ts"],"names":[],"mappings":"AAAA,cAAc,oCAAoC,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { DeparturesIterator, DeparturesIteratorResult } from "./departures-iterator.js";
2
+ import type { GtfsScheduledTrip } from "../data/gtfs-scheduled-trip.js";
3
+ import type { GtfsUpdatedTrip } from "../data/gtfs-updated-trip.js";
4
+ import type { GtfsTripServicingMovement } from "../data/utils.js";
5
+ import type { DeparturesSearchDirection } from "../corequery-types.js";
6
+ export declare class MultifeedDeparturesIteratorResult extends DeparturesIteratorResult {
7
+ readonly feed: string;
8
+ constructor(feed: string, trip: GtfsScheduledTrip | GtfsUpdatedTrip, serviceDay: Temporal.PlainDate, instant: Temporal.Instant, movement: GtfsTripServicingMovement);
9
+ static from(feed: string, result: DeparturesIteratorResult): MultifeedDeparturesIteratorResult;
10
+ }
11
+ export declare class MultifeedDeparturesIterator {
12
+ private readonly _iterators;
13
+ private _zipper;
14
+ constructor(_iterators: Map<DeparturesIterator, string>);
15
+ static build(config: Record<string, DeparturesIterator>): MultifeedDeparturesIterator;
16
+ set(instant: Temporal.Instant, direction: DeparturesSearchDirection): void;
17
+ peek(): MultifeedDeparturesIteratorResult | null;
18
+ take(): MultifeedDeparturesIteratorResult;
19
+ private _wrap;
20
+ }
@@ -0,0 +1,52 @@
1
+ import { DeparturesIterator, DeparturesIteratorResult, } from "./departures-iterator.js";
2
+ import { ZipperDeparturesIterator } from "./zipper-departures-iterator.js";
3
+ // TODO: [DS] Delete this. We're gonna combine feeds at the corequery departure
4
+ // iterator level, not within the GTFS ecosystem.
5
+ export class MultifeedDeparturesIteratorResult extends DeparturesIteratorResult {
6
+ feed;
7
+ constructor(feed, trip, serviceDay, instant, movement) {
8
+ super(trip, serviceDay, instant, movement);
9
+ this.feed = feed;
10
+ }
11
+ static from(feed, result) {
12
+ return new MultifeedDeparturesIteratorResult(feed, result.trip, result.serviceDay, result.instant, result.movement);
13
+ }
14
+ }
15
+ export class MultifeedDeparturesIterator {
16
+ _iterators;
17
+ _zipper;
18
+ constructor(_iterators) {
19
+ this._iterators = _iterators;
20
+ this._zipper = new ZipperDeparturesIterator(Array.from(_iterators.keys()));
21
+ }
22
+ static build(config) {
23
+ const iterators = new Map();
24
+ for (const [feed, iterator] of Object.entries(config)) {
25
+ iterators.set(iterator, feed);
26
+ }
27
+ return new MultifeedDeparturesIterator(iterators);
28
+ }
29
+ set(instant, direction) {
30
+ this._zipper.set(instant, direction);
31
+ }
32
+ peek() {
33
+ const result = this._zipper.peek();
34
+ const iterator = this._zipper.peekAtIterator();
35
+ if (result == null || iterator == null)
36
+ return null;
37
+ return this._wrap(result, iterator);
38
+ }
39
+ take() {
40
+ const iterator = this._zipper.peekAtIterator();
41
+ if (iterator == null)
42
+ throw new Error("Nothing to take.");
43
+ return this._wrap(this._zipper.take(), iterator);
44
+ }
45
+ _wrap(result, iterator) {
46
+ const feed = this._iterators.get(iterator);
47
+ if (feed == null)
48
+ throw new Error("Unrecognized iterator.");
49
+ return MultifeedDeparturesIteratorResult.from(feed, result);
50
+ }
51
+ }
52
+ //# sourceMappingURL=multifeed-departures-iterator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multifeed-departures-iterator.js","sourceRoot":"","sources":["../../src/departures/multifeed-departures-iterator.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,wBAAwB,GACzB,MAAM,0BAA0B,CAAC;AAIlC,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAG3E,+EAA+E;AAC/E,iDAAiD;AAEjD,MAAM,OAAO,iCAAkC,SAAQ,wBAAwB;IAElE;IADX,YACW,IAAY,EACrB,IAAyC,EACzC,UAA8B,EAC9B,OAAyB,EACzB,QAAmC;QAEnC,KAAK,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QANlC,SAAI,GAAJ,IAAI,CAAQ;IAOvB,CAAC;IAED,MAAM,CAAC,IAAI,CACT,IAAY,EACZ,MAAgC;QAEhC,OAAO,IAAI,iCAAiC,CAC1C,IAAI,EACJ,MAAM,CAAC,IAAI,EACX,MAAM,CAAC,UAAU,EACjB,MAAM,CAAC,OAAO,EACd,MAAM,CAAC,QAAQ,CAChB,CAAC;IACJ,CAAC;CACF;AAED,MAAM,OAAO,2BAA2B;IAGT;IAFrB,OAAO,CAA2B;IAE1C,YAA6B,UAA2C;QAA3C,eAAU,GAAV,UAAU,CAAiC;QACtE,IAAI,CAAC,OAAO,GAAG,IAAI,wBAAwB,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC7E,CAAC;IAED,MAAM,CAAC,KAAK,CACV,MAA0C;QAE1C,MAAM,SAAS,GAAG,IAAI,GAAG,EAA8B,CAAC;QACxD,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACtD,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAChC,CAAC;QAED,OAAO,IAAI,2BAA2B,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;IAED,GAAG,CAAC,OAAyB,EAAE,SAAoC;QACjE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACvC,CAAC;IAED,IAAI;QACF,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;QAC/C,IAAI,MAAM,IAAI,IAAI,IAAI,QAAQ,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC;QAEpD,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACtC,CAAC;IAED,IAAI;QACF,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;QAC/C,IAAI,QAAQ,IAAI,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAC1D,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,QAAQ,CAAC,CAAC;IACnD,CAAC;IAEO,KAAK,CACX,MAAgC,EAChC,QAA4B;QAE5B,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC3C,IAAI,IAAI,IAAI,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAE5D,OAAO,iCAAiC,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC9D,CAAC;CACF"}
@@ -0,0 +1,12 @@
1
+ import { DeparturesIteratorResult } from "./departures-iterator.js";
2
+ import { RealtimeDeparturesBlock, type RealtimeDeparturesBlockEntry } from "./realtime-departures-block.js";
3
+ import type { GtfsRealtimeData } from "../data/gtfs-realtime-data.js";
4
+ import { DeparturesBlockIterator } from "./departures-block-iterator.js";
5
+ export declare class RealtimeDeparturesBlockIterator extends DeparturesBlockIterator<RealtimeDeparturesBlock, RealtimeDeparturesBlockEntry> {
6
+ private readonly _realtimeData;
7
+ constructor(block: RealtimeDeparturesBlock, _realtimeData: GtfsRealtimeData);
8
+ static tryBuild(stopId: number, realtimeData: GtfsRealtimeData): RealtimeDeparturesBlockIterator | null;
9
+ protected _convertEntryToResult(entry: RealtimeDeparturesBlockEntry): DeparturesIteratorResult;
10
+ protected _shouldSkipEntry(entry: RealtimeDeparturesBlockEntry): boolean;
11
+ private _isTripCancelled;
12
+ }
@@ -0,0 +1,38 @@
1
+ import { DeparturesIteratorResult } from "./departures-iterator.js";
2
+ import { RealtimeDeparturesBlock, } from "./realtime-departures-block.js";
3
+ import { DeparturesBlockIterator } from "./departures-block-iterator.js";
4
+ export class RealtimeDeparturesBlockIterator extends DeparturesBlockIterator {
5
+ _realtimeData;
6
+ constructor(block, _realtimeData) {
7
+ super(block, block.entries);
8
+ this._realtimeData = _realtimeData;
9
+ }
10
+ static tryBuild(stopId, realtimeData) {
11
+ const block = RealtimeDeparturesBlock.tryBuild(stopId, realtimeData);
12
+ if (block == null)
13
+ return null;
14
+ return new RealtimeDeparturesBlockIterator(block, realtimeData);
15
+ }
16
+ _convertEntryToResult(entry) {
17
+ return new DeparturesIteratorResult(entry.trip, entry.trip.serviceDay, entry.instant, entry.movement);
18
+ }
19
+ _shouldSkipEntry(entry) {
20
+ const { movement, trip } = entry;
21
+ // Even users not filtering arrivals won't be interested to see the same
22
+ // trip listed twice at stations like Flinders Street or Town Hall, once for
23
+ // the arrival and then again for the departure of the continuing trip. We
24
+ // just need to be sure the continuing trip is actually running!
25
+ const isArrivalWhichContinues = movement.type === "terminating" &&
26
+ trip.scheduledTrip.nextTrip != null &&
27
+ trip.scheduledTrip.nextTrip.calendar.occursOn(trip.serviceDay) &&
28
+ !this._isTripCancelled(trip.scheduledTrip.nextTrip.gtfsTripId, entry.trip.serviceDay);
29
+ if (isArrivalWhichContinues)
30
+ return true;
31
+ return false;
32
+ }
33
+ _isTripCancelled(tripId, serviceDay) {
34
+ const realtimeTrip = this._realtimeData.getForScheduledTrip(tripId, serviceDay);
35
+ return realtimeTrip?.isCancelled ?? false;
36
+ }
37
+ }
38
+ //# sourceMappingURL=realtime-departures-block-iterator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-departures-block-iterator.js","sourceRoot":"","sources":["../../src/departures/realtime-departures-block-iterator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EACL,uBAAuB,GAExB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAEzE,MAAM,OAAO,+BAAgC,SAAQ,uBAGpD;IAGoB;IAFnB,YACE,KAA8B,EACb,aAA+B;QAEhD,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAFX,kBAAa,GAAb,aAAa,CAAkB;IAGlD,CAAC;IAED,MAAM,CAAC,QAAQ,CAAC,MAAc,EAAE,YAA8B;QAC5D,MAAM,KAAK,GAAG,uBAAuB,CAAC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QACrE,IAAI,KAAK,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC;QAE/B,OAAO,IAAI,+BAA+B,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IAClE,CAAC;IAEkB,qBAAqB,CACtC,KAAmC;QAEnC,OAAO,IAAI,wBAAwB,CACjC,KAAK,CAAC,IAAI,EACV,KAAK,CAAC,IAAI,CAAC,UAAU,EACrB,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,QAAQ,CACf,CAAC;IACJ,CAAC;IAEkB,gBAAgB,CACjC,KAAmC;QAEnC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;QAEjC,wEAAwE;QACxE,4EAA4E;QAC5E,0EAA0E;QAC1E,gEAAgE;QAChE,MAAM,uBAAuB,GAC3B,QAAQ,CAAC,IAAI,KAAK,aAAa;YAC/B,IAAI,CAAC,aAAa,CAAC,QAAQ,IAAI,IAAI;YACnC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC;YAC9D,CAAC,IAAI,CAAC,gBAAgB,CACpB,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,UAAU,EACtC,KAAK,CAAC,IAAI,CAAC,UAAU,CACtB,CAAC;QACJ,IAAI,uBAAuB;YAAE,OAAO,IAAI,CAAC;QAEzC,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,gBAAgB,CACtB,MAAc,EACd,UAA8B;QAE9B,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa,CAAC,mBAAmB,CACzD,MAAM,EACN,UAAU,CACX,CAAC;QACF,OAAO,YAAY,EAAE,WAAW,IAAI,KAAK,CAAC;IAC5C,CAAC;CACF"}
@@ -0,0 +1,16 @@
1
+ import type { GtfsRealtimeData } from "../data/gtfs-realtime-data.js";
2
+ import type { GtfsUpdatedTripServicingMovement } from "../data/gtfs-updated-trip-movements.js";
3
+ import type { GtfsUpdatedTrip } from "../data/gtfs-updated-trip.js";
4
+ import { DeparturesBlock } from "./departures-block.js";
5
+ export type RealtimeDeparturesBlockEntry = {
6
+ readonly trip: GtfsUpdatedTrip;
7
+ readonly instant: Temporal.Instant;
8
+ readonly movement: GtfsUpdatedTripServicingMovement;
9
+ };
10
+ export declare class RealtimeDeparturesBlock extends DeparturesBlock {
11
+ readonly entries: readonly RealtimeDeparturesBlockEntry[];
12
+ private constructor();
13
+ static tryBuild(stopId: number, realtimeData: GtfsRealtimeData): RealtimeDeparturesBlock | null;
14
+ getIterationIndexOfNextFrom(instant: Temporal.Instant): number;
15
+ getIterationIndexOfPreviousFrom(instant: Temporal.Instant): number;
16
+ }
@@ -0,0 +1,43 @@
1
+ import { itsOk } from "@dan-schel/js-utils";
2
+ import { DeparturesBlock } from "./departures-block.js";
3
+ export class RealtimeDeparturesBlock extends DeparturesBlock {
4
+ entries;
5
+ constructor(entries, earliestDepartureInstant, latestDepartureInstant) {
6
+ super(earliestDepartureInstant, latestDepartureInstant);
7
+ this.entries = entries;
8
+ }
9
+ static tryBuild(stopId,
10
+ // No point using an index for the realtime data, since it can change every
11
+ // 30 seconds, so you're unlikely to re-use it across queries.
12
+ realtimeData) {
13
+ const movements = [];
14
+ for (const trip of realtimeData.allTrips()) {
15
+ for (const movement of trip.movements) {
16
+ if (!movement.isServicing)
17
+ continue;
18
+ if (movement.stopId !== stopId)
19
+ continue;
20
+ movements.push({
21
+ trip,
22
+ instant: movement.timeRelevantToDeparturesAlgorithm,
23
+ movement,
24
+ });
25
+ }
26
+ }
27
+ if (movements.length === 0)
28
+ return null;
29
+ movements.sort((a, b) => Temporal.Instant.compare(a.instant, b.instant));
30
+ const earliestDepInstant = itsOk(movements[0]).instant;
31
+ const latestDepInstant = itsOk(movements[movements.length - 1]).instant;
32
+ return new RealtimeDeparturesBlock(movements, earliestDepInstant, latestDepInstant);
33
+ }
34
+ getIterationIndexOfNextFrom(instant) {
35
+ const result = this.entries.findIndex((m) => Temporal.Instant.compare(m.instant, instant) >= 0);
36
+ return result !== -1 ? result : this.entries.length;
37
+ }
38
+ getIterationIndexOfPreviousFrom(instant) {
39
+ // No need to handle -1, because we'd want to return -1 in that case anyway!
40
+ return this.entries.findLastIndex((m) => Temporal.Instant.compare(m.instant, instant) <= 0);
41
+ }
42
+ }
43
+ //# sourceMappingURL=realtime-departures-block.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime-departures-block.js","sourceRoot":"","sources":["../../src/departures/realtime-departures-block.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAI5C,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAQxD,MAAM,OAAO,uBAAwB,SAAQ,eAAe;IAE/C;IADX,YACW,OAAgD,EACzD,wBAA0C,EAC1C,sBAAwC;QAExC,KAAK,CAAC,wBAAwB,EAAE,sBAAsB,CAAC,CAAC;QAJ/C,YAAO,GAAP,OAAO,CAAyC;IAK3D,CAAC;IAED,MAAM,CAAC,QAAQ,CACb,MAAc;IAEd,2EAA2E;IAC3E,8DAA8D;IAC9D,YAA8B;QAE9B,MAAM,SAAS,GAAmC,EAAE,CAAC;QACrD,KAAK,MAAM,IAAI,IAAI,YAAY,CAAC,QAAQ,EAAE,EAAE,CAAC;YAC3C,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBACtC,IAAI,CAAC,QAAQ,CAAC,WAAW;oBAAE,SAAS;gBACpC,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM;oBAAE,SAAS;gBAEzC,SAAS,CAAC,IAAI,CAAC;oBACb,IAAI;oBACJ,OAAO,EAAE,QAAQ,CAAC,iCAAiC;oBACnD,QAAQ;iBACT,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAExC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;QAEzE,MAAM,kBAAkB,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QACvD,MAAM,gBAAgB,GAAG,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QAExE,OAAO,IAAI,uBAAuB,CAChC,SAAS,EACT,kBAAkB,EAClB,gBAAgB,CACjB,CAAC;IACJ,CAAC;IAEQ,2BAA2B,CAAC,OAAyB;QAC5D,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CACnC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CACzD,CAAC;QACF,OAAO,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;IACtD,CAAC;IAEQ,+BAA+B,CAAC,OAAyB;QAChE,4EAA4E;QAC5E,OAAO,IAAI,CAAC,OAAO,CAAC,aAAa,CAC/B,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CACzD,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,12 @@
1
+ import type { ScheduledDeparturesBlock } from "./scheduled-departures-block.js";
2
+ import { DeparturesIteratorResult } from "./departures-iterator.js";
3
+ import type { GtfsRealtimeData } from "../data/gtfs-realtime-data.js";
4
+ import { DeparturesBlockIterator } from "./departures-block-iterator.js";
5
+ import type { GtfsScheduledMovementsIndexEntry } from "./gtfs-scheduled-movements-index.js";
6
+ export declare class ScheduledDeparturesBlockIterator extends DeparturesBlockIterator<ScheduledDeparturesBlock, GtfsScheduledMovementsIndexEntry> {
7
+ private readonly _realtimeData;
8
+ constructor(block: ScheduledDeparturesBlock, _realtimeData: GtfsRealtimeData);
9
+ protected _convertEntryToResult(entry: GtfsScheduledMovementsIndexEntry): DeparturesIteratorResult;
10
+ protected _shouldSkipEntry(entry: GtfsScheduledMovementsIndexEntry): boolean;
11
+ private _isTripCancelled;
12
+ }
@@ -0,0 +1,55 @@
1
+ import { DeparturesIteratorResult } from "./departures-iterator.js";
2
+ import { DeparturesBlockIterator } from "./departures-block-iterator.js";
3
+ export class ScheduledDeparturesBlockIterator extends DeparturesBlockIterator {
4
+ _realtimeData;
5
+ constructor(block, _realtimeData) {
6
+ super(block, block.allMovementsAtStop);
7
+ this._realtimeData = _realtimeData;
8
+ }
9
+ _convertEntryToResult(entry) {
10
+ return new DeparturesIteratorResult(entry.trip, this.block.serviceDay, entry.time.toInstant(this.block.serviceDay, this.block.timezone), entry.movement);
11
+ }
12
+ _shouldSkipEntry(entry) {
13
+ // A scheduled departures block has all movements for a given stop, not just
14
+ // the ones that occur today!
15
+ const doesntRunToday = !entry.trip.calendar.occursOn(this.block.serviceDay);
16
+ if (doesntRunToday)
17
+ return true;
18
+ // Trips with realtime data will be supplied by the realtime departures
19
+ // block, so we don't want to show duplicate entries by also showing them
20
+ // from the scheduled departures block (at the outdated departure time/order
21
+ // too!).
22
+ const tripId = entry.trip.gtfsTripId;
23
+ const realtimeTrip = this._realtimeData.getForScheduledTrip(tripId, this.block.serviceDay);
24
+ const isOverriddenByRealtimeTrip = realtimeTrip != null;
25
+ if (isOverriddenByRealtimeTrip)
26
+ return true;
27
+ // Even users not filtering arrivals won't be interested to see the same
28
+ // trip listed twice at stations like Flinders Street or Town Hall, once for
29
+ // the arrival and then again for the departure of the continuing trip. We
30
+ // just need to be sure the continuing trip is actually running!
31
+ //
32
+ // TODO: Realtime trips which connect to other trips must cause those
33
+ // scheduled trips to become realtime trips too, and realtime trips need to
34
+ // have their own `nextTrip` and `prevTrip` properties, otherwise fetching
35
+ // `nextTrip` here can lead to outdated info (the next trip might have been
36
+ // altered and no longer connects with this one). Alternatively, having
37
+ // `nextTrip` and `prevTrip` was a mistake, and we just only have trip IDs
38
+ // in their place, or maybe an entirely separate list of transfers which
39
+ // lives outside the trip (and supports other future transfer types).
40
+ //
41
+ // TODO: Wherever this logic ends up living, make sure it's tested.
42
+ const isArrivalWhichContinues = entry.movement.type === "terminating" &&
43
+ entry.trip.nextTrip != null &&
44
+ entry.trip.nextTrip.calendar.occursOn(this.block.serviceDay) &&
45
+ !this._isTripCancelled(entry.trip.nextTrip.gtfsTripId);
46
+ if (isArrivalWhichContinues)
47
+ return true;
48
+ return false;
49
+ }
50
+ _isTripCancelled(tripId) {
51
+ const realtimeTrip = this._realtimeData.getForScheduledTrip(tripId, this.block.serviceDay);
52
+ return realtimeTrip?.isCancelled ?? false;
53
+ }
54
+ }
55
+ //# sourceMappingURL=scheduled-departures-block-iterator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduled-departures-block-iterator.js","sourceRoot":"","sources":["../../src/departures/scheduled-departures-block-iterator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAGzE,MAAM,OAAO,gCAAiC,SAAQ,uBAGrD;IAGoB;IAFnB,YACE,KAA+B,EACd,aAA+B;QAEhD,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAFtB,kBAAa,GAAb,aAAa,CAAkB;IAGlD,CAAC;IAEkB,qBAAqB,CACtC,KAAuC;QAEvC,OAAO,IAAI,wBAAwB,CACjC,KAAK,CAAC,IAAI,EACV,IAAI,CAAC,KAAK,CAAC,UAAU,EACrB,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,EAChE,KAAK,CAAC,QAAQ,CACf,CAAC;IACJ,CAAC;IAEkB,gBAAgB,CACjC,KAAuC;QAEvC,4EAA4E;QAC5E,6BAA6B;QAC7B,MAAM,cAAc,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC5E,IAAI,cAAc;YAAE,OAAO,IAAI,CAAC;QAEhC,uEAAuE;QACvE,yEAAyE;QACzE,4EAA4E;QAC5E,SAAS;QACT,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC;QACrC,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa,CAAC,mBAAmB,CACzD,MAAM,EACN,IAAI,CAAC,KAAK,CAAC,UAAU,CACtB,CAAC;QACF,MAAM,0BAA0B,GAAG,YAAY,IAAI,IAAI,CAAC;QACxD,IAAI,0BAA0B;YAAE,OAAO,IAAI,CAAC;QAE5C,wEAAwE;QACxE,4EAA4E;QAC5E,0EAA0E;QAC1E,gEAAgE;QAChE,EAAE;QACF,qEAAqE;QACrE,2EAA2E;QAC3E,0EAA0E;QAC1E,2EAA2E;QAC3E,uEAAuE;QACvE,0EAA0E;QAC1E,wEAAwE;QACxE,qEAAqE;QACrE,EAAE;QACF,mEAAmE;QACnE,MAAM,uBAAuB,GAC3B,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,aAAa;YACrC,KAAK,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI;YAC3B,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC;YAC5D,CAAC,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QACzD,IAAI,uBAAuB;YAAE,OAAO,IAAI,CAAC;QAEzC,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,gBAAgB,CAAC,MAAc;QACrC,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa,CAAC,mBAAmB,CACzD,MAAM,EACN,IAAI,CAAC,KAAK,CAAC,UAAU,CACtB,CAAC;QACF,OAAO,YAAY,EAAE,WAAW,IAAI,KAAK,CAAC;IAC5C,CAAC;CACF"}
@@ -0,0 +1,18 @@
1
+ import { DeparturesBlock } from "./departures-block.js";
2
+ import { GtfsStopTime } from "../data/gtfs-stop-time.js";
3
+ import type { GtfsScheduledMovementsIndexEntry } from "./gtfs-scheduled-movements-index.js";
4
+ export declare class ScheduledDeparturesBlock extends DeparturesBlock {
5
+ readonly allMovementsAtStop: readonly GtfsScheduledMovementsIndexEntry[];
6
+ readonly serviceDay: Temporal.PlainDate;
7
+ readonly timezone: string;
8
+ constructor(allMovementsAtStop: readonly GtfsScheduledMovementsIndexEntry[], serviceDay: Temporal.PlainDate, earliestDepartureInstant: Temporal.Instant, latestDepartureInstant: Temporal.Instant, timezone: string);
9
+ static build(movements: readonly GtfsScheduledMovementsIndexEntry[], serviceDay: Temporal.PlainDate, timezone: string): ScheduledDeparturesBlock;
10
+ /**
11
+ * Returns the GtfsStopTime for the given instant, relative to the service day
12
+ * (and for the timezone) of this block.
13
+ */
14
+ toGtfsStopTime(time: Temporal.Instant): GtfsStopTime;
15
+ getIterationIndexOfNextFrom(instant: Temporal.Instant): number;
16
+ getIterationIndexOfPreviousFrom(instant: Temporal.Instant): number;
17
+ isSameServiceDay(other: ScheduledDeparturesBlock): boolean;
18
+ }
@@ -0,0 +1,54 @@
1
+ import { itsOk } from "@dan-schel/js-utils";
2
+ import { DeparturesBlock } from "./departures-block.js";
3
+ import { GtfsStopTime } from "../data/gtfs-stop-time.js";
4
+ export class ScheduledDeparturesBlock extends DeparturesBlock {
5
+ allMovementsAtStop;
6
+ serviceDay;
7
+ timezone;
8
+ constructor(
9
+ // Note that we pass ALL movements for this stop into the block, not just
10
+ // ones which occur on this service day. That filtering is done at the
11
+ // `ScheduledDeparturesBlockIterator` level instead (by skipping over
12
+ // values when we reach them in the iteration), and that way we avoid
13
+ // doing a bunch of computation upfront for each movement at the stop here
14
+ // (for the whole day), which might be useless if we're at a big stop like
15
+ // Southern Cross with thousands of movements and we end up only iterating
16
+ // through of them.
17
+ allMovementsAtStop, serviceDay, earliestDepartureInstant, latestDepartureInstant, timezone) {
18
+ super(earliestDepartureInstant, latestDepartureInstant);
19
+ this.allMovementsAtStop = allMovementsAtStop;
20
+ this.serviceDay = serviceDay;
21
+ this.timezone = timezone;
22
+ }
23
+ static build(movements, serviceDay, timezone) {
24
+ if (movements.length === 0)
25
+ throw new Error("Movements cannot be empty");
26
+ const firstEntry = itsOk(movements[0]);
27
+ const lastEntry = itsOk(movements[movements.length - 1]);
28
+ return new ScheduledDeparturesBlock(movements, serviceDay, firstEntry.time.toInstant(serviceDay, timezone), lastEntry.time.toInstant(serviceDay, timezone), timezone);
29
+ }
30
+ /**
31
+ * Returns the GtfsStopTime for the given instant, relative to the service day
32
+ * (and for the timezone) of this block.
33
+ */
34
+ toGtfsStopTime(time) {
35
+ const midnight = GtfsStopTime.fromSecondsSinceMidnight(0);
36
+ const midnightInstant = midnight.toInstant(this.serviceDay, this.timezone);
37
+ const secondsSinceMidnight = time.since(midnightInstant).total("seconds");
38
+ return GtfsStopTime.fromSecondsSinceMidnight(secondsSinceMidnight);
39
+ }
40
+ getIterationIndexOfNextFrom(instant) {
41
+ const time = this.toGtfsStopTime(instant);
42
+ const result = this.allMovementsAtStop.findIndex((m) => m.time.isAfterOrEqual(time));
43
+ return result !== -1 ? result : this.allMovementsAtStop.length;
44
+ }
45
+ getIterationIndexOfPreviousFrom(instant) {
46
+ const time = this.toGtfsStopTime(instant);
47
+ // No need to handle -1, because we'd want to return -1 in that case anyway!
48
+ return this.allMovementsAtStop.findLastIndex((m) => m.time.isBeforeOrEqual(time));
49
+ }
50
+ isSameServiceDay(other) {
51
+ return Temporal.PlainDate.compare(this.serviceDay, other.serviceDay) === 0;
52
+ }
53
+ }
54
+ //# sourceMappingURL=scheduled-departures-block.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduled-departures-block.js","sourceRoot":"","sources":["../../src/departures/scheduled-departures-block.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAGzD,MAAM,OAAO,wBAAyB,SAAQ,eAAe;IAUhD;IAEA;IAGA;IAdX;IACE,yEAAyE;IACzE,sEAAsE;IACtE,qEAAqE;IACrE,qEAAqE;IACrE,0EAA0E;IAC1E,0EAA0E;IAC1E,0EAA0E;IAC1E,mBAAmB;IACV,kBAA+D,EAE/D,UAA8B,EACvC,wBAA0C,EAC1C,sBAAwC,EAC/B,QAAgB;QAEzB,KAAK,CAAC,wBAAwB,EAAE,sBAAsB,CAAC,CAAC;QAP/C,uBAAkB,GAAlB,kBAAkB,CAA6C;QAE/D,eAAU,GAAV,UAAU,CAAoB;QAG9B,aAAQ,GAAR,QAAQ,CAAQ;IAG3B,CAAC;IAED,MAAM,CAAC,KAAK,CACV,SAAsD,EACtD,UAA8B,EAC9B,QAAgB;QAEhB,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAEzE,MAAM,UAAU,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;QACvC,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QAEzD,OAAO,IAAI,wBAAwB,CACjC,SAAS,EACT,UAAU,EACV,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,QAAQ,CAAC,EAC/C,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,QAAQ,CAAC,EAC9C,QAAQ,CACT,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,cAAc,CAAC,IAAsB;QACnC,MAAM,QAAQ,GAAG,YAAY,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC;QAC1D,MAAM,eAAe,GAAG,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC3E,MAAM,oBAAoB,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC1E,OAAO,YAAY,CAAC,wBAAwB,CAAC,oBAAoB,CAAC,CAAC;IACrE,CAAC;IAEQ,2BAA2B,CAAC,OAAyB;QAC5D,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QAE1C,MAAM,MAAM,GAAG,IAAI,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CACrD,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAC5B,CAAC;QAEF,OAAO,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC;IACjE,CAAC;IAEQ,+BAA+B,CAAC,OAAyB;QAChE,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;QAE1C,4EAA4E;QAC5E,OAAO,IAAI,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CACjD,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAC7B,CAAC;IACJ,CAAC;IAED,gBAAgB,CAAC,KAA+B;QAC9C,OAAO,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAC7E,CAAC;CACF"}
@@ -0,0 +1,20 @@
1
+ import type { BoundedInstantRange } from "../data/bounded-instant-range.js";
2
+ import type { GtfsScheduledMovementsIndex, GtfsScheduledMovementsIndexEntry } from "./gtfs-scheduled-movements-index.js";
3
+ import { ScheduledDeparturesBlock } from "./scheduled-departures-block.js";
4
+ import type { PlainDateRange } from "../data/plain-date-range.js";
5
+ import type { TimezoneData } from "../config/timezone-data.js";
6
+ export declare class ScheduledDeparturesBlocksBuilder {
7
+ private readonly _movements;
8
+ private readonly _timezoneData;
9
+ private readonly _rangeEncompassingAllCalendars;
10
+ /** If given, all movements are guaranteed to occur at/after this time. */
11
+ readonly earliestPossibleMovementInstant: Temporal.Instant | null;
12
+ /** If given, all movements are guaranteed to occur at/before this time. */
13
+ readonly latestPossibleMovementInstant: Temporal.Instant | null;
14
+ constructor(_movements: readonly GtfsScheduledMovementsIndexEntry[], _timezoneData: TimezoneData, _rangeEncompassingAllCalendars: PlainDateRange);
15
+ static tryBuild(stopId: number, scheduledMovementsIndex: GtfsScheduledMovementsIndex, timezoneData: TimezoneData): ScheduledDeparturesBlocksBuilder | null;
16
+ hasMoreBefore(instant: Temporal.Instant): boolean;
17
+ hasMoreAfter(instant: Temporal.Instant): boolean;
18
+ allWithinTimeRange(range: BoundedInstantRange): ScheduledDeparturesBlock[];
19
+ private _splitDateAndSecondOfDayUtc;
20
+ }
@@ -0,0 +1,222 @@
1
+ import { itsOk } from "@dan-schel/js-utils";
2
+ import { ScheduledDeparturesBlock } from "./scheduled-departures-block.js";
3
+ export class ScheduledDeparturesBlocksBuilder {
4
+ _movements;
5
+ _timezoneData;
6
+ _rangeEncompassingAllCalendars;
7
+ /** If given, all movements are guaranteed to occur at/after this time. */
8
+ earliestPossibleMovementInstant;
9
+ /** If given, all movements are guaranteed to occur at/before this time. */
10
+ latestPossibleMovementInstant;
11
+ constructor(_movements, _timezoneData, _rangeEncompassingAllCalendars) {
12
+ this._movements = _movements;
13
+ this._timezoneData = _timezoneData;
14
+ this._rangeEncompassingAllCalendars = _rangeEncompassingAllCalendars;
15
+ if (_movements.length === 0)
16
+ throw new Error("No movements given.");
17
+ if (_rangeEncompassingAllCalendars.start != null) {
18
+ const firstMovement = itsOk(_movements[0]);
19
+ this.earliestPossibleMovementInstant = firstMovement.time.toInstant(_rangeEncompassingAllCalendars.start, _timezoneData.timezone);
20
+ }
21
+ else {
22
+ this.earliestPossibleMovementInstant = null;
23
+ }
24
+ if (_rangeEncompassingAllCalendars.end != null) {
25
+ const lastMovement = itsOk(_movements.at(-1));
26
+ this.latestPossibleMovementInstant = lastMovement.time.toInstant(_rangeEncompassingAllCalendars.end, _timezoneData.timezone);
27
+ }
28
+ else {
29
+ this.latestPossibleMovementInstant = null;
30
+ }
31
+ }
32
+ static tryBuild(stopId, scheduledMovementsIndex, timezoneData) {
33
+ const movements = scheduledMovementsIndex.getMovementsForStop(stopId);
34
+ const rangeEncompassingAllCalendars = scheduledMovementsIndex.getRangeEncompassingAllCalendarsForStop(stopId);
35
+ if (movements.length === 0 || rangeEncompassingAllCalendars == null) {
36
+ return null;
37
+ }
38
+ return new ScheduledDeparturesBlocksBuilder(movements, timezoneData, rangeEncompassingAllCalendars);
39
+ }
40
+ hasMoreBefore(instant) {
41
+ const earliest = this.earliestPossibleMovementInstant;
42
+ if (earliest == null)
43
+ return true;
44
+ return Temporal.Instant.compare(earliest, instant) < 0;
45
+ }
46
+ hasMoreAfter(instant) {
47
+ const latest = this.latestPossibleMovementInstant;
48
+ if (latest == null)
49
+ return true;
50
+ return Temporal.Instant.compare(latest, instant) > 0;
51
+ }
52
+ allWithinTimeRange(range) {
53
+ /* -------------------------------------------------------------------------
54
+
55
+ Ok. Let's work this out!
56
+
57
+ Suppose we're querying:
58
+
59
+ Start => 12:00am Aug 2 AEST (14:00 Aug 1 UTC)
60
+ End => 12:00am Aug 3 AEST (14:00 Aug 2 UTC)
61
+
62
+ We know our query starts at 14:00 UTC Aug 1. That means it's likely
63
+ the first service day we'll need to check is Aug 1, or possibly one day
64
+ before/after depending on the timezone conversions and earliest/latest
65
+ movement times, and likewise for the last service day. What we need to
66
+ figure out is how many days to add/subtract from each to make sure we've
67
+ definitely found all the scheduled blocks which overlap our query range.
68
+
69
+ For this station, the first movement of the day is 5:18am, and last is
70
+ 2:08am the next day. That means:
71
+
72
+ Local time zone => [05:18 +0d] to [02:08 +1d]
73
+ UTC, during AEST => [19:18 -1d] to [16:08 +0d] (-10hrs from local)
74
+ UTC, during AEDT => [18:18 -1d] to [15:08 +0d] (-11hrs from local)
75
+
76
+ This means for a given service day, the movements occur always occur between
77
+ [18:18 -1d] and [16:08 +0d] in UTC, regardless of whether its AEST or AEDT.
78
+ (For our first pass, we're not gonna check if a certain service day is AEST
79
+ or AEDT.)
80
+
81
+ Those day offsets mean for the service day of say, May 4, the first movement
82
+ could be at 18:18 UTC on May 3 at the earliest (which would translate to
83
+ 5:18am AEDT on May 4, though May 4 uses AEST so this is actually being
84
+ conservative).
85
+
86
+ We're gonna represent our times as seconds since [00:00 +0d]. It can be a
87
+ negative value if the time is earlier than [00:00 +0d].
88
+
89
+ ------------------------------------------------------------------------- */
90
+ const maxViableOffsetSecs = this._timezoneData.maximumViableOffsetSeconds;
91
+ const minViableOffsetSecs = this._timezoneData.minimumViableOffsetSeconds;
92
+ const firstMvmt = itsOk(this._movements[0]);
93
+ const lastMvmt = itsOk(this._movements.at(-1));
94
+ const firstMvmtSecondsSinceMidnight = firstMvmt.time.secondsSinceMidnight;
95
+ const lastMvmtSecondsSinceMidnight = lastMvmt.time.secondsSinceMidnight;
96
+ // -20520 (represents [18:18 -1d] in seconds since [00:00 +0d])
97
+ const e = firstMvmtSecondsSinceMidnight - maxViableOffsetSecs;
98
+ // 58080 (represents [16:08 +0d] in seconds since [00:00 +0d])
99
+ const l = lastMvmtSecondsSinceMidnight - minViableOffsetSecs;
100
+ /* -------------------------------------------------------------------------
101
+
102
+ The first service day which is relevant to our query will be the first one
103
+ which ENDS AFTER the start of our query range.
104
+
105
+ Our query range starts from Aug 1 in UTC terms, at 14:00 UTC. This is
106
+ earlier than [16:08 +0d], so the service day for Aug 1 DOES fall within our
107
+ query by just over 2 hours, or 0.089 days.
108
+
109
+ That number of days value actually tells us how many days to shift by. Let's
110
+ say instead that the last movement was [16:08 +1d]. That would mean the last
111
+ movement for Aug 1 would be at 16:08 UTC on Aug 2, or 1.089 days after the
112
+ beginning of our query. Because it's a full day after our query begins, we
113
+ therefore must know that the PREVIOUS service day's movements (Jul 31) must
114
+ end 0.089 days after our query begins (because we're accounting for the full
115
+ range of offsets possible for a service day already in our calculations
116
+ above, we can confidently say 0.089, not worrying about different days
117
+ having different offsets, we account for that at the very end), so the
118
+ earliest service day we'd need to check is Jul 31 (we shift back one day).
119
+
120
+ Likewise if the last movement was just a few hours earlier at [13:08 +0d],
121
+ because that's before 14:00 UTC (a.k.a. -0.036 days after), we know that all
122
+ of Aug 1's movements have occured from this stop before our query start
123
+ time, so we can shift forward one day. We only shift by one day because the
124
+ last service is still within 24 hours of our query start time.
125
+
126
+ In summary:
127
+ - If the service day ends 0.089 days after the query, shift by 0 days.
128
+ - If the service day ends 1.089 days after the query, shift by -1 days.
129
+ - If the service day ends -0.036 days after the query, shift by +1 days.
130
+
131
+ i.e. We're shifting by `-floor(numOfDays)`.
132
+
133
+ (Floor always moves values toward negative infinity, i.e. -0.05 -> -1)
134
+
135
+ ------------------------------------------------------------------------- */
136
+ const startSplit = this._splitDateAndSecondOfDayUtc(range.start);
137
+ const startDate = startSplit.date; // Aug 1
138
+ const startSecondOfDayUtc = startSplit.secondOfDayUtc; // 50400 (14:00 UTC)
139
+ const daysAfterStart = (l - startSecondOfDayUtc) / (24 * 60 * 60); // 0.089
140
+ const daysToShiftStart = -Math.floor(daysAfterStart); // 0
141
+ const firstServiceDay = startDate.add({ days: daysToShiftStart }); // Aug 1
142
+ /* -------------------------------------------------------------------------
143
+
144
+ And now we do the same to find the last service day in range, by looking for
145
+ the last service day which STARTS BEFORE the end of our query range.
146
+
147
+ Our query range ends at 14:00 UTC on Aug 2. The first movement of the day is
148
+ [18:18 -1d], so 18:18 Aug 1, which is just under 20 hours before our query
149
+ end time, or 0.821 days.
150
+
151
+ That means the last service day in range is Aug 2, because while Aug 2
152
+ starts before our query ends, it doesn't start OVER 24 HOURS before our
153
+ query ends, and therefore Aug 3 must start AFTER our query ends and is
154
+ therefore irrelevant.
155
+
156
+ If the first movement of the day was [18:18 -2d], so 18:18 Jul 31, which is
157
+ 1.821 days before 14:00 Aug 2, then at 14:00 Aug 2 we'd have started to
158
+ enter the service day of Aug 3, because it must've began at 18:18 Aug 1.
159
+
160
+ And if the first movement of the day was [18:18 +0d], so 18:18 Aug 2, which
161
+ is a few hours after 14:00 Aug 2 (a.k.a. -0.036 days before), then Aug 2's
162
+ movements don't start until after the query end time, so we only need to go
163
+ up until Aug 1.
164
+
165
+ This means:
166
+ - If the service days starts 0.821 days before the query, shift by 0 days.
167
+ - If the service days starts 1.821 days before the query, shift by +1 days.
168
+ - If the service days starts -0.036 days before the query, shift by -1 days.
169
+
170
+ i.e. We're shifting by `floor(numOfDays)`.
171
+
172
+ ------------------------------------------------------------------------- */
173
+ const endSplit = this._splitDateAndSecondOfDayUtc(range.end);
174
+ const endDate = endSplit.date; // Aug 2
175
+ const endSecondOfDayUtc = endSplit.secondOfDayUtc; // 50400 (14:00 UTC)
176
+ const daysBeforeEnd = (endSecondOfDayUtc - e) / (24 * 60 * 60); // 0.821
177
+ const daysToShiftEnd = Math.floor(daysBeforeEnd); // 0
178
+ const lastServiceDay = endDate.add({ days: daysToShiftEnd }); // Aug 2
179
+ /* -------------------------------------------------------------------------
180
+
181
+ Now that we have our date range, we just need to construct the blocks.
182
+
183
+ When the blocks are constructed, they will determine the Temporal.Instant of
184
+ the first and last movement in the block using the ACTUAL offset for that
185
+ service day (the offset at 12pm noon as per the GTFS spec).
186
+
187
+ So far, we've been calculating everything assuming the worst case scenario
188
+ of minimum/maximum offsets, so there's a possibility now that when we
189
+ construct the block we were being conservative and the block doesn't
190
+ actually intersect our query range, hence the check before adding it to the
191
+ final result.
192
+
193
+ (Because not every trip runs every day, and realtime trips are filtered out
194
+ of the scheduled blocks for the relevant day, this can be another
195
+ contributing factor to a block's time range being narrower once constructed
196
+ than what this algorithm assumes.)
197
+
198
+ ------------------------------------------------------------------------- */
199
+ const blocks = [];
200
+ for (let date = firstServiceDay; Temporal.PlainDate.compare(date, lastServiceDay) <= 0; date = date.add({ days: 1 })) {
201
+ if (!this._rangeEncompassingAllCalendars.includes(date))
202
+ continue;
203
+ const tz = this._timezoneData.timezone;
204
+ const block = ScheduledDeparturesBlock.build(this._movements, date, tz);
205
+ // Use `touches`, not `intersects`, so that the first and last movements
206
+ // of a block are included if the query range starts or ends exactly at
207
+ // the same time as them.
208
+ if (block.instantRange.touches(range)) {
209
+ blocks.push(block);
210
+ }
211
+ }
212
+ return blocks;
213
+ }
214
+ _splitDateAndSecondOfDayUtc(instant) {
215
+ const startOfDayUtc = instant.toZonedDateTimeISO("UTC").startOfDay();
216
+ return {
217
+ date: startOfDayUtc.toPlainDate(),
218
+ secondOfDayUtc: instant.since(startOfDayUtc.toInstant()).total("seconds"),
219
+ };
220
+ }
221
+ }
222
+ //# sourceMappingURL=scheduled-departures-blocks-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduled-departures-blocks-builder.js","sourceRoot":"","sources":["../../src/departures/scheduled-departures-blocks-builder.ts"],"names":[],"mappings":"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"}