@opentripplanner/core-utils 13.0.0-alpha.3 → 13.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -3
- package/esm/__mocks__/fake-route-data.story.json +5425 -0
- package/esm/__mocks__/fake-transit-operators.story.json +97 -0
- package/esm/__tests__/__mocks__/routes.json +234 -105
- package/esm/itinerary.js +0 -2
- package/esm/itinerary.js.map +1 -1
- package/esm/otpSchema.json +0 -12
- package/esm/profile.js +1 -1
- package/esm/profile.js.map +1 -1
- package/esm/query-gen.js +2 -4
- package/esm/query-gen.js.map +1 -1
- package/esm/query-params.js +773 -0
- package/esm/query-params.js.map +1 -0
- package/esm/query.js +1 -4
- package/esm/query.js.map +1 -1
- package/esm/route.js +36 -21
- package/esm/route.js.map +1 -1
- package/esm/routes.json +234 -105
- package/esm/storage.js +2 -6
- package/esm/storage.js.map +1 -1
- package/esm/time.js +10 -0
- package/esm/time.js.map +1 -1
- package/lib/__mocks__/fake-route-data.story.json +5425 -0
- package/lib/__mocks__/fake-transit-operators.story.json +97 -0
- package/lib/__tests__/__mocks__/routes.json +234 -105
- package/lib/itinerary.d.ts.map +1 -1
- package/lib/itinerary.js +0 -2
- package/lib/itinerary.js.map +1 -1
- package/lib/otpSchema.json +0 -12
- package/lib/profile.js +1 -1
- package/lib/profile.js.map +1 -1
- package/lib/query-gen.js +2 -2
- package/lib/query-gen.js.map +1 -1
- package/lib/query-params.js +735 -0
- package/lib/query-params.js.map +1 -0
- package/lib/query.js +1 -4
- package/lib/query.js.map +1 -1
- package/lib/route.d.ts +35 -1
- package/lib/route.d.ts.map +1 -1
- package/lib/route.js +38 -17
- package/lib/route.js.map +1 -1
- package/lib/storage.d.ts.map +1 -1
- package/lib/storage.js +2 -6
- package/lib/storage.js.map +1 -1
- package/lib/time.d.ts +7 -0
- package/lib/time.d.ts.map +1 -1
- package/lib/time.js +10 -1
- package/lib/time.js.map +1 -1
- package/package.json +3 -3
- package/src/__mocks__/fake-route-data.story.json +5425 -0
- package/src/__mocks__/fake-transit-operators.story.json +97 -0
- package/src/__snapshots__/core-utils.story.tsx.snap +8382 -0
- package/src/__tests__/__mocks__/routes.json +234 -105
- package/src/__tests__/__snapshots__/route.js.snap +285 -95
- package/src/__tests__/route.js +27 -55
- package/src/core-utils.story.tsx +201 -2
- package/src/itinerary.ts +0 -2
- package/src/otpSchema.json +0 -12
- package/src/profile.js +1 -1
- package/src/query-gen.ts +2 -2
- package/src/query.js +1 -4
- package/src/route.ts +41 -21
- package/src/storage.ts +5 -9
- package/src/time.ts +9 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/esm/query-params.jsx +0 -893
- package/lib/query-params.jsx +0 -893
package/src/core-utils.story.tsx
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
import React, { useState } from "react";
|
|
2
2
|
import styled from "styled-components";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
alphabeticShortNameComparator,
|
|
5
|
+
getMostReadableTextColor,
|
|
6
|
+
getRouteSortOrderValue,
|
|
7
|
+
makeMultiCriteriaSort,
|
|
8
|
+
makeNumericValueComparator,
|
|
9
|
+
makeStringValueComparator,
|
|
10
|
+
makeTransitOperatorComparator,
|
|
11
|
+
routeTypeComparator
|
|
12
|
+
} from "./route";
|
|
13
|
+
import { routes } from "./__mocks__/fake-route-data.story.json";
|
|
14
|
+
import { fakeTransitOperators } from "./__mocks__/fake-transit-operators.story.json";
|
|
4
15
|
|
|
5
16
|
export default {
|
|
6
17
|
title: "core-utils"
|
|
@@ -50,8 +61,196 @@ export const RouteColorTester = (): JSX.Element => {
|
|
|
50
61
|
</>
|
|
51
62
|
);
|
|
52
63
|
};
|
|
53
|
-
// Disable color contrast checking for the uncorrected color pairs
|
|
64
|
+
// Disable color contrast checking for the uncorrected color pairs
|
|
54
65
|
RouteColorTester.parameters = {
|
|
55
66
|
a11y: { config: { rules: [{ id: "color-contrast", reviewOnFail: true }] } },
|
|
56
67
|
storyshots: { disable: true }
|
|
57
68
|
};
|
|
69
|
+
|
|
70
|
+
// Route sort logic story:
|
|
71
|
+
|
|
72
|
+
const Columns = styled.div`
|
|
73
|
+
display: flex;
|
|
74
|
+
flex-direction: row;
|
|
75
|
+
position: relative;
|
|
76
|
+
width: 100%;
|
|
77
|
+
`;
|
|
78
|
+
|
|
79
|
+
const StyledTable = styled.table`
|
|
80
|
+
td,
|
|
81
|
+
th {
|
|
82
|
+
border: 1px solid black;
|
|
83
|
+
padding: 2px;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
tr {
|
|
87
|
+
background-color: white;
|
|
88
|
+
display: grid;
|
|
89
|
+
grid-template-columns: 1fr 2fr 2fr 4fr 2fr 2fr;
|
|
90
|
+
width: 75%;
|
|
91
|
+
img {
|
|
92
|
+
height: 30px;
|
|
93
|
+
width: 30px;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
`;
|
|
97
|
+
|
|
98
|
+
function makeRouteComparator(sortArray): (a: number, b: number) => number {
|
|
99
|
+
return makeMultiCriteriaSort(
|
|
100
|
+
...(sortArray as Array<(a: any, b: any) => number>)
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* This is based on the logic in the makeRouteComparator function in route.ts
|
|
106
|
+
* If another route comparator is added to makeRouteComparator, this component
|
|
107
|
+
* will need to be updated to reflect the new comparator.
|
|
108
|
+
*/
|
|
109
|
+
export const RouteSortingLogic = (): JSX.Element => {
|
|
110
|
+
const [useOperatorComparator, setUseOperatorComparator] = useState(true);
|
|
111
|
+
const [useSortOrderComparator, setUseSortOrderComparator] = useState(true);
|
|
112
|
+
const [useRouteComparator, setUseRouteComparator] = useState(true);
|
|
113
|
+
const [useAlphaSortName, setUseAlphaSortName] = useState(true);
|
|
114
|
+
const [useNumericShortName, setUseNumericShortName] = useState(true);
|
|
115
|
+
const [useStringShortName, setUseStringShortName] = useState(true);
|
|
116
|
+
const [useStringLongName, setUseLongName] = useState(true);
|
|
117
|
+
|
|
118
|
+
const transitOperatorComparator = useOperatorComparator
|
|
119
|
+
? makeTransitOperatorComparator(fakeTransitOperators)
|
|
120
|
+
: null;
|
|
121
|
+
const sortOrderComparator = useSortOrderComparator
|
|
122
|
+
? makeNumericValueComparator(obj => getRouteSortOrderValue(obj))
|
|
123
|
+
: null;
|
|
124
|
+
const routeComparator = useRouteComparator ? routeTypeComparator : null;
|
|
125
|
+
const alphaShortName = useAlphaSortName
|
|
126
|
+
? alphabeticShortNameComparator
|
|
127
|
+
: null;
|
|
128
|
+
const numericShortName = useNumericShortName
|
|
129
|
+
? makeNumericValueComparator(obj => parseInt(obj.shortName, 10))
|
|
130
|
+
: null;
|
|
131
|
+
const stringShortName = useStringShortName
|
|
132
|
+
? makeStringValueComparator(obj => obj.shortName)
|
|
133
|
+
: null;
|
|
134
|
+
const stringLongName = useStringLongName
|
|
135
|
+
? makeStringValueComparator(obj => obj.longName || "")
|
|
136
|
+
: null;
|
|
137
|
+
|
|
138
|
+
const sortArray = [
|
|
139
|
+
transitOperatorComparator,
|
|
140
|
+
sortOrderComparator,
|
|
141
|
+
routeComparator,
|
|
142
|
+
alphaShortName,
|
|
143
|
+
numericShortName,
|
|
144
|
+
stringShortName,
|
|
145
|
+
stringLongName
|
|
146
|
+
].filter(x => x !== null);
|
|
147
|
+
|
|
148
|
+
const sortedRoutes = Array.from(routes as Array<any>).sort(
|
|
149
|
+
makeRouteComparator(sortArray)
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
return (
|
|
153
|
+
<Columns>
|
|
154
|
+
<StyledTable>
|
|
155
|
+
<tr>
|
|
156
|
+
<th>Logo</th>
|
|
157
|
+
<th>Mode</th>
|
|
158
|
+
<th>Short Name</th>
|
|
159
|
+
<th>Long Name</th>
|
|
160
|
+
<th>Agency Order</th>
|
|
161
|
+
<th>Sort Order</th>
|
|
162
|
+
</tr>
|
|
163
|
+
{sortedRoutes.map(r => {
|
|
164
|
+
const operator = fakeTransitOperators.find(
|
|
165
|
+
x => x.agencyId === r.agency?.id
|
|
166
|
+
);
|
|
167
|
+
return (
|
|
168
|
+
<tr key={r.id}>
|
|
169
|
+
<td>
|
|
170
|
+
<img src={operator?.logo} alt={r.agency?.name || ""} />
|
|
171
|
+
</td>
|
|
172
|
+
<td>{r.mode}</td>
|
|
173
|
+
<td>{r.shortName}</td>
|
|
174
|
+
<td>{r.longName}</td>
|
|
175
|
+
<td>{operator?.order}</td>
|
|
176
|
+
<td>{r.sortOrder}</td>
|
|
177
|
+
</tr>
|
|
178
|
+
);
|
|
179
|
+
})}
|
|
180
|
+
</StyledTable>
|
|
181
|
+
<div
|
|
182
|
+
style={{
|
|
183
|
+
display: "flex",
|
|
184
|
+
flexDirection: "column",
|
|
185
|
+
position: "fixed",
|
|
186
|
+
right: 0,
|
|
187
|
+
width: "25%"
|
|
188
|
+
}}
|
|
189
|
+
>
|
|
190
|
+
<label htmlFor="operator-comparator">
|
|
191
|
+
<input
|
|
192
|
+
checked={useOperatorComparator}
|
|
193
|
+
id="operator-comparator"
|
|
194
|
+
onChange={() => setUseOperatorComparator(!useOperatorComparator)}
|
|
195
|
+
type="checkbox"
|
|
196
|
+
/>
|
|
197
|
+
Transit Operator Comparator
|
|
198
|
+
</label>
|
|
199
|
+
<label htmlFor="sort-order-comparator">
|
|
200
|
+
<input
|
|
201
|
+
id="sort-order-comparator"
|
|
202
|
+
type="checkbox"
|
|
203
|
+
checked={useSortOrderComparator}
|
|
204
|
+
onChange={() => setUseSortOrderComparator(!useSortOrderComparator)}
|
|
205
|
+
/>
|
|
206
|
+
SortOrder Comparator
|
|
207
|
+
</label>
|
|
208
|
+
<label htmlFor="route-comparator">
|
|
209
|
+
<input
|
|
210
|
+
id="route-comparator"
|
|
211
|
+
type="checkbox"
|
|
212
|
+
checked={useRouteComparator}
|
|
213
|
+
onChange={() => setUseRouteComparator(!useRouteComparator)}
|
|
214
|
+
/>
|
|
215
|
+
Route Comparator
|
|
216
|
+
</label>
|
|
217
|
+
<label htmlFor="alpha-sort-name">
|
|
218
|
+
<input
|
|
219
|
+
id="alpha-sort-name"
|
|
220
|
+
type="checkbox"
|
|
221
|
+
checked={useAlphaSortName}
|
|
222
|
+
onChange={() => setUseAlphaSortName(!useAlphaSortName)}
|
|
223
|
+
/>
|
|
224
|
+
Alpha Short Name
|
|
225
|
+
</label>
|
|
226
|
+
<label htmlFor="numeric-short-name">
|
|
227
|
+
<input
|
|
228
|
+
id="numeric-short-name"
|
|
229
|
+
type="checkbox"
|
|
230
|
+
checked={useNumericShortName}
|
|
231
|
+
onChange={() => setUseNumericShortName(!useNumericShortName)}
|
|
232
|
+
/>
|
|
233
|
+
Numeric Short Name
|
|
234
|
+
</label>
|
|
235
|
+
<label htmlFor="string-short-name">
|
|
236
|
+
<input
|
|
237
|
+
id="string-short-name"
|
|
238
|
+
type="checkbox"
|
|
239
|
+
checked={useStringShortName}
|
|
240
|
+
onChange={() => setUseStringShortName(!useStringShortName)}
|
|
241
|
+
/>
|
|
242
|
+
String Short Name
|
|
243
|
+
</label>
|
|
244
|
+
<label htmlFor="string-long-name">
|
|
245
|
+
<input
|
|
246
|
+
id="string-long-name"
|
|
247
|
+
type="checkbox"
|
|
248
|
+
checked={useStringLongName}
|
|
249
|
+
onChange={() => setUseLongName(!useStringLongName)}
|
|
250
|
+
/>
|
|
251
|
+
String Long Name
|
|
252
|
+
</label>
|
|
253
|
+
</div>
|
|
254
|
+
</Columns>
|
|
255
|
+
);
|
|
256
|
+
};
|
package/src/itinerary.ts
CHANGED
package/src/otpSchema.json
CHANGED
|
@@ -9671,18 +9671,6 @@
|
|
|
9671
9671
|
"isDeprecated": false,
|
|
9672
9672
|
"deprecationReason": null
|
|
9673
9673
|
},
|
|
9674
|
-
{
|
|
9675
|
-
"name": "stopPosition",
|
|
9676
|
-
"description": "The sequence of the stop in the pattern. This is not required to start from 0 or be consecutive - any\nincreasing integer sequence along the stops is valid.\n\nThe purpose of this field is to identify the stop within the pattern so it can be cross-referenced\nbetween it and the itinerary. It is safe to cross-reference when done quickly, i.e. within seconds.\nHowever, it should be noted that realtime updates can change the values, so don't store it for\nlonger amounts of time.\n\nDepending on the source data, this might not be the GTFS `stop_sequence` but another value, perhaps\neven generated.",
|
|
9677
|
-
"args": [],
|
|
9678
|
-
"type": {
|
|
9679
|
-
"kind": "SCALAR",
|
|
9680
|
-
"name": "Int",
|
|
9681
|
-
"ofType": null
|
|
9682
|
-
},
|
|
9683
|
-
"isDeprecated": false,
|
|
9684
|
-
"deprecationReason": null
|
|
9685
|
-
},
|
|
9686
9674
|
{
|
|
9687
9675
|
"name": "scheduledArrival",
|
|
9688
9676
|
"description": "Scheduled arrival time. Format: seconds since midnight of the departure date",
|
package/src/profile.js
CHANGED
package/src/query-gen.ts
CHANGED
|
@@ -58,7 +58,7 @@ export function extractAdditionalModes(
|
|
|
58
58
|
return prev;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
// In checkboxes
|
|
61
|
+
// In checkboxes, mode must be enabled and have a transport mode in it
|
|
62
62
|
if (
|
|
63
63
|
(cur.type === "CHECKBOX" || cur.type === "SUBMODE") &&
|
|
64
64
|
cur.addTransportMode &&
|
|
@@ -180,7 +180,7 @@ function isCombinationValid(
|
|
|
180
180
|
|
|
181
181
|
return !!VALID_COMBOS.find(
|
|
182
182
|
vc =>
|
|
183
|
-
simplifiedModes.
|
|
183
|
+
simplifiedModes.length === vc.length &&
|
|
184
184
|
vc.every(m => simplifiedModes.includes(m))
|
|
185
185
|
);
|
|
186
186
|
}
|
package/src/query.js
CHANGED
|
@@ -72,10 +72,7 @@ export function ensureSingleAccessMode(queryModes) {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
export function getUrlParams() {
|
|
75
|
-
|
|
76
|
-
return qs.parse(window.location.href.split("?")[1]);
|
|
77
|
-
}
|
|
78
|
-
return undefined;
|
|
75
|
+
return qs.parse(window.location.href.split("?")[1]);
|
|
79
76
|
}
|
|
80
77
|
|
|
81
78
|
export function getOtpUrlParams() {
|
package/src/route.ts
CHANGED
|
@@ -65,10 +65,10 @@ export function getTransitOperatorFromOtpRoute(
|
|
|
65
65
|
const feedId = route.id.split(":")[0];
|
|
66
66
|
let agencyId: string | number;
|
|
67
67
|
if (route.agency) {
|
|
68
|
-
// This is returned in
|
|
68
|
+
// This is returned in OTP2
|
|
69
69
|
agencyId = route.agency.id;
|
|
70
70
|
} else if (route.agencyId) {
|
|
71
|
-
// This is returned in
|
|
71
|
+
// This is returned in OTP1
|
|
72
72
|
agencyId = route.agencyId;
|
|
73
73
|
} else {
|
|
74
74
|
return null;
|
|
@@ -112,9 +112,9 @@ function getTransitOperatorComparatorValue(
|
|
|
112
112
|
// if the transitOperators is undefined or has zero length, use the route's
|
|
113
113
|
// agency name as the comparator value
|
|
114
114
|
if (!transitOperators || transitOperators.length === 0) {
|
|
115
|
-
//
|
|
115
|
+
// OTP2 Route
|
|
116
116
|
if (route.agency) return route.agency.name;
|
|
117
|
-
//
|
|
117
|
+
// OTP1 Route
|
|
118
118
|
if (route.agencyName) return route.agencyName;
|
|
119
119
|
// shouldn't happen as agency names will be defined
|
|
120
120
|
return "zzz";
|
|
@@ -140,7 +140,9 @@ function getTransitOperatorComparatorValue(
|
|
|
140
140
|
* Calculates the sort comparator value given two routes based off of the
|
|
141
141
|
* route's agency and provided transitOperators config data.
|
|
142
142
|
*/
|
|
143
|
-
function makeTransitOperatorComparator(
|
|
143
|
+
export function makeTransitOperatorComparator(
|
|
144
|
+
transitOperators: TransitOperator[]
|
|
145
|
+
) {
|
|
144
146
|
return (a: Route, b: Route) => {
|
|
145
147
|
const aVal = getTransitOperatorComparatorValue(a, transitOperators);
|
|
146
148
|
const bVal = getTransitOperatorComparatorValue(b, transitOperators);
|
|
@@ -237,7 +239,7 @@ function getRouteTypeComparatorValue(route: Route): number {
|
|
|
237
239
|
* Calculates the sort comparator value given two routes based off of route type
|
|
238
240
|
* (OTP mode).
|
|
239
241
|
*/
|
|
240
|
-
function routeTypeComparator(a: Route, b: Route): number {
|
|
242
|
+
export function routeTypeComparator(a: Route, b: Route): number {
|
|
241
243
|
return getRouteTypeComparatorValue(a) - getRouteTypeComparatorValue(b);
|
|
242
244
|
}
|
|
243
245
|
|
|
@@ -261,7 +263,7 @@ function startsWithAlphabeticCharacter(val: unknown): boolean {
|
|
|
261
263
|
* character. Routes with shortn that do start with an alphabetic character will
|
|
262
264
|
* be prioritized over those that don't.
|
|
263
265
|
*/
|
|
264
|
-
function alphabeticShortNameComparator(a: Route, b: Route): number {
|
|
266
|
+
export function alphabeticShortNameComparator(a: Route, b: Route): number {
|
|
265
267
|
const aStartsWithAlphabeticCharacter = startsWithAlphabeticCharacter(
|
|
266
268
|
a.shortName
|
|
267
269
|
);
|
|
@@ -282,6 +284,14 @@ function alphabeticShortNameComparator(a: Route, b: Route): number {
|
|
|
282
284
|
return 0;
|
|
283
285
|
}
|
|
284
286
|
|
|
287
|
+
const isNullOrNaN = (val: any): boolean => {
|
|
288
|
+
// isNaN(null) returns false so we have to check for null explicitly.
|
|
289
|
+
// Note: Using the global version of isNaN (the Number version behaves differently.
|
|
290
|
+
// eslint-disable-next-line no-restricted-globals
|
|
291
|
+
if (typeof val === null || isNaN(val)) return true;
|
|
292
|
+
|
|
293
|
+
return typeof val !== "number";
|
|
294
|
+
};
|
|
285
295
|
/**
|
|
286
296
|
* Checks whether an appropriate comparison of numeric values can be made for
|
|
287
297
|
* sorting purposes. If both values are not valid numbers according to the
|
|
@@ -304,19 +314,21 @@ function alphabeticShortNameComparator(a: Route, b: Route): number {
|
|
|
304
314
|
export function makeNumericValueComparator(
|
|
305
315
|
objGetterFn?: (item: Route) => number
|
|
306
316
|
) {
|
|
307
|
-
|
|
308
|
-
/* eslint-disable no-restricted-globals */
|
|
309
|
-
return (a: number, b: number): number => {
|
|
317
|
+
return (a: number, b: number): number | null => {
|
|
310
318
|
const { aVal, bVal } = getSortValues(objGetterFn, a, b);
|
|
311
|
-
if (typeof aVal !== "number" || typeof bVal !== "number") return 0;
|
|
312
319
|
|
|
313
320
|
// if both values aren't valid numbers, use the next sort criteria
|
|
314
|
-
if (
|
|
321
|
+
if (isNullOrNaN(aVal) && isNullOrNaN(bVal)) {
|
|
322
|
+
return 0;
|
|
323
|
+
}
|
|
315
324
|
// b is a valid number, b gets priority
|
|
316
|
-
if (
|
|
325
|
+
if (isNullOrNaN(aVal)) return 1;
|
|
326
|
+
|
|
317
327
|
// a is a valid number, a gets priority
|
|
318
|
-
if (
|
|
328
|
+
if (isNullOrNaN(bVal)) return -1;
|
|
329
|
+
|
|
319
330
|
// a and b are valid numbers, return the sort value
|
|
331
|
+
// @ts-expect-error We know from the checks above that both aVal and bVal are valid numbers.
|
|
320
332
|
return aVal - bVal;
|
|
321
333
|
};
|
|
322
334
|
}
|
|
@@ -350,15 +362,23 @@ export function makeStringValueComparator(
|
|
|
350
362
|
}
|
|
351
363
|
|
|
352
364
|
/**
|
|
353
|
-
*
|
|
354
|
-
*
|
|
355
|
-
*
|
|
365
|
+
* OTP1 sets the routeSortOrder to -999 by default. If we're encountering that value in OTP1,
|
|
366
|
+
* assume that it actually means that the route sortOrder is not set in the GTFS. If we encounter
|
|
367
|
+
* it in OTP2, it's a valid value, so we should return it.
|
|
356
368
|
*
|
|
357
369
|
* See https://github.com/opentripplanner/OpenTripPlanner/issues/2938
|
|
358
370
|
* Also see https://github.com/opentripplanner/otp-react-redux/issues/122
|
|
371
|
+
* This was updated in OTP2 TO be empty by default. https://docs.opentripplanner.org/en/v2.3.0/OTP2-MigrationGuide/#:~:text=the%20Alerts-,Changes%20to%20the%20Index%20API,-Error%20handling%20is
|
|
359
372
|
*/
|
|
360
|
-
function getRouteSortOrderValue(
|
|
361
|
-
|
|
373
|
+
export function getRouteSortOrderValue(route: Route): number {
|
|
374
|
+
const isOTP1 = !!route.agencyId;
|
|
375
|
+
const { sortOrder } = route;
|
|
376
|
+
|
|
377
|
+
if ((isOTP1 && sortOrder === -999) || sortOrder === undefined) {
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return sortOrder;
|
|
362
382
|
}
|
|
363
383
|
|
|
364
384
|
/**
|
|
@@ -368,7 +388,7 @@ function getRouteSortOrderValue(val: number): number {
|
|
|
368
388
|
* returned. If all comparison functions return equivalence, then the values
|
|
369
389
|
* are assumed to be equivalent.
|
|
370
390
|
*/
|
|
371
|
-
function makeMultiCriteriaSort(
|
|
391
|
+
export function makeMultiCriteriaSort(
|
|
372
392
|
...criteria: ((a: unknown, b: unknown) => number)[]
|
|
373
393
|
) {
|
|
374
394
|
return (a: number, b: number): number => {
|
|
@@ -420,7 +440,7 @@ export function makeRouteComparator(
|
|
|
420
440
|
): (a: number, b: number) => number {
|
|
421
441
|
return makeMultiCriteriaSort(
|
|
422
442
|
makeTransitOperatorComparator(transitOperators),
|
|
423
|
-
makeNumericValueComparator(obj => getRouteSortOrderValue(obj
|
|
443
|
+
makeNumericValueComparator(obj => getRouteSortOrderValue(obj)),
|
|
424
444
|
routeTypeComparator,
|
|
425
445
|
alphabeticShortNameComparator,
|
|
426
446
|
makeNumericValueComparator(obj => parseInt(obj.shortName, 10)),
|
package/src/storage.ts
CHANGED
|
@@ -6,12 +6,10 @@ const STORAGE_PREFIX = "otp";
|
|
|
6
6
|
* Store a javascript object at the specified key.
|
|
7
7
|
*/
|
|
8
8
|
export function storeItem(key: string, object: unknown): void {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
);
|
|
14
|
-
}
|
|
9
|
+
window.localStorage.setItem(
|
|
10
|
+
`${STORAGE_PREFIX}.${key}`,
|
|
11
|
+
JSON.stringify(object)
|
|
12
|
+
);
|
|
15
13
|
}
|
|
16
14
|
|
|
17
15
|
/**
|
|
@@ -36,9 +34,7 @@ export function getItem(key: string, notFoundValue: unknown = null): unknown {
|
|
|
36
34
|
* Remove item at specified key.
|
|
37
35
|
*/
|
|
38
36
|
export function removeItem(key: string): void {
|
|
39
|
-
|
|
40
|
-
window.localStorage.removeItem(`${STORAGE_PREFIX}.${key}`);
|
|
41
|
-
}
|
|
37
|
+
window.localStorage.removeItem(`${STORAGE_PREFIX}.${key}`);
|
|
42
38
|
}
|
|
43
39
|
|
|
44
40
|
/**
|
package/src/time.ts
CHANGED
|
@@ -26,6 +26,15 @@ export function toHoursMinutesSeconds(
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* If a duration is less than 60 seconds, round it to one minute, to avoid a duration
|
|
31
|
+
* of 0 minutes on a leg.
|
|
32
|
+
* @param {number} duration The leg or trip duration in seconds
|
|
33
|
+
* @returns a duration in seconds of at least 60 seconds.
|
|
34
|
+
*/
|
|
35
|
+
export const ensureAtLeastOneMinute = (duration: number): number =>
|
|
36
|
+
duration < 60 ? 60 : duration;
|
|
37
|
+
|
|
29
38
|
/**
|
|
30
39
|
* @param {[type]} config the OTP config object found in store
|
|
31
40
|
* @return {string} the config-defined time formatter or HH:mm (24-hr time)
|