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