@osmix/core 0.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.
@@ -0,0 +1,135 @@
1
+ import { describe, expect, it } from "vitest"
2
+ import { BufferConstructor, ResizeableTypedArray } from "../src/typed-arrays"
3
+
4
+ describe("typed array helpers", () => {
5
+ it("selects the appropriate buffer constructor", () => {
6
+ if (typeof SharedArrayBuffer !== "undefined") {
7
+ expect(BufferConstructor).toBe(SharedArrayBuffer)
8
+ } else {
9
+ expect(BufferConstructor).toBe(ArrayBuffer)
10
+ }
11
+ })
12
+
13
+ describe("ResizeableTypedArray", () => {
14
+ it("push stores values and returns the index", () => {
15
+ const arr = new ResizeableTypedArray(Float64Array)
16
+
17
+ const first = arr.push(1.5)
18
+ const second = arr.push(2.5)
19
+
20
+ expect(first).toBe(0)
21
+ expect(second).toBe(1)
22
+ expect(arr.length).toBe(2)
23
+ expect(arr.at(0)).toBe(1.5)
24
+ expect(arr.at(1)).toBe(2.5)
25
+ })
26
+
27
+ it("should push many values", () => {
28
+ const arr = new ResizeableTypedArray(Float64Array)
29
+
30
+ arr.pushMany([1.5, 2.5])
31
+
32
+ expect(arr.length).toBe(2)
33
+ expect(arr.at(0)).toBe(1.5)
34
+ expect(arr.at(1)).toBe(2.5)
35
+ })
36
+
37
+ it("at supports negative indices and guards bounds", () => {
38
+ const arr = new ResizeableTypedArray(Int16Array)
39
+
40
+ arr.pushMany([10, 20, 30])
41
+
42
+ expect(arr.length).toBe(3)
43
+ expect(Array.from(arr.slice(0, arr.length))).toEqual([10, 20, 30])
44
+ expect(arr.at(-1)).toBe(30)
45
+ expect(arr.at(-3)).toBe(10)
46
+ expect(() => arr.at(-4)).toThrow(/Index out of bounds/)
47
+ expect(() => arr.at(3)).toThrow(/Index out of bounds/)
48
+ })
49
+
50
+ it("pushMany appends arrays while preserving order", () => {
51
+ const arr = new ResizeableTypedArray(Uint32Array)
52
+
53
+ arr.pushMany([1, 2, 3])
54
+ arr.pushMany(Uint32Array.from([4, 5]))
55
+
56
+ expect(arr.length).toBe(5)
57
+ expect(Array.from(arr.slice(0, arr.length))).toEqual([1, 2, 3, 4, 5])
58
+ })
59
+
60
+ it("slice returns a copy of the requested segment", () => {
61
+ const arr = new ResizeableTypedArray(Uint8Array)
62
+
63
+ arr.pushMany([1, 2, 3, 4])
64
+
65
+ const segment = arr.slice(1, 3)
66
+
67
+ expect(segment).toBeInstanceOf(Uint8Array)
68
+ expect(Array.from(segment)).toEqual([2, 3])
69
+
70
+ segment[0] = 99
71
+ expect(arr.at(1)).toBe(2)
72
+ })
73
+
74
+ it("compact trims unused capacity", () => {
75
+ const arr = new ResizeableTypedArray(Float64Array)
76
+
77
+ arr.pushMany([5, 6, 7])
78
+
79
+ const previousCapacity = arr.array.length
80
+ const compacted = arr.compact()
81
+ const expectedByteLength = arr.length * Float64Array.BYTES_PER_ELEMENT
82
+
83
+ expect(compacted).toBe(arr.array)
84
+ expect(compacted.length).toBe(arr.length)
85
+ expect(compacted.length).toBeLessThan(previousCapacity)
86
+ expect(arr.array.buffer.byteLength).toBe(expectedByteLength)
87
+ })
88
+
89
+ it("from reuses an existing buffer and grows when needed", () => {
90
+ const backing = new ArrayBuffer(16)
91
+ new Uint32Array(backing).set([1, 2, 3, 4])
92
+
93
+ const arr = ResizeableTypedArray.from(Uint32Array, backing)
94
+
95
+ arr.bufferSize = arr.buffer.byteLength
96
+ arr.maxByteLength = Math.max(arr.maxByteLength, arr.bufferSize * 2)
97
+ arr.items = arr.array.length
98
+
99
+ expect(arr.length).toBe(4)
100
+ expect(Array.from(arr.slice(0, arr.length))).toEqual([1, 2, 3, 4])
101
+
102
+ arr.push(5)
103
+
104
+ expect(arr.length).toBe(5)
105
+ expect(arr.array.length).toBe(8)
106
+ expect(Array.from(arr.slice(0, arr.length))).toEqual([1, 2, 3, 4, 5])
107
+ })
108
+
109
+ it.runIf(typeof SharedArrayBuffer !== "undefined")(
110
+ "grows shared buffers in place",
111
+ () => {
112
+ const backing = new SharedArrayBuffer(8, {
113
+ maxByteLength: 32,
114
+ })
115
+ const seed = new Uint8Array(backing)
116
+ seed.set([1, 2, 3, 4, 5, 6, 7, 8])
117
+
118
+ const arr = ResizeableTypedArray.from(Uint8Array, backing)
119
+
120
+ arr.bufferSize = arr.buffer.byteLength
121
+ arr.maxByteLength = backing.maxByteLength
122
+ arr.items = arr.array.length
123
+
124
+ const originalBuffer = arr.buffer
125
+
126
+ arr.push(9)
127
+
128
+ expect(arr.buffer).toBe(originalBuffer)
129
+ expect(arr.array.length).toBe(16)
130
+ expect(arr.buffer.byteLength).toBe(16)
131
+ expect(Array.from(arr.slice(0, 9))).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9])
132
+ },
133
+ )
134
+ })
135
+ })
@@ -0,0 +1,66 @@
1
+ import {
2
+ getFixtureFile,
3
+ getFixtureFileReadStream,
4
+ PBFs,
5
+ } from "@osmix/shared/test/fixtures"
6
+ import { assert, beforeAll, describe, it } from "vitest"
7
+ import { Osmix } from "../src/osmix"
8
+
9
+ describe("write", () => {
10
+ describe.each(Object.entries(PBFs))("%s", async (name, pbf) => {
11
+ beforeAll(() => getFixtureFile(pbf.url))
12
+
13
+ it("write osm primitive blocks", async () => {
14
+ // Parse the original PBF
15
+ const fileStream = getFixtureFileReadStream(pbf.url)
16
+ const osm = await Osmix.fromPbf(fileStream, { id: name })
17
+
18
+ // Get the first node, way, and relation
19
+ const node1 = osm.nodes.getByIndex(0)
20
+ const way1 = osm.ways.getByIndex(0)
21
+ const relation1 = osm.relations.getByIndex(0)
22
+ assert.exists(node1)
23
+ assert.exists(way1)
24
+ assert.exists(relation1)
25
+
26
+ const transformStream = new TransformStream<Uint8Array, ArrayBufferLike>()
27
+ const testOsmPromise = Osmix.fromPbf(transformStream.readable, {
28
+ id: `${name}-reparsed`,
29
+ })
30
+
31
+ // Write the PBF to an array buffer
32
+ // let data = new Uint8Array(0)
33
+ await osm.toPbfStream().pipeTo(transformStream.writable)
34
+
35
+ // Re-parse the new PBF
36
+ // assert.exists(data.buffer)
37
+ const testOsm = await testOsmPromise
38
+
39
+ // Compare the original parsed PBF and newly parsed/written/re-parsed PBF
40
+ assert.equal(osm.nodes.size, testOsm.nodes.size)
41
+ assert.equal(osm.ways.size, testOsm.ways.size)
42
+ assert.equal(osm.relations.size, testOsm.relations.size)
43
+
44
+ if (node1) {
45
+ const testNode1 = testOsm.nodes.getById(node1.id)
46
+ assert.deepEqual(testNode1, node1)
47
+ assert.equal(testNode1?.id, node1.id)
48
+ assert.equal(testNode1?.lon, node1.lon)
49
+ assert.equal(testNode1?.lat, node1.lat)
50
+ assert.deepEqual(testNode1?.tags, node1.tags)
51
+ }
52
+ if (way1) {
53
+ const testWay1 = testOsm.ways.getById(way1.id)
54
+ assert.equal(testWay1?.id, way1.id)
55
+ assert.deepEqual(testWay1?.refs, way1.refs)
56
+ assert.deepEqual(testWay1?.tags, way1.tags)
57
+ }
58
+ if (relation1) {
59
+ const testRelation1 = testOsm.relations.getById(relation1.id)
60
+ assert.equal(testRelation1?.id, relation1.id)
61
+ assert.deepEqual(testRelation1?.members, relation1.members)
62
+ assert.deepEqual(testRelation1?.tags, relation1.tags)
63
+ }
64
+ })
65
+ })
66
+ })
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "extends": "@osmix/shared/tsconfig/base.json",
4
+ "exclude": ["node_modules", "dist"],
5
+ "include": ["src", "test"],
6
+ "compilerOptions": {
7
+ "outDir": "./dist"
8
+ }
9
+ }