@bldrs-ai/conway 1.399.1223 → 1.400.1226
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 +177 -11
- package/compiled/examples/cli-bundled.cjs +177 -11
- package/compiled/examples/cli-step-bundled.cjs +69 -8
- package/compiled/examples/validator-bundled.cjs +177 -11
- package/compiled/src/ifc/ifc_step_model.d.ts +5 -2
- package/compiled/src/ifc/ifc_step_model.d.ts.map +1 -1
- package/compiled/src/ifc/ifc_step_model.js +5 -3
- package/compiled/src/ifc/ifc_step_parser.d.ts +36 -0
- package/compiled/src/ifc/ifc_step_parser.d.ts.map +1 -1
- package/compiled/src/ifc/ifc_step_parser.js +40 -0
- package/compiled/src/ifc/ifc_stream_model.test.d.ts +2 -0
- package/compiled/src/ifc/ifc_stream_model.test.d.ts.map +1 -0
- package/compiled/src/ifc/ifc_stream_model.test.js +70 -0
- package/compiled/src/parsing/parsing_buffer.d.ts +23 -0
- package/compiled/src/parsing/parsing_buffer.d.ts.map +1 -1
- package/compiled/src/parsing/parsing_buffer.js +31 -0
- package/compiled/src/step/parsing/byte_source.d.ts +55 -0
- package/compiled/src/step/parsing/byte_source.d.ts.map +1 -0
- package/compiled/src/step/parsing/byte_source.js +35 -0
- package/compiled/src/step/parsing/step_parser.d.ts +14 -0
- package/compiled/src/step/parsing/step_parser.d.ts.map +1 -1
- package/compiled/src/step/parsing/step_parser.js +41 -4
- package/compiled/src/step/parsing/streaming_index_builder.d.ts +60 -0
- package/compiled/src/step/parsing/streaming_index_builder.d.ts.map +1 -0
- package/compiled/src/step/parsing/streaming_index_builder.js +115 -0
- package/compiled/src/step/parsing/streaming_index_builder.test.d.ts +2 -0
- package/compiled/src/step/parsing/streaming_index_builder.test.d.ts.map +1 -0
- package/compiled/src/step/parsing/streaming_index_builder.test.js +107 -0
- package/compiled/src/step/step_model_base.d.ts +9 -3
- package/compiled/src/step/step_model_base.d.ts.map +1 -1
- package/compiled/src/step/step_model_base.js +9 -3
- package/compiled/src/version/version.js +1 -1
- package/compiled/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -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.400.1226";
|
|
34
34
|
|
|
35
35
|
// compiled/dependencies/conway-geom/interface/conway_geometry.js
|
|
36
36
|
var wasmType = "";
|
|
@@ -1286,6 +1286,37 @@ var ParsingBuffer = class {
|
|
|
1286
1286
|
this.buffer = buffer;
|
|
1287
1287
|
this.end = endOffset;
|
|
1288
1288
|
}
|
|
1289
|
+
/**
|
|
1290
|
+
* Streaming support: repoint this buffer at a fresh window over the same
|
|
1291
|
+
* logical stream while keeping `address` file-absolute.
|
|
1292
|
+
*
|
|
1293
|
+
* A moving-window parse holds only a slice of the source in memory at a
|
|
1294
|
+
* time. Between top-level records (where the rewind stack is empty) the
|
|
1295
|
+
* driver slides the window forward: it copies the unconsumed tail to the
|
|
1296
|
+
* front of a reused buffer, appends freshly-read bytes, and calls this to
|
|
1297
|
+
* repoint the parser. `addressBase` is the file offset that window index 0
|
|
1298
|
+
* now corresponds to; we store it as a negative initial offset so
|
|
1299
|
+
* `address` ( = cursor − initialOffset ) stays the file-absolute value the
|
|
1300
|
+
* non-streaming parse would have produced.
|
|
1301
|
+
*
|
|
1302
|
+
* Must only be called with the rewind stack empty (i.e. at a record
|
|
1303
|
+
* boundary) — the stack holds window-relative cursors that a slide would
|
|
1304
|
+
* invalidate. Throws otherwise.
|
|
1305
|
+
*
|
|
1306
|
+
* @param buffer The new window buffer.
|
|
1307
|
+
* @param cursorInWindow The cursor position within the new window.
|
|
1308
|
+
* @param endInWindow The count of valid bytes in the new window.
|
|
1309
|
+
* @param addressBase The file offset that window index 0 maps to.
|
|
1310
|
+
*/
|
|
1311
|
+
rebaseWindow(buffer, cursorInWindow, endInWindow, addressBase) {
|
|
1312
|
+
if (this.rewindStack_.length !== 0) {
|
|
1313
|
+
throw Error("rebaseWindow called mid-transaction (rewind stack non-empty)");
|
|
1314
|
+
}
|
|
1315
|
+
this.buffer = buffer;
|
|
1316
|
+
this.cursor_ = cursorInWindow;
|
|
1317
|
+
this.initialOffset_ = -addressBase;
|
|
1318
|
+
this.end = endInWindow;
|
|
1319
|
+
}
|
|
1289
1320
|
/**
|
|
1290
1321
|
* Construct this with a buffer, initial offset into the buffer and an end offset.
|
|
1291
1322
|
*
|
|
@@ -2538,6 +2569,29 @@ var StepParser = class extends StepHeaderParser {
|
|
|
2538
2569
|
onProgress?.(next.value);
|
|
2539
2570
|
}
|
|
2540
2571
|
}
|
|
2572
|
+
/**
|
|
2573
|
+
* Streaming driver over parseDataBlockIncremental: identical parse (same
|
|
2574
|
+
* generator body) but invokes `onRecordBoundary` at every top-level record
|
|
2575
|
+
* boundary so a caller feeding the parser from a moving window can slide
|
|
2576
|
+
* that window forward while the rewind stack is empty. See
|
|
2577
|
+
* streaming_index_builder.ts for the coordinator that owns the window.
|
|
2578
|
+
*
|
|
2579
|
+
* @param input The input parsing buffer, positioned at the data section.
|
|
2580
|
+
* @param onRecordBoundary Called at each top-level record boundary with the
|
|
2581
|
+
* buffer; the callback may rebase the buffer's window in place.
|
|
2582
|
+
* @param onProgress Optional byte-cursor progress callback.
|
|
2583
|
+
* @return {BlockParseResult} The parsing result, including the index and result enum.
|
|
2584
|
+
*/
|
|
2585
|
+
parseDataBlockStreamed(input2, onRecordBoundary, onProgress) {
|
|
2586
|
+
const parser211 = this.parseDataBlockIncremental(input2, onRecordBoundary);
|
|
2587
|
+
while (true) {
|
|
2588
|
+
const next = parser211.next();
|
|
2589
|
+
if (next.done === true) {
|
|
2590
|
+
return next.value;
|
|
2591
|
+
}
|
|
2592
|
+
onProgress?.(next.value);
|
|
2593
|
+
}
|
|
2594
|
+
}
|
|
2541
2595
|
/**
|
|
2542
2596
|
* Cooperative variant of parseDataBlock: identical parse (same generator
|
|
2543
2597
|
* body), but periodically awaits a macrotask so the event loop can run —
|
|
@@ -2575,7 +2629,7 @@ var StepParser = class extends StepHeaderParser {
|
|
|
2575
2629
|
* @yields {number} The current byte cursor within the input buffer.
|
|
2576
2630
|
* @return {BlockParseResult} The parsing result, including the index and result enum.
|
|
2577
2631
|
*/
|
|
2578
|
-
*parseDataBlockIncremental(input2) {
|
|
2632
|
+
*parseDataBlockIncremental(input2, onRecordBoundary) {
|
|
2579
2633
|
const indexResult = { elements: [] };
|
|
2580
2634
|
const match = input2.match;
|
|
2581
2635
|
const comment = () => match(commentParser2);
|
|
@@ -2622,7 +2676,7 @@ var StepParser = class extends StepHeaderParser {
|
|
|
2622
2676
|
return syntaxError();
|
|
2623
2677
|
}
|
|
2624
2678
|
whitespace();
|
|
2625
|
-
const startElement = input2.
|
|
2679
|
+
const startElement = input2.address;
|
|
2626
2680
|
let stackDepth = 1;
|
|
2627
2681
|
const savedInlineElements = inlineElements;
|
|
2628
2682
|
inlineElements = void 0;
|
|
@@ -2716,6 +2770,7 @@ var StepParser = class extends StepHeaderParser {
|
|
|
2716
2770
|
if ((++parsedElementCount & PARSE_PROGRESS_ELEMENT_MASK) === 0) {
|
|
2717
2771
|
yield input2.cursor;
|
|
2718
2772
|
}
|
|
2773
|
+
onRecordBoundary?.(input2);
|
|
2719
2774
|
if (!charws(HASH2)) {
|
|
2720
2775
|
if (tokenws(END_SECTION)) {
|
|
2721
2776
|
return parseResult2(ParseResult.COMPLETE);
|
|
@@ -2738,7 +2793,7 @@ var StepParser = class extends StepHeaderParser {
|
|
|
2738
2793
|
}
|
|
2739
2794
|
whitespace();
|
|
2740
2795
|
inlineElements = void 0;
|
|
2741
|
-
const startElement2 = input2.
|
|
2796
|
+
const startElement2 = input2.address;
|
|
2742
2797
|
while (!charws(CLOSE_PAREN2)) {
|
|
2743
2798
|
input2.begin();
|
|
2744
2799
|
const elementResult = parseInlineElement(expressID);
|
|
@@ -2769,7 +2824,7 @@ var StepParser = class extends StepHeaderParser {
|
|
|
2769
2824
|
return syntaxError();
|
|
2770
2825
|
}
|
|
2771
2826
|
whitespace();
|
|
2772
|
-
const startElement = input2.
|
|
2827
|
+
const startElement = input2.address;
|
|
2773
2828
|
let stackDepth = 1;
|
|
2774
2829
|
inlineElements = void 0;
|
|
2775
2830
|
while (stackDepth > 0) {
|
|
@@ -4920,18 +4975,24 @@ var StepModelBase = class {
|
|
|
4920
4975
|
* Construct this step model with its matching schema, a buffer to read from and an element index.
|
|
4921
4976
|
*
|
|
4922
4977
|
* @param schema The Step schema this is based on.
|
|
4923
|
-
* @param buffer_ The buffer to read this from.
|
|
4978
|
+
* @param buffer_ The buffer to read this from. Pass `undefined` together
|
|
4979
|
+
* with `provider` to build a model whose source is windowed from
|
|
4980
|
+
* construction (e.g. a streaming open — see buildModelStreaming); the
|
|
4981
|
+
* synchronous read paths (geometry extraction) then require the relevant
|
|
4982
|
+
* ranges to be resident, exactly as after `spillSourceToExternalStore`.
|
|
4924
4983
|
* @param elementIndex The element index for this, parsed or deserialized - note this takes
|
|
4925
4984
|
* ownership of this array in the sense it will modify values/unfold inline elements etc.
|
|
4985
|
+
* @param provider Optional pre-built buffer provider. When omitted, a
|
|
4986
|
+
* resident provider over `buffer_` is used (the classic path).
|
|
4926
4987
|
*/
|
|
4927
|
-
constructor(schema, buffer_, elementIndex) {
|
|
4988
|
+
constructor(schema, buffer_, elementIndex, provider) {
|
|
4928
4989
|
this.schema = schema;
|
|
4929
4990
|
this.buffer_ = buffer_;
|
|
4930
4991
|
this.vtableBuilder_ = new StepVtableBuilder();
|
|
4931
4992
|
this.descriptorCache_ = [];
|
|
4932
4993
|
this.elementMemoization = true;
|
|
4933
4994
|
this.nullOnErrors = true;
|
|
4934
|
-
this.bufferProvider_ = new ResidentStepBufferProvider(buffer_);
|
|
4995
|
+
this.bufferProvider_ = provider ?? new ResidentStepBufferProvider(buffer_);
|
|
4935
4996
|
const localElementIndex = elementIndex;
|
|
4936
4997
|
let where = 0;
|
|
4937
4998
|
const firstInlineElement = localElementIndex.length;
|
|
@@ -70694,11 +70755,13 @@ var IfcStepModel = class extends StepModelBase {
|
|
|
70694
70755
|
* Construct this model given a buffer containing the data and the parsed data index on that,
|
|
70695
70756
|
* adding the typeIndex on top of that.
|
|
70696
70757
|
*
|
|
70697
|
-
* @param buffer The buffer to values from
|
|
70758
|
+
* @param buffer The buffer to values from, or `undefined` with `provider`
|
|
70759
|
+
* set for a windowed (streaming) source.
|
|
70698
70760
|
* @param elementIndex The parsed index to elements in the STEP.
|
|
70761
|
+
* @param provider Optional pre-built buffer provider (windowed source).
|
|
70699
70762
|
*/
|
|
70700
|
-
constructor(buffer, elementIndex) {
|
|
70701
|
-
super(schema_ifc_gen_default, buffer, elementIndex);
|
|
70763
|
+
constructor(buffer, elementIndex, provider) {
|
|
70764
|
+
super(schema_ifc_gen_default, buffer, elementIndex, provider);
|
|
70702
70765
|
this.externalMappingType = ifc_step_external_mapping_default;
|
|
70703
70766
|
this.geometry = new IfcModelGeometry(this);
|
|
70704
70767
|
this.voidGeometry = new IfcModelGeometry(this, true);
|
|
@@ -70712,7 +70775,76 @@ var IfcStepModel = class extends StepModelBase {
|
|
|
70712
70775
|
}
|
|
70713
70776
|
};
|
|
70714
70777
|
|
|
70778
|
+
// compiled/src/step/parsing/streaming_index_builder.js
|
|
70779
|
+
function buildIndexStreaming(source, parser211, pool3) {
|
|
70780
|
+
const fileSize = source.byteLength;
|
|
70781
|
+
let windowBytes = Math.max(pool3, MIN_WINDOW);
|
|
70782
|
+
for (; ; ) {
|
|
70783
|
+
const window2 = new Uint8Array(windowBytes);
|
|
70784
|
+
let windowStartFile = 0;
|
|
70785
|
+
let windowLen = source.read(0, windowBytes, window2, 0);
|
|
70786
|
+
let bytesRead = windowLen;
|
|
70787
|
+
const input2 = new ParsingBuffer(window2, 0, windowLen);
|
|
70788
|
+
const [header, headerResult] = parser211.parseHeader(input2);
|
|
70789
|
+
if (headerResult !== ParseResult.COMPLETE) {
|
|
70790
|
+
return {
|
|
70791
|
+
header,
|
|
70792
|
+
elements: [],
|
|
70793
|
+
result: headerResult,
|
|
70794
|
+
stats: { pool: pool3, windowBytes, slides: 0, maxRecordLen: 0, bytesRead }
|
|
70795
|
+
};
|
|
70796
|
+
}
|
|
70797
|
+
const slideThreshold = windowBytes >> 1;
|
|
70798
|
+
let slides = 0;
|
|
70799
|
+
let maxRecordLen = 0;
|
|
70800
|
+
let prevBoundaryFile = windowStartFile + input2.cursor;
|
|
70801
|
+
const onRecordBoundary = (buffer) => {
|
|
70802
|
+
const cursor = buffer.cursor;
|
|
70803
|
+
const recordFileStart = windowStartFile + cursor;
|
|
70804
|
+
const recordLen = recordFileStart - prevBoundaryFile;
|
|
70805
|
+
if (recordLen > maxRecordLen) {
|
|
70806
|
+
maxRecordLen = recordLen;
|
|
70807
|
+
}
|
|
70808
|
+
prevBoundaryFile = recordFileStart;
|
|
70809
|
+
if (windowStartFile + windowLen >= fileSize) {
|
|
70810
|
+
return;
|
|
70811
|
+
}
|
|
70812
|
+
if (cursor < slideThreshold) {
|
|
70813
|
+
return;
|
|
70814
|
+
}
|
|
70815
|
+
const tail = windowLen - cursor;
|
|
70816
|
+
window2.copyWithin(0, cursor, windowLen);
|
|
70817
|
+
const want = windowBytes - tail;
|
|
70818
|
+
const got = source.read(windowStartFile + windowLen, want, window2, tail);
|
|
70819
|
+
bytesRead += got;
|
|
70820
|
+
windowLen = tail + got;
|
|
70821
|
+
windowStartFile = recordFileStart;
|
|
70822
|
+
buffer.rebaseWindow(window2, 0, windowLen, windowStartFile);
|
|
70823
|
+
++slides;
|
|
70824
|
+
};
|
|
70825
|
+
const [index, result] = parser211.parseDataBlockStreamed(input2, onRecordBoundary);
|
|
70826
|
+
const stoppedShort = result !== ParseResult.COMPLETE;
|
|
70827
|
+
const notAtEof = windowStartFile + windowLen < fileSize;
|
|
70828
|
+
if (stoppedShort && notAtEof) {
|
|
70829
|
+
windowBytes *= 2;
|
|
70830
|
+
continue;
|
|
70831
|
+
}
|
|
70832
|
+
const lastRecordLen = windowStartFile + input2.cursor - prevBoundaryFile;
|
|
70833
|
+
if (lastRecordLen > maxRecordLen) {
|
|
70834
|
+
maxRecordLen = lastRecordLen;
|
|
70835
|
+
}
|
|
70836
|
+
return {
|
|
70837
|
+
header,
|
|
70838
|
+
elements: index.elements,
|
|
70839
|
+
result,
|
|
70840
|
+
stats: { pool: pool3, windowBytes, slides, maxRecordLen, bytesRead }
|
|
70841
|
+
};
|
|
70842
|
+
}
|
|
70843
|
+
}
|
|
70844
|
+
var MIN_WINDOW = 4 * 1024;
|
|
70845
|
+
|
|
70715
70846
|
// compiled/src/ifc/ifc_step_parser.js
|
|
70847
|
+
var DEFAULT_STREAM_POOL_BYTES = 1024 * 1024;
|
|
70716
70848
|
var IfcStepParser = class extends StepParser {
|
|
70717
70849
|
/**
|
|
70718
70850
|
* Construct the IFC step parser.
|
|
@@ -70745,6 +70877,40 @@ var IfcStepParser = class extends StepParser {
|
|
|
70745
70877
|
const [itemIndex, parseResult2] = await this.parseDataBlockAsync(input2, onProgress);
|
|
70746
70878
|
return [parseResult2, new IfcStepModel(input2.buffer, itemIndex.elements)];
|
|
70747
70879
|
}
|
|
70880
|
+
/**
|
|
70881
|
+
* Build a model by streaming the source through a bounded moving window
|
|
70882
|
+
* (see buildIndexStreaming / M0) rather than parsing one resident buffer,
|
|
70883
|
+
* then backing the model with a windowed provider over `store` — so the
|
|
70884
|
+
* source is never held fully resident in the JS heap.
|
|
70885
|
+
*
|
|
70886
|
+
* `source` serves the parse (synchronous windowed reads — on a worker this
|
|
70887
|
+
* is an OPFS sync-access handle; in node/tests a file descriptor or buffer)
|
|
70888
|
+
* and `store` serves the model's post-parse property access (asynchronous
|
|
70889
|
+
* windowed reads paged in on demand — OPFS `File.slice()` in the browser).
|
|
70890
|
+
* Both view the same file bytes, so the file-absolute addresses the index
|
|
70891
|
+
* records resolve identically through either.
|
|
70892
|
+
*
|
|
70893
|
+
* NOTE (M1 scope): this delivers the bounded-memory *parse*. Synchronous
|
|
70894
|
+
* geometry extraction still needs its record ranges resident — as after
|
|
70895
|
+
* `spillSourceToExternalStore` — so a caller that extracts geometry must
|
|
70896
|
+
* `ensureResident` first (demand-driven geometry is M3). Property / index
|
|
70897
|
+
* access works directly via the async surfaces.
|
|
70898
|
+
*
|
|
70899
|
+
* @param source Synchronous byte source feeding the streaming parse.
|
|
70900
|
+
* @param store Async external store backing the windowed model.
|
|
70901
|
+
* @param opts Optional window sizing: `pool` (parse window),
|
|
70902
|
+
* `chunkBytes` / `maxResidentChunks` (model window).
|
|
70903
|
+
* @return {[ParseResult, IfcStepModel | undefined]} The parse result and
|
|
70904
|
+
* the windowed model.
|
|
70905
|
+
*/
|
|
70906
|
+
parseStreamToModel(source, store, opts) {
|
|
70907
|
+
if (store.byteLength !== source.byteLength) {
|
|
70908
|
+
throw new Error(`Streaming store byteLength ${store.byteLength} does not match source byteLength ${source.byteLength}`);
|
|
70909
|
+
}
|
|
70910
|
+
const { elements, result } = buildIndexStreaming(source, this, opts?.pool ?? DEFAULT_STREAM_POOL_BYTES);
|
|
70911
|
+
const provider = new WindowedStepBufferProvider(store, opts?.chunkBytes, opts?.maxResidentChunks);
|
|
70912
|
+
return [result, new IfcStepModel(void 0, elements, provider)];
|
|
70913
|
+
}
|
|
70748
70914
|
};
|
|
70749
70915
|
IfcStepParser.Instance = new IfcStepParser();
|
|
70750
70916
|
var ifc_step_parser_default = IfcStepParser;
|
|
@@ -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.400.1226";
|
|
14969
14969
|
|
|
14970
14970
|
// compiled/dependencies/conway-geom/interface/conway_geometry.js
|
|
14971
14971
|
function pThreadsAllowed() {
|
|
@@ -17100,6 +17100,37 @@ var ParsingBuffer = class {
|
|
|
17100
17100
|
this.buffer = buffer;
|
|
17101
17101
|
this.end = endOffset;
|
|
17102
17102
|
}
|
|
17103
|
+
/**
|
|
17104
|
+
* Streaming support: repoint this buffer at a fresh window over the same
|
|
17105
|
+
* logical stream while keeping `address` file-absolute.
|
|
17106
|
+
*
|
|
17107
|
+
* A moving-window parse holds only a slice of the source in memory at a
|
|
17108
|
+
* time. Between top-level records (where the rewind stack is empty) the
|
|
17109
|
+
* driver slides the window forward: it copies the unconsumed tail to the
|
|
17110
|
+
* front of a reused buffer, appends freshly-read bytes, and calls this to
|
|
17111
|
+
* repoint the parser. `addressBase` is the file offset that window index 0
|
|
17112
|
+
* now corresponds to; we store it as a negative initial offset so
|
|
17113
|
+
* `address` ( = cursor − initialOffset ) stays the file-absolute value the
|
|
17114
|
+
* non-streaming parse would have produced.
|
|
17115
|
+
*
|
|
17116
|
+
* Must only be called with the rewind stack empty (i.e. at a record
|
|
17117
|
+
* boundary) — the stack holds window-relative cursors that a slide would
|
|
17118
|
+
* invalidate. Throws otherwise.
|
|
17119
|
+
*
|
|
17120
|
+
* @param buffer The new window buffer.
|
|
17121
|
+
* @param cursorInWindow The cursor position within the new window.
|
|
17122
|
+
* @param endInWindow The count of valid bytes in the new window.
|
|
17123
|
+
* @param addressBase The file offset that window index 0 maps to.
|
|
17124
|
+
*/
|
|
17125
|
+
rebaseWindow(buffer, cursorInWindow, endInWindow, addressBase) {
|
|
17126
|
+
if (this.rewindStack_.length !== 0) {
|
|
17127
|
+
throw Error("rebaseWindow called mid-transaction (rewind stack non-empty)");
|
|
17128
|
+
}
|
|
17129
|
+
this.buffer = buffer;
|
|
17130
|
+
this.cursor_ = cursorInWindow;
|
|
17131
|
+
this.initialOffset_ = -addressBase;
|
|
17132
|
+
this.end = endInWindow;
|
|
17133
|
+
}
|
|
17103
17134
|
/**
|
|
17104
17135
|
* Construct this with a buffer, initial offset into the buffer and an end offset.
|
|
17105
17136
|
*
|
|
@@ -18352,6 +18383,29 @@ var StepParser = class extends StepHeaderParser {
|
|
|
18352
18383
|
onProgress?.(next.value);
|
|
18353
18384
|
}
|
|
18354
18385
|
}
|
|
18386
|
+
/**
|
|
18387
|
+
* Streaming driver over parseDataBlockIncremental: identical parse (same
|
|
18388
|
+
* generator body) but invokes `onRecordBoundary` at every top-level record
|
|
18389
|
+
* boundary so a caller feeding the parser from a moving window can slide
|
|
18390
|
+
* that window forward while the rewind stack is empty. See
|
|
18391
|
+
* streaming_index_builder.ts for the coordinator that owns the window.
|
|
18392
|
+
*
|
|
18393
|
+
* @param input The input parsing buffer, positioned at the data section.
|
|
18394
|
+
* @param onRecordBoundary Called at each top-level record boundary with the
|
|
18395
|
+
* buffer; the callback may rebase the buffer's window in place.
|
|
18396
|
+
* @param onProgress Optional byte-cursor progress callback.
|
|
18397
|
+
* @return {BlockParseResult} The parsing result, including the index and result enum.
|
|
18398
|
+
*/
|
|
18399
|
+
parseDataBlockStreamed(input, onRecordBoundary, onProgress) {
|
|
18400
|
+
const parser210 = this.parseDataBlockIncremental(input, onRecordBoundary);
|
|
18401
|
+
while (true) {
|
|
18402
|
+
const next = parser210.next();
|
|
18403
|
+
if (next.done === true) {
|
|
18404
|
+
return next.value;
|
|
18405
|
+
}
|
|
18406
|
+
onProgress?.(next.value);
|
|
18407
|
+
}
|
|
18408
|
+
}
|
|
18355
18409
|
/**
|
|
18356
18410
|
* Cooperative variant of parseDataBlock: identical parse (same generator
|
|
18357
18411
|
* body), but periodically awaits a macrotask so the event loop can run —
|
|
@@ -18389,7 +18443,7 @@ var StepParser = class extends StepHeaderParser {
|
|
|
18389
18443
|
* @yields {number} The current byte cursor within the input buffer.
|
|
18390
18444
|
* @return {BlockParseResult} The parsing result, including the index and result enum.
|
|
18391
18445
|
*/
|
|
18392
|
-
*parseDataBlockIncremental(input) {
|
|
18446
|
+
*parseDataBlockIncremental(input, onRecordBoundary) {
|
|
18393
18447
|
const indexResult = { elements: [] };
|
|
18394
18448
|
const match = input.match;
|
|
18395
18449
|
const comment = () => match(commentParser2);
|
|
@@ -18436,7 +18490,7 @@ var StepParser = class extends StepHeaderParser {
|
|
|
18436
18490
|
return syntaxError();
|
|
18437
18491
|
}
|
|
18438
18492
|
whitespace();
|
|
18439
|
-
const startElement = input.
|
|
18493
|
+
const startElement = input.address;
|
|
18440
18494
|
let stackDepth = 1;
|
|
18441
18495
|
const savedInlineElements = inlineElements;
|
|
18442
18496
|
inlineElements = void 0;
|
|
@@ -18530,6 +18584,7 @@ var StepParser = class extends StepHeaderParser {
|
|
|
18530
18584
|
if ((++parsedElementCount & PARSE_PROGRESS_ELEMENT_MASK) === 0) {
|
|
18531
18585
|
yield input.cursor;
|
|
18532
18586
|
}
|
|
18587
|
+
onRecordBoundary?.(input);
|
|
18533
18588
|
if (!charws(HASH2)) {
|
|
18534
18589
|
if (tokenws(END_SECTION)) {
|
|
18535
18590
|
return parseResult(ParseResult.COMPLETE);
|
|
@@ -18552,7 +18607,7 @@ var StepParser = class extends StepHeaderParser {
|
|
|
18552
18607
|
}
|
|
18553
18608
|
whitespace();
|
|
18554
18609
|
inlineElements = void 0;
|
|
18555
|
-
const startElement2 = input.
|
|
18610
|
+
const startElement2 = input.address;
|
|
18556
18611
|
while (!charws(CLOSE_PAREN2)) {
|
|
18557
18612
|
input.begin();
|
|
18558
18613
|
const elementResult = parseInlineElement(expressID);
|
|
@@ -18583,7 +18638,7 @@ var StepParser = class extends StepHeaderParser {
|
|
|
18583
18638
|
return syntaxError();
|
|
18584
18639
|
}
|
|
18585
18640
|
whitespace();
|
|
18586
|
-
const startElement = input.
|
|
18641
|
+
const startElement = input.address;
|
|
18587
18642
|
let stackDepth = 1;
|
|
18588
18643
|
inlineElements = void 0;
|
|
18589
18644
|
while (stackDepth > 0) {
|
|
@@ -20734,18 +20789,24 @@ var StepModelBase = class {
|
|
|
20734
20789
|
* Construct this step model with its matching schema, a buffer to read from and an element index.
|
|
20735
20790
|
*
|
|
20736
20791
|
* @param schema The Step schema this is based on.
|
|
20737
|
-
* @param buffer_ The buffer to read this from.
|
|
20792
|
+
* @param buffer_ The buffer to read this from. Pass `undefined` together
|
|
20793
|
+
* with `provider` to build a model whose source is windowed from
|
|
20794
|
+
* construction (e.g. a streaming open — see buildModelStreaming); the
|
|
20795
|
+
* synchronous read paths (geometry extraction) then require the relevant
|
|
20796
|
+
* ranges to be resident, exactly as after `spillSourceToExternalStore`.
|
|
20738
20797
|
* @param elementIndex The element index for this, parsed or deserialized - note this takes
|
|
20739
20798
|
* ownership of this array in the sense it will modify values/unfold inline elements etc.
|
|
20799
|
+
* @param provider Optional pre-built buffer provider. When omitted, a
|
|
20800
|
+
* resident provider over `buffer_` is used (the classic path).
|
|
20740
20801
|
*/
|
|
20741
|
-
constructor(schema, buffer_, elementIndex) {
|
|
20802
|
+
constructor(schema, buffer_, elementIndex, provider) {
|
|
20742
20803
|
this.schema = schema;
|
|
20743
20804
|
this.buffer_ = buffer_;
|
|
20744
20805
|
this.vtableBuilder_ = new StepVtableBuilder();
|
|
20745
20806
|
this.descriptorCache_ = [];
|
|
20746
20807
|
this.elementMemoization = true;
|
|
20747
20808
|
this.nullOnErrors = true;
|
|
20748
|
-
this.bufferProvider_ = new ResidentStepBufferProvider(buffer_);
|
|
20809
|
+
this.bufferProvider_ = provider ?? new ResidentStepBufferProvider(buffer_);
|
|
20749
20810
|
const localElementIndex = elementIndex;
|
|
20750
20811
|
let where = 0;
|
|
20751
20812
|
const firstInlineElement = localElementIndex.length;
|
|
@@ -86539,11 +86600,13 @@ var IfcStepModel = class extends StepModelBase {
|
|
|
86539
86600
|
* Construct this model given a buffer containing the data and the parsed data index on that,
|
|
86540
86601
|
* adding the typeIndex on top of that.
|
|
86541
86602
|
*
|
|
86542
|
-
* @param buffer The buffer to values from
|
|
86603
|
+
* @param buffer The buffer to values from, or `undefined` with `provider`
|
|
86604
|
+
* set for a windowed (streaming) source.
|
|
86543
86605
|
* @param elementIndex The parsed index to elements in the STEP.
|
|
86606
|
+
* @param provider Optional pre-built buffer provider (windowed source).
|
|
86544
86607
|
*/
|
|
86545
|
-
constructor(buffer, elementIndex) {
|
|
86546
|
-
super(schema_ifc_gen_default, buffer, elementIndex);
|
|
86608
|
+
constructor(buffer, elementIndex, provider) {
|
|
86609
|
+
super(schema_ifc_gen_default, buffer, elementIndex, provider);
|
|
86547
86610
|
this.externalMappingType = ifc_step_external_mapping_default;
|
|
86548
86611
|
this.geometry = new IfcModelGeometry(this);
|
|
86549
86612
|
this.voidGeometry = new IfcModelGeometry(this, true);
|
|
@@ -86557,7 +86620,76 @@ var IfcStepModel = class extends StepModelBase {
|
|
|
86557
86620
|
}
|
|
86558
86621
|
};
|
|
86559
86622
|
|
|
86623
|
+
// compiled/src/step/parsing/streaming_index_builder.js
|
|
86624
|
+
function buildIndexStreaming(source, parser210, pool3) {
|
|
86625
|
+
const fileSize = source.byteLength;
|
|
86626
|
+
let windowBytes = Math.max(pool3, MIN_WINDOW);
|
|
86627
|
+
for (; ; ) {
|
|
86628
|
+
const window2 = new Uint8Array(windowBytes);
|
|
86629
|
+
let windowStartFile = 0;
|
|
86630
|
+
let windowLen = source.read(0, windowBytes, window2, 0);
|
|
86631
|
+
let bytesRead = windowLen;
|
|
86632
|
+
const input = new ParsingBuffer(window2, 0, windowLen);
|
|
86633
|
+
const [header, headerResult] = parser210.parseHeader(input);
|
|
86634
|
+
if (headerResult !== ParseResult.COMPLETE) {
|
|
86635
|
+
return {
|
|
86636
|
+
header,
|
|
86637
|
+
elements: [],
|
|
86638
|
+
result: headerResult,
|
|
86639
|
+
stats: { pool: pool3, windowBytes, slides: 0, maxRecordLen: 0, bytesRead }
|
|
86640
|
+
};
|
|
86641
|
+
}
|
|
86642
|
+
const slideThreshold = windowBytes >> 1;
|
|
86643
|
+
let slides = 0;
|
|
86644
|
+
let maxRecordLen = 0;
|
|
86645
|
+
let prevBoundaryFile = windowStartFile + input.cursor;
|
|
86646
|
+
const onRecordBoundary = (buffer) => {
|
|
86647
|
+
const cursor = buffer.cursor;
|
|
86648
|
+
const recordFileStart = windowStartFile + cursor;
|
|
86649
|
+
const recordLen = recordFileStart - prevBoundaryFile;
|
|
86650
|
+
if (recordLen > maxRecordLen) {
|
|
86651
|
+
maxRecordLen = recordLen;
|
|
86652
|
+
}
|
|
86653
|
+
prevBoundaryFile = recordFileStart;
|
|
86654
|
+
if (windowStartFile + windowLen >= fileSize) {
|
|
86655
|
+
return;
|
|
86656
|
+
}
|
|
86657
|
+
if (cursor < slideThreshold) {
|
|
86658
|
+
return;
|
|
86659
|
+
}
|
|
86660
|
+
const tail = windowLen - cursor;
|
|
86661
|
+
window2.copyWithin(0, cursor, windowLen);
|
|
86662
|
+
const want = windowBytes - tail;
|
|
86663
|
+
const got = source.read(windowStartFile + windowLen, want, window2, tail);
|
|
86664
|
+
bytesRead += got;
|
|
86665
|
+
windowLen = tail + got;
|
|
86666
|
+
windowStartFile = recordFileStart;
|
|
86667
|
+
buffer.rebaseWindow(window2, 0, windowLen, windowStartFile);
|
|
86668
|
+
++slides;
|
|
86669
|
+
};
|
|
86670
|
+
const [index, result] = parser210.parseDataBlockStreamed(input, onRecordBoundary);
|
|
86671
|
+
const stoppedShort = result !== ParseResult.COMPLETE;
|
|
86672
|
+
const notAtEof = windowStartFile + windowLen < fileSize;
|
|
86673
|
+
if (stoppedShort && notAtEof) {
|
|
86674
|
+
windowBytes *= 2;
|
|
86675
|
+
continue;
|
|
86676
|
+
}
|
|
86677
|
+
const lastRecordLen = windowStartFile + input.cursor - prevBoundaryFile;
|
|
86678
|
+
if (lastRecordLen > maxRecordLen) {
|
|
86679
|
+
maxRecordLen = lastRecordLen;
|
|
86680
|
+
}
|
|
86681
|
+
return {
|
|
86682
|
+
header,
|
|
86683
|
+
elements: index.elements,
|
|
86684
|
+
result,
|
|
86685
|
+
stats: { pool: pool3, windowBytes, slides, maxRecordLen, bytesRead }
|
|
86686
|
+
};
|
|
86687
|
+
}
|
|
86688
|
+
}
|
|
86689
|
+
var MIN_WINDOW = 4 * 1024;
|
|
86690
|
+
|
|
86560
86691
|
// compiled/src/ifc/ifc_step_parser.js
|
|
86692
|
+
var DEFAULT_STREAM_POOL_BYTES = 1024 * 1024;
|
|
86561
86693
|
var IfcStepParser = class extends StepParser {
|
|
86562
86694
|
/**
|
|
86563
86695
|
* Construct the IFC step parser.
|
|
@@ -86590,6 +86722,40 @@ var IfcStepParser = class extends StepParser {
|
|
|
86590
86722
|
const [itemIndex, parseResult] = await this.parseDataBlockAsync(input, onProgress);
|
|
86591
86723
|
return [parseResult, new IfcStepModel(input.buffer, itemIndex.elements)];
|
|
86592
86724
|
}
|
|
86725
|
+
/**
|
|
86726
|
+
* Build a model by streaming the source through a bounded moving window
|
|
86727
|
+
* (see buildIndexStreaming / M0) rather than parsing one resident buffer,
|
|
86728
|
+
* then backing the model with a windowed provider over `store` — so the
|
|
86729
|
+
* source is never held fully resident in the JS heap.
|
|
86730
|
+
*
|
|
86731
|
+
* `source` serves the parse (synchronous windowed reads — on a worker this
|
|
86732
|
+
* is an OPFS sync-access handle; in node/tests a file descriptor or buffer)
|
|
86733
|
+
* and `store` serves the model's post-parse property access (asynchronous
|
|
86734
|
+
* windowed reads paged in on demand — OPFS `File.slice()` in the browser).
|
|
86735
|
+
* Both view the same file bytes, so the file-absolute addresses the index
|
|
86736
|
+
* records resolve identically through either.
|
|
86737
|
+
*
|
|
86738
|
+
* NOTE (M1 scope): this delivers the bounded-memory *parse*. Synchronous
|
|
86739
|
+
* geometry extraction still needs its record ranges resident — as after
|
|
86740
|
+
* `spillSourceToExternalStore` — so a caller that extracts geometry must
|
|
86741
|
+
* `ensureResident` first (demand-driven geometry is M3). Property / index
|
|
86742
|
+
* access works directly via the async surfaces.
|
|
86743
|
+
*
|
|
86744
|
+
* @param source Synchronous byte source feeding the streaming parse.
|
|
86745
|
+
* @param store Async external store backing the windowed model.
|
|
86746
|
+
* @param opts Optional window sizing: `pool` (parse window),
|
|
86747
|
+
* `chunkBytes` / `maxResidentChunks` (model window).
|
|
86748
|
+
* @return {[ParseResult, IfcStepModel | undefined]} The parse result and
|
|
86749
|
+
* the windowed model.
|
|
86750
|
+
*/
|
|
86751
|
+
parseStreamToModel(source, store, opts) {
|
|
86752
|
+
if (store.byteLength !== source.byteLength) {
|
|
86753
|
+
throw new Error(`Streaming store byteLength ${store.byteLength} does not match source byteLength ${source.byteLength}`);
|
|
86754
|
+
}
|
|
86755
|
+
const { elements, result } = buildIndexStreaming(source, this, opts?.pool ?? DEFAULT_STREAM_POOL_BYTES);
|
|
86756
|
+
const provider = new WindowedStepBufferProvider(store, opts?.chunkBytes, opts?.maxResidentChunks);
|
|
86757
|
+
return [result, new IfcStepModel(void 0, elements, provider)];
|
|
86758
|
+
}
|
|
86593
86759
|
};
|
|
86594
86760
|
IfcStepParser.Instance = new IfcStepParser();
|
|
86595
86761
|
var ifc_step_parser_default = IfcStepParser;
|