@bldrs-ai/conway 1.509.1435 → 1.511.1441
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 +410 -16
- package/compiled/examples/cli-bundled.cjs +544 -18
- package/compiled/examples/cli-step-bundled.cjs +312 -16
- package/compiled/examples/validator-bundled.cjs +410 -16
- package/compiled/src/compat/web-ifc/ifc_api.d.ts +33 -0
- package/compiled/src/compat/web-ifc/ifc_api.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ifc_api.js +47 -0
- package/compiled/src/compat/web-ifc/ifc_api_deferred_open.test.js +29 -0
- package/compiled/src/compat/web-ifc/ifc_api_model_passthrough.d.ts +8 -0
- package/compiled/src/compat/web-ifc/ifc_api_model_passthrough.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ifc_api_model_passthrough_factory.d.ts +14 -0
- package/compiled/src/compat/web-ifc/ifc_api_model_passthrough_factory.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ifc_api_model_passthrough_factory.js +33 -0
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ap214.d.ts +7 -0
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ap214.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ap214.js +16 -0
- package/compiled/src/compat/web-ifc/ifc_api_proxy_ifc.d.ts +64 -0
- 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 +293 -30
- package/compiled/src/compat/web-ifc/ifc_api_streamed_open.test.js +29 -0
- package/compiled/src/ifc/ifc_demand_extraction.test.js +12 -1
- package/compiled/src/ifc/ifc_geometry_extraction.d.ts +35 -0
- package/compiled/src/ifc/ifc_geometry_extraction.d.ts.map +1 -1
- package/compiled/src/ifc/ifc_geometry_extraction.js +142 -2
- package/compiled/src/ifc/ifc_step_parser.d.ts +23 -1
- package/compiled/src/ifc/ifc_step_parser.d.ts.map +1 -1
- package/compiled/src/ifc/ifc_step_parser.js +23 -1
- package/compiled/src/ifc/ifc_stream_open.d.ts +28 -1
- package/compiled/src/ifc/ifc_stream_open.d.ts.map +1 -1
- package/compiled/src/ifc/ifc_stream_open.js +44 -1
- package/compiled/src/ifc/ifc_stream_open.test.js +10 -1
- package/compiled/src/index.d.ts +3 -2
- package/compiled/src/index.d.ts.map +1 -1
- package/compiled/src/index.js +3 -2
- package/compiled/src/namespace_surface.test.js +3 -0
- package/compiled/src/step/parsing/byte_source.d.ts +98 -0
- package/compiled/src/step/parsing/byte_source.d.ts.map +1 -1
- package/compiled/src/step/parsing/byte_source.js +71 -0
- package/compiled/src/step/parsing/byte_source.test.d.ts +2 -0
- package/compiled/src/step/parsing/byte_source.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/byte_source.test.js +47 -0
- package/compiled/src/step/parsing/byte_source_node.d.ts +41 -0
- package/compiled/src/step/parsing/byte_source_node.d.ts.map +1 -0
- package/compiled/src/step/parsing/byte_source_node.js +54 -0
- package/compiled/src/step/parsing/express_ref_scan.d.ts +20 -0
- package/compiled/src/step/parsing/express_ref_scan.d.ts.map +1 -0
- package/compiled/src/step/parsing/express_ref_scan.js +91 -0
- package/compiled/src/step/parsing/express_ref_scan.test.d.ts +2 -0
- package/compiled/src/step/parsing/express_ref_scan.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/express_ref_scan.test.js +28 -0
- package/compiled/src/step/parsing/step_parser.d.ts +7 -4
- package/compiled/src/step/parsing/step_parser.d.ts.map +1 -1
- package/compiled/src/step/parsing/step_parser.js +25 -6
- package/compiled/src/step/parsing/streaming_index_builder.d.ts +3 -3
- package/compiled/src/step/parsing/streaming_index_builder.d.ts.map +1 -1
- package/compiled/src/step/parsing/streaming_index_builder.js +27 -7
- package/compiled/src/step/parsing/streaming_index_builder_async.test.js +13 -1
- package/compiled/src/step/step_buffer_provider.d.ts +44 -0
- package/compiled/src/step/step_buffer_provider.d.ts.map +1 -1
- package/compiled/src/step/step_buffer_provider.js +56 -8
- package/compiled/src/step/step_buffer_provider.test.js +14 -0
- package/compiled/src/step/step_entity_base.d.ts +15 -0
- package/compiled/src/step/step_entity_base.d.ts.map +1 -1
- package/compiled/src/step/step_entity_base.js +33 -0
- package/compiled/src/step/step_model_base.d.ts +62 -0
- package/compiled/src/step/step_model_base.d.ts.map +1 -1
- package/compiled/src/step/step_model_base.js +136 -0
- package/compiled/src/stream/index.d.ts +3 -2
- package/compiled/src/stream/index.d.ts.map +1 -1
- package/compiled/src/stream/index.js +3 -2
- package/compiled/src/version/version.js +1 -1
- package/compiled/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -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.511.1441";
|
|
14969
14969
|
|
|
14970
14970
|
// compiled/dependencies/conway-geom/interface/conway_geometry.js
|
|
14971
14971
|
function pThreadsAllowed() {
|
|
@@ -18440,7 +18440,9 @@ var StepParser = class extends StepHeaderParser {
|
|
|
18440
18440
|
if (next.done === true) {
|
|
18441
18441
|
return next.value;
|
|
18442
18442
|
}
|
|
18443
|
-
|
|
18443
|
+
if (typeof next.value === "number") {
|
|
18444
|
+
onProgress?.(next.value);
|
|
18445
|
+
}
|
|
18444
18446
|
}
|
|
18445
18447
|
}
|
|
18446
18448
|
/**
|
|
@@ -18452,7 +18454,8 @@ var StepParser = class extends StepHeaderParser {
|
|
|
18452
18454
|
*
|
|
18453
18455
|
* @param input The input parsing buffer, positioned at the data section.
|
|
18454
18456
|
* @param onRecordBoundary Called at each top-level record boundary with the
|
|
18455
|
-
* buffer; the callback may rebase the buffer's window in place.
|
|
18457
|
+
* buffer; the callback may rebase the buffer's window in place. Must be
|
|
18458
|
+
* synchronous on this driver — a returned Promise is a caller bug.
|
|
18456
18459
|
* @param onRecordIndexed Called as each top-level record is indexed, with
|
|
18457
18460
|
* its localID, expressID and typeID (0 for external-mapping records) — the
|
|
18458
18461
|
* seam for incremental semantic consumers (type index, roots registry,
|
|
@@ -18468,6 +18471,9 @@ var StepParser = class extends StepHeaderParser {
|
|
|
18468
18471
|
if (next.done === true) {
|
|
18469
18472
|
return next.value;
|
|
18470
18473
|
}
|
|
18474
|
+
if (typeof next.value !== "number") {
|
|
18475
|
+
throw new Error("parseDataBlockStreamed: async window slide requires parseDataBlockStreamedAsync");
|
|
18476
|
+
}
|
|
18471
18477
|
onProgress?.(next.value);
|
|
18472
18478
|
}
|
|
18473
18479
|
}
|
|
@@ -18480,7 +18486,9 @@ var StepParser = class extends StepHeaderParser {
|
|
|
18480
18486
|
*
|
|
18481
18487
|
* @param input The input parsing buffer, positioned at the data section.
|
|
18482
18488
|
* @param onRecordBoundary Called at each top-level record boundary with the
|
|
18483
|
-
* buffer; the callback may rebase the buffer's window in place.
|
|
18489
|
+
* buffer; the callback may rebase the buffer's window in place. May return
|
|
18490
|
+
* a Promise when the slide itself is I/O (an async ByteSource); this
|
|
18491
|
+
* driver awaits it before the next record is lexed.
|
|
18484
18492
|
* @param onRecordIndexed Called as each top-level record is indexed — see
|
|
18485
18493
|
* parseDataBlockStreamed.
|
|
18486
18494
|
* @param onProgress Optional byte-cursor progress callback.
|
|
@@ -18497,6 +18505,10 @@ var StepParser = class extends StepHeaderParser {
|
|
|
18497
18505
|
if (next.done === true) {
|
|
18498
18506
|
return next.value;
|
|
18499
18507
|
}
|
|
18508
|
+
if (typeof next.value !== "number") {
|
|
18509
|
+
await next.value;
|
|
18510
|
+
continue;
|
|
18511
|
+
}
|
|
18500
18512
|
onProgress?.(next.value);
|
|
18501
18513
|
if (Date.now() - lastYield >= yieldIntervalMs) {
|
|
18502
18514
|
await yieldToEventLoop();
|
|
@@ -18524,7 +18536,9 @@ var StepParser = class extends StepHeaderParser {
|
|
|
18524
18536
|
if (next.done === true) {
|
|
18525
18537
|
return next.value;
|
|
18526
18538
|
}
|
|
18527
|
-
|
|
18539
|
+
if (typeof next.value === "number") {
|
|
18540
|
+
onProgress?.(next.value);
|
|
18541
|
+
}
|
|
18528
18542
|
if (Date.now() - lastYield >= yieldIntervalMs) {
|
|
18529
18543
|
await yieldToEventLoop();
|
|
18530
18544
|
lastYield = Date.now();
|
|
@@ -18688,7 +18702,10 @@ var StepParser = class extends StepHeaderParser {
|
|
|
18688
18702
|
if ((++parsedElementCount & PARSE_PROGRESS_ELEMENT_MASK) === 0) {
|
|
18689
18703
|
yield input.cursor;
|
|
18690
18704
|
}
|
|
18691
|
-
onRecordBoundary?.(input);
|
|
18705
|
+
const slide = onRecordBoundary?.(input);
|
|
18706
|
+
if (slide !== void 0 && typeof slide.then === "function") {
|
|
18707
|
+
yield slide;
|
|
18708
|
+
}
|
|
18692
18709
|
if (!charws(HASH2)) {
|
|
18693
18710
|
if (tokenws(END_SECTION)) {
|
|
18694
18711
|
return parseResult(ParseResult.COMPLETE);
|
|
@@ -20231,6 +20248,70 @@ var EntityTypesIfc;
|
|
|
20231
20248
|
var EntityTypesIfcCount = 909;
|
|
20232
20249
|
var entity_types_ifc_gen_default = EntityTypesIfc;
|
|
20233
20250
|
|
|
20251
|
+
// compiled/src/step/parsing/express_ref_scan.js
|
|
20252
|
+
var HASH3 = 35;
|
|
20253
|
+
var QUOTE4 = 39;
|
|
20254
|
+
var DQUOTE = 34;
|
|
20255
|
+
var ZERO5 = 48;
|
|
20256
|
+
var NINE2 = 57;
|
|
20257
|
+
var SLASH3 = 47;
|
|
20258
|
+
var STAR2 = 42;
|
|
20259
|
+
function scanExpressRefs(bytes, from = 0, length = bytes.length - from) {
|
|
20260
|
+
const refs = [];
|
|
20261
|
+
const seen = /* @__PURE__ */ new Set();
|
|
20262
|
+
const end = Math.min(from + length, bytes.length);
|
|
20263
|
+
let cursor = from;
|
|
20264
|
+
while (cursor < end) {
|
|
20265
|
+
const byte = bytes[cursor];
|
|
20266
|
+
if (byte === QUOTE4) {
|
|
20267
|
+
cursor = skipQuoted_(bytes, cursor + 1, end, QUOTE4, true);
|
|
20268
|
+
continue;
|
|
20269
|
+
}
|
|
20270
|
+
if (byte === DQUOTE) {
|
|
20271
|
+
cursor = skipQuoted_(bytes, cursor + 1, end, DQUOTE, false);
|
|
20272
|
+
continue;
|
|
20273
|
+
}
|
|
20274
|
+
if (byte === SLASH3 && cursor + 1 < end && bytes[cursor + 1] === STAR2) {
|
|
20275
|
+
cursor += 2;
|
|
20276
|
+
while (cursor + 1 < end && !(bytes[cursor] === STAR2 && bytes[cursor + 1] === SLASH3)) {
|
|
20277
|
+
++cursor;
|
|
20278
|
+
}
|
|
20279
|
+
cursor += 2;
|
|
20280
|
+
continue;
|
|
20281
|
+
}
|
|
20282
|
+
if (byte === HASH3) {
|
|
20283
|
+
let value = 0;
|
|
20284
|
+
let digit = cursor + 1;
|
|
20285
|
+
while (digit < end && bytes[digit] >= ZERO5 && bytes[digit] <= NINE2) {
|
|
20286
|
+
value = value * 10 + (bytes[digit] - ZERO5);
|
|
20287
|
+
++digit;
|
|
20288
|
+
}
|
|
20289
|
+
if (digit > cursor + 1 && value !== 0 && !seen.has(value)) {
|
|
20290
|
+
seen.add(value);
|
|
20291
|
+
refs.push(value);
|
|
20292
|
+
}
|
|
20293
|
+
cursor = digit;
|
|
20294
|
+
continue;
|
|
20295
|
+
}
|
|
20296
|
+
++cursor;
|
|
20297
|
+
}
|
|
20298
|
+
return refs;
|
|
20299
|
+
}
|
|
20300
|
+
function skipQuoted_(bytes, from, end, quote, doubledEscape) {
|
|
20301
|
+
let cursor = from;
|
|
20302
|
+
while (cursor < end) {
|
|
20303
|
+
if (bytes[cursor] === quote) {
|
|
20304
|
+
if (doubledEscape && cursor + 1 < end && bytes[cursor + 1] === quote) {
|
|
20305
|
+
cursor += 2;
|
|
20306
|
+
continue;
|
|
20307
|
+
}
|
|
20308
|
+
return cursor + 1;
|
|
20309
|
+
}
|
|
20310
|
+
++cursor;
|
|
20311
|
+
}
|
|
20312
|
+
return end;
|
|
20313
|
+
}
|
|
20314
|
+
|
|
20234
20315
|
// compiled/src/step/step_buffer_provider.js
|
|
20235
20316
|
var DEFAULT_CHUNK_BYTES = 4 * 1024 * 1024;
|
|
20236
20317
|
var DEFAULT_MAX_RESIDENT_CHUNKS = 16;
|
|
@@ -20411,7 +20492,7 @@ var WindowedStepBufferProvider = class {
|
|
|
20411
20492
|
const firstChunk = Math.floor(address / chunkBytes);
|
|
20412
20493
|
const lastChunk = Math.floor((address + Math.max(length, 1) - 1) / chunkBytes);
|
|
20413
20494
|
for (let chunkIndex = firstChunk; chunkIndex <= lastChunk; ++chunkIndex) {
|
|
20414
|
-
this.
|
|
20495
|
+
this.addPin_(chunkIndex, 1);
|
|
20415
20496
|
}
|
|
20416
20497
|
try {
|
|
20417
20498
|
const loads = [];
|
|
@@ -20454,15 +20535,63 @@ var WindowedStepBufferProvider = class {
|
|
|
20454
20535
|
}
|
|
20455
20536
|
} finally {
|
|
20456
20537
|
for (let chunkIndex = firstChunk; chunkIndex <= lastChunk; ++chunkIndex) {
|
|
20457
|
-
|
|
20458
|
-
if (pins <= 1) {
|
|
20459
|
-
this.ensurePins_.delete(chunkIndex);
|
|
20460
|
-
} else {
|
|
20461
|
-
this.ensurePins_.set(chunkIndex, pins - 1);
|
|
20462
|
-
}
|
|
20538
|
+
this.addPin_(chunkIndex, -1);
|
|
20463
20539
|
}
|
|
20464
20540
|
}
|
|
20465
20541
|
}
|
|
20542
|
+
/**
|
|
20543
|
+
* Hold a range against LRU eviction until {@link unpinRange}.
|
|
20544
|
+
*
|
|
20545
|
+
* @param address Absolute start of the range.
|
|
20546
|
+
* @param length Length of the range.
|
|
20547
|
+
*/
|
|
20548
|
+
pinRange(address, length) {
|
|
20549
|
+
for (const chunkIndex of this.chunkSpan_(address, length)) {
|
|
20550
|
+
this.addPin_(chunkIndex, 1);
|
|
20551
|
+
}
|
|
20552
|
+
}
|
|
20553
|
+
/**
|
|
20554
|
+
* Drop one {@link pinRange} hold.
|
|
20555
|
+
*
|
|
20556
|
+
* @param address Absolute start of the range.
|
|
20557
|
+
* @param length Length of the range.
|
|
20558
|
+
*/
|
|
20559
|
+
unpinRange(address, length) {
|
|
20560
|
+
for (const chunkIndex of this.chunkSpan_(address, length)) {
|
|
20561
|
+
this.addPin_(chunkIndex, -1);
|
|
20562
|
+
}
|
|
20563
|
+
}
|
|
20564
|
+
/**
|
|
20565
|
+
* Chunk indices covering `[address, address + length)`.
|
|
20566
|
+
*
|
|
20567
|
+
* @param address Absolute start.
|
|
20568
|
+
* @param length Length in bytes.
|
|
20569
|
+
* @return {number[]} Inclusive chunk indices.
|
|
20570
|
+
*/
|
|
20571
|
+
chunkSpan_(address, length) {
|
|
20572
|
+
const chunkBytes = this.chunkBytes_;
|
|
20573
|
+
const firstChunk = Math.floor(address / chunkBytes);
|
|
20574
|
+
const lastChunk = Math.floor((address + Math.max(length, 1) - 1) / chunkBytes);
|
|
20575
|
+
const span = [];
|
|
20576
|
+
for (let chunkIndex = firstChunk; chunkIndex <= lastChunk; ++chunkIndex) {
|
|
20577
|
+
span.push(chunkIndex);
|
|
20578
|
+
}
|
|
20579
|
+
return span;
|
|
20580
|
+
}
|
|
20581
|
+
/**
|
|
20582
|
+
* Adjust a chunk's pin count, deleting the entry at zero.
|
|
20583
|
+
*
|
|
20584
|
+
* @param chunkIndex The chunk.
|
|
20585
|
+
* @param delta +1 pin or -1 unpin.
|
|
20586
|
+
*/
|
|
20587
|
+
addPin_(chunkIndex, delta) {
|
|
20588
|
+
const pins = (this.ensurePins_.get(chunkIndex) ?? 0) + delta;
|
|
20589
|
+
if (pins <= 0) {
|
|
20590
|
+
this.ensurePins_.delete(chunkIndex);
|
|
20591
|
+
} else {
|
|
20592
|
+
this.ensurePins_.set(chunkIndex, pins);
|
|
20593
|
+
}
|
|
20594
|
+
}
|
|
20466
20595
|
};
|
|
20467
20596
|
|
|
20468
20597
|
// compiled/src/step/parsing/step_vtable_builder.js
|
|
@@ -20532,7 +20661,7 @@ var StepVtableBuilder = class {
|
|
|
20532
20661
|
var OPEN_PAREN3 = parsing_constants_default.OPEN_PAREN;
|
|
20533
20662
|
var CLOSE_PAREN3 = parsing_constants_default.CLOSE_PAREN;
|
|
20534
20663
|
var COMMA3 = parsing_constants_default.COMMA;
|
|
20535
|
-
var
|
|
20664
|
+
var ZERO6 = parsing_constants_default.ZERO;
|
|
20536
20665
|
var WHITESPACE4 = parsing_constants_default.WHITE_SPACE_SET;
|
|
20537
20666
|
var Uint32Sink = class {
|
|
20538
20667
|
/**
|
|
@@ -20648,7 +20777,7 @@ function extractUnsignedIntegerListAt(buffer, cursor, endCursor, sink) {
|
|
|
20648
20777
|
return void 0;
|
|
20649
20778
|
}
|
|
20650
20779
|
}
|
|
20651
|
-
const digit = buffer[cursor] -
|
|
20780
|
+
const digit = buffer[cursor] - ZERO6;
|
|
20652
20781
|
if (digit < 0 || digit > 9) {
|
|
20653
20782
|
sink.truncate(marked);
|
|
20654
20783
|
return void 0;
|
|
@@ -20656,7 +20785,7 @@ function extractUnsignedIntegerListAt(buffer, cursor, endCursor, sink) {
|
|
|
20656
20785
|
let value = digit;
|
|
20657
20786
|
++cursor;
|
|
20658
20787
|
while (cursor < endCursor) {
|
|
20659
|
-
const next = buffer[cursor] -
|
|
20788
|
+
const next = buffer[cursor] - ZERO6;
|
|
20660
20789
|
if (next < 0 || next > 9) {
|
|
20661
20790
|
break;
|
|
20662
20791
|
}
|
|
@@ -21451,6 +21580,141 @@ var StepModelBase = class {
|
|
|
21451
21580
|
}
|
|
21452
21581
|
await this.ensureResidentByLocalID(localID);
|
|
21453
21582
|
}
|
|
21583
|
+
/**
|
|
21584
|
+
* Page in the byte ranges a record *and every `#ref` reachable from
|
|
21585
|
+
* its text* will need, so a following synchronous extract of that
|
|
21586
|
+
* subgraph succeeds on a windowed source. Inverse relationships
|
|
21587
|
+
* (not written in the record) are not discovered — callers that
|
|
21588
|
+
* need them (rel-voids, styled items) pass their local IDs as
|
|
21589
|
+
* `extraLocalIDs`.
|
|
21590
|
+
*
|
|
21591
|
+
* No-op while the source is fully resident.
|
|
21592
|
+
*
|
|
21593
|
+
* @param localID Seed record.
|
|
21594
|
+
* @param extraLocalIDs Additional seeds (voids, styles, materials).
|
|
21595
|
+
* @param seen Optional set to extend (also skips already-pinned IDs).
|
|
21596
|
+
* @return {Promise<Set<number>>} The local IDs that were visited.
|
|
21597
|
+
*/
|
|
21598
|
+
async ensureResidentClosureByLocalID(localID, extraLocalIDs, seen = /* @__PURE__ */ new Set()) {
|
|
21599
|
+
if (!this.isSourceExternal) {
|
|
21600
|
+
return seen;
|
|
21601
|
+
}
|
|
21602
|
+
const stack = [localID];
|
|
21603
|
+
if (extraLocalIDs !== void 0) {
|
|
21604
|
+
for (const extra of extraLocalIDs) {
|
|
21605
|
+
stack.push(extra);
|
|
21606
|
+
}
|
|
21607
|
+
}
|
|
21608
|
+
while (stack.length > 0) {
|
|
21609
|
+
const id = stack.pop();
|
|
21610
|
+
if (seen.has(id) || id >= this.count_) {
|
|
21611
|
+
continue;
|
|
21612
|
+
}
|
|
21613
|
+
seen.add(id);
|
|
21614
|
+
await this.ensureResidentByLocalID(id);
|
|
21615
|
+
this.pinByLocalID(id);
|
|
21616
|
+
for (const expressID of this.scanRecordRefs_(id)) {
|
|
21617
|
+
const referenced = this.expressIDMap_.get(expressID);
|
|
21618
|
+
if (referenced !== void 0 && !seen.has(referenced)) {
|
|
21619
|
+
stack.push(referenced);
|
|
21620
|
+
}
|
|
21621
|
+
}
|
|
21622
|
+
}
|
|
21623
|
+
return seen;
|
|
21624
|
+
}
|
|
21625
|
+
/**
|
|
21626
|
+
* Hold a record's source range against windowed LRU eviction until
|
|
21627
|
+
* {@link unpinByLocalID}. No-op while the source is fully resident.
|
|
21628
|
+
*
|
|
21629
|
+
* @param localID The record to pin.
|
|
21630
|
+
*/
|
|
21631
|
+
pinByLocalID(localID) {
|
|
21632
|
+
if (!this.isSourceExternal || localID >= this.count_) {
|
|
21633
|
+
return;
|
|
21634
|
+
}
|
|
21635
|
+
this.bufferProvider_.pinRange?.(this.address_[localID], this.length_[localID]);
|
|
21636
|
+
}
|
|
21637
|
+
/**
|
|
21638
|
+
* Drop one {@link pinByLocalID} hold.
|
|
21639
|
+
*
|
|
21640
|
+
* @param localID The record to unpin.
|
|
21641
|
+
*/
|
|
21642
|
+
unpinByLocalID(localID) {
|
|
21643
|
+
if (!this.isSourceExternal || localID >= this.count_) {
|
|
21644
|
+
return;
|
|
21645
|
+
}
|
|
21646
|
+
this.bufferProvider_.unpinRange?.(this.address_[localID], this.length_[localID]);
|
|
21647
|
+
}
|
|
21648
|
+
/**
|
|
21649
|
+
* Unpin every local ID in `localIDs` (best-effort; missing IDs are
|
|
21650
|
+
* ignored). Use after {@link ensureResidentClosureByLocalID}, which
|
|
21651
|
+
* pins as it walks.
|
|
21652
|
+
*
|
|
21653
|
+
* @param localIDs The records to unpin.
|
|
21654
|
+
*/
|
|
21655
|
+
unpinLocalIDs(localIDs) {
|
|
21656
|
+
for (const localID of localIDs) {
|
|
21657
|
+
this.unpinByLocalID(localID);
|
|
21658
|
+
}
|
|
21659
|
+
}
|
|
21660
|
+
/**
|
|
21661
|
+
* Express-ID twin of {@link ensureResidentClosureByLocalID}. Unknown
|
|
21662
|
+
* IDs resolve to an empty visit set.
|
|
21663
|
+
*
|
|
21664
|
+
* @param expressID Seed record.
|
|
21665
|
+
* @param extraLocalIDs Additional seeds (local IDs).
|
|
21666
|
+
* @return {Promise<Set<number>>} The local IDs that were visited.
|
|
21667
|
+
*/
|
|
21668
|
+
async ensureResidentClosureByExpressID(expressID, extraLocalIDs, seen) {
|
|
21669
|
+
if (!this.isSourceExternal) {
|
|
21670
|
+
return seen ?? /* @__PURE__ */ new Set();
|
|
21671
|
+
}
|
|
21672
|
+
const localID = this.expressIDMap_.get(expressID);
|
|
21673
|
+
if (localID === void 0) {
|
|
21674
|
+
return seen ?? /* @__PURE__ */ new Set();
|
|
21675
|
+
}
|
|
21676
|
+
return this.ensureResidentClosureByLocalID(localID, extraLocalIDs, seen);
|
|
21677
|
+
}
|
|
21678
|
+
/**
|
|
21679
|
+
* Express IDs referenced by a resident record (`#<id>` tokens in its
|
|
21680
|
+
* text, including multi-mapped class records). The record itself
|
|
21681
|
+
* must already be resident.
|
|
21682
|
+
*
|
|
21683
|
+
* @param localID The record to scan.
|
|
21684
|
+
* @return {number[]} Distinct referenced express IDs.
|
|
21685
|
+
*/
|
|
21686
|
+
referencedExpressIDs(localID) {
|
|
21687
|
+
return this.scanRecordRefs_(localID);
|
|
21688
|
+
}
|
|
21689
|
+
/**
|
|
21690
|
+
* Scan a resident record's bytes for `#<expressID>` references.
|
|
21691
|
+
*
|
|
21692
|
+
* @param localID The record to scan.
|
|
21693
|
+
* @return {number[]} Distinct referenced express IDs.
|
|
21694
|
+
*/
|
|
21695
|
+
scanRecordRefs_(localID) {
|
|
21696
|
+
const address = this.address_[localID];
|
|
21697
|
+
const length = this.length_[localID];
|
|
21698
|
+
const acquisition = this.bufferProvider_.acquire(address, length);
|
|
21699
|
+
const viewStart = address - acquisition.offset;
|
|
21700
|
+
const refs = scanExpressRefs(acquisition.buffer, viewStart, length);
|
|
21701
|
+
const complex = this.complexEntries_?.get(localID);
|
|
21702
|
+
if (complex?.multiMapping === void 0) {
|
|
21703
|
+
return refs;
|
|
21704
|
+
}
|
|
21705
|
+
const seen = new Set(refs);
|
|
21706
|
+
for (const mapped of complex.multiMapping) {
|
|
21707
|
+
const mappedAcquisition = this.bufferProvider_.acquire(mapped.address, mapped.length);
|
|
21708
|
+
const mappedStart = mapped.address - mappedAcquisition.offset;
|
|
21709
|
+
for (const expressID of scanExpressRefs(mappedAcquisition.buffer, mappedStart, mapped.length)) {
|
|
21710
|
+
if (!seen.has(expressID)) {
|
|
21711
|
+
seen.add(expressID);
|
|
21712
|
+
refs.push(expressID);
|
|
21713
|
+
}
|
|
21714
|
+
}
|
|
21715
|
+
}
|
|
21716
|
+
return refs;
|
|
21717
|
+
}
|
|
21454
21718
|
/**
|
|
21455
21719
|
* Get the number of elements/entities in this model.
|
|
21456
21720
|
*
|
|
@@ -26607,6 +26871,38 @@ var StepEntityBase = class {
|
|
|
26607
26871
|
}
|
|
26608
26872
|
return value;
|
|
26609
26873
|
}
|
|
26874
|
+
/**
|
|
26875
|
+
* Resolve a single reference field to its local ID without
|
|
26876
|
+
* constructing the target entity. Prep maps that only store
|
|
26877
|
+
* `Item.localID` (IfcStyledItem → faceset) must not hydrate the
|
|
26878
|
+
* target: on a windowed source that would pin the faceset record
|
|
26879
|
+
* (often megabytes) for every styled item at once.
|
|
26880
|
+
*
|
|
26881
|
+
* @param offset The offset in the vtable to extract from.
|
|
26882
|
+
* @param baseOffset The base offset of the class in the vtable.
|
|
26883
|
+
* @param depth The depth in the inheritance hierarchy.
|
|
26884
|
+
* @param optional Is this an optional field?
|
|
26885
|
+
* @return {number | null} The referenced local ID, or null if the
|
|
26886
|
+
* field is unset/optional-null.
|
|
26887
|
+
*/
|
|
26888
|
+
extractReferenceLocalID(offset, baseOffset, depth, optional) {
|
|
26889
|
+
const [cursor, endCursor, buffer] = this.getOffsetAndEndCursor(offset, baseOffset, depth);
|
|
26890
|
+
const expressID = stepExtractReference(buffer, cursor, endCursor);
|
|
26891
|
+
if (expressID !== void 0) {
|
|
26892
|
+
return this.model.resolveExpressID(expressID) ?? null;
|
|
26893
|
+
}
|
|
26894
|
+
const inline = this.model.getInlineElementByAddress(extractInlineElementAddress(buffer, cursor, endCursor));
|
|
26895
|
+
if (inline !== void 0) {
|
|
26896
|
+
return inline.localID;
|
|
26897
|
+
}
|
|
26898
|
+
if (!optional) {
|
|
26899
|
+
throw new Error("Value in STEP was incorrectly typed");
|
|
26900
|
+
}
|
|
26901
|
+
if (!this.model.nullOnErrors && stepExtractOptional(buffer, cursor, endCursor) !== null) {
|
|
26902
|
+
throw new Error("Value in STEP was incorrectly typed");
|
|
26903
|
+
}
|
|
26904
|
+
return null;
|
|
26905
|
+
}
|
|
26610
26906
|
/**
|
|
26611
26907
|
*
|
|
26612
26908
|
* @param buffer
|
|
@@ -87347,11 +87643,88 @@ function buildIndexStreaming(source, parser210, pool3, onRecordIndexed, sink) {
|
|
|
87347
87643
|
}
|
|
87348
87644
|
}
|
|
87349
87645
|
var MIN_WINDOW = 4 * 1024;
|
|
87646
|
+
async function readSource(source, offset, length, into, intoOffset) {
|
|
87647
|
+
return await source.read(offset, length, into, intoOffset);
|
|
87648
|
+
}
|
|
87649
|
+
async function buildIndexStreamingAsync(source, parser210, pool3, onRecordIndexed, sink, onProgress, yieldIntervalMs) {
|
|
87650
|
+
const fileSize = source.byteLength;
|
|
87651
|
+
let windowBytes = Math.max(pool3, MIN_WINDOW);
|
|
87652
|
+
for (; ; ) {
|
|
87653
|
+
const window2 = new Uint8Array(windowBytes);
|
|
87654
|
+
let windowStartFile = 0;
|
|
87655
|
+
let windowLen = await readSource(source, 0, windowBytes, window2, 0);
|
|
87656
|
+
let bytesRead = windowLen;
|
|
87657
|
+
const input = new ParsingBuffer(window2, 0, windowLen);
|
|
87658
|
+
const [header, headerResult] = parser210.parseHeader(input);
|
|
87659
|
+
if (headerResult !== ParseResult.COMPLETE) {
|
|
87660
|
+
return {
|
|
87661
|
+
header,
|
|
87662
|
+
elements: [],
|
|
87663
|
+
result: headerResult,
|
|
87664
|
+
stats: { pool: pool3, windowBytes, slides: 0, maxRecordLen: 0, bytesRead }
|
|
87665
|
+
};
|
|
87666
|
+
}
|
|
87667
|
+
const slideThreshold = windowBytes >> 1;
|
|
87668
|
+
let slides = 0;
|
|
87669
|
+
let maxRecordLen = 0;
|
|
87670
|
+
let prevBoundaryFile = windowStartFile + input.cursor;
|
|
87671
|
+
const onRecordBoundary = (buffer) => {
|
|
87672
|
+
const cursor = buffer.cursor;
|
|
87673
|
+
const recordFileStart = windowStartFile + cursor;
|
|
87674
|
+
const recordLen = recordFileStart - prevBoundaryFile;
|
|
87675
|
+
if (recordLen > maxRecordLen) {
|
|
87676
|
+
maxRecordLen = recordLen;
|
|
87677
|
+
}
|
|
87678
|
+
prevBoundaryFile = recordFileStart;
|
|
87679
|
+
if (windowStartFile + windowLen >= fileSize) {
|
|
87680
|
+
return;
|
|
87681
|
+
}
|
|
87682
|
+
if (cursor < slideThreshold) {
|
|
87683
|
+
return;
|
|
87684
|
+
}
|
|
87685
|
+
const tail = windowLen - cursor;
|
|
87686
|
+
window2.copyWithin(0, cursor, windowLen);
|
|
87687
|
+
const want = windowBytes - tail;
|
|
87688
|
+
const fillAt = windowStartFile + windowLen;
|
|
87689
|
+
return readSource(source, fillAt, want, window2, tail).then((got) => {
|
|
87690
|
+
bytesRead += got;
|
|
87691
|
+
windowLen = tail + got;
|
|
87692
|
+
windowStartFile = recordFileStart;
|
|
87693
|
+
buffer.rebaseWindow(window2, 0, windowLen, windowStartFile);
|
|
87694
|
+
++slides;
|
|
87695
|
+
});
|
|
87696
|
+
};
|
|
87697
|
+
const progressTick = onProgress !== void 0 ? (cursor) => onProgress(windowStartFile + cursor) : void 0;
|
|
87698
|
+
const [index, result] = await parser210.parseDataBlockStreamedAsync(input, onRecordBoundary, onRecordIndexed, progressTick, sink, yieldIntervalMs);
|
|
87699
|
+
const stoppedShort = result !== ParseResult.COMPLETE;
|
|
87700
|
+
const notAtEof = windowStartFile + windowLen < fileSize;
|
|
87701
|
+
if (stoppedShort && notAtEof) {
|
|
87702
|
+
windowBytes *= 2;
|
|
87703
|
+
sink?.reset();
|
|
87704
|
+
continue;
|
|
87705
|
+
}
|
|
87706
|
+
const lastRecordLen = windowStartFile + input.cursor - prevBoundaryFile;
|
|
87707
|
+
if (lastRecordLen > maxRecordLen) {
|
|
87708
|
+
maxRecordLen = lastRecordLen;
|
|
87709
|
+
}
|
|
87710
|
+
return {
|
|
87711
|
+
header,
|
|
87712
|
+
elements: index.elements,
|
|
87713
|
+
result,
|
|
87714
|
+
stats: { pool: pool3, windowBytes, slides, maxRecordLen, bytesRead }
|
|
87715
|
+
};
|
|
87716
|
+
}
|
|
87717
|
+
}
|
|
87350
87718
|
function buildColumnarIndexStreaming(source, parser210, pool3, onRecordIndexed) {
|
|
87351
87719
|
const sink = new ColumnarIndexSink();
|
|
87352
87720
|
const { header, result, stats } = buildIndexStreaming(source, parser210, pool3, onRecordIndexed, sink);
|
|
87353
87721
|
return { header, columns: sink.finalize(), result, stats };
|
|
87354
87722
|
}
|
|
87723
|
+
async function buildColumnarIndexStreamingAsync(source, parser210, pool3, onRecordIndexed, onProgress, yieldIntervalMs) {
|
|
87724
|
+
const sink = new ColumnarIndexSink();
|
|
87725
|
+
const { header, result, stats } = await buildIndexStreamingAsync(source, parser210, pool3, onRecordIndexed, sink, onProgress, yieldIntervalMs);
|
|
87726
|
+
return { header, columns: sink.finalize(), result, stats };
|
|
87727
|
+
}
|
|
87355
87728
|
|
|
87356
87729
|
// compiled/src/ifc/ifc_step_parser.js
|
|
87357
87730
|
var DEFAULT_STREAM_POOL_BYTES = 1024 * 1024;
|
|
@@ -87421,6 +87794,27 @@ var IfcStepParser = class extends StepParser {
|
|
|
87421
87794
|
const provider = new WindowedStepBufferProvider(store, opts?.chunkBytes, opts?.maxResidentChunks);
|
|
87422
87795
|
return [result, new IfcStepModel(void 0, columns, provider)];
|
|
87423
87796
|
}
|
|
87797
|
+
/**
|
|
87798
|
+
* Cooperative twin of {@link parseStreamToModel}: the index build
|
|
87799
|
+
* yields to the event loop and can fill windows from an async
|
|
87800
|
+
* {@link ReadableByteSource} (an OPFS `File.slice()` store). The
|
|
87801
|
+
* model is still windowed — geometry extract must
|
|
87802
|
+
* `ensureResident` first.
|
|
87803
|
+
*
|
|
87804
|
+
* @param source Sync or async byte source feeding the parse.
|
|
87805
|
+
* @param store Async external store backing the windowed model.
|
|
87806
|
+
* @param opts Optional window sizing plus parse progress.
|
|
87807
|
+
* @return {Promise<[ParseResult, IfcStepModel | undefined]>} The
|
|
87808
|
+
* parse result and the windowed model.
|
|
87809
|
+
*/
|
|
87810
|
+
async parseStreamToModelAsync(source, store, opts) {
|
|
87811
|
+
if (store.byteLength !== source.byteLength) {
|
|
87812
|
+
throw new Error(`Streaming store byteLength ${store.byteLength} does not match source byteLength ${source.byteLength}`);
|
|
87813
|
+
}
|
|
87814
|
+
const { columns, result } = await buildColumnarIndexStreamingAsync(source, this, opts?.pool ?? DEFAULT_STREAM_POOL_BYTES, void 0, opts?.onProgress);
|
|
87815
|
+
const provider = new WindowedStepBufferProvider(store, opts?.chunkBytes, opts?.maxResidentChunks);
|
|
87816
|
+
return [result, new IfcStepModel(void 0, columns, provider)];
|
|
87817
|
+
}
|
|
87424
87818
|
};
|
|
87425
87819
|
IfcStepParser.Instance = new IfcStepParser();
|
|
87426
87820
|
var ifc_step_parser_default = IfcStepParser;
|
|
@@ -91946,8 +92340,9 @@ var IfcGeometryExtraction = class _IfcGeometryExtraction {
|
|
|
91946
92340
|
const styledItems = this.model.types(IfcStyledItem);
|
|
91947
92341
|
for (const styledItem of styledItems) {
|
|
91948
92342
|
try {
|
|
91949
|
-
|
|
91950
|
-
|
|
92343
|
+
const itemLocalID = styledItem.extractReferenceLocalID(0, 0, 1, true);
|
|
92344
|
+
if (itemLocalID !== null) {
|
|
92345
|
+
this.materials.styledItemMap.set(itemLocalID, styledItem.localID);
|
|
91951
92346
|
}
|
|
91952
92347
|
} catch (ex) {
|
|
91953
92348
|
this.handleMapPrepError_("IfcStyledItem", styledItem.expressID, ex);
|
|
@@ -92203,6 +92598,137 @@ var IfcGeometryExtraction = class _IfcGeometryExtraction {
|
|
|
92203
92598
|
this.extractProductGeometry(element);
|
|
92204
92599
|
return true;
|
|
92205
92600
|
}
|
|
92601
|
+
/**
|
|
92602
|
+
* Page in every record {@link prepareDemandExtraction} will read, so
|
|
92603
|
+
* the relationship sweeps succeed on a windowed source. Call before
|
|
92604
|
+
* the first prepare on a model whose source is external.
|
|
92605
|
+
*
|
|
92606
|
+
* Pins the prep-type records themselves (and a 1-hop of product /
|
|
92607
|
+
* material records the relationship getters hydrate). Does **not**
|
|
92608
|
+
* BFS-pin styled-item Item closures — those are facesets, and
|
|
92609
|
+
* walking them here pulled most of the file into the windowed LRU
|
|
92610
|
+
* before the first product extract.
|
|
92611
|
+
*
|
|
92612
|
+
* @return {Promise<Set<number>>} Pinned local IDs — caller must
|
|
92613
|
+
* {@link StepModelBase.unpinLocalIDs} after prepare/extract.
|
|
92614
|
+
*/
|
|
92615
|
+
async ensureResidentForDemandPrep() {
|
|
92616
|
+
const pinned = /* @__PURE__ */ new Set();
|
|
92617
|
+
if (!this.model.isSourceExternal) {
|
|
92618
|
+
return pinned;
|
|
92619
|
+
}
|
|
92620
|
+
for (const type of [IfcProject, IfcMaterialDefinitionRepresentation]) {
|
|
92621
|
+
for (const expressID of this.model.expressIDsOfTypes(type)) {
|
|
92622
|
+
await this.model.ensureResidentClosureByExpressID(expressID, void 0, pinned);
|
|
92623
|
+
}
|
|
92624
|
+
}
|
|
92625
|
+
const recordOnlyTypes = [
|
|
92626
|
+
IfcRelAssociatesMaterial,
|
|
92627
|
+
IfcRelVoidsElement,
|
|
92628
|
+
IfcStyledItem,
|
|
92629
|
+
IfcRelAggregates
|
|
92630
|
+
];
|
|
92631
|
+
for (const type of recordOnlyTypes) {
|
|
92632
|
+
for (const expressID of this.model.expressIDsOfTypes(type)) {
|
|
92633
|
+
const localID = this.model.resolveExpressID(expressID);
|
|
92634
|
+
if (localID === void 0 || pinned.has(localID)) {
|
|
92635
|
+
continue;
|
|
92636
|
+
}
|
|
92637
|
+
await this.model.ensureResidentByLocalID(localID);
|
|
92638
|
+
this.model.pinByLocalID(localID);
|
|
92639
|
+
pinned.add(localID);
|
|
92640
|
+
}
|
|
92641
|
+
}
|
|
92642
|
+
const oneHopTypes = [
|
|
92643
|
+
IfcRelAssociatesMaterial,
|
|
92644
|
+
IfcRelVoidsElement,
|
|
92645
|
+
IfcRelAggregates
|
|
92646
|
+
];
|
|
92647
|
+
for (const type of oneHopTypes) {
|
|
92648
|
+
for (const expressID of this.model.expressIDsOfTypes(type)) {
|
|
92649
|
+
const localID = this.model.resolveExpressID(expressID);
|
|
92650
|
+
if (localID === void 0) {
|
|
92651
|
+
continue;
|
|
92652
|
+
}
|
|
92653
|
+
for (const refExpressID of this.model.referencedExpressIDs(localID)) {
|
|
92654
|
+
const refLocalID = this.model.resolveExpressID(refExpressID);
|
|
92655
|
+
if (refLocalID === void 0 || pinned.has(refLocalID)) {
|
|
92656
|
+
continue;
|
|
92657
|
+
}
|
|
92658
|
+
await this.model.ensureResidentByLocalID(refLocalID);
|
|
92659
|
+
this.model.pinByLocalID(refLocalID);
|
|
92660
|
+
pinned.add(refLocalID);
|
|
92661
|
+
}
|
|
92662
|
+
}
|
|
92663
|
+
}
|
|
92664
|
+
return pinned;
|
|
92665
|
+
}
|
|
92666
|
+
/**
|
|
92667
|
+
* Page in the `#ref` closure a per-product extract will acquire,
|
|
92668
|
+
* including this product's voids, bound materials and styled items
|
|
92669
|
+
* (those are inverse — not written in the product record).
|
|
92670
|
+
*
|
|
92671
|
+
* @param localID The product's local ID.
|
|
92672
|
+
* @return {Promise<Set<number>>} Pinned local IDs — caller must unpin
|
|
92673
|
+
* after extract.
|
|
92674
|
+
*/
|
|
92675
|
+
async ensureResidentForProductExtract(localID, seen) {
|
|
92676
|
+
if (!this.model.isSourceExternal) {
|
|
92677
|
+
return seen ?? /* @__PURE__ */ new Set();
|
|
92678
|
+
}
|
|
92679
|
+
const extra = [];
|
|
92680
|
+
const voids = this.productToVoidGeometryMap.get(localID);
|
|
92681
|
+
if (voids !== void 0) {
|
|
92682
|
+
extra.push(...voids);
|
|
92683
|
+
}
|
|
92684
|
+
const material = this.materials.relMaterialsMap.get(localID);
|
|
92685
|
+
if (material !== void 0) {
|
|
92686
|
+
extra.push(material);
|
|
92687
|
+
}
|
|
92688
|
+
const visited = await this.model.ensureResidentClosureByLocalID(localID, extra, seen);
|
|
92689
|
+
const styleExtra = [];
|
|
92690
|
+
for (const visitedID of visited) {
|
|
92691
|
+
const styled = this.materials.styledItemMap.get(visitedID);
|
|
92692
|
+
if (styled !== void 0) {
|
|
92693
|
+
styleExtra.push(styled);
|
|
92694
|
+
}
|
|
92695
|
+
const definition = this.materials.materialDefinitionsMap.get(visitedID);
|
|
92696
|
+
if (definition !== void 0) {
|
|
92697
|
+
styleExtra.push(definition);
|
|
92698
|
+
}
|
|
92699
|
+
}
|
|
92700
|
+
if (styleExtra.length > 0) {
|
|
92701
|
+
await this.model.ensureResidentClosureByLocalID(localID, styleExtra, visited);
|
|
92702
|
+
}
|
|
92703
|
+
return visited;
|
|
92704
|
+
}
|
|
92705
|
+
/**
|
|
92706
|
+
* Page in the records {@link extractRelAggregateGeometry} will
|
|
92707
|
+
* acquire: the relationship, the relating product (and its voids)
|
|
92708
|
+
* and every related product.
|
|
92709
|
+
*
|
|
92710
|
+
* @param relAggregate The relationship to prefetch.
|
|
92711
|
+
* @return {Promise<Set<number>>} Pinned local IDs — caller must unpin
|
|
92712
|
+
* after extract.
|
|
92713
|
+
*/
|
|
92714
|
+
async ensureResidentForAggregateExtract(relAggregate) {
|
|
92715
|
+
if (!this.model.isSourceExternal) {
|
|
92716
|
+
return /* @__PURE__ */ new Set();
|
|
92717
|
+
}
|
|
92718
|
+
const pinned = await this.model.ensureResidentClosureByLocalID(relAggregate.localID);
|
|
92719
|
+
const relating = relAggregate.RelatingObject;
|
|
92720
|
+
if (relating !== null && relating !== void 0) {
|
|
92721
|
+
await this.ensureResidentForProductExtract(relating.localID, pinned);
|
|
92722
|
+
}
|
|
92723
|
+
const related = relAggregate.RelatedObjects;
|
|
92724
|
+
if (related === null || related === void 0) {
|
|
92725
|
+
return pinned;
|
|
92726
|
+
}
|
|
92727
|
+
for (const product of related) {
|
|
92728
|
+
await this.ensureResidentForProductExtract(product.localID, pinned);
|
|
92729
|
+
}
|
|
92730
|
+
return pinned;
|
|
92731
|
+
}
|
|
92206
92732
|
/**
|
|
92207
92733
|
* The whole-model walk's SECOND product pass, shared with the demand
|
|
92208
92734
|
* pump: for every IfcRelAggregates, re-extract the related products
|