@bablr/agast-vm-helpers 0.8.0 → 0.10.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/builders.js +22 -17
- package/lib/deembed.js +5 -18
- package/lib/index.js +282 -214
- package/lib/print.js +25 -13
- package/lib/stream.js +14 -28
- package/lib/symbols.js +6 -9
- package/package.json +2 -2
package/lib/builders.js
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
EmbeddedMatcher,
|
|
4
|
-
EmbeddedRegex,
|
|
5
|
-
EmbeddedTag,
|
|
6
|
-
EmbeddedObject,
|
|
7
|
-
EmbeddedInstruction,
|
|
8
|
-
} from './symbols.js';
|
|
1
|
+
import { isNode } from '@bablr/agast-helpers/path';
|
|
2
|
+
import { Matcher, Regex, Tag, EmbeddedObject, Instruction, Node } from './symbols.js';
|
|
9
3
|
|
|
10
4
|
const isObject = (val) => val !== null && typeof val === 'object';
|
|
11
5
|
|
|
12
6
|
const { freeze } = Object;
|
|
13
7
|
|
|
8
|
+
export const buildOptions = (options) => {
|
|
9
|
+
let { shift, bind, allowEmpty, internal } = options;
|
|
10
|
+
|
|
11
|
+
let s = !shift ? 'S' : ' ';
|
|
12
|
+
let b = bind ? 'b' : ' ';
|
|
13
|
+
let e = allowEmpty ? 'e' : ' ';
|
|
14
|
+
let i = internal ? 'i' : ' ';
|
|
15
|
+
|
|
16
|
+
return `${s}${b}${e}${i}`;
|
|
17
|
+
};
|
|
18
|
+
|
|
14
19
|
export const buildCall = (verb, ...args) => {
|
|
15
20
|
return freeze({ verb, arguments: freeze(args) });
|
|
16
21
|
};
|
|
@@ -20,29 +25,29 @@ export const buildEmbeddedObject = (obj) => {
|
|
|
20
25
|
return freeze({ type: EmbeddedObject, value: freeze(obj) });
|
|
21
26
|
};
|
|
22
27
|
|
|
23
|
-
export const buildEmbeddedNode = (node) => {
|
|
24
|
-
if (!isObject(node)) throw new Error();
|
|
25
|
-
return freeze({ type: EmbeddedNode, value: freeze(node) });
|
|
26
|
-
};
|
|
27
|
-
|
|
28
28
|
export const buildEmbeddedMatcher = (matcher) => {
|
|
29
29
|
if (!isObject(matcher)) throw new Error();
|
|
30
|
-
return freeze({ type:
|
|
30
|
+
return freeze({ type: Matcher, value: matcher });
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
export const buildEmbeddedInstruction = (instr) => {
|
|
34
34
|
if (!isObject(instr)) throw new Error();
|
|
35
|
-
return freeze({ type:
|
|
35
|
+
return freeze({ type: Instruction, value: instr });
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
export const buildEmbeddedRegex = (re) => {
|
|
39
39
|
if (!isObject(re)) throw new Error();
|
|
40
|
-
return freeze({ type:
|
|
40
|
+
return freeze({ type: Regex, value: re });
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
export const buildEmbeddedTag = (tag) => {
|
|
44
44
|
if (!isObject(tag)) throw new Error();
|
|
45
|
-
return freeze({ type:
|
|
45
|
+
return freeze({ type: Tag, value: tag });
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const buildEmbeddedNode = (node) => {
|
|
49
|
+
if (!isNode(node)) throw new Error();
|
|
50
|
+
return freeze({ type: Node, value: node });
|
|
46
51
|
};
|
|
47
52
|
|
|
48
53
|
export const buildEffect = (value) => {
|
package/lib/deembed.js
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
EmbeddedNode,
|
|
3
|
-
EmbeddedObject,
|
|
4
|
-
EmbeddedTag,
|
|
5
|
-
EmbeddedMatcher,
|
|
6
|
-
EmbeddedRegex,
|
|
7
|
-
EmbeddedInstruction,
|
|
8
|
-
} from './symbols.js';
|
|
1
|
+
import { EmbeddedObject, Tag, Matcher, Regex, Instruction } from './symbols.js';
|
|
9
2
|
|
|
10
3
|
export const getEmbeddedObject = (expr) => {
|
|
11
4
|
if (!expr) return expr;
|
|
@@ -13,32 +6,26 @@ export const getEmbeddedObject = (expr) => {
|
|
|
13
6
|
return expr.value;
|
|
14
7
|
};
|
|
15
8
|
|
|
16
|
-
export const getEmbeddedNode = (expr) => {
|
|
17
|
-
if (!expr) return expr;
|
|
18
|
-
if (expr.type !== EmbeddedNode) throw new Error();
|
|
19
|
-
return expr.value;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
9
|
export const getEmbeddedMatcher = (expr) => {
|
|
23
10
|
if (!expr) return expr;
|
|
24
|
-
if (expr.type !==
|
|
11
|
+
if (expr.type !== Matcher) throw new Error();
|
|
25
12
|
return expr.value;
|
|
26
13
|
};
|
|
27
14
|
|
|
28
15
|
export const getEmbeddedInstruction = (expr) => {
|
|
29
16
|
if (!expr) return expr;
|
|
30
|
-
if (expr.type !==
|
|
17
|
+
if (expr.type !== Instruction) throw new Error();
|
|
31
18
|
return expr.value;
|
|
32
19
|
};
|
|
33
20
|
|
|
34
21
|
export const getEmbeddedRegex = (expr) => {
|
|
35
22
|
if (!expr) return expr;
|
|
36
|
-
if (expr.type !==
|
|
23
|
+
if (expr.type !== Regex) throw new Error();
|
|
37
24
|
return expr.value;
|
|
38
25
|
};
|
|
39
26
|
|
|
40
27
|
export const getEmbeddedTag = (expr) => {
|
|
41
|
-
if (expr.type !==
|
|
28
|
+
if (expr.type !== Tag) throw new Error();
|
|
42
29
|
const tag = expr.value;
|
|
43
30
|
return tag;
|
|
44
31
|
};
|
package/lib/index.js
CHANGED
|
@@ -2,39 +2,41 @@ import {
|
|
|
2
2
|
sourceTextFor,
|
|
3
3
|
getCooked,
|
|
4
4
|
isNull,
|
|
5
|
-
nodeFlags,
|
|
6
5
|
isNullNode,
|
|
7
|
-
|
|
8
|
-
isFragmentNode,
|
|
6
|
+
isCover,
|
|
9
7
|
buildReferenceTag,
|
|
10
8
|
getRoot,
|
|
11
|
-
|
|
9
|
+
get,
|
|
10
|
+
list,
|
|
12
11
|
} from '@bablr/agast-helpers/tree';
|
|
13
|
-
import * as
|
|
14
|
-
import * as sumtree from '@bablr/agast-helpers/children';
|
|
12
|
+
import * as Tags from '@bablr/agast-helpers/tags';
|
|
15
13
|
import {
|
|
16
14
|
buildGapTag,
|
|
17
15
|
buildNullTag,
|
|
18
16
|
buildOpenNodeTag,
|
|
19
|
-
buildBindingTag,
|
|
20
|
-
buildInitializerTag,
|
|
21
17
|
buildShiftTag,
|
|
22
18
|
buildCloseNodeTag,
|
|
23
19
|
buildLiteralTag,
|
|
24
20
|
buildDoctypeTag,
|
|
21
|
+
buildAttributeDefinition,
|
|
22
|
+
nodeFlags,
|
|
25
23
|
referenceFlags,
|
|
26
|
-
|
|
24
|
+
buildBindingTag,
|
|
25
|
+
buildDocument,
|
|
26
|
+
buildPropertyTag,
|
|
27
|
+
tokenFlags,
|
|
28
|
+
buildFullOpenNodeTag,
|
|
27
29
|
} from '@bablr/agast-helpers/builders';
|
|
28
30
|
import { buildEmbeddedMatcher, buildEmbeddedRegex } from './builders.js';
|
|
29
31
|
import {
|
|
30
32
|
AttributeDefinition,
|
|
33
|
+
CloseNodeTag,
|
|
31
34
|
GapTag,
|
|
32
|
-
InitializerTag,
|
|
33
35
|
LiteralTag,
|
|
34
36
|
NullTag,
|
|
35
|
-
|
|
37
|
+
OpenNodeTag,
|
|
36
38
|
} from './symbols.js';
|
|
37
|
-
import {
|
|
39
|
+
import { buildNode, getFlags, getTags } from '@bablr/agast-helpers/path';
|
|
38
40
|
|
|
39
41
|
const { freeze } = Object;
|
|
40
42
|
|
|
@@ -42,6 +44,7 @@ export const effectsFor = (verb) => {
|
|
|
42
44
|
switch (verb) {
|
|
43
45
|
case 'eat':
|
|
44
46
|
case 'shift':
|
|
47
|
+
case 'eatHeld':
|
|
45
48
|
return { success: 'eat', failure: 'fail' };
|
|
46
49
|
|
|
47
50
|
case 'eatMatch':
|
|
@@ -59,108 +62,96 @@ export const effectsFor = (verb) => {
|
|
|
59
62
|
}
|
|
60
63
|
};
|
|
61
64
|
|
|
65
|
+
export const reifyBablrOptions = (str) => {
|
|
66
|
+
if (str.length !== 4) throw new Error();
|
|
67
|
+
let shift = !str.includes('S');
|
|
68
|
+
let bind = str.includes('b');
|
|
69
|
+
let allowEmpty = str.includes('e');
|
|
70
|
+
let internal = str.includes('i');
|
|
71
|
+
|
|
72
|
+
return freeze({ shift, bind, allowEmpty, internal });
|
|
73
|
+
};
|
|
74
|
+
|
|
62
75
|
export const shouldBranch = (effects) => {
|
|
63
76
|
return effects ? effects.success === 'none' || effects.failure === 'none' : false;
|
|
64
77
|
};
|
|
65
78
|
|
|
79
|
+
export const reifyMatcherReferenceName = (matcher) => {
|
|
80
|
+
if (matcher == null) return null;
|
|
81
|
+
return reifyExpression(get(['refMatcher', 'name'], matcher.value));
|
|
82
|
+
};
|
|
83
|
+
|
|
66
84
|
export const reifyNodeFlags = (flags) => {
|
|
67
|
-
let {
|
|
85
|
+
let { token, hasGap } = flags.value.attributes;
|
|
68
86
|
|
|
69
87
|
return {
|
|
70
|
-
token
|
|
71
|
-
hasGap
|
|
72
|
-
fragment: !!(fragmentToken && reifyExpression(fragmentToken.node)),
|
|
73
|
-
cover: !!(coverFragmentToken && reifyExpression(coverFragmentToken.node)),
|
|
88
|
+
token,
|
|
89
|
+
hasGap,
|
|
74
90
|
};
|
|
75
91
|
};
|
|
76
92
|
|
|
77
93
|
export const reifyReferenceFlags = (flags) => {
|
|
78
|
-
let
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
94
|
+
let arrayToken = get('arrayToken', flags);
|
|
95
|
+
let expressionToken = get('expressionToken', flags);
|
|
96
|
+
let intrinsicToken = get('intrinsicToken', flags);
|
|
97
|
+
let hasGapToken = get('hasGapToken', flags);
|
|
98
|
+
|
|
99
|
+
return freeze({
|
|
100
|
+
array: !!reifyExpression(arrayToken),
|
|
101
|
+
expression: !!reifyExpression(expressionToken),
|
|
102
|
+
intrinsic: !!reifyExpression(intrinsicToken),
|
|
103
|
+
hasGap: !!reifyExpression(hasGapToken),
|
|
104
|
+
});
|
|
84
105
|
};
|
|
85
106
|
|
|
86
|
-
export const
|
|
87
|
-
|
|
88
|
-
for (const property of btree.traverse(properties.node)) {
|
|
89
|
-
switch (property.node.type) {
|
|
90
|
-
case Symbol.for('Property'): {
|
|
91
|
-
let { reference, value: node } = property.node.properties;
|
|
92
|
-
|
|
93
|
-
reference = reference ? reifyExpression(reference.node) : buildReferenceTag('.');
|
|
94
|
-
node = reifyExpression(node.node);
|
|
95
|
-
|
|
96
|
-
let { name, isArray } = reference.value;
|
|
97
|
-
if (name) {
|
|
98
|
-
if (isArray) {
|
|
99
|
-
built[name] ||= [];
|
|
100
|
-
built[name].push({ reference, node });
|
|
101
|
-
} else {
|
|
102
|
-
built[name] = { reference, node };
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
break;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return built;
|
|
110
|
-
};
|
|
107
|
+
export const buildTags = (node) => {
|
|
108
|
+
let open = get('openTag', node);
|
|
111
109
|
|
|
112
|
-
|
|
113
|
-
let
|
|
110
|
+
let openTag = reifyExpression(open);
|
|
111
|
+
let children = buildChildren(list('children', node));
|
|
112
|
+
let closeTag = buildCloseNodeTag();
|
|
114
113
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
114
|
+
if (openTag.value.selfClosing) {
|
|
115
|
+
return Tags.fromValues([openTag]);
|
|
116
|
+
}
|
|
118
117
|
|
|
119
|
-
|
|
120
|
-
|
|
118
|
+
return Tags.fromValues([openTag, children, closeTag]);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export const buildChildren = (children) => {
|
|
122
|
+
let built = Tags.fromValues([]);
|
|
121
123
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
for (const child of children) {
|
|
125
|
+
if ([AttributeDefinition, LiteralTag].includes(child.value.name)) {
|
|
126
|
+
built = Tags.push(built, reifyExpression(child));
|
|
127
|
+
continue;
|
|
126
128
|
}
|
|
127
|
-
built = sumtree.push(built, buildCloseNodeTag());
|
|
128
|
-
} else {
|
|
129
|
-
built = sumtree.push(built, open);
|
|
130
|
-
for (const child of sumtree.traverse(children.node)) {
|
|
131
|
-
if ([AttributeDefinition, LiteralTag].includes(child.node.type)) {
|
|
132
|
-
built = sumtree.push(built, reifyExpression(child.node));
|
|
133
|
-
continue;
|
|
134
|
-
}
|
|
135
129
|
|
|
136
|
-
|
|
130
|
+
if (child.value.name !== Symbol.for('Property')) throw new Error('umimplemented');
|
|
137
131
|
|
|
138
|
-
|
|
132
|
+
let reference = get('referenceTag', child);
|
|
133
|
+
let boundNode = reifyExpression(get('value', child));
|
|
134
|
+
let { node, bindingTags } = boundNode;
|
|
139
135
|
|
|
140
|
-
|
|
141
|
-
let bindingTag = binding
|
|
142
|
-
? reifyExpression(binding.node)
|
|
143
|
-
: buildBindingTag(isStubNode(value.node) ? null : []);
|
|
136
|
+
let bindings = bindingTags.map((tag) => tag.value);
|
|
144
137
|
|
|
145
|
-
|
|
138
|
+
let referenceTag =
|
|
139
|
+
reference && !isNullNode(reference) ? reifyExpression(reference) : buildReferenceTag();
|
|
146
140
|
|
|
147
|
-
|
|
148
|
-
|
|
141
|
+
if (node.value.type === Symbol.for('__')) {
|
|
142
|
+
for (let child of Tags.traverse(getTags(node))) {
|
|
143
|
+
if (![OpenNodeTag, CloseNodeTag].includes(child.value.type))
|
|
144
|
+
built = Tags.push(built, child);
|
|
149
145
|
}
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
150
148
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
} else {
|
|
155
|
-
built = sumtree.push(built, bindingTag);
|
|
156
|
-
built = sumtree.push(
|
|
157
|
-
built,
|
|
158
|
-
buildChild(Property, buildProperty(referenceTag.value, buildBindingTag().value, value)),
|
|
159
|
-
);
|
|
160
|
-
}
|
|
149
|
+
if (node.value.name === NullTag || node.value.name === GapTag) {
|
|
150
|
+
throw new Error('not implemented');
|
|
151
|
+
node = buildNode(node);
|
|
161
152
|
}
|
|
162
153
|
|
|
163
|
-
built =
|
|
154
|
+
built = Tags.push(built, buildPropertyTag([referenceTag, bindingTags, node]));
|
|
164
155
|
}
|
|
165
156
|
|
|
166
157
|
return built;
|
|
@@ -172,91 +163,135 @@ export const reifyExpression = (node) => {
|
|
|
172
163
|
if (node == null) return node;
|
|
173
164
|
if (isNullNode(node)) return null;
|
|
174
165
|
|
|
175
|
-
if (
|
|
166
|
+
if (isCover(node)) {
|
|
176
167
|
node = getRoot(node);
|
|
177
168
|
}
|
|
178
169
|
|
|
179
|
-
|
|
170
|
+
if (getFlags(node)?.token && !node.value.name) {
|
|
171
|
+
return getCooked(node);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
switch (node.value.name?.description) {
|
|
180
175
|
case 'Document': {
|
|
181
|
-
let
|
|
176
|
+
let tree = get(['tree', 'node'], node);
|
|
182
177
|
|
|
183
|
-
|
|
184
|
-
tree = reifyExpression(tree.node);
|
|
178
|
+
tree = reifyExpression(tree);
|
|
185
179
|
|
|
186
|
-
let
|
|
187
|
-
let { properties } = tree;
|
|
180
|
+
let doctypeTag = null;
|
|
188
181
|
|
|
189
|
-
return
|
|
190
|
-
flags: nodeFlags,
|
|
191
|
-
type: null,
|
|
192
|
-
children: sumtree.addAt(
|
|
193
|
-
0,
|
|
194
|
-
buildChildren(node.properties.tree.node),
|
|
195
|
-
buildDoctypeTag(attributes),
|
|
196
|
-
),
|
|
197
|
-
properties,
|
|
198
|
-
attributes,
|
|
199
|
-
});
|
|
182
|
+
return buildDocument(doctypeTag, tree);
|
|
200
183
|
}
|
|
201
184
|
|
|
202
|
-
case '
|
|
203
|
-
let
|
|
185
|
+
case 'TreeNode': {
|
|
186
|
+
let open = get('openTag', node);
|
|
204
187
|
|
|
205
|
-
|
|
188
|
+
let openTag = reifyExpression(open);
|
|
206
189
|
|
|
207
|
-
let { flags,
|
|
190
|
+
let { flags, name, attributes, literalValue } = openTag.value;
|
|
208
191
|
|
|
209
|
-
|
|
192
|
+
if (literalValue && !flags.token) {
|
|
193
|
+
let tokenFragment = buildNode(
|
|
194
|
+
Tags.fromValues([buildOpenNodeTag(tokenFlags, null, literalValue, {}, true)]),
|
|
195
|
+
);
|
|
210
196
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
197
|
+
return buildNode(
|
|
198
|
+
Tags.fromValues([
|
|
199
|
+
buildOpenNodeTag(flags, name, null, attributes),
|
|
200
|
+
Tags.fromValues([buildPropertyTag([buildReferenceTag('_'), [], tokenFragment])]),
|
|
201
|
+
buildCloseNodeTag(),
|
|
202
|
+
]),
|
|
203
|
+
);
|
|
204
|
+
} else {
|
|
205
|
+
return buildNode(buildTags(node));
|
|
206
|
+
}
|
|
218
207
|
}
|
|
219
208
|
|
|
220
209
|
case 'DoctypeTag': {
|
|
221
|
-
let
|
|
210
|
+
let version = get('version', node);
|
|
211
|
+
let attributes = get('attributes', node);
|
|
212
|
+
|
|
222
213
|
return buildDoctypeTag(
|
|
223
|
-
attributes && reifyExpression(attributes
|
|
224
|
-
parseInt(sourceTextFor(version
|
|
214
|
+
attributes && reifyExpression(attributes),
|
|
215
|
+
parseInt(sourceTextFor(version), 10),
|
|
225
216
|
);
|
|
226
217
|
}
|
|
227
218
|
|
|
228
219
|
case 'ReferenceTag': {
|
|
229
|
-
let
|
|
220
|
+
let type = get('type', node);
|
|
221
|
+
let name = get('name', node);
|
|
222
|
+
let flags = get('flags', node);
|
|
230
223
|
|
|
231
|
-
name = name && reifyExpression(name
|
|
232
|
-
type = type && reifyExpression(type
|
|
233
|
-
flags =
|
|
224
|
+
name = name && (reifyExpression(name) || null);
|
|
225
|
+
type = type && reifyExpression(type);
|
|
226
|
+
flags = (flags && reifyReferenceFlags(flags)) || undefined;
|
|
234
227
|
|
|
235
|
-
return buildReferenceTag(type, name,
|
|
228
|
+
return buildReferenceTag(type, name, flags);
|
|
236
229
|
}
|
|
237
230
|
|
|
238
231
|
case 'LiteralTag': {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
return buildLiteralTag(getCooked(value.node.properties.content.node));
|
|
232
|
+
return buildLiteralTag(getCooked(get(['value', 'content'], node)));
|
|
242
233
|
}
|
|
243
234
|
|
|
244
235
|
case 'Identifier': {
|
|
245
|
-
return getCooked(
|
|
236
|
+
return getCooked(get('content', node));
|
|
246
237
|
}
|
|
247
238
|
|
|
248
239
|
case 'IdentifierPath': {
|
|
249
|
-
return
|
|
240
|
+
return freeze(
|
|
241
|
+
[...list('segments', node)].map((segment) =>
|
|
242
|
+
freeze({ type: null, name: reifyExpression(segment) }),
|
|
243
|
+
),
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
case 'AttributeDefinition': {
|
|
248
|
+
let key = get('key', node);
|
|
249
|
+
let value = get('value', node);
|
|
250
|
+
|
|
251
|
+
key = key && reifyExpression(key).map((segment) => segment.name);
|
|
252
|
+
value = value && reifyExpression(value);
|
|
253
|
+
|
|
254
|
+
return buildAttributeDefinition(key, value);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
case 'NodeFlags': {
|
|
258
|
+
return reifyNodeFlags(node);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
case 'ReferenceFlags': {
|
|
262
|
+
return reifyReferenceFlags(node);
|
|
250
263
|
}
|
|
251
264
|
|
|
252
265
|
case 'OpenNodeTag': {
|
|
253
|
-
let
|
|
266
|
+
let flags = get('flags', node);
|
|
267
|
+
let type = get('type', node);
|
|
268
|
+
let name = get('name', node);
|
|
269
|
+
let attributes = get('attributes', node);
|
|
270
|
+
let literalValue = get('literalValue', node);
|
|
271
|
+
let openToken = get('openToken', node);
|
|
272
|
+
let selfClosing = get('selfClosingToken', node);
|
|
273
|
+
|
|
274
|
+
literalValue = literalValue && reifyExpression(literalValue);
|
|
254
275
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
attributes = reifyExpression(attributes?.node);
|
|
276
|
+
if (!openToken) {
|
|
277
|
+
if (!literalValue) throw new Error();
|
|
258
278
|
|
|
259
|
-
|
|
279
|
+
return buildOpenNodeTag(tokenFlags, null, literalValue, {});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
let anonymousToken = !openToken;
|
|
283
|
+
|
|
284
|
+
flags = anonymousToken ? tokenFlags : (flags && reifyNodeFlags(flags)) || nodeFlags;
|
|
285
|
+
type = reifyExpression(type);
|
|
286
|
+
name = reifyExpression(name);
|
|
287
|
+
attributes = reifyExpression(attributes) || {};
|
|
288
|
+
selfClosing = !!reifyExpression(selfClosing);
|
|
289
|
+
|
|
290
|
+
// if (literalValue && !flags.token) {
|
|
291
|
+
// return buildOpenNodeTag(tokenFlags, null, literalValue, {}, true);
|
|
292
|
+
// }
|
|
293
|
+
|
|
294
|
+
return buildFullOpenNodeTag(flags, type, name, literalValue, attributes, selfClosing);
|
|
260
295
|
}
|
|
261
296
|
|
|
262
297
|
case 'CloseNodeTag': {
|
|
@@ -264,153 +299,186 @@ export const reifyExpression = (node) => {
|
|
|
264
299
|
}
|
|
265
300
|
|
|
266
301
|
case 'Integer': {
|
|
267
|
-
|
|
268
|
-
return parseInt(digits.map((digit) => getCooked(digit.node)).join(''), 10);
|
|
302
|
+
return parseInt([...list('digits', node)].map((digit) => getCooked(digit)).join(''), 10);
|
|
269
303
|
}
|
|
270
304
|
|
|
271
305
|
case 'Infinity': {
|
|
272
|
-
return getCooked(
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
case 'Punctuator': {
|
|
276
|
-
return getCooked(node);
|
|
306
|
+
return getCooked(get('sign', node)) === '-' ? -Infinity : Infinity;
|
|
277
307
|
}
|
|
278
308
|
|
|
279
309
|
case 'GapTag':
|
|
280
310
|
return buildGapTag();
|
|
281
311
|
|
|
282
|
-
case 'InitializerTag':
|
|
283
|
-
return buildInitializerTag();
|
|
284
|
-
|
|
285
|
-
case 'BindingTag':
|
|
286
|
-
let { languagePath } = node.properties;
|
|
287
|
-
|
|
288
|
-
return buildBindingTag(reifyExpression(languagePath));
|
|
289
|
-
|
|
290
312
|
case 'NullTag':
|
|
291
313
|
return buildNullTag();
|
|
292
314
|
|
|
315
|
+
case 'NullNode':
|
|
316
|
+
case 'GapNode':
|
|
317
|
+
let tag = reifyExpression(get('sigilTag', node));
|
|
318
|
+
return buildNode(tag);
|
|
319
|
+
|
|
293
320
|
case 'ShiftTag':
|
|
294
321
|
return buildShiftTag();
|
|
295
322
|
|
|
296
323
|
case 'String':
|
|
297
|
-
return
|
|
324
|
+
return get('content', node) ? getCooked(get('content', node)) : '';
|
|
298
325
|
|
|
299
326
|
case 'SpamexString': {
|
|
300
|
-
return buildEmbeddedMatcher(
|
|
327
|
+
return buildEmbeddedMatcher(get('content', node));
|
|
301
328
|
}
|
|
302
329
|
|
|
303
330
|
case 'RegexString': {
|
|
304
|
-
return buildEmbeddedRegex(
|
|
331
|
+
return buildEmbeddedRegex(get('content', node));
|
|
305
332
|
}
|
|
306
333
|
|
|
307
|
-
case '
|
|
308
|
-
let
|
|
334
|
+
case 'TreeNodeMatcherOpen': {
|
|
335
|
+
let flags = get('flags', node);
|
|
336
|
+
let name = get('name', node);
|
|
337
|
+
let type = get('type', node);
|
|
338
|
+
let attributes = get('attributes', node);
|
|
339
|
+
let literalValue = get('literalValue', node);
|
|
340
|
+
|
|
341
|
+
flags = (flags && reifyNodeFlags(flags)) || {};
|
|
342
|
+
name = name
|
|
343
|
+
? name.value.name === Symbol.for('String')
|
|
344
|
+
? getCooked(get('content', name))
|
|
345
|
+
: reifyExpression(name)
|
|
346
|
+
: null;
|
|
347
|
+
type = reifyExpression(type);
|
|
348
|
+
attributes = attributes ? reifyExpression(attributes) : {};
|
|
349
|
+
literalValue = literalValue && reifyExpression(literalValue);
|
|
350
|
+
|
|
351
|
+
return freeze({
|
|
352
|
+
flags,
|
|
353
|
+
type,
|
|
354
|
+
name,
|
|
355
|
+
literalValue,
|
|
356
|
+
attributes,
|
|
357
|
+
});
|
|
358
|
+
}
|
|
309
359
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
type.node.type === Symbol.for('String')
|
|
313
|
-
? getCooked(type.node.properties.content.node)
|
|
314
|
-
: reifyExpression(type.node);
|
|
315
|
-
attributes = attributes ? reifyExpression(attributes.node) : {};
|
|
316
|
-
intrinsicValue = intrinsicValue && reifyExpression(intrinsicValue.node);
|
|
360
|
+
case 'TreeNodeMatcher': {
|
|
361
|
+
let open = reifyExpression(get('open', node));
|
|
317
362
|
|
|
318
|
-
|
|
363
|
+
if (!open) {
|
|
364
|
+
return [...list('children', node)].map(reifyExpression)[0];
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
return open;
|
|
319
368
|
}
|
|
320
369
|
|
|
321
|
-
case '
|
|
322
|
-
let
|
|
370
|
+
case 'PropertyMatcher': {
|
|
371
|
+
let refMatcher = get('refMatcher', node);
|
|
372
|
+
let boundMatcher = get('valueMatcher', node);
|
|
373
|
+
|
|
374
|
+
refMatcher = reifyExpression(refMatcher);
|
|
323
375
|
|
|
324
|
-
|
|
376
|
+
if (!boundMatcher) throw new Error();
|
|
325
377
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
};
|
|
378
|
+
if (boundMatcher.value.name !== Symbol.for('BoundNodeMatcher')) throw new Error();
|
|
379
|
+
|
|
380
|
+
let { nodeMatcher, bindingMatchers } = reifyExpression(boundMatcher);
|
|
381
|
+
|
|
382
|
+
return freeze({ refMatcher, bindingMatchers, nodeMatcher });
|
|
332
383
|
}
|
|
333
384
|
|
|
334
|
-
case '
|
|
335
|
-
let
|
|
385
|
+
case 'ReferenceMatcher': {
|
|
386
|
+
let type = get('type', node);
|
|
387
|
+
let name = get('name', node);
|
|
388
|
+
let flags = get('flags', node);
|
|
389
|
+
|
|
390
|
+
type = type && reifyExpression(type);
|
|
391
|
+
name = name && reifyExpression(name);
|
|
392
|
+
flags = (flags && reifyReferenceFlags(flags)) || referenceFlags;
|
|
336
393
|
|
|
337
|
-
return
|
|
394
|
+
return freeze({ type, name, flags });
|
|
338
395
|
}
|
|
339
396
|
|
|
340
|
-
case '
|
|
341
|
-
let
|
|
397
|
+
case 'BoundNodeMatcher': {
|
|
398
|
+
let bindingMatchers, nodeMatcher;
|
|
399
|
+
// if (get(['nodeMatcher', 'open'], node)) {
|
|
400
|
+
bindingMatchers = [...list('bindingMatchers', node)].map(reifyExpression);
|
|
401
|
+
nodeMatcher = reifyExpression(get('nodeMatcher', node));
|
|
402
|
+
// } else {
|
|
403
|
+
// ({ bindingMatchers, nodeMatcher } = reifyExpression(get('nodeMatcher', node)));
|
|
404
|
+
// }
|
|
405
|
+
|
|
406
|
+
return freeze({ bindingMatchers, nodeMatcher });
|
|
407
|
+
}
|
|
342
408
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
409
|
+
case 'BoundNode': {
|
|
410
|
+
let bindingTags = [],
|
|
411
|
+
node_;
|
|
412
|
+
if (get(['node', 'openTag'], node)) {
|
|
413
|
+
bindingTags = [...list('bindingTags', node)].map(reifyExpression);
|
|
414
|
+
node_ = reifyExpression(get('node', node));
|
|
415
|
+
} else {
|
|
416
|
+
({ bindingTags, node: node_ } = reifyExpression(get('node', node)));
|
|
417
|
+
}
|
|
346
418
|
|
|
347
|
-
return {
|
|
419
|
+
return freeze({ bindingTags, node: node_ });
|
|
348
420
|
}
|
|
349
421
|
|
|
350
|
-
case '
|
|
351
|
-
let
|
|
422
|
+
case 'BindingTag': {
|
|
423
|
+
let segments = [...list('segments', node)].map((segment) => {
|
|
424
|
+
return reifyExpression(segment);
|
|
425
|
+
});
|
|
426
|
+
return buildBindingTag(segments);
|
|
427
|
+
}
|
|
352
428
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
let isArray = !isNull(openIndexToken?.node);
|
|
356
|
-
flags = (flags && reifyReferenceFlags(flags?.node)) || referenceFlags;
|
|
429
|
+
case 'BindingSegment': {
|
|
430
|
+
let path = get('path', node);
|
|
357
431
|
|
|
358
|
-
|
|
432
|
+
switch (path.value.name && path.value.name.description) {
|
|
433
|
+
case 'Identifier':
|
|
434
|
+
return freeze({ type: null, name: reifyExpression(path) });
|
|
435
|
+
case null:
|
|
436
|
+
return freeze({ type: reifyExpression(path), name: null });
|
|
437
|
+
default:
|
|
438
|
+
throw new Error();
|
|
439
|
+
}
|
|
359
440
|
}
|
|
360
441
|
|
|
361
442
|
case 'BindingMatcher': {
|
|
362
|
-
let
|
|
363
|
-
|
|
364
|
-
languagePath = languagePath && reifyExpression(languagePath.node);
|
|
443
|
+
let segments = [...list('segments', node)].map((segment) => reifyExpression(segment));
|
|
365
444
|
|
|
366
|
-
return {
|
|
445
|
+
return freeze({ segments });
|
|
367
446
|
}
|
|
368
447
|
|
|
369
448
|
case 'GapNodeMatcher':
|
|
370
|
-
return
|
|
449
|
+
return buildNode(buildGapTag());
|
|
371
450
|
|
|
372
451
|
case 'NullNodeMatcher':
|
|
373
|
-
return
|
|
374
|
-
|
|
375
|
-
case 'ArrayNodeMatcher':
|
|
376
|
-
return [];
|
|
452
|
+
return buildNode(buildNullTag());
|
|
377
453
|
|
|
378
454
|
case 'Call': {
|
|
379
|
-
const
|
|
455
|
+
const verb = get('verb', node);
|
|
380
456
|
|
|
381
|
-
const
|
|
457
|
+
const args = [...list('arguments', node)].map((el) => reifyExpression(el));
|
|
382
458
|
|
|
383
|
-
return { verb: reifyExpression(verb
|
|
459
|
+
return freeze({ verb: reifyExpression(verb), arguments: args });
|
|
384
460
|
}
|
|
385
461
|
|
|
386
462
|
case 'Object': {
|
|
387
|
-
const { properties } = node.properties;
|
|
388
|
-
|
|
389
463
|
return Object.fromEntries(
|
|
390
|
-
[...
|
|
391
|
-
const
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
},
|
|
395
|
-
} = property;
|
|
396
|
-
return [getCooked(key.node), reifyExpression(value.node)];
|
|
464
|
+
[...list('properties', node)].map((property) => {
|
|
465
|
+
const key = get('key', property);
|
|
466
|
+
const value = get('value', property);
|
|
467
|
+
return freeze([reifyExpression(key), reifyExpression(value)]);
|
|
397
468
|
}),
|
|
398
469
|
);
|
|
399
470
|
}
|
|
400
471
|
|
|
401
472
|
case 'Array': {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
return [...btree.traverse(elements.node)].map((el) => reifyExpression(el.node));
|
|
473
|
+
return freeze([...list('elements', node)].map((el) => reifyExpression(el)));
|
|
405
474
|
}
|
|
406
475
|
|
|
407
|
-
case 'Punctuator':
|
|
408
476
|
case 'Keyword':
|
|
409
477
|
return getCooked(node);
|
|
410
478
|
|
|
411
479
|
case 'Boolean': {
|
|
412
480
|
// prettier-ignore
|
|
413
|
-
switch (getCooked(
|
|
481
|
+
switch (getCooked(get('sigilToken', node))) {
|
|
414
482
|
case 'true': return true;
|
|
415
483
|
case 'false': return false;
|
|
416
484
|
default: throw new Error();
|
package/lib/print.js
CHANGED
|
@@ -2,40 +2,52 @@ import {
|
|
|
2
2
|
printSource,
|
|
3
3
|
printTag,
|
|
4
4
|
printExpression as printExpression_,
|
|
5
|
+
printCSTML,
|
|
5
6
|
} from '@bablr/agast-helpers/tree';
|
|
6
7
|
import {
|
|
7
|
-
|
|
8
|
-
EmbeddedTag,
|
|
8
|
+
Tag,
|
|
9
9
|
EmbeddedObject,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
Matcher,
|
|
11
|
+
Regex,
|
|
12
|
+
Instruction,
|
|
13
|
+
TreeNode,
|
|
14
|
+
NullNode,
|
|
15
|
+
GapNode,
|
|
16
|
+
Node,
|
|
13
17
|
} from './symbols.js';
|
|
14
18
|
|
|
15
19
|
export const printEmbedded = (value) => {
|
|
16
20
|
switch (value.type) {
|
|
17
|
-
case
|
|
21
|
+
case Tag:
|
|
18
22
|
return `t\`${printTag(value.value)}\``;
|
|
19
23
|
|
|
20
|
-
case
|
|
24
|
+
case Node:
|
|
25
|
+
return `n\`${printCSTML(value.value)}\``;
|
|
26
|
+
|
|
27
|
+
case Matcher:
|
|
21
28
|
return `m\`${printSource(value.value)}\``;
|
|
22
29
|
|
|
23
|
-
case
|
|
30
|
+
case Regex:
|
|
24
31
|
return `re\`${printSource(value.value)}\``;
|
|
25
32
|
|
|
26
|
-
case
|
|
33
|
+
case Instruction:
|
|
27
34
|
return `i\`${printCall(value.value)}\``;
|
|
28
35
|
|
|
29
36
|
case EmbeddedObject: {
|
|
30
37
|
return printObject(value.value);
|
|
31
38
|
}
|
|
32
39
|
|
|
33
|
-
case
|
|
34
|
-
|
|
35
|
-
|
|
40
|
+
case NullNode:
|
|
41
|
+
case GapNode:
|
|
42
|
+
case TreeNode:
|
|
43
|
+
throw new Error(
|
|
44
|
+
'Cannot print plain node. Did you mean to wrap this node in buildEmbeddedNode?',
|
|
45
|
+
);
|
|
36
46
|
|
|
37
47
|
default:
|
|
38
|
-
throw new Error(
|
|
48
|
+
throw new Error(
|
|
49
|
+
'Cannot print plain object. Did you mean to wrap this object in buildEmbedded*?',
|
|
50
|
+
);
|
|
39
51
|
}
|
|
40
52
|
};
|
|
41
53
|
|
package/lib/stream.js
CHANGED
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
import { Coroutine } from '@bablr/coroutine';
|
|
2
2
|
import {
|
|
3
|
-
InitializerTag,
|
|
4
3
|
CloseNodeTag,
|
|
5
4
|
EmbeddedObject,
|
|
6
5
|
GapTag,
|
|
7
6
|
NullTag,
|
|
8
7
|
OpenNodeTag,
|
|
9
8
|
ReferenceTag,
|
|
10
|
-
TokenGroup,
|
|
11
9
|
} from './symbols.js';
|
|
12
10
|
import {
|
|
13
11
|
getStreamIterator,
|
|
14
|
-
prettyGroupTags,
|
|
15
|
-
printSelfClosingNodeTag,
|
|
16
12
|
printTag,
|
|
13
|
+
wait,
|
|
17
14
|
StreamIterable,
|
|
15
|
+
prettyGroupTags,
|
|
16
|
+
hoistTrivia,
|
|
18
17
|
} from '@bablr/agast-helpers/stream';
|
|
19
18
|
import { buildWriteEffect } from './builders.js';
|
|
20
|
-
import { getCooked } from '@bablr/agast-helpers/tree';
|
|
21
19
|
|
|
22
20
|
const getEmbeddedObject = (obj) => {
|
|
23
21
|
if (obj.type !== EmbeddedObject) throw new Error();
|
|
@@ -31,7 +29,7 @@ function* __generateStandardOutput(tags) {
|
|
|
31
29
|
co.advance();
|
|
32
30
|
|
|
33
31
|
if (co.current instanceof Promise) {
|
|
34
|
-
co.current = yield co.current;
|
|
32
|
+
co.current = yield wait(co.current);
|
|
35
33
|
}
|
|
36
34
|
if (co.done) break;
|
|
37
35
|
|
|
@@ -60,7 +58,7 @@ function* __generateAllOutput(tags) {
|
|
|
60
58
|
co.advance();
|
|
61
59
|
|
|
62
60
|
if (co.current instanceof Promise) {
|
|
63
|
-
co.current = yield co.current;
|
|
61
|
+
co.current = yield wait(co.current);
|
|
64
62
|
}
|
|
65
63
|
if (co.done) break;
|
|
66
64
|
|
|
@@ -101,7 +99,7 @@ function* __writeCSTMLStrategy(tags) {
|
|
|
101
99
|
co.advance();
|
|
102
100
|
|
|
103
101
|
if (co.current instanceof Promise) {
|
|
104
|
-
co.current = yield co.current;
|
|
102
|
+
co.current = yield wait(co.current);
|
|
105
103
|
}
|
|
106
104
|
if (co.done) break;
|
|
107
105
|
|
|
@@ -117,12 +115,7 @@ function* __writeCSTMLStrategy(tags) {
|
|
|
117
115
|
continue;
|
|
118
116
|
}
|
|
119
117
|
|
|
120
|
-
|
|
121
|
-
const intrinsicValue = getCooked(tag.value);
|
|
122
|
-
yield buildWriteEffect(printSelfClosingNodeTag(tag.value[0], intrinsicValue));
|
|
123
|
-
} else {
|
|
124
|
-
yield buildWriteEffect(printTag(tag));
|
|
125
|
-
}
|
|
118
|
+
yield buildWriteEffect(printTag(tag));
|
|
126
119
|
|
|
127
120
|
prevTag = tag;
|
|
128
121
|
}
|
|
@@ -141,7 +134,8 @@ function* __writePrettyCSTMLStrategy(tags, options) {
|
|
|
141
134
|
return;
|
|
142
135
|
}
|
|
143
136
|
|
|
144
|
-
const co = new Coroutine(getStreamIterator(prettyGroupTags(tags)));
|
|
137
|
+
const co = new Coroutine(getStreamIterator(prettyGroupTags(hoistTrivia(tags))));
|
|
138
|
+
// const co = new Coroutine(getStreamIterator(prettyGroupTags(tags)));
|
|
145
139
|
let indentLevel = 0;
|
|
146
140
|
let first = true;
|
|
147
141
|
let inline = false;
|
|
@@ -150,11 +144,10 @@ function* __writePrettyCSTMLStrategy(tags, options) {
|
|
|
150
144
|
for (;;) {
|
|
151
145
|
co.advance();
|
|
152
146
|
|
|
153
|
-
if (co.done) break;
|
|
154
|
-
|
|
155
147
|
if (co.current instanceof Promise) {
|
|
156
|
-
co.current = yield co.current;
|
|
148
|
+
co.current = yield wait(co.current);
|
|
157
149
|
}
|
|
150
|
+
if (co.done) break;
|
|
158
151
|
|
|
159
152
|
const tag = co.value;
|
|
160
153
|
|
|
@@ -181,8 +174,7 @@ function* __writePrettyCSTMLStrategy(tags, options) {
|
|
|
181
174
|
ref &&
|
|
182
175
|
(tag.type === NullTag ||
|
|
183
176
|
tag.type === GapTag ||
|
|
184
|
-
tag.type ===
|
|
185
|
-
tag.type === TokenGroup);
|
|
177
|
+
(tag.type === OpenNodeTag && tag.value.selfClosing));
|
|
186
178
|
|
|
187
179
|
if (!first && !inline) {
|
|
188
180
|
yield buildWriteEffect('\n');
|
|
@@ -203,20 +195,14 @@ function* __writePrettyCSTMLStrategy(tags, options) {
|
|
|
203
195
|
yield buildWriteEffect(' ');
|
|
204
196
|
}
|
|
205
197
|
|
|
206
|
-
|
|
207
|
-
ref = null;
|
|
208
|
-
const intrinsicValue = tag.value[0].value.flags.token ? getCooked(tag.value) : null;
|
|
209
|
-
yield buildWriteEffect(printSelfClosingNodeTag(tag.value[0], intrinsicValue));
|
|
210
|
-
} else {
|
|
211
|
-
yield buildWriteEffect(printTag(tag));
|
|
212
|
-
}
|
|
198
|
+
yield buildWriteEffect(printTag(tag));
|
|
213
199
|
|
|
214
200
|
if (tag.type === ReferenceTag) {
|
|
215
201
|
inline = true;
|
|
216
202
|
ref = tag;
|
|
217
203
|
}
|
|
218
204
|
|
|
219
|
-
if (tag.type === OpenNodeTag) {
|
|
205
|
+
if (tag.type === OpenNodeTag && !tag.value.selfClosing) {
|
|
220
206
|
indentLevel++;
|
|
221
207
|
}
|
|
222
208
|
|
package/lib/symbols.js
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
export * from '@bablr/agast-helpers/symbols';
|
|
2
2
|
|
|
3
|
-
export const
|
|
4
|
-
export const
|
|
5
|
-
|
|
6
|
-
export const
|
|
7
|
-
export const
|
|
8
|
-
export const
|
|
9
|
-
export const EmbeddedRegex = Symbol.for('EmbeddedRegex');
|
|
10
|
-
export const EmbeddedTag = Symbol.for('EmbeddedTag');
|
|
11
|
-
export const EmbeddedObject = Symbol.for('EmbeddedObject');
|
|
3
|
+
export const Instruction = Symbol.for('Instruction');
|
|
4
|
+
export const Matcher = Symbol.for('Matcher');
|
|
5
|
+
export const Regex = Symbol.for('Regex');
|
|
6
|
+
export const Tag = Symbol.for('Tag');
|
|
7
|
+
export const Object = Symbol.for('Object');
|
|
8
|
+
export const EmbeddedObject = Object;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bablr/agast-vm-helpers",
|
|
3
3
|
"description": "Helper functions for working with the BABLR VM",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.10.0",
|
|
5
5
|
"author": "Conrad Buck<conartist6@gmail.com>",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"files": [
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"sideEffects": false,
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@bablr/agast-helpers": "0.
|
|
25
|
+
"@bablr/agast-helpers": "0.10.0",
|
|
26
26
|
"@bablr/coroutine": "0.1.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|