@osmix/pbf 0.0.2 → 0.0.4
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 +12 -0
- package/README.md +75 -82
- package/dist/blobs-to-blocks.d.ts +52 -3
- package/dist/blobs-to-blocks.d.ts.map +1 -0
- package/dist/blobs-to-blocks.js +63 -9
- package/dist/blobs-to-blocks.js.map +1 -0
- package/dist/blocks-to-pbf.d.ts +43 -6
- package/dist/blocks-to-pbf.d.ts.map +1 -0
- package/dist/blocks-to-pbf.js +44 -7
- package/dist/blocks-to-pbf.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/pbf-to-blobs.d.ts +23 -3
- package/dist/pbf-to-blobs.d.ts.map +1 -0
- package/dist/pbf-to-blobs.js +25 -3
- package/dist/pbf-to-blobs.js.map +1 -0
- package/dist/pbf-to-blocks.d.ts +50 -7
- package/dist/pbf-to-blocks.d.ts.map +1 -0
- package/dist/pbf-to-blocks.js +51 -8
- package/dist/pbf-to-blocks.js.map +1 -0
- package/dist/proto/fileformat.d.ts +1 -0
- package/dist/proto/fileformat.d.ts.map +1 -0
- package/dist/proto/fileformat.js +1 -0
- package/dist/proto/fileformat.js.map +1 -0
- package/dist/proto/osmformat.d.ts +1 -0
- package/dist/proto/osmformat.d.ts.map +1 -0
- package/dist/proto/osmformat.js +1 -0
- package/dist/proto/osmformat.js.map +1 -0
- package/dist/spec.d.ts +1 -0
- package/dist/spec.d.ts.map +1 -0
- package/dist/spec.js +1 -0
- package/dist/spec.js.map +1 -0
- package/dist/src/blobs-to-blocks.d.ts +51 -3
- package/dist/src/blobs-to-blocks.d.ts.map +1 -1
- package/dist/src/blobs-to-blocks.js +60 -7
- package/dist/src/blobs-to-blocks.js.map +1 -1
- package/dist/src/blocks-to-pbf.d.ts +41 -5
- package/dist/src/blocks-to-pbf.d.ts.map +1 -1
- package/dist/src/blocks-to-pbf.js +41 -5
- package/dist/src/blocks-to-pbf.js.map +1 -1
- package/dist/src/index.d.ts +28 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +28 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/pbf-to-blobs.d.ts +22 -3
- package/dist/src/pbf-to-blobs.d.ts.map +1 -1
- package/dist/src/pbf-to-blobs.js +24 -3
- package/dist/src/pbf-to-blobs.js.map +1 -1
- package/dist/src/pbf-to-blocks.d.ts +46 -4
- package/dist/src/pbf-to-blocks.d.ts.map +1 -1
- package/dist/src/pbf-to-blocks.js +46 -4
- package/dist/src/pbf-to-blocks.js.map +1 -1
- package/dist/src/utils.d.ts +0 -4
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +0 -32
- package/dist/src/utils.js.map +1 -1
- package/dist/test/blobs-to-blocks.test.js +22 -18
- package/dist/test/blobs-to-blocks.test.js.map +1 -1
- package/dist/test/pbf-to-blobs.test.js +24 -16
- package/dist/test/pbf-to-blobs.test.js.map +1 -1
- package/dist/test/read.bench.js +6 -4
- package/dist/test/read.bench.js.map +1 -1
- package/dist/test/read.test.js +5 -5
- package/dist/test/read.test.js.map +1 -1
- package/dist/test/streams.test.js +21 -13
- package/dist/test/streams.test.js.map +1 -1
- package/dist/test/utils.d.ts.map +1 -1
- package/dist/test/utils.js +8 -8
- package/dist/test/utils.js.map +1 -1
- package/dist/test/utils.test.js +8 -8
- package/dist/test/utils.test.js.map +1 -1
- package/dist/test/write.test.js +13 -8
- package/dist/test/write.test.js.map +1 -1
- package/dist/utils.d.ts +5 -10
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +8 -32
- package/dist/utils.js.map +1 -0
- package/package.json +12 -11
- package/src/blobs-to-blocks.ts +78 -7
- package/src/blocks-to-pbf.ts +42 -5
- package/src/index.ts +29 -0
- package/src/pbf-to-blobs.ts +24 -3
- package/src/pbf-to-blocks.ts +46 -4
- package/src/utils.ts +0 -29
- package/test/blobs-to-blocks.test.ts +25 -19
- package/test/pbf-to-blobs.test.ts +23 -17
- package/test/read.bench.ts +8 -4
- package/test/read.test.ts +5 -5
- package/test/streams.test.ts +22 -13
- package/test/utils.test.ts +8 -8
- package/test/utils.ts +8 -8
- package/test/write.test.ts +13 -8
- package/tsconfig.build.json +5 -0
- package/dist/test/utils.bun.test.d.ts +0 -2
- package/dist/test/utils.bun.test.d.ts.map +0 -1
- package/dist/test/utils.bun.test.js +0 -221
- package/dist/test/utils.bun.test.js.map +0 -1
- package/dist/test/verify-pbf-reading.bun.test.d.ts +0 -2
- package/dist/test/verify-pbf-reading.bun.test.d.ts.map +0 -1
- package/dist/test/verify-pbf-reading.bun.test.js +0 -32
- package/dist/test/verify-pbf-reading.bun.test.js.map +0 -1
- package/test/utils.bun.test.ts +0 -277
- package/test/verify-pbf-reading.bun.test.ts +0 -39
package/src/pbf-to-blobs.ts
CHANGED
|
@@ -7,9 +7,28 @@ import {
|
|
|
7
7
|
} from "./proto/fileformat"
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* Create a stateful parser that extracts compressed blobs from raw PBF bytes.
|
|
11
|
+
*
|
|
12
|
+
* OSM PBF files consist of length-prefixed blobs. This function returns a generator
|
|
13
|
+
* that accumulates incoming byte chunks and yields complete compressed blobs as they
|
|
14
|
+
* become available. The caller is responsible for decompression.
|
|
15
|
+
*
|
|
16
|
+
* The first yielded blob contains the file header; subsequent blobs contain primitive data.
|
|
17
|
+
*
|
|
18
|
+
* @returns A generator function that accepts byte chunks and yields compressed blob payloads.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* import { createOsmPbfBlobGenerator } from "@osmix/pbf"
|
|
23
|
+
*
|
|
24
|
+
* const generateBlobs = createOsmPbfBlobGenerator()
|
|
25
|
+
*
|
|
26
|
+
* for await (const chunk of stream) {
|
|
27
|
+
* for (const compressedBlob of generateBlobs(chunk)) {
|
|
28
|
+
* // Decompress and parse blob...
|
|
29
|
+
* }
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
13
32
|
*/
|
|
14
33
|
export function createOsmPbfBlobGenerator() {
|
|
15
34
|
let pbf: Pbf = new Pbf(new Uint8Array(0))
|
|
@@ -19,6 +38,8 @@ export function createOsmPbfBlobGenerator() {
|
|
|
19
38
|
|
|
20
39
|
/**
|
|
21
40
|
* Feed the parser with the next chunk of bytes and yield any complete compressed blobs.
|
|
41
|
+
* @param chunk - Raw bytes from the PBF file.
|
|
42
|
+
* @yields Compressed blob payloads (zlib-compressed protobuf data).
|
|
22
43
|
*/
|
|
23
44
|
return function* nextChunk(chunk: Uint8Array) {
|
|
24
45
|
const currentBuffer: Uint8Array = pbf.buf.slice(pbf.pos)
|
package/src/pbf-to-blocks.ts
CHANGED
|
@@ -13,11 +13,37 @@ import {
|
|
|
13
13
|
webDecompress,
|
|
14
14
|
} from "./utils"
|
|
15
15
|
|
|
16
|
+
/** Number of bytes used to encode the BlobHeader length prefix (big-endian uint32). */
|
|
16
17
|
export const HEADER_LENGTH_BYTES = 4
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
20
|
+
* Parse an OSM PBF file from various input sources.
|
|
21
|
+
*
|
|
22
|
+
* Accepts `ArrayBuffer`, `Uint8Array`, `ReadableStream<Uint8Array>`, or async generators.
|
|
23
|
+
* Returns the file header and a lazy async generator of primitive blocks for on-demand parsing.
|
|
24
|
+
*
|
|
25
|
+
* @param data - PBF bytes as buffer, stream, or async iterable.
|
|
26
|
+
* @returns Object with `header` (file metadata) and `blocks` (async generator of primitive blocks).
|
|
27
|
+
* @throws If the header block is missing or malformed.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* import { readOsmPbf } from "@osmix/pbf"
|
|
32
|
+
*
|
|
33
|
+
* // From a file stream
|
|
34
|
+
* const { header, blocks } = await readOsmPbf(Bun.file('./monaco.pbf').stream())
|
|
35
|
+
*
|
|
36
|
+
* // From a fetch response
|
|
37
|
+
* const response = await fetch('/data/monaco.pbf')
|
|
38
|
+
* const { header, blocks } = await readOsmPbf(response.body!)
|
|
39
|
+
*
|
|
40
|
+
* // Iterate blocks lazily
|
|
41
|
+
* for await (const block of blocks) {
|
|
42
|
+
* for (const group of block.primitivegroup) {
|
|
43
|
+
* console.log(group.dense?.id.length ?? 0, "dense nodes")
|
|
44
|
+
* }
|
|
45
|
+
* }
|
|
46
|
+
* ```
|
|
21
47
|
*/
|
|
22
48
|
export async function readOsmPbf(
|
|
23
49
|
data: AsyncGeneratorValue<Uint8Array<ArrayBufferLike>>,
|
|
@@ -43,8 +69,24 @@ export async function readOsmPbf(
|
|
|
43
69
|
}
|
|
44
70
|
|
|
45
71
|
/**
|
|
46
|
-
* Web `TransformStream` that
|
|
47
|
-
*
|
|
72
|
+
* Web `TransformStream` that decodes raw PBF byte chunks into OSM header and data blocks.
|
|
73
|
+
*
|
|
74
|
+
* The first blob in an OSM PBF file is always the header block; subsequent blobs
|
|
75
|
+
* contain primitive data (nodes, ways, relations). This stream handles the framing,
|
|
76
|
+
* decompression, and protobuf decoding automatically.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```ts
|
|
80
|
+
* import { OsmPbfBytesToBlocksTransformStream } from "@osmix/pbf"
|
|
81
|
+
*
|
|
82
|
+
* const response = await fetch('/data/monaco.pbf')
|
|
83
|
+
* const blocksStream = response.body!
|
|
84
|
+
* .pipeThrough(new OsmPbfBytesToBlocksTransformStream())
|
|
85
|
+
*
|
|
86
|
+
* const reader = blocksStream.getReader()
|
|
87
|
+
* const { value: header } = await reader.read() // First read yields header
|
|
88
|
+
* // Subsequent reads yield primitive blocks
|
|
89
|
+
* ```
|
|
48
90
|
*/
|
|
49
91
|
export class OsmPbfBytesToBlocksTransformStream extends TransformStream<
|
|
50
92
|
Uint8Array<ArrayBufferLike>,
|
package/src/utils.ts
CHANGED
|
@@ -38,30 +38,12 @@ export async function* toAsyncGenerator<T>(
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
/**
|
|
42
|
-
* Returns true when executing inside the Bun runtime.
|
|
43
|
-
*/
|
|
44
|
-
export function isBun(): boolean {
|
|
45
|
-
return "Bun" in globalThis
|
|
46
|
-
}
|
|
47
|
-
|
|
48
41
|
/**
|
|
49
42
|
* Web decompression stream
|
|
50
43
|
*/
|
|
51
44
|
export async function webDecompress(
|
|
52
45
|
data: Uint8Array<ArrayBuffer>,
|
|
53
46
|
): Promise<Uint8Array<ArrayBuffer>> {
|
|
54
|
-
if (isBun()) {
|
|
55
|
-
// @ts-ignore Only used in Bun runtime.
|
|
56
|
-
const { inflate } = await import("node:zlib")
|
|
57
|
-
const result = await new Promise<Uint8Array>((resolve, reject) => {
|
|
58
|
-
inflate(data, (error: unknown, result: Uint8Array) => {
|
|
59
|
-
if (error) reject(error)
|
|
60
|
-
else resolve(new Uint8Array(result))
|
|
61
|
-
})
|
|
62
|
-
})
|
|
63
|
-
return result as unknown as Uint8Array<ArrayBuffer>
|
|
64
|
-
}
|
|
65
47
|
return transformBytes(data, new DecompressionStream("deflate"))
|
|
66
48
|
}
|
|
67
49
|
|
|
@@ -71,17 +53,6 @@ export async function webDecompress(
|
|
|
71
53
|
export async function webCompress(
|
|
72
54
|
data: Uint8Array<ArrayBuffer>,
|
|
73
55
|
): Promise<Uint8Array<ArrayBuffer>> {
|
|
74
|
-
if (isBun()) {
|
|
75
|
-
// @ts-ignore Only used in Bun runtime.
|
|
76
|
-
const { deflate } = await import("node:zlib")
|
|
77
|
-
const result = await new Promise<Uint8Array>((resolve, reject) => {
|
|
78
|
-
deflate(data, (error: unknown, result: Uint8Array) => {
|
|
79
|
-
if (error) reject(error)
|
|
80
|
-
else resolve(new Uint8Array(result))
|
|
81
|
-
})
|
|
82
|
-
})
|
|
83
|
-
return result as unknown as Uint8Array<ArrayBuffer>
|
|
84
|
-
}
|
|
85
56
|
return transformBytes(data, new CompressionStream("deflate"))
|
|
86
57
|
}
|
|
87
58
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { describe, expect, it } from "bun:test"
|
|
2
2
|
import { osmPbfBlobsToBlocksGenerator } from "../src/blobs-to-blocks"
|
|
3
3
|
import { createOsmPbfBlobGenerator } from "../src/pbf-to-blobs"
|
|
4
4
|
import {
|
|
@@ -25,32 +25,38 @@ describe("osmPbfBlobsToBlocksGenerator", () => {
|
|
|
25
25
|
)
|
|
26
26
|
|
|
27
27
|
const { value: headerBlock, done } = await generator.next()
|
|
28
|
-
|
|
28
|
+
expect(done).toBe(false)
|
|
29
29
|
if (!isHeaderBlock(headerBlock)) {
|
|
30
|
-
|
|
30
|
+
throw new Error("Expected header block")
|
|
31
31
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
expect(headerBlock.bbox).toEqual(header.bbox)
|
|
33
|
+
expect(headerBlock.required_features).toEqual(header.required_features)
|
|
34
|
+
expect(headerBlock.optional_features).toEqual(header.optional_features)
|
|
35
35
|
|
|
36
36
|
const { value: block, done: blockDone } = await generator.next()
|
|
37
|
-
|
|
37
|
+
expect(blockDone).toBe(false)
|
|
38
38
|
if (!isPrimitiveBlock(block)) {
|
|
39
|
-
|
|
39
|
+
throw new Error("Expected primitive block")
|
|
40
40
|
}
|
|
41
|
-
|
|
41
|
+
expect(block.primitivegroup).toHaveLength(
|
|
42
|
+
primitiveBlock.primitivegroup.length,
|
|
43
|
+
)
|
|
42
44
|
const group = block.primitivegroup[0]
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
expect(primitiveBlock.primitivegroup[0]).toBeDefined()
|
|
46
|
+
expect(group?.dense).toBeDefined()
|
|
47
|
+
expect(group?.ways?.[0]).toBeDefined()
|
|
48
|
+
if (!group) throw new Error("group is undefined")
|
|
49
|
+
if (!primitiveBlock.primitivegroup[0])
|
|
50
|
+
throw new Error("primitiveBlock.primitivegroup[0] is undefined")
|
|
51
|
+
expect(group.ways).toHaveLength(
|
|
52
|
+
primitiveBlock.primitivegroup[0].ways.length,
|
|
53
|
+
)
|
|
54
|
+
expect(group.ways[0]?.refs).toEqual(
|
|
49
55
|
primitiveBlock.primitivegroup[0]?.ways?.[0]?.refs,
|
|
50
56
|
)
|
|
51
57
|
|
|
52
58
|
const final = await generator.next()
|
|
53
|
-
|
|
59
|
+
expect(final.done).toBe(true)
|
|
54
60
|
})
|
|
55
61
|
|
|
56
62
|
it("accepts synchronous generators", async () => {
|
|
@@ -64,10 +70,10 @@ describe("osmPbfBlobsToBlocksGenerator", () => {
|
|
|
64
70
|
)
|
|
65
71
|
|
|
66
72
|
const header = await generator.next()
|
|
67
|
-
|
|
73
|
+
expect(header.done).toBe(false)
|
|
68
74
|
const block = await generator.next()
|
|
69
|
-
|
|
75
|
+
expect(block.done).toBe(false)
|
|
70
76
|
const final = await generator.next()
|
|
71
|
-
|
|
77
|
+
expect(final.done).toBe(true)
|
|
72
78
|
})
|
|
73
79
|
})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test"
|
|
1
2
|
import Pbf from "pbf"
|
|
2
|
-
import { assert, describe, it } from "vitest"
|
|
3
3
|
import { osmPbfBlobsToBlocksGenerator } from "../src/blobs-to-blocks"
|
|
4
4
|
import { createOsmPbfBlobGenerator } from "../src/pbf-to-blobs"
|
|
5
5
|
import { writeBlob, writeBlobHeader } from "../src/proto/fileformat"
|
|
@@ -30,7 +30,7 @@ describe("createOsmPbfBlobGenerator", () => {
|
|
|
30
30
|
for (const blob of generate(fileBytes.slice(offset))) yielded.push(blob)
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
expect(yielded.length).toBe(2)
|
|
34
34
|
|
|
35
35
|
const blocks = osmPbfBlobsToBlocksGenerator(
|
|
36
36
|
(async function* () {
|
|
@@ -38,29 +38,35 @@ describe("createOsmPbfBlobGenerator", () => {
|
|
|
38
38
|
})(),
|
|
39
39
|
)
|
|
40
40
|
const { value: headerBlock, done } = await blocks.next()
|
|
41
|
-
|
|
41
|
+
expect(done).toBe(false)
|
|
42
42
|
if (!isHeaderBlock(headerBlock)) {
|
|
43
|
-
|
|
43
|
+
throw new Error("Expected first block to be a header")
|
|
44
44
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
expect(headerBlock.bbox).toEqual(header.bbox)
|
|
46
|
+
expect(headerBlock.required_features).toEqual(header.required_features)
|
|
47
|
+
expect(headerBlock.optional_features).toEqual(header.optional_features)
|
|
48
48
|
|
|
49
49
|
const { value: primitive } = await blocks.next()
|
|
50
50
|
if (!isPrimitiveBlock(primitive)) {
|
|
51
|
-
|
|
51
|
+
throw new Error("Expected primitive block after header")
|
|
52
52
|
}
|
|
53
|
-
|
|
54
|
-
primitive.primitivegroup,
|
|
53
|
+
expect(primitive.primitivegroup).toHaveLength(
|
|
55
54
|
primitiveBlock.primitivegroup.length,
|
|
56
55
|
)
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
expect(primitive.primitivegroup[0]).toBeDefined()
|
|
57
|
+
expect(primitiveBlock.primitivegroup[0]).toBeDefined()
|
|
58
|
+
if (!primitive.primitivegroup[0])
|
|
59
|
+
throw new Error("primitive.primitivegroup[0] is undefined")
|
|
60
|
+
if (!primitiveBlock.primitivegroup[0])
|
|
61
|
+
throw new Error("primitiveBlock.primitivegroup[0] is undefined")
|
|
59
62
|
const dense = primitive.primitivegroup[0].dense
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
expect(dense).toBeDefined()
|
|
64
|
+
if (!dense) throw new Error("dense is undefined")
|
|
65
|
+
if (!primitiveBlock.primitivegroup[0]?.dense)
|
|
66
|
+
throw new Error("primitiveBlock.primitivegroup[0].dense is undefined")
|
|
67
|
+
expect(dense.id).toEqual(primitiveBlock.primitivegroup[0].dense.id)
|
|
68
|
+
expect(dense.lat).toEqual(primitiveBlock.primitivegroup[0].dense.lat)
|
|
69
|
+
expect(dense.lon).toEqual(primitiveBlock.primitivegroup[0].dense.lon)
|
|
64
70
|
})
|
|
65
71
|
|
|
66
72
|
it("throws when a blob omits zlib data", () => {
|
|
@@ -80,6 +86,6 @@ describe("createOsmPbfBlobGenerator", () => {
|
|
|
80
86
|
const chunk = concatUint8(uint32BE(blobHeader.byteLength), blobHeader, blob)
|
|
81
87
|
const generate = createOsmPbfBlobGenerator()
|
|
82
88
|
const iterator = generate(chunk)
|
|
83
|
-
|
|
89
|
+
expect(() => iterator.next()).toThrow(/Blob has no zlib data/)
|
|
84
90
|
})
|
|
85
91
|
})
|
package/test/read.bench.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
import { beforeAll, describe, expect } from "bun:test"
|
|
1
2
|
import {
|
|
2
3
|
getFixtureFile,
|
|
3
4
|
getFixtureFileReadStream,
|
|
4
5
|
PBFs,
|
|
5
6
|
} from "@osmix/shared/test/fixtures"
|
|
6
|
-
|
|
7
|
+
|
|
8
|
+
// @ts-expect-error - bench is available at runtime but not in types
|
|
9
|
+
const { bench } = globalThis as { bench: typeof import("bun:test").test }
|
|
10
|
+
|
|
7
11
|
import {
|
|
8
12
|
OsmPbfBytesToBlocksTransformStream,
|
|
9
13
|
readOsmPbf,
|
|
@@ -35,8 +39,8 @@ describe.each(Object.entries(PBFs))("%s", (_name, pbf) => {
|
|
|
35
39
|
}),
|
|
36
40
|
)
|
|
37
41
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
expect(count.nodes).toBe(pbf.nodes)
|
|
43
|
+
expect(count.ways).toBe(pbf.ways)
|
|
44
|
+
expect(count.relations).toBe(pbf.relations)
|
|
41
45
|
})
|
|
42
46
|
})
|
package/test/read.test.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { beforeAll, describe, expect, it } from "bun:test"
|
|
1
2
|
import {
|
|
2
3
|
getFixtureFile,
|
|
3
4
|
getFixtureFileReadStream,
|
|
4
5
|
PBFs,
|
|
5
6
|
} from "@osmix/shared/test/fixtures"
|
|
6
|
-
import { assert, beforeAll, describe, it } from "vitest"
|
|
7
7
|
import {
|
|
8
8
|
OsmPbfBytesToBlocksTransformStream,
|
|
9
9
|
readOsmPbf,
|
|
@@ -25,15 +25,15 @@ describe("read", () => {
|
|
|
25
25
|
if ("primitivegroup" in block) {
|
|
26
26
|
for (const group of block.primitivegroup) onGroup(group)
|
|
27
27
|
} else {
|
|
28
|
-
|
|
28
|
+
expect(block.bbox).toEqual(pbf.bbox)
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
31
|
}),
|
|
32
32
|
)
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
expect(count.nodes).toBe(pbf.nodes)
|
|
35
|
+
expect(count.ways).toBe(pbf.ways)
|
|
36
|
+
expect(count.relations).toBe(pbf.relations)
|
|
37
37
|
})
|
|
38
38
|
|
|
39
39
|
it("from buffer", async () => {
|
package/test/streams.test.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { describe, expect, it } from "bun:test"
|
|
2
2
|
import { OsmBlocksToPbfBytesTransformStream } from "../src/blocks-to-pbf"
|
|
3
3
|
import { OsmPbfBytesToBlocksTransformStream } from "../src/pbf-to-blocks"
|
|
4
4
|
import { concatUint8 } from "../src/utils"
|
|
@@ -46,13 +46,13 @@ describe("transform streams", () => {
|
|
|
46
46
|
}),
|
|
47
47
|
)
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
expect(concatUint8(...chunks)).toEqual(fileBytes)
|
|
50
50
|
})
|
|
51
51
|
|
|
52
52
|
it("parses streamed bytes back into header and primitive blocks", async () => {
|
|
53
53
|
const { header, primitiveBlock, fileBytes } =
|
|
54
54
|
await createSamplePbfFileBytes()
|
|
55
|
-
|
|
55
|
+
expect(primitiveBlock.primitivegroup[0]).toBeDefined()
|
|
56
56
|
const blocks: unknown[] = []
|
|
57
57
|
|
|
58
58
|
const input = new ReadableStream({
|
|
@@ -71,22 +71,31 @@ describe("transform streams", () => {
|
|
|
71
71
|
}),
|
|
72
72
|
)
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
expect(blocks.length).toBe(2)
|
|
75
75
|
const headerBlock = blocks[0]
|
|
76
76
|
if (!isHeaderBlock(headerBlock)) {
|
|
77
|
-
|
|
77
|
+
throw new Error("Expected header block")
|
|
78
78
|
}
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
expect(headerBlock.bbox).toEqual(header.bbox)
|
|
80
|
+
expect(headerBlock.required_features).toEqual(header.required_features)
|
|
81
81
|
const block = blocks[1]
|
|
82
82
|
if (!isPrimitiveBlock(block)) {
|
|
83
|
-
|
|
83
|
+
throw new Error("Expected primitive block")
|
|
84
84
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
expect(block.primitivegroup).toHaveLength(
|
|
86
|
+
primitiveBlock.primitivegroup.length,
|
|
87
|
+
)
|
|
88
|
+
expect(block.primitivegroup).toBeDefined()
|
|
89
|
+
expect(block.primitivegroup[0]).toBeDefined()
|
|
90
|
+
if (!block.primitivegroup[0])
|
|
91
|
+
throw new Error("block.primitivegroup[0] is undefined")
|
|
92
|
+
if (!primitiveBlock.primitivegroup[0])
|
|
93
|
+
throw new Error("primitiveBlock.primitivegroup[0] is undefined")
|
|
88
94
|
const dense = block.primitivegroup[0].dense
|
|
89
|
-
|
|
90
|
-
|
|
95
|
+
expect(dense).toBeDefined()
|
|
96
|
+
if (!dense) throw new Error("dense is undefined")
|
|
97
|
+
if (!primitiveBlock.primitivegroup[0]?.dense)
|
|
98
|
+
throw new Error("primitiveBlock.primitivegroup[0].dense is undefined")
|
|
99
|
+
expect(dense.id).toEqual(primitiveBlock.primitivegroup[0].dense.id)
|
|
91
100
|
})
|
|
92
101
|
})
|
package/test/utils.test.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { describe, expect, it } from "bun:test"
|
|
2
2
|
import {
|
|
3
3
|
concatUint8,
|
|
4
4
|
toAsyncGenerator,
|
|
@@ -11,9 +11,9 @@ describe("utils", () => {
|
|
|
11
11
|
it("wraps values into an async generator", async () => {
|
|
12
12
|
const generator = toAsyncGenerator(3)
|
|
13
13
|
const first = await generator.next()
|
|
14
|
-
|
|
14
|
+
expect(first).toEqual({ value: 3, done: false })
|
|
15
15
|
const done = await generator.next()
|
|
16
|
-
|
|
16
|
+
expect(done).toEqual({ value: undefined, done: true })
|
|
17
17
|
})
|
|
18
18
|
|
|
19
19
|
it("consumes readable streams", async () => {
|
|
@@ -26,7 +26,7 @@ describe("utils", () => {
|
|
|
26
26
|
})
|
|
27
27
|
const values: number[] = []
|
|
28
28
|
for await (const value of toAsyncGenerator(stream)) values.push(value)
|
|
29
|
-
|
|
29
|
+
expect(values).toEqual([1, 2])
|
|
30
30
|
})
|
|
31
31
|
|
|
32
32
|
it("throws on nullish inputs", async () => {
|
|
@@ -39,18 +39,18 @@ describe("utils", () => {
|
|
|
39
39
|
it("concatenates Uint8Array segments", () => {
|
|
40
40
|
const a = Uint8Array.of(1, 2)
|
|
41
41
|
const b = Uint8Array.of(3)
|
|
42
|
-
|
|
42
|
+
expect(concatUint8(a, b)).toEqual(Uint8Array.of(1, 2, 3))
|
|
43
43
|
})
|
|
44
44
|
|
|
45
45
|
it("encodes big-endian 32-bit integers", () => {
|
|
46
|
-
|
|
46
|
+
expect(uint32BE(0x01020304)).toEqual(Uint8Array.of(1, 2, 3, 4))
|
|
47
47
|
})
|
|
48
48
|
|
|
49
49
|
it("compresses and decompresses data", async () => {
|
|
50
50
|
const input = new TextEncoder().encode("osmix") as Uint8Array<ArrayBuffer>
|
|
51
51
|
const compressed = await webCompress(input)
|
|
52
|
-
|
|
52
|
+
expect(compressed).not.toEqual(input)
|
|
53
53
|
const decompressed = await webDecompress(compressed)
|
|
54
|
-
|
|
54
|
+
expect(decompressed).toEqual(input)
|
|
55
55
|
})
|
|
56
56
|
})
|
package/test/utils.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { expect } from "bun:test"
|
|
1
2
|
import type { PbfFixture } from "@osmix/shared/test/fixtures"
|
|
2
|
-
import { assert } from "vitest"
|
|
3
3
|
import type {
|
|
4
4
|
OsmPbfBlock,
|
|
5
5
|
OsmPbfGroup,
|
|
@@ -13,18 +13,18 @@ export async function testOsmPbfReader(
|
|
|
13
13
|
},
|
|
14
14
|
pbf: PbfFixture,
|
|
15
15
|
) {
|
|
16
|
-
|
|
16
|
+
expect(osm.header.bbox).toEqual(pbf.bbox)
|
|
17
17
|
|
|
18
18
|
const { onGroup, count } = createOsmEntityCounter()
|
|
19
19
|
for await (const block of osm.blocks)
|
|
20
20
|
for (const group of block.primitivegroup) onGroup(group)
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
expect(count.nodes).toBe(pbf.nodes)
|
|
23
|
+
expect(count.ways).toBe(pbf.ways)
|
|
24
|
+
expect(count.relations).toBe(pbf.relations)
|
|
25
|
+
expect(count.node0).toBe(pbf.node0.id)
|
|
26
|
+
expect(count.way0).toBe(pbf.way0)
|
|
27
|
+
expect(count.relation0).toBe(pbf.relation0)
|
|
28
28
|
|
|
29
29
|
return count
|
|
30
30
|
}
|
package/test/write.test.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test"
|
|
1
2
|
import { unlink } from "node:fs/promises"
|
|
2
3
|
import {
|
|
3
4
|
getFixtureFile,
|
|
@@ -6,7 +7,6 @@ import {
|
|
|
6
7
|
getFixturePath,
|
|
7
8
|
PBFs,
|
|
8
9
|
} from "@osmix/shared/test/fixtures"
|
|
9
|
-
import { assert, describe, it } from "vitest"
|
|
10
10
|
import {
|
|
11
11
|
OsmBlocksToPbfBytesTransformStream,
|
|
12
12
|
osmBlockToPbfBlobBytes,
|
|
@@ -53,15 +53,20 @@ describe("write", () => {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
// Re-parse the new PBF and test
|
|
56
|
-
|
|
57
|
-
//
|
|
56
|
+
expect(data.buffer).toBeDefined()
|
|
57
|
+
// Note: We don't assert byte-level equality because the written PBF may have
|
|
58
|
+
// different compression, block ordering, or encoding than the original file.
|
|
59
|
+
// Semantic equivalence (verified by parsing and comparing entities) is more meaningful.
|
|
58
60
|
const osm2 = await readOsmPbf(data)
|
|
59
61
|
|
|
60
|
-
|
|
62
|
+
expect(osm.header).toEqual(osm2.header)
|
|
61
63
|
const entities = await testOsmPbfReader(osm2, pbf)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
if (node0 === null || way0 === null || relation0 === null) {
|
|
65
|
+
throw new Error("Expected node0, way0, and relation0 to be set")
|
|
66
|
+
}
|
|
67
|
+
expect(entities.node0).toBe(node0)
|
|
68
|
+
expect(entities.way0).toBe(way0)
|
|
69
|
+
expect(entities.relation0).toBe(relation0)
|
|
65
70
|
})
|
|
66
71
|
|
|
67
72
|
it("to file", async () => {
|
|
@@ -77,7 +82,7 @@ describe("write", () => {
|
|
|
77
82
|
const testFileData = await getFixtureFile(pbf.url)
|
|
78
83
|
const testOsm = await readOsmPbf(testFileData)
|
|
79
84
|
|
|
80
|
-
|
|
85
|
+
expect(testOsm.header.bbox).toEqual(pbf.bbox)
|
|
81
86
|
await testOsmPbfReader(testOsm, pbf)
|
|
82
87
|
|
|
83
88
|
await unlink(getFixturePath(testFileName))
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.bun.test.d.ts","sourceRoot":"","sources":["../../test/utils.bun.test.ts"],"names":[],"mappings":""}
|