@furkot/directions 2.1.1 → 2.1.3

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 CHANGED
@@ -28,7 +28,7 @@ MIT © [Damian Krzeminski](https://pirxpilot.me)
28
28
  [npm-url]: https://npmjs.org/package/@furkot/directions
29
29
 
30
30
  [build-url]: https://github.com/furkot/directions/actions/workflows/check.yaml
31
- [build-image]: https://img.shields.io/github/workflow/status/furkot/directions/check
31
+ [build-image]: https://img.shields.io/github/actions/workflow/status/furkot/directions/check.yaml?branch=main
32
32
 
33
33
  [deps-image]: https://img.shields.io/librariesio/release/npm/@furkot/directions
34
34
  [deps-url]: https://libraries.io/npm/@furkot%2Fdirections
package/lib/directions.js CHANGED
@@ -1,5 +1,6 @@
1
1
  const travelMode = require('./model').travelMode;
2
- const { defaults: defaults, withTimeout } = require('./service/util');
2
+ const { defaults, withTimeout } = require('./service/util');
3
+ const prepareQuery = require('./profile');
3
4
 
4
5
  module.exports = furkotDirections;
5
6
 
@@ -41,40 +42,41 @@ const services = {
41
42
  const defaultTimeout = 20 * 1000;
42
43
 
43
44
  function furkotDirections(options) {
44
-
45
45
  options = {
46
46
  timeout: defaultTimeout,
47
47
  order: ['osrm', 'mapquest', 'valhalla', 'graphhopper', 'openroute'],
48
48
  ...options
49
49
  };
50
50
  if (!options.services) {
51
- options.services = options.order.map(name => {
52
- const service = services[options[name] || name];
53
- if (!service) {
54
- return;
55
- }
56
- const enable = options[`${name}_enable`];
57
- if (!enable) {
58
- return;
59
- }
60
- // object representing actual parameters for a service
61
- const serviceOptions = {
62
- name,
63
- limiter: options[`${name}_limiter`],
64
- enable,
65
- skip: service.skip
66
- };
67
- if (options[name]) {
68
- Object.keys(options).reduce(mapOptions, {
69
- options,
51
+ options.services = options.order
52
+ .map(name => {
53
+ const service = services[options[name] || name];
54
+ if (!service) {
55
+ return;
56
+ }
57
+ const enable = options[`${name}_enable`];
58
+ if (!enable) {
59
+ return;
60
+ }
61
+ // object representing actual parameters for a service
62
+ const serviceOptions = {
70
63
  name,
71
- optName: options[name],
72
- serviceOptions
73
- });
74
- }
75
- // we are adding options that has not been copied to serviceOptions yet
76
- return service.service(defaults(serviceOptions, options));
77
- }).filter(Boolean);
64
+ limiter: options[`${name}_limiter`],
65
+ enable,
66
+ skip: service.skip
67
+ };
68
+ if (options[name]) {
69
+ Object.keys(options).reduce(mapOptions, {
70
+ options,
71
+ name,
72
+ optName: options[name],
73
+ serviceOptions
74
+ });
75
+ }
76
+ // we are adding options that has not been copied to serviceOptions yet
77
+ return service.service(defaults(serviceOptions, options));
78
+ })
79
+ .filter(Boolean);
78
80
  }
79
81
 
80
82
  directions.options = options;
@@ -86,7 +88,7 @@ function furkotDirections(options) {
86
88
  */
87
89
  function directions(query, { signal } = {}) {
88
90
  if (query?.points?.length > 1) {
89
- return requestDirections(query, options.timeout);
91
+ return requestDirections(prepareQuery(query), options.timeout);
90
92
  }
91
93
 
92
94
  async function requestDirections(query, timeout) {
@@ -111,10 +113,13 @@ function furkotDirections(options) {
111
113
  break;
112
114
  }
113
115
  if (query.points.length > 2) {
114
- return requestDirections({
115
- ...query,
116
- points: query.points.slice(0, 2)
117
- }, timeout);
116
+ return requestDirections(
117
+ {
118
+ ...query,
119
+ points: query.points.slice(0, 2)
120
+ },
121
+ timeout
122
+ );
118
123
  }
119
124
  }
120
125
  return {
package/lib/model.js CHANGED
@@ -22,9 +22,7 @@ const directionsQuery = {
22
22
  avoidHighways: false, // true to avoid highways
23
23
  avoidTolls: false, // true to avoid toll roads
24
24
  units: 'm', // m - miles, km - kilometers
25
- points: [
26
- [0, 0]
27
- ], // array of consecutive series of points; each point is [lon, lat]
25
+ points: [[0, 0]], // array of consecutive series of points; each point is [lon, lat]
28
26
  isInChina: false, // points are in China (some services need this information)
29
27
  begin: '', // date/time for the begin of route as 'YYYY-MM-DDThh:mm'
30
28
  turnbyturn: false, // provide detailed turn-by-turn instructions (segments in directionsResult)
@@ -39,19 +37,25 @@ const directionsResult = {
39
37
  query: directionsQuery, // query parameters
40
38
  places: [], // addresses or place names corresponding to points (if directions service performs reverse geocoding)
41
39
  name: '', // human-readable name of directions (if available)
42
- routes: [{ // routes; one for each point with a successor in the query.points
43
- duration: 0, // route duration in seconds
44
- distance: 0, // route distance in meters
45
- path: [], // simplified series of interim points; each point is [lon, lat]
46
- seasonal: false, // indicates a road that is seasonally closed
47
- segmentIndex: 0 // index of the turn-by-turn directions segment
48
- }],
49
- segments: [{ // turn-by-turn directions
50
- duration: 0, // segment duration in seconds
51
- distance: 0, // segment distance in meters
52
- path: [], // series of interim points; each point is [lon, lat]
53
- instructions: '' // textual instructions for this segment
54
- }],
40
+ routes: [
41
+ {
42
+ // routes; one for each point with a successor in the query.points
43
+ duration: 0, // route duration in seconds
44
+ distance: 0, // route distance in meters
45
+ path: [], // simplified series of interim points; each point is [lon, lat]
46
+ seasonal: false, // indicates a road that is seasonally closed
47
+ segmentIndex: 0 // index of the turn-by-turn directions segment
48
+ }
49
+ ],
50
+ segments: [
51
+ {
52
+ // turn-by-turn directions
53
+ duration: 0, // segment duration in seconds
54
+ distance: 0, // segment distance in meters
55
+ path: [], // series of interim points; each point is [lon, lat]
56
+ instructions: '' // textual instructions for this segment
57
+ }
58
+ ],
55
59
  stats: [], // list of providers that requests have been sent to to obtain directions
56
60
  provider: '' // identifies service providing the directions
57
61
  };
@@ -0,0 +1,15 @@
1
+ const profiles = {
2
+ 5: require('./rv')
3
+ };
4
+
5
+ module.exports = prepareQuery;
6
+
7
+ /**
8
+ * Prepares query depending on the mode.
9
+ * @param {Object} query - The query object.
10
+ * @returns {Object} The prepared query.
11
+ */
12
+ function prepareQuery(query) {
13
+ const { mode } = query;
14
+ return profiles[mode]?.(query) || query;
15
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Default RV dimensions based on Valhalla defaults for truck:
3
+ * https://valhalla.github.io/valhalla/api/turn-by-turn/api-reference/#automobile-and-bus-costing-options
4
+ */
5
+ const defaultRV = {
6
+ axle_load: 9.07,
7
+ hazmat: true,
8
+ height: 4.11,
9
+ length: 21.64,
10
+ weight: 21.77,
11
+ width: 2.6
12
+ };
13
+
14
+ const passengerCar = {
15
+ height: 3.8,
16
+ length: 8,
17
+ weight: 6,
18
+ width: 2.5
19
+ };
20
+
21
+ module.exports = {
22
+ defaultRV,
23
+ passengerCar
24
+ };
@@ -0,0 +1,71 @@
1
+ const { passengerCar, defaultRV } = require('./dimensions');
2
+ const passengerCarEntries = Object.entries(passengerCar);
3
+
4
+ module.exports = prepareQuery;
5
+
6
+ /**
7
+ * Treat RV as passenger car when it doesn't carry hazmat and all its dimensions
8
+ * that are present fall within the passenger car limits.
9
+ * @param {Object} vehicle - The vehicle object.
10
+ * @returns {boolean} Whether to treat RV as passenger car.
11
+ */
12
+ function isPassengerCar(vehicle) {
13
+ return !vehicle.hazmat && passengerCarEntries.every(([k, v]) => vehicle[k] <= v);
14
+ }
15
+
16
+ /**
17
+ * Treat RV as non commercial truck when it doesn't carry hazmat and its
18
+ * weight and length are below truck limits.
19
+ * @param {Object} vehicle - The vehicle object.
20
+ * @returns {boolean} Whether to treat RV as non commercial truck.
21
+ */
22
+ function isNonCommercialTruck(vehicle) {
23
+ return !vehicle.hazmat && vehicle.length < defaultRV.length && vehicle.weight < defaultRV.weight;
24
+ }
25
+
26
+ /**
27
+ * Prepares vehicle size for the query.
28
+ * @param {Object} query - The query object.
29
+ * @returns {Object} The prepared query with vehicle size.
30
+ */
31
+ function prepareVehicle(vehicle) {
32
+ if (!vehicle) {
33
+ // treat as a standard truck
34
+ return {
35
+ vehicle: defaultRV
36
+ };
37
+ }
38
+ if (isPassengerCar(vehicle)) {
39
+ // treat as a regular passenger car
40
+ return {
41
+ mode: 0
42
+ };
43
+ }
44
+ vehicle = Object.assign({}, defaultRV, vehicle);
45
+ let proposedMode;
46
+ if (isNonCommercialTruck(vehicle)) {
47
+ // treat as a passenger car if at least height and width can be enforced
48
+ proposedMode = 0;
49
+ }
50
+ return {
51
+ proposedMode,
52
+ vehicle
53
+ };
54
+ }
55
+
56
+ /**
57
+ * Prepares query.
58
+ * @param {Object} query - The query object.
59
+ * @returns {Object} The prepared query.
60
+ */
61
+ function prepareQuery(query) {
62
+ const { mode: initialMode, vehicle: initialVehicle } = query;
63
+ return Object.assign(
64
+ {
65
+ initialMode,
66
+ initialVehicle
67
+ },
68
+ query,
69
+ prepareVehicle(query.vehicle)
70
+ );
71
+ }
@@ -1,7 +1,7 @@
1
1
  // https://docs.graphhopper.com/#tag/Routing-API
2
2
  // https://github.com/boldtrn/kurviger-api-documentation
3
3
 
4
- const { pathType, travelMode } = require("../../model");
4
+ const { pathType, travelMode } = require('../../model');
5
5
  const status = require('../status');
6
6
  const tagRoute = require('../tag-route');
7
7
  const util = require('../util');
@@ -9,12 +9,11 @@ const util = require('../util');
9
9
  module.exports = init;
10
10
 
11
11
  const vehicle = {
12
- '-1': 'car',
13
- 0: 'car',
14
12
  1: 'bike',
15
13
  2: 'foot',
16
14
  5: 'truck'
17
15
  };
16
+ const defaultVehicle = 'car';
18
17
 
19
18
  const weighting = {
20
19
  true: 'curvature',
@@ -40,7 +39,10 @@ const tollTypes = {
40
39
  };
41
40
 
42
41
  function extractSegment(result, { distance, interval, text, time }) {
43
- const { directions: { segments }, path } = result;
42
+ const {
43
+ directions: { segments },
44
+ path
45
+ } = result;
44
46
  const [from, to] = interval;
45
47
  segments.push({
46
48
  duration: Math.round((time || 0) / 1000),
@@ -64,7 +66,10 @@ function setTolls(seg) {
64
66
  }
65
67
 
66
68
  function extractDirections(result, { details, distance, instructions, points, time }) {
67
- const { directions: { routes, segments }, fullPath } = result;
69
+ const {
70
+ directions: { routes, segments },
71
+ fullPath
72
+ } = result;
68
73
  result.path = util.decode(points);
69
74
  const route = {
70
75
  duration: Math.round((time || 0) / 1000),
@@ -111,7 +116,7 @@ function extractDirections(result, { details, distance, instructions, points, ti
111
116
  }
112
117
 
113
118
  function getStatus(st, response) {
114
- st = st && st.status;
119
+ st = st?.status;
115
120
  if (!(st || response)) {
116
121
  return;
117
122
  }
@@ -130,9 +135,14 @@ function getStatus(st, response) {
130
135
  }
131
136
  }
132
137
 
138
+ function vehicleType(query) {
139
+ const { mode, proposedMode } = query;
140
+ return vehicle[proposedMode ?? mode] || defaultVehicle;
141
+ }
142
+
133
143
  function vehicleSize(query, options) {
134
- const { mode, vehicle } = query;
135
- if (!(vehicle && mode === travelMode.rv)) {
144
+ const { initialMode, mode, vehicle } = query;
145
+ if (!(vehicle && (initialMode ?? mode) === travelMode.rv)) {
136
146
  return;
137
147
  }
138
148
  const { hazmat } = vehicle;
@@ -142,7 +152,7 @@ function vehicleSize(query, options) {
142
152
  multiply_by: '0.0'
143
153
  });
144
154
  }
145
- ['height', 'width', 'length', 'weight', 'axle_load'].forEach(p => {
155
+ ['height', 'width', 'length', 'weight'].forEach(p => {
146
156
  if (vehicle[p]) {
147
157
  options.push({
148
158
  if: `max_${p} < ${vehicle[p]}`,
@@ -153,19 +163,23 @@ function vehicleSize(query, options) {
153
163
  }
154
164
 
155
165
  function init(options) {
156
-
157
166
  function prepareUrl(url) {
158
167
  return `${url}?key=${options.graphhopper_key}`;
159
168
  }
160
169
 
161
170
  function prepareRequest(query) {
162
171
  const { avoidFerry, avoidHighways, avoidTolls, avoidUnpaved, curvy, mode, path, points, turnbyturn } = query;
163
- if (options.parameters.max_curvy_distance && curvy && mode === -1 && points.length === 2 &&
164
- util.distance(points[0], points[1]) > options.parameters.max_curvy_distance) {
172
+ if (
173
+ options.parameters.max_curvy_distance &&
174
+ curvy &&
175
+ mode === -1 &&
176
+ points.length === 2 &&
177
+ util.distance(points[0], points[1]) > options.parameters.max_curvy_distance
178
+ ) {
165
179
  return;
166
180
  }
167
- let req = {
168
- vehicle: vehicle[mode] || vehicle[0],
181
+ const req = {
182
+ vehicle: vehicleType(query),
169
183
  points,
170
184
  details: ['road_environment', 'toll']
171
185
  };
@@ -190,21 +204,24 @@ function init(options) {
190
204
  if (avoidUnpaved) {
191
205
  req.avoid_unpaved_roads = true;
192
206
  }
193
- }
194
- else {
207
+ } else {
195
208
  req.details.push('surface');
196
209
  req['ch.disable'] = true;
197
210
  req.custom_model = {
198
- priority: [{
199
- if: 'road_class == MOTORWAY',
200
- multiply_by: avoidHighways ? '0.1' : '1.0'
201
- }, {
202
- if: 'toll == ALL',
203
- multiply_by: avoidTolls ? '0.1' : '1.0'
204
- }, {
205
- if: 'road_environment == FERRY',
206
- multiply_by: avoidFerry ? '0.1' : '1.0'
207
- }]
211
+ priority: [
212
+ {
213
+ if: 'road_class == MOTORWAY',
214
+ multiply_by: avoidHighways ? '0.1' : '1.0'
215
+ },
216
+ {
217
+ if: 'toll == ALL',
218
+ multiply_by: avoidTolls ? '0.1' : '1.0'
219
+ },
220
+ {
221
+ if: 'road_environment == FERRY',
222
+ multiply_by: avoidFerry ? '0.1' : '1.0'
223
+ }
224
+ ]
208
225
  };
209
226
  if (avoidUnpaved) {
210
227
  req.custom_model.priority.push({
@@ -219,7 +236,6 @@ function init(options) {
219
236
  }
220
237
 
221
238
  function processResponse(response, query) {
222
-
223
239
  if (response && response.status >= 400) {
224
240
  // let it cascade to the next service
225
241
  return;
@@ -229,7 +245,7 @@ function init(options) {
229
245
  query,
230
246
  provider: options.name
231
247
  };
232
- const paths = response && response.paths;
248
+ const paths = response?.paths;
233
249
  if (paths) {
234
250
  directions.routes = [];
235
251
  if (query.turnbyturn || query.path === pathType.smooth || query.path === pathType.coarse) {
@@ -1,5 +1,5 @@
1
1
  const fetchagent = require('fetchagent');
2
- const { pathType } = require("../model");
2
+ const { pathType } = require('../model');
3
3
  const makeLimiter = require('limiter-component');
4
4
  const status = require('./status');
5
5
  const makeSimplify = require('./simplify');
@@ -89,15 +89,14 @@ function init(options) {
89
89
  }
90
90
 
91
91
  async function request(url, req) {
92
- const options = this;
93
92
  let fa = fetchagent;
94
- if (options.post) {
93
+ if (this.post) {
95
94
  fa = fa.post(url).send(req);
96
95
  } else {
97
96
  fa = fa.get(url).query(req);
98
97
  }
99
- if (options.authorization) {
100
- fa.set('authorization', options.authorization);
98
+ if (this.authorization) {
99
+ fa.set('authorization', this.authorization);
101
100
  }
102
101
  const res = await fa.set('accept', 'application/json').end();
103
102
  let status;
@@ -1,4 +1,4 @@
1
- const { pathType } = require("../../model");
1
+ const { pathType } = require('../../model');
2
2
  const status = require('../status');
3
3
  const util = require('../util');
4
4
 
@@ -39,7 +39,12 @@ function addPoint(result, p, i, points) {
39
39
  }
40
40
 
41
41
  function extractSegment(result, { distance, index, narrative, time }) {
42
- const { directions: { segments }, maneuverIndexes: indexes, path, unitMultiplier } = result;
42
+ const {
43
+ directions: { segments },
44
+ maneuverIndexes: indexes,
45
+ path,
46
+ unitMultiplier
47
+ } = result;
43
48
  segments.push({
44
49
  duration: time,
45
50
  distance: Math.round((distance || 0) * unitMultiplier),
@@ -50,7 +55,11 @@ function extractSegment(result, { distance, index, narrative, time }) {
50
55
  }
51
56
 
52
57
  function extractDirections(result, leg) {
53
- const { directions: { routes, segments }, legIndexes: indexes, path } = result;
58
+ const {
59
+ directions: { routes, segments },
60
+ legIndexes: indexes,
61
+ path
62
+ } = result;
54
63
  const route = {
55
64
  duration: leg.time || 0,
56
65
  distance: Math.round((leg.distance || 0) * result.unitMultiplier)
@@ -71,12 +80,12 @@ function extractDirections(result, leg) {
71
80
  return result;
72
81
  }
73
82
 
74
- function getStatus(err, response) {
83
+ function getStatus(_err, response) {
75
84
  if (!response) {
76
85
  return;
77
86
  }
78
87
  const { info, route } = response;
79
- const st = info && info.statuscode;
88
+ const st = info?.statuscode;
80
89
  if (st === 403 || st === 500) {
81
90
  // assume its because we exceeded the limit
82
91
  return status.failure;
@@ -94,7 +103,6 @@ function getStatus(err, response) {
94
103
  }
95
104
 
96
105
  function init(options) {
97
-
98
106
  function getProvider(query) {
99
107
  if (query.alternate) {
100
108
  return options.name;
@@ -103,8 +111,11 @@ function init(options) {
103
111
  }
104
112
 
105
113
  function getUrl(query) {
106
- return options[getProvider(query) + '_url'] + '/directions/v2/' +
107
- (query.alternate && query.points.length <= 2 ? 'alternateroutes' : 'route');
114
+ return (
115
+ options[getProvider(query) + '_url'] +
116
+ '/directions/v2/' +
117
+ (query.alternate && query.points.length <= 2 ? 'alternateroutes' : 'route')
118
+ );
108
119
  }
109
120
 
110
121
  function prepareRequest(query) {
@@ -146,8 +157,7 @@ function init(options) {
146
157
  }
147
158
 
148
159
  function processResponse(response, query) {
149
-
150
- if (response && response.info) {
160
+ if (response?.info) {
151
161
  const { statuscode: st } = response.info;
152
162
  if (st === 402 || st > 600) {
153
163
  // let it cascade to the next service
@@ -155,8 +165,8 @@ function init(options) {
155
165
  }
156
166
  }
157
167
 
158
- const route = response && response.route;
159
- if (!(route && route.legs && route.legs.length)) {
168
+ const route = response?.route;
169
+ if (!route?.legs?.length) {
160
170
  // shouldn't happen
161
171
  return;
162
172
  }
@@ -175,9 +185,9 @@ function init(options) {
175
185
  route.legs.reduce(extractDirections, {
176
186
  directions,
177
187
  unitMultiplier: query.units === 'km' ? util.metersInKm : util.metersInMile,
178
- maneuverIndexes: route.shape && route.shape.maneuverIndexes,
179
- legIndexes: route.shape && route.shape.legIndexes,
180
- path: route.shape && route.shape.shapePoints.reduce(addPoint, []),
188
+ maneuverIndexes: route.shape?.maneuverIndexes,
189
+ legIndexes: route.shape?.legIndexes,
190
+ path: route.shape?.shapePoints.reduce(addPoint, []),
181
191
  fullPath
182
192
  });
183
193
  if (fullPath) {
@@ -1,7 +1,7 @@
1
1
  // https://openrouteservice.org/dev/#/api-docs/directions
2
2
 
3
3
  const LatLon = require('geodesy/latlon-spherical');
4
- const { pathType, travelMode } = require("../../model");
4
+ const { pathType, travelMode } = require('../../model');
5
5
  const status = require('../status');
6
6
  const tagRoute = require('../tag-route');
7
7
  const util = require('../util');
@@ -26,27 +26,29 @@ const avoidFeatures = {
26
26
  avoidFerry: 'ferries'
27
27
  };
28
28
  const ferryTypes = {
29
- '9': true
29
+ 9: true
30
30
  };
31
31
  const roughTypes = {
32
- '2': true, // Unpaved
33
- '8': true, // Compacted Gravel
34
- '9': true, // Fine Gravel
35
- '10': true, // Gravel
36
- '11': true, // Dirt
37
- '12': true, // Ground
38
- '15': true, // Sand
39
- '17': true, // Grass
40
- '18': true // Grass Paver
32
+ 2: true, // Unpaved
33
+ 8: true, // Compacted Gravel
34
+ 9: true, // Fine Gravel
35
+ 10: true, // Gravel
36
+ 11: true, // Dirt
37
+ 12: true, // Ground
38
+ 15: true, // Sand
39
+ 17: true, // Grass
40
+ 18: true // Grass Paver
41
41
  };
42
42
  const tollTypes = {
43
- '1': true
43
+ 1: true
44
44
  };
45
45
  const maxRoundabout = 12 * 60 * 60; // 12 hours maximum for route that is 10 times longer than direct distance
46
46
 
47
-
48
47
  function extractStep(result, { distance, duration, instruction, way_points }) {
49
- const { directions: { segments }, path } = result;
48
+ const {
49
+ directions: { segments },
50
+ path
51
+ } = result;
50
52
  const seg = {
51
53
  duration: Math.round(duration || 0),
52
54
  distance: Math.round(distance || 0),
@@ -70,13 +72,20 @@ function setTolls(seg) {
70
72
  }
71
73
 
72
74
  function extractDirections(result, { distance, duration, steps }, i) {
73
- const { directions: { routes, segments }, path, surface, waypoints, waytypes, tollways } = result;
75
+ const {
76
+ directions: { routes, segments },
77
+ path,
78
+ surface,
79
+ waypoints,
80
+ waytypes,
81
+ tollways
82
+ } = result;
74
83
  const route = {
75
84
  duration: Math.round(duration || 0),
76
85
  distance: Math.round(distance || 0),
77
86
  path: path?.slice(waypoints[i], waypoints[i + 1] + 1)
78
87
  };
79
- if (!(route.duration || route.distance || (route.path?.length > 1))) {
88
+ if (!(route.duration || route.distance || route.path?.length > 1)) {
80
89
  route.path = [];
81
90
  }
82
91
  if (segments) {
@@ -87,7 +96,7 @@ function extractDirections(result, { distance, duration, steps }, i) {
87
96
  steps.reduce(extractStep, result);
88
97
  if (segments.length === 1) {
89
98
  const seg = segments[0];
90
- if (!(seg.duration || seg.distance || (seg.path?.length > 1))) {
99
+ if (!(seg.duration || seg.distance || seg.path?.length > 1)) {
91
100
  seg.path = [];
92
101
  }
93
102
  }
@@ -127,24 +136,30 @@ function toLatLon(p) {
127
136
  }
128
137
 
129
138
  function directDistance(locations) {
130
- return locations.reduce((result, next) => {
131
- next = toLatLon(next);
132
- result.dist += result.ll.distanceTo(next);
133
- result.ll = next;
134
- return result;
135
- }, {
136
- dist: 0,
137
- ll: toLatLon(locations[0])
138
- }).dist;
139
+ return locations.reduce(
140
+ (result, next) => {
141
+ next = toLatLon(next);
142
+ result.dist += result.ll.distanceTo(next);
143
+ result.ll = next;
144
+ return result;
145
+ },
146
+ {
147
+ dist: 0,
148
+ ll: toLatLon(locations[0])
149
+ }
150
+ ).dist;
139
151
  }
140
152
 
141
153
  function getStatus(st, response) {
142
154
  if (!st && response?.routes?.length) {
143
- const { distance, duration } = response.routes.reduce((result, { summary}) => {
144
- result.distance += summary.distance;
145
- result.duration += summary.duration;
146
- return result;
147
- }, { distance: 0, duration: 0 });
155
+ const { distance, duration } = response.routes.reduce(
156
+ (result, { summary }) => {
157
+ result.distance += summary.distance;
158
+ result.duration += summary.duration;
159
+ return result;
160
+ },
161
+ { distance: 0, duration: 0 }
162
+ );
148
163
  const coordinates = response.metadata?.query?.coordinates;
149
164
  const direct = coordinates ? directDistance(coordinates) : distance;
150
165
  if (distance < 5 * direct || duration < maxRoundabout) {
@@ -169,13 +184,8 @@ function vehicleSize(query, restrictions) {
169
184
  }
170
185
 
171
186
  function init(options) {
172
-
173
187
  function prepareUrl(query) {
174
- return [
175
- options.openroute_url,
176
- profile[query.mode] || profile[0],
177
- 'json'
178
- ].join('/');
188
+ return [options.openroute_url, profile[query.mode] || profile[0], 'json'].join('/');
179
189
  }
180
190
 
181
191
  function avoidFeature(result, flag) {
@@ -219,7 +229,6 @@ function init(options) {
219
229
  }
220
230
 
221
231
  function processResponse(response, query) {
222
-
223
232
  if (!response?.routes?.length) {
224
233
  // let it cascade to the next service
225
234
  return;
@@ -1,4 +1,4 @@
1
- const { pathType } = require("../../model");
1
+ const { pathType } = require('../../model');
2
2
  const status = require('../status');
3
3
  const util = require('../util');
4
4
 
@@ -45,8 +45,8 @@ function convertRoute({ legs }) {
45
45
  }
46
46
 
47
47
  // response codes: http://project-osrm.org/docs/v5.5.2/api/#responses
48
- function getStatus(err, response) {
49
- const code = response && response.code;
48
+ function getStatus(_err, response) {
49
+ const code = response?.code;
50
50
  if (!response) {
51
51
  return;
52
52
  }
@@ -75,26 +75,16 @@ const profile = {
75
75
  };
76
76
 
77
77
  function prepareUrl(baseUrl, query) {
78
-
79
78
  function coords2string(c) {
80
79
  return c[0].toFixed(5) + ',' + c[1].toFixed(5);
81
80
  }
82
81
 
82
+ const path = query.points.map(coords2string).join(';');
83
83
 
84
- const path = query.points
85
- .map(coords2string)
86
- .join(';');
87
-
88
- return [
89
- baseUrl,
90
- 'route/v1',
91
- profile[query.mode],
92
- path
93
- ].join('/');
84
+ return [baseUrl, 'route/v1', profile[query.mode], path].join('/');
94
85
  }
95
86
 
96
87
  function init(options) {
97
-
98
88
  function processResponse(response, query) {
99
89
  const directions = {
100
90
  query,
@@ -112,14 +102,14 @@ function init(options) {
112
102
  if (query.turnbyturn || query.path === pathType.smooth || query.path === pathType.coarse) {
113
103
  directions.segments = [];
114
104
  // copy segments from route to its own table
115
- directions.routes.forEach(function (route) {
105
+ directions.routes.forEach(route => {
116
106
  route.segmentIndex = directions.segments.length;
117
107
  directions.segments = directions.segments.concat(route.segments);
118
108
  delete route.segments;
119
109
  });
120
110
  } else {
121
111
  // delete segments
122
- directions.routes.forEach(function (route) {
112
+ directions.routes.forEach(route => {
123
113
  delete route.segments;
124
114
  });
125
115
  }
@@ -3,7 +3,7 @@ const util = require('./util');
3
3
  module.exports = partition;
4
4
 
5
5
  function distanceSquare(p1, p2) {
6
- return Math.pow((p1[0] - p2[0]), 2) + Math.pow((p1[1] - p2[1]), 2);
6
+ return (p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2;
7
7
  }
8
8
 
9
9
  function pointOnLine(point, p1, p2) {
@@ -1,4 +1,4 @@
1
- const pathType = require("../model").pathType;
1
+ const pathType = require('../model').pathType;
2
2
  const util = require('./util');
3
3
 
4
4
  module.exports = init;
@@ -6,7 +6,7 @@ module.exports = init;
6
6
  function init(options) {
7
7
  options = options || {};
8
8
 
9
- const algorithm = options.algorithm || require("vis-why");
9
+ const algorithm = options.algorithm || require('vis-why');
10
10
  const endPoints = options.endPoints || 25; // how many points keep at ends
11
11
  const maxPoints = options.pathPoints || 100; // maximum number of points kept per path
12
12
  const ed = maxPoints / endPoints;
@@ -53,8 +53,10 @@ function init(options) {
53
53
  }
54
54
  }
55
55
  if (first.split) {
56
- util.concat(path, segments[i].path.slice(first.split,
57
- (i === result.segmentIndex - 1 && last.split) ? last.split : undefined));
56
+ util.concat(
57
+ path,
58
+ segments[i].path.slice(first.split, i === result.segmentIndex - 1 && last.split ? last.split : undefined)
59
+ );
58
60
  i += 1;
59
61
  }
60
62
  for (; i < (last.split ? result.segmentIndex - 1 : result.segmentIndex); i += 1) {
@@ -64,7 +66,7 @@ function init(options) {
64
66
  util.concat(path, segments[i].path.slice(0, last.split));
65
67
  }
66
68
  result.segmentIndex = route.segmentIndex;
67
- if (type === pathType.full || (first.length + path.length + last.length) <= maxPoints) {
69
+ if (type === pathType.full || first.length + path.length + last.length <= maxPoints) {
68
70
  if (endDistance) {
69
71
  route.path = util.concat(util.concat(first, path), last);
70
72
  } else {
@@ -64,7 +64,7 @@ function isFuture(time) {
64
64
 
65
65
  // like normal join but with optional filter fn
66
66
  function join(arr, conn, fn) {
67
- fn = fn || function (it) { return it; };
67
+ fn = fn || (it => it);
68
68
  return arr.filter(fn).join(conn);
69
69
  }
70
70
 
@@ -73,24 +73,27 @@ function last(arr) {
73
73
  }
74
74
 
75
75
  function split2object(str, conn, obj) {
76
- return str.split(conn || '-').reduce(function (result, word) {
76
+ return str.split(conn || '-').reduce((result, word) => {
77
77
  result[word] = word;
78
78
  return result;
79
79
  }, obj || {});
80
80
  }
81
81
 
82
82
  function collateResults(results, query) {
83
- return results.reduce((result, r) => {
84
- concatArrayProp(result, r, 'segments');
85
- concatArrayProp(result, r, 'places');
86
- concatArrayProp(result, r, 'routes');
87
- if (!result.name && r?.name) {
88
- result.name = r.name;
83
+ return results.reduce(
84
+ (result, r) => {
85
+ concatArrayProp(result, r, 'segments');
86
+ concatArrayProp(result, r, 'places');
87
+ concatArrayProp(result, r, 'routes');
88
+ if (!result.name && r?.name) {
89
+ result.name = r.name;
90
+ }
91
+ return result;
92
+ },
93
+ {
94
+ query
89
95
  }
90
- return result;
91
- }, {
92
- query
93
- });
96
+ );
94
97
 
95
98
  function concatArrayProp(to, from, prop) {
96
99
  if (!from[prop]) {
@@ -110,12 +113,10 @@ function withTimeout(promise, millis, signal) {
110
113
  let reject;
111
114
 
112
115
  signal?.addEventListener('abort', onabort);
113
- return Promise
114
- .race([promise, new Promise(timeoutPromise)])
115
- .finally(() => {
116
- signal?.removeEventListener('abort', onabort);
117
- clearTimeout(id);
118
- });
116
+ return Promise.race([promise, new Promise(timeoutPromise)]).finally(() => {
117
+ signal?.removeEventListener('abort', onabort);
118
+ clearTimeout(id);
119
+ });
119
120
 
120
121
  function onabort() {
121
122
  reject(signal.reason);
@@ -124,10 +125,7 @@ function withTimeout(promise, millis, signal) {
124
125
  function timeoutPromise(_resolve, _reject) {
125
126
  resolve = _resolve;
126
127
  reject = _reject;
127
- id = setTimeout(
128
- () => resolve(),
129
- millis
130
- );
128
+ id = setTimeout(() => resolve(), millis);
131
129
  }
132
130
  }
133
131
 
@@ -1,7 +1,7 @@
1
1
  // https://github.com/valhalla/valhalla-docs
2
2
 
3
3
  const LatLon = require('geodesy/latlon-spherical');
4
- const { pathType, travelMode } = require("../../model");
4
+ const { pathType, travelMode } = require('../../model');
5
5
  const status = require('../status');
6
6
  const util = require('../util');
7
7
 
@@ -23,7 +23,7 @@ const costingOptions = {
23
23
  hazmat: true
24
24
  }
25
25
  };
26
- const minSpeed = 15 * 1000 / 3600; // bump speed when it is absurdly low
26
+ const minSpeed = (15 * 1000) / 3600; // bump speed when it is absurdly low
27
27
  const turnDistance = 100; // don't adjust speed of turns
28
28
  const maxRoundabout = 12 * 60 * 60; // 12 hours maximum for route that is 10 times longer than direct distance
29
29
 
@@ -41,18 +41,15 @@ function prepareWaypoint(p) {
41
41
  };
42
42
  }
43
43
 
44
- function extractSegment(result, {
45
- type,
46
- begin_shape_index,
47
- end_shape_index,
48
- instruction,
49
- length,
50
- time,
51
- rough,
52
- toll,
53
- travel_mode
54
- }) {
55
- const { directions: { segments, routes }, unitMultiplier, path } = result;
44
+ function extractSegment(
45
+ result,
46
+ { type, begin_shape_index, end_shape_index, instruction, length, time, rough, toll, travel_mode }
47
+ ) {
48
+ const {
49
+ directions: { segments, routes },
50
+ unitMultiplier,
51
+ path
52
+ } = result;
56
53
  const distance = Math.round((length || 0) * unitMultiplier);
57
54
  let duration = time;
58
55
  if (rough) {
@@ -69,7 +66,7 @@ function extractSegment(result, {
69
66
  const seg = {
70
67
  duration,
71
68
  distance,
72
- path: path && path.slice(begin_shape_index, end_shape_index),
69
+ path: path?.slice(begin_shape_index, end_shape_index),
73
70
  instructions: instruction
74
71
  };
75
72
  if (rough) {
@@ -98,8 +95,8 @@ function extractDirections(result, leg) {
98
95
  const { directions } = result;
99
96
  result.path = util.decode(leg.shape, { factor: 1e6 });
100
97
  const route = {
101
- duration: (leg.summary && leg.summary.time) || 0,
102
- distance: Math.round(((leg.summary && leg.summary.length) || 0) * result.unitMultiplier)
98
+ duration: leg.summary?.time || 0,
99
+ distance: Math.round((leg.summary?.length || 0) * result.unitMultiplier)
103
100
  };
104
101
  if (result.fullPath) {
105
102
  route.path = result.path;
@@ -125,19 +122,24 @@ function toLatLon(p) {
125
122
 
126
123
  function directDistance(locations, units) {
127
124
  units = units === 'miles' ? util.metersInMile : util.metersInKm;
128
- return locations.reduce((result, next) => {
129
- next = toLatLon(next);
130
- result.dist += result.ll.distanceTo(next);
131
- result.ll = next;
132
- return result;
133
- }, {
134
- dist: 0,
135
- ll: toLatLon(locations[0])
136
- }).dist / units;
125
+ return (
126
+ locations.reduce(
127
+ (result, next) => {
128
+ next = toLatLon(next);
129
+ result.dist += result.ll.distanceTo(next);
130
+ result.ll = next;
131
+ return result;
132
+ },
133
+ {
134
+ dist: 0,
135
+ ll: toLatLon(locations[0])
136
+ }
137
+ ).dist / units
138
+ );
137
139
  }
138
140
 
139
- function getStatus(err, response) {
140
- let st = response && response.status_code;
141
+ function getStatus(_err, response) {
142
+ let st = response?.status_code;
141
143
  if (!response) {
142
144
  return;
143
145
  }
@@ -150,14 +152,13 @@ function getStatus(err, response) {
150
152
  // no route
151
153
  return status.empty;
152
154
  }
153
- st = response.trip && response.trip.status;
155
+ st = response.trip?.status;
154
156
  if (st === 0) {
155
- if (response.trip.legs && response.trip.legs.length) {
157
+ if (response.trip.legs?.length) {
156
158
  const { length, time } = response.trip.summary;
157
159
  const distance = directDistance(response.trip.locations, response.trip.units);
158
160
  // make sure points are not too far from roads
159
- if (length > 0.9 * distance &&
160
- (length < 10 * distance || time < maxRoundabout)) {
161
+ if (length > 0.9 * distance && (length < 10 * distance || time < maxRoundabout)) {
161
162
  return status.success;
162
163
  }
163
164
  }
@@ -166,20 +167,24 @@ function getStatus(err, response) {
166
167
  }
167
168
  }
168
169
 
170
+ function costingType(query) {
171
+ const { mode, proposedMode } = query;
172
+ return costing[proposedMode ?? mode] || defaultCosting;
173
+ }
174
+
169
175
  function vehicleSize(query, options) {
170
- const { mode, vehicle } = query;
171
- if (!(vehicle && mode === travelMode.rv)) {
176
+ const { initialMode, mode, vehicle } = query;
177
+ if (!(vehicle && (initialMode ?? mode) === travelMode.rv)) {
172
178
  return;
173
179
  }
174
180
  Object.assign(options, vehicle);
175
181
  }
176
182
 
177
183
  function init(options) {
178
-
179
184
  function prepareRequest(query) {
180
185
  let req = {
181
186
  locations: query.points.map(prepareWaypoint),
182
- costing: costing[query.mode] || defaultCosting,
187
+ costing: costingType(query),
183
188
  costing_options: {},
184
189
  directions_options: {
185
190
  units: units[query.units] || units.m
@@ -224,8 +229,8 @@ function init(options) {
224
229
  }
225
230
 
226
231
  function processResponse(response, query) {
227
- const trip = response && response.trip;
228
- if (trip && trip.legs && trip.legs.length) {
232
+ const trip = response?.trip;
233
+ if (trip?.legs?.length) {
229
234
  const directions = {
230
235
  query,
231
236
  provider: options.name,
package/package.json CHANGED
@@ -1,13 +1,16 @@
1
1
  {
2
2
  "name": "@furkot/directions",
3
- "version": "2.1.1",
3
+ "version": "2.1.3",
4
4
  "description": "Directions service for Furkot",
5
5
  "author": {
6
6
  "name": "Damian Krzeminski",
7
7
  "email": "pirxpilot@furkot.com",
8
8
  "url": "https://pirxpilot.me"
9
9
  },
10
- "repository": "furkot/directions",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/furkot/directions.git"
13
+ },
11
14
  "license": "MIT",
12
15
  "keywords": [
13
16
  "furkot-directions",
@@ -20,13 +23,10 @@
20
23
  "fetchagent": "~2.1.0",
21
24
  "geodesy": "^1.1.1",
22
25
  "limiter-component": "^1.2.0",
23
- "vis-why": "^1.2.2"
26
+ "vis-why": "~2"
24
27
  },
25
28
  "devDependencies": {
26
- "jshint": "~2",
27
- "mocha": "~10",
28
- "should": "~13",
29
- "sinon": "~14"
29
+ "@biomejs/biome": "^1.9.4"
30
30
  },
31
31
  "scripts": {
32
32
  "test": "make check"
@@ -35,4 +35,4 @@
35
35
  "index.js",
36
36
  "lib"
37
37
  ]
38
- }
38
+ }