@bablr/agast-vm-helpers 0.6.1 → 0.7.1
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 +69 -0
- package/lib/deembed.js +8 -1
- package/lib/index.js +36 -29
- package/lib/print.js +66 -0
- package/lib/stream.js +231 -0
- package/lib/symbols.js +10 -0
- package/package.json +7 -3
package/lib/builders.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EmbeddedNode,
|
|
3
|
+
EmbeddedMatcher,
|
|
4
|
+
EmbeddedRegex,
|
|
5
|
+
EmbeddedTag,
|
|
6
|
+
EmbeddedObject,
|
|
7
|
+
EmbeddedInstruction,
|
|
8
|
+
} from './symbols.js';
|
|
9
|
+
|
|
10
|
+
const isObject = (val) => val !== null && typeof val === 'object';
|
|
11
|
+
|
|
12
|
+
const { freeze } = Object;
|
|
13
|
+
|
|
14
|
+
export const buildCall = (verb, ...args) => {
|
|
15
|
+
return freeze({ verb, arguments: freeze(args) });
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const buildEmbeddedObject = (obj) => {
|
|
19
|
+
if (!isObject(obj)) throw new Error();
|
|
20
|
+
return freeze({ type: EmbeddedObject, value: freeze(obj) });
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const buildEmbeddedMatcher = (matcher) => {
|
|
24
|
+
if (!isObject(matcher)) throw new Error();
|
|
25
|
+
return freeze({ type: EmbeddedMatcher, value: matcher });
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const buildEmbeddedInstruction = (instr) => {
|
|
29
|
+
if (!isObject(instr)) throw new Error();
|
|
30
|
+
return freeze({ type: EmbeddedInstruction, value: instr });
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const buildEmbeddedRegex = (re) => {
|
|
34
|
+
if (!isObject(re)) throw new Error();
|
|
35
|
+
return freeze({ type: EmbeddedRegex, value: re });
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const buildEmbeddedTag = (tag) => {
|
|
39
|
+
if (!isObject(tag)) throw new Error();
|
|
40
|
+
return freeze({ type: EmbeddedTag, value: tag });
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const buildEffect = (value) => {
|
|
44
|
+
return freeze({ type: 'Effect', value });
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const buildWriteEffect = (text, options = {}) => {
|
|
48
|
+
return buildEffect(
|
|
49
|
+
freeze({
|
|
50
|
+
verb: 'write',
|
|
51
|
+
value: buildEmbeddedObject(freeze({ text, options: buildEmbeddedObject(freeze(options)) })),
|
|
52
|
+
}),
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const buildAnsiPushEffect = (spans = '') => {
|
|
57
|
+
return buildEffect(
|
|
58
|
+
freeze({
|
|
59
|
+
verb: 'ansi-push',
|
|
60
|
+
value: buildEmbeddedObject(
|
|
61
|
+
freeze({ spans: spans === '' ? freeze([]) : freeze(spans.split(' ')) }),
|
|
62
|
+
),
|
|
63
|
+
}),
|
|
64
|
+
);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const buildAnsiPopEffect = () => {
|
|
68
|
+
return buildEffect(freeze({ verb: 'ansi-pop', value: undefined }));
|
|
69
|
+
};
|
package/lib/deembed.js
CHANGED
|
@@ -4,7 +4,8 @@ import {
|
|
|
4
4
|
EmbeddedTag,
|
|
5
5
|
EmbeddedMatcher,
|
|
6
6
|
EmbeddedRegex,
|
|
7
|
-
|
|
7
|
+
EmbeddedInstruction,
|
|
8
|
+
} from './symbols.js';
|
|
8
9
|
|
|
9
10
|
export const getEmbeddedObject = (expr) => {
|
|
10
11
|
if (!expr) return expr;
|
|
@@ -24,6 +25,12 @@ export const getEmbeddedMatcher = (expr) => {
|
|
|
24
25
|
return expr.value;
|
|
25
26
|
};
|
|
26
27
|
|
|
28
|
+
export const getEmbeddedInstruction = (expr) => {
|
|
29
|
+
if (!expr) return expr;
|
|
30
|
+
if (expr.type !== EmbeddedInstruction) throw new Error();
|
|
31
|
+
return expr.value;
|
|
32
|
+
};
|
|
33
|
+
|
|
27
34
|
export const getEmbeddedRegex = (expr) => {
|
|
28
35
|
if (!expr) return expr;
|
|
29
36
|
if (expr.type !== EmbeddedRegex) throw new Error();
|
package/lib/index.js
CHANGED
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
nodeFlags,
|
|
6
6
|
printType,
|
|
7
7
|
buildGapTag,
|
|
8
|
-
buildEmbeddedMatcher,
|
|
9
8
|
isNullNode,
|
|
10
9
|
buildNullTag,
|
|
11
10
|
buildStubNode,
|
|
@@ -13,12 +12,12 @@ import {
|
|
|
13
12
|
buildReferenceTag,
|
|
14
13
|
} from '@bablr/agast-helpers/tree';
|
|
15
14
|
import * as btree from '@bablr/agast-helpers/btree';
|
|
15
|
+
import * as sumtree from '@bablr/agast-helpers/sumtree';
|
|
16
16
|
import {
|
|
17
17
|
buildCloseNodeTag,
|
|
18
18
|
buildLiteralTag,
|
|
19
19
|
buildDoctypeTag,
|
|
20
20
|
referenceFlags,
|
|
21
|
-
buildEmbeddedRegex,
|
|
22
21
|
} from '@bablr/agast-helpers/builders';
|
|
23
22
|
import {
|
|
24
23
|
DoctypeTag,
|
|
@@ -27,9 +26,10 @@ import {
|
|
|
27
26
|
ShiftTag,
|
|
28
27
|
GapTag,
|
|
29
28
|
NullTag,
|
|
30
|
-
|
|
29
|
+
InitializerTag,
|
|
31
30
|
LiteralTag,
|
|
32
31
|
} from '@bablr/agast-helpers/symbols';
|
|
32
|
+
import { buildEmbeddedMatcher, buildEmbeddedRegex } from './builders.js';
|
|
33
33
|
|
|
34
34
|
const { freeze } = Object;
|
|
35
35
|
|
|
@@ -59,11 +59,13 @@ export const shouldBranch = (effects) => {
|
|
|
59
59
|
};
|
|
60
60
|
|
|
61
61
|
export const reifyNodeFlags = (flags) => {
|
|
62
|
-
let { tokenToken, hasGapToken } = flags.properties;
|
|
62
|
+
let { tokenToken, hasGapToken, fragmentToken, coverFragmentToken } = flags.properties;
|
|
63
63
|
|
|
64
64
|
return {
|
|
65
65
|
token: !!(tokenToken && reifyExpression(tokenToken.node)),
|
|
66
66
|
hasGap: !!(hasGapToken && reifyExpression(hasGapToken.node)),
|
|
67
|
+
fragment: !!(fragmentToken && reifyExpression(fragmentToken.node)),
|
|
68
|
+
cover: !!(coverFragmentToken && reifyExpression(coverFragmentToken.node)),
|
|
67
69
|
};
|
|
68
70
|
};
|
|
69
71
|
|
|
@@ -115,20 +117,20 @@ export const buildFragmentChildren = (node) => {
|
|
|
115
117
|
open = reifyExpression(open.node);
|
|
116
118
|
close = reifyExpression(close.node);
|
|
117
119
|
|
|
118
|
-
built =
|
|
120
|
+
built = sumtree.push(built, open);
|
|
119
121
|
|
|
120
|
-
for (const child of
|
|
122
|
+
for (const child of sumtree.traverse(children)) {
|
|
121
123
|
if (child.node.type !== Symbol.for('Property')) throw new Error('umimplemented');
|
|
122
124
|
|
|
123
125
|
let { reference } = child.node.properties;
|
|
124
126
|
|
|
125
127
|
reference = reifyExpression(reference.node);
|
|
126
128
|
|
|
127
|
-
built =
|
|
128
|
-
built =
|
|
129
|
+
built = sumtree.push(built, reference);
|
|
130
|
+
built = sumtree.push(built, buildGapTag());
|
|
129
131
|
}
|
|
130
132
|
|
|
131
|
-
built =
|
|
133
|
+
built = sumtree.push(built, close);
|
|
132
134
|
|
|
133
135
|
return built;
|
|
134
136
|
};
|
|
@@ -144,25 +146,25 @@ export const buildChildren = (node) => {
|
|
|
144
146
|
close = reifyExpression(close?.node);
|
|
145
147
|
|
|
146
148
|
if (selfClosing) {
|
|
147
|
-
built =
|
|
149
|
+
built = sumtree.push(built, open);
|
|
148
150
|
if (!isNull(intrinsicValue?.node)) {
|
|
149
|
-
built =
|
|
151
|
+
built = sumtree.push(built, buildLiteralTag(intrinsicValue.node));
|
|
150
152
|
}
|
|
151
|
-
built =
|
|
153
|
+
built = sumtree.push(built, buildCloseNodeTag());
|
|
152
154
|
} else {
|
|
153
|
-
built =
|
|
154
|
-
for (const child of
|
|
155
|
+
built = sumtree.push(built, open);
|
|
156
|
+
for (const child of sumtree.traverse(children)) {
|
|
155
157
|
if (child.node.type !== Symbol.for('Property')) throw new Error('umimplemented');
|
|
156
158
|
|
|
157
159
|
let { reference } = child.node.properties;
|
|
158
160
|
|
|
159
161
|
reference = reifyExpression(reference.node);
|
|
160
162
|
|
|
161
|
-
built =
|
|
162
|
-
built =
|
|
163
|
+
built = sumtree.push(built, reference);
|
|
164
|
+
built = sumtree.push(built, buildGapTag());
|
|
163
165
|
}
|
|
164
166
|
|
|
165
|
-
built =
|
|
167
|
+
built = sumtree.push(built, close);
|
|
166
168
|
}
|
|
167
169
|
|
|
168
170
|
return built;
|
|
@@ -193,7 +195,7 @@ export const reifyExpression = (node) => {
|
|
|
193
195
|
flags: nodeFlags,
|
|
194
196
|
language: attributes.bablrLanguage,
|
|
195
197
|
type: null,
|
|
196
|
-
children:
|
|
198
|
+
children: sumtree.addAt(
|
|
197
199
|
0,
|
|
198
200
|
buildFragmentChildren(node.properties.tree.node),
|
|
199
201
|
buildDoctypeTag(attributes),
|
|
@@ -269,7 +271,7 @@ export const reifyExpression = (node) => {
|
|
|
269
271
|
}
|
|
270
272
|
|
|
271
273
|
case 'Identifier': {
|
|
272
|
-
return getCooked(node);
|
|
274
|
+
return getCooked(node.properties.content.node);
|
|
273
275
|
}
|
|
274
276
|
|
|
275
277
|
case 'IdentifierPath': {
|
|
@@ -310,8 +312,8 @@ export const reifyExpression = (node) => {
|
|
|
310
312
|
case 'GapTag':
|
|
311
313
|
return { type: GapTag, value: undefined };
|
|
312
314
|
|
|
313
|
-
case '
|
|
314
|
-
return { type:
|
|
315
|
+
case 'InitializerTag':
|
|
316
|
+
return { type: InitializerTag, value: undefined };
|
|
315
317
|
|
|
316
318
|
case 'NullTag':
|
|
317
319
|
return { type: NullTag, value: undefined };
|
|
@@ -355,7 +357,7 @@ export const reifyExpression = (node) => {
|
|
|
355
357
|
type =
|
|
356
358
|
type.node.type === Symbol.for('String')
|
|
357
359
|
? getCooked(type.node.properties.content.node)
|
|
358
|
-
:
|
|
360
|
+
: reifyExpression(type.node);
|
|
359
361
|
attributes = attributes ? reifyExpression(attributes.node) : {};
|
|
360
362
|
intrinsicValue = intrinsicValue && reifyExpression(intrinsicValue.node);
|
|
361
363
|
|
|
@@ -394,11 +396,7 @@ export const reifyExpression = (node) => {
|
|
|
394
396
|
case 'ReferenceMatcher': {
|
|
395
397
|
let { name, openIndexToken, flags } = node.properties;
|
|
396
398
|
|
|
397
|
-
name =
|
|
398
|
-
name &&
|
|
399
|
-
(name.node.type === Symbol.for('Identifier')
|
|
400
|
-
? reifyExpression(name.node)
|
|
401
|
-
: getCooked(name.node));
|
|
399
|
+
name = name && reifyExpression(name.node);
|
|
402
400
|
let isArray = !isNull(openIndexToken?.node);
|
|
403
401
|
flags = (flags && reifyReferenceFlags(flags?.node)) || referenceFlags;
|
|
404
402
|
|
|
@@ -443,10 +441,13 @@ export const reifyExpression = (node) => {
|
|
|
443
441
|
return [...btree.traverse(elements)].map((el) => reifyExpression(el.node));
|
|
444
442
|
}
|
|
445
443
|
|
|
446
|
-
case '
|
|
447
|
-
case '
|
|
444
|
+
case 'Punctuator':
|
|
445
|
+
case 'Keyword':
|
|
448
446
|
return getCooked(node);
|
|
449
447
|
|
|
448
|
+
case 'Identifier':
|
|
449
|
+
return getCooked(node.properties.content.node);
|
|
450
|
+
|
|
450
451
|
case 'Boolean': {
|
|
451
452
|
// prettier-ignore
|
|
452
453
|
switch (getCooked(node.properties.sigilToken.node)) {
|
|
@@ -459,6 +460,12 @@ export const reifyExpression = (node) => {
|
|
|
459
460
|
case 'Null':
|
|
460
461
|
return null;
|
|
461
462
|
|
|
463
|
+
case 'NotANumber':
|
|
464
|
+
return NaN;
|
|
465
|
+
|
|
466
|
+
case 'Undefined':
|
|
467
|
+
return undefined;
|
|
468
|
+
|
|
462
469
|
default:
|
|
463
470
|
throw new Error('bad expression');
|
|
464
471
|
}
|
package/lib/print.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import {
|
|
2
|
+
printSource,
|
|
3
|
+
printTag,
|
|
4
|
+
printExpression as printExpression_,
|
|
5
|
+
} from '@bablr/agast-helpers/tree';
|
|
6
|
+
import {
|
|
7
|
+
EmbeddedNode,
|
|
8
|
+
EmbeddedTag,
|
|
9
|
+
EmbeddedObject,
|
|
10
|
+
EmbeddedMatcher,
|
|
11
|
+
EmbeddedRegex,
|
|
12
|
+
EmbeddedInstruction,
|
|
13
|
+
} from './symbols.js';
|
|
14
|
+
|
|
15
|
+
export const printEmbedded = (value) => {
|
|
16
|
+
switch (value.type) {
|
|
17
|
+
case EmbeddedTag:
|
|
18
|
+
return `t\`${printTag(value.value)}\``;
|
|
19
|
+
|
|
20
|
+
case EmbeddedMatcher:
|
|
21
|
+
return `m\`${printSource(value.value)}\``;
|
|
22
|
+
|
|
23
|
+
case EmbeddedRegex:
|
|
24
|
+
return `re\`${printSource(value.value)}\``;
|
|
25
|
+
|
|
26
|
+
case EmbeddedInstruction:
|
|
27
|
+
return `i\`${printCall(value.value)}\``;
|
|
28
|
+
|
|
29
|
+
case EmbeddedObject: {
|
|
30
|
+
return printObject(value.value);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
case EmbeddedNode: {
|
|
34
|
+
return printSource(value.value);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
default:
|
|
38
|
+
throw new Error();
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const printObject = (obj) => {
|
|
43
|
+
let entries = Object.entries(obj);
|
|
44
|
+
return entries.length
|
|
45
|
+
? `{ ${entries.map(([k, v]) => `${k}: ${printExpression(v)}`).join(', ')} }`
|
|
46
|
+
: '{}';
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const printArray = (arr) => `[${arr.map((v) => printExpression(v)).join(', ')}]`;
|
|
50
|
+
|
|
51
|
+
export const printCall = (call) => {
|
|
52
|
+
let { verb, arguments: args } = call;
|
|
53
|
+
return `${verb}${`(${args.map((v) => printExpression(v)).join(', ')})`}`;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const printExpression = (expr) => {
|
|
57
|
+
if (['string', 'symbol', 'boolean', 'number'].includes(typeof expr) || expr == null) {
|
|
58
|
+
return printExpression_(expr);
|
|
59
|
+
} else if (Array.isArray(expr)) {
|
|
60
|
+
return printArray(expr);
|
|
61
|
+
} else if (typeof expr === 'object') {
|
|
62
|
+
return printEmbedded(expr);
|
|
63
|
+
} else {
|
|
64
|
+
throw new Error();
|
|
65
|
+
}
|
|
66
|
+
};
|
package/lib/stream.js
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { Coroutine } from '@bablr/coroutine';
|
|
2
|
+
import {
|
|
3
|
+
InitializerTag,
|
|
4
|
+
CloseNodeTag,
|
|
5
|
+
EmbeddedObject,
|
|
6
|
+
GapTag,
|
|
7
|
+
NullTag,
|
|
8
|
+
OpenNodeTag,
|
|
9
|
+
ReferenceTag,
|
|
10
|
+
TokenGroup,
|
|
11
|
+
} from './symbols.js';
|
|
12
|
+
import {
|
|
13
|
+
getStreamIterator,
|
|
14
|
+
prettyGroupTags,
|
|
15
|
+
printSelfClosingNodeTag,
|
|
16
|
+
printTag,
|
|
17
|
+
StreamIterable,
|
|
18
|
+
} from '@bablr/agast-helpers/stream';
|
|
19
|
+
import { buildWriteEffect } from './builders.js';
|
|
20
|
+
import { getCooked } from '@bablr/agast-helpers/tree';
|
|
21
|
+
|
|
22
|
+
const getEmbeddedObject = (obj) => {
|
|
23
|
+
if (obj.type !== EmbeddedObject) throw new Error();
|
|
24
|
+
return obj.value;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
function* __generateStandardOutput(tags) {
|
|
28
|
+
const co = new Coroutine(getStreamIterator(tags));
|
|
29
|
+
|
|
30
|
+
for (;;) {
|
|
31
|
+
co.advance();
|
|
32
|
+
|
|
33
|
+
if (co.current instanceof Promise) {
|
|
34
|
+
co.current = yield co.current;
|
|
35
|
+
}
|
|
36
|
+
if (co.done) break;
|
|
37
|
+
|
|
38
|
+
const tag = co.value;
|
|
39
|
+
|
|
40
|
+
if (tag.type === 'Effect') {
|
|
41
|
+
const effect = tag.value;
|
|
42
|
+
if (effect.verb === 'write') {
|
|
43
|
+
const writeEffect = getEmbeddedObject(effect.value);
|
|
44
|
+
if (writeEffect.stream == null || writeEffect.stream === 1) {
|
|
45
|
+
yield* writeEffect.text;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const generateStandardOutput = (tags) => new StreamIterable(__generateStandardOutput(tags));
|
|
53
|
+
|
|
54
|
+
function* __generateAllOutput(tags) {
|
|
55
|
+
const co = new Coroutine(getStreamIterator(tags));
|
|
56
|
+
|
|
57
|
+
let currentStream = null;
|
|
58
|
+
|
|
59
|
+
for (;;) {
|
|
60
|
+
co.advance();
|
|
61
|
+
|
|
62
|
+
if (co.current instanceof Promise) {
|
|
63
|
+
co.current = yield co.current;
|
|
64
|
+
}
|
|
65
|
+
if (co.done) break;
|
|
66
|
+
|
|
67
|
+
const tag = co.value;
|
|
68
|
+
|
|
69
|
+
if (tag.type === 'Effect') {
|
|
70
|
+
const effect = tag.value;
|
|
71
|
+
if (effect.verb === 'write') {
|
|
72
|
+
const writeEffect = getEmbeddedObject(effect.value);
|
|
73
|
+
const prevStream = currentStream;
|
|
74
|
+
currentStream = getEmbeddedObject(writeEffect.options).stream || 1;
|
|
75
|
+
if (
|
|
76
|
+
prevStream &&
|
|
77
|
+
(prevStream !== currentStream || currentStream === 2) &&
|
|
78
|
+
!writeEffect.text.startsWith('\n')
|
|
79
|
+
) {
|
|
80
|
+
yield* '\n';
|
|
81
|
+
}
|
|
82
|
+
yield* writeEffect.text;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export const generateAllOutput = (tags) => new StreamIterable(__generateAllOutput(tags));
|
|
89
|
+
|
|
90
|
+
function* __writeCSTMLStrategy(tags) {
|
|
91
|
+
if (!tags) {
|
|
92
|
+
yield buildWriteEffect('<//>');
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
let prevTag = null;
|
|
97
|
+
|
|
98
|
+
const co = new Coroutine(getStreamIterator(prettyGroupTags(tags)));
|
|
99
|
+
|
|
100
|
+
for (;;) {
|
|
101
|
+
co.advance();
|
|
102
|
+
|
|
103
|
+
if (co.current instanceof Promise) {
|
|
104
|
+
co.current = yield co.current;
|
|
105
|
+
}
|
|
106
|
+
if (co.done) break;
|
|
107
|
+
|
|
108
|
+
const tag = co.value;
|
|
109
|
+
|
|
110
|
+
if (tag.type === ReferenceTag && prevTag.type === NullTag) {
|
|
111
|
+
yield buildWriteEffect(' ');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (tag.type === 'Effect') {
|
|
115
|
+
yield tag;
|
|
116
|
+
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (tag.type === TokenGroup) {
|
|
121
|
+
const intrinsicValue = getCooked(tag.value);
|
|
122
|
+
yield buildWriteEffect(printSelfClosingNodeTag(tag.value[0], intrinsicValue));
|
|
123
|
+
} else {
|
|
124
|
+
yield buildWriteEffect(printTag(tag));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
prevTag = tag;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
yield buildWriteEffect('\n');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export const writeCSTMLStrategy = (tags, options = {}) =>
|
|
134
|
+
new StreamIterable(__writeCSTMLStrategy(tags, options));
|
|
135
|
+
|
|
136
|
+
function* __writePrettyCSTMLStrategy(tags, options) {
|
|
137
|
+
let { indent = ' ', emitEffects = false, inline: inlineOption = true } = options;
|
|
138
|
+
|
|
139
|
+
if (!tags) {
|
|
140
|
+
yield buildWriteEffect('<//>');
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const co = new Coroutine(getStreamIterator(prettyGroupTags(tags)));
|
|
145
|
+
let indentLevel = 0;
|
|
146
|
+
let first = true;
|
|
147
|
+
let inline = false;
|
|
148
|
+
let ref = null;
|
|
149
|
+
|
|
150
|
+
for (;;) {
|
|
151
|
+
co.advance();
|
|
152
|
+
|
|
153
|
+
if (co.done) break;
|
|
154
|
+
|
|
155
|
+
if (co.current instanceof Promise) {
|
|
156
|
+
co.current = yield co.current;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const tag = co.value;
|
|
160
|
+
|
|
161
|
+
if (tag.type === 'Effect') {
|
|
162
|
+
const effect = tag.value;
|
|
163
|
+
if (emitEffects && effect.verb === 'write') {
|
|
164
|
+
const writeEffect = getEmbeddedObject(effect.value);
|
|
165
|
+
yield buildWriteEffect(
|
|
166
|
+
(first ? '' : '\n') + writeEffect.text,
|
|
167
|
+
getEmbeddedObject(writeEffect.options),
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
inline = false;
|
|
171
|
+
first = false;
|
|
172
|
+
} else {
|
|
173
|
+
yield tag;
|
|
174
|
+
}
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
inline =
|
|
179
|
+
inlineOption &&
|
|
180
|
+
inline &&
|
|
181
|
+
ref &&
|
|
182
|
+
(tag.type === NullTag ||
|
|
183
|
+
tag.type === GapTag ||
|
|
184
|
+
tag.type === InitializerTag ||
|
|
185
|
+
tag.type === TokenGroup);
|
|
186
|
+
|
|
187
|
+
if (!first && !inline) {
|
|
188
|
+
yield buildWriteEffect('\n');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (tag.type === CloseNodeTag) {
|
|
192
|
+
ref = null;
|
|
193
|
+
if (indentLevel === 0) {
|
|
194
|
+
throw new Error('imbalanced tag stack');
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
indentLevel--;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (!inline) {
|
|
201
|
+
yield buildWriteEffect(indent.repeat(indentLevel));
|
|
202
|
+
} else {
|
|
203
|
+
yield buildWriteEffect(' ');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (tag.type === TokenGroup) {
|
|
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
|
+
}
|
|
213
|
+
|
|
214
|
+
if (tag.type === ReferenceTag) {
|
|
215
|
+
inline = true;
|
|
216
|
+
ref = tag;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (tag.type === OpenNodeTag) {
|
|
220
|
+
indentLevel++;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
first = false;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
yield buildWriteEffect('\n');
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export const writePrettyCSTMLStrategy = (tags, options = {}) => {
|
|
230
|
+
return new StreamIterable(__writePrettyCSTMLStrategy(tags, options));
|
|
231
|
+
};
|
package/lib/symbols.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from '@bablr/agast-helpers/symbols';
|
|
2
|
+
|
|
3
|
+
export const node = Symbol.for('@bablr/node');
|
|
4
|
+
export const fragment = Symbol.for('@bablr/fragment');
|
|
5
|
+
|
|
6
|
+
export const EmbeddedInstruction = Symbol.for('EmbeddedInstruction');
|
|
7
|
+
export const EmbeddedMatcher = Symbol.for('EmbeddedMatcher');
|
|
8
|
+
export const EmbeddedRegex = Symbol.for('EmbeddedRegex');
|
|
9
|
+
export const EmbeddedTag = Symbol.for('EmbeddedTag');
|
|
10
|
+
export const EmbeddedObject = Symbol.for('EmbeddedObject');
|
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.7.1",
|
|
5
5
|
"author": "Conrad Buck<conartist6@gmail.com>",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"files": [
|
|
@@ -15,11 +15,15 @@
|
|
|
15
15
|
"./facades": "./lib/facades.js",
|
|
16
16
|
"./internal-builders": "./lib/internal-builders.js",
|
|
17
17
|
"./iterable": "./lib/iterable.js",
|
|
18
|
-
"./languages": "./lib/languages.js"
|
|
18
|
+
"./languages": "./lib/languages.js",
|
|
19
|
+
"./print": "./lib/print.js",
|
|
20
|
+
"./stream": "./lib/stream.js",
|
|
21
|
+
"./symbols": "./lib/symbols.js"
|
|
19
22
|
},
|
|
20
23
|
"sideEffects": false,
|
|
21
24
|
"dependencies": {
|
|
22
|
-
"@bablr/agast-helpers": "0.
|
|
25
|
+
"@bablr/agast-helpers": "0.7.1",
|
|
26
|
+
"@bablr/coroutine": "0.1.0"
|
|
23
27
|
},
|
|
24
28
|
"devDependencies": {
|
|
25
29
|
"@bablr/eslint-config-base": "github:bablr-lang/eslint-config-base#49f5952efed27f94ee9b94340eb1563c440bf64e",
|