@bablr/agast-helpers 0.6.1 → 0.7.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/print.js CHANGED
@@ -6,13 +6,8 @@ import {
6
6
  ShiftTag,
7
7
  GapTag,
8
8
  NullTag,
9
- ArrayInitializerTag,
9
+ InitializerTag,
10
10
  LiteralTag,
11
- EmbeddedNode,
12
- EmbeddedTag,
13
- EmbeddedObject,
14
- EmbeddedMatcher,
15
- EmbeddedRegex,
16
11
  } from './symbols.js';
17
12
  import { isEmptyReference, isGapNode, isNullNode, printSource, referenceFlags } from './tree.js';
18
13
 
@@ -26,11 +21,6 @@ let isFunction = (val) => typeof val === 'function';
26
21
  let when = (condition, value) =>
27
22
  condition ? (isFunction(value) ? value() : value) : { *[Symbol.iterator]() {} };
28
23
 
29
- export const printCall = (call) => {
30
- let { verb, arguments: args } = call;
31
- return `${verb}${`(${args.map((v) => printExpression(v)).join(' ')})`}`;
32
- };
33
-
34
24
  export const printArray = (arr) => `[${arr.map((v) => printExpression(v)).join(', ')}]`;
35
25
 
36
26
  export const printObject = (obj) => {
@@ -76,6 +66,8 @@ export const printOpenNodeMatcher = (matcher) => {
76
66
  export const printExpression = (expr) => {
77
67
  if (isString(expr)) {
78
68
  return printString(expr);
69
+ } else if (typeof expr === 'symbol') {
70
+ return printString(expr.description);
79
71
  } else if (expr == null || typeof expr === 'boolean') {
80
72
  return String(expr);
81
73
  } else if (isNumber(expr)) {
@@ -89,37 +81,11 @@ export const printExpression = (expr) => {
89
81
  }
90
82
  } else if (isArray(expr)) {
91
83
  return printArray(expr);
92
- } else if (typeof expr === 'object') {
93
- return printEmbedded(expr);
94
84
  } else {
95
85
  throw new Error();
96
86
  }
97
87
  };
98
88
 
99
- export const printEmbedded = (value) => {
100
- switch (value.type) {
101
- case EmbeddedTag:
102
- return `t\`${printTag(value.value)}\``;
103
-
104
- case EmbeddedMatcher:
105
- return `m\`${printSource(value.value)}\``;
106
-
107
- case EmbeddedRegex:
108
- return `re\`${printSource(value.value)}\``;
109
-
110
- case EmbeddedObject: {
111
- return printObject(value.value);
112
- }
113
-
114
- case EmbeddedNode: {
115
- return printSource(value.value);
116
- }
117
-
118
- default:
119
- throw new Error();
120
- }
121
- };
122
-
123
89
  export const printAttributes = (attributes) => {
124
90
  const printed = attributes && printObject(attributes);
125
91
  return !printed || printed === '{}' ? '' : printed;
@@ -174,10 +140,14 @@ export const printGapTag = (tag) => {
174
140
  return `<//>`;
175
141
  };
176
142
 
177
- export const printArrayInitializerTag = (tag) => {
178
- if (tag?.type !== ArrayInitializerTag) throw new Error();
143
+ export const printInitializerTag = (tag) => {
144
+ if (tag?.type !== InitializerTag) throw new Error();
179
145
 
180
- return `[]`;
146
+ if (tag.value.isArray) {
147
+ return `[]`;
148
+ } else {
149
+ return 'undefined';
150
+ }
181
151
  };
182
152
 
183
153
  export const printShiftTag = (tag) => {
@@ -236,10 +206,13 @@ export const printReferenceFlags = (flags = referenceFlags) => {
236
206
  };
237
207
 
238
208
  export const printNodeFlags = (flags) => {
209
+ if (flags.cover && !flags.fragment) throw new Error();
239
210
  let star = flags.token ? '*' : '';
240
211
  let dollar = flags.hasGap ? '$' : '';
212
+ let frag = flags.fragment ? '_' : '';
213
+ let cover = flags.cover ? '_' : '';
241
214
 
242
- return `${star}${dollar}`;
215
+ return `${star}${dollar}${frag}${cover}`;
243
216
  };
244
217
 
245
218
  export const printOpenNodeTag = (tag) => {
@@ -288,8 +261,8 @@ export const printTag = (tag) => {
288
261
  case GapTag:
289
262
  return printGapTag(tag);
290
263
 
291
- case ArrayInitializerTag:
292
- return printArrayInitializerTag(tag);
264
+ case InitializerTag:
265
+ return printInitializerTag(tag);
293
266
 
294
267
  case ShiftTag:
295
268
  return printShiftTag(tag);
package/lib/shorthand.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  buildOpenNodeTag,
5
5
  buildCloseNodeTag,
6
6
  buildLiteralTag,
7
- buildArrayInitializerTag,
7
+ buildInitializerTag,
8
8
  } from './builders.js';
9
9
  import { parseReference, treeFromStreamSync } from './tree.js';
10
10
 
@@ -31,7 +31,7 @@ export const lit = (str) => buildLiteralTag(stripArray(str));
31
31
 
32
32
  export const doctype = buildDoctypeTag;
33
33
  export const gap = buildGapTag;
34
- export const arr = buildArrayInitializerTag;
34
+ export const arr = () => buildInitializerTag(true);
35
35
  export const nodeOpen = buildOpenNodeTag;
36
36
  export const nodeClose = buildCloseNodeTag;
37
37
  export const tree = (...tags) => treeFromStreamSync(tags);
package/lib/stream.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Coroutine } from '@bablr/coroutine';
2
2
  import emptyStack from '@iter-tools/imm-stack';
3
3
  import { printSelfClosingNodeTag, printTag } from './print.js';
4
- import { buildTokenGroup, buildWriteEffect } from './builders.js';
4
+ import { buildTokenGroup } from './builders.js';
5
5
  import {
6
6
  DoctypeTag,
7
7
  OpenNodeTag,
@@ -10,19 +10,13 @@ import {
10
10
  ShiftTag,
11
11
  GapTag,
12
12
  NullTag,
13
- ArrayInitializerTag,
13
+ InitializerTag,
14
14
  LiteralTag,
15
- EmbeddedObject,
16
15
  TokenGroup,
17
16
  } from './symbols.js';
18
17
 
19
18
  export * from './print.js';
20
19
 
21
- const getEmbeddedObject = (obj) => {
22
- if (obj.type !== EmbeddedObject) throw new Error();
23
- return obj.value;
24
- };
25
-
26
20
  export const getStreamIterator = (obj) => {
27
21
  return obj[Symbol.for('@@streamIterator')]?.() || obj[Symbol.iterator]?.();
28
22
  };
@@ -203,71 +197,8 @@ function* __isEmpty(tags) {
203
197
  export const isEmpty = (tags) =>
204
198
  new StreamIterable(__isEmpty(tags))[Symbol.iterator]().next().value;
205
199
 
206
- function* __generateStandardOutput(tags) {
207
- const co = new Coroutine(getStreamIterator(tags));
208
-
209
- for (;;) {
210
- co.advance();
211
-
212
- if (co.current instanceof Promise) {
213
- co.current = yield co.current;
214
- }
215
- if (co.done) break;
216
-
217
- const tag = co.value;
218
-
219
- if (tag.type === 'Effect') {
220
- const effect = tag.value;
221
- if (effect.verb === 'write') {
222
- const writeEffect = getEmbeddedObject(effect.value);
223
- if (writeEffect.stream == null || writeEffect.stream === 1) {
224
- yield* writeEffect.text;
225
- }
226
- }
227
- }
228
- }
229
- }
230
-
231
- export const generateStandardOutput = (tags) => new StreamIterable(__generateStandardOutput(tags));
232
-
233
- function* __generateAllOutput(tags) {
234
- const co = new Coroutine(getStreamIterator(tags));
235
-
236
- let currentStream = null;
237
-
238
- for (;;) {
239
- co.advance();
240
-
241
- if (co.current instanceof Promise) {
242
- co.current = yield co.current;
243
- }
244
- if (co.done) break;
245
-
246
- const tag = co.value;
247
-
248
- if (tag.type === 'Effect') {
249
- const effect = tag.value;
250
- if (effect.verb === 'write') {
251
- const writeEffect = getEmbeddedObject(effect.value);
252
- const prevStream = currentStream;
253
- currentStream = getEmbeddedObject(writeEffect.options).stream || 1;
254
- if (
255
- prevStream &&
256
- (prevStream !== currentStream || currentStream === 2) &&
257
- !writeEffect.text.startsWith('\n')
258
- ) {
259
- yield* '\n';
260
- }
261
- yield* writeEffect.text;
262
- }
263
- }
264
- }
265
- }
266
-
267
- export const generateAllOutput = (tags) => new StreamIterable(__generateAllOutput(tags));
268
-
269
200
  export const printCSTML = (tags) => {
270
- return stringFromStream(generateStandardOutput(generateCSTML(tags)));
201
+ return stringFromStream(generateCSTML(tags));
271
202
  };
272
203
 
273
204
  function* __emptyStreamIterator() {}
@@ -388,9 +319,7 @@ function* __prettyGroupTags(tags) {
388
319
 
389
320
  if (
390
321
  (tag.type === 'Effect' && tag.value.verb === 'write') ||
391
- [ReferenceTag, DoctypeTag, GapTag, NullTag, ArrayInitializerTag, ShiftTag].includes(
392
- tag.type,
393
- ) ||
322
+ [ReferenceTag, DoctypeTag, GapTag, NullTag, InitializerTag, ShiftTag].includes(tag.type) ||
394
323
  (tag.type === OpenNodeTag && (!tag.value.type || ref?.value.name === '@'))
395
324
  ) {
396
325
  state.broken = true;
@@ -470,7 +399,7 @@ function* __generatePrettyCSTML(tags, options) {
470
399
  ref &&
471
400
  (tag.type === NullTag ||
472
401
  tag.type === GapTag ||
473
- tag.type === ArrayInitializerTag ||
402
+ tag.type === InitializerTag ||
474
403
  tag.type === TokenGroup);
475
404
 
476
405
  if (!first && !inline) {
@@ -520,151 +449,8 @@ export const generatePrettyCSTML = (tags, options = {}) => {
520
449
  return new StreamIterable(__generatePrettyCSTML(tags, options));
521
450
  };
522
451
 
523
- function* __writeCSTMLStrategy(tags) {
524
- if (!tags) {
525
- yield buildWriteEffect('<//>');
526
- return;
527
- }
528
-
529
- let prevTag = null;
530
-
531
- const co = new Coroutine(getStreamIterator(prettyGroupTags(tags)));
532
-
533
- for (;;) {
534
- co.advance();
535
-
536
- if (co.current instanceof Promise) {
537
- co.current = yield co.current;
538
- }
539
- if (co.done) break;
540
-
541
- const tag = co.value;
542
-
543
- if (tag.type === ReferenceTag && prevTag.type === NullTag) {
544
- yield buildWriteEffect(' ');
545
- }
546
-
547
- if (tag.type === 'Effect') {
548
- yield tag;
549
-
550
- continue;
551
- }
552
-
553
- if (tag.type === TokenGroup) {
554
- const intrinsicValue = getCooked(tag.value);
555
- yield buildWriteEffect(printSelfClosingNodeTag(tag.value[0], intrinsicValue));
556
- } else {
557
- yield buildWriteEffect(printTag(tag));
558
- }
559
-
560
- prevTag = tag;
561
- }
562
-
563
- yield buildWriteEffect('\n');
564
- }
565
-
566
- export const writeCSTMLStrategy = (tags, options = {}) =>
567
- new StreamIterable(__writeCSTMLStrategy(tags, options));
568
-
569
- function* __writePrettyCSTMLStrategy(tags, options) {
570
- let { indent = ' ', emitEffects = false, inline: inlineOption = true } = options;
571
-
572
- if (!tags) {
573
- yield buildWriteEffect('<//>');
574
- return;
575
- }
576
-
577
- const co = new Coroutine(getStreamIterator(prettyGroupTags(tags)));
578
- let indentLevel = 0;
579
- let first = true;
580
- let inline = false;
581
- let ref = null;
582
-
583
- for (;;) {
584
- co.advance();
585
-
586
- if (co.done) break;
587
-
588
- if (co.current instanceof Promise) {
589
- co.current = yield co.current;
590
- }
591
-
592
- const tag = co.value;
593
-
594
- if (tag.type === 'Effect') {
595
- const effect = tag.value;
596
- if (emitEffects && effect.verb === 'write') {
597
- const writeEffect = getEmbeddedObject(effect.value);
598
- yield buildWriteEffect(
599
- (first ? '' : '\n') + writeEffect.text,
600
- getEmbeddedObject(writeEffect.options),
601
- );
602
-
603
- inline = false;
604
- first = false;
605
- } else {
606
- yield tag;
607
- }
608
- continue;
609
- }
610
-
611
- inline =
612
- inlineOption &&
613
- inline &&
614
- ref &&
615
- (tag.type === NullTag ||
616
- tag.type === GapTag ||
617
- tag.type === ArrayInitializerTag ||
618
- tag.type === TokenGroup);
619
-
620
- if (!first && !inline) {
621
- yield buildWriteEffect('\n');
622
- }
623
-
624
- if (tag.type === CloseNodeTag) {
625
- ref = null;
626
- if (indentLevel === 0) {
627
- throw new Error('imbalanced tag stack');
628
- }
629
-
630
- indentLevel--;
631
- }
632
-
633
- if (!inline) {
634
- yield buildWriteEffect(indent.repeat(indentLevel));
635
- } else {
636
- yield buildWriteEffect(' ');
637
- }
638
-
639
- if (tag.type === TokenGroup) {
640
- ref = null;
641
- const intrinsicValue = tag.value[0].value.flags.token ? getCooked(tag.value) : null;
642
- yield buildWriteEffect(printSelfClosingNodeTag(tag.value[0], intrinsicValue));
643
- } else {
644
- yield buildWriteEffect(printTag(tag));
645
- }
646
-
647
- if (tag.type === ReferenceTag) {
648
- inline = true;
649
- ref = tag;
650
- }
651
-
652
- if (tag.type === OpenNodeTag) {
653
- indentLevel++;
654
- }
655
-
656
- first = false;
657
- }
658
-
659
- yield buildWriteEffect('\n');
660
- }
661
-
662
- export const writePrettyCSTMLStrategy = (tags, options = {}) => {
663
- return new StreamIterable(__writePrettyCSTMLStrategy(tags, options));
664
- };
665
-
666
452
  export const printPrettyCSTML = (tags, options = {}) => {
667
- return stringFromStream(generateStandardOutput(generatePrettyCSTML(tags, options)));
453
+ return stringFromStream(generatePrettyCSTML(tags, options));
668
454
  };
669
455
 
670
456
  export const getCooked = (tags) => {
package/lib/sumtree.js ADDED
@@ -0,0 +1,62 @@
1
+ import { buildModule, defaultNodeSize } from '@bablr/btree/enhanceable';
2
+ import { LiteralTag, ReferenceTag } from './symbols.js';
3
+
4
+ const { isArray } = Array;
5
+ const { freeze } = Object;
6
+
7
+ export { defaultNodeSize };
8
+
9
+ export const {
10
+ treeFrom,
11
+ treeFromValues,
12
+ findBalancePoint,
13
+ splitValues,
14
+ collapses,
15
+ nodeCollapses,
16
+ nodeCanDonate,
17
+ pop,
18
+ push,
19
+ addAt,
20
+ isValidNode,
21
+ assertValidNode,
22
+ getValues,
23
+ getSums,
24
+ setValues,
25
+ isLeafNode,
26
+ traverse,
27
+ getSize,
28
+ findPath,
29
+ getAt,
30
+ replaceAt,
31
+ } = buildModule(
32
+ defaultNodeSize,
33
+ (acc, val) => {
34
+ const { references } = acc;
35
+ if (isArray(val)) {
36
+ acc.lineBreaks += val[2].lineBreaks;
37
+ for (const { 0: key, 1: value } of Object.entries(val[2].references)) {
38
+ references[key] = (references[key] ?? 0) + value;
39
+ }
40
+ } else {
41
+ if (val.type === LiteralTag) {
42
+ let text = val.value;
43
+ let idx = 0;
44
+ while ((idx = text.indexOf('\n', idx + 1)) >= 0) {
45
+ acc.lineBreaks++;
46
+ }
47
+ } else if (val.type === ReferenceTag) {
48
+ const { name } = val.value;
49
+ references[name] = (references[name] ?? 0) + 1;
50
+ }
51
+ }
52
+ return acc;
53
+ },
54
+ () => ({
55
+ lineBreaks: 0,
56
+ references: {},
57
+ }),
58
+ (stats) => {
59
+ freeze(stats);
60
+ freeze(stats.references);
61
+ },
62
+ );
package/lib/symbols.js CHANGED
@@ -1,6 +1,3 @@
1
- export const node = Symbol.for('@bablr/node');
2
- export const fragment = Symbol.for('@bablr/fragment');
3
-
4
1
  export const DoctypeTag = Symbol.for('DoctypeTag');
5
2
  export const OpenNodeTag = Symbol.for('OpenNodeTag');
6
3
  export const CloseNodeTag = Symbol.for('CloseNodeTag');
@@ -8,13 +5,9 @@ export const ReferenceTag = Symbol.for('ReferenceTag');
8
5
  export const ShiftTag = Symbol.for('ShiftTag');
9
6
  export const GapTag = Symbol.for('GapTag');
10
7
  export const NullTag = Symbol.for('NullTag');
11
- export const ArrayInitializerTag = Symbol.for('ArrayInitializerTag');
8
+ export const InitializerTag = Symbol.for('InitializerTag');
12
9
  export const LiteralTag = Symbol.for('LiteralTag');
13
10
 
14
- export const EmbeddedNode = Symbol.for('EmbeddedNode');
15
- export const EmbeddedMatcher = Symbol.for('EmbeddedMatcher');
16
- export const EmbeddedRegex = Symbol.for('EmbeddedRegex');
17
- export const EmbeddedTag = Symbol.for('EmbeddedTag');
18
- export const EmbeddedObject = Symbol.for('EmbeddedObject');
19
-
20
11
  export const TokenGroup = Symbol.for('TokenGroup');
12
+
13
+ export const EmbeddedNode = Symbol.for('EmbeddedNode');
package/lib/template.js CHANGED
@@ -1,14 +1,14 @@
1
1
  import * as t from './builders.js';
2
2
  import {
3
3
  ReferenceTag,
4
- ArrayInitializerTag,
4
+ InitializerTag,
5
5
  OpenNodeTag,
6
6
  CloseNodeTag,
7
7
  DoctypeTag,
8
8
  EmbeddedNode,
9
9
  GapTag,
10
10
  } from './symbols.js';
11
- import * as btree from './btree.js';
11
+ import * as sumtree from './sumtree.js';
12
12
  import { getOpenTag, get, isFragmentNode } from './tree.js';
13
13
 
14
14
  const { freeze } = Object;
@@ -30,7 +30,7 @@ export function* interpolateFragment(node, ref, expressions) {
30
30
  if (!open.value.type) {
31
31
  let currentRef = null;
32
32
  let isFragment = isFragmentNode(node);
33
- for (let tag of btree.traverse(node.children)) {
33
+ for (let tag of sumtree.traverse(node.children)) {
34
34
  switch (tag.type) {
35
35
  case DoctypeTag: {
36
36
  break;
@@ -48,7 +48,7 @@ export function* interpolateFragment(node, ref, expressions) {
48
48
  break;
49
49
  }
50
50
 
51
- case ArrayInitializerTag: {
51
+ case InitializerTag: {
52
52
  const { name } = currentRef.value;
53
53
  counters.set(name, -1);
54
54
  if (name === '.') {