@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/tree.js CHANGED
@@ -1,45 +1,37 @@
1
- import { Coroutine } from '@bablr/coroutine';
2
1
  import {
3
- nodeFlags,
4
2
  buildReferenceTag,
5
- buildNullTag,
6
3
  buildOpenNodeTag,
7
4
  buildLiteralTag,
8
5
  buildCloseNodeTag,
9
6
  tokenFlags,
10
- buildInitializerTag,
11
- buildBindingTag,
12
- buildProperty,
13
7
  buildChild,
14
- buildShiftTag,
15
8
  buildGapTag,
16
- buildBinding,
17
- buildReference,
18
- multiFragmentFlags,
19
- buildPropertyWrapper,
9
+ buildOpenFragmentTag,
20
10
  } from './builders.js';
21
11
  import {
22
12
  printPrettyCSTML as printPrettyCSTMLFromStream,
23
13
  printCSTML as printCSTMLFromStream,
24
14
  printSource as printSourceFromStream,
25
- getStreamIterator,
15
+ treeFromStream,
16
+ treeFromStreamSync,
17
+ treeFromStreamAsync,
18
+ evaluateReturnSync,
19
+ evaluateReturnAsync,
26
20
  } from './stream.js';
27
21
  import {
28
- DoctypeTag,
29
22
  OpenNodeTag,
30
23
  CloseNodeTag,
31
24
  ReferenceTag,
32
25
  GapTag,
33
- NullTag,
34
- InitializerTag,
35
26
  LiteralTag,
36
27
  AttributeDefinition,
37
28
  BindingTag,
38
- Property,
39
29
  ShiftTag,
40
- PropertyWrapper,
30
+ Property,
31
+ NullNode,
32
+ TreeNode,
33
+ GapNode,
41
34
  } from './symbols.js';
42
- import * as BTree from './btree.js';
43
35
  import * as Tags from './tags.js';
44
36
  export * from './builders.js';
45
37
  export * from './print.js';
@@ -49,36 +41,37 @@ import {
49
41
  has,
50
42
  list,
51
43
  TagPath,
52
- Path,
53
- isFragmentNode,
44
+ isCover,
54
45
  isNullNode,
55
46
  isGapNode,
56
47
  getOpenTag,
57
48
  getCloseTag,
58
49
  getRoot,
59
- getRootArray,
60
- isStubTag,
61
- wrapperIsFull,
50
+ getTags,
62
51
  } from './path.js';
63
- import { isPlainObject } from './object.js';
52
+ import { freeze, isPlainObject } from './object.js';
64
53
 
65
54
  export {
66
55
  get,
67
56
  getOr,
68
57
  has,
69
58
  list,
70
- isFragmentNode,
59
+ isCover,
71
60
  isNullNode,
72
61
  isGapNode,
73
62
  getOpenTag,
74
63
  getCloseTag,
75
64
  getRoot,
76
- getRootArray,
65
+ treeFromStream,
66
+ treeFromStreamSync,
67
+ treeFromStreamAsync,
68
+ evaluateReturnSync,
69
+ evaluateReturnAsync,
77
70
  };
78
71
 
79
- export const buildToken = (type, value, attributes = {}) => {
72
+ export const buildToken = (name, value, attributes = {}) => {
80
73
  return treeFromStreamSync([
81
- buildOpenNodeTag(tokenFlags, type, attributes),
74
+ buildOpenNodeTag(tokenFlags, name, null, attributes),
82
75
  buildLiteralTag(value),
83
76
  buildCloseNodeTag(),
84
77
  ]);
@@ -87,10 +80,9 @@ export const buildToken = (type, value, attributes = {}) => {
87
80
  const isString = (str) => typeof str === 'string';
88
81
 
89
82
  const { isArray } = Array;
90
- const { freeze, hasOwn } = Object;
91
83
 
92
84
  export const mergeReferences = (outer, inner) => {
93
- let { type, name, isArray, index, flags: { expression, hasGap } = {} } = outer;
85
+ let { type, name, index, flags: { array, expression, intrinsic, hasGap } = {} } = outer;
94
86
 
95
87
  if (
96
88
  (name != null && inner.name != null && name !== inner.name) ||
@@ -99,13 +91,15 @@ export const mergeReferences = (outer, inner) => {
99
91
  return inner;
100
92
  }
101
93
 
102
- isArray = isArray || inner.isArray;
94
+ array = !!(array || inner.flags.array);
103
95
  expression = !!(expression || inner.flags.expression);
96
+ intrinsic = !!(intrinsic || inner.flags.intrinsic);
104
97
  hasGap = !!(hasGap || inner.flags.hasGap);
105
98
  name = type === '.' ? inner.name : name;
106
99
  type = type === '.' ? inner.type : type;
107
100
 
108
- return buildReferenceTag(type, name, isArray, { expression, hasGap }, index).value;
101
+ return buildReferenceTag(type, name, freeze({ array, expression, intrinsic, hasGap }), index)
102
+ .value;
109
103
  };
110
104
 
111
105
  export const mergeReferenceTags = (outer, inner) => {
@@ -114,297 +108,24 @@ export const mergeReferenceTags = (outer, inner) => {
114
108
  return buildChild(ReferenceTag, value);
115
109
  };
116
110
 
117
- export const isEmptyReference = (ref) => {
118
- let { type, isArray, flags } = ref.value;
119
- return type === '.' && !isArray && !(flags.expression || flags.hasGap);
120
- };
121
-
122
- function* __treeFromStream(tags, options) {
123
- let path = null;
124
- let rootPath = null;
125
- let held = null;
126
- let doctype = null;
127
- const co = new Coroutine(getStreamIterator(tags));
128
- const expressionsCo = new Coroutine(getStreamIterator(options.expressions || []));
129
- let referenceTag = null;
130
- let bindingTag = null;
131
-
132
- for (;;) {
133
- co.advance();
134
-
135
- if (co.current instanceof Promise) {
136
- co.current = yield co.current;
137
- }
138
-
139
- if (co.done) break;
140
-
141
- const tag = co.value;
142
-
143
- if (tag.type === 'Effect') {
144
- continue;
145
- }
146
-
147
- if (tag.type === DoctypeTag) {
148
- doctype = tag;
149
- continue;
150
- }
151
-
152
- if (held && tag.type !== OpenNodeTag && tag.type !== GapTag) {
153
- throw new Error('cannot eat this type of tag while holding');
154
- }
155
-
156
- let suppressTag = false;
157
-
158
- switch (tag.type) {
159
- case LiteralTag:
160
- break;
161
-
162
- case CloseNodeTag: {
163
- let { node } = path;
164
- if (!node.tags[1]) throw new Error();
165
- break;
166
- }
167
-
168
- case ReferenceTag: {
169
- referenceTag = tag;
170
- suppressTag = true;
171
- break;
172
- }
173
-
174
- case BindingTag: {
175
- bindingTag = tag;
176
- suppressTag = true;
177
- break;
178
- }
179
-
180
- case InitializerTag: {
181
- add(path.node, referenceTag, []);
182
- suppressTag = true;
183
- referenceTag = null;
184
- break;
185
- }
186
-
187
- case NullTag:
188
- case GapTag: {
189
- if (!path) {
190
- return buildStubNode(tag);
191
- }
192
-
193
- const isGap = tag.type === GapTag;
194
-
195
- if (path.parent && referenceTag.type !== ReferenceTag) throw new Error();
196
-
197
- let node = createNode(tag);
198
-
199
- suppressTag = true;
200
-
201
- if (isGap) {
202
- if (held) {
203
- node = held;
204
- add(path.node, referenceTag, node, bindingTag);
205
- } else if (!expressionsCo.done) {
206
- expressionsCo.advance();
207
-
208
- let outerReference = referenceTag;
209
-
210
- if (!expressionsCo.done) {
211
- node =
212
- node == null
213
- ? buildStubNode(buildNullTag())
214
- : expressionsCo.value == null
215
- ? buildStubNode(buildNullTag())
216
- : expressionsCo.value;
217
-
218
- if (isFragmentNode(node)) {
219
- const parentNode = path.node;
220
-
221
- let referenceTag;
222
- let bindingTag;
223
-
224
- for (const tag of Tags.traverse(node.tags)) {
225
- switch (tag.type) {
226
- case DoctypeTag: {
227
- break;
228
- }
229
-
230
- case OpenNodeTag: {
231
- referenceTag = bindingTag = null;
232
- if (!tag.value.type) {
233
- break;
234
- } else {
235
- throw new Error();
236
- }
237
- }
238
-
239
- case ReferenceTag:
240
- referenceTag = tag;
241
- break;
242
-
243
- case InitializerTag: {
244
- add(parentNode, mergeReferenceTags(outerReference, referenceTag), []);
245
- break;
246
- }
247
-
248
- case BindingTag: {
249
- bindingTag = tag;
250
- break;
251
- }
252
-
253
- case GapTag:
254
- case NullTag: {
255
- add(
256
- parentNode,
257
- mergeReferenceTags(outerReference, referenceTag),
258
- buildStubNode(tag),
259
- bindingTag,
260
- );
261
- referenceTag = bindingTag = null;
262
- break;
263
- }
264
-
265
- default:
266
- throw new Error();
267
- }
268
- }
269
- } else {
270
- if (path.node.flags.token) {
271
- throw new Error('not implemented');
272
- }
273
- add(path.node, referenceTag, node, bindingTag ?? buildBindingTag());
274
- }
275
- } else {
276
- if (!path.node.flags.token) {
277
- add(path.node, referenceTag, node, bindingTag ?? buildBindingTag());
278
- }
279
- }
280
- }
281
- }
282
-
283
- referenceTag = null;
284
- held = isGap ? null : held;
285
-
286
- if (!path.node.flags.token) {
287
- path = { parent: path, node, depth: (path.depth ?? -1) + 1, arrays: new Set() };
288
- }
289
-
290
- break;
291
- }
292
-
293
- // case ShiftTag: {
294
- // const { tags, properties } = path.node;
295
-
296
- // let property = properties[ref.value.name];
297
- // let node;
298
-
299
- // if (ref.value.isArray) {
300
- // ({ node } = btree.getAt(-1, property));
301
- // properties[ref.value.name].pop();
302
- // } else {
303
- // ({ node } = property);
304
- // properties[ref.value.name] = null;
305
- // }
306
-
307
- // held = node;
308
- // break;
309
- // }
310
-
311
- case OpenNodeTag: {
312
- const node = createNode(tag);
313
- if (path) {
314
- if (path) {
315
- add(path.node, referenceTag, node, bindingTag ?? buildBindingTag());
316
- referenceTag = null;
317
- }
318
-
319
- path = { parent: path, node, depth: (path ? path.depth : -1) + 1, arrays: new Set() };
320
- } else {
321
- path = { parent: null, node, depth: 0, arrays: new Set() };
322
-
323
- rootPath = path;
324
- }
325
-
326
- suppressTag = true;
327
- break;
328
- }
329
-
330
- default: {
331
- throw new Error();
332
- }
333
- }
334
-
335
- if (!suppressTag) {
336
- path.node.tags = Tags.push(path.node.tags, tag);
337
- }
338
-
339
- switch (tag.type) {
340
- case NullTag:
341
- case GapTag:
342
- case CloseNodeTag: {
343
- const completedNode = path.node;
344
-
345
- if (!(tag.type === GapTag && completedNode.flags.token)) {
346
- finalizeNode(completedNode);
347
- }
348
-
349
- if (tag.type === GapTag) {
350
- if (path && completedNode.type === null && completedNode.flags.token) {
351
- break;
352
- }
353
- }
354
-
355
- path = path.parent;
356
- break;
357
- }
358
- }
359
- }
360
-
361
- if (path && path.node.type) {
362
- throw new Error('imbalanced tag stack');
363
- }
364
-
365
- return rootPath.node;
366
- }
367
-
368
- export const buildNullNode = () => {
369
- return treeFromStreamSync([buildNullTag()]);
370
- };
371
-
372
- export const treeFromStream = (tags, options = {}) => __treeFromStream(tags, options);
111
+ export const documentFromStream = (tags, options) => {
112
+ throw new Error('not implemented');
373
113
 
374
- export const treeFromStreamSync = (tokens, options = {}) => {
375
- return evaluateReturnSync(treeFromStream(tokens, options));
376
- };
377
-
378
- export const treeFromStreamAsync = async (tokens, options = {}) => {
379
- return evaluateReturnAsync(treeFromStream(tokens, options));
380
- };
381
-
382
- export const evaluateReturnSync = (generator) => {
383
- const co = new Coroutine(generator[Symbol.iterator]());
384
- while (!co.done) co.advance();
385
- return co.value;
386
- };
114
+ // strip doctype tag off
387
115
 
388
- export const evaluateReturnAsync = async (generator) => {
389
- const co = new Coroutine(getStreamIterator(generator));
390
- while (!co.done) {
391
- co.advance();
392
-
393
- if (co.current instanceof Promise) {
394
- co.current = await co.current;
395
- }
396
- }
397
- return co.value;
116
+ // return buildChild(Document, freeze({ doctype, tree }));
398
117
  };
399
118
 
400
119
  export const isEmpty = (node) => {
401
- for (const tag of Tags.traverseInner(node.tags)) {
120
+ if (node == null) return true;
121
+
122
+ for (const tag of Tags.traverse(getTags(node))) {
402
123
  switch (tag.type) {
403
124
  case Property: {
404
- if (tag.value.reference.type === '@') {
125
+ if (tag.value.property.reference.type === '@') {
405
126
  return false;
406
127
  } else {
407
- const property = tag.value;
128
+ const { property } = tag.value;
408
129
 
409
130
  if (!isNullNode(property.node)) {
410
131
  return false;
@@ -421,36 +142,15 @@ export const isEmpty = (node) => {
421
142
  return true;
422
143
  };
423
144
 
424
- let buildGapProperty = () =>
425
- buildProperty(buildReference('.'), buildBinding(), buildStubNode(buildGapTag()));
426
-
427
- export const buildBounds = (
428
- openBoundary = BTree.fromValues([buildGapProperty()]),
429
- closeBoundary = openBoundary,
430
- ) => {
431
- return freeze([openBoundary, closeBoundary]);
432
- };
433
-
434
- export const buildStubNode = (tag) => {
435
- if (!isStubTag(tag)) throw new Error();
436
- return freeze({
437
- flags: nodeFlags,
438
- type: null,
439
- bounds: buildBounds(null, null),
440
- tags: Tags.from(tag),
441
- attributes: freeze({}),
442
- });
443
- };
444
-
445
145
  export const streamFromTree = (tree, options = {}) => {
446
- let rootNode = isPlainObject(tree) ? tree : tree.node;
146
+ if (tree && !isPlainObject(tree)) throw new Error();
447
147
 
448
- return __streamFromTree(null, rootNode, options);
148
+ return __streamFromTree(null, tree, options);
449
149
  };
450
150
 
451
151
  function* __streamFromTree(doctypeTag, rootNode, options) {
452
152
  const { unshift = false } = options;
453
- if (!rootNode || !Tags.getSize(rootNode.tags)) return;
153
+ if (!rootNode || !Tags.getSize(getTags(rootNode))) return;
454
154
 
455
155
  let tagPath = TagPath.fromNode(rootNode, 0);
456
156
 
@@ -461,26 +161,24 @@ function* __streamFromTree(doctypeTag, rootNode, options) {
461
161
  }
462
162
 
463
163
  do {
464
- if (tagPath.tag.type === OpenNodeTag && !tagPath.tag.value.literalValue) count++;
164
+ if (tagPath.tag.type === OpenNodeTag && !tagPath.tag.value.selfClosing) count++;
465
165
  if (tagPath.tag.type === CloseNodeTag) count--;
466
166
 
467
167
  if (
468
168
  !(
469
169
  tagPath.tag.type === AttributeDefinition ||
470
- (tagPath.tag.type === BindingTag && !tagPath.tag.value.languagePath?.length)
170
+ (tagPath.tag.type === BindingTag && !tagPath.tag.value.segments?.length)
471
171
  )
472
172
  ) {
473
173
  yield tagPath.tag;
474
174
  }
475
175
  } while ((tagPath = unshift ? tagPath.nextUnshifted : tagPath.next));
476
176
 
477
- if (count !== 0) throw new Error();
177
+ // if (count !== 0) throw new Error();
478
178
  }
479
179
 
480
180
  export const vcsStreamFromTree = (rootNode) => {
481
- let rootNode_ = isPlainObject(rootNode) ? rootNode : rootNode.node;
482
-
483
- return __vcsStreamFromTree(rootNode_);
181
+ return __vcsStreamFromTree(rootNode);
484
182
  };
485
183
 
486
184
  function* __vcsStreamFromTree(rootNode) {
@@ -490,7 +188,7 @@ function* __vcsStreamFromTree(rootNode) {
490
188
  let nodeShifted = false;
491
189
  let i = 0;
492
190
  let seenFirstProperty = false;
493
- let node = Tags.getValues(rootNode.tags);
191
+ let node = Tags.getValues(rootNode.value.tags);
494
192
 
495
193
  outer: while (node) {
496
194
  while (i >= node.length) {
@@ -514,7 +212,7 @@ function* __vcsStreamFromTree(rootNode) {
514
212
  if (isArray(child)) {
515
213
  stack = { stack, agastNode, node, depth, i, nodeShifted, seenFirstProperty };
516
214
 
517
- yield buildOpenNodeTag(multiFragmentFlags);
215
+ yield buildOpenFragmentTag();
518
216
 
519
217
  node = Tags.getValues(child);
520
218
  depth++;
@@ -522,10 +220,12 @@ function* __vcsStreamFromTree(rootNode) {
522
220
  } else {
523
221
  let wrappedTag = child;
524
222
 
525
- if (wrappedTag.type === PropertyWrapper) {
223
+ if (wrappedTag.type === Property) {
526
224
  for (let tag of wrappedTag.value.tags) {
527
225
  switch (tag.type) {
528
- case Property: {
226
+ case TreeNode:
227
+ case NullNode:
228
+ case GapNode: {
529
229
  let replaceWithGap = nodeShifted && !seenFirstProperty;
530
230
 
531
231
  if (replaceWithGap) {
@@ -536,11 +236,11 @@ function* __vcsStreamFromTree(rootNode) {
536
236
  break;
537
237
  } else {
538
238
  stack = { stack, agastNode, node, depth, i, nodeShifted, seenFirstProperty: true };
539
- node = Tags.getValues(tag.value.node.tags);
239
+ node = Tags.getValues(tag.value.tags);
540
240
 
541
241
  depth++;
542
242
  i = 0;
543
- agastNode = tag.value.node;
243
+ agastNode = tag.value;
544
244
  nodeShifted = wrappedTag.value.tags[0].type === ShiftTag;
545
245
  seenFirstProperty = false;
546
246
  continue outer;
@@ -573,11 +273,11 @@ function* __vcsStreamFromTree(rootNode) {
573
273
  }
574
274
 
575
275
  export const getCooked = (cookable) => {
576
- if (!cookable || isGapNode(cookable.type)) {
276
+ if (!cookable || isGapNode(cookable)) {
577
277
  return '';
578
278
  }
579
279
 
580
- const tags = cookable.tags || cookable;
280
+ const tags = getTags(cookable) || cookable;
581
281
 
582
282
  let cooked = '';
583
283
 
@@ -602,9 +302,9 @@ export const getCooked = (cookable) => {
602
302
  case BindingTag:
603
303
  break;
604
304
 
605
- case PropertyWrapper: {
606
- let { node, reference } = tag.value.property;
607
- let { attributes } = node;
305
+ case Property: {
306
+ let { node, reference } = tag.value;
307
+ let { attributes } = node.value;
608
308
 
609
309
  if (reference.type === '@') {
610
310
  let { cooked: cookedValue } = attributes;
@@ -618,6 +318,10 @@ export const getCooked = (cookable) => {
618
318
  break;
619
319
  }
620
320
 
321
+ case GapTag: {
322
+ return null;
323
+ }
324
+
621
325
  case LiteralTag: {
622
326
  cooked += tag.value;
623
327
  break;
@@ -654,34 +358,6 @@ export const printSource = (tree) => {
654
358
 
655
359
  export const sourceTextFor = printSource;
656
360
 
657
- export const getRange = (node) => {
658
- const { tags } = node;
659
- let path = Path.from(node);
660
- return Tags.getSize(tags) ? [TagPath.from(path, 0), TagPath.from(path, -1)] : null;
661
- };
662
-
663
- export const createNode = (openTag) => {
664
- let bounds = buildBounds();
665
- let literalTags = [];
666
- let tags = openTag ? Tags.fromValues([openTag, ...literalTags]) : Tags.fromValues(literalTags);
667
- let flags, type, attributes;
668
-
669
- if (!openTag || openTag.type === GapTag || openTag.type === NullTag) {
670
- flags = nodeFlags;
671
- type = openTag && ([NullTag, GapTag].includes(openTag.type) ? null : openTag.type);
672
- attributes = openTag?.attributes || {};
673
- } else {
674
- ({ flags, type, attributes = {} } = openTag.value || {});
675
- }
676
- return { flags, type, bounds, tags, attributes };
677
- };
678
-
679
- export const finalizeNode = (node) => {
680
- freeze(node);
681
- freeze(node.attributes);
682
- return node;
683
- };
684
-
685
361
  export const notNull = (node) => {
686
362
  return node != null && !isNullNode(node);
687
363
  };
@@ -689,133 +365,3 @@ export const notNull = (node) => {
689
365
  export const isNull = (node) => {
690
366
  return node == null || isNullNode(node);
691
367
  };
692
-
693
- export const addProperty = (node, property) => {
694
- if (!node || !property) throw new Error();
695
- if (!Object.isFrozen(property)) throw new Error();
696
-
697
- if (property.node === null) {
698
- throw new Error();
699
- }
700
-
701
- let { node: value, binding, reference } = property;
702
-
703
- let isArrayInitializer = reference.type !== '_' && isArray(value);
704
- let isInitializer = value === undefined || isArrayInitializer;
705
-
706
- if (isArrayInitializer && value.length) throw new Error();
707
-
708
- if (!isInitializer && property.node.type && !property.binding) {
709
- throw new Error();
710
- }
711
-
712
- if (reference.type === '_') {
713
- node.tags = Tags.push(node.tags, value);
714
- return node;
715
- }
716
-
717
- let referenceTag = buildChild(ReferenceTag, reference);
718
- let propertyWrapper;
719
-
720
- if (isInitializer) {
721
- let tags = freeze([referenceTag, buildInitializerTag(isArrayInitializer)]);
722
-
723
- propertyWrapper = buildPropertyWrapper(
724
- tags,
725
- buildProperty(reference, null, isArrayInitializer ? [] : null),
726
- );
727
- } else {
728
- let tags = freeze([
729
- referenceTag,
730
- buildChild(BindingTag, binding),
731
- buildChild(Property, property),
732
- ]);
733
-
734
- propertyWrapper = buildPropertyWrapper(tags, property);
735
- }
736
-
737
- let lastTag = Tags.getAt(-1, node.tags);
738
- let unboundProperty = lastTag.type === PropertyWrapper && lastTag.value.tags.length < 3;
739
-
740
- if (unboundProperty) {
741
- node.tags = Tags.replaceAt(-1, node.tags, buildChild(PropertyWrapper, propertyWrapper));
742
- } else {
743
- node.tags = Tags.push(node.tags, buildChild(PropertyWrapper, propertyWrapper));
744
- }
745
-
746
- return node;
747
- };
748
-
749
- export const shiftProperty = (node, property) => {
750
- if (!node || !property) throw new Error();
751
- if (!property.reference) throw new Error();
752
- if (!Object.isFrozen(property)) throw new Error();
753
-
754
- if (property.node === null) {
755
- property.node = buildNullNode();
756
- }
757
-
758
- let { node: value } = property;
759
-
760
- let isArrayInitializer = isArray(value);
761
- let isInitializer = value === undefined || isArrayInitializer;
762
-
763
- if (isInitializer || !property.binding) {
764
- throw new Error();
765
- }
766
-
767
- let existingProperty = Tags.getAt(-1, node.tags);
768
-
769
- if (!wrapperIsFull(existingProperty)) {
770
- existingProperty = Tags.getAt(-2, node.tags);
771
- }
772
-
773
- let existingRef = existingProperty?.value.tags[0];
774
-
775
- let bindingTag = buildChild(BindingTag, property.binding);
776
-
777
- let shiftStack = existingProperty?.value.property.node.bounds[0] || BTree.fromValues([]);
778
- let stackSize = shiftStack && property.reference.flags.expression ? BTree.getSize(shiftStack) : 0;
779
-
780
- let index = existingRef.type === ReferenceTag ? 1 : existingRef.value.index + 1;
781
- let height = BTree.getSize(shiftStack) + 1;
782
-
783
- let shiftTag = stackSize ? buildShiftTag(index, height) : existingRef;
784
-
785
- let tags = freeze([shiftTag, bindingTag, buildChild(Property, property)]);
786
-
787
- let lastTag = Tags.getAt(-1, node.tags);
788
- let unboundProperty = lastTag.type === PropertyWrapper && lastTag.value.tags.length < 3;
789
-
790
- let propertyWrapper = buildPropertyWrapper(tags, property);
791
-
792
- if (unboundProperty) {
793
- node.tags = Tags.replaceAt(-1, node.tags, buildChild(PropertyWrapper, propertyWrapper));
794
- } else {
795
- node.tags = Tags.push(node.tags, buildChild(PropertyWrapper, propertyWrapper));
796
- }
797
-
798
- return node;
799
- };
800
-
801
- export const add = (node, referenceTag, value, bindingTag) => {
802
- let lastChild = Tags.getAt(-1, node.tags);
803
- let reference = referenceTag.value;
804
- let binding = bindingTag
805
- ? bindingTag.value
806
- : lastChild?.type === BindingTag
807
- ? lastChild.value
808
- : buildBinding();
809
- return addProperty(node, buildProperty(reference, binding, value));
810
- };
811
-
812
- export const shift = (node, referenceTag, value, bindingTag) => {
813
- let lastChild = Tags.getAt(-1, node.tags);
814
- let reference = referenceTag.value;
815
- let binding = bindingTag
816
- ? bindingTag.value
817
- : lastChild.type === BindingTag
818
- ? lastChild.value
819
- : buildBinding();
820
- return shiftProperty(node, buildProperty(reference, binding, value));
821
- };