minotor 3.0.2 → 5.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +9 -3
  2. package/README.md +1 -0
  3. package/dist/cli.mjs +294 -307
  4. package/dist/cli.mjs.map +1 -1
  5. package/dist/gtfs/trips.d.ts +12 -6
  6. package/dist/parser.cjs.js +290 -302
  7. package/dist/parser.cjs.js.map +1 -1
  8. package/dist/parser.esm.js +290 -302
  9. package/dist/parser.esm.js.map +1 -1
  10. package/dist/router.cjs.js +1 -1
  11. package/dist/router.cjs.js.map +1 -1
  12. package/dist/router.d.ts +2 -2
  13. package/dist/router.esm.js +1 -1
  14. package/dist/router.esm.js.map +1 -1
  15. package/dist/router.umd.js +1 -1
  16. package/dist/router.umd.js.map +1 -1
  17. package/dist/routing/route.d.ts +3 -3
  18. package/dist/timetable/io.d.ts +5 -4
  19. package/dist/timetable/proto/timetable.d.ts +7 -16
  20. package/dist/timetable/route.d.ts +7 -5
  21. package/dist/timetable/timetable.d.ts +7 -5
  22. package/package.json +1 -1
  23. package/src/__e2e__/timetable/timetable.bin +2 -2
  24. package/src/cli/repl.ts +0 -1
  25. package/src/gtfs/__tests__/parser.test.ts +2 -2
  26. package/src/gtfs/__tests__/routes.test.ts +3 -0
  27. package/src/gtfs/__tests__/trips.test.ts +123 -166
  28. package/src/gtfs/parser.ts +50 -9
  29. package/src/gtfs/routes.ts +1 -0
  30. package/src/gtfs/trips.ts +195 -112
  31. package/src/router.ts +2 -2
  32. package/src/routing/__tests__/route.test.ts +3 -3
  33. package/src/routing/__tests__/router.test.ts +186 -203
  34. package/src/routing/route.ts +3 -3
  35. package/src/routing/router.ts +1 -1
  36. package/src/timetable/__tests__/io.test.ts +52 -64
  37. package/src/timetable/__tests__/route.test.ts +25 -17
  38. package/src/timetable/__tests__/timetable.test.ts +16 -24
  39. package/src/timetable/io.ts +20 -19
  40. package/src/timetable/proto/timetable.proto +7 -9
  41. package/src/timetable/proto/timetable.ts +80 -202
  42. package/src/timetable/route.ts +27 -13
  43. package/src/timetable/timetable.ts +20 -16
@@ -12,11 +12,7 @@ import {
12
12
  } from '../io.js';
13
13
  import { REGULAR, Route } from '../route.js';
14
14
  import { Time } from '../time.js';
15
- import {
16
- RoutesAdjacency,
17
- ServiceRoutesMap,
18
- StopsAdjacency,
19
- } from '../timetable.js';
15
+ import { ServiceRoutesMap, StopsAdjacency } from '../timetable.js';
20
16
 
21
17
  describe('Timetable IO', () => {
22
18
  const stopsAdjacency: StopsAdjacency = new Map([
@@ -24,7 +20,7 @@ describe('Timetable IO', () => {
24
20
  1,
25
21
  {
26
22
  transfers: [{ destination: 2, type: 'RECOMMENDED' }],
27
- routes: ['route1'],
23
+ routes: [0],
28
24
  },
29
25
  ],
30
26
  [
@@ -37,45 +33,39 @@ describe('Timetable IO', () => {
37
33
  minTransferTime: Duration.fromMinutes(3),
38
34
  },
39
35
  ],
40
- routes: ['route2'],
36
+ routes: [1],
41
37
  },
42
38
  ],
43
39
  ]);
44
- const routesAdjacency: RoutesAdjacency = new Map([
45
- [
46
- 'route1',
47
- new Route(
48
- new Uint16Array([
49
- Time.fromHMS(16, 40, 0).toMinutes(),
50
- Time.fromHMS(16, 50, 0).toMinutes(),
51
- ]),
52
- new Uint8Array([REGULAR, REGULAR]),
53
- new Uint32Array([1, 2]),
54
- 'gtfs1',
55
- ),
56
- ],
57
- [
58
- 'route2',
59
- new Route(
60
- new Uint16Array([
61
- Time.fromHMS(15, 20, 0).toMinutes(),
62
- Time.fromHMS(15, 30, 0).toMinutes(),
63
- ]),
64
- new Uint8Array([REGULAR, REGULAR]),
65
- new Uint32Array([2, 1]),
66
- 'gtfs2',
67
- ),
68
- ],
69
- ]);
40
+ const routesAdjacency = [
41
+ new Route(
42
+ new Uint16Array([
43
+ Time.fromHMS(16, 40, 0).toMinutes(),
44
+ Time.fromHMS(16, 50, 0).toMinutes(),
45
+ ]),
46
+ new Uint8Array([REGULAR, REGULAR]),
47
+ new Uint32Array([1, 2]),
48
+ 'gtfs1',
49
+ ),
50
+ new Route(
51
+ new Uint16Array([
52
+ Time.fromHMS(15, 20, 0).toMinutes(),
53
+ Time.fromHMS(15, 30, 0).toMinutes(),
54
+ ]),
55
+ new Uint8Array([REGULAR, REGULAR]),
56
+ new Uint32Array([2, 1]),
57
+ 'gtfs2',
58
+ ),
59
+ ];
70
60
  const routes: ServiceRoutesMap = new Map([
71
- ['gtfs1', { type: 'RAIL', name: 'Route 1' }],
72
- ['gtfs2', { type: 'RAIL', name: 'Route 2' }],
61
+ ['gtfs1', { type: 'RAIL', name: 'Route 1', routes: [0] }],
62
+ ['gtfs2', { type: 'RAIL', name: 'Route 2', routes: [1] }],
73
63
  ]);
74
64
  const stopsAdjacencyProto = {
75
65
  stops: {
76
66
  '1': {
77
67
  transfers: [{ destination: 2, type: 0 }],
78
- routes: ['route1'],
68
+ routes: [0],
79
69
  },
80
70
  '2': {
81
71
  transfers: [
@@ -85,42 +75,40 @@ describe('Timetable IO', () => {
85
75
  minTransferTime: 180,
86
76
  },
87
77
  ],
88
- routes: ['route2'],
78
+ routes: [1],
89
79
  },
90
80
  },
91
81
  };
92
82
 
93
- const routesAdjacencyProto = {
94
- routes: {
95
- route1: {
96
- stopTimes: new Uint8Array(
97
- new Uint16Array([
98
- Time.fromHMS(16, 40, 0).toMinutes(),
99
- Time.fromHMS(16, 50, 0).toMinutes(),
100
- ]).buffer,
101
- ),
102
- pickUpDropOffTypes: new Uint8Array([REGULAR, REGULAR]),
103
- stops: new Uint8Array(new Uint32Array([1, 2]).buffer),
104
- serviceRouteId: 'gtfs1',
105
- },
106
- route2: {
107
- stopTimes: new Uint8Array(
108
- new Uint16Array([
109
- Time.fromHMS(15, 20, 0).toMinutes(),
110
- Time.fromHMS(15, 30, 0).toMinutes(),
111
- ]).buffer,
112
- ),
113
- pickUpDropOffTypes: new Uint8Array([REGULAR, REGULAR]),
114
- stops: new Uint8Array(new Uint32Array([2, 1]).buffer),
115
- serviceRouteId: 'gtfs2',
116
- },
83
+ const routesAdjacencyProto = [
84
+ {
85
+ stopTimes: new Uint8Array(
86
+ new Uint16Array([
87
+ Time.fromHMS(16, 40, 0).toMinutes(),
88
+ Time.fromHMS(16, 50, 0).toMinutes(),
89
+ ]).buffer,
90
+ ),
91
+ pickUpDropOffTypes: new Uint8Array([REGULAR, REGULAR]),
92
+ stops: new Uint8Array(new Uint32Array([1, 2]).buffer),
93
+ serviceRouteId: 'gtfs1',
117
94
  },
118
- };
95
+ {
96
+ stopTimes: new Uint8Array(
97
+ new Uint16Array([
98
+ Time.fromHMS(15, 20, 0).toMinutes(),
99
+ Time.fromHMS(15, 30, 0).toMinutes(),
100
+ ]).buffer,
101
+ ),
102
+ pickUpDropOffTypes: new Uint8Array([REGULAR, REGULAR]),
103
+ stops: new Uint8Array(new Uint32Array([2, 1]).buffer),
104
+ serviceRouteId: 'gtfs2',
105
+ },
106
+ ];
119
107
 
120
108
  const routesProto = {
121
109
  routes: {
122
- gtfs1: { type: 2, name: 'Route 1' },
123
- gtfs2: { type: 2, name: 'Route 2' },
110
+ gtfs1: { type: 2, name: 'Route 1', routes: [0] },
111
+ gtfs2: { type: 2, name: 'Route 2', routes: [1] },
124
112
  },
125
113
  };
126
114
 
@@ -1,6 +1,7 @@
1
1
  import assert from 'node:assert';
2
2
  import { describe, it } from 'node:test';
3
3
 
4
+ import { encodePickUpDropOffTypes } from '../../gtfs/trips.js';
4
5
  import {
5
6
  MUST_COORDINATE_WITH_DRIVER,
6
7
  MUST_PHONE_AGENCY,
@@ -29,23 +30,30 @@ describe('Route', () => {
29
30
  Time.fromHMS(10, 31, 0).toMinutes(),
30
31
  ]);
31
32
 
32
- const pickUpDropOffTypes = new Uint8Array([
33
- // Trip 0
34
- REGULAR,
35
- REGULAR,
36
- NOT_AVAILABLE,
37
- REGULAR,
38
- // Trip 1
39
- REGULAR,
40
- REGULAR,
41
- REGULAR,
42
- REGULAR,
43
- // Trip 2
44
- MUST_PHONE_AGENCY,
45
- REGULAR,
46
- MUST_COORDINATE_WITH_DRIVER,
47
- REGULAR,
48
- ]);
33
+ const pickUpDropOffTypes = encodePickUpDropOffTypes(
34
+ [
35
+ // Trip 0
36
+ REGULAR,
37
+ NOT_AVAILABLE,
38
+ // Trip 1
39
+ REGULAR,
40
+ REGULAR,
41
+ // Trip 2
42
+ MUST_PHONE_AGENCY,
43
+ MUST_COORDINATE_WITH_DRIVER,
44
+ ],
45
+ [
46
+ // Trip 0
47
+ REGULAR,
48
+ REGULAR,
49
+ // Trip 1
50
+ REGULAR,
51
+ REGULAR,
52
+ // Trip 2
53
+ REGULAR,
54
+ REGULAR,
55
+ ],
56
+ );
49
57
 
50
58
  const stops = new Uint32Array([1001, 1002]);
51
59
  const serviceRouteId = 'test-route-1';
@@ -1,11 +1,11 @@
1
1
  import assert from 'node:assert';
2
2
  import { describe, it } from 'node:test';
3
3
 
4
+ import { encodePickUpDropOffTypes } from '../../gtfs/trips.js';
4
5
  import { Duration } from '../duration.js';
5
6
  import { NOT_AVAILABLE, REGULAR, Route } from '../route.js';
6
7
  import { Time } from '../time.js';
7
8
  import {
8
- RoutesAdjacency,
9
9
  RouteType,
10
10
  ServiceRoutesMap,
11
11
  StopsAdjacency,
@@ -18,7 +18,7 @@ describe('Timetable', () => {
18
18
  1,
19
19
  {
20
20
  transfers: [{ destination: 2, type: 'RECOMMENDED' }],
21
- routes: ['route1', 'route2'],
21
+ routes: [0, 1],
22
22
  },
23
23
  ],
24
24
  [
@@ -31,7 +31,7 @@ describe('Timetable', () => {
31
31
  minTransferTime: Duration.fromMinutes(3),
32
32
  },
33
33
  ],
34
- routes: ['route2', 'route1'],
34
+ routes: [1, 0],
35
35
  },
36
36
  ],
37
37
  [
@@ -42,6 +42,7 @@ describe('Timetable', () => {
42
42
  },
43
43
  ],
44
44
  ]);
45
+
45
46
  const route1 = new Route(
46
47
  new Uint16Array([
47
48
  Time.fromHMS(16, 40, 0).toMinutes(),
@@ -53,16 +54,10 @@ describe('Timetable', () => {
53
54
  Time.fromHMS(19, 0, 0).toMinutes(),
54
55
  Time.fromHMS(19, 10, 0).toMinutes(),
55
56
  ]),
56
- new Uint8Array([
57
- REGULAR,
58
- REGULAR,
59
- NOT_AVAILABLE,
60
- REGULAR,
61
- REGULAR,
62
- REGULAR,
63
- REGULAR,
64
- REGULAR,
65
- ]),
57
+ encodePickUpDropOffTypes(
58
+ [REGULAR, NOT_AVAILABLE, REGULAR, REGULAR],
59
+ [REGULAR, REGULAR, REGULAR, REGULAR],
60
+ ),
66
61
  new Uint32Array([1, 2]),
67
62
  'gtfs1',
68
63
  );
@@ -73,17 +68,14 @@ describe('Timetable', () => {
73
68
  Time.fromHMS(23, 20, 0).toMinutes(),
74
69
  Time.fromHMS(23, 30, 0).toMinutes(),
75
70
  ]),
76
- new Uint8Array([REGULAR, REGULAR, REGULAR, REGULAR]),
71
+ encodePickUpDropOffTypes([REGULAR, REGULAR], [REGULAR, REGULAR]),
77
72
  new Uint32Array([2, 1]),
78
73
  'gtfs2',
79
74
  );
80
- const routesAdjacency: RoutesAdjacency = new Map([
81
- ['route1', route1],
82
- ['route2', route2],
83
- ]);
75
+ const routesAdjacency = [route1, route2];
84
76
  const routes: ServiceRoutesMap = new Map([
85
- ['gtfs1', { type: 'RAIL', name: 'Route 1' }],
86
- ['gtfs2', { type: 'RAIL', name: 'Route 2' }],
77
+ ['gtfs1', { type: 'RAIL', name: 'Route 1', routes: [0] }],
78
+ ['gtfs2', { type: 'RAIL', name: 'Route 2', routes: [1] }],
87
79
  ]);
88
80
 
89
81
  const sampleTimetable: Timetable = new Timetable(
@@ -105,14 +97,14 @@ describe('Timetable', () => {
105
97
 
106
98
  it('should find the earliest trip for stop1 on route1', () => {
107
99
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
108
- const route = sampleTimetable.getRoute('route1')!;
100
+ const route = sampleTimetable.getRoute(0)!;
109
101
  const tripIndex = route.findEarliestTrip(1);
110
102
  assert.strictEqual(tripIndex, 0);
111
103
  });
112
104
 
113
105
  it('should find the earliest trip for stop1 on route1 after a specific time', () => {
114
106
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
115
- const route = sampleTimetable.getRoute('route1')!;
107
+ const route = sampleTimetable.getRoute(0)!;
116
108
  const afterTime = Time.fromHMS(17, 0, 0);
117
109
  const tripIndex = route.findEarliestTrip(1, afterTime);
118
110
  assert.strictEqual(tripIndex, 1);
@@ -120,14 +112,14 @@ describe('Timetable', () => {
120
112
 
121
113
  it('should return undefined if no valid trip exists after a specific time', () => {
122
114
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
123
- const route = sampleTimetable.getRoute('route1')!;
115
+ const route = sampleTimetable.getRoute(0)!;
124
116
  const afterTime = Time.fromHMS(23, 40, 0);
125
117
  const tripIndex = route.findEarliestTrip(1, afterTime);
126
118
  assert.strictEqual(tripIndex, undefined);
127
119
  });
128
120
  it('should return undefined if the stop on a trip has pick up not available', () => {
129
121
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
130
- const route = sampleTimetable.getRoute('route1')!;
122
+ const route = sampleTimetable.getRoute(0)!;
131
123
  const tripIndex = route.findEarliestTrip(2);
132
124
  assert.strictEqual(tripIndex, 1);
133
125
  });
@@ -1,15 +1,14 @@
1
1
  import { Duration } from './duration.js';
2
2
  import {
3
- RoutesAdjacency as ProtoRoutesAdjacency,
3
+ Route as ProtoRoute,
4
4
  RouteType as ProtoRouteType,
5
5
  ServiceRoutesMap as ProtoServiceRoutesMap,
6
6
  StopsAdjacency as ProtoStopsAdjacency,
7
7
  Transfer as ProtoTransfer,
8
8
  TransferType as ProtoTransferType,
9
9
  } from './proto/timetable.js';
10
- import { Route } from './route.js';
10
+ import { Route, RouteId } from './route.js';
11
11
  import {
12
- RoutesAdjacency,
13
12
  RouteType,
14
13
  ServiceRouteId,
15
14
  ServiceRoutesMap,
@@ -130,7 +129,7 @@ export const serializeStopsAdjacency = (
130
129
  };
131
130
 
132
131
  stopsAdjacency.forEach(
133
- (value: { transfers: Transfer[]; routes: string[] }, key: number) => {
132
+ (value: { transfers: Transfer[]; routes: number[] }, key: number) => {
134
133
  protoStopsAdjacency.stops[key] = {
135
134
  transfers: value.transfers.map((transfer) => ({
136
135
  destination: transfer.destination,
@@ -148,20 +147,18 @@ export const serializeStopsAdjacency = (
148
147
  };
149
148
 
150
149
  export const serializeRoutesAdjacency = (
151
- routesAdjacency: RoutesAdjacency,
152
- ): ProtoRoutesAdjacency => {
153
- const protoRoutesAdjacency: ProtoRoutesAdjacency = {
154
- routes: {},
155
- };
150
+ routesAdjacency: Route[],
151
+ ): ProtoRoute[] => {
152
+ const protoRoutesAdjacency: ProtoRoute[] = [];
156
153
 
157
- routesAdjacency.forEach((route: Route, key: string) => {
154
+ routesAdjacency.forEach((route: Route) => {
158
155
  const routeData = route.serialize();
159
- protoRoutesAdjacency.routes[key] = {
156
+ protoRoutesAdjacency.push({
160
157
  stopTimes: uint16ArrayToBytes(routeData.stopTimes),
161
158
  pickUpDropOffTypes: routeData.pickUpDropOffTypes,
162
159
  stops: uint32ArrayToBytes(routeData.stops),
163
160
  serviceRouteId: routeData.serviceRouteId,
164
- };
161
+ });
165
162
  });
166
163
 
167
164
  return protoRoutesAdjacency;
@@ -175,10 +172,14 @@ export const serializeServiceRoutesMap = (
175
172
  };
176
173
 
177
174
  serviceRoutesMap.forEach(
178
- (value: { type: RouteType; name: string }, key: string) => {
175
+ (
176
+ value: { type: RouteType; name: string; routes: RouteId[] },
177
+ key: string,
178
+ ) => {
179
179
  protoServiceRoutesMap.routes[key] = {
180
180
  type: serializeRouteType(value.type),
181
181
  name: value.name,
182
+ routes: value.routes,
182
183
  };
183
184
  },
184
185
  );
@@ -211,14 +212,13 @@ export const deserializeStopsAdjacency = (
211
212
  };
212
213
 
213
214
  export const deserializeRoutesAdjacency = (
214
- protoRoutesAdjacency: ProtoRoutesAdjacency,
215
- ): RoutesAdjacency => {
216
- const routesAdjacency: RoutesAdjacency = new Map();
215
+ protoRoutesAdjacency: ProtoRoute[],
216
+ ): Route[] => {
217
+ const routesAdjacency: Route[] = [];
217
218
 
218
- Object.entries(protoRoutesAdjacency.routes).forEach(([key, value]) => {
219
+ protoRoutesAdjacency.forEach((value) => {
219
220
  const stops = bytesToUint32Array(value.stops);
220
- routesAdjacency.set(
221
- key,
221
+ routesAdjacency.push(
222
222
  new Route(
223
223
  bytesToUint16Array(value.stopTimes),
224
224
  value.pickUpDropOffTypes,
@@ -240,6 +240,7 @@ export const deserializeServiceRoutesMap = (
240
240
  serviceRoutesMap.set(key, {
241
241
  type: parseRouteType(value.type),
242
242
  name: value.name,
243
+ routes: value.routes,
243
244
  });
244
245
  });
245
246
 
@@ -15,7 +15,8 @@ message Route {
15
15
  * 1: NOT_AVAILABLE
16
16
  * 2: MUST_PHONE_AGENCY
17
17
  * 3: MUST_COORDINATE_WITH_DRIVER
18
- * Format: [pickupTypeStop1, dropOffTypeStop1, pickupTypeStop2, dropOffTypeStop2, etc.]
18
+ * Format: [drop_off_1][pickup_1][drop_off_0][pickup_0]
19
+ * 2 bits per value
19
20
  */
20
21
  bytes pickUpDropOffTypes = 2;
21
22
  /**
@@ -26,10 +27,6 @@ message Route {
26
27
  string serviceRouteId = 4;
27
28
  }
28
29
 
29
- message RoutesAdjacency {
30
- map<string, Route> routes = 1;
31
- }
32
-
33
30
  enum TransferType {
34
31
  RECOMMENDED_TRANSFER_POINT = 0;
35
32
  TIMED_TRANSFER = 1;
@@ -40,15 +37,15 @@ enum TransferType {
40
37
  message Transfer {
41
38
  uint32 destination = 1;
42
39
  TransferType type = 2;
43
- optional int32 minTransferTime = 3;
40
+ optional uint32 minTransferTime = 3;
44
41
  }
45
42
 
46
43
  message StopsAdjacency {
47
44
  message StopAdjacency {
48
45
  repeated Transfer transfers = 1;
49
- repeated string routes = 2;
46
+ repeated int32 routes = 2;
50
47
  }
51
- map<string, StopAdjacency> stops = 1;
48
+ map<uint32, StopAdjacency> stops = 1;
52
49
  }
53
50
 
54
51
  enum RouteType {
@@ -67,6 +64,7 @@ enum RouteType {
67
64
  message ServiceRoute {
68
65
  RouteType type = 1;
69
66
  string name = 2;
67
+ repeated int32 routes = 3;
70
68
  }
71
69
 
72
70
  message ServiceRoutesMap {
@@ -76,6 +74,6 @@ message ServiceRoutesMap {
76
74
  message Timetable {
77
75
  string version = 1;
78
76
  StopsAdjacency stopsAdjacency = 2;
79
- RoutesAdjacency routesAdjacency = 3;
77
+ repeated Route routesAdjacency = 3;
80
78
  ServiceRoutesMap routes = 4;
81
79
  }