@bablr/agast-helpers 0.7.1 → 0.8.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 +70 -27
- package/lib/children.js +120 -0
- package/lib/object.js +86 -0
- package/lib/path-facade.js +39 -0
- package/lib/path.js +386 -448
- package/lib/print.js +51 -87
- package/lib/shorthand.js +26 -1
- package/lib/stream.js +33 -13
- package/lib/symbols.js +3 -1
- package/lib/template.js +23 -36
- package/lib/tree.js +368 -122
- package/package.json +8 -5
- package/lib/sumtree.js +0 -62
package/lib/tree.js
CHANGED
|
@@ -7,6 +7,12 @@ import {
|
|
|
7
7
|
buildLiteralTag,
|
|
8
8
|
buildCloseNodeTag,
|
|
9
9
|
tokenFlags,
|
|
10
|
+
buildInitializerTag,
|
|
11
|
+
buildBindingTag,
|
|
12
|
+
buildProperty,
|
|
13
|
+
buildChild,
|
|
14
|
+
buildShiftTag,
|
|
15
|
+
buildGapTag,
|
|
10
16
|
} from './builders.js';
|
|
11
17
|
import {
|
|
12
18
|
printPrettyCSTML as printPrettyCSTMLFromStream,
|
|
@@ -23,14 +29,16 @@ import {
|
|
|
23
29
|
NullTag,
|
|
24
30
|
InitializerTag,
|
|
25
31
|
LiteralTag,
|
|
26
|
-
|
|
32
|
+
AttributeDefinition,
|
|
33
|
+
BindingTag,
|
|
34
|
+
Property,
|
|
35
|
+
ShiftTag,
|
|
27
36
|
} from './symbols.js';
|
|
28
37
|
import * as btree from './btree.js';
|
|
29
|
-
import * as
|
|
38
|
+
import * as Children from './children.js';
|
|
30
39
|
export * from './builders.js';
|
|
31
40
|
export * from './print.js';
|
|
32
41
|
import {
|
|
33
|
-
add,
|
|
34
42
|
get,
|
|
35
43
|
TagPath,
|
|
36
44
|
Path,
|
|
@@ -39,14 +47,26 @@ import {
|
|
|
39
47
|
isGapNode,
|
|
40
48
|
getOpenTag,
|
|
41
49
|
getCloseTag,
|
|
42
|
-
|
|
50
|
+
getRoot,
|
|
51
|
+
getRootArray,
|
|
52
|
+
getFirstNodeShiftStack,
|
|
43
53
|
} from './path.js';
|
|
54
|
+
import { isPlainObject } from './object.js';
|
|
44
55
|
|
|
45
|
-
export {
|
|
56
|
+
export {
|
|
57
|
+
get,
|
|
58
|
+
isFragmentNode,
|
|
59
|
+
isNullNode,
|
|
60
|
+
isGapNode,
|
|
61
|
+
getOpenTag,
|
|
62
|
+
getCloseTag,
|
|
63
|
+
getRoot,
|
|
64
|
+
getRootArray,
|
|
65
|
+
};
|
|
46
66
|
|
|
47
|
-
export const buildToken = (
|
|
67
|
+
export const buildToken = (type, value, attributes = {}) => {
|
|
48
68
|
return treeFromStreamSync([
|
|
49
|
-
buildOpenNodeTag(tokenFlags,
|
|
69
|
+
buildOpenNodeTag(tokenFlags, type, attributes),
|
|
50
70
|
buildLiteralTag(value),
|
|
51
71
|
buildCloseNodeTag(),
|
|
52
72
|
]);
|
|
@@ -55,72 +75,36 @@ export const buildToken = (language, type, value, attributes = {}) => {
|
|
|
55
75
|
const isString = (str) => typeof str === 'string';
|
|
56
76
|
|
|
57
77
|
const { isArray } = Array;
|
|
58
|
-
const { freeze } = Object;
|
|
59
|
-
|
|
60
|
-
export const parseReference = (str) => {
|
|
61
|
-
let {
|
|
62
|
-
1: name,
|
|
63
|
-
2: isArray,
|
|
64
|
-
3: index,
|
|
65
|
-
4: expressionToken,
|
|
66
|
-
5: hasGapToken,
|
|
67
|
-
} = /^\s*([.#@]|[a-zA-Z]+)\s*(\[\s*(\d+\s*)?\])?\s*(\+)?(\$)?\s*$/.exec(str);
|
|
68
|
-
|
|
69
|
-
let flags = {
|
|
70
|
-
expression: !!expressionToken,
|
|
71
|
-
hasGap: !!hasGapToken,
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
index = index ? parseInt(index, 10) : null;
|
|
75
|
-
isArray = !!isArray;
|
|
76
|
-
name = name || null;
|
|
77
|
-
|
|
78
|
-
return buildReferenceTag(name, isArray, flags, index);
|
|
79
|
-
};
|
|
78
|
+
const { freeze, hasOwn } = Object;
|
|
80
79
|
|
|
81
80
|
export const mergeReferences = (outer, inner) => {
|
|
82
|
-
let {
|
|
83
|
-
name,
|
|
84
|
-
isArray,
|
|
85
|
-
index,
|
|
86
|
-
flags: { expression, hasGap },
|
|
87
|
-
} = outer.value;
|
|
81
|
+
let { type, name, isArray, index, flags: { expression, hasGap } = {} } = outer;
|
|
88
82
|
|
|
89
83
|
if (
|
|
90
|
-
name != null &&
|
|
91
|
-
|
|
92
|
-
inner.value.name != null &&
|
|
93
|
-
inner.value.name !== '.' &&
|
|
94
|
-
name !== inner.value.name
|
|
84
|
+
(name != null && inner.name != null && name !== inner.name) ||
|
|
85
|
+
(type != null && inner.type != null && type !== inner.type)
|
|
95
86
|
) {
|
|
96
87
|
return inner;
|
|
97
88
|
}
|
|
98
89
|
|
|
99
|
-
isArray = isArray || inner.
|
|
100
|
-
expression = !!(expression || inner.
|
|
101
|
-
hasGap = !!(hasGap || inner.
|
|
102
|
-
name =
|
|
103
|
-
|
|
104
|
-
return buildReferenceTag(name, isArray, { expression, hasGap }, index);
|
|
105
|
-
};
|
|
90
|
+
isArray = isArray || inner.isArray;
|
|
91
|
+
expression = !!(expression || inner.flags.expression);
|
|
92
|
+
hasGap = !!(hasGap || inner.flags.hasGap);
|
|
93
|
+
name = type === '.' ? inner.name : name;
|
|
94
|
+
type = type === '.' ? inner.type : type;
|
|
106
95
|
|
|
107
|
-
|
|
108
|
-
let { name, isArray, flags } = ref.value;
|
|
109
|
-
return name === '.' && !isArray && !(flags.expression || flags.hasGap);
|
|
96
|
+
return buildReferenceTag(type, name, isArray, { expression, hasGap }, index).value;
|
|
110
97
|
};
|
|
111
98
|
|
|
112
|
-
export const
|
|
113
|
-
|
|
99
|
+
export const mergeReferenceTags = (outer, inner) => {
|
|
100
|
+
let value = mergeReferences(outer.value, inner.value);
|
|
114
101
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const attributes = { ...openTag.value.attributes, [key]: value };
|
|
118
|
-
const newOpenTag = buildOpenNodeTag(flags, language, type, attributes);
|
|
119
|
-
|
|
120
|
-
node.attributes = attributes;
|
|
102
|
+
return buildChild(ReferenceTag, value);
|
|
103
|
+
};
|
|
121
104
|
|
|
122
|
-
|
|
123
|
-
}
|
|
105
|
+
export const isEmptyReference = (ref) => {
|
|
106
|
+
let { type, isArray, flags } = ref.value;
|
|
107
|
+
return type === '.' && !isArray && !(flags.expression || flags.hasGap);
|
|
124
108
|
};
|
|
125
109
|
|
|
126
110
|
function* __treeFromStream(tags, options) {
|
|
@@ -130,7 +114,8 @@ function* __treeFromStream(tags, options) {
|
|
|
130
114
|
let doctype = null;
|
|
131
115
|
const co = new Coroutine(getStreamIterator(tags));
|
|
132
116
|
const expressionsCo = new Coroutine(getStreamIterator(options.expressions || []));
|
|
133
|
-
let
|
|
117
|
+
let referenceTag = null;
|
|
118
|
+
let bindingTag = null;
|
|
134
119
|
|
|
135
120
|
for (;;) {
|
|
136
121
|
co.advance();
|
|
@@ -165,15 +150,21 @@ function* __treeFromStream(tags, options) {
|
|
|
165
150
|
}
|
|
166
151
|
|
|
167
152
|
case ReferenceTag: {
|
|
168
|
-
|
|
153
|
+
referenceTag = tag;
|
|
154
|
+
suppressTag = true;
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
case BindingTag: {
|
|
159
|
+
bindingTag = tag;
|
|
169
160
|
suppressTag = true;
|
|
170
161
|
break;
|
|
171
162
|
}
|
|
172
163
|
|
|
173
164
|
case InitializerTag: {
|
|
174
|
-
add(path.node,
|
|
165
|
+
add(path.node, referenceTag, []);
|
|
175
166
|
suppressTag = true;
|
|
176
|
-
|
|
167
|
+
referenceTag = null;
|
|
177
168
|
break;
|
|
178
169
|
}
|
|
179
170
|
|
|
@@ -185,19 +176,19 @@ function* __treeFromStream(tags, options) {
|
|
|
185
176
|
|
|
186
177
|
const isGap = tag.type === GapTag;
|
|
187
178
|
|
|
188
|
-
if (path.parent &&
|
|
179
|
+
if (path.parent && referenceTag.type !== ReferenceTag) throw new Error();
|
|
189
180
|
|
|
190
181
|
let node = createNode(tag);
|
|
191
182
|
|
|
192
183
|
if (isGap) {
|
|
193
184
|
if (held) {
|
|
194
185
|
node = held;
|
|
195
|
-
add(path.node,
|
|
186
|
+
add(path.node, referenceTag, node, bindingTag);
|
|
196
187
|
suppressTag = true;
|
|
197
188
|
} else if (!expressionsCo.done) {
|
|
198
189
|
expressionsCo.advance();
|
|
199
190
|
|
|
200
|
-
let outerReference =
|
|
191
|
+
let outerReference = referenceTag;
|
|
201
192
|
|
|
202
193
|
if (!expressionsCo.done) {
|
|
203
194
|
node =
|
|
@@ -211,15 +202,17 @@ function* __treeFromStream(tags, options) {
|
|
|
211
202
|
if (isFragmentNode(node)) {
|
|
212
203
|
const parentNode = path.node;
|
|
213
204
|
|
|
214
|
-
let
|
|
205
|
+
let referenceTag;
|
|
206
|
+
let bindingTag;
|
|
215
207
|
|
|
216
|
-
for (const tag of
|
|
208
|
+
for (const tag of Children.traverse(node.children)) {
|
|
217
209
|
switch (tag.type) {
|
|
218
210
|
case DoctypeTag: {
|
|
219
211
|
break;
|
|
220
212
|
}
|
|
221
|
-
|
|
222
|
-
case
|
|
213
|
+
|
|
214
|
+
case OpenNodeTag: {
|
|
215
|
+
referenceTag = bindingTag = null;
|
|
223
216
|
if (!tag.value.type) {
|
|
224
217
|
break;
|
|
225
218
|
} else {
|
|
@@ -228,29 +221,28 @@ function* __treeFromStream(tags, options) {
|
|
|
228
221
|
}
|
|
229
222
|
|
|
230
223
|
case ReferenceTag:
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
reference = tag;
|
|
224
|
+
referenceTag = tag;
|
|
234
225
|
break;
|
|
235
226
|
|
|
236
227
|
case InitializerTag: {
|
|
237
|
-
add(parentNode,
|
|
228
|
+
add(parentNode, mergeReferenceTags(outerReference, referenceTag), []);
|
|
238
229
|
break;
|
|
239
230
|
}
|
|
240
231
|
|
|
241
|
-
case
|
|
242
|
-
|
|
243
|
-
break;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
case GapTag: {
|
|
247
|
-
const resolvedNode = getShifted(shift, reference, node);
|
|
248
|
-
add(parentNode, mergeReferences(outerReference, reference), resolvedNode);
|
|
232
|
+
case BindingTag: {
|
|
233
|
+
bindingTag = tag;
|
|
249
234
|
break;
|
|
250
235
|
}
|
|
251
236
|
|
|
237
|
+
case GapTag:
|
|
252
238
|
case NullTag: {
|
|
253
|
-
add(
|
|
239
|
+
add(
|
|
240
|
+
parentNode,
|
|
241
|
+
mergeReferenceTags(outerReference, referenceTag),
|
|
242
|
+
buildStubNode(tag),
|
|
243
|
+
bindingTag,
|
|
244
|
+
);
|
|
245
|
+
referenceTag = bindingTag = null;
|
|
254
246
|
break;
|
|
255
247
|
}
|
|
256
248
|
|
|
@@ -262,21 +254,21 @@ function* __treeFromStream(tags, options) {
|
|
|
262
254
|
if (path.node.flags.token) {
|
|
263
255
|
throw new Error('not implemented');
|
|
264
256
|
}
|
|
265
|
-
add(path.node,
|
|
257
|
+
add(path.node, referenceTag, node, bindingTag ?? buildBindingTag());
|
|
266
258
|
}
|
|
267
259
|
} else {
|
|
268
260
|
if (!path.node.flags.token) {
|
|
269
|
-
add(path.node,
|
|
261
|
+
add(path.node, referenceTag, node, bindingTag ?? buildBindingTag());
|
|
270
262
|
}
|
|
271
263
|
}
|
|
272
264
|
}
|
|
273
265
|
}
|
|
274
266
|
|
|
275
|
-
|
|
267
|
+
referenceTag = null;
|
|
276
268
|
held = isGap ? null : held;
|
|
277
269
|
|
|
278
270
|
if (!path.node.flags.token) {
|
|
279
|
-
path = { parent: path, node, depth: (path.depth
|
|
271
|
+
path = { parent: path, node, depth: (path.depth ?? -1) + 1, arrays: new Set() };
|
|
280
272
|
}
|
|
281
273
|
|
|
282
274
|
break;
|
|
@@ -305,20 +297,18 @@ function* __treeFromStream(tags, options) {
|
|
|
305
297
|
const node = createNode(tag);
|
|
306
298
|
|
|
307
299
|
if (path) {
|
|
308
|
-
add(path.node,
|
|
309
|
-
|
|
300
|
+
add(path.node, referenceTag, node, bindingTag ?? buildBindingTag());
|
|
301
|
+
referenceTag = null;
|
|
310
302
|
}
|
|
311
303
|
|
|
312
304
|
path = { parent: path, node, depth: (path ? path.depth : -1) + 1, arrays: new Set() };
|
|
313
305
|
} else {
|
|
314
|
-
const {
|
|
306
|
+
const { type, flags, attributes } = tag.value;
|
|
315
307
|
|
|
316
308
|
const attributes_ = doctype?.value.attributes ?? attributes;
|
|
317
|
-
const language_ = attributes?.['bablrLanguage'] ?? language;
|
|
318
309
|
|
|
319
310
|
const node = {
|
|
320
311
|
flags,
|
|
321
|
-
language: language_,
|
|
322
312
|
type,
|
|
323
313
|
children: [],
|
|
324
314
|
properties: {},
|
|
@@ -339,7 +329,7 @@ function* __treeFromStream(tags, options) {
|
|
|
339
329
|
}
|
|
340
330
|
|
|
341
331
|
if (!suppressTag) {
|
|
342
|
-
path.node.children =
|
|
332
|
+
path.node.children = Children.push(path.node.children, tag);
|
|
343
333
|
}
|
|
344
334
|
|
|
345
335
|
switch (tag.type) {
|
|
@@ -403,14 +393,12 @@ export const evaluateReturnAsync = async (generator) => {
|
|
|
403
393
|
return co.value;
|
|
404
394
|
};
|
|
405
395
|
|
|
406
|
-
export const streamFromTree = (rootNode, options = {}) => __streamFromTree(rootNode, options);
|
|
407
|
-
|
|
408
396
|
export const isEmpty = (node) => {
|
|
409
397
|
const { properties } = node;
|
|
410
398
|
|
|
411
399
|
let ref = null;
|
|
412
400
|
|
|
413
|
-
for (const tag of
|
|
401
|
+
for (const tag of Children.traverse(node.children)) {
|
|
414
402
|
switch (tag.type) {
|
|
415
403
|
case ReferenceTag: {
|
|
416
404
|
const { name } = tag.value;
|
|
@@ -431,8 +419,8 @@ export const isEmpty = (node) => {
|
|
|
431
419
|
break;
|
|
432
420
|
}
|
|
433
421
|
|
|
434
|
-
case
|
|
435
|
-
if (
|
|
422
|
+
case Property: {
|
|
423
|
+
if (tag.value.reference.type === '@') {
|
|
436
424
|
return false;
|
|
437
425
|
}
|
|
438
426
|
break;
|
|
@@ -449,7 +437,6 @@ export const isEmpty = (node) => {
|
|
|
449
437
|
export const buildStubNode = (tag) => {
|
|
450
438
|
return freeze({
|
|
451
439
|
flags: nodeFlags,
|
|
452
|
-
language: null,
|
|
453
440
|
type: null,
|
|
454
441
|
children: freeze([tag]),
|
|
455
442
|
properties: freeze({}),
|
|
@@ -457,9 +444,15 @@ export const buildStubNode = (tag) => {
|
|
|
457
444
|
});
|
|
458
445
|
};
|
|
459
446
|
|
|
447
|
+
export const streamFromTree = (rootNode, options = {}) => {
|
|
448
|
+
let rootNode_ = isPlainObject(rootNode) ? rootNode : rootNode.node;
|
|
449
|
+
|
|
450
|
+
return __streamFromTree(rootNode_, options);
|
|
451
|
+
};
|
|
452
|
+
|
|
460
453
|
function* __streamFromTree(rootNode, options) {
|
|
461
454
|
const { unshift = false } = options;
|
|
462
|
-
if (!rootNode || !
|
|
455
|
+
if (!rootNode || !Children.getSize(rootNode.children)) return;
|
|
463
456
|
|
|
464
457
|
let tagPath = TagPath.fromNode(rootNode, 0);
|
|
465
458
|
|
|
@@ -469,7 +462,14 @@ function* __streamFromTree(rootNode, options) {
|
|
|
469
462
|
if (tagPath.tag.type === OpenNodeTag) count++;
|
|
470
463
|
if (tagPath.tag.type === CloseNodeTag) count--;
|
|
471
464
|
|
|
472
|
-
|
|
465
|
+
if (
|
|
466
|
+
!(
|
|
467
|
+
tagPath.tag.type === AttributeDefinition ||
|
|
468
|
+
(tagPath.tag.type === BindingTag && !tagPath.tag.value.languagePath?.length)
|
|
469
|
+
)
|
|
470
|
+
) {
|
|
471
|
+
yield tagPath.tag;
|
|
472
|
+
}
|
|
473
473
|
} while ((tagPath = unshift ? tagPath.nextUnshifted : tagPath.next));
|
|
474
474
|
|
|
475
475
|
if (count !== 0) throw new Error();
|
|
@@ -487,26 +487,30 @@ export const getCooked = (cookable) => {
|
|
|
487
487
|
// const openTag = getOpenTag(cookable);
|
|
488
488
|
// const closeTag = getCloseTag(cookable);
|
|
489
489
|
|
|
490
|
-
let
|
|
490
|
+
let referenceTag = null;
|
|
491
491
|
|
|
492
|
-
for (
|
|
492
|
+
for (let tag of Children.traverse(children)) {
|
|
493
493
|
switch (tag.type) {
|
|
494
494
|
case ReferenceTag: {
|
|
495
|
-
|
|
495
|
+
let { type } = tag.value;
|
|
496
496
|
|
|
497
|
-
if (!(
|
|
497
|
+
if (!(type === '#' || type === '@')) {
|
|
498
498
|
throw new Error('cookable nodes must not contain other nodes');
|
|
499
499
|
}
|
|
500
500
|
|
|
501
|
-
|
|
501
|
+
referenceTag = tag;
|
|
502
502
|
break;
|
|
503
503
|
}
|
|
504
504
|
|
|
505
|
-
case
|
|
506
|
-
|
|
505
|
+
case BindingTag:
|
|
506
|
+
break;
|
|
507
|
+
|
|
508
|
+
case Property: {
|
|
509
|
+
let { node, reference } = tag.value;
|
|
510
|
+
let { attributes } = node;
|
|
507
511
|
|
|
508
|
-
if (reference.
|
|
509
|
-
|
|
512
|
+
if (reference.type === '@') {
|
|
513
|
+
let { cooked: cookedValue } = attributes;
|
|
510
514
|
|
|
511
515
|
if (!isString(cookedValue))
|
|
512
516
|
throw new Error('cannot cook string: it contains uncooked escapes');
|
|
@@ -556,22 +560,27 @@ export const sourceTextFor = printSource;
|
|
|
556
560
|
export const getRange = (node) => {
|
|
557
561
|
const { children } = node;
|
|
558
562
|
let path = Path.from(node);
|
|
559
|
-
return
|
|
563
|
+
return Children.getSize(children) ? [TagPath.from(path, 0), TagPath.from(path, -1)] : null;
|
|
560
564
|
};
|
|
561
565
|
|
|
562
566
|
export const createNode = (openTag) => {
|
|
563
567
|
if (!openTag || openTag.type === GapTag || openTag.type === NullTag) {
|
|
564
568
|
return {
|
|
565
569
|
flags: nodeFlags,
|
|
566
|
-
language: openTag?.language,
|
|
567
570
|
type: openTag && ([NullTag, GapTag].includes(openTag.type) ? null : openTag.type),
|
|
568
571
|
children: [],
|
|
569
572
|
properties: {},
|
|
570
573
|
attributes: openTag?.attributes || {},
|
|
571
574
|
};
|
|
572
575
|
} else {
|
|
573
|
-
const { flags,
|
|
574
|
-
return {
|
|
576
|
+
const { flags, type, attributes = {} } = openTag.value || {};
|
|
577
|
+
return {
|
|
578
|
+
flags,
|
|
579
|
+
type,
|
|
580
|
+
children: [],
|
|
581
|
+
properties: {},
|
|
582
|
+
attributes,
|
|
583
|
+
};
|
|
575
584
|
}
|
|
576
585
|
};
|
|
577
586
|
|
|
@@ -595,7 +604,7 @@ export const branchProperties = (properties) => {
|
|
|
595
604
|
|
|
596
605
|
for (const { 0: key, 1: value } of Object.entries(copy)) {
|
|
597
606
|
if (isArray(value)) {
|
|
598
|
-
copy[key] = btree.
|
|
607
|
+
copy[key] = btree.fromValues(value);
|
|
599
608
|
}
|
|
600
609
|
}
|
|
601
610
|
|
|
@@ -603,10 +612,9 @@ export const branchProperties = (properties) => {
|
|
|
603
612
|
};
|
|
604
613
|
|
|
605
614
|
export const branchNode = (node) => {
|
|
606
|
-
const { flags,
|
|
615
|
+
const { flags, type, children, properties, attributes } = node;
|
|
607
616
|
return {
|
|
608
617
|
flags,
|
|
609
|
-
language,
|
|
610
618
|
type,
|
|
611
619
|
children,
|
|
612
620
|
properties: branchProperties(properties),
|
|
@@ -622,10 +630,6 @@ export const acceptNode = (node, accepted) => {
|
|
|
622
630
|
return node;
|
|
623
631
|
};
|
|
624
632
|
|
|
625
|
-
export const getRoot = (node) => {
|
|
626
|
-
return node == null ? node : isFragmentNode(node) ? node.properties['.'].node : node;
|
|
627
|
-
};
|
|
628
|
-
|
|
629
633
|
export function* traverseProperties(properties) {
|
|
630
634
|
for (const value of Object.values(properties)) {
|
|
631
635
|
if (isArray(value)) {
|
|
@@ -641,3 +645,245 @@ export function* traverseProperties(properties) {
|
|
|
641
645
|
}
|
|
642
646
|
}
|
|
643
647
|
}
|
|
648
|
+
|
|
649
|
+
export const addToProperties = (properties, property) => {
|
|
650
|
+
let { reference, node: value } = property;
|
|
651
|
+
let { flags, name, isArray } = reference;
|
|
652
|
+
|
|
653
|
+
if (!name) throw new Error();
|
|
654
|
+
if (value === null) throw new Error();
|
|
655
|
+
if (!hasOwn(property, 'binding')) throw new Error();
|
|
656
|
+
|
|
657
|
+
if (Object.isFrozen(properties)) {
|
|
658
|
+
throw new Error('not implemented');
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
let isInitializer = value === undefined || Array.isArray(value);
|
|
662
|
+
|
|
663
|
+
let outerProperty = property;
|
|
664
|
+
|
|
665
|
+
if (flags.expression && !isInitializer) {
|
|
666
|
+
let shiftStack =
|
|
667
|
+
getFirstNodeShiftStack(value) ||
|
|
668
|
+
btree.fromValues([buildProperty(reference, null, buildStubNode(buildGapTag()))]);
|
|
669
|
+
|
|
670
|
+
shiftStack = btree.push(shiftStack, property);
|
|
671
|
+
outerProperty = buildProperty(reference, null, shiftStack);
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
if (isArray && !isInitializer) {
|
|
675
|
+
properties[name] = buildProperty(
|
|
676
|
+
reference,
|
|
677
|
+
null,
|
|
678
|
+
btree.push(properties[name]?.node || btree.fromValues([]), outerProperty),
|
|
679
|
+
);
|
|
680
|
+
} else {
|
|
681
|
+
properties[name] = outerProperty;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
return properties;
|
|
685
|
+
};
|
|
686
|
+
|
|
687
|
+
export const shiftToProperties = (properties, property) => {
|
|
688
|
+
let { reference, node: value } = property;
|
|
689
|
+
let { flags, name, isArray } = reference;
|
|
690
|
+
|
|
691
|
+
if (!name) throw new Error();
|
|
692
|
+
|
|
693
|
+
if (Object.isFrozen(properties)) {
|
|
694
|
+
throw new Error('not implemented');
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
if (!flags.expression) {
|
|
698
|
+
return addToProperties(properties, property);
|
|
699
|
+
}
|
|
700
|
+
let isInitializer = value === undefined || Array.isArray(value);
|
|
701
|
+
|
|
702
|
+
let outerProperty;
|
|
703
|
+
if (flags.expression && !isInitializer) {
|
|
704
|
+
let shiftStack =
|
|
705
|
+
getFirstNodeShiftStack(value) ||
|
|
706
|
+
btree.fromValues([buildProperty(reference, null, buildStubNode(buildGapTag()))]);
|
|
707
|
+
|
|
708
|
+
shiftStack = btree.push(shiftStack, property);
|
|
709
|
+
outerProperty = buildProperty(reference, null, shiftStack);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
if (isArray) {
|
|
713
|
+
properties[name] = buildProperty(
|
|
714
|
+
reference,
|
|
715
|
+
null,
|
|
716
|
+
btree.replaceAt(-1, properties[name].node, outerProperty),
|
|
717
|
+
);
|
|
718
|
+
} else {
|
|
719
|
+
properties[name] = outerProperty;
|
|
720
|
+
}
|
|
721
|
+
return properties;
|
|
722
|
+
};
|
|
723
|
+
|
|
724
|
+
export const addProperty = (node, property) => {
|
|
725
|
+
if (!node || !property) throw new Error();
|
|
726
|
+
if (!Object.isFrozen(property)) throw new Error();
|
|
727
|
+
|
|
728
|
+
let back1 = Children.getAt(-1, node.children);
|
|
729
|
+
let back2 = Children.getAt(-2, node.children);
|
|
730
|
+
|
|
731
|
+
let referenceTag;
|
|
732
|
+
let bindingTag = null;
|
|
733
|
+
|
|
734
|
+
if (property.node === null) {
|
|
735
|
+
throw new Error();
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
let { node: value } = property;
|
|
739
|
+
|
|
740
|
+
let isArrayInitializer = isArray(value);
|
|
741
|
+
let isInitializer = value === undefined || isArrayInitializer;
|
|
742
|
+
|
|
743
|
+
if (isArrayInitializer && value.length) throw new Error();
|
|
744
|
+
|
|
745
|
+
if (!isInitializer && property.node.type && !property.binding) {
|
|
746
|
+
throw new Error();
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
let foundShift = false;
|
|
750
|
+
let foundBinding = false;
|
|
751
|
+
if (back1.type === BindingTag) {
|
|
752
|
+
bindingTag = property.binding && back1;
|
|
753
|
+
referenceTag = back2;
|
|
754
|
+
foundShift = foundBinding = true;
|
|
755
|
+
} else if (back1.type === ReferenceTag) {
|
|
756
|
+
bindingTag = property.binding && buildChild(BindingTag, property.binding);
|
|
757
|
+
referenceTag = back1;
|
|
758
|
+
foundShift = true;
|
|
759
|
+
} else {
|
|
760
|
+
bindingTag = property.binding && buildChild(BindingTag, property.binding);
|
|
761
|
+
referenceTag = buildChild(ReferenceTag, property.reference);
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
if (!referenceTag) throw new Error();
|
|
765
|
+
|
|
766
|
+
if (isInitializer) {
|
|
767
|
+
if (property.reference.name) {
|
|
768
|
+
addToProperties(node.properties, property);
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
if (!foundShift) {
|
|
772
|
+
node.children = Children.push(node.children, referenceTag);
|
|
773
|
+
}
|
|
774
|
+
node.children = Children.push(node.children, buildInitializerTag(isArrayInitializer));
|
|
775
|
+
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
if (property.reference.name) {
|
|
780
|
+
addToProperties(node.properties, property);
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
if (!foundShift) {
|
|
784
|
+
node.children = Children.push(node.children, referenceTag);
|
|
785
|
+
}
|
|
786
|
+
if (!foundBinding && bindingTag) {
|
|
787
|
+
node.children = Children.push(node.children, bindingTag);
|
|
788
|
+
}
|
|
789
|
+
node.children = Children.push(node.children, buildChild(Property, property));
|
|
790
|
+
|
|
791
|
+
return node;
|
|
792
|
+
};
|
|
793
|
+
|
|
794
|
+
export const shiftProperty = (node, property) => {
|
|
795
|
+
if (!node || !property) throw new Error();
|
|
796
|
+
if (!property.reference) throw new Error();
|
|
797
|
+
if (!Object.isFrozen(property)) throw new Error();
|
|
798
|
+
|
|
799
|
+
let back1 = Children.getAt(-1, node.children);
|
|
800
|
+
let back2 = Children.getAt(-2, node.children);
|
|
801
|
+
|
|
802
|
+
let shiftTag;
|
|
803
|
+
let bindingTag = null;
|
|
804
|
+
|
|
805
|
+
if (property.node === null) {
|
|
806
|
+
property.node = buildNullNode();
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
let { node: value } = property;
|
|
810
|
+
|
|
811
|
+
let isArrayInitializer = isArray(value);
|
|
812
|
+
let isInitializer = value === undefined || isArrayInitializer;
|
|
813
|
+
|
|
814
|
+
if (!isInitializer && !property.binding) {
|
|
815
|
+
throw new Error();
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
let foundShift = false;
|
|
819
|
+
let foundBinding = false;
|
|
820
|
+
if (back1.type === BindingTag) {
|
|
821
|
+
bindingTag = back1;
|
|
822
|
+
shiftTag = back2;
|
|
823
|
+
foundShift = foundBinding = true;
|
|
824
|
+
|
|
825
|
+
if (bindingTag.value !== property.binding) throw new Error();
|
|
826
|
+
} else if ([ShiftTag, ReferenceTag].includes(back1.type)) {
|
|
827
|
+
bindingTag = buildChild(BindingTag, property.binding);
|
|
828
|
+
shiftTag = back1;
|
|
829
|
+
foundShift = true;
|
|
830
|
+
} else {
|
|
831
|
+
bindingTag = buildChild(BindingTag, property.binding);
|
|
832
|
+
shiftTag = buildChild(ReferenceTag, property.reference);
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
if (!shiftTag) throw new Error();
|
|
836
|
+
|
|
837
|
+
if (isInitializer) {
|
|
838
|
+
shiftToProperties(node.properties, property);
|
|
839
|
+
|
|
840
|
+
if (!foundShift) {
|
|
841
|
+
node.children = Children.push(node.children, shiftTag);
|
|
842
|
+
}
|
|
843
|
+
node.children = Children.push(node.children, buildInitializerTag(isArrayInitializer));
|
|
844
|
+
|
|
845
|
+
return;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
let shiftStack = node.properties[property.reference.name]?.node || btree.fromValues([]);
|
|
849
|
+
let stackSize = shiftStack && property.reference.flags.expression ? btree.getSize(shiftStack) : 0;
|
|
850
|
+
|
|
851
|
+
shiftToProperties(node.properties, property);
|
|
852
|
+
|
|
853
|
+
let index = shiftTag.type === ReferenceTag ? 1 : shiftTag.value.index + 1;
|
|
854
|
+
let height = btree.getSize(shiftStack) + 1;
|
|
855
|
+
|
|
856
|
+
let newShiftTag = stackSize ? buildShiftTag(index, height) : shiftTag;
|
|
857
|
+
|
|
858
|
+
if (!foundShift) {
|
|
859
|
+
node.children = Children.push(node.children, newShiftTag);
|
|
860
|
+
}
|
|
861
|
+
if (!foundBinding) {
|
|
862
|
+
node.children = Children.push(node.children, bindingTag);
|
|
863
|
+
}
|
|
864
|
+
node.children = Children.push(node.children, buildChild(Property, property));
|
|
865
|
+
|
|
866
|
+
return node;
|
|
867
|
+
};
|
|
868
|
+
|
|
869
|
+
export const add = (node, referenceTag, value, bindingTag) => {
|
|
870
|
+
let lastChild = Children.getAt(-1, node.children);
|
|
871
|
+
let reference = referenceTag.value;
|
|
872
|
+
let binding = bindingTag
|
|
873
|
+
? bindingTag.value
|
|
874
|
+
: lastChild.type === BindingTag
|
|
875
|
+
? lastChild.value
|
|
876
|
+
: buildBindingTag().value;
|
|
877
|
+
return addProperty(node, buildProperty(reference, binding, value));
|
|
878
|
+
};
|
|
879
|
+
|
|
880
|
+
export const shift = (node, referenceTag, value, bindingTag) => {
|
|
881
|
+
let lastChild = Children.getAt(-1, node.children);
|
|
882
|
+
let reference = referenceTag.value;
|
|
883
|
+
let binding = bindingTag
|
|
884
|
+
? bindingTag.value
|
|
885
|
+
: lastChild.type === BindingTag
|
|
886
|
+
? lastChild.value
|
|
887
|
+
: buildBindingTag().value;
|
|
888
|
+
return shiftProperty(node, buildProperty(reference, binding, value));
|
|
889
|
+
};
|