@any-routing/mapbox-data-provider 1.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -0
- package/package.json +14 -0
- package/project.json +21 -0
- package/src/index.ts +2 -0
- package/src/lib/mapbox-data-provider.ts +108 -0
- package/src/lib/mapbox-provider.types.ts +98 -0
- package/src/lib/mapbox.executor.spec.ts +69 -0
- package/src/lib/mapbox.executor.ts +118 -0
- package/src/lib/mapbox.worker.ts +4 -0
- package/tsconfig.json +16 -0
- package/tsconfig.lib.json +10 -0
- package/tsconfig.spec.json +8 -0
- package/vite.config.mts +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# mapbox-data-provider
|
|
2
|
+
|
|
3
|
+
`AnyRoutingDataProvider` implementation backed by the
|
|
4
|
+
[Mapbox Directions API](https://docs.mapbox.com/api/navigation/directions/).
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
import { MapboxProvider } from '@any-routing/mapbox-data-provider';
|
|
8
|
+
|
|
9
|
+
const dataProvider = new MapboxProvider({
|
|
10
|
+
accessToken: 'YOUR_MAPBOX_ACCESS_TOKEN',
|
|
11
|
+
profile: 'driving',
|
|
12
|
+
alternatives: true,
|
|
13
|
+
});
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The provider requests GeoJSON geometry and turn-by-turn steps by default.
|
|
17
|
+
Requests run in a Web Worker by default; use `worker: false` when a worker is
|
|
18
|
+
not available.
|
package/package.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@any-routing/mapbox-data-provider",
|
|
3
|
+
"version": "1.0.0-rc.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./index.js",
|
|
6
|
+
"types": "./index.d.ts",
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"@any-routing/core": "1.0.0-rc.1",
|
|
9
|
+
"@turf/bbox": "7.4.0",
|
|
10
|
+
"@turf/helpers": "7.4.0",
|
|
11
|
+
"@types/geojson": "7946.0.16",
|
|
12
|
+
"comlink": "4.4.2"
|
|
13
|
+
}
|
|
14
|
+
}
|
package/project.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mapbox-data-provider",
|
|
3
|
+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
+
"sourceRoot": "libs/mapbox-data-provider/src",
|
|
5
|
+
"projectType": "library",
|
|
6
|
+
"release": {
|
|
7
|
+
"version": {
|
|
8
|
+
"manifestRootsToUpdate": ["dist/{projectRoot}"],
|
|
9
|
+
"currentVersionResolver": "git-tag",
|
|
10
|
+
"fallbackCurrentVersionResolver": "disk"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"tags": [],
|
|
14
|
+
"targets": {
|
|
15
|
+
"nx-release-publish": {
|
|
16
|
+
"options": {
|
|
17
|
+
"packageRoot": "dist/{projectRoot}"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { Remote, wrap } from 'comlink';
|
|
2
|
+
import type { AnyRoutingDataProvider, RequestOptions, Waypoint } from '@any-routing/core';
|
|
3
|
+
import { MapboxExecutor, type ExecutorRequestOptions } from './mapbox.executor';
|
|
4
|
+
import type { MapboxRoutingData, Options } from './mapbox-provider.types';
|
|
5
|
+
|
|
6
|
+
const defaultOptions: Partial<Options> = {
|
|
7
|
+
baseUrl: 'https://api.mapbox.com/directions/v5/mapbox',
|
|
8
|
+
profile: 'driving',
|
|
9
|
+
worker: true,
|
|
10
|
+
alternatives: false,
|
|
11
|
+
steps: true,
|
|
12
|
+
geometries: 'geojson',
|
|
13
|
+
overview: 'full',
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export class MapboxProvider implements AnyRoutingDataProvider {
|
|
17
|
+
private worker?: Worker;
|
|
18
|
+
private executorAPI: MapboxExecutor | Remote<MapboxExecutor>;
|
|
19
|
+
private _options: Options;
|
|
20
|
+
|
|
21
|
+
public get options(): Options {
|
|
22
|
+
return this._options;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
constructor(options: Options) {
|
|
26
|
+
this._options = { ...defaultOptions, ...options };
|
|
27
|
+
if (!this.options.accessToken) {
|
|
28
|
+
throw new Error('A Mapbox access token is required');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (this.options.worker) {
|
|
32
|
+
this.worker = new Worker(new URL('./mapbox.worker', import.meta.url), { type: 'module' });
|
|
33
|
+
this.executorAPI = wrap<MapboxExecutor>(this.worker);
|
|
34
|
+
} else {
|
|
35
|
+
this.executorAPI = new MapboxExecutor();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public destroy(): void {
|
|
40
|
+
this.worker?.terminate();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public request(waypoints: Waypoint[], opts: RequestOptions): Promise<MapboxRoutingData> {
|
|
44
|
+
const url = this.buildUrl(waypoints, { ...this.options, ...opts });
|
|
45
|
+
const requestOptions = { ...this.options, ...opts, url };
|
|
46
|
+
delete requestOptions.buildUrl;
|
|
47
|
+
return this.executorAPI.request(requestOptions as ExecutorRequestOptions);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public async abortAllRequests(): Promise<void> {
|
|
51
|
+
await this.executorAPI.abortAllRequests();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public setOption<T extends keyof Options>(key: T, value: Options[T]): void {
|
|
55
|
+
this.options[key] = value;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public async hasPendingRequests(): Promise<boolean> {
|
|
59
|
+
return await this.executorAPI.hasPendingRequests();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private buildUrl(waypoints: Waypoint[], opts: Options & RequestOptions): string {
|
|
63
|
+
if (waypoints.length < 2) {
|
|
64
|
+
throw new Error('At least two waypoints are required');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const coordinates = waypoints
|
|
68
|
+
.map(({ position }) => `${position.lng},${position.lat}`)
|
|
69
|
+
.join(';');
|
|
70
|
+
const queryParams: Record<string, string> = {
|
|
71
|
+
access_token: opts.accessToken,
|
|
72
|
+
alternatives: String(opts.alternatives ?? false),
|
|
73
|
+
steps: String(opts.steps ?? true),
|
|
74
|
+
geometries: opts.geometries ?? 'geojson',
|
|
75
|
+
overview: opts.overview ?? 'full',
|
|
76
|
+
...(opts.continueStraight !== undefined
|
|
77
|
+
? { continue_straight: String(opts.continueStraight) }
|
|
78
|
+
: {}),
|
|
79
|
+
...(opts.language ? { language: opts.language } : {}),
|
|
80
|
+
...(opts.bannerInstructions !== undefined
|
|
81
|
+
? { banner_instructions: String(opts.bannerInstructions) }
|
|
82
|
+
: {}),
|
|
83
|
+
...(opts.voiceInstructions !== undefined
|
|
84
|
+
? { voice_instructions: String(opts.voiceInstructions) }
|
|
85
|
+
: {}),
|
|
86
|
+
...(opts.voiceUnits ? { voice_units: opts.voiceUnits } : {}),
|
|
87
|
+
...(opts.exclude
|
|
88
|
+
? { exclude: Array.isArray(opts.exclude) ? opts.exclude.join(',') : opts.exclude }
|
|
89
|
+
: {}),
|
|
90
|
+
...(opts.approaches
|
|
91
|
+
? {
|
|
92
|
+
approaches: Array.isArray(opts.approaches)
|
|
93
|
+
? opts.approaches.join(';')
|
|
94
|
+
: opts.approaches,
|
|
95
|
+
}
|
|
96
|
+
: {}),
|
|
97
|
+
...(opts.avoidManeuverRestrictions !== undefined
|
|
98
|
+
? { avoid_maneuver_restrictions: String(opts.avoidManeuverRestrictions) }
|
|
99
|
+
: {}),
|
|
100
|
+
...Object.fromEntries(
|
|
101
|
+
Object.entries(opts.queryParams ?? {}).map(([key, value]) => [key, String(value)]),
|
|
102
|
+
),
|
|
103
|
+
};
|
|
104
|
+
const query = new URLSearchParams(queryParams).toString();
|
|
105
|
+
const url = `${opts.baseUrl}/${opts.profile ?? 'driving'}/${coordinates}?${query}`;
|
|
106
|
+
return opts.buildUrl ? opts.buildUrl({ waypoints, options: opts }, url) : url;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AnyRoutingDataResponse,
|
|
3
|
+
RequestOptions,
|
|
4
|
+
RouteSummary,
|
|
5
|
+
Waypoint,
|
|
6
|
+
} from '@any-routing/core';
|
|
7
|
+
import type { ExecutorRequestOptions } from './mapbox.executor';
|
|
8
|
+
|
|
9
|
+
export type MapboxProfile = 'driving' | 'driving-traffic' | 'walking' | 'cycling' | (string & {});
|
|
10
|
+
|
|
11
|
+
export type MapboxGeometry = 'geojson' | 'polyline' | 'polyline6';
|
|
12
|
+
export type MapboxOverview = 'full' | 'simplified' | 'false';
|
|
13
|
+
|
|
14
|
+
export interface MapboxRouteSummary extends RouteSummary {
|
|
15
|
+
rawRoute: MapboxRawRoute;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface MapboxRoutingData extends AnyRoutingDataResponse {
|
|
19
|
+
routes: MapboxRouteSummary[];
|
|
20
|
+
requestOptions: ExecutorRequestOptions;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface MapboxRawStep {
|
|
24
|
+
distance: number;
|
|
25
|
+
duration: number;
|
|
26
|
+
name?: string;
|
|
27
|
+
geometry?: MapboxRawLineString;
|
|
28
|
+
maneuver?: {
|
|
29
|
+
location: [number, number];
|
|
30
|
+
type?: string;
|
|
31
|
+
modifier?: string;
|
|
32
|
+
instruction?: string;
|
|
33
|
+
};
|
|
34
|
+
[key: string]: unknown;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface MapboxRawLeg {
|
|
38
|
+
distance: number;
|
|
39
|
+
duration: number;
|
|
40
|
+
steps?: MapboxRawStep[];
|
|
41
|
+
summary?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface MapboxRawLineString {
|
|
45
|
+
type: 'LineString';
|
|
46
|
+
coordinates: [number, number][];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface MapboxRawRoute {
|
|
50
|
+
distance: number;
|
|
51
|
+
duration: number;
|
|
52
|
+
geometry: MapboxRawLineString;
|
|
53
|
+
legs: MapboxRawLeg[];
|
|
54
|
+
weight?: number;
|
|
55
|
+
weight_name?: string;
|
|
56
|
+
[key: string]: unknown;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface MapboxRawWaypoint {
|
|
60
|
+
name?: string;
|
|
61
|
+
location: [number, number];
|
|
62
|
+
distance?: number;
|
|
63
|
+
waypoint_index?: number;
|
|
64
|
+
trips_index?: number;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface MapboxApiResponse {
|
|
68
|
+
code: string;
|
|
69
|
+
message?: string;
|
|
70
|
+
routes?: MapboxRawRoute[];
|
|
71
|
+
waypoints?: MapboxRawWaypoint[];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export type Options = {
|
|
75
|
+
accessToken: string;
|
|
76
|
+
baseUrl?: string;
|
|
77
|
+
profile?: MapboxProfile;
|
|
78
|
+
worker?: boolean;
|
|
79
|
+
alternatives?: boolean;
|
|
80
|
+
steps?: boolean;
|
|
81
|
+
overview?: MapboxOverview;
|
|
82
|
+
geometries?: MapboxGeometry;
|
|
83
|
+
annotations?: boolean | string[];
|
|
84
|
+
continueStraight?: boolean | 'default';
|
|
85
|
+
language?: string;
|
|
86
|
+
bannerInstructions?: boolean;
|
|
87
|
+
voiceInstructions?: boolean;
|
|
88
|
+
voiceUnits?: 'imperial' | 'metric';
|
|
89
|
+
exclude?: string | string[];
|
|
90
|
+
approaches?: string | string[];
|
|
91
|
+
avoidManeuverRestrictions?: boolean;
|
|
92
|
+
queryParams?: Record<string, string | number | boolean>;
|
|
93
|
+
requestParams?: RequestInit;
|
|
94
|
+
buildUrl?: (
|
|
95
|
+
ctx: { waypoints: Waypoint[]; options: Options & RequestOptions },
|
|
96
|
+
url: string,
|
|
97
|
+
) => string;
|
|
98
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { MapboxExecutor } from './mapbox.executor';
|
|
3
|
+
|
|
4
|
+
describe('MapboxExecutor', () => {
|
|
5
|
+
it('requests GeoJSON routes and normalizes route geometry', async () => {
|
|
6
|
+
const fetchMock = vi.fn().mockResolvedValue(
|
|
7
|
+
new Response(
|
|
8
|
+
JSON.stringify({
|
|
9
|
+
code: 'Ok',
|
|
10
|
+
routes: [
|
|
11
|
+
{
|
|
12
|
+
distance: 1250,
|
|
13
|
+
duration: 90,
|
|
14
|
+
geometry: {
|
|
15
|
+
type: 'LineString',
|
|
16
|
+
coordinates: [
|
|
17
|
+
[-73.99, 40.75],
|
|
18
|
+
[-73.98, 40.76],
|
|
19
|
+
],
|
|
20
|
+
},
|
|
21
|
+
legs: [
|
|
22
|
+
{
|
|
23
|
+
distance: 1250,
|
|
24
|
+
duration: 90,
|
|
25
|
+
steps: [
|
|
26
|
+
{
|
|
27
|
+
distance: 1250,
|
|
28
|
+
duration: 90,
|
|
29
|
+
geometry: {
|
|
30
|
+
type: 'LineString',
|
|
31
|
+
coordinates: [
|
|
32
|
+
[-73.99, 40.75],
|
|
33
|
+
[-73.98, 40.76],
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
maneuver: { location: [-73.99, 40.75] },
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
}),
|
|
44
|
+
{ status: 200, headers: { 'Content-Type': 'application/json' } },
|
|
45
|
+
),
|
|
46
|
+
);
|
|
47
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
48
|
+
|
|
49
|
+
const result = await new MapboxExecutor().request({
|
|
50
|
+
url: 'https://api.mapbox.com/directions/v5/mapbox/driving/coordinates',
|
|
51
|
+
mode: 'default',
|
|
52
|
+
accessToken: 'test-token',
|
|
53
|
+
profile: 'driving',
|
|
54
|
+
geometries: 'geojson',
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
expect(fetchMock).toHaveBeenCalledWith(
|
|
58
|
+
expect.stringContaining('/directions/'),
|
|
59
|
+
expect.objectContaining({ method: 'GET' }),
|
|
60
|
+
);
|
|
61
|
+
expect(result.routes[0]?.distance).toBe(1250);
|
|
62
|
+
expect(result.routes[0]?.durationTime).toBe(90);
|
|
63
|
+
expect(result.routes[0]?.path).toEqual([
|
|
64
|
+
[40.75, -73.99],
|
|
65
|
+
[40.76, -73.98],
|
|
66
|
+
]);
|
|
67
|
+
expect(result.routesShapeGeojson.features).toHaveLength(1);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import bbox from '@turf/bbox';
|
|
2
|
+
import { featureCollection, lineString } from '@turf/helpers';
|
|
3
|
+
import type { BBox, Feature, LineString } from 'geojson';
|
|
4
|
+
import { Requester } from '@any-routing/core';
|
|
5
|
+
import type {
|
|
6
|
+
MapboxApiResponse,
|
|
7
|
+
MapboxRawLeg,
|
|
8
|
+
MapboxRawRoute,
|
|
9
|
+
MapboxRouteSummary,
|
|
10
|
+
MapboxRoutingData,
|
|
11
|
+
Options,
|
|
12
|
+
} from './mapbox-provider.types';
|
|
13
|
+
|
|
14
|
+
export type ExecutorRequestOptions = { url: string } & Options;
|
|
15
|
+
|
|
16
|
+
type ShapeProperties = { waypoint: number; routeId: number };
|
|
17
|
+
|
|
18
|
+
export class MapboxExecutor {
|
|
19
|
+
private readonly requester = new Requester();
|
|
20
|
+
|
|
21
|
+
async request(opts: ExecutorRequestOptions): Promise<MapboxRoutingData> {
|
|
22
|
+
const data = (await this.requester.request(opts.url, {
|
|
23
|
+
method: 'GET',
|
|
24
|
+
headers: {
|
|
25
|
+
Accept: 'application/json',
|
|
26
|
+
},
|
|
27
|
+
...opts.requestParams,
|
|
28
|
+
})) as MapboxApiResponse;
|
|
29
|
+
|
|
30
|
+
if (data.code !== 'Ok' || !data.routes?.length) {
|
|
31
|
+
throw new Error(data.message || `Mapbox request failed with code "${data.code}"`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const routes = data.routes.map((route, routeId) => summarizeRoute(route, routeId));
|
|
35
|
+
const features = routes.flatMap((route, fid) =>
|
|
36
|
+
route.shape.features.map((feature) => ({
|
|
37
|
+
id: fid,
|
|
38
|
+
...feature,
|
|
39
|
+
properties: { ...feature.properties, id: fid, routeId: route.id },
|
|
40
|
+
})),
|
|
41
|
+
);
|
|
42
|
+
const routesShapeGeojson = featureCollection(features);
|
|
43
|
+
return {
|
|
44
|
+
routesShapeBounds: bbox(routesShapeGeojson) as BBox,
|
|
45
|
+
rawResponse: data,
|
|
46
|
+
routes,
|
|
47
|
+
selectedRouteId: routes.length ? 0 : null,
|
|
48
|
+
routesShapeGeojson,
|
|
49
|
+
version: performance.now(),
|
|
50
|
+
latest: !this.requester.hasPendingRequests,
|
|
51
|
+
requestOptions: opts,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
hasPendingRequests(): boolean {
|
|
56
|
+
return this.requester.hasPendingRequests;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
abortAllRequests(): void {
|
|
60
|
+
this.requester.abortAllRequests();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function summarizeRoute(route: MapboxRawRoute, routeId: number): MapboxRouteSummary {
|
|
65
|
+
const now = new Date();
|
|
66
|
+
const shapeFeatures = route.legs.flatMap((leg, waypoint) =>
|
|
67
|
+
buildLegShape(leg, route, routeId, waypoint),
|
|
68
|
+
);
|
|
69
|
+
const path = route.geometry.coordinates.map(([lng, lat]) => [lat, lng] as [number, number]);
|
|
70
|
+
const waypoints = route.legs.flatMap((leg, index) => {
|
|
71
|
+
const firstStep = leg.steps?.[0];
|
|
72
|
+
const location = firstStep?.maneuver?.location;
|
|
73
|
+
if (location) {
|
|
74
|
+
const [lng, lat] = location;
|
|
75
|
+
return [{ lat, lng }, ...(index === route.legs.length - 1 ? getLastWaypoint(leg) : [])];
|
|
76
|
+
}
|
|
77
|
+
return index === 0 ? [{ lat: path[0]?.[0] ?? 0, lng: path[0]?.[1] ?? 0 }] : [];
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
id: routeId,
|
|
82
|
+
durationTime: route.duration,
|
|
83
|
+
distance: route.distance,
|
|
84
|
+
arriveTime: new Date(now.getTime() + route.duration * 1000),
|
|
85
|
+
departureTime: now,
|
|
86
|
+
path,
|
|
87
|
+
waypoints,
|
|
88
|
+
shape: featureCollection(
|
|
89
|
+
shapeFeatures.length
|
|
90
|
+
? shapeFeatures
|
|
91
|
+
: [lineString(route.geometry.coordinates, { waypoint: 0, routeId })],
|
|
92
|
+
),
|
|
93
|
+
rawRoute: route,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function buildLegShape(
|
|
98
|
+
leg: MapboxRawLeg,
|
|
99
|
+
route: MapboxRawRoute,
|
|
100
|
+
routeId: number,
|
|
101
|
+
waypoint: number,
|
|
102
|
+
): Feature<LineString, ShapeProperties>[] {
|
|
103
|
+
const coordinates = leg.steps?.flatMap((step) => step.geometry?.coordinates ?? []) ?? [];
|
|
104
|
+
const deduplicated = coordinates.filter(
|
|
105
|
+
(coordinate, index) =>
|
|
106
|
+
index === 0 ||
|
|
107
|
+
coordinate[0] !== coordinates[index - 1]?.[0] ||
|
|
108
|
+
coordinate[1] !== coordinates[index - 1]?.[1],
|
|
109
|
+
);
|
|
110
|
+
const legCoordinates = deduplicated.length > 1 ? deduplicated : route.geometry.coordinates;
|
|
111
|
+
return legCoordinates.length > 1 ? [lineString(legCoordinates, { waypoint, routeId })] : [];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function getLastWaypoint(leg: MapboxRawLeg): { lat: number; lng: number }[] {
|
|
115
|
+
const step = leg.steps?.[leg.steps.length - 1];
|
|
116
|
+
const location = step?.maneuver?.location;
|
|
117
|
+
return location ? [{ lat: location[1], lng: location[0] }] : [];
|
|
118
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"module": "es2022",
|
|
5
|
+
"forceConsistentCasingInFileNames": true,
|
|
6
|
+
"strict": true,
|
|
7
|
+
"importHelpers": true,
|
|
8
|
+
"noImplicitOverride": true,
|
|
9
|
+
"noImplicitReturns": true,
|
|
10
|
+
"noFallthroughCasesInSwitch": true,
|
|
11
|
+
"noPropertyAccessFromIndexSignature": true
|
|
12
|
+
},
|
|
13
|
+
"files": [],
|
|
14
|
+
"include": [],
|
|
15
|
+
"references": [{ "path": "./tsconfig.lib.json" }, { "path": "./tsconfig.spec.json" }]
|
|
16
|
+
}
|
package/vite.config.mts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/// <reference types="vitest" />
|
|
2
|
+
import { defineConfig } from 'vite';
|
|
3
|
+
import dts from 'vite-plugin-dts';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
|
6
|
+
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
|
|
7
|
+
|
|
8
|
+
export default defineConfig(() => ({
|
|
9
|
+
root: import.meta.dirname,
|
|
10
|
+
cacheDir: '../../node_modules/.vite/libs/mapbox-data-provider',
|
|
11
|
+
plugins: [
|
|
12
|
+
nxViteTsPaths(),
|
|
13
|
+
nxCopyAssetsPlugin(['*.md']),
|
|
14
|
+
dts({
|
|
15
|
+
entryRoot: 'src',
|
|
16
|
+
tsconfigPath: path.join(import.meta.dirname, 'tsconfig.lib.json'),
|
|
17
|
+
pathsToAliases: false,
|
|
18
|
+
}),
|
|
19
|
+
],
|
|
20
|
+
build: {
|
|
21
|
+
outDir: '../../dist/libs/mapbox-data-provider',
|
|
22
|
+
emptyOutDir: true,
|
|
23
|
+
reportCompressedSize: true,
|
|
24
|
+
commonjsOptions: { transformMixedEsModules: true },
|
|
25
|
+
lib: {
|
|
26
|
+
entry: 'src/index.ts',
|
|
27
|
+
name: 'mapbox-data-provider',
|
|
28
|
+
fileName: 'index',
|
|
29
|
+
formats: ['es' as const],
|
|
30
|
+
},
|
|
31
|
+
rolldownOptions: { external: [] },
|
|
32
|
+
},
|
|
33
|
+
test: {
|
|
34
|
+
name: 'mapbox-data-provider',
|
|
35
|
+
watch: false,
|
|
36
|
+
globals: true,
|
|
37
|
+
environment: 'node',
|
|
38
|
+
include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
|
39
|
+
reporters: ['default'],
|
|
40
|
+
},
|
|
41
|
+
}));
|