@osmix/geojson 0.0.15 → 0.0.17
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/CHANGELOG.md +43 -0
- package/LICENSE +21 -0
- package/README.md +50 -52
- package/dist/entity-to-feature.d.ts +7 -7
- package/dist/entity-to-feature.d.ts.map +1 -1
- package/dist/entity-to-feature.js +27 -11
- package/dist/entity-to-feature.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/osm-from-geojson.d.ts +2 -2
- package/dist/osm-from-geojson.d.ts.map +1 -1
- package/dist/osm-from-geojson.js +6 -6
- package/dist/osm-from-geojson.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +2 -1
- package/dist/utils.js.map +1 -1
- package/package.json +31 -31
- package/src/entity-to-feature.ts +309 -314
- package/src/index.ts +3 -3
- package/src/osm-from-geojson.ts +266 -287
- package/src/types.ts +31 -35
- package/src/utils.ts +27 -27
- package/test/entity-to-feature.test.ts +56 -59
- package/test/no-shared-array-buffer.test.ts +31 -0
- package/test/osm-from-geojson.test.ts +855 -866
- package/tsconfig.build.json +6 -6
- package/tsconfig.json +7 -7
package/src/types.ts
CHANGED
|
@@ -3,17 +3,17 @@
|
|
|
3
3
|
* @module
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type { OsmEntityType, OsmInfoParsed, OsmTags } from "@osmix/
|
|
6
|
+
import type { OsmEntityType, OsmInfoParsed, OsmTags } from "@osmix/types";
|
|
7
7
|
import type {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
} from "geojson"
|
|
8
|
+
Feature,
|
|
9
|
+
GeometryCollection,
|
|
10
|
+
LineString,
|
|
11
|
+
MultiLineString,
|
|
12
|
+
MultiPoint,
|
|
13
|
+
MultiPolygon,
|
|
14
|
+
Point,
|
|
15
|
+
Polygon,
|
|
16
|
+
} from "geojson";
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* GeoJSON Feature properties for OSM entities.
|
|
@@ -22,15 +22,15 @@ import type {
|
|
|
22
22
|
* All OSM tags are spread into the properties object.
|
|
23
23
|
*/
|
|
24
24
|
export type OsmGeoJSONProperties = {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
25
|
+
/** OSM entity ID. */
|
|
26
|
+
id: number;
|
|
27
|
+
/** Entity type: "node", "way", or "relation". */
|
|
28
|
+
type: OsmEntityType;
|
|
29
|
+
/** OSM tags (key-value pairs). */
|
|
30
|
+
tags?: OsmTags;
|
|
31
|
+
/** Entity metadata (version, timestamp, user, etc.). */
|
|
32
|
+
info?: OsmInfoParsed;
|
|
33
|
+
};
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* GeoJSON Feature with OSM-specific properties.
|
|
@@ -41,15 +41,15 @@ export type OsmGeoJSONProperties = {
|
|
|
41
41
|
* - Relations → MultiPolygon, MultiLineString, MultiPoint, or GeometryCollection
|
|
42
42
|
*/
|
|
43
43
|
export type OsmGeoJSONFeature<
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
> = Feature<T, OsmGeoJSONProperties
|
|
44
|
+
T extends
|
|
45
|
+
| Point
|
|
46
|
+
| LineString
|
|
47
|
+
| Polygon
|
|
48
|
+
| MultiPolygon
|
|
49
|
+
| MultiLineString
|
|
50
|
+
| MultiPoint
|
|
51
|
+
| GeometryCollection,
|
|
52
|
+
> = Feature<T, OsmGeoJSONProperties>;
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
55
|
* GeoJSON FeatureCollection types that can be imported into an Osm index.
|
|
@@ -58,8 +58,8 @@ export type OsmGeoJSONFeature<
|
|
|
58
58
|
* Other geometry types are not supported for import.
|
|
59
59
|
*/
|
|
60
60
|
export type ImportableGeoJSON = GeoJSON.FeatureCollection<
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
GeoJSON.Point | GeoJSON.LineString | GeoJSON.Polygon | GeoJSON.MultiPolygon
|
|
62
|
+
>;
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
65
|
* Input types accepted by `fromGeoJSON`.
|
|
@@ -70,8 +70,4 @@ export type ImportableGeoJSON = GeoJSON.FeatureCollection<
|
|
|
70
70
|
* - `string` - JSON string
|
|
71
71
|
* - `ImportableGeoJSON` - Already-parsed FeatureCollection
|
|
72
72
|
*/
|
|
73
|
-
export type ReadOsmDataTypes =
|
|
74
|
-
| ArrayBufferLike
|
|
75
|
-
| ReadableStream
|
|
76
|
-
| string
|
|
77
|
-
| ImportableGeoJSON
|
|
73
|
+
export type ReadOsmDataTypes = ArrayBufferLike | ReadableStream | string | ImportableGeoJSON;
|
package/src/utils.ts
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
* @module
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import
|
|
6
|
+
import { isSharedArrayBuffer } from "@osmix/shared/backing-buffers";
|
|
7
|
+
|
|
8
|
+
import type { ImportableGeoJSON, ReadOsmDataTypes } from "./types.ts";
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* Parse GeoJSON from various input formats.
|
|
@@ -28,31 +30,29 @@ import type { ImportableGeoJSON, ReadOsmDataTypes } from "./types.ts"
|
|
|
28
30
|
* const geojson = await readDataAsGeoJSON(response.body!)
|
|
29
31
|
* ```
|
|
30
32
|
*/
|
|
31
|
-
export async function readDataAsGeoJSON(
|
|
32
|
-
|
|
33
|
-
)
|
|
34
|
-
if (data == null) throw new Error("Data is null")
|
|
35
|
-
if (typeof data === "string") return JSON.parse(data) as ImportableGeoJSON
|
|
33
|
+
export async function readDataAsGeoJSON(data: ReadOsmDataTypes): Promise<ImportableGeoJSON> {
|
|
34
|
+
if (data == null) throw new Error("Data is null");
|
|
35
|
+
if (typeof data === "string") return JSON.parse(data) as ImportableGeoJSON;
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
37
|
+
if (data instanceof ReadableStream) {
|
|
38
|
+
const reader = data.pipeThrough(new TextDecoderStream()).getReader();
|
|
39
|
+
let result = "";
|
|
40
|
+
while (true) {
|
|
41
|
+
const { done, value } = await reader.read();
|
|
42
|
+
if (done) break;
|
|
43
|
+
if (value !== undefined) result += value;
|
|
44
|
+
}
|
|
45
|
+
return JSON.parse(result) as ImportableGeoJSON;
|
|
46
|
+
}
|
|
47
|
+
if (data instanceof ArrayBuffer || isSharedArrayBuffer(data)) {
|
|
48
|
+
const decoder = new TextDecoder();
|
|
49
|
+
const text = decoder.decode(new Uint8Array(data));
|
|
50
|
+
return JSON.parse(text) as ImportableGeoJSON;
|
|
51
|
+
}
|
|
52
|
+
if (typeof data === "object" && "type" in data && "features" in data) {
|
|
53
|
+
return data as ImportableGeoJSON;
|
|
54
|
+
}
|
|
55
|
+
throw new Error(
|
|
56
|
+
"Invalid data type. Accepts string, ReadableStream, ArrayBufferLike, or GeoJSON FeatureCollection.",
|
|
57
|
+
);
|
|
58
58
|
}
|
|
@@ -1,65 +1,62 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
relationToFeature,
|
|
6
|
-
wayToFeature,
|
|
7
|
-
} from "../src/entity-to-feature"
|
|
1
|
+
import type { OsmNode, OsmRelation, OsmWay } from "@osmix/types";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { nodeToFeature, relationToFeature, wayToFeature } from "../src/entity-to-feature";
|
|
8
5
|
|
|
9
6
|
describe("geojson helpers", () => {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
7
|
+
const node0: OsmNode = { id: 1, lat: 0, lon: 0, tags: { amenity: "cafe" } };
|
|
8
|
+
const node1: OsmNode = { id: 2, lat: 1, lon: 1 };
|
|
9
|
+
const nodes: OsmNode[] = [node0, node1];
|
|
10
|
+
const nodeMap = new Map(nodes.map((n) => [n.id, n]));
|
|
11
|
+
const refToPosition = (id: number) => {
|
|
12
|
+
const node = nodeMap.get(id);
|
|
13
|
+
if (!node) throw new Error(`Node ${id} not found`);
|
|
14
|
+
return [node.lon, node.lat] as [number, number];
|
|
15
|
+
};
|
|
19
16
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
17
|
+
it("converts node to GeoJSON Point", () => {
|
|
18
|
+
const feature = nodeToFeature(node0);
|
|
19
|
+
expect(feature.type).toBe("Feature");
|
|
20
|
+
expect(feature.geometry.type).toBe("Point");
|
|
21
|
+
expect(feature.geometry.coordinates).toEqual([node0.lon, node0.lat]);
|
|
22
|
+
expect(feature.properties).toEqual({
|
|
23
|
+
id: node0.id,
|
|
24
|
+
type: "node",
|
|
25
|
+
...node0.tags,
|
|
26
|
+
...node0.info,
|
|
27
|
+
});
|
|
28
|
+
});
|
|
32
29
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
30
|
+
it("creates polygon for closed ways", () => {
|
|
31
|
+
const way: OsmWay = {
|
|
32
|
+
id: 10,
|
|
33
|
+
refs: [1, 2, 1],
|
|
34
|
+
tags: { area: "yes" },
|
|
35
|
+
};
|
|
36
|
+
const feature = wayToFeature(way, refToPosition);
|
|
37
|
+
expect(feature.geometry.type).toBe("Polygon");
|
|
38
|
+
});
|
|
42
39
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
40
|
+
it("builds relation geometry collection", () => {
|
|
41
|
+
// Create a way that forms a closed ring
|
|
42
|
+
const way: OsmWay = {
|
|
43
|
+
id: 10,
|
|
44
|
+
refs: [1, 2, 1], // Closed way
|
|
45
|
+
tags: { area: "yes" },
|
|
46
|
+
};
|
|
47
|
+
const wayMap = new Map([[way.id, way]]);
|
|
48
|
+
const getWay = (wayId: number) => wayMap.get(wayId) ?? null;
|
|
52
49
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
})
|
|
50
|
+
const relation: OsmRelation = {
|
|
51
|
+
id: 20,
|
|
52
|
+
members: [{ type: "way", ref: 10, role: "outer" }],
|
|
53
|
+
tags: { type: "multipolygon" },
|
|
54
|
+
};
|
|
55
|
+
const feature = relationToFeature(relation, refToPosition, getWay);
|
|
56
|
+
expect(feature.geometry.type).toBe("Polygon");
|
|
57
|
+
if (feature.geometry.type === "Polygon") {
|
|
58
|
+
expect(feature.geometry.coordinates?.[0]).toBeDefined();
|
|
59
|
+
expect(feature.geometry.coordinates[0]).toHaveLength(3); // Should have 3 coordinates (closed ring)
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
describe("GeoJSON without SharedArrayBuffer", () => {
|
|
4
|
+
afterEach(() => {
|
|
5
|
+
vi.unstubAllGlobals();
|
|
6
|
+
vi.resetModules();
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it("reads binary GeoJSON into ArrayBuffer-backed indexes", async () => {
|
|
10
|
+
vi.stubGlobal("SharedArrayBuffer", undefined);
|
|
11
|
+
vi.resetModules();
|
|
12
|
+
|
|
13
|
+
const { fromGeoJSON } = await import("../src/osm-from-geojson.ts");
|
|
14
|
+
const input = new TextEncoder().encode(
|
|
15
|
+
JSON.stringify({
|
|
16
|
+
type: "FeatureCollection",
|
|
17
|
+
features: [
|
|
18
|
+
{
|
|
19
|
+
type: "Feature",
|
|
20
|
+
geometry: { type: "Point", coordinates: [115.2167, -8.65] },
|
|
21
|
+
properties: { name: "Denpasar" },
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
}),
|
|
25
|
+
).buffer;
|
|
26
|
+
|
|
27
|
+
const osm = await fromGeoJSON(input);
|
|
28
|
+
|
|
29
|
+
expect(osm.nodes.getById(-1)?.tags?.["name"]).toBe("Denpasar");
|
|
30
|
+
});
|
|
31
|
+
});
|