minotor 2.0.1 → 3.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/dist/cli.mjs +89 -47
- package/dist/cli.mjs.map +1 -1
- package/dist/parser.cjs.js +82 -40
- package/dist/parser.cjs.js.map +1 -1
- package/dist/parser.esm.js +82 -40
- 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.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/timetable/time.d.ts +18 -9
- package/dist/timetable/timetable.d.ts +3 -3
- package/package.json +1 -1
- package/src/gtfs/__tests__/parser.test.ts +4 -4
- package/src/gtfs/__tests__/time.test.ts +2 -2
- package/src/gtfs/__tests__/trips.test.ts +36 -36
- package/src/gtfs/trips.ts +4 -4
- package/src/routing/__tests__/route.test.ts +4 -4
- package/src/routing/__tests__/router.test.ts +60 -60
- package/src/routing/result.ts +2 -2
- package/src/routing/router.ts +5 -5
- package/src/timetable/__tests__/io.test.ts +12 -12
- package/src/timetable/__tests__/timetable.test.ts +16 -16
- package/src/timetable/io.ts +46 -2
- package/src/timetable/time.ts +51 -30
- package/src/timetable/timetable.ts +7 -7
package/dist/parser.esm.js
CHANGED
|
@@ -12990,6 +12990,35 @@ function bytesToUint32Array(bytes) {
|
|
|
12990
12990
|
}
|
|
12991
12991
|
return result;
|
|
12992
12992
|
}
|
|
12993
|
+
function uint16ArrayToBytes(array) {
|
|
12994
|
+
if (isLittleEndian === STANDARD_ENDIANNESS) {
|
|
12995
|
+
return new Uint8Array(array.buffer, array.byteOffset, array.byteLength);
|
|
12996
|
+
}
|
|
12997
|
+
// If endianness doesn't match, we need to swap byte order
|
|
12998
|
+
const result = new Uint8Array(array.length * 2);
|
|
12999
|
+
const view = new DataView(result.buffer);
|
|
13000
|
+
for (let i = 0; i < array.length; i++) {
|
|
13001
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
13002
|
+
view.setUint16(i * 2, array[i], STANDARD_ENDIANNESS);
|
|
13003
|
+
}
|
|
13004
|
+
return result;
|
|
13005
|
+
}
|
|
13006
|
+
function bytesToUint16Array(bytes) {
|
|
13007
|
+
if (bytes.byteLength % 2 !== 0) {
|
|
13008
|
+
throw new Error('Byte array length must be a multiple of 2 to convert to Uint16Array');
|
|
13009
|
+
}
|
|
13010
|
+
// If system endianness matches our standard, we can create a view directly
|
|
13011
|
+
if (isLittleEndian === STANDARD_ENDIANNESS) {
|
|
13012
|
+
return new Uint16Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / 2);
|
|
13013
|
+
}
|
|
13014
|
+
// If endianness doesn't match, we need to swap byte order
|
|
13015
|
+
const result = new Uint16Array(bytes.byteLength / 2);
|
|
13016
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
13017
|
+
for (let i = 0; i < result.length; i++) {
|
|
13018
|
+
result[i] = view.getUint16(i * 2, STANDARD_ENDIANNESS);
|
|
13019
|
+
}
|
|
13020
|
+
return result;
|
|
13021
|
+
}
|
|
12993
13022
|
const serializeStopsAdjacency = (stopsAdjacency) => {
|
|
12994
13023
|
const protoStopsAdjacency = {
|
|
12995
13024
|
stops: {},
|
|
@@ -13010,7 +13039,7 @@ const serializeRoutesAdjacency = (routesAdjacency) => {
|
|
|
13010
13039
|
};
|
|
13011
13040
|
routesAdjacency.forEach((value, key) => {
|
|
13012
13041
|
protoRoutesAdjacency.routes[key] = {
|
|
13013
|
-
stopTimes:
|
|
13042
|
+
stopTimes: uint16ArrayToBytes(value.stopTimes),
|
|
13014
13043
|
pickUpDropOffTypes: value.pickUpDropOffTypes,
|
|
13015
13044
|
stops: uint32ArrayToBytes(value.stops),
|
|
13016
13045
|
serviceRouteId: value.serviceRouteId,
|
|
@@ -13053,7 +13082,7 @@ const deserializeRoutesAdjacency = (protoRoutesAdjacency) => {
|
|
|
13053
13082
|
indices.set(stops[i], i);
|
|
13054
13083
|
}
|
|
13055
13084
|
routesAdjacency.set(key, {
|
|
13056
|
-
stopTimes:
|
|
13085
|
+
stopTimes: bytesToUint16Array(value.stopTimes),
|
|
13057
13086
|
pickUpDropOffTypes: value.pickUpDropOffTypes,
|
|
13058
13087
|
stops: stops,
|
|
13059
13088
|
stopIndices: indices,
|
|
@@ -13151,7 +13180,7 @@ const serializeRouteType = (type) => {
|
|
|
13151
13180
|
};
|
|
13152
13181
|
|
|
13153
13182
|
/**
|
|
13154
|
-
* A class representing a time
|
|
13183
|
+
* A class representing a time as minutes since midnight.
|
|
13155
13184
|
*/
|
|
13156
13185
|
class Time {
|
|
13157
13186
|
/**
|
|
@@ -13166,25 +13195,26 @@ class Time {
|
|
|
13166
13195
|
/**
|
|
13167
13196
|
* Gets the midnight time as a Time instance.
|
|
13168
13197
|
*
|
|
13169
|
-
* @returns A Time instance representing midnight
|
|
13198
|
+
* @returns A Time instance representing midnight.
|
|
13170
13199
|
*/
|
|
13171
13200
|
static origin() {
|
|
13172
13201
|
return new Time(0);
|
|
13173
13202
|
}
|
|
13174
|
-
constructor(
|
|
13175
|
-
this.
|
|
13203
|
+
constructor(minutes) {
|
|
13204
|
+
this.minutesSinceMidnight = minutes;
|
|
13176
13205
|
}
|
|
13177
13206
|
/**
|
|
13178
|
-
* Creates a Time instance from the number of
|
|
13207
|
+
* Creates a Time instance from the number of minutes since midnight.
|
|
13179
13208
|
*
|
|
13180
|
-
* @param
|
|
13209
|
+
* @param minutes - The number of minutes since midnight.
|
|
13181
13210
|
* @returns A Time instance representing the specified time.
|
|
13182
13211
|
*/
|
|
13183
|
-
static
|
|
13184
|
-
return new Time(
|
|
13212
|
+
static fromMinutes(minutes) {
|
|
13213
|
+
return new Time(minutes);
|
|
13185
13214
|
}
|
|
13186
13215
|
/**
|
|
13187
13216
|
* Creates a Time instance from hours, minutes, and seconds.
|
|
13217
|
+
* Rounds to the closest minute as times are represented in minutes from midnight.
|
|
13188
13218
|
*
|
|
13189
13219
|
* @param hours - The hours component of the time.
|
|
13190
13220
|
* @param minutes - The minutes component of the time.
|
|
@@ -13199,7 +13229,22 @@ class Time {
|
|
|
13199
13229
|
seconds >= 60) {
|
|
13200
13230
|
throw new Error('Invalid time. Ensure hours, minutes, and seconds are valid values.');
|
|
13201
13231
|
}
|
|
13202
|
-
|
|
13232
|
+
const totalSeconds = seconds + 60 * minutes + 3600 * hours;
|
|
13233
|
+
const roundedMinutes = Math.round(totalSeconds / 60);
|
|
13234
|
+
return new Time(roundedMinutes);
|
|
13235
|
+
}
|
|
13236
|
+
/**
|
|
13237
|
+
* Creates a Time instance from hours, minutes.
|
|
13238
|
+
*
|
|
13239
|
+
* @param hours - The hours component of the time.
|
|
13240
|
+
* @param minutes - The minutes component of the time.
|
|
13241
|
+
* @returns A Time instance representing the specified time.
|
|
13242
|
+
*/
|
|
13243
|
+
static fromHM(hours, minutes) {
|
|
13244
|
+
if (hours < 0 || minutes < 0 || minutes >= 60) {
|
|
13245
|
+
throw new Error('Invalid time. Ensure hours and minutes are valid values.');
|
|
13246
|
+
}
|
|
13247
|
+
return new Time(minutes + hours * 60);
|
|
13203
13248
|
}
|
|
13204
13249
|
/**
|
|
13205
13250
|
* Parses a JavaScript Date object and creates a Time instance.
|
|
@@ -13211,7 +13256,7 @@ class Time {
|
|
|
13211
13256
|
const hours = date.getHours();
|
|
13212
13257
|
const minutes = date.getMinutes();
|
|
13213
13258
|
const seconds = date.getSeconds();
|
|
13214
|
-
return
|
|
13259
|
+
return Time.fromHMS(hours, minutes, seconds);
|
|
13215
13260
|
}
|
|
13216
13261
|
/**
|
|
13217
13262
|
* Parses a time string in the format "HH:MM:SS" or "HH:MM" and creates a Time instance.
|
|
@@ -13231,7 +13276,7 @@ class Time {
|
|
|
13231
13276
|
const hours = parseInt(hoursStr, 10);
|
|
13232
13277
|
const minutes = parseInt(minutesStr, 10);
|
|
13233
13278
|
const seconds = secondsStr !== undefined ? parseInt(secondsStr, 10) : 0;
|
|
13234
|
-
return
|
|
13279
|
+
return Time.fromHMS(hours, minutes, seconds);
|
|
13235
13280
|
}
|
|
13236
13281
|
/**
|
|
13237
13282
|
* Converts the Time instance to a string in "HH:MM:SS" format.
|
|
@@ -13239,20 +13284,17 @@ class Time {
|
|
|
13239
13284
|
* @returns A string representing the time.
|
|
13240
13285
|
*/
|
|
13241
13286
|
toString() {
|
|
13242
|
-
const hours = Math.floor(this.
|
|
13243
|
-
const minutes = Math.floor(
|
|
13244
|
-
|
|
13245
|
-
return `${hours.toString().padStart(2, '0')}:${minutes
|
|
13246
|
-
.toString()
|
|
13247
|
-
.padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
|
|
13287
|
+
const hours = Math.floor(this.minutesSinceMidnight / 60);
|
|
13288
|
+
const minutes = Math.floor(this.minutesSinceMidnight % 60);
|
|
13289
|
+
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
|
|
13248
13290
|
}
|
|
13249
13291
|
/**
|
|
13250
|
-
*
|
|
13292
|
+
* Converts the Time instance to the total number of minutes since midnight, rounded to the closest minute.
|
|
13251
13293
|
*
|
|
13252
|
-
* @returns The time in
|
|
13294
|
+
* @returns The time in minutes since midnight.
|
|
13253
13295
|
*/
|
|
13254
|
-
|
|
13255
|
-
return this.
|
|
13296
|
+
toMinutes() {
|
|
13297
|
+
return this.minutesSinceMidnight;
|
|
13256
13298
|
}
|
|
13257
13299
|
/**
|
|
13258
13300
|
* Adds a Duration to the current Time instance and returns a new Time instance.
|
|
@@ -13261,8 +13303,8 @@ class Time {
|
|
|
13261
13303
|
* @returns A new Time instance with the added duration.
|
|
13262
13304
|
*/
|
|
13263
13305
|
plus(duration) {
|
|
13264
|
-
const totalSeconds = this.
|
|
13265
|
-
return new Time(totalSeconds);
|
|
13306
|
+
const totalSeconds = this.minutesSinceMidnight * 60 + duration.toSeconds();
|
|
13307
|
+
return new Time(Math.round(totalSeconds / 60));
|
|
13266
13308
|
}
|
|
13267
13309
|
/**
|
|
13268
13310
|
* Subtracts a Duration from the current Time instance and returns a new Time instance.
|
|
@@ -13271,11 +13313,11 @@ class Time {
|
|
|
13271
13313
|
* @returns A new Time instance with the subtracted duration.
|
|
13272
13314
|
*/
|
|
13273
13315
|
minus(duration) {
|
|
13274
|
-
let totalSeconds = this.
|
|
13316
|
+
let totalSeconds = this.minutesSinceMidnight * 60 - duration.toSeconds();
|
|
13275
13317
|
if (totalSeconds < 0) {
|
|
13276
13318
|
totalSeconds += 24 * 3600; // Adjust for negative time to loop back to previous day
|
|
13277
13319
|
}
|
|
13278
|
-
return new Time(totalSeconds);
|
|
13320
|
+
return new Time(Math.round(totalSeconds / 60));
|
|
13279
13321
|
}
|
|
13280
13322
|
/**
|
|
13281
13323
|
* Subtracts another Time instance from the current Time instance and returns the Duration.
|
|
@@ -13284,8 +13326,8 @@ class Time {
|
|
|
13284
13326
|
* @returns A Duration instance representing the time difference.
|
|
13285
13327
|
*/
|
|
13286
13328
|
diff(otherTime) {
|
|
13287
|
-
const
|
|
13288
|
-
return Duration.fromSeconds(Math.abs(
|
|
13329
|
+
const totalMinutes = this.minutesSinceMidnight - otherTime.toMinutes();
|
|
13330
|
+
return Duration.fromSeconds(Math.abs(totalMinutes * 60));
|
|
13289
13331
|
}
|
|
13290
13332
|
/**
|
|
13291
13333
|
* Computes the maximum Time instance among the provided Time instances.
|
|
@@ -13298,7 +13340,7 @@ class Time {
|
|
|
13298
13340
|
throw new Error('At least one Time instance is required.');
|
|
13299
13341
|
}
|
|
13300
13342
|
return times.reduce((maxTime, currentTime) => {
|
|
13301
|
-
return currentTime.
|
|
13343
|
+
return currentTime.toMinutes() > maxTime.toMinutes()
|
|
13302
13344
|
? currentTime
|
|
13303
13345
|
: maxTime;
|
|
13304
13346
|
});
|
|
@@ -13314,7 +13356,7 @@ class Time {
|
|
|
13314
13356
|
throw new Error('At least one Time instance is required.');
|
|
13315
13357
|
}
|
|
13316
13358
|
return times.reduce((minTime, currentTime) => {
|
|
13317
|
-
return currentTime.
|
|
13359
|
+
return currentTime.toMinutes() < minTime.toMinutes()
|
|
13318
13360
|
? currentTime
|
|
13319
13361
|
: minTime;
|
|
13320
13362
|
});
|
|
@@ -13337,7 +13379,7 @@ const ALL_TRANSPORT_MODES = [
|
|
|
13337
13379
|
'TROLLEYBUS',
|
|
13338
13380
|
'MONORAIL',
|
|
13339
13381
|
];
|
|
13340
|
-
const CURRENT_VERSION = '0.0.
|
|
13382
|
+
const CURRENT_VERSION = '0.0.3';
|
|
13341
13383
|
/**
|
|
13342
13384
|
* The internal transit timetable format
|
|
13343
13385
|
* reuses some GTFS concepts for the sake of simplicity for now.
|
|
@@ -13459,7 +13501,7 @@ class Timetable {
|
|
|
13459
13501
|
const stopTimeIndex = tripIndex * stopsNumber + stopIndex;
|
|
13460
13502
|
const departure = route.stopTimes[stopTimeIndex * 2 + 1];
|
|
13461
13503
|
const pickUpType = route.pickUpDropOffTypes[stopTimeIndex * 2];
|
|
13462
|
-
if (departure >= after.
|
|
13504
|
+
if (departure >= after.toMinutes() && pickUpType !== NOT_AVAILABLE) {
|
|
13463
13505
|
return tripIndex;
|
|
13464
13506
|
}
|
|
13465
13507
|
}
|
|
@@ -13473,14 +13515,14 @@ class Timetable {
|
|
|
13473
13515
|
const stopTimeIndex = tripIndex * stopsNumber + stopIndex;
|
|
13474
13516
|
const departure = route.stopTimes[stopTimeIndex * 2 + 1];
|
|
13475
13517
|
const pickUpType = route.pickUpDropOffTypes[stopTimeIndex * 2];
|
|
13476
|
-
if (departure < after.
|
|
13518
|
+
if (departure < after.toMinutes()) {
|
|
13477
13519
|
break;
|
|
13478
13520
|
}
|
|
13479
13521
|
if (pickUpType !== NOT_AVAILABLE &&
|
|
13480
13522
|
(earliestDeparture === undefined ||
|
|
13481
|
-
departure < earliestDeparture.
|
|
13523
|
+
departure < earliestDeparture.toMinutes())) {
|
|
13482
13524
|
earliestTripIndex = tripIndex;
|
|
13483
|
-
earliestDeparture = Time.
|
|
13525
|
+
earliestDeparture = Time.fromMinutes(departure);
|
|
13484
13526
|
}
|
|
13485
13527
|
}
|
|
13486
13528
|
return earliestTripIndex;
|
|
@@ -15845,7 +15887,7 @@ const parseStopTimes = (stopTimesStream, stopsMap, validTripIds, validStopIds) =
|
|
|
15845
15887
|
if (!route) {
|
|
15846
15888
|
const stopsCount = stops.length;
|
|
15847
15889
|
const stopsArray = new Uint32Array(stops);
|
|
15848
|
-
const stopTimesArray = new
|
|
15890
|
+
const stopTimesArray = new Uint16Array(stopsCount * 2);
|
|
15849
15891
|
for (let i = 0; i < stopsCount; i++) {
|
|
15850
15892
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
15851
15893
|
stopTimesArray[i * 2] = arrivalTimes[i];
|
|
@@ -15891,7 +15933,7 @@ const parseStopTimes = (stopTimesStream, stopsMap, validTripIds, validStopIds) =
|
|
|
15891
15933
|
}
|
|
15892
15934
|
// insert data for the new trip at the right place
|
|
15893
15935
|
const newStopTimesLength = route.stopTimes.length + stopsCount * 2;
|
|
15894
|
-
const newStopTimes = new
|
|
15936
|
+
const newStopTimes = new Uint16Array(newStopTimesLength);
|
|
15895
15937
|
const newPickUpDropOffTypes = new Uint8Array(newStopTimesLength);
|
|
15896
15938
|
newStopTimes.set(route.stopTimes.slice(0, insertPosition * 2), 0);
|
|
15897
15939
|
newPickUpDropOffTypes.set(route.pickUpDropOffTypes.slice(0, insertPosition * 2), 0);
|
|
@@ -15952,9 +15994,9 @@ const parseStopTimes = (stopTimesStream, stopsMap, validTripIds, validStopIds) =
|
|
|
15952
15994
|
const departure = (_d = line.departure_time) !== null && _d !== void 0 ? _d : line.arrival_time;
|
|
15953
15995
|
const arrival = (_e = line.arrival_time) !== null && _e !== void 0 ? _e : line.departure_time;
|
|
15954
15996
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
15955
|
-
arrivalTimes.push(toTime(arrival).
|
|
15997
|
+
arrivalTimes.push(toTime(arrival).toMinutes());
|
|
15956
15998
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
15957
|
-
departureTimes.push(toTime(departure).
|
|
15999
|
+
departureTimes.push(toTime(departure).toMinutes());
|
|
15958
16000
|
pickUpTypes.push(parsePickupDropOffType(line.pickup_type));
|
|
15959
16001
|
dropOffTypes.push(parsePickupDropOffType(line.drop_off_type));
|
|
15960
16002
|
previousSeq = line.stop_sequence;
|