@opentripplanner/core-utils 10.0.0-alpha.4 → 10.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/src/itinerary.ts CHANGED
@@ -78,7 +78,6 @@ export function legDropoffRequiresAdvanceBooking(leg: Leg): boolean {
78
78
  return isAdvanceBookingRequired(leg.dropOffBookingInfo);
79
79
  }
80
80
 
81
- // alpha-only comment
82
81
  export function isRideshareLeg(leg: Leg): boolean {
83
82
  return !!leg.rideHailingEstimate?.provider?.id;
84
83
  }
@@ -409,13 +408,10 @@ export function getCompanyForNetwork(
409
408
  * @return {string} A label for use in presentation on a website.
410
409
  */
411
410
  export function getCompaniesLabelFromNetworks(
412
- networks: string | string[],
411
+ networks: string[],
413
412
  companies: Company[] = []
414
413
  ): string {
415
- let networksArray = networks;
416
- if (typeof networks === "string") networksArray = [networks];
417
-
418
- return (networksArray as string[])
414
+ return networks
419
415
  .map(network => getCompanyForNetwork(network, companies))
420
416
  .filter(co => !!co)
421
417
  .map(co => co.label)
@@ -570,7 +566,11 @@ export function getLegCost(
570
566
  leg: Leg,
571
567
  mediumId: string | null,
572
568
  riderCategoryId: string | null
573
- ): { price?: Money; transferAmount?: Money | undefined; useId?: string } {
569
+ ): {
570
+ price?: Money;
571
+ transferAmount?: Money | undefined;
572
+ productUseId?: string;
573
+ } {
574
574
  if (!leg.fareProducts) return { price: undefined };
575
575
  const relevantFareProducts = leg.fareProducts.filter(({ product }) => {
576
576
  // riderCategory and medium can be specifically defined as null to handle
@@ -593,7 +593,7 @@ export function getLegCost(
593
593
  return {
594
594
  price: totalCostProduct?.product.price,
595
595
  transferAmount: transferFareProduct?.product.price,
596
- useId: totalCostProduct?.id
596
+ productUseId: totalCostProduct?.id
597
597
  };
598
598
  }
599
599
 
@@ -618,13 +618,13 @@ export function getItineraryCost(
618
618
  // Filter out duplicate use IDs
619
619
  // One fare product can be used on multiple legs,
620
620
  // and we don't want to count it more than once.
621
- .reduce<{ useId: string; price: Money }[]>((prev, cur) => {
622
- if (!prev.some(p => p.useId === cur.useId)) {
623
- prev.push({ useId: cur.useId, price: cur.price });
621
+ .reduce<{ productUseId: string; price: Money }[]>((prev, cur) => {
622
+ if (!prev.some(p => p.productUseId === cur.productUseId)) {
623
+ prev.push({ productUseId: cur.productUseId, price: cur.price });
624
624
  }
625
625
  return prev;
626
626
  }, [])
627
- .map(prodUse => prodUse.price);
627
+ .map(productUse => productUse.price);
628
628
 
629
629
  if (legCosts.length === 0) return undefined;
630
630
  // Calculate the total
@@ -2292,7 +2292,7 @@
2292
2292
  "fields": [
2293
2293
  {
2294
2294
  "name": "id",
2295
- "description": "Identifier local to the itinerary that allows to cross-reference and deduplicate\nfare products that span more than one leg.\n\nIf you want to uniquely identify the fare product itself (not its use) use the product's `id`.\n\n### Example: Day pass\n\nWhen a day pass is valid for all three legs in the itinerary it will appear\nfor each leg but with the same use-`id`.\n\n*It is the responsibility of the API consumers to display the day pass as a product for the\nentire itinerary rather than three day passes!*\n\n### Example: Several single tickets\n\nIf you have two legs and need to buy two single tickets they will appear in each leg with the\nsame `product.id` but different use-`id`.",
2295
+ "description": "Represents the use of a single instance of a fare product throughout the itinerary. It can\nbe used to cross-reference and de-duplicate fare products that are applicable for more than one\nleg.\n\nIf you want to uniquely identify the fare product itself (not its use) use the product's `id`.\n\n### Example: Day pass\n\nThe day pass is valid for both legs in the itinerary. It is listed as the applicable `product` for each leg,\nand the same FareProductUse id is shown, indicating that only one pass was used/bought.\n\n**Illustration**\n```yaml\nitinerary:\n leg1:\n fareProducts:\n id: \"AAA\" // id of a FareProductUse instance\n product:\n id: \"day-pass\" // product id\n name: \"Day Pass\"\n leg2:\n fareProducts:\n id: \"AAA\" // identical to leg1. the passenger needs to buy ONE pass, not two.\n product:\n id: \"day-pass\" // product id\n name: \"Day Pass\"\n```\n\n**It is the responsibility of the API consumers to display the day pass as a product for the\nentire itinerary rather than two day passes!**\n\n### Example: Several single tickets\n\nIf you have two legs and need to buy two single tickets they will appear in each leg with the\nsame `FareProduct.id` but different `FareProductUse.id`.\n\n**Illustration**\n```yaml\nitinerary:\n leg1:\n fareProducts:\n id: \"AAA\" // id of a FareProductUse instance, not product id\n product:\n id: \"single-ticket\" // product id\n name: \"Single Ticket\"\n leg2:\n fareProducts:\n id: \"BBB\" // different to leg1. the passenger needs to buy two single tickets.\n product:\n id: \"single-ticket\" // product id\n name: \"Single Ticket\"\n```",
2296
2296
  "args": [],
2297
2297
  "type": {
2298
2298
  "kind": "NON_NULL",
@@ -3558,7 +3558,7 @@
3558
3558
  },
3559
3559
  {
3560
3560
  "name": "steps",
3561
- "description": null,
3561
+ "description": "The turn-by-turn navigation instructions.",
3562
3562
  "args": [],
3563
3563
  "type": {
3564
3564
  "kind": "LIST",
@@ -3572,6 +3572,18 @@
3572
3572
  "isDeprecated": false,
3573
3573
  "deprecationReason": null
3574
3574
  },
3575
+ {
3576
+ "name": "headsign",
3577
+ "description": "For transit legs, the headsign that the vehicle shows at the stop where the passenger boards.\nFor non-transit legs, null.",
3578
+ "args": [],
3579
+ "type": {
3580
+ "kind": "SCALAR",
3581
+ "name": "String",
3582
+ "ofType": null
3583
+ },
3584
+ "isDeprecated": false,
3585
+ "deprecationReason": null
3586
+ },
3575
3587
  {
3576
3588
  "name": "pickupType",
3577
3589
  "description": "This is used to indicate if boarding this leg is possible only with special arrangements.",
@@ -8446,49 +8458,43 @@
8446
8458
  "enumValues": [
8447
8459
  {
8448
8460
  "name": "NO_TRANSIT_CONNECTION",
8449
- "description": "No transit connection was found between the origin and destination withing the operating day or the next day",
8461
+ "description": "No transit connection was found between the origin and destination within the operating day or\nthe next day, not even sub-optimal ones.",
8450
8462
  "isDeprecated": false,
8451
8463
  "deprecationReason": null
8452
8464
  },
8453
8465
  {
8454
8466
  "name": "NO_TRANSIT_CONNECTION_IN_SEARCH_WINDOW",
8455
- "description": "Transit connection was found, but it was outside the search window, see metadata for the next search window",
8467
+ "description": "A transit connection was found, but it was outside the search window. See the metadata for a token\nfor retrieving the result outside the search window.",
8456
8468
  "isDeprecated": false,
8457
8469
  "deprecationReason": null
8458
8470
  },
8459
8471
  {
8460
8472
  "name": "OUTSIDE_SERVICE_PERIOD",
8461
- "description": "The date specified is outside the range of data currently loaded into the system",
8473
+ "description": "The date specified is outside the range of data currently loaded into the system as it is too\nfar into the future or the past.\n\nThe specific date range of the system is configurable by an administrator and also depends on\nthe input data provided.",
8462
8474
  "isDeprecated": false,
8463
8475
  "deprecationReason": null
8464
8476
  },
8465
8477
  {
8466
8478
  "name": "OUTSIDE_BOUNDS",
8467
- "description": "The coordinates are outside the bounds of the data currently loaded into the system",
8479
+ "description": "The coordinates are outside the geographic bounds of the transit and street data currently loaded\ninto the system and therefore cannot return any results.",
8468
8480
  "isDeprecated": false,
8469
8481
  "deprecationReason": null
8470
8482
  },
8471
8483
  {
8472
8484
  "name": "LOCATION_NOT_FOUND",
8473
- "description": "The specified location is not close to any streets or transit stops",
8485
+ "description": "The specified location is not close to any streets or transit stops currently loaded into the\nsystem, even though it is generally within its bounds.\n\nThis can happen when there is only transit but no street data coverage at the location in\nquestion.",
8474
8486
  "isDeprecated": false,
8475
8487
  "deprecationReason": null
8476
8488
  },
8477
8489
  {
8478
8490
  "name": "NO_STOPS_IN_RANGE",
8479
- "description": "No stops are reachable from the location specified. You can try searching using a different access or egress mode",
8491
+ "description": "No stops are reachable from the start or end locations specified.\n\nYou can try searching using a different access or egress mode, for example cycling instead of walking,\nincrease the walking/cycling/driving speed or have an administrator change the system's configuration\nso that stops further away are considered.",
8480
8492
  "isDeprecated": false,
8481
8493
  "deprecationReason": null
8482
8494
  },
8483
8495
  {
8484
8496
  "name": "WALKING_BETTER_THAN_TRANSIT",
8485
- "description": "The origin and destination are so close to each other, that walking is always better, but no direct mode was specified for the search",
8486
- "isDeprecated": false,
8487
- "deprecationReason": null
8488
- },
8489
- {
8490
- "name": "SYSTEM_ERROR",
8491
- "description": "An unknown error happened during the search. The details have been logged to the server logs",
8497
+ "description": "Transit connections were requested and found but because it is easier to just walk all the way\nto the destination they were removed.\n\nIf you want to still show the transit results, you need to make walking less desirable by\nincreasing the walk reluctance.",
8492
8498
  "isDeprecated": false,
8493
8499
  "deprecationReason": null
8494
8500
  }
@@ -9433,18 +9439,6 @@
9433
9439
  "isDeprecated": false,
9434
9440
  "deprecationReason": null
9435
9441
  },
9436
- {
9437
- "name": "stopPosition",
9438
- "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.",
9439
- "args": [],
9440
- "type": {
9441
- "kind": "SCALAR",
9442
- "name": "Int",
9443
- "ofType": null
9444
- },
9445
- "isDeprecated": false,
9446
- "deprecationReason": null
9447
- },
9448
9442
  {
9449
9443
  "name": "scheduledArrival",
9450
9444
  "description": "Scheduled arrival time. Format: seconds since midnight of the departure date",
@@ -10071,7 +10065,7 @@
10071
10065
  "args": [
10072
10066
  {
10073
10067
  "name": "language",
10074
- "description": "If translated headsign is found from gtfs translation.txt and wanted language is not same as\nfeed's language then returns wanted translation. Otherwise uses name from trip_headsign.txt.",
10068
+ "description": "If a translated headsign is found from GTFS translation.txt and wanted language is not same as\nfeed's language then returns wanted translation. Otherwise uses name from trip_headsign.txt.",
10075
10069
  "type": {
10076
10070
  "kind": "SCALAR",
10077
10071
  "name": "String",
@@ -1,18 +1,19 @@
1
1
  query Plan(
2
- $fromPlace: String!
3
- $toPlace: String!
4
- $modes: [TransportMode]
5
- $time: String
6
- $date: String
7
- $wheelchair: Boolean
2
+ $arriveBy: Boolean
3
+ $banned: InputBanned
8
4
  $bikeReluctance: Float
9
5
  $carReluctance: Float
10
- $walkReluctance: Float
11
- $arriveBy: Boolean
6
+ $date: String
7
+ $fromPlace: String!
8
+ $modes: [TransportMode]
9
+ $numItineraries: Int
12
10
  $preferred: InputPreferred
11
+ $time: String
12
+ $toPlace: String!
13
13
  $unpreferred: InputUnpreferred
14
- $banned: InputBanned
15
- $numItineraries: Int
14
+ $walkReluctance: Float
15
+ $walkSpeed: Float
16
+ $wheelchair: Boolean
16
17
  ) {
17
18
  plan(
18
19
  arriveBy: $arriveBy
@@ -30,6 +31,7 @@ query Plan(
30
31
  transportModes: $modes
31
32
  unpreferred: $unpreferred
32
33
  walkReluctance: $walkReluctance
34
+ walkSpeed: $walkSpeed
33
35
  wheelchair: $wheelchair
34
36
  ) {
35
37
  itineraries {
@@ -104,6 +106,7 @@ query Plan(
104
106
  }
105
107
  vertexType
106
108
  }
109
+ headsign
107
110
  interlineWithPreviousLeg
108
111
  intermediateStops {
109
112
  lat
@@ -222,7 +225,6 @@ query Plan(
222
225
  }
223
226
  gtfsId
224
227
  id
225
- tripHeadsign
226
228
  }
227
229
  }
228
230
  startTime
package/src/profile.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export function filterProfileOptions(response) {
2
- // Filter out similar options. TODO: handle on server??
2
+ // Filter out similar options. TODO: handle on server?
3
3
  const optStrs = [];
4
4
  const filteredIndices = [];
5
5
 
package/src/query-gen.ts CHANGED
@@ -57,7 +57,7 @@ export function extractAdditionalModes(
57
57
  return prev;
58
58
  }
59
59
 
60
- // In checkboxes (or submode checkboxes), mode must be enabled and have a transport mode in it
60
+ // In checkboxes, mode must be enabled and have a transport mode in it
61
61
  if (
62
62
  (cur.type === "CHECKBOX" || cur.type === "SUBMODE") &&
63
63
  cur.addTransportMode &&
@@ -67,7 +67,7 @@ export function extractAdditionalModes(
67
67
  }
68
68
  if (cur.type === "DROPDOWN") {
69
69
  const transportMode = cur.options.find(o => o.value === cur.value)
70
- .addTransportMode;
70
+ ?.addTransportMode;
71
71
  if (transportMode) {
72
72
  return [...prev, transportMode];
73
73
  }
@@ -228,12 +228,18 @@ export function generateOtp2Query(
228
228
  prev[cur.inverseKey] = cur.high - cur.value + cur.low;
229
229
  }
230
230
  prev[cur.key] = cur.value;
231
+
232
+ // If we assign a value on true, return the value (or null) instead of a boolean.
233
+ if (cur.type === "CHECKBOX" && cur.truthValue) {
234
+ prev[cur.key] = cur.value === true ? cur.truthValue : null;
235
+ }
231
236
  return prev;
232
237
  }, {}) as ModeSettingValues;
233
238
 
234
239
  const {
235
240
  bikeReluctance,
236
241
  carReluctance,
242
+ walkSpeed,
237
243
  walkReluctance,
238
244
  wheelchair
239
245
  } = modeSettingValues;
@@ -253,6 +259,7 @@ export function generateOtp2Query(
253
259
  time,
254
260
  toPlace: `${to.name}::${to.lat},${to.lon}}`,
255
261
  walkReluctance,
262
+ walkSpeed,
256
263
  wheelchair
257
264
  }
258
265
  };
@@ -365,31 +365,6 @@ const queryParams = [
365
365
  }
366
366
  ]
367
367
  },
368
-
369
- {
370
- /* walkSpeed -- the user's walking speed in m/s */
371
- name: "walkSpeed",
372
- routingTypes: ["ITINERARY", "PROFILE"],
373
- default: 1.34,
374
- selector: "DROPDOWN",
375
- label: "Walk Speed",
376
- applicable: query => query.mode && query.mode.indexOf("WALK") !== -1,
377
- options: [
378
- {
379
- text: "2 MPH",
380
- value: 0.89
381
- },
382
- {
383
- text: "3 MPH",
384
- value: 1.34
385
- },
386
- {
387
- text: "4 MPH",
388
- value: 1.79
389
- }
390
- ]
391
- },
392
-
393
368
  {
394
369
  name: "walkReluctance",
395
370
  routingTypes: ["ITINERARY", "PROFILE"],
package/src/query.js CHANGED
@@ -19,7 +19,6 @@ export const defaultParams = [
19
19
  "maxWalkDistance",
20
20
  "walkReluctance",
21
21
  "maxWalkTime",
22
- "walkSpeed",
23
22
  "maxBikeDistance",
24
23
  "maxBikeTime",
25
24
  "bikeSpeed",