@bldrs-ai/conway 1.399.1223 → 1.401.1237

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/compiled/Dist/ConwayGeomWasmNode.js +0 -0
  2. package/compiled/Dist/ConwayGeomWasmNodeMT.js +0 -0
  3. package/compiled/Dist/ConwayGeomWasmWeb.js +0 -0
  4. package/compiled/Dist/ConwayGeomWasmWebMT.js +1 -1
  5. package/compiled/Dist/ConwayGeomWasmWebMT.wasm +0 -0
  6. package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmNode.js +0 -0
  7. package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmNodeMT.js +0 -0
  8. package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmWeb.js +0 -0
  9. package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmWebMT.js +1 -1
  10. package/compiled/dependencies/conway-geom/Dist/ConwayGeomWasmWebMT.wasm +0 -0
  11. package/compiled/examples/browser-bundled.cjs +184 -11
  12. package/compiled/examples/cli-bundled.cjs +213 -40
  13. package/compiled/examples/cli-step-bundled.cjs +105 -37
  14. package/compiled/examples/validator-bundled.cjs +184 -11
  15. package/compiled/src/ifc/ifc_step_model.d.ts +5 -2
  16. package/compiled/src/ifc/ifc_step_model.d.ts.map +1 -1
  17. package/compiled/src/ifc/ifc_step_model.js +5 -3
  18. package/compiled/src/ifc/ifc_step_parser.d.ts +36 -0
  19. package/compiled/src/ifc/ifc_step_parser.d.ts.map +1 -1
  20. package/compiled/src/ifc/ifc_step_parser.js +40 -0
  21. package/compiled/src/ifc/ifc_stream_model.test.d.ts +2 -0
  22. package/compiled/src/ifc/ifc_stream_model.test.d.ts.map +1 -0
  23. package/compiled/src/ifc/ifc_stream_model.test.js +70 -0
  24. package/compiled/src/parsing/parsing_buffer.d.ts +23 -0
  25. package/compiled/src/parsing/parsing_buffer.d.ts.map +1 -1
  26. package/compiled/src/parsing/parsing_buffer.js +31 -0
  27. package/compiled/src/step/parsing/byte_source.d.ts +55 -0
  28. package/compiled/src/step/parsing/byte_source.d.ts.map +1 -0
  29. package/compiled/src/step/parsing/byte_source.js +35 -0
  30. package/compiled/src/step/parsing/incremental_type_index.d.ts +64 -0
  31. package/compiled/src/step/parsing/incremental_type_index.d.ts.map +1 -0
  32. package/compiled/src/step/parsing/incremental_type_index.js +92 -0
  33. package/compiled/src/step/parsing/incremental_type_index.test.d.ts +2 -0
  34. package/compiled/src/step/parsing/incremental_type_index.test.d.ts.map +1 -0
  35. package/compiled/src/step/parsing/incremental_type_index.test.js +55 -0
  36. package/compiled/src/step/parsing/step_parser.d.ts +19 -0
  37. package/compiled/src/step/parsing/step_parser.d.ts.map +1 -1
  38. package/compiled/src/step/parsing/step_parser.js +48 -4
  39. package/compiled/src/step/parsing/streaming_index_builder.d.ts +70 -0
  40. package/compiled/src/step/parsing/streaming_index_builder.d.ts.map +1 -0
  41. package/compiled/src/step/parsing/streaming_index_builder.js +125 -0
  42. package/compiled/src/step/parsing/streaming_index_builder.test.d.ts +2 -0
  43. package/compiled/src/step/parsing/streaming_index_builder.test.d.ts.map +1 -0
  44. package/compiled/src/step/parsing/streaming_index_builder.test.js +107 -0
  45. package/compiled/src/step/parsing/streaming_record_dispatcher.d.ts +55 -0
  46. package/compiled/src/step/parsing/streaming_record_dispatcher.d.ts.map +1 -0
  47. package/compiled/src/step/parsing/streaming_record_dispatcher.js +67 -0
  48. package/compiled/src/step/parsing/streaming_record_dispatcher.test.d.ts +2 -0
  49. package/compiled/src/step/parsing/streaming_record_dispatcher.test.d.ts.map +1 -0
  50. package/compiled/src/step/parsing/streaming_record_dispatcher.test.js +66 -0
  51. package/compiled/src/step/step_model_base.d.ts +9 -3
  52. package/compiled/src/step/step_model_base.d.ts.map +1 -1
  53. package/compiled/src/step/step_model_base.js +9 -3
  54. package/compiled/src/version/version.js +1 -1
  55. package/compiled/tsconfig.tsbuildinfo +1 -1
  56. package/package.json +1 -1
@@ -0,0 +1,55 @@
1
+ /**
2
+ * A random-access, forward-readable byte source for the streaming parser.
3
+ *
4
+ * The streaming index builder (see streaming_index_builder.ts) reads the
5
+ * source sequentially into a small moving window, so a `ByteSource` only has
6
+ * to satisfy positioned reads — it never needs the whole file resident. The
7
+ * in-memory `BufferByteSource` here is for tests and the resident case; a
8
+ * file-descriptor source (node) or an HTTP-Range source (M4) implements the
9
+ * same shape without holding the file in the JS heap.
10
+ *
11
+ * M0 keeps reads synchronous to reuse the existing synchronous parse loop
12
+ * unchanged. The asynchronous variant (network pull-parser) is M4.
13
+ */
14
+ export interface ByteSource {
15
+ /** Total length of the source in bytes. */
16
+ readonly byteLength: number;
17
+ /**
18
+ * Read up to `length` bytes starting at `offset` into `into` at
19
+ * `intoOffset`, returning the number of bytes actually copied (fewer than
20
+ * `length` only at end of source).
21
+ *
22
+ * @param offset Absolute source offset to read from.
23
+ * @param length Maximum number of bytes to read.
24
+ * @param into Destination buffer.
25
+ * @param intoOffset Offset within `into` to write at.
26
+ * @return {number} The number of bytes copied.
27
+ */
28
+ read(offset: number, length: number, into: Uint8Array, intoOffset: number): number;
29
+ }
30
+ /**
31
+ * A `ByteSource` backed by an in-memory `Uint8Array`. Reads are `subarray`
32
+ * copies into the destination window. Used by tests and the resident path;
33
+ * note it does hold the whole buffer (that residency is the source's, not the
34
+ * parser's — the parser still only touches a window).
35
+ */
36
+ export declare class BufferByteSource implements ByteSource {
37
+ private readonly buffer;
38
+ /**
39
+ * @param buffer The backing bytes.
40
+ */
41
+ constructor(buffer: Uint8Array);
42
+ /**
43
+ * @return {number} The buffer length.
44
+ */
45
+ get byteLength(): number;
46
+ /**
47
+ * @param offset Absolute source offset to read from.
48
+ * @param length Maximum number of bytes to read.
49
+ * @param into Destination buffer.
50
+ * @param intoOffset Offset within `into` to write at.
51
+ * @return {number} The number of bytes copied.
52
+ */
53
+ read(offset: number, length: number, into: Uint8Array, intoOffset: number): number;
54
+ }
55
+ //# sourceMappingURL=byte_source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"byte_source.d.ts","sourceRoot":"","sources":["../../../../src/step/parsing/byte_source.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,UAAU;IAEzB,2CAA2C;IAC3C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAE3B;;;;;;;;;;OAUG;IACH,IAAI,CAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAI,MAAM,CAAA;CACrF;AAED;;;;;GAKG;AACH,qBAAa,gBAAiB,YAAW,UAAU;IAKpC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHpC;;OAEG;gBAC2B,MAAM,EAAE,UAAU;IAEhD;;OAEG;IACH,IAAW,UAAU,IAAI,MAAM,CAE9B;IAED;;;;;;OAMG;IACI,IAAI,CACP,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAI,MAAM;CAYnF"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * A `ByteSource` backed by an in-memory `Uint8Array`. Reads are `subarray`
3
+ * copies into the destination window. Used by tests and the resident path;
4
+ * note it does hold the whole buffer (that residency is the source's, not the
5
+ * parser's — the parser still only touches a window).
6
+ */
7
+ export class BufferByteSource {
8
+ /**
9
+ * @param buffer The backing bytes.
10
+ */
11
+ constructor(buffer) {
12
+ this.buffer = buffer;
13
+ }
14
+ /**
15
+ * @return {number} The buffer length.
16
+ */
17
+ get byteLength() {
18
+ return this.buffer.length;
19
+ }
20
+ /**
21
+ * @param offset Absolute source offset to read from.
22
+ * @param length Maximum number of bytes to read.
23
+ * @param into Destination buffer.
24
+ * @param intoOffset Offset within `into` to write at.
25
+ * @return {number} The number of bytes copied.
26
+ */
27
+ read(offset, length, into, intoOffset) {
28
+ const end = Math.min(offset + length, this.buffer.length);
29
+ if (end <= offset) {
30
+ return 0;
31
+ }
32
+ into.set(this.buffer.subarray(offset, end), intoOffset);
33
+ return end - offset;
34
+ }
35
+ }
@@ -0,0 +1,64 @@
1
+ import { StepEntityConstructorAbstract } from "../step_entity_constructor.js";
2
+ import { RecordHandler } from "./streaming_record_dispatcher.js";
3
+ /**
4
+ * A type index built **incrementally** from the streaming parse's per-record
5
+ * events (M2), rather than from the finished element array. Feed its
6
+ * {@link handler} to a {@link StreamingRecordDispatcher} (or directly to
7
+ * `buildIndexStreaming`'s `onRecordIndexed`) and it accumulates, per concrete
8
+ * type, the set of express IDs seen — so the moment parsing reaches a record
9
+ * it is queryable, without waiting for end-of-parse.
10
+ *
11
+ * Queries take entity constructors and expand to their subtype closure via
12
+ * the generated `query` (conway #383), so `expressIDsOfTypes(IfcProduct)`
13
+ * unions every product subtype exactly as the resident model's type index
14
+ * does.
15
+ *
16
+ * Express IDs are held in per-type `Set`s, so the consumer is idempotent
17
+ * under the streaming builder's rare grow-and-restart (records re-fire from
18
+ * localID 0): re-adding an express ID is a no-op. Memory is O(records) — the
19
+ * same order as the element index it mirrors.
20
+ *
21
+ * Scope: membership is keyed on the raw parse `typeID`. External-mapping /
22
+ * complex records (typeID 0) are therefore not attributed to their mapped
23
+ * classes here — resolving those needs the record's `multiMapping`, which the
24
+ * event stream doesn't carry; that's the model's construction-time index. For
25
+ * the overwhelming majority of records (simple, one type each) this index is
26
+ * exact, which the parity test pins.
27
+ */
28
+ export declare class IncrementalTypeIndex<TypeIDType extends number> {
29
+ /** Concrete typeID → express IDs of records of exactly that type. */
30
+ private readonly byType_;
31
+ /**
32
+ * Record one indexed entity. Bound as {@link handler} for direct use as a
33
+ * dispatcher subscription / `onRecordIndexed` callback.
34
+ *
35
+ * @param localID Unused (kept for the RecordHandler shape).
36
+ * @param expressID The record's express ID.
37
+ * @param typeID The record's concrete type ID (undefined / 0 records are
38
+ * ignored — they carry no concrete queryable type here).
39
+ */
40
+ readonly handler: RecordHandler<TypeIDType>;
41
+ /**
42
+ * The distinct concrete type IDs seen so far.
43
+ *
44
+ * @return {IterableIterator<TypeIDType>} The concrete types.
45
+ */
46
+ concreteTypes(): IterableIterator<TypeIDType>;
47
+ /**
48
+ * Lazily iterate the express IDs of all records of the given types
49
+ * (including subtypes).
50
+ *
51
+ * @param types The entity constructors to query (subtype closures unioned).
52
+ * @return {IterableIterator<number>} Express IDs of matching records.
53
+ * @yields {number} Each matching express ID.
54
+ */
55
+ expressIDsOfTypes(...types: StepEntityConstructorAbstract<TypeIDType>[]): IterableIterator<number>;
56
+ /**
57
+ * Count records of the given types (including subtypes) seen so far.
58
+ *
59
+ * @param types The entity constructors to count.
60
+ * @return {number} The number of matching records.
61
+ */
62
+ count(...types: StepEntityConstructorAbstract<TypeIDType>[]): number;
63
+ }
64
+ //# sourceMappingURL=incremental_type_index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"incremental_type_index.d.ts","sourceRoot":"","sources":["../../../../src/step/parsing/incremental_type_index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,4BAA4B,CAAA;AAC1E,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAA;AAG7D;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,oBAAoB,CAAC,UAAU,SAAS,MAAM;IAEzD,qEAAqE;IACrE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;IAE7D;;;;;;;;OAQG;IACH,SAAgB,OAAO,EAAE,aAAa,CAAC,UAAU,CAAC,CAe/C;IAEH;;;;OAIG;IACI,aAAa,IAAI,gBAAgB,CAAC,UAAU,CAAC;IAIpD;;;;;;;OAOG;IACK,iBAAiB,CACrB,GAAG,KAAK,EAAE,6BAA6B,CAAC,UAAU,CAAC,EAAE,GACrD,gBAAgB,CAAC,MAAM,CAAC;IAc5B;;;;;OAKG;IACI,KAAK,CAAE,GAAG,KAAK,EAAE,6BAA6B,CAAC,UAAU,CAAC,EAAE,GAAI,MAAM;CAa9E"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * A type index built **incrementally** from the streaming parse's per-record
3
+ * events (M2), rather than from the finished element array. Feed its
4
+ * {@link handler} to a {@link StreamingRecordDispatcher} (or directly to
5
+ * `buildIndexStreaming`'s `onRecordIndexed`) and it accumulates, per concrete
6
+ * type, the set of express IDs seen — so the moment parsing reaches a record
7
+ * it is queryable, without waiting for end-of-parse.
8
+ *
9
+ * Queries take entity constructors and expand to their subtype closure via
10
+ * the generated `query` (conway #383), so `expressIDsOfTypes(IfcProduct)`
11
+ * unions every product subtype exactly as the resident model's type index
12
+ * does.
13
+ *
14
+ * Express IDs are held in per-type `Set`s, so the consumer is idempotent
15
+ * under the streaming builder's rare grow-and-restart (records re-fire from
16
+ * localID 0): re-adding an express ID is a no-op. Memory is O(records) — the
17
+ * same order as the element index it mirrors.
18
+ *
19
+ * Scope: membership is keyed on the raw parse `typeID`. External-mapping /
20
+ * complex records (typeID 0) are therefore not attributed to their mapped
21
+ * classes here — resolving those needs the record's `multiMapping`, which the
22
+ * event stream doesn't carry; that's the model's construction-time index. For
23
+ * the overwhelming majority of records (simple, one type each) this index is
24
+ * exact, which the parity test pins.
25
+ */
26
+ export class IncrementalTypeIndex {
27
+ constructor() {
28
+ /** Concrete typeID → express IDs of records of exactly that type. */
29
+ this.byType_ = new Map();
30
+ /**
31
+ * Record one indexed entity. Bound as {@link handler} for direct use as a
32
+ * dispatcher subscription / `onRecordIndexed` callback.
33
+ *
34
+ * @param localID Unused (kept for the RecordHandler shape).
35
+ * @param expressID The record's express ID.
36
+ * @param typeID The record's concrete type ID (undefined / 0 records are
37
+ * ignored — they carry no concrete queryable type here).
38
+ */
39
+ this.handler = (localID, expressID, typeID) => {
40
+ if (typeID === void 0) {
41
+ return;
42
+ }
43
+ let ids = this.byType_.get(typeID);
44
+ if (ids === void 0) {
45
+ ids = new Set();
46
+ this.byType_.set(typeID, ids);
47
+ }
48
+ ids.add(expressID);
49
+ };
50
+ }
51
+ /**
52
+ * The distinct concrete type IDs seen so far.
53
+ *
54
+ * @return {IterableIterator<TypeIDType>} The concrete types.
55
+ */
56
+ concreteTypes() {
57
+ return this.byType_.keys();
58
+ }
59
+ /**
60
+ * Lazily iterate the express IDs of all records of the given types
61
+ * (including subtypes).
62
+ *
63
+ * @param types The entity constructors to query (subtype closures unioned).
64
+ * @return {IterableIterator<number>} Express IDs of matching records.
65
+ * @yields {number} Each matching express ID.
66
+ */
67
+ *expressIDsOfTypes(...types) {
68
+ const typeSet = types.length === 1 ? types[0].query :
69
+ new Set(types.flatMap((type) => type.query));
70
+ for (const typeID of typeSet) {
71
+ const ids = this.byType_.get(typeID);
72
+ if (ids !== void 0) {
73
+ yield* ids;
74
+ }
75
+ }
76
+ }
77
+ /**
78
+ * Count records of the given types (including subtypes) seen so far.
79
+ *
80
+ * @param types The entity constructors to count.
81
+ * @return {number} The number of matching records.
82
+ */
83
+ count(...types) {
84
+ const typeSet = types.length === 1 ? types[0].query :
85
+ new Set(types.flatMap((type) => type.query));
86
+ let total = 0;
87
+ for (const typeID of typeSet) {
88
+ total += this.byType_.get(typeID)?.size ?? 0;
89
+ }
90
+ return total;
91
+ }
92
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=incremental_type_index.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"incremental_type_index.test.d.ts","sourceRoot":"","sources":["../../../../src/step/parsing/incremental_type_index.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,55 @@
1
+ /* eslint-disable no-magic-numbers */
2
+ // M2b: a type index built incrementally from the streaming parse's record
3
+ // events must, once parsing finishes, hold the same membership as the
4
+ // resident model's type index — for every queried type (and its subtypes).
5
+ import * as fs from "fs";
6
+ import { beforeAll, describe, expect, test } from "@jest/globals";
7
+ import ParsingBuffer from "../../parsing/parsing_buffer.js";
8
+ import IfcStepParser from "../../ifc/ifc_step_parser.js";
9
+ import { BufferByteSource } from "./byte_source.js";
10
+ import { buildIndexStreaming } from "./streaming_index_builder.js";
11
+ import { IncrementalTypeIndex } from "./incremental_type_index.js";
12
+ import { StreamingRecordDispatcher } from "./streaming_record_dispatcher.js";
13
+ import { ParseResult } from "./step_parser.js";
14
+ import { IfcRoot, IfcProduct, IfcWall, IfcPropertySet } from "../../ifc/ifc4_gen/index.js";
15
+ let bytes;
16
+ let model;
17
+ beforeAll(() => {
18
+ bytes = new Uint8Array(fs.readFileSync("data/index.ifc"));
19
+ const input = new ParsingBuffer(bytes);
20
+ IfcStepParser.Instance.parseHeader(input);
21
+ model = IfcStepParser.Instance.parseDataToModel(input)[1];
22
+ });
23
+ describe("IncrementalTypeIndex", () => {
24
+ /**
25
+ * Stream index.ifc, feeding an IncrementalTypeIndex, and return it.
26
+ *
27
+ * @return {IncrementalTypeIndex} The populated index.
28
+ */
29
+ function streamed() {
30
+ const index = new IncrementalTypeIndex();
31
+ const dispatcher = new StreamingRecordDispatcher();
32
+ dispatcher.onAnyRecord(index.handler);
33
+ const r = buildIndexStreaming(new BufferByteSource(bytes), IfcStepParser.Instance, 4 * 1024, dispatcher.onRecordIndexed);
34
+ expect(r.result).toBe(ParseResult.COMPLETE);
35
+ return index;
36
+ }
37
+ test.each([
38
+ ["IfcRoot", IfcRoot],
39
+ ["IfcProduct", IfcProduct],
40
+ ["IfcWall", IfcWall],
41
+ ["IfcPropertySet", IfcPropertySet],
42
+ ])("membership matches the resident type index for %s", (_name, ctor) => {
43
+ const index = streamed();
44
+ const incremental = new Set(index.expressIDsOfTypes(ctor));
45
+ const resident = new Set(model.expressIDsOfTypes(ctor));
46
+ expect(incremental).toEqual(resident);
47
+ expect(index.count(ctor)).toBe(resident.size);
48
+ });
49
+ test("a multi-type query unions the subtype closures", () => {
50
+ const index = streamed();
51
+ const incremental = new Set(index.expressIDsOfTypes(IfcWall, IfcPropertySet));
52
+ const resident = new Set(model.expressIDsOfTypes(IfcWall, IfcPropertySet));
53
+ expect(incremental).toEqual(resident);
54
+ });
55
+ });
@@ -116,6 +116,25 @@ export default class StepParser<TypeIDType> extends StepHeaderParser {
116
116
  * @return {BlockParseResult} The parsing result, including the index and result enum.
117
117
  */
118
118
  parseDataBlock(input: ParsingBuffer, onProgress?: ParseProgressCallback): BlockParseResult<TypeIDType>;
119
+ /**
120
+ * Streaming driver over parseDataBlockIncremental: identical parse (same
121
+ * generator body) but invokes `onRecordBoundary` at every top-level record
122
+ * boundary so a caller feeding the parser from a moving window can slide
123
+ * that window forward while the rewind stack is empty. See
124
+ * streaming_index_builder.ts for the coordinator that owns the window.
125
+ *
126
+ * @param input The input parsing buffer, positioned at the data section.
127
+ * @param onRecordBoundary Called at each top-level record boundary with the
128
+ * buffer; the callback may rebase the buffer's window in place.
129
+ * @param onRecordIndexed Called as each top-level record is indexed, with
130
+ * its localID, expressID and typeID (0 for external-mapping records) — the
131
+ * seam for incremental semantic consumers (type index, roots registry,
132
+ * names skeleton). Must be synchronous and cheap; expensive work belongs on
133
+ * a demand queue, not the parse path.
134
+ * @param onProgress Optional byte-cursor progress callback.
135
+ * @return {BlockParseResult} The parsing result, including the index and result enum.
136
+ */
137
+ parseDataBlockStreamed(input: ParsingBuffer, onRecordBoundary: (input: ParsingBuffer) => void, onRecordIndexed?: (localID: number, expressID: number, typeID: TypeIDType | undefined) => void, onProgress?: ParseProgressCallback): BlockParseResult<TypeIDType>;
119
138
  /**
120
139
  * Cooperative variant of parseDataBlock: identical parse (same generator
121
140
  * body), but periodically awaits a macrotask so the event loop can run —
@@ -1 +1 @@
1
- {"version":3,"file":"step_parser.d.ts","sourceRoot":"","sources":["../../../../src/step/parsing/step_parser.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"step_parser.d.ts","sourceRoot":"","sources":["../../../../src/step/parsing/step_parser.ts"],"names":[],"mappings":"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"}
@@ -310,6 +310,34 @@ export default class StepParser extends StepHeaderParser {
310
310
  onProgress?.(next.value);
311
311
  }
312
312
  }
313
+ /**
314
+ * Streaming driver over parseDataBlockIncremental: identical parse (same
315
+ * generator body) but invokes `onRecordBoundary` at every top-level record
316
+ * boundary so a caller feeding the parser from a moving window can slide
317
+ * that window forward while the rewind stack is empty. See
318
+ * streaming_index_builder.ts for the coordinator that owns the window.
319
+ *
320
+ * @param input The input parsing buffer, positioned at the data section.
321
+ * @param onRecordBoundary Called at each top-level record boundary with the
322
+ * buffer; the callback may rebase the buffer's window in place.
323
+ * @param onRecordIndexed Called as each top-level record is indexed, with
324
+ * its localID, expressID and typeID (0 for external-mapping records) — the
325
+ * seam for incremental semantic consumers (type index, roots registry,
326
+ * names skeleton). Must be synchronous and cheap; expensive work belongs on
327
+ * a demand queue, not the parse path.
328
+ * @param onProgress Optional byte-cursor progress callback.
329
+ * @return {BlockParseResult} The parsing result, including the index and result enum.
330
+ */
331
+ parseDataBlockStreamed(input, onRecordBoundary, onRecordIndexed, onProgress) {
332
+ const parser = this.parseDataBlockIncremental(input, onRecordBoundary, onRecordIndexed);
333
+ while (true) {
334
+ const next = parser.next();
335
+ if (next.done === true) {
336
+ return next.value;
337
+ }
338
+ onProgress?.(next.value);
339
+ }
340
+ }
313
341
  /**
314
342
  * Cooperative variant of parseDataBlock: identical parse (same generator
315
343
  * body), but periodically awaits a macrotask so the event loop can run —
@@ -347,7 +375,7 @@ export default class StepParser extends StepHeaderParser {
347
375
  * @yields {number} The current byte cursor within the input buffer.
348
376
  * @return {BlockParseResult} The parsing result, including the index and result enum.
349
377
  */
350
- *parseDataBlockIncremental(input) {
378
+ *parseDataBlockIncremental(input, onRecordBoundary, onRecordIndexed) {
351
379
  const indexResult = { elements: [] };
352
380
  const match = input.match;
353
381
  const comment = () => match(commentParser);
@@ -394,7 +422,10 @@ export default class StepParser extends StepHeaderParser {
394
422
  return syntaxError();
395
423
  }
396
424
  whitespace();
397
- const startElement = input.cursor;
425
+ // File-absolute (== input.cursor when initialOffset is 0, i.e. every
426
+ // resident parse; file-absolute under a streaming moving window so the
427
+ // recorded address/length stay stable as the window slides).
428
+ const startElement = input.address;
398
429
  let stackDepth = 1;
399
430
  const savedInlineElements = inlineElements;
400
431
  inlineElements = void 0;
@@ -492,6 +523,11 @@ export default class StepParser extends StepHeaderParser {
492
523
  if ((++parsedElementCount & PARSE_PROGRESS_ELEMENT_MASK) === 0) {
493
524
  yield input.cursor;
494
525
  }
526
+ // Top-level record boundary: the rewind stack is empty and the cursor
527
+ // sits at the next record's leading whitespace/`#`. A streaming driver
528
+ // uses this to slide its moving window forward (see
529
+ // streaming_index_builder.ts). No-op on the resident path.
530
+ onRecordBoundary?.(input);
495
531
  if (!charws(HASH)) {
496
532
  if (tokenws(END_SECTION)) {
497
533
  return parseResult(ParseResult.COMPLETE);
@@ -516,7 +552,10 @@ export default class StepParser extends StepHeaderParser {
516
552
  }
517
553
  whitespace();
518
554
  inlineElements = void 0;
519
- const startElement = input.cursor;
555
+ // File-absolute (== input.cursor when initialOffset is 0, i.e. every
556
+ // resident parse; file-absolute under a streaming moving window so the
557
+ // recorded address/length stay stable as the window slides).
558
+ const startElement = input.address;
520
559
  // todo, loop and read inline then add them to a special "External Mapping" node.
521
560
  while (!charws(CLOSE_PAREN)) {
522
561
  input.begin();
@@ -530,6 +569,7 @@ export default class StepParser extends StepHeaderParser {
530
569
  if (!charws(SEMICOLON)) {
531
570
  return syntaxError();
532
571
  }
572
+ onRecordIndexed?.(indexResult.elements.length, expressID, 0);
533
573
  indexResult.elements.push({
534
574
  address: startElement,
535
575
  length: input.address - startElement,
@@ -547,7 +587,10 @@ export default class StepParser extends StepHeaderParser {
547
587
  return syntaxError();
548
588
  }
549
589
  whitespace();
550
- const startElement = input.cursor;
590
+ // File-absolute (== input.cursor when initialOffset is 0, i.e. every
591
+ // resident parse; file-absolute under a streaming moving window so the
592
+ // recorded address/length stay stable as the window slides).
593
+ const startElement = input.address;
551
594
  let stackDepth = 1;
552
595
  inlineElements = void 0;
553
596
  while (stackDepth > 0) {
@@ -620,6 +663,7 @@ export default class StepParser extends StepHeaderParser {
620
663
  if (!charws(SEMICOLON)) {
621
664
  return syntaxError();
622
665
  }
666
+ onRecordIndexed?.(indexResult.elements.length, expressID, foundItem);
623
667
  indexResult.elements.push({
624
668
  address: startElement,
625
669
  length: input.address - startElement,
@@ -0,0 +1,70 @@
1
+ import { ByteSource } from "./byte_source.js";
2
+ import StepParser, { ParseResult, StepHeader, StepIndexEntry } from "./step_parser.js";
3
+ /**
4
+ * Diagnostics from a streaming index build — how hard the moving window had
5
+ * to work, so a pool-size sweep can compare cost against a resident parse.
6
+ */
7
+ export interface StreamingIndexStats {
8
+ /** Target window size in bytes (the pool). */
9
+ pool: number;
10
+ /** Physical window buffer size actually used (grows past `pool` only if a
11
+ * single record exceeds the pool). */
12
+ windowBytes: number;
13
+ /** Number of times the window slid forward. */
14
+ slides: number;
15
+ /** Largest single top-level record observed, in bytes. */
16
+ maxRecordLen: number;
17
+ /** Total bytes read from the source (≈ file size + re-reads on growth). */
18
+ bytesRead: number;
19
+ }
20
+ /**
21
+ * The output of a streaming index build: the same element index a resident
22
+ * `parseDataBlock` produces, plus the header and window diagnostics.
23
+ */
24
+ export interface StreamingIndexResult<TypeIDType> {
25
+ header: StepHeader;
26
+ elements: StepIndexEntry<TypeIDType>[];
27
+ result: ParseResult;
28
+ stats: StreamingIndexStats;
29
+ }
30
+ /**
31
+ * Build the entity index by streaming a `ByteSource` through a fixed-size
32
+ * moving window, instead of parsing one resident buffer. The parse loop is
33
+ * byte-for-byte the resident one (`StepParser.parseDataBlockStreamed` drives
34
+ * the same generator); this coordinator only owns the window: it fills it,
35
+ * parses the header from the first fill, then slides the window forward at
36
+ * top-level record boundaries as the parser advances.
37
+ *
38
+ * Because the parser records file-absolute addresses and its rewind stack is
39
+ * empty at every top-level boundary, sliding there is transparent: the
40
+ * unconsumed tail is copied to the front, fresh bytes are appended, and the
41
+ * buffer is rebased so `address` keeps its file-absolute value. Peak JS heap
42
+ * for the index build is therefore `window + index columns`, independent of
43
+ * file size.
44
+ *
45
+ * The window slides only once the cursor passes `pool / 2`, bounding the
46
+ * memmove frequency; a record up to `pool / 2` bytes always fits after a
47
+ * slide. If a single record exceeds that (never on the current corpus, whose
48
+ * largest STEP record is ~25 KB), the whole parse restarts from the
49
+ * beginning with the window doubled, and repeats until every record fits —
50
+ * correctness over the pathological case, at the cost of a re-scan. (M1's
51
+ * production path will instead grow in place / restart from the last
52
+ * boundary; from-scratch keeps the spike simple.)
53
+ *
54
+ * @param source The byte source.
55
+ * @param parser The STEP parser (typed to the schema).
56
+ * @param pool Target window size in bytes.
57
+ * @param onRecordIndexed Optional per-record event, invoked live as each
58
+ * top-level record is indexed with its (localID, expressID, typeID) — the
59
+ * seam for incremental semantic consumers (M2). localIDs are dense and
60
+ * assigned in parse order from 0. On the rare grow-and-restart (a single
61
+ * record larger than the window — never on real files, whose largest STEP
62
+ * record is ~25 KB), the parse re-runs from the start and records re-fire
63
+ * from localID 0; consumers must therefore be idempotent by localID /
64
+ * expressID (the standard consumers — type index keyed by localID, roots
65
+ * registry keyed by expressID — are). Must be synchronous and cheap;
66
+ * expensive work belongs on a demand queue, not the parse path.
67
+ * @return {StreamingIndexResult} The index, header, result and diagnostics.
68
+ */
69
+ export declare function buildIndexStreaming<TypeIDType>(source: ByteSource, parser: StepParser<TypeIDType>, pool: number, onRecordIndexed?: (localID: number, expressID: number, typeID: TypeIDType | undefined) => void): StreamingIndexResult<TypeIDType>;
70
+ //# sourceMappingURL=streaming_index_builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streaming_index_builder.d.ts","sourceRoot":"","sources":["../../../../src/step/parsing/streaming_index_builder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,UAAU,EAAE,EACjB,WAAW,EACX,UAAU,EACV,cAAc,EACf,MAAM,eAAe,CAAA;AAGtB;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAElC,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAA;IAEZ;0CACsC;IACtC,WAAW,EAAE,MAAM,CAAA;IAEnB,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAA;IAEd,0DAA0D;IAC1D,YAAY,EAAE,MAAM,CAAA;IAEpB,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAA;CAClB;AAGD;;;GAGG;AACH,MAAM,WAAW,oBAAoB,CAAC,UAAU;IAC9C,MAAM,EAAE,UAAU,CAAA;IAClB,QAAQ,EAAE,cAAc,CAAC,UAAU,CAAC,EAAE,CAAA;IACtC,MAAM,EAAE,WAAW,CAAA;IACnB,KAAK,EAAE,mBAAmB,CAAA;CAC3B;AAGD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAC1C,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,UAAU,CAAC,UAAU,CAAC,EAC9B,IAAI,EAAE,MAAM,EACZ,eAAe,CAAC,EACd,CAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,SAAS,KAAM,IAAI,GAChF,oBAAoB,CAAC,UAAU,CAAC,CA4GnC"}