@opentripplanner/core-utils 14.3.1 → 14.3.3

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/lib/itinerary.js CHANGED
@@ -1,344 +1,387 @@
1
- import polyline from "@mapbox/polyline";
2
- import turfAlong from "@turf/along";
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.calculateEmissions = calculateEmissions;
8
+ exports.calculatePhysicalActivity = calculatePhysicalActivity;
9
+ exports.calculateTncFares = calculateTncFares;
10
+ exports.containsGeometry = containsGeometry;
11
+ exports.descope = exports.convertGraphQLResponseToLegacy = void 0;
12
+ exports.endsWithGeometry = endsWithGeometry;
13
+ exports.getCompaniesLabelFromNetworks = getCompaniesLabelFromNetworks;
14
+ exports.getCompanyForNetwork = getCompanyForNetwork;
15
+ exports.getCompanyFromLeg = getCompanyFromLeg;
16
+ exports.getDisplayedStopCode = getDisplayedStopCode;
17
+ exports.getElevationProfile = getElevationProfile;
18
+ exports.getItineraryBounds = getItineraryBounds;
19
+ exports.getItineraryCost = getItineraryCost;
20
+ exports.getLegBounds = getLegBounds;
21
+ exports.getLegCost = getLegCost;
22
+ exports.getLegRouteShortName = exports.getLegRouteName = exports.getLegRouteLongName = void 0;
23
+ exports.getMapColor = getMapColor;
24
+ exports.getTNCLocation = getTNCLocation;
25
+ exports.getTextWidth = getTextWidth;
26
+ exports.getTransitModes = getTransitModes;
27
+ exports.hasBike = hasBike;
28
+ exports.hasCar = hasCar;
29
+ exports.hasHail = hasHail;
30
+ exports.hasMicromobility = hasMicromobility;
31
+ exports.hasRental = hasRental;
32
+ exports.hasTransit = hasTransit;
33
+ exports.isAccessMode = isAccessMode;
34
+ exports.isAdvanceBookingRequired = isAdvanceBookingRequired;
35
+ exports.isBicycle = isBicycle;
36
+ exports.isBicycleRent = isBicycleRent;
37
+ exports.isCar = isCar;
38
+ exports.isCoordinationRequired = isCoordinationRequired;
39
+ exports.isFlex = isFlex;
40
+ exports.isMicromobility = isMicromobility;
41
+ exports.isReservationRequired = isReservationRequired;
42
+ exports.isRideshareLeg = isRideshareLeg;
43
+ exports.isTransit = isTransit;
44
+ exports.isTransitLeg = isTransitLeg;
45
+ exports.isWalk = isWalk;
46
+ exports.legContainsGeometry = legContainsGeometry;
47
+ exports.legDropoffRequiresAdvanceBooking = legDropoffRequiresAdvanceBooking;
48
+ exports.legElevationAtDistance = legElevationAtDistance;
49
+ exports.legLocationAtDistance = legLocationAtDistance;
50
+ exports.mapOldElevationComponentToNew = mapOldElevationComponentToNew;
51
+ exports.startsWithGeometry = startsWithGeometry;
52
+ exports.toSentenceCase = toSentenceCase;
53
+ exports.zeroDollars = exports.transitModes = void 0;
54
+ var _polyline = _interopRequireDefault(require("@mapbox/polyline"));
55
+ var _along = _interopRequireDefault(require("@turf/along"));
3
56
  // All OTP transit modes
4
- export const transitModes = [
5
- "TRAM",
6
- "TROLLEYBUS",
7
- "BUS",
8
- "SUBWAY",
9
- "FERRY",
10
- "RAIL",
11
- "GONDOLA"
12
- ];
57
+ const transitModes = exports.transitModes = ["TRAM", "TROLLEYBUS", "BUS", "SUBWAY", "FERRY", "RAIL", "GONDOLA"];
58
+
13
59
  /**
14
60
  * @param {config} config OTP-RR configuration object
15
61
  * @return {Array} List of all transit modes defined in config; otherwise default mode list
16
62
  */
17
- export function getTransitModes(config) {
18
- if (!config || !config.modes || !config.modes.transitModes)
19
- return transitModes;
20
- return config.modes.transitModes.map(tm => typeof tm !== "string" ? tm.mode : tm);
63
+
64
+ function getTransitModes(config) {
65
+ if (!config || !config.modes || !config.modes.transitModes) return transitModes;
66
+ return config.modes.transitModes.map(tm => typeof tm !== "string" ? tm.mode : tm);
21
67
  }
22
- export function isTransitLeg(leg) {
23
- return leg.transitLeg;
68
+ function isTransitLeg(leg) {
69
+ return leg.transitLeg;
24
70
  }
25
- export function isTransit(mode) {
26
- return transitModes.includes(mode) || mode === "TRANSIT";
71
+ function isTransit(mode) {
72
+ return transitModes.includes(mode) || mode === "TRANSIT";
27
73
  }
74
+
28
75
  /**
29
76
  * Returns true if the leg pickup rules enabled which require
30
77
  * calling ahead for the service to run. "mustPhone" is the only
31
78
  * property which encodes this info.
32
79
  */
33
- export function isReservationRequired(leg) {
34
- return (leg === null || leg === void 0 ? void 0 : leg.boardRule) === "mustPhone" || (leg === null || leg === void 0 ? void 0 : leg.alightRule) === "mustPhone";
80
+ function isReservationRequired(leg) {
81
+ return (leg === null || leg === void 0 ? void 0 : leg.boardRule) === "mustPhone" || (leg === null || leg === void 0 ? void 0 : leg.alightRule) === "mustPhone";
35
82
  }
36
83
  /**
37
84
  * Returns true if a user must ask the driver to let the user off
38
85
  * or if the user must flag the driver down for pickup.
39
86
  * "coordinateWithDriver" in board/alight rule encodes this info.
40
87
  */
41
- export function isCoordinationRequired(leg) {
42
- return ((leg === null || leg === void 0 ? void 0 : leg.boardRule) === "coordinateWithDriver" ||
43
- (leg === null || leg === void 0 ? void 0 : leg.alightRule) === "coordinateWithDriver");
88
+ function isCoordinationRequired(leg) {
89
+ return (leg === null || leg === void 0 ? void 0 : leg.boardRule) === "coordinateWithDriver" || (leg === null || leg === void 0 ? void 0 : leg.alightRule) === "coordinateWithDriver";
44
90
  }
45
- export function containsGeometry(place) {
46
- var _a, _b;
47
- return (((_a = place === null || place === void 0 ? void 0 : place.stop) === null || _a === void 0 ? void 0 : _a.geometries) !== null && ((_b = place === null || place === void 0 ? void 0 : place.stop) === null || _b === void 0 ? void 0 : _b.geometries) !== undefined);
91
+ function containsGeometry(place) {
92
+ var _place$stop, _place$stop2;
93
+ return (place === null || place === void 0 || (_place$stop = place.stop) === null || _place$stop === void 0 ? void 0 : _place$stop.geometries) !== null && (place === null || place === void 0 || (_place$stop2 = place.stop) === null || _place$stop2 === void 0 ? void 0 : _place$stop2.geometries) !== undefined;
48
94
  }
49
- export function endsWithGeometry(leg) {
50
- return containsGeometry(leg === null || leg === void 0 ? void 0 : leg.to);
95
+ function endsWithGeometry(leg) {
96
+ return containsGeometry(leg === null || leg === void 0 ? void 0 : leg.to);
51
97
  }
52
- export function startsWithGeometry(leg) {
53
- return containsGeometry(leg === null || leg === void 0 ? void 0 : leg.from);
98
+ function startsWithGeometry(leg) {
99
+ return containsGeometry(leg === null || leg === void 0 ? void 0 : leg.from);
54
100
  }
55
- export function legContainsGeometry(leg) {
56
- return endsWithGeometry(leg) || startsWithGeometry(leg);
101
+ function legContainsGeometry(leg) {
102
+ return endsWithGeometry(leg) || startsWithGeometry(leg);
57
103
  }
58
- export function isAdvanceBookingRequired(info) {
59
- var _a;
60
- return ((_a = info === null || info === void 0 ? void 0 : info.latestBookingTime) === null || _a === void 0 ? void 0 : _a.daysPrior) > 0;
104
+ function isAdvanceBookingRequired(info) {
105
+ var _info$latestBookingTi;
106
+ return (info === null || info === void 0 || (_info$latestBookingTi = info.latestBookingTime) === null || _info$latestBookingTi === void 0 ? void 0 : _info$latestBookingTi.daysPrior) > 0;
61
107
  }
62
- export function legDropoffRequiresAdvanceBooking(leg) {
63
- return isAdvanceBookingRequired(leg === null || leg === void 0 ? void 0 : leg.dropOffBookingInfo);
108
+ function legDropoffRequiresAdvanceBooking(leg) {
109
+ return isAdvanceBookingRequired(leg === null || leg === void 0 ? void 0 : leg.dropOffBookingInfo);
64
110
  }
111
+
65
112
  /**
66
113
  * The two rules checked by the above two functions are the only values
67
114
  * returned by OTP when a leg is a flex leg.
68
115
  */
69
- export function isFlex(leg) {
70
- var _a;
71
- return (((_a = leg === null || leg === void 0 ? void 0 : leg.stopCalls) === null || _a === void 0 ? void 0 : _a.some(call => { var _a;
72
- // Flex calls are "Location" or "LocationGroup"
73
- // eslint-disable-next-line no-underscore-dangle
74
- return (_a = call === null || call === void 0 ? void 0 : call.stopLocation) === null || _a === void 0 ? void 0 : _a.__typename.startsWith("Location"); })) || false);
75
- }
76
- export function isRideshareLeg(leg) {
77
- var _a, _b;
78
- return !!((_b = (_a = leg.rideHailingEstimate) === null || _a === void 0 ? void 0 : _a.provider) === null || _b === void 0 ? void 0 : _b.id);
79
- }
80
- export function isWalk(mode) {
81
- if (!mode)
82
- return false;
83
- return mode === "WALK";
84
- }
85
- export function isBicycle(mode) {
86
- if (!mode)
87
- return false;
88
- return mode === "BICYCLE";
89
- }
90
- export function isBicycleRent(mode) {
91
- if (!mode)
92
- return false;
93
- return mode === "BICYCLE_RENT";
94
- }
95
- export function isCar(mode) {
96
- if (!mode)
97
- return false;
98
- return mode.startsWith("CAR");
99
- }
100
- export function isMicromobility(mode) {
101
- if (!mode)
102
- return false;
103
- return mode.startsWith("MICROMOBILITY") || mode.startsWith("SCOOTER");
104
- }
105
- export function isAccessMode(mode) {
106
- return (isWalk(mode) ||
107
- isBicycle(mode) ||
108
- isBicycleRent(mode) ||
109
- isCar(mode) ||
110
- isMicromobility(mode));
111
- }
116
+ function isFlex(leg) {
117
+ var _leg$stopCalls;
118
+ return (leg === null || leg === void 0 || (_leg$stopCalls = leg.stopCalls) === null || _leg$stopCalls === void 0 ? void 0 : _leg$stopCalls.some(call => {
119
+ var _call$stopLocation;
120
+ return (// Flex calls are "Location" or "LocationGroup"
121
+ // eslint-disable-next-line no-underscore-dangle
122
+ call === null || call === void 0 || (_call$stopLocation = call.stopLocation) === null || _call$stopLocation === void 0 ? void 0 : _call$stopLocation.__typename.startsWith("Location")
123
+ );
124
+ })) || false;
125
+ }
126
+ function isRideshareLeg(leg) {
127
+ var _leg$rideHailingEstim;
128
+ return !!((_leg$rideHailingEstim = leg.rideHailingEstimate) !== null && _leg$rideHailingEstim !== void 0 && (_leg$rideHailingEstim = _leg$rideHailingEstim.provider) !== null && _leg$rideHailingEstim !== void 0 && _leg$rideHailingEstim.id);
129
+ }
130
+ function isWalk(mode) {
131
+ if (!mode) return false;
132
+ return mode === "WALK";
133
+ }
134
+ function isBicycle(mode) {
135
+ if (!mode) return false;
136
+ return mode === "BICYCLE";
137
+ }
138
+ function isBicycleRent(mode) {
139
+ if (!mode) return false;
140
+ return mode === "BICYCLE_RENT";
141
+ }
142
+ function isCar(mode) {
143
+ if (!mode) return false;
144
+ return mode.startsWith("CAR");
145
+ }
146
+ function isMicromobility(mode) {
147
+ if (!mode) return false;
148
+ return mode.startsWith("MICROMOBILITY") || mode.startsWith("SCOOTER");
149
+ }
150
+ function isAccessMode(mode) {
151
+ return isWalk(mode) || isBicycle(mode) || isBicycleRent(mode) || isCar(mode) || isMicromobility(mode);
152
+ }
153
+
112
154
  /**
113
155
  * @param {string} modesStr a comma-separated list of OTP modes
114
156
  * @return {boolean} whether any of the modes are transit modes
115
157
  */
116
- export function hasTransit(modesStr) {
117
- return modesStr.split(",").some(mode => isTransit(mode));
158
+ function hasTransit(modesStr) {
159
+ return modesStr.split(",").some(mode => isTransit(mode));
118
160
  }
161
+
119
162
  /**
120
163
  * @param {string} modesStr a comma-separated list of OTP modes
121
164
  * @return {boolean} whether any of the modes are car-based modes
122
165
  */
123
- export function hasCar(modesStr) {
124
- return modesStr.split(",").some(mode => isCar(mode));
166
+ function hasCar(modesStr) {
167
+ return modesStr.split(",").some(mode => isCar(mode));
125
168
  }
169
+
126
170
  /**
127
171
  * @param {string} modesStr a comma-separated list of OTP modes
128
172
  * @return {boolean} whether any of the modes are bicycle-based modes
129
173
  */
130
- export function hasBike(modesStr) {
131
- return modesStr
132
- .split(",")
133
- .some(mode => isBicycle(mode) || isBicycleRent(mode));
174
+ function hasBike(modesStr) {
175
+ return modesStr.split(",").some(mode => isBicycle(mode) || isBicycleRent(mode));
134
176
  }
177
+
135
178
  /**
136
179
  * @param {string} modesStr a comma-separated list of OTP modes
137
180
  * @return {boolean} whether any of the modes are micromobility-based modes
138
181
  */
139
- export function hasMicromobility(modesStr) {
140
- return modesStr.split(",").some(mode => isMicromobility(mode));
182
+ function hasMicromobility(modesStr) {
183
+ return modesStr.split(",").some(mode => isMicromobility(mode));
141
184
  }
185
+
142
186
  /**
143
187
  * @param {string} modesStr a comma-separated list of OTP modes
144
188
  * @return {boolean} whether any of the modes is a hailing mode
145
189
  */
146
- export function hasHail(modesStr) {
147
- return modesStr.split(",").some(mode => mode.indexOf("_HAIL") > -1);
190
+ function hasHail(modesStr) {
191
+ return modesStr.split(",").some(mode => mode.indexOf("_HAIL") > -1);
148
192
  }
193
+
149
194
  /**
150
195
  * @param {string} modesStr a comma-separated list of OTP modes
151
196
  * @return {boolean} whether any of the modes is a rental mode
152
197
  */
153
- export function hasRental(modesStr) {
154
- return modesStr.split(",").some(mode => mode.indexOf("_RENT") > -1);
155
- }
156
- export function getMapColor(mode) {
157
- mode = mode || this.get("mode");
158
- if (mode === "WALK")
159
- return "#444";
160
- if (mode === "BICYCLE")
161
- return "#0073e5";
162
- if (mode === "SUBWAY")
163
- return "#e60000";
164
- if (mode === "RAIL")
165
- return "#b00";
166
- if (mode === "BUS")
167
- return "#080";
168
- if (mode === "TROLLEYBUS")
169
- return "#080";
170
- if (mode === "TRAM")
171
- return "#800";
172
- if (mode === "FERRY")
173
- return "#008";
174
- if (mode === "CAR")
175
- return "#444";
176
- if (mode === "MICROMOBILITY" || mode === "SCOOTER")
177
- return "#f5a729";
178
- return "#aaa";
179
- }
180
- export function toSentenceCase(str) {
181
- if (str == null) {
182
- return "";
183
- }
184
- str = String(str);
185
- return str.charAt(0).toUpperCase() + str.substr(1).toLowerCase();
186
- }
198
+ function hasRental(modesStr) {
199
+ return modesStr.split(",").some(mode => mode.indexOf("_RENT") > -1);
200
+ }
201
+ function getMapColor(mode) {
202
+ mode = mode || this.get("mode");
203
+ if (mode === "WALK") return "#444";
204
+ if (mode === "BICYCLE") return "#0073e5";
205
+ if (mode === "SUBWAY") return "#e60000";
206
+ if (mode === "RAIL") return "#b00";
207
+ if (mode === "BUS") return "#080";
208
+ if (mode === "TROLLEYBUS") return "#080";
209
+ if (mode === "TRAM") return "#800";
210
+ if (mode === "FERRY") return "#008";
211
+ if (mode === "CAR") return "#444";
212
+ if (mode === "MICROMOBILITY" || mode === "SCOOTER") return "#f5a729";
213
+ return "#aaa";
214
+ }
215
+ function toSentenceCase(str) {
216
+ if (str == null) {
217
+ return "";
218
+ }
219
+ str = String(str);
220
+ return str.charAt(0).toUpperCase() + str.substr(1).toLowerCase();
221
+ }
222
+
187
223
  /**
188
224
  * Derive the company string based on mode and network associated with leg.
189
225
  */
190
- export function getCompanyFromLeg(leg) {
191
- var _a;
192
- if (!leg)
193
- return null;
194
- const { from, mode, rentedBike, rentedCar, rentedVehicle, rideHailingEstimate } = leg;
195
- if (mode === "CAR" && rentedCar) {
196
- return from.networks[0];
197
- }
198
- if (mode === "CAR" && rideHailingEstimate) {
199
- return rideHailingEstimate.provider.id;
200
- }
201
- if (mode === "BICYCLE" && rentedBike && from.networks) {
202
- return from.networks[0];
203
- }
204
- if (from.rentalVehicle) {
205
- return from.rentalVehicle.network;
206
- }
207
- if ((_a = from.vehicleRentalStation) === null || _a === void 0 ? void 0 : _a.rentalNetwork) {
208
- return from.vehicleRentalStation.rentalNetwork.networkId;
209
- }
210
- if ((mode === "MICROMOBILITY" || mode === "SCOOTER") &&
211
- rentedVehicle &&
212
- from.networks) {
213
- return from.networks[0];
214
- }
215
- return null;
216
- }
217
- export function getItineraryBounds(itinerary) {
218
- let coords = [];
219
- itinerary.legs.forEach(leg => {
220
- const legCoords = polyline
221
- .toGeoJSON(leg.legGeometry.points)
222
- .coordinates.map((c) => [c[1], c[0]]);
223
- coords = [...coords, ...legCoords];
224
- });
225
- return coords;
226
- }
226
+ function getCompanyFromLeg(leg) {
227
+ var _from$vehicleRentalSt;
228
+ if (!leg) return null;
229
+ const {
230
+ from,
231
+ mode,
232
+ rentedBike,
233
+ rentedCar,
234
+ rentedVehicle,
235
+ rideHailingEstimate
236
+ } = leg;
237
+ if (mode === "CAR" && rentedCar) {
238
+ return from.networks[0];
239
+ }
240
+ if (mode === "CAR" && rideHailingEstimate) {
241
+ return rideHailingEstimate.provider.id;
242
+ }
243
+ if (mode === "BICYCLE" && rentedBike && from.networks) {
244
+ return from.networks[0];
245
+ }
246
+ if (from.rentalVehicle) {
247
+ return from.rentalVehicle.network;
248
+ }
249
+ if ((_from$vehicleRentalSt = from.vehicleRentalStation) !== null && _from$vehicleRentalSt !== void 0 && _from$vehicleRentalSt.rentalNetwork) {
250
+ return from.vehicleRentalStation.rentalNetwork.networkId;
251
+ }
252
+ if ((mode === "MICROMOBILITY" || mode === "SCOOTER") && rentedVehicle && from.networks) {
253
+ return from.networks[0];
254
+ }
255
+ return null;
256
+ }
257
+ function getItineraryBounds(itinerary) {
258
+ let coords = [];
259
+ itinerary.legs.forEach(leg => {
260
+ const legCoords = _polyline.default.toGeoJSON(leg.legGeometry.points).coordinates.map(c => [c[1], c[0]]);
261
+ coords = [...coords, ...legCoords];
262
+ });
263
+ return coords;
264
+ }
265
+
227
266
  /**
228
267
  * Return a coords object that encloses the given leg's geometry.
229
268
  */
230
- export function getLegBounds(leg) {
231
- const coords = polyline
232
- .toGeoJSON(leg.legGeometry.points)
233
- .coordinates.map(c => [c[1], c[0]]);
234
- // in certain cases, there might be zero-length coordinates in the leg
235
- // geometry. In these cases, build us an array of coordinates using the from
236
- // and to data of the leg.
237
- if (coords.length === 0) {
238
- coords.push([leg.from.lat, leg.from.lon], [leg.to.lat, leg.to.lon]);
239
- }
240
- return coords;
241
- }
269
+ function getLegBounds(leg) {
270
+ const coords = _polyline.default.toGeoJSON(leg.legGeometry.points).coordinates.map(c => [c[1], c[0]]);
271
+
272
+ // in certain cases, there might be zero-length coordinates in the leg
273
+ // geometry. In these cases, build us an array of coordinates using the from
274
+ // and to data of the leg.
275
+ if (coords.length === 0) {
276
+ coords.push([leg.from.lat, leg.from.lon], [leg.to.lat, leg.to.lon]);
277
+ }
278
+ return coords;
279
+ }
280
+
242
281
  /* Returns an interpolated lat-lon at a specified distance along a leg */
243
- export function legLocationAtDistance(leg, distance) {
244
- if (!leg.legGeometry)
245
- return null;
246
- try {
247
- const line = polyline.toGeoJSON(leg.legGeometry.points);
248
- const pt = turfAlong(line, distance, { units: "meters" });
249
- if (pt && pt.geometry && pt.geometry.coordinates) {
250
- return [pt.geometry.coordinates[1], pt.geometry.coordinates[0]];
251
- }
252
- }
253
- catch (e) {
254
- // FIXME handle error!
282
+
283
+ function legLocationAtDistance(leg, distance) {
284
+ if (!leg.legGeometry) return null;
285
+ try {
286
+ const line = _polyline.default.toGeoJSON(leg.legGeometry.points);
287
+ const pt = (0, _along.default)(line, distance, {
288
+ units: "meters"
289
+ });
290
+ if (pt && pt.geometry && pt.geometry.coordinates) {
291
+ return [pt.geometry.coordinates[1], pt.geometry.coordinates[0]];
255
292
  }
256
- return null;
293
+ } catch (e) {
294
+ // FIXME handle error!
295
+ }
296
+ return null;
257
297
  }
298
+
258
299
  /* Returns an interpolated elevation at a specified distance along a leg */
259
- export function legElevationAtDistance(points, distance) {
260
- // Iterate through the combined elevation profile
261
- let traversed = 0;
262
- // If first point distance is not zero, insert starting point at zero with
263
- // null elevation. Encountering this value should trigger the warning below.
264
- if (points[0][0] > 0) {
265
- points.unshift([0, null]);
266
- }
267
- for (let i = 1; i < points.length; i++) {
268
- const start = points[i - 1];
269
- const elevDistanceSpan = points[i][0] - start[0];
270
- if (distance >= traversed && distance <= traversed + elevDistanceSpan) {
271
- // Distance falls within this point and the previous one;
272
- // compute & return interpolated elevation value
273
- if (start[1] === null) {
274
- console.warn("Elevation value does not exist for distance.", distance, traversed);
275
- return null;
276
- }
277
- const pct = (distance - traversed) / elevDistanceSpan;
278
- const elevSpan = points[i][1] - start[1];
279
- return start[1] + elevSpan * pct;
280
- }
281
- traversed += elevDistanceSpan;
300
+
301
+ function legElevationAtDistance(points, distance) {
302
+ // Iterate through the combined elevation profile
303
+ let traversed = 0;
304
+ // If first point distance is not zero, insert starting point at zero with
305
+ // null elevation. Encountering this value should trigger the warning below.
306
+ if (points[0][0] > 0) {
307
+ points.unshift([0, null]);
308
+ }
309
+ for (let i = 1; i < points.length; i++) {
310
+ const start = points[i - 1];
311
+ const elevDistanceSpan = points[i][0] - start[0];
312
+ if (distance >= traversed && distance <= traversed + elevDistanceSpan) {
313
+ // Distance falls within this point and the previous one;
314
+ // compute & return interpolated elevation value
315
+ if (start[1] === null) {
316
+ console.warn("Elevation value does not exist for distance.", distance, traversed);
317
+ return null;
318
+ }
319
+ const pct = (distance - traversed) / elevDistanceSpan;
320
+ const elevSpan = points[i][1] - start[1];
321
+ return start[1] + elevSpan * pct;
282
322
  }
283
- console.warn("Elevation value does not exist for distance.", distance, traversed);
284
- return null;
285
- }
286
- export function mapOldElevationComponentToNew(oldElev) {
287
- return {
288
- distance: oldElev.first,
289
- elevation: oldElev.second
290
- };
291
- }
323
+ traversed += elevDistanceSpan;
324
+ }
325
+ console.warn("Elevation value does not exist for distance.", distance, traversed);
326
+ return null;
327
+ }
328
+ function mapOldElevationComponentToNew(oldElev) {
329
+ return {
330
+ distance: oldElev.first,
331
+ elevation: oldElev.second
332
+ };
333
+ }
334
+
292
335
  // Iterate through the steps, building the array of elevation points and
293
336
  // keeping track of the minimum and maximum elevations reached
294
- export function getElevationProfile(steps, unitConversion = 1) {
295
- let minElev = 100000;
296
- let maxElev = -100000;
297
- let traversed = 0;
298
- let gain = 0;
299
- let loss = 0;
300
- let previous = null;
301
- const points = [];
302
- steps.forEach(step => {
303
- var _a;
304
- // Support for old REST response data (in step.elevation)
305
- const stepElevationProfile = step.elevationProfile ||
306
- (Array.isArray(step.elevation) &&
307
- ((_a = step.elevation) === null || _a === void 0 ? void 0 : _a.map(mapOldElevationComponentToNew)));
308
- if (!stepElevationProfile || stepElevationProfile.length === 0) {
309
- traversed += step.distance;
310
- return;
311
- }
312
- for (let i = 0; i < stepElevationProfile.length; i++) {
313
- const elev = stepElevationProfile[i];
314
- if (previous) {
315
- const diff = (elev.elevation - previous.elevation) * unitConversion;
316
- if (diff > 0)
317
- gain += diff;
318
- else
319
- loss += diff;
320
- }
321
- if (i === 0 && elev.distance !== 0) {
322
- // console.warn(`No elevation data available for step ${stepIndex}-${i} at beginning of segment`, elev)
323
- }
324
- const convertedElevation = elev.elevation * unitConversion;
325
- if (convertedElevation < minElev)
326
- minElev = convertedElevation;
327
- if (convertedElevation > maxElev)
328
- maxElev = convertedElevation;
329
- points.push([traversed + elev.distance, elev.elevation]);
330
- // Insert "filler" point if the last point in elevation profile does not
331
- // reach the full distance of the step.
332
- if (i === stepElevationProfile.length - 1 &&
333
- elev.distance !== step.distance) {
334
- // points.push([traversed + step.distance, elev.second])
335
- }
336
- previous = elev;
337
- }
338
- traversed += step.distance;
339
- });
340
- return { maxElev, minElev, points, traversed, gain, loss };
341
- }
337
+ function getElevationProfile(steps, unitConversion = 1) {
338
+ let minElev = 100000;
339
+ let maxElev = -100000;
340
+ let traversed = 0;
341
+ let gain = 0;
342
+ let loss = 0;
343
+ let previous = null;
344
+ const points = [];
345
+ steps.forEach(step => {
346
+ var _step$elevation;
347
+ // Support for old REST response data (in step.elevation)
348
+ const stepElevationProfile = step.elevationProfile || Array.isArray(step.elevation) && ((_step$elevation = step.elevation) === null || _step$elevation === void 0 ? void 0 : _step$elevation.map(mapOldElevationComponentToNew));
349
+ if (!stepElevationProfile || stepElevationProfile.length === 0) {
350
+ traversed += step.distance;
351
+ return;
352
+ }
353
+ for (let i = 0; i < stepElevationProfile.length; i++) {
354
+ const elev = stepElevationProfile[i];
355
+ if (previous) {
356
+ const diff = (elev.elevation - previous.elevation) * unitConversion;
357
+ if (diff > 0) gain += diff;else loss += diff;
358
+ }
359
+ if (i === 0 && elev.distance !== 0) {
360
+ // console.warn(`No elevation data available for step ${stepIndex}-${i} at beginning of segment`, elev)
361
+ }
362
+ const convertedElevation = elev.elevation * unitConversion;
363
+ if (convertedElevation < minElev) minElev = convertedElevation;
364
+ if (convertedElevation > maxElev) maxElev = convertedElevation;
365
+ points.push([traversed + elev.distance, elev.elevation]);
366
+ // Insert "filler" point if the last point in elevation profile does not
367
+ // reach the full distance of the step.
368
+ if (i === stepElevationProfile.length - 1 && elev.distance !== step.distance) {
369
+ // points.push([traversed + step.distance, elev.second])
370
+ }
371
+ previous = elev;
372
+ }
373
+ traversed += step.distance;
374
+ });
375
+ return {
376
+ maxElev,
377
+ minElev,
378
+ points,
379
+ traversed,
380
+ gain,
381
+ loss
382
+ };
383
+ }
384
+
342
385
  /**
343
386
  * Uses canvas.measureText to compute and return the width of the given text of given font in pixels.
344
387
  *
@@ -347,26 +390,29 @@ export function getElevationProfile(steps, unitConversion = 1) {
347
390
  *
348
391
  * @see https://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393
349
392
  */
350
- export function getTextWidth(text, font = "22px Arial") {
351
- // reuse canvas object for better performance
352
- const canvas = getTextWidth.canvas ||
353
- (getTextWidth.canvas = document.createElement("canvas"));
354
- const context = canvas.getContext("2d");
355
- context.font = font;
356
- const metrics = context.measureText(text);
357
- return metrics.width;
358
- }
393
+ function getTextWidth(text, font = "22px Arial") {
394
+ // Create custom type for function including reused canvas object
395
+
396
+ // reuse canvas object for better performance
397
+ const canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement("canvas"));
398
+ const context = canvas.getContext("2d");
399
+ context.font = font;
400
+ const metrics = context.measureText(text);
401
+ return metrics.width;
402
+ }
403
+
359
404
  /**
360
405
  * Get the configured company object for the given network string if the company
361
406
  * has been defined in the provided companies array config.
362
407
  */
363
- export function getCompanyForNetwork(networkString, companies = []) {
364
- const company = companies.find(co => co.id === networkString);
365
- if (!company) {
366
- console.warn(`No company found in config.yml that matches rented vehicle network: ${networkString}`, companies);
367
- }
368
- return company;
369
- }
408
+ function getCompanyForNetwork(networkString, companies = []) {
409
+ const company = companies.find(co => co.id === networkString);
410
+ if (!company) {
411
+ console.warn(`No company found in config.yml that matches rented vehicle network: ${networkString}`, companies);
412
+ }
413
+ return company;
414
+ }
415
+
370
416
  /**
371
417
  * Get a string label to display from a list of vehicle rental networks. Returns
372
418
  * empty string if no networks provided.
@@ -375,57 +421,58 @@ export function getCompanyForNetwork(networkString, companies = []) {
375
421
  * @param {Array<object>} [companies=[]] An optional list of the companies config.
376
422
  * @return {string} A label for use in presentation on a website.
377
423
  */
378
- export function getCompaniesLabelFromNetworks(networks, companies = []) {
379
- if (!networks)
380
- return "";
381
- return (Array.isArray(networks) ? networks : [networks])
382
- .map(network => getCompanyForNetwork(network, companies))
383
- .filter(co => !!co)
384
- .map(co => co.label)
385
- .join("/");
386
- }
387
- export function getTNCLocation(leg, type) {
388
- const location = leg[type];
389
- return `${location.lat.toFixed(5)},${location.lon.toFixed(5)}`;
390
- }
391
- export function calculatePhysicalActivity(itinerary) {
392
- let walkDuration = 0;
393
- let bikeDuration = 0;
394
- itinerary.legs.forEach(leg => {
395
- if (leg.mode.startsWith("WALK"))
396
- walkDuration += leg.duration;
397
- if (leg.mode.startsWith("BICYCLE"))
398
- bikeDuration += leg.duration;
399
- });
400
- const caloriesBurned = (walkDuration / 3600) * 280 + (bikeDuration / 3600) * 290;
401
- return {
402
- bikeDuration,
403
- caloriesBurned,
404
- walkDuration
405
- };
406
- }
424
+ function getCompaniesLabelFromNetworks(networks, companies = []) {
425
+ if (!networks) return "";
426
+ return (Array.isArray(networks) ? networks : [networks]).map(network => getCompanyForNetwork(network, companies)).filter(co => !!co).map(co => co.label).join("/");
427
+ }
428
+ function getTNCLocation(leg, type) {
429
+ const location = leg[type];
430
+ return `${location.lat.toFixed(5)},${location.lon.toFixed(5)}`;
431
+ }
432
+ function calculatePhysicalActivity(itinerary) {
433
+ let walkDuration = 0;
434
+ let bikeDuration = 0;
435
+ itinerary.legs.forEach(leg => {
436
+ if (leg.mode.startsWith("WALK")) walkDuration += leg.duration;
437
+ if (leg.mode.startsWith("BICYCLE")) bikeDuration += leg.duration;
438
+ });
439
+ const caloriesBurned = walkDuration / 3600 * 280 + bikeDuration / 3600 * 290;
440
+ return {
441
+ bikeDuration,
442
+ caloriesBurned,
443
+ walkDuration
444
+ };
445
+ }
446
+
407
447
  /**
408
448
  * For an itinerary, calculates the TNC fares and returns an object with
409
449
  * these values and currency info.
410
450
  * It is assumed that the same currency is used for all TNC legs.
411
451
  */
412
- export function calculateTncFares(itinerary) {
413
- return itinerary.legs
414
- .filter(leg => leg.mode === "CAR" && leg.rideHailingEstimate)
415
- .reduce(({ maxTNCFare, minTNCFare }, { rideHailingEstimate }) => {
416
- const { minPrice, maxPrice } = rideHailingEstimate;
417
- return {
418
- // Assumes a single currency for entire itinerary.
419
- currencyCode: minPrice.currency.code,
420
- maxTNCFare: maxTNCFare + maxPrice.amount,
421
- minTNCFare: minTNCFare + minPrice.amount
422
- };
423
- }, {
424
- currencyCode: null,
425
- maxTNCFare: 0,
426
- minTNCFare: 0
427
- });
452
+ function calculateTncFares(itinerary) {
453
+ return itinerary.legs.filter(leg => leg.mode === "CAR" && leg.rideHailingEstimate).reduce(({
454
+ maxTNCFare,
455
+ minTNCFare
456
+ }, {
457
+ rideHailingEstimate
458
+ }) => {
459
+ const {
460
+ minPrice,
461
+ maxPrice
462
+ } = rideHailingEstimate;
463
+ return {
464
+ // Assumes a single currency for entire itinerary.
465
+ currencyCode: minPrice.currency.code,
466
+ maxTNCFare: maxTNCFare + maxPrice.amount,
467
+ minTNCFare: minTNCFare + minPrice.amount
468
+ };
469
+ }, {
470
+ currencyCode: null,
471
+ maxTNCFare: 0,
472
+ minTNCFare: 0
473
+ });
428
474
  }
475
+
429
476
  /**
430
477
  * Sources:
431
478
  * - https://www.itf-oecd.org/sites/default/files/docs/environmental-performance-new-mobility.pdf
@@ -434,82 +481,89 @@ export function calculateTncFares(itinerary) {
434
481
  * Other values extrapolated.
435
482
  */
436
483
  const CARBON_INTENSITY_DEFAULTS = {
437
- walk: 0.026,
438
- bicycle: 0.017,
439
- car: 0.162,
440
- tram: 0.066,
441
- trolleybus: 0.066,
442
- subway: 0.066,
443
- rail: 0.066,
444
- bus: 0.09,
445
- ferry: 0.082,
446
- cable_car: 0.021,
447
- gondola: 0.021,
448
- funicular: 0.066,
449
- transit: 0.066,
450
- leg_switch: 0,
451
- airplane: 0.382,
452
- micromobility: 0.095
484
+ walk: 0.026,
485
+ bicycle: 0.017,
486
+ car: 0.162,
487
+ tram: 0.066,
488
+ trolleybus: 0.066,
489
+ subway: 0.066,
490
+ rail: 0.066,
491
+ bus: 0.09,
492
+ ferry: 0.082,
493
+ cable_car: 0.021,
494
+ gondola: 0.021,
495
+ funicular: 0.066,
496
+ transit: 0.066,
497
+ leg_switch: 0,
498
+ airplane: 0.382,
499
+ micromobility: 0.095
453
500
  };
501
+
454
502
  /**
455
503
  * @param {itinerary} itinerary OTP trip itinierary, only legs is required.
456
504
  * @param {carbonIntensity} carbonIntensity carbon intensity by mode in grams/meter
457
505
  * @param {units} units units to be used in return value
458
506
  * @return Amount of carbon in chosen unit
459
507
  */
460
- export function calculateEmissions(
508
+ function calculateEmissions(
461
509
  // This type makes all the properties from Itinerary optional except legs.
462
510
  itinerary, carbonIntensity = {}, units) {
463
- var _a;
464
- // Apply defaults for any values that we don't have.
465
- const carbonIntensityWithDefaults = {
466
- ...CARBON_INTENSITY_DEFAULTS,
467
- ...carbonIntensity
468
- };
469
- // Distance is in meters, totalCarbon is in grams
470
- const totalCarbon = ((_a = itinerary === null || itinerary === void 0 ? void 0 : itinerary.legs) === null || _a === void 0 ? void 0 : _a.reduce((total, leg) => {
471
- return ((leg.distance * carbonIntensityWithDefaults[leg.mode.toLowerCase()] ||
472
- 0) + total);
473
- }, 0)) || 0;
474
- switch (units) {
475
- case "ounce":
476
- return totalCarbon / 28.35;
477
- case "kilogram":
478
- return totalCarbon / 1000;
479
- case "pound":
480
- return totalCarbon / 454;
481
- case "gram":
482
- default:
483
- return totalCarbon;
484
- }
485
- }
511
+ var _itinerary$legs;
512
+ // Apply defaults for any values that we don't have.
513
+ const carbonIntensityWithDefaults = {
514
+ ...CARBON_INTENSITY_DEFAULTS,
515
+ ...carbonIntensity
516
+ };
517
+
518
+ // Distance is in meters, totalCarbon is in grams
519
+ const totalCarbon = (itinerary === null || itinerary === void 0 || (_itinerary$legs = itinerary.legs) === null || _itinerary$legs === void 0 ? void 0 : _itinerary$legs.reduce((total, leg) => {
520
+ return (leg.distance * carbonIntensityWithDefaults[leg.mode.toLowerCase()] || 0) + total;
521
+ }, 0)) || 0;
522
+ switch (units) {
523
+ case "ounce":
524
+ return totalCarbon / 28.35;
525
+ case "kilogram":
526
+ return totalCarbon / 1000;
527
+ case "pound":
528
+ return totalCarbon / 454;
529
+ case "gram":
530
+ default:
531
+ return totalCarbon;
532
+ }
533
+ }
534
+
486
535
  /**
487
- * Returns the user-facing stop id to display for a stop or place, using the following priority:
488
- * 1. stop code,
489
- * 2. stop id without the agency id portion, if stop id contains an agency portion,
490
- * 3. stop id, whether null or not (this is the fallback case).
536
+ * Returns the user-facing stop code to display for a stop or place
491
537
  */
492
- export function getDisplayedStopId(placeOrStop) {
493
- let stopId;
494
- let stopCode;
495
- if ("stopId" in placeOrStop) {
496
- ({ stopCode, stopId } = placeOrStop);
497
- }
498
- else if ("id" in placeOrStop) {
499
- ({ code: stopCode, id: stopId } = placeOrStop);
500
- }
501
- return stopCode || (stopId === null || stopId === void 0 ? void 0 : stopId.split(":")[1]) || stopId;
502
- }
538
+ function getDisplayedStopCode(placeOrStop) {
539
+ if ("stopId" in placeOrStop) {
540
+ var _placeOrStop$stopCode;
541
+ return (_placeOrStop$stopCode = placeOrStop.stopCode) !== null && _placeOrStop$stopCode !== void 0 ? _placeOrStop$stopCode : undefined;
542
+ }
543
+ if ("id" in placeOrStop) {
544
+ var _placeOrStop$code;
545
+ return (_placeOrStop$code = placeOrStop.code) !== null && _placeOrStop$code !== void 0 ? _placeOrStop$code : undefined;
546
+ }
547
+ return undefined;
548
+ }
549
+
503
550
  /**
504
551
  * Removes the first part of the OTP standard scope (":"), if it is present
552
+ * If it's null or undefined, return the original value.
505
553
  * @param item String that is potentially scoped with `:` character
506
554
  * @returns descoped string
507
555
  */
508
- export const descope = (item) => { var _a; return (_a = item === null || item === void 0 ? void 0 : item.split(":")) === null || _a === void 0 ? void 0 : _a[1]; };
509
- export const zeroDollars = (currency) => ({
510
- amount: 0,
511
- currency
556
+ const descope = item => {
557
+ if (!item) return item;
558
+ const index = item.indexOf(":");
559
+ return index === -1 ? item : item.substring(index + 1);
560
+ };
561
+ exports.descope = descope;
562
+ const zeroDollars = currency => ({
563
+ amount: 0,
564
+ currency
512
565
  });
566
+
513
567
  /**
514
568
  * Extracts useful data from the fare products on a leg, such as the leg cost and transfer info.
515
569
  * @param leg Leg with Fares v2 information
@@ -521,52 +575,56 @@ export const zeroDollars = (currency) => ({
521
575
  * all the information needed, but the other fields are kept to
522
576
  * make the transition to Fares V2 less jarring.
523
577
  */
524
- export function getLegCost(leg, mediumId, riderCategoryId, seenFareIds) {
525
- if (!leg.fareProducts)
526
- return { price: undefined };
527
- const relevantFareProducts = leg.fareProducts
528
- .filter(({ product }) => {
529
- // riderCategory and medium can be specifically defined as null to handle
530
- // generic GTFS based fares from OTP when there is no fare model
531
- var _a, _b, _c, _d;
532
- // Remove (optional) agency scoping
533
- const productRiderCategoryId = descope((_a = product === null || product === void 0 ? void 0 : product.riderCategory) === null || _a === void 0 ? void 0 : _a.id) ||
534
- ((_b = product === null || product === void 0 ? void 0 : product.riderCategory) === null || _b === void 0 ? void 0 : _b.id) ||
535
- null;
536
- const productMediaId = descope((_c = product === null || product === void 0 ? void 0 : product.medium) === null || _c === void 0 ? void 0 : _c.id) || ((_d = product === null || product === void 0 ? void 0 : product.medium) === null || _d === void 0 ? void 0 : _d.id) || null;
537
- return (productRiderCategoryId === riderCategoryId &&
538
- productMediaId === mediumId &&
539
- (
540
- // Make sure there's a price
541
- // Some fare products don't have a price at all.
542
- product === null || product === void 0 ? void 0 : product.price));
543
- })
544
- .map(fare => {
545
- const alreadySeen = (seenFareIds === null || seenFareIds === void 0 ? void 0 : seenFareIds.indexOf(fare.id)) > -1;
546
- const { currency } = fare.product.price;
547
- return {
548
- id: fare.id,
549
- product: {
550
- ...fare.product,
551
- legPrice: alreadySeen ? zeroDollars(currency) : fare.product.price
552
- }
553
- };
554
- })
555
- .sort((a, b) => { var _a, _b, _c, _d; return ((_b = (_a = a.product) === null || _a === void 0 ? void 0 : _a.legPrice) === null || _b === void 0 ? void 0 : _b.amount) - ((_d = (_c = b.product) === null || _c === void 0 ? void 0 : _c.legPrice) === null || _d === void 0 ? void 0 : _d.amount); });
556
- // Return the cheapest, but include other matches as well
557
- const cheapestRelevantFareProduct = relevantFareProducts[0];
558
- // TODO: return one object here instead of dumbing it down?
578
+ exports.zeroDollars = zeroDollars;
579
+ function getLegCost(leg, mediumId, riderCategoryId, seenFareIds) {
580
+ if (!leg.fareProducts) return {
581
+ price: undefined
582
+ };
583
+ const relevantFareProducts = leg.fareProducts.filter(({
584
+ product
585
+ }) => {
586
+ var _product$riderCategor, _product$riderCategor2, _product$medium, _product$medium2;
587
+ // riderCategory and medium can be specifically defined as null to handle
588
+ // generic GTFS based fares from OTP when there is no fare model
589
+
590
+ // Remove (optional) agency scoping
591
+ const productRiderCategoryId = descope(product === null || product === void 0 || (_product$riderCategor = product.riderCategory) === null || _product$riderCategor === void 0 ? void 0 : _product$riderCategor.id) || (product === null || product === void 0 || (_product$riderCategor2 = product.riderCategory) === null || _product$riderCategor2 === void 0 ? void 0 : _product$riderCategor2.id) || null;
592
+ const productMediaId = descope(product === null || product === void 0 || (_product$medium = product.medium) === null || _product$medium === void 0 ? void 0 : _product$medium.id) || (product === null || product === void 0 || (_product$medium2 = product.medium) === null || _product$medium2 === void 0 ? void 0 : _product$medium2.id) || null;
593
+ return productRiderCategoryId === riderCategoryId && productMediaId === mediumId && (// Make sure there's a price
594
+ // Some fare products don't have a price at all.
595
+ product === null || product === void 0 ? void 0 : product.price);
596
+ }).map(fare => {
597
+ const alreadySeen = (seenFareIds === null || seenFareIds === void 0 ? void 0 : seenFareIds.indexOf(fare.id)) > -1;
598
+ const {
599
+ currency
600
+ } = fare.product.price;
559
601
  return {
560
- alternateFareProducts: relevantFareProducts.splice(1).map(fp => fp.product),
561
- appliedFareProduct: cheapestRelevantFareProduct === null || cheapestRelevantFareProduct === void 0 ? void 0 : cheapestRelevantFareProduct.product,
562
- isDependent:
563
- // eslint-disable-next-line no-underscore-dangle
564
- (cheapestRelevantFareProduct === null || cheapestRelevantFareProduct === void 0 ? void 0 : cheapestRelevantFareProduct.product.__typename) ===
565
- "DependentFareProduct",
566
- price: cheapestRelevantFareProduct === null || cheapestRelevantFareProduct === void 0 ? void 0 : cheapestRelevantFareProduct.product.legPrice,
567
- productUseId: cheapestRelevantFareProduct === null || cheapestRelevantFareProduct === void 0 ? void 0 : cheapestRelevantFareProduct.id
602
+ id: fare.id,
603
+ product: {
604
+ ...fare.product,
605
+ legPrice: alreadySeen ? zeroDollars(currency) : fare.product.price
606
+ }
568
607
  };
608
+ }).sort((a, b) => {
609
+ var _a$product, _b$product;
610
+ return ((_a$product = a.product) === null || _a$product === void 0 || (_a$product = _a$product.legPrice) === null || _a$product === void 0 ? void 0 : _a$product.amount) - ((_b$product = b.product) === null || _b$product === void 0 || (_b$product = _b$product.legPrice) === null || _b$product === void 0 ? void 0 : _b$product.amount);
611
+ });
612
+
613
+ // Return the cheapest, but include other matches as well
614
+ const cheapestRelevantFareProduct = relevantFareProducts[0];
615
+
616
+ // TODO: return one object here instead of dumbing it down?
617
+ return {
618
+ alternateFareProducts: relevantFareProducts.splice(1).map(fp => fp.product),
619
+ appliedFareProduct: cheapestRelevantFareProduct === null || cheapestRelevantFareProduct === void 0 ? void 0 : cheapestRelevantFareProduct.product,
620
+ isDependent:
621
+ // eslint-disable-next-line no-underscore-dangle
622
+ (cheapestRelevantFareProduct === null || cheapestRelevantFareProduct === void 0 ? void 0 : cheapestRelevantFareProduct.product.__typename) === "DependentFareProduct",
623
+ price: cheapestRelevantFareProduct === null || cheapestRelevantFareProduct === void 0 ? void 0 : cheapestRelevantFareProduct.product.legPrice,
624
+ productUseId: cheapestRelevantFareProduct === null || cheapestRelevantFareProduct === void 0 ? void 0 : cheapestRelevantFareProduct.id
625
+ };
569
626
  }
627
+
570
628
  /**
571
629
  * Returns the total itinerary cost for a given set of legs.
572
630
  * @param legs Itinerary legs with fare products (must have used getLegsWithFares)
@@ -575,127 +633,149 @@ export function getLegCost(leg, mediumId, riderCategoryId, seenFareIds) {
575
633
  * @param seenFareIds List of fare product IDs that have already been seen on prev legs.
576
634
  * @returns Money object for the total itinerary cost.
577
635
  */
578
- export function getItineraryCost(legs, mediumId, riderCategoryId) {
579
- var _a;
580
- // TODO: Better input type handling
581
- if (Array.isArray(mediumId) || Array.isArray(riderCategoryId)) {
582
- if ((mediumId === null || mediumId === void 0 ? void 0 : mediumId.length) !== riderCategoryId.length) {
583
- console.warn("Invalid input types, only using first item. medium id list and rider category list must have same number of items");
584
- return getItineraryCost(legs, mediumId[0], riderCategoryId[0]);
585
- }
586
- let total = { amount: 0, currency: null };
587
- for (let i = 0; i < mediumId.length; i++) {
588
- const newCost = getItineraryCost(legs, mediumId[i], riderCategoryId[i]);
589
- if (newCost) {
590
- total = {
591
- amount: (total === null || total === void 0 ? void 0 : total.amount) + ((newCost === null || newCost === void 0 ? void 0 : newCost.amount) || 0),
592
- currency: (_a = total.currency) !== null && _a !== void 0 ? _a : newCost === null || newCost === void 0 ? void 0 : newCost.currency
593
- };
594
- }
595
- }
596
- if (total.currency === null)
597
- return undefined;
598
- return total;
636
+ function getItineraryCost(legs, mediumId, riderCategoryId) {
637
+ // TODO: Better input type handling
638
+ if (Array.isArray(mediumId) || Array.isArray(riderCategoryId)) {
639
+ if ((mediumId === null || mediumId === void 0 ? void 0 : mediumId.length) !== riderCategoryId.length) {
640
+ console.warn("Invalid input types, only using first item. medium id list and rider category list must have same number of items");
641
+ return getItineraryCost(legs, mediumId[0], riderCategoryId[0]);
599
642
  }
600
- const legCosts = legs
601
- // Only legs with fares (no walking legs)
602
- .filter(leg => { var _a; return ((_a = leg.fareProducts) === null || _a === void 0 ? void 0 : _a.length) > 0; })
603
- // Get the leg cost object of each leg
604
- .reduce((acc, leg) => {
605
- // getLegCost handles filtering out duplicate use IDs
606
- // One fare product can be used on multiple legs,
607
- // and we don't want to count it more than once.
608
- // Use an object keyed by productUseId to deduplicate, then extract prices
609
- const { appliedFareProduct, productUseId } = getLegCost(leg, mediumId, riderCategoryId, acc.seenIds);
610
- if (!appliedFareProduct)
611
- return acc;
612
- return {
613
- legCosts: [...acc.legCosts, appliedFareProduct],
614
- seenIds: [...acc.seenIds, productUseId]
643
+ let total = {
644
+ amount: 0,
645
+ currency: null
646
+ };
647
+ for (let i = 0; i < mediumId.length; i++) {
648
+ const newCost = getItineraryCost(legs, mediumId[i], riderCategoryId[i]);
649
+ if (newCost) {
650
+ var _total, _total$currency;
651
+ total = {
652
+ amount: ((_total = total) === null || _total === void 0 ? void 0 : _total.amount) + ((newCost === null || newCost === void 0 ? void 0 : newCost.amount) || 0),
653
+ currency: (_total$currency = total.currency) !== null && _total$currency !== void 0 ? _total$currency : newCost === null || newCost === void 0 ? void 0 : newCost.currency
615
654
  };
616
- }, { seenIds: [], legCosts: [] })
617
- .legCosts.map(lc => lc.legPrice);
618
- if (legCosts.length === 0)
619
- return undefined;
620
- // Calculate the total
621
- return legCosts.reduce((prev, cur) => {
622
- var _a;
623
- return ({
624
- amount: prev.amount + (cur === null || cur === void 0 ? void 0 : cur.amount) || 0,
625
- currency: (_a = prev.currency) !== null && _a !== void 0 ? _a : cur === null || cur === void 0 ? void 0 : cur.currency
626
- });
627
- }, { amount: 0, currency: null });
655
+ }
656
+ }
657
+ if (total.currency === null) return undefined;
658
+ return total;
659
+ }
660
+ const legCosts = legs
661
+ // Only legs with fares (no walking legs)
662
+ .filter(leg => {
663
+ var _leg$fareProducts;
664
+ return ((_leg$fareProducts = leg.fareProducts) === null || _leg$fareProducts === void 0 ? void 0 : _leg$fareProducts.length) > 0;
665
+ })
666
+ // Get the leg cost object of each leg
667
+ .reduce((acc, leg) => {
668
+ // getLegCost handles filtering out duplicate use IDs
669
+ // One fare product can be used on multiple legs,
670
+ // and we don't want to count it more than once.
671
+ // Use an object keyed by productUseId to deduplicate, then extract prices
672
+ const {
673
+ appliedFareProduct,
674
+ productUseId
675
+ } = getLegCost(leg, mediumId, riderCategoryId, acc.seenIds);
676
+ if (!appliedFareProduct) return acc;
677
+ return {
678
+ legCosts: [...acc.legCosts, appliedFareProduct],
679
+ seenIds: [...acc.seenIds, productUseId]
680
+ };
681
+ }, {
682
+ seenIds: [],
683
+ legCosts: []
684
+ }).legCosts.map(lc => lc.legPrice);
685
+ if (legCosts.length === 0) return undefined;
686
+ // Calculate the total
687
+ return legCosts.reduce((prev, cur) => {
688
+ var _prev$currency;
689
+ return {
690
+ amount: prev.amount + (cur === null || cur === void 0 ? void 0 : cur.amount) || 0,
691
+ currency: (_prev$currency = prev.currency) !== null && _prev$currency !== void 0 ? _prev$currency : cur === null || cur === void 0 ? void 0 : cur.currency
692
+ };
693
+ }, {
694
+ amount: 0,
695
+ currency: null
696
+ });
628
697
  }
629
698
  const pickupDropoffTypeToOtp1 = otp2Type => {
630
- switch (otp2Type) {
631
- case "COORDINATE_WITH_DRIVER":
632
- return "coordinateWithDriver";
633
- case "CALL_AGENCY":
634
- return "mustPhone";
635
- case "SCHEDULED":
636
- return "scheduled";
637
- case "NONE":
638
- return "none";
639
- default:
640
- return null;
641
- }
699
+ switch (otp2Type) {
700
+ case "COORDINATE_WITH_DRIVER":
701
+ return "coordinateWithDriver";
702
+ case "CALL_AGENCY":
703
+ return "mustPhone";
704
+ case "SCHEDULED":
705
+ return "scheduled";
706
+ case "NONE":
707
+ return "none";
708
+ default:
709
+ return null;
710
+ }
642
711
  };
643
- export const convertGraphQLResponseToLegacy = (leg) => {
644
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
645
- return ({
646
- ...leg,
647
- agencyBrandingUrl: (_a = leg.agency) === null || _a === void 0 ? void 0 : _a.url,
648
- agencyId: (_b = leg.agency) === null || _b === void 0 ? void 0 : _b.id,
649
- agencyName: (_c = leg.agency) === null || _c === void 0 ? void 0 : _c.name,
650
- agencyUrl: (_d = leg.agency) === null || _d === void 0 ? void 0 : _d.url,
651
- alightRule: pickupDropoffTypeToOtp1(leg.dropoffType),
652
- boardRule: pickupDropoffTypeToOtp1(leg.pickupType),
653
- bookingRuleInfo: {
654
- dropOff: (leg === null || leg === void 0 ? void 0 : leg.dropOffBookingInfo) || {},
655
- pickUp: (leg === null || leg === void 0 ? void 0 : leg.pickUpBookingInfo) || {}
656
- },
657
- dropOffBookingInfo: {
658
- latestBookingTime: leg.dropOffBookingInfo
659
- },
660
- from: {
661
- ...leg.from,
662
- stopCode: (_e = leg.from.stop) === null || _e === void 0 ? void 0 : _e.code,
663
- stopId: (_f = leg.from.stop) === null || _f === void 0 ? void 0 : _f.gtfsId
664
- },
665
- route: (_g = leg.route) === null || _g === void 0 ? void 0 : _g.shortName,
666
- routeColor: (_h = leg.route) === null || _h === void 0 ? void 0 : _h.color,
667
- routeId: (_j = leg.route) === null || _j === void 0 ? void 0 : _j.gtfsId,
668
- routeLongName: (_k = leg.route) === null || _k === void 0 ? void 0 : _k.longName,
669
- routeShortName: (_l = leg.route) === null || _l === void 0 ? void 0 : _l.shortName,
670
- routeTextColor: (_m = leg.route) === null || _m === void 0 ? void 0 : _m.textColor,
671
- to: {
672
- ...leg.to,
673
- stopCode: (_o = leg.to.stop) === null || _o === void 0 ? void 0 : _o.code,
674
- stopId: (_p = leg.to.stop) === null || _p === void 0 ? void 0 : _p.gtfsId
675
- },
676
- tripHeadsign: (_q = leg.trip) === null || _q === void 0 ? void 0 : _q.tripHeadsign,
677
- tripId: (_r = leg.trip) === null || _r === void 0 ? void 0 : _r.gtfsId
678
- });
712
+ const convertGraphQLResponseToLegacy = leg => {
713
+ var _leg$agency, _leg$agency2, _leg$agency3, _leg$agency4, _leg$from$stop, _leg$from$stop2, _leg$route, _leg$route2, _leg$route3, _leg$route4, _leg$route5, _leg$route6, _leg$to$stop, _leg$to$stop2, _leg$trip, _leg$trip2;
714
+ return {
715
+ ...leg,
716
+ agencyBrandingUrl: (_leg$agency = leg.agency) === null || _leg$agency === void 0 ? void 0 : _leg$agency.url,
717
+ agencyId: (_leg$agency2 = leg.agency) === null || _leg$agency2 === void 0 ? void 0 : _leg$agency2.id,
718
+ agencyName: (_leg$agency3 = leg.agency) === null || _leg$agency3 === void 0 ? void 0 : _leg$agency3.name,
719
+ agencyUrl: (_leg$agency4 = leg.agency) === null || _leg$agency4 === void 0 ? void 0 : _leg$agency4.url,
720
+ alightRule: pickupDropoffTypeToOtp1(leg.dropoffType),
721
+ boardRule: pickupDropoffTypeToOtp1(leg.pickupType),
722
+ bookingRuleInfo: {
723
+ dropOff: (leg === null || leg === void 0 ? void 0 : leg.dropOffBookingInfo) || {},
724
+ pickUp: (leg === null || leg === void 0 ? void 0 : leg.pickUpBookingInfo) || {}
725
+ },
726
+ dropOffBookingInfo: {
727
+ latestBookingTime: leg.dropOffBookingInfo
728
+ },
729
+ from: {
730
+ ...leg.from,
731
+ stopCode: (_leg$from$stop = leg.from.stop) === null || _leg$from$stop === void 0 ? void 0 : _leg$from$stop.code,
732
+ stopId: (_leg$from$stop2 = leg.from.stop) === null || _leg$from$stop2 === void 0 ? void 0 : _leg$from$stop2.gtfsId
733
+ },
734
+ route: (_leg$route = leg.route) === null || _leg$route === void 0 ? void 0 : _leg$route.shortName,
735
+ routeColor: (_leg$route2 = leg.route) === null || _leg$route2 === void 0 ? void 0 : _leg$route2.color,
736
+ routeId: (_leg$route3 = leg.route) === null || _leg$route3 === void 0 ? void 0 : _leg$route3.gtfsId,
737
+ routeLongName: (_leg$route4 = leg.route) === null || _leg$route4 === void 0 ? void 0 : _leg$route4.longName,
738
+ routeShortName: (_leg$route5 = leg.route) === null || _leg$route5 === void 0 ? void 0 : _leg$route5.shortName,
739
+ routeTextColor: (_leg$route6 = leg.route) === null || _leg$route6 === void 0 ? void 0 : _leg$route6.textColor,
740
+ to: {
741
+ ...leg.to,
742
+ stopCode: (_leg$to$stop = leg.to.stop) === null || _leg$to$stop === void 0 ? void 0 : _leg$to$stop.code,
743
+ stopId: (_leg$to$stop2 = leg.to.stop) === null || _leg$to$stop2 === void 0 ? void 0 : _leg$to$stop2.gtfsId
744
+ },
745
+ tripHeadsign: (_leg$trip = leg.trip) === null || _leg$trip === void 0 ? void 0 : _leg$trip.tripHeadsign,
746
+ tripId: (_leg$trip2 = leg.trip) === null || _leg$trip2 === void 0 ? void 0 : _leg$trip2.gtfsId
747
+ };
679
748
  };
749
+
680
750
  /** Extracts the route number for a leg returned from OTP1 or OTP2. */
681
- export const getLegRouteShortName = (leg) => {
682
- const { route, routeShortName } = leg;
683
- // typeof route === "object" denotes newer OTP2 responses. routeShortName and route as string is OTP1.
684
- return typeof route === "object"
685
- ? route === null || route === void 0 ? void 0 : route.shortName
686
- : routeShortName || route;
751
+ exports.convertGraphQLResponseToLegacy = convertGraphQLResponseToLegacy;
752
+ const getLegRouteShortName = leg => {
753
+ const {
754
+ route,
755
+ routeShortName
756
+ } = leg;
757
+ // typeof route === "object" denotes newer OTP2 responses. routeShortName and route as string is OTP1.
758
+ return typeof route === "object" ? route === null || route === void 0 ? void 0 : route.shortName : routeShortName || route;
687
759
  };
760
+
688
761
  /** Extract the route long name for a leg returned from OTP1 or OTP2. */
689
- export const getLegRouteLongName = (leg) => {
690
- const { route, routeLongName } = leg;
691
- // typeof route === "object" denotes newer OTP2 responses. routeLongName is OTP1.
692
- return typeof route === "object" ? route === null || route === void 0 ? void 0 : route.longName : routeLongName;
762
+ exports.getLegRouteShortName = getLegRouteShortName;
763
+ const getLegRouteLongName = leg => {
764
+ const {
765
+ route,
766
+ routeLongName
767
+ } = leg;
768
+ // typeof route === "object" denotes newer OTP2 responses. routeLongName is OTP1.
769
+ return typeof route === "object" ? route === null || route === void 0 ? void 0 : route.longName : routeLongName;
693
770
  };
771
+
694
772
  /**
695
773
  * Returns the route short name, or the route long name if no short name is provided.
696
774
  * This is happens with Seattle area streetcars and ferries.
697
775
  */
698
- export const getLegRouteName = (leg) => {
699
- return getLegRouteShortName(leg) || getLegRouteLongName(leg);
776
+ exports.getLegRouteLongName = getLegRouteLongName;
777
+ const getLegRouteName = leg => {
778
+ return getLegRouteShortName(leg) || getLegRouteLongName(leg);
700
779
  };
780
+ exports.getLegRouteName = getLegRouteName;
701
781
  //# sourceMappingURL=itinerary.js.map