@bablr/agast-helpers 0.7.1 → 0.9.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 +110 -49
- package/lib/object.js +86 -0
- package/lib/path-facade.js +44 -0
- package/lib/path.js +780 -556
- package/lib/print.js +75 -97
- package/lib/shorthand.js +26 -1
- package/lib/stream.js +55 -163
- package/lib/symbols.js +6 -2
- package/lib/tags.js +236 -0
- package/lib/template.js +28 -37
- package/lib/tree.js +391 -213
- package/package.json +11 -6
- package/lib/sumtree.js +0 -62
package/lib/tags.js
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { buildModule, defaultNodeSize } from '@bablr/btree/enhanceable';
|
|
2
|
+
import { CloseNodeTag, LiteralTag, OpenNodeTag, PropertyWrapper, ReferenceTag } from './symbols.js';
|
|
3
|
+
import { isObject } from './object.js';
|
|
4
|
+
|
|
5
|
+
const { isArray } = Array;
|
|
6
|
+
const { freeze } = Object;
|
|
7
|
+
|
|
8
|
+
export { defaultNodeSize };
|
|
9
|
+
|
|
10
|
+
const __getAtName = (name, sortedArray, startIdx = 0, endIdx = sortedArray.length - 1) => {
|
|
11
|
+
if (!sortedArray.length || endIdx < startIdx) return null;
|
|
12
|
+
|
|
13
|
+
let idx = startIdx + Math.floor((endIdx - startIdx) / 2 + 0.1);
|
|
14
|
+
let entry = sortedArray[idx];
|
|
15
|
+
let { 0: key, 1: value } = entry;
|
|
16
|
+
|
|
17
|
+
let direction = compareNames(name, key);
|
|
18
|
+
|
|
19
|
+
if (direction === 0) {
|
|
20
|
+
return value;
|
|
21
|
+
} else {
|
|
22
|
+
if (startIdx === endIdx) return null;
|
|
23
|
+
|
|
24
|
+
if (direction > 0) {
|
|
25
|
+
return __getAtName(name, sortedArray, idx + 1, endIdx);
|
|
26
|
+
} else {
|
|
27
|
+
return __getAtName(name, sortedArray, startIdx, idx - 1);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const getAtName = (name, sortedArray, startIdx = 0, endIdx = sortedArray.length - 1) => {
|
|
33
|
+
return __getAtName(name, sortedArray, startIdx, endIdx);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const compareNames = (a, b) => (a > b ? 1 : b > a ? -1 : 0);
|
|
37
|
+
|
|
38
|
+
const module_ = buildModule(
|
|
39
|
+
defaultNodeSize,
|
|
40
|
+
(acc, val) => {
|
|
41
|
+
const { references, specialTypes } = acc;
|
|
42
|
+
if (isArray(val)) {
|
|
43
|
+
acc.lineBreaks += getSums(val).lineBreaks;
|
|
44
|
+
|
|
45
|
+
for (const { 0: key, 1: value } of getSums(val).references) {
|
|
46
|
+
references.set(key, (references.get(key) ?? 0) + value);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
for (const { 0: key, 1: value } of getSums(val).specialTypes) {
|
|
50
|
+
specialTypes.set(key, (specialTypes.get(key) ?? 0) + value);
|
|
51
|
+
}
|
|
52
|
+
} else if (val) {
|
|
53
|
+
if (val.type === LiteralTag) {
|
|
54
|
+
let text = val.value;
|
|
55
|
+
let idx = 0;
|
|
56
|
+
while ((idx = text.indexOf('\n', idx + 1)) >= 0) {
|
|
57
|
+
acc.lineBreaks++;
|
|
58
|
+
}
|
|
59
|
+
} else if (val.type === PropertyWrapper) {
|
|
60
|
+
let { tags } = val.value;
|
|
61
|
+
let refOrShiftTag = tags[0];
|
|
62
|
+
|
|
63
|
+
if (refOrShiftTag.type === ReferenceTag) {
|
|
64
|
+
const { type, name } = refOrShiftTag.value;
|
|
65
|
+
if (name) {
|
|
66
|
+
references.set(name, (references.get(name) ?? 0) + 1);
|
|
67
|
+
} else {
|
|
68
|
+
specialTypes.set(type, (specialTypes.get(type) ?? 0) + 1);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return acc;
|
|
74
|
+
},
|
|
75
|
+
() => ({
|
|
76
|
+
lineBreaks: 0,
|
|
77
|
+
references: new Map(),
|
|
78
|
+
specialTypes: new Map(),
|
|
79
|
+
}),
|
|
80
|
+
(mapStats) => {
|
|
81
|
+
let { lineBreaks } = mapStats;
|
|
82
|
+
let stats = {
|
|
83
|
+
lineBreaks,
|
|
84
|
+
references: [...mapStats.references].sort((a, b) => compareNames(a[0], b[0])),
|
|
85
|
+
specialTypes: [...mapStats.specialTypes].sort((a, b) => compareNames(a[0], b[0])),
|
|
86
|
+
};
|
|
87
|
+
freeze(stats);
|
|
88
|
+
freeze(stats.references);
|
|
89
|
+
freeze(stats.specialTypes);
|
|
90
|
+
return stats;
|
|
91
|
+
},
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
const {
|
|
95
|
+
from,
|
|
96
|
+
fromValues,
|
|
97
|
+
addAt,
|
|
98
|
+
isValidNode,
|
|
99
|
+
assertValidNode,
|
|
100
|
+
getValues,
|
|
101
|
+
getSums,
|
|
102
|
+
setValues,
|
|
103
|
+
traverse,
|
|
104
|
+
getSize,
|
|
105
|
+
findPath,
|
|
106
|
+
} = module_;
|
|
107
|
+
|
|
108
|
+
const getAt = (idx, tags, wrapperIndex) => {
|
|
109
|
+
let result = module_.getAt(idx, tags);
|
|
110
|
+
return wrapperIndex == null || result?.type !== PropertyWrapper
|
|
111
|
+
? result
|
|
112
|
+
: result.value.tags[wrapperIndex];
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const push = (tags, tag) => {
|
|
116
|
+
let firstTag = getAt(0, tags);
|
|
117
|
+
if (isArray(tag)) {
|
|
118
|
+
if (!firstTag || firstTag.type !== OpenNodeTag) {
|
|
119
|
+
return module_.concat(tags, tag);
|
|
120
|
+
}
|
|
121
|
+
let children = getValues(tags)[1] ?? module_.fromValues([]);
|
|
122
|
+
|
|
123
|
+
let { 0: open } = getValues(tags);
|
|
124
|
+
|
|
125
|
+
children = module_.concat(children, tag);
|
|
126
|
+
|
|
127
|
+
return module_.fromValues([open, children]);
|
|
128
|
+
} else {
|
|
129
|
+
if (tag.type === OpenNodeTag) {
|
|
130
|
+
if (getSize(tags) !== 0) throw new Error();
|
|
131
|
+
return module_.push(tags, tag);
|
|
132
|
+
} else {
|
|
133
|
+
if (!firstTag || firstTag.type !== OpenNodeTag) {
|
|
134
|
+
return module_.push(tags, tag);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
let children = getValues(tags)[1] ?? [];
|
|
138
|
+
|
|
139
|
+
// sometimes this is the top level
|
|
140
|
+
if (firstTag) {
|
|
141
|
+
if (tag.type === CloseNodeTag) {
|
|
142
|
+
let { 0: open, 1: children = module_.fromValues([]) } = getValues(tags);
|
|
143
|
+
|
|
144
|
+
return module_.fromValues([open, children, tag]);
|
|
145
|
+
} else {
|
|
146
|
+
let { 0: open } = getValues(tags);
|
|
147
|
+
|
|
148
|
+
children = module_.push(children, tag);
|
|
149
|
+
|
|
150
|
+
return module_.fromValues([open, children]);
|
|
151
|
+
}
|
|
152
|
+
} else {
|
|
153
|
+
return module_.push(tags, tag);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const replaceAt = (idx, tree, value) => {
|
|
160
|
+
let idx_ = idx < 0 ? getSize(tree) + idx : idx;
|
|
161
|
+
|
|
162
|
+
if (value.type !== getAt(idx_, tree).type) throw new Error();
|
|
163
|
+
let firstTag = getAt(0, tree);
|
|
164
|
+
|
|
165
|
+
if (firstTag && firstTag.type === OpenNodeTag) {
|
|
166
|
+
let newTags = [...getValues(tree)];
|
|
167
|
+
if (idx_ === 0) {
|
|
168
|
+
newTags[0] = value;
|
|
169
|
+
} else if (isObject(value) && value.type === CloseNodeTag) {
|
|
170
|
+
if (idx_ !== getSize(tree) - 1) throw new Error();
|
|
171
|
+
newTags[2] = value;
|
|
172
|
+
} else {
|
|
173
|
+
let children = getValues(tree)[1];
|
|
174
|
+
|
|
175
|
+
children = module_.replaceAt(idx_ - 1, children, value);
|
|
176
|
+
|
|
177
|
+
newTags[1] = children;
|
|
178
|
+
}
|
|
179
|
+
return module_.fromValues(newTags);
|
|
180
|
+
} else {
|
|
181
|
+
return module_.replaceAt(idx_, tree, value);
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const removeAt = (idx, tree) => {
|
|
186
|
+
let idx_ = idx < 0 ? getSize(tree) + idx : idx;
|
|
187
|
+
|
|
188
|
+
let firstTag = getAt(0, tree);
|
|
189
|
+
|
|
190
|
+
if (firstTag && firstTag.type === OpenNodeTag) {
|
|
191
|
+
let newTags = [...getValues(tree)];
|
|
192
|
+
if (idx_ === 0) {
|
|
193
|
+
newTags.splice(0, 1);
|
|
194
|
+
} else if (idx_ === getSize(tree - 1)) {
|
|
195
|
+
newTags.splice(2, 1);
|
|
196
|
+
} else {
|
|
197
|
+
let children = getValues(tree)[1];
|
|
198
|
+
|
|
199
|
+
children = module_.removeAt(idx_ - 1, children);
|
|
200
|
+
|
|
201
|
+
newTags[1] = children;
|
|
202
|
+
}
|
|
203
|
+
return module_.fromValues(newTags);
|
|
204
|
+
} else {
|
|
205
|
+
return module_.removeAt(idx_, tree);
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
function* traverseInner(tree) {
|
|
210
|
+
for (let tag of module_.traverse(tree)) {
|
|
211
|
+
if (tag.type === PropertyWrapper) {
|
|
212
|
+
yield* tag.value.tags;
|
|
213
|
+
} else {
|
|
214
|
+
yield tag;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export {
|
|
220
|
+
from,
|
|
221
|
+
fromValues,
|
|
222
|
+
push,
|
|
223
|
+
addAt,
|
|
224
|
+
isValidNode,
|
|
225
|
+
assertValidNode,
|
|
226
|
+
getSize,
|
|
227
|
+
getValues,
|
|
228
|
+
getSums,
|
|
229
|
+
setValues,
|
|
230
|
+
traverse,
|
|
231
|
+
traverseInner,
|
|
232
|
+
findPath,
|
|
233
|
+
getAt,
|
|
234
|
+
replaceAt,
|
|
235
|
+
removeAt,
|
|
236
|
+
};
|
package/lib/template.js
CHANGED
|
@@ -5,11 +5,11 @@ import {
|
|
|
5
5
|
OpenNodeTag,
|
|
6
6
|
CloseNodeTag,
|
|
7
7
|
DoctypeTag,
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
Property,
|
|
9
|
+
BindingTag,
|
|
10
10
|
} from './symbols.js';
|
|
11
|
-
import * as
|
|
12
|
-
import { getOpenTag,
|
|
11
|
+
import * as Tags from './tags.js';
|
|
12
|
+
import { getOpenTag, isFragmentNode } from './tree.js';
|
|
13
13
|
|
|
14
14
|
const { freeze } = Object;
|
|
15
15
|
|
|
@@ -18,19 +18,20 @@ export const buildFilledGapFunction = (expressions) => (value) => {
|
|
|
18
18
|
return t.buildGapTag();
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
-
export
|
|
22
|
-
|
|
21
|
+
export const interpolateFragment = (node, ref, expressions) => {
|
|
22
|
+
return __interpolateFragment(node, ref, expressions);
|
|
23
|
+
};
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
function* __interpolateFragment(node, ref, expressions) {
|
|
26
|
+
const open = getOpenTag(node);
|
|
25
27
|
|
|
26
28
|
const gap = buildFilledGapFunction(expressions);
|
|
27
29
|
|
|
28
|
-
const counters = new Map();
|
|
29
|
-
|
|
30
30
|
if (!open.value.type) {
|
|
31
31
|
let currentRef = null;
|
|
32
|
+
let currentBinding = null;
|
|
32
33
|
let isFragment = isFragmentNode(node);
|
|
33
|
-
for (let tag of
|
|
34
|
+
for (let tag of Tags.traverseInner(node.tags)) {
|
|
34
35
|
switch (tag.type) {
|
|
35
36
|
case DoctypeTag: {
|
|
36
37
|
break;
|
|
@@ -48,11 +49,15 @@ export function* interpolateFragment(node, ref, expressions) {
|
|
|
48
49
|
break;
|
|
49
50
|
}
|
|
50
51
|
|
|
52
|
+
case BindingTag: {
|
|
53
|
+
currentBinding = tag;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
|
|
51
57
|
case InitializerTag: {
|
|
52
|
-
const {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
yield freeze({ ...ref });
|
|
58
|
+
const { type } = currentRef.value;
|
|
59
|
+
if (type === '.') {
|
|
60
|
+
yield freeze(ref);
|
|
56
61
|
} else {
|
|
57
62
|
yield currentRef;
|
|
58
63
|
}
|
|
@@ -60,35 +65,21 @@ export function* interpolateFragment(node, ref, expressions) {
|
|
|
60
65
|
break;
|
|
61
66
|
}
|
|
62
67
|
|
|
63
|
-
case
|
|
64
|
-
|
|
68
|
+
case Property: {
|
|
69
|
+
let { reference } = tag.value;
|
|
70
|
+
const { type } = reference;
|
|
65
71
|
|
|
66
|
-
if (
|
|
72
|
+
if (type === '.') {
|
|
67
73
|
// TODO check/combine flags
|
|
68
|
-
yield
|
|
74
|
+
yield ref;
|
|
69
75
|
} else {
|
|
70
76
|
yield currentRef;
|
|
71
77
|
}
|
|
72
78
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
counters.set(name, count);
|
|
79
|
+
yield currentBinding;
|
|
76
80
|
|
|
77
|
-
|
|
81
|
+
yield gap(tag.value.node);
|
|
78
82
|
|
|
79
|
-
yield gap(get(resolvedRef, node));
|
|
80
|
-
|
|
81
|
-
break;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
case EmbeddedNode: {
|
|
85
|
-
const { name } = currentRef.value;
|
|
86
|
-
if (name === '.') {
|
|
87
|
-
yield freeze({ ...ref });
|
|
88
|
-
} else {
|
|
89
|
-
yield currentRef;
|
|
90
|
-
}
|
|
91
|
-
yield gap(tag.value);
|
|
92
83
|
break;
|
|
93
84
|
}
|
|
94
85
|
|
|
@@ -99,8 +90,8 @@ export function* interpolateFragment(node, ref, expressions) {
|
|
|
99
90
|
}
|
|
100
91
|
}
|
|
101
92
|
} else if (open.type === OpenNodeTag) {
|
|
102
|
-
yield freeze(
|
|
103
|
-
yield gap(
|
|
93
|
+
yield freeze(ref);
|
|
94
|
+
yield gap(node);
|
|
104
95
|
} else {
|
|
105
96
|
throw new Error();
|
|
106
97
|
}
|