minotor 7.0.2 → 8.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/.cspell.json +11 -1
- package/CHANGELOG.md +8 -3
- package/README.md +26 -24
- package/dist/cli.mjs +1243 -267
- package/dist/cli.mjs.map +1 -1
- package/dist/gtfs/transfers.d.ts +13 -4
- package/dist/gtfs/trips.d.ts +12 -7
- package/dist/parser.cjs.js +494 -71
- package/dist/parser.cjs.js.map +1 -1
- package/dist/parser.esm.js +494 -71
- 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 +2 -2
- 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__/plotter.test.d.ts +1 -0
- package/dist/routing/plotter.d.ts +42 -3
- package/dist/routing/result.d.ts +23 -7
- package/dist/routing/route.d.ts +2 -0
- package/dist/routing/router.d.ts +78 -19
- package/dist/timetable/__tests__/tripId.test.d.ts +1 -0
- package/dist/timetable/io.d.ts +4 -2
- package/dist/timetable/proto/timetable.d.ts +13 -1
- package/dist/timetable/route.d.ts +41 -8
- package/dist/timetable/timetable.d.ts +18 -3
- package/dist/timetable/tripId.d.ts +15 -0
- package/package.json +1 -1
- package/src/__e2e__/router.test.ts +114 -105
- package/src/__e2e__/timetable/stops.bin +2 -2
- package/src/__e2e__/timetable/timetable.bin +2 -2
- package/src/cli/repl.ts +259 -1
- package/src/gtfs/__tests__/transfers.test.ts +468 -12
- package/src/gtfs/__tests__/trips.test.ts +350 -28
- package/src/gtfs/parser.ts +16 -4
- package/src/gtfs/transfers.ts +61 -18
- package/src/gtfs/trips.ts +97 -22
- package/src/router.ts +2 -2
- package/src/routing/__tests__/plotter.test.ts +230 -0
- package/src/routing/__tests__/result.test.ts +486 -125
- package/src/routing/__tests__/route.test.ts +7 -3
- package/src/routing/__tests__/router.test.ts +378 -172
- package/src/routing/plotter.ts +279 -48
- package/src/routing/result.ts +114 -34
- package/src/routing/route.ts +0 -3
- package/src/routing/router.ts +332 -211
- package/src/timetable/__tests__/io.test.ts +33 -1
- package/src/timetable/__tests__/route.test.ts +10 -3
- package/src/timetable/__tests__/timetable.test.ts +225 -57
- package/src/timetable/__tests__/tripId.test.ts +27 -0
- package/src/timetable/io.ts +71 -10
- package/src/timetable/proto/timetable.proto +14 -2
- package/src/timetable/proto/timetable.ts +218 -20
- package/src/timetable/route.ts +152 -19
- package/src/timetable/timetable.ts +45 -6
- package/src/timetable/tripId.ts +29 -0
package/dist/parser.cjs.js
CHANGED
|
@@ -12296,41 +12296,191 @@ const Transfer = {
|
|
|
12296
12296
|
return message;
|
|
12297
12297
|
},
|
|
12298
12298
|
};
|
|
12299
|
-
function
|
|
12300
|
-
return {
|
|
12299
|
+
function createBaseTripBoarding() {
|
|
12300
|
+
return { hopOnStop: 0, routeId: 0, tripIndex: 0 };
|
|
12301
12301
|
}
|
|
12302
|
-
const
|
|
12302
|
+
const TripBoarding = {
|
|
12303
12303
|
encode(message, writer = new BinaryWriter()) {
|
|
12304
|
-
|
|
12305
|
-
|
|
12304
|
+
if (message.hopOnStop !== 0) {
|
|
12305
|
+
writer.uint32(8).uint32(message.hopOnStop);
|
|
12306
12306
|
}
|
|
12307
|
-
|
|
12308
|
-
|
|
12309
|
-
|
|
12307
|
+
if (message.routeId !== 0) {
|
|
12308
|
+
writer.uint32(16).uint32(message.routeId);
|
|
12309
|
+
}
|
|
12310
|
+
if (message.tripIndex !== 0) {
|
|
12311
|
+
writer.uint32(24).uint32(message.tripIndex);
|
|
12310
12312
|
}
|
|
12311
|
-
writer.join();
|
|
12312
12313
|
return writer;
|
|
12313
12314
|
},
|
|
12314
12315
|
decode(input, length) {
|
|
12315
12316
|
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
|
|
12316
12317
|
const end = length === undefined ? reader.len : reader.pos + length;
|
|
12317
|
-
const message =
|
|
12318
|
+
const message = createBaseTripBoarding();
|
|
12318
12319
|
while (reader.pos < end) {
|
|
12319
12320
|
const tag = reader.uint32();
|
|
12320
12321
|
switch (tag >>> 3) {
|
|
12321
12322
|
case 1: {
|
|
12322
|
-
if (tag !==
|
|
12323
|
+
if (tag !== 8) {
|
|
12323
12324
|
break;
|
|
12324
12325
|
}
|
|
12325
|
-
message.
|
|
12326
|
+
message.hopOnStop = reader.uint32();
|
|
12327
|
+
continue;
|
|
12328
|
+
}
|
|
12329
|
+
case 2: {
|
|
12330
|
+
if (tag !== 16) {
|
|
12331
|
+
break;
|
|
12332
|
+
}
|
|
12333
|
+
message.routeId = reader.uint32();
|
|
12334
|
+
continue;
|
|
12335
|
+
}
|
|
12336
|
+
case 3: {
|
|
12337
|
+
if (tag !== 24) {
|
|
12338
|
+
break;
|
|
12339
|
+
}
|
|
12340
|
+
message.tripIndex = reader.uint32();
|
|
12341
|
+
continue;
|
|
12342
|
+
}
|
|
12343
|
+
}
|
|
12344
|
+
if ((tag & 7) === 4 || tag === 0) {
|
|
12345
|
+
break;
|
|
12346
|
+
}
|
|
12347
|
+
reader.skip(tag & 7);
|
|
12348
|
+
}
|
|
12349
|
+
return message;
|
|
12350
|
+
},
|
|
12351
|
+
fromJSON(object) {
|
|
12352
|
+
return {
|
|
12353
|
+
hopOnStop: isSet(object.hopOnStop) ? globalThis.Number(object.hopOnStop) : 0,
|
|
12354
|
+
routeId: isSet(object.routeId) ? globalThis.Number(object.routeId) : 0,
|
|
12355
|
+
tripIndex: isSet(object.tripIndex) ? globalThis.Number(object.tripIndex) : 0,
|
|
12356
|
+
};
|
|
12357
|
+
},
|
|
12358
|
+
toJSON(message) {
|
|
12359
|
+
const obj = {};
|
|
12360
|
+
if (message.hopOnStop !== 0) {
|
|
12361
|
+
obj.hopOnStop = Math.round(message.hopOnStop);
|
|
12362
|
+
}
|
|
12363
|
+
if (message.routeId !== 0) {
|
|
12364
|
+
obj.routeId = Math.round(message.routeId);
|
|
12365
|
+
}
|
|
12366
|
+
if (message.tripIndex !== 0) {
|
|
12367
|
+
obj.tripIndex = Math.round(message.tripIndex);
|
|
12368
|
+
}
|
|
12369
|
+
return obj;
|
|
12370
|
+
},
|
|
12371
|
+
create(base) {
|
|
12372
|
+
return TripBoarding.fromPartial(base !== null && base !== void 0 ? base : {});
|
|
12373
|
+
},
|
|
12374
|
+
fromPartial(object) {
|
|
12375
|
+
var _a, _b, _c;
|
|
12376
|
+
const message = createBaseTripBoarding();
|
|
12377
|
+
message.hopOnStop = (_a = object.hopOnStop) !== null && _a !== void 0 ? _a : 0;
|
|
12378
|
+
message.routeId = (_b = object.routeId) !== null && _b !== void 0 ? _b : 0;
|
|
12379
|
+
message.tripIndex = (_c = object.tripIndex) !== null && _c !== void 0 ? _c : 0;
|
|
12380
|
+
return message;
|
|
12381
|
+
},
|
|
12382
|
+
};
|
|
12383
|
+
function createBaseTripContinuationEntry() {
|
|
12384
|
+
return { key: 0, value: [] };
|
|
12385
|
+
}
|
|
12386
|
+
const TripContinuationEntry = {
|
|
12387
|
+
encode(message, writer = new BinaryWriter()) {
|
|
12388
|
+
if (message.key !== 0) {
|
|
12389
|
+
writer.uint32(8).uint32(message.key);
|
|
12390
|
+
}
|
|
12391
|
+
for (const v of message.value) {
|
|
12392
|
+
TripBoarding.encode(v, writer.uint32(18).fork()).join();
|
|
12393
|
+
}
|
|
12394
|
+
return writer;
|
|
12395
|
+
},
|
|
12396
|
+
decode(input, length) {
|
|
12397
|
+
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
|
|
12398
|
+
const end = length === undefined ? reader.len : reader.pos + length;
|
|
12399
|
+
const message = createBaseTripContinuationEntry();
|
|
12400
|
+
while (reader.pos < end) {
|
|
12401
|
+
const tag = reader.uint32();
|
|
12402
|
+
switch (tag >>> 3) {
|
|
12403
|
+
case 1: {
|
|
12404
|
+
if (tag !== 8) {
|
|
12405
|
+
break;
|
|
12406
|
+
}
|
|
12407
|
+
message.key = reader.uint32();
|
|
12326
12408
|
continue;
|
|
12327
12409
|
}
|
|
12328
12410
|
case 2: {
|
|
12329
|
-
if (tag
|
|
12411
|
+
if (tag !== 18) {
|
|
12412
|
+
break;
|
|
12413
|
+
}
|
|
12414
|
+
message.value.push(TripBoarding.decode(reader, reader.uint32()));
|
|
12415
|
+
continue;
|
|
12416
|
+
}
|
|
12417
|
+
}
|
|
12418
|
+
if ((tag & 7) === 4 || tag === 0) {
|
|
12419
|
+
break;
|
|
12420
|
+
}
|
|
12421
|
+
reader.skip(tag & 7);
|
|
12422
|
+
}
|
|
12423
|
+
return message;
|
|
12424
|
+
},
|
|
12425
|
+
fromJSON(object) {
|
|
12426
|
+
return {
|
|
12427
|
+
key: isSet(object.key) ? globalThis.Number(object.key) : 0,
|
|
12428
|
+
value: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.value) ? object.value.map((e) => TripBoarding.fromJSON(e)) : [],
|
|
12429
|
+
};
|
|
12430
|
+
},
|
|
12431
|
+
toJSON(message) {
|
|
12432
|
+
var _a;
|
|
12433
|
+
const obj = {};
|
|
12434
|
+
if (message.key !== 0) {
|
|
12435
|
+
obj.key = Math.round(message.key);
|
|
12436
|
+
}
|
|
12437
|
+
if ((_a = message.value) === null || _a === void 0 ? void 0 : _a.length) {
|
|
12438
|
+
obj.value = message.value.map((e) => TripBoarding.toJSON(e));
|
|
12439
|
+
}
|
|
12440
|
+
return obj;
|
|
12441
|
+
},
|
|
12442
|
+
create(base) {
|
|
12443
|
+
return TripContinuationEntry.fromPartial(base !== null && base !== void 0 ? base : {});
|
|
12444
|
+
},
|
|
12445
|
+
fromPartial(object) {
|
|
12446
|
+
var _a, _b;
|
|
12447
|
+
const message = createBaseTripContinuationEntry();
|
|
12448
|
+
message.key = (_a = object.key) !== null && _a !== void 0 ? _a : 0;
|
|
12449
|
+
message.value = ((_b = object.value) === null || _b === void 0 ? void 0 : _b.map((e) => TripBoarding.fromPartial(e))) || [];
|
|
12450
|
+
return message;
|
|
12451
|
+
},
|
|
12452
|
+
};
|
|
12453
|
+
function createBaseStopAdjacency() {
|
|
12454
|
+
return { routes: [], transfers: [], tripContinuations: [] };
|
|
12455
|
+
}
|
|
12456
|
+
const StopAdjacency = {
|
|
12457
|
+
encode(message, writer = new BinaryWriter()) {
|
|
12458
|
+
writer.uint32(10).fork();
|
|
12459
|
+
for (const v of message.routes) {
|
|
12460
|
+
writer.uint32(v);
|
|
12461
|
+
}
|
|
12462
|
+
writer.join();
|
|
12463
|
+
for (const v of message.transfers) {
|
|
12464
|
+
Transfer.encode(v, writer.uint32(18).fork()).join();
|
|
12465
|
+
}
|
|
12466
|
+
for (const v of message.tripContinuations) {
|
|
12467
|
+
TripContinuationEntry.encode(v, writer.uint32(26).fork()).join();
|
|
12468
|
+
}
|
|
12469
|
+
return writer;
|
|
12470
|
+
},
|
|
12471
|
+
decode(input, length) {
|
|
12472
|
+
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
|
|
12473
|
+
const end = length === undefined ? reader.len : reader.pos + length;
|
|
12474
|
+
const message = createBaseStopAdjacency();
|
|
12475
|
+
while (reader.pos < end) {
|
|
12476
|
+
const tag = reader.uint32();
|
|
12477
|
+
switch (tag >>> 3) {
|
|
12478
|
+
case 1: {
|
|
12479
|
+
if (tag === 8) {
|
|
12330
12480
|
message.routes.push(reader.uint32());
|
|
12331
12481
|
continue;
|
|
12332
12482
|
}
|
|
12333
|
-
if (tag ===
|
|
12483
|
+
if (tag === 10) {
|
|
12334
12484
|
const end2 = reader.uint32() + reader.pos;
|
|
12335
12485
|
while (reader.pos < end2) {
|
|
12336
12486
|
message.routes.push(reader.uint32());
|
|
@@ -12339,6 +12489,20 @@ const StopAdjacency = {
|
|
|
12339
12489
|
}
|
|
12340
12490
|
break;
|
|
12341
12491
|
}
|
|
12492
|
+
case 2: {
|
|
12493
|
+
if (tag !== 18) {
|
|
12494
|
+
break;
|
|
12495
|
+
}
|
|
12496
|
+
message.transfers.push(Transfer.decode(reader, reader.uint32()));
|
|
12497
|
+
continue;
|
|
12498
|
+
}
|
|
12499
|
+
case 3: {
|
|
12500
|
+
if (tag !== 26) {
|
|
12501
|
+
break;
|
|
12502
|
+
}
|
|
12503
|
+
message.tripContinuations.push(TripContinuationEntry.decode(reader, reader.uint32()));
|
|
12504
|
+
continue;
|
|
12505
|
+
}
|
|
12342
12506
|
}
|
|
12343
12507
|
if ((tag & 7) === 4 || tag === 0) {
|
|
12344
12508
|
break;
|
|
@@ -12349,20 +12513,26 @@ const StopAdjacency = {
|
|
|
12349
12513
|
},
|
|
12350
12514
|
fromJSON(object) {
|
|
12351
12515
|
return {
|
|
12516
|
+
routes: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.routes) ? object.routes.map((e) => globalThis.Number(e)) : [],
|
|
12352
12517
|
transfers: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.transfers)
|
|
12353
12518
|
? object.transfers.map((e) => Transfer.fromJSON(e))
|
|
12354
12519
|
: [],
|
|
12355
|
-
|
|
12520
|
+
tripContinuations: globalThis.Array.isArray(object === null || object === void 0 ? void 0 : object.tripContinuations)
|
|
12521
|
+
? object.tripContinuations.map((e) => TripContinuationEntry.fromJSON(e))
|
|
12522
|
+
: [],
|
|
12356
12523
|
};
|
|
12357
12524
|
},
|
|
12358
12525
|
toJSON(message) {
|
|
12359
|
-
var _a, _b;
|
|
12526
|
+
var _a, _b, _c;
|
|
12360
12527
|
const obj = {};
|
|
12361
|
-
if ((_a = message.
|
|
12528
|
+
if ((_a = message.routes) === null || _a === void 0 ? void 0 : _a.length) {
|
|
12529
|
+
obj.routes = message.routes.map((e) => Math.round(e));
|
|
12530
|
+
}
|
|
12531
|
+
if ((_b = message.transfers) === null || _b === void 0 ? void 0 : _b.length) {
|
|
12362
12532
|
obj.transfers = message.transfers.map((e) => Transfer.toJSON(e));
|
|
12363
12533
|
}
|
|
12364
|
-
if ((
|
|
12365
|
-
obj.
|
|
12534
|
+
if ((_c = message.tripContinuations) === null || _c === void 0 ? void 0 : _c.length) {
|
|
12535
|
+
obj.tripContinuations = message.tripContinuations.map((e) => TripContinuationEntry.toJSON(e));
|
|
12366
12536
|
}
|
|
12367
12537
|
return obj;
|
|
12368
12538
|
},
|
|
@@ -12370,10 +12540,11 @@ const StopAdjacency = {
|
|
|
12370
12540
|
return StopAdjacency.fromPartial(base !== null && base !== void 0 ? base : {});
|
|
12371
12541
|
},
|
|
12372
12542
|
fromPartial(object) {
|
|
12373
|
-
var _a, _b;
|
|
12543
|
+
var _a, _b, _c;
|
|
12374
12544
|
const message = createBaseStopAdjacency();
|
|
12375
|
-
message.
|
|
12376
|
-
message.
|
|
12545
|
+
message.routes = ((_a = object.routes) === null || _a === void 0 ? void 0 : _a.map((e) => e)) || [];
|
|
12546
|
+
message.transfers = ((_b = object.transfers) === null || _b === void 0 ? void 0 : _b.map((e) => Transfer.fromPartial(e))) || [];
|
|
12547
|
+
message.tripContinuations = ((_c = object.tripContinuations) === null || _c === void 0 ? void 0 : _c.map((e) => TripContinuationEntry.fromPartial(e))) || [];
|
|
12377
12548
|
return message;
|
|
12378
12549
|
},
|
|
12379
12550
|
};
|
|
@@ -12862,7 +13033,8 @@ const toPickupDropOffType = (numericalType) => {
|
|
|
12862
13033
|
* A route identifies all trips of a given service route sharing the same list of stops.
|
|
12863
13034
|
*/
|
|
12864
13035
|
class Route {
|
|
12865
|
-
constructor(stopTimes, pickUpDropOffTypes, stops, serviceRouteId) {
|
|
13036
|
+
constructor(id, stopTimes, pickUpDropOffTypes, stops, serviceRouteId) {
|
|
13037
|
+
this.id = id;
|
|
12866
13038
|
this.stopTimes = stopTimes;
|
|
12867
13039
|
this.pickUpDropOffTypes = pickUpDropOffTypes;
|
|
12868
13040
|
this.stops = stops;
|
|
@@ -12875,6 +13047,78 @@ class Route {
|
|
|
12875
13047
|
this.stopIndices.set(stops[i], i);
|
|
12876
13048
|
}
|
|
12877
13049
|
}
|
|
13050
|
+
/**
|
|
13051
|
+
* Creates a new route from multiple trips with their stops.
|
|
13052
|
+
*
|
|
13053
|
+
* @param params The route parameters including ID, service route ID, and trips.
|
|
13054
|
+
* @returns The new route.
|
|
13055
|
+
*/
|
|
13056
|
+
static of(params) {
|
|
13057
|
+
var _a, _b;
|
|
13058
|
+
const { id, serviceRouteId, trips } = params;
|
|
13059
|
+
if (trips.length === 0) {
|
|
13060
|
+
throw new Error('At least one trip must be provided');
|
|
13061
|
+
}
|
|
13062
|
+
// All trips must have the same stops in the same order
|
|
13063
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13064
|
+
const firstTrip = trips[0];
|
|
13065
|
+
const stopIds = new Uint32Array(firstTrip.stops.map((stop) => stop.id));
|
|
13066
|
+
const numStops = stopIds.length;
|
|
13067
|
+
// Validate all trips have the same stops
|
|
13068
|
+
for (let tripIndex = 1; tripIndex < trips.length; tripIndex++) {
|
|
13069
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13070
|
+
const trip = trips[tripIndex];
|
|
13071
|
+
if (trip.stops.length !== numStops) {
|
|
13072
|
+
throw new Error(`Trip ${tripIndex} has ${trip.stops.length} stops, expected ${numStops}`);
|
|
13073
|
+
}
|
|
13074
|
+
for (let stopIndex = 0; stopIndex < numStops; stopIndex++) {
|
|
13075
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13076
|
+
if (trip.stops[stopIndex].id !== stopIds[stopIndex]) {
|
|
13077
|
+
throw new Error(`Trip ${tripIndex} has different stop at index ${stopIndex}`);
|
|
13078
|
+
}
|
|
13079
|
+
}
|
|
13080
|
+
}
|
|
13081
|
+
// Create stopTimes array with arrivals and departures for all trips
|
|
13082
|
+
const stopTimes = new Uint16Array(trips.length * numStops * 2);
|
|
13083
|
+
for (let tripIndex = 0; tripIndex < trips.length; tripIndex++) {
|
|
13084
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13085
|
+
const trip = trips[tripIndex];
|
|
13086
|
+
for (let stopIndex = 0; stopIndex < numStops; stopIndex++) {
|
|
13087
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13088
|
+
const stop = trip.stops[stopIndex];
|
|
13089
|
+
const baseIndex = (tripIndex * numStops + stopIndex) * 2;
|
|
13090
|
+
stopTimes[baseIndex] = stop.arrivalTime.toMinutes();
|
|
13091
|
+
stopTimes[baseIndex + 1] = stop.departureTime.toMinutes();
|
|
13092
|
+
}
|
|
13093
|
+
}
|
|
13094
|
+
// Create pickUpDropOffTypes array (2-bit encoded) for all trips
|
|
13095
|
+
const totalStopEntries = trips.length * numStops;
|
|
13096
|
+
const pickUpDropOffTypes = new Uint8Array(Math.ceil(totalStopEntries / 2));
|
|
13097
|
+
for (let tripIndex = 0; tripIndex < trips.length; tripIndex++) {
|
|
13098
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13099
|
+
const trip = trips[tripIndex];
|
|
13100
|
+
for (let stopIndex = 0; stopIndex < numStops; stopIndex++) {
|
|
13101
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13102
|
+
const stop = trip.stops[stopIndex];
|
|
13103
|
+
const globalIndex = tripIndex * numStops + stopIndex;
|
|
13104
|
+
const pickUp = (_a = stop.pickUpType) !== null && _a !== void 0 ? _a : REGULAR;
|
|
13105
|
+
const dropOff = (_b = stop.dropOffType) !== null && _b !== void 0 ? _b : REGULAR;
|
|
13106
|
+
const byteIndex = Math.floor(globalIndex / 2);
|
|
13107
|
+
const isSecondPair = globalIndex % 2 === 1;
|
|
13108
|
+
if (isSecondPair) {
|
|
13109
|
+
// Second pair: pickup in upper 2 bits, dropOff in bits 4-5
|
|
13110
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13111
|
+
pickUpDropOffTypes[byteIndex] |= (pickUp << 6) | (dropOff << 4);
|
|
13112
|
+
}
|
|
13113
|
+
else {
|
|
13114
|
+
// First pair: pickup in bits 2-3, dropOff in lower 2 bits
|
|
13115
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13116
|
+
pickUpDropOffTypes[byteIndex] |= (pickUp << 2) | dropOff;
|
|
13117
|
+
}
|
|
13118
|
+
}
|
|
13119
|
+
}
|
|
13120
|
+
return new Route(id, stopTimes, pickUpDropOffTypes, stopIds, serviceRouteId);
|
|
13121
|
+
}
|
|
12878
13122
|
/**
|
|
12879
13123
|
* Serializes the Route into binary arrays.
|
|
12880
13124
|
*
|
|
@@ -12898,11 +13142,11 @@ class Route {
|
|
|
12898
13142
|
isBefore(stopA, stopB) {
|
|
12899
13143
|
const stopAIndex = this.stopIndices.get(stopA);
|
|
12900
13144
|
if (stopAIndex === undefined) {
|
|
12901
|
-
throw new Error(`Stop index ${
|
|
13145
|
+
throw new Error(`Stop index not found for ${stopA} in route ${this.serviceRouteId}`);
|
|
12902
13146
|
}
|
|
12903
13147
|
const stopBIndex = this.stopIndices.get(stopB);
|
|
12904
13148
|
if (stopBIndex === undefined) {
|
|
12905
|
-
throw new Error(`Stop index ${
|
|
13149
|
+
throw new Error(`Stop index not found for ${stopB} in route ${this.serviceRouteId}`);
|
|
12906
13150
|
}
|
|
12907
13151
|
return stopAIndex < stopBIndex;
|
|
12908
13152
|
}
|
|
@@ -12914,6 +13158,14 @@ class Route {
|
|
|
12914
13158
|
getNbStops() {
|
|
12915
13159
|
return this.nbStops;
|
|
12916
13160
|
}
|
|
13161
|
+
/**
|
|
13162
|
+
* Retrieves the number of trips in the route.
|
|
13163
|
+
*
|
|
13164
|
+
* @returns The total number of trips in the route.
|
|
13165
|
+
*/
|
|
13166
|
+
getNbTrips() {
|
|
13167
|
+
return this.nbTrips;
|
|
13168
|
+
}
|
|
12917
13169
|
/**
|
|
12918
13170
|
* Finds the ServiceRouteId of the route. It corresponds the identifier
|
|
12919
13171
|
* of the service shown to the end user as a route.
|
|
@@ -12931,7 +13183,7 @@ class Route {
|
|
|
12931
13183
|
* @returns The arrival time at the specified stop and trip as a Time object.
|
|
12932
13184
|
*/
|
|
12933
13185
|
arrivalAt(stopId, tripIndex) {
|
|
12934
|
-
const arrivalIndex = (tripIndex * this.stops.length + this.
|
|
13186
|
+
const arrivalIndex = (tripIndex * this.stops.length + this.stopRouteIndex(stopId)) * 2;
|
|
12935
13187
|
const arrival = this.stopTimes[arrivalIndex];
|
|
12936
13188
|
if (arrival === undefined) {
|
|
12937
13189
|
throw new Error(`Arrival time not found for stop ${stopId} at trip index ${tripIndex} in route ${this.serviceRouteId}`);
|
|
@@ -12946,7 +13198,7 @@ class Route {
|
|
|
12946
13198
|
* @returns The departure time at the specified stop and trip as a Time object.
|
|
12947
13199
|
*/
|
|
12948
13200
|
departureFrom(stopId, tripIndex) {
|
|
12949
|
-
const departureIndex = (tripIndex * this.stops.length + this.
|
|
13201
|
+
const departureIndex = (tripIndex * this.stops.length + this.stopRouteIndex(stopId)) * 2 + 1;
|
|
12950
13202
|
const departure = this.stopTimes[departureIndex];
|
|
12951
13203
|
if (departure === undefined) {
|
|
12952
13204
|
throw new Error(`Departure time not found for stop ${stopId} at trip index ${tripIndex} in route ${this.serviceRouteId}`);
|
|
@@ -12961,7 +13213,7 @@ class Route {
|
|
|
12961
13213
|
* @returns The pick-up type at the specified stop and trip.
|
|
12962
13214
|
*/
|
|
12963
13215
|
pickUpTypeFrom(stopId, tripIndex) {
|
|
12964
|
-
const globalIndex = tripIndex * this.stops.length + this.
|
|
13216
|
+
const globalIndex = tripIndex * this.stops.length + this.stopRouteIndex(stopId);
|
|
12965
13217
|
const byteIndex = Math.floor(globalIndex / 2);
|
|
12966
13218
|
const isSecondPair = globalIndex % 2 === 1;
|
|
12967
13219
|
const byte = this.pickUpDropOffTypes[byteIndex];
|
|
@@ -12981,7 +13233,7 @@ class Route {
|
|
|
12981
13233
|
* @returns The drop-off type at the specified stop and trip.
|
|
12982
13234
|
*/
|
|
12983
13235
|
dropOffTypeAt(stopId, tripIndex) {
|
|
12984
|
-
const globalIndex = tripIndex * this.stops.length + this.
|
|
13236
|
+
const globalIndex = tripIndex * this.stops.length + this.stopRouteIndex(stopId);
|
|
12985
13237
|
const byteIndex = Math.floor(globalIndex / 2);
|
|
12986
13238
|
const isSecondPair = globalIndex % 2 === 1;
|
|
12987
13239
|
const byte = this.pickUpDropOffTypes[byteIndex];
|
|
@@ -13041,13 +13293,25 @@ class Route {
|
|
|
13041
13293
|
* @param stopId The StopId of the stop to locate in the route.
|
|
13042
13294
|
* @returns The index of the stop in the route.
|
|
13043
13295
|
*/
|
|
13044
|
-
|
|
13296
|
+
stopRouteIndex(stopId) {
|
|
13045
13297
|
const stopIndex = this.stopIndices.get(stopId);
|
|
13046
13298
|
if (stopIndex === undefined) {
|
|
13047
13299
|
throw new Error(`Stop index for ${stopId} not found in route ${this.serviceRouteId}`);
|
|
13048
13300
|
}
|
|
13049
13301
|
return stopIndex;
|
|
13050
13302
|
}
|
|
13303
|
+
/**
|
|
13304
|
+
* Retrieves the id of a stop at a given index in a route.
|
|
13305
|
+
* @param stopRouteIndex The route index of the stop.
|
|
13306
|
+
* @returns The id of the stop at the given index in the route.
|
|
13307
|
+
*/
|
|
13308
|
+
stopId(stopRouteIndex) {
|
|
13309
|
+
const stopId = this.stops[stopRouteIndex];
|
|
13310
|
+
if (stopId === undefined) {
|
|
13311
|
+
throw new Error(`StopId for stop at index ${stopRouteIndex} not found in route ${this.serviceRouteId}`);
|
|
13312
|
+
}
|
|
13313
|
+
return stopId;
|
|
13314
|
+
}
|
|
13051
13315
|
}
|
|
13052
13316
|
|
|
13053
13317
|
const isLittleEndian = (() => {
|
|
@@ -13118,10 +13382,15 @@ const bytesToUint16Array = (bytes) => {
|
|
|
13118
13382
|
const serializeStopsAdjacency = (stopsAdjacency) => {
|
|
13119
13383
|
return stopsAdjacency.map((value) => {
|
|
13120
13384
|
return {
|
|
13121
|
-
transfers: value.transfers
|
|
13122
|
-
|
|
13123
|
-
|
|
13385
|
+
transfers: value.transfers
|
|
13386
|
+
? value.transfers.map((transfer) => (Object.assign({ destination: transfer.destination, type: serializeTransferType(transfer.type) }, (transfer.minTransferTime !== undefined && {
|
|
13387
|
+
minTransferTime: transfer.minTransferTime.toSeconds(),
|
|
13388
|
+
}))))
|
|
13389
|
+
: [],
|
|
13124
13390
|
routes: value.routes,
|
|
13391
|
+
tripContinuations: value.tripContinuations
|
|
13392
|
+
? serializeTripContinuations(value.tripContinuations)
|
|
13393
|
+
: [],
|
|
13125
13394
|
};
|
|
13126
13395
|
});
|
|
13127
13396
|
};
|
|
@@ -13161,10 +13430,17 @@ const deserializeStopsAdjacency = (protoStopsAdjacency) => {
|
|
|
13161
13430
|
}));
|
|
13162
13431
|
transfers.push(newTransfer);
|
|
13163
13432
|
}
|
|
13164
|
-
|
|
13165
|
-
transfers: transfers,
|
|
13433
|
+
const stopAdjacency = {
|
|
13166
13434
|
routes: value.routes,
|
|
13167
|
-
}
|
|
13435
|
+
};
|
|
13436
|
+
if (transfers.length > 0) {
|
|
13437
|
+
stopAdjacency.transfers = transfers;
|
|
13438
|
+
}
|
|
13439
|
+
const deserializedTripContinuations = deserializeTripContinuations(value.tripContinuations);
|
|
13440
|
+
if (deserializedTripContinuations.size > 0) {
|
|
13441
|
+
stopAdjacency.tripContinuations = deserializedTripContinuations;
|
|
13442
|
+
}
|
|
13443
|
+
result.push(stopAdjacency);
|
|
13168
13444
|
}
|
|
13169
13445
|
return result;
|
|
13170
13446
|
};
|
|
@@ -13174,7 +13450,7 @@ const deserializeRoutesAdjacency = (protoRoutesAdjacency) => {
|
|
|
13174
13450
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13175
13451
|
const value = protoRoutesAdjacency[i];
|
|
13176
13452
|
const stops = bytesToUint32Array(value.stops);
|
|
13177
|
-
routesAdjacency.push(new Route(bytesToUint16Array(value.stopTimes), value.pickUpDropOffTypes, stops, value.serviceRouteId));
|
|
13453
|
+
routesAdjacency.push(new Route(i, bytesToUint16Array(value.stopTimes), value.pickUpDropOffTypes, stops, value.serviceRouteId));
|
|
13178
13454
|
}
|
|
13179
13455
|
return routesAdjacency;
|
|
13180
13456
|
};
|
|
@@ -13268,6 +13544,46 @@ const serializeRouteType = (type) => {
|
|
|
13268
13544
|
return RouteType.MONORAIL;
|
|
13269
13545
|
}
|
|
13270
13546
|
};
|
|
13547
|
+
const serializeTripContinuations = (tripContinuations) => {
|
|
13548
|
+
const result = [];
|
|
13549
|
+
for (const [key, value] of tripContinuations.entries()) {
|
|
13550
|
+
result.push({
|
|
13551
|
+
key: key,
|
|
13552
|
+
value: value.map((tripBoarding) => ({
|
|
13553
|
+
hopOnStop: tripBoarding.hopOnStop,
|
|
13554
|
+
routeId: tripBoarding.routeId,
|
|
13555
|
+
tripIndex: tripBoarding.tripIndex,
|
|
13556
|
+
})),
|
|
13557
|
+
});
|
|
13558
|
+
}
|
|
13559
|
+
return result;
|
|
13560
|
+
};
|
|
13561
|
+
const deserializeTripContinuations = (protoTripContinuations) => {
|
|
13562
|
+
const result = new Map();
|
|
13563
|
+
for (let i = 0; i < protoTripContinuations.length; i++) {
|
|
13564
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13565
|
+
const entry = protoTripContinuations[i];
|
|
13566
|
+
const tripBoardings = entry.value.map((protoTripBoarding) => ({
|
|
13567
|
+
hopOnStop: protoTripBoarding.hopOnStop,
|
|
13568
|
+
routeId: protoTripBoarding.routeId,
|
|
13569
|
+
tripIndex: protoTripBoarding.tripIndex,
|
|
13570
|
+
}));
|
|
13571
|
+
result.set(entry.key, tripBoardings);
|
|
13572
|
+
}
|
|
13573
|
+
return result;
|
|
13574
|
+
};
|
|
13575
|
+
|
|
13576
|
+
// const ROUTE_ID_BITS = 17;
|
|
13577
|
+
const TRIP_INDEX_BITS = 15;
|
|
13578
|
+
/**
|
|
13579
|
+
* Encodes a route ID and trip index into a single trip ID.
|
|
13580
|
+
* @param routeId - The route identifier, needs to fit on 17 bits
|
|
13581
|
+
* @param tripIndex - The index of the trip within the route, needs to fit on 15 bits
|
|
13582
|
+
* @returns The encoded trip ID
|
|
13583
|
+
*/
|
|
13584
|
+
const encode = (routeId, tripIndex) => {
|
|
13585
|
+
return (routeId << TRIP_INDEX_BITS) | tripIndex;
|
|
13586
|
+
};
|
|
13271
13587
|
|
|
13272
13588
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
13273
13589
|
const ALL_TRANSPORT_MODES = new Set([
|
|
@@ -13282,7 +13598,8 @@ const ALL_TRANSPORT_MODES = new Set([
|
|
|
13282
13598
|
'TROLLEYBUS',
|
|
13283
13599
|
'MONORAIL',
|
|
13284
13600
|
]);
|
|
13285
|
-
const
|
|
13601
|
+
const EMPTY_TRIP_CONTINUATIONS = [];
|
|
13602
|
+
const CURRENT_VERSION = '0.0.8';
|
|
13286
13603
|
/**
|
|
13287
13604
|
* The internal transit timetable format.
|
|
13288
13605
|
*/
|
|
@@ -13293,9 +13610,10 @@ class Timetable {
|
|
|
13293
13610
|
this.serviceRoutes = routes;
|
|
13294
13611
|
this.activeStops = new Set();
|
|
13295
13612
|
for (let i = 0; i < stopsAdjacency.length; i++) {
|
|
13296
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13297
13613
|
const stop = stopsAdjacency[i];
|
|
13298
|
-
if (stop.routes.length > 0 ||
|
|
13614
|
+
if (stop.routes.length > 0 ||
|
|
13615
|
+
(stop.transfers && stop.transfers.length > 0) ||
|
|
13616
|
+
(stop.tripContinuations && stop.tripContinuations.size > 0)) {
|
|
13299
13617
|
this.activeStops.add(i);
|
|
13300
13618
|
}
|
|
13301
13619
|
}
|
|
@@ -13358,8 +13676,27 @@ class Timetable {
|
|
|
13358
13676
|
* @returns An array of transfer options available at the stop.
|
|
13359
13677
|
*/
|
|
13360
13678
|
getTransfers(stopId) {
|
|
13361
|
-
|
|
13362
|
-
|
|
13679
|
+
const stopAdjacency = this.stopsAdjacency[stopId];
|
|
13680
|
+
if (!stopAdjacency) {
|
|
13681
|
+
throw new Error(`Stop ID ${stopId} not found`);
|
|
13682
|
+
}
|
|
13683
|
+
return stopAdjacency.transfers || [];
|
|
13684
|
+
}
|
|
13685
|
+
/**
|
|
13686
|
+
* Retrieves all trip continuation options available at the specified stop for a given trip.
|
|
13687
|
+
*
|
|
13688
|
+
* @param stopId - The ID of the stop to get trip continuations for.
|
|
13689
|
+
* @param tripIndex - The index of the trip to get continuations for.
|
|
13690
|
+
* @returns An array of trip continuation options available at the stop for the specified trip.
|
|
13691
|
+
*/
|
|
13692
|
+
getContinuousTrips(stopId, routeId, tripIndex) {
|
|
13693
|
+
var _a;
|
|
13694
|
+
const stopAdjacency = this.stopsAdjacency[stopId];
|
|
13695
|
+
if (!stopAdjacency) {
|
|
13696
|
+
throw new Error(`Stop ID ${stopId} not found`);
|
|
13697
|
+
}
|
|
13698
|
+
return (((_a = stopAdjacency.tripContinuations) === null || _a === void 0 ? void 0 : _a.get(encode(routeId, tripIndex))) ||
|
|
13699
|
+
EMPTY_TRIP_CONTINUATIONS);
|
|
13363
13700
|
}
|
|
13364
13701
|
/**
|
|
13365
13702
|
* Retrieves the service route associated with the given route.
|
|
@@ -15645,6 +15982,7 @@ const parseGtfsLocationType = (gtfsLocationType) => {
|
|
|
15645
15982
|
const parseTransfers = (transfersStream, stopsMap) => __awaiter(void 0, void 0, void 0, function* () {
|
|
15646
15983
|
var _a, e_1, _b, _c;
|
|
15647
15984
|
const transfers = new Map();
|
|
15985
|
+
const tripContinuations = new Map();
|
|
15648
15986
|
try {
|
|
15649
15987
|
for (var _d = true, _e = __asyncValues(parseCsv(transfersStream, [
|
|
15650
15988
|
'transfer_type',
|
|
@@ -15658,25 +15996,48 @@ const parseTransfers = (transfersStream, stopsMap) => __awaiter(void 0, void 0,
|
|
|
15658
15996
|
transferEntry.transfer_type === 5) {
|
|
15659
15997
|
continue;
|
|
15660
15998
|
}
|
|
15661
|
-
if (transferEntry.from_trip_id && transferEntry.to_trip_id) {
|
|
15662
|
-
console.warn(`Unsupported transfer between trips ${transferEntry.from_trip_id} and ${transferEntry.to_trip_id}.`);
|
|
15663
|
-
continue;
|
|
15664
|
-
}
|
|
15665
|
-
if (transferEntry.from_route_id && transferEntry.to_route_id) {
|
|
15666
|
-
console.warn(`Unsupported transfer between routes ${transferEntry.from_route_id} and ${transferEntry.to_route_id}.`);
|
|
15667
|
-
continue;
|
|
15668
|
-
}
|
|
15669
15999
|
if (!transferEntry.from_stop_id || !transferEntry.to_stop_id) {
|
|
15670
16000
|
console.warn(`Missing transfer origin or destination stop.`);
|
|
15671
16001
|
continue;
|
|
15672
16002
|
}
|
|
15673
|
-
if (transferEntry.transfer_type === 2 && !transferEntry.min_transfer_time) {
|
|
15674
|
-
console.info(`Missing minimum transfer time between ${transferEntry.from_stop_id} and ${transferEntry.to_stop_id}.`);
|
|
15675
|
-
}
|
|
15676
16003
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
15677
16004
|
const fromStop = stopsMap.get(transferEntry.from_stop_id);
|
|
15678
16005
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
15679
16006
|
const toStop = stopsMap.get(transferEntry.to_stop_id);
|
|
16007
|
+
if (transferEntry.transfer_type === 4) {
|
|
16008
|
+
if (transferEntry.from_trip_id === undefined ||
|
|
16009
|
+
transferEntry.from_trip_id === '' ||
|
|
16010
|
+
transferEntry.to_trip_id === undefined ||
|
|
16011
|
+
transferEntry.to_trip_id === '') {
|
|
16012
|
+
console.warn(`Unsupported in-seat transfer, missing from_trip_id and/or to_trip_id.`);
|
|
16013
|
+
continue;
|
|
16014
|
+
}
|
|
16015
|
+
const tripBoardingEntry = {
|
|
16016
|
+
fromTrip: transferEntry.from_trip_id,
|
|
16017
|
+
toTrip: transferEntry.to_trip_id,
|
|
16018
|
+
hopOnStop: toStop.id,
|
|
16019
|
+
};
|
|
16020
|
+
const existingBoardings = tripContinuations.get(fromStop.id);
|
|
16021
|
+
if (existingBoardings) {
|
|
16022
|
+
existingBoardings.push(tripBoardingEntry);
|
|
16023
|
+
}
|
|
16024
|
+
else {
|
|
16025
|
+
tripContinuations.set(fromStop.id, [tripBoardingEntry]);
|
|
16026
|
+
}
|
|
16027
|
+
continue;
|
|
16028
|
+
}
|
|
16029
|
+
if (transferEntry.from_trip_id && transferEntry.to_trip_id) {
|
|
16030
|
+
console.warn(`Unsupported transfer of type ${transferEntry.transfer_type} between trips ${transferEntry.from_trip_id} and ${transferEntry.to_trip_id}.`);
|
|
16031
|
+
continue;
|
|
16032
|
+
}
|
|
16033
|
+
if (transferEntry.from_route_id && transferEntry.to_route_id) {
|
|
16034
|
+
console.warn(`Unsupported transfer of type ${transferEntry.transfer_type} between routes ${transferEntry.from_route_id} and ${transferEntry.to_route_id}.`);
|
|
16035
|
+
continue;
|
|
16036
|
+
}
|
|
16037
|
+
if (transferEntry.transfer_type === 2 &&
|
|
16038
|
+
transferEntry.min_transfer_time === undefined) {
|
|
16039
|
+
console.info(`Missing minimum transfer time between ${transferEntry.from_stop_id} and ${transferEntry.to_stop_id}.`);
|
|
16040
|
+
}
|
|
15680
16041
|
const transfer = Object.assign({ destination: toStop.id, type: parseGtfsTransferType(transferEntry.transfer_type) }, (transferEntry.min_transfer_time && {
|
|
15681
16042
|
minTransferTime: Duration.fromSeconds(transferEntry.min_transfer_time),
|
|
15682
16043
|
}));
|
|
@@ -15692,7 +16053,10 @@ const parseTransfers = (transfersStream, stopsMap) => __awaiter(void 0, void 0,
|
|
|
15692
16053
|
}
|
|
15693
16054
|
finally { if (e_1) throw e_1.error; }
|
|
15694
16055
|
}
|
|
15695
|
-
return
|
|
16056
|
+
return {
|
|
16057
|
+
transfers,
|
|
16058
|
+
tripContinuations,
|
|
16059
|
+
};
|
|
15696
16060
|
});
|
|
15697
16061
|
const parseGtfsTransferType = (gtfsTransferType) => {
|
|
15698
16062
|
switch (gtfsTransferType) {
|
|
@@ -15755,11 +16119,13 @@ const finalizeRouteFromBuilder = (builder) => {
|
|
|
15755
16119
|
const stopTimesArray = new Uint16Array(stopsCount * tripsCount * 2);
|
|
15756
16120
|
const allPickUpTypes = [];
|
|
15757
16121
|
const allDropOffTypes = [];
|
|
16122
|
+
const gtfsTripIds = [];
|
|
15758
16123
|
for (let tripIndex = 0; tripIndex < tripsCount; tripIndex++) {
|
|
15759
16124
|
const trip = builder.trips[tripIndex];
|
|
15760
16125
|
if (!trip) {
|
|
15761
16126
|
throw new Error(`Missing trip data at index ${tripIndex}`);
|
|
15762
16127
|
}
|
|
16128
|
+
gtfsTripIds.push(trip.gtfsTripId);
|
|
15763
16129
|
const baseIndex = tripIndex * stopsCount * 2;
|
|
15764
16130
|
for (let stopIndex = 0; stopIndex < stopsCount; stopIndex++) {
|
|
15765
16131
|
const timeIndex = baseIndex + stopIndex * 2;
|
|
@@ -15781,12 +16147,15 @@ const finalizeRouteFromBuilder = (builder) => {
|
|
|
15781
16147
|
}
|
|
15782
16148
|
// Use 2-bit encoding for pickup/drop-off types
|
|
15783
16149
|
const pickUpDropOffTypesArray = encodePickUpDropOffTypes(allPickUpTypes, allDropOffTypes);
|
|
15784
|
-
return
|
|
15785
|
-
|
|
15786
|
-
|
|
15787
|
-
|
|
15788
|
-
|
|
15789
|
-
|
|
16150
|
+
return [
|
|
16151
|
+
{
|
|
16152
|
+
serviceRouteId: builder.serviceRouteId,
|
|
16153
|
+
stops: stopsArray,
|
|
16154
|
+
stopTimes: stopTimesArray,
|
|
16155
|
+
pickUpDropOffTypes: pickUpDropOffTypesArray,
|
|
16156
|
+
},
|
|
16157
|
+
gtfsTripIds,
|
|
16158
|
+
];
|
|
15790
16159
|
};
|
|
15791
16160
|
/**
|
|
15792
16161
|
* Parses the trips.txt file from a GTFS feed
|
|
@@ -15825,11 +16194,12 @@ const parseTrips = (tripsStream, serviceIds, validGtfsRoutes) => __awaiter(void
|
|
|
15825
16194
|
}
|
|
15826
16195
|
return trips;
|
|
15827
16196
|
});
|
|
15828
|
-
const buildStopsAdjacencyStructure = (serviceRoutes, routes, transfersMap, nbStops, activeStops) => {
|
|
15829
|
-
// TODO somehow works when it's a map
|
|
16197
|
+
const buildStopsAdjacencyStructure = (tripsMapping, serviceRoutes, routes, transfersMap, tripContinuationsMap, nbStops, activeStops) => {
|
|
15830
16198
|
const stopsAdjacency = new Array(nbStops);
|
|
15831
16199
|
for (let i = 0; i < nbStops; i++) {
|
|
15832
|
-
stopsAdjacency[i] = {
|
|
16200
|
+
stopsAdjacency[i] = {
|
|
16201
|
+
routes: [],
|
|
16202
|
+
};
|
|
15833
16203
|
}
|
|
15834
16204
|
for (let index = 0; index < routes.length; index++) {
|
|
15835
16205
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
@@ -15854,12 +16224,50 @@ const buildStopsAdjacencyStructure = (serviceRoutes, routes, transfersMap, nbSto
|
|
|
15854
16224
|
const transfer = transfers[i];
|
|
15855
16225
|
if (activeStops.has(stop) || activeStops.has(transfer.destination)) {
|
|
15856
16226
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
15857
|
-
stopsAdjacency[stop]
|
|
16227
|
+
const stopAdj = stopsAdjacency[stop];
|
|
16228
|
+
if (!stopAdj.transfers) {
|
|
16229
|
+
stopAdj.transfers = [];
|
|
16230
|
+
}
|
|
16231
|
+
stopAdj.transfers.push(transfer);
|
|
15858
16232
|
activeStops.add(transfer.destination);
|
|
15859
16233
|
activeStops.add(stop);
|
|
15860
16234
|
}
|
|
15861
16235
|
}
|
|
15862
16236
|
}
|
|
16237
|
+
for (const [stop, tripContinuations] of tripContinuationsMap) {
|
|
16238
|
+
for (let i = 0; i < tripContinuations.length; i++) {
|
|
16239
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
16240
|
+
const tripContinuation = tripContinuations[i];
|
|
16241
|
+
if (activeStops.has(stop) ||
|
|
16242
|
+
activeStops.has(tripContinuation.hopOnStop)) {
|
|
16243
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
16244
|
+
const stopAdj = stopsAdjacency[stop];
|
|
16245
|
+
if (!stopAdj.tripContinuations) {
|
|
16246
|
+
stopAdj.tripContinuations = new Map();
|
|
16247
|
+
}
|
|
16248
|
+
const originTrip = tripsMapping.get(tripContinuation.fromTrip);
|
|
16249
|
+
const destinationTrip = tripsMapping.get(tripContinuation.toTrip);
|
|
16250
|
+
if (destinationTrip === undefined || originTrip === undefined) {
|
|
16251
|
+
continue;
|
|
16252
|
+
}
|
|
16253
|
+
const tripBoarding = {
|
|
16254
|
+
hopOnStop: tripContinuation.hopOnStop,
|
|
16255
|
+
routeId: destinationTrip.routeId,
|
|
16256
|
+
tripIndex: destinationTrip.tripRouteIndex,
|
|
16257
|
+
};
|
|
16258
|
+
const tripId = encode(originTrip.routeId, originTrip.tripRouteIndex);
|
|
16259
|
+
const existingContinuations = stopAdj.tripContinuations.get(tripId);
|
|
16260
|
+
if (existingContinuations) {
|
|
16261
|
+
existingContinuations.push(tripBoarding);
|
|
16262
|
+
}
|
|
16263
|
+
else {
|
|
16264
|
+
stopAdj.tripContinuations.set(tripId, [tripBoarding]);
|
|
16265
|
+
}
|
|
16266
|
+
activeStops.add(tripContinuation.hopOnStop);
|
|
16267
|
+
activeStops.add(stop);
|
|
16268
|
+
}
|
|
16269
|
+
}
|
|
16270
|
+
}
|
|
15863
16271
|
return stopsAdjacency;
|
|
15864
16272
|
};
|
|
15865
16273
|
/**
|
|
@@ -15918,6 +16326,7 @@ const parseStopTimes = (stopTimesStream, stopsMap, activeTripIds, activeStopIds)
|
|
|
15918
16326
|
}
|
|
15919
16327
|
routeBuilder.trips.push({
|
|
15920
16328
|
firstDeparture,
|
|
16329
|
+
gtfsTripId: currentTripId,
|
|
15921
16330
|
arrivalTimes: arrivalTimes,
|
|
15922
16331
|
departureTimes: departureTimes,
|
|
15923
16332
|
pickUpTypes: pickUpTypes,
|
|
@@ -15955,6 +16364,9 @@ const parseStopTimes = (stopTimesStream, stopsMap, activeTripIds, activeStopIds)
|
|
|
15955
16364
|
continue;
|
|
15956
16365
|
}
|
|
15957
16366
|
if (line.pickup_type === '1' && line.drop_off_type === '1') {
|
|
16367
|
+
// Warning: could potentially lead to issues if there is an in-seat transfer
|
|
16368
|
+
// at this stop - it can be not boardable nor alightable but still useful for an in-seat transfer.
|
|
16369
|
+
// This doesn't seem to happen in practice for now so keeping this condition to save memory.
|
|
15958
16370
|
continue;
|
|
15959
16371
|
}
|
|
15960
16372
|
if (currentTripId && line.trip_id !== currentTripId && stops.length > 0) {
|
|
@@ -15991,11 +16403,19 @@ const parseStopTimes = (stopTimesStream, stopsMap, activeTripIds, activeStopIds)
|
|
|
15991
16403
|
addTrip(currentTripId);
|
|
15992
16404
|
}
|
|
15993
16405
|
const routesAdjacency = [];
|
|
16406
|
+
const tripsMapping = new Map();
|
|
15994
16407
|
for (const [, routeBuilder] of routeBuilders) {
|
|
15995
|
-
const routeData = finalizeRouteFromBuilder(routeBuilder);
|
|
15996
|
-
|
|
16408
|
+
const [routeData, gtfsTripIds] = finalizeRouteFromBuilder(routeBuilder);
|
|
16409
|
+
const routeId = routesAdjacency.length;
|
|
16410
|
+
routesAdjacency.push(new Route(routeId, routeData.stopTimes, routeData.pickUpDropOffTypes, routeData.stops, routeData.serviceRouteId));
|
|
16411
|
+
gtfsTripIds.forEach((tripId, index) => {
|
|
16412
|
+
tripsMapping.set(tripId, {
|
|
16413
|
+
routeId,
|
|
16414
|
+
tripRouteIndex: index,
|
|
16415
|
+
});
|
|
16416
|
+
});
|
|
15997
16417
|
}
|
|
15998
|
-
return { routes: routesAdjacency, serviceRoutesMap };
|
|
16418
|
+
return { routes: routesAdjacency, serviceRoutesMap, tripsMapping };
|
|
15999
16419
|
});
|
|
16000
16420
|
const parsePickupDropOffType = (gtfsType) => {
|
|
16001
16421
|
switch (gtfsType) {
|
|
@@ -16074,24 +16494,27 @@ class GtfsParser {
|
|
|
16074
16494
|
const tripsEnd = performance.now();
|
|
16075
16495
|
log.info(`${trips.size} valid trips. (${(tripsEnd - tripsStart).toFixed(2)}ms)`);
|
|
16076
16496
|
let transfers = new Map();
|
|
16497
|
+
let tripContinuations = new Map();
|
|
16077
16498
|
if (entries[TRANSFERS_FILE]) {
|
|
16078
16499
|
log.info(`Parsing ${TRANSFERS_FILE}`);
|
|
16079
16500
|
const transfersStart = performance.now();
|
|
16080
16501
|
const transfersStream = yield zip.stream(TRANSFERS_FILE);
|
|
16081
|
-
transfers = yield parseTransfers(transfersStream, parsedStops);
|
|
16502
|
+
const { transfers: parsedTransfers, tripContinuations: parsedTripContinuations, } = yield parseTransfers(transfersStream, parsedStops);
|
|
16503
|
+
transfers = parsedTransfers;
|
|
16504
|
+
tripContinuations = parsedTripContinuations;
|
|
16082
16505
|
const transfersEnd = performance.now();
|
|
16083
|
-
log.info(`${transfers.size} valid transfers. (${(transfersEnd - transfersStart).toFixed(2)}ms)`);
|
|
16506
|
+
log.info(`${transfers.size} valid transfers and ${tripContinuations.size} trip continuations. (${(transfersEnd - transfersStart).toFixed(2)}ms)`);
|
|
16084
16507
|
}
|
|
16085
16508
|
log.info(`Parsing ${STOP_TIMES_FILE}`);
|
|
16086
16509
|
const stopTimesStart = performance.now();
|
|
16087
16510
|
const stopTimesStream = yield zip.stream(STOP_TIMES_FILE);
|
|
16088
|
-
const { routes, serviceRoutesMap } = yield parseStopTimes(stopTimesStream, parsedStops, trips, activeStopIds);
|
|
16511
|
+
const { routes, serviceRoutesMap, tripsMapping } = yield parseStopTimes(stopTimesStream, parsedStops, trips, activeStopIds);
|
|
16089
16512
|
const serviceRoutes = indexRoutes(validGtfsRoutes, serviceRoutesMap);
|
|
16090
16513
|
const stopTimesEnd = performance.now();
|
|
16091
16514
|
log.info(`${routes.length} valid unique routes. (${(stopTimesEnd - stopTimesStart).toFixed(2)}ms)`);
|
|
16092
16515
|
log.info('Building stops adjacency structure');
|
|
16093
16516
|
const stopsAdjacencyStart = performance.now();
|
|
16094
|
-
const stopsAdjacency = buildStopsAdjacencyStructure(serviceRoutes, routes, transfers, parsedStops.size, activeStopIds);
|
|
16517
|
+
const stopsAdjacency = buildStopsAdjacencyStructure(tripsMapping, serviceRoutes, routes, transfers, tripContinuations, parsedStops.size, activeStopIds);
|
|
16095
16518
|
const stopsAdjacencyEnd = performance.now();
|
|
16096
16519
|
log.info(`${stopsAdjacency.length} valid stops in the structure. (${(stopsAdjacencyEnd - stopsAdjacencyStart).toFixed(2)}ms)`);
|
|
16097
16520
|
yield zip.close();
|