@bablr/agast-helpers 0.10.10 → 0.11.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/README.md +1 -1
- package/lib/b-list-keyed.js +1 -0
- package/lib/b-list.js +1 -0
- package/lib/b-map.js +1 -0
- package/lib/b-set.js +1 -0
- package/lib/builders.js +917 -115
- package/lib/debug.js +39 -0
- package/lib/debug.register.js +5 -0
- package/lib/iterable.js +170 -0
- package/lib/object.js +52 -3
- package/lib/parse.js +30 -0
- package/lib/path.js +580 -634
- package/lib/print.js +45 -22
- package/lib/shorthand.js +4 -30
- package/lib/spans.js +0 -163
- package/lib/stream.js +345 -196
- package/lib/symbols.js +1 -0
- package/lib/tags.js +256 -77
- package/lib/template.js +19 -16
- package/lib/tree.js +49 -44
- package/package.json +14 -8
- package/lib/btree.js +0 -1
package/lib/symbols.js
CHANGED
|
@@ -5,6 +5,7 @@ export const ReferenceTag = Symbol.for('ReferenceTag');
|
|
|
5
5
|
export const ShiftTag = Symbol.for('ShiftTag');
|
|
6
6
|
export const GapTag = Symbol.for('GapTag');
|
|
7
7
|
export const BindingTag = Symbol.for('BindingTag');
|
|
8
|
+
export const StreamTag = Symbol.for('StreamTag');
|
|
8
9
|
export const NullTag = Symbol.for('NullTag');
|
|
9
10
|
export const AttributeDefinition = Symbol.for('AttributeDefinition');
|
|
10
11
|
export const LiteralTag = Symbol.for('LiteralTag');
|
package/lib/tags.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { buildModule, defaultNodeSize } from '@bablr/btree/enhanceable';
|
|
2
2
|
import {
|
|
3
|
+
ReferenceTag,
|
|
3
4
|
AttributeDefinition,
|
|
4
5
|
CloseNodeTag,
|
|
5
6
|
GapTag,
|
|
@@ -7,22 +8,59 @@ import {
|
|
|
7
8
|
OpenNodeTag,
|
|
8
9
|
Property,
|
|
9
10
|
ShiftTag,
|
|
11
|
+
TreeNode,
|
|
12
|
+
GapNode,
|
|
13
|
+
NullNode,
|
|
14
|
+
BindingTag,
|
|
15
|
+
Document,
|
|
10
16
|
} from './symbols.js';
|
|
11
|
-
import { isObject } from './object.js';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
17
|
+
import { freezeRecord, isArray, isObject, isString } from './object.js';
|
|
18
|
+
import { buildReference, parseTag, parseTagType } from './builders.js';
|
|
19
|
+
import { printTag } from './print.js';
|
|
20
|
+
import { arrayValues } from './iterable.js';
|
|
14
21
|
|
|
15
|
-
|
|
16
|
-
const { freeze } = Object;
|
|
22
|
+
let { reduce } = Array.prototype;
|
|
17
23
|
|
|
18
24
|
export { defaultNodeSize };
|
|
19
25
|
|
|
20
|
-
const
|
|
26
|
+
export const referenceIsSingular = (ref) => {
|
|
27
|
+
return !ref.flags.array && !['#', '@', '.'].includes(ref.type);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const referencesAreEqual = (a, b) => {
|
|
31
|
+
return (
|
|
32
|
+
a === b ||
|
|
33
|
+
(a.type === b.type &&
|
|
34
|
+
a.name === b.name &&
|
|
35
|
+
a.flags.array === b.flags.array &&
|
|
36
|
+
a.flags.intrinsic === b.flags.intrinsic &&
|
|
37
|
+
a.flags.hasGap === b.flags.hasGap &&
|
|
38
|
+
a.flags.expression === b.flags.expression)
|
|
39
|
+
);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const getTags = (node) => {
|
|
43
|
+
switch (node.type) {
|
|
44
|
+
case TreeNode:
|
|
45
|
+
return node.value.tags;
|
|
46
|
+
case NullNode:
|
|
47
|
+
return node.value.tags;
|
|
48
|
+
case GapNode:
|
|
49
|
+
return node.value.tags;
|
|
50
|
+
case Document:
|
|
51
|
+
return getTags(node.value.tree);
|
|
52
|
+
default:
|
|
53
|
+
throw new Error();
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const __findStats = (name, sortedArray, startIdx, endIdx) => {
|
|
21
58
|
if (!sortedArray.length || endIdx < startIdx) return null;
|
|
22
59
|
|
|
23
60
|
let idx = startIdx + Math.floor((endIdx - startIdx) / 2 + 0.1);
|
|
24
|
-
let
|
|
25
|
-
let
|
|
61
|
+
let skipIdx = idx * 3;
|
|
62
|
+
let key = sortedArray[skipIdx];
|
|
63
|
+
let value = sortedArray[skipIdx + 1];
|
|
26
64
|
|
|
27
65
|
let direction = compareNames(name, key);
|
|
28
66
|
|
|
@@ -32,21 +70,127 @@ const __getAtName = (name, sortedArray, startIdx = 0, endIdx = sortedArray.lengt
|
|
|
32
70
|
if (startIdx === endIdx) return null;
|
|
33
71
|
|
|
34
72
|
if (direction > 0) {
|
|
35
|
-
return
|
|
73
|
+
return __findStats(name, sortedArray, idx + 1, endIdx);
|
|
74
|
+
} else {
|
|
75
|
+
return __findStats(name, sortedArray, startIdx, idx - 1);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const findStats = (name, sortedArray, startIdx = 0, endIdx = sortedArray.length / 3 - 1) => {
|
|
81
|
+
return __findStats(name, sortedArray, startIdx, endIdx);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const getIndex = (pathSegment, tags) => {
|
|
85
|
+
let { type, name, index, shiftIndex } = pathSegment;
|
|
86
|
+
let firstPropsIndex = __getPropertyTagsIndex(tags, type, name, 0);
|
|
87
|
+
let prop = firstPropsIndex == null ? null : getAt(firstPropsIndex, tags);
|
|
88
|
+
let ref = prop?.value.reference;
|
|
89
|
+
let sums = getSums(tags);
|
|
90
|
+
let counts = name ? sums.names : sums.types;
|
|
91
|
+
|
|
92
|
+
if (ref?.flags.array) {
|
|
93
|
+
if (index < 0) {
|
|
94
|
+
index = findStats(type, counts) + index;
|
|
95
|
+
} else if (index == null) {
|
|
96
|
+
index = findStats(name, counts) - 1;
|
|
97
|
+
|
|
98
|
+
if (index < 0) return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let parentIndex = __getPropertyTagsIndex(tags, type, name, index ?? 0);
|
|
103
|
+
|
|
104
|
+
if (parentIndex != null && ref?.flags.expression) {
|
|
105
|
+
let shiftIndex_ = shiftIndex == null ? -1 : shiftIndex;
|
|
106
|
+
if (shiftIndex_ < 0) {
|
|
107
|
+
let shifts = 0;
|
|
108
|
+
// TODO speed this up for deeply nested shifts
|
|
109
|
+
// algorithm: make big jump forward, then look at shift index to see if we overshot completely
|
|
110
|
+
// works because we know the size of the thing and a bigger thing doesn't fit in a smaller one
|
|
111
|
+
while (getAt(parentIndex + shifts, getValues(tags)[1])?.value.shift) {
|
|
112
|
+
shifts++;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (-shiftIndex_ > shifts + 1) return null;
|
|
116
|
+
|
|
117
|
+
return parentIndex + shifts + shiftIndex_ + 1;
|
|
36
118
|
} else {
|
|
37
|
-
|
|
119
|
+
if (parentIndex + shiftIndex_ >= getSize(tags)) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return parentIndex + shiftIndex_;
|
|
38
124
|
}
|
|
39
125
|
}
|
|
126
|
+
|
|
127
|
+
return parentIndex;
|
|
40
128
|
};
|
|
41
129
|
|
|
42
|
-
|
|
43
|
-
|
|
130
|
+
const __getPropertyTagsIndex = (tags, type, name, index) => {
|
|
131
|
+
let nameCount = 0;
|
|
132
|
+
let node = getValues(tags)[1];
|
|
133
|
+
let idx = -1;
|
|
134
|
+
|
|
135
|
+
// drill into subtrees, passing over subtrees with too few references of the desired name
|
|
136
|
+
outer: while (node) {
|
|
137
|
+
let sums = getSums(node);
|
|
138
|
+
|
|
139
|
+
if (!sums) throw new Error();
|
|
140
|
+
|
|
141
|
+
let valueNameCount = name != null ? findStats(name, sums.names) : findStats(type, sums.types);
|
|
142
|
+
|
|
143
|
+
if (nameCount + valueNameCount < index) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
for (const value of arrayValues(getValues(node))) {
|
|
148
|
+
if (!isNode(value)) {
|
|
149
|
+
idx++;
|
|
150
|
+
let tag = value;
|
|
151
|
+
if (isObject(tag) && tag.type === Property) {
|
|
152
|
+
let { tags, reference } = tag.value;
|
|
153
|
+
if (parseTagType(tags[1][0]) === ReferenceTag) {
|
|
154
|
+
if (
|
|
155
|
+
(name != null && reference.name === name) ||
|
|
156
|
+
(type != null && reference.type === type)
|
|
157
|
+
) {
|
|
158
|
+
nameCount += 1;
|
|
159
|
+
if (nameCount > index) {
|
|
160
|
+
return idx + 1;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
} else {
|
|
166
|
+
let valueSums = getSums(value);
|
|
167
|
+
if (
|
|
168
|
+
nameCount +
|
|
169
|
+
(name != null ? findStats(name, valueSums.names) : findStats(type, valueSums.types)) >
|
|
170
|
+
index
|
|
171
|
+
) {
|
|
172
|
+
node = value;
|
|
173
|
+
continue outer;
|
|
174
|
+
} else {
|
|
175
|
+
nameCount +=
|
|
176
|
+
(name != null ? findStats(name, valueSums.names) : findStats(type, valueSums.types)) ??
|
|
177
|
+
0;
|
|
178
|
+
idx += getSize(value);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return null;
|
|
44
187
|
};
|
|
45
188
|
|
|
46
189
|
export const compareNames = (a, b) => (a > b ? 1 : b > a ? -1 : 0);
|
|
47
190
|
|
|
48
|
-
export const sumValues = (values) => {
|
|
49
|
-
let mapStats =
|
|
191
|
+
export const sumValues = (values, depth) => {
|
|
192
|
+
let mapStats = reduce.call(
|
|
193
|
+
values,
|
|
50
194
|
(acc, val) => {
|
|
51
195
|
const { names, types } = acc;
|
|
52
196
|
if (isArray(val)) {
|
|
@@ -59,30 +203,35 @@ export const sumValues = (values) => {
|
|
|
59
203
|
];
|
|
60
204
|
|
|
61
205
|
for (let { 0: arr, 1: map } of arrs) {
|
|
62
|
-
for (
|
|
206
|
+
for (let i = 0; i < arr.length; i++) {
|
|
207
|
+
let key = arr[i];
|
|
208
|
+
let value = arr[++i];
|
|
209
|
+
let reference = arr[++i];
|
|
210
|
+
|
|
63
211
|
let count = map.get(key)?.[1] ?? 0;
|
|
64
212
|
|
|
65
|
-
if (
|
|
66
|
-
throw new Error();
|
|
213
|
+
if (referenceIsSingular(reference) && count > 0) throw new Error();
|
|
67
214
|
|
|
68
|
-
map.set(key,
|
|
215
|
+
map.set(key, [key, count + value, reference]);
|
|
69
216
|
}
|
|
70
217
|
}
|
|
71
218
|
} else if (val) {
|
|
72
|
-
|
|
73
|
-
|
|
219
|
+
let tag = parseTag(val);
|
|
220
|
+
if (tag.type === LiteralTag) {
|
|
221
|
+
let text = tag.value;
|
|
74
222
|
let idx = 0;
|
|
75
223
|
while ((idx = text.indexOf('\n', idx + 1)) >= 0) {
|
|
76
224
|
acc.lineBreaks++;
|
|
77
225
|
}
|
|
78
|
-
} else if (
|
|
226
|
+
} else if (tag.type === GapTag) {
|
|
79
227
|
acc.gaps++;
|
|
80
|
-
} else if (
|
|
81
|
-
let { tags } =
|
|
82
|
-
|
|
228
|
+
} else if (tag.type === Property) {
|
|
229
|
+
let { tags } = tag.value;
|
|
230
|
+
if (!isArray(tags[1][0]) && !isString(tags[1][0])) throw new Error();
|
|
231
|
+
let refOrShiftTag = isArray(tags[1][0]) ? buildReference() : parseTag(tags[1][0]);
|
|
83
232
|
|
|
84
|
-
if (tags[2]) {
|
|
85
|
-
acc.gaps += tags[2].value.tags[2].gaps;
|
|
233
|
+
if (tags[1][2]) {
|
|
234
|
+
acc.gaps += tags[1][2].value.tags[2].gaps;
|
|
86
235
|
}
|
|
87
236
|
if (refOrShiftTag?.type !== ShiftTag) {
|
|
88
237
|
let ref = refOrShiftTag?.value || buildReference();
|
|
@@ -91,17 +240,17 @@ export const sumValues = (values) => {
|
|
|
91
240
|
if (name) {
|
|
92
241
|
let count = names.get(name)?.[1] ?? 0;
|
|
93
242
|
|
|
94
|
-
if (
|
|
243
|
+
if (referenceIsSingular(ref) && count > 0) throw new Error();
|
|
95
244
|
|
|
96
|
-
names.set(name,
|
|
245
|
+
names.set(name, [name, count + 1, ref]);
|
|
97
246
|
}
|
|
98
247
|
|
|
99
248
|
if (type) {
|
|
100
249
|
let count = types.get(type)?.[1] ?? 0;
|
|
101
250
|
|
|
102
|
-
if (
|
|
251
|
+
if (referenceIsSingular(ref) && count > 0) throw new Error();
|
|
103
252
|
|
|
104
|
-
types.set(type,
|
|
253
|
+
types.set(type, [type, count + 1, ref]);
|
|
105
254
|
}
|
|
106
255
|
}
|
|
107
256
|
}
|
|
@@ -117,130 +266,146 @@ export const sumValues = (values) => {
|
|
|
117
266
|
);
|
|
118
267
|
|
|
119
268
|
let { lineBreaks, gaps } = mapStats;
|
|
120
|
-
let stats = {
|
|
269
|
+
let stats = freezeRecord({
|
|
121
270
|
gaps,
|
|
122
271
|
lineBreaks,
|
|
123
|
-
names:
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
272
|
+
names: freezeRecord(
|
|
273
|
+
[...mapStats.names.values()].sort((a, b) => compareNames(a[0], b[0])).flatMap((_) => _),
|
|
274
|
+
),
|
|
275
|
+
types: freezeRecord(
|
|
276
|
+
[...mapStats.types.values()].sort((a, b) => compareNames(a[0], b[0])).flatMap((_) => _),
|
|
277
|
+
),
|
|
278
|
+
});
|
|
129
279
|
return stats;
|
|
130
280
|
};
|
|
131
281
|
|
|
132
|
-
const module_ = buildModule(defaultNodeSize, sumValues);
|
|
282
|
+
const module_ = buildModule(defaultNodeSize, sumValues, Symbol.for('Tags'));
|
|
133
283
|
|
|
134
284
|
const {
|
|
135
285
|
from,
|
|
136
286
|
fromValues,
|
|
287
|
+
create,
|
|
137
288
|
addAt,
|
|
138
289
|
isValidNode,
|
|
290
|
+
isNode,
|
|
139
291
|
assertValidNode,
|
|
140
292
|
getValues,
|
|
141
293
|
getSums,
|
|
142
|
-
|
|
294
|
+
getDepth,
|
|
295
|
+
getType,
|
|
143
296
|
traverse,
|
|
144
297
|
getSize,
|
|
145
298
|
findPath,
|
|
146
299
|
} = module_;
|
|
147
300
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
301
|
+
let { slice } = Array.prototype;
|
|
302
|
+
|
|
303
|
+
const getAt = (idx, tags) => {
|
|
304
|
+
if (isArray(idx) && idx.length > 1) {
|
|
305
|
+
return module_.getAt(slice.call(idx, 1), module_.getAt(slice.call(idx, 0, 1), tags));
|
|
306
|
+
} else {
|
|
307
|
+
return module_.getAt(idx, tags);
|
|
151
308
|
}
|
|
152
|
-
return module_.getAt(idx, tags);
|
|
153
309
|
};
|
|
154
310
|
|
|
155
|
-
const push = (
|
|
156
|
-
let
|
|
311
|
+
const push = (tag, tags) => {
|
|
312
|
+
let tag_ = parseTag(tag);
|
|
313
|
+
let firstTag = parseTag(getAt(0, tags));
|
|
157
314
|
|
|
158
315
|
if (
|
|
159
|
-
!
|
|
160
|
-
![
|
|
161
|
-
|
|
162
|
-
|
|
316
|
+
!isNode(tag_) &&
|
|
317
|
+
![
|
|
318
|
+
OpenNodeTag,
|
|
319
|
+
Property,
|
|
320
|
+
CloseNodeTag,
|
|
321
|
+
AttributeDefinition,
|
|
322
|
+
BindingTag,
|
|
323
|
+
LiteralTag,
|
|
324
|
+
GapTag,
|
|
325
|
+
].includes(tag_.type)
|
|
163
326
|
)
|
|
164
327
|
throw new Error();
|
|
165
328
|
|
|
166
|
-
if (
|
|
329
|
+
if (isNode(tag_)) {
|
|
167
330
|
if (!firstTag || firstTag.type !== OpenNodeTag) {
|
|
168
|
-
return module_.concat(tags,
|
|
331
|
+
return module_.concat(tags, tag_);
|
|
169
332
|
}
|
|
170
333
|
let children = getValues(tags)[1] ?? module_.fromValues([]);
|
|
171
334
|
|
|
172
335
|
let { 0: open } = getValues(tags);
|
|
173
336
|
|
|
174
|
-
children = module_.concat(children,
|
|
337
|
+
children = module_.concat(children, tag_);
|
|
175
338
|
|
|
176
339
|
return module_.fromValues([open, children]);
|
|
177
340
|
} else {
|
|
178
|
-
if (
|
|
341
|
+
if (tag_.type === OpenNodeTag) {
|
|
179
342
|
if (getSize(tags) !== 0) throw new Error();
|
|
180
|
-
return module_.push(
|
|
343
|
+
return module_.push(printTag(tag_), tags);
|
|
181
344
|
} else {
|
|
182
345
|
if (!firstTag || firstTag.type !== OpenNodeTag) {
|
|
183
|
-
return module_.push(
|
|
346
|
+
return module_.push(printTag(tag_), tags);
|
|
184
347
|
}
|
|
185
348
|
|
|
186
|
-
let children = getValues(tags)[1] ?? [];
|
|
349
|
+
let children = getValues(tags)[1] ?? module_.fromValues([]);
|
|
187
350
|
|
|
188
351
|
// sometimes this is the top level
|
|
189
352
|
if (firstTag) {
|
|
190
|
-
if (
|
|
353
|
+
if (tag_.type === CloseNodeTag) {
|
|
191
354
|
let { 0: open, 1: children = module_.fromValues([]) } = getValues(tags);
|
|
192
355
|
|
|
193
|
-
return module_.fromValues([open, children,
|
|
356
|
+
return module_.fromValues([open, children, printTag(tag_)]);
|
|
194
357
|
} else {
|
|
195
358
|
let { 0: open } = getValues(tags);
|
|
196
359
|
|
|
197
|
-
children = module_.push(
|
|
360
|
+
children = module_.push(printTag(tag_), children);
|
|
198
361
|
|
|
199
|
-
return module_.fromValues([open, children]);
|
|
362
|
+
return module_.fromValues([open, children], 1);
|
|
200
363
|
}
|
|
201
364
|
} else {
|
|
202
|
-
return module_.push(
|
|
365
|
+
return module_.push(tag_, tags);
|
|
203
366
|
}
|
|
204
367
|
}
|
|
205
368
|
}
|
|
206
369
|
};
|
|
207
370
|
|
|
208
|
-
const replaceAt = (idx,
|
|
371
|
+
const replaceAt = (idx, tag, tree) => {
|
|
209
372
|
let idx_ = idx < 0 ? getSize(tree) + idx : idx;
|
|
373
|
+
let tagObj = parseTag(tag);
|
|
374
|
+
let tag_ = printTag(tag);
|
|
210
375
|
|
|
211
|
-
if (
|
|
212
|
-
let firstTag = getAt(0, tree);
|
|
376
|
+
if (tagObj.type !== parseTagType(getAt(idx_, tree))) throw new Error();
|
|
377
|
+
let firstTag = parseTag(getAt(0, tree));
|
|
213
378
|
|
|
214
379
|
if (firstTag && firstTag.type === OpenNodeTag) {
|
|
215
|
-
let newTags = [...getValues(tree)];
|
|
380
|
+
let newTags = [...arrayValues(getValues(tree))];
|
|
216
381
|
if (idx_ === 0) {
|
|
217
|
-
newTags[0] =
|
|
218
|
-
} else if (
|
|
382
|
+
newTags[0] = tag_;
|
|
383
|
+
} else if (tagObj.type === CloseNodeTag) {
|
|
219
384
|
if (idx_ !== getSize(tree) - 1) throw new Error();
|
|
220
|
-
newTags[2] =
|
|
385
|
+
newTags[2] = tag_;
|
|
221
386
|
} else {
|
|
222
387
|
let children = getValues(tree)[1];
|
|
223
388
|
|
|
224
|
-
children = module_.replaceAt(idx_ - 1,
|
|
389
|
+
children = module_.replaceAt(idx_ - 1, tag_, children);
|
|
225
390
|
|
|
226
391
|
newTags[1] = children;
|
|
227
392
|
}
|
|
228
393
|
return module_.fromValues(newTags);
|
|
229
394
|
} else {
|
|
230
|
-
return module_.replaceAt(idx_,
|
|
395
|
+
return module_.replaceAt(idx_, tag_, tree);
|
|
231
396
|
}
|
|
232
397
|
};
|
|
233
398
|
|
|
234
399
|
const removeAt = (idx, tree) => {
|
|
235
400
|
let idx_ = idx < 0 ? getSize(tree) + idx : idx;
|
|
236
401
|
|
|
237
|
-
let firstTag = getAt(0, tree);
|
|
402
|
+
let firstTag = parseTag(getAt(0, tree));
|
|
238
403
|
|
|
239
404
|
if (firstTag && firstTag.type === OpenNodeTag) {
|
|
240
|
-
let newTags = [...getValues(tree)];
|
|
405
|
+
let newTags = [...arrayValues(getValues(tree))];
|
|
241
406
|
if (idx_ === 0) {
|
|
242
407
|
newTags.splice(0, 1);
|
|
243
|
-
} else if (idx_ === getSize(tree - 1)
|
|
408
|
+
} else if (idx_ === getSize(tree) - 1) {
|
|
244
409
|
newTags.splice(2, 1);
|
|
245
410
|
} else {
|
|
246
411
|
let children = getValues(tree)[1];
|
|
@@ -256,27 +421,41 @@ const removeAt = (idx, tree) => {
|
|
|
256
421
|
};
|
|
257
422
|
|
|
258
423
|
function* traverseInner(tree) {
|
|
259
|
-
for (let tag of
|
|
260
|
-
if (tag.type === Property) {
|
|
261
|
-
yield*
|
|
424
|
+
for (let tag of traverse(tree)) {
|
|
425
|
+
if (isObject(tag) && tag.type === Property) {
|
|
426
|
+
yield* traverse(tag.value.tags);
|
|
262
427
|
} else {
|
|
263
428
|
yield tag;
|
|
264
429
|
}
|
|
265
430
|
}
|
|
266
431
|
}
|
|
267
432
|
|
|
433
|
+
const map = (fn, tree) => {
|
|
434
|
+
let { 0: open, 1: children, 2: close } = getValues(tree);
|
|
435
|
+
|
|
436
|
+
let newValues = [fn(open)];
|
|
437
|
+
if (children) newValues.push(module_.map(fn, children));
|
|
438
|
+
if (close) newValues.push(fn(close));
|
|
439
|
+
|
|
440
|
+
return module_.fromValues(newValues);
|
|
441
|
+
};
|
|
442
|
+
|
|
268
443
|
export {
|
|
269
444
|
from,
|
|
270
445
|
fromValues,
|
|
446
|
+
create,
|
|
271
447
|
push,
|
|
272
448
|
addAt,
|
|
273
449
|
isValidNode,
|
|
450
|
+
isNode,
|
|
274
451
|
assertValidNode,
|
|
275
452
|
getSize,
|
|
276
453
|
getValues,
|
|
277
454
|
getSums,
|
|
278
|
-
|
|
455
|
+
getDepth,
|
|
456
|
+
getType,
|
|
279
457
|
traverse,
|
|
458
|
+
map,
|
|
280
459
|
traverseInner,
|
|
281
460
|
findPath,
|
|
282
461
|
getAt,
|
package/lib/template.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as t from './builders.js';
|
|
2
|
-
import {
|
|
2
|
+
import { isObject } from './object.js';
|
|
3
|
+
import { parseTagType } from './builders.js';
|
|
4
|
+
import { buildNullNode, isMultiFragment, isNode, Path } from './path.js';
|
|
3
5
|
import { OpenNodeTag, CloseNodeTag, DoctypeTag, Property, GapNode } from './symbols.js';
|
|
4
6
|
import * as Tags from './tags.js';
|
|
5
7
|
import { getOpenTag, isNull } from './tree.js';
|
|
@@ -12,6 +14,8 @@ export const buildFilledGapFunction = (expressions) => (value) => {
|
|
|
12
14
|
};
|
|
13
15
|
|
|
14
16
|
export const interpolate = (expressions, node) => {
|
|
17
|
+
if (!isNode(node)) throw new Error();
|
|
18
|
+
|
|
15
19
|
let path = Path.from(node);
|
|
16
20
|
|
|
17
21
|
outer: for (let expression of expressions) {
|
|
@@ -19,12 +23,12 @@ export const interpolate = (expressions, node) => {
|
|
|
19
23
|
do {
|
|
20
24
|
path = path.atDepth(0);
|
|
21
25
|
let tag;
|
|
22
|
-
while ((tag = Tags.getAt(i, getTags(path.node)))) {
|
|
26
|
+
while ((tag = Tags.getAt(i, Tags.getTags(path.node)))) {
|
|
23
27
|
if (path.node.type === GapNode) {
|
|
24
28
|
path = path.replaceWith(expression ?? buildNullNode());
|
|
25
29
|
continue outer;
|
|
26
|
-
} else if (tag.type === Property && tag.value.tags[2]) {
|
|
27
|
-
let tags = getTags(tag.value.tags[2]);
|
|
30
|
+
} else if (isObject(tag) && tag.type === Property && tag.value.tags[1][2]) {
|
|
31
|
+
let tags = Tags.getTags(tag.value.tags[1][2]);
|
|
28
32
|
if (tags[2].gaps) {
|
|
29
33
|
path = path.push(i);
|
|
30
34
|
i = 0;
|
|
@@ -41,21 +45,19 @@ export const interpolate = (expressions, node) => {
|
|
|
41
45
|
return path.atDepth(0).node;
|
|
42
46
|
};
|
|
43
47
|
|
|
44
|
-
export const interpolateFragment = (node, ref
|
|
45
|
-
return __interpolateFragment(node, ref
|
|
48
|
+
export const interpolateFragment = (node, ref) => {
|
|
49
|
+
return __interpolateFragment(node, ref);
|
|
46
50
|
};
|
|
47
51
|
|
|
48
|
-
function* __interpolateFragment(node, ref
|
|
52
|
+
function* __interpolateFragment(node, ref) {
|
|
49
53
|
if (isNull(node)) return;
|
|
50
54
|
|
|
51
|
-
const open = getOpenTag(node);
|
|
52
|
-
|
|
53
|
-
const gap = buildFilledGapFunction(expressions);
|
|
55
|
+
const open = t.parseTag(getOpenTag(node));
|
|
54
56
|
|
|
55
57
|
if (!open.value.name) {
|
|
56
58
|
let isMultiFragment_ = isMultiFragment(node);
|
|
57
|
-
for (let tag of Tags.traverse(getTags(node))) {
|
|
58
|
-
switch (tag
|
|
59
|
+
for (let tag of Tags.traverse(Tags.getTags(node))) {
|
|
60
|
+
switch (parseTagType(tag)) {
|
|
59
61
|
case DoctypeTag: {
|
|
60
62
|
break;
|
|
61
63
|
}
|
|
@@ -71,16 +73,17 @@ function* __interpolateFragment(node, ref, expressions) {
|
|
|
71
73
|
let { reference, node, tags } = tag.value;
|
|
72
74
|
const { type } = reference;
|
|
73
75
|
|
|
76
|
+
// don't I elsewhere forbid this?
|
|
74
77
|
if (type === '_') {
|
|
75
78
|
// TODO check/combine flags
|
|
76
79
|
yield ref;
|
|
77
80
|
} else {
|
|
78
|
-
yield tags[0];
|
|
81
|
+
yield tags[1][0];
|
|
79
82
|
}
|
|
80
83
|
|
|
81
|
-
yield* tags[1];
|
|
84
|
+
yield* Tags.traverse(tags[1][1]);
|
|
82
85
|
|
|
83
|
-
yield
|
|
86
|
+
yield node;
|
|
84
87
|
|
|
85
88
|
break;
|
|
86
89
|
}
|
|
@@ -93,7 +96,7 @@ function* __interpolateFragment(node, ref, expressions) {
|
|
|
93
96
|
}
|
|
94
97
|
} else if (open.type === OpenNodeTag) {
|
|
95
98
|
yield freeze(ref);
|
|
96
|
-
yield
|
|
99
|
+
yield node;
|
|
97
100
|
} else {
|
|
98
101
|
throw new Error();
|
|
99
102
|
}
|