@osmix/core 0.1.10 → 0.2.0

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 (70) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/LICENSE +21 -0
  3. package/README.md +86 -69
  4. package/dist/contracts.d.ts +26 -0
  5. package/dist/contracts.d.ts.map +1 -0
  6. package/dist/contracts.js +1 -0
  7. package/dist/contracts.js.map +1 -0
  8. package/dist/entities.d.ts +1 -1
  9. package/dist/entities.d.ts.map +1 -1
  10. package/dist/entities.js +2 -7
  11. package/dist/entities.js.map +1 -1
  12. package/dist/ids.d.ts +2 -0
  13. package/dist/ids.d.ts.map +1 -1
  14. package/dist/ids.js +23 -15
  15. package/dist/ids.js.map +1 -1
  16. package/dist/index.d.ts +1 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +0 -1
  19. package/dist/index.js.map +1 -1
  20. package/dist/mocks.d.ts.map +1 -1
  21. package/dist/mocks.js.map +1 -1
  22. package/dist/nodes.d.ts +9 -3
  23. package/dist/nodes.d.ts.map +1 -1
  24. package/dist/nodes.js +6 -13
  25. package/dist/nodes.js.map +1 -1
  26. package/dist/osm.d.ts +1 -1
  27. package/dist/osm.d.ts.map +1 -1
  28. package/dist/osm.js +1 -4
  29. package/dist/osm.js.map +1 -1
  30. package/dist/relations.d.ts +3 -2
  31. package/dist/relations.d.ts.map +1 -1
  32. package/dist/relations.js +15 -9
  33. package/dist/relations.js.map +1 -1
  34. package/dist/stringtable.d.ts.map +1 -1
  35. package/dist/stringtable.js +4 -13
  36. package/dist/stringtable.js.map +1 -1
  37. package/dist/tags.d.ts +1 -1
  38. package/dist/tags.d.ts.map +1 -1
  39. package/dist/tags.js.map +1 -1
  40. package/dist/typed-arrays.d.ts.map +1 -1
  41. package/dist/typed-arrays.js.map +1 -1
  42. package/dist/ways.d.ts +2 -1
  43. package/dist/ways.d.ts.map +1 -1
  44. package/dist/ways.js +18 -18
  45. package/dist/ways.js.map +1 -1
  46. package/package.json +46 -31
  47. package/src/contracts.ts +28 -0
  48. package/src/entities.ts +179 -194
  49. package/src/ids.ts +228 -235
  50. package/src/index.ts +12 -9
  51. package/src/mocks.ts +114 -113
  52. package/src/nodes.ts +364 -397
  53. package/src/osm.ts +196 -207
  54. package/src/relations.ts +530 -558
  55. package/src/stringtable.ts +174 -183
  56. package/src/tags.ts +263 -271
  57. package/src/typed-arrays.ts +184 -194
  58. package/src/types/geoflatbush.d.ts +28 -33
  59. package/src/types/geokdbush.d.ts +28 -33
  60. package/src/types/kdbush.d.ts +34 -34
  61. package/src/ways.ts +381 -405
  62. package/test/ids.bench.ts +29 -0
  63. package/test/ids.test.ts +84 -0
  64. package/test/memory.test.ts +29 -30
  65. package/test/relations.bench.ts +27 -0
  66. package/test/relations.test.ts +101 -0
  67. package/test/tags-search.test.ts +76 -56
  68. package/test/typed-arrays.test.ts +100 -99
  69. package/tsconfig.build.json +6 -6
  70. package/tsconfig.json +7 -7
@@ -7,20 +7,21 @@
7
7
  * @module
8
8
  */
9
9
 
10
- import type { OsmPbfStringTable } from "@osmix/pbf"
11
- import type { ContentHasher } from "@osmix/shared/content-hasher"
12
- import { type BufferType, ResizeableTypedArray as RTA } from "./typed-arrays.ts"
10
+ import type { OsmPbfStringTable } from "@osmix/pbf";
11
+ import type { ContentHasher } from "@osmix/shared/content-hasher";
12
+
13
+ import { type BufferType, ResizeableTypedArray as RTA } from "./typed-arrays.ts";
13
14
 
14
15
  /**
15
16
  * Serializable state for worker transfer.
16
17
  */
17
18
  export interface StringTableTransferables<T extends BufferType = BufferType> {
18
- /** Concatenated UTF-8 bytes. */
19
- bytes: T
20
- /** Maps string index → byte offset. */
21
- start: T
22
- /** Maps string index → byte length. */
23
- count: T
19
+ /** Concatenated UTF-8 bytes. */
20
+ bytes: T;
21
+ /** Maps string index → byte offset. */
22
+ start: T;
23
+ /** Maps string index → byte length. */
24
+ count: T;
24
25
  }
25
26
 
26
27
  /**
@@ -30,178 +31,168 @@ export interface StringTableTransferables<T extends BufferType = BufferType> {
30
31
  * Rebuilds reverse index lazily after transfer.
31
32
  */
32
33
  export default class StringTable {
33
- /** UTF-8 encoder for string→bytes conversion */
34
- private enc = new TextEncoder()
35
- /** UTF-8 decoder for bytes→string conversion */
36
- private dec = new TextDecoder() // UTF-8
37
-
38
- // ─── Serializable State ────────────────────────────────────────────────────
39
- /** Concatenated UTF-8 bytes of all strings */
40
- bytes: RTA<Uint8Array>
41
- /** Maps string index → byte offset in bytes array */
42
- start: RTA<Uint32Array>
43
- /** Maps string index → byte length */
44
- count: RTA<Uint16Array>
45
-
46
- // ─── Builder State (string → index) ────────────────────────────────────────
47
- /** Forward lookup: string → index (populated during add) */
48
- private stringToIndex = new Map<string, number>()
49
-
50
- /** Whether the reverse index has been built (lazy after transfer) */
51
- private reverseIndexBuilt = false
52
-
53
- // ─── Retrieval Cache (index → string) ──────────────────────────────────────
54
- /** Cache of decoded strings to avoid repeated UTF-8 decoding */
55
- private indexToString = new Map<number, string>()
56
-
57
- /**
58
- * Create a new StringTable.
59
- */
60
- constructor(opts?: StringTableTransferables) {
61
- this.bytes = opts?.bytes
62
- ? RTA.from(Uint8Array, opts.bytes)
63
- : new RTA(Uint8Array)
64
- this.start = opts?.start
65
- ? RTA.from(Uint32Array, opts.start)
66
- : new RTA(Uint32Array)
67
- this.count = opts?.count
68
- ? RTA.from(Uint16Array, opts.count)
69
- : new RTA(Uint16Array)
70
- }
71
-
72
- /**
73
- * Get transferable objects for passing to another thread.
74
- */
75
- transferables(): StringTableTransferables {
76
- return {
77
- bytes: this.bytes.array.buffer,
78
- start: this.start.array.buffer,
79
- count: this.count.array.buffer,
80
- }
81
- }
82
-
83
- /**
84
- * Add a string to the table and return its index.
85
- */
86
- add(str: string): number {
87
- const existingIndex = this.stringToIndex.get(str)
88
- if (existingIndex !== undefined) return existingIndex
89
- const startIndex = this.start.length
90
- const encoded = this.enc.encode(str)
91
- this.start.push(this.bytes.length)
92
- this.bytes.pushMany(encoded)
93
- this.count.push(encoded.length)
94
- this.stringToIndex.set(str, startIndex)
95
- return startIndex
96
- }
97
-
98
- /**
99
- * Decode all the strings in a primitive block and add them to the string table.
100
- * Return a mapping of block index -> string table index
101
- */
102
- createBlockIndexMap(blockStringtable: OsmPbfStringTable) {
103
- const index = new Uint32Array(blockStringtable.length)
104
- for (let i = 0; i < blockStringtable.length; i++) {
105
- const bytesString = blockStringtable[i]
106
- const str = this.dec.decode(bytesString)
107
- const existingIndex = this.stringToIndex.get(str)
108
- if (existingIndex !== undefined) {
109
- index[i] = existingIndex
110
- continue
111
- }
112
- index[i] = this.add(str)
113
- }
114
- return index
115
- }
116
-
117
- /**
118
- * Get a string by its index.
119
- * Caches results to avoid repeated UTF-8 decoding.
120
- */
121
- get(index: number): string {
122
- const string = this.indexToString.get(index)
123
- if (string) return string
124
- const bytes = this.getBytes(index)
125
- const tempBuffer = new ArrayBuffer(bytes.byteLength)
126
- const tempBytes = new Uint8Array(tempBuffer)
127
- tempBytes.set(bytes)
128
- const decoded = this.dec.decode(tempBytes)
129
- this.indexToString.set(index, decoded)
130
- return decoded
131
- }
132
-
133
- /**
134
- * Get the raw UTF-8 bytes of a string.
135
- * Returns a subarray view (not a copy).
136
- */
137
- getBytes(index: number): Uint8Array {
138
- if (index < 0 || index >= this.length)
139
- throw Error(`String index out of range: ${index}`)
140
- const start = this.start.at(index)
141
- const count = this.count.at(index)
142
- return this.bytes.array.subarray(start, start + count)
143
- }
144
-
145
- /** Number of strings in the table. */
146
- get length() {
147
- return this.start.length
148
- }
149
-
150
- /**
151
- * Finalize the string table by compacting internal arrays.
152
- *
153
- * This releases unused buffer capacity and marks the reverse index as built
154
- * (since all strings were added before this call).
155
- */
156
- buildIndex() {
157
- this.bytes.compact()
158
- this.start.compact()
159
- this.count.compact()
160
- this.reverseIndexBuilt = true
161
- }
162
-
163
- /**
164
- * Convert the string table to an OSM PBF string table.
165
- */
166
- toOsmPbfStringTable(): OsmPbfStringTable {
167
- const stringTable: OsmPbfStringTable = []
168
- for (let i = 0; i < this.length; i++) {
169
- stringTable.push(this.getBytes(i))
170
- }
171
- return stringTable
172
- }
173
-
174
- /**
175
- * Lazily build the reverse index (string → index).
176
- * Decodes all strings once to populate the lookup map.
177
- */
178
- private ensureReverseIndex() {
179
- if (this.reverseIndexBuilt) return
180
- // Decode all strings and populate the forward lookup map
181
- for (let i = 0; i < this.length; i++) {
182
- this.stringToIndex.set(this.get(i), i)
183
- }
184
- this.reverseIndexBuilt = true
185
- }
186
-
187
- /**
188
- * Find the index of a string.
189
- */
190
- find(str: string): number {
191
- const existing = this.stringToIndex.get(str)
192
- if (existing !== undefined) return existing
193
- this.ensureReverseIndex()
194
- return this.stringToIndex.get(str) ?? -1
195
- }
196
-
197
- /**
198
- * Update a ContentHasher with the string table's data.
199
- * Hashes the bytes, start offsets, and counts.
200
- */
201
- updateHash(hasher: ContentHasher): ContentHasher {
202
- return hasher
203
- .update(this.bytes.array)
204
- .update(this.start.array)
205
- .update(this.count.array)
206
- }
34
+ /** UTF-8 encoder for string→bytes conversion */
35
+ private enc = new TextEncoder();
36
+ /** UTF-8 decoder for bytes→string conversion */
37
+ private dec = new TextDecoder(); // UTF-8
38
+
39
+ // ─── Serializable State ────────────────────────────────────────────────────
40
+ /** Concatenated UTF-8 bytes of all strings */
41
+ bytes: RTA<Uint8Array>;
42
+ /** Maps string index → byte offset in bytes array */
43
+ start: RTA<Uint32Array>;
44
+ /** Maps string index → byte length */
45
+ count: RTA<Uint16Array>;
46
+
47
+ // ─── Builder State (string → index) ────────────────────────────────────────
48
+ /** Forward lookup: string → index (populated during add) */
49
+ private stringToIndex = new Map<string, number>();
50
+
51
+ /** Whether the reverse index has been built (lazy after transfer) */
52
+ private reverseIndexBuilt = false;
53
+
54
+ // ─── Retrieval Cache (index → string) ──────────────────────────────────────
55
+ /** Cache of decoded strings to avoid repeated UTF-8 decoding */
56
+ private indexToString = new Map<number, string>();
57
+
58
+ /**
59
+ * Create a new StringTable.
60
+ */
61
+ constructor(opts?: StringTableTransferables) {
62
+ this.bytes = opts?.bytes ? RTA.from(Uint8Array, opts.bytes) : new RTA(Uint8Array);
63
+ this.start = opts?.start ? RTA.from(Uint32Array, opts.start) : new RTA(Uint32Array);
64
+ this.count = opts?.count ? RTA.from(Uint16Array, opts.count) : new RTA(Uint16Array);
65
+ }
66
+
67
+ /**
68
+ * Get transferable objects for passing to another thread.
69
+ */
70
+ transferables(): StringTableTransferables {
71
+ return {
72
+ bytes: this.bytes.array.buffer,
73
+ start: this.start.array.buffer,
74
+ count: this.count.array.buffer,
75
+ };
76
+ }
77
+
78
+ /**
79
+ * Add a string to the table and return its index.
80
+ */
81
+ add(str: string): number {
82
+ const existingIndex = this.stringToIndex.get(str);
83
+ if (existingIndex !== undefined) return existingIndex;
84
+ const startIndex = this.start.length;
85
+ const encoded = this.enc.encode(str);
86
+ this.start.push(this.bytes.length);
87
+ this.bytes.pushMany(encoded);
88
+ this.count.push(encoded.length);
89
+ this.stringToIndex.set(str, startIndex);
90
+ return startIndex;
91
+ }
92
+
93
+ /**
94
+ * Decode all the strings in a primitive block and add them to the string table.
95
+ * Return a mapping of block index -> string table index
96
+ */
97
+ createBlockIndexMap(blockStringtable: OsmPbfStringTable) {
98
+ const index = new Uint32Array(blockStringtable.length);
99
+ for (let i = 0; i < blockStringtable.length; i++) {
100
+ const bytesString = blockStringtable[i];
101
+ const str = this.dec.decode(bytesString);
102
+ const existingIndex = this.stringToIndex.get(str);
103
+ if (existingIndex !== undefined) {
104
+ index[i] = existingIndex;
105
+ continue;
106
+ }
107
+ index[i] = this.add(str);
108
+ }
109
+ return index;
110
+ }
111
+
112
+ /**
113
+ * Get a string by its index.
114
+ * Caches results to avoid repeated UTF-8 decoding.
115
+ */
116
+ get(index: number): string {
117
+ const string = this.indexToString.get(index);
118
+ if (string) return string;
119
+ const bytes = this.getBytes(index);
120
+ const tempBuffer = new ArrayBuffer(bytes.byteLength);
121
+ const tempBytes = new Uint8Array(tempBuffer);
122
+ tempBytes.set(bytes);
123
+ const decoded = this.dec.decode(tempBytes);
124
+ this.indexToString.set(index, decoded);
125
+ return decoded;
126
+ }
127
+
128
+ /**
129
+ * Get the raw UTF-8 bytes of a string.
130
+ * Returns a subarray view (not a copy).
131
+ */
132
+ getBytes(index: number): Uint8Array {
133
+ if (index < 0 || index >= this.length) throw Error(`String index out of range: ${index}`);
134
+ const start = this.start.at(index);
135
+ const count = this.count.at(index);
136
+ return this.bytes.array.subarray(start, start + count);
137
+ }
138
+
139
+ /** Number of strings in the table. */
140
+ get length() {
141
+ return this.start.length;
142
+ }
143
+
144
+ /**
145
+ * Finalize the string table by compacting internal arrays.
146
+ *
147
+ * This releases unused buffer capacity and marks the reverse index as built
148
+ * (since all strings were added before this call).
149
+ */
150
+ buildIndex() {
151
+ this.bytes.compact();
152
+ this.start.compact();
153
+ this.count.compact();
154
+ this.reverseIndexBuilt = true;
155
+ }
156
+
157
+ /**
158
+ * Convert the string table to an OSM PBF string table.
159
+ */
160
+ toOsmPbfStringTable(): OsmPbfStringTable {
161
+ const stringTable: OsmPbfStringTable = [];
162
+ for (let i = 0; i < this.length; i++) {
163
+ stringTable.push(this.getBytes(i));
164
+ }
165
+ return stringTable;
166
+ }
167
+
168
+ /**
169
+ * Lazily build the reverse index (string → index).
170
+ * Decodes all strings once to populate the lookup map.
171
+ */
172
+ private ensureReverseIndex() {
173
+ if (this.reverseIndexBuilt) return;
174
+ // Decode all strings and populate the forward lookup map
175
+ for (let i = 0; i < this.length; i++) {
176
+ this.stringToIndex.set(this.get(i), i);
177
+ }
178
+ this.reverseIndexBuilt = true;
179
+ }
180
+
181
+ /**
182
+ * Find the index of a string.
183
+ */
184
+ find(str: string): number {
185
+ const existing = this.stringToIndex.get(str);
186
+ if (existing !== undefined) return existing;
187
+ this.ensureReverseIndex();
188
+ return this.stringToIndex.get(str) ?? -1;
189
+ }
190
+
191
+ /**
192
+ * Update a ContentHasher with the string table's data.
193
+ * Hashes the bytes, start offsets, and counts.
194
+ */
195
+ updateHash(hasher: ContentHasher): ContentHasher {
196
+ return hasher.update(this.bytes.array).update(this.start.array).update(this.count.array);
197
+ }
207
198
  }