@bldrs-ai/conway 1.529.1492 → 1.534.1505
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/compiled/examples/browser-bundled.cjs +19 -19
- package/compiled/examples/cli-bundled.cjs +126 -44
- package/compiled/examples/cli-step-bundled.cjs +17 -15
- package/compiled/examples/validator-bundled.cjs +19 -19
- package/compiled/src/compat/web-ifc/ifc_api_deferred_open.test.js +120 -0
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ifc.d.ts +32 -1
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ifc.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ifc.js +77 -13
- package/compiled/src/ifc/ifc_scene_builder.d.ts +80 -0
- package/compiled/src/ifc/ifc_scene_builder.d.ts.map +1 -1
- package/compiled/src/ifc/ifc_scene_builder.js +119 -28
- package/compiled/src/ifc/ifc_spatial_skeleton.d.ts +145 -0
- package/compiled/src/ifc/ifc_spatial_skeleton.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_spatial_skeleton.js +266 -0
- package/compiled/src/ifc/ifc_spatial_skeleton.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_spatial_skeleton.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_spatial_skeleton.test.js +199 -0
- package/compiled/src/ifc/ifc_stream_open.d.ts +41 -5
- package/compiled/src/ifc/ifc_stream_open.d.ts.map +1 -1
- package/compiled/src/ifc/ifc_stream_open.js +29 -2
- package/compiled/src/ifc/ifc_stream_open.test.js +26 -1
- package/compiled/src/index.d.ts +7 -3
- package/compiled/src/index.d.ts.map +1 -1
- package/compiled/src/index.js +6 -2
- package/compiled/src/namespace_surface.test.js +6 -1
- package/compiled/src/step/parsing/prefix_type_index.d.ts +124 -0
- package/compiled/src/step/parsing/prefix_type_index.d.ts.map +1 -0
- package/compiled/src/step/parsing/prefix_type_index.js +207 -0
- package/compiled/src/step/parsing/prefix_type_index.test.d.ts +2 -0
- package/compiled/src/step/parsing/prefix_type_index.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/prefix_type_index.test.js +298 -0
- package/compiled/src/step/parsing/record_event.d.ts +23 -0
- package/compiled/src/step/parsing/record_event.d.ts.map +1 -0
- package/compiled/src/step/parsing/record_event.js +1 -0
- package/compiled/src/step/parsing/record_field_cursor.d.ts +94 -0
- package/compiled/src/step/parsing/record_field_cursor.d.ts.map +1 -0
- package/compiled/src/step/parsing/record_field_cursor.js +189 -0
- package/compiled/src/step/parsing/step_parser.d.ts +9 -6
- package/compiled/src/step/parsing/step_parser.d.ts.map +1 -1
- package/compiled/src/step/parsing/step_parser.js +21 -14
- package/compiled/src/step/parsing/streaming_index_builder.d.ts +13 -5
- package/compiled/src/step/parsing/streaming_index_builder.d.ts.map +1 -1
- package/compiled/src/step/parsing/streaming_index_builder.js +9 -4
- package/compiled/src/step/parsing/streaming_record_dispatcher.d.ts +24 -8
- package/compiled/src/step/parsing/streaming_record_dispatcher.d.ts.map +1 -1
- package/compiled/src/step/parsing/streaming_record_dispatcher.js +34 -13
- package/compiled/src/stream/index.d.ts +12 -5
- package/compiled/src/stream/index.d.ts.map +1 -1
- package/compiled/src/stream/index.js +11 -4
- package/compiled/src/version/version.js +1 -1
- package/compiled/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/compiled/src/step/parsing/incremental_type_index.d.ts +0 -64
- package/compiled/src/step/parsing/incremental_type_index.d.ts.map +0 -1
- package/compiled/src/step/parsing/incremental_type_index.js +0 -92
- package/compiled/src/step/parsing/incremental_type_index.test.d.ts +0 -2
- package/compiled/src/step/parsing/incremental_type_index.test.d.ts.map +0 -1
- package/compiled/src/step/parsing/incremental_type_index.test.js +0 -55
|
@@ -30,7 +30,7 @@ var import_node_process = require("node:process");
|
|
|
30
30
|
var readline = __toESM(require("node:readline"), 1);
|
|
31
31
|
|
|
32
32
|
// compiled/src/version/version.js
|
|
33
|
-
var versionString = "Conway v1.
|
|
33
|
+
var versionString = "Conway v1.534.1505";
|
|
34
34
|
|
|
35
35
|
// compiled/dependencies/conway-geom/interface/conway_geometry.js
|
|
36
36
|
var wasmType = "";
|
|
@@ -2626,10 +2626,12 @@ var StepParser = class extends StepHeaderParser {
|
|
|
2626
2626
|
* buffer; the callback may rebase the buffer's window in place. Must be
|
|
2627
2627
|
* synchronous on this driver — a returned Promise is a caller bug.
|
|
2628
2628
|
* @param onRecordIndexed Called as each top-level record is indexed, with
|
|
2629
|
-
* its localID, expressID
|
|
2630
|
-
*
|
|
2631
|
-
*
|
|
2632
|
-
*
|
|
2629
|
+
* its localID, expressID, typeID (0 for external-mapping records) and the
|
|
2630
|
+
* record's bytes as an un-materialised `(buffer, byteOffset, byteLength)`
|
|
2631
|
+
* window view — the seam for incremental semantic consumers (type index,
|
|
2632
|
+
* roots registry, names skeleton). See {@link RecordEventHandler} for the
|
|
2633
|
+
* window-lifetime rule. Must be synchronous and cheap; expensive work
|
|
2634
|
+
* belongs on a demand queue, not the parse path.
|
|
2633
2635
|
* @param onProgress Optional byte-cursor progress callback.
|
|
2634
2636
|
* @return {BlockParseResult} The parsing result, including the index and result enum.
|
|
2635
2637
|
*/
|
|
@@ -2913,11 +2915,6 @@ var StepParser = class extends StepHeaderParser {
|
|
|
2913
2915
|
if (!charws(SEMICOLON)) {
|
|
2914
2916
|
return syntaxError();
|
|
2915
2917
|
}
|
|
2916
|
-
{
|
|
2917
|
-
const recordLen = input2.address - startElement2;
|
|
2918
|
-
onRecordIndexed?.(topLevelCount, expressID, 0, input2.buffer.subarray(input2.cursor - recordLen, input2.cursor));
|
|
2919
|
-
}
|
|
2920
|
-
++topLevelCount;
|
|
2921
2918
|
pushEntry({
|
|
2922
2919
|
address: startElement2,
|
|
2923
2920
|
length: input2.address - startElement2,
|
|
@@ -2927,6 +2924,11 @@ var StepParser = class extends StepHeaderParser {
|
|
|
2927
2924
|
inlineEntities: inlineElements,
|
|
2928
2925
|
multiMapping: multiElements
|
|
2929
2926
|
});
|
|
2927
|
+
{
|
|
2928
|
+
const recordLen = input2.address - startElement2;
|
|
2929
|
+
onRecordIndexed?.(topLevelCount, expressID, 0, input2.buffer, input2.cursor - recordLen, recordLen);
|
|
2930
|
+
}
|
|
2931
|
+
++topLevelCount;
|
|
2930
2932
|
multiElements = void 0;
|
|
2931
2933
|
continue;
|
|
2932
2934
|
}
|
|
@@ -3006,11 +3008,6 @@ var StepParser = class extends StepHeaderParser {
|
|
|
3006
3008
|
if (!charws(SEMICOLON)) {
|
|
3007
3009
|
return syntaxError();
|
|
3008
3010
|
}
|
|
3009
|
-
{
|
|
3010
|
-
const recordLen = input2.address - startElement;
|
|
3011
|
-
onRecordIndexed?.(topLevelCount, expressID, foundItem, input2.buffer.subarray(input2.cursor - recordLen, input2.cursor));
|
|
3012
|
-
}
|
|
3013
|
-
++topLevelCount;
|
|
3014
3011
|
pushEntry({
|
|
3015
3012
|
address: startElement,
|
|
3016
3013
|
length: input2.address - startElement,
|
|
@@ -3018,6 +3015,11 @@ var StepParser = class extends StepHeaderParser {
|
|
|
3018
3015
|
expressID,
|
|
3019
3016
|
inlineEntities: inlineElements
|
|
3020
3017
|
});
|
|
3018
|
+
{
|
|
3019
|
+
const recordLen = input2.address - startElement;
|
|
3020
|
+
onRecordIndexed?.(topLevelCount, expressID, foundItem, input2.buffer, input2.cursor - recordLen, recordLen);
|
|
3021
|
+
}
|
|
3022
|
+
++topLevelCount;
|
|
3021
3023
|
}
|
|
3022
3024
|
return parseResult2(ParseResult.INCOMPLETE);
|
|
3023
3025
|
}
|
|
@@ -72163,13 +72165,11 @@ async function buildIndexStreamingAsync(source, parser211, pool3, onRecordIndexe
|
|
|
72163
72165
|
};
|
|
72164
72166
|
}
|
|
72165
72167
|
}
|
|
72166
|
-
function buildColumnarIndexStreaming(source, parser211, pool3, onRecordIndexed) {
|
|
72167
|
-
const sink = new ColumnarIndexSink();
|
|
72168
|
+
function buildColumnarIndexStreaming(source, parser211, pool3, onRecordIndexed, sink = new ColumnarIndexSink()) {
|
|
72168
72169
|
const { header, result, stats } = buildIndexStreaming(source, parser211, pool3, onRecordIndexed, sink);
|
|
72169
72170
|
return { header, columns: sink.finalize(), result, stats };
|
|
72170
72171
|
}
|
|
72171
|
-
async function buildColumnarIndexStreamingAsync(source, parser211, pool3, onRecordIndexed, onProgress, yieldIntervalMs) {
|
|
72172
|
-
const sink = new ColumnarIndexSink();
|
|
72172
|
+
async function buildColumnarIndexStreamingAsync(source, parser211, pool3, onRecordIndexed, onProgress, yieldIntervalMs, sink = new ColumnarIndexSink()) {
|
|
72173
72173
|
const { header, result, stats } = await buildIndexStreamingAsync(source, parser211, pool3, onRecordIndexed, sink, onProgress, yieldIntervalMs);
|
|
72174
72174
|
return { header, columns: sink.finalize(), result, stats };
|
|
72175
72175
|
}
|
|
@@ -14965,7 +14965,7 @@ ${t5.join("\n")}` : "";
|
|
|
14965
14965
|
var import_process = require("process");
|
|
14966
14966
|
|
|
14967
14967
|
// compiled/src/version/version.js
|
|
14968
|
-
var versionString = "Conway v1.
|
|
14968
|
+
var versionString = "Conway v1.534.1505";
|
|
14969
14969
|
|
|
14970
14970
|
// compiled/dependencies/conway-geom/interface/conway_geometry.js
|
|
14971
14971
|
function pThreadsAllowed() {
|
|
@@ -18462,10 +18462,12 @@ var StepParser = class extends StepHeaderParser {
|
|
|
18462
18462
|
* buffer; the callback may rebase the buffer's window in place. Must be
|
|
18463
18463
|
* synchronous on this driver — a returned Promise is a caller bug.
|
|
18464
18464
|
* @param onRecordIndexed Called as each top-level record is indexed, with
|
|
18465
|
-
* its localID, expressID
|
|
18466
|
-
*
|
|
18467
|
-
*
|
|
18468
|
-
*
|
|
18465
|
+
* its localID, expressID, typeID (0 for external-mapping records) and the
|
|
18466
|
+
* record's bytes as an un-materialised `(buffer, byteOffset, byteLength)`
|
|
18467
|
+
* window view — the seam for incremental semantic consumers (type index,
|
|
18468
|
+
* roots registry, names skeleton). See {@link RecordEventHandler} for the
|
|
18469
|
+
* window-lifetime rule. Must be synchronous and cheap; expensive work
|
|
18470
|
+
* belongs on a demand queue, not the parse path.
|
|
18469
18471
|
* @param onProgress Optional byte-cursor progress callback.
|
|
18470
18472
|
* @return {BlockParseResult} The parsing result, including the index and result enum.
|
|
18471
18473
|
*/
|
|
@@ -18749,11 +18751,6 @@ var StepParser = class extends StepHeaderParser {
|
|
|
18749
18751
|
if (!charws(SEMICOLON)) {
|
|
18750
18752
|
return syntaxError();
|
|
18751
18753
|
}
|
|
18752
|
-
{
|
|
18753
|
-
const recordLen = input.address - startElement2;
|
|
18754
|
-
onRecordIndexed?.(topLevelCount, expressID, 0, input.buffer.subarray(input.cursor - recordLen, input.cursor));
|
|
18755
|
-
}
|
|
18756
|
-
++topLevelCount;
|
|
18757
18754
|
pushEntry({
|
|
18758
18755
|
address: startElement2,
|
|
18759
18756
|
length: input.address - startElement2,
|
|
@@ -18763,6 +18760,11 @@ var StepParser = class extends StepHeaderParser {
|
|
|
18763
18760
|
inlineEntities: inlineElements,
|
|
18764
18761
|
multiMapping: multiElements
|
|
18765
18762
|
});
|
|
18763
|
+
{
|
|
18764
|
+
const recordLen = input.address - startElement2;
|
|
18765
|
+
onRecordIndexed?.(topLevelCount, expressID, 0, input.buffer, input.cursor - recordLen, recordLen);
|
|
18766
|
+
}
|
|
18767
|
+
++topLevelCount;
|
|
18766
18768
|
multiElements = void 0;
|
|
18767
18769
|
continue;
|
|
18768
18770
|
}
|
|
@@ -18842,11 +18844,6 @@ var StepParser = class extends StepHeaderParser {
|
|
|
18842
18844
|
if (!charws(SEMICOLON)) {
|
|
18843
18845
|
return syntaxError();
|
|
18844
18846
|
}
|
|
18845
|
-
{
|
|
18846
|
-
const recordLen = input.address - startElement;
|
|
18847
|
-
onRecordIndexed?.(topLevelCount, expressID, foundItem, input.buffer.subarray(input.cursor - recordLen, input.cursor));
|
|
18848
|
-
}
|
|
18849
|
-
++topLevelCount;
|
|
18850
18847
|
pushEntry({
|
|
18851
18848
|
address: startElement,
|
|
18852
18849
|
length: input.address - startElement,
|
|
@@ -18854,6 +18851,11 @@ var StepParser = class extends StepHeaderParser {
|
|
|
18854
18851
|
expressID,
|
|
18855
18852
|
inlineEntities: inlineElements
|
|
18856
18853
|
});
|
|
18854
|
+
{
|
|
18855
|
+
const recordLen = input.address - startElement;
|
|
18856
|
+
onRecordIndexed?.(topLevelCount, expressID, foundItem, input.buffer, input.cursor - recordLen, recordLen);
|
|
18857
|
+
}
|
|
18858
|
+
++topLevelCount;
|
|
18857
18859
|
}
|
|
18858
18860
|
return parseResult(ParseResult.INCOMPLETE);
|
|
18859
18861
|
}
|
|
@@ -88131,13 +88133,11 @@ async function buildIndexStreamingAsync(source, parser210, pool3, onRecordIndexe
|
|
|
88131
88133
|
};
|
|
88132
88134
|
}
|
|
88133
88135
|
}
|
|
88134
|
-
function buildColumnarIndexStreaming(source, parser210, pool3, onRecordIndexed) {
|
|
88135
|
-
const sink = new ColumnarIndexSink();
|
|
88136
|
+
function buildColumnarIndexStreaming(source, parser210, pool3, onRecordIndexed, sink = new ColumnarIndexSink()) {
|
|
88136
88137
|
const { header, result, stats } = buildIndexStreaming(source, parser210, pool3, onRecordIndexed, sink);
|
|
88137
88138
|
return { header, columns: sink.finalize(), result, stats };
|
|
88138
88139
|
}
|
|
88139
|
-
async function buildColumnarIndexStreamingAsync(source, parser210, pool3, onRecordIndexed, onProgress, yieldIntervalMs) {
|
|
88140
|
-
const sink = new ColumnarIndexSink();
|
|
88140
|
+
async function buildColumnarIndexStreamingAsync(source, parser210, pool3, onRecordIndexed, onProgress, yieldIntervalMs, sink = new ColumnarIndexSink()) {
|
|
88141
88141
|
const { header, result, stats } = await buildIndexStreamingAsync(source, parser210, pool3, onRecordIndexed, sink, onProgress, yieldIntervalMs);
|
|
88142
88142
|
return { header, columns: sink.finalize(), result, stats };
|
|
88143
88143
|
}
|
|
@@ -88456,6 +88456,7 @@ var IfcSceneBuilder = class {
|
|
|
88456
88456
|
this.sceneLocalIdMap_ = /* @__PURE__ */ new Map();
|
|
88457
88457
|
this.geometrySet_ = /* @__PURE__ */ new Set();
|
|
88458
88458
|
this.sceneStack_ = [];
|
|
88459
|
+
this.geometryNodeVisits_ = 0;
|
|
88459
88460
|
}
|
|
88460
88461
|
/**
|
|
88461
88462
|
*
|
|
@@ -88646,37 +88647,118 @@ var IfcSceneBuilder = class {
|
|
|
88646
88647
|
isAllSpaces() {
|
|
88647
88648
|
return this.scene_.every((node) => !(node instanceof IfcSceneGeometry) || node.isSpace);
|
|
88648
88649
|
}
|
|
88650
|
+
*walk(includeSpaces = false) {
|
|
88651
|
+
for (let index = 0; index < this.scene_.length; ++index) {
|
|
88652
|
+
const resolved = this.resolveGeometryNode_(index, includeSpaces);
|
|
88653
|
+
if (resolved === void 0 || resolved[2] === void 0) {
|
|
88654
|
+
continue;
|
|
88655
|
+
}
|
|
88656
|
+
yield [resolved[0], resolved[1], resolved[2], resolved[3], resolved[4]];
|
|
88657
|
+
}
|
|
88658
|
+
}
|
|
88649
88659
|
/**
|
|
88650
|
-
*
|
|
88660
|
+
* The number of nodes in the scene array. Append-only, so a caller that
|
|
88661
|
+
* remembers this value has a stable cursor into the scene: everything
|
|
88662
|
+
* added after it sits at a higher index.
|
|
88651
88663
|
*
|
|
88652
|
-
* @
|
|
88653
|
-
* @param includeSpaces
|
|
88654
|
-
* the canonical material and the associated step element as it walks the hierarchy.
|
|
88655
|
-
* @param walkTemporary Include temporary items.
|
|
88664
|
+
* @return {number} The node count.
|
|
88656
88665
|
*/
|
|
88657
|
-
|
|
88658
|
-
|
|
88659
|
-
|
|
88660
|
-
|
|
88661
|
-
|
|
88662
|
-
|
|
88663
|
-
|
|
88664
|
-
|
|
88665
|
-
|
|
88666
|
-
|
|
88667
|
-
|
|
88668
|
-
|
|
88669
|
-
|
|
88670
|
-
|
|
88671
|
-
|
|
88672
|
-
|
|
88673
|
-
|
|
88674
|
-
|
|
88675
|
-
|
|
88676
|
-
|
|
88666
|
+
get nodeCount() {
|
|
88667
|
+
return this.scene_.length;
|
|
88668
|
+
}
|
|
88669
|
+
/**
|
|
88670
|
+
* How many times a node has been considered by any walk form since this
|
|
88671
|
+
* scene was built.
|
|
88672
|
+
*
|
|
88673
|
+
* Exists so the *complexity* of an incremental consumer can be asserted
|
|
88674
|
+
* rather than timed: a capture that walks only what the scene gained
|
|
88675
|
+
* visits each node about once for the whole load, where one that
|
|
88676
|
+
* re-walks from zero visits every node once per call. Output parity
|
|
88677
|
+
* cannot distinguish those — both deliver the same meshes — so without
|
|
88678
|
+
* this a regression from O(new nodes) back to O(batches x scene) passes
|
|
88679
|
+
* every correctness test while restoring the cost. See the batch-size
|
|
88680
|
+
* invariance test in ifc_api_deferred_open.test.ts.
|
|
88681
|
+
*
|
|
88682
|
+
* @return {number} The visit count.
|
|
88683
|
+
*/
|
|
88684
|
+
get geometryNodeVisits() {
|
|
88685
|
+
return this.geometryNodeVisits_;
|
|
88686
|
+
}
|
|
88687
|
+
/**
|
|
88688
|
+
* Walk only the nodes added at or after `startIndex` — the incremental
|
|
88689
|
+
* form of {@link walk}, for a consumer draining the scene in batches.
|
|
88690
|
+
*
|
|
88691
|
+
* Unlike `walk`, this yields nodes whose geometry does NOT resolve, with
|
|
88692
|
+
* `undefined` in the geometry slot and the node's index last. That is
|
|
88693
|
+
* deliberate: a cursor-based caller passes each index exactly once, so a
|
|
88694
|
+
* node skipped for missing geometry would be lost forever, where the
|
|
88695
|
+
* whole-scene walk would have picked it up on its next pass. Geometry can
|
|
88696
|
+
* appear late — a product that maps geometry a release freed re-extracts
|
|
88697
|
+
* it — so the caller must park those indices and retry them with
|
|
88698
|
+
* {@link walkNode}. Yielding them is what makes that possible.
|
|
88699
|
+
*
|
|
88700
|
+
* @param startIndex First node index to consider.
|
|
88701
|
+
* @param includeSpaces Include space geometry.
|
|
88702
|
+
* @yields The walk tuple plus the node's index.
|
|
88703
|
+
*/
|
|
88704
|
+
*walkFrom(startIndex, includeSpaces = false) {
|
|
88705
|
+
for (let index = startIndex; index < this.scene_.length; ++index) {
|
|
88706
|
+
const resolved = this.resolveGeometryNode_(index, includeSpaces);
|
|
88707
|
+
if (resolved === void 0) {
|
|
88708
|
+
continue;
|
|
88677
88709
|
}
|
|
88710
|
+
yield resolved;
|
|
88678
88711
|
}
|
|
88679
88712
|
}
|
|
88713
|
+
/**
|
|
88714
|
+
* Resolve one node by index, for retrying a node {@link walkFrom} yielded
|
|
88715
|
+
* without geometry.
|
|
88716
|
+
*
|
|
88717
|
+
* @param index The node's index in the scene array.
|
|
88718
|
+
* @param includeSpaces Include space geometry.
|
|
88719
|
+
* @return {[...]|undefined} The walk tuple plus the index, or undefined
|
|
88720
|
+
* when the node isn't geometry this walk covers.
|
|
88721
|
+
*/
|
|
88722
|
+
walkNode(index, includeSpaces = false) {
|
|
88723
|
+
return this.resolveGeometryNode_(index, includeSpaces);
|
|
88724
|
+
}
|
|
88725
|
+
/**
|
|
88726
|
+
* The shared body of walk/walkFrom/walkNode: one node in, one walk tuple
|
|
88727
|
+
* out. Single-sourced so the incremental walk cannot drift from the whole
|
|
88728
|
+
* -scene one — a drift here would show up as geometry placed differently
|
|
88729
|
+
* depending on batch size.
|
|
88730
|
+
*
|
|
88731
|
+
* @param index The node's index in the scene array.
|
|
88732
|
+
* @param includeSpaces Include space geometry.
|
|
88733
|
+
* @return {[...]|undefined} Undefined when the node isn't a geometry node
|
|
88734
|
+
* this walk covers; otherwise the tuple, whose geometry slot is undefined
|
|
88735
|
+
* if the geometry doesn't currently resolve.
|
|
88736
|
+
*/
|
|
88737
|
+
resolveGeometryNode_(index, includeSpaces) {
|
|
88738
|
+
++this.geometryNodeVisits_;
|
|
88739
|
+
const node = this.scene_[index];
|
|
88740
|
+
if (!(node instanceof IfcSceneGeometry) || !includeSpaces && node.isSpace) {
|
|
88741
|
+
return void 0;
|
|
88742
|
+
}
|
|
88743
|
+
const geometry = node.model.geometry?.getByLocalID(node.localID);
|
|
88744
|
+
if (geometry === void 0) {
|
|
88745
|
+
return [void 0, void 0, void 0, void 0, void 0, index];
|
|
88746
|
+
}
|
|
88747
|
+
const parentIndex = node.parentIndex;
|
|
88748
|
+
let parentNode;
|
|
88749
|
+
if (parentIndex !== void 0) {
|
|
88750
|
+
parentNode = this.scene_[parentIndex];
|
|
88751
|
+
}
|
|
88752
|
+
const material = this.materials.getMaterialByGeometryID(node.materialOverideLocalID ?? geometry.localID);
|
|
88753
|
+
return [
|
|
88754
|
+
parentNode?.absoluteTransform,
|
|
88755
|
+
parentNode?.absoluteNativeTransform,
|
|
88756
|
+
geometry,
|
|
88757
|
+
material !== void 0 ? material[0] : void 0,
|
|
88758
|
+
node.relatedElementLocalId !== void 0 ? this.model.getElementByLocalID(node.relatedElementLocalId) : void 0,
|
|
88759
|
+
index
|
|
88760
|
+
];
|
|
88761
|
+
}
|
|
88680
88762
|
/**
|
|
88681
88763
|
*
|
|
88682
88764
|
*/
|
|
@@ -15943,7 +15943,7 @@ var ParsingBuffer = class {
|
|
|
15943
15943
|
};
|
|
15944
15944
|
|
|
15945
15945
|
// compiled/src/version/version.js
|
|
15946
|
-
var versionString = "Conway v1.
|
|
15946
|
+
var versionString = "Conway v1.534.1505";
|
|
15947
15947
|
|
|
15948
15948
|
// compiled/dependencies/conway-geom/interface/conway_geometry.js
|
|
15949
15949
|
function pThreadsAllowed() {
|
|
@@ -18365,10 +18365,12 @@ var StepParser = class extends StepHeaderParser {
|
|
|
18365
18365
|
* buffer; the callback may rebase the buffer's window in place. Must be
|
|
18366
18366
|
* synchronous on this driver — a returned Promise is a caller bug.
|
|
18367
18367
|
* @param onRecordIndexed Called as each top-level record is indexed, with
|
|
18368
|
-
* its localID, expressID
|
|
18369
|
-
*
|
|
18370
|
-
*
|
|
18371
|
-
*
|
|
18368
|
+
* its localID, expressID, typeID (0 for external-mapping records) and the
|
|
18369
|
+
* record's bytes as an un-materialised `(buffer, byteOffset, byteLength)`
|
|
18370
|
+
* window view — the seam for incremental semantic consumers (type index,
|
|
18371
|
+
* roots registry, names skeleton). See {@link RecordEventHandler} for the
|
|
18372
|
+
* window-lifetime rule. Must be synchronous and cheap; expensive work
|
|
18373
|
+
* belongs on a demand queue, not the parse path.
|
|
18372
18374
|
* @param onProgress Optional byte-cursor progress callback.
|
|
18373
18375
|
* @return {BlockParseResult} The parsing result, including the index and result enum.
|
|
18374
18376
|
*/
|
|
@@ -18652,11 +18654,6 @@ var StepParser = class extends StepHeaderParser {
|
|
|
18652
18654
|
if (!charws(SEMICOLON)) {
|
|
18653
18655
|
return syntaxError();
|
|
18654
18656
|
}
|
|
18655
|
-
{
|
|
18656
|
-
const recordLen = input.address - startElement2;
|
|
18657
|
-
onRecordIndexed?.(topLevelCount, expressID, 0, input.buffer.subarray(input.cursor - recordLen, input.cursor));
|
|
18658
|
-
}
|
|
18659
|
-
++topLevelCount;
|
|
18660
18657
|
pushEntry({
|
|
18661
18658
|
address: startElement2,
|
|
18662
18659
|
length: input.address - startElement2,
|
|
@@ -18666,6 +18663,11 @@ var StepParser = class extends StepHeaderParser {
|
|
|
18666
18663
|
inlineEntities: inlineElements,
|
|
18667
18664
|
multiMapping: multiElements
|
|
18668
18665
|
});
|
|
18666
|
+
{
|
|
18667
|
+
const recordLen = input.address - startElement2;
|
|
18668
|
+
onRecordIndexed?.(topLevelCount, expressID, 0, input.buffer, input.cursor - recordLen, recordLen);
|
|
18669
|
+
}
|
|
18670
|
+
++topLevelCount;
|
|
18669
18671
|
multiElements = void 0;
|
|
18670
18672
|
continue;
|
|
18671
18673
|
}
|
|
@@ -18745,11 +18747,6 @@ var StepParser = class extends StepHeaderParser {
|
|
|
18745
18747
|
if (!charws(SEMICOLON)) {
|
|
18746
18748
|
return syntaxError();
|
|
18747
18749
|
}
|
|
18748
|
-
{
|
|
18749
|
-
const recordLen = input.address - startElement;
|
|
18750
|
-
onRecordIndexed?.(topLevelCount, expressID, foundItem, input.buffer.subarray(input.cursor - recordLen, input.cursor));
|
|
18751
|
-
}
|
|
18752
|
-
++topLevelCount;
|
|
18753
18750
|
pushEntry({
|
|
18754
18751
|
address: startElement,
|
|
18755
18752
|
length: input.address - startElement,
|
|
@@ -18757,6 +18754,11 @@ var StepParser = class extends StepHeaderParser {
|
|
|
18757
18754
|
expressID,
|
|
18758
18755
|
inlineEntities: inlineElements
|
|
18759
18756
|
});
|
|
18757
|
+
{
|
|
18758
|
+
const recordLen = input.address - startElement;
|
|
18759
|
+
onRecordIndexed?.(topLevelCount, expressID, foundItem, input.buffer, input.cursor - recordLen, recordLen);
|
|
18760
|
+
}
|
|
18761
|
+
++topLevelCount;
|
|
18760
18762
|
}
|
|
18761
18763
|
return parseResult(ParseResult.INCOMPLETE);
|
|
18762
18764
|
}
|
|
@@ -944,7 +944,7 @@ var EntityTypesIfcCount = 909;
|
|
|
944
944
|
var entity_types_ifc_gen_default = EntityTypesIfc;
|
|
945
945
|
|
|
946
946
|
// compiled/src/version/version.js
|
|
947
|
-
var versionString = "Conway v1.
|
|
947
|
+
var versionString = "Conway v1.534.1505";
|
|
948
948
|
|
|
949
949
|
// compiled/dependencies/conway-geom/interface/conway_geometry.js
|
|
950
950
|
var wasmType = "";
|
|
@@ -3540,10 +3540,12 @@ var StepParser = class extends StepHeaderParser {
|
|
|
3540
3540
|
* buffer; the callback may rebase the buffer's window in place. Must be
|
|
3541
3541
|
* synchronous on this driver — a returned Promise is a caller bug.
|
|
3542
3542
|
* @param onRecordIndexed Called as each top-level record is indexed, with
|
|
3543
|
-
* its localID, expressID
|
|
3544
|
-
*
|
|
3545
|
-
*
|
|
3546
|
-
*
|
|
3543
|
+
* its localID, expressID, typeID (0 for external-mapping records) and the
|
|
3544
|
+
* record's bytes as an un-materialised `(buffer, byteOffset, byteLength)`
|
|
3545
|
+
* window view — the seam for incremental semantic consumers (type index,
|
|
3546
|
+
* roots registry, names skeleton). See {@link RecordEventHandler} for the
|
|
3547
|
+
* window-lifetime rule. Must be synchronous and cheap; expensive work
|
|
3548
|
+
* belongs on a demand queue, not the parse path.
|
|
3547
3549
|
* @param onProgress Optional byte-cursor progress callback.
|
|
3548
3550
|
* @return {BlockParseResult} The parsing result, including the index and result enum.
|
|
3549
3551
|
*/
|
|
@@ -3827,11 +3829,6 @@ var StepParser = class extends StepHeaderParser {
|
|
|
3827
3829
|
if (!charws(SEMICOLON)) {
|
|
3828
3830
|
return syntaxError();
|
|
3829
3831
|
}
|
|
3830
|
-
{
|
|
3831
|
-
const recordLen = input.address - startElement2;
|
|
3832
|
-
onRecordIndexed?.(topLevelCount, expressID, 0, input.buffer.subarray(input.cursor - recordLen, input.cursor));
|
|
3833
|
-
}
|
|
3834
|
-
++topLevelCount;
|
|
3835
3832
|
pushEntry({
|
|
3836
3833
|
address: startElement2,
|
|
3837
3834
|
length: input.address - startElement2,
|
|
@@ -3841,6 +3838,11 @@ var StepParser = class extends StepHeaderParser {
|
|
|
3841
3838
|
inlineEntities: inlineElements,
|
|
3842
3839
|
multiMapping: multiElements
|
|
3843
3840
|
});
|
|
3841
|
+
{
|
|
3842
|
+
const recordLen = input.address - startElement2;
|
|
3843
|
+
onRecordIndexed?.(topLevelCount, expressID, 0, input.buffer, input.cursor - recordLen, recordLen);
|
|
3844
|
+
}
|
|
3845
|
+
++topLevelCount;
|
|
3844
3846
|
multiElements = void 0;
|
|
3845
3847
|
continue;
|
|
3846
3848
|
}
|
|
@@ -3920,11 +3922,6 @@ var StepParser = class extends StepHeaderParser {
|
|
|
3920
3922
|
if (!charws(SEMICOLON)) {
|
|
3921
3923
|
return syntaxError();
|
|
3922
3924
|
}
|
|
3923
|
-
{
|
|
3924
|
-
const recordLen = input.address - startElement;
|
|
3925
|
-
onRecordIndexed?.(topLevelCount, expressID, foundItem, input.buffer.subarray(input.cursor - recordLen, input.cursor));
|
|
3926
|
-
}
|
|
3927
|
-
++topLevelCount;
|
|
3928
3925
|
pushEntry({
|
|
3929
3926
|
address: startElement,
|
|
3930
3927
|
length: input.address - startElement,
|
|
@@ -3932,6 +3929,11 @@ var StepParser = class extends StepHeaderParser {
|
|
|
3932
3929
|
expressID,
|
|
3933
3930
|
inlineEntities: inlineElements
|
|
3934
3931
|
});
|
|
3932
|
+
{
|
|
3933
|
+
const recordLen = input.address - startElement;
|
|
3934
|
+
onRecordIndexed?.(topLevelCount, expressID, foundItem, input.buffer, input.cursor - recordLen, recordLen);
|
|
3935
|
+
}
|
|
3936
|
+
++topLevelCount;
|
|
3935
3937
|
}
|
|
3936
3938
|
return parseResult2(ParseResult.INCOMPLETE);
|
|
3937
3939
|
}
|
|
@@ -72161,13 +72163,11 @@ async function buildIndexStreamingAsync(source, parser211, pool3, onRecordIndexe
|
|
|
72161
72163
|
};
|
|
72162
72164
|
}
|
|
72163
72165
|
}
|
|
72164
|
-
function buildColumnarIndexStreaming(source, parser211, pool3, onRecordIndexed) {
|
|
72165
|
-
const sink = new ColumnarIndexSink();
|
|
72166
|
+
function buildColumnarIndexStreaming(source, parser211, pool3, onRecordIndexed, sink = new ColumnarIndexSink()) {
|
|
72166
72167
|
const { header, result, stats } = buildIndexStreaming(source, parser211, pool3, onRecordIndexed, sink);
|
|
72167
72168
|
return { header, columns: sink.finalize(), result, stats };
|
|
72168
72169
|
}
|
|
72169
|
-
async function buildColumnarIndexStreamingAsync(source, parser211, pool3, onRecordIndexed, onProgress, yieldIntervalMs) {
|
|
72170
|
-
const sink = new ColumnarIndexSink();
|
|
72170
|
+
async function buildColumnarIndexStreamingAsync(source, parser211, pool3, onRecordIndexed, onProgress, yieldIntervalMs, sink = new ColumnarIndexSink()) {
|
|
72171
72171
|
const { header, result, stats } = await buildIndexStreamingAsync(source, parser211, pool3, onRecordIndexed, sink, onProgress, yieldIntervalMs);
|
|
72172
72172
|
return { header, columns: sink.finalize(), result, stats };
|
|
72173
72173
|
}
|
|
@@ -277,6 +277,126 @@ describe("OpenModelStreamed + DEFER_GEOMETRY", () => {
|
|
|
277
277
|
api4.CloseModel(classicID);
|
|
278
278
|
api4.CloseModel(deferredID);
|
|
279
279
|
}, 240000);
|
|
280
|
+
test("shared representation survives a batch boundary, emitted once", async () => {
|
|
281
|
+
// data/mapped_shared_representation.ifc: one IfcRepresentationMap
|
|
282
|
+
// mapped by two products 15 products apart, so a batch size of 4
|
|
283
|
+
// guarantees they land in DIFFERENT batches. The smoke corpus cannot
|
|
284
|
+
// produce this shape — there every sharer of a definition falls
|
|
285
|
+
// inside one batch — so this is the only fixture that exercises the
|
|
286
|
+
// delta capture across a boundary where geometry is shared.
|
|
287
|
+
//
|
|
288
|
+
// It pins the cursor capture from both directions. Lose a parked or
|
|
289
|
+
// suffix node and the second mapped product goes missing; re-emit a
|
|
290
|
+
// node the cursor should have passed (the failure a reverted cursor
|
|
291
|
+
// or a broken watermark produces) and instances duplicate. Both show
|
|
292
|
+
// up as an instance-count mismatch against classic, which is why the
|
|
293
|
+
// comparison is against classic rather than a hard-coded number.
|
|
294
|
+
const api5 = new IfcAPI();
|
|
295
|
+
await api5.Init();
|
|
296
|
+
const fixture = new Uint8Array(fs.readFileSync("data/mapped_shared_representation.ifc"));
|
|
297
|
+
const classicID = api5.OpenModel(fixture, SETTINGS);
|
|
298
|
+
const classicPlacements = [];
|
|
299
|
+
api5.StreamAllMeshes(classicID, (mesh) => {
|
|
300
|
+
for (let where = 0; where < mesh.geometries.size(); ++where) {
|
|
301
|
+
const placed = mesh.geometries.get(where);
|
|
302
|
+
classicPlacements.push(`${placed.geometryExpressID}@${[...placed.flatTransformation]
|
|
303
|
+
.map((value) => value.toFixed(3)).join(",")}`);
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
const deferredID = await api5.OpenModelStreamed(fixture, { ...SETTINGS, DEFER_GEOMETRY: true });
|
|
307
|
+
const pumpedPlacements = [];
|
|
308
|
+
let batches = 0;
|
|
309
|
+
for (;;) {
|
|
310
|
+
const { extracted, remaining } = api5.ExtractGeometryBatch(deferredID, 4, (mesh) => {
|
|
311
|
+
for (let where = 0; where < mesh.geometries.size(); ++where) {
|
|
312
|
+
const placed = mesh.geometries.get(where);
|
|
313
|
+
pumpedPlacements.push(`${placed.geometryExpressID}@${[...placed.flatTransformation]
|
|
314
|
+
.map((value) => value.toFixed(3)).join(",")}`);
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
++batches;
|
|
318
|
+
if (remaining === 0 && extracted === 0) {
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
// The boundary the fixture exists to create: with 16 products at
|
|
323
|
+
// batch 4, the two sharers cannot be in the same batch.
|
|
324
|
+
expect(batches).toBeGreaterThan(2);
|
|
325
|
+
// Exact multiset equality — placement included, so an instance
|
|
326
|
+
// delivered at the wrong location fails as loudly as a missing one.
|
|
327
|
+
expect(pumpedPlacements.slice().sort())
|
|
328
|
+
.toEqual(classicPlacements.slice().sort());
|
|
329
|
+
// Emitted once each: a duplicate would survive the multiset check
|
|
330
|
+
// only if classic duplicated too, but state it directly since
|
|
331
|
+
// re-emission is the specific failure a broken cursor produces.
|
|
332
|
+
expect(new Set(pumpedPlacements).size).toBe(pumpedPlacements.length);
|
|
333
|
+
// Both users of the shared map are present, at their own placements
|
|
334
|
+
// — the shared SOURCE geometry appears under two distinct transforms.
|
|
335
|
+
const mappedTransforms = new Set(pumpedPlacements.map((entry) => entry.split("@")[1]));
|
|
336
|
+
expect(mappedTransforms.size).toBe(pumpedPlacements.length);
|
|
337
|
+
api5.CloseModel(classicID);
|
|
338
|
+
api5.CloseModel(deferredID);
|
|
339
|
+
}, 240000);
|
|
340
|
+
test("delta capture visits each scene node once, whatever the batch size", async () => {
|
|
341
|
+
// Output parity cannot see this. The whole-scene walk this replaced
|
|
342
|
+
// delivered exactly the same meshes; what changed is the COST of
|
|
343
|
+
// delivering them — it re-resolved every node on every call, so the
|
|
344
|
+
// capture was O(batches x scene). A revert would pass every
|
|
345
|
+
// correctness assertion in this file while restoring the 1.47-2.97x
|
|
346
|
+
// regression the PR description measures, so the complexity gets an
|
|
347
|
+
// assertion of its own.
|
|
348
|
+
//
|
|
349
|
+
// Counting node visits rather than timing: deterministic, and it
|
|
350
|
+
// fails the same way on a fast machine as a slow one.
|
|
351
|
+
const api6 = new IfcAPI();
|
|
352
|
+
await api6.Init();
|
|
353
|
+
const fixture = new Uint8Array(fs.readFileSync("data/mapped_shared_representation.ifc"));
|
|
354
|
+
/**
|
|
355
|
+
* Pump a fresh deferred model to completion and report how much
|
|
356
|
+
* scene walking it took.
|
|
357
|
+
*
|
|
358
|
+
* @param batchSize Products per ExtractGeometryBatch call.
|
|
359
|
+
* @return {Promise<{visits: number, nodes: number, batches: number}>}
|
|
360
|
+
* Node visits, final scene size, and calls taken.
|
|
361
|
+
*/
|
|
362
|
+
async function pump(batchSize) {
|
|
363
|
+
const modelID = await api6.OpenModelStreamed(fixture, { ...SETTINGS, DEFER_GEOMETRY: true });
|
|
364
|
+
let batches = 0;
|
|
365
|
+
for (;;) {
|
|
366
|
+
const { extracted, remaining } = api6.ExtractGeometryBatch(modelID, batchSize, () => { });
|
|
367
|
+
++batches;
|
|
368
|
+
if (remaining === 0 && extracted === 0) {
|
|
369
|
+
break;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
const scene = api6.getPassthrough(modelID)
|
|
373
|
+
.model[1];
|
|
374
|
+
// A revert that drops the counter along with the cursor would
|
|
375
|
+
// otherwise fail as `expected undefined to be less than 68`, which
|
|
376
|
+
// reads like a broken test rather than the regression it is.
|
|
377
|
+
expect(typeof scene?.geometryNodeVisits)
|
|
378
|
+
.toBe("number");
|
|
379
|
+
const measured = { visits: scene.geometryNodeVisits, nodes: scene.nodeCount, batches };
|
|
380
|
+
api6.CloseModel(modelID);
|
|
381
|
+
return measured;
|
|
382
|
+
}
|
|
383
|
+
const oneAtATime = await pump(1);
|
|
384
|
+
const allAtOnce = await pump(64);
|
|
385
|
+
// The fixture is 16 products, so batch 1 really does take many calls
|
|
386
|
+
// — otherwise this asserts nothing.
|
|
387
|
+
expect(oneAtATime.batches).toBeGreaterThan(8);
|
|
388
|
+
expect(allAtOnce.batches).toBeLessThan(oneAtATime.batches);
|
|
389
|
+
// The invariant: total walking is a property of the SCENE, not of how
|
|
390
|
+
// many calls drained it. Allowing 2x the node count leaves room for
|
|
391
|
+
// the whole-model drain's own pass and for parked-node retries
|
|
392
|
+
// (DEMAND_PARKED_NODE_RETRIES each, and nothing in this corpus parks
|
|
393
|
+
// a node at all), while a per-call re-walk would land near
|
|
394
|
+
// batches x nodes — an order of magnitude clear of the bound.
|
|
395
|
+
expect(oneAtATime.visits).toBeLessThan(oneAtATime.nodes * 2);
|
|
396
|
+
// And it must not grow when the batch shrinks, which is the specific
|
|
397
|
+
// shape of the regression: same scene, ~16x the calls, same work.
|
|
398
|
+
expect(oneAtATime.visits).toBeLessThan(allAtOnce.visits * 2);
|
|
399
|
+
}, 240000);
|
|
280
400
|
test("ExtractGeometryBatch is a safe no-op on non-deferred models", async () => {
|
|
281
401
|
const modelID = await api.OpenModelStreamed(buffer, SETTINGS);
|
|
282
402
|
expect(api.ExtractGeometryBatch(modelID, 8))
|
|
@@ -75,7 +75,38 @@ export declare class IfcApiProxyIfc implements IfcApiModelPassthrough {
|
|
|
75
75
|
* batches - the watermark makes each instance captured exactly once,
|
|
76
76
|
* in the same order the classic single walk would process it.
|
|
77
77
|
*/
|
|
78
|
-
|
|
78
|
+
/**
|
|
79
|
+
* How much of the scene array the delta capture has consumed. The scene
|
|
80
|
+
* is append-only, so this is a stable cursor: everything a batch adds
|
|
81
|
+
* sits above it. Replaces the per-entity walk watermark this used to
|
|
82
|
+
* keep, which existed only because the capture restarted its walk from
|
|
83
|
+
* zero every batch — an O(batches x scene) cost that dominated on
|
|
84
|
+
* instance-dense models (D3D: 562k instances, 1182 batches at size 64).
|
|
85
|
+
*/
|
|
86
|
+
private demandSceneCursor_;
|
|
87
|
+
/**
|
|
88
|
+
* Node indices walkFrom yielded without resolvable geometry, against the
|
|
89
|
+
* number of times a later capture has re-checked them. Parked because a
|
|
90
|
+
* cursor passes each index once, where the whole-scene walk this replaced
|
|
91
|
+
* re-checked every node on every call. See IfcSceneBuilder.walkFrom.
|
|
92
|
+
*
|
|
93
|
+
* Bounded by DEMAND_PARKED_NODE_RETRIES because not every unresolved node
|
|
94
|
+
* is waiting on something: extraction can append a scene node and then
|
|
95
|
+
* fail to cache geometry for it (extractSweptDiskSolid returns early on a
|
|
96
|
+
* failed directrix; extractRepresentationItem still calls addGeometry),
|
|
97
|
+
* and no amount of re-checking makes a deterministic failure resolve.
|
|
98
|
+
* Retrying those forever would be O(batches x unresolvable) — still under
|
|
99
|
+
* the O(batches x scene) this replaced, but unbounded in batch count for
|
|
100
|
+
* no benefit. Expiring after a fixed number of attempts makes the total
|
|
101
|
+
* retry work O(retries x unresolvable) regardless of batch size.
|
|
102
|
+
*
|
|
103
|
+
* Measured at zero on every model available here — the 12-model smoke
|
|
104
|
+
* corpus, PSB, and D3D (which logs exactly the malformed-geometry errors
|
|
105
|
+
* that produce this case) all park nothing — so this path is a
|
|
106
|
+
* correctness guard rather than a hot path, and its constant is chosen to
|
|
107
|
+
* be generous rather than tuned.
|
|
108
|
+
*/
|
|
109
|
+
private readonly demandPendingNodes_;
|
|
79
110
|
/** Cursor into demandProducts_ — products before it are extracted. */
|
|
80
111
|
private demandCursor_;
|
|
81
112
|
/** Wall-clock split of the store-backed batch pump (profile script). */
|