minotor 1.0.7 → 2.0.0
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.
- package/CHANGELOG.md +9 -3
- package/README.md +3 -2
- package/dist/cli.mjs +604 -531
- package/dist/cli.mjs.map +1 -1
- package/dist/gtfs/stops.d.ts +19 -5
- package/dist/gtfs/transfers.d.ts +5 -4
- package/dist/gtfs/trips.d.ts +7 -5
- package/dist/gtfs/utils.d.ts +7 -8
- package/dist/parser.cjs.js +569 -501
- package/dist/parser.cjs.js.map +1 -1
- package/dist/parser.esm.js +569 -501
- package/dist/parser.esm.js.map +1 -1
- package/dist/router.cjs.js +1 -1
- package/dist/router.cjs.js.map +1 -1
- package/dist/router.d.ts +3 -3
- package/dist/router.esm.js +1 -1
- package/dist/router.esm.js.map +1 -1
- package/dist/router.umd.js +1 -1
- package/dist/router.umd.js.map +1 -1
- package/dist/routing/__tests__/route.test.d.ts +1 -0
- package/dist/routing/query.d.ts +7 -7
- package/dist/routing/result.d.ts +3 -3
- package/dist/routing/route.d.ts +1 -0
- package/dist/stops/proto/stops.d.ts +5 -4
- package/dist/stops/stops.d.ts +10 -1
- package/dist/stops/stopsIndex.d.ts +21 -4
- package/dist/timetable/proto/timetable.d.ts +21 -18
- package/dist/timetable/timetable.d.ts +38 -14
- package/package.json +4 -3
- package/src/cli/repl.ts +13 -10
- package/src/gtfs/__tests__/parser.test.ts +50 -579
- package/src/gtfs/__tests__/stops.test.ts +181 -112
- package/src/gtfs/__tests__/transfers.test.ts +170 -12
- package/src/gtfs/__tests__/trips.test.ts +212 -141
- package/src/gtfs/__tests__/utils.test.ts +4 -4
- package/src/gtfs/parser.ts +22 -13
- package/src/gtfs/stops.ts +63 -28
- package/src/gtfs/transfers.ts +14 -6
- package/src/gtfs/trips.ts +110 -47
- package/src/gtfs/utils.ts +11 -11
- package/src/router.ts +2 -4
- package/src/routing/__tests__/route.test.ts +112 -0
- package/src/routing/__tests__/router.test.ts +234 -244
- package/src/routing/query.ts +7 -7
- package/src/routing/result.ts +9 -6
- package/src/routing/route.ts +11 -0
- package/src/routing/router.ts +26 -24
- package/src/stops/__tests__/io.test.ts +9 -8
- package/src/stops/__tests__/stopFinder.test.ts +45 -36
- package/src/stops/io.ts +8 -5
- package/src/stops/proto/stops.proto +8 -7
- package/src/stops/proto/stops.ts +68 -38
- package/src/stops/stops.ts +13 -1
- package/src/stops/stopsIndex.ts +50 -7
- package/src/timetable/__tests__/io.test.ts +40 -49
- package/src/timetable/__tests__/timetable.test.ts +50 -58
- package/src/timetable/io.ts +69 -56
- package/src/timetable/proto/timetable.proto +22 -17
- package/src/timetable/proto/timetable.ts +94 -184
- package/src/timetable/timetable.ts +62 -29
package/src/stops/proto/stops.ts
CHANGED
|
@@ -62,27 +62,29 @@ export function locationTypeToJSON(object: LocationType): string {
|
|
|
62
62
|
|
|
63
63
|
export interface Stop {
|
|
64
64
|
name: string;
|
|
65
|
+
sourceStopId: string;
|
|
65
66
|
lat?: number | undefined;
|
|
66
67
|
lon?: number | undefined;
|
|
67
|
-
children:
|
|
68
|
-
parent?:
|
|
68
|
+
children: number[];
|
|
69
|
+
parent?: number | undefined;
|
|
69
70
|
locationType: LocationType;
|
|
70
71
|
platform?: string | undefined;
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
export interface StopsMap {
|
|
74
75
|
version: string;
|
|
75
|
-
stops: { [key:
|
|
76
|
+
stops: { [key: number]: Stop };
|
|
76
77
|
}
|
|
77
78
|
|
|
78
79
|
export interface StopsMap_StopsEntry {
|
|
79
|
-
key:
|
|
80
|
+
key: number;
|
|
80
81
|
value: Stop | undefined;
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
function createBaseStop(): Stop {
|
|
84
85
|
return {
|
|
85
86
|
name: "",
|
|
87
|
+
sourceStopId: "",
|
|
86
88
|
lat: undefined,
|
|
87
89
|
lon: undefined,
|
|
88
90
|
children: [],
|
|
@@ -97,23 +99,28 @@ export const Stop: MessageFns<Stop> = {
|
|
|
97
99
|
if (message.name !== "") {
|
|
98
100
|
writer.uint32(10).string(message.name);
|
|
99
101
|
}
|
|
102
|
+
if (message.sourceStopId !== "") {
|
|
103
|
+
writer.uint32(18).string(message.sourceStopId);
|
|
104
|
+
}
|
|
100
105
|
if (message.lat !== undefined) {
|
|
101
|
-
writer.uint32(
|
|
106
|
+
writer.uint32(25).double(message.lat);
|
|
102
107
|
}
|
|
103
108
|
if (message.lon !== undefined) {
|
|
104
|
-
writer.uint32(
|
|
109
|
+
writer.uint32(33).double(message.lon);
|
|
105
110
|
}
|
|
111
|
+
writer.uint32(42).fork();
|
|
106
112
|
for (const v of message.children) {
|
|
107
|
-
writer.uint32(
|
|
113
|
+
writer.uint32(v);
|
|
108
114
|
}
|
|
115
|
+
writer.join();
|
|
109
116
|
if (message.parent !== undefined) {
|
|
110
|
-
writer.uint32(
|
|
117
|
+
writer.uint32(48).uint32(message.parent);
|
|
111
118
|
}
|
|
112
119
|
if (message.locationType !== 0) {
|
|
113
|
-
writer.uint32(
|
|
120
|
+
writer.uint32(56).int32(message.locationType);
|
|
114
121
|
}
|
|
115
122
|
if (message.platform !== undefined) {
|
|
116
|
-
writer.uint32(
|
|
123
|
+
writer.uint32(66).string(message.platform);
|
|
117
124
|
}
|
|
118
125
|
return writer;
|
|
119
126
|
},
|
|
@@ -134,11 +141,11 @@ export const Stop: MessageFns<Stop> = {
|
|
|
134
141
|
continue;
|
|
135
142
|
}
|
|
136
143
|
case 2: {
|
|
137
|
-
if (tag !==
|
|
144
|
+
if (tag !== 18) {
|
|
138
145
|
break;
|
|
139
146
|
}
|
|
140
147
|
|
|
141
|
-
message.
|
|
148
|
+
message.sourceStopId = reader.string();
|
|
142
149
|
continue;
|
|
143
150
|
}
|
|
144
151
|
case 3: {
|
|
@@ -146,35 +153,53 @@ export const Stop: MessageFns<Stop> = {
|
|
|
146
153
|
break;
|
|
147
154
|
}
|
|
148
155
|
|
|
149
|
-
message.
|
|
156
|
+
message.lat = reader.double();
|
|
150
157
|
continue;
|
|
151
158
|
}
|
|
152
159
|
case 4: {
|
|
153
|
-
if (tag !==
|
|
160
|
+
if (tag !== 33) {
|
|
154
161
|
break;
|
|
155
162
|
}
|
|
156
163
|
|
|
157
|
-
message.
|
|
164
|
+
message.lon = reader.double();
|
|
158
165
|
continue;
|
|
159
166
|
}
|
|
160
167
|
case 5: {
|
|
161
|
-
if (tag
|
|
162
|
-
|
|
168
|
+
if (tag === 40) {
|
|
169
|
+
message.children.push(reader.uint32());
|
|
170
|
+
|
|
171
|
+
continue;
|
|
163
172
|
}
|
|
164
173
|
|
|
165
|
-
|
|
166
|
-
|
|
174
|
+
if (tag === 42) {
|
|
175
|
+
const end2 = reader.uint32() + reader.pos;
|
|
176
|
+
while (reader.pos < end2) {
|
|
177
|
+
message.children.push(reader.uint32());
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
break;
|
|
167
184
|
}
|
|
168
185
|
case 6: {
|
|
169
186
|
if (tag !== 48) {
|
|
170
187
|
break;
|
|
171
188
|
}
|
|
172
189
|
|
|
173
|
-
message.
|
|
190
|
+
message.parent = reader.uint32();
|
|
174
191
|
continue;
|
|
175
192
|
}
|
|
176
193
|
case 7: {
|
|
177
|
-
if (tag !==
|
|
194
|
+
if (tag !== 56) {
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
message.locationType = reader.int32() as any;
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
case 8: {
|
|
202
|
+
if (tag !== 66) {
|
|
178
203
|
break;
|
|
179
204
|
}
|
|
180
205
|
|
|
@@ -193,10 +218,11 @@ export const Stop: MessageFns<Stop> = {
|
|
|
193
218
|
fromJSON(object: any): Stop {
|
|
194
219
|
return {
|
|
195
220
|
name: isSet(object.name) ? globalThis.String(object.name) : "",
|
|
221
|
+
sourceStopId: isSet(object.sourceStopId) ? globalThis.String(object.sourceStopId) : "",
|
|
196
222
|
lat: isSet(object.lat) ? globalThis.Number(object.lat) : undefined,
|
|
197
223
|
lon: isSet(object.lon) ? globalThis.Number(object.lon) : undefined,
|
|
198
|
-
children: globalThis.Array.isArray(object?.children) ? object.children.map((e: any) => globalThis.
|
|
199
|
-
parent: isSet(object.parent) ? globalThis.
|
|
224
|
+
children: globalThis.Array.isArray(object?.children) ? object.children.map((e: any) => globalThis.Number(e)) : [],
|
|
225
|
+
parent: isSet(object.parent) ? globalThis.Number(object.parent) : undefined,
|
|
200
226
|
locationType: isSet(object.locationType) ? locationTypeFromJSON(object.locationType) : 0,
|
|
201
227
|
platform: isSet(object.platform) ? globalThis.String(object.platform) : undefined,
|
|
202
228
|
};
|
|
@@ -207,6 +233,9 @@ export const Stop: MessageFns<Stop> = {
|
|
|
207
233
|
if (message.name !== "") {
|
|
208
234
|
obj.name = message.name;
|
|
209
235
|
}
|
|
236
|
+
if (message.sourceStopId !== "") {
|
|
237
|
+
obj.sourceStopId = message.sourceStopId;
|
|
238
|
+
}
|
|
210
239
|
if (message.lat !== undefined) {
|
|
211
240
|
obj.lat = message.lat;
|
|
212
241
|
}
|
|
@@ -214,10 +243,10 @@ export const Stop: MessageFns<Stop> = {
|
|
|
214
243
|
obj.lon = message.lon;
|
|
215
244
|
}
|
|
216
245
|
if (message.children?.length) {
|
|
217
|
-
obj.children = message.children;
|
|
246
|
+
obj.children = message.children.map((e) => Math.round(e));
|
|
218
247
|
}
|
|
219
248
|
if (message.parent !== undefined) {
|
|
220
|
-
obj.parent = message.parent;
|
|
249
|
+
obj.parent = Math.round(message.parent);
|
|
221
250
|
}
|
|
222
251
|
if (message.locationType !== 0) {
|
|
223
252
|
obj.locationType = locationTypeToJSON(message.locationType);
|
|
@@ -234,6 +263,7 @@ export const Stop: MessageFns<Stop> = {
|
|
|
234
263
|
fromPartial<I extends Exact<DeepPartial<Stop>, I>>(object: I): Stop {
|
|
235
264
|
const message = createBaseStop();
|
|
236
265
|
message.name = object.name ?? "";
|
|
266
|
+
message.sourceStopId = object.sourceStopId ?? "";
|
|
237
267
|
message.lat = object.lat ?? undefined;
|
|
238
268
|
message.lon = object.lon ?? undefined;
|
|
239
269
|
message.children = object.children?.map((e) => e) || [];
|
|
@@ -298,8 +328,8 @@ export const StopsMap: MessageFns<StopsMap> = {
|
|
|
298
328
|
return {
|
|
299
329
|
version: isSet(object.version) ? globalThis.String(object.version) : "",
|
|
300
330
|
stops: isObject(object.stops)
|
|
301
|
-
? Object.entries(object.stops).reduce<{ [key:
|
|
302
|
-
acc[key] = Stop.fromJSON(value);
|
|
331
|
+
? Object.entries(object.stops).reduce<{ [key: number]: Stop }>((acc, [key, value]) => {
|
|
332
|
+
acc[globalThis.Number(key)] = Stop.fromJSON(value);
|
|
303
333
|
return acc;
|
|
304
334
|
}, {})
|
|
305
335
|
: {},
|
|
@@ -329,9 +359,9 @@ export const StopsMap: MessageFns<StopsMap> = {
|
|
|
329
359
|
fromPartial<I extends Exact<DeepPartial<StopsMap>, I>>(object: I): StopsMap {
|
|
330
360
|
const message = createBaseStopsMap();
|
|
331
361
|
message.version = object.version ?? "";
|
|
332
|
-
message.stops = Object.entries(object.stops ?? {}).reduce<{ [key:
|
|
362
|
+
message.stops = Object.entries(object.stops ?? {}).reduce<{ [key: number]: Stop }>((acc, [key, value]) => {
|
|
333
363
|
if (value !== undefined) {
|
|
334
|
-
acc[key] = Stop.fromPartial(value);
|
|
364
|
+
acc[globalThis.Number(key)] = Stop.fromPartial(value);
|
|
335
365
|
}
|
|
336
366
|
return acc;
|
|
337
367
|
}, {});
|
|
@@ -340,13 +370,13 @@ export const StopsMap: MessageFns<StopsMap> = {
|
|
|
340
370
|
};
|
|
341
371
|
|
|
342
372
|
function createBaseStopsMap_StopsEntry(): StopsMap_StopsEntry {
|
|
343
|
-
return { key:
|
|
373
|
+
return { key: 0, value: undefined };
|
|
344
374
|
}
|
|
345
375
|
|
|
346
376
|
export const StopsMap_StopsEntry: MessageFns<StopsMap_StopsEntry> = {
|
|
347
377
|
encode(message: StopsMap_StopsEntry, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
|
348
|
-
if (message.key !==
|
|
349
|
-
writer.uint32(
|
|
378
|
+
if (message.key !== 0) {
|
|
379
|
+
writer.uint32(8).uint32(message.key);
|
|
350
380
|
}
|
|
351
381
|
if (message.value !== undefined) {
|
|
352
382
|
Stop.encode(message.value, writer.uint32(18).fork()).join();
|
|
@@ -362,11 +392,11 @@ export const StopsMap_StopsEntry: MessageFns<StopsMap_StopsEntry> = {
|
|
|
362
392
|
const tag = reader.uint32();
|
|
363
393
|
switch (tag >>> 3) {
|
|
364
394
|
case 1: {
|
|
365
|
-
if (tag !==
|
|
395
|
+
if (tag !== 8) {
|
|
366
396
|
break;
|
|
367
397
|
}
|
|
368
398
|
|
|
369
|
-
message.key = reader.
|
|
399
|
+
message.key = reader.uint32();
|
|
370
400
|
continue;
|
|
371
401
|
}
|
|
372
402
|
case 2: {
|
|
@@ -388,15 +418,15 @@ export const StopsMap_StopsEntry: MessageFns<StopsMap_StopsEntry> = {
|
|
|
388
418
|
|
|
389
419
|
fromJSON(object: any): StopsMap_StopsEntry {
|
|
390
420
|
return {
|
|
391
|
-
key: isSet(object.key) ? globalThis.
|
|
421
|
+
key: isSet(object.key) ? globalThis.Number(object.key) : 0,
|
|
392
422
|
value: isSet(object.value) ? Stop.fromJSON(object.value) : undefined,
|
|
393
423
|
};
|
|
394
424
|
},
|
|
395
425
|
|
|
396
426
|
toJSON(message: StopsMap_StopsEntry): unknown {
|
|
397
427
|
const obj: any = {};
|
|
398
|
-
if (message.key !==
|
|
399
|
-
obj.key = message.key;
|
|
428
|
+
if (message.key !== 0) {
|
|
429
|
+
obj.key = Math.round(message.key);
|
|
400
430
|
}
|
|
401
431
|
if (message.value !== undefined) {
|
|
402
432
|
obj.value = Stop.toJSON(message.value);
|
|
@@ -409,7 +439,7 @@ export const StopsMap_StopsEntry: MessageFns<StopsMap_StopsEntry> = {
|
|
|
409
439
|
},
|
|
410
440
|
fromPartial<I extends Exact<DeepPartial<StopsMap_StopsEntry>, I>>(object: I): StopsMap_StopsEntry {
|
|
411
441
|
const message = createBaseStopsMap_StopsEntry();
|
|
412
|
-
message.key = object.key ??
|
|
442
|
+
message.key = object.key ?? 0;
|
|
413
443
|
message.value = (object.value !== undefined && object.value !== null) ? Stop.fromPartial(object.value) : undefined;
|
|
414
444
|
return message;
|
|
415
445
|
},
|
package/src/stops/stops.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
// A stop ID defined in the source of the transit data (e.g. GTFS)
|
|
2
|
+
export type SourceStopId = string;
|
|
3
|
+
// An internally indexed StopId
|
|
4
|
+
export type StopId = number;
|
|
5
|
+
|
|
2
6
|
export type Platform = string;
|
|
3
7
|
export type Latitude = number;
|
|
4
8
|
export type Longitude = number;
|
|
@@ -12,6 +16,7 @@ export type LocationType =
|
|
|
12
16
|
|
|
13
17
|
export type Stop = {
|
|
14
18
|
id: StopId;
|
|
19
|
+
sourceStopId: SourceStopId;
|
|
15
20
|
name: string;
|
|
16
21
|
lat?: Latitude;
|
|
17
22
|
lon?: Longitude;
|
|
@@ -21,4 +26,11 @@ export type Stop = {
|
|
|
21
26
|
platform?: Platform;
|
|
22
27
|
};
|
|
23
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Mapping internal StopIds to Stop objects.
|
|
31
|
+
*/
|
|
24
32
|
export type StopsMap = Map<StopId, Stop>;
|
|
33
|
+
/**
|
|
34
|
+
* Mapping source stopIds to internal stopIds;
|
|
35
|
+
*/
|
|
36
|
+
export type SourceStopsMap = Map<SourceStopId, StopId>;
|
package/src/stops/stopsIndex.ts
CHANGED
|
@@ -6,7 +6,13 @@ import { addAll, createIndex, search, SearchResult } from 'slimsearch';
|
|
|
6
6
|
import { generateAccentVariants } from './i18n.js';
|
|
7
7
|
import { deserializeStopsMap, serializeStopsMap } from './io.js';
|
|
8
8
|
import { StopsMap as ProtoStopsMap } from './proto/stops.js';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
SourceStopId,
|
|
11
|
+
SourceStopsMap,
|
|
12
|
+
Stop,
|
|
13
|
+
StopId,
|
|
14
|
+
StopsMap,
|
|
15
|
+
} from './stops.js';
|
|
10
16
|
|
|
11
17
|
type StopPoint = { id: StopId; lat: number; lon: number };
|
|
12
18
|
|
|
@@ -17,19 +23,24 @@ type StopPoint = { id: StopId; lat: number; lon: number };
|
|
|
17
23
|
*/
|
|
18
24
|
export class StopsIndex {
|
|
19
25
|
private readonly stopsMap: StopsMap;
|
|
26
|
+
private readonly sourceStopsMap: SourceStopsMap;
|
|
20
27
|
private readonly textIndex;
|
|
21
28
|
private readonly geoIndex: KDTree;
|
|
22
29
|
private readonly stopPoints: StopPoint[];
|
|
23
30
|
|
|
24
31
|
constructor(stopsMap: StopsMap) {
|
|
25
32
|
this.stopsMap = stopsMap;
|
|
33
|
+
this.sourceStopsMap = new Map<SourceStopId, StopId>();
|
|
34
|
+
for (const [id, stop] of stopsMap.entries()) {
|
|
35
|
+
this.sourceStopsMap.set(stop.sourceStopId, id);
|
|
36
|
+
}
|
|
26
37
|
this.textIndex = createIndex({
|
|
27
38
|
fields: ['name'],
|
|
28
39
|
storeFields: ['id'],
|
|
29
40
|
searchOptions: { prefix: true, fuzzy: 0.2 },
|
|
30
41
|
processTerm: generateAccentVariants,
|
|
31
42
|
});
|
|
32
|
-
const stopsSet = new Map<
|
|
43
|
+
const stopsSet = new Map<StopId, { id: StopId; name: string }>();
|
|
33
44
|
for (const [id, stop] of stopsMap.entries()) {
|
|
34
45
|
const effectiveStopId = stop.parent ?? id;
|
|
35
46
|
if (!stopsSet.has(effectiveStopId)) {
|
|
@@ -86,6 +97,15 @@ export class StopsIndex {
|
|
|
86
97
|
return writer.finish();
|
|
87
98
|
}
|
|
88
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Returns the number of stops in the index.
|
|
102
|
+
*
|
|
103
|
+
* @returns The total number of stops.
|
|
104
|
+
*/
|
|
105
|
+
size(): number {
|
|
106
|
+
return this.stopsMap.size;
|
|
107
|
+
}
|
|
108
|
+
|
|
89
109
|
/**
|
|
90
110
|
* Finds stops by their name using a text search.
|
|
91
111
|
*
|
|
@@ -95,7 +115,7 @@ export class StopsIndex {
|
|
|
95
115
|
*/
|
|
96
116
|
findStopsByName(query: string, maxResults = 5): Stop[] {
|
|
97
117
|
const results = search(this.textIndex, query).map(
|
|
98
|
-
(result: SearchResult) => this.stopsMap.get(result.id as
|
|
118
|
+
(result: SearchResult) => this.stopsMap.get(result.id as number) as Stop,
|
|
99
119
|
);
|
|
100
120
|
return results.slice(0, maxResults);
|
|
101
121
|
}
|
|
@@ -129,16 +149,37 @@ export class StopsIndex {
|
|
|
129
149
|
}
|
|
130
150
|
|
|
131
151
|
/**
|
|
132
|
-
* Finds a stop by its ID.
|
|
152
|
+
* Finds a stop by its internal ID.
|
|
133
153
|
*
|
|
134
|
-
* @param id - The ID of the stop to search for.
|
|
154
|
+
* @param id - The internal ID of the stop to search for.
|
|
135
155
|
* @returns The Stop object that matches the specified ID, or undefined if not found.
|
|
136
156
|
*/
|
|
137
157
|
findStopById(id: StopId): Stop | undefined {
|
|
138
158
|
return this.stopsMap.get(id);
|
|
139
159
|
}
|
|
140
160
|
|
|
141
|
-
|
|
161
|
+
/**
|
|
162
|
+
* Finds a stop by its ID in the transit data source (e.g. GTFS).
|
|
163
|
+
*
|
|
164
|
+
* @param id - The source ID of the stop to search for.
|
|
165
|
+
* @returns The Stop object that matches the specified ID, or undefined if not found.
|
|
166
|
+
*/
|
|
167
|
+
findStopBySourceStopId(sourceStopId: SourceStopId): Stop | undefined {
|
|
168
|
+
const stopId = this.sourceStopsMap.get(sourceStopId);
|
|
169
|
+
if (stopId === undefined) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
return this.findStopById(stopId);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Find ids of all sibling stops.
|
|
177
|
+
*/
|
|
178
|
+
equivalentStops(sourceId: SourceStopId): Stop[] {
|
|
179
|
+
const id = this.sourceStopsMap.get(sourceId);
|
|
180
|
+
if (id === undefined) {
|
|
181
|
+
return [];
|
|
182
|
+
}
|
|
142
183
|
const stop = this.stopsMap.get(id);
|
|
143
184
|
if (!stop) {
|
|
144
185
|
return [];
|
|
@@ -146,6 +187,8 @@ export class StopsIndex {
|
|
|
146
187
|
const equivalentStops = stop.parent
|
|
147
188
|
? (this.stopsMap.get(stop.parent)?.children ?? [])
|
|
148
189
|
: stop.children;
|
|
149
|
-
return Array.from(new Set([id, ...equivalentStops]))
|
|
190
|
+
return Array.from(new Set([id, ...equivalentStops])).map(
|
|
191
|
+
(stopId) => this.stopsMap.get(stopId) as Stop,
|
|
192
|
+
);
|
|
150
193
|
}
|
|
151
194
|
}
|
|
@@ -20,18 +20,18 @@ import {
|
|
|
20
20
|
describe('timetable io', () => {
|
|
21
21
|
const stopsAdjacency: StopsAdjacency = new Map([
|
|
22
22
|
[
|
|
23
|
-
|
|
23
|
+
1,
|
|
24
24
|
{
|
|
25
|
-
transfers: [{ destination:
|
|
25
|
+
transfers: [{ destination: 2, type: 'RECOMMENDED' }],
|
|
26
26
|
routes: ['route1'],
|
|
27
27
|
},
|
|
28
28
|
],
|
|
29
29
|
[
|
|
30
|
-
|
|
30
|
+
2,
|
|
31
31
|
{
|
|
32
32
|
transfers: [
|
|
33
33
|
{
|
|
34
|
-
destination:
|
|
34
|
+
destination: 1,
|
|
35
35
|
type: 'GUARANTEED',
|
|
36
36
|
minTransferTime: Duration.fromMinutes(3),
|
|
37
37
|
},
|
|
@@ -44,18 +44,15 @@ describe('timetable io', () => {
|
|
|
44
44
|
[
|
|
45
45
|
'route1',
|
|
46
46
|
{
|
|
47
|
-
stopTimes: [
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
},
|
|
54
|
-
],
|
|
55
|
-
stops: ['stop1', 'stop2'],
|
|
47
|
+
stopTimes: new Uint32Array([
|
|
48
|
+
Time.fromHMS(0, 16, 40).toSeconds(),
|
|
49
|
+
Time.fromHMS(0, 16, 50).toSeconds(),
|
|
50
|
+
]),
|
|
51
|
+
pickUpDropOffTypes: new Uint8Array([0, 0]), // REGULAR
|
|
52
|
+
stops: new Uint32Array([1, 2]),
|
|
56
53
|
stopIndices: new Map([
|
|
57
|
-
[
|
|
58
|
-
[
|
|
54
|
+
[1, 0],
|
|
55
|
+
[2, 1],
|
|
59
56
|
]),
|
|
60
57
|
serviceRouteId: 'gtfs1',
|
|
61
58
|
},
|
|
@@ -63,18 +60,15 @@ describe('timetable io', () => {
|
|
|
63
60
|
[
|
|
64
61
|
'route2',
|
|
65
62
|
{
|
|
66
|
-
stopTimes: [
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
},
|
|
73
|
-
],
|
|
74
|
-
stops: ['stop2', 'stop1'],
|
|
63
|
+
stopTimes: new Uint32Array([
|
|
64
|
+
Time.fromHMS(0, 33, 20).toSeconds(),
|
|
65
|
+
Time.fromHMS(0, 33, 30).toSeconds(),
|
|
66
|
+
]),
|
|
67
|
+
pickUpDropOffTypes: new Uint8Array([0, 0]), // REGULAR
|
|
68
|
+
stops: new Uint32Array([2, 1]),
|
|
75
69
|
stopIndices: new Map([
|
|
76
|
-
[
|
|
77
|
-
[
|
|
70
|
+
[2, 0],
|
|
71
|
+
[1, 1],
|
|
78
72
|
]),
|
|
79
73
|
serviceRouteId: 'gtfs2',
|
|
80
74
|
},
|
|
@@ -84,17 +78,16 @@ describe('timetable io', () => {
|
|
|
84
78
|
['gtfs1', { type: 'RAIL', name: 'Route 1' }],
|
|
85
79
|
['gtfs2', { type: 'RAIL', name: 'Route 2' }],
|
|
86
80
|
]);
|
|
87
|
-
|
|
88
81
|
const stopsAdjacencyProto = {
|
|
89
82
|
stops: {
|
|
90
|
-
|
|
91
|
-
transfers: [{ destination:
|
|
83
|
+
'1': {
|
|
84
|
+
transfers: [{ destination: 2, type: 0 }],
|
|
92
85
|
routes: ['route1'],
|
|
93
86
|
},
|
|
94
|
-
|
|
87
|
+
'2': {
|
|
95
88
|
transfers: [
|
|
96
89
|
{
|
|
97
|
-
destination:
|
|
90
|
+
destination: 1,
|
|
98
91
|
type: 1,
|
|
99
92
|
minTransferTime: 180,
|
|
100
93
|
},
|
|
@@ -107,27 +100,25 @@ describe('timetable io', () => {
|
|
|
107
100
|
const routesAdjacencyProto = {
|
|
108
101
|
routes: {
|
|
109
102
|
route1: {
|
|
110
|
-
stopTimes:
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
],
|
|
118
|
-
stops: ['stop1', 'stop2'],
|
|
103
|
+
stopTimes: new Uint8Array(
|
|
104
|
+
new Uint32Array([
|
|
105
|
+
Time.fromHMS(0, 16, 40).toSeconds(),
|
|
106
|
+
Time.fromHMS(0, 16, 50).toSeconds(),
|
|
107
|
+
]).buffer,
|
|
108
|
+
),
|
|
109
|
+
pickUpDropOffTypes: new Uint8Array([0, 0]), // REGULAR
|
|
110
|
+
stops: new Uint8Array(new Uint32Array([1, 2]).buffer),
|
|
119
111
|
serviceRouteId: 'gtfs1',
|
|
120
112
|
},
|
|
121
113
|
route2: {
|
|
122
|
-
stopTimes:
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
],
|
|
130
|
-
stops: ['stop2', 'stop1'],
|
|
114
|
+
stopTimes: new Uint8Array(
|
|
115
|
+
new Uint32Array([
|
|
116
|
+
Time.fromHMS(0, 33, 20).toSeconds(),
|
|
117
|
+
Time.fromHMS(0, 33, 30).toSeconds(),
|
|
118
|
+
]).buffer,
|
|
119
|
+
),
|
|
120
|
+
pickUpDropOffTypes: new Uint8Array([0, 0]), // REGULAR
|
|
121
|
+
stops: new Uint8Array(new Uint32Array([2, 1]).buffer),
|
|
131
122
|
serviceRouteId: 'gtfs2',
|
|
132
123
|
},
|
|
133
124
|
},
|