@opentripplanner/core-utils 15.0.0 → 16.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 (58) hide show
  1. package/esm/index.js +3 -0
  2. package/esm/index.js.map +1 -1
  3. package/esm/itinerary.js +104 -78
  4. package/esm/itinerary.js.map +1 -1
  5. package/esm/map.js +2 -2
  6. package/esm/map.js.map +1 -1
  7. package/esm/query-gen.js +9 -5
  8. package/esm/query-gen.js.map +1 -1
  9. package/esm/route.js +26 -20
  10. package/esm/route.js.map +1 -1
  11. package/esm/storage.js +4 -1
  12. package/esm/storage.js.map +1 -1
  13. package/esm/time.js +6 -5
  14. package/esm/time.js.map +1 -1
  15. package/esm/ui.js +4 -2
  16. package/esm/ui.js.map +1 -1
  17. package/lib/index.d.ts.map +1 -1
  18. package/lib/index.js +6 -0
  19. package/lib/index.js.map +1 -1
  20. package/lib/itinerary.d.ts +20 -11
  21. package/lib/itinerary.d.ts.map +1 -1
  22. package/lib/itinerary.js +96 -85
  23. package/lib/itinerary.js.map +1 -1
  24. package/lib/map.d.ts +2 -2
  25. package/lib/map.d.ts.map +1 -1
  26. package/lib/map.js +1 -1
  27. package/lib/map.js.map +1 -1
  28. package/lib/query-gen.d.ts +1 -19
  29. package/lib/query-gen.d.ts.map +1 -1
  30. package/lib/query-gen.js +9 -5
  31. package/lib/query-gen.js.map +1 -1
  32. package/lib/route.d.ts +10 -8
  33. package/lib/route.d.ts.map +1 -1
  34. package/lib/route.js +22 -16
  35. package/lib/route.js.map +1 -1
  36. package/lib/storage.d.ts +1 -1
  37. package/lib/storage.d.ts.map +1 -1
  38. package/lib/storage.js +4 -1
  39. package/lib/storage.js.map +1 -1
  40. package/lib/time.d.ts +3 -1
  41. package/lib/time.d.ts.map +1 -1
  42. package/lib/time.js +5 -4
  43. package/lib/time.js.map +1 -1
  44. package/lib/ui.d.ts.map +1 -1
  45. package/lib/ui.js +4 -2
  46. package/lib/ui.js.map +1 -1
  47. package/package.json +9 -7
  48. package/src/__tests__/itinerary.ts +64 -6
  49. package/src/index.ts +3 -0
  50. package/src/itinerary.ts +145 -97
  51. package/src/map.ts +5 -3
  52. package/src/query-gen.ts +15 -9
  53. package/src/route.ts +65 -38
  54. package/src/storage.ts +8 -2
  55. package/src/time.ts +7 -6
  56. package/src/ui.ts +8 -6
  57. package/tsconfig.json +1 -0
  58. package/tsconfig.tsbuildinfo +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAK5D;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,aAAa,GAAE,OAAc,GAAG,OAAO,CAY3E;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAE5C;AAED;;;GAGG;AACH,wBAAgB,MAAM,IAAI,MAAM,CAI/B"}
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAK5D;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,CAAC,EACvB,GAAG,EAAE,MAAM,EACX,aAAa,GAAE,CAAC,GAAG,IAAW,GAC7B,CAAC,GAAG,IAAI,CAeV;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAE5C;AAED;;;GAGG;AACH,wBAAgB,MAAM,IAAI,MAAM,CAI/B"}
package/lib/storage.js CHANGED
@@ -23,9 +23,12 @@ function storeItem(key, object) {
23
23
  * null or, the optionally provided notFoundValue.
24
24
  */
25
25
  function getItem(key, notFoundValue = null) {
26
- let itemAsString;
26
+ let itemAsString = null;
27
27
  try {
28
28
  itemAsString = window.localStorage.getItem(`${STORAGE_PREFIX}.${key}`);
29
+ if (!itemAsString) {
30
+ return notFoundValue;
31
+ }
29
32
  const json = JSON.parse(itemAsString);
30
33
  if (json) return json;
31
34
  return notFoundValue;
@@ -1 +1 @@
1
- {"version":3,"file":"storage.js","names":["STORAGE_PREFIX","storeItem","key","object","window","localStorage","setItem","JSON","stringify","getItem","notFoundValue","itemAsString","json","parse","e","console","warn","removeItem","randId","Math","random","toString","substr"],"sources":["../src/storage.ts"],"sourcesContent":["/* eslint-disable no-console */\n// Prefix to use with local storage keys.\nconst STORAGE_PREFIX = \"otp\";\n\n/**\n * Store a javascript object at the specified key.\n */\nexport function storeItem(key: string, object: unknown): void {\n window.localStorage.setItem(\n `${STORAGE_PREFIX}.${key}`,\n JSON.stringify(object)\n );\n}\n\n/**\n * Retrieve a javascript object at the specified key. If not found, defaults to\n * null or, the optionally provided notFoundValue.\n */\nexport function getItem(key: string, notFoundValue: unknown = null): unknown {\n let itemAsString: string;\n try {\n itemAsString = window.localStorage.getItem(`${STORAGE_PREFIX}.${key}`);\n const json = JSON.parse(itemAsString);\n if (json) return json;\n return notFoundValue;\n } catch (e) {\n // Catch any errors associated with parsing bad JSON.\n console.warn(e, itemAsString);\n return notFoundValue;\n }\n}\n\n/**\n * Remove item at specified key.\n */\nexport function removeItem(key: string): void {\n window.localStorage.removeItem(`${STORAGE_PREFIX}.${key}`);\n}\n\n/**\n * Generate a random ID. This might not quite be a UUID, but it serves our\n * purposes for now.\n */\nexport function randId(): string {\n return Math.random()\n .toString(36)\n .substr(2, 9);\n}\n"],"mappings":";;;;;;;;;AAAA;AACA;AACA,MAAMA,cAAc,GAAG,KAAK;;AAE5B;AACA;AACA;AACO,SAASC,SAASA,CAACC,GAAW,EAAEC,MAAe,EAAQ;EAC5DC,MAAM,CAACC,YAAY,CAACC,OAAO,CACzB,GAAGN,cAAc,IAAIE,GAAG,EAAE,EAC1BK,IAAI,CAACC,SAAS,CAACL,MAAM,CACvB,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACO,SAASM,OAAOA,CAACP,GAAW,EAAEQ,aAAsB,GAAG,IAAI,EAAW;EAC3E,IAAIC,YAAoB;EACxB,IAAI;IACFA,YAAY,GAAGP,MAAM,CAACC,YAAY,CAACI,OAAO,CAAC,GAAGT,cAAc,IAAIE,GAAG,EAAE,CAAC;IACtE,MAAMU,IAAI,GAAGL,IAAI,CAACM,KAAK,CAACF,YAAY,CAAC;IACrC,IAAIC,IAAI,EAAE,OAAOA,IAAI;IACrB,OAAOF,aAAa;EACtB,CAAC,CAAC,OAAOI,CAAC,EAAE;IACV;IACAC,OAAO,CAACC,IAAI,CAACF,CAAC,EAAEH,YAAY,CAAC;IAC7B,OAAOD,aAAa;EACtB;AACF;;AAEA;AACA;AACA;AACO,SAASO,UAAUA,CAACf,GAAW,EAAQ;EAC5CE,MAAM,CAACC,YAAY,CAACY,UAAU,CAAC,GAAGjB,cAAc,IAAIE,GAAG,EAAE,CAAC;AAC5D;;AAEA;AACA;AACA;AACA;AACO,SAASgB,MAAMA,CAAA,EAAW;EAC/B,OAAOC,IAAI,CAACC,MAAM,CAAC,CAAC,CACjBC,QAAQ,CAAC,EAAE,CAAC,CACZC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;AACjB","ignoreList":[]}
1
+ {"version":3,"file":"storage.js","names":["STORAGE_PREFIX","storeItem","key","object","window","localStorage","setItem","JSON","stringify","getItem","notFoundValue","itemAsString","json","parse","e","console","warn","removeItem","randId","Math","random","toString","substr"],"sources":["../src/storage.ts"],"sourcesContent":["/* eslint-disable no-console */\n// Prefix to use with local storage keys.\nconst STORAGE_PREFIX = \"otp\";\n\n/**\n * Store a javascript object at the specified key.\n */\nexport function storeItem(key: string, object: unknown): void {\n window.localStorage.setItem(\n `${STORAGE_PREFIX}.${key}`,\n JSON.stringify(object)\n );\n}\n\n/**\n * Retrieve a javascript object at the specified key. If not found, defaults to\n * null or, the optionally provided notFoundValue.\n */\nexport function getItem<T>(\n key: string,\n notFoundValue: T | null = null\n): T | null {\n let itemAsString: string | null = null;\n try {\n itemAsString = window.localStorage.getItem(`${STORAGE_PREFIX}.${key}`);\n if (!itemAsString) {\n return notFoundValue;\n }\n const json = JSON.parse(itemAsString);\n if (json) return json;\n return notFoundValue;\n } catch (e) {\n // Catch any errors associated with parsing bad JSON.\n console.warn(e, itemAsString);\n return notFoundValue;\n }\n}\n\n/**\n * Remove item at specified key.\n */\nexport function removeItem(key: string): void {\n window.localStorage.removeItem(`${STORAGE_PREFIX}.${key}`);\n}\n\n/**\n * Generate a random ID. This might not quite be a UUID, but it serves our\n * purposes for now.\n */\nexport function randId(): string {\n return Math.random()\n .toString(36)\n .substr(2, 9);\n}\n"],"mappings":";;;;;;;;;AAAA;AACA;AACA,MAAMA,cAAc,GAAG,KAAK;;AAE5B;AACA;AACA;AACO,SAASC,SAASA,CAACC,GAAW,EAAEC,MAAe,EAAQ;EAC5DC,MAAM,CAACC,YAAY,CAACC,OAAO,CACzB,GAAGN,cAAc,IAAIE,GAAG,EAAE,EAC1BK,IAAI,CAACC,SAAS,CAACL,MAAM,CACvB,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACO,SAASM,OAAOA,CACrBP,GAAW,EACXQ,aAAuB,GAAG,IAAI,EACpB;EACV,IAAIC,YAA2B,GAAG,IAAI;EACtC,IAAI;IACFA,YAAY,GAAGP,MAAM,CAACC,YAAY,CAACI,OAAO,CAAC,GAAGT,cAAc,IAAIE,GAAG,EAAE,CAAC;IACtE,IAAI,CAACS,YAAY,EAAE;MACjB,OAAOD,aAAa;IACtB;IACA,MAAME,IAAI,GAAGL,IAAI,CAACM,KAAK,CAACF,YAAY,CAAC;IACrC,IAAIC,IAAI,EAAE,OAAOA,IAAI;IACrB,OAAOF,aAAa;EACtB,CAAC,CAAC,OAAOI,CAAC,EAAE;IACV;IACAC,OAAO,CAACC,IAAI,CAACF,CAAC,EAAEH,YAAY,CAAC;IAC7B,OAAOD,aAAa;EACtB;AACF;;AAEA;AACA;AACA;AACO,SAASO,UAAUA,CAACf,GAAW,EAAQ;EAC5CE,MAAM,CAACC,YAAY,CAACY,UAAU,CAAC,GAAGjB,cAAc,IAAIE,GAAG,EAAE,CAAC;AAC5D;;AAEA;AACA;AACA;AACA;AACO,SAASgB,MAAMA,CAAA,EAAW;EAC/B,OAAOC,IAAI,CAACC,MAAM,CAAC,CAAC,CACjBC,QAAQ,CAAC,EAAE,CAAC,CACZC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;AACjB","ignoreList":[]}
package/lib/time.d.ts CHANGED
@@ -30,7 +30,9 @@ export declare function getLongDateFormat(config: Config): string;
30
30
  * Offsets a time according to the provided time options
31
31
  * and returns the result.
32
32
  */
33
- export declare function offsetTime(ms: any, options: any): any;
33
+ export declare function offsetTime(ms: number, options?: {
34
+ offset: number;
35
+ }): number;
34
36
  /**
35
37
  * Formats a seconds after midnight value for display in narrative
36
38
  * @param {number} seconds time since midnight in seconds
package/lib/time.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"time.d.ts","sourceRoot":"","sources":["../src/time.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAMhD,eAAO,MAAM,mBAAmB,eAAe,CAAC;AAChD,eAAO,MAAM,mBAAmB,UAAU,CAAC;AAE3C;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,GACd;IACD,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,CAMA;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GAAI,UAAU,MAAM,KAAG,MAC3B,CAAC;AAEhC;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,kBAAkB;AAClB,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAExD;AACD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EAAE,KAAA,EAAE,OAAO,KAAA,OAErC;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,MAAM,CAGR;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,gBAAgB,SAAkB,GAAG,MAAM,CAG1E;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,SAAoB,GAAG,MAAM,CAEnE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,SAAoB,GAAG,MAAM,CAEnE"}
1
+ {"version":3,"file":"time.d.ts","sourceRoot":"","sources":["../src/time.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAMhD,eAAO,MAAM,mBAAmB,eAAe,CAAC;AAChD,eAAO,MAAM,mBAAmB,UAAU,CAAC;AAE3C;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,GACd;IACD,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,CAMA;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GAAI,UAAU,MAAM,KAAG,MAC3B,CAAC;AAEhC;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,kBAAkB;AAClB,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAExD;AACD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAE3E;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,MAAM,CAGR;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,gBAAgB,SAAkB,GAAG,MAAM,CAI1E;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,SAAoB,GAAG,MAAM,CAEnE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,SAAoB,GAAG,MAAM,CAEnE"}
package/lib/time.js CHANGED
@@ -87,8 +87,9 @@ function formatSecondsAfterMidnight(seconds, timeFormat) {
87
87
  * GMT+0 if the Intl API is unavailable.
88
88
  */
89
89
  function getUserTimezone(fallbackTimezone = "Etc/Greenwich") {
90
- if (process.env.NODE_ENV === "test") return process.env.TZ;
91
- return (Intl === null || Intl === void 0 ? void 0 : Intl.DateTimeFormat().resolvedOptions().timeZone) || fallbackTimezone;
90
+ var _process$env$TZ, _Intl$DateTimeFormat$;
91
+ if (process.env.NODE_ENV === "test") return (_process$env$TZ = process.env.TZ) !== null && _process$env$TZ !== void 0 ? _process$env$TZ : fallbackTimezone;
92
+ return (_Intl$DateTimeFormat$ = Intl === null || Intl === void 0 ? void 0 : Intl.DateTimeFormat().resolvedOptions().timeZone) !== null && _Intl$DateTimeFormat$ !== void 0 ? _Intl$DateTimeFormat$ : fallbackTimezone;
92
93
  }
93
94
 
94
95
  /**
@@ -96,7 +97,7 @@ function getUserTimezone(fallbackTimezone = "Etc/Greenwich") {
96
97
  * The conversion to the user's timezone is needed for testing purposes.
97
98
  */
98
99
  function getCurrentTime(timezone = getUserTimezone()) {
99
- return (0, _dateFns.format)((0, _dateFnsTz.utcToZonedTime)(Date.now(), timezone), OTP_API_TIME_FORMAT);
100
+ return (0, _dateFns.format)((0, _dateFnsTz.toZonedTime)(Date.now(), timezone), OTP_API_TIME_FORMAT);
100
101
  }
101
102
 
102
103
  /**
@@ -104,6 +105,6 @@ function getCurrentTime(timezone = getUserTimezone()) {
104
105
  * The conversion to the user's timezone is needed for testing purposes.
105
106
  */
106
107
  function getCurrentDate(timezone = getUserTimezone()) {
107
- return (0, _dateFns.format)((0, _dateFnsTz.utcToZonedTime)(Date.now(), timezone), OTP_API_DATE_FORMAT);
108
+ return (0, _dateFns.format)((0, _dateFnsTz.toZonedTime)(Date.now(), timezone), OTP_API_DATE_FORMAT);
108
109
  }
109
110
  //# sourceMappingURL=time.js.map
package/lib/time.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"time.js","names":["_dateFns","require","_dateFnsTz","OTP_API_DATE_FORMAT","exports","OTP_API_TIME_FORMAT","toHoursMinutesSeconds","seconds","hours","Math","floor","minutes","ensureAtLeastOneMinute","duration","getTimeFormat","config","_config$dateTime","dateTime","timeFormat","getDateFormat","_config$dateTime2","dateFormat","getLongDateFormat","_config$dateTime3","longDateFormat","offsetTime","ms","options","offset","formatSecondsAfterMidnight","time","add","startOfDay","Date","format","getUserTimezone","fallbackTimezone","process","env","NODE_ENV","TZ","Intl","DateTimeFormat","resolvedOptions","timeZone","getCurrentTime","timezone","utcToZonedTime","now","getCurrentDate"],"sources":["../src/time.ts"],"sourcesContent":["import { Config } from \"@opentripplanner/types\";\nimport { startOfDay, add, format } from \"date-fns\";\nimport { utcToZonedTime } from \"date-fns-tz\";\n\n// Date/time formats (per date-fns) when sending/receiving date from OTP\n// regardless of whatever the user has configured as the display format.\nexport const OTP_API_DATE_FORMAT = \"yyyy-MM-dd\";\nexport const OTP_API_TIME_FORMAT = \"HH:mm\";\n\n/**\n * Breaks up a duration in seconds into hours, minutes, and seconds.\n * @param {number} seconds The number of seconds to break up\n * @returns an object with fields with the corresponding, hours, minutes, seconds.\n */\nexport function toHoursMinutesSeconds(\n seconds: number\n): {\n hours: number;\n minutes: number;\n seconds: number;\n} {\n return {\n hours: Math.floor(seconds / 3600),\n minutes: Math.floor(seconds / 60) % 60,\n seconds: seconds % 60\n };\n}\n\n/**\n * If a duration is less than 60 seconds, round it to one minute, to avoid a duration\n * of 0 minutes on a leg.\n * @param {number} duration The leg or trip duration in seconds\n * @returns a duration in seconds of at least 60 seconds.\n */\nexport const ensureAtLeastOneMinute = (duration: number): number =>\n duration < 60 ? 60 : duration;\n\n/**\n * @param {[type]} config the OTP config object found in store\n * @return {string} the config-defined time formatter or HH:mm (24-hr time)\n */\nexport function getTimeFormat(config: Config): string {\n return config?.dateTime?.timeFormat || OTP_API_TIME_FORMAT;\n}\n\nexport function getDateFormat(config: Config): string {\n return config?.dateTime?.dateFormat || OTP_API_DATE_FORMAT;\n}\n\n/** @deprecated */\nexport function getLongDateFormat(config: Config): string {\n return config?.dateTime?.longDateFormat || \"D MMMM YYYY\";\n}\n/**\n * Offsets a time according to the provided time options\n * and returns the result.\n */\nexport function offsetTime(ms, options) {\n return ms + (options?.offset || 0);\n}\n\n/**\n * Formats a seconds after midnight value for display in narrative\n * @param {number} seconds time since midnight in seconds\n * @param {string} timeFormat A valid date-fns time format\n * @return {string} formatted text representation\n */\nexport function formatSecondsAfterMidnight(\n seconds: number,\n timeFormat: string\n): string {\n const time = add(startOfDay(new Date()), { seconds });\n return format(time, timeFormat);\n}\n\n/**\n * Uses Intl.DateTimeFormat() api to get the user's time zone. In a test\n * environment, pulls timezone information from an env variable. Default to\n * GMT+0 if the Intl API is unavailable.\n */\nexport function getUserTimezone(fallbackTimezone = \"Etc/Greenwich\"): string {\n if (process.env.NODE_ENV === \"test\") return process.env.TZ;\n return Intl?.DateTimeFormat().resolvedOptions().timeZone || fallbackTimezone;\n}\n\n/**\n * Formats current time for use in OTP query\n * The conversion to the user's timezone is needed for testing purposes.\n */\nexport function getCurrentTime(timezone = getUserTimezone()): string {\n return format(utcToZonedTime(Date.now(), timezone), OTP_API_TIME_FORMAT);\n}\n\n/**\n * Formats current date for use in OTP query\n * The conversion to the user's timezone is needed for testing purposes.\n */\nexport function getCurrentDate(timezone = getUserTimezone()): string {\n return format(utcToZonedTime(Date.now(), timezone), OTP_API_DATE_FORMAT);\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"time.js","names":["_dateFns","require","_dateFnsTz","OTP_API_DATE_FORMAT","exports","OTP_API_TIME_FORMAT","toHoursMinutesSeconds","seconds","hours","Math","floor","minutes","ensureAtLeastOneMinute","duration","getTimeFormat","config","_config$dateTime","dateTime","timeFormat","getDateFormat","_config$dateTime2","dateFormat","getLongDateFormat","_config$dateTime3","longDateFormat","offsetTime","ms","options","offset","formatSecondsAfterMidnight","time","add","startOfDay","Date","format","getUserTimezone","fallbackTimezone","_process$env$TZ","_Intl$DateTimeFormat$","process","env","NODE_ENV","TZ","Intl","DateTimeFormat","resolvedOptions","timeZone","getCurrentTime","timezone","toZonedTime","now","getCurrentDate"],"sources":["../src/time.ts"],"sourcesContent":["import { Config } from \"@opentripplanner/types\";\nimport { startOfDay, add, format } from \"date-fns\";\nimport { toZonedTime } from \"date-fns-tz\";\n\n// Date/time formats (per date-fns) when sending/receiving date from OTP\n// regardless of whatever the user has configured as the display format.\nexport const OTP_API_DATE_FORMAT = \"yyyy-MM-dd\";\nexport const OTP_API_TIME_FORMAT = \"HH:mm\";\n\n/**\n * Breaks up a duration in seconds into hours, minutes, and seconds.\n * @param {number} seconds The number of seconds to break up\n * @returns an object with fields with the corresponding, hours, minutes, seconds.\n */\nexport function toHoursMinutesSeconds(\n seconds: number\n): {\n hours: number;\n minutes: number;\n seconds: number;\n} {\n return {\n hours: Math.floor(seconds / 3600),\n minutes: Math.floor(seconds / 60) % 60,\n seconds: seconds % 60\n };\n}\n\n/**\n * If a duration is less than 60 seconds, round it to one minute, to avoid a duration\n * of 0 minutes on a leg.\n * @param {number} duration The leg or trip duration in seconds\n * @returns a duration in seconds of at least 60 seconds.\n */\nexport const ensureAtLeastOneMinute = (duration: number): number =>\n duration < 60 ? 60 : duration;\n\n/**\n * @param {[type]} config the OTP config object found in store\n * @return {string} the config-defined time formatter or HH:mm (24-hr time)\n */\nexport function getTimeFormat(config: Config): string {\n return config?.dateTime?.timeFormat || OTP_API_TIME_FORMAT;\n}\n\nexport function getDateFormat(config: Config): string {\n return config?.dateTime?.dateFormat || OTP_API_DATE_FORMAT;\n}\n\n/** @deprecated */\nexport function getLongDateFormat(config: Config): string {\n return config?.dateTime?.longDateFormat || \"D MMMM YYYY\";\n}\n/**\n * Offsets a time according to the provided time options\n * and returns the result.\n */\nexport function offsetTime(ms: number, options?: { offset: number }): number {\n return ms + (options?.offset || 0);\n}\n\n/**\n * Formats a seconds after midnight value for display in narrative\n * @param {number} seconds time since midnight in seconds\n * @param {string} timeFormat A valid date-fns time format\n * @return {string} formatted text representation\n */\nexport function formatSecondsAfterMidnight(\n seconds: number,\n timeFormat: string\n): string {\n const time = add(startOfDay(new Date()), { seconds });\n return format(time, timeFormat);\n}\n\n/**\n * Uses Intl.DateTimeFormat() api to get the user's time zone. In a test\n * environment, pulls timezone information from an env variable. Default to\n * GMT+0 if the Intl API is unavailable.\n */\nexport function getUserTimezone(fallbackTimezone = \"Etc/Greenwich\"): string {\n if (process.env.NODE_ENV === \"test\")\n return process.env.TZ ?? fallbackTimezone;\n return Intl?.DateTimeFormat().resolvedOptions().timeZone ?? fallbackTimezone;\n}\n\n/**\n * Formats current time for use in OTP query\n * The conversion to the user's timezone is needed for testing purposes.\n */\nexport function getCurrentTime(timezone = getUserTimezone()): string {\n return format(toZonedTime(Date.now(), timezone), OTP_API_TIME_FORMAT);\n}\n\n/**\n * Formats current date for use in OTP query\n * The conversion to the user's timezone is needed for testing purposes.\n */\nexport function getCurrentDate(timezone = getUserTimezone()): string {\n return format(toZonedTime(Date.now(), timezone), OTP_API_DATE_FORMAT);\n}\n"],"mappings":"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","ignoreList":[]}
package/lib/ui.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAAA,wBAAgB,QAAQ,IAAI,OAAO,CAKlC;AACD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CA4C9D"}
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAAA,wBAAgB,QAAQ,IAAI,OAAO,CAKlC;AACD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CA8C9D"}
package/lib/ui.js CHANGED
@@ -21,9 +21,11 @@ function enableScrollForSelector(selector) {
21
21
 
22
22
  function isOverlayTotallyScrolled() {
23
23
  // https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#Problems_and_solutions
24
+ if (!overlay) return false;
24
25
  return overlay.scrollHeight - overlay.scrollTop <= overlay.clientHeight;
25
26
  }
26
27
  function disableRubberBand(event) {
28
+ if (!overlay || clientY === null) return;
27
29
  const clientYDelta = event.targetTouches[0].clientY - clientY;
28
30
  if (overlay.scrollTop === 0 && clientYDelta > 0) {
29
31
  // element is at the top of its scroll
@@ -34,13 +36,13 @@ function enableScrollForSelector(selector) {
34
36
  event.preventDefault();
35
37
  }
36
38
  }
37
- overlay.addEventListener("touchstart", function (event) {
39
+ overlay === null || overlay === void 0 || overlay.addEventListener("touchstart", event => {
38
40
  if (event.targetTouches.length === 1) {
39
41
  // detect single touch
40
42
  clientY = event.targetTouches[0].clientY;
41
43
  }
42
44
  }, false);
43
- overlay.addEventListener("touchmove", function (event) {
45
+ overlay === null || overlay === void 0 || overlay.addEventListener("touchmove", event => {
44
46
  if (event.targetTouches.length === 1) {
45
47
  // detect single touch
46
48
  disableRubberBand(event);
package/lib/ui.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ui.js","names":["isMobile","test","navigator","userAgent","enableScrollForSelector","selector","overlay","document","querySelector","clientY","isOverlayTotallyScrolled","scrollHeight","scrollTop","clientHeight","disableRubberBand","event","clientYDelta","targetTouches","preventDefault","addEventListener","length"],"sources":["../src/ui.ts"],"sourcesContent":["export function isMobile(): boolean {\n // TODO: consider using 3rd-party library?\n return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(\n navigator.userAgent\n );\n}\n/**\n * Enables scrolling for a specified selector, while disabling scrolling for all\n * other targets. This is adapted from https://stackoverflow.com/a/41601290/915811\n * and intended to fix issues with iOS elastic scrolling, e.g.,\n * https://github.com/conveyal/trimet-mod-otp/issues/92.\n */\nexport function enableScrollForSelector(selector: string): void {\n const overlay = document.querySelector(selector);\n let clientY = null; // remember Y position on touch start\n\n function isOverlayTotallyScrolled(): boolean {\n // https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#Problems_and_solutions\n return overlay.scrollHeight - overlay.scrollTop <= overlay.clientHeight;\n }\n\n function disableRubberBand(event: TouchEvent) {\n const clientYDelta = event.targetTouches[0].clientY - clientY;\n\n if (overlay.scrollTop === 0 && clientYDelta > 0) {\n // element is at the top of its scroll\n event.preventDefault();\n }\n\n if (isOverlayTotallyScrolled() && clientYDelta < 0) {\n // element is at the top of its scroll\n event.preventDefault();\n }\n }\n\n overlay.addEventListener(\n \"touchstart\",\n function(event: TouchEvent) {\n if (event.targetTouches.length === 1) {\n // detect single touch\n clientY = event.targetTouches[0].clientY;\n }\n },\n false\n );\n\n overlay.addEventListener(\n \"touchmove\",\n function(event: TouchEvent) {\n if (event.targetTouches.length === 1) {\n // detect single touch\n disableRubberBand(event);\n }\n },\n false\n );\n}\n"],"mappings":";;;;;;;AAAO,SAASA,QAAQA,CAAA,EAAY;EAClC;EACA,OAAO,gEAAgE,CAACC,IAAI,CAC1EC,SAAS,CAACC,SACZ,CAAC;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,uBAAuBA,CAACC,QAAgB,EAAQ;EAC9D,MAAMC,OAAO,GAAGC,QAAQ,CAACC,aAAa,CAACH,QAAQ,CAAC;EAChD,IAAII,OAAO,GAAG,IAAI,CAAC,CAAC;;EAEpB,SAASC,wBAAwBA,CAAA,EAAY;IAC3C;IACA,OAAOJ,OAAO,CAACK,YAAY,GAAGL,OAAO,CAACM,SAAS,IAAIN,OAAO,CAACO,YAAY;EACzE;EAEA,SAASC,iBAAiBA,CAACC,KAAiB,EAAE;IAC5C,MAAMC,YAAY,GAAGD,KAAK,CAACE,aAAa,CAAC,CAAC,CAAC,CAACR,OAAO,GAAGA,OAAO;IAE7D,IAAIH,OAAO,CAACM,SAAS,KAAK,CAAC,IAAII,YAAY,GAAG,CAAC,EAAE;MAC/C;MACAD,KAAK,CAACG,cAAc,CAAC,CAAC;IACxB;IAEA,IAAIR,wBAAwB,CAAC,CAAC,IAAIM,YAAY,GAAG,CAAC,EAAE;MAClD;MACAD,KAAK,CAACG,cAAc,CAAC,CAAC;IACxB;EACF;EAEAZ,OAAO,CAACa,gBAAgB,CACtB,YAAY,EACZ,UAASJ,KAAiB,EAAE;IAC1B,IAAIA,KAAK,CAACE,aAAa,CAACG,MAAM,KAAK,CAAC,EAAE;MACpC;MACAX,OAAO,GAAGM,KAAK,CAACE,aAAa,CAAC,CAAC,CAAC,CAACR,OAAO;IAC1C;EACF,CAAC,EACD,KACF,CAAC;EAEDH,OAAO,CAACa,gBAAgB,CACtB,WAAW,EACX,UAASJ,KAAiB,EAAE;IAC1B,IAAIA,KAAK,CAACE,aAAa,CAACG,MAAM,KAAK,CAAC,EAAE;MACpC;MACAN,iBAAiB,CAACC,KAAK,CAAC;IAC1B;EACF,CAAC,EACD,KACF,CAAC;AACH","ignoreList":[]}
1
+ {"version":3,"file":"ui.js","names":["isMobile","test","navigator","userAgent","enableScrollForSelector","selector","overlay","document","querySelector","clientY","isOverlayTotallyScrolled","scrollHeight","scrollTop","clientHeight","disableRubberBand","event","clientYDelta","targetTouches","preventDefault","addEventListener","length"],"sources":["../src/ui.ts"],"sourcesContent":["export function isMobile(): boolean {\n // TODO: consider using 3rd-party library?\n return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(\n navigator.userAgent\n );\n}\n/**\n * Enables scrolling for a specified selector, while disabling scrolling for all\n * other targets. This is adapted from https://stackoverflow.com/a/41601290/915811\n * and intended to fix issues with iOS elastic scrolling, e.g.,\n * https://github.com/conveyal/trimet-mod-otp/issues/92.\n */\nexport function enableScrollForSelector(selector: string): void {\n const overlay = document.querySelector<HTMLElement>(selector);\n let clientY: number | null = null; // remember Y position on touch start\n\n function isOverlayTotallyScrolled(): boolean {\n // https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#Problems_and_solutions\n if (!overlay) return false;\n return overlay.scrollHeight - overlay.scrollTop <= overlay.clientHeight;\n }\n\n function disableRubberBand(event: TouchEvent) {\n if (!overlay || clientY === null) return;\n const clientYDelta = event.targetTouches[0].clientY - clientY;\n\n if (overlay.scrollTop === 0 && clientYDelta > 0) {\n // element is at the top of its scroll\n event.preventDefault();\n }\n\n if (isOverlayTotallyScrolled() && clientYDelta < 0) {\n // element is at the top of its scroll\n event.preventDefault();\n }\n }\n\n overlay?.addEventListener(\n \"touchstart\",\n (event: TouchEvent) => {\n if (event.targetTouches.length === 1) {\n // detect single touch\n clientY = event.targetTouches[0].clientY;\n }\n },\n false\n );\n\n overlay?.addEventListener(\n \"touchmove\",\n (event: TouchEvent) => {\n if (event.targetTouches.length === 1) {\n // detect single touch\n disableRubberBand(event);\n }\n },\n false\n );\n}\n"],"mappings":";;;;;;;AAAO,SAASA,QAAQA,CAAA,EAAY;EAClC;EACA,OAAO,gEAAgE,CAACC,IAAI,CAC1EC,SAAS,CAACC,SACZ,CAAC;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,uBAAuBA,CAACC,QAAgB,EAAQ;EAC9D,MAAMC,OAAO,GAAGC,QAAQ,CAACC,aAAa,CAAcH,QAAQ,CAAC;EAC7D,IAAII,OAAsB,GAAG,IAAI,CAAC,CAAC;;EAEnC,SAASC,wBAAwBA,CAAA,EAAY;IAC3C;IACA,IAAI,CAACJ,OAAO,EAAE,OAAO,KAAK;IAC1B,OAAOA,OAAO,CAACK,YAAY,GAAGL,OAAO,CAACM,SAAS,IAAIN,OAAO,CAACO,YAAY;EACzE;EAEA,SAASC,iBAAiBA,CAACC,KAAiB,EAAE;IAC5C,IAAI,CAACT,OAAO,IAAIG,OAAO,KAAK,IAAI,EAAE;IAClC,MAAMO,YAAY,GAAGD,KAAK,CAACE,aAAa,CAAC,CAAC,CAAC,CAACR,OAAO,GAAGA,OAAO;IAE7D,IAAIH,OAAO,CAACM,SAAS,KAAK,CAAC,IAAII,YAAY,GAAG,CAAC,EAAE;MAC/C;MACAD,KAAK,CAACG,cAAc,CAAC,CAAC;IACxB;IAEA,IAAIR,wBAAwB,CAAC,CAAC,IAAIM,YAAY,GAAG,CAAC,EAAE;MAClD;MACAD,KAAK,CAACG,cAAc,CAAC,CAAC;IACxB;EACF;EAEAZ,OAAO,aAAPA,OAAO,eAAPA,OAAO,CAAEa,gBAAgB,CACvB,YAAY,EACXJ,KAAiB,IAAK;IACrB,IAAIA,KAAK,CAACE,aAAa,CAACG,MAAM,KAAK,CAAC,EAAE;MACpC;MACAX,OAAO,GAAGM,KAAK,CAACE,aAAa,CAAC,CAAC,CAAC,CAACR,OAAO;IAC1C;EACF,CAAC,EACD,KACF,CAAC;EAEDH,OAAO,aAAPA,OAAO,eAAPA,OAAO,CAAEa,gBAAgB,CACvB,WAAW,EACVJ,KAAiB,IAAK;IACrB,IAAIA,KAAK,CAACE,aAAa,CAACG,MAAM,KAAK,CAAC,EAAE;MACpC;MACAN,iBAAiB,CAACC,KAAK,CAAC;IAC1B;EACF,CAAC,EACD,KACF,CAAC;AACH","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opentripplanner/core-utils",
3
- "version": "15.0.0",
3
+ "version": "16.0.1",
4
4
  "description": "Core functionality that is shared among numerous UI components",
5
5
  "engines": {
6
6
  "node": ">=13"
@@ -15,18 +15,20 @@
15
15
  "@conveyal/lonlat": "^1.4.1",
16
16
  "@mapbox/polyline": "^1.1.1",
17
17
  "@styled-icons/foundation": "^10.34.0",
18
- "@turf/along": "^6.0.1",
19
- "chroma-js": "^2.4.2",
20
- "date-fns": "^2.28.0",
21
- "date-fns-tz": "^1.2.2",
18
+ "@turf/along": "^7.3.1",
19
+ "chroma-js": "^3.2.0",
20
+ "date-fns": "^3.6.0",
21
+ "date-fns-tz": "^3.2.0",
22
22
  "graphql": "^16.6.0",
23
23
  "lodash.clonedeep": "^4.5.0",
24
24
  "qs": "^6.9.1",
25
- "@opentripplanner/geocoder": "3.0.7"
25
+ "@opentripplanner/geocoder": "3.0.8"
26
26
  },
27
27
  "gitHead": "0af1b7cda60bd4252b219dcf893e01c2acb2ed5d",
28
28
  "devDependencies": {
29
- "@opentripplanner/types": "8.3.1"
29
+ "@types/chroma-js": "^3.1.2",
30
+ "@types/mapbox__polyline": "^1.0.5",
31
+ "@opentripplanner/types": "8.4.0"
30
32
  },
31
33
  "scripts": {
32
34
  "tsc": "tsc"
@@ -12,6 +12,7 @@ import {
12
12
  getLegRouteShortName,
13
13
  isFlex,
14
14
  isTransit,
15
+ legElevationAtDistance,
15
16
  mapOldElevationComponentToNew
16
17
  } from "../itinerary";
17
18
 
@@ -22,6 +23,7 @@ import complexItinerary from "./__mocks__/complex-fares.json";
22
23
  import tripleItinerary from "./__mocks__/three-transfer-itinerary.json";
23
24
  import flexItinerary from "../../../itinerary-body/src/__mocks__/itineraries/flex-itinerary.json";
24
25
  import faresv2Itinerary from "../../../itinerary-body/src/__mocks__/itineraries/fares-v2-fare-components.json";
26
+ import legFareProdcuts from "../../../itinerary-body/src/__mocks__/itineraries/leg-fare-products.json";
25
27
 
26
28
  global.structuredClone = val => JSON.parse(JSON.stringify(val));
27
29
 
@@ -261,21 +263,21 @@ describe("util > itinerary", () => {
261
263
  "cash",
262
264
  "regular"
263
265
  );
264
- expect(result.amount).toEqual(5.75);
265
- expect(result.currency).toEqual({
266
+ expect(result?.amount).toEqual(5.75);
267
+ expect(result?.currency).toEqual({
266
268
  code: "USD",
267
269
  digits: 2
268
270
  });
269
271
  });
270
272
  it("should calculate the total cost of an itinerary using fares v2", () => {
271
273
  const result = getItineraryCost(faresv2Itinerary.legs, "3", "ADULT");
272
- expect(result.amount).toEqual(2.8);
274
+ expect(result?.amount).toEqual(2.8);
273
275
  const complexResult = getItineraryCost(
274
276
  faresv2Itinerary.legs,
275
277
  ["0", "0"],
276
278
  ["ADULT", "ADULT"]
277
279
  );
278
- expect(complexResult.amount).toEqual(2.8 * 2);
280
+ expect(complexResult?.amount).toEqual(2.8 * 2);
279
281
  });
280
282
  it("should calculate the total cost of an itinerary with multiple v2 fares & transfers", () => {
281
283
  const result = getItineraryCost(complexItinerary.legs, "0", "ADULT");
@@ -287,7 +289,7 @@ describe("util > itinerary", () => {
287
289
  ["0", "0"],
288
290
  ["ADULT", null]
289
291
  );
290
- expect(result.amount).toEqual(11.55);
292
+ expect(result?.amount).toEqual(11.55);
291
293
  });
292
294
  it("should calculate the individual leg cost of a fares v2 legs", () => {
293
295
  const firstLegResult = getLegCost(faresv2Itinerary.legs[1], "3", "ADULT");
@@ -308,13 +310,20 @@ describe("util > itinerary", () => {
308
310
  2.8
309
311
  );
310
312
  });
311
- it("should calculate the total cost of an itinerary will null ids", () => {
313
+ it("should calculate the total cost of an itinerary with null ids", () => {
312
314
  const result = getItineraryCost(fareProductItinerary.legs, null, null);
313
315
  expect(result.amount).toEqual(2.75);
314
316
  expect(result.currency).toEqual({
315
317
  code: "USD",
316
318
  digits: 2
317
319
  });
320
+ const resultWithDashEnabled = getItineraryCost(
321
+ legFareProdcuts.legs,
322
+ "orca",
323
+ "youth",
324
+ true
325
+ );
326
+ expect(resultWithDashEnabled).toEqual(undefined);
318
327
  });
319
328
  it("should return undefined when the keys are invalid", () => {
320
329
  const result = getItineraryCost(
@@ -404,4 +413,53 @@ describe("util > itinerary", () => {
404
413
  ).toBe("15");
405
414
  });
406
415
  });
416
+
417
+ describe("legElevationAtDistance", () => {
418
+ it("should interpolate elevation within a segment", () => {
419
+ const points: any = [
420
+ [0, 100],
421
+ [10, 110],
422
+ [20, 120]
423
+ ];
424
+ // halfway between 100 and 110
425
+ expect(legElevationAtDistance(points, 5)).toBe(105);
426
+ expect(legElevationAtDistance(points, 15)).toBe(115);
427
+ });
428
+
429
+ it("should return start elevation at distance 0", () => {
430
+ const points: any = [
431
+ [0, 42],
432
+ [10, 52]
433
+ ];
434
+ expect(legElevationAtDistance(points, 0)).toBe(42);
435
+ });
436
+
437
+ it("should return end elevation at the segment boundary", () => {
438
+ const points: any = [
439
+ [0, 100],
440
+ [10, 110],
441
+ [20, 120]
442
+ ];
443
+ expect(legElevationAtDistance(points, 10)).toBe(110);
444
+ expect(legElevationAtDistance(points, 20)).toBe(120);
445
+ });
446
+
447
+ it("should return undefined when distance is before the profile", () => {
448
+ const points: any = [
449
+ [0, 100],
450
+ [10, 110],
451
+ [20, 120]
452
+ ];
453
+ expect(legElevationAtDistance(points, -1)).toBeUndefined();
454
+ expect(legElevationAtDistance(points, 21)).toBeUndefined();
455
+ });
456
+
457
+ it("should return undefined when first point is not at zero", () => {
458
+ const points: any = [
459
+ [5, 100],
460
+ [15, 110]
461
+ ];
462
+ expect(legElevationAtDistance(points, 4)).toBeUndefined();
463
+ });
464
+ });
407
465
  });
package/src/index.ts CHANGED
@@ -1,7 +1,10 @@
1
1
  import * as itinerary from "./itinerary";
2
2
  import * as map from "./map";
3
+ // @ts-expect-error not typed
3
4
  import * as profile from "./profile";
5
+ // @ts-expect-error not typed
4
6
  import * as query from "./query";
7
+ // @ts-expect-error not typed
5
8
  import * as queryParams from "./query-params";
6
9
  import * as route from "./route";
7
10
  import * as storage from "./storage";