@opentripplanner/core-utils 4.11.6-alpha.1 → 5.0.1
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/esm/deprecated-with-types.js +47 -0
- package/esm/deprecated-with-types.js.map +1 -0
- package/esm/index.js +0 -4
- package/esm/index.js.map +1 -1
- package/esm/itinerary.js +1 -1
- package/esm/itinerary.js.map +1 -1
- package/esm/map.js +16 -8
- package/esm/map.js.map +1 -1
- package/esm/route.js +5 -3
- package/esm/route.js.map +1 -1
- package/esm/storage.js +1 -0
- package/esm/storage.js.map +1 -1
- package/esm/time.js +6 -36
- package/esm/time.js.map +1 -1
- package/esm/ui.js +1 -1
- package/esm/ui.js.map +1 -1
- package/lib/deprecated-with-types.d.ts +23 -0
- package/lib/deprecated-with-types.d.ts.map +1 -0
- package/lib/deprecated-with-types.js +61 -0
- package/lib/deprecated-with-types.js.map +1 -0
- package/lib/index.d.ts +19 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +0 -6
- package/lib/index.js.map +1 -1
- package/lib/itinerary.d.ts +113 -0
- package/lib/itinerary.d.ts.map +1 -0
- package/lib/itinerary.js +2 -1
- package/lib/itinerary.js.map +1 -1
- package/lib/map.d.ts +30 -0
- package/lib/map.d.ts.map +1 -0
- package/lib/map.js +15 -7
- package/lib/map.js.map +1 -1
- package/lib/route.d.ts +98 -0
- package/lib/route.d.ts.map +1 -0
- package/lib/route.js +5 -3
- package/lib/route.js.map +1 -1
- package/lib/storage.d.ts +19 -0
- package/lib/storage.d.ts.map +1 -0
- package/lib/storage.js +2 -0
- package/lib/storage.js.map +1 -1
- package/lib/time.d.ts +65 -0
- package/lib/time.d.ts.map +1 -0
- package/lib/time.js +22 -39
- package/lib/time.js.map +1 -1
- package/lib/ui.d.ts +13 -0
- package/lib/ui.d.ts.map +1 -0
- package/lib/ui.js +1 -1
- package/lib/ui.js.map +1 -1
- package/package.json +4 -1
- package/src/__tests__/__snapshots__/route.js.snap +30 -30
- package/src/deprecated-with-types.ts +62 -0
- package/src/{index.js → index.ts} +0 -4
- package/src/{itinerary.js → itinerary.ts} +70 -36
- package/src/{map.js → map.ts} +51 -28
- package/src/{route.js → route.ts} +52 -28
- package/src/{storage.js → storage.ts} +6 -5
- package/src/{time.js → time.ts} +28 -46
- package/src/{ui.js → ui.ts} +8 -8
- package/tsconfig.json +15 -0
- package/tsconfig.tsbuildinfo +4921 -0
- package/esm/messages.js +0 -25
- package/esm/messages.js.map +0 -1
- package/esm/types.js +0 -560
- package/esm/types.js.map +0 -1
- package/lib/messages.js +0 -29
- package/lib/messages.js.map +0 -1
- package/lib/types.js +0 -661
- package/lib/types.js.map +0 -1
- package/src/messages.js +0 -20
- package/src/types.js +0 -605
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
import polyline from "@mapbox/polyline";
|
|
2
|
+
import {
|
|
3
|
+
Company,
|
|
4
|
+
Config,
|
|
5
|
+
ElevationProfile,
|
|
6
|
+
FlexBookingInfo,
|
|
7
|
+
Itinerary,
|
|
8
|
+
LatLngArray,
|
|
9
|
+
Leg,
|
|
10
|
+
Step
|
|
11
|
+
} from "@opentripplanner/types";
|
|
2
12
|
import turfAlong from "@turf/along";
|
|
3
13
|
|
|
4
14
|
import {
|
|
@@ -40,13 +50,16 @@ export const transitModes = [
|
|
|
40
50
|
* @return {Array} List of all transit modes defined in config; otherwise default mode list
|
|
41
51
|
*/
|
|
42
52
|
|
|
43
|
-
export function getTransitModes(config) {
|
|
53
|
+
export function getTransitModes(config: Config): string[] {
|
|
44
54
|
if (!config || !config.modes || !config.modes.transitModes)
|
|
45
55
|
return transitModes;
|
|
46
|
-
|
|
56
|
+
|
|
57
|
+
return config.modes.transitModes.map(tm =>
|
|
58
|
+
typeof tm !== "string" ? tm.mode : tm
|
|
59
|
+
);
|
|
47
60
|
}
|
|
48
61
|
|
|
49
|
-
export function isTransit(mode) {
|
|
62
|
+
export function isTransit(mode: string): boolean {
|
|
50
63
|
return transitModes.includes(mode) || mode === "TRANSIT";
|
|
51
64
|
}
|
|
52
65
|
|
|
@@ -55,7 +68,7 @@ export function isTransit(mode) {
|
|
|
55
68
|
* calling ahead for the service to run. "mustPhone" is the only
|
|
56
69
|
* property of boardRule which encodes this info.
|
|
57
70
|
*/
|
|
58
|
-
export function isReservationRequired(leg) {
|
|
71
|
+
export function isReservationRequired(leg: Leg): boolean {
|
|
59
72
|
return leg.boardRule === "mustPhone";
|
|
60
73
|
}
|
|
61
74
|
/**
|
|
@@ -63,53 +76,53 @@ export function isReservationRequired(leg) {
|
|
|
63
76
|
* asking the driver to let the user off. "coordinateWithDriver" is the only
|
|
64
77
|
* property of alightRule which encodes this info.
|
|
65
78
|
*/
|
|
66
|
-
export function isContinuousDropoff(leg) {
|
|
79
|
+
export function isContinuousDropoff(leg: Leg): boolean {
|
|
67
80
|
return leg.alightRule === "coordinateWithDriver";
|
|
68
81
|
}
|
|
69
82
|
/**
|
|
70
83
|
* The two rules checked by the above two functions are the only values
|
|
71
84
|
* returned by OTP when a leg is a flex leg.
|
|
72
85
|
*/
|
|
73
|
-
export function isFlex(leg) {
|
|
86
|
+
export function isFlex(leg: Leg): boolean {
|
|
74
87
|
return isReservationRequired(leg) || isContinuousDropoff(leg);
|
|
75
88
|
}
|
|
76
89
|
|
|
77
|
-
export function isAdvanceBookingRequired(info) {
|
|
90
|
+
export function isAdvanceBookingRequired(info: FlexBookingInfo): boolean {
|
|
78
91
|
return info?.latestBookingTime?.daysPrior > 0;
|
|
79
92
|
}
|
|
80
|
-
export function legDropoffRequiresAdvanceBooking(leg) {
|
|
93
|
+
export function legDropoffRequiresAdvanceBooking(leg: Leg): boolean {
|
|
81
94
|
return isAdvanceBookingRequired(leg.dropOffBookingInfo);
|
|
82
95
|
}
|
|
83
96
|
|
|
84
|
-
export function isWalk(mode) {
|
|
97
|
+
export function isWalk(mode: string): boolean {
|
|
85
98
|
if (!mode) return false;
|
|
86
99
|
|
|
87
100
|
return mode === "WALK";
|
|
88
101
|
}
|
|
89
102
|
|
|
90
|
-
export function isBicycle(mode) {
|
|
103
|
+
export function isBicycle(mode: string): boolean {
|
|
91
104
|
if (!mode) return false;
|
|
92
105
|
|
|
93
106
|
return mode === "BICYCLE";
|
|
94
107
|
}
|
|
95
108
|
|
|
96
|
-
export function isBicycleRent(mode) {
|
|
109
|
+
export function isBicycleRent(mode: string): boolean {
|
|
97
110
|
if (!mode) return false;
|
|
98
111
|
|
|
99
112
|
return mode === "BICYCLE_RENT";
|
|
100
113
|
}
|
|
101
114
|
|
|
102
|
-
export function isCar(mode) {
|
|
115
|
+
export function isCar(mode: string): boolean {
|
|
103
116
|
if (!mode) return false;
|
|
104
117
|
return mode.startsWith("CAR");
|
|
105
118
|
}
|
|
106
119
|
|
|
107
|
-
export function isMicromobility(mode) {
|
|
120
|
+
export function isMicromobility(mode: string): boolean {
|
|
108
121
|
if (!mode) return false;
|
|
109
122
|
return mode.startsWith("MICROMOBILITY") || mode.startsWith("SCOOTER");
|
|
110
123
|
}
|
|
111
124
|
|
|
112
|
-
export function isAccessMode(mode) {
|
|
125
|
+
export function isAccessMode(mode: string): boolean {
|
|
113
126
|
return (
|
|
114
127
|
isWalk(mode) ||
|
|
115
128
|
isBicycle(mode) ||
|
|
@@ -123,7 +136,7 @@ export function isAccessMode(mode) {
|
|
|
123
136
|
* @param {string} modesStr a comma-separated list of OTP modes
|
|
124
137
|
* @return {boolean} whether any of the modes are transit modes
|
|
125
138
|
*/
|
|
126
|
-
export function hasTransit(modesStr) {
|
|
139
|
+
export function hasTransit(modesStr: string): boolean {
|
|
127
140
|
return modesStr.split(",").some(mode => isTransit(mode));
|
|
128
141
|
}
|
|
129
142
|
|
|
@@ -131,7 +144,7 @@ export function hasTransit(modesStr) {
|
|
|
131
144
|
* @param {string} modesStr a comma-separated list of OTP modes
|
|
132
145
|
* @return {boolean} whether any of the modes are car-based modes
|
|
133
146
|
*/
|
|
134
|
-
export function hasCar(modesStr) {
|
|
147
|
+
export function hasCar(modesStr: string): boolean {
|
|
135
148
|
return modesStr.split(",").some(mode => isCar(mode));
|
|
136
149
|
}
|
|
137
150
|
|
|
@@ -139,7 +152,7 @@ export function hasCar(modesStr) {
|
|
|
139
152
|
* @param {string} modesStr a comma-separated list of OTP modes
|
|
140
153
|
* @return {boolean} whether any of the modes are bicycle-based modes
|
|
141
154
|
*/
|
|
142
|
-
export function hasBike(modesStr) {
|
|
155
|
+
export function hasBike(modesStr: string): boolean {
|
|
143
156
|
return modesStr
|
|
144
157
|
.split(",")
|
|
145
158
|
.some(mode => isBicycle(mode) || isBicycleRent(mode));
|
|
@@ -149,7 +162,7 @@ export function hasBike(modesStr) {
|
|
|
149
162
|
* @param {string} modesStr a comma-separated list of OTP modes
|
|
150
163
|
* @return {boolean} whether any of the modes are micromobility-based modes
|
|
151
164
|
*/
|
|
152
|
-
export function hasMicromobility(modesStr) {
|
|
165
|
+
export function hasMicromobility(modesStr: string): boolean {
|
|
153
166
|
return modesStr.split(",").some(mode => isMicromobility(mode));
|
|
154
167
|
}
|
|
155
168
|
|
|
@@ -157,7 +170,7 @@ export function hasMicromobility(modesStr) {
|
|
|
157
170
|
* @param {string} modesStr a comma-separated list of OTP modes
|
|
158
171
|
* @return {boolean} whether any of the modes is a hailing mode
|
|
159
172
|
*/
|
|
160
|
-
export function hasHail(modesStr) {
|
|
173
|
+
export function hasHail(modesStr: string): boolean {
|
|
161
174
|
return modesStr.split(",").some(mode => mode.indexOf("_HAIL") > -1);
|
|
162
175
|
}
|
|
163
176
|
|
|
@@ -165,11 +178,11 @@ export function hasHail(modesStr) {
|
|
|
165
178
|
* @param {string} modesStr a comma-separated list of OTP modes
|
|
166
179
|
* @return {boolean} whether any of the modes is a rental mode
|
|
167
180
|
*/
|
|
168
|
-
export function hasRental(modesStr) {
|
|
181
|
+
export function hasRental(modesStr: string): boolean {
|
|
169
182
|
return modesStr.split(",").some(mode => mode.indexOf("_RENT") > -1);
|
|
170
183
|
}
|
|
171
184
|
|
|
172
|
-
export function getMapColor(mode) {
|
|
185
|
+
export function getMapColor(mode: string): string {
|
|
173
186
|
mode = mode || this.get("mode");
|
|
174
187
|
if (mode === "WALK") return "#444";
|
|
175
188
|
if (mode === "BICYCLE") return "#0073e5";
|
|
@@ -183,7 +196,7 @@ export function getMapColor(mode) {
|
|
|
183
196
|
return "#aaa";
|
|
184
197
|
}
|
|
185
198
|
|
|
186
|
-
export function toSentenceCase(str) {
|
|
199
|
+
export function toSentenceCase(str: string): string {
|
|
187
200
|
if (str == null) {
|
|
188
201
|
return "";
|
|
189
202
|
}
|
|
@@ -194,7 +207,7 @@ export function toSentenceCase(str) {
|
|
|
194
207
|
/**
|
|
195
208
|
* Derive the company string based on mode and network associated with leg.
|
|
196
209
|
*/
|
|
197
|
-
export function getCompanyFromLeg(leg) {
|
|
210
|
+
export function getCompanyFromLeg(leg: Leg): string {
|
|
198
211
|
if (!leg) return null;
|
|
199
212
|
const { from, mode, rentedBike, rentedCar, rentedVehicle, tncData } = leg;
|
|
200
213
|
if (mode === "CAR" && rentedCar) {
|
|
@@ -216,12 +229,12 @@ export function getCompanyFromLeg(leg) {
|
|
|
216
229
|
return null;
|
|
217
230
|
}
|
|
218
231
|
|
|
219
|
-
export function getItineraryBounds(itinerary) {
|
|
232
|
+
export function getItineraryBounds(itinerary: Itinerary): LatLngArray[] {
|
|
220
233
|
let coords = [];
|
|
221
234
|
itinerary.legs.forEach(leg => {
|
|
222
235
|
const legCoords = polyline
|
|
223
236
|
.toGeoJSON(leg.legGeometry.points)
|
|
224
|
-
.coordinates.map(c => [c[1], c[0]]);
|
|
237
|
+
.coordinates.map((c: number[]) => [c[1], c[0]]);
|
|
225
238
|
coords = [...coords, ...legCoords];
|
|
226
239
|
});
|
|
227
240
|
return coords;
|
|
@@ -230,7 +243,7 @@ export function getItineraryBounds(itinerary) {
|
|
|
230
243
|
/**
|
|
231
244
|
* Return a coords object that encloses the given leg's geometry.
|
|
232
245
|
*/
|
|
233
|
-
export function getLegBounds(leg) {
|
|
246
|
+
export function getLegBounds(leg: Leg): number[] {
|
|
234
247
|
const coords = polyline
|
|
235
248
|
.toGeoJSON(leg.legGeometry.points)
|
|
236
249
|
.coordinates.map(c => [c[1], c[0]]);
|
|
@@ -246,7 +259,7 @@ export function getLegBounds(leg) {
|
|
|
246
259
|
|
|
247
260
|
/* Returns an interpolated lat-lon at a specified distance along a leg */
|
|
248
261
|
|
|
249
|
-
export function legLocationAtDistance(leg, distance) {
|
|
262
|
+
export function legLocationAtDistance(leg: Leg, distance: number): number[] {
|
|
250
263
|
if (!leg.legGeometry) return null;
|
|
251
264
|
|
|
252
265
|
try {
|
|
@@ -264,7 +277,10 @@ export function legLocationAtDistance(leg, distance) {
|
|
|
264
277
|
|
|
265
278
|
/* Returns an interpolated elevation at a specified distance along a leg */
|
|
266
279
|
|
|
267
|
-
export function legElevationAtDistance(
|
|
280
|
+
export function legElevationAtDistance(
|
|
281
|
+
points: number[][],
|
|
282
|
+
distance: number
|
|
283
|
+
): number {
|
|
268
284
|
// Iterate through the combined elevation profile
|
|
269
285
|
let traversed = 0;
|
|
270
286
|
// If first point distance is not zero, insert starting point at zero with
|
|
@@ -302,7 +318,10 @@ export function legElevationAtDistance(points, distance) {
|
|
|
302
318
|
|
|
303
319
|
// Iterate through the steps, building the array of elevation points and
|
|
304
320
|
// keeping track of the minimum and maximum elevations reached
|
|
305
|
-
export function getElevationProfile(
|
|
321
|
+
export function getElevationProfile(
|
|
322
|
+
steps: Step[],
|
|
323
|
+
unitConversion = 1
|
|
324
|
+
): ElevationProfile {
|
|
306
325
|
let minElev = 100000;
|
|
307
326
|
let maxElev = -100000;
|
|
308
327
|
let traversed = 0;
|
|
@@ -349,11 +368,14 @@ export function getElevationProfile(steps, unitConversion = 1) {
|
|
|
349
368
|
*
|
|
350
369
|
* @see https://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393
|
|
351
370
|
*/
|
|
352
|
-
export function getTextWidth(text, font = "22px Arial") {
|
|
371
|
+
export function getTextWidth(text: string, font = "22px Arial"): number {
|
|
372
|
+
// Create custom type for function including re-used canvas object
|
|
373
|
+
type GetTextWidth = typeof getTextWidth & { canvas: HTMLCanvasElement };
|
|
374
|
+
|
|
353
375
|
// re-use canvas object for better performance
|
|
354
376
|
const canvas =
|
|
355
|
-
getTextWidth.canvas ||
|
|
356
|
-
(getTextWidth.canvas = document.createElement("canvas"));
|
|
377
|
+
(getTextWidth as GetTextWidth).canvas ||
|
|
378
|
+
((getTextWidth as GetTextWidth).canvas = document.createElement("canvas"));
|
|
357
379
|
const context = canvas.getContext("2d");
|
|
358
380
|
context.font = font;
|
|
359
381
|
const metrics = context.measureText(text);
|
|
@@ -364,7 +386,10 @@ export function getTextWidth(text, font = "22px Arial") {
|
|
|
364
386
|
* Get the configured company object for the given network string if the company
|
|
365
387
|
* has been defined in the provided companies array config.
|
|
366
388
|
*/
|
|
367
|
-
export function getCompanyForNetwork(
|
|
389
|
+
export function getCompanyForNetwork(
|
|
390
|
+
networkString: string,
|
|
391
|
+
companies: Company[] = []
|
|
392
|
+
): Company {
|
|
368
393
|
const company = companies.find(co => co.id === networkString);
|
|
369
394
|
if (!company) {
|
|
370
395
|
console.warn(
|
|
@@ -382,7 +407,10 @@ export function getCompanyForNetwork(networkString, companies = []) {
|
|
|
382
407
|
* @param {Array<object>} [companies=[]] An optional list of the companies config.
|
|
383
408
|
* @return {string} A label for use in presentation on a website.
|
|
384
409
|
*/
|
|
385
|
-
export function getCompaniesLabelFromNetworks(
|
|
410
|
+
export function getCompaniesLabelFromNetworks(
|
|
411
|
+
networks: string[],
|
|
412
|
+
companies: Company[] = []
|
|
413
|
+
): string {
|
|
386
414
|
return networks
|
|
387
415
|
.map(network => getCompanyForNetwork(network, companies))
|
|
388
416
|
.filter(co => !!co)
|
|
@@ -390,12 +418,18 @@ export function getCompaniesLabelFromNetworks(networks, companies = []) {
|
|
|
390
418
|
.join("/");
|
|
391
419
|
}
|
|
392
420
|
|
|
393
|
-
export function getTNCLocation(leg, type) {
|
|
421
|
+
export function getTNCLocation(leg: Leg, type: string): string {
|
|
394
422
|
const location = leg[type];
|
|
395
423
|
return `${location.lat.toFixed(5)},${location.lon.toFixed(5)}`;
|
|
396
424
|
}
|
|
397
425
|
|
|
398
|
-
export function calculatePhysicalActivity(
|
|
426
|
+
export function calculatePhysicalActivity(
|
|
427
|
+
itinerary: Itinerary
|
|
428
|
+
): {
|
|
429
|
+
bikeDuration: number;
|
|
430
|
+
caloriesBurned: number;
|
|
431
|
+
walkDuration: number;
|
|
432
|
+
} {
|
|
399
433
|
let walkDuration = 0;
|
|
400
434
|
let bikeDuration = 0;
|
|
401
435
|
itinerary.legs.forEach(leg => {
|
package/src/{map.js → map.ts}
RENAMED
|
@@ -1,9 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Company,
|
|
3
|
+
Itinerary,
|
|
4
|
+
LatLngArray,
|
|
5
|
+
Leg,
|
|
6
|
+
Location,
|
|
7
|
+
TransitiveData,
|
|
8
|
+
UserPosition
|
|
9
|
+
} from "@opentripplanner/types";
|
|
1
10
|
import {
|
|
2
11
|
getPlaceName,
|
|
3
|
-
|
|
12
|
+
isAccessMode,
|
|
4
13
|
isFlex,
|
|
5
|
-
|
|
6
|
-
|
|
14
|
+
isTransit,
|
|
15
|
+
toSentenceCase
|
|
7
16
|
} from "./itinerary";
|
|
8
17
|
|
|
9
18
|
import {
|
|
@@ -15,7 +24,9 @@ import {
|
|
|
15
24
|
|
|
16
25
|
export { coordsToString, getDetailText, latlngToString };
|
|
17
26
|
|
|
18
|
-
export function currentPositionToLocation(
|
|
27
|
+
export function currentPositionToLocation(
|
|
28
|
+
currentPosition: UserPosition
|
|
29
|
+
): Location {
|
|
19
30
|
if (currentPosition.error || !currentPosition.coords) {
|
|
20
31
|
console.warn(
|
|
21
32
|
"Cannot construct location from current position due to geolocation error or missing coordinates."
|
|
@@ -29,18 +40,24 @@ export function currentPositionToLocation(currentPosition) {
|
|
|
29
40
|
};
|
|
30
41
|
}
|
|
31
42
|
|
|
32
|
-
export function stringToCoords(str) {
|
|
43
|
+
export function stringToCoords(str: string): number[] {
|
|
33
44
|
return (str && str.split(",").map(c => +c)) || [];
|
|
34
45
|
}
|
|
35
46
|
|
|
36
|
-
export function constructLocation(latlng
|
|
47
|
+
export function constructLocation(latlng: {
|
|
48
|
+
lat: number;
|
|
49
|
+
lng: number;
|
|
50
|
+
}): Location {
|
|
37
51
|
return {
|
|
38
52
|
lat: latlng.lat,
|
|
39
53
|
lon: latlng.lng
|
|
40
54
|
};
|
|
41
55
|
}
|
|
42
56
|
|
|
43
|
-
export function formatStoredPlaceName(
|
|
57
|
+
export function formatStoredPlaceName(
|
|
58
|
+
location: Location,
|
|
59
|
+
withDetails = true
|
|
60
|
+
): string {
|
|
44
61
|
if (withDetails) {
|
|
45
62
|
logDeprecationWarning("the formatStoredPlaceName withDetails parameter");
|
|
46
63
|
}
|
|
@@ -56,7 +73,7 @@ export function formatStoredPlaceName(location, withDetails = true) {
|
|
|
56
73
|
return displayName;
|
|
57
74
|
}
|
|
58
75
|
|
|
59
|
-
export function matchLatLon(location1, location2) {
|
|
76
|
+
export function matchLatLon(location1: Location, location2: Location): boolean {
|
|
60
77
|
if (!location1 || !location2) return location1 === location2;
|
|
61
78
|
return location1.lat === location2.lat && location1.lon === location2.lon;
|
|
62
79
|
}
|
|
@@ -70,11 +87,11 @@ export function matchLatLon(location1, location2) {
|
|
|
70
87
|
* @returns An itinerary in the transitive.js format.
|
|
71
88
|
*/
|
|
72
89
|
export function itineraryToTransitive(
|
|
73
|
-
itin,
|
|
74
|
-
companies,
|
|
75
|
-
getRouteLabel,
|
|
76
|
-
disableFlexArc
|
|
77
|
-
) {
|
|
90
|
+
itin: Itinerary,
|
|
91
|
+
companies: Company[],
|
|
92
|
+
getRouteLabel: (leg: Leg) => string,
|
|
93
|
+
disableFlexArc: boolean
|
|
94
|
+
): TransitiveData {
|
|
78
95
|
const tdata = {
|
|
79
96
|
journeys: [],
|
|
80
97
|
streetEdges: [],
|
|
@@ -109,20 +126,17 @@ export function itineraryToTransitive(
|
|
|
109
126
|
|
|
110
127
|
itin.legs.forEach((leg, idx) => {
|
|
111
128
|
if (isAccessMode(leg.mode)) {
|
|
112
|
-
let fromPlaceId;
|
|
113
|
-
if (
|
|
114
|
-
leg.from.bikeShareId &&
|
|
115
|
-
(leg.mode === "BICYCLE" || leg.mode === "BICYCLE_RENT")
|
|
116
|
-
) {
|
|
129
|
+
let fromPlaceId: string;
|
|
130
|
+
if (leg.from.bikeShareId) {
|
|
117
131
|
fromPlaceId = `bicycle_rent_station_${leg.from.bikeShareId}`;
|
|
118
132
|
if (
|
|
119
133
|
// OTP2 Scooter case
|
|
120
134
|
leg.mode === "SCOOTER"
|
|
121
135
|
) {
|
|
122
|
-
fromPlaceId = `escooter_rent_station_${leg.from.
|
|
136
|
+
fromPlaceId = `escooter_rent_station_${leg.from.bikeShareId}`;
|
|
123
137
|
}
|
|
124
|
-
// OTP1 Scooter case
|
|
125
138
|
} else if (leg.from.vertexType === "VEHICLERENTAL") {
|
|
139
|
+
// OTP1 Scooter case
|
|
126
140
|
fromPlaceId = `escooter_rent_station_${leg.from.name}`;
|
|
127
141
|
} else if (
|
|
128
142
|
leg.mode === "CAR" &&
|
|
@@ -131,13 +145,18 @@ export function itineraryToTransitive(
|
|
|
131
145
|
) {
|
|
132
146
|
// create a special place ID for car legs preceded by walking legs
|
|
133
147
|
fromPlaceId = `itin_car_${streetEdgeId}_from`;
|
|
134
|
-
} else {
|
|
148
|
+
} else if (!fromPlaceId) {
|
|
135
149
|
fromPlaceId = `itin_street_${streetEdgeId}_from`;
|
|
136
150
|
}
|
|
137
151
|
|
|
138
152
|
let toPlaceId;
|
|
139
153
|
if (leg.to.bikeShareId) {
|
|
140
154
|
toPlaceId = `bicycle_rent_station_${leg.to.bikeShareId}`;
|
|
155
|
+
// OTP2 scooter case
|
|
156
|
+
// Need to check next leg since this is a "to" place "
|
|
157
|
+
if (leg.mode === "SCOOTER" || itin.legs?.[idx + 1].mode === "SCOOTER") {
|
|
158
|
+
toPlaceId = `escooter_rent_station_${leg.to.bikeShareId}`;
|
|
159
|
+
}
|
|
141
160
|
} else if (leg.to.vertexType === "VEHICLERENTAL") {
|
|
142
161
|
toPlaceId = `escooter_rent_station_${leg.to.name}`;
|
|
143
162
|
} else if (
|
|
@@ -147,11 +166,12 @@ export function itineraryToTransitive(
|
|
|
147
166
|
) {
|
|
148
167
|
// create a special place ID for car legs followed by walking legs
|
|
149
168
|
toPlaceId = `itin_car_${streetEdgeId}_to`;
|
|
150
|
-
} else {
|
|
169
|
+
} else if (!toPlaceId) {
|
|
151
170
|
toPlaceId = `itin_street_${streetEdgeId}_to`;
|
|
152
171
|
}
|
|
153
172
|
|
|
154
173
|
const segment = {
|
|
174
|
+
arc: false,
|
|
155
175
|
type: leg.mode,
|
|
156
176
|
streetEdges: [streetEdgeId],
|
|
157
177
|
from: { type: "PLACE", place_id: fromPlaceId },
|
|
@@ -307,27 +327,30 @@ export function itineraryToTransitive(
|
|
|
307
327
|
return tdata;
|
|
308
328
|
}
|
|
309
329
|
|
|
310
|
-
|
|
330
|
+
type TransitivePlaceRaw = {
|
|
331
|
+
place_id: string;
|
|
332
|
+
};
|
|
333
|
+
export function isBikeshareStation(place: TransitivePlaceRaw): boolean {
|
|
311
334
|
return place.place_id.lastIndexOf("bicycle_rent_station") !== -1;
|
|
312
335
|
}
|
|
313
336
|
|
|
314
|
-
export function isEScooterStation(place) {
|
|
337
|
+
export function isEScooterStation(place: TransitivePlaceRaw): boolean {
|
|
315
338
|
return place.place_id.lastIndexOf("escooter_rent_station") !== -1;
|
|
316
339
|
}
|
|
317
340
|
|
|
318
|
-
export function isCarWalkTransition(place) {
|
|
341
|
+
export function isCarWalkTransition(place: TransitivePlaceRaw): boolean {
|
|
319
342
|
return place.place_id.lastIndexOf("itin_car_") !== -1;
|
|
320
343
|
}
|
|
321
344
|
|
|
322
|
-
export function isValidLat(lat) {
|
|
345
|
+
export function isValidLat(lat: number): boolean {
|
|
323
346
|
return Number.isFinite(lat) && lat >= -90 && lat <= 90;
|
|
324
347
|
}
|
|
325
348
|
|
|
326
|
-
export function isValidLng(lng) {
|
|
349
|
+
export function isValidLng(lng: number): boolean {
|
|
327
350
|
return Number.isFinite(lng) && lng >= -180 && lng <= 180;
|
|
328
351
|
}
|
|
329
352
|
|
|
330
|
-
export function isValidLatLng(arr) {
|
|
353
|
+
export function isValidLatLng(arr: LatLngArray): boolean {
|
|
331
354
|
return (
|
|
332
355
|
Array.isArray(arr) &&
|
|
333
356
|
arr.length === 2 &&
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Leg, Route, TransitOperator } from "@opentripplanner/types";
|
|
1
2
|
/**
|
|
2
3
|
* Returns the transit operator (if an exact match is found) from the transit
|
|
3
4
|
* operators config value. It is critical to use both the feedId and agencyId in
|
|
@@ -11,10 +12,10 @@
|
|
|
11
12
|
* was found
|
|
12
13
|
*/
|
|
13
14
|
export function getTransitOperatorFromFeedIdAndAgencyId(
|
|
14
|
-
feedId,
|
|
15
|
-
agencyId,
|
|
16
|
-
transitOperators
|
|
17
|
-
) {
|
|
15
|
+
feedId: string,
|
|
16
|
+
agencyId: string | number,
|
|
17
|
+
transitOperators: TransitOperator[]
|
|
18
|
+
): TransitOperator {
|
|
18
19
|
return (
|
|
19
20
|
transitOperators.find(
|
|
20
21
|
transitOperator =>
|
|
@@ -32,7 +33,10 @@ export function getTransitOperatorFromFeedIdAndAgencyId(
|
|
|
32
33
|
* @param {object} transitOperators transitOperators from config.
|
|
33
34
|
* @return {object} the operator if one was found or null if no match was found
|
|
34
35
|
*/
|
|
35
|
-
export function getTransitOperatorFromLeg(
|
|
36
|
+
export function getTransitOperatorFromLeg(
|
|
37
|
+
leg: Leg,
|
|
38
|
+
transitOperators: TransitOperator[]
|
|
39
|
+
): TransitOperator {
|
|
36
40
|
if (!leg.routeId || !leg.agencyId) return null;
|
|
37
41
|
const feedId = leg.routeId.split(":")[0];
|
|
38
42
|
return getTransitOperatorFromFeedIdAndAgencyId(
|
|
@@ -52,10 +56,13 @@ export function getTransitOperatorFromLeg(leg, transitOperators) {
|
|
|
52
56
|
* @param {array} transitOperators transitOperators from config
|
|
53
57
|
* @return {object} the operator if one was found or null if no match was found
|
|
54
58
|
*/
|
|
55
|
-
export function getTransitOperatorFromOtpRoute(
|
|
59
|
+
export function getTransitOperatorFromOtpRoute(
|
|
60
|
+
route: Route,
|
|
61
|
+
transitOperators: TransitOperator[]
|
|
62
|
+
): TransitOperator {
|
|
56
63
|
if (!route.id) return null;
|
|
57
64
|
const feedId = route.id.split(":")[0];
|
|
58
|
-
let agencyId;
|
|
65
|
+
let agencyId: string | number;
|
|
59
66
|
if (route.agency) {
|
|
60
67
|
// This is returned in the OTP Route model
|
|
61
68
|
agencyId = route.agency.id;
|
|
@@ -97,7 +104,10 @@ const END_OF_LIST_COMPARATOR_VALUE = 999999999999;
|
|
|
97
104
|
* the transitOperators value is not defined. Otherwise an integer will be
|
|
98
105
|
* returned.
|
|
99
106
|
*/
|
|
100
|
-
function getTransitOperatorComparatorValue(
|
|
107
|
+
function getTransitOperatorComparatorValue(
|
|
108
|
+
route: Route,
|
|
109
|
+
transitOperators: TransitOperator[]
|
|
110
|
+
): number | string {
|
|
101
111
|
// if the transitOperators is undefined or has zero length, use the route's
|
|
102
112
|
// agency name as the comparator value
|
|
103
113
|
if (!transitOperators || transitOperators.length === 0) {
|
|
@@ -129,8 +139,8 @@ function getTransitOperatorComparatorValue(route, transitOperators) {
|
|
|
129
139
|
* Calculates the sort comparator value given two routes based off of the
|
|
130
140
|
* route's agency and provided transitOperators config data.
|
|
131
141
|
*/
|
|
132
|
-
function makeTransitOperatorComparator(transitOperators) {
|
|
133
|
-
return (a, b) => {
|
|
142
|
+
function makeTransitOperatorComparator(transitOperators: TransitOperator[]) {
|
|
143
|
+
return (a: Route, b: Route) => {
|
|
134
144
|
const aVal = getTransitOperatorComparatorValue(a, transitOperators);
|
|
135
145
|
const bVal = getTransitOperatorComparatorValue(b, transitOperators);
|
|
136
146
|
if (typeof aVal === "string") {
|
|
@@ -140,8 +150,7 @@ function makeTransitOperatorComparator(transitOperators) {
|
|
|
140
150
|
if (aVal > bVal) return 1;
|
|
141
151
|
return 0;
|
|
142
152
|
}
|
|
143
|
-
|
|
144
|
-
// transitOperators are defined and therefore a numeric value is guaranteed
|
|
153
|
+
// @ts-expect-error transitOperators are defined and therefore a numeric value is guaranteed
|
|
145
154
|
// to be returned
|
|
146
155
|
return aVal - bVal;
|
|
147
156
|
};
|
|
@@ -151,9 +160,13 @@ function makeTransitOperatorComparator(transitOperators) {
|
|
|
151
160
|
* Gets the desired sort values according to an optional getter function. If the
|
|
152
161
|
* getter function is not defined, the original sort values are returned.
|
|
153
162
|
*/
|
|
154
|
-
function getSortValues(
|
|
155
|
-
|
|
156
|
-
|
|
163
|
+
function getSortValues(
|
|
164
|
+
getterFn: (item: unknown) => unknown,
|
|
165
|
+
a: unknown,
|
|
166
|
+
b: unknown
|
|
167
|
+
) {
|
|
168
|
+
let aVal: unknown;
|
|
169
|
+
let bVal: unknown;
|
|
157
170
|
if (typeof getterFn === "function") {
|
|
158
171
|
aVal = getterFn(a);
|
|
159
172
|
bVal = getterFn(b);
|
|
@@ -199,11 +212,11 @@ const routeTypeComparatorValue = {
|
|
|
199
212
|
// Gets a comparator value for a given route's type (OTP mode).
|
|
200
213
|
// Note: JSDoc format not used to avoid bug in documentationjs.
|
|
201
214
|
// ttps://github.com/documentationjs/documentation/issues/372
|
|
202
|
-
function getRouteTypeComparatorValue(route) {
|
|
215
|
+
function getRouteTypeComparatorValue(route: Route): number {
|
|
203
216
|
// For some strange reason, the short route response in OTP returns the
|
|
204
217
|
// string-based modes, but the long route response returns the
|
|
205
218
|
// integer route type. This attempts to account for both of those cases.
|
|
206
|
-
if (!route) throw new Error(
|
|
219
|
+
if (!route) throw new Error(`Route is undefined. ${route}`);
|
|
207
220
|
if (typeof modeComparatorValue[route.mode] !== "undefined") {
|
|
208
221
|
return modeComparatorValue[route.mode];
|
|
209
222
|
}
|
|
@@ -212,6 +225,7 @@ function getRouteTypeComparatorValue(route) {
|
|
|
212
225
|
}
|
|
213
226
|
// Default the comparator value to a large number (placing the route at the
|
|
214
227
|
// end of the list).
|
|
228
|
+
// eslint-disable-next-line no-console
|
|
215
229
|
console.warn("no mode/route type found for route", route);
|
|
216
230
|
return END_OF_LIST_COMPARATOR_VALUE;
|
|
217
231
|
}
|
|
@@ -220,7 +234,7 @@ function getRouteTypeComparatorValue(route) {
|
|
|
220
234
|
* Calculates the sort comparator value given two routes based off of route type
|
|
221
235
|
* (OTP mode).
|
|
222
236
|
*/
|
|
223
|
-
function routeTypeComparator(a, b) {
|
|
237
|
+
function routeTypeComparator(a: Route, b: Route): number {
|
|
224
238
|
return getRouteTypeComparatorValue(a) - getRouteTypeComparatorValue(b);
|
|
225
239
|
}
|
|
226
240
|
|
|
@@ -228,7 +242,7 @@ function routeTypeComparator(a, b) {
|
|
|
228
242
|
* Determines whether a value is a string that starts with an alphabetic
|
|
229
243
|
* ascii character.
|
|
230
244
|
*/
|
|
231
|
-
function startsWithAlphabeticCharacter(val) {
|
|
245
|
+
function startsWithAlphabeticCharacter(val: unknown): boolean {
|
|
232
246
|
if (typeof val === "string" && val.length > 0) {
|
|
233
247
|
const firstCharCode = val.charCodeAt(0);
|
|
234
248
|
return (
|
|
@@ -244,7 +258,7 @@ function startsWithAlphabeticCharacter(val) {
|
|
|
244
258
|
* character. Routes with shortn that do start with an alphabetic character will
|
|
245
259
|
* be prioritized over those that don't.
|
|
246
260
|
*/
|
|
247
|
-
function alphabeticShortNameComparator(a, b) {
|
|
261
|
+
function alphabeticShortNameComparator(a: Route, b: Route): number {
|
|
248
262
|
const aStartsWithAlphabeticCharacter = startsWithAlphabeticCharacter(
|
|
249
263
|
a.shortName
|
|
250
264
|
);
|
|
@@ -284,11 +298,15 @@ function alphabeticShortNameComparator(a, b) {
|
|
|
284
298
|
* @param {function} [objGetterFn] An optional function to obtain the
|
|
285
299
|
* comparison value from the comparator function arguments
|
|
286
300
|
*/
|
|
287
|
-
export function makeNumericValueComparator(
|
|
301
|
+
export function makeNumericValueComparator(
|
|
302
|
+
objGetterFn?: (item: Route) => number
|
|
303
|
+
) {
|
|
288
304
|
/* Note: Using the global version of isNaN (the Number version behaves differently. */
|
|
289
305
|
/* eslint-disable no-restricted-globals */
|
|
290
|
-
return (a, b) => {
|
|
306
|
+
return (a: number, b: number): number => {
|
|
291
307
|
const { aVal, bVal } = getSortValues(objGetterFn, a, b);
|
|
308
|
+
if (typeof aVal !== "number" || typeof bVal !== "number") return 0;
|
|
309
|
+
|
|
292
310
|
// if both values aren't valid numbers, use the next sort criteria
|
|
293
311
|
if (isNaN(aVal) && isNaN(bVal)) return 0;
|
|
294
312
|
// b is a valid number, b gets priority
|
|
@@ -310,8 +328,10 @@ export function makeNumericValueComparator(objGetterFn) {
|
|
|
310
328
|
* @param {function} [objGetterFn] An optional function to obtain the
|
|
311
329
|
* comparison value from the comparator function arguments
|
|
312
330
|
*/
|
|
313
|
-
export function makeStringValueComparator(
|
|
314
|
-
|
|
331
|
+
export function makeStringValueComparator(
|
|
332
|
+
objGetterFn?: (item: Route) => string
|
|
333
|
+
) {
|
|
334
|
+
return (a: string, b: string): number => {
|
|
315
335
|
const { aVal, bVal } = getSortValues(objGetterFn, a, b);
|
|
316
336
|
// both a and b are uncomparable strings, return equivalent value
|
|
317
337
|
if (!aVal && !bVal) return 0;
|
|
@@ -334,7 +354,7 @@ export function makeStringValueComparator(objGetterFn) {
|
|
|
334
354
|
* See https://github.com/opentripplanner/OpenTripPlanner/issues/2938
|
|
335
355
|
* Also see https://github.com/opentripplanner/otp-react-redux/issues/122
|
|
336
356
|
*/
|
|
337
|
-
function getRouteSortOrderValue(val) {
|
|
357
|
+
function getRouteSortOrderValue(val: number): number {
|
|
338
358
|
return val === -999 ? undefined : val;
|
|
339
359
|
}
|
|
340
360
|
|
|
@@ -345,8 +365,10 @@ function getRouteSortOrderValue(val) {
|
|
|
345
365
|
* returned. If all comparison functions return equivalence, then the values
|
|
346
366
|
* are assumed to be equivalent.
|
|
347
367
|
*/
|
|
348
|
-
function makeMultiCriteriaSort(
|
|
349
|
-
|
|
368
|
+
function makeMultiCriteriaSort(
|
|
369
|
+
...criteria: ((a: unknown, b: unknown) => number)[]
|
|
370
|
+
) {
|
|
371
|
+
return (a: number, b: number): number => {
|
|
350
372
|
for (let i = 0; i < criteria.length; i++) {
|
|
351
373
|
const curCriteriaComparatorValue = criteria[i](a, b);
|
|
352
374
|
// if the comparison objects are not equivalent, return the value obtained
|
|
@@ -390,7 +412,9 @@ function makeMultiCriteriaSort(...criteria) {
|
|
|
390
412
|
* those with shortNames.
|
|
391
413
|
* 7. longName as string.
|
|
392
414
|
*/
|
|
393
|
-
export function makeRouteComparator(
|
|
415
|
+
export function makeRouteComparator(
|
|
416
|
+
transitOperators: TransitOperator[]
|
|
417
|
+
): (a: number, b: number) => number {
|
|
394
418
|
return makeMultiCriteriaSort(
|
|
395
419
|
makeTransitOperatorComparator(transitOperators),
|
|
396
420
|
makeNumericValueComparator(obj => getRouteSortOrderValue(obj.sortOrder)),
|