@bablr/bablr-vm 0.18.1 → 0.19.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/lib/context.js +28 -35
- package/lib/evaluate.js +503 -0
- package/lib/index.js +1 -1
- package/lib/match.js +470 -0
- package/lib/node.js +172 -43
- package/lib/source.js +2 -2
- package/lib/spans.js +31 -23
- package/lib/state.js +264 -49
- package/lib/utils/pattern.js +16 -13
- package/lib/utils/pump.js +20 -0
- package/package.json +7 -6
package/lib/state.js
CHANGED
|
@@ -1,11 +1,30 @@
|
|
|
1
1
|
import emptyStack from '@iter-tools/imm-stack';
|
|
2
2
|
import { WeakStackFrame } from '@bablr/weak-stack';
|
|
3
3
|
import { getCooked } from '@bablr/agast-helpers/stream';
|
|
4
|
+
import { reifyExpression } from '@bablr/agast-vm-helpers';
|
|
5
|
+
import {
|
|
6
|
+
EmbeddedMatcher,
|
|
7
|
+
EmbeddedNode,
|
|
8
|
+
EmbeddedRegex,
|
|
9
|
+
GapTag,
|
|
10
|
+
ReferenceTag,
|
|
11
|
+
ShiftTag,
|
|
12
|
+
} from '@bablr/agast-helpers/symbols';
|
|
13
|
+
import * as btree from '@bablr/agast-helpers/btree';
|
|
14
|
+
import {
|
|
15
|
+
buildCall,
|
|
16
|
+
buildEmbeddedRegex,
|
|
17
|
+
buildEmbeddedTag,
|
|
18
|
+
buildGapTag,
|
|
19
|
+
buildReferenceTag,
|
|
20
|
+
buildStubNode,
|
|
21
|
+
} from '@bablr/agast-helpers/tree';
|
|
22
|
+
import { get, Path, PathResolver, TagPath, updatePath } from '@bablr/agast-helpers/path';
|
|
4
23
|
import { match, guardWithPattern } from './utils/pattern.js';
|
|
5
24
|
import { facades, actuals } from './facades.js';
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
25
|
+
import { buildInternalState, FragmentFacade, internalStates } from './node.js';
|
|
26
|
+
|
|
27
|
+
export const nodeStates = new WeakMap();
|
|
9
28
|
|
|
10
29
|
export const StateFacade = class BABLRStateFacade {
|
|
11
30
|
constructor(state) {
|
|
@@ -24,8 +43,16 @@ export const StateFacade = class BABLRStateFacade {
|
|
|
24
43
|
return actuals.get(this).span.name;
|
|
25
44
|
}
|
|
26
45
|
|
|
27
|
-
get
|
|
28
|
-
return actuals.get(this).
|
|
46
|
+
get resultPath() {
|
|
47
|
+
return actuals.get(this).resultPath;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
get reference() {
|
|
51
|
+
return actuals.get(this).reference;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
get referencePath() {
|
|
55
|
+
return actuals.get(this).referencePath;
|
|
29
56
|
}
|
|
30
57
|
|
|
31
58
|
get holding() {
|
|
@@ -36,12 +63,17 @@ export const StateFacade = class BABLRStateFacade {
|
|
|
36
63
|
return actuals.get(this).path;
|
|
37
64
|
}
|
|
38
65
|
|
|
66
|
+
get depths() {
|
|
67
|
+
const { path, result } = actuals.get(this).depths;
|
|
68
|
+
return { path, result };
|
|
69
|
+
}
|
|
70
|
+
|
|
39
71
|
get node() {
|
|
40
|
-
return
|
|
72
|
+
return FragmentFacade.wrap(actuals.get(this).node, this.ctx);
|
|
41
73
|
}
|
|
42
74
|
|
|
43
75
|
get parentNode() {
|
|
44
|
-
return
|
|
76
|
+
return FragmentFacade.wrap(actuals.get(this).parentNode, this.ctx);
|
|
45
77
|
}
|
|
46
78
|
|
|
47
79
|
get source() {
|
|
@@ -56,44 +88,57 @@ export const StateFacade = class BABLRStateFacade {
|
|
|
56
88
|
return actuals.get(this).status;
|
|
57
89
|
}
|
|
58
90
|
|
|
59
|
-
|
|
60
|
-
return
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
pathForTag(tag) {
|
|
64
|
-
return actuals.get(this).pathForTag(tag);
|
|
91
|
+
get parent() {
|
|
92
|
+
return facades.get(actuals.get(this).parent);
|
|
65
93
|
}
|
|
66
94
|
|
|
67
|
-
|
|
68
|
-
return
|
|
95
|
+
nodeForPath(path) {
|
|
96
|
+
return actuals.get(this).nodeForPath(path);
|
|
69
97
|
}
|
|
70
98
|
};
|
|
71
99
|
|
|
72
100
|
export const State = class BABLRState extends WeakStackFrame {
|
|
73
101
|
constructor(
|
|
102
|
+
parent,
|
|
74
103
|
source,
|
|
75
|
-
agast,
|
|
76
104
|
context,
|
|
105
|
+
expressions = emptyStack,
|
|
77
106
|
balanced = emptyStack,
|
|
78
107
|
spans = emptyStack.push({ name: 'Bare' }),
|
|
108
|
+
referencePath = null,
|
|
109
|
+
resultPath = null,
|
|
110
|
+
depths = { path: -1, result: -1, emitted: -1 },
|
|
111
|
+
held = null,
|
|
112
|
+
node = null,
|
|
79
113
|
) {
|
|
80
|
-
super();
|
|
114
|
+
super(parent);
|
|
81
115
|
|
|
82
|
-
if (!source
|
|
116
|
+
if (!source) throw new Error('invalid args to State');
|
|
83
117
|
|
|
84
118
|
this.source = source;
|
|
85
|
-
this.agast = agast;
|
|
86
119
|
this.context = context;
|
|
120
|
+
this.expressions = expressions;
|
|
87
121
|
this.balanced = balanced;
|
|
88
122
|
this.spans = spans;
|
|
123
|
+
this.referencePath = referencePath;
|
|
124
|
+
this.resultPath = resultPath;
|
|
125
|
+
this.depths = depths;
|
|
126
|
+
this.held = held;
|
|
127
|
+
this.node = node;
|
|
89
128
|
|
|
90
129
|
this.status = 'active';
|
|
91
130
|
|
|
131
|
+
this.emitted = null;
|
|
132
|
+
|
|
92
133
|
new StateFacade(this);
|
|
93
134
|
}
|
|
94
135
|
|
|
95
|
-
static from(source,
|
|
96
|
-
return State.create(source,
|
|
136
|
+
static from(source, context, expressions = []) {
|
|
137
|
+
return State.create(source, context, emptyStack.push(...expressions));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
get unboundAttributes() {
|
|
141
|
+
return nodeStates.get(this.node).unboundAttributes;
|
|
97
142
|
}
|
|
98
143
|
|
|
99
144
|
get guardedSource() {
|
|
@@ -108,23 +153,19 @@ export const State = class BABLRState extends WeakStackFrame {
|
|
|
108
153
|
}
|
|
109
154
|
|
|
110
155
|
get path() {
|
|
111
|
-
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
get node() {
|
|
115
|
-
return this.agast.node;
|
|
156
|
+
throw new Error('not implemented');
|
|
116
157
|
}
|
|
117
158
|
|
|
118
159
|
get parentNode() {
|
|
119
|
-
|
|
160
|
+
throw new Error('not implemented');
|
|
120
161
|
}
|
|
121
162
|
|
|
122
163
|
get holding() {
|
|
123
|
-
return this.
|
|
164
|
+
return !!this.held;
|
|
124
165
|
}
|
|
125
166
|
|
|
126
|
-
get
|
|
127
|
-
return this.
|
|
167
|
+
get reference() {
|
|
168
|
+
return this.referencePath?.tag;
|
|
128
169
|
}
|
|
129
170
|
|
|
130
171
|
get isGap() {
|
|
@@ -135,50 +176,224 @@ export const State = class BABLRState extends WeakStackFrame {
|
|
|
135
176
|
return !!this.parent;
|
|
136
177
|
}
|
|
137
178
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
179
|
+
advance(tag) {
|
|
180
|
+
const { path, instructionsPump, expressionsPump, agast } = internalStates.get(this.node);
|
|
141
181
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
182
|
+
if (tag.type === GapTag) {
|
|
183
|
+
expressionsPump.queue(
|
|
184
|
+
this.expressions.size ? this.expressions.value : buildStubNode(buildGapTag()),
|
|
185
|
+
);
|
|
186
|
+
this.expressions = this.expressions.pop();
|
|
187
|
+
}
|
|
188
|
+
instructionsPump.queue(buildCall('advance', buildEmbeddedTag(tag)));
|
|
189
|
+
agast.next();
|
|
145
190
|
|
|
146
|
-
|
|
147
|
-
return this.agast.nodeForTag(tag);
|
|
191
|
+
this.resultPath = TagPath.from(path, -1);
|
|
148
192
|
}
|
|
149
193
|
|
|
150
194
|
guardedMatch(pattern) {
|
|
151
|
-
let { span,
|
|
195
|
+
let { span, source } = this;
|
|
152
196
|
let { guard } = span;
|
|
153
197
|
|
|
154
|
-
|
|
155
|
-
|
|
198
|
+
let pattern_ = pattern;
|
|
199
|
+
if (pattern.type === EmbeddedMatcher) {
|
|
200
|
+
pattern_ = reifyExpression(pattern.value).nodeMatcher;
|
|
201
|
+
} else if (pattern.type === EmbeddedRegex) {
|
|
202
|
+
pattern_ = pattern.value;
|
|
203
|
+
} else if (typeof pattern !== 'string') {
|
|
204
|
+
throw new Error();
|
|
156
205
|
}
|
|
157
206
|
|
|
158
207
|
if (
|
|
159
208
|
span.type === 'Lexical' &&
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
209
|
+
pattern.type === EmbeddedMatcher &&
|
|
210
|
+
(pattern_.flags.token
|
|
211
|
+
? pattern_.attributes.balancer || pattern_.attributes.balanced
|
|
212
|
+
: pattern_.attributes?.balancer)
|
|
163
213
|
) {
|
|
164
214
|
// also check that the open node starts a lexical span?
|
|
165
215
|
guard = null;
|
|
166
216
|
}
|
|
167
217
|
|
|
168
|
-
if (
|
|
218
|
+
if (pattern_?.intrinsicValue) {
|
|
169
219
|
// if (pattern.type === OpenNodeTag) {
|
|
170
220
|
|
|
171
221
|
// // TODO differntiate better between self-closing tags and matchers
|
|
172
222
|
// pattern = pattern.value;
|
|
173
223
|
// }
|
|
174
224
|
|
|
175
|
-
|
|
225
|
+
pattern_ = pattern_.intrinsicValue || getCooked(pattern_.children);
|
|
226
|
+
|
|
227
|
+
if (pattern_.type === Symbol.for('String')) {
|
|
228
|
+
pattern_ = reifyExpression(pattern_);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return match(pattern_, guard ? guardWithPattern(guard, source) : source);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
match(pattern) {
|
|
236
|
+
return match(pattern, this.source);
|
|
237
|
+
}
|
|
176
238
|
|
|
177
|
-
|
|
178
|
-
|
|
239
|
+
branch() {
|
|
240
|
+
const baseState = this;
|
|
241
|
+
let {
|
|
242
|
+
source,
|
|
243
|
+
context,
|
|
244
|
+
balanced,
|
|
245
|
+
spans,
|
|
246
|
+
resultPath,
|
|
247
|
+
depths,
|
|
248
|
+
referencePath,
|
|
249
|
+
held,
|
|
250
|
+
node,
|
|
251
|
+
expressions,
|
|
252
|
+
} = baseState;
|
|
253
|
+
|
|
254
|
+
let resolver = new PathResolver();
|
|
255
|
+
|
|
256
|
+
const internalState = buildInternalState();
|
|
257
|
+
|
|
258
|
+
for (let tag of btree.traverse(node.children)) {
|
|
259
|
+
if (tag.type === GapTag) {
|
|
260
|
+
let { name, isArray, flags } = resolver.reference.value;
|
|
261
|
+
const resolvedPath = buildReferenceTag(
|
|
262
|
+
name,
|
|
263
|
+
isArray,
|
|
264
|
+
flags,
|
|
265
|
+
Number.isFinite(resolver.counters[name]) ? resolver.counters[name] : null,
|
|
266
|
+
);
|
|
267
|
+
const expr = get(resolvedPath, node);
|
|
268
|
+
internalState.expressionsPump.queue(expr);
|
|
269
|
+
} else if (tag.type === EmbeddedNode) {
|
|
270
|
+
internalState.expressionsPump.queue(tag.value);
|
|
271
|
+
tag = buildGapTag();
|
|
179
272
|
}
|
|
273
|
+
|
|
274
|
+
resolver.advance(tag);
|
|
275
|
+
|
|
276
|
+
internalState.instructionsPump.queue(buildCall('advance', buildEmbeddedTag(tag)));
|
|
277
|
+
internalState.agast.next();
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const newNode = internalState.agastState.node;
|
|
281
|
+
const nodeState = nodeStates.get(node);
|
|
282
|
+
let newResultPath;
|
|
283
|
+
|
|
284
|
+
if (resultPath.path.node === node) {
|
|
285
|
+
newResultPath = TagPath.from(Path.from(newNode), resultPath.childrenIndex);
|
|
286
|
+
} else {
|
|
287
|
+
newResultPath = resultPath;
|
|
180
288
|
}
|
|
181
289
|
|
|
182
|
-
|
|
290
|
+
nodeStates.set(newNode, { ...nodeState });
|
|
291
|
+
internalStates.set(newNode, internalState);
|
|
292
|
+
|
|
293
|
+
const child = this.push(
|
|
294
|
+
source.branch(),
|
|
295
|
+
context,
|
|
296
|
+
expressions,
|
|
297
|
+
balanced,
|
|
298
|
+
spans,
|
|
299
|
+
referencePath,
|
|
300
|
+
newResultPath,
|
|
301
|
+
depths,
|
|
302
|
+
held,
|
|
303
|
+
newNode,
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
return child;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
accept() {
|
|
310
|
+
const accepted = this;
|
|
311
|
+
|
|
312
|
+
this.status = 'accepted';
|
|
313
|
+
|
|
314
|
+
const { parent } = this;
|
|
315
|
+
|
|
316
|
+
if (!parent) {
|
|
317
|
+
throw new Error('accepted the root state');
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
parent.spans = accepted.spans;
|
|
321
|
+
parent.balanced = accepted.balanced;
|
|
322
|
+
parent.referencePath = accepted.referencePath;
|
|
323
|
+
parent.held = accepted.held;
|
|
324
|
+
parent.depths = accepted.depths;
|
|
325
|
+
parent.expressions = accepted.expressions;
|
|
326
|
+
// do I need this condition?
|
|
327
|
+
if (parent.depths.path === accepted.depths.path) {
|
|
328
|
+
const parentChildren = parent.node.children;
|
|
329
|
+
parent.node.children = parentChildren;
|
|
330
|
+
|
|
331
|
+
const internalState = internalStates.get(parent.node);
|
|
332
|
+
const { path: parentPath } = internalState;
|
|
333
|
+
// FIXME
|
|
334
|
+
// some `properties` are not copied
|
|
335
|
+
for (let i = btree.getSum(parentChildren); i < btree.getSum(accepted.node.children); i++) {
|
|
336
|
+
let tag = btree.getAt(i, accepted.node.children);
|
|
337
|
+
|
|
338
|
+
if (tag.type === GapTag) {
|
|
339
|
+
let referenceIdx = i;
|
|
340
|
+
let reference;
|
|
341
|
+
let isShift = btree.getAt(i - 1, accepted.node.children).type === ShiftTag;
|
|
342
|
+
|
|
343
|
+
while (
|
|
344
|
+
(reference = btree.getAt(--referenceIdx, accepted.node.children)).type !== ReferenceTag
|
|
345
|
+
);
|
|
346
|
+
|
|
347
|
+
let { name, isArray, flags } = reference.value;
|
|
348
|
+
const resolvedPath = buildReferenceTag(
|
|
349
|
+
name,
|
|
350
|
+
isArray,
|
|
351
|
+
flags,
|
|
352
|
+
isArray ? btree.getSum(parentPath.node.properties[name]) - (isShift ? 1 : 0) : null,
|
|
353
|
+
);
|
|
354
|
+
const expr = get(resolvedPath, accepted.node);
|
|
355
|
+
internalState.expressionsPump.queue(expr);
|
|
356
|
+
} else if (tag.type === EmbeddedNode) {
|
|
357
|
+
internalState.expressionsPump.queue(tag.value);
|
|
358
|
+
tag = buildGapTag();
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
internalState.instructionsPump.queue(buildCall('advance', buildEmbeddedTag(tag)));
|
|
362
|
+
internalState.agast.next();
|
|
363
|
+
|
|
364
|
+
updatePath(parentPath, tag);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if (parent.depths.result === accepted.depths.result + 1) {
|
|
369
|
+
parent.resultPath = new TagPath(parent.resultPath.path, accepted.resultPath.childrenIndex);
|
|
370
|
+
} else {
|
|
371
|
+
parent.resultPath = accepted.resultPath;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
nodeStates.set(parent.node, nodeStates.get(accepted.node));
|
|
375
|
+
|
|
376
|
+
parent.source.accept(accepted.source);
|
|
377
|
+
|
|
378
|
+
return parent;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
reject() {
|
|
382
|
+
const rejectedState = this;
|
|
383
|
+
const { parent } = rejectedState;
|
|
384
|
+
|
|
385
|
+
if (this.status === 'rejected') {
|
|
386
|
+
return parent;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (this.status !== 'active') throw new Error();
|
|
390
|
+
|
|
391
|
+
this.status = 'rejected';
|
|
392
|
+
|
|
393
|
+
if (!parent) throw new Error('rejected root state');
|
|
394
|
+
|
|
395
|
+
rejectedState.source.reject();
|
|
396
|
+
|
|
397
|
+
return parent;
|
|
183
398
|
}
|
|
184
399
|
};
|
package/lib/utils/pattern.js
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import isString from 'iter-tools-es/methods/is-string';
|
|
2
2
|
import isEmpty from 'iter-tools-es/methods/is-empty';
|
|
3
3
|
import { generateMatches } from '@bablr/regex-vm';
|
|
4
|
-
import { getStreamIterator, maybeWait } from '@bablr/agast-helpers/stream';
|
|
5
|
-
import * as t from '@bablr/agast-helpers/shorthand';
|
|
4
|
+
import { getStreamIterator, maybeWait, printType } from '@bablr/agast-helpers/stream';
|
|
6
5
|
import * as l from '@bablr/agast-vm-helpers/languages';
|
|
6
|
+
import {
|
|
7
|
+
buildAlternative,
|
|
8
|
+
buildAlternatives,
|
|
9
|
+
buildElements,
|
|
10
|
+
buildPattern,
|
|
11
|
+
buildToken,
|
|
12
|
+
} from '@bablr/helpers/builders';
|
|
13
|
+
import { buildEmbeddedRegex } from '@bablr/agast-helpers/builders';
|
|
7
14
|
|
|
8
15
|
export const assertValidRegex = (expr) => {
|
|
9
16
|
const { flags } = expr;
|
|
@@ -16,25 +23,21 @@ export const assertValidRegex = (expr) => {
|
|
|
16
23
|
};
|
|
17
24
|
|
|
18
25
|
const buildStringRegex = (str) => {
|
|
19
|
-
return
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}),
|
|
25
|
-
],
|
|
26
|
-
close: t.s_node(l.Regex, 'Punctuator', '/'),
|
|
27
|
-
});
|
|
26
|
+
return buildPattern(
|
|
27
|
+
buildAlternatives([
|
|
28
|
+
buildAlternative(buildElements([...str].map((chr) => buildToken(l.Regex, 'Character', chr)))),
|
|
29
|
+
]),
|
|
30
|
+
);
|
|
28
31
|
};
|
|
29
32
|
|
|
30
33
|
export const match = (pattern, source) => {
|
|
31
34
|
const pattern_ = isString(pattern) ? buildStringRegex(pattern) : pattern;
|
|
32
35
|
|
|
33
|
-
if (pattern_.type !== 'Pattern') throw new Error();
|
|
36
|
+
if (printType(pattern_.type) !== 'Pattern') throw new Error();
|
|
34
37
|
|
|
35
38
|
assertValidRegex(pattern_);
|
|
36
39
|
|
|
37
|
-
const iter = getStreamIterator(generateMatches(pattern_, source));
|
|
40
|
+
const iter = getStreamIterator(generateMatches(buildEmbeddedRegex(pattern_), source));
|
|
38
41
|
|
|
39
42
|
const step = iter.next();
|
|
40
43
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export class Pump {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.held = [];
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
queue(value) {
|
|
7
|
+
this.held.push(value);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
next() {
|
|
11
|
+
const held = this.held[0];
|
|
12
|
+
if (!held) throw new Error();
|
|
13
|
+
this.held.shift();
|
|
14
|
+
return { done: false, value: held };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
[Symbol.iterator]() {
|
|
18
|
+
return this;
|
|
19
|
+
}
|
|
20
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bablr/bablr-vm",
|
|
3
3
|
"description": "A VM for parsing using BABLR languages",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.19.0",
|
|
5
5
|
"author": "Conrad Buck<conartist6@gmail.com>",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"files": [
|
|
@@ -12,14 +12,15 @@
|
|
|
12
12
|
},
|
|
13
13
|
"sideEffects": false,
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@bablr/agast-helpers": "
|
|
16
|
-
"@bablr/agast-vm
|
|
15
|
+
"@bablr/agast-helpers": "0.6.0",
|
|
16
|
+
"@bablr/agast-vm": "0.7.0",
|
|
17
|
+
"@bablr/agast-vm-helpers": "0.6.0",
|
|
17
18
|
"@bablr/coroutine": "0.1.0",
|
|
18
|
-
"@bablr/helpers": "
|
|
19
|
-
"@bablr/regex-vm": "
|
|
19
|
+
"@bablr/helpers": "0.21.1",
|
|
20
|
+
"@bablr/regex-vm": "0.10.0",
|
|
20
21
|
"@bablr/weak-stack": "0.1.0",
|
|
21
22
|
"@iter-tools/imm-stack": "1.1.0",
|
|
22
|
-
"iter-tools-es": "
|
|
23
|
+
"iter-tools-es": "7.5.3"
|
|
23
24
|
},
|
|
24
25
|
"devDependencies": {
|
|
25
26
|
"@bablr/eslint-config-base": "github:bablr-lang/eslint-config-base#d834ccc52795d6c3b96ecc6c419960fceed221a6",
|