@tabnas/transduce 0.2.7 → 0.2.9
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/dist/capability.js +9 -1
- package/dist/capability.js.map +1 -1
- package/dist/parser-event-source.d.ts +17 -0
- package/dist/parser-event-source.js +227 -0
- package/dist/parser-event-source.js.map +1 -0
- package/dist/parser-source.js +5 -3
- package/dist/parser-source.js.map +1 -1
- package/dist/routers.js +4 -0
- package/dist/routers.js.map +1 -1
- package/dist/transduce-tree.d.ts +11 -0
- package/dist/transduce-tree.js +143 -0
- package/dist/transduce-tree.js.map +1 -0
- package/dist/transduce.d.ts +5 -1
- package/dist/transduce.js +21 -9
- package/dist/transduce.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -1
- package/src/capability.ts +9 -1
- package/src/parser-event-source.ts +252 -0
- package/src/parser-source.ts +5 -3
- package/src/routers.ts +9 -1
- package/src/transduce-tree.ts +140 -0
- package/src/transduce.ts +21 -2
package/dist/capability.js
CHANGED
|
@@ -33,7 +33,14 @@ exports.isIncremental = isIncremental;
|
|
|
33
33
|
// and `feed` replaces xml's root element with the feed it makes of the tree
|
|
34
34
|
// when the root closes, so the adapter refuses each on its own samples.
|
|
35
35
|
// The grammars whose incremental events never contradict the whole-value
|
|
36
|
-
// walk on any fixture, by
|
|
36
|
+
// walk on any fixture, by the name of the format each reads: its package's
|
|
37
|
+
// (`@tabnas/<name>`), but `pgn` for @tabnas/chess, the name hosts ask by.
|
|
38
|
+
// @tabnas/chess builds each game on a stack in the parse's context, so
|
|
39
|
+
// the database is the only container in the parse tree and a game is
|
|
40
|
+
// stored in it only once complete: each game is walked at its insertion.
|
|
41
|
+
// That is @tabnas/chess 0.1.17 and later; earlier releases attached a
|
|
42
|
+
// game's parts after the adapter had sent them, and this package does not
|
|
43
|
+
// depend on @tabnas/chess, so a host that streams PGN takes 0.1.17 or later.
|
|
37
44
|
exports.INCREMENTAL = Object.freeze([
|
|
38
45
|
'json',
|
|
39
46
|
'json5',
|
|
@@ -41,6 +48,7 @@ exports.INCREMENTAL = Object.freeze([
|
|
|
41
48
|
'jsonic',
|
|
42
49
|
'jsonl',
|
|
43
50
|
'markdown',
|
|
51
|
+
'pgn',
|
|
44
52
|
'xml',
|
|
45
53
|
'yaml',
|
|
46
54
|
'zon',
|
package/dist/capability.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capability.js","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":";AAAA,4CAA4C;;;;AAE5C,0EAA0E;AAC1E,EAAE;AACF,uEAAuE;AACvE,0EAA0E;AAC1E,4EAA4E;AAC5E,6DAA6D;AAC7D,wEAAwE;AACxE,qEAAqE;AACrE,0EAA0E;AAC1E,uEAAuE;AACvE,sEAAsE;AACtE,2EAA2E;AAC3E,wEAAwE;AACxE,yEAAyE;AACzE,mCAAmC;AACnC,EAAE;AACF,6EAA6E;AAC7E,2EAA2E;AAC3E,0EAA0E;AAC1E,sEAAsE;AACtE,0EAA0E;AAC1E,UAAU;AAEV,yEAAyE;AACzE,yEAAyE;AACzE,0EAA0E;AAC1E,uEAAuE;AACvE,2EAA2E;AAC3E,4EAA4E;AAC5E,wEAAwE;AAExE,yEAAyE;AACzE,
|
|
1
|
+
{"version":3,"file":"capability.js","sourceRoot":"","sources":["../src/capability.ts"],"names":[],"mappings":";AAAA,4CAA4C;;;;AAE5C,0EAA0E;AAC1E,EAAE;AACF,uEAAuE;AACvE,0EAA0E;AAC1E,4EAA4E;AAC5E,6DAA6D;AAC7D,wEAAwE;AACxE,qEAAqE;AACrE,0EAA0E;AAC1E,uEAAuE;AACvE,sEAAsE;AACtE,2EAA2E;AAC3E,wEAAwE;AACxE,yEAAyE;AACzE,mCAAmC;AACnC,EAAE;AACF,6EAA6E;AAC7E,2EAA2E;AAC3E,0EAA0E;AAC1E,sEAAsE;AACtE,0EAA0E;AAC1E,UAAU;AAEV,yEAAyE;AACzE,yEAAyE;AACzE,0EAA0E;AAC1E,uEAAuE;AACvE,2EAA2E;AAC3E,4EAA4E;AAC5E,wEAAwE;AAExE,yEAAyE;AACzE,2EAA2E;AAC3E,0EAA0E;AAC1E,uEAAuE;AACvE,qEAAqE;AACrE,yEAAyE;AACzE,sEAAsE;AACtE,0EAA0E;AAC1E,6EAA6E;AAChE,QAAA,WAAW,GAAsB,MAAM,CAAC,MAAM,CAAC;IAC1D,MAAM;IACN,OAAO;IACP,OAAO;IACP,QAAQ;IACR,OAAO;IACP,UAAU;IACV,KAAK;IACL,KAAK;IACL,MAAM;IACN,KAAK;CACN,CAAC,CAAA;AAEF,oDAAoD;AACpD,uBAA8B,OAAe;IAC3C,OAAO,QAAA,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;AACtC,CAAC;AAEY,QAAA,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC;IACtC,WAAW,EAAX,QAAA,WAAW;IACX,WAAW,EAAE,aAAa;CAC3B,CAAC,CAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { AbortFlag, Datum, Limits, Metrics } from '@tabnas/alchemy/shared';
|
|
2
|
+
import type { Flow, ParserSink } from '@tabnas/alchemy/shared';
|
|
3
|
+
import type { Tabnas } from '@tabnas/parser';
|
|
4
|
+
export declare class ParserEventSource {
|
|
5
|
+
private parser;
|
|
6
|
+
private text;
|
|
7
|
+
private sourceLimits;
|
|
8
|
+
private abortFlag;
|
|
9
|
+
private sourceMetrics;
|
|
10
|
+
private used;
|
|
11
|
+
constructor(parser: Tabnas, text: string);
|
|
12
|
+
limits(limits: Limits): this;
|
|
13
|
+
abort(abort: AbortFlag): this;
|
|
14
|
+
metrics(metrics: Metrics): this;
|
|
15
|
+
run(sink: ParserSink): Flow;
|
|
16
|
+
}
|
|
17
|
+
export declare function scalarOf(value: unknown, lexeme: string | undefined): Datum;
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* Copyright (c) 2026 tabnas, MIT License */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.ParserEventSource = void 0;
|
|
5
|
+
exports.scalarOf = scalarOf;
|
|
6
|
+
// `ParserEventSource`: `ParserEvents/1` from a tabnas parse of one text,
|
|
7
|
+
// the input a transducer part reads (rs/src/source/parser_events.rs).
|
|
8
|
+
//
|
|
9
|
+
// The source installs one `ruleDone` subscriber, which relays each rule
|
|
10
|
+
// pass the engine completes as a `ParserEvent`, on the thread that parses,
|
|
11
|
+
// into a `ParserSink`: an `open` when a rule's open pass has run, a `close`
|
|
12
|
+
// when its close pass has. It knows no grammar. When the engine has
|
|
13
|
+
// returned the parse's value it sends one `end`, so a document is complete
|
|
14
|
+
// only once it validated, as every source's is.
|
|
15
|
+
//
|
|
16
|
+
// What each pass carries is alchemy's `RulePass`:
|
|
17
|
+
//
|
|
18
|
+
// - the rule's `name`, its depth `d` and instance `i` (the engine's, which
|
|
19
|
+
// counts from 1 here and from 0 in Go and Rust: DIVERGENCE.md 6), the
|
|
20
|
+
// alternate that matched (`alt`: `p`, `r`, `b`, and its groups `g`,
|
|
21
|
+
// sorted, since they are tags whose order the runtimes' engines keep
|
|
22
|
+
// differently), whether recovery forced the close, and its named counters
|
|
23
|
+
// `n`, sorted by name;
|
|
24
|
+
// - the `tokens` the pass consumed: those its alternate matched (the
|
|
25
|
+
// engine's `o[:oN]` or `c[:cN]`), less the `b` it gave back from their
|
|
26
|
+
// end, which are the next rule's to consume, and none when `b` is more
|
|
27
|
+
// than it recorded, since a close alternate can back up a token it did
|
|
28
|
+
// not record. A token is its name, its value, its source text and its
|
|
29
|
+
// 1-based row and column; a token with no value (the end of the source,
|
|
30
|
+
// a fixed token such as `[`, which Rust's engine gives its text:
|
|
31
|
+
// DIVERGENCE.md 7) has `null`, and a number carries its source text as its lexeme when
|
|
32
|
+
// that text is a JSON number spelling the value (RFC 8259), the rule the
|
|
33
|
+
// incremental source keeps lexemes by, so a renderer can write it as it
|
|
34
|
+
// stands;
|
|
35
|
+
// - on a close pass, the rule's node when that is a scalar (`value`), a
|
|
36
|
+
// number with the lexeme of the rule's first open token as above;
|
|
37
|
+
// nothing on an open pass, nor for a container.
|
|
38
|
+
//
|
|
39
|
+
// A pass made while a probe is open is speculative: the grammar parses
|
|
40
|
+
// ahead and rewinds past it (tabnas-bnf's probe, the engine's own for a
|
|
41
|
+
// serialized grammar's `pd_` keys), so it is never the document's. The
|
|
42
|
+
// engine flags it (`RuleDone.probe`), and the source drops it before any
|
|
43
|
+
// sink sees it.
|
|
44
|
+
//
|
|
45
|
+
// The source holds its limits as it builds each pass, before the sink sees
|
|
46
|
+
// it: a token's value or source text, or a pass's value, longer than
|
|
47
|
+
// `max_scalar_bytes` is refused with that limit's name, as a JSON-events
|
|
48
|
+
// source refuses a scalar. `max_depth` and `max_key_bytes` hold where a
|
|
49
|
+
// part's outputs become `JsonEvents/1`, on the events it writes. The abort
|
|
50
|
+
// flag is polled per pass, and `Metrics.events` counts the events
|
|
51
|
+
// delivered.
|
|
52
|
+
//
|
|
53
|
+
// Failure mapping is `ParserSource`'s: a sink failure is thrown as it was;
|
|
54
|
+
// a sink that stopped is `'stop'`; a parse cancelled through the caller's
|
|
55
|
+
// `AbortFlag` is `ABORTED`; any other engine error is `INPUT_INVALID` with
|
|
56
|
+
// the engine's code and position. A source runs once, as `ParserSource`
|
|
57
|
+
// does: its parser carries the run's subscriber and budget.
|
|
58
|
+
const shared_1 = require("@tabnas/alchemy/shared");
|
|
59
|
+
const rule_events_1 = require("./rule-events");
|
|
60
|
+
const source_1 = require("./source");
|
|
61
|
+
// A tabnas parser applied to one text, as a source of its rule passes.
|
|
62
|
+
class ParserEventSource {
|
|
63
|
+
// A source with default limits, its own abort flag and fresh metrics; the
|
|
64
|
+
// builder methods change each.
|
|
65
|
+
constructor(parser, text) {
|
|
66
|
+
this.sourceLimits = shared_1.Limits.default();
|
|
67
|
+
this.abortFlag = new shared_1.AbortFlag();
|
|
68
|
+
this.sourceMetrics = new shared_1.Metrics();
|
|
69
|
+
this.used = false;
|
|
70
|
+
this.parser = parser;
|
|
71
|
+
this.text = text;
|
|
72
|
+
}
|
|
73
|
+
limits(limits) {
|
|
74
|
+
this.sourceLimits = limits;
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
abort(abort) {
|
|
78
|
+
this.abortFlag = abort;
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
metrics(metrics) {
|
|
82
|
+
this.sourceMetrics = metrics;
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
// Parse, relaying each pass into `sink`, then `end`.
|
|
86
|
+
run(sink) {
|
|
87
|
+
if (this.used) {
|
|
88
|
+
throw new shared_1.Fail('STREAM_REUSED', "a ParserEventSource runs once: its parser carries the run's subscriber and budget; " +
|
|
89
|
+
'make a new source, with a new parser, for another run');
|
|
90
|
+
}
|
|
91
|
+
this.used = true;
|
|
92
|
+
const abort = this.abortFlag;
|
|
93
|
+
const stop = new shared_1.AbortFlag();
|
|
94
|
+
const relay = new Relay(sink, this.sourceLimits.max_scalar_bytes, abort, stop);
|
|
95
|
+
(0, rule_events_1.prepare)(this.parser, () => !abort.isAborted() && !stop.isAborted(), (rule, done) => relay.onDone(rule, done));
|
|
96
|
+
let parsed;
|
|
97
|
+
try {
|
|
98
|
+
this.parser.parse(this.text);
|
|
99
|
+
parsed = { ok: true };
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
parsed = { ok: false, error };
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
const status = relay.status;
|
|
106
|
+
if ('failed' === status.type)
|
|
107
|
+
throw status.error;
|
|
108
|
+
if ('stopped' === status.type)
|
|
109
|
+
return 'stop';
|
|
110
|
+
if (!parsed.ok)
|
|
111
|
+
throw (0, source_1.engineFailure)(parsed.error, abort);
|
|
112
|
+
return relay.send({ type: 'end' });
|
|
113
|
+
}
|
|
114
|
+
finally {
|
|
115
|
+
this.sourceMetrics.events += relay.events;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
exports.ParserEventSource = ParserEventSource;
|
|
120
|
+
// The subscriber's state: the sink and how the run stands.
|
|
121
|
+
class Relay {
|
|
122
|
+
constructor(sink, maxScalarBytes, abort,
|
|
123
|
+
// Set to make the parse guard cancel the parse.
|
|
124
|
+
stop) {
|
|
125
|
+
this.sink = sink;
|
|
126
|
+
this.maxScalarBytes = maxScalarBytes;
|
|
127
|
+
this.abort = abort;
|
|
128
|
+
this.stop = stop;
|
|
129
|
+
this.status = { type: 'running' };
|
|
130
|
+
this.events = 0;
|
|
131
|
+
}
|
|
132
|
+
send(ev) {
|
|
133
|
+
this.events++;
|
|
134
|
+
return this.sink.event(ev);
|
|
135
|
+
}
|
|
136
|
+
fail(error) {
|
|
137
|
+
this.status = { type: 'failed', error };
|
|
138
|
+
this.stop.abort();
|
|
139
|
+
}
|
|
140
|
+
// One pass the engine completed.
|
|
141
|
+
onDone(rule, done) {
|
|
142
|
+
if (true === done.probe || 'running' !== this.status.type)
|
|
143
|
+
return;
|
|
144
|
+
if (this.abort.isAborted()) {
|
|
145
|
+
this.fail(shared_1.Fail.aborted());
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const open = 'o' === done.state;
|
|
149
|
+
let ev;
|
|
150
|
+
try {
|
|
151
|
+
const pass = rulePass(rule, done, open, this.maxScalarBytes);
|
|
152
|
+
ev = open ? { type: 'open', pass } : { type: 'close', pass };
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
this.fail(error);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
if ('stop' === this.send(ev)) {
|
|
160
|
+
this.status = { type: 'stopped' };
|
|
161
|
+
this.stop.abort();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
this.fail(error);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// The pass as alchemy's `RulePass`, its sizes held to `max_scalar_bytes`.
|
|
170
|
+
function rulePass(rule, done, open, max) {
|
|
171
|
+
const r = rule;
|
|
172
|
+
const recorded = open ? r.o.slice(0, r.oN) : r.c.slice(0, r.cN);
|
|
173
|
+
const b = null == done.alt ? 0 : done.alt.b;
|
|
174
|
+
const kept = recorded.slice(0, Math.max(0, recorded.length - b));
|
|
175
|
+
const tokens = kept.map((t) => {
|
|
176
|
+
const src = 'string' === typeof t.src ? t.src : String(t.src ?? '');
|
|
177
|
+
held((0, shared_1.utf8Bytes)(src), "a token's source text", max);
|
|
178
|
+
const val = scalarOf(t.val, src);
|
|
179
|
+
if ('string' === val.type)
|
|
180
|
+
held((0, shared_1.utf8Bytes)(val.value), "a token's value", max);
|
|
181
|
+
return { name: t.name, val, src, row: t.rI, col: t.cI };
|
|
182
|
+
});
|
|
183
|
+
let value;
|
|
184
|
+
if (!open && undefined !== r.node && undefined !== (0, shared_1.engineScalar)(r.node)) {
|
|
185
|
+
const first = r.o[0];
|
|
186
|
+
value = scalarOf(r.node, 0 < r.oN && 'string' === typeof first?.src ? first.src : undefined);
|
|
187
|
+
if ('string' === value.type)
|
|
188
|
+
held((0, shared_1.utf8Bytes)(value.value), "a rule's value", max);
|
|
189
|
+
}
|
|
190
|
+
const n = Object.entries((r.n ?? {}))
|
|
191
|
+
.map(([k, v]) => [k, Math.trunc(v)])
|
|
192
|
+
.sort(([a], [b]) => byCodeUnit(a, b));
|
|
193
|
+
const alt = null == done.alt
|
|
194
|
+
? undefined
|
|
195
|
+
: { p: done.alt.p, r: done.alt.r, b: done.alt.b, g: [...done.alt.g].sort(byCodeUnit) };
|
|
196
|
+
return {
|
|
197
|
+
name: rule.name,
|
|
198
|
+
d: rule.d,
|
|
199
|
+
i: rule.i,
|
|
200
|
+
...(undefined === alt ? {} : { alt }),
|
|
201
|
+
tokens,
|
|
202
|
+
forced: true === done.forced,
|
|
203
|
+
n,
|
|
204
|
+
...(undefined === value ? {} : { value }),
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
// Strings in code-unit order, as Rust's `sort` orders ASCII names.
|
|
208
|
+
function byCodeUnit(a, b) {
|
|
209
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
210
|
+
}
|
|
211
|
+
// An engine value as a pass carries it: `undefined` as null, and a number
|
|
212
|
+
// with `lexeme` when that text is a JSON number spelling it.
|
|
213
|
+
function scalarOf(value, lexeme) {
|
|
214
|
+
const scalar = (0, shared_1.engineScalar)(value);
|
|
215
|
+
if (undefined !== scalar && 'number' === scalar.type) {
|
|
216
|
+
const keep = undefined !== lexeme && (0, shared_1.isJsonNumber)(lexeme) && Number(lexeme) === scalar.value;
|
|
217
|
+
return shared_1.Datum.number(scalar.value, keep ? lexeme : undefined);
|
|
218
|
+
}
|
|
219
|
+
return (0, shared_1.fromTabnas)(value);
|
|
220
|
+
}
|
|
221
|
+
// `max_scalar_bytes` held on one text a pass carries.
|
|
222
|
+
function held(bytes, what, max) {
|
|
223
|
+
if (bytes > max) {
|
|
224
|
+
throw shared_1.Fail.limit('max_scalar_bytes', max, `${what} of ${bytes} bytes is larger than ${max}`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
//# sourceMappingURL=parser-event-source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser-event-source.js","sourceRoot":"","sources":["../src/parser-event-source.ts"],"names":[],"mappings":"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"}
|
package/dist/parser-source.js
CHANGED
|
@@ -55,9 +55,11 @@ class ParserSource {
|
|
|
55
55
|
this.sourceMode = mode;
|
|
56
56
|
return this;
|
|
57
57
|
}
|
|
58
|
-
// The grammar the parser implements, by
|
|
59
|
-
//
|
|
60
|
-
// `
|
|
58
|
+
// The grammar the parser implements, by the name of the format it reads:
|
|
59
|
+
// the `languageId` its package's manifest declares, which is the
|
|
60
|
+
// package's own name for most (`json` for `@tabnas/json`) but `pgn` for
|
|
61
|
+
// `@tabnas/chess`. Incremental mode runs only for a name
|
|
62
|
+
// `capability.incremental` lists (`chess` is not one).
|
|
61
63
|
grammar(name) {
|
|
62
64
|
this.grammarName = name;
|
|
63
65
|
return this;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser-source.js","sourceRoot":"","sources":["../src/parser-source.ts"],"names":[],"mappings":";AAAA,4CAA4C;;;AAE5C,kEAAkE;AAClE,EAAE;AACF,2EAA2E;AAC3E,yEAAyE;AACzE,qEAAqE;AACrE,0EAA0E;AAC1E,mEAAmE;AACnE,oEAAoE;AACpE,0EAA0E;AAC1E,mEAAmE;AACnE,0EAA0E;AAC1E,yEAAyE;AACzE,yEAAyE;AACzE,uEAAuE;AACvE,8CAA8C;AAC9C,EAAE;AACF,2EAA2E;AAC3E,0EAA0E;AAC1E,wEAAwE;AACxE,+CAA+C;AAC/C,EAAE;AACF,wEAAwE;AACxE,wEAAwE;AACxE,sEAAsE;AACtE,wEAAwE;AACxE,kEAAkE;AAClE,uEAAuE;AACvE,sEAAsE;AACtE,wCAAwC;AAExC,mDAAyF;AAGzF,6CAA4C;AAC5C,mCAAiC;AACjC,+CAA+D;AAC/D,qCAA8E;AAE9E,oDAAoD;AACpD;IAWE,uEAAuE;IACvE,sDAAsD;IACtD,YAAY,MAAc,EAAE,IAAY;QAVhC,eAAU,GAAe,mBAAU,CAAC,WAAW,EAAE,CAAA;QACjD,iBAAY,GAAW,eAAM,CAAC,OAAO,EAAE,CAAA;QACvC,cAAS,GAAc,IAAI,kBAAS,EAAE,CAAA;QACtC,kBAAa,GAAY,IAAI,gBAAO,EAAE,CAAA;QACtC,gBAAW,GAAkB,IAAI,CAAA;QACjC,iBAAY,GAAG,KAAK,CAAA;QACpB,SAAI,GAAG,KAAK,CAAA;QAKlB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;IAClB,CAAC;IAED,IAAI,CAAC,IAAgB;QACnB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAA;QACtB,OAAO,IAAI,CAAA;IACb,CAAC;IAED,
|
|
1
|
+
{"version":3,"file":"parser-source.js","sourceRoot":"","sources":["../src/parser-source.ts"],"names":[],"mappings":"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"}
|
package/dist/routers.js
CHANGED
|
@@ -6,6 +6,7 @@ const guard_1 = require("./guard");
|
|
|
6
6
|
const route_1 = require("./route");
|
|
7
7
|
const scan_1 = require("./scan");
|
|
8
8
|
const table_from_json_1 = require("./table-from-json");
|
|
9
|
+
const transduce_tree_1 = require("./transduce-tree");
|
|
9
10
|
// Each method constructs the stage it names with the same parameters.
|
|
10
11
|
exports.routers = Object.freeze({
|
|
11
12
|
router(specs, limits, duplicates, metrics, downstream) {
|
|
@@ -20,5 +21,8 @@ exports.routers = Object.freeze({
|
|
|
20
21
|
guarded(inner, limits, abort, metrics) {
|
|
21
22
|
return new guard_1.Guarded(inner, limits, abort, metrics);
|
|
22
23
|
},
|
|
24
|
+
transduceTree(spec, downstream) {
|
|
25
|
+
return new transduce_tree_1.TransduceTree(spec, downstream);
|
|
26
|
+
},
|
|
23
27
|
});
|
|
24
28
|
//# sourceMappingURL=routers.js.map
|
package/dist/routers.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routers.js","sourceRoot":"","sources":["../src/routers.ts"],"names":[],"mappings":";AAAA,4CAA4C;;;
|
|
1
|
+
{"version":3,"file":"routers.js","sourceRoot":"","sources":["../src/routers.ts"],"names":[],"mappings":";AAAA,4CAA4C;;;AA2B5C,mCAAiC;AACjC,mCAAgC;AAChC,iCAAiC;AACjC,uDAAiD;AACjD,qDAAgD;AAEhD,sEAAsE;AACzD,QAAA,OAAO,GAAY,MAAM,CAAC,MAAM,CAAC;IAC5C,MAAM,CACJ,KAA6B,EAC7B,MAAc,EACd,UAAsB,EACtB,OAAgB,EAChB,UAAqB;QAErB,OAAO,IAAI,cAAM,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,CAAC,CAAA;IACnE,CAAC;IAED,aAAa,CACX,OAAqB,EACrB,MAAc,EACd,UAAsB,EACtB,OAAgB,EAChB,IAAe;QAEf,OAAO,IAAI,+BAAa,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;IACtE,CAAC;IAED,QAAQ,CACN,OAAU,EACV,IAA6C,EAC7C,MAAyB,EACzB,GAAwB;QAExB,OAAO,IAAI,eAAQ,CAAU,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,CAAA;IAC1D,CAAC;IAED,OAAO,CAAC,KAAW,EAAE,MAAc,EAAE,KAAgB,EAAE,OAAgB;QACrE,OAAO,IAAI,eAAO,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,CAAA;IACnD,CAAC;IAED,aAAa,CAAC,IAAc,EAAE,UAAgB;QAC5C,OAAO,IAAI,8BAAa,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;IAC5C,CAAC;CACF,CAAC,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Flow, ParserEvent, ParserSink, Sink, TreeSpec } from '@tabnas/alchemy/shared';
|
|
2
|
+
export declare class TransduceTree implements ParserSink {
|
|
3
|
+
readonly spec: TreeSpec;
|
|
4
|
+
readonly down: Sink;
|
|
5
|
+
open: number;
|
|
6
|
+
carry: boolean;
|
|
7
|
+
constructor(spec: TreeSpec, down: Sink);
|
|
8
|
+
event(ev: ParserEvent): Flow;
|
|
9
|
+
private openPass;
|
|
10
|
+
private closePass;
|
|
11
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* Copyright (c) 2026 tabnas, MIT License */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.TransduceTree = void 0;
|
|
5
|
+
// `TransduceTree`: alchemy's `transduce-tree` run natively, the parser's
|
|
6
|
+
// rule passes (`ParserEvents/1`) in and a tree's `JsonEvents/1` out, as a
|
|
7
|
+
// `TreeSpec` keyed by rule name says (rs/src/transduce_tree.rs).
|
|
8
|
+
//
|
|
9
|
+
// The library's text (`stdlib/transduce.alc`) is the specification, and
|
|
10
|
+
// alchemy's `TreeSpec` documents what a native must do: each pass is looked
|
|
11
|
+
// up by its rule's name, one lookup per pass whatever the spec's size; an
|
|
12
|
+
// open pass announces its key, then begins its container or yields its
|
|
13
|
+
// scalar from one of its tokens; a close pass ends its container, or
|
|
14
|
+
// yields its own value; and a container whose rule is replaced by a rule
|
|
15
|
+
// the spec names a container is one container, so that close ends nothing
|
|
16
|
+
// and the replacing open begins nothing. The state is the count of open
|
|
17
|
+
// containers and whether a close handed its container on, so the native
|
|
18
|
+
// retains the document's nesting and nothing of its width or length, as
|
|
19
|
+
// the library's step does. alchemy-cli's differential test holds the two
|
|
20
|
+
// to the same bytes.
|
|
21
|
+
//
|
|
22
|
+
// A pass's events are worked out before the first of them is written, as
|
|
23
|
+
// the library's step returns them together: a pass that fails writes none.
|
|
24
|
+
// The failures are the library's, with its codes and texts.
|
|
25
|
+
const shared_1 = require("@tabnas/alchemy/shared");
|
|
26
|
+
// The library's `transduce-tree`, natively, writing to `down`.
|
|
27
|
+
class TransduceTree {
|
|
28
|
+
constructor(spec, down) {
|
|
29
|
+
this.spec = spec;
|
|
30
|
+
this.down = down;
|
|
31
|
+
// Containers open.
|
|
32
|
+
this.open = 0;
|
|
33
|
+
// A close handed its container on to the rule replacing it.
|
|
34
|
+
this.carry = false;
|
|
35
|
+
}
|
|
36
|
+
event(ev) {
|
|
37
|
+
switch (ev.type) {
|
|
38
|
+
case 'open':
|
|
39
|
+
return this.openPass(ev.pass);
|
|
40
|
+
case 'close':
|
|
41
|
+
return this.closePass(ev.pass);
|
|
42
|
+
case 'end':
|
|
43
|
+
if (0 < this.open) {
|
|
44
|
+
throw new shared_1.Fail('PROTOCOL_ORDER_ERROR', "the rule passes ended inside a container, which a tree's never do");
|
|
45
|
+
}
|
|
46
|
+
return this.down.event(shared_1.Ev.end);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
openPass(pass) {
|
|
50
|
+
const rule = this.spec.rules.get(pass.name);
|
|
51
|
+
if (undefined === rule)
|
|
52
|
+
return 'continue';
|
|
53
|
+
let key;
|
|
54
|
+
if (undefined !== rule.key) {
|
|
55
|
+
if ('name' in rule.key)
|
|
56
|
+
key = rule.key.name;
|
|
57
|
+
else {
|
|
58
|
+
const token = pass.tokens[rule.key.token];
|
|
59
|
+
if (undefined !== token) {
|
|
60
|
+
if ('string' !== token.val.type) {
|
|
61
|
+
throw typeError(`key: the name must be a string, not ${kind(token.val)}`);
|
|
62
|
+
}
|
|
63
|
+
key = token.val.value;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
let then;
|
|
68
|
+
if (undefined !== rule.container) {
|
|
69
|
+
if (this.carry)
|
|
70
|
+
this.carry = false;
|
|
71
|
+
else {
|
|
72
|
+
this.open++;
|
|
73
|
+
then = 'object' === rule.container ? shared_1.Ev.objectStart : shared_1.Ev.arrayStart;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else if (undefined !== rule.scalar && 'value' !== rule.scalar) {
|
|
77
|
+
const token = pass.tokens[rule.scalar.token];
|
|
78
|
+
if (undefined !== token)
|
|
79
|
+
then = scalar(token.val);
|
|
80
|
+
}
|
|
81
|
+
if (undefined !== key && 'stop' === this.down.event(shared_1.Ev.key(key)))
|
|
82
|
+
return 'stop';
|
|
83
|
+
return undefined === then ? 'continue' : this.down.event(then);
|
|
84
|
+
}
|
|
85
|
+
closePass(pass) {
|
|
86
|
+
const rule = this.spec.rules.get(pass.name);
|
|
87
|
+
if (undefined === rule)
|
|
88
|
+
return 'continue';
|
|
89
|
+
if (undefined === rule.container) {
|
|
90
|
+
if ('value' === rule.scalar && undefined !== pass.value)
|
|
91
|
+
return this.down.event(scalar(pass.value));
|
|
92
|
+
return 'continue';
|
|
93
|
+
}
|
|
94
|
+
if (undefined !== pass.alt && (0, shared_1.isTreeContainer)(this.spec, pass.alt.r)) {
|
|
95
|
+
this.carry = true;
|
|
96
|
+
return 'continue';
|
|
97
|
+
}
|
|
98
|
+
if (0 === this.open)
|
|
99
|
+
throw typeError('pop: the vector is empty; there is no last item to remove');
|
|
100
|
+
this.open--;
|
|
101
|
+
this.carry = false;
|
|
102
|
+
return this.down.event('object' === rule.container ? shared_1.Ev.objectEnd : shared_1.Ev.arrayEnd);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
exports.TransduceTree = TransduceTree;
|
|
106
|
+
// A value as the library's `scalar` takes it, or its refusal.
|
|
107
|
+
function scalar(value) {
|
|
108
|
+
switch (value.type) {
|
|
109
|
+
case 'null':
|
|
110
|
+
return shared_1.Ev.null;
|
|
111
|
+
case 'bool':
|
|
112
|
+
return shared_1.Ev.bool(value.value);
|
|
113
|
+
case 'number':
|
|
114
|
+
return shared_1.Ev.number(value.value, value.lexeme);
|
|
115
|
+
case 'string':
|
|
116
|
+
return shared_1.Ev.string(value.value);
|
|
117
|
+
default:
|
|
118
|
+
throw typeError(`scalar: the value must be null, a boolean, a number or a string, not ${kind(value)}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// What a value is, in the runtime's words.
|
|
122
|
+
function kind(value) {
|
|
123
|
+
switch (value.type) {
|
|
124
|
+
case 'null':
|
|
125
|
+
return 'null';
|
|
126
|
+
case 'bool':
|
|
127
|
+
return 'a boolean';
|
|
128
|
+
case 'number':
|
|
129
|
+
return 'a number';
|
|
130
|
+
case 'string':
|
|
131
|
+
return 'a string';
|
|
132
|
+
case 'array':
|
|
133
|
+
return 'a vector';
|
|
134
|
+
case 'object':
|
|
135
|
+
return 'a record';
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// The runtime's type error: `DSL_TYPE_ERROR`, the `type_mismatch` word
|
|
139
|
+
// first.
|
|
140
|
+
function typeError(message) {
|
|
141
|
+
return new shared_1.Fail('DSL_TYPE_ERROR', `type_mismatch: ${message}`);
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=transduce-tree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transduce-tree.js","sourceRoot":"","sources":["../src/transduce-tree.ts"],"names":[],"mappings":"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"}
|
package/dist/transduce.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const VERSION = "0.2.
|
|
1
|
+
export declare const VERSION = "0.2.9";
|
|
2
2
|
export { Datum, DatumBuilder, byteSize, fromJSON, fromTabnas, getPath, takePath, toJSON, toText, walkDatum, } from '@tabnas/alchemy/shared';
|
|
3
3
|
export type { Duplicates } from '@tabnas/alchemy/shared';
|
|
4
4
|
export { Code, Fail, isFail } from '@tabnas/alchemy/shared';
|
|
@@ -23,6 +23,10 @@ export { Prune, SourceMode, ValueSource, engineFailure, walkValue } from './sour
|
|
|
23
23
|
export type { Source } from './source';
|
|
24
24
|
export { Guarded } from './guard';
|
|
25
25
|
export { ParserSource } from './parser-source';
|
|
26
|
+
export { ParserEventSource } from './parser-event-source';
|
|
27
|
+
export { TransduceTree } from './transduce-tree';
|
|
28
|
+
export { isTreeContainer, parserEventFromJSON, parserEventToJSON } from '@tabnas/alchemy/shared';
|
|
29
|
+
export type { ParserEvent, ParserSink, PassAlt, PassToken, RulePass, TreeContainer, TreeKey, TreeRule, TreeScalar, TreeSpec, } from '@tabnas/alchemy/shared';
|
|
26
30
|
export { DEFAULT_CHUNK_BYTES, LineFormat, LinesSource } from './lines';
|
|
27
31
|
export type { LinesChunk, LinesInput, LinesWriter } from './lines';
|
|
28
32
|
export { INCREMENTAL, capability, isIncremental } from './capability';
|
package/dist/transduce.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/* Copyright (c) 2026 tabnas, MIT License */
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
exports.engineFailure = exports.ValueSource = exports.SourceMode = exports.Prune = exports.replay = exports.TreeContract = exports.FnSink = exports.EventRecorder = exports.CountSink = exports.pathText = exports.keyText = exports.Selector = exports.Path = exports.Transition = exports.ScanEmit = exports.CaptureSpec = exports.SelectedRecorder = exports.Router = exports.FnRoute = exports.Matcher = exports.utf8Bytes = exports.NODE_BYTES = exports.Metrics = exports.Limits = exports.LIMIT_NAMES = exports.AbortFlag = exports.numberText = exports.jsonString = exports.jsonNumber = exports.isJsonNumber = exports.isStart = exports.isScalar = exports.isEnd = exports.eventText = exports.eventEquals = exports.Ev = exports.isFail = exports.Fail = exports.Code = exports.walkDatum = exports.toText = exports.toJSON = exports.takePath = exports.getPath = exports.fromTabnas = exports.fromJSON = exports.byteSize = exports.DatumBuilder = exports.Datum = exports.VERSION = void 0;
|
|
5
|
-
exports.routers = exports.TableFromJson = exports.columnFromMeta = exports.boundColumn = exports.Table = exports.Schema = exports.Cell = exports.isIncremental = exports.capability = exports.INCREMENTAL = exports.LinesSource = exports.LineFormat = exports.DEFAULT_CHUNK_BYTES = exports.ParserSource = exports.Guarded = exports.walkValue = void 0;
|
|
5
|
+
exports.routers = exports.TableFromJson = exports.columnFromMeta = exports.boundColumn = exports.Table = exports.Schema = exports.Cell = exports.isIncremental = exports.capability = exports.INCREMENTAL = exports.LinesSource = exports.LineFormat = exports.DEFAULT_CHUNK_BYTES = exports.parserEventToJSON = exports.parserEventFromJSON = exports.isTreeContainer = exports.TransduceTree = exports.ParserEventSource = exports.ParserSource = exports.Guarded = exports.walkValue = void 0;
|
|
6
6
|
// Streaming transducers over any tabnas parser.
|
|
7
7
|
//
|
|
8
8
|
// A transducer decides what a source contributes to an output model; a
|
|
@@ -12,7 +12,11 @@ exports.routers = exports.TableFromJson = exports.columnFromMeta = exports.bound
|
|
|
12
12
|
// - the source protocol `JsonEvent` (`JsonEvents/1`) and the push boundary
|
|
13
13
|
// `Sink`;
|
|
14
14
|
// - sources that produce it from a parsed value, from a live tabnas parse
|
|
15
|
-
// through the engine's rule events, or from line-delimited input
|
|
15
|
+
// through the engine's rule events, or from line-delimited input, and
|
|
16
|
+
// the source of the parser's rule passes themselves (`ParserEventSource`,
|
|
17
|
+
// `ParserEvents/1`), what a transducer part reads;
|
|
18
|
+
// - `TransduceTree`, alchemy's `transduce-tree` run natively over those
|
|
19
|
+
// passes;
|
|
16
20
|
// - `Selector`s and the matcher and router that recognize selected scopes
|
|
17
21
|
// in one pass and materialize them under a byte limit;
|
|
18
22
|
// - the table protocol `TableEvent` (`TableRows/1`) and the standard
|
|
@@ -30,7 +34,7 @@ exports.routers = exports.TableFromJson = exports.columnFromMeta = exports.bound
|
|
|
30
34
|
// under the names it always exported them by. `routers` is this package's
|
|
31
35
|
// stages as alchemy's `Routers`, for a host to pass to alchemy's `compile`.
|
|
32
36
|
// This package's version, as package.json declares it.
|
|
33
|
-
exports.VERSION = '0.2.
|
|
37
|
+
exports.VERSION = '0.2.9';
|
|
34
38
|
var shared_1 = require("@tabnas/alchemy/shared");
|
|
35
39
|
Object.defineProperty(exports, "Datum", { enumerable: true, get: function () { return shared_1.Datum; } });
|
|
36
40
|
Object.defineProperty(exports, "DatumBuilder", { enumerable: true, get: function () { return shared_1.DatumBuilder; } });
|
|
@@ -98,6 +102,14 @@ var guard_1 = require("./guard");
|
|
|
98
102
|
Object.defineProperty(exports, "Guarded", { enumerable: true, get: function () { return guard_1.Guarded; } });
|
|
99
103
|
var parser_source_1 = require("./parser-source");
|
|
100
104
|
Object.defineProperty(exports, "ParserSource", { enumerable: true, get: function () { return parser_source_1.ParserSource; } });
|
|
105
|
+
var parser_event_source_1 = require("./parser-event-source");
|
|
106
|
+
Object.defineProperty(exports, "ParserEventSource", { enumerable: true, get: function () { return parser_event_source_1.ParserEventSource; } });
|
|
107
|
+
var transduce_tree_1 = require("./transduce-tree");
|
|
108
|
+
Object.defineProperty(exports, "TransduceTree", { enumerable: true, get: function () { return transduce_tree_1.TransduceTree; } });
|
|
109
|
+
var shared_10 = require("@tabnas/alchemy/shared");
|
|
110
|
+
Object.defineProperty(exports, "isTreeContainer", { enumerable: true, get: function () { return shared_10.isTreeContainer; } });
|
|
111
|
+
Object.defineProperty(exports, "parserEventFromJSON", { enumerable: true, get: function () { return shared_10.parserEventFromJSON; } });
|
|
112
|
+
Object.defineProperty(exports, "parserEventToJSON", { enumerable: true, get: function () { return shared_10.parserEventToJSON; } });
|
|
101
113
|
var lines_1 = require("./lines");
|
|
102
114
|
Object.defineProperty(exports, "DEFAULT_CHUNK_BYTES", { enumerable: true, get: function () { return lines_1.DEFAULT_CHUNK_BYTES; } });
|
|
103
115
|
Object.defineProperty(exports, "LineFormat", { enumerable: true, get: function () { return lines_1.LineFormat; } });
|
|
@@ -106,12 +118,12 @@ var capability_1 = require("./capability");
|
|
|
106
118
|
Object.defineProperty(exports, "INCREMENTAL", { enumerable: true, get: function () { return capability_1.INCREMENTAL; } });
|
|
107
119
|
Object.defineProperty(exports, "capability", { enumerable: true, get: function () { return capability_1.capability; } });
|
|
108
120
|
Object.defineProperty(exports, "isIncremental", { enumerable: true, get: function () { return capability_1.isIncremental; } });
|
|
109
|
-
var
|
|
110
|
-
Object.defineProperty(exports, "Cell", { enumerable: true, get: function () { return
|
|
111
|
-
Object.defineProperty(exports, "Schema", { enumerable: true, get: function () { return
|
|
112
|
-
Object.defineProperty(exports, "Table", { enumerable: true, get: function () { return
|
|
113
|
-
Object.defineProperty(exports, "boundColumn", { enumerable: true, get: function () { return
|
|
114
|
-
Object.defineProperty(exports, "columnFromMeta", { enumerable: true, get: function () { return
|
|
121
|
+
var shared_11 = require("@tabnas/alchemy/shared");
|
|
122
|
+
Object.defineProperty(exports, "Cell", { enumerable: true, get: function () { return shared_11.Cell; } });
|
|
123
|
+
Object.defineProperty(exports, "Schema", { enumerable: true, get: function () { return shared_11.Schema; } });
|
|
124
|
+
Object.defineProperty(exports, "Table", { enumerable: true, get: function () { return shared_11.Table; } });
|
|
125
|
+
Object.defineProperty(exports, "boundColumn", { enumerable: true, get: function () { return shared_11.boundColumn; } });
|
|
126
|
+
Object.defineProperty(exports, "columnFromMeta", { enumerable: true, get: function () { return shared_11.columnFromMeta; } });
|
|
115
127
|
var table_from_json_1 = require("./table-from-json");
|
|
116
128
|
Object.defineProperty(exports, "TableFromJson", { enumerable: true, get: function () { return table_from_json_1.TableFromJson; } });
|
|
117
129
|
var routers_1 = require("./routers");
|
package/dist/transduce.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transduce.js","sourceRoot":"","sources":["../src/transduce.ts"],"names":[],"mappings":";AAAA,4CAA4C;;;;AAE5C,gDAAgD;AAChD,EAAE;AACF,uEAAuE;AACvE,oEAAoE;AACpE,mBAAmB;AACnB,EAAE;AACF,2EAA2E;AAC3E,YAAY;AACZ,0EAA0E;AAC1E,
|
|
1
|
+
{"version":3,"file":"transduce.js","sourceRoot":"","sources":["../src/transduce.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"7.0.2","root":["../src/capability.ts","../src/guard.ts","../src/lines.ts","../src/matcher.ts","../src/parser-source.ts","../src/route.ts","../src/routers.ts","../src/rule-events.ts","../src/scan.ts","../src/source.ts","../src/table-from-json.ts","../src/transduce.ts"],"packageJsons":["../node_modules/@tabnas/alchemy/package.json","../node_modules/@tabnas/csv/package.json","../node_modules/@tabnas/json/package.json","../node_modules/@tabnas/jsonic/package.json","../node_modules/@tabnas/parser/package.json","../node_modules/@types/node/package.json","../node_modules/undici-types/package.json","../package.json"],"missingPackageJsons":["../node_modules/@tabnas/alchemy/dist/package.json","../node_modules/@tabnas/alchemy/dist/shared/package.json","../node_modules/@tabnas/alchemy/shared/package.json","../node_modules/@tabnas/csv/dist/package.json","../node_modules/@tabnas/json/dist/package.json","../node_modules/@tabnas/parser/dist/package.json","../node_modules/@types/assert/package.json","../node_modules/@types/assert/strict/package.json","../node_modules/@types/async_hooks/package.json","../node_modules/@types/buffer/package.json","../node_modules/@types/child_process/package.json","../node_modules/@types/cluster/package.json","../node_modules/@types/console/package.json","../node_modules/@types/constants/package.json","../node_modules/@types/crypto/package.json","../node_modules/@types/dgram/package.json","../node_modules/@types/diagnostics_channel/package.json","../node_modules/@types/dns/package.json","../node_modules/@types/dns/promises/package.json","../node_modules/@types/domain/package.json","../node_modules/@types/events/package.json","../node_modules/@types/fs/package.json","../node_modules/@types/fs/promises/package.json","../node_modules/@types/http/package.json","../node_modules/@types/http2/package.json","../node_modules/@types/https/package.json","../node_modules/@types/inspector/package.json","../node_modules/@types/inspector/promises/package.json","../node_modules/@types/module/package.json","../node_modules/@types/net/package.json","../node_modules/@types/node/assert/package.json","../node_modules/@types/node/dns/package.json","../node_modules/@types/node/fs/package.json","../node_modules/@types/node/inspector/package.json","../node_modules/@types/node/path/package.json","../node_modules/@types/node/readline/package.json","../node_modules/@types/node/stream/package.json","../node_modules/@types/node/test/package.json","../node_modules/@types/node/timers/package.json","../node_modules/@types/node/util/package.json","../node_modules/@types/node/web-globals/package.json","../node_modules/@types/node/zlib/package.json","../node_modules/@types/os/package.json","../node_modules/@types/path/package.json","../node_modules/@types/path/posix/package.json","../node_modules/@types/path/win32/package.json","../node_modules/@types/perf_hooks/package.json","../node_modules/@types/process/package.json","../node_modules/@types/punycode/package.json","../node_modules/@types/querystring/package.json","../node_modules/@types/readline/package.json","../node_modules/@types/readline/promises/package.json","../node_modules/@types/repl/package.json","../node_modules/@types/stream/consumers/package.json","../node_modules/@types/stream/iter/package.json","../node_modules/@types/stream/package.json","../node_modules/@types/stream/promises/package.json","../node_modules/@types/stream/web/package.json","../node_modules/@types/string_decoder/package.json","../node_modules/@types/timers/package.json","../node_modules/@types/timers/promises/package.json","../node_modules/@types/tls/package.json","../node_modules/@types/trace_events/package.json","../node_modules/@types/tty/package.json","../node_modules/@types/url/package.json","../node_modules/@types/util/package.json","../node_modules/@types/util/types/package.json","../node_modules/@types/v8/package.json","../node_modules/@types/vm/package.json","../node_modules/@types/wasi/package.json","../node_modules/@types/worker_threads/package.json","../node_modules/@types/zlib/package.json","../node_modules/assert/package.json","../node_modules/assert/strict/package.json","../node_modules/async_hooks/package.json","../node_modules/buffer/package.json","../node_modules/child_process/package.json","../node_modules/cluster/package.json","../node_modules/console/package.json","../node_modules/constants/package.json","../node_modules/crypto/package.json","../node_modules/dgram/package.json","../node_modules/diagnostics_channel/package.json","../node_modules/dns/package.json","../node_modules/dns/promises/package.json","../node_modules/domain/package.json","../node_modules/events/package.json","../node_modules/fs/package.json","../node_modules/fs/promises/package.json","../node_modules/http/package.json","../node_modules/http2/package.json","../node_modules/https/package.json","../node_modules/inspector/package.json","../node_modules/inspector/promises/package.json","../node_modules/module/package.json","../node_modules/net/package.json","../node_modules/os/package.json","../node_modules/path/package.json","../node_modules/path/posix/package.json","../node_modules/path/win32/package.json","../node_modules/perf_hooks/package.json","../node_modules/process/package.json","../node_modules/punycode/package.json","../node_modules/querystring/package.json","../node_modules/readline/package.json","../node_modules/readline/promises/package.json","../node_modules/repl/package.json","../node_modules/stream/consumers/package.json","../node_modules/stream/iter/package.json","../node_modules/stream/package.json","../node_modules/stream/promises/package.json","../node_modules/stream/web/package.json","../node_modules/string_decoder/package.json","../node_modules/timers/package.json","../node_modules/timers/promises/package.json","../node_modules/tls/package.json","../node_modules/trace_events/package.json","../node_modules/tty/package.json","../node_modules/url/package.json","../node_modules/util/package.json","../node_modules/util/types/package.json","../node_modules/v8/package.json","../node_modules/vm/package.json","../node_modules/wasi/package.json","../node_modules/worker_threads/package.json","../node_modules/zlib/package.json"]}
|
|
1
|
+
{"version":"7.0.2","root":["../src/capability.ts","../src/guard.ts","../src/lines.ts","../src/matcher.ts","../src/parser-event-source.ts","../src/parser-source.ts","../src/route.ts","../src/routers.ts","../src/rule-events.ts","../src/scan.ts","../src/source.ts","../src/table-from-json.ts","../src/transduce-tree.ts","../src/transduce.ts"],"packageJsons":["../node_modules/@tabnas/alchemy/package.json","../node_modules/@tabnas/csv/package.json","../node_modules/@tabnas/json/package.json","../node_modules/@tabnas/jsonic/package.json","../node_modules/@tabnas/parser/package.json","../node_modules/@types/node/package.json","../node_modules/undici-types/package.json","../package.json"],"missingPackageJsons":["../node_modules/@tabnas/alchemy/dist/package.json","../node_modules/@tabnas/alchemy/dist/shared/package.json","../node_modules/@tabnas/alchemy/shared/package.json","../node_modules/@tabnas/csv/dist/package.json","../node_modules/@tabnas/json/dist/package.json","../node_modules/@tabnas/parser/dist/package.json","../node_modules/@types/assert/package.json","../node_modules/@types/assert/strict/package.json","../node_modules/@types/async_hooks/package.json","../node_modules/@types/buffer/package.json","../node_modules/@types/child_process/package.json","../node_modules/@types/cluster/package.json","../node_modules/@types/console/package.json","../node_modules/@types/constants/package.json","../node_modules/@types/crypto/package.json","../node_modules/@types/dgram/package.json","../node_modules/@types/diagnostics_channel/package.json","../node_modules/@types/dns/package.json","../node_modules/@types/dns/promises/package.json","../node_modules/@types/domain/package.json","../node_modules/@types/events/package.json","../node_modules/@types/fs/package.json","../node_modules/@types/fs/promises/package.json","../node_modules/@types/http/package.json","../node_modules/@types/http2/package.json","../node_modules/@types/https/package.json","../node_modules/@types/inspector/package.json","../node_modules/@types/inspector/promises/package.json","../node_modules/@types/module/package.json","../node_modules/@types/net/package.json","../node_modules/@types/node/assert/package.json","../node_modules/@types/node/dns/package.json","../node_modules/@types/node/fs/package.json","../node_modules/@types/node/inspector/package.json","../node_modules/@types/node/path/package.json","../node_modules/@types/node/readline/package.json","../node_modules/@types/node/stream/package.json","../node_modules/@types/node/test/package.json","../node_modules/@types/node/timers/package.json","../node_modules/@types/node/util/package.json","../node_modules/@types/node/web-globals/package.json","../node_modules/@types/node/zlib/package.json","../node_modules/@types/os/package.json","../node_modules/@types/path/package.json","../node_modules/@types/path/posix/package.json","../node_modules/@types/path/win32/package.json","../node_modules/@types/perf_hooks/package.json","../node_modules/@types/process/package.json","../node_modules/@types/punycode/package.json","../node_modules/@types/querystring/package.json","../node_modules/@types/readline/package.json","../node_modules/@types/readline/promises/package.json","../node_modules/@types/repl/package.json","../node_modules/@types/stream/consumers/package.json","../node_modules/@types/stream/iter/package.json","../node_modules/@types/stream/package.json","../node_modules/@types/stream/promises/package.json","../node_modules/@types/stream/web/package.json","../node_modules/@types/string_decoder/package.json","../node_modules/@types/timers/package.json","../node_modules/@types/timers/promises/package.json","../node_modules/@types/tls/package.json","../node_modules/@types/trace_events/package.json","../node_modules/@types/tty/package.json","../node_modules/@types/url/package.json","../node_modules/@types/util/package.json","../node_modules/@types/util/types/package.json","../node_modules/@types/v8/package.json","../node_modules/@types/vm/package.json","../node_modules/@types/wasi/package.json","../node_modules/@types/worker_threads/package.json","../node_modules/@types/zlib/package.json","../node_modules/assert/package.json","../node_modules/assert/strict/package.json","../node_modules/async_hooks/package.json","../node_modules/buffer/package.json","../node_modules/child_process/package.json","../node_modules/cluster/package.json","../node_modules/console/package.json","../node_modules/constants/package.json","../node_modules/crypto/package.json","../node_modules/dgram/package.json","../node_modules/diagnostics_channel/package.json","../node_modules/dns/package.json","../node_modules/dns/promises/package.json","../node_modules/domain/package.json","../node_modules/events/package.json","../node_modules/fs/package.json","../node_modules/fs/promises/package.json","../node_modules/http/package.json","../node_modules/http2/package.json","../node_modules/https/package.json","../node_modules/inspector/package.json","../node_modules/inspector/promises/package.json","../node_modules/module/package.json","../node_modules/net/package.json","../node_modules/os/package.json","../node_modules/path/package.json","../node_modules/path/posix/package.json","../node_modules/path/win32/package.json","../node_modules/perf_hooks/package.json","../node_modules/process/package.json","../node_modules/punycode/package.json","../node_modules/querystring/package.json","../node_modules/readline/package.json","../node_modules/readline/promises/package.json","../node_modules/repl/package.json","../node_modules/stream/consumers/package.json","../node_modules/stream/iter/package.json","../node_modules/stream/package.json","../node_modules/stream/promises/package.json","../node_modules/stream/web/package.json","../node_modules/string_decoder/package.json","../node_modules/timers/package.json","../node_modules/timers/promises/package.json","../node_modules/tls/package.json","../node_modules/trace_events/package.json","../node_modules/tty/package.json","../node_modules/url/package.json","../node_modules/util/package.json","../node_modules/util/types/package.json","../node_modules/v8/package.json","../node_modules/vm/package.json","../node_modules/wasi/package.json","../node_modules/worker_threads/package.json","../node_modules/zlib/package.json"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tabnas/transduce",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"main": "dist/transduce.js",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"types": "dist/transduce.d.ts",
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@tabnas/alchemy": "*",
|
|
53
|
+
"@tabnas/chess": "*",
|
|
53
54
|
"@tabnas/csv": "*",
|
|
54
55
|
"@tabnas/feed": "*",
|
|
55
56
|
"@tabnas/ini": "*",
|
package/src/capability.ts
CHANGED
|
@@ -32,7 +32,14 @@
|
|
|
32
32
|
// when the root closes, so the adapter refuses each on its own samples.
|
|
33
33
|
|
|
34
34
|
// The grammars whose incremental events never contradict the whole-value
|
|
35
|
-
// walk on any fixture, by
|
|
35
|
+
// walk on any fixture, by the name of the format each reads: its package's
|
|
36
|
+
// (`@tabnas/<name>`), but `pgn` for @tabnas/chess, the name hosts ask by.
|
|
37
|
+
// @tabnas/chess builds each game on a stack in the parse's context, so
|
|
38
|
+
// the database is the only container in the parse tree and a game is
|
|
39
|
+
// stored in it only once complete: each game is walked at its insertion.
|
|
40
|
+
// That is @tabnas/chess 0.1.17 and later; earlier releases attached a
|
|
41
|
+
// game's parts after the adapter had sent them, and this package does not
|
|
42
|
+
// depend on @tabnas/chess, so a host that streams PGN takes 0.1.17 or later.
|
|
36
43
|
export const INCREMENTAL: readonly string[] = Object.freeze([
|
|
37
44
|
'json',
|
|
38
45
|
'json5',
|
|
@@ -40,6 +47,7 @@ export const INCREMENTAL: readonly string[] = Object.freeze([
|
|
|
40
47
|
'jsonic',
|
|
41
48
|
'jsonl',
|
|
42
49
|
'markdown',
|
|
50
|
+
'pgn',
|
|
43
51
|
'xml',
|
|
44
52
|
'yaml',
|
|
45
53
|
'zon',
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/* Copyright (c) 2026 tabnas, MIT License */
|
|
2
|
+
|
|
3
|
+
// `ParserEventSource`: `ParserEvents/1` from a tabnas parse of one text,
|
|
4
|
+
// the input a transducer part reads (rs/src/source/parser_events.rs).
|
|
5
|
+
//
|
|
6
|
+
// The source installs one `ruleDone` subscriber, which relays each rule
|
|
7
|
+
// pass the engine completes as a `ParserEvent`, on the thread that parses,
|
|
8
|
+
// into a `ParserSink`: an `open` when a rule's open pass has run, a `close`
|
|
9
|
+
// when its close pass has. It knows no grammar. When the engine has
|
|
10
|
+
// returned the parse's value it sends one `end`, so a document is complete
|
|
11
|
+
// only once it validated, as every source's is.
|
|
12
|
+
//
|
|
13
|
+
// What each pass carries is alchemy's `RulePass`:
|
|
14
|
+
//
|
|
15
|
+
// - the rule's `name`, its depth `d` and instance `i` (the engine's, which
|
|
16
|
+
// counts from 1 here and from 0 in Go and Rust: DIVERGENCE.md 6), the
|
|
17
|
+
// alternate that matched (`alt`: `p`, `r`, `b`, and its groups `g`,
|
|
18
|
+
// sorted, since they are tags whose order the runtimes' engines keep
|
|
19
|
+
// differently), whether recovery forced the close, and its named counters
|
|
20
|
+
// `n`, sorted by name;
|
|
21
|
+
// - the `tokens` the pass consumed: those its alternate matched (the
|
|
22
|
+
// engine's `o[:oN]` or `c[:cN]`), less the `b` it gave back from their
|
|
23
|
+
// end, which are the next rule's to consume, and none when `b` is more
|
|
24
|
+
// than it recorded, since a close alternate can back up a token it did
|
|
25
|
+
// not record. A token is its name, its value, its source text and its
|
|
26
|
+
// 1-based row and column; a token with no value (the end of the source,
|
|
27
|
+
// a fixed token such as `[`, which Rust's engine gives its text:
|
|
28
|
+
// DIVERGENCE.md 7) has `null`, and a number carries its source text as its lexeme when
|
|
29
|
+
// that text is a JSON number spelling the value (RFC 8259), the rule the
|
|
30
|
+
// incremental source keeps lexemes by, so a renderer can write it as it
|
|
31
|
+
// stands;
|
|
32
|
+
// - on a close pass, the rule's node when that is a scalar (`value`), a
|
|
33
|
+
// number with the lexeme of the rule's first open token as above;
|
|
34
|
+
// nothing on an open pass, nor for a container.
|
|
35
|
+
//
|
|
36
|
+
// A pass made while a probe is open is speculative: the grammar parses
|
|
37
|
+
// ahead and rewinds past it (tabnas-bnf's probe, the engine's own for a
|
|
38
|
+
// serialized grammar's `pd_` keys), so it is never the document's. The
|
|
39
|
+
// engine flags it (`RuleDone.probe`), and the source drops it before any
|
|
40
|
+
// sink sees it.
|
|
41
|
+
//
|
|
42
|
+
// The source holds its limits as it builds each pass, before the sink sees
|
|
43
|
+
// it: a token's value or source text, or a pass's value, longer than
|
|
44
|
+
// `max_scalar_bytes` is refused with that limit's name, as a JSON-events
|
|
45
|
+
// source refuses a scalar. `max_depth` and `max_key_bytes` hold where a
|
|
46
|
+
// part's outputs become `JsonEvents/1`, on the events it writes. The abort
|
|
47
|
+
// flag is polled per pass, and `Metrics.events` counts the events
|
|
48
|
+
// delivered.
|
|
49
|
+
//
|
|
50
|
+
// Failure mapping is `ParserSource`'s: a sink failure is thrown as it was;
|
|
51
|
+
// a sink that stopped is `'stop'`; a parse cancelled through the caller's
|
|
52
|
+
// `AbortFlag` is `ABORTED`; any other engine error is `INPUT_INVALID` with
|
|
53
|
+
// the engine's code and position. A source runs once, as `ParserSource`
|
|
54
|
+
// does: its parser carries the run's subscriber and budget.
|
|
55
|
+
|
|
56
|
+
import {
|
|
57
|
+
AbortFlag,
|
|
58
|
+
Datum,
|
|
59
|
+
Fail,
|
|
60
|
+
Limits,
|
|
61
|
+
Metrics,
|
|
62
|
+
engineScalar,
|
|
63
|
+
fromTabnas,
|
|
64
|
+
isJsonNumber,
|
|
65
|
+
utf8Bytes,
|
|
66
|
+
} from '@tabnas/alchemy/shared'
|
|
67
|
+
import type { Flow, ParserEvent, ParserSink, PassAlt, PassToken, RulePass } from '@tabnas/alchemy/shared'
|
|
68
|
+
import type { Rule, RuleDone, Tabnas } from '@tabnas/parser'
|
|
69
|
+
|
|
70
|
+
import { prepare } from './rule-events'
|
|
71
|
+
import { engineFailure } from './source'
|
|
72
|
+
|
|
73
|
+
// A tabnas parser applied to one text, as a source of its rule passes.
|
|
74
|
+
export class ParserEventSource {
|
|
75
|
+
private parser: Tabnas
|
|
76
|
+
private text: string
|
|
77
|
+
private sourceLimits: Limits = Limits.default()
|
|
78
|
+
private abortFlag: AbortFlag = new AbortFlag()
|
|
79
|
+
private sourceMetrics: Metrics = new Metrics()
|
|
80
|
+
private used = false
|
|
81
|
+
|
|
82
|
+
// A source with default limits, its own abort flag and fresh metrics; the
|
|
83
|
+
// builder methods change each.
|
|
84
|
+
constructor(parser: Tabnas, text: string) {
|
|
85
|
+
this.parser = parser
|
|
86
|
+
this.text = text
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
limits(limits: Limits): this {
|
|
90
|
+
this.sourceLimits = limits
|
|
91
|
+
return this
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
abort(abort: AbortFlag): this {
|
|
95
|
+
this.abortFlag = abort
|
|
96
|
+
return this
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
metrics(metrics: Metrics): this {
|
|
100
|
+
this.sourceMetrics = metrics
|
|
101
|
+
return this
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Parse, relaying each pass into `sink`, then `end`.
|
|
105
|
+
run(sink: ParserSink): Flow {
|
|
106
|
+
if (this.used) {
|
|
107
|
+
throw new Fail(
|
|
108
|
+
'STREAM_REUSED',
|
|
109
|
+
"a ParserEventSource runs once: its parser carries the run's subscriber and budget; " +
|
|
110
|
+
'make a new source, with a new parser, for another run',
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
this.used = true
|
|
114
|
+
const abort = this.abortFlag
|
|
115
|
+
const stop = new AbortFlag()
|
|
116
|
+
const relay = new Relay(sink, this.sourceLimits.max_scalar_bytes, abort, stop)
|
|
117
|
+
prepare(
|
|
118
|
+
this.parser,
|
|
119
|
+
() => !abort.isAborted() && !stop.isAborted(),
|
|
120
|
+
(rule, done) => relay.onDone(rule, done),
|
|
121
|
+
)
|
|
122
|
+
let parsed: { ok: true } | { ok: false; error: unknown }
|
|
123
|
+
try {
|
|
124
|
+
this.parser.parse(this.text)
|
|
125
|
+
parsed = { ok: true }
|
|
126
|
+
} catch (error) {
|
|
127
|
+
parsed = { ok: false, error }
|
|
128
|
+
}
|
|
129
|
+
try {
|
|
130
|
+
const status = relay.status
|
|
131
|
+
if ('failed' === status.type) throw status.error
|
|
132
|
+
if ('stopped' === status.type) return 'stop'
|
|
133
|
+
if (!parsed.ok) throw engineFailure(parsed.error, abort)
|
|
134
|
+
return relay.send({ type: 'end' })
|
|
135
|
+
} finally {
|
|
136
|
+
this.sourceMetrics.events += relay.events
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
type Status = { type: 'running' } | { type: 'stopped' } | { type: 'failed'; error: unknown }
|
|
142
|
+
|
|
143
|
+
// The subscriber's state: the sink and how the run stands.
|
|
144
|
+
class Relay {
|
|
145
|
+
status: Status = { type: 'running' }
|
|
146
|
+
events = 0
|
|
147
|
+
|
|
148
|
+
constructor(
|
|
149
|
+
readonly sink: ParserSink,
|
|
150
|
+
readonly maxScalarBytes: number,
|
|
151
|
+
readonly abort: AbortFlag,
|
|
152
|
+
// Set to make the parse guard cancel the parse.
|
|
153
|
+
readonly stop: AbortFlag,
|
|
154
|
+
) {}
|
|
155
|
+
|
|
156
|
+
send(ev: ParserEvent): Flow {
|
|
157
|
+
this.events++
|
|
158
|
+
return this.sink.event(ev)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
private fail(error: unknown): void {
|
|
162
|
+
this.status = { type: 'failed', error }
|
|
163
|
+
this.stop.abort()
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// One pass the engine completed.
|
|
167
|
+
onDone(rule: Rule, done: RuleDone): void {
|
|
168
|
+
if (true === done.probe || 'running' !== this.status.type) return
|
|
169
|
+
if (this.abort.isAborted()) {
|
|
170
|
+
this.fail(Fail.aborted())
|
|
171
|
+
return
|
|
172
|
+
}
|
|
173
|
+
const open = 'o' === done.state
|
|
174
|
+
let ev: ParserEvent
|
|
175
|
+
try {
|
|
176
|
+
const pass = rulePass(rule, done, open, this.maxScalarBytes)
|
|
177
|
+
ev = open ? { type: 'open', pass } : { type: 'close', pass }
|
|
178
|
+
} catch (error) {
|
|
179
|
+
this.fail(error)
|
|
180
|
+
return
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
if ('stop' === this.send(ev)) {
|
|
184
|
+
this.status = { type: 'stopped' }
|
|
185
|
+
this.stop.abort()
|
|
186
|
+
}
|
|
187
|
+
} catch (error) {
|
|
188
|
+
this.fail(error)
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// The pass as alchemy's `RulePass`, its sizes held to `max_scalar_bytes`.
|
|
194
|
+
function rulePass(rule: Rule, done: RuleDone, open: boolean, max: number): RulePass {
|
|
195
|
+
const r: any = rule
|
|
196
|
+
const recorded: any[] = open ? r.o.slice(0, r.oN) : r.c.slice(0, r.cN)
|
|
197
|
+
const b = null == done.alt ? 0 : done.alt.b
|
|
198
|
+
const kept = recorded.slice(0, Math.max(0, recorded.length - b))
|
|
199
|
+
const tokens: PassToken[] = kept.map((t: any) => {
|
|
200
|
+
const src: string = 'string' === typeof t.src ? t.src : String(t.src ?? '')
|
|
201
|
+
held(utf8Bytes(src), "a token's source text", max)
|
|
202
|
+
const val = scalarOf(t.val, src)
|
|
203
|
+
if ('string' === val.type) held(utf8Bytes(val.value), "a token's value", max)
|
|
204
|
+
return { name: t.name, val, src, row: t.rI, col: t.cI }
|
|
205
|
+
})
|
|
206
|
+
let value: Datum | undefined
|
|
207
|
+
if (!open && undefined !== r.node && undefined !== engineScalar(r.node)) {
|
|
208
|
+
const first = r.o[0]
|
|
209
|
+
value = scalarOf(r.node, 0 < r.oN && 'string' === typeof first?.src ? first.src : undefined)
|
|
210
|
+
if ('string' === value.type) held(utf8Bytes(value.value), "a rule's value", max)
|
|
211
|
+
}
|
|
212
|
+
const n = Object.entries((r.n ?? {}) as Record<string, number>)
|
|
213
|
+
.map(([k, v]) => [k, Math.trunc(v)] as const)
|
|
214
|
+
.sort(([a], [b]) => byCodeUnit(a, b))
|
|
215
|
+
const alt: PassAlt | undefined =
|
|
216
|
+
null == done.alt
|
|
217
|
+
? undefined
|
|
218
|
+
: { p: done.alt.p, r: done.alt.r, b: done.alt.b, g: [...done.alt.g].sort(byCodeUnit) }
|
|
219
|
+
return {
|
|
220
|
+
name: rule.name,
|
|
221
|
+
d: rule.d,
|
|
222
|
+
i: rule.i,
|
|
223
|
+
...(undefined === alt ? {} : { alt }),
|
|
224
|
+
tokens,
|
|
225
|
+
forced: true === done.forced,
|
|
226
|
+
n,
|
|
227
|
+
...(undefined === value ? {} : { value }),
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Strings in code-unit order, as Rust's `sort` orders ASCII names.
|
|
232
|
+
function byCodeUnit(a: string, b: string): number {
|
|
233
|
+
return a < b ? -1 : a > b ? 1 : 0
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// An engine value as a pass carries it: `undefined` as null, and a number
|
|
237
|
+
// with `lexeme` when that text is a JSON number spelling it.
|
|
238
|
+
export function scalarOf(value: unknown, lexeme: string | undefined): Datum {
|
|
239
|
+
const scalar = engineScalar(value)
|
|
240
|
+
if (undefined !== scalar && 'number' === scalar.type) {
|
|
241
|
+
const keep = undefined !== lexeme && isJsonNumber(lexeme) && Number(lexeme) === scalar.value
|
|
242
|
+
return Datum.number(scalar.value, keep ? lexeme : undefined)
|
|
243
|
+
}
|
|
244
|
+
return fromTabnas(value)
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// `max_scalar_bytes` held on one text a pass carries.
|
|
248
|
+
function held(bytes: number, what: string, max: number): void {
|
|
249
|
+
if (bytes > max) {
|
|
250
|
+
throw Fail.limit('max_scalar_bytes', max, `${what} of ${bytes} bytes is larger than ${max}`)
|
|
251
|
+
}
|
|
252
|
+
}
|
package/src/parser-source.ts
CHANGED
|
@@ -62,9 +62,11 @@ export class ParserSource implements Source {
|
|
|
62
62
|
return this
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
// The grammar the parser implements, by
|
|
66
|
-
//
|
|
67
|
-
// `
|
|
65
|
+
// The grammar the parser implements, by the name of the format it reads:
|
|
66
|
+
// the `languageId` its package's manifest declares, which is the
|
|
67
|
+
// package's own name for most (`json` for `@tabnas/json`) but `pgn` for
|
|
68
|
+
// `@tabnas/chess`. Incremental mode runs only for a name
|
|
69
|
+
// `capability.incremental` lists (`chess` is not one).
|
|
68
70
|
grammar(name: string): this {
|
|
69
71
|
this.grammarName = name
|
|
70
72
|
return this
|
package/src/routers.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/* Copyright (c) 2026 tabnas, MIT License */
|
|
2
2
|
|
|
3
3
|
// This package's stages as alchemy's `Routers`: what an alchemy program's
|
|
4
|
-
// runtime builds its routes, tables, scans and guards from
|
|
4
|
+
// runtime builds its routes, tables, scans and guards from, and the native
|
|
5
|
+
// `transduce-tree` it runs over the parser's rule passes. Alchemy
|
|
5
6
|
// declares the interface (`@tabnas/alchemy/shared`) and imports no
|
|
6
7
|
// transducer; a host passes `routers` to its `compile`, with render's
|
|
7
8
|
// `renderers`: `compile(src, file, { routers, renderers })`.
|
|
@@ -13,6 +14,7 @@ import {
|
|
|
13
14
|
Flow,
|
|
14
15
|
Limits,
|
|
15
16
|
Metrics,
|
|
17
|
+
ParserSink,
|
|
16
18
|
RouteSink,
|
|
17
19
|
Routers,
|
|
18
20
|
Scan,
|
|
@@ -20,12 +22,14 @@ import {
|
|
|
20
22
|
TableBinding,
|
|
21
23
|
TableSink,
|
|
22
24
|
Transition,
|
|
25
|
+
TreeSpec,
|
|
23
26
|
} from '@tabnas/alchemy/shared'
|
|
24
27
|
|
|
25
28
|
import { Guarded } from './guard'
|
|
26
29
|
import { Router } from './route'
|
|
27
30
|
import { ScanEmit } from './scan'
|
|
28
31
|
import { TableFromJson } from './table-from-json'
|
|
32
|
+
import { TransduceTree } from './transduce-tree'
|
|
29
33
|
|
|
30
34
|
// Each method constructs the stage it names with the same parameters.
|
|
31
35
|
export const routers: Routers = Object.freeze({
|
|
@@ -61,4 +65,8 @@ export const routers: Routers = Object.freeze({
|
|
|
61
65
|
guarded(inner: Sink, limits: Limits, abort: AbortFlag, metrics: Metrics): Sink {
|
|
62
66
|
return new Guarded(inner, limits, abort, metrics)
|
|
63
67
|
},
|
|
68
|
+
|
|
69
|
+
transduceTree(spec: TreeSpec, downstream: Sink): ParserSink {
|
|
70
|
+
return new TransduceTree(spec, downstream)
|
|
71
|
+
},
|
|
64
72
|
})
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/* Copyright (c) 2026 tabnas, MIT License */
|
|
2
|
+
|
|
3
|
+
// `TransduceTree`: alchemy's `transduce-tree` run natively, the parser's
|
|
4
|
+
// rule passes (`ParserEvents/1`) in and a tree's `JsonEvents/1` out, as a
|
|
5
|
+
// `TreeSpec` keyed by rule name says (rs/src/transduce_tree.rs).
|
|
6
|
+
//
|
|
7
|
+
// The library's text (`stdlib/transduce.alc`) is the specification, and
|
|
8
|
+
// alchemy's `TreeSpec` documents what a native must do: each pass is looked
|
|
9
|
+
// up by its rule's name, one lookup per pass whatever the spec's size; an
|
|
10
|
+
// open pass announces its key, then begins its container or yields its
|
|
11
|
+
// scalar from one of its tokens; a close pass ends its container, or
|
|
12
|
+
// yields its own value; and a container whose rule is replaced by a rule
|
|
13
|
+
// the spec names a container is one container, so that close ends nothing
|
|
14
|
+
// and the replacing open begins nothing. The state is the count of open
|
|
15
|
+
// containers and whether a close handed its container on, so the native
|
|
16
|
+
// retains the document's nesting and nothing of its width or length, as
|
|
17
|
+
// the library's step does. alchemy-cli's differential test holds the two
|
|
18
|
+
// to the same bytes.
|
|
19
|
+
//
|
|
20
|
+
// A pass's events are worked out before the first of them is written, as
|
|
21
|
+
// the library's step returns them together: a pass that fails writes none.
|
|
22
|
+
// The failures are the library's, with its codes and texts.
|
|
23
|
+
|
|
24
|
+
import { Datum, Ev, Fail, isTreeContainer } from '@tabnas/alchemy/shared'
|
|
25
|
+
import type { Flow, JsonEvent, ParserEvent, ParserSink, RulePass, Sink, TreeSpec } from '@tabnas/alchemy/shared'
|
|
26
|
+
|
|
27
|
+
// The library's `transduce-tree`, natively, writing to `down`.
|
|
28
|
+
export class TransduceTree implements ParserSink {
|
|
29
|
+
// Containers open.
|
|
30
|
+
open = 0
|
|
31
|
+
// A close handed its container on to the rule replacing it.
|
|
32
|
+
carry = false
|
|
33
|
+
|
|
34
|
+
constructor(
|
|
35
|
+
readonly spec: TreeSpec,
|
|
36
|
+
readonly down: Sink,
|
|
37
|
+
) {}
|
|
38
|
+
|
|
39
|
+
event(ev: ParserEvent): Flow {
|
|
40
|
+
switch (ev.type) {
|
|
41
|
+
case 'open':
|
|
42
|
+
return this.openPass(ev.pass)
|
|
43
|
+
case 'close':
|
|
44
|
+
return this.closePass(ev.pass)
|
|
45
|
+
case 'end':
|
|
46
|
+
if (0 < this.open) {
|
|
47
|
+
throw new Fail('PROTOCOL_ORDER_ERROR', "the rule passes ended inside a container, which a tree's never do")
|
|
48
|
+
}
|
|
49
|
+
return this.down.event(Ev.end)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private openPass(pass: RulePass): Flow {
|
|
54
|
+
const rule = this.spec.rules.get(pass.name)
|
|
55
|
+
if (undefined === rule) return 'continue'
|
|
56
|
+
let key: string | undefined
|
|
57
|
+
if (undefined !== rule.key) {
|
|
58
|
+
if ('name' in rule.key) key = rule.key.name
|
|
59
|
+
else {
|
|
60
|
+
const token = pass.tokens[rule.key.token]
|
|
61
|
+
if (undefined !== token) {
|
|
62
|
+
if ('string' !== token.val.type) {
|
|
63
|
+
throw typeError(`key: the name must be a string, not ${kind(token.val)}`)
|
|
64
|
+
}
|
|
65
|
+
key = token.val.value
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
let then: JsonEvent | undefined
|
|
70
|
+
if (undefined !== rule.container) {
|
|
71
|
+
if (this.carry) this.carry = false
|
|
72
|
+
else {
|
|
73
|
+
this.open++
|
|
74
|
+
then = 'object' === rule.container ? Ev.objectStart : Ev.arrayStart
|
|
75
|
+
}
|
|
76
|
+
} else if (undefined !== rule.scalar && 'value' !== rule.scalar) {
|
|
77
|
+
const token = pass.tokens[rule.scalar.token]
|
|
78
|
+
if (undefined !== token) then = scalar(token.val)
|
|
79
|
+
}
|
|
80
|
+
if (undefined !== key && 'stop' === this.down.event(Ev.key(key))) return 'stop'
|
|
81
|
+
return undefined === then ? 'continue' : this.down.event(then)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private closePass(pass: RulePass): Flow {
|
|
85
|
+
const rule = this.spec.rules.get(pass.name)
|
|
86
|
+
if (undefined === rule) return 'continue'
|
|
87
|
+
if (undefined === rule.container) {
|
|
88
|
+
if ('value' === rule.scalar && undefined !== pass.value) return this.down.event(scalar(pass.value))
|
|
89
|
+
return 'continue'
|
|
90
|
+
}
|
|
91
|
+
if (undefined !== pass.alt && isTreeContainer(this.spec, pass.alt.r)) {
|
|
92
|
+
this.carry = true
|
|
93
|
+
return 'continue'
|
|
94
|
+
}
|
|
95
|
+
if (0 === this.open) throw typeError('pop: the vector is empty; there is no last item to remove')
|
|
96
|
+
this.open--
|
|
97
|
+
this.carry = false
|
|
98
|
+
return this.down.event('object' === rule.container ? Ev.objectEnd : Ev.arrayEnd)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// A value as the library's `scalar` takes it, or its refusal.
|
|
103
|
+
function scalar(value: Datum): JsonEvent {
|
|
104
|
+
switch (value.type) {
|
|
105
|
+
case 'null':
|
|
106
|
+
return Ev.null
|
|
107
|
+
case 'bool':
|
|
108
|
+
return Ev.bool(value.value)
|
|
109
|
+
case 'number':
|
|
110
|
+
return Ev.number(value.value, value.lexeme)
|
|
111
|
+
case 'string':
|
|
112
|
+
return Ev.string(value.value)
|
|
113
|
+
default:
|
|
114
|
+
throw typeError(`scalar: the value must be null, a boolean, a number or a string, not ${kind(value)}`)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// What a value is, in the runtime's words.
|
|
119
|
+
function kind(value: Datum): string {
|
|
120
|
+
switch (value.type) {
|
|
121
|
+
case 'null':
|
|
122
|
+
return 'null'
|
|
123
|
+
case 'bool':
|
|
124
|
+
return 'a boolean'
|
|
125
|
+
case 'number':
|
|
126
|
+
return 'a number'
|
|
127
|
+
case 'string':
|
|
128
|
+
return 'a string'
|
|
129
|
+
case 'array':
|
|
130
|
+
return 'a vector'
|
|
131
|
+
case 'object':
|
|
132
|
+
return 'a record'
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// The runtime's type error: `DSL_TYPE_ERROR`, the `type_mismatch` word
|
|
137
|
+
// first.
|
|
138
|
+
function typeError(message: string): Fail {
|
|
139
|
+
return new Fail('DSL_TYPE_ERROR', `type_mismatch: ${message}`)
|
|
140
|
+
}
|
package/src/transduce.ts
CHANGED
|
@@ -9,7 +9,11 @@
|
|
|
9
9
|
// - the source protocol `JsonEvent` (`JsonEvents/1`) and the push boundary
|
|
10
10
|
// `Sink`;
|
|
11
11
|
// - sources that produce it from a parsed value, from a live tabnas parse
|
|
12
|
-
// through the engine's rule events, or from line-delimited input
|
|
12
|
+
// through the engine's rule events, or from line-delimited input, and
|
|
13
|
+
// the source of the parser's rule passes themselves (`ParserEventSource`,
|
|
14
|
+
// `ParserEvents/1`), what a transducer part reads;
|
|
15
|
+
// - `TransduceTree`, alchemy's `transduce-tree` run natively over those
|
|
16
|
+
// passes;
|
|
13
17
|
// - `Selector`s and the matcher and router that recognize selected scopes
|
|
14
18
|
// in one pass and materialize them under a byte limit;
|
|
15
19
|
// - the table protocol `TableEvent` (`TableRows/1`) and the standard
|
|
@@ -28,7 +32,7 @@
|
|
|
28
32
|
// stages as alchemy's `Routers`, for a host to pass to alchemy's `compile`.
|
|
29
33
|
|
|
30
34
|
// This package's version, as package.json declares it.
|
|
31
|
-
export const VERSION = '0.2.
|
|
35
|
+
export const VERSION = '0.2.9'
|
|
32
36
|
|
|
33
37
|
export {
|
|
34
38
|
Datum,
|
|
@@ -72,6 +76,21 @@ export { Prune, SourceMode, ValueSource, engineFailure, walkValue } from './sour
|
|
|
72
76
|
export type { Source } from './source'
|
|
73
77
|
export { Guarded } from './guard'
|
|
74
78
|
export { ParserSource } from './parser-source'
|
|
79
|
+
export { ParserEventSource } from './parser-event-source'
|
|
80
|
+
export { TransduceTree } from './transduce-tree'
|
|
81
|
+
export { isTreeContainer, parserEventFromJSON, parserEventToJSON } from '@tabnas/alchemy/shared'
|
|
82
|
+
export type {
|
|
83
|
+
ParserEvent,
|
|
84
|
+
ParserSink,
|
|
85
|
+
PassAlt,
|
|
86
|
+
PassToken,
|
|
87
|
+
RulePass,
|
|
88
|
+
TreeContainer,
|
|
89
|
+
TreeKey,
|
|
90
|
+
TreeRule,
|
|
91
|
+
TreeScalar,
|
|
92
|
+
TreeSpec,
|
|
93
|
+
} from '@tabnas/alchemy/shared'
|
|
75
94
|
export { DEFAULT_CHUNK_BYTES, LineFormat, LinesSource } from './lines'
|
|
76
95
|
export type { LinesChunk, LinesInput, LinesWriter } from './lines'
|
|
77
96
|
export { INCREMENTAL, capability, isIncremental } from './capability'
|