@bablr/agast-helpers 0.9.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 +148 -95
- package/lib/path.js +1303 -437
- package/lib/print.js +66 -43
- package/lib/shorthand.js +17 -13
- package/lib/stream.js +433 -32
- package/lib/symbols.js +3 -2
- package/lib/tags.js +106 -57
- package/lib/template.js +44 -42
- package/lib/tree.js +59 -513
- package/package.json +3 -3
- package/lib/path-facade.js +0 -44
package/lib/tags.js
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import { buildModule, defaultNodeSize } from '@bablr/btree/enhanceable';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
AttributeDefinition,
|
|
4
|
+
CloseNodeTag,
|
|
5
|
+
GapNode,
|
|
6
|
+
GapTag,
|
|
7
|
+
LiteralTag,
|
|
8
|
+
OpenNodeTag,
|
|
9
|
+
Property,
|
|
10
|
+
ReferenceTag,
|
|
11
|
+
ShiftTag,
|
|
12
|
+
} from './symbols.js';
|
|
3
13
|
import { isObject } from './object.js';
|
|
14
|
+
import { referenceIsSingular } from './path.js';
|
|
15
|
+
import { buildReference } from './builders.js';
|
|
4
16
|
|
|
5
17
|
const { isArray } = Array;
|
|
6
18
|
const { freeze } = Object;
|
|
@@ -35,61 +47,89 @@ export const getAtName = (name, sortedArray, startIdx = 0, endIdx = sortedArray.
|
|
|
35
47
|
|
|
36
48
|
export const compareNames = (a, b) => (a > b ? 1 : b > a ? -1 : 0);
|
|
37
49
|
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
50
|
+
export const sumValues = (values) => {
|
|
51
|
+
let mapStats = values.reduce(
|
|
52
|
+
(acc, val) => {
|
|
53
|
+
const { references, specialTypes } = acc;
|
|
54
|
+
if (isArray(val)) {
|
|
55
|
+
acc.lineBreaks += getSums(val).lineBreaks;
|
|
56
|
+
acc.gaps += getSums(val).gaps;
|
|
44
57
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
58
|
+
let arrs = [
|
|
59
|
+
[getSums(val).references, references],
|
|
60
|
+
[getSums(val).specialTypes, specialTypes],
|
|
61
|
+
];
|
|
48
62
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
63
|
+
for (let { 0: arr, 1: map } of arrs) {
|
|
64
|
+
for (const { 0: key, 1: value, 2: reference } of arr) {
|
|
65
|
+
let count = map.get(key)?.[1] ?? 0;
|
|
66
|
+
|
|
67
|
+
if (!reference.flags.array && referenceIsSingular(reference) && count > 0)
|
|
68
|
+
throw new Error();
|
|
69
|
+
|
|
70
|
+
map.set(key, freeze([key, count + value, reference]));
|
|
71
|
+
}
|
|
58
72
|
}
|
|
59
|
-
} else if (val
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
73
|
+
} else if (val) {
|
|
74
|
+
if (val.type === LiteralTag) {
|
|
75
|
+
let text = val.value;
|
|
76
|
+
let idx = 0;
|
|
77
|
+
while ((idx = text.indexOf('\n', idx + 1)) >= 0) {
|
|
78
|
+
acc.lineBreaks++;
|
|
79
|
+
}
|
|
80
|
+
} else if (val.type === GapTag) {
|
|
81
|
+
acc.gaps++;
|
|
82
|
+
} else if (val.type === Property) {
|
|
83
|
+
let { tags } = val.value;
|
|
84
|
+
let refOrShiftTag = tags[0];
|
|
85
|
+
|
|
86
|
+
if (tags[2]) {
|
|
87
|
+
acc.gaps += tags[2].value.tags[2].gaps;
|
|
88
|
+
}
|
|
89
|
+
if (refOrShiftTag?.type !== ShiftTag) {
|
|
90
|
+
let ref = refOrShiftTag?.value || buildReference();
|
|
91
|
+
const { type, name } = ref;
|
|
92
|
+
|
|
93
|
+
if (name) {
|
|
94
|
+
let count = references.get(name)?.[1] ?? 0;
|
|
95
|
+
|
|
96
|
+
if (!ref.flags.array && referenceIsSingular(ref) && count > 0) throw new Error();
|
|
97
|
+
|
|
98
|
+
references.set(name, freeze([name, count + 1, ref]));
|
|
99
|
+
} else {
|
|
100
|
+
let count = specialTypes.get(type)?.[1] ?? 0;
|
|
101
|
+
|
|
102
|
+
if (!ref.flags.array && referenceIsSingular(ref) && count > 0) throw new Error();
|
|
103
|
+
|
|
104
|
+
specialTypes.set(type, freeze([type, count + 1, ref]));
|
|
105
|
+
}
|
|
69
106
|
}
|
|
70
107
|
}
|
|
71
108
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
109
|
+
return acc;
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
gaps: 0,
|
|
113
|
+
lineBreaks: 0,
|
|
114
|
+
references: new Map(),
|
|
115
|
+
specialTypes: new Map(),
|
|
116
|
+
},
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
let { lineBreaks, gaps } = mapStats;
|
|
120
|
+
let stats = {
|
|
121
|
+
gaps,
|
|
122
|
+
lineBreaks,
|
|
123
|
+
references: [...mapStats.references.values()].sort((a, b) => compareNames(a[0], b[0])),
|
|
124
|
+
specialTypes: [...mapStats.specialTypes.values()].sort((a, b) => compareNames(a[0], b[0])),
|
|
125
|
+
};
|
|
126
|
+
freeze(stats);
|
|
127
|
+
freeze(stats.references);
|
|
128
|
+
freeze(stats.specialTypes);
|
|
129
|
+
return stats;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const module_ = buildModule(defaultNodeSize, sumValues);
|
|
93
133
|
|
|
94
134
|
const {
|
|
95
135
|
from,
|
|
@@ -105,15 +145,24 @@ const {
|
|
|
105
145
|
findPath,
|
|
106
146
|
} = module_;
|
|
107
147
|
|
|
108
|
-
const getAt = (idx, tags,
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
148
|
+
const getAt = (idx, tags, propertyIndex) => {
|
|
149
|
+
if (propertyIndex !== undefined) {
|
|
150
|
+
throw new Error('propertyIndex');
|
|
151
|
+
}
|
|
152
|
+
return module_.getAt(idx, tags);
|
|
113
153
|
};
|
|
114
154
|
|
|
115
155
|
const push = (tags, tag) => {
|
|
116
156
|
let firstTag = getAt(0, tags);
|
|
157
|
+
|
|
158
|
+
if (
|
|
159
|
+
!Array.isArray(tag) &&
|
|
160
|
+
![OpenNodeTag, Property, CloseNodeTag, AttributeDefinition, LiteralTag, GapTag].includes(
|
|
161
|
+
tag.type,
|
|
162
|
+
)
|
|
163
|
+
)
|
|
164
|
+
throw new Error();
|
|
165
|
+
|
|
117
166
|
if (isArray(tag)) {
|
|
118
167
|
if (!firstTag || firstTag.type !== OpenNodeTag) {
|
|
119
168
|
return module_.concat(tags, tag);
|
|
@@ -208,8 +257,8 @@ const removeAt = (idx, tree) => {
|
|
|
208
257
|
|
|
209
258
|
function* traverseInner(tree) {
|
|
210
259
|
for (let tag of module_.traverse(tree)) {
|
|
211
|
-
if (tag.type ===
|
|
212
|
-
yield* tag.value.tags;
|
|
260
|
+
if (tag.type === Property) {
|
|
261
|
+
yield* module_.traverse(tag.value.tags);
|
|
213
262
|
} else {
|
|
214
263
|
yield tag;
|
|
215
264
|
}
|
package/lib/template.js
CHANGED
|
@@ -1,15 +1,8 @@
|
|
|
1
1
|
import * as t from './builders.js';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
InitializerTag,
|
|
5
|
-
OpenNodeTag,
|
|
6
|
-
CloseNodeTag,
|
|
7
|
-
DoctypeTag,
|
|
8
|
-
Property,
|
|
9
|
-
BindingTag,
|
|
10
|
-
} from './symbols.js';
|
|
2
|
+
import { getTags, isMultiFragment, Path } from './path.js';
|
|
3
|
+
import { OpenNodeTag, CloseNodeTag, DoctypeTag, Property, GapNode } from './symbols.js';
|
|
11
4
|
import * as Tags from './tags.js';
|
|
12
|
-
import { getOpenTag,
|
|
5
|
+
import { getOpenTag, isNull } from './tree.js';
|
|
13
6
|
|
|
14
7
|
const { freeze } = Object;
|
|
15
8
|
|
|
@@ -18,67 +11,76 @@ export const buildFilledGapFunction = (expressions) => (value) => {
|
|
|
18
11
|
return t.buildGapTag();
|
|
19
12
|
};
|
|
20
13
|
|
|
14
|
+
export const interpolate = (node, expressions) => {
|
|
15
|
+
let path = Path.from(node);
|
|
16
|
+
|
|
17
|
+
outer: for (let expression of expressions) {
|
|
18
|
+
let i = 0;
|
|
19
|
+
do {
|
|
20
|
+
path = path.atDepth(0);
|
|
21
|
+
let tag;
|
|
22
|
+
while ((tag = Tags.getAt(i, getTags(path.node)))) {
|
|
23
|
+
if (path.node.type === GapNode) {
|
|
24
|
+
path = path.replaceWith(expression);
|
|
25
|
+
continue outer;
|
|
26
|
+
} else if (tag.type === Property && tag.value.tags[2]) {
|
|
27
|
+
let tags = getTags(tag.value.tags[2]);
|
|
28
|
+
if (tags[2].gaps) {
|
|
29
|
+
path = path.push(i);
|
|
30
|
+
i = 0;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
i++;
|
|
35
|
+
}
|
|
36
|
+
i = path.parent?.tagsIndex + 1;
|
|
37
|
+
path = path.parent;
|
|
38
|
+
} while (path.depth);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return path.atDepth(0).node;
|
|
42
|
+
};
|
|
43
|
+
|
|
21
44
|
export const interpolateFragment = (node, ref, expressions) => {
|
|
22
45
|
return __interpolateFragment(node, ref, expressions);
|
|
23
46
|
};
|
|
24
47
|
|
|
25
48
|
function* __interpolateFragment(node, ref, expressions) {
|
|
49
|
+
if (isNull(node)) return;
|
|
50
|
+
|
|
26
51
|
const open = getOpenTag(node);
|
|
27
52
|
|
|
28
53
|
const gap = buildFilledGapFunction(expressions);
|
|
29
54
|
|
|
30
|
-
if (!open.value.
|
|
31
|
-
let
|
|
32
|
-
let
|
|
33
|
-
let isFragment = isFragmentNode(node);
|
|
34
|
-
for (let tag of Tags.traverseInner(node.tags)) {
|
|
55
|
+
if (!open.value.name) {
|
|
56
|
+
let isMultiFragment_ = isMultiFragment(node);
|
|
57
|
+
for (let tag of Tags.traverse(getTags(node))) {
|
|
35
58
|
switch (tag.type) {
|
|
36
59
|
case DoctypeTag: {
|
|
37
60
|
break;
|
|
38
61
|
}
|
|
39
62
|
case OpenNodeTag:
|
|
40
63
|
case CloseNodeTag: {
|
|
41
|
-
if (!
|
|
64
|
+
if (!isMultiFragment_) {
|
|
42
65
|
yield tag;
|
|
43
66
|
}
|
|
44
67
|
break;
|
|
45
68
|
}
|
|
46
69
|
|
|
47
|
-
case ReferenceTag: {
|
|
48
|
-
currentRef = tag;
|
|
49
|
-
break;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
case BindingTag: {
|
|
53
|
-
currentBinding = tag;
|
|
54
|
-
break;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
case InitializerTag: {
|
|
58
|
-
const { type } = currentRef.value;
|
|
59
|
-
if (type === '.') {
|
|
60
|
-
yield freeze(ref);
|
|
61
|
-
} else {
|
|
62
|
-
yield currentRef;
|
|
63
|
-
}
|
|
64
|
-
yield tag;
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
70
|
case Property: {
|
|
69
|
-
let { reference } = tag.value;
|
|
71
|
+
let { reference, node, tags } = tag.value;
|
|
70
72
|
const { type } = reference;
|
|
71
73
|
|
|
72
|
-
if (type === '
|
|
74
|
+
if (type === '_') {
|
|
73
75
|
// TODO check/combine flags
|
|
74
76
|
yield ref;
|
|
75
77
|
} else {
|
|
76
|
-
yield
|
|
78
|
+
yield tags[0];
|
|
77
79
|
}
|
|
78
80
|
|
|
79
|
-
yield
|
|
81
|
+
yield* tags[1];
|
|
80
82
|
|
|
81
|
-
yield gap(
|
|
83
|
+
yield gap(node);
|
|
82
84
|
|
|
83
85
|
break;
|
|
84
86
|
}
|