@ifc-lite/parser 4.3.2 → 5.0.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 (155) hide show
  1. package/dist/attribute-helpers.d.ts +38 -4
  2. package/dist/attribute-helpers.d.ts.map +1 -1
  3. package/dist/attribute-helpers.js +71 -4
  4. package/dist/attribute-helpers.js.map +1 -1
  5. package/dist/columnar-parser-attributes.d.ts.map +1 -1
  6. package/dist/columnar-parser-attributes.js +35 -5
  7. package/dist/columnar-parser-attributes.js.map +1 -1
  8. package/dist/columnar-parser-indexes.d.ts.map +1 -1
  9. package/dist/columnar-parser-indexes.js +14 -2
  10. package/dist/columnar-parser-indexes.js.map +1 -1
  11. package/dist/columnar-parser-relationships.d.ts.map +1 -1
  12. package/dist/columnar-parser-relationships.js +6 -1
  13. package/dist/columnar-parser-relationships.js.map +1 -1
  14. package/dist/columnar-parser.d.ts +3 -1
  15. package/dist/columnar-parser.d.ts.map +1 -1
  16. package/dist/columnar-parser.js +16 -25
  17. package/dist/columnar-parser.js.map +1 -1
  18. package/dist/compact-entity-index-transport.d.ts +23 -0
  19. package/dist/compact-entity-index-transport.d.ts.map +1 -0
  20. package/dist/compact-entity-index-transport.js +28 -0
  21. package/dist/compact-entity-index-transport.js.map +1 -0
  22. package/dist/compact-entity-index.d.ts +0 -10
  23. package/dist/compact-entity-index.d.ts.map +1 -1
  24. package/dist/compact-entity-index.js +31 -24
  25. package/dist/compact-entity-index.js.map +1 -1
  26. package/dist/data-store-transport.d.ts +2 -12
  27. package/dist/data-store-transport.d.ts.map +1 -1
  28. package/dist/data-store-transport.js +7 -20
  29. package/dist/data-store-transport.js.map +1 -1
  30. package/dist/entity-extractor.d.ts.map +1 -1
  31. package/dist/entity-extractor.js +101 -6
  32. package/dist/entity-extractor.js.map +1 -1
  33. package/dist/entity-refs-from-index.d.ts.map +1 -1
  34. package/dist/entity-refs-from-index.js +12 -2
  35. package/dist/entity-refs-from-index.js.map +1 -1
  36. package/dist/entity-scanner.d.ts +63 -0
  37. package/dist/entity-scanner.d.ts.map +1 -1
  38. package/dist/entity-scanner.js +79 -2
  39. package/dist/entity-scanner.js.map +1 -1
  40. package/dist/express-id.d.ts +47 -0
  41. package/dist/express-id.d.ts.map +1 -0
  42. package/dist/express-id.js +57 -0
  43. package/dist/express-id.js.map +1 -0
  44. package/dist/generated/entities.d.ts +1 -1
  45. package/dist/generated/entities.d.ts.map +1 -1
  46. package/dist/generated/schema-registry.js +146 -146
  47. package/dist/generated/schema-registry.js.map +1 -1
  48. package/dist/georef-epset.d.ts +25 -0
  49. package/dist/georef-epset.d.ts.map +1 -0
  50. package/dist/georef-epset.js +214 -0
  51. package/dist/georef-epset.js.map +1 -0
  52. package/dist/georef-extractor.d.ts.map +1 -1
  53. package/dist/georef-extractor.js +38 -175
  54. package/dist/georef-extractor.js.map +1 -1
  55. package/dist/georef-map-conversion.d.ts +29 -0
  56. package/dist/georef-map-conversion.d.ts.map +1 -0
  57. package/dist/georef-map-conversion.js +75 -0
  58. package/dist/georef-map-conversion.js.map +1 -0
  59. package/dist/ifc-schema.d.ts +4 -2
  60. package/dist/ifc-schema.d.ts.map +1 -1
  61. package/dist/ifc-schema.js +15 -5
  62. package/dist/ifc-schema.js.map +1 -1
  63. package/dist/index.d.ts +5 -2
  64. package/dist/index.d.ts.map +1 -1
  65. package/dist/index.js +5 -2
  66. package/dist/index.js.map +1 -1
  67. package/dist/material-extractor.d.ts +2 -17
  68. package/dist/material-extractor.d.ts.map +1 -1
  69. package/dist/material-extractor.js +12 -37
  70. package/dist/material-extractor.js.map +1 -1
  71. package/dist/material-layer-reader.d.ts +45 -0
  72. package/dist/material-layer-reader.d.ts.map +1 -0
  73. package/dist/material-layer-reader.js +63 -0
  74. package/dist/material-layer-reader.js.map +1 -0
  75. package/dist/material-resolver.d.ts.map +1 -1
  76. package/dist/material-resolver.js +14 -14
  77. package/dist/material-resolver.js.map +1 -1
  78. package/dist/measure-unit-scale.d.ts +41 -0
  79. package/dist/measure-unit-scale.d.ts.map +1 -0
  80. package/dist/measure-unit-scale.js +53 -0
  81. package/dist/measure-unit-scale.js.map +1 -0
  82. package/dist/on-demand-extractors.d.ts +3 -19
  83. package/dist/on-demand-extractors.d.ts.map +1 -1
  84. package/dist/on-demand-extractors.js +54 -264
  85. package/dist/on-demand-extractors.js.map +1 -1
  86. package/dist/owning-project.d.ts +54 -0
  87. package/dist/owning-project.d.ts.map +1 -0
  88. package/dist/owning-project.js +76 -0
  89. package/dist/owning-project.js.map +1 -0
  90. package/dist/parser.worker.d.ts +14 -0
  91. package/dist/parser.worker.d.ts.map +1 -1
  92. package/dist/parser.worker.js +2 -0
  93. package/dist/parser.worker.js.map +1 -1
  94. package/dist/project-units-symbols.d.ts +33 -0
  95. package/dist/project-units-symbols.d.ts.map +1 -0
  96. package/dist/project-units-symbols.js +265 -0
  97. package/dist/project-units-symbols.js.map +1 -0
  98. package/dist/project-units.d.ts +11 -19
  99. package/dist/project-units.d.ts.map +1 -1
  100. package/dist/project-units.js +9 -267
  101. package/dist/project-units.js.map +1 -1
  102. package/dist/property-set-merge.d.ts +65 -8
  103. package/dist/property-set-merge.d.ts.map +1 -1
  104. package/dist/property-set-merge.js +130 -29
  105. package/dist/property-set-merge.js.map +1 -1
  106. package/dist/property-value-parser.d.ts +55 -0
  107. package/dist/property-value-parser.d.ts.map +1 -0
  108. package/dist/property-value-parser.js +277 -0
  109. package/dist/property-value-parser.js.map +1 -0
  110. package/dist/quantity-collect.d.ts +42 -3
  111. package/dist/quantity-collect.d.ts.map +1 -1
  112. package/dist/quantity-collect.js +114 -7
  113. package/dist/quantity-collect.js.map +1 -1
  114. package/dist/query-backend-maps.d.ts +5 -8
  115. package/dist/query-backend-maps.d.ts.map +1 -1
  116. package/dist/query-backend-maps.js +155 -15
  117. package/dist/query-backend-maps.js.map +1 -1
  118. package/dist/relationship-extractor.d.ts.map +1 -1
  119. package/dist/relationship-extractor.js +18 -0
  120. package/dist/relationship-extractor.js.map +1 -1
  121. package/dist/scan-entities-balanced.d.ts +38 -0
  122. package/dist/scan-entities-balanced.d.ts.map +1 -0
  123. package/dist/scan-entities-balanced.js +258 -0
  124. package/dist/scan-entities-balanced.js.map +1 -0
  125. package/dist/scan-worker-inline.d.ts +17 -11
  126. package/dist/scan-worker-inline.d.ts.map +1 -1
  127. package/dist/scan-worker-inline.js +9 -235
  128. package/dist/scan-worker-inline.js.map +1 -1
  129. package/dist/scan-worker-source.d.ts +9 -0
  130. package/dist/scan-worker-source.d.ts.map +1 -0
  131. package/dist/scan-worker-source.js +383 -0
  132. package/dist/scan-worker-source.js.map +1 -0
  133. package/dist/spatial-hierarchy-builder.js +3 -3
  134. package/dist/spatial-hierarchy-builder.js.map +1 -1
  135. package/dist/step-lexing.d.ts +2 -0
  136. package/dist/step-lexing.d.ts.map +1 -1
  137. package/dist/step-lexing.js +116 -18
  138. package/dist/step-lexing.js.map +1 -1
  139. package/dist/step-trivia.d.ts +60 -0
  140. package/dist/step-trivia.d.ts.map +1 -0
  141. package/dist/step-trivia.js +63 -0
  142. package/dist/step-trivia.js.map +1 -0
  143. package/dist/tokenizer.d.ts +20 -21
  144. package/dist/tokenizer.d.ts.map +1 -1
  145. package/dist/tokenizer.js +164 -203
  146. package/dist/tokenizer.js.map +1 -1
  147. package/dist/unit-extractor.d.ts +43 -1
  148. package/dist/unit-extractor.d.ts.map +1 -1
  149. package/dist/unit-extractor.js +63 -4
  150. package/dist/unit-extractor.js.map +1 -1
  151. package/dist/worker-parser.d.ts +11 -1
  152. package/dist/worker-parser.d.ts.map +1 -1
  153. package/dist/worker-parser.js +16 -2
  154. package/dist/worker-parser.js.map +1 -1
  155. package/package.json +6 -6
@@ -0,0 +1,258 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ /**
5
+ * The balanced-parenthesis entity scan: closes a record on the ')' that
6
+ * balances its argument list, rather than on the terminating ';'.
7
+ *
8
+ * Split out of `tokenizer.ts`, which holds the fast semicolon scan
9
+ * (`StepTokenizer.scanEntitiesFast`). The two share nothing but the
10
+ * `step-lexing` helpers -- the cursor helpers below (`readExpressId`,
11
+ * `readTypeName`, `skipTrivia`) exist only for this scan, because the fast one
12
+ * inlines its equivalents for speed. `StepTokenizer.scanEntities` is the
13
+ * public entry point and delegates here.
14
+ */
15
+ import { safeUtf8Decode } from '@ifc-lite/data';
16
+ import { isIndexableExpressId } from './express-id.js';
17
+ import { countNewlines, findEntityLength, opensLiteralOrComment, skipLexical, skipTrivia, } from './step-lexing.js';
18
+ /**
19
+ * One balanced-parenthesis scan over one buffer.
20
+ *
21
+ * The cursor and the refusal count are bound to the scan rather than kept on
22
+ * `StepTokenizer`, so a second scan cannot read the first one's leftovers.
23
+ */
24
+ export class BalancedEntityScan {
25
+ buffer;
26
+ position = 0;
27
+ lineNumber = 1;
28
+ oversizedIds = 0;
29
+ malformed = 0;
30
+ constructor(buffer) {
31
+ this.buffer = buffer;
32
+ }
33
+ /** Records this scan refused for an out-of-contract express id (#3395). */
34
+ get oversizedIdCount() {
35
+ return this.oversizedIds;
36
+ }
37
+ /** Mirrors `StepTokenizer.malformedRecordCount`'s contract: 0 or 1, set by
38
+ * the single post-loop check at the end of `run()`. */
39
+ get malformedRecordCount() {
40
+ return this.malformed;
41
+ }
42
+ /** Every entity declaration (`#EXPRESS_ID = TYPE(...)`) in the buffer. */
43
+ *run() {
44
+ this.position = 0;
45
+ this.lineNumber = 1;
46
+ this.oversizedIds = 0;
47
+ this.malformed = 0;
48
+ // Set on the way to the single post-loop check below: `stopped` for an
49
+ // unclosed string or comment that ran the scan to end of buffer with
50
+ // nothing left to find, `declOpen` while a `#id=TYPE(` header is
51
+ // incomplete. `declOpen` stays armed ONLY when the reason for abandoning
52
+ // is running out of buffer; a mismatch with buffer still left clears it,
53
+ // because the scan resumes byte-by-byte from wherever it gave up, and a
54
+ // `#ref` token inside the abandoned record's own argument list reads as
55
+ // a fresh, equally incomplete attempt that must not report "cut off"
56
+ // just because nothing later happens to clear it.
57
+ let stopped = false;
58
+ let declOpen = false;
59
+ while (this.position < this.buffer.length) {
60
+ // Look for '#' character (entity ID marker)
61
+ if (this.buffer[this.position] === 0x23) { // '#'
62
+ const startOffset = this.position;
63
+ const startLine = this.lineNumber;
64
+ // Read express ID
65
+ const expressId = this.readExpressId();
66
+ if (expressId === null) {
67
+ this.position++;
68
+ continue;
69
+ }
70
+ declOpen = true;
71
+ // Whitespace AND comments: 10303-21 allows a comment wherever
72
+ // whitespace is allowed, so `#1 /* was #7 */ =` is a declaration.
73
+ if (this.skipTrivia()) {
74
+ stopped = true;
75
+ break;
76
+ }
77
+ // Check for '=' (assignment). Not a truncation when buffer is still
78
+ // left to scan -- clear declOpen so a reference token inside a LATER
79
+ // abandoned record's argument list (walked byte-by-byte once this
80
+ // one is given up on) cannot leave it stuck armed with nothing left
81
+ // to clear it.
82
+ if (this.position >= this.buffer.length) {
83
+ this.position++;
84
+ continue;
85
+ }
86
+ if (this.buffer[this.position] !== 0x3D) {
87
+ declOpen = false;
88
+ this.position++;
89
+ continue;
90
+ }
91
+ this.position++; // Skip '='
92
+ if (this.skipTrivia()) {
93
+ stopped = true;
94
+ break;
95
+ }
96
+ // Read type name. `readTypeName` returns null both on EOF and on a
97
+ // bad start byte, and leaves `position` untouched either way, so
98
+ // check `position` here to tell the two apart the same way the '='
99
+ // and '(' checks do.
100
+ const type = this.readTypeName();
101
+ if (!type) {
102
+ if (this.position < this.buffer.length)
103
+ declOpen = false;
104
+ this.position++;
105
+ continue;
106
+ }
107
+ if (this.skipTrivia()) {
108
+ stopped = true;
109
+ break;
110
+ }
111
+ // Check for '(' (start of parameters). Same EOF-vs-mismatch split.
112
+ if (this.position >= this.buffer.length) {
113
+ this.position++;
114
+ continue;
115
+ }
116
+ if (this.buffer[this.position] !== 0x28) {
117
+ declOpen = false;
118
+ this.position++;
119
+ continue;
120
+ }
121
+ declOpen = false; // header complete: '(' found
122
+ // Find matching closing parenthesis to get full entity length
123
+ const entityLength = findEntityLength(this.buffer, this.position, startOffset);
124
+ if (entityLength > 0) {
125
+ // Step past the whole record, as Rust's next_entity does. Leaving
126
+ // `position` at the '(' made this loop re-walk the body, which was
127
+ // harmless only while it ignored quotes and comments.
128
+ //
129
+ // Count from `position`, not from `startOffset`: `position` is on the
130
+ // '(' here, and every newline before it was already counted by the
131
+ // three skipTrivia calls above. Counting the whole record instead
132
+ // double-counts a newline written between `#1=` and its type name,
133
+ // which is ordinary whitespace and legal.
134
+ this.lineNumber += countNewlines(this.buffer, this.position, startOffset + entityLength);
135
+ this.position = startOffset + entityLength;
136
+ yield {
137
+ expressId,
138
+ type,
139
+ offset: startOffset,
140
+ length: entityLength,
141
+ line: startLine,
142
+ };
143
+ }
144
+ else {
145
+ // 0 means findEntityLength ran off the end of the buffer without
146
+ // ever balancing the '(' -- an unterminated literal or comment
147
+ // inside the argument list, or no closing ')' at all. Its own loop
148
+ // has no other exit, so this is always the EOF case, never a
149
+ // mid-file syntax choice to resume past.
150
+ stopped = true;
151
+ break;
152
+ }
153
+ }
154
+ else if (this.buffer[this.position] === 0x0A) {
155
+ // Newline
156
+ this.lineNumber++;
157
+ this.position++;
158
+ }
159
+ else if (opensLiteralOrComment(this.buffer, this.position, this.buffer.length)) {
160
+ // A commented-out record satisfies every check above, so a comment has
161
+ // to be skipped as a region; a literal has to be skipped so its
162
+ // contents cannot look like one. See step-lexing.
163
+ const skip = skipLexical(this.buffer, this.position, this.buffer.length);
164
+ this.lineNumber += skip.lines;
165
+ this.position = skip.next;
166
+ if (skip.stop) {
167
+ stopped = true;
168
+ break;
169
+ }
170
+ }
171
+ else {
172
+ this.position++;
173
+ }
174
+ }
175
+ // ONE post-loop check, not an increment at every exit site above: the
176
+ // scan stopped early if it hit an explicit "no terminator" boundary, or
177
+ // the last `#id=TYPE(` header was cut short before its '(' was found.
178
+ // Always 0 or 1 -- the scan stops at the first one, so there is nothing
179
+ // to accumulate past that.
180
+ if (stopped || declOpen)
181
+ this.malformed = 1;
182
+ }
183
+ readExpressId() {
184
+ let id = 0;
185
+ let digits = 0;
186
+ let pos = this.position + 1; // Skip '#'
187
+ while (pos < this.buffer.length) {
188
+ const char = this.buffer[pos];
189
+ if (char >= 0x30 && char <= 0x39) { // '0'-'9'
190
+ id = id * 10 + (char - 0x30);
191
+ digits++;
192
+ pos++;
193
+ }
194
+ else {
195
+ break;
196
+ }
197
+ }
198
+ if (digits === 0)
199
+ return null;
200
+ // Same storage contract as scanEntitiesFast; see express-id.ts (#3395).
201
+ // And the same rule about WHICH refusals count: only a declaration,
202
+ // `#<trivia>=`. This scan resumes one byte into a refused record and
203
+ // walks its argument list, so an oversized `#ref` in there reaches this
204
+ // method too. Look ahead rather than consume — `position` must stay where
205
+ // the caller's recovery expects it.
206
+ if (!isIndexableExpressId(id)) {
207
+ // Trivia, not just whitespace, so this probe recognises exactly the
208
+ // declarations the accept path above does. Skipping only whitespace here
209
+ // would let `#4294967297 /* n */ =` be dropped without being counted.
210
+ const probe = skipTrivia(this.buffer, pos, this.buffer.length).next;
211
+ if (probe < this.buffer.length && this.buffer[probe] === 0x3D)
212
+ this.oversizedIds++;
213
+ return null;
214
+ }
215
+ this.position = pos;
216
+ return id;
217
+ }
218
+ readTypeName() {
219
+ const start = this.position;
220
+ let end = start;
221
+ // Type names start with uppercase letter
222
+ if (this.position >= this.buffer.length || this.buffer[this.position] < 0x41 || this.buffer[this.position] > 0x5A) {
223
+ return null;
224
+ }
225
+ while (end < this.buffer.length) {
226
+ const char = this.buffer[end];
227
+ // Allow letters, numbers, and underscore
228
+ if ((char >= 0x41 && char <= 0x5A) || // A-Z
229
+ (char >= 0x61 && char <= 0x7A) || // a-z
230
+ (char >= 0x30 && char <= 0x39) || // 0-9
231
+ char === 0x5F // _
232
+ ) {
233
+ end++;
234
+ }
235
+ else {
236
+ break;
237
+ }
238
+ }
239
+ if (end === start)
240
+ return null;
241
+ const typeName = safeUtf8Decode(this.buffer, start, end);
242
+ this.position = end;
243
+ return typeName;
244
+ }
245
+ /**
246
+ * Advance past whitespace and comments (see `skipTrivia` in step-lexing).
247
+ * Returns true when the comment it was in never closed, so the caller's
248
+ * single post-loop check can count it instead of reading a false '0' from
249
+ * a scan that actually ran out of buffer mid-header.
250
+ */
251
+ skipTrivia() {
252
+ const skip = skipTrivia(this.buffer, this.position, this.buffer.length);
253
+ this.lineNumber += skip.lines;
254
+ this.position = skip.next;
255
+ return skip.stop;
256
+ }
257
+ }
258
+ //# sourceMappingURL=scan-entities-balanced.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan-entities-balanced.js","sourceRoot":"","sources":["../src/scan-entities-balanced.ts"],"names":[],"mappings":"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"}
@@ -2,9 +2,10 @@
2
2
  * Inline Web Worker for IFC entity scanning.
3
3
  *
4
4
  * Moves the 7-8s entity scanning off the main thread so geometry streaming
5
- * and UI remain responsive. The scanning logic is embedded as a string to
6
- * avoid bundler/import issues with Web Workers.
5
+ * and UI remain responsive. The scanning logic is embedded as a string (see
6
+ * `scan-worker-source.ts`) to avoid bundler/import issues with Web Workers.
7
7
  */
8
+ import { WORKER_CODE } from './scan-worker-source.js';
8
9
  export interface EntityRefWorkerResult {
9
10
  expressId: number;
10
11
  type: string;
@@ -12,18 +13,23 @@ export interface EntityRefWorkerResult {
12
13
  byteLength: number;
13
14
  lineNumber: number;
14
15
  }
15
- /**
16
- * Self-contained entity scanner code (runs inside Web Worker).
17
- * This is the same algorithm as StepTokenizer.scanEntitiesFast() but
18
- * written as a standalone function for worker embedding.
19
- */
20
- /** Exported for direct testing (run inside a mock `self`); the runtime path
21
- * wraps it in a Blob worker via {@link getWorkerBlobUrl}. */
22
- export declare const WORKER_CODE = "\n'use strict';\nself.onmessage = function(e) {\n var buf = new Uint8Array(e.data);\n var len = buf.length;\n var pos = 0;\n var line = 1;\n\n // Pre-allocate result array (estimate ~13,500 entities per MB)\n var estimatedCount = Math.max((len / 1024 / 1024) * 13500, 1000) | 0;\n // Pack results into typed arrays for fast transfer\n var ids = new Uint32Array(estimatedCount);\n var offsets = new Uint32Array(estimatedCount);\n var lengths = new Uint32Array(estimatedCount);\n var lines = new Uint32Array(estimatedCount);\n // Type names stored separately (strings)\n var types = new Array(estimatedCount);\n var count = 0;\n\n // Type name cache (IFC files have ~776 unique types across millions of entities)\n var typeCache = new Map();\n\n function growArrays() {\n var newSize = (count * 2) | 0;\n var newIds = new Uint32Array(newSize);\n newIds.set(ids);\n ids = newIds;\n var newOffsets = new Uint32Array(newSize);\n newOffsets.set(offsets);\n offsets = newOffsets;\n var newLengths = new Uint32Array(newSize);\n newLengths.set(lengths);\n lengths = newLengths;\n var newLines = new Uint32Array(newSize);\n newLines.set(lines);\n lines = newLines;\n types.length = newSize;\n }\n\n while (pos < len) {\n var ch = buf[pos];\n\n if (ch === 0x23) { // '#'\n var startOffset = pos;\n var startLine = line;\n pos++;\n\n // Read express ID\n var expressId = 0;\n var hasDigits = false;\n while (pos < len) {\n var c = buf[pos];\n if (c >= 0x30 && c <= 0x39) {\n expressId = expressId * 10 + (c - 0x30);\n hasDigits = true;\n pos++;\n } else {\n break;\n }\n }\n if (!hasDigits) continue;\n\n // Skip whitespace\n while (pos < len) {\n var c2 = buf[pos];\n if (c2 === 0x20 || c2 === 0x09 || c2 === 0x0D) { pos++; }\n else if (c2 === 0x0A) { line++; pos++; }\n else break;\n }\n\n // Check for '='\n if (pos >= len || buf[pos] !== 0x3D) continue;\n pos++;\n\n // Skip whitespace\n while (pos < len) {\n var c3 = buf[pos];\n if (c3 === 0x20 || c3 === 0x09 || c3 === 0x0D) { pos++; }\n else if (c3 === 0x0A) { line++; pos++; }\n else break;\n }\n\n // Read type name\n var typeStart = pos;\n if (pos >= len || buf[pos] < 0x41 || buf[pos] > 0x5A) continue;\n\n while (pos < len) {\n var c4 = buf[pos];\n if ((c4 >= 0x41 && c4 <= 0x5A) || (c4 >= 0x61 && c4 <= 0x7A) ||\n (c4 >= 0x30 && c4 <= 0x39) || c4 === 0x5F) {\n pos++;\n } else {\n break;\n }\n }\n if (pos === typeStart) continue;\n\n // Cache type name \u2014 use length + hash compound key and verify the actual\n // bytes on a hit. Length alone can't disambiguate a 32-bit hash collision\n // (e.g. \"Aa\"/\"BB\"), so without the byte compare a crafted/unlucky file\n // could have one type silently misread as another. Mirrors tokenizer.ts.\n var typeLen = pos - typeStart;\n var typeHash = typeLen;\n for (var i = typeStart; i < pos; i++) {\n typeHash = (typeHash * 31 + buf[i]) | 0;\n }\n var cacheKey = typeLen + ':' + typeHash;\n var typeName = typeCache.get(cacheKey);\n var cacheHitMatches = false;\n if (typeName !== undefined && typeName.length === typeLen) {\n cacheHitMatches = true;\n for (var v = 0; v < typeLen; v++) {\n if (typeName.charCodeAt(v) !== buf[typeStart + v]) {\n cacheHitMatches = false;\n break;\n }\n }\n }\n if (typeName === undefined || !cacheHitMatches) {\n typeName = String.fromCharCode.apply(null, buf.subarray(typeStart, pos));\n typeCache.set(cacheKey, typeName);\n }\n\n // Skip whitespace\n while (pos < len) {\n var c5 = buf[pos];\n if (c5 === 0x20 || c5 === 0x09 || c5 === 0x0D) { pos++; }\n else if (c5 === 0x0A) { line++; pos++; }\n else break;\n }\n\n // Check for '('\n if (pos >= len || buf[pos] !== 0x28) continue;\n\n // Skip to semicolon (handling strings)\n var inString = false;\n while (pos < len) {\n var c6 = buf[pos];\n if (c6 === 0x27) { // quote\n if (inString && pos + 1 < len && buf[pos + 1] === 0x27) {\n pos += 2;\n continue;\n }\n inString = !inString;\n } else if (c6 === 0x3B && !inString) { // semicolon\n var entityLength = pos - startOffset + 1;\n\n // Grow if needed\n if (count >= ids.length) growArrays();\n\n ids[count] = expressId;\n offsets[count] = startOffset;\n lengths[count] = entityLength;\n lines[count] = startLine;\n types[count] = typeName;\n count++;\n\n pos++;\n break;\n } else if (c6 === 0x0A) {\n line++;\n }\n pos++;\n }\n } else if (ch === 0x0A) {\n line++;\n pos++;\n } else if (ch === 0x27) { // quote\n // Consume a string literal whole. HEADER records carry no '#', so this\n // loop walks them byte by byte, and a '/*' inside a description would\n // otherwise open a comment that never closes and take DATA with it.\n var sp = pos + 1;\n while (sp < len) {\n if (buf[sp] === 0x27) {\n if (sp + 1 < len && buf[sp + 1] === 0x27) { sp += 2; continue; }\n sp++;\n break;\n }\n if (buf[sp] === 0x0A) { line++; }\n sp++;\n }\n pos = sp;\n } else if (ch === 0x2F && pos + 1 < len && buf[pos + 1] === 0x2A) {\n // Skip a /* */ region. A record that is commented out is still a\n // well-formed #id = TYPE(...), so every check above accepts it and only\n // skipping the region rejects it. Kept byte-identical to\n // step-lexing.ts, which this cannot import: the worker source is a\n // string, so the third copy of this loop has to carry its own copy of\n // the rule. Comments do not nest, per ISO 10303-21.\n var cp = pos + 2;\n var closed = false;\n while (cp + 1 < len) {\n if (buf[cp] === 0x2A && buf[cp + 1] === 0x2F) { closed = true; break; }\n if (buf[cp] === 0x0A) { line++; }\n cp++;\n }\n if (!closed) {\n // Unterminated: everything to EOF is commented out.\n pos = len;\n break;\n }\n pos = cp + 2;\n } else {\n pos++;\n }\n }\n\n // Trim arrays once, reuse for both message and transfer list\n var needsTrim = ids.buffer.byteLength > count * 4;\n var trimmedIds = needsTrim ? ids.slice(0, count) : ids;\n var trimmedOffsets = needsTrim ? offsets.slice(0, count) : offsets;\n var trimmedLengths = needsTrim ? lengths.slice(0, count) : lengths;\n var trimmedLines = needsTrim ? lines.slice(0, count) : lines;\n self.postMessage({\n ids: trimmedIds.buffer,\n offsets: trimmedOffsets.buffer,\n lengths: trimmedLengths.buffer,\n lines: trimmedLines.buffer,\n types: types.slice(0, count),\n count: count,\n }, [\n trimmedIds.buffer,\n trimmedOffsets.buffer,\n trimmedLengths.buffer,\n trimmedLines.buffer,\n ]);\n};\n";
16
+ /** What one worker scan produced: the records it accepted, and how many it
17
+ * refused for an out-of-contract express id (#3395). The second half is not
18
+ * decoration a guard that acts without reporting turns a corrupted index
19
+ * into a silently short one, which reads exactly like success. */
20
+ export interface EntityScanWorkerResult {
21
+ refs: EntityRefWorkerResult[];
22
+ oversizedIdCount: number;
23
+ /** See {@link StepTokenizer.malformedRecordCount} in tokenizer.ts same
24
+ * condition, same recovery, counted by this worker's own copy of the
25
+ * scan loop. */
26
+ malformedRecordCount: number;
27
+ }
28
+ export { WORKER_CODE };
23
29
  /**
24
30
  * Scan IFC entities in a Web Worker (non-blocking).
25
31
  * Sends a structured clone of the buffer to the worker (browser handles copy).
26
32
  * Caller keeps the original buffer intact for columnar parsing.
27
33
  */
28
- export declare function scanEntitiesInWorker(buffer: ArrayBuffer | SharedArrayBuffer): Promise<EntityRefWorkerResult[]>;
34
+ export declare function scanEntitiesInWorker(buffer: ArrayBuffer | SharedArrayBuffer): Promise<EntityScanWorkerResult>;
29
35
  //# sourceMappingURL=scan-worker-inline.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"scan-worker-inline.d.ts","sourceRoot":"","sources":["../src/scan-worker-inline.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AAEH,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH;8DAC8D;AAC9D,eAAO,MAAM,WAAW,uqOAmOvB,CAAC;AAYF;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,WAAW,GAAG,iBAAiB,GACtC,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAsDlC"}
1
+ {"version":3,"file":"scan-worker-inline.d.ts","sourceRoot":"","sources":["../src/scan-worker-inline.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAEtD,MAAM,WAAW,qBAAqB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;mEAGmE;AACnE,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,qBAAqB,EAAE,CAAC;IAC9B,gBAAgB,EAAE,MAAM,CAAC;IACzB;;qBAEiB;IACjB,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,OAAO,EAAE,WAAW,EAAE,CAAC;AAYvB;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,WAAW,GAAG,iBAAiB,GACtC,OAAO,CAAC,sBAAsB,CAAC,CAsDjC"}
@@ -2,240 +2,14 @@
2
2
  * License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
4
  /**
5
- * Self-contained entity scanner code (runs inside Web Worker).
6
- * This is the same algorithm as StepTokenizer.scanEntitiesFast() but
7
- * written as a standalone function for worker embedding.
5
+ * Inline Web Worker for IFC entity scanning.
6
+ *
7
+ * Moves the 7-8s entity scanning off the main thread so geometry streaming
8
+ * and UI remain responsive. The scanning logic is embedded as a string (see
9
+ * `scan-worker-source.ts`) to avoid bundler/import issues with Web Workers.
8
10
  */
9
- /** Exported for direct testing (run inside a mock `self`); the runtime path
10
- * wraps it in a Blob worker via {@link getWorkerBlobUrl}. */
11
- export const WORKER_CODE = `
12
- 'use strict';
13
- self.onmessage = function(e) {
14
- var buf = new Uint8Array(e.data);
15
- var len = buf.length;
16
- var pos = 0;
17
- var line = 1;
18
-
19
- // Pre-allocate result array (estimate ~13,500 entities per MB)
20
- var estimatedCount = Math.max((len / 1024 / 1024) * 13500, 1000) | 0;
21
- // Pack results into typed arrays for fast transfer
22
- var ids = new Uint32Array(estimatedCount);
23
- var offsets = new Uint32Array(estimatedCount);
24
- var lengths = new Uint32Array(estimatedCount);
25
- var lines = new Uint32Array(estimatedCount);
26
- // Type names stored separately (strings)
27
- var types = new Array(estimatedCount);
28
- var count = 0;
29
-
30
- // Type name cache (IFC files have ~776 unique types across millions of entities)
31
- var typeCache = new Map();
32
-
33
- function growArrays() {
34
- var newSize = (count * 2) | 0;
35
- var newIds = new Uint32Array(newSize);
36
- newIds.set(ids);
37
- ids = newIds;
38
- var newOffsets = new Uint32Array(newSize);
39
- newOffsets.set(offsets);
40
- offsets = newOffsets;
41
- var newLengths = new Uint32Array(newSize);
42
- newLengths.set(lengths);
43
- lengths = newLengths;
44
- var newLines = new Uint32Array(newSize);
45
- newLines.set(lines);
46
- lines = newLines;
47
- types.length = newSize;
48
- }
49
-
50
- while (pos < len) {
51
- var ch = buf[pos];
52
-
53
- if (ch === 0x23) { // '#'
54
- var startOffset = pos;
55
- var startLine = line;
56
- pos++;
57
-
58
- // Read express ID
59
- var expressId = 0;
60
- var hasDigits = false;
61
- while (pos < len) {
62
- var c = buf[pos];
63
- if (c >= 0x30 && c <= 0x39) {
64
- expressId = expressId * 10 + (c - 0x30);
65
- hasDigits = true;
66
- pos++;
67
- } else {
68
- break;
69
- }
70
- }
71
- if (!hasDigits) continue;
72
-
73
- // Skip whitespace
74
- while (pos < len) {
75
- var c2 = buf[pos];
76
- if (c2 === 0x20 || c2 === 0x09 || c2 === 0x0D) { pos++; }
77
- else if (c2 === 0x0A) { line++; pos++; }
78
- else break;
79
- }
80
-
81
- // Check for '='
82
- if (pos >= len || buf[pos] !== 0x3D) continue;
83
- pos++;
84
-
85
- // Skip whitespace
86
- while (pos < len) {
87
- var c3 = buf[pos];
88
- if (c3 === 0x20 || c3 === 0x09 || c3 === 0x0D) { pos++; }
89
- else if (c3 === 0x0A) { line++; pos++; }
90
- else break;
91
- }
92
-
93
- // Read type name
94
- var typeStart = pos;
95
- if (pos >= len || buf[pos] < 0x41 || buf[pos] > 0x5A) continue;
96
-
97
- while (pos < len) {
98
- var c4 = buf[pos];
99
- if ((c4 >= 0x41 && c4 <= 0x5A) || (c4 >= 0x61 && c4 <= 0x7A) ||
100
- (c4 >= 0x30 && c4 <= 0x39) || c4 === 0x5F) {
101
- pos++;
102
- } else {
103
- break;
104
- }
105
- }
106
- if (pos === typeStart) continue;
107
-
108
- // Cache type name — use length + hash compound key and verify the actual
109
- // bytes on a hit. Length alone can't disambiguate a 32-bit hash collision
110
- // (e.g. "Aa"/"BB"), so without the byte compare a crafted/unlucky file
111
- // could have one type silently misread as another. Mirrors tokenizer.ts.
112
- var typeLen = pos - typeStart;
113
- var typeHash = typeLen;
114
- for (var i = typeStart; i < pos; i++) {
115
- typeHash = (typeHash * 31 + buf[i]) | 0;
116
- }
117
- var cacheKey = typeLen + ':' + typeHash;
118
- var typeName = typeCache.get(cacheKey);
119
- var cacheHitMatches = false;
120
- if (typeName !== undefined && typeName.length === typeLen) {
121
- cacheHitMatches = true;
122
- for (var v = 0; v < typeLen; v++) {
123
- if (typeName.charCodeAt(v) !== buf[typeStart + v]) {
124
- cacheHitMatches = false;
125
- break;
126
- }
127
- }
128
- }
129
- if (typeName === undefined || !cacheHitMatches) {
130
- typeName = String.fromCharCode.apply(null, buf.subarray(typeStart, pos));
131
- typeCache.set(cacheKey, typeName);
132
- }
133
-
134
- // Skip whitespace
135
- while (pos < len) {
136
- var c5 = buf[pos];
137
- if (c5 === 0x20 || c5 === 0x09 || c5 === 0x0D) { pos++; }
138
- else if (c5 === 0x0A) { line++; pos++; }
139
- else break;
140
- }
141
-
142
- // Check for '('
143
- if (pos >= len || buf[pos] !== 0x28) continue;
144
-
145
- // Skip to semicolon (handling strings)
146
- var inString = false;
147
- while (pos < len) {
148
- var c6 = buf[pos];
149
- if (c6 === 0x27) { // quote
150
- if (inString && pos + 1 < len && buf[pos + 1] === 0x27) {
151
- pos += 2;
152
- continue;
153
- }
154
- inString = !inString;
155
- } else if (c6 === 0x3B && !inString) { // semicolon
156
- var entityLength = pos - startOffset + 1;
157
-
158
- // Grow if needed
159
- if (count >= ids.length) growArrays();
160
-
161
- ids[count] = expressId;
162
- offsets[count] = startOffset;
163
- lengths[count] = entityLength;
164
- lines[count] = startLine;
165
- types[count] = typeName;
166
- count++;
167
-
168
- pos++;
169
- break;
170
- } else if (c6 === 0x0A) {
171
- line++;
172
- }
173
- pos++;
174
- }
175
- } else if (ch === 0x0A) {
176
- line++;
177
- pos++;
178
- } else if (ch === 0x27) { // quote
179
- // Consume a string literal whole. HEADER records carry no '#', so this
180
- // loop walks them byte by byte, and a '/*' inside a description would
181
- // otherwise open a comment that never closes and take DATA with it.
182
- var sp = pos + 1;
183
- while (sp < len) {
184
- if (buf[sp] === 0x27) {
185
- if (sp + 1 < len && buf[sp + 1] === 0x27) { sp += 2; continue; }
186
- sp++;
187
- break;
188
- }
189
- if (buf[sp] === 0x0A) { line++; }
190
- sp++;
191
- }
192
- pos = sp;
193
- } else if (ch === 0x2F && pos + 1 < len && buf[pos + 1] === 0x2A) {
194
- // Skip a /* */ region. A record that is commented out is still a
195
- // well-formed #id = TYPE(...), so every check above accepts it and only
196
- // skipping the region rejects it. Kept byte-identical to
197
- // step-lexing.ts, which this cannot import: the worker source is a
198
- // string, so the third copy of this loop has to carry its own copy of
199
- // the rule. Comments do not nest, per ISO 10303-21.
200
- var cp = pos + 2;
201
- var closed = false;
202
- while (cp + 1 < len) {
203
- if (buf[cp] === 0x2A && buf[cp + 1] === 0x2F) { closed = true; break; }
204
- if (buf[cp] === 0x0A) { line++; }
205
- cp++;
206
- }
207
- if (!closed) {
208
- // Unterminated: everything to EOF is commented out.
209
- pos = len;
210
- break;
211
- }
212
- pos = cp + 2;
213
- } else {
214
- pos++;
215
- }
216
- }
217
-
218
- // Trim arrays once, reuse for both message and transfer list
219
- var needsTrim = ids.buffer.byteLength > count * 4;
220
- var trimmedIds = needsTrim ? ids.slice(0, count) : ids;
221
- var trimmedOffsets = needsTrim ? offsets.slice(0, count) : offsets;
222
- var trimmedLengths = needsTrim ? lengths.slice(0, count) : lengths;
223
- var trimmedLines = needsTrim ? lines.slice(0, count) : lines;
224
- self.postMessage({
225
- ids: trimmedIds.buffer,
226
- offsets: trimmedOffsets.buffer,
227
- lengths: trimmedLengths.buffer,
228
- lines: trimmedLines.buffer,
229
- types: types.slice(0, count),
230
- count: count,
231
- }, [
232
- trimmedIds.buffer,
233
- trimmedOffsets.buffer,
234
- trimmedLengths.buffer,
235
- trimmedLines.buffer,
236
- ]);
237
- };
238
- `;
11
+ import { WORKER_CODE } from './scan-worker-source.js';
12
+ export { WORKER_CODE };
239
13
  let workerBlobUrl = null;
240
14
  function getWorkerBlobUrl() {
241
15
  if (!workerBlobUrl) {
@@ -268,7 +42,7 @@ export function scanEntitiesInWorker(buffer) {
268
42
  // checker.
269
43
  const activeWorker = worker;
270
44
  activeWorker.onmessage = (e) => {
271
- const { ids, offsets, lengths, lines, types, count } = e.data;
45
+ const { ids, offsets, lengths, lines, types, count, oversizedIds, malformedRecords } = e.data;
272
46
  const idArr = new Uint32Array(ids);
273
47
  const offsetArr = new Uint32Array(offsets);
274
48
  const lengthArr = new Uint32Array(lengths);
@@ -284,7 +58,7 @@ export function scanEntitiesInWorker(buffer) {
284
58
  };
285
59
  }
286
60
  activeWorker.terminate();
287
- resolve(refs);
61
+ resolve({ refs, oversizedIdCount: oversizedIds, malformedRecordCount: malformedRecords ?? 0 });
288
62
  };
289
63
  activeWorker.onerror = (e) => {
290
64
  activeWorker.terminate();
@@ -1 +1 @@
1
- {"version":3,"file":"scan-worker-inline.js","sourceRoot":"","sources":["../src/scan-worker-inline.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scan-worker-inline.js","sourceRoot":"","sources":["../src/scan-worker-inline.ts"],"names":[],"mappings":"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"}