@chestnutlabs/gcode-parser 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -0
- package/dist/growable.d.ts +96 -0
- package/dist/growable.d.ts.map +1 -0
- package/dist/growable.js +217 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/parse.d.ts +163 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +651 -0
- package/dist/protocol.d.ts +117 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +29 -0
- package/dist/session.d.ts +73 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +156 -0
- package/dist/streaming.d.ts +42 -0
- package/dist/streaming.d.ts.map +1 -0
- package/dist/streaming.js +162 -0
- package/dist/worker-core.d.ts +69 -0
- package/dist/worker-core.d.ts.map +1 -0
- package/dist/worker-core.js +309 -0
- package/dist/worker-slim.d.ts +2 -0
- package/dist/worker-slim.d.ts.map +1 -0
- package/dist/worker-slim.js +14 -0
- package/dist/worker.d.ts +2 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +34 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# @chestnutlabs/gcode-parser
|
|
2
|
+
|
|
3
|
+
Worker-safe G-code parse core and session client for the Chestnut Labs G-code Preview stack
|
|
4
|
+
(design: DD-003). Parses `.gcode` / `.gcode.3mf` **off the main thread** into
|
|
5
|
+
[`ToolpathIR`](../toolpath-core), with streaming input, progressive partial previews for large
|
|
6
|
+
files, resource limits, cancellation, and an adversarial-input corpus behind it.
|
|
7
|
+
|
|
8
|
+
```ts
|
|
9
|
+
import { GcodeParseSession } from '@chestnutlabs/gcode-parser';
|
|
10
|
+
|
|
11
|
+
const session = new GcodeParseSession(); // batteries worker: all dialects + .gcode.3mf
|
|
12
|
+
const result = await session.parse(bytes, {
|
|
13
|
+
onPartial: (ir) => render(ir), // progressive preview
|
|
14
|
+
onProgress: (p) => bar(p)
|
|
15
|
+
});
|
|
16
|
+
render(result.ir);
|
|
17
|
+
session.dispose();
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Workers
|
|
21
|
+
|
|
22
|
+
- **Batteries default (zero setup):** the session creates its own worker via the bundler-native
|
|
23
|
+
`new Worker(new URL('./worker.js', import.meta.url))` pattern — all supported dialect adapters
|
|
24
|
+
plus `.gcode.3mf` container support. Vite resolves it out of the box (CI-tested).
|
|
25
|
+
- **Slim / custom:** pass a worker factory for the slim build (no dialects/containers), your own
|
|
26
|
+
adapter set via `createWorkerHandler(...)`, other bundlers, or strict-CSP environments.
|
|
27
|
+
|
|
28
|
+
Wire options accept dialect selection, container/plate selection (`plate` for multi-plate
|
|
29
|
+
`.gcode.3mf`), and resource limits. Most applications should consume this through
|
|
30
|
+
[`@chestnutlabs/gcode-preview-core`](../gcode-preview-core) or a framework adapter rather than
|
|
31
|
+
directly.
|
|
32
|
+
|
|
33
|
+
Part of [Chestnut Labs G-code Preview](../../README.md) · MIT
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Budget-aware growable SoA segment writer (DD-003 §7.2/§7.3).
|
|
3
|
+
*
|
|
4
|
+
* Accumulates segments directly into growable typed arrays (no intermediate object
|
|
5
|
+
* graphs) and keeps a byte-accurate account of every live working allocation. Any
|
|
6
|
+
* projected allocation — growth steps and the final right-size compaction, during
|
|
7
|
+
* which old and new capacity coexist — is checked against `maxBufferBytes` BEFORE
|
|
8
|
+
* it is performed. On budget exhaustion the writer reports failure and the parse
|
|
9
|
+
* stops at the current command boundary with a structured bounded result; it never
|
|
10
|
+
* throws an unhandled allocation error.
|
|
11
|
+
*/
|
|
12
|
+
export declare class BudgetExceededError extends Error {
|
|
13
|
+
readonly requestedBytes: number;
|
|
14
|
+
readonly accountedBytes: number;
|
|
15
|
+
readonly maxBufferBytes: number;
|
|
16
|
+
constructor(requestedBytes: number, accountedBytes: number, maxBufferBytes: number);
|
|
17
|
+
}
|
|
18
|
+
export interface SegmentRecord {
|
|
19
|
+
x0: number;
|
|
20
|
+
y0: number;
|
|
21
|
+
z0: number;
|
|
22
|
+
x1: number;
|
|
23
|
+
y1: number;
|
|
24
|
+
z1: number;
|
|
25
|
+
e: number;
|
|
26
|
+
feedrate: number;
|
|
27
|
+
kind: number;
|
|
28
|
+
tool: number;
|
|
29
|
+
layer: number;
|
|
30
|
+
srcByte: number;
|
|
31
|
+
}
|
|
32
|
+
export interface FinalChannels {
|
|
33
|
+
count: number;
|
|
34
|
+
x0: Float32Array;
|
|
35
|
+
y0: Float32Array;
|
|
36
|
+
z0: Float32Array;
|
|
37
|
+
x1: Float32Array;
|
|
38
|
+
y1: Float32Array;
|
|
39
|
+
z1: Float32Array;
|
|
40
|
+
e: Float32Array;
|
|
41
|
+
feedrate: Float32Array;
|
|
42
|
+
kind: Uint8Array;
|
|
43
|
+
tool: Uint16Array;
|
|
44
|
+
layer: Uint32Array;
|
|
45
|
+
feature: Uint8Array;
|
|
46
|
+
object: Uint32Array;
|
|
47
|
+
srcByte: Uint32Array;
|
|
48
|
+
}
|
|
49
|
+
export declare class SegmentWriter {
|
|
50
|
+
private readonly maxBufferBytes;
|
|
51
|
+
private capacity;
|
|
52
|
+
private _count;
|
|
53
|
+
private x0;
|
|
54
|
+
private y0;
|
|
55
|
+
private z0;
|
|
56
|
+
private x1;
|
|
57
|
+
private y1;
|
|
58
|
+
private z1;
|
|
59
|
+
private e;
|
|
60
|
+
private feedrate;
|
|
61
|
+
private kind;
|
|
62
|
+
private tool;
|
|
63
|
+
private layer;
|
|
64
|
+
private feature;
|
|
65
|
+
private object;
|
|
66
|
+
private srcByte;
|
|
67
|
+
/** Bytes of live typed-array capacity currently held by this writer. */
|
|
68
|
+
private accountedBytes;
|
|
69
|
+
/** Extra live bytes the caller wants included in the budget (line buffer, warnings). */
|
|
70
|
+
private externalBytes;
|
|
71
|
+
constructor(maxBufferBytes: number);
|
|
72
|
+
get count(): number;
|
|
73
|
+
get accounted(): number;
|
|
74
|
+
/** Report additional live working bytes (e.g., the line-drain buffer) into the budget. */
|
|
75
|
+
setExternalBytes(bytes: number): void;
|
|
76
|
+
/** Throws BudgetExceededError if `requested` more bytes would break the budget. */
|
|
77
|
+
private ensureBudget;
|
|
78
|
+
private allocate;
|
|
79
|
+
/** Append one segment. Throws BudgetExceededError when growth would break the budget. */
|
|
80
|
+
push(s: SegmentRecord): void;
|
|
81
|
+
/** Overwrite the layer channel for a segment range (used for post-hoc layer resolution). */
|
|
82
|
+
setLayerRange(start: number, end: number, layerIndex: number): void;
|
|
83
|
+
/** Zero the whole layer channel (non-planar clearing semantics). */
|
|
84
|
+
clearLayers(): void;
|
|
85
|
+
/**
|
|
86
|
+
* Copy a segment range into fresh right-sized arrays (progressive-preview
|
|
87
|
+
* snapshots, DD-004 §5.4 / issue #60). Budget-checked: the copies coexist with
|
|
88
|
+
* the live buffers until they are transferred away, so they count against
|
|
89
|
+
* `maxBufferBytes` at creation time. Throws BudgetExceededError when the copy
|
|
90
|
+
* would break the budget — callers skip the snapshot, never the parse.
|
|
91
|
+
*/
|
|
92
|
+
snapshotRange(start: number, end: number): FinalChannels;
|
|
93
|
+
/** Right-size to exact count. Budget-checked (old + new coexist during the copy). */
|
|
94
|
+
finalize(): FinalChannels;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=growable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"growable.d.ts","sourceRoot":"","sources":["../src/growable.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,qBAAa,mBAAoB,SAAQ,KAAK;aAE1B,cAAc,EAAE,MAAM;aACtB,cAAc,EAAE,MAAM;aACtB,cAAc,EAAE,MAAM;gBAFtB,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM;CAOzC;AAuBD,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,EAAE,MAAM,CAAC;IACV,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,YAAY,CAAC;IACjB,EAAE,EAAE,YAAY,CAAC;IACjB,EAAE,EAAE,YAAY,CAAC;IACjB,EAAE,EAAE,YAAY,CAAC;IACjB,EAAE,EAAE,YAAY,CAAC;IACjB,EAAE,EAAE,YAAY,CAAC;IACjB,CAAC,EAAE,YAAY,CAAC;IAChB,QAAQ,EAAE,YAAY,CAAC;IACvB,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,UAAU,CAAC;IACpB,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,WAAW,CAAC;CACtB;AAID,qBAAa,aAAa;IAwBZ,OAAO,CAAC,QAAQ,CAAC,cAAc;IAvB3C,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,MAAM,CAAK;IAEnB,OAAO,CAAC,EAAE,CAAgB;IAC1B,OAAO,CAAC,EAAE,CAAgB;IAC1B,OAAO,CAAC,EAAE,CAAgB;IAC1B,OAAO,CAAC,EAAE,CAAgB;IAC1B,OAAO,CAAC,EAAE,CAAgB;IAC1B,OAAO,CAAC,EAAE,CAAgB;IAC1B,OAAO,CAAC,CAAC,CAAgB;IACzB,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,IAAI,CAAc;IAC1B,OAAO,CAAC,IAAI,CAAe;IAC3B,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,OAAO,CAAe;IAE9B,wEAAwE;IACxE,OAAO,CAAC,cAAc,CAAK;IAC3B,wFAAwF;IACxF,OAAO,CAAC,aAAa,CAAK;gBAEG,cAAc,EAAE,MAAM;IAInD,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,0FAA0F;IAC1F,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIrC,mFAAmF;IACnF,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,QAAQ;IAwDhB,yFAAyF;IACzF,IAAI,CAAC,CAAC,EAAE,aAAa,GAAG,IAAI;IAsB5B,4FAA4F;IAC5F,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAInE,oEAAoE;IACpE,WAAW,IAAI,IAAI;IAInB;;;;;;OAMG;IACH,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,aAAa;IAsBxD,qFAAqF;IACrF,QAAQ,IAAI,aAAa;CAsB1B"}
|
package/dist/growable.js
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Budget-aware growable SoA segment writer (DD-003 §7.2/§7.3).
|
|
3
|
+
*
|
|
4
|
+
* Accumulates segments directly into growable typed arrays (no intermediate object
|
|
5
|
+
* graphs) and keeps a byte-accurate account of every live working allocation. Any
|
|
6
|
+
* projected allocation — growth steps and the final right-size compaction, during
|
|
7
|
+
* which old and new capacity coexist — is checked against `maxBufferBytes` BEFORE
|
|
8
|
+
* it is performed. On budget exhaustion the writer reports failure and the parse
|
|
9
|
+
* stops at the current command boundary with a structured bounded result; it never
|
|
10
|
+
* throws an unhandled allocation error.
|
|
11
|
+
*/
|
|
12
|
+
export class BudgetExceededError extends Error {
|
|
13
|
+
requestedBytes;
|
|
14
|
+
accountedBytes;
|
|
15
|
+
maxBufferBytes;
|
|
16
|
+
constructor(requestedBytes, accountedBytes, maxBufferBytes) {
|
|
17
|
+
super(`allocation of ${requestedBytes} B would exceed maxBufferBytes=${maxBufferBytes} B (accounted: ${accountedBytes} B)`);
|
|
18
|
+
this.requestedBytes = requestedBytes;
|
|
19
|
+
this.accountedBytes = accountedBytes;
|
|
20
|
+
this.maxBufferBytes = maxBufferBytes;
|
|
21
|
+
this.name = 'BudgetExceededError';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const CHANNELS = [
|
|
25
|
+
{ name: 'x0', bytesPerElement: 4 },
|
|
26
|
+
{ name: 'y0', bytesPerElement: 4 },
|
|
27
|
+
{ name: 'z0', bytesPerElement: 4 },
|
|
28
|
+
{ name: 'x1', bytesPerElement: 4 },
|
|
29
|
+
{ name: 'y1', bytesPerElement: 4 },
|
|
30
|
+
{ name: 'z1', bytesPerElement: 4 },
|
|
31
|
+
{ name: 'e', bytesPerElement: 4 },
|
|
32
|
+
{ name: 'feedrate', bytesPerElement: 4 },
|
|
33
|
+
{ name: 'kind', bytesPerElement: 1 },
|
|
34
|
+
{ name: 'tool', bytesPerElement: 2 },
|
|
35
|
+
{ name: 'layer', bytesPerElement: 4 },
|
|
36
|
+
{ name: 'feature', bytesPerElement: 1 },
|
|
37
|
+
{ name: 'object', bytesPerElement: 4 },
|
|
38
|
+
{ name: 'srcByte', bytesPerElement: 4 }
|
|
39
|
+
];
|
|
40
|
+
const BYTES_PER_SEGMENT = CHANNELS.reduce((a, c) => a + c.bytesPerElement, 0); // 40 B core set
|
|
41
|
+
const INITIAL_CAPACITY = 4096;
|
|
42
|
+
export class SegmentWriter {
|
|
43
|
+
maxBufferBytes;
|
|
44
|
+
capacity = 0;
|
|
45
|
+
_count = 0;
|
|
46
|
+
x0;
|
|
47
|
+
y0;
|
|
48
|
+
z0;
|
|
49
|
+
x1;
|
|
50
|
+
y1;
|
|
51
|
+
z1;
|
|
52
|
+
e;
|
|
53
|
+
feedrate;
|
|
54
|
+
kind;
|
|
55
|
+
tool;
|
|
56
|
+
layer;
|
|
57
|
+
feature;
|
|
58
|
+
object;
|
|
59
|
+
srcByte;
|
|
60
|
+
/** Bytes of live typed-array capacity currently held by this writer. */
|
|
61
|
+
accountedBytes = 0;
|
|
62
|
+
/** Extra live bytes the caller wants included in the budget (line buffer, warnings). */
|
|
63
|
+
externalBytes = 0;
|
|
64
|
+
constructor(maxBufferBytes) {
|
|
65
|
+
this.maxBufferBytes = maxBufferBytes;
|
|
66
|
+
this.allocate(INITIAL_CAPACITY);
|
|
67
|
+
}
|
|
68
|
+
get count() {
|
|
69
|
+
return this._count;
|
|
70
|
+
}
|
|
71
|
+
get accounted() {
|
|
72
|
+
return this.accountedBytes + this.externalBytes;
|
|
73
|
+
}
|
|
74
|
+
/** Report additional live working bytes (e.g., the line-drain buffer) into the budget. */
|
|
75
|
+
setExternalBytes(bytes) {
|
|
76
|
+
this.externalBytes = bytes;
|
|
77
|
+
}
|
|
78
|
+
/** Throws BudgetExceededError if `requested` more bytes would break the budget. */
|
|
79
|
+
ensureBudget(requested) {
|
|
80
|
+
if (this.accounted + requested > this.maxBufferBytes) {
|
|
81
|
+
throw new BudgetExceededError(requested, this.accounted, this.maxBufferBytes);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
allocate(newCapacity) {
|
|
85
|
+
// During a grow/compact, old and new capacity coexist until copies complete.
|
|
86
|
+
const newBytes = newCapacity * BYTES_PER_SEGMENT;
|
|
87
|
+
this.ensureBudget(newBytes);
|
|
88
|
+
const nx0 = new Float32Array(newCapacity);
|
|
89
|
+
const ny0 = new Float32Array(newCapacity);
|
|
90
|
+
const nz0 = new Float32Array(newCapacity);
|
|
91
|
+
const nx1 = new Float32Array(newCapacity);
|
|
92
|
+
const ny1 = new Float32Array(newCapacity);
|
|
93
|
+
const nz1 = new Float32Array(newCapacity);
|
|
94
|
+
const ne = new Float32Array(newCapacity);
|
|
95
|
+
const nfeed = new Float32Array(newCapacity);
|
|
96
|
+
const nkind = new Uint8Array(newCapacity);
|
|
97
|
+
const ntool = new Uint16Array(newCapacity);
|
|
98
|
+
const nlayer = new Uint32Array(newCapacity);
|
|
99
|
+
const nfeature = new Uint8Array(newCapacity);
|
|
100
|
+
const nobject = new Uint32Array(newCapacity);
|
|
101
|
+
const nsrc = new Uint32Array(newCapacity);
|
|
102
|
+
if (this.capacity > 0) {
|
|
103
|
+
nx0.set(this.x0.subarray(0, this._count));
|
|
104
|
+
ny0.set(this.y0.subarray(0, this._count));
|
|
105
|
+
nz0.set(this.z0.subarray(0, this._count));
|
|
106
|
+
nx1.set(this.x1.subarray(0, this._count));
|
|
107
|
+
ny1.set(this.y1.subarray(0, this._count));
|
|
108
|
+
nz1.set(this.z1.subarray(0, this._count));
|
|
109
|
+
ne.set(this.e.subarray(0, this._count));
|
|
110
|
+
nfeed.set(this.feedrate.subarray(0, this._count));
|
|
111
|
+
nkind.set(this.kind.subarray(0, this._count));
|
|
112
|
+
ntool.set(this.tool.subarray(0, this._count));
|
|
113
|
+
nlayer.set(this.layer.subarray(0, this._count));
|
|
114
|
+
nfeature.set(this.feature.subarray(0, this._count));
|
|
115
|
+
nobject.set(this.object.subarray(0, this._count));
|
|
116
|
+
nsrc.set(this.srcByte.subarray(0, this._count));
|
|
117
|
+
}
|
|
118
|
+
const oldBytes = this.capacity * BYTES_PER_SEGMENT;
|
|
119
|
+
this.x0 = nx0;
|
|
120
|
+
this.y0 = ny0;
|
|
121
|
+
this.z0 = nz0;
|
|
122
|
+
this.x1 = nx1;
|
|
123
|
+
this.y1 = ny1;
|
|
124
|
+
this.z1 = nz1;
|
|
125
|
+
this.e = ne;
|
|
126
|
+
this.feedrate = nfeed;
|
|
127
|
+
this.kind = nkind;
|
|
128
|
+
this.tool = ntool;
|
|
129
|
+
this.layer = nlayer;
|
|
130
|
+
this.feature = nfeature;
|
|
131
|
+
this.object = nobject;
|
|
132
|
+
this.srcByte = nsrc;
|
|
133
|
+
this.capacity = newCapacity;
|
|
134
|
+
this.accountedBytes = this.accountedBytes - oldBytes + newBytes;
|
|
135
|
+
}
|
|
136
|
+
/** Append one segment. Throws BudgetExceededError when growth would break the budget. */
|
|
137
|
+
push(s) {
|
|
138
|
+
if (this._count === this.capacity) {
|
|
139
|
+
this.allocate(this.capacity * 2);
|
|
140
|
+
}
|
|
141
|
+
const i = this._count;
|
|
142
|
+
this.x0[i] = s.x0;
|
|
143
|
+
this.y0[i] = s.y0;
|
|
144
|
+
this.z0[i] = s.z0;
|
|
145
|
+
this.x1[i] = s.x1;
|
|
146
|
+
this.y1[i] = s.y1;
|
|
147
|
+
this.z1[i] = s.z1;
|
|
148
|
+
this.e[i] = s.e;
|
|
149
|
+
this.feedrate[i] = s.feedrate;
|
|
150
|
+
this.kind[i] = s.kind;
|
|
151
|
+
this.tool[i] = s.tool;
|
|
152
|
+
this.layer[i] = s.layer;
|
|
153
|
+
this.feature[i] = 0;
|
|
154
|
+
this.object[i] = 0;
|
|
155
|
+
this.srcByte[i] = s.srcByte;
|
|
156
|
+
this._count++;
|
|
157
|
+
}
|
|
158
|
+
/** Overwrite the layer channel for a segment range (used for post-hoc layer resolution). */
|
|
159
|
+
setLayerRange(start, end, layerIndex) {
|
|
160
|
+
this.layer.fill(layerIndex, start, end + 1);
|
|
161
|
+
}
|
|
162
|
+
/** Zero the whole layer channel (non-planar clearing semantics). */
|
|
163
|
+
clearLayers() {
|
|
164
|
+
this.layer.fill(0, 0, this._count);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Copy a segment range into fresh right-sized arrays (progressive-preview
|
|
168
|
+
* snapshots, DD-004 §5.4 / issue #60). Budget-checked: the copies coexist with
|
|
169
|
+
* the live buffers until they are transferred away, so they count against
|
|
170
|
+
* `maxBufferBytes` at creation time. Throws BudgetExceededError when the copy
|
|
171
|
+
* would break the budget — callers skip the snapshot, never the parse.
|
|
172
|
+
*/
|
|
173
|
+
snapshotRange(start, end) {
|
|
174
|
+
const count = Math.max(0, end - start);
|
|
175
|
+
this.ensureBudget(count * BYTES_PER_SEGMENT);
|
|
176
|
+
return {
|
|
177
|
+
count,
|
|
178
|
+
x0: this.x0.slice(start, end),
|
|
179
|
+
y0: this.y0.slice(start, end),
|
|
180
|
+
z0: this.z0.slice(start, end),
|
|
181
|
+
x1: this.x1.slice(start, end),
|
|
182
|
+
y1: this.y1.slice(start, end),
|
|
183
|
+
z1: this.z1.slice(start, end),
|
|
184
|
+
e: this.e.slice(start, end),
|
|
185
|
+
feedrate: this.feedrate.slice(start, end),
|
|
186
|
+
kind: this.kind.slice(start, end),
|
|
187
|
+
tool: this.tool.slice(start, end),
|
|
188
|
+
layer: this.layer.slice(start, end),
|
|
189
|
+
feature: this.feature.slice(start, end),
|
|
190
|
+
object: this.object.slice(start, end),
|
|
191
|
+
srcByte: this.srcByte.slice(start, end)
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
/** Right-size to exact count. Budget-checked (old + new coexist during the copy). */
|
|
195
|
+
finalize() {
|
|
196
|
+
if (this._count < this.capacity) {
|
|
197
|
+
this.allocate(Math.max(this._count, 1));
|
|
198
|
+
}
|
|
199
|
+
return {
|
|
200
|
+
count: this._count,
|
|
201
|
+
x0: this.x0.subarray(0, this._count),
|
|
202
|
+
y0: this.y0.subarray(0, this._count),
|
|
203
|
+
z0: this.z0.subarray(0, this._count),
|
|
204
|
+
x1: this.x1.subarray(0, this._count),
|
|
205
|
+
y1: this.y1.subarray(0, this._count),
|
|
206
|
+
z1: this.z1.subarray(0, this._count),
|
|
207
|
+
e: this.e.subarray(0, this._count),
|
|
208
|
+
feedrate: this.feedrate.subarray(0, this._count),
|
|
209
|
+
kind: this.kind.subarray(0, this._count),
|
|
210
|
+
tool: this.tool.subarray(0, this._count),
|
|
211
|
+
layer: this.layer.subarray(0, this._count),
|
|
212
|
+
feature: this.feature.subarray(0, this._count),
|
|
213
|
+
object: this.object.subarray(0, this._count),
|
|
214
|
+
srcByte: this.srcByte.subarray(0, this._count)
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @chestnutlabs/gcode-parser — worker-safe G-code parse core (DD-003).
|
|
3
|
+
*
|
|
4
|
+
* Phase 1 (#44): pure parse core. Phase 2 (#45): cooperative async driver,
|
|
5
|
+
* worker protocol v1, and the GcodeParseSession client. Streaming inputs and
|
|
6
|
+
* full limit wiring land in phase 3 (#46). Depends only on
|
|
7
|
+
* @chestnutlabs/toolpath-core.
|
|
8
|
+
*/
|
|
9
|
+
export { parseGcodeToIR, parseGcodeToIRAsync, DEFAULT_LIMITS } from './parse.js';
|
|
10
|
+
export type { AsyncParseHooks, AsyncParseResult, CommandEvent, ParseLimits, ParseOptions, ParseResult, ParseStats, StopReason } from './parse.js';
|
|
11
|
+
export { BudgetExceededError } from './growable.js';
|
|
12
|
+
export { parseGcodeStreamToIR, isBlobLike, isReadableStreamLike } from './streaming.js';
|
|
13
|
+
export type { StreamInput, BlobLike, ReadableStreamLike } from './streaming.js';
|
|
14
|
+
export { PROTOCOL_VERSION, PARTIAL_PREVIEW_MIN_BYTES, irTransferList } from './protocol.js';
|
|
15
|
+
export type { WireParseOptions, WorkerRequest, WorkerResponse, PartialMessage } from './protocol.js';
|
|
16
|
+
export { createWorkerHandler } from './worker-core.js';
|
|
17
|
+
export type { PostFn, DialectRunLike, DialectRunnerFactoryLike, WorkerHandlerOptions } from './worker-core.js';
|
|
18
|
+
export { GcodeParseSession, ParseSessionError, CancelledError } from './session.js';
|
|
19
|
+
export type { SessionOptions, WorkerLike, ParseProgress } from './session.js';
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjF,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,WAAW,EACX,UAAU,EACV,UAAU,EACX,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACxF,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC5F,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACrG,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,YAAY,EAAE,MAAM,EAAE,cAAc,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC/G,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACpF,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @chestnutlabs/gcode-parser — worker-safe G-code parse core (DD-003).
|
|
3
|
+
*
|
|
4
|
+
* Phase 1 (#44): pure parse core. Phase 2 (#45): cooperative async driver,
|
|
5
|
+
* worker protocol v1, and the GcodeParseSession client. Streaming inputs and
|
|
6
|
+
* full limit wiring land in phase 3 (#46). Depends only on
|
|
7
|
+
* @chestnutlabs/toolpath-core.
|
|
8
|
+
*/
|
|
9
|
+
export { parseGcodeToIR, parseGcodeToIRAsync, DEFAULT_LIMITS } from './parse.js';
|
|
10
|
+
export { BudgetExceededError } from './growable.js';
|
|
11
|
+
export { parseGcodeStreamToIR, isBlobLike, isReadableStreamLike } from './streaming.js';
|
|
12
|
+
export { PROTOCOL_VERSION, PARTIAL_PREVIEW_MIN_BYTES, irTransferList } from './protocol.js';
|
|
13
|
+
export { createWorkerHandler } from './worker-core.js';
|
|
14
|
+
export { GcodeParseSession, ParseSessionError, CancelledError } from './session.js';
|
package/dist/parse.d.ts
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure G-code parse core (DD-003 §14 phase 1, issue #44; async driver added in phase 2, #45).
|
|
3
|
+
*
|
|
4
|
+
* Ports the inherited xyz-tools interpreter semantics — motion handling (G0/G1),
|
|
5
|
+
* arc flattening (G2/G3 incl. R-mode and full circles), units (G20/G21), homing
|
|
6
|
+
* (G28), tool selection (T0–T7), travel/extrusion path splitting, and the
|
|
7
|
+
* layer-indexing rules (0.05 tolerance, non-planar clearing) — but writes the
|
|
8
|
+
* DD-001 `ToolpathIR` SoA buffers **directly** through a budget-aware growable
|
|
9
|
+
* writer, with **real** per-segment `srcByte`, extrusion deltas, and modal
|
|
10
|
+
* feed rate (the #29 adapter had to report those `unavailable`).
|
|
11
|
+
*
|
|
12
|
+
* Provenance: machine-state semantics adapted from the inherited MIT source
|
|
13
|
+
* (`src/interpreter.ts`, `src/gcode-parser.ts`, `src/indexers.ts` @ the founding
|
|
14
|
+
* baseline) — recorded in docs/UPSTREAM_PROVENANCE.md. Deliberate quirk-for-quirk
|
|
15
|
+
* fidelity (e.g. truthy `x || state.x` in arcs, tool captured at path start) is
|
|
16
|
+
* required by the golden-equivalence gate; do not "fix" behavior here without a
|
|
17
|
+
* reviewed golden regeneration.
|
|
18
|
+
*
|
|
19
|
+
* Two drivers share one engine:
|
|
20
|
+
* - `parseGcodeToIR` — synchronous (tests, Node tooling).
|
|
21
|
+
* - `parseGcodeToIRAsync` — the DD-003 §5.2 cooperative driver: processes at most
|
|
22
|
+
* `yieldIntervalMs` of CPU work between explicit MessageChannel macrotask yields
|
|
23
|
+
* so a queued worker `cancel` message can actually be dispatched; reports
|
|
24
|
+
* progress and honors a cancellation hook.
|
|
25
|
+
*
|
|
26
|
+
* Byte offsets assume single-byte (ASCII/UTF-8) G-code, which holds for slicer
|
|
27
|
+
* output; multi-byte comment bytes would skew offsets and are a documented
|
|
28
|
+
* limitation until the streaming decoder lands (phase 3).
|
|
29
|
+
*/
|
|
30
|
+
import { type ToolpathIR } from '@chestnutlabs/toolpath-core';
|
|
31
|
+
export interface ParseLimits {
|
|
32
|
+
maxInputBytes: number;
|
|
33
|
+
maxSegments: number;
|
|
34
|
+
maxBufferBytes: number;
|
|
35
|
+
maxLineLength: number;
|
|
36
|
+
maxWarnings: number;
|
|
37
|
+
}
|
|
38
|
+
export declare const DEFAULT_LIMITS: ParseLimits;
|
|
39
|
+
/**
|
|
40
|
+
* Read-only normalized command event (DD-005 §4.3, amendment 1): observers see
|
|
41
|
+
* each lexed command BEFORE dispatch and cannot alter parsing.
|
|
42
|
+
*/
|
|
43
|
+
export interface CommandEvent {
|
|
44
|
+
/** Normalized lowercase word+number, e.g. 'm486'. */
|
|
45
|
+
gcode: string;
|
|
46
|
+
params: Readonly<Record<string, number>>;
|
|
47
|
+
/** The raw line, for vendor syntaxes the lexer's params don't capture. */
|
|
48
|
+
rawLine: string;
|
|
49
|
+
srcByte: number;
|
|
50
|
+
/** Segment count at event time — maps events to segment ranges. */
|
|
51
|
+
segIndex: number;
|
|
52
|
+
}
|
|
53
|
+
export interface ParseOptions {
|
|
54
|
+
parserVersion?: string;
|
|
55
|
+
sourceId?: string;
|
|
56
|
+
limits?: Partial<ParseLimits>;
|
|
57
|
+
/** Layer-detection tolerance (inherited default 0.05). */
|
|
58
|
+
minLayerThreshold?: number;
|
|
59
|
+
/**
|
|
60
|
+
* DD-005 §4.3 read-only hooks: observe comments/commands during the parse.
|
|
61
|
+
* Inert when unset (one branch per line); they cannot alter lexing, dispatch,
|
|
62
|
+
* or machine state — the golden-gated semantics are untouched.
|
|
63
|
+
*/
|
|
64
|
+
onComment?: (text: string, srcByte: number) => void;
|
|
65
|
+
onCommand?: (event: CommandEvent) => void;
|
|
66
|
+
}
|
|
67
|
+
export interface StopReason {
|
|
68
|
+
code: 'E_LIMIT_INPUT_BYTES' | 'E_LIMIT_SEGMENTS' | 'E_LIMIT_BUFFER_BYTES';
|
|
69
|
+
message: string;
|
|
70
|
+
srcByte?: number;
|
|
71
|
+
}
|
|
72
|
+
export interface ParseStats {
|
|
73
|
+
bytes: number;
|
|
74
|
+
lines: number;
|
|
75
|
+
commands: number;
|
|
76
|
+
segments: number;
|
|
77
|
+
points: number;
|
|
78
|
+
retractions: number;
|
|
79
|
+
deretractions: number;
|
|
80
|
+
feedrateChanges: number;
|
|
81
|
+
others: number;
|
|
82
|
+
extrusionDistance: number;
|
|
83
|
+
warningsByCode: Record<string, number>;
|
|
84
|
+
stopReason?: StopReason;
|
|
85
|
+
}
|
|
86
|
+
export interface ParseResult {
|
|
87
|
+
ir: ToolpathIR;
|
|
88
|
+
stats: ParseStats;
|
|
89
|
+
/** Dialect/machine metadata (DD-005 §4.2) — populated by the worker pipeline
|
|
90
|
+
* when dialect adapters are registered and matched; absent otherwise. */
|
|
91
|
+
metadata?: import('@chestnutlabs/toolpath-core').DialectMetadata;
|
|
92
|
+
}
|
|
93
|
+
export interface AsyncParseHooks {
|
|
94
|
+
/** Called after each cooperative yield with bytes processed so far. */
|
|
95
|
+
onProgress?: (bytesProcessed: number, totalBytes: number, segments: number) => void;
|
|
96
|
+
/** Checked after each yield; returning true stops the parse with a partial result. */
|
|
97
|
+
shouldCancel?: () => boolean;
|
|
98
|
+
/** Max CPU ms between yields (DD-003 §5.2 default 50). */
|
|
99
|
+
yieldIntervalMs?: number;
|
|
100
|
+
/**
|
|
101
|
+
* Progressive preview (DD-004 §5.4, issue #60): receives path-aligned delta
|
|
102
|
+
* snapshots of the IR built so far. Emission starts once bytesProcessed ≥
|
|
103
|
+
* `partialMinBytes` and repeats at most every `partialIntervalMs`.
|
|
104
|
+
*/
|
|
105
|
+
onPartial?: (slice: ToolpathIR, cumulativeSegments: number) => void;
|
|
106
|
+
/** Bytes processed before the first partial may be emitted (default 0 when onPartial set). */
|
|
107
|
+
partialMinBytes?: number;
|
|
108
|
+
/** Minimum ms between partial snapshots (default 1000). */
|
|
109
|
+
partialIntervalMs?: number;
|
|
110
|
+
/**
|
|
111
|
+
* DD-005 §4.5 stream detection windows: when set, the STREAMING driver fills
|
|
112
|
+
* `head` with the first ≤64 KB of decoded text and keeps `tail` as a bounded
|
|
113
|
+
* rolling window (last ≤16 KB) — read after the parse for late dialect
|
|
114
|
+
* detection on non-seekable streams. In-memory drivers ignore this (their
|
|
115
|
+
* windows are sliceable up front).
|
|
116
|
+
*/
|
|
117
|
+
captureWindows?: {
|
|
118
|
+
head: string;
|
|
119
|
+
tail: string;
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
export interface AsyncParseResult extends ParseResult {
|
|
123
|
+
cancelled: boolean;
|
|
124
|
+
}
|
|
125
|
+
/** Internal engine surface shared by the sync, async, and streaming drivers. Not public API. */
|
|
126
|
+
export interface Engine {
|
|
127
|
+
text: string;
|
|
128
|
+
limits: ParseLimits;
|
|
129
|
+
processLine(rawLine: string, offset: number): void;
|
|
130
|
+
stopped(): boolean;
|
|
131
|
+
markInputTooBig(): void;
|
|
132
|
+
/** Streaming driver: record the true source byte count as it becomes known. */
|
|
133
|
+
setSourceBytes(bytes: number): void;
|
|
134
|
+
/**
|
|
135
|
+
* Progressive-preview delta (issue #60): copy segments [fromSeg, cut) where
|
|
136
|
+
* `cut` is the current path boundary — every included segment has a resolved
|
|
137
|
+
* layer. Returns null when nothing new is ready or the copy would break the
|
|
138
|
+
* §7.2 buffer budget (snapshots are skippable; the parse never is).
|
|
139
|
+
*/
|
|
140
|
+
snapshot(fromSeg: number): {
|
|
141
|
+
slice: ToolpathIR;
|
|
142
|
+
upTo: number;
|
|
143
|
+
} | null;
|
|
144
|
+
finish(cancelledAtByte?: number): ParseResult;
|
|
145
|
+
}
|
|
146
|
+
/** Internal: build an engine over decoded text (streaming passes '' and feeds lines itself). */
|
|
147
|
+
export declare function createEngine(input: string | Uint8Array, opts: ParseOptions): Engine;
|
|
148
|
+
/** Parse a whole G-code text into a ToolpathIR. Pure and synchronous. */
|
|
149
|
+
export declare function parseGcodeToIR(input: string | Uint8Array, opts?: ParseOptions): ParseResult;
|
|
150
|
+
/**
|
|
151
|
+
* Cooperative async driver (DD-003 §5.2): identical parsing semantics, but the
|
|
152
|
+
* loop processes at most `yieldIntervalMs` (default 50) of CPU work between
|
|
153
|
+
* explicit macrotask yields so queued `cancel` messages are dispatched. Progress
|
|
154
|
+
* and cancellation are surfaced through hooks.
|
|
155
|
+
*/
|
|
156
|
+
export declare function parseGcodeToIRAsync(input: string | Uint8Array, opts?: ParseOptions, hooks?: AsyncParseHooks): Promise<AsyncParseResult>;
|
|
157
|
+
/**
|
|
158
|
+
* Shared partial-snapshot emitter for the async and streaming drivers (#60):
|
|
159
|
+
* called at cooperative yield points; emits a delta once bytesProcessed passes
|
|
160
|
+
* `partialMinBytes` and at most every `partialIntervalMs`.
|
|
161
|
+
*/
|
|
162
|
+
export declare function makePartialEmitter(engine: Engine, hooks: AsyncParseHooks): (bytesProcessed: number) => void;
|
|
163
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"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"}
|