@osmix/pbf 0.0.1 → 0.0.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.
Files changed (100) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +75 -82
  3. package/dist/src/blobs-to-blocks.d.ts +54 -0
  4. package/dist/src/blobs-to-blocks.d.ts.map +1 -0
  5. package/dist/src/blobs-to-blocks.js +75 -0
  6. package/dist/src/blobs-to-blocks.js.map +1 -0
  7. package/dist/src/blocks-to-pbf.d.ts +53 -0
  8. package/dist/src/blocks-to-pbf.d.ts.map +1 -0
  9. package/dist/{blocks-to-pbf.js → src/blocks-to-pbf.js} +44 -7
  10. package/dist/src/blocks-to-pbf.js.map +1 -0
  11. package/dist/src/index.d.ts +37 -0
  12. package/dist/src/index.d.ts.map +1 -0
  13. package/dist/src/index.js +37 -0
  14. package/dist/src/index.js.map +1 -0
  15. package/dist/src/pbf-to-blobs.d.ts +26 -0
  16. package/dist/src/pbf-to-blobs.d.ts.map +1 -0
  17. package/dist/{pbf-to-blobs.js → src/pbf-to-blobs.js} +25 -3
  18. package/dist/src/pbf-to-blobs.js.map +1 -0
  19. package/dist/src/pbf-to-blocks.d.ts +63 -0
  20. package/dist/src/pbf-to-blocks.d.ts.map +1 -0
  21. package/dist/src/pbf-to-blocks.js +96 -0
  22. package/dist/src/pbf-to-blocks.js.map +1 -0
  23. package/dist/{proto → src/proto}/fileformat.d.ts +1 -0
  24. package/dist/src/proto/fileformat.d.ts.map +1 -0
  25. package/dist/{proto → src/proto}/fileformat.js +1 -0
  26. package/dist/src/proto/fileformat.js.map +1 -0
  27. package/dist/{proto → src/proto}/osmformat.d.ts +1 -0
  28. package/dist/src/proto/osmformat.d.ts.map +1 -0
  29. package/dist/{proto → src/proto}/osmformat.js +1 -0
  30. package/dist/src/proto/osmformat.js.map +1 -0
  31. package/dist/{spec.d.ts → src/spec.d.ts} +1 -0
  32. package/dist/src/spec.d.ts.map +1 -0
  33. package/dist/{spec.js → src/spec.js} +1 -0
  34. package/dist/src/spec.js.map +1 -0
  35. package/dist/{utils.d.ts → src/utils.d.ts} +5 -10
  36. package/dist/src/utils.d.ts.map +1 -0
  37. package/dist/{utils.js → src/utils.js} +8 -32
  38. package/dist/src/utils.js.map +1 -0
  39. package/dist/test/blobs-to-blocks.test.d.ts +2 -0
  40. package/dist/test/blobs-to-blocks.test.d.ts.map +1 -0
  41. package/dist/test/blobs-to-blocks.test.js +61 -0
  42. package/dist/test/blobs-to-blocks.test.js.map +1 -0
  43. package/dist/test/helpers.d.ts +11 -0
  44. package/dist/test/helpers.d.ts.map +1 -0
  45. package/dist/test/helpers.js +58 -0
  46. package/dist/test/helpers.js.map +1 -0
  47. package/dist/test/pbf-to-blobs.test.d.ts +2 -0
  48. package/dist/test/pbf-to-blobs.test.d.ts.map +1 -0
  49. package/dist/test/pbf-to-blobs.test.js +77 -0
  50. package/dist/test/pbf-to-blobs.test.js.map +1 -0
  51. package/dist/test/read.bench.d.ts +2 -0
  52. package/dist/test/read.bench.d.ts.map +1 -0
  53. package/dist/test/read.bench.js +31 -0
  54. package/dist/test/read.bench.js.map +1 -0
  55. package/dist/test/read.test.d.ts +2 -0
  56. package/dist/test/read.test.d.ts.map +1 -0
  57. package/dist/test/read.test.js +34 -0
  58. package/dist/test/read.test.js.map +1 -0
  59. package/dist/test/streams.test.d.ts +2 -0
  60. package/dist/test/streams.test.d.ts.map +1 -0
  61. package/dist/test/streams.test.js +78 -0
  62. package/dist/test/streams.test.js.map +1 -0
  63. package/dist/test/utils.d.ts +25 -0
  64. package/dist/test/utils.d.ts.map +1 -0
  65. package/dist/test/utils.js +47 -0
  66. package/dist/test/utils.js.map +1 -0
  67. package/dist/test/utils.test.d.ts +2 -0
  68. package/dist/test/utils.test.d.ts.map +1 -0
  69. package/dist/test/utils.test.js +44 -0
  70. package/dist/test/utils.test.js.map +1 -0
  71. package/dist/test/write.test.d.ts +2 -0
  72. package/dist/test/write.test.d.ts.map +1 -0
  73. package/dist/test/write.test.js +69 -0
  74. package/dist/test/write.test.js.map +1 -0
  75. package/package.json +7 -7
  76. package/src/blobs-to-blocks.ts +78 -7
  77. package/src/blocks-to-pbf.ts +42 -5
  78. package/src/index.ts +29 -0
  79. package/src/pbf-to-blobs.ts +24 -3
  80. package/src/pbf-to-blocks.ts +52 -12
  81. package/src/utils.ts +0 -7
  82. package/test/blobs-to-blocks.test.ts +25 -19
  83. package/test/pbf-to-blobs.test.ts +23 -17
  84. package/test/read.bench.ts +8 -4
  85. package/test/read.test.ts +5 -5
  86. package/test/streams.test.ts +22 -13
  87. package/test/utils.test.ts +8 -8
  88. package/test/utils.ts +8 -8
  89. package/test/write.test.ts +14 -9
  90. package/dist/blobs-to-blocks.d.ts +0 -5
  91. package/dist/blobs-to-blocks.js +0 -21
  92. package/dist/blocks-to-pbf.d.ts +0 -16
  93. package/dist/index.d.ts +0 -8
  94. package/dist/index.js +0 -8
  95. package/dist/pbf-to-blobs.d.ts +0 -6
  96. package/dist/pbf-to-blocks.d.ts +0 -20
  97. package/dist/pbf-to-blocks.js +0 -53
  98. package/test/utils.bun.test.ts +0 -327
  99. package/test/verify-pbf-reading.bun.test.ts +0 -39
  100. package/vitest.config.ts +0 -7
@@ -0,0 +1,77 @@
1
+ import { describe, expect, it } from "bun:test";
2
+ import Pbf from "pbf";
3
+ import { osmPbfBlobsToBlocksGenerator } from "../src/blobs-to-blocks";
4
+ import { createOsmPbfBlobGenerator } from "../src/pbf-to-blobs";
5
+ import { writeBlob, writeBlobHeader } from "../src/proto/fileformat";
6
+ import { writeHeaderBlock } from "../src/proto/osmformat";
7
+ import { concatUint8, uint32BE } from "../src/utils";
8
+ import { createSampleHeader, createSamplePbfFileBytes, isHeaderBlock, isPrimitiveBlock, } from "./helpers";
9
+ describe("createOsmPbfBlobGenerator", () => {
10
+ it("yields compressed blobs across fragmented chunks", async () => {
11
+ const { header, primitiveBlock, fileBytes } = await createSamplePbfFileBytes();
12
+ const generate = createOsmPbfBlobGenerator();
13
+ const yielded = [];
14
+ let offset = 0;
15
+ const chunkSizes = [1, 9];
16
+ for (const size of chunkSizes) {
17
+ const chunk = fileBytes.slice(offset, offset + size);
18
+ offset += size;
19
+ for (const blob of generate(chunk))
20
+ yielded.push(blob);
21
+ }
22
+ if (offset < fileBytes.length) {
23
+ for (const blob of generate(fileBytes.slice(offset)))
24
+ yielded.push(blob);
25
+ }
26
+ expect(yielded.length).toBe(2);
27
+ const blocks = osmPbfBlobsToBlocksGenerator((async function* () {
28
+ for (const blob of yielded)
29
+ yield blob;
30
+ })());
31
+ const { value: headerBlock, done } = await blocks.next();
32
+ expect(done).toBe(false);
33
+ if (!isHeaderBlock(headerBlock)) {
34
+ throw new Error("Expected first block to be a header");
35
+ }
36
+ expect(headerBlock.bbox).toEqual(header.bbox);
37
+ expect(headerBlock.required_features).toEqual(header.required_features);
38
+ expect(headerBlock.optional_features).toEqual(header.optional_features);
39
+ const { value: primitive } = await blocks.next();
40
+ if (!isPrimitiveBlock(primitive)) {
41
+ throw new Error("Expected primitive block after header");
42
+ }
43
+ expect(primitive.primitivegroup).toHaveLength(primitiveBlock.primitivegroup.length);
44
+ expect(primitive.primitivegroup[0]).toBeDefined();
45
+ expect(primitiveBlock.primitivegroup[0]).toBeDefined();
46
+ if (!primitive.primitivegroup[0])
47
+ throw new Error("primitive.primitivegroup[0] is undefined");
48
+ if (!primitiveBlock.primitivegroup[0])
49
+ throw new Error("primitiveBlock.primitivegroup[0] is undefined");
50
+ const dense = primitive.primitivegroup[0].dense;
51
+ expect(dense).toBeDefined();
52
+ if (!dense)
53
+ throw new Error("dense is undefined");
54
+ if (!primitiveBlock.primitivegroup[0]?.dense)
55
+ throw new Error("primitiveBlock.primitivegroup[0].dense is undefined");
56
+ expect(dense.id).toEqual(primitiveBlock.primitivegroup[0].dense.id);
57
+ expect(dense.lat).toEqual(primitiveBlock.primitivegroup[0].dense.lat);
58
+ expect(dense.lon).toEqual(primitiveBlock.primitivegroup[0].dense.lon);
59
+ });
60
+ it("throws when a blob omits zlib data", () => {
61
+ const headerBlock = createSampleHeader();
62
+ const headerPbf = new Pbf();
63
+ writeHeaderBlock(headerBlock, headerPbf);
64
+ const headerContent = headerPbf.finish();
65
+ const blobPbf = new Pbf();
66
+ writeBlob({ raw_size: headerContent.length, raw: headerContent }, blobPbf);
67
+ const blob = blobPbf.finish();
68
+ const blobHeaderPbf = new Pbf();
69
+ writeBlobHeader({ type: "OSMHeader", datasize: blob.length }, blobHeaderPbf);
70
+ const blobHeader = blobHeaderPbf.finish();
71
+ const chunk = concatUint8(uint32BE(blobHeader.byteLength), blobHeader, blob);
72
+ const generate = createOsmPbfBlobGenerator();
73
+ const iterator = generate(chunk);
74
+ expect(() => iterator.next()).toThrow(/Blob has no zlib data/);
75
+ });
76
+ });
77
+ //# sourceMappingURL=pbf-to-blobs.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pbf-to-blobs.test.js","sourceRoot":"","sources":["../../test/pbf-to-blobs.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=read.bench.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.bench.d.ts","sourceRoot":"","sources":["../../test/read.bench.ts"],"names":[],"mappings":""}
@@ -0,0 +1,31 @@
1
+ import { beforeAll, describe, expect } from "bun:test";
2
+ import { getFixtureFile, getFixtureFileReadStream, PBFs, } from "@osmix/shared/test/fixtures";
3
+ // @ts-expect-error - bench is available at runtime but not in types
4
+ const { bench } = globalThis;
5
+ import { OsmPbfBytesToBlocksTransformStream, readOsmPbf, } from "../src/pbf-to-blocks";
6
+ import { createOsmEntityCounter, testOsmPbfReader } from "./utils";
7
+ describe.each(Object.entries(PBFs))("%s", (_name, pbf) => {
8
+ beforeAll(() => getFixtureFile(pbf.url));
9
+ bench("parse with generators", async () => {
10
+ const file = await getFixtureFile(pbf.url);
11
+ const osm = await readOsmPbf(file);
12
+ await testOsmPbfReader(osm, pbf);
13
+ });
14
+ bench("parse streaming", async () => {
15
+ const { onGroup, count } = createOsmEntityCounter();
16
+ await getFixtureFileReadStream(pbf.url)
17
+ .pipeThrough(new OsmPbfBytesToBlocksTransformStream())
18
+ .pipeTo(new WritableStream({
19
+ write: (block) => {
20
+ if ("primitivegroup" in block) {
21
+ for (const group of block.primitivegroup)
22
+ onGroup(group);
23
+ }
24
+ },
25
+ }));
26
+ expect(count.nodes).toBe(pbf.nodes);
27
+ expect(count.ways).toBe(pbf.ways);
28
+ expect(count.relations).toBe(pbf.relations);
29
+ });
30
+ });
31
+ //# sourceMappingURL=read.bench.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.bench.js","sourceRoot":"","sources":["../../test/read.bench.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACtD,OAAO,EACN,cAAc,EACd,wBAAwB,EACxB,IAAI,GACJ,MAAM,6BAA6B,CAAA;AAEpC,oEAAoE;AACpE,MAAM,EAAE,KAAK,EAAE,GAAG,UAAuD,CAAA;AAEzE,OAAO,EACN,kCAAkC,EAClC,UAAU,GACV,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAElE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IACxD,SAAS,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;IAExC,KAAK,CAAC,uBAAuB,EAAE,KAAK,IAAI,EAAE;QACzC,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAC1C,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAA;QAElC,MAAM,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;IACjC,CAAC,CAAC,CAAA;IAEF,KAAK,CAAC,iBAAiB,EAAE,KAAK,IAAI,EAAE;QACnC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,sBAAsB,EAAE,CAAA;QAEnD,MAAM,wBAAwB,CAAC,GAAG,CAAC,GAAG,CAAC;aACrC,WAAW,CAAC,IAAI,kCAAkC,EAAE,CAAC;aACrD,MAAM,CACN,IAAI,cAAc,CAAC;YAClB,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;gBAChB,IAAI,gBAAgB,IAAI,KAAK,EAAE,CAAC;oBAC/B,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,cAAc;wBAAE,OAAO,CAAC,KAAK,CAAC,CAAA;gBACzD,CAAC;YACF,CAAC;SACD,CAAC,CACF,CAAA;QAEF,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QACnC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACjC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IAC5C,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=read.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.test.d.ts","sourceRoot":"","sources":["../../test/read.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,34 @@
1
+ import { beforeAll, describe, expect, it } from "bun:test";
2
+ import { getFixtureFile, getFixtureFileReadStream, PBFs, } from "@osmix/shared/test/fixtures";
3
+ import { OsmPbfBytesToBlocksTransformStream, readOsmPbf, } from "../src/pbf-to-blocks";
4
+ import { createOsmEntityCounter, testOsmPbfReader } from "./utils";
5
+ describe("read", () => {
6
+ describe.each(Object.entries(PBFs))("%s", async (_name, pbf) => {
7
+ beforeAll(() => getFixtureFile(pbf.url));
8
+ it("from stream", async () => {
9
+ const { onGroup, count } = createOsmEntityCounter();
10
+ await getFixtureFileReadStream(pbf.url)
11
+ .pipeThrough(new OsmPbfBytesToBlocksTransformStream())
12
+ .pipeTo(new WritableStream({
13
+ write: (block) => {
14
+ if ("primitivegroup" in block) {
15
+ for (const group of block.primitivegroup)
16
+ onGroup(group);
17
+ }
18
+ else {
19
+ expect(block.bbox).toEqual(pbf.bbox);
20
+ }
21
+ },
22
+ }));
23
+ expect(count.nodes).toBe(pbf.nodes);
24
+ expect(count.ways).toBe(pbf.ways);
25
+ expect(count.relations).toBe(pbf.relations);
26
+ });
27
+ it("from buffer", async () => {
28
+ const fileData = await getFixtureFile(pbf.url);
29
+ const osm = await readOsmPbf(fileData);
30
+ await testOsmPbfReader(osm, pbf);
31
+ });
32
+ });
33
+ });
34
+ //# sourceMappingURL=read.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.test.js","sourceRoot":"","sources":["../../test/read.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,UAAU,CAAA;AAC1D,OAAO,EACN,cAAc,EACd,wBAAwB,EACxB,IAAI,GACJ,MAAM,6BAA6B,CAAA;AACpC,OAAO,EACN,kCAAkC,EAClC,UAAU,GACV,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAElE,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE;IACrB,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QAC9D,SAAS,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;QAExC,EAAE,CAAC,aAAa,EAAE,KAAK,IAAI,EAAE;YAC5B,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,sBAAsB,EAAE,CAAA;YAEnD,MAAM,wBAAwB,CAAC,GAAG,CAAC,GAAG,CAAC;iBACrC,WAAW,CAAC,IAAI,kCAAkC,EAAE,CAAC;iBACrD,MAAM,CACN,IAAI,cAAc,CAAC;gBAClB,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;oBAChB,IAAI,gBAAgB,IAAI,KAAK,EAAE,CAAC;wBAC/B,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,cAAc;4BAAE,OAAO,CAAC,KAAK,CAAC,CAAA;oBACzD,CAAC;yBAAM,CAAC;wBACP,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;oBACrC,CAAC;gBACF,CAAC;aACD,CAAC,CACF,CAAA;YAEF,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YACnC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;YACjC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC5C,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,aAAa,EAAE,KAAK,IAAI,EAAE;YAC5B,MAAM,QAAQ,GAAG,MAAM,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YAC9C,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAA;YACtC,MAAM,gBAAgB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;QACjC,CAAC,CAAC,CAAA;IACH,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=streams.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streams.test.d.ts","sourceRoot":"","sources":["../../test/streams.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,78 @@
1
+ import { describe, expect, it } from "bun:test";
2
+ import { OsmBlocksToPbfBytesTransformStream } from "../src/blocks-to-pbf";
3
+ import { OsmPbfBytesToBlocksTransformStream } from "../src/pbf-to-blocks";
4
+ import { concatUint8 } from "../src/utils";
5
+ import { createSamplePbfFileBytes, createSamplePrimitiveBlock, isHeaderBlock, isPrimitiveBlock, } from "./helpers";
6
+ describe("transform streams", () => {
7
+ it("requires the header to be written before data blocks", async () => {
8
+ const input = new ReadableStream({
9
+ start(controller) {
10
+ controller.enqueue(createSamplePrimitiveBlock());
11
+ controller.close();
12
+ },
13
+ });
14
+ await expect(input
15
+ .pipeThrough(new OsmBlocksToPbfBytesTransformStream())
16
+ .pipeTo(new WritableStream())).rejects.toThrow("Header first in ReadableStream of blocks.");
17
+ });
18
+ it("serialises blocks into the expected PBF byte sequence", async () => {
19
+ const { header, primitiveBlock, fileBytes } = await createSamplePbfFileBytes();
20
+ const chunks = [];
21
+ const input = new ReadableStream({
22
+ start(controller) {
23
+ controller.enqueue(header);
24
+ controller.enqueue(primitiveBlock);
25
+ controller.close();
26
+ },
27
+ });
28
+ await input.pipeThrough(new OsmBlocksToPbfBytesTransformStream()).pipeTo(new WritableStream({
29
+ write(chunk) {
30
+ chunks.push(chunk);
31
+ },
32
+ }));
33
+ expect(concatUint8(...chunks)).toEqual(fileBytes);
34
+ });
35
+ it("parses streamed bytes back into header and primitive blocks", async () => {
36
+ const { header, primitiveBlock, fileBytes } = await createSamplePbfFileBytes();
37
+ expect(primitiveBlock.primitivegroup[0]).toBeDefined();
38
+ const blocks = [];
39
+ const input = new ReadableStream({
40
+ start(controller) {
41
+ controller.enqueue(fileBytes.slice(0, 7).buffer);
42
+ controller.enqueue(fileBytes.slice(7).buffer);
43
+ controller.close();
44
+ },
45
+ });
46
+ await input.pipeThrough(new OsmPbfBytesToBlocksTransformStream()).pipeTo(new WritableStream({
47
+ write(chunk) {
48
+ blocks.push(chunk);
49
+ },
50
+ }));
51
+ expect(blocks.length).toBe(2);
52
+ const headerBlock = blocks[0];
53
+ if (!isHeaderBlock(headerBlock)) {
54
+ throw new Error("Expected header block");
55
+ }
56
+ expect(headerBlock.bbox).toEqual(header.bbox);
57
+ expect(headerBlock.required_features).toEqual(header.required_features);
58
+ const block = blocks[1];
59
+ if (!isPrimitiveBlock(block)) {
60
+ throw new Error("Expected primitive block");
61
+ }
62
+ expect(block.primitivegroup).toHaveLength(primitiveBlock.primitivegroup.length);
63
+ expect(block.primitivegroup).toBeDefined();
64
+ expect(block.primitivegroup[0]).toBeDefined();
65
+ if (!block.primitivegroup[0])
66
+ throw new Error("block.primitivegroup[0] is undefined");
67
+ if (!primitiveBlock.primitivegroup[0])
68
+ throw new Error("primitiveBlock.primitivegroup[0] is undefined");
69
+ const dense = block.primitivegroup[0].dense;
70
+ expect(dense).toBeDefined();
71
+ if (!dense)
72
+ throw new Error("dense is undefined");
73
+ if (!primitiveBlock.primitivegroup[0]?.dense)
74
+ throw new Error("primitiveBlock.primitivegroup[0].dense is undefined");
75
+ expect(dense.id).toEqual(primitiveBlock.primitivegroup[0].dense.id);
76
+ });
77
+ });
78
+ //# sourceMappingURL=streams.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streams.test.js","sourceRoot":"","sources":["../../test/streams.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { PbfFixture } from "@osmix/shared/test/fixtures";
2
+ import type { OsmPbfBlock, OsmPbfGroup, OsmPbfHeaderBlock } from "../src/proto/osmformat";
3
+ export declare function testOsmPbfReader(osm: {
4
+ header: OsmPbfHeaderBlock;
5
+ blocks: AsyncGenerator<OsmPbfBlock>;
6
+ }, pbf: PbfFixture): Promise<{
7
+ nodes: number;
8
+ ways: number;
9
+ relations: number;
10
+ node0: number;
11
+ way0: number;
12
+ relation0: number;
13
+ }>;
14
+ export declare function createOsmEntityCounter(): {
15
+ onGroup: (group: OsmPbfGroup) => void;
16
+ count: {
17
+ nodes: number;
18
+ ways: number;
19
+ relations: number;
20
+ node0: number;
21
+ way0: number;
22
+ relation0: number;
23
+ };
24
+ };
25
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../test/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AAC7D,OAAO,KAAK,EACX,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,MAAM,wBAAwB,CAAA;AAE/B,wBAAsB,gBAAgB,CACrC,GAAG,EAAE;IACJ,MAAM,EAAE,iBAAiB,CAAA;IACzB,MAAM,EAAE,cAAc,CAAC,WAAW,CAAC,CAAA;CACnC,EACD,GAAG,EAAE,UAAU;;;;;;;GAgBf;AAED,wBAAgB,sBAAsB;qBAUb,WAAW;;;;;;;;;EAuBnC"}
@@ -0,0 +1,47 @@
1
+ import { expect } from "bun:test";
2
+ export async function testOsmPbfReader(osm, pbf) {
3
+ expect(osm.header.bbox).toEqual(pbf.bbox);
4
+ const { onGroup, count } = createOsmEntityCounter();
5
+ for await (const block of osm.blocks)
6
+ for (const group of block.primitivegroup)
7
+ onGroup(group);
8
+ expect(count.nodes).toBe(pbf.nodes);
9
+ expect(count.ways).toBe(pbf.ways);
10
+ expect(count.relations).toBe(pbf.relations);
11
+ expect(count.node0).toBe(pbf.node0.id);
12
+ expect(count.way0).toBe(pbf.way0);
13
+ expect(count.relation0).toBe(pbf.relation0);
14
+ return count;
15
+ }
16
+ export function createOsmEntityCounter() {
17
+ const count = {
18
+ nodes: 0,
19
+ ways: 0,
20
+ relations: 0,
21
+ node0: -1,
22
+ way0: -1,
23
+ relation0: -1,
24
+ };
25
+ const onGroup = (group) => {
26
+ if (count.node0 === -1 && group.dense?.id?.[0] != null) {
27
+ count.node0 = group.dense.id[0];
28
+ }
29
+ if (count.way0 === -1 && group.ways?.[0]?.id != null) {
30
+ count.way0 = group.ways[0].id;
31
+ }
32
+ if (count.relation0 === -1 && group.relations?.[0]?.id != null) {
33
+ count.relation0 = group.relations[0].id;
34
+ }
35
+ count.nodes += group.nodes?.length ?? 0;
36
+ if (group.dense) {
37
+ count.nodes += group.dense.id.length;
38
+ }
39
+ count.ways += group.ways?.length ?? 0;
40
+ count.relations += group.relations?.length ?? 0;
41
+ };
42
+ return {
43
+ onGroup,
44
+ count,
45
+ };
46
+ }
47
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../test/utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=utils.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.test.d.ts","sourceRoot":"","sources":["../../test/utils.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,44 @@
1
+ import { describe, expect, it } from "bun:test";
2
+ import { concatUint8, toAsyncGenerator, uint32BE, webCompress, webDecompress, } from "../src/utils";
3
+ describe("utils", () => {
4
+ it("wraps values into an async generator", async () => {
5
+ const generator = toAsyncGenerator(3);
6
+ const first = await generator.next();
7
+ expect(first).toEqual({ value: 3, done: false });
8
+ const done = await generator.next();
9
+ expect(done).toEqual({ value: undefined, done: true });
10
+ });
11
+ it("consumes readable streams", async () => {
12
+ const stream = new ReadableStream({
13
+ start(controller) {
14
+ controller.enqueue(1);
15
+ controller.enqueue(2);
16
+ controller.close();
17
+ },
18
+ });
19
+ const values = [];
20
+ for await (const value of toAsyncGenerator(stream))
21
+ values.push(value);
22
+ expect(values).toEqual([1, 2]);
23
+ });
24
+ it("throws on nullish inputs", async () => {
25
+ const invalidInput = null;
26
+ await expect(toAsyncGenerator(invalidInput).next()).rejects.toThrow("Value is null");
27
+ });
28
+ it("concatenates Uint8Array segments", () => {
29
+ const a = Uint8Array.of(1, 2);
30
+ const b = Uint8Array.of(3);
31
+ expect(concatUint8(a, b)).toEqual(Uint8Array.of(1, 2, 3));
32
+ });
33
+ it("encodes big-endian 32-bit integers", () => {
34
+ expect(uint32BE(0x01020304)).toEqual(Uint8Array.of(1, 2, 3, 4));
35
+ });
36
+ it("compresses and decompresses data", async () => {
37
+ const input = new TextEncoder().encode("osmix");
38
+ const compressed = await webCompress(input);
39
+ expect(compressed).not.toEqual(input);
40
+ const decompressed = await webDecompress(compressed);
41
+ expect(decompressed).toEqual(input);
42
+ });
43
+ });
44
+ //# sourceMappingURL=utils.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.test.js","sourceRoot":"","sources":["../../test/utils.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,UAAU,CAAA;AAC/C,OAAO,EACN,WAAW,EACX,gBAAgB,EAChB,QAAQ,EACR,WAAW,EACX,aAAa,GACb,MAAM,cAAc,CAAA;AAErB,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE;IACtB,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACrD,MAAM,SAAS,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAA;QACrC,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,CAAA;QACpC,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;QAChD,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,CAAA;QACnC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IACvD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;QAC1C,MAAM,MAAM,GAAG,IAAI,cAAc,CAAS;YACzC,KAAK,CAAC,UAAU;gBACf,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;gBACrB,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;gBACrB,UAAU,CAAC,KAAK,EAAE,CAAA;YACnB,CAAC;SACD,CAAC,CAAA;QACF,MAAM,MAAM,GAAa,EAAE,CAAA;QAC3B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,gBAAgB,CAAC,MAAM,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACtE,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAC/B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0BAA0B,EAAE,KAAK,IAAI,EAAE;QACzC,MAAM,YAAY,GAAG,IAAwB,CAAA;QAC7C,MAAM,MAAM,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAClE,eAAe,CACf,CAAA;IACF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC3C,MAAM,CAAC,GAAG,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;QAC7B,MAAM,CAAC,GAAG,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QAC1B,MAAM,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAC1D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC7C,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAChE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QACjD,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAA4B,CAAA;QAC1E,MAAM,UAAU,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,CAAA;QAC3C,MAAM,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QACrC,MAAM,YAAY,GAAG,MAAM,aAAa,CAAC,UAAU,CAAC,CAAA;QACpD,MAAM,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IACpC,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=write.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write.test.d.ts","sourceRoot":"","sources":["../../test/write.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,69 @@
1
+ import { describe, expect, it } from "bun:test";
2
+ import { unlink } from "node:fs/promises";
3
+ import { getFixtureFile, getFixtureFileReadStream, getFixtureFileWriteStream, getFixturePath, PBFs, } from "@osmix/shared/test/fixtures";
4
+ import { OsmBlocksToPbfBytesTransformStream, osmBlockToPbfBlobBytes, } from "../src/blocks-to-pbf";
5
+ import { OsmPbfBytesToBlocksTransformStream, readOsmPbf, } from "../src/pbf-to-blocks";
6
+ import { testOsmPbfReader } from "./utils";
7
+ describe("write", () => {
8
+ describe.each(Object.entries(PBFs))("%s", (name, pbf) => {
9
+ it("to buffer", async () => {
10
+ const fileData = await getFixtureFile(pbf.url);
11
+ const osm = await readOsmPbf(fileData);
12
+ let node0 = null;
13
+ let way0 = null;
14
+ let relation0 = null;
15
+ // Write the PBF to an array buffer
16
+ let data = new Uint8Array(0);
17
+ const write = (chunk) => {
18
+ const newData = new Uint8Array(data.length + chunk.length);
19
+ newData.set(data);
20
+ newData.set(chunk, data.length);
21
+ data = newData;
22
+ };
23
+ write(await osmBlockToPbfBlobBytes(osm.header));
24
+ for await (const block of osm.blocks) {
25
+ for (const group of block.primitivegroup) {
26
+ if (node0 == null && group.dense?.id?.[0] != null) {
27
+ node0 = group.dense.id[0];
28
+ }
29
+ if (way0 == null && group.ways?.[0]?.id != null) {
30
+ way0 = group.ways[0].id;
31
+ }
32
+ if (relation0 == null && group.relations?.[0]?.id != null) {
33
+ relation0 = group.relations[0].id;
34
+ }
35
+ }
36
+ write(await osmBlockToPbfBlobBytes(block));
37
+ }
38
+ // Re-parse the new PBF and test
39
+ expect(data.buffer).toBeDefined();
40
+ // Note: We don't assert byte-level equality because the written PBF may have
41
+ // different compression, block ordering, or encoding than the original file.
42
+ // Semantic equivalence (verified by parsing and comparing entities) is more meaningful.
43
+ const osm2 = await readOsmPbf(data);
44
+ expect(osm.header).toEqual(osm2.header);
45
+ const entities = await testOsmPbfReader(osm2, pbf);
46
+ if (node0 === null || way0 === null || relation0 === null) {
47
+ throw new Error("Expected node0, way0, and relation0 to be set");
48
+ }
49
+ expect(entities.node0).toBe(node0);
50
+ expect(entities.way0).toBe(way0);
51
+ expect(entities.relation0).toBe(relation0);
52
+ });
53
+ it("to file", async () => {
54
+ const testFileName = `${name}-write-test.pbf`;
55
+ const fileStream = getFixtureFileReadStream(pbf.url);
56
+ const fileWriteStream = getFixtureFileWriteStream(testFileName);
57
+ await fileStream
58
+ .pipeThrough(new OsmPbfBytesToBlocksTransformStream())
59
+ .pipeThrough(new OsmBlocksToPbfBytesTransformStream())
60
+ .pipeTo(fileWriteStream);
61
+ const testFileData = await getFixtureFile(pbf.url);
62
+ const testOsm = await readOsmPbf(testFileData);
63
+ expect(testOsm.header.bbox).toEqual(pbf.bbox);
64
+ await testOsmPbfReader(testOsm, pbf);
65
+ await unlink(getFixturePath(testFileName));
66
+ });
67
+ });
68
+ });
69
+ //# sourceMappingURL=write.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write.test.js","sourceRoot":"","sources":["../../test/write.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json.schemastore.org/package",
3
3
  "name": "@osmix/pbf",
4
4
  "description": "A low level, modern, runtime agnostic OSM PBF parser and writer written in TypeScript.",
5
- "version": "0.0.1",
5
+ "version": "0.0.3",
6
6
  "type": "module",
7
7
  "main": "./src/index.ts",
8
8
  "publishConfig": {
@@ -32,16 +32,16 @@
32
32
  },
33
33
  "sideEffects": false,
34
34
  "scripts": {
35
- "bench": "vitest bench",
35
+ "bench": "bun test --bench",
36
36
  "build": "tsc",
37
- "test": "vitest",
38
- "typecheck": "tsc --noEmit"
37
+ "prepublishOnly": "tsc",
38
+ "test": "bun test",
39
+ "typecheck": "tsgo --noEmit"
39
40
  },
40
41
  "devDependencies": {
41
42
  "@osmix/shared": "workspace:*",
42
- "@types/node": "catalog:",
43
- "typescript": "catalog:",
44
- "vitest": "catalog:"
43
+ "@types/bun": "catalog:",
44
+ "typescript": "catalog:"
45
45
  },
46
46
  "dependencies": {
47
47
  "pbf": "catalog:"
@@ -1,10 +1,47 @@
1
+ /**
2
+ * Blob-to-block conversion utilities.
3
+ *
4
+ * Handles decompression and protobuf decoding of raw OSM PBF blobs into
5
+ * typed header and primitive block structures.
6
+ *
7
+ * @module
8
+ */
9
+
1
10
  import Pbf from "pbf"
2
- import { readHeaderBlock, readPrimitiveBlock } from "./proto/osmformat"
11
+ import {
12
+ type OsmPbfBlock,
13
+ type OsmPbfHeaderBlock,
14
+ readHeaderBlock,
15
+ readPrimitiveBlock,
16
+ } from "./proto/osmformat"
3
17
  import { webDecompress } from "./utils"
4
18
 
5
19
  /**
6
- * Decompresses raw OSM PBF blobs and yields typed header and primitive blocks.
7
- * Expects the first blob to contain the file header and streams the rest as data blocks.
20
+ * Decompress and decode a stream of raw PBF blobs into typed blocks.
21
+ *
22
+ * This async generator handles the transition from compressed bytes to parsed
23
+ * protobuf structures. The first blob is always decoded as a header block;
24
+ * subsequent blobs are decoded as primitive blocks containing OSM entities.
25
+ *
26
+ * @param blobs - Async or sync generator yielding compressed blob payloads.
27
+ * @param decompress - Optional decompression function (defaults to Web Streams zlib).
28
+ * @yields Header block first, then primitive blocks.
29
+ *
30
+ * @example
31
+ * ```ts
32
+ * import { osmPbfBlobsToBlocksGenerator, createOsmPbfBlobGenerator } from "@osmix/pbf"
33
+ *
34
+ * const generateBlobs = createOsmPbfBlobGenerator()
35
+ * const blobsGen = (async function* () {
36
+ * for await (const chunk of stream) {
37
+ * yield* generateBlobs(chunk)
38
+ * }
39
+ * })()
40
+ *
41
+ * for await (const block of osmPbfBlobsToBlocksGenerator(blobsGen)) {
42
+ * // First iteration yields header, rest yield primitive blocks
43
+ * }
44
+ * ```
8
45
  */
9
46
  export async function* osmPbfBlobsToBlocksGenerator(
10
47
  blobs:
@@ -16,13 +53,47 @@ export async function* osmPbfBlobsToBlocksGenerator(
16
53
  ) {
17
54
  let headerRead = false
18
55
  for await (const blob of blobs) {
19
- const decompressedBlob = await decompress(blob)
20
- const pbf = new Pbf(decompressedBlob)
21
56
  if (!headerRead) {
22
57
  headerRead = true
23
- yield readHeaderBlock(pbf)
58
+ yield readOsmHeaderBlock(blob, decompress)
24
59
  } else {
25
- yield readPrimitiveBlock(pbf)
60
+ yield readOsmPrimitiveBlock(blob, decompress)
26
61
  }
27
62
  }
28
63
  }
64
+
65
+ /**
66
+ * Decompress and parse a header block from a compressed blob.
67
+ *
68
+ * @param compressedBlob - Zlib-compressed protobuf header blob.
69
+ * @param decompress - Optional decompression function.
70
+ * @returns Parsed header block with required/optional features and bbox.
71
+ */
72
+ export async function readOsmHeaderBlock(
73
+ compressedBlob: Uint8Array<ArrayBuffer>,
74
+ decompress: (
75
+ data: Uint8Array<ArrayBuffer>,
76
+ ) => Promise<Uint8Array<ArrayBuffer>> = webDecompress,
77
+ ): Promise<OsmPbfHeaderBlock> {
78
+ const decompressedBlob = await decompress(compressedBlob)
79
+ const pbf = new Pbf(decompressedBlob)
80
+ return readHeaderBlock(pbf)
81
+ }
82
+
83
+ /**
84
+ * Decompress and parse a primitive block from a compressed blob.
85
+ *
86
+ * @param compressedBlob - Zlib-compressed protobuf primitive blob.
87
+ * @param decompress - Optional decompression function.
88
+ * @returns Parsed primitive block with string table and primitive groups.
89
+ */
90
+ export async function readOsmPrimitiveBlock(
91
+ compressedBlob: Uint8Array<ArrayBuffer>,
92
+ decompress: (
93
+ data: Uint8Array<ArrayBuffer>,
94
+ ) => Promise<Uint8Array<ArrayBuffer>> = webDecompress,
95
+ ): Promise<OsmPbfBlock> {
96
+ const decompressedBlob = await decompress(compressedBlob)
97
+ const pbf = new Pbf(decompressedBlob)
98
+ return readPrimitiveBlock(pbf)
99
+ }