@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/builders.js +15 -63
- package/lib/path.js +285 -227
- package/lib/print.js +16 -43
- package/lib/shorthand.js +2 -2
- package/lib/stream.js +6 -220
- package/lib/sumtree.js +62 -0
- package/lib/symbols.js +3 -10
- package/lib/template.js +4 -4
- package/lib/tree.js +33 -242
- package/package.json +2 -1
package/lib/tree.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Coroutine } from '@bablr/coroutine';
|
|
2
|
-
import emptyStack from '@iter-tools/imm-stack';
|
|
3
2
|
import {
|
|
4
3
|
nodeFlags,
|
|
5
4
|
buildReferenceTag,
|
|
@@ -20,14 +19,14 @@ import {
|
|
|
20
19
|
OpenNodeTag,
|
|
21
20
|
CloseNodeTag,
|
|
22
21
|
ReferenceTag,
|
|
23
|
-
ShiftTag,
|
|
24
22
|
GapTag,
|
|
25
23
|
NullTag,
|
|
26
|
-
|
|
24
|
+
InitializerTag,
|
|
27
25
|
LiteralTag,
|
|
28
26
|
EmbeddedNode,
|
|
29
27
|
} from './symbols.js';
|
|
30
28
|
import * as btree from './btree.js';
|
|
29
|
+
import * as sumtree from './sumtree.js';
|
|
31
30
|
export * from './builders.js';
|
|
32
31
|
export * from './print.js';
|
|
33
32
|
import {
|
|
@@ -40,6 +39,7 @@ import {
|
|
|
40
39
|
isGapNode,
|
|
41
40
|
getOpenTag,
|
|
42
41
|
getCloseTag,
|
|
42
|
+
getShifted,
|
|
43
43
|
} from './path.js';
|
|
44
44
|
|
|
45
45
|
export { add, get, isFragmentNode, isNullNode, isGapNode, getOpenTag, getCloseTag };
|
|
@@ -92,8 +92,9 @@ export const mergeReferences = (outer, inner) => {
|
|
|
92
92
|
inner.value.name != null &&
|
|
93
93
|
inner.value.name !== '.' &&
|
|
94
94
|
name !== inner.value.name
|
|
95
|
-
)
|
|
96
|
-
|
|
95
|
+
) {
|
|
96
|
+
return inner;
|
|
97
|
+
}
|
|
97
98
|
|
|
98
99
|
isArray = isArray || inner.value.isArray;
|
|
99
100
|
expression = !!(expression || inner.value.flags.expression);
|
|
@@ -108,6 +109,20 @@ export const isEmptyReference = (ref) => {
|
|
|
108
109
|
return name === '.' && !isArray && !(flags.expression || flags.hasGap);
|
|
109
110
|
};
|
|
110
111
|
|
|
112
|
+
export const defineAttribute = (node, key, value) => {
|
|
113
|
+
const openTag = getOpenTag(node);
|
|
114
|
+
|
|
115
|
+
if (value != null) {
|
|
116
|
+
const { flags, language, type } = openTag.value;
|
|
117
|
+
const attributes = { ...openTag.value.attributes, [key]: value };
|
|
118
|
+
const newOpenTag = buildOpenNodeTag(flags, language, type, attributes);
|
|
119
|
+
|
|
120
|
+
node.attributes = attributes;
|
|
121
|
+
|
|
122
|
+
node.children = sumtree.replaceAt(0, node.children, newOpenTag);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
111
126
|
function* __treeFromStream(tags, options) {
|
|
112
127
|
let path = null;
|
|
113
128
|
let rootPath = null;
|
|
@@ -155,7 +170,7 @@ function* __treeFromStream(tags, options) {
|
|
|
155
170
|
break;
|
|
156
171
|
}
|
|
157
172
|
|
|
158
|
-
case
|
|
173
|
+
case InitializerTag: {
|
|
159
174
|
add(path.node, reference, []);
|
|
160
175
|
suppressTag = true;
|
|
161
176
|
reference = null;
|
|
@@ -198,7 +213,7 @@ function* __treeFromStream(tags, options) {
|
|
|
198
213
|
|
|
199
214
|
let reference;
|
|
200
215
|
|
|
201
|
-
for (const tag of
|
|
216
|
+
for (const tag of sumtree.traverse(node.children)) {
|
|
202
217
|
switch (tag.type) {
|
|
203
218
|
case DoctypeTag: {
|
|
204
219
|
break;
|
|
@@ -218,7 +233,7 @@ function* __treeFromStream(tags, options) {
|
|
|
218
233
|
reference = tag;
|
|
219
234
|
break;
|
|
220
235
|
|
|
221
|
-
case
|
|
236
|
+
case InitializerTag: {
|
|
222
237
|
add(parentNode, mergeReferences(outerReference, reference), []);
|
|
223
238
|
break;
|
|
224
239
|
}
|
|
@@ -229,7 +244,7 @@ function* __treeFromStream(tags, options) {
|
|
|
229
244
|
}
|
|
230
245
|
|
|
231
246
|
case GapTag: {
|
|
232
|
-
const resolvedNode =
|
|
247
|
+
const resolvedNode = getShifted(shift, reference, node);
|
|
233
248
|
add(parentNode, mergeReferences(outerReference, reference), resolvedNode);
|
|
234
249
|
break;
|
|
235
250
|
}
|
|
@@ -324,7 +339,7 @@ function* __treeFromStream(tags, options) {
|
|
|
324
339
|
}
|
|
325
340
|
|
|
326
341
|
if (!suppressTag) {
|
|
327
|
-
path.node.children =
|
|
342
|
+
path.node.children = sumtree.push(path.node.children, tag);
|
|
328
343
|
}
|
|
329
344
|
|
|
330
345
|
switch (tag.type) {
|
|
@@ -395,7 +410,7 @@ export const isEmpty = (node) => {
|
|
|
395
410
|
|
|
396
411
|
let ref = null;
|
|
397
412
|
|
|
398
|
-
for (const tag of
|
|
413
|
+
for (const tag of sumtree.traverse(node.children)) {
|
|
399
414
|
switch (tag.type) {
|
|
400
415
|
case ReferenceTag: {
|
|
401
416
|
const { name } = tag.value;
|
|
@@ -444,9 +459,9 @@ export const buildStubNode = (tag) => {
|
|
|
444
459
|
|
|
445
460
|
function* __streamFromTree(rootNode, options) {
|
|
446
461
|
const { unshift = false } = options;
|
|
447
|
-
if (!rootNode || !
|
|
462
|
+
if (!rootNode || !sumtree.getSize(rootNode.children)) return;
|
|
448
463
|
|
|
449
|
-
let tagPath = TagPath.
|
|
464
|
+
let tagPath = TagPath.fromNode(rootNode, 0);
|
|
450
465
|
|
|
451
466
|
let count = 0;
|
|
452
467
|
|
|
@@ -474,7 +489,7 @@ export const getCooked = (cookable) => {
|
|
|
474
489
|
|
|
475
490
|
let reference = null;
|
|
476
491
|
|
|
477
|
-
for (const tag of
|
|
492
|
+
for (const tag of sumtree.traverse(children)) {
|
|
478
493
|
switch (tag.type) {
|
|
479
494
|
case ReferenceTag: {
|
|
480
495
|
const { name } = tag.value;
|
|
@@ -540,7 +555,8 @@ export const sourceTextFor = printSource;
|
|
|
540
555
|
|
|
541
556
|
export const getRange = (node) => {
|
|
542
557
|
const { children } = node;
|
|
543
|
-
|
|
558
|
+
let path = Path.from(node);
|
|
559
|
+
return sumtree.getSize(children) ? [TagPath.from(path, 0), TagPath.from(path, -1)] : null;
|
|
544
560
|
};
|
|
545
561
|
|
|
546
562
|
export const createNode = (openTag) => {
|
|
@@ -560,26 +576,7 @@ export const createNode = (openTag) => {
|
|
|
560
576
|
};
|
|
561
577
|
|
|
562
578
|
export const finalizeNode = (node) => {
|
|
563
|
-
for (const property of Object.values(node.properties)) {
|
|
564
|
-
if (isArray(property)) {
|
|
565
|
-
btree.freeze(property);
|
|
566
|
-
for (const childProperty of btree.traverse(property)) {
|
|
567
|
-
freeze(childProperty);
|
|
568
|
-
if (childProperty.reference.value.flags.expression) {
|
|
569
|
-
btree.freeze(childProperty.node);
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
} else {
|
|
573
|
-
freeze(property);
|
|
574
|
-
|
|
575
|
-
if (property.reference.value.flags.expression) {
|
|
576
|
-
btree.freeze(property.node);
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
|
|
581
579
|
freeze(node);
|
|
582
|
-
btree.freeze(node.children);
|
|
583
580
|
freeze(node.properties);
|
|
584
581
|
freeze(node.attributes);
|
|
585
582
|
return node;
|
|
@@ -598,7 +595,7 @@ export const branchProperties = (properties) => {
|
|
|
598
595
|
|
|
599
596
|
for (const { 0: key, 1: value } of Object.entries(copy)) {
|
|
600
597
|
if (isArray(value)) {
|
|
601
|
-
copy[key] = btree.
|
|
598
|
+
copy[key] = btree.treeFromValues(value);
|
|
602
599
|
}
|
|
603
600
|
}
|
|
604
601
|
|
|
@@ -611,8 +608,7 @@ export const branchNode = (node) => {
|
|
|
611
608
|
flags,
|
|
612
609
|
language,
|
|
613
610
|
type,
|
|
614
|
-
|
|
615
|
-
children: btree.fromValues(btree.traverse(children)),
|
|
611
|
+
children,
|
|
616
612
|
properties: branchProperties(properties),
|
|
617
613
|
attributes: { ...attributes },
|
|
618
614
|
};
|
|
@@ -645,208 +641,3 @@ export function* traverseProperties(properties) {
|
|
|
645
641
|
}
|
|
646
642
|
}
|
|
647
643
|
}
|
|
648
|
-
|
|
649
|
-
export class Resolver {
|
|
650
|
-
constructor(
|
|
651
|
-
states = emptyStack.push({ properties: new Map(), idx: 0 }),
|
|
652
|
-
reference = null,
|
|
653
|
-
popped = false,
|
|
654
|
-
held = null,
|
|
655
|
-
) {
|
|
656
|
-
this.states = states;
|
|
657
|
-
this.reference = reference;
|
|
658
|
-
this.popped = popped;
|
|
659
|
-
this.held = held;
|
|
660
|
-
this.doctype = null;
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
get idx() {
|
|
664
|
-
return this.states.value.idx;
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
get properties() {
|
|
668
|
-
return this.states.value.properties;
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
advance(tag) {
|
|
672
|
-
const { states } = this;
|
|
673
|
-
|
|
674
|
-
++states.value.idx;
|
|
675
|
-
|
|
676
|
-
this.popped = false;
|
|
677
|
-
|
|
678
|
-
let hadReference = this.reference;
|
|
679
|
-
|
|
680
|
-
switch (tag.type) {
|
|
681
|
-
case ReferenceTag: {
|
|
682
|
-
const { name, isArray } = tag.value;
|
|
683
|
-
const { properties } = states.value;
|
|
684
|
-
|
|
685
|
-
if (this.reference) throw new Error();
|
|
686
|
-
|
|
687
|
-
this.reference = tag;
|
|
688
|
-
|
|
689
|
-
if (name && name !== '#' && name !== '@') {
|
|
690
|
-
let state = properties.get(name);
|
|
691
|
-
|
|
692
|
-
if (isArray) {
|
|
693
|
-
if (state && !state.isArray) throw new Error();
|
|
694
|
-
|
|
695
|
-
const { count = -1 } = state || {};
|
|
696
|
-
|
|
697
|
-
state = { count: count + 1, isArray };
|
|
698
|
-
} else if (state) {
|
|
699
|
-
throw new Error(`attempted to consume property {name: ${name}} twice`);
|
|
700
|
-
} else {
|
|
701
|
-
state = { count: 1, isArray: false };
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
properties.set(name, state);
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
break;
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
case EmbeddedNode: {
|
|
711
|
-
if (!this.reference || !['#', '@'].includes(this.reference.value.name)) throw new Error();
|
|
712
|
-
|
|
713
|
-
// this.states = states.push({ properties: new Map(), idx: 0 });
|
|
714
|
-
break;
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
case OpenNodeTag: {
|
|
718
|
-
const { reference } = this;
|
|
719
|
-
const { flags } = tag.value;
|
|
720
|
-
const isRootNode = states.size === 1;
|
|
721
|
-
|
|
722
|
-
if (tag.value.type) {
|
|
723
|
-
this.states = states.push({ properties: new Map(), idx: 0 });
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
if (!tag.value.type && (!isRootNode || this.reference)) throw new Error();
|
|
727
|
-
|
|
728
|
-
if (
|
|
729
|
-
tag.type === OpenNodeTag &&
|
|
730
|
-
((!reference && !isRootNode) ||
|
|
731
|
-
(reference &&
|
|
732
|
-
reference.type !== ReferenceTag &&
|
|
733
|
-
reference.type !== ShiftTag &&
|
|
734
|
-
reference.type !== OpenNodeTag))
|
|
735
|
-
) {
|
|
736
|
-
throw new Error('Invalid location for OpenNodeTag');
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
if (!isRootNode && !reference) {
|
|
740
|
-
throw new Error();
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
this.reference = null;
|
|
744
|
-
break;
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
case ArrayInitializerTag: {
|
|
748
|
-
if (!this.reference) throw new Error();
|
|
749
|
-
|
|
750
|
-
const { name } = this.reference.value;
|
|
751
|
-
const { properties } = states.value;
|
|
752
|
-
const state = properties.get(name);
|
|
753
|
-
|
|
754
|
-
if (!state || !state.isArray || state.count !== 0) throw new Error();
|
|
755
|
-
|
|
756
|
-
properties.set(name, { count: 0, isArray: true });
|
|
757
|
-
|
|
758
|
-
this.reference = null;
|
|
759
|
-
break;
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
case ShiftTag: {
|
|
763
|
-
this.held = this.states.value;
|
|
764
|
-
this.states = this.states.push({ properties: new Map(), idx: 0 });
|
|
765
|
-
this.reference = tag;
|
|
766
|
-
|
|
767
|
-
break;
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
case NullTag: {
|
|
771
|
-
if (!this.reference) throw new Error();
|
|
772
|
-
|
|
773
|
-
this.popped = true;
|
|
774
|
-
this.reference = null;
|
|
775
|
-
break;
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
case GapTag: {
|
|
779
|
-
// if (!this.reference) throw new Error();
|
|
780
|
-
|
|
781
|
-
if (this.held) {
|
|
782
|
-
// this.states = this.states.push(this.held);
|
|
783
|
-
this.held = null;
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
this.popped = true;
|
|
787
|
-
this.reference = null;
|
|
788
|
-
break;
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
case CloseNodeTag: {
|
|
792
|
-
if (this.reference) throw new Error();
|
|
793
|
-
|
|
794
|
-
this.states = states.pop();
|
|
795
|
-
this.popped = true;
|
|
796
|
-
break;
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
case DoctypeTag:
|
|
800
|
-
this.doctype = tag;
|
|
801
|
-
break;
|
|
802
|
-
|
|
803
|
-
case LiteralTag:
|
|
804
|
-
break;
|
|
805
|
-
|
|
806
|
-
default:
|
|
807
|
-
throw new Error();
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
if (hadReference && this.reference) throw new Error();
|
|
811
|
-
|
|
812
|
-
return this;
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
resolve(reference) {
|
|
816
|
-
let { name, isArray, flags } = reference.value;
|
|
817
|
-
const { states } = this;
|
|
818
|
-
const state = states.value.properties.get(name);
|
|
819
|
-
let index = null;
|
|
820
|
-
|
|
821
|
-
if (name === '@' || name === '#') return reference;
|
|
822
|
-
|
|
823
|
-
if (isArray && state) {
|
|
824
|
-
index = state?.count || 0;
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
return buildReferenceTag(name, isArray, flags, index);
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
branch() {
|
|
831
|
-
const { states, reference, popped, held } = this;
|
|
832
|
-
const { properties, idx } = states.value;
|
|
833
|
-
|
|
834
|
-
return new Resolver(
|
|
835
|
-
states.replace({ properties: new Map(properties), idx }),
|
|
836
|
-
reference,
|
|
837
|
-
popped,
|
|
838
|
-
held,
|
|
839
|
-
);
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
accept(resolver) {
|
|
843
|
-
this.states = resolver.states;
|
|
844
|
-
this.reference = resolver.reference;
|
|
845
|
-
this.popped = resolver.popped;
|
|
846
|
-
this.held = resolver.held;
|
|
847
|
-
|
|
848
|
-
return this;
|
|
849
|
-
}
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
freeze(Resolver.prototype);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bablr/agast-helpers",
|
|
3
3
|
"description": "Helper functions for working with agAST trees",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.7.0",
|
|
5
5
|
"author": "Conrad Buck<conartist6@gmail.com>",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"files": [
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"./print": "./lib/print.js",
|
|
15
15
|
"./shorthand": "./lib/shorthand.js",
|
|
16
16
|
"./stream": "./lib/stream.js",
|
|
17
|
+
"./sumtree": "./lib/sumtree.js",
|
|
17
18
|
"./symbols": "./lib/symbols.js",
|
|
18
19
|
"./template": "./lib/template.js",
|
|
19
20
|
"./tree": "./lib/tree.js"
|