@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.
- package/README.md +0 -4
- package/esm/itinerary.js +70 -32
- package/esm/itinerary.js.map +1 -1
- package/esm/otpSchema.json +7321 -5821
- package/esm/planQuery.graphql +12 -0
- package/esm/profile.js +1 -1
- package/esm/profile.js.map +1 -1
- package/esm/query-gen.js +2 -2
- package/esm/query-gen.js.map +1 -1
- package/esm/query-params.js +2 -2
- package/esm/query-params.js.map +1 -1
- package/esm/query.js +2 -5
- package/esm/query.js.map +1 -1
- package/esm/storage.js +2 -6
- package/esm/storage.js.map +1 -1
- package/esm/time.js +1 -2
- package/esm/time.js.map +1 -1
- package/lib/index.js +50 -35
- package/lib/index.js.map +1 -1
- package/lib/itinerary.d.ts +25 -8
- package/lib/itinerary.d.ts.map +1 -1
- package/lib/itinerary.js +524 -495
- package/lib/itinerary.js.map +1 -1
- package/lib/map.js +40 -39
- package/lib/map.js.map +1 -1
- package/lib/otpSchema.json +7321 -5821
- package/lib/planQuery.graphql +12 -0
- package/lib/profile.js +1 -1
- package/lib/profile.js.map +1 -1
- package/lib/query-gen.js +134 -138
- package/lib/query-gen.js.map +1 -1
- package/lib/query-params.js +2 -2
- package/lib/query-params.js.map +1 -1
- package/lib/query.js +3 -6
- package/lib/query.js.map +1 -1
- package/lib/route.js +230 -248
- package/lib/route.js.map +1 -1
- package/lib/storage.d.ts.map +1 -1
- package/lib/storage.js +22 -28
- package/lib/storage.js.map +1 -1
- package/lib/suspense.js +28 -16
- package/lib/suspense.js.map +1 -1
- package/lib/time.js +36 -49
- package/lib/time.js.map +1 -1
- package/lib/ui.js +33 -36
- package/lib/ui.js.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/__snapshots__/query-params.ts.snap +203 -203
- package/src/__tests__/__snapshots__/query.js.snap +28 -28
- package/src/__tests__/__snapshots__/route.js.snap +76 -76
- package/src/__tests__/__snapshots__/time.js.snap +2 -2
- package/src/__tests__/itinerary.ts +108 -23
- package/src/__tests__/query.js +1 -1
- package/src/__tests__/route.js +1 -1
- package/src/core-utils.story.tsx +34 -23
- package/src/itinerary.ts +85 -37
- package/src/otpSchema.json +7321 -5821
- package/src/planQuery.graphql +12 -0
- package/src/profile.js +1 -1
- package/src/query-gen.ts +1 -1
- package/src/query-params.jsx +2 -2
- package/src/query.js +2 -5
- package/src/storage.ts +5 -9
- package/tsconfig.tsbuildinfo +1 -1
package/lib/itinerary.js
CHANGED
|
@@ -1,382 +1,385 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
exports.
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
|
|
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
|
-
|
|
66
|
-
|
|
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
|
-
|
|
31
|
+
return leg.transitLeg;
|
|
70
32
|
}
|
|
33
|
+
exports.isTransitLeg = isTransitLeg;
|
|
71
34
|
function isTransit(mode) {
|
|
72
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
93
|
-
|
|
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
|
-
|
|
63
|
+
return containsGeometry(leg === null || leg === void 0 ? void 0 : leg.to);
|
|
97
64
|
}
|
|
65
|
+
exports.endsWithGeometry = endsWithGeometry;
|
|
98
66
|
function startsWithGeometry(leg) {
|
|
99
|
-
|
|
67
|
+
return containsGeometry(leg === null || leg === void 0 ? void 0 : leg.from);
|
|
100
68
|
}
|
|
69
|
+
exports.startsWithGeometry = startsWithGeometry;
|
|
101
70
|
function legContainsGeometry(leg) {
|
|
102
|
-
|
|
71
|
+
return endsWithGeometry(leg) || startsWithGeometry(leg);
|
|
103
72
|
}
|
|
73
|
+
exports.legContainsGeometry = legContainsGeometry;
|
|
104
74
|
function isAdvanceBookingRequired(info) {
|
|
105
|
-
|
|
106
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
123
|
-
|
|
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
|
-
|
|
127
|
-
|
|
101
|
+
if (!mode)
|
|
102
|
+
return false;
|
|
103
|
+
return mode === "WALK";
|
|
128
104
|
}
|
|
105
|
+
exports.isWalk = isWalk;
|
|
129
106
|
function isBicycle(mode) {
|
|
130
|
-
|
|
131
|
-
|
|
107
|
+
if (!mode)
|
|
108
|
+
return false;
|
|
109
|
+
return mode === "BICYCLE";
|
|
132
110
|
}
|
|
111
|
+
exports.isBicycle = isBicycle;
|
|
133
112
|
function isBicycleRent(mode) {
|
|
134
|
-
|
|
135
|
-
|
|
113
|
+
if (!mode)
|
|
114
|
+
return false;
|
|
115
|
+
return mode === "BICYCLE_RENT";
|
|
136
116
|
}
|
|
117
|
+
exports.isBicycleRent = isBicycleRent;
|
|
137
118
|
function isCar(mode) {
|
|
138
|
-
|
|
139
|
-
|
|
119
|
+
if (!mode)
|
|
120
|
+
return false;
|
|
121
|
+
return mode.startsWith("CAR");
|
|
140
122
|
}
|
|
123
|
+
exports.isCar = isCar;
|
|
141
124
|
function isMicromobility(mode) {
|
|
142
|
-
|
|
143
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
185
|
+
return modesStr.split(",").some(mode => mode.indexOf("_RENT") > -1);
|
|
195
186
|
}
|
|
187
|
+
exports.hasRental = hasRental;
|
|
196
188
|
function getMapColor(mode) {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
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
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
from,
|
|
226
|
-
mode
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
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
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
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
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
coords.
|
|
272
|
-
|
|
273
|
-
|
|
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
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
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
|
-
|
|
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
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
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
|
-
|
|
325
|
-
|
|
326
|
-
|
|
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
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
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
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
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
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
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
|
-
|
|
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
|
-
|
|
423
|
-
|
|
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
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
bikeDuration
|
|
435
|
-
|
|
436
|
-
|
|
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
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
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
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
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
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
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
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
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
|
|
555
|
-
* @param
|
|
556
|
-
* @param
|
|
557
|
-
* @
|
|
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
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
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
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
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
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
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
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
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
|
-
|
|
673
|
-
|
|
674
|
-
route,
|
|
675
|
-
routeShortName
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
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
|
-
|
|
684
|
-
|
|
685
|
-
route,
|
|
686
|
-
routeLongName
|
|
687
|
-
|
|
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
|
-
|
|
697
|
-
|
|
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
|