@tabnas/transduce 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/LICENSE +21 -0
- package/dist/capability.d.ts +6 -0
- package/dist/capability.js +52 -0
- package/dist/capability.js.map +1 -0
- package/dist/datum.d.ts +64 -0
- package/dist/datum.js +391 -0
- package/dist/datum.js.map +1 -0
- package/dist/error.d.ts +43 -0
- package/dist/error.js +169 -0
- package/dist/error.js.map +1 -0
- package/dist/event.d.ts +56 -0
- package/dist/event.js +101 -0
- package/dist/event.js.map +1 -0
- package/dist/guard.d.ts +20 -0
- package/dist/guard.js +90 -0
- package/dist/guard.js.map +1 -0
- package/dist/json.d.ts +4 -0
- package/dist/json.js +92 -0
- package/dist/json.js.map +1 -0
- package/dist/limits.d.ts +36 -0
- package/dist/limits.js +133 -0
- package/dist/limits.js.map +1 -0
- package/dist/lines.d.ts +39 -0
- package/dist/lines.js +1139 -0
- package/dist/lines.js.map +1 -0
- package/dist/matcher.d.ts +26 -0
- package/dist/matcher.js +245 -0
- package/dist/matcher.js.map +1 -0
- package/dist/parser-source.d.ts +27 -0
- package/dist/parser-source.js +194 -0
- package/dist/parser-source.js.map +1 -0
- package/dist/route.d.ts +61 -0
- package/dist/route.js +197 -0
- package/dist/route.js.map +1 -0
- package/dist/rule-events.d.ts +58 -0
- package/dist/rule-events.js +598 -0
- package/dist/rule-events.js.map +1 -0
- package/dist/scan.d.ts +19 -0
- package/dist/scan.js +70 -0
- package/dist/scan.js.map +1 -0
- package/dist/selector.d.ts +40 -0
- package/dist/selector.js +154 -0
- package/dist/selector.js.map +1 -0
- package/dist/sink.d.ts +29 -0
- package/dist/sink.js +184 -0
- package/dist/sink.js.map +1 -0
- package/dist/source.d.ts +37 -0
- package/dist/source.js +113 -0
- package/dist/source.js.map +1 -0
- package/dist/table-from-json.d.ts +12 -0
- package/dist/table-from-json.js +217 -0
- package/dist/table-from-json.js.map +1 -0
- package/dist/table.d.ts +81 -0
- package/dist/table.js +141 -0
- package/dist/table.js.map +1 -0
- package/dist/transduce.d.ts +28 -0
- package/dist/transduce.js +109 -0
- package/dist/transduce.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/value.d.ts +16 -0
- package/dist/value.js +96 -0
- package/dist/value.js.map +1 -0
- package/package.json +65 -0
package/dist/scan.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* Copyright (c) 2026 tabnas, MIT License */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.ScanEmit = exports.Transition = void 0;
|
|
5
|
+
// `scan-emit`: declarative state evolution over a stream.
|
|
6
|
+
//
|
|
7
|
+
// A pure step function takes the state and one item and returns the next
|
|
8
|
+
// state with the items to emit; a finish function turns the final state
|
|
9
|
+
// into the closing items. The operator owns the state and the iteration;
|
|
10
|
+
// the functions own nothing. This is what the DSL's `scan-emit` lowers to,
|
|
11
|
+
// and the table transducer is one instance of it.
|
|
12
|
+
const error_1 = require("./error");
|
|
13
|
+
exports.Transition = Object.freeze({
|
|
14
|
+
of(state, outputs) {
|
|
15
|
+
return { state, outputs };
|
|
16
|
+
},
|
|
17
|
+
// A step that emits nothing.
|
|
18
|
+
stay(state) {
|
|
19
|
+
return { state, outputs: [] };
|
|
20
|
+
},
|
|
21
|
+
// A step that emits one item.
|
|
22
|
+
emit(state, output) {
|
|
23
|
+
return { state, outputs: [output] };
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
// The operator. Feed items with `item`, then call `finish` exactly once
|
|
27
|
+
// when the input completed successfully; never call it after a failure or
|
|
28
|
+
// a cancellation. A step or the finish throws a `Fail` to fail the run; a
|
|
29
|
+
// step that failed leaves the operator without a state, so a later item or
|
|
30
|
+
// `finish` is a `PROTOCOL_ORDER_ERROR`.
|
|
31
|
+
class ScanEmit {
|
|
32
|
+
constructor(initial, step, finish, out) {
|
|
33
|
+
this.state = { value: initial };
|
|
34
|
+
this.step = step;
|
|
35
|
+
this.finisher = finish;
|
|
36
|
+
this.out = out;
|
|
37
|
+
}
|
|
38
|
+
// One input item. Its outputs go downstream before this returns.
|
|
39
|
+
item(item) {
|
|
40
|
+
const state = this.state;
|
|
41
|
+
if (null === state) {
|
|
42
|
+
throw error_1.Fail.protocol('scan-emit received an item after it finished');
|
|
43
|
+
}
|
|
44
|
+
this.state = null;
|
|
45
|
+
const transition = this.step(state.value, item);
|
|
46
|
+
this.state = { value: transition.state };
|
|
47
|
+
for (const o of transition.outputs) {
|
|
48
|
+
if ('stop' === this.out(o))
|
|
49
|
+
return 'stop';
|
|
50
|
+
}
|
|
51
|
+
return 'continue';
|
|
52
|
+
}
|
|
53
|
+
// The input completed: emit the closing items.
|
|
54
|
+
finish() {
|
|
55
|
+
const state = this.state;
|
|
56
|
+
const finish = this.finisher;
|
|
57
|
+
if (null === state || null === finish) {
|
|
58
|
+
throw error_1.Fail.protocol('scan-emit finished twice');
|
|
59
|
+
}
|
|
60
|
+
this.state = null;
|
|
61
|
+
this.finisher = null;
|
|
62
|
+
for (const o of finish(state.value)) {
|
|
63
|
+
if ('stop' === this.out(o))
|
|
64
|
+
return 'stop';
|
|
65
|
+
}
|
|
66
|
+
return 'continue';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.ScanEmit = ScanEmit;
|
|
70
|
+
//# sourceMappingURL=scan.js.map
|
package/dist/scan.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":";AAAA,4CAA4C;;;AAE5C,0DAA0D;AAC1D,EAAE;AACF,yEAAyE;AACzE,wEAAwE;AACxE,yEAAyE;AACzE,2EAA2E;AAC3E,kDAAkD;AAElD,mCAA8B;AAMjB,QAAA,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC;IACtC,EAAE,CAAO,KAAQ,EAAE,OAAY;QAC7B,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAA;IAC3B,CAAC;IACD,6BAA6B;IAC7B,IAAI,CAAO,KAAQ;QACjB,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,CAAA;IAC/B,CAAC;IACD,8BAA8B;IAC9B,IAAI,CAAO,KAAQ,EAAE,MAAS;QAC5B,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE,CAAA;IACrC,CAAC;CACF,CAAC,CAAA;AAEF,wEAAwE;AACxE,0EAA0E;AAC1E,0EAA0E;AAC1E,2EAA2E;AAC3E,wCAAwC;AACxC;IAME,YACE,OAAU,EACV,IAA6C,EAC7C,MAAyB,EACzB,GAAwB;QAExB,IAAI,CAAC,KAAK,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,CAAA;QAC/B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAA;QACtB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAA;IAChB,CAAC;IAED,iEAAiE;IACjE,IAAI,CAAC,IAAO;QACV,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;QACxB,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;YACnB,MAAM,YAAI,CAAC,QAAQ,CAAC,8CAA8C,CAAC,CAAA;QACrE,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;QACjB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;QAC/C,IAAI,CAAC,KAAK,GAAG,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,CAAA;QACxC,KAAK,MAAM,CAAC,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;YACnC,IAAI,MAAM,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;gBAAE,OAAO,MAAM,CAAA;QAC3C,CAAC;QACD,OAAO,UAAU,CAAA;IACnB,CAAC;IAED,+CAA+C;IAC/C,MAAM;QACJ,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;QACxB,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAA;QAC5B,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;YACtC,MAAM,YAAI,CAAC,QAAQ,CAAC,0BAA0B,CAAC,CAAA;QACjD,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;QACjB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAA;QACpB,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;YACpC,IAAI,MAAM,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;gBAAE,OAAO,MAAM,CAAA;QAC3C,CAAC;QACD,OAAO,UAAU,CAAA;IACnB,CAAC;CACF"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export type Segment = string | number;
|
|
2
|
+
export declare function keyText(key: string): string;
|
|
3
|
+
export declare class Path {
|
|
4
|
+
readonly segments: Segment[];
|
|
5
|
+
constructor(segments?: Segment[]);
|
|
6
|
+
static root(): Path;
|
|
7
|
+
push(seg: Segment): void;
|
|
8
|
+
pop(): Segment | undefined;
|
|
9
|
+
depth(): number;
|
|
10
|
+
clone(): Path;
|
|
11
|
+
toString(): string;
|
|
12
|
+
}
|
|
13
|
+
export declare function pathText(segments: readonly Segment[]): string;
|
|
14
|
+
export type Step = {
|
|
15
|
+
readonly type: 'property';
|
|
16
|
+
readonly name: string;
|
|
17
|
+
} | {
|
|
18
|
+
readonly type: 'index';
|
|
19
|
+
readonly index: number;
|
|
20
|
+
} | {
|
|
21
|
+
readonly type: 'each_index';
|
|
22
|
+
} | {
|
|
23
|
+
readonly type: 'each_member';
|
|
24
|
+
};
|
|
25
|
+
export declare class Selector {
|
|
26
|
+
readonly steps: readonly Step[];
|
|
27
|
+
constructor(steps?: readonly Step[]);
|
|
28
|
+
static root(): Selector;
|
|
29
|
+
property(name: string): Selector;
|
|
30
|
+
index(index: number): Selector;
|
|
31
|
+
eachIndex(): Selector;
|
|
32
|
+
eachMember(): Selector;
|
|
33
|
+
compose(other: Selector): Selector;
|
|
34
|
+
static fromSegments(segments: readonly Segment[]): Selector;
|
|
35
|
+
isRoot(): boolean;
|
|
36
|
+
isMulti(): boolean;
|
|
37
|
+
mayOverlap(other: Selector): boolean;
|
|
38
|
+
equals(other: Selector): boolean;
|
|
39
|
+
toString(): string;
|
|
40
|
+
}
|
package/dist/selector.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* Copyright (c) 2026 tabnas, MIT License */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.Selector = exports.Path = void 0;
|
|
5
|
+
exports.keyText = keyText;
|
|
6
|
+
exports.pathText = pathText;
|
|
7
|
+
// Selectors: reusable descriptions of where in a document to look.
|
|
8
|
+
//
|
|
9
|
+
// A selector is data, never code: it is built from constructors or from
|
|
10
|
+
// validated path segments (`Selector.fromSegments`), and a matcher
|
|
11
|
+
// interprets it. A concrete `Path` names one location; a `Selector` may
|
|
12
|
+
// name many (`each_index`, `each_member`). Both print in jq syntax, which
|
|
13
|
+
// is what the rest of the fleet prints and accepts.
|
|
14
|
+
const json_1 = require("./json");
|
|
15
|
+
// One key as jq writes it: bare when it is an ASCII identifier, a JSON
|
|
16
|
+
// string otherwise.
|
|
17
|
+
function keyText(key) {
|
|
18
|
+
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(key) ? '.' + key : '.' + (0, json_1.jsonString)(key);
|
|
19
|
+
}
|
|
20
|
+
// A concrete location in a document.
|
|
21
|
+
class Path {
|
|
22
|
+
constructor(segments = []) {
|
|
23
|
+
this.segments = segments;
|
|
24
|
+
}
|
|
25
|
+
static root() {
|
|
26
|
+
return new Path([]);
|
|
27
|
+
}
|
|
28
|
+
push(seg) {
|
|
29
|
+
this.segments.push(seg);
|
|
30
|
+
}
|
|
31
|
+
pop() {
|
|
32
|
+
return this.segments.pop();
|
|
33
|
+
}
|
|
34
|
+
depth() {
|
|
35
|
+
return this.segments.length;
|
|
36
|
+
}
|
|
37
|
+
clone() {
|
|
38
|
+
return new Path(this.segments.slice());
|
|
39
|
+
}
|
|
40
|
+
// jq syntax: `.a[0]."b-c"`, and `.` for the root.
|
|
41
|
+
toString() {
|
|
42
|
+
return pathText(this.segments);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
exports.Path = Path;
|
|
46
|
+
// Segments in jq syntax.
|
|
47
|
+
function pathText(segments) {
|
|
48
|
+
if (0 === segments.length)
|
|
49
|
+
return '.';
|
|
50
|
+
let out = '';
|
|
51
|
+
for (const seg of segments) {
|
|
52
|
+
out += 'number' === typeof seg ? `[${seg}]` : keyText(seg);
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
const EACH_INDEX = Object.freeze({ type: 'each_index' });
|
|
57
|
+
const EACH_MEMBER = Object.freeze({ type: 'each_member' });
|
|
58
|
+
// A description of locations: the root, narrowed step by step. Immutable:
|
|
59
|
+
// every builder returns a new selector.
|
|
60
|
+
class Selector {
|
|
61
|
+
constructor(steps = []) {
|
|
62
|
+
this.steps = Object.freeze(steps.slice());
|
|
63
|
+
}
|
|
64
|
+
// The document itself.
|
|
65
|
+
static root() {
|
|
66
|
+
return new Selector([]);
|
|
67
|
+
}
|
|
68
|
+
property(name) {
|
|
69
|
+
return new Selector([...this.steps, { type: 'property', name }]);
|
|
70
|
+
}
|
|
71
|
+
index(index) {
|
|
72
|
+
if (!Number.isInteger(index) || index < 0) {
|
|
73
|
+
throw new TypeError('an index step is a non-negative integer: ' + index);
|
|
74
|
+
}
|
|
75
|
+
return new Selector([...this.steps, { type: 'index', index }]);
|
|
76
|
+
}
|
|
77
|
+
eachIndex() {
|
|
78
|
+
return new Selector([...this.steps, EACH_INDEX]);
|
|
79
|
+
}
|
|
80
|
+
eachMember() {
|
|
81
|
+
return new Selector([...this.steps, EACH_MEMBER]);
|
|
82
|
+
}
|
|
83
|
+
// `this`, then `other` below every location `this` names.
|
|
84
|
+
compose(other) {
|
|
85
|
+
return new Selector([...this.steps, ...other.steps]);
|
|
86
|
+
}
|
|
87
|
+
// A selector naming exactly one location: `as-path` over data.
|
|
88
|
+
static fromSegments(segments) {
|
|
89
|
+
let s = Selector.root();
|
|
90
|
+
for (const seg of segments) {
|
|
91
|
+
s = 'number' === typeof seg ? s.index(seg) : s.property(seg);
|
|
92
|
+
}
|
|
93
|
+
return s;
|
|
94
|
+
}
|
|
95
|
+
isRoot() {
|
|
96
|
+
return 0 === this.steps.length;
|
|
97
|
+
}
|
|
98
|
+
// Whether the selector can name more than one location.
|
|
99
|
+
isMulti() {
|
|
100
|
+
return this.steps.some((s) => 'each_index' === s.type || 'each_member' === s.type);
|
|
101
|
+
}
|
|
102
|
+
// Whether this selector names a location strictly inside a location
|
|
103
|
+
// `other` names, or the same one: the test a router uses to refuse
|
|
104
|
+
// overlapping captures.
|
|
105
|
+
mayOverlap(other) {
|
|
106
|
+
const [short, long] = this.steps.length <= other.steps.length ? [this, other] : [other, this];
|
|
107
|
+
for (let i = 0; i < short.steps.length; i++) {
|
|
108
|
+
if (!stepMayMatchSame(short.steps[i], long.steps[i]))
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
equals(other) {
|
|
114
|
+
return this.toString() === other.toString();
|
|
115
|
+
}
|
|
116
|
+
// jq syntax: `.response.records[*]`, `."odd key"`, `[3]`, `[]` for
|
|
117
|
+
// every member, `.` for the root.
|
|
118
|
+
toString() {
|
|
119
|
+
if (0 === this.steps.length)
|
|
120
|
+
return '.';
|
|
121
|
+
let out = '';
|
|
122
|
+
for (const step of this.steps) {
|
|
123
|
+
switch (step.type) {
|
|
124
|
+
case 'property':
|
|
125
|
+
out += keyText(step.name);
|
|
126
|
+
break;
|
|
127
|
+
case 'index':
|
|
128
|
+
out += `[${step.index}]`;
|
|
129
|
+
break;
|
|
130
|
+
case 'each_index':
|
|
131
|
+
out += '[*]';
|
|
132
|
+
break;
|
|
133
|
+
case 'each_member':
|
|
134
|
+
out += '[]';
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return out;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
exports.Selector = Selector;
|
|
142
|
+
function stepMayMatchSame(a, b) {
|
|
143
|
+
switch (a.type) {
|
|
144
|
+
case 'property':
|
|
145
|
+
return (('property' === b.type && a.name === b.name) || 'each_member' === b.type);
|
|
146
|
+
case 'each_member':
|
|
147
|
+
return 'property' === b.type || 'each_member' === b.type;
|
|
148
|
+
case 'index':
|
|
149
|
+
return ('index' === b.type && a.index === b.index) || 'each_index' === b.type;
|
|
150
|
+
case 'each_index':
|
|
151
|
+
return 'index' === b.type || 'each_index' === b.type;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=selector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selector.js","sourceRoot":"","sources":["../src/selector.ts"],"names":[],"mappings":"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"}
|
package/dist/sink.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { JsonEvent } from './event';
|
|
2
|
+
export type Flow = 'continue' | 'stop';
|
|
3
|
+
export interface Sink {
|
|
4
|
+
event(ev: JsonEvent): Flow;
|
|
5
|
+
}
|
|
6
|
+
export declare class EventRecorder implements Sink {
|
|
7
|
+
readonly events: JsonEvent[];
|
|
8
|
+
event(ev: JsonEvent): Flow;
|
|
9
|
+
}
|
|
10
|
+
export declare class FnSink implements Sink {
|
|
11
|
+
private fn;
|
|
12
|
+
constructor(fn: (ev: JsonEvent) => Flow | void);
|
|
13
|
+
event(ev: JsonEvent): Flow;
|
|
14
|
+
}
|
|
15
|
+
export declare class CountSink implements Sink {
|
|
16
|
+
events: number;
|
|
17
|
+
event(_ev: JsonEvent): Flow;
|
|
18
|
+
}
|
|
19
|
+
export declare function replay(events: Iterable<JsonEvent>, sink: Sink): Flow;
|
|
20
|
+
export declare class TreeContract<S extends Sink> implements Sink {
|
|
21
|
+
readonly inner: S;
|
|
22
|
+
private open;
|
|
23
|
+
private rootDone;
|
|
24
|
+
constructor(inner: S);
|
|
25
|
+
private path;
|
|
26
|
+
private notATree;
|
|
27
|
+
private closed;
|
|
28
|
+
event(ev: JsonEvent): Flow;
|
|
29
|
+
}
|
package/dist/sink.js
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* Copyright (c) 2026 tabnas, MIT License */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.TreeContract = exports.CountSink = exports.FnSink = exports.EventRecorder = void 0;
|
|
5
|
+
exports.replay = replay;
|
|
6
|
+
// The push boundary between stages.
|
|
7
|
+
//
|
|
8
|
+
// A pipeline is a chain of sinks. The source calls the first sink once per
|
|
9
|
+
// event, synchronously, inside the parse; each stage does its work and
|
|
10
|
+
// calls the next. Nothing is queued between stages, so a slow writer at the
|
|
11
|
+
// end slows the parser at the start: that is the backpressure, and it
|
|
12
|
+
// costs no buffer. A stage that must stop early (a `take`) answers
|
|
13
|
+
// `'stop'`, which the source turns into a cancelled parse. A stage that
|
|
14
|
+
// fails throws a `Fail`; the source stops the parse and the failure
|
|
15
|
+
// reaches the caller unchanged.
|
|
16
|
+
const error_1 = require("./error");
|
|
17
|
+
const selector_1 = require("./selector");
|
|
18
|
+
// A sink that records every event, for tests and small results.
|
|
19
|
+
class EventRecorder {
|
|
20
|
+
constructor() {
|
|
21
|
+
this.events = [];
|
|
22
|
+
}
|
|
23
|
+
event(ev) {
|
|
24
|
+
this.events.push(ev);
|
|
25
|
+
return 'continue';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.EventRecorder = EventRecorder;
|
|
29
|
+
// A sink made of a function. A function that returns nothing continues.
|
|
30
|
+
class FnSink {
|
|
31
|
+
constructor(fn) {
|
|
32
|
+
this.fn = fn;
|
|
33
|
+
}
|
|
34
|
+
event(ev) {
|
|
35
|
+
return this.fn(ev) || 'continue';
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.FnSink = FnSink;
|
|
39
|
+
// A sink that counts events and drops them: the cheapest consumer, for
|
|
40
|
+
// measuring a source on its own.
|
|
41
|
+
class CountSink {
|
|
42
|
+
constructor() {
|
|
43
|
+
this.events = 0;
|
|
44
|
+
}
|
|
45
|
+
event(_ev) {
|
|
46
|
+
this.events++;
|
|
47
|
+
return 'continue';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
exports.CountSink = CountSink;
|
|
51
|
+
// Replay a recording into a sink, stopping where the sink stops.
|
|
52
|
+
function replay(events, sink) {
|
|
53
|
+
for (const ev of events) {
|
|
54
|
+
if ('stop' === sink.event(ev))
|
|
55
|
+
return 'stop';
|
|
56
|
+
}
|
|
57
|
+
return 'continue';
|
|
58
|
+
}
|
|
59
|
+
// A tree's events, held to their contract in front of a sink that takes
|
|
60
|
+
// them as one (a render that writes a document from them): one root value,
|
|
61
|
+
// and in each object a key and then its value, each key once. A value
|
|
62
|
+
// walked from a parsed tree keeps it by construction. A parse streamed as
|
|
63
|
+
// it proceeds may not: it hands on a member its grammar reads twice
|
|
64
|
+
// (JSON's `{"a":1,"a":2}`, whose value keeps the last) where a tree has
|
|
65
|
+
// one, and the rule-event adapter refuses most shapes it cannot follow but
|
|
66
|
+
// not every one a grammar can produce. A repeated key in one object is
|
|
67
|
+
// refused with `DUPLICATE_MEMBER`, and events no tree has (a value where a
|
|
68
|
+
// key is due, a key outside an object, a close with nothing open, a second
|
|
69
|
+
// root) with `STREAMABILITY_UNKNOWN`, each at the path of the object
|
|
70
|
+
// concerned; the event is not passed on. Each open object keeps the keys
|
|
71
|
+
// it has had, dropped when it closes.
|
|
72
|
+
class TreeContract {
|
|
73
|
+
constructor(inner) {
|
|
74
|
+
this.open = [];
|
|
75
|
+
this.rootDone = false;
|
|
76
|
+
this.inner = inner;
|
|
77
|
+
}
|
|
78
|
+
// The path of the value due next: the open containers, each by the member
|
|
79
|
+
// or element open in it, and in the innermost object its last key when
|
|
80
|
+
// that member's value is due.
|
|
81
|
+
path() {
|
|
82
|
+
const segments = [];
|
|
83
|
+
const last = this.open.length - 1;
|
|
84
|
+
this.open.forEach((open, i) => {
|
|
85
|
+
if (open.array) {
|
|
86
|
+
segments.push(open.next);
|
|
87
|
+
}
|
|
88
|
+
else if ((i !== last || !open.keyDue) && null != open.last) {
|
|
89
|
+
// A container open inside this object is its last key's value,
|
|
90
|
+
// whatever `keyDue` says: the member was counted as taken when its
|
|
91
|
+
// value opened.
|
|
92
|
+
segments.push(open.last);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
return new selector_1.Path(segments);
|
|
96
|
+
}
|
|
97
|
+
notATree(what) {
|
|
98
|
+
return new error_1.Fail('STREAMABILITY_UNKNOWN', `the stream holds ${what}, which a tree's events never do, so it is not a tree's`).atPath(this.path().toString());
|
|
99
|
+
}
|
|
100
|
+
// A value is complete: the next in its array is due, or the root is.
|
|
101
|
+
closed() {
|
|
102
|
+
const top = this.open[this.open.length - 1];
|
|
103
|
+
if (undefined === top)
|
|
104
|
+
this.rootDone = true;
|
|
105
|
+
else if (top.array)
|
|
106
|
+
top.next++;
|
|
107
|
+
}
|
|
108
|
+
event(ev) {
|
|
109
|
+
const top = this.open[this.open.length - 1];
|
|
110
|
+
switch (ev.type) {
|
|
111
|
+
case 'key': {
|
|
112
|
+
if (undefined !== top && !top.array && top.keyDue) {
|
|
113
|
+
if (top.keys.has(ev.key)) {
|
|
114
|
+
const path = this.path();
|
|
115
|
+
path.push(ev.key);
|
|
116
|
+
throw new error_1.Fail('DUPLICATE_MEMBER', `member ${JSON.stringify(ev.key)} appears twice in one object, and a tree's ` +
|
|
117
|
+
`events hold each key once`).atPath(path.toString());
|
|
118
|
+
}
|
|
119
|
+
top.keys.add(ev.key);
|
|
120
|
+
top.last = ev.key;
|
|
121
|
+
top.keyDue = false;
|
|
122
|
+
}
|
|
123
|
+
else if (undefined !== top && !top.array) {
|
|
124
|
+
throw this.notATree('a key where a value is due');
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
throw this.notATree('a key outside an object');
|
|
128
|
+
}
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
case 'object_end':
|
|
132
|
+
if (undefined !== top && !top.array && top.keyDue) {
|
|
133
|
+
this.open.pop();
|
|
134
|
+
this.closed();
|
|
135
|
+
}
|
|
136
|
+
else if (undefined !== top && !top.array) {
|
|
137
|
+
throw this.notATree("an object's end where a value is due");
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
throw this.notATree("an object's end where none is due");
|
|
141
|
+
}
|
|
142
|
+
break;
|
|
143
|
+
case 'array_end':
|
|
144
|
+
if (undefined !== top && top.array) {
|
|
145
|
+
this.open.pop();
|
|
146
|
+
this.closed();
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
throw this.notATree("an array's end where none is due");
|
|
150
|
+
}
|
|
151
|
+
break;
|
|
152
|
+
case 'end':
|
|
153
|
+
if (0 < this.open.length) {
|
|
154
|
+
throw this.notATree('its end inside an open container');
|
|
155
|
+
}
|
|
156
|
+
break;
|
|
157
|
+
default: {
|
|
158
|
+
// A value: in an object, only once its key is in; at the root,
|
|
159
|
+
// only once.
|
|
160
|
+
if (undefined === top) {
|
|
161
|
+
if (this.rootDone)
|
|
162
|
+
throw this.notATree('a second root value');
|
|
163
|
+
}
|
|
164
|
+
else if (!top.array) {
|
|
165
|
+
if (top.keyDue)
|
|
166
|
+
throw this.notATree('a value where a key is due');
|
|
167
|
+
top.keyDue = true;
|
|
168
|
+
}
|
|
169
|
+
if ('object_start' === ev.type) {
|
|
170
|
+
this.open.push({ array: false, keys: new Set(), last: null, keyDue: true });
|
|
171
|
+
}
|
|
172
|
+
else if ('array_start' === ev.type) {
|
|
173
|
+
this.open.push({ array: true, next: 0 });
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
this.closed();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return this.inner.event(ev);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
exports.TreeContract = TreeContract;
|
|
184
|
+
//# sourceMappingURL=sink.js.map
|
package/dist/sink.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sink.js","sourceRoot":"","sources":["../src/sink.ts"],"names":[],"mappings":";AAAA,4CAA4C;;;;AAE5C,oCAAoC;AACpC,EAAE;AACF,2EAA2E;AAC3E,uEAAuE;AACvE,4EAA4E;AAC5E,sEAAsE;AACtE,mEAAmE;AACnE,wEAAwE;AACxE,oEAAoE;AACpE,gCAAgC;AAEhC,mCAA8B;AAE9B,yCAA0C;AAY1C,gEAAgE;AAChE;IAAA;QACW,WAAM,GAAgB,EAAE,CAAA;IAMnC,CAAC;IAJC,KAAK,CAAC,EAAa;QACjB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACpB,OAAO,UAAU,CAAA;IACnB,CAAC;CACF;;AAED,wEAAwE;AACxE;IAGE,YAAY,EAAkC;QAC5C,IAAI,CAAC,EAAE,GAAG,EAAE,CAAA;IACd,CAAC;IAED,KAAK,CAAC,EAAa;QACjB,OAAO,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,UAAU,CAAA;IAClC,CAAC;CACF;;AAED,uEAAuE;AACvE,iCAAiC;AACjC;IAAA;QACE,WAAM,GAAG,CAAC,CAAA;IAMZ,CAAC;IAJC,KAAK,CAAC,GAAc;QAClB,IAAI,CAAC,MAAM,EAAE,CAAA;QACb,OAAO,UAAU,CAAA;IACnB,CAAC;CACF;;AAED,iEAAiE;AACjE,gBAAuB,MAA2B,EAAE,IAAU;IAC5D,KAAK,MAAM,EAAE,IAAI,MAAM,EAAE,CAAC;QACxB,IAAI,MAAM,KAAK,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAAE,OAAO,MAAM,CAAA;IAC9C,CAAC;IACD,OAAO,UAAU,CAAA;AACnB,CAAC;AASD,wEAAwE;AACxE,2EAA2E;AAC3E,sEAAsE;AACtE,0EAA0E;AAC1E,oEAAoE;AACpE,wEAAwE;AACxE,2EAA2E;AAC3E,uEAAuE;AACvE,2EAA2E;AAC3E,2EAA2E;AAC3E,qEAAqE;AACrE,yEAAyE;AACzE,sCAAsC;AACtC;IAKE,YAAY,KAAQ;QAHZ,SAAI,GAAW,EAAE,CAAA;QACjB,aAAQ,GAAG,KAAK,CAAA;QAGtB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;IACpB,CAAC;IAED,0EAA0E;IAC1E,uEAAuE;IACvE,8BAA8B;IACtB,IAAI;QACV,MAAM,QAAQ,GAAc,EAAE,CAAA;QAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAA;QACjC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;YAC5B,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBACf,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAC1B,CAAC;iBAAM,IAAI,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC7D,+DAA+D;gBAC/D,mEAAmE;gBACnE,gBAAgB;gBAChB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAC1B,CAAC;QACH,CAAC,CAAC,CAAA;QACF,OAAO,IAAI,eAAI,CAAC,QAAQ,CAAC,CAAA;IAC3B,CAAC;IAEO,QAAQ,CAAC,IAAY;QAC3B,OAAO,IAAI,YAAI,CACb,uBAAuB,EACvB,oBAAoB,IAAI,yDAAyD,CAClF,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAA;IAClC,CAAC;IAED,qEAAqE;IAC7D,MAAM;QACZ,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;QAC3C,IAAI,SAAS,KAAK,GAAG;YAAE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAA;aACtC,IAAI,GAAG,CAAC,KAAK;YAAE,GAAG,CAAC,IAAI,EAAE,CAAA;IAChC,CAAC;IAED,KAAK,CAAC,EAAa;QACjB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;QAC3C,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;YAChB,KAAK,KAAK,EAAE,CAAC;gBACX,IAAI,SAAS,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;oBAClD,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;wBACzB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;wBACxB,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;wBACjB,MAAM,IAAI,YAAI,CACZ,kBAAkB,EAClB,UAAU,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,6CAA6C;4BAC3E,2BAA2B,CAC9B,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAA;oBAC3B,CAAC;oBACD,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;oBACpB,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC,GAAG,CAAA;oBACjB,GAAG,CAAC,MAAM,GAAG,KAAK,CAAA;gBACpB,CAAC;qBAAM,IAAI,SAAS,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;oBAC3C,MAAM,IAAI,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAA;gBACnD,CAAC;qBAAM,CAAC;oBACN,MAAM,IAAI,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAAA;gBAChD,CAAC;gBACD,MAAK;YACP,CAAC;YACD,KAAK,YAAY;gBACf,IAAI,SAAS,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;oBAClD,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAA;oBACf,IAAI,CAAC,MAAM,EAAE,CAAA;gBACf,CAAC;qBAAM,IAAI,SAAS,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;oBAC3C,MAAM,IAAI,CAAC,QAAQ,CAAC,sCAAsC,CAAC,CAAA;gBAC7D,CAAC;qBAAM,CAAC;oBACN,MAAM,IAAI,CAAC,QAAQ,CAAC,mCAAmC,CAAC,CAAA;gBAC1D,CAAC;gBACD,MAAK;YACP,KAAK,WAAW;gBACd,IAAI,SAAS,KAAK,GAAG,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;oBACnC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAA;oBACf,IAAI,CAAC,MAAM,EAAE,CAAA;gBACf,CAAC;qBAAM,CAAC;oBACN,MAAM,IAAI,CAAC,QAAQ,CAAC,kCAAkC,CAAC,CAAA;gBACzD,CAAC;gBACD,MAAK;YACP,KAAK,KAAK;gBACR,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;oBACzB,MAAM,IAAI,CAAC,QAAQ,CAAC,kCAAkC,CAAC,CAAA;gBACzD,CAAC;gBACD,MAAK;YACP,SAAS,CAAC;gBACR,+DAA+D;gBAC/D,aAAa;gBACb,IAAI,SAAS,KAAK,GAAG,EAAE,CAAC;oBACtB,IAAI,IAAI,CAAC,QAAQ;wBAAE,MAAM,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAA;gBAC/D,CAAC;qBAAM,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;oBACtB,IAAI,GAAG,CAAC,MAAM;wBAAE,MAAM,IAAI,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAA;oBACjE,GAAG,CAAC,MAAM,GAAG,IAAI,CAAA;gBACnB,CAAC;gBACD,IAAI,cAAc,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC;oBAC/B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;gBAC7E,CAAC;qBAAM,IAAI,aAAa,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC;oBACrC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAA;gBAC1C,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,MAAM,EAAE,CAAA;gBACf,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;IAC7B,CAAC;CACF"}
|
package/dist/source.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Fail } from './error';
|
|
2
|
+
import { AbortFlag } from './limits';
|
|
3
|
+
import { Selector } from './selector';
|
|
4
|
+
import { Flow, Sink } from './sink';
|
|
5
|
+
export type Prune = {
|
|
6
|
+
type: 'never';
|
|
7
|
+
} | {
|
|
8
|
+
type: 'under';
|
|
9
|
+
selector: Selector;
|
|
10
|
+
} | {
|
|
11
|
+
type: 'all_arrays';
|
|
12
|
+
};
|
|
13
|
+
export declare const Prune: Readonly<{
|
|
14
|
+
never(): Prune;
|
|
15
|
+
under(selector: Selector): Prune;
|
|
16
|
+
allArrays(): Prune;
|
|
17
|
+
}>;
|
|
18
|
+
export type SourceMode = {
|
|
19
|
+
type: 'materialize';
|
|
20
|
+
} | {
|
|
21
|
+
type: 'incremental';
|
|
22
|
+
prune: Prune;
|
|
23
|
+
};
|
|
24
|
+
export declare const SourceMode: Readonly<{
|
|
25
|
+
materialize(): SourceMode;
|
|
26
|
+
incremental(prune?: Prune): SourceMode;
|
|
27
|
+
}>;
|
|
28
|
+
export interface Source {
|
|
29
|
+
run(sink: Sink): Flow;
|
|
30
|
+
}
|
|
31
|
+
export declare function engineFailure(error: unknown, abort: AbortFlag): Fail;
|
|
32
|
+
export declare function walkValue(value: unknown, sink: Sink): Flow;
|
|
33
|
+
export declare class ValueSource implements Source {
|
|
34
|
+
readonly value: unknown;
|
|
35
|
+
constructor(value: unknown);
|
|
36
|
+
run(sink: Sink): Flow;
|
|
37
|
+
}
|
package/dist/source.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* Copyright (c) 2026 tabnas, MIT License */
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.ValueSource = exports.SourceMode = exports.Prune = void 0;
|
|
5
|
+
exports.engineFailure = engineFailure;
|
|
6
|
+
exports.walkValue = walkValue;
|
|
7
|
+
// Sources: where `JsonEvents/1` come from.
|
|
8
|
+
//
|
|
9
|
+
// - `ValueSource` walks a parsed engine value. Always correct, retains the
|
|
10
|
+
// whole value: the fallback for every grammar.
|
|
11
|
+
// - `ParserSource` drives a tabnas parse of one text and, in incremental
|
|
12
|
+
// mode, turns its rule events into source events as they happen, for the
|
|
13
|
+
// grammars the differential suite has verified (`capability`); in
|
|
14
|
+
// materialize mode it parses and walks.
|
|
15
|
+
// - `LinesSource` reads JSON Lines or CSV a record (or a chunk of records)
|
|
16
|
+
// at a time, bounding memory whatever the input's size.
|
|
17
|
+
//
|
|
18
|
+
// Every source emits through `Guarded`, which enforces the source limits,
|
|
19
|
+
// polls the abort flag and counts the source metrics.
|
|
20
|
+
const error_1 = require("./error");
|
|
21
|
+
const event_1 = require("./event");
|
|
22
|
+
const value_1 = require("./value");
|
|
23
|
+
exports.Prune = Object.freeze({
|
|
24
|
+
never() {
|
|
25
|
+
return { type: 'never' };
|
|
26
|
+
},
|
|
27
|
+
under(selector) {
|
|
28
|
+
return { type: 'under', selector };
|
|
29
|
+
},
|
|
30
|
+
allArrays() {
|
|
31
|
+
return { type: 'all_arrays' };
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
exports.SourceMode = Object.freeze({
|
|
35
|
+
materialize() {
|
|
36
|
+
return { type: 'materialize' };
|
|
37
|
+
},
|
|
38
|
+
incremental(prune = exports.Prune.never()) {
|
|
39
|
+
return { type: 'incremental', prune };
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
// The engine's cancel code: what a cancelled parse reports, whether the
|
|
43
|
+
// canceller is this crate's abort or a guard of the grammar's own.
|
|
44
|
+
const CANCEL = 'cancel';
|
|
45
|
+
// Map an engine error to a failure. A cancel while the caller's flag is set
|
|
46
|
+
// is `ABORTED`. A cancel otherwise is a guard the GRAMMAR installed, so
|
|
47
|
+
// the message says so instead of "parse cancelled", which would read as
|
|
48
|
+
// the caller's doing; it stays `INPUT_INVALID`, because the document is
|
|
49
|
+
// what the grammar refused. Any other error is the input's, with the
|
|
50
|
+
// engine's code and position. A thrown value that is not an engine error
|
|
51
|
+
// (a grammar's plugin threw) is the input's too, without a position.
|
|
52
|
+
function engineFailure(error, abort) {
|
|
53
|
+
if (error instanceof error_1.Fail)
|
|
54
|
+
return error;
|
|
55
|
+
if (CANCEL !== (0, error_1.engineCode)(error))
|
|
56
|
+
return error_1.Fail.fromTabnas(error);
|
|
57
|
+
if (abort.isAborted())
|
|
58
|
+
return error_1.Fail.aborted();
|
|
59
|
+
const fail = error_1.Fail.fromTabnas(error);
|
|
60
|
+
fail.message =
|
|
61
|
+
`the grammar stopped the parse with a guard of its own (${(0, error_1.engineCode)(error)}: ` +
|
|
62
|
+
`${(0, error_1.engineDetail)(error)}); a grammar may refuse nesting or size below this crate's Limits`;
|
|
63
|
+
return fail;
|
|
64
|
+
}
|
|
65
|
+
// Emit one engine value's events (without `end`). `undefined` is `null`,
|
|
66
|
+
// as the engine serializes it; an object's members are in insertion order.
|
|
67
|
+
function walkValue(value, sink) {
|
|
68
|
+
if (Array.isArray(value)) {
|
|
69
|
+
if ('stop' === sink.event(event_1.Ev.arrayStart))
|
|
70
|
+
return 'stop';
|
|
71
|
+
for (const item of value) {
|
|
72
|
+
if ('stop' === walkValue(item, sink))
|
|
73
|
+
return 'stop';
|
|
74
|
+
}
|
|
75
|
+
return sink.event(event_1.Ev.arrayEnd);
|
|
76
|
+
}
|
|
77
|
+
const scalar = (0, value_1.engineScalar)(value);
|
|
78
|
+
if (undefined !== scalar) {
|
|
79
|
+
switch (scalar.type) {
|
|
80
|
+
case 'null':
|
|
81
|
+
return sink.event(event_1.Ev.null);
|
|
82
|
+
case 'bool':
|
|
83
|
+
return sink.event(event_1.Ev.bool(scalar.value));
|
|
84
|
+
case 'number':
|
|
85
|
+
return sink.event(event_1.Ev.number(scalar.value));
|
|
86
|
+
case 'string':
|
|
87
|
+
return sink.event(event_1.Ev.string(scalar.value));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if ('stop' === sink.event(event_1.Ev.objectStart))
|
|
91
|
+
return 'stop';
|
|
92
|
+
for (const k of (0, value_1.engineKeys)(value)) {
|
|
93
|
+
if ('stop' === sink.event(event_1.Ev.key(k)))
|
|
94
|
+
return 'stop';
|
|
95
|
+
if ('stop' === walkValue(value[k], sink))
|
|
96
|
+
return 'stop';
|
|
97
|
+
}
|
|
98
|
+
return sink.event(event_1.Ev.objectEnd);
|
|
99
|
+
}
|
|
100
|
+
// Emit a parsed engine value as events, ending with `end`. Applies no
|
|
101
|
+
// limits: wrap the sink in `Guarded` for those.
|
|
102
|
+
class ValueSource {
|
|
103
|
+
constructor(value) {
|
|
104
|
+
this.value = value;
|
|
105
|
+
}
|
|
106
|
+
run(sink) {
|
|
107
|
+
if ('stop' === walkValue(this.value, sink))
|
|
108
|
+
return 'stop';
|
|
109
|
+
return sink.event(event_1.Ev.end);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
exports.ValueSource = ValueSource;
|
|
113
|
+
//# sourceMappingURL=source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source.js","sourceRoot":"","sources":["../src/source.ts"],"names":[],"mappings":"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"}
|