@bablr/agast-helpers 0.8.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 +159 -88
- package/lib/path.js +1571 -419
- package/lib/print.js +78 -41
- package/lib/shorthand.js +17 -13
- package/lib/stream.js +437 -164
- package/lib/symbols.js +5 -2
- package/lib/tags.js +285 -0
- package/lib/template.js +52 -46
- package/lib/tree.js +165 -687
- package/package.json +6 -4
- package/lib/children.js +0 -120
- package/lib/path-facade.js +0 -39
package/lib/path.js
CHANGED
|
@@ -1,19 +1,230 @@
|
|
|
1
1
|
import { WeakStackFrame } from '@bablr/weak-stack';
|
|
2
|
-
import * as
|
|
3
|
-
import * as
|
|
2
|
+
import * as BTree from '@bablr/agast-helpers/btree';
|
|
3
|
+
import * as Tags from './tags.js';
|
|
4
4
|
import {
|
|
5
5
|
ReferenceTag,
|
|
6
|
-
InitializerTag,
|
|
7
|
-
DoctypeTag,
|
|
8
|
-
OpenNodeTag,
|
|
9
6
|
CloseNodeTag,
|
|
10
7
|
GapTag,
|
|
11
8
|
NullTag,
|
|
12
9
|
ShiftTag,
|
|
13
10
|
BindingTag,
|
|
14
11
|
Property,
|
|
12
|
+
OpenNodeTag,
|
|
13
|
+
AttributeDefinition,
|
|
14
|
+
LiteralTag,
|
|
15
|
+
TreeNode,
|
|
16
|
+
NullNode,
|
|
17
|
+
GapNode,
|
|
18
|
+
Document,
|
|
15
19
|
} from './symbols.js';
|
|
16
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
immSet,
|
|
22
|
+
isPlainObject,
|
|
23
|
+
isString,
|
|
24
|
+
has as objHas,
|
|
25
|
+
get as objGet,
|
|
26
|
+
isObject,
|
|
27
|
+
isSymbol,
|
|
28
|
+
} from './object.js';
|
|
29
|
+
import {
|
|
30
|
+
buildReferenceTag,
|
|
31
|
+
buildChild,
|
|
32
|
+
buildProperty,
|
|
33
|
+
buildGapTag,
|
|
34
|
+
buildNullTag,
|
|
35
|
+
buildOpenNodeTag,
|
|
36
|
+
buildShift,
|
|
37
|
+
buildPropertyTag,
|
|
38
|
+
} from './builders.js';
|
|
39
|
+
|
|
40
|
+
export const incrementShift = (shift) => {
|
|
41
|
+
if (!shift) return buildShift(1, 3);
|
|
42
|
+
|
|
43
|
+
return buildShift(shift.index + 1, shift.height + 1);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const finalizeNode = (node) => {
|
|
47
|
+
freeze(node);
|
|
48
|
+
freeze(node.value);
|
|
49
|
+
|
|
50
|
+
return node;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export const buildNode = (tags) => {
|
|
54
|
+
if (isArray(tags) && !Number.isFinite(tags[0])) throw new Error();
|
|
55
|
+
if (!isArray(tags) && !isSymbol(tags.type)) throw new Error();
|
|
56
|
+
let tags_ = isArray(tags) ? tags : Tags.fromValues([tags]);
|
|
57
|
+
|
|
58
|
+
if (!Number.isFinite(tags_[0])) throw new Error();
|
|
59
|
+
if (!isArray(tags_[1]) || !tags_[1].length) throw new Error();
|
|
60
|
+
|
|
61
|
+
let openTag = tags_[1][0];
|
|
62
|
+
if (![GapTag, NullTag, OpenNodeTag].includes(openTag.type)) throw new Error();
|
|
63
|
+
// let tags = openTag ? Tags.fromValues([openTag]) : Tags.fromValues([]);
|
|
64
|
+
|
|
65
|
+
if (openTag.type === GapTag) {
|
|
66
|
+
return finalizeNode({
|
|
67
|
+
type: GapNode,
|
|
68
|
+
value: {
|
|
69
|
+
tags: Tags.fromValues([openTag]),
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
} else if (openTag.type === NullTag) {
|
|
73
|
+
return finalizeNode({
|
|
74
|
+
type: NullNode,
|
|
75
|
+
value: { tags: Tags.fromValues([openTag]) },
|
|
76
|
+
});
|
|
77
|
+
} else if (openTag.type === OpenNodeTag) {
|
|
78
|
+
return finalizeNode({
|
|
79
|
+
type: TreeNode,
|
|
80
|
+
value: {
|
|
81
|
+
flags: openTag.value.flags,
|
|
82
|
+
type: openTag.value.type,
|
|
83
|
+
name: openTag.value.name,
|
|
84
|
+
attributes: openTag.value.attributes,
|
|
85
|
+
tags: tags_,
|
|
86
|
+
children: tags_[1][1] || Tags.fromValues([]),
|
|
87
|
+
bounds: buildBoundsFromTags(tags_),
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
} else {
|
|
91
|
+
throw new Error();
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const buildBoundsFromTags = (tags) => {
|
|
96
|
+
let gapProperty = buildProperty([buildReferenceTag(), [], buildNode(buildGapTag())]);
|
|
97
|
+
let bounds = [BTree.fromValues([gapProperty]), BTree.fromValues([gapProperty])];
|
|
98
|
+
let firstProperty, lastProperty;
|
|
99
|
+
|
|
100
|
+
if (Tags.getAt(-1, tags)?.type !== CloseNodeTag) {
|
|
101
|
+
return freeze(bounds);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
for (let i = 1; i < Tags.getSize(tags); i++) {
|
|
105
|
+
let tag = Tags.getAt(i, tags);
|
|
106
|
+
|
|
107
|
+
if (tag.type === Property && !isNullNode(tag.value.node)) {
|
|
108
|
+
firstProperty = tag;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
for (let i = Tags.getSize(tags) - 2; i >= 0; i--) {
|
|
114
|
+
let tag = Tags.getAt(i, tags);
|
|
115
|
+
|
|
116
|
+
if (tag.type === Property && !isNullNode(tag.value.node)) {
|
|
117
|
+
lastProperty = tag;
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (firstProperty && firstProperty.value.node.type === TreeNode) {
|
|
123
|
+
let openStack = firstProperty.value.node.value.bounds[0];
|
|
124
|
+
|
|
125
|
+
openStack = BTree.pop(openStack);
|
|
126
|
+
openStack = BTree.push(openStack, firstProperty);
|
|
127
|
+
openStack = BTree.concat(openStack, BTree.pop(bounds[0]));
|
|
128
|
+
openStack = BTree.push(
|
|
129
|
+
openStack,
|
|
130
|
+
buildPropertyTag([buildReferenceTag(), [], buildNode(buildGapTag())]),
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
bounds[0] = openStack;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
let closeStack = bounds[1];
|
|
137
|
+
|
|
138
|
+
if (lastProperty && lastProperty.value.type === TreeNode) {
|
|
139
|
+
if (!lastProperty.value.node) throw new Error();
|
|
140
|
+
|
|
141
|
+
closeStack = lastProperty.value.node.value.bounds[1];
|
|
142
|
+
|
|
143
|
+
closeStack = closeStack
|
|
144
|
+
? BTree.replaceAt(-1, closeStack, lastProperty)
|
|
145
|
+
: BTree.fromValues([lastProperty]);
|
|
146
|
+
|
|
147
|
+
closeStack = BTree.push(
|
|
148
|
+
closeStack,
|
|
149
|
+
buildPropertyTag([buildReferenceTag(), [], buildNode(buildGapTag())]),
|
|
150
|
+
);
|
|
151
|
+
bounds[1] = closeStack;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return freeze(bounds);
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export const isNode = (value) => {
|
|
158
|
+
return [TreeNode, NullNode, GapNode].includes(value?.type);
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
export const endsNode = (tag) => {
|
|
162
|
+
return (
|
|
163
|
+
[CloseNodeTag, NullTag, GapTag].includes(tag.type) ||
|
|
164
|
+
(tag.type === OpenNodeTag && tag.value.selfClosing)
|
|
165
|
+
);
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
export const propertyIsFull = (tag) => {
|
|
169
|
+
if (tag.type !== Property) return true;
|
|
170
|
+
|
|
171
|
+
let { tags } = tag.value;
|
|
172
|
+
|
|
173
|
+
return tags.length === 3;
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
export const nodeIsComplete = (node) => {
|
|
177
|
+
let sigilTag = getOpenTag(node);
|
|
178
|
+
return sigilTag.type !== OpenNodeTag || sigilTag.value.selfClosing ? true : !!getCloseTag(node);
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
export const getTags = (node) => {
|
|
182
|
+
switch (node.type) {
|
|
183
|
+
case TreeNode:
|
|
184
|
+
return node.value.tags;
|
|
185
|
+
case NullNode:
|
|
186
|
+
return node.value.tags;
|
|
187
|
+
case GapNode:
|
|
188
|
+
return node.value.tags;
|
|
189
|
+
case Document:
|
|
190
|
+
return getTags(node.value.tree);
|
|
191
|
+
default:
|
|
192
|
+
throw new Error();
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
export const offsetForTag = (tag) => {
|
|
197
|
+
switch (tag.type) {
|
|
198
|
+
case ReferenceTag:
|
|
199
|
+
case ShiftTag:
|
|
200
|
+
return [0];
|
|
201
|
+
case BindingTag:
|
|
202
|
+
return [1, -1];
|
|
203
|
+
default:
|
|
204
|
+
return [];
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
export const isNodeTag = (tag) => {
|
|
209
|
+
switch (tag.type) {
|
|
210
|
+
case TreeNode:
|
|
211
|
+
case NullNode:
|
|
212
|
+
case GapNode:
|
|
213
|
+
return true;
|
|
214
|
+
default:
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
export const arraysEqual = (a, b) => {
|
|
220
|
+
if (a.length !== b.length) return false;
|
|
221
|
+
|
|
222
|
+
for (let i = 0; i < a.length; i++) {
|
|
223
|
+
if (a[i] !== b[i]) return false;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return true;
|
|
227
|
+
};
|
|
17
228
|
|
|
18
229
|
export const buildPathSegment = (name, index = null, shiftIndex = null) => {
|
|
19
230
|
if (!name) throw new Error();
|
|
@@ -29,90 +240,114 @@ export const buildFullPathSegment = (type, name, index = null, shiftIndex = null
|
|
|
29
240
|
return { type, name, index, shiftIndex };
|
|
30
241
|
};
|
|
31
242
|
|
|
32
|
-
export const
|
|
33
|
-
if (node == null || !
|
|
34
|
-
return
|
|
243
|
+
export const getRootProperty = (node) => {
|
|
244
|
+
if (node == null || !isCover(node)) {
|
|
245
|
+
return null;
|
|
35
246
|
}
|
|
36
|
-
let idx =
|
|
247
|
+
let idx = getPropertyTagsIndex(node, '_', null);
|
|
37
248
|
|
|
38
249
|
if (idx == null) return null;
|
|
39
250
|
|
|
40
|
-
let tag =
|
|
251
|
+
let tag = Tags.getAt(idx, getTags(node));
|
|
41
252
|
|
|
42
253
|
if (tag.type !== Property) throw new Error();
|
|
43
|
-
return tag
|
|
254
|
+
return tag;
|
|
44
255
|
};
|
|
45
256
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
257
|
+
// TODO prevent infinite recursion
|
|
258
|
+
export const getRoot = (node, depth = Infinity) => {
|
|
259
|
+
let node_ = node;
|
|
260
|
+
let i = 0;
|
|
261
|
+
|
|
262
|
+
while (isCover(node_) && i < depth) {
|
|
263
|
+
node_ = getRootProperty(node_)?.value.node;
|
|
264
|
+
i++;
|
|
55
265
|
}
|
|
56
|
-
|
|
266
|
+
|
|
267
|
+
return node_;
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
export const getSigilTag = (node) => {
|
|
271
|
+
return Tags.getValues(getTags(node))[0];
|
|
57
272
|
};
|
|
58
273
|
|
|
59
274
|
export const getOpenTag = (node) => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (tag.type === NullTag || tag.type === GapTag) return null;
|
|
63
|
-
if (tag.type === DoctypeTag) {
|
|
64
|
-
tag = Children.getAt(1, node.children);
|
|
65
|
-
}
|
|
66
|
-
if (tag && tag.type !== OpenNodeTag) throw new Error();
|
|
67
|
-
return tag;
|
|
275
|
+
let tag = Tags.getValues(getTags(node))[0];
|
|
276
|
+
return tag.type === OpenNodeTag ? tag : null;
|
|
68
277
|
};
|
|
69
278
|
|
|
70
279
|
export const getCloseTag = (node) => {
|
|
71
|
-
|
|
72
|
-
const tag = Children.getAt(-1, children);
|
|
73
|
-
if (tag.type !== CloseNodeTag) return null;
|
|
74
|
-
return tag;
|
|
280
|
+
return Tags.getValues(getTags(node))[2];
|
|
75
281
|
};
|
|
76
282
|
|
|
77
283
|
export const isNullNode = (node) => {
|
|
78
|
-
return node &&
|
|
284
|
+
return node && Tags.getAt(0, getTags(node)).type === NullTag;
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
export const isCover = (node) => {
|
|
288
|
+
return node?.type === TreeNode && node.value.type === Symbol.for('_');
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
export const getChildren = (node) => {
|
|
292
|
+
return node?.type === TreeNode ? node.value.children : [];
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
export const isFragment = (node) => {
|
|
296
|
+
return node?.type === TreeNode && [Symbol.for('__'), Symbol.for('_')].includes(node.value.type);
|
|
79
297
|
};
|
|
80
298
|
|
|
81
|
-
export const
|
|
82
|
-
return node
|
|
299
|
+
export const isMultiFragment = (node) => {
|
|
300
|
+
return node?.type === TreeNode && node.value.type === Symbol.for('__');
|
|
83
301
|
};
|
|
84
302
|
|
|
85
303
|
export const isGapNode = (node) => {
|
|
86
|
-
return node &&
|
|
304
|
+
return node && Tags.getAt(0, getTags(node)).type === GapTag;
|
|
87
305
|
};
|
|
88
306
|
|
|
89
307
|
export const isStubNode = (node) => {
|
|
90
|
-
return (
|
|
91
|
-
|
|
92
|
-
|
|
308
|
+
return node && [GapTag, NullTag].includes(Tags.getAt(0, getTags(node)).type);
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
export const isStubTag = (tag) => {
|
|
312
|
+
return [GapTag, NullTag].includes(tag.type);
|
|
93
313
|
};
|
|
94
314
|
|
|
95
|
-
export const getChildPropertyIndex = (agAstNode,
|
|
96
|
-
let child =
|
|
315
|
+
export const getChildPropertyIndex = (agAstNode, tagsIndex) => {
|
|
316
|
+
let child = Tags.getAt(tagsIndex, agAstNode.value.tags);
|
|
317
|
+
|
|
318
|
+
if (child.type !== Property) return null;
|
|
97
319
|
|
|
98
|
-
let
|
|
320
|
+
let tag = child.value.tags[0];
|
|
99
321
|
|
|
100
|
-
let
|
|
322
|
+
let refIndex = tag.type === ShiftTag ? tagsIndex - tag.value.index : tagsIndex;
|
|
323
|
+
|
|
324
|
+
let stack = Tags.findPath(refIndex, agAstNode.value.tags);
|
|
101
325
|
let { node, index: leafIdx } = stack.value;
|
|
102
|
-
let leaf =
|
|
326
|
+
let leaf = Tags.getAt(leafIdx, node);
|
|
327
|
+
|
|
328
|
+
if (leaf.type !== Property) {
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
103
331
|
|
|
104
|
-
|
|
332
|
+
let leafRefTag = leaf.value.tags[0];
|
|
105
333
|
|
|
106
|
-
|
|
334
|
+
if (leafRefTag.type !== ReferenceTag) return null;
|
|
335
|
+
|
|
336
|
+
let { name, flags } = leafRefTag.value;
|
|
107
337
|
let count = -1;
|
|
108
338
|
|
|
109
|
-
if (!
|
|
339
|
+
if (!name) throw new Error();
|
|
340
|
+
|
|
341
|
+
if (!flags.array) return null;
|
|
110
342
|
|
|
111
343
|
for (let i = leafIdx; i >= 0; i--) {
|
|
112
|
-
let value =
|
|
344
|
+
let value = Tags.getAt(i, node);
|
|
345
|
+
if (value.type === Property) {
|
|
346
|
+
let firstTag = value.value.tags[0];
|
|
113
347
|
|
|
114
|
-
|
|
115
|
-
|
|
348
|
+
if (firstTag.type === ReferenceTag && firstTag.value.name === name) {
|
|
349
|
+
count++;
|
|
350
|
+
}
|
|
116
351
|
}
|
|
117
352
|
}
|
|
118
353
|
stack = stack.pop();
|
|
@@ -123,11 +358,16 @@ export const getChildPropertyIndex = (agAstNode, childrenIndex) => {
|
|
|
123
358
|
|
|
124
359
|
do {
|
|
125
360
|
for (let i = leafIdx - 1; i >= 0; i--) {
|
|
126
|
-
let
|
|
127
|
-
let { references } = Children.getSums(childNode);
|
|
361
|
+
let value = Tags.getValues(node)[i];
|
|
128
362
|
|
|
129
|
-
if (
|
|
130
|
-
|
|
363
|
+
if (Array.isArray(value)) {
|
|
364
|
+
let childNode = value;
|
|
365
|
+
let { references } = Tags.getSums(childNode);
|
|
366
|
+
|
|
367
|
+
let res;
|
|
368
|
+
if ((res = Tags.getAtName(name, references))) {
|
|
369
|
+
count += res;
|
|
370
|
+
}
|
|
131
371
|
}
|
|
132
372
|
}
|
|
133
373
|
stack = stack.pop();
|
|
@@ -141,69 +381,106 @@ export const getChildPropertyIndex = (agAstNode, childrenIndex) => {
|
|
|
141
381
|
return count - 1;
|
|
142
382
|
};
|
|
143
383
|
|
|
144
|
-
export const
|
|
145
|
-
let
|
|
146
|
-
let
|
|
147
|
-
let
|
|
384
|
+
export const getPropertyTagsIndex = (agAstNode, type, name, index, shiftIndex) => {
|
|
385
|
+
let firstPropsIndex = __getPropertyTagsIndex(agAstNode, type, name, 0);
|
|
386
|
+
let prop = firstPropsIndex == null ? null : Tags.getAt(firstPropsIndex, getTags(agAstNode));
|
|
387
|
+
let ref = prop?.value.reference;
|
|
388
|
+
let sums = Tags.getSums(agAstNode.value.tags);
|
|
389
|
+
let counts = name ? sums.references : sums.specialTypes;
|
|
148
390
|
|
|
149
|
-
if (
|
|
150
|
-
if (index
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
391
|
+
if (ref?.flags.array) {
|
|
392
|
+
if (index < 0) {
|
|
393
|
+
index = Tags.getAtName(type, counts) + index;
|
|
394
|
+
} else if (index == null) {
|
|
395
|
+
index = Tags.getAtName(name, counts) - 1;
|
|
396
|
+
|
|
397
|
+
if (index < 0) return null;
|
|
156
398
|
}
|
|
157
399
|
}
|
|
158
400
|
|
|
159
|
-
|
|
160
|
-
|
|
401
|
+
let parentIndex = __getPropertyTagsIndex(agAstNode, type, name, index ?? 0);
|
|
402
|
+
|
|
403
|
+
if (parentIndex != null && ref?.flags.expression) {
|
|
404
|
+
let shiftIndex_ = shiftIndex == null ? -1 : shiftIndex;
|
|
405
|
+
if (shiftIndex_ < 0) {
|
|
406
|
+
let shifts = 0;
|
|
407
|
+
// TODO speed this up for deeply nested shifts
|
|
408
|
+
// algorithm: make big jump forward, then look at shift index to see if we overshot completely
|
|
409
|
+
// works because we know the size of the thing and a bigger thing doesn't fit in a smaller one
|
|
410
|
+
while (Tags.getAt(parentIndex + shifts, agAstNode.value.children)?.value.shift) {
|
|
411
|
+
shifts++;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
if (-shiftIndex_ > shifts + 1) return null;
|
|
415
|
+
|
|
416
|
+
return parentIndex + shifts + shiftIndex_ + 1;
|
|
417
|
+
} else {
|
|
418
|
+
if (parentIndex + shiftIndex_ >= Tags.getSize(agAstNode.value.tags)) {
|
|
419
|
+
return null;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
return parentIndex + shiftIndex_;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
161
425
|
|
|
162
|
-
|
|
163
|
-
let { type, name } = reference.value;
|
|
164
|
-
return __getPropertyChildrenIndex(agAstNode, type, name, 0);
|
|
426
|
+
return parentIndex;
|
|
165
427
|
};
|
|
166
428
|
|
|
167
|
-
const
|
|
429
|
+
const __getPropertyTagsIndex = (agAstNode, type, name, index) => {
|
|
168
430
|
let nameCount = 0;
|
|
169
|
-
let node = agAstNode.
|
|
431
|
+
let node = Tags.getValues(agAstNode.value.tags)[1];
|
|
170
432
|
let idx = -1;
|
|
171
433
|
|
|
172
434
|
// drill into subtrees, passing over subtrees with too few references of the desired name
|
|
173
435
|
outer: while (node) {
|
|
174
|
-
let
|
|
175
|
-
|
|
176
|
-
|
|
436
|
+
let sums = Tags.getSums(node);
|
|
437
|
+
|
|
438
|
+
if (!sums) return null;
|
|
439
|
+
|
|
440
|
+
let valueNameCount =
|
|
441
|
+
name != null
|
|
442
|
+
? Tags.getAtName(name, sums.references)
|
|
443
|
+
: Tags.getAtName(type, sums.specialTypes);
|
|
177
444
|
|
|
178
445
|
if (nameCount + valueNameCount < index) {
|
|
179
446
|
return null;
|
|
180
447
|
}
|
|
181
448
|
|
|
182
|
-
for (const value of
|
|
183
|
-
if (
|
|
449
|
+
for (const value of Tags.getValues(node)) {
|
|
450
|
+
if (!isArray(value)) {
|
|
184
451
|
idx++;
|
|
185
452
|
let tag = value;
|
|
186
|
-
if (
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
453
|
+
if (tag.type === Property) {
|
|
454
|
+
let { tags, reference } = tag.value;
|
|
455
|
+
if (tags[0].type === ReferenceTag) {
|
|
456
|
+
if (
|
|
457
|
+
(name != null && reference.name === name) ||
|
|
458
|
+
(type != null && reference.type === type)
|
|
459
|
+
) {
|
|
460
|
+
nameCount += 1;
|
|
461
|
+
if (nameCount > index) {
|
|
462
|
+
return idx + 1;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
193
465
|
}
|
|
194
466
|
}
|
|
195
467
|
} else {
|
|
196
|
-
let valueSums =
|
|
468
|
+
let valueSums = Tags.getSums(value);
|
|
197
469
|
if (
|
|
198
|
-
nameCount +
|
|
470
|
+
nameCount +
|
|
471
|
+
(name != null
|
|
472
|
+
? Tags.getAtName(name, valueSums.references)
|
|
473
|
+
: Tags.getAtName(type, valueSums.specialTypes)) >
|
|
199
474
|
index
|
|
200
475
|
) {
|
|
201
476
|
node = value;
|
|
202
477
|
continue outer;
|
|
203
478
|
} else {
|
|
204
479
|
nameCount +=
|
|
205
|
-
(
|
|
206
|
-
|
|
480
|
+
(name != null
|
|
481
|
+
? Tags.getAtName(name, valueSums.references)
|
|
482
|
+
: Tags.getAtName(type, valueSums.specialTypes)) ?? 0;
|
|
483
|
+
idx += Tags.getSize(value);
|
|
207
484
|
}
|
|
208
485
|
}
|
|
209
486
|
}
|
|
@@ -217,11 +494,12 @@ const __getPropertyChildrenIndex = (agAstNode, type, name, index) => {
|
|
|
217
494
|
const { hasOwn, freeze } = Object;
|
|
218
495
|
const { isArray } = Array;
|
|
219
496
|
|
|
220
|
-
export const getOriginalFirstNode = (node
|
|
221
|
-
|
|
497
|
+
export const getOriginalFirstNode = (node) => {
|
|
498
|
+
if (node.type !== TreeNode) return;
|
|
499
|
+
|
|
500
|
+
for (let child of Tags.traverse(getTags(node))) {
|
|
222
501
|
if (child.type === Property) {
|
|
223
|
-
return
|
|
224
|
-
.node;
|
|
502
|
+
return child.value.node;
|
|
225
503
|
}
|
|
226
504
|
}
|
|
227
505
|
return null;
|
|
@@ -232,112 +510,135 @@ export const getFirstNode = (node) => {
|
|
|
232
510
|
};
|
|
233
511
|
|
|
234
512
|
export const getFirstNodeProperty = (node) => {
|
|
235
|
-
for (let child of
|
|
513
|
+
for (let child of Tags.traverse(getTags(node))) {
|
|
236
514
|
if (child.type === Property) {
|
|
237
|
-
|
|
515
|
+
let ref = child.value.reference;
|
|
516
|
+
if (!ref.flags.expression) {
|
|
517
|
+
return child;
|
|
518
|
+
} else {
|
|
519
|
+
let tagsIndex = getPropertyTagsIndex(node, ref.type, ref.name, 0, -1);
|
|
520
|
+
return Tags.getAt(tagsIndex, getTags(node), 2)?.value;
|
|
521
|
+
}
|
|
522
|
+
// is it shifted?
|
|
238
523
|
}
|
|
239
524
|
}
|
|
240
525
|
return null;
|
|
241
526
|
};
|
|
242
527
|
|
|
243
|
-
export const
|
|
244
|
-
|
|
245
|
-
if (child.type === Property) {
|
|
246
|
-
let { reference } = child.value;
|
|
247
|
-
|
|
248
|
-
if (!reference.flags.expression) return null;
|
|
249
|
-
|
|
250
|
-
let property = node.properties[reference.name];
|
|
251
|
-
if (reference.isArray) {
|
|
252
|
-
property = btree.getAt(-1, property.node);
|
|
253
|
-
}
|
|
254
|
-
return property.node;
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
return null;
|
|
528
|
+
export const referenceIsSingular = (ref) => {
|
|
529
|
+
return (ref.name && !['#', '@'].includes(ref.type)) || ref.type === '_';
|
|
258
530
|
};
|
|
259
531
|
|
|
260
532
|
export const referencesAreEqual = (a, b) => {
|
|
261
533
|
return (
|
|
262
534
|
a === b ||
|
|
263
|
-
(a.
|
|
264
|
-
a.
|
|
265
|
-
a.
|
|
266
|
-
a.
|
|
535
|
+
(a.type === b.type &&
|
|
536
|
+
a.name === b.name &&
|
|
537
|
+
a.flags.array === b.flags.array &&
|
|
538
|
+
a.flags.intrinsic === b.flags.intrinsic &&
|
|
539
|
+
a.flags.hasGap === b.flags.hasGap &&
|
|
540
|
+
a.flags.expression === b.flags.expression)
|
|
267
541
|
);
|
|
268
542
|
};
|
|
269
543
|
|
|
270
|
-
export const
|
|
271
|
-
|
|
272
|
-
if (!hasOwn(pathSegment_, 'shiftIndex')) throw new Error();
|
|
273
|
-
let { name, index, shiftIndex } = pathSegment_;
|
|
274
|
-
|
|
275
|
-
if (hasOwn(properties, name)) {
|
|
276
|
-
let prop = properties[name];
|
|
544
|
+
export const isDefined = (obj, key) => hasOwn(obj, key) && obj[key] !== undefined;
|
|
545
|
+
export const isUndefined = (obj, key) => !hasOwn(obj, key) || obj[key] === undefined;
|
|
277
546
|
|
|
278
|
-
|
|
279
|
-
|
|
547
|
+
export function* relatedNodes(node) {
|
|
548
|
+
for (const child of Tags.traverse(getTags(node))) {
|
|
549
|
+
if (child.type === Property) {
|
|
550
|
+
yield child.node;
|
|
280
551
|
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
281
554
|
|
|
282
|
-
|
|
555
|
+
export const getProperty = (pathSegment, node) => {
|
|
556
|
+
if (!node || node.type !== TreeNode) return null;
|
|
283
557
|
|
|
284
|
-
|
|
285
|
-
prop = btree.getAt(shiftIndex ?? -1, prop.node);
|
|
286
|
-
}
|
|
558
|
+
if (pathSegment == null) throw new Error('Bad path segment');
|
|
287
559
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
560
|
+
let { name, type, index, shiftIndex } =
|
|
561
|
+
typeof pathSegment === 'string' ? buildPathSegment(pathSegment) : pathSegment;
|
|
562
|
+
|
|
563
|
+
let propIndex = getPropertyTagsIndex(node, type, name, index, shiftIndex);
|
|
564
|
+
|
|
565
|
+
if (propIndex == null) return null;
|
|
566
|
+
|
|
567
|
+
return Tags.getAt(propIndex, getTags(node));
|
|
291
568
|
};
|
|
292
569
|
|
|
293
|
-
export const
|
|
294
|
-
|
|
570
|
+
export const has = (path, node) => {
|
|
571
|
+
if (!isArray(path)) {
|
|
572
|
+
path = [path];
|
|
573
|
+
}
|
|
295
574
|
|
|
296
|
-
|
|
297
|
-
|
|
575
|
+
let pathArr = [...path];
|
|
576
|
+
let node_ = get(pathArr.slice(0, -1), node);
|
|
577
|
+
let seg = pathArr[pathArr.length - 1];
|
|
298
578
|
|
|
579
|
+
return !!getProperty(seg, node_);
|
|
580
|
+
};
|
|
581
|
+
|
|
582
|
+
export const get = (path, node) => getOr(null, path, node);
|
|
583
|
+
|
|
584
|
+
export const getOr = (defaultValue, path, node) => {
|
|
299
585
|
if (path == null) throw new Error('Bad path');
|
|
586
|
+
if (!node) return null;
|
|
300
587
|
|
|
301
588
|
if (!isArray(path)) {
|
|
302
589
|
path = [path];
|
|
303
590
|
}
|
|
304
591
|
|
|
305
|
-
let
|
|
306
|
-
|
|
592
|
+
let root = getRoot(node);
|
|
593
|
+
let result = root || node;
|
|
594
|
+
|
|
595
|
+
let start = 0;
|
|
596
|
+
// TODO allow dot dot at all levels
|
|
597
|
+
if (path[0]?.type === '_') {
|
|
598
|
+
if (!root) return null;
|
|
599
|
+
start = 1;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
for (let i = start; i < path.length; i++) {
|
|
307
603
|
let nameOrSeg = path[i];
|
|
308
604
|
let isName = typeof nameOrSeg === 'string';
|
|
309
605
|
let property;
|
|
606
|
+
let index = path[i + 1];
|
|
310
607
|
|
|
311
|
-
if (
|
|
608
|
+
if (typeof index === 'number') {
|
|
609
|
+
i++;
|
|
610
|
+
} else {
|
|
611
|
+
index = undefined;
|
|
612
|
+
}
|
|
312
613
|
|
|
313
|
-
|
|
614
|
+
if (!isName && (!nameOrSeg || !hasOwn(nameOrSeg, 'shiftIndex'))) throw new Error('Bad path');
|
|
314
615
|
|
|
315
|
-
|
|
316
|
-
let { index } = nameOrSeg;
|
|
616
|
+
let seg = isName ? buildPathSegment(nameOrSeg, index) : nameOrSeg;
|
|
317
617
|
|
|
318
|
-
|
|
319
|
-
isName ? buildPathSegment(name, index) : nameOrSeg,
|
|
320
|
-
node_.properties,
|
|
321
|
-
);
|
|
618
|
+
property = getProperty(seg, result);
|
|
322
619
|
|
|
323
|
-
|
|
324
|
-
} else if (!isName) {
|
|
325
|
-
let { type } = nameOrSeg;
|
|
326
|
-
if (type !== '.') throw new Error('not implemented');
|
|
620
|
+
if (!property) return defaultValue;
|
|
327
621
|
|
|
328
|
-
|
|
622
|
+
result = getRoot(property.value.node);
|
|
623
|
+
}
|
|
329
624
|
|
|
330
|
-
|
|
625
|
+
return isNullNode(result) ? null : result;
|
|
626
|
+
};
|
|
331
627
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
throw new Error();
|
|
335
|
-
}
|
|
628
|
+
export function* list(name, node) {
|
|
629
|
+
let count = countList(name, node);
|
|
336
630
|
|
|
337
|
-
|
|
631
|
+
for (let i = 0; i < count; i++) {
|
|
632
|
+
yield get(buildPathSegment(name, i, -1), node);
|
|
338
633
|
}
|
|
634
|
+
}
|
|
339
635
|
|
|
340
|
-
|
|
636
|
+
export const countList = (name, node) => {
|
|
637
|
+
if (!node) throw new Error();
|
|
638
|
+
|
|
639
|
+
if (name == null) throw new Error('Bad path');
|
|
640
|
+
|
|
641
|
+
return Tags.getAtName(name, Tags.getSums(getTags(node)).references);
|
|
341
642
|
};
|
|
342
643
|
|
|
343
644
|
export function* allTagPathsFor(range, options = {}) {
|
|
@@ -353,7 +654,7 @@ export function* allTagPathsFor(range, options = {}) {
|
|
|
353
654
|
|
|
354
655
|
while (path) {
|
|
355
656
|
if (path.inner && path.previousSibling.tag.type === ReferenceTag) {
|
|
356
|
-
path =
|
|
657
|
+
path = TagPath.from(path.inner, 0);
|
|
357
658
|
}
|
|
358
659
|
|
|
359
660
|
if (path.path.depth < startPath.path.depth) {
|
|
@@ -362,21 +663,17 @@ export function* allTagPathsFor(range, options = {}) {
|
|
|
362
663
|
|
|
363
664
|
yield path;
|
|
364
665
|
|
|
365
|
-
if (
|
|
366
|
-
endPath &&
|
|
367
|
-
path.childrenIndex === endPath.childrenIndex &&
|
|
368
|
-
path.path.node === endPath.path.node
|
|
369
|
-
) {
|
|
666
|
+
if (endPath && path.tagsIndex === endPath.tagsIndex && path.path.node === endPath.path.node) {
|
|
370
667
|
return;
|
|
371
668
|
}
|
|
372
669
|
|
|
373
|
-
let gapPath = path.path.parent && TagPath.from(path.path.parent, path.path.
|
|
670
|
+
let gapPath = path.path.parent && TagPath.from(path.path.parent, path.path.parentIndex, 1);
|
|
374
671
|
|
|
375
672
|
if (
|
|
376
673
|
endPath &&
|
|
377
674
|
path.tag.type === CloseNodeTag &&
|
|
378
675
|
gapPath &&
|
|
379
|
-
gapPath.
|
|
676
|
+
gapPath.tagsIndex === endPath.tagsIndex &&
|
|
380
677
|
gapPath.path.node === endPath.path.node
|
|
381
678
|
) {
|
|
382
679
|
return;
|
|
@@ -392,7 +689,7 @@ export function* allTagsFor(range, options = {}) {
|
|
|
392
689
|
}
|
|
393
690
|
|
|
394
691
|
export const buildFullRange = (node) => {
|
|
395
|
-
let sum =
|
|
692
|
+
let sum = Tags.getSize(getTags(node));
|
|
396
693
|
return sum ? [0, sum - 1] : null;
|
|
397
694
|
};
|
|
398
695
|
|
|
@@ -404,13 +701,17 @@ export function* ownTagPathsFor(range) {
|
|
|
404
701
|
|
|
405
702
|
if (startPath.parent.node !== endPath.parent.node) throw new Error();
|
|
406
703
|
|
|
407
|
-
let {
|
|
704
|
+
let { tags } = startPath.parent.node;
|
|
408
705
|
|
|
409
|
-
for (let i = startPath.
|
|
410
|
-
yield
|
|
706
|
+
for (let i = startPath.tagsIndex; i < endPath.tagsIndex; i++) {
|
|
707
|
+
yield tags[i];
|
|
411
708
|
}
|
|
412
709
|
}
|
|
413
710
|
|
|
711
|
+
export const buildNullNode = () => {
|
|
712
|
+
return buildNode(buildNullTag());
|
|
713
|
+
};
|
|
714
|
+
|
|
414
715
|
const findRight = (arr, predicate) => {
|
|
415
716
|
for (let i = arr.length - 1; i >= 0; i--) {
|
|
416
717
|
let value = arr[i];
|
|
@@ -457,57 +758,127 @@ const skipToDepth = (depth, frame) => {
|
|
|
457
758
|
return parent;
|
|
458
759
|
};
|
|
459
760
|
|
|
761
|
+
export const getRange = (node) => {
|
|
762
|
+
const { tags } = node;
|
|
763
|
+
let path = Path.from(node);
|
|
764
|
+
return Tags.getSize(tags) ? [TagPath.from(path, 0), TagPath.from(path, -1)] : null;
|
|
765
|
+
};
|
|
766
|
+
|
|
767
|
+
export const getFlags = (node) => {
|
|
768
|
+
return node.type === TreeNode ? node.value.flags : null;
|
|
769
|
+
};
|
|
770
|
+
|
|
771
|
+
export const getAttributes = (node) => {
|
|
772
|
+
return node.type === TreeNode ? node.value.attributes : freeze({});
|
|
773
|
+
};
|
|
774
|
+
|
|
775
|
+
export const isSelfClosingTag = (tag) => {
|
|
776
|
+
return tag.type === OpenNodeTag
|
|
777
|
+
? tag.value.selfClosing
|
|
778
|
+
: [NullTag, GapTag].includes(tag.type)
|
|
779
|
+
? true
|
|
780
|
+
: false;
|
|
781
|
+
};
|
|
782
|
+
|
|
460
783
|
export let pathForTagPath = (tagPath) => {
|
|
461
784
|
let refTagPath = tagPath;
|
|
462
785
|
let isShift = tagPath.tag.type === ShiftTag;
|
|
463
786
|
|
|
464
787
|
if (isShift) {
|
|
465
|
-
refTagPath = tagPath.siblingAt(tagPath.
|
|
788
|
+
refTagPath = tagPath.siblingAt(tagPath.tagsIndex - tagPath.tag.value.index);
|
|
466
789
|
}
|
|
467
790
|
|
|
468
791
|
let { type, name } = refTagPath.tag.value;
|
|
469
792
|
|
|
470
793
|
if (refTagPath.tag.type !== ReferenceTag) throw new Error();
|
|
471
794
|
|
|
472
|
-
let index = getChildPropertyIndex(tagPath.node, refTagPath.
|
|
795
|
+
let index = getChildPropertyIndex(tagPath.node, refTagPath.tagsIndex);
|
|
473
796
|
let shiftIndex = isShift ? (tagPath.tag.value.index ?? 0) + 1 : null;
|
|
474
797
|
|
|
475
798
|
return [{ type, name, index, shiftIndex }];
|
|
476
799
|
};
|
|
477
800
|
|
|
801
|
+
let getSigilTag_ = (tag) => {
|
|
802
|
+
switch (tag.type) {
|
|
803
|
+
case Property:
|
|
804
|
+
return getTags(tag.value.property.node)[1][0];
|
|
805
|
+
case TreeNode:
|
|
806
|
+
case NullNode:
|
|
807
|
+
case GapNode:
|
|
808
|
+
return getTags(tag)[1][0];
|
|
809
|
+
case OpenNodeTag:
|
|
810
|
+
case GapTag:
|
|
811
|
+
case NullTag:
|
|
812
|
+
return tag;
|
|
813
|
+
}
|
|
814
|
+
};
|
|
815
|
+
|
|
478
816
|
export const Path = class AgastPath extends WeakStackFrame {
|
|
817
|
+
static create(node) {
|
|
818
|
+
return node && new Path(node);
|
|
819
|
+
}
|
|
820
|
+
|
|
479
821
|
static from(node) {
|
|
480
|
-
return node &&
|
|
822
|
+
return node && new Path(node);
|
|
481
823
|
}
|
|
482
824
|
|
|
483
|
-
|
|
484
|
-
|
|
825
|
+
static fromTag(openTag) {
|
|
826
|
+
return Path.from(buildNode(openTag));
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
static set(node, path, value) {
|
|
830
|
+
return Path.from(node).replaceAt(path, value).node;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
static get(node, path) {
|
|
834
|
+
return Path.from(node).get(path).node;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
constructor(nodeOrParent, parentIndex = null, isGap = false) {
|
|
838
|
+
let isRoot = !(nodeOrParent instanceof Path);
|
|
839
|
+
let parent = isRoot ? null : nodeOrParent;
|
|
840
|
+
let node = isRoot ? nodeOrParent : parent.getChild(parentIndex - 1).value.node;
|
|
841
|
+
|
|
842
|
+
if (isGap) {
|
|
843
|
+
({ node } = BTree.getAt(-1, node.value.bounds[0]).value);
|
|
844
|
+
}
|
|
485
845
|
|
|
486
|
-
if (!
|
|
846
|
+
if (!node || ![TreeNode, NullNode, GapNode].includes(node.type)) throw new Error();
|
|
487
847
|
|
|
488
|
-
if (parent && referenceIndex == null) throw new Error();
|
|
489
848
|
if (!node) throw new Error();
|
|
849
|
+
if (!Object.isFrozen(node)) throw new Error();
|
|
490
850
|
if (isArray(node)) throw new Error();
|
|
491
851
|
|
|
852
|
+
super(parent);
|
|
853
|
+
|
|
492
854
|
this.node = node;
|
|
493
|
-
this.
|
|
855
|
+
this.parentIndex = parentIndex;
|
|
856
|
+
this.isGap = isGap;
|
|
857
|
+
|
|
858
|
+
this.name = node.type === TreeNode ? node.value.name : null;
|
|
859
|
+
this.type = node.type === TreeNode ? node.value.type : null;
|
|
860
|
+
this.flags = node.type === TreeNode ? node.value.flags : null;
|
|
861
|
+
this.attributes = node.type === TreeNode ? node.value.attributes : null;
|
|
862
|
+
this.tags = getTags(node);
|
|
494
863
|
|
|
495
|
-
let
|
|
496
|
-
referenceIndex != null && Children.getAt(referenceIndex, parent.node.children);
|
|
864
|
+
let parentTag = parentIndex == null ? null : Tags.getAt(parentIndex, getTags(parent.node));
|
|
497
865
|
|
|
498
|
-
if (
|
|
866
|
+
if (parentTag && parentTag.type !== Property) {
|
|
499
867
|
throw new Error();
|
|
500
868
|
}
|
|
501
869
|
|
|
502
|
-
if (
|
|
870
|
+
if (
|
|
871
|
+
parentIndex != null &&
|
|
872
|
+
(!this.referenceTag || ![ReferenceTag, ShiftTag].includes(this.referenceTag.type))
|
|
873
|
+
) {
|
|
503
874
|
throw new Error();
|
|
504
875
|
}
|
|
505
876
|
|
|
506
877
|
// if (
|
|
507
878
|
// parent &&
|
|
508
|
-
// (['#', '@'].includes(this.
|
|
509
|
-
// ? parent.tagPathAt(
|
|
510
|
-
// : get(pathForTagPath(parent.tagPathAt(
|
|
879
|
+
// (['#', '@'].includes(this.referenceTag.value.type)
|
|
880
|
+
// ? parent.tagPathAt(parentIndex, 1).tag.value
|
|
881
|
+
// : get(pathForTagPath(parent.tagPathAt(parentIndex)), parent.node)) !== node
|
|
511
882
|
// ) {
|
|
512
883
|
// throw new Error('Path not reachable');
|
|
513
884
|
// }
|
|
@@ -519,240 +890,1042 @@ export const Path = class AgastPath extends WeakStackFrame {
|
|
|
519
890
|
freeze(this);
|
|
520
891
|
}
|
|
521
892
|
|
|
893
|
+
getChild(childrenIndex) {
|
|
894
|
+
let { node } = this;
|
|
895
|
+
if (isStubNode(node)) return null;
|
|
896
|
+
return Tags.getAt(childrenIndex, getChildren(node)) || null;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
getSigilTagPath() {
|
|
900
|
+
return TagPath.from(this, 0);
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
tagPathAt(tagsIndex, propertyIndex) {
|
|
904
|
+
return TagPath.from(this, tagsIndex, propertyIndex);
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
getPropertyTagPath(childrenIndex) {
|
|
908
|
+
let tagPath = this.tagPathAt(childrenIndex + 1);
|
|
909
|
+
return tagPath && tagPath.tag.type === Property ? tagPath : null;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
getReferenceTagPath(childrenIndex) {
|
|
913
|
+
return this.tagPathAt(childrenIndex + 1, [0]);
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
// getBindings(childrenIndex) {
|
|
917
|
+
// let property = this.getPropertyTagPath(childrenIndex);
|
|
918
|
+
// return property && Tags.getAt([1], property.value.tags);
|
|
919
|
+
// }
|
|
920
|
+
|
|
921
|
+
getBindingTagPath(childrenIndex, bindingIndex) {
|
|
922
|
+
return this.tagPathAt(childrenIndex + 1, [1, bindingIndex]);
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
getNodeTagPath(childrenIndex) {
|
|
926
|
+
return this.tagPathAt(childrenIndex + 1, [2]);
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
getHashTagPath(childrenIndex) {
|
|
930
|
+
return this.tagPathAt(childrenIndex + 1, [3]);
|
|
931
|
+
}
|
|
932
|
+
|
|
522
933
|
get openTagPath() {
|
|
523
934
|
let tagPath = TagPath.from(this, 0);
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
935
|
+
return tagPath.tag.type === OpenNodeTag ? tagPath : null;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
get closeTagPath() {
|
|
939
|
+
let tagPath = TagPath.from(this, -1);
|
|
940
|
+
return tagPath.tag.type === CloseNodeTag ? tagPath : null;
|
|
528
941
|
}
|
|
529
942
|
|
|
530
943
|
get openTag() {
|
|
531
944
|
return this.openTagPath.tag;
|
|
532
945
|
}
|
|
533
946
|
|
|
534
|
-
get
|
|
535
|
-
|
|
536
|
-
if (tagPath.tag.type !== CloseNodeTag) return null;
|
|
537
|
-
return tagPath;
|
|
947
|
+
get open() {
|
|
948
|
+
return this.openTag.value;
|
|
538
949
|
}
|
|
539
950
|
|
|
540
951
|
get closeTag() {
|
|
541
952
|
return this.closeTagPath.tag;
|
|
542
953
|
}
|
|
543
954
|
|
|
544
|
-
|
|
545
|
-
return
|
|
955
|
+
get bindings() {
|
|
956
|
+
return this.parentPropertyPath?.tag.value.bindings;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
get bindingTags() {
|
|
960
|
+
return this.parentPropertyPath?.tag.value.tags[1];
|
|
546
961
|
}
|
|
547
962
|
|
|
548
963
|
get reference() {
|
|
549
|
-
return
|
|
550
|
-
(this.parent?.node ?? null) && Children.getAt(this.referenceIndex, this.parent.node.children)
|
|
551
|
-
);
|
|
964
|
+
return this.referenceTag?.value ?? null;
|
|
552
965
|
}
|
|
553
966
|
|
|
554
|
-
get
|
|
555
|
-
return
|
|
967
|
+
get referenceTag() {
|
|
968
|
+
return this.referenceTagPath?.tag ?? null;
|
|
556
969
|
}
|
|
557
970
|
|
|
558
|
-
get(
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
path_ = [path_];
|
|
971
|
+
get referenceTagPath() {
|
|
972
|
+
if (!this.parent?.node) {
|
|
973
|
+
return null;
|
|
562
974
|
}
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
let pathInst = this;
|
|
566
|
-
for (let i = 0; i < path_.length; i++) {
|
|
567
|
-
let nameOrSeg = path_[i];
|
|
568
|
-
|
|
569
|
-
if (isString(nameOrSeg)) {
|
|
570
|
-
nameOrSeg = { type: null, name: nameOrSeg, index: null, shiftIndex: null };
|
|
571
|
-
}
|
|
975
|
+
return TagPath.from(this.parent, this.parentIndex, 0).referenceTagPath;
|
|
976
|
+
}
|
|
572
977
|
|
|
573
|
-
|
|
978
|
+
get propertyKeyTagPath() {
|
|
979
|
+
if (!this.parent?.node) {
|
|
980
|
+
return null;
|
|
981
|
+
}
|
|
982
|
+
return TagPath.from(this.parent, this.parentIndex, 0);
|
|
983
|
+
}
|
|
574
984
|
|
|
575
|
-
|
|
985
|
+
get parentPropertyPath() {
|
|
986
|
+
if (!this.parent?.node || this.parentIndex == null) {
|
|
987
|
+
return null;
|
|
988
|
+
}
|
|
989
|
+
let path = TagPath.from(this.parent, this.parentIndex);
|
|
990
|
+
if (path.tag.type === ShiftTag) {
|
|
991
|
+
path = TagPath.from(this.parent, this.parentIndex - path.tag.value.index);
|
|
992
|
+
}
|
|
993
|
+
return path;
|
|
994
|
+
}
|
|
576
995
|
|
|
577
|
-
|
|
996
|
+
get parentProperty() {
|
|
997
|
+
return this.parentPropertyPath?.tag ?? null;
|
|
998
|
+
}
|
|
578
999
|
|
|
579
|
-
|
|
1000
|
+
get parentNode() {
|
|
1001
|
+
return this.parent.node;
|
|
1002
|
+
}
|
|
580
1003
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
1004
|
+
get firstPropertyTagPath() {
|
|
1005
|
+
let tagPath = this.tagPathAt(0);
|
|
1006
|
+
while (tagPath && (!tagPath.propertyPath || isNullNode(tagPath.propertyPath.tag.value.node))) {
|
|
1007
|
+
tagPath = tagPath.nextSibling;
|
|
1008
|
+
if (tagPath?.propertyPath) {
|
|
1009
|
+
tagPath = tagPath.propertyPath;
|
|
585
1010
|
}
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
1011
|
+
}
|
|
1012
|
+
return tagPath;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
get lastPropertyTagPath() {
|
|
1016
|
+
let tagPath = this.tagPathAt(-1);
|
|
1017
|
+
while (tagPath && (!tagPath.propertyPath || isNullNode(tagPath.propertyPath.tag.value.node))) {
|
|
1018
|
+
tagPath = tagPath.previousSibling;
|
|
1019
|
+
if (tagPath?.propertyPath) {
|
|
1020
|
+
tagPath = tagPath.propertyPath;
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
return tagPath;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
get coverBoundary() {
|
|
1027
|
+
let path = this;
|
|
1028
|
+
|
|
1029
|
+
if (path.parent && !isFragment(this.node) && isCover(path.parent.node)) {
|
|
1030
|
+
path = path.parent;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
while (path && isCover(path.node) && path.parent && isCover(path.parent.node)) {
|
|
1034
|
+
path = path.parent;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
return path;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
get(path) {
|
|
1041
|
+
let path_ = typeof path === 'string' ? [path] : [...path];
|
|
1042
|
+
let pathInst = this;
|
|
1043
|
+
|
|
1044
|
+
let skippedRootFragment = false;
|
|
1045
|
+
|
|
1046
|
+
if (!(path.length && isObject(path[1]) && path[0].type === '_')) {
|
|
1047
|
+
while (!pathInst.node.value.name && pathInst.node.value.type === Symbol.for('_')) {
|
|
1048
|
+
if (pathInst.depth) throw new Error();
|
|
1049
|
+
skippedRootFragment = true;
|
|
1050
|
+
pathInst = pathInst.push(getPropertyTagsIndex(pathInst.node, '_', null, 0));
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
for (let i = 0; i < path_.length; i++) {
|
|
1055
|
+
let nameOrSeg = path_[i];
|
|
1056
|
+
|
|
1057
|
+
let seg = nameOrSeg;
|
|
1058
|
+
if (isString(nameOrSeg)) {
|
|
1059
|
+
let index = path_[i + 1];
|
|
1060
|
+
if (typeof index === 'number') {
|
|
1061
|
+
i++;
|
|
1062
|
+
} else {
|
|
1063
|
+
index = undefined;
|
|
1064
|
+
}
|
|
1065
|
+
seg = buildPathSegment(nameOrSeg, index);
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
if (i === 0 && seg.type === '_' && skippedRootFragment) continue;
|
|
1069
|
+
|
|
1070
|
+
let tagsIndex = getPropertyTagsIndex(
|
|
1071
|
+
pathInst.node,
|
|
1072
|
+
seg.type,
|
|
1073
|
+
seg.name,
|
|
1074
|
+
seg.index,
|
|
1075
|
+
seg.shiftIndex,
|
|
1076
|
+
);
|
|
1077
|
+
|
|
1078
|
+
if (tagsIndex == null) return null;
|
|
1079
|
+
|
|
1080
|
+
pathInst = pathInst.push(tagsIndex);
|
|
594
1081
|
}
|
|
595
1082
|
|
|
596
1083
|
return pathInst;
|
|
597
1084
|
}
|
|
598
1085
|
|
|
1086
|
+
replaceWith(node, bindingTags) {
|
|
1087
|
+
let bindings = bindingTags?.map((tag) => tag.value); // TODO improve here
|
|
1088
|
+
if (bindings != null && !isArray(bindings)) throw new Error();
|
|
1089
|
+
if (!isPlainObject(node)) throw new Error();
|
|
1090
|
+
|
|
1091
|
+
if (!node) throw new Error();
|
|
1092
|
+
|
|
1093
|
+
if (!this.parent) {
|
|
1094
|
+
return Path.from(node);
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
let built = node;
|
|
1098
|
+
let path = this.parent;
|
|
1099
|
+
let replacementPath = [];
|
|
1100
|
+
|
|
1101
|
+
let targetShift_ = this.parent?.parentProperty?.value.tags[0];
|
|
1102
|
+
let targetShift = targetShift_ && (targetShift_.type === ReferenceTag ? null : targetShift_);
|
|
1103
|
+
let targetReference = this.reference;
|
|
1104
|
+
let targetBindings = bindings == null ? this.bindings : bindings;
|
|
1105
|
+
let targetParentIndex = this.parentIndex;
|
|
1106
|
+
let held = null;
|
|
1107
|
+
let heldCount = 0;
|
|
1108
|
+
let value;
|
|
1109
|
+
|
|
1110
|
+
while (path) {
|
|
1111
|
+
value = built;
|
|
1112
|
+
built = buildNode(getTags(path.node));
|
|
1113
|
+
|
|
1114
|
+
let { tags, shift } = Tags.getAt(targetParentIndex, getTags(path.node)).value;
|
|
1115
|
+
|
|
1116
|
+
let firstTag = tags[0];
|
|
1117
|
+
let newFirstTag = firstTag;
|
|
1118
|
+
if (shift) {
|
|
1119
|
+
newFirstTag = buildChild(ReferenceTag, targetReference);
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
let tags_ = [
|
|
1123
|
+
firstTag,
|
|
1124
|
+
targetBindings.map((binding) => buildChild(BindingTag, binding)),
|
|
1125
|
+
value,
|
|
1126
|
+
];
|
|
1127
|
+
|
|
1128
|
+
if (!held && !shift) {
|
|
1129
|
+
built = buildNode(
|
|
1130
|
+
Tags.replaceAt(
|
|
1131
|
+
targetParentIndex,
|
|
1132
|
+
built.value.tags,
|
|
1133
|
+
buildChild(Property, buildProperty(tags_)),
|
|
1134
|
+
),
|
|
1135
|
+
);
|
|
1136
|
+
replacementPath.push(targetParentIndex);
|
|
1137
|
+
} else {
|
|
1138
|
+
let i = targetParentIndex + 1;
|
|
1139
|
+
let nextProperty = Tags.getAt(i, built.value.tags);
|
|
1140
|
+
|
|
1141
|
+
let nextShift = nextProperty?.type === Property && nextProperty.value.shift;
|
|
1142
|
+
|
|
1143
|
+
if (nextShift) {
|
|
1144
|
+
let { reference, bindings } = BTree.getAt(0, nextProperty.value.node.value.bounds[0]);
|
|
1145
|
+
|
|
1146
|
+
path = path.push(i);
|
|
1147
|
+
|
|
1148
|
+
built = buildNode(
|
|
1149
|
+
Tags.replaceAt(
|
|
1150
|
+
targetParentIndex - shift.index,
|
|
1151
|
+
built.value.tags,
|
|
1152
|
+
buildChild(Property, buildProperty(tags_)),
|
|
1153
|
+
),
|
|
1154
|
+
);
|
|
1155
|
+
|
|
1156
|
+
targetParentIndex -= shift.index;
|
|
1157
|
+
for (let i = shift.index - 1; i >= 0; i--) {
|
|
1158
|
+
built = buildNode(Tags.removeAt(targetParentIndex + 1, built.value.tags));
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
tags_ = [newFirstTag, tags_[1], tags_[2]];
|
|
1162
|
+
|
|
1163
|
+
targetShift = null;
|
|
1164
|
+
targetReference = reference;
|
|
1165
|
+
targetBindings = bindings;
|
|
1166
|
+
targetParentIndex = getPropertyTagsIndex(
|
|
1167
|
+
nextProperty.value.node,
|
|
1168
|
+
reference.type,
|
|
1169
|
+
reference.name,
|
|
1170
|
+
0,
|
|
1171
|
+
0,
|
|
1172
|
+
);
|
|
1173
|
+
held = null;
|
|
1174
|
+
|
|
1175
|
+
replacementPath.push(targetParentIndex);
|
|
1176
|
+
continue;
|
|
1177
|
+
} else {
|
|
1178
|
+
built = buildNode(
|
|
1179
|
+
Tags.replaceAt(
|
|
1180
|
+
targetParentIndex,
|
|
1181
|
+
getTags(built),
|
|
1182
|
+
buildChild(Property, buildProperty(tags_, shift)),
|
|
1183
|
+
),
|
|
1184
|
+
);
|
|
1185
|
+
replacementPath.push(targetParentIndex);
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
held = targetShift ? value : null;
|
|
1190
|
+
heldCount = held ? heldCount + 1 : 0;
|
|
1191
|
+
|
|
1192
|
+
targetShift_ = path?.parentProperty?.value.tags[0];
|
|
1193
|
+
targetShift = targetShift_ && (targetShift_.type === ReferenceTag ? null : targetShift_);
|
|
1194
|
+
targetReference = path.reference;
|
|
1195
|
+
targetBindings = path.bindings;
|
|
1196
|
+
targetParentIndex = path.parentIndex;
|
|
1197
|
+
path = path.parent;
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
return this.mapOnto(built);
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
replaceAt(path, node, bindings) {
|
|
1204
|
+
return this.get(path).replaceWith(node, bindings).atDepth(0);
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
mapOnto(rootNode) {
|
|
1208
|
+
let path = Path.from(rootNode);
|
|
1209
|
+
|
|
1210
|
+
for (let i = 1; i <= this.depth; i++) {
|
|
1211
|
+
let { parentIndex, isGap } = this.atDepth(i);
|
|
1212
|
+
path = path.push(parentIndex, isGap);
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
return path;
|
|
1216
|
+
}
|
|
1217
|
+
|
|
599
1218
|
atDepth(depth) {
|
|
600
1219
|
return skipToDepth(depth, this);
|
|
601
1220
|
}
|
|
1221
|
+
|
|
1222
|
+
get rootNode() {
|
|
1223
|
+
return this.atDepth(0).node;
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
get done() {
|
|
1227
|
+
let { parent, node } = this;
|
|
1228
|
+
let sigilTag = getSigilTag(node);
|
|
1229
|
+
|
|
1230
|
+
return !parent && sigilTag && !!(isSelfClosingTag(sigilTag) || getCloseTag(node));
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
get held() {
|
|
1234
|
+
let tagPath = this.tagPathAt(-1);
|
|
1235
|
+
|
|
1236
|
+
// TODO is this safe
|
|
1237
|
+
if (tagPath.tag.type !== Property) return null;
|
|
1238
|
+
|
|
1239
|
+
let { tags } = tagPath.tag.value;
|
|
1240
|
+
|
|
1241
|
+
if (tags[0]?.type === ShiftTag && !tags[2]) {
|
|
1242
|
+
return TagPath.from(tagPath.path, tagPath.tagsIndex - 1).tag.value;
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
// if we're not at the left side, we aren't held
|
|
1246
|
+
if (
|
|
1247
|
+
!tagPath.equalTo(this.firstPropertyTagPath) ||
|
|
1248
|
+
propertyIsFull(tagPath.tag) ||
|
|
1249
|
+
(tagPath.inner && nodeIsComplete(tagPath.inner.node))
|
|
1250
|
+
) {
|
|
1251
|
+
return null;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
let coverParent = this;
|
|
1255
|
+
|
|
1256
|
+
for (;;) {
|
|
1257
|
+
let refPath = coverParent.propertyKeyTagPath;
|
|
1258
|
+
|
|
1259
|
+
if (refPath?.tag.type === ShiftTag) {
|
|
1260
|
+
return TagPath.from(refPath.path, refPath.tagsIndex - 1).tag.value;
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
coverParent = coverParent.parent;
|
|
1264
|
+
if (coverParent?.node.type !== Symbol.for('_')) break;
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
return null;
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
advance(tag) {
|
|
1271
|
+
if (!tag) throw new Error();
|
|
1272
|
+
|
|
1273
|
+
let tagPath = this.tagPathAt(-1, 2);
|
|
1274
|
+
|
|
1275
|
+
if (tagPath?.tag.type === Property ? tagPath?.nextSibling : tagPath?.next) throw new Error();
|
|
1276
|
+
|
|
1277
|
+
if (this.done) throw new Error();
|
|
1278
|
+
|
|
1279
|
+
let resultPath = this;
|
|
1280
|
+
|
|
1281
|
+
switch (tag.type) {
|
|
1282
|
+
case BindingTag: {
|
|
1283
|
+
if (!this.lastPropertyTagPath) {
|
|
1284
|
+
resultPath = this.advanceUnwrapped(buildReferenceTag()).path;
|
|
1285
|
+
}
|
|
1286
|
+
break;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
case TreeNode:
|
|
1290
|
+
case NullNode:
|
|
1291
|
+
case GapNode:
|
|
1292
|
+
case NullTag:
|
|
1293
|
+
case GapTag:
|
|
1294
|
+
case OpenNodeTag: {
|
|
1295
|
+
let sigilTag = getSigilTag_(tag);
|
|
1296
|
+
|
|
1297
|
+
if (sigilTag.type === OpenNodeTag && sigilTag.value.type === Symbol.for('__')) {
|
|
1298
|
+
break;
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
let lastTagPath = this.lastPropertyTagPath;
|
|
1302
|
+
let newProperty = !lastTagPath || propertyIsFull(lastTagPath.tag);
|
|
1303
|
+
let reference = lastTagPath?.referenceTagPath.tag.value;
|
|
1304
|
+
|
|
1305
|
+
// TODO revisit this condition
|
|
1306
|
+
if (!getFlags(this.node)?.token || reference?.type === '@') {
|
|
1307
|
+
if (newProperty || !lastTagPath.tag.value.tags.length) {
|
|
1308
|
+
resultPath = this.advanceUnwrapped(buildReferenceTag()).path;
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
break;
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
if (tag.type === Property) {
|
|
1317
|
+
resultPath = Path.from(buildNode(Tags.push(getTags(resultPath.node), tag)));
|
|
1318
|
+
} else {
|
|
1319
|
+
resultPath = resultPath.advanceUnwrapped(tag).path;
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
if (
|
|
1323
|
+
(tag.type === CloseNodeTag || (tag.type === OpenNodeTag && tag.value.selfClosing)) &&
|
|
1324
|
+
resultPath.depth
|
|
1325
|
+
) {
|
|
1326
|
+
return resultPath.parent;
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
return resultPath;
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
advanceUnwrapped(tag) {
|
|
1333
|
+
if (!tag) throw new Error();
|
|
1334
|
+
|
|
1335
|
+
let tagPath = this.tagPathAt(-1, [-1, -1]);
|
|
1336
|
+
|
|
1337
|
+
if (
|
|
1338
|
+
[TreeNode, NullNode, GapNode].includes(tagPath?.tag.type)
|
|
1339
|
+
? tagPath?.nextSibling
|
|
1340
|
+
: tagPath?.next
|
|
1341
|
+
)
|
|
1342
|
+
throw new Error();
|
|
1343
|
+
|
|
1344
|
+
if (this.done) throw new Error();
|
|
1345
|
+
|
|
1346
|
+
let targetPath = tagPath && endsNode(tagPath.tag) ? this.parent : this;
|
|
1347
|
+
|
|
1348
|
+
switch (tag.type) {
|
|
1349
|
+
case ReferenceTag: {
|
|
1350
|
+
let { type, name, flags } = tag.value;
|
|
1351
|
+
|
|
1352
|
+
if ([ReferenceTag, ShiftTag, BindingTag].includes(targetPath.tagPathAt(-1, -1)?.tag.type))
|
|
1353
|
+
throw new Error('invalid location for reference');
|
|
1354
|
+
if (!name && !type) throw new Error();
|
|
1355
|
+
|
|
1356
|
+
if (flags.hasGap && flags.intrinsic) throw new Error();
|
|
1357
|
+
if (type && !['_', '.', '#', '@'].includes(type)) throw new Error();
|
|
1358
|
+
if (flags.array && ['_', '#', '@'].includes(type)) throw new Error();
|
|
1359
|
+
if (getFlags(targetPath.node).token && type !== '@') throw new Error();
|
|
1360
|
+
if (targetPath.open.type === Symbol.for('_') && name != null) throw new Error();
|
|
1361
|
+
if (targetPath.open.type === Symbol.for('_') && !['_', '#'].includes(type))
|
|
1362
|
+
throw new Error();
|
|
1363
|
+
|
|
1364
|
+
if (tag.value.name) {
|
|
1365
|
+
let property = getProperty(tag.value.name, targetPath.node);
|
|
1366
|
+
if (
|
|
1367
|
+
getOr(null, tag.value.name, targetPath.node) &&
|
|
1368
|
+
!property.value.shift &&
|
|
1369
|
+
!referencesAreEqual(tag.value, property.value.reference)
|
|
1370
|
+
) {
|
|
1371
|
+
throw new Error('mismatched references');
|
|
1372
|
+
}
|
|
1373
|
+
} else if (tag.value.type === '_') {
|
|
1374
|
+
let rootIdx = getPropertyTagsIndex(targetPath.node, '_', null, 0);
|
|
1375
|
+
|
|
1376
|
+
if (
|
|
1377
|
+
rootIdx != null &&
|
|
1378
|
+
!referencesAreEqual(
|
|
1379
|
+
tag.value,
|
|
1380
|
+
Tags.getAt(rootIdx, getTags(targetPath.node)).value.property.reference,
|
|
1381
|
+
)
|
|
1382
|
+
) {
|
|
1383
|
+
throw new Error('mismatched references');
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
let property = buildChild(Property, buildProperty([tag]));
|
|
1388
|
+
|
|
1389
|
+
targetPath = targetPath.replaceWith(
|
|
1390
|
+
buildNode(Tags.push(getTags(targetPath.node), property)),
|
|
1391
|
+
);
|
|
1392
|
+
break;
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
case BindingTag: {
|
|
1396
|
+
if (![ReferenceTag, ShiftTag].includes(this.tagPathAt(-1, -1).tag.type)) {
|
|
1397
|
+
throw new Error('Invalid location for BindingTag');
|
|
1398
|
+
}
|
|
1399
|
+
if (!tag.value.segments) throw new Error();
|
|
1400
|
+
|
|
1401
|
+
let refPath = this.tagPathAt(-1, 0);
|
|
1402
|
+
let propPath = TagPath.from(refPath.path, refPath.tagsIndex);
|
|
1403
|
+
|
|
1404
|
+
let { shift } = propPath.tag.value;
|
|
1405
|
+
|
|
1406
|
+
if (![ReferenceTag, ShiftTag].includes(refPath.tag.type)) throw new Error();
|
|
1407
|
+
|
|
1408
|
+
if (refPath.tag.type === ShiftTag) {
|
|
1409
|
+
refPath = TagPath.from(refPath.path, refPath.tagsIndex - shift.index, 0);
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
let { 0: firstTag, 1: bindingTags = [] } = propPath.tag.value.tags;
|
|
1413
|
+
let tags = [firstTag, [...bindingTags, tag]];
|
|
1414
|
+
let property = buildChild(Property, buildProperty(tags, shift));
|
|
1415
|
+
|
|
1416
|
+
targetPath = this.replaceWith(
|
|
1417
|
+
buildNode(Tags.replaceAt(propPath.tagsIndex, getTags(this.node), property)),
|
|
1418
|
+
);
|
|
1419
|
+
break;
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
case OpenNodeTag: {
|
|
1423
|
+
let { literalValue, flags, type } = tag.value;
|
|
1424
|
+
|
|
1425
|
+
if (this.held && flags.token) throw new Error();
|
|
1426
|
+
|
|
1427
|
+
if (type === Symbol.for('__')) {
|
|
1428
|
+
throw new Error('not implemented');
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
let refTag = this.node && Tags.getAt(-1, getChildren(this.node)).value.tags[0];
|
|
1432
|
+
|
|
1433
|
+
if (![ReferenceTag, ShiftTag].includes(refTag.type)) throw new Error();
|
|
1434
|
+
|
|
1435
|
+
let node = buildNode(tag);
|
|
1436
|
+
|
|
1437
|
+
if (literalValue && !flags.token) {
|
|
1438
|
+
throw new Error();
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
targetPath = this.advanceUnwrapped(node).path;
|
|
1442
|
+
|
|
1443
|
+
targetPath = targetPath.tagPathAt(-1).inner;
|
|
1444
|
+
|
|
1445
|
+
break;
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
case GapTag:
|
|
1449
|
+
case NullTag: {
|
|
1450
|
+
// if (getSigilTag(this.node)) throw new Error();
|
|
1451
|
+
if (this.tagPathAt(-1, 0).tag.type !== ReferenceTag) {
|
|
1452
|
+
throw new Error('Invalid location for NullTag');
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
let node = buildNode(tag);
|
|
1456
|
+
|
|
1457
|
+
targetPath = this.advanceUnwrapped(node).path;
|
|
1458
|
+
// targetPath = targetPath.tagPathAt(-1).inner; // ?
|
|
1459
|
+
|
|
1460
|
+
break;
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
case CloseNodeTag: {
|
|
1464
|
+
let { node } = targetPath;
|
|
1465
|
+
|
|
1466
|
+
let lastChild = targetPath.getChild(-1);
|
|
1467
|
+
|
|
1468
|
+
if (lastChild?.type === Property && !propertyIsFull(lastChild)) throw new Error();
|
|
1469
|
+
|
|
1470
|
+
let openTag = getOpenTag(node);
|
|
1471
|
+
|
|
1472
|
+
if (!openTag) throw new Error();
|
|
1473
|
+
if (openTag.value.selfClosing) throw new Error();
|
|
1474
|
+
|
|
1475
|
+
targetPath = targetPath.replaceWith(buildNode(Tags.push(getTags(node), tag)));
|
|
1476
|
+
break;
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
case NullNode:
|
|
1480
|
+
case GapNode:
|
|
1481
|
+
case TreeNode: {
|
|
1482
|
+
let node = tag;
|
|
1483
|
+
let parentPath = targetPath;
|
|
1484
|
+
let { node: parentNode } = parentPath;
|
|
1485
|
+
|
|
1486
|
+
let tagPath = TagPath.from(parentPath, -1);
|
|
1487
|
+
|
|
1488
|
+
if (isMultiFragment(node)) {
|
|
1489
|
+
let existingProperty = tagPath;
|
|
1490
|
+
|
|
1491
|
+
while (existingProperty?.tag.type === AttributeDefinition) {
|
|
1492
|
+
existingProperty = existingProperty.previousSibling.propertyPath;
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
if (
|
|
1496
|
+
existingProperty.tag.type !== OpenNodeTag &&
|
|
1497
|
+
existingProperty.tag &&
|
|
1498
|
+
!propertyIsFull(existingProperty.tag)
|
|
1499
|
+
) {
|
|
1500
|
+
throw new Error();
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
let newPath = Path.from(buildNode(this.node.value.tags));
|
|
1504
|
+
|
|
1505
|
+
for (let tag of Tags.traverse(node.value.children)) {
|
|
1506
|
+
if (tag.type === Property) {
|
|
1507
|
+
newPath = newPath.advance(tag);
|
|
1508
|
+
} else {
|
|
1509
|
+
newPath = newPath.advanceUnwrapped(tag).path.atDepth(0);
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
targetPath = this.replaceWith(newPath.node);
|
|
1514
|
+
break;
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
let shift = tagPath.tag.type === Property ? tagPath.tag.value.shift : undefined;
|
|
1518
|
+
let { held } = this;
|
|
1519
|
+
|
|
1520
|
+
if (held) {
|
|
1521
|
+
// let heldProperty = this.tagPathAt(-2, 2).tag.value;
|
|
1522
|
+
let matchesHeld = isGapNode(node);
|
|
1523
|
+
if (getRoot(node)) {
|
|
1524
|
+
matchesHeld =
|
|
1525
|
+
matchesHeld ||
|
|
1526
|
+
isGapNode(node) ||
|
|
1527
|
+
held.node === node ||
|
|
1528
|
+
held.node === (getOriginalFirstNode(getRoot(node)) || held.node);
|
|
1529
|
+
if (!matchesHeld) {
|
|
1530
|
+
// TODO We're passing by the node that shifted if it's a cover!
|
|
1531
|
+
throw new Error();
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
if (propertyIsFull(tagPath.tag)) {
|
|
1537
|
+
let tags = [null, [], node];
|
|
1538
|
+
let property = buildChild(Property, buildProperty(tags, shift));
|
|
1539
|
+
|
|
1540
|
+
targetPath = this.replaceWith(buildNode(Tags.push(parentNode.value.tags, property)));
|
|
1541
|
+
} else {
|
|
1542
|
+
let { 0: firstTag, 1: bindingTags = [] } = tagPath.tag.value.tags;
|
|
1543
|
+
let tags = [firstTag, bindingTags, node];
|
|
1544
|
+
let property = buildChild(Property, buildProperty(tags, shift));
|
|
1545
|
+
|
|
1546
|
+
targetPath = this.replaceWith(
|
|
1547
|
+
buildNode(Tags.replaceAt(tagPath.tagsIndex, parentNode.value.tags, property)),
|
|
1548
|
+
);
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
break;
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
case AttributeDefinition: {
|
|
1555
|
+
if (this.held) throw new Error('invalid place for an attribute binding');
|
|
1556
|
+
|
|
1557
|
+
let lastChild = this.getChild(-1);
|
|
1558
|
+
|
|
1559
|
+
if (lastChild?.type === Property && !propertyIsFull(lastChild)) throw new Error();
|
|
1560
|
+
|
|
1561
|
+
// add undefined attributes from value
|
|
1562
|
+
let { node } = this;
|
|
1563
|
+
if (tag.type !== AttributeDefinition) throw new Error();
|
|
1564
|
+
|
|
1565
|
+
let { path, value } = tag.value;
|
|
1566
|
+
let openTag = getOpenTag(node);
|
|
1567
|
+
let { attributes } = node.value;
|
|
1568
|
+
|
|
1569
|
+
if (!objHas(attributes, path) && objGet(attributes, path) !== undefined)
|
|
1570
|
+
throw new Error('Can only define undefined attributes');
|
|
1571
|
+
|
|
1572
|
+
if (value === undefined) throw new Error('cannot define attribute to undefined');
|
|
1573
|
+
|
|
1574
|
+
let { flags, name } = openTag.value;
|
|
1575
|
+
attributes = immSet(attributes, path, value);
|
|
1576
|
+
let newOpenTag = buildOpenNodeTag(flags, name, null, attributes);
|
|
1577
|
+
|
|
1578
|
+
targetPath = this.replaceWith(
|
|
1579
|
+
buildNode(Tags.push(Tags.replaceAt(0, getTags(node), newOpenTag), tag)),
|
|
1580
|
+
);
|
|
1581
|
+
break;
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
case ShiftTag: {
|
|
1585
|
+
let lastPropertyTag = this.tagPathAt(-1).tag;
|
|
1586
|
+
|
|
1587
|
+
if (lastPropertyTag.type !== Property) throw new Error();
|
|
1588
|
+
|
|
1589
|
+
let { reference, shift: heldShift } = lastPropertyTag.value;
|
|
1590
|
+
|
|
1591
|
+
if (!reference) {
|
|
1592
|
+
({ reference } = this.tagPathAt(-1 - (heldShift?.index ?? 0)).tag.value);
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
if (!reference.flags.expression && reference.type !== '_') throw new Error();
|
|
1596
|
+
|
|
1597
|
+
let shift = heldShift
|
|
1598
|
+
? buildShift(heldShift.index + 1, heldShift.height + 1)
|
|
1599
|
+
: buildShift(1, 3);
|
|
1600
|
+
|
|
1601
|
+
let property = buildChild(Property, buildProperty([tag], shift));
|
|
1602
|
+
|
|
1603
|
+
targetPath = this.replaceWith(buildNode(Tags.push(this.node.value.tags, property)));
|
|
1604
|
+
break;
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
case LiteralTag:
|
|
1608
|
+
if (typeof tag.value !== 'string') throw new Error();
|
|
1609
|
+
|
|
1610
|
+
targetPath = this.replaceWith(buildNode(Tags.push(this.node.value.tags, tag)));
|
|
1611
|
+
break;
|
|
1612
|
+
|
|
1613
|
+
default:
|
|
1614
|
+
throw new Error();
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1617
|
+
return targetPath && TagPath.from(targetPath, -1, isNodeTag(tag) ? -1 : offsetForTag(tag));
|
|
1618
|
+
}
|
|
602
1619
|
};
|
|
603
1620
|
|
|
1621
|
+
Object.freeze(Path.prototype);
|
|
1622
|
+
|
|
604
1623
|
export const tagPathsAreEqual = (a, b) => {
|
|
605
1624
|
if (a == null || b == null) return b == a;
|
|
606
|
-
return a.path.node === b.path.node && a.
|
|
1625
|
+
return a.path.node === b.path.node && a.tagsIndex === b.tagsIndex;
|
|
607
1626
|
};
|
|
608
1627
|
|
|
609
1628
|
export class TagPath {
|
|
610
|
-
|
|
611
|
-
|
|
1629
|
+
static from(path, tagsIndex, propertyIndex) {
|
|
1630
|
+
let tags = getTags(path.node);
|
|
1631
|
+
let size = Tags.getSize(tags);
|
|
1632
|
+
let index = Number.isFinite(tagsIndex) && tagsIndex < 0 ? size + tagsIndex : tagsIndex;
|
|
1633
|
+
|
|
1634
|
+
let propertyIndex_ = typeof propertyIndex === 'number' ? [propertyIndex] : propertyIndex;
|
|
1635
|
+
|
|
1636
|
+
let propTag = Tags.getAt(index, tags);
|
|
1637
|
+
|
|
1638
|
+
if (
|
|
1639
|
+
[OpenNodeTag, CloseNodeTag, LiteralTag, AttributeDefinition, GapTag, NullTag].includes(
|
|
1640
|
+
propTag?.type,
|
|
1641
|
+
)
|
|
1642
|
+
) {
|
|
1643
|
+
propertyIndex_ = [];
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
let resolvedPropertyIndex =
|
|
1647
|
+
propTag && (propertyIndex_?.length ? Tags.findPath(propertyIndex_, propTag.value.tags) : []);
|
|
1648
|
+
|
|
1649
|
+
return resolvedPropertyIndex && new TagPath(path, index, resolvedPropertyIndex);
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
static fromNode(node, tagsIndex, propertyIndex) {
|
|
1653
|
+
return TagPath.from(Path.from(node), tagsIndex, propertyIndex);
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
static fromTag(openTag) {
|
|
1657
|
+
return TagPath.fromNode(buildNode(openTag), 0);
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
constructor(path, tagsIndex, propertyIndex) {
|
|
1661
|
+
if (path == null) throw new Error();
|
|
1662
|
+
if (path.tag) throw new Error();
|
|
1663
|
+
if (!Number.isFinite(tagsIndex) || tagsIndex < 0) throw new Error();
|
|
1664
|
+
if (!isArray(propertyIndex)) throw new Error();
|
|
1665
|
+
|
|
1666
|
+
let propertyIndex_ = Object.freeze([...propertyIndex]);
|
|
612
1667
|
|
|
613
|
-
let tag =
|
|
1668
|
+
let tag = Tags.getAt(tagsIndex, getTags(path.node));
|
|
614
1669
|
|
|
615
|
-
if (
|
|
1670
|
+
if (propertyIndex_.length) {
|
|
1671
|
+
tag = Tags.getAt(propertyIndex_, tag.value.tags);
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
if (tag == null || isArray(tag)) throw new Error();
|
|
1675
|
+
|
|
1676
|
+
for (let segment of propertyIndex_) {
|
|
1677
|
+
if (!isPlainObject(segment) || !(segment.index === 0 || segment.index > 0)) throw new Error();
|
|
1678
|
+
}
|
|
616
1679
|
|
|
617
1680
|
this.path = path;
|
|
1681
|
+
this.tagsIndex = tagsIndex;
|
|
1682
|
+
this.propertyIndex = propertyIndex_;
|
|
1683
|
+
|
|
618
1684
|
this.node = path.node;
|
|
619
1685
|
this.tag = tag;
|
|
620
|
-
|
|
1686
|
+
|
|
1687
|
+
if (tag.type === Property && propertyIndex_.length) throw new Error();
|
|
621
1688
|
|
|
622
1689
|
freeze(this);
|
|
623
1690
|
}
|
|
624
1691
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
let index = childrenIndex < 0 ? size + childrenIndex : childrenIndex;
|
|
628
|
-
|
|
629
|
-
return index >= 0 && index < size ? new TagPath(path, index) : null;
|
|
1692
|
+
get child() {
|
|
1693
|
+
return this.tag;
|
|
630
1694
|
}
|
|
631
1695
|
|
|
632
|
-
|
|
633
|
-
return
|
|
1696
|
+
get parentNode() {
|
|
1697
|
+
return this.path.parentNode;
|
|
634
1698
|
}
|
|
635
1699
|
|
|
636
|
-
get
|
|
637
|
-
return this.
|
|
1700
|
+
get depth() {
|
|
1701
|
+
return this.path.depth;
|
|
638
1702
|
}
|
|
639
1703
|
|
|
640
1704
|
siblingAt(index) {
|
|
641
1705
|
return TagPath.from(this.path, index);
|
|
642
1706
|
}
|
|
643
1707
|
|
|
1708
|
+
mapOnto(rootNode) {
|
|
1709
|
+
let path = this.path.mapOnto(rootNode);
|
|
1710
|
+
|
|
1711
|
+
return TagPath.from(path, this.tagsIndex, this.propertyIndex);
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
get referenceTagPath() {
|
|
1715
|
+
let path = TagPath.from(this.path, this.tagsIndex, 0);
|
|
1716
|
+
if (path && path.propertyPath) {
|
|
1717
|
+
let { shift } = path.propertyPath.tag.value;
|
|
1718
|
+
if (shift) {
|
|
1719
|
+
path = TagPath.from(this.path, this.tagsIndex - shift.index, 0);
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
return path?.tag.type === ReferenceTag ? path : null;
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
get nextProperty() {
|
|
1726
|
+
let { path, tagsIndex } = this;
|
|
1727
|
+
|
|
1728
|
+
let nextChild = TagPath.from(path, tagsIndex + 1);
|
|
1729
|
+
|
|
1730
|
+
return nextChild?.tag.type === Property ? nextChild : null;
|
|
1731
|
+
}
|
|
1732
|
+
|
|
644
1733
|
get nextSibling() {
|
|
645
|
-
|
|
1734
|
+
let { path, tagsIndex, propertyIndex } = this;
|
|
1735
|
+
|
|
1736
|
+
let propertyIndex0 = propertyIndex[0]?.index;
|
|
646
1737
|
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
? null
|
|
650
|
-
: Children.getAt(childrenIndex + 1, path.node.children);
|
|
1738
|
+
let nextChildIndex = tagsIndex === 0 ? 0 : tagsIndex - 1 + 1;
|
|
1739
|
+
let nextChild = path.getChild(nextChildIndex);
|
|
651
1740
|
|
|
652
|
-
|
|
1741
|
+
if (propertyIndex0 == null && !nextChild) {
|
|
1742
|
+
return this.tag.type === CloseNodeTag ? null : path.closeTagPath;
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
switch (propertyIndex0) {
|
|
1746
|
+
case 0:
|
|
1747
|
+
case 1: {
|
|
1748
|
+
let childIndex = tagsIndex - 1;
|
|
1749
|
+
let bindingIndex = propertyIndex[1]?.index ?? -1;
|
|
1750
|
+
let binding = path.getBindingTagPath(childIndex, bindingIndex + 1);
|
|
1751
|
+
if (binding) return binding;
|
|
1752
|
+
return path.getNodeTagPath(childIndex);
|
|
1753
|
+
}
|
|
1754
|
+
case 2:
|
|
1755
|
+
default: {
|
|
1756
|
+
if (!nextChild || nextChild.type !== Property) {
|
|
1757
|
+
return path.tagPathAt(tagsIndex + 1);
|
|
1758
|
+
} else {
|
|
1759
|
+
let ref = path.getReferenceTagPath(nextChildIndex);
|
|
1760
|
+
if (ref) return ref;
|
|
1761
|
+
let binding = path.getBindingTagPath(nextChildIndex, 0);
|
|
1762
|
+
if (binding) return binding;
|
|
1763
|
+
return path.getNodeTagPath(nextChildIndex);
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
get previousSibling() {
|
|
1770
|
+
let { path, tagsIndex, propertyIndex } = this;
|
|
1771
|
+
|
|
1772
|
+
let propertyIndex0 = propertyIndex[0]?.index;
|
|
1773
|
+
|
|
1774
|
+
if (!tagsIndex) return null;
|
|
1775
|
+
|
|
1776
|
+
let prevChildIndex = tagsIndex === 0 ? 0 : tagsIndex - 1 - 1;
|
|
1777
|
+
let prevChild = path.getChild(prevChildIndex);
|
|
1778
|
+
|
|
1779
|
+
if (!prevChild) {
|
|
1780
|
+
return path.getOpenTagPath();
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1783
|
+
if (propertyIndex0) {
|
|
1784
|
+
if (propertyIndex0 > 0) {
|
|
1785
|
+
let property = path.getChild(tagsIndex - 1);
|
|
1786
|
+
let bindingIndex = propertyIndex[1]?.index ?? property.value.bindings.length;
|
|
1787
|
+
let binding = path.getBindingTagPath(tagsIndex - 1, bindingIndex - 1);
|
|
1788
|
+
if (binding) return binding;
|
|
1789
|
+
}
|
|
1790
|
+
|
|
1791
|
+
let ref = path.getReferenceTagPath(tagsIndex - 1);
|
|
1792
|
+
if (ref) return ref;
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
return prevChild && prevChild.type === Property
|
|
1796
|
+
? path.getNodeTagPath(tagsIndex - 1 - 1)
|
|
1797
|
+
: prevChild;
|
|
653
1798
|
}
|
|
654
1799
|
|
|
655
1800
|
get next() {
|
|
656
|
-
let { path,
|
|
1801
|
+
let { path, tagsIndex, propertyIndex } = this;
|
|
1802
|
+
|
|
1803
|
+
propertyIndex = [...propertyIndex];
|
|
657
1804
|
|
|
658
1805
|
let leaving = false;
|
|
659
1806
|
|
|
660
1807
|
for (;;) {
|
|
661
|
-
let
|
|
662
|
-
let
|
|
663
|
-
let
|
|
664
|
-
let wasLeaving = leaving;
|
|
1808
|
+
let tag = Tags.getAt(tagsIndex, getTags(path.node));
|
|
1809
|
+
let propTag = tag;
|
|
1810
|
+
let lastRef = null;
|
|
665
1811
|
leaving = false;
|
|
666
1812
|
|
|
667
1813
|
if (!tag) return null;
|
|
668
1814
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
// in
|
|
675
|
-
if (tag.type === Property && !wasLeaving) {
|
|
676
|
-
// jump to gap tag?
|
|
677
|
-
if (
|
|
678
|
-
path.parent &&
|
|
679
|
-
tag.value.reference.flags.expression &&
|
|
680
|
-
(childrenIndex === 3 ||
|
|
681
|
-
(childrenIndex === 5 &&
|
|
682
|
-
Children.getAt(2, path.node.children).type === InitializerTag)) &&
|
|
683
|
-
Children.getAt(path.referenceIndex, path.parent.node.children)?.type === ShiftTag
|
|
684
|
-
) {
|
|
685
|
-
let { reference: ref } = tag.value;
|
|
686
|
-
let shiftStack = path.node.properties[ref.name].node;
|
|
687
|
-
|
|
688
|
-
if (ref.isArray) {
|
|
689
|
-
shiftStack = btree.getAt(-1, shiftStack).node;
|
|
690
|
-
}
|
|
691
|
-
let gapNode = btree.getAt(0, shiftStack).node;
|
|
1815
|
+
if (tag.type === Property) {
|
|
1816
|
+
if (propertyIndex.length === 0 && !leaving) {
|
|
1817
|
+
propertyIndex.push({ index: 0, node: tag.value.tags });
|
|
1818
|
+
}
|
|
692
1819
|
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
1820
|
+
if (propertyIndex != null) {
|
|
1821
|
+
propTag = Tags.getAt(propertyIndex, tag.value.tags);
|
|
1822
|
+
lastRef = Tags.getAt(0, tag.value.tags);
|
|
696
1823
|
}
|
|
1824
|
+
}
|
|
697
1825
|
|
|
698
|
-
|
|
699
|
-
|
|
1826
|
+
if (isArray(propTag)) {
|
|
1827
|
+
if (propTag.length) {
|
|
1828
|
+
// enter bindings array
|
|
1829
|
+
propertyIndex.push({ index: 0, node: propTag });
|
|
1830
|
+
propTag = propTag[propertyIndex[1].index];
|
|
1831
|
+
} else {
|
|
1832
|
+
propertyIndex = [{ index: propertyIndex[0].index + 1, node: tag }];
|
|
1833
|
+
}
|
|
700
1834
|
continue;
|
|
701
1835
|
}
|
|
702
1836
|
|
|
1837
|
+
let isInitialTag =
|
|
1838
|
+
path.node === this.path.node &&
|
|
1839
|
+
tagsIndex === this.tagsIndex &&
|
|
1840
|
+
arraysEqual(propertyIndex, this.propertyIndex);
|
|
1841
|
+
|
|
1842
|
+
// done
|
|
1843
|
+
if (!isInitialTag && !isNodeTag(propTag)) {
|
|
1844
|
+
return TagPath.from(path, tagsIndex, propertyIndex);
|
|
1845
|
+
}
|
|
1846
|
+
|
|
703
1847
|
// shift
|
|
704
|
-
if (
|
|
705
|
-
let
|
|
1848
|
+
if (propTag.type === BindingTag && lastRef.type === ShiftTag) {
|
|
1849
|
+
let lastProp = Tags.getAt(tagsIndex, path.tags);
|
|
1850
|
+
let { shift } = lastProp.value;
|
|
1851
|
+
let refIndex = tagsIndex - shift.index;
|
|
706
1852
|
if (refIndex < 0) throw new Error();
|
|
707
|
-
let refTag =
|
|
708
|
-
|
|
709
|
-
const { name, isArray } = refTag.value;
|
|
710
|
-
let pathDesc = buildPathSegment(name);
|
|
711
|
-
let index;
|
|
712
|
-
if (isArray) {
|
|
713
|
-
index = getChildPropertyIndex(path.node, refIndex);
|
|
714
|
-
pathDesc = buildPathSegment(name, index);
|
|
715
|
-
}
|
|
1853
|
+
let refTag = Tags.getAt(refIndex, path.tags, 0);
|
|
716
1854
|
|
|
717
|
-
|
|
718
|
-
pathDesc.shiftIndex = prevTag.value.height;
|
|
1855
|
+
if (refTag.type !== ReferenceTag) throw new Error();
|
|
719
1856
|
|
|
720
|
-
|
|
721
|
-
|
|
1857
|
+
let { node } = tag.value;
|
|
1858
|
+
if (!node) return null;
|
|
722
1859
|
|
|
723
|
-
|
|
1860
|
+
path = new Path(path, tagsIndex);
|
|
724
1861
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
1862
|
+
if (!path) return null;
|
|
1863
|
+
|
|
1864
|
+
tagsIndex = 0;
|
|
1865
|
+
propertyIndex = [];
|
|
1866
|
+
continue;
|
|
728
1867
|
}
|
|
729
1868
|
|
|
1869
|
+
let { nextSibling } = this;
|
|
1870
|
+
|
|
730
1871
|
// over
|
|
731
|
-
if (
|
|
732
|
-
|
|
733
|
-
|
|
1872
|
+
if (nextSibling) {
|
|
1873
|
+
({ tagsIndex, propertyIndex } = nextSibling);
|
|
1874
|
+
// in
|
|
1875
|
+
if (isNodeTag(nextSibling.tag)) {
|
|
1876
|
+
let shiftPath = path;
|
|
1877
|
+
|
|
1878
|
+
while (
|
|
1879
|
+
shiftPath.parent &&
|
|
1880
|
+
!Tags.getAt(shiftPath.parentIndex - 1, shiftPath.parent.node.value.children).value.shift
|
|
1881
|
+
) {
|
|
1882
|
+
shiftPath = shiftPath.parent;
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
let isGap =
|
|
1886
|
+
path.parent &&
|
|
1887
|
+
tagsIndex === 1 &&
|
|
1888
|
+
shiftPath.parent &&
|
|
1889
|
+
Tags.getAt(shiftPath.parentIndex - 1, shiftPath.parent.node.value.children).value
|
|
1890
|
+
.shift &&
|
|
1891
|
+
tag.value.node ===
|
|
1892
|
+
Tags.getAt(shiftPath.parentIndex - 2, shiftPath.parent.node.value.children).value
|
|
1893
|
+
.node;
|
|
1894
|
+
|
|
1895
|
+
path = new Path(path, tagsIndex, isGap);
|
|
1896
|
+
tagsIndex = 0;
|
|
1897
|
+
propertyIndex = [];
|
|
1898
|
+
continue;
|
|
1899
|
+
} else {
|
|
1900
|
+
return nextSibling;
|
|
1901
|
+
}
|
|
734
1902
|
}
|
|
735
1903
|
|
|
736
1904
|
// out
|
|
737
|
-
if (path.
|
|
1905
|
+
if (path.parentIndex != null && path.parent) {
|
|
738
1906
|
do {
|
|
739
1907
|
if (
|
|
740
|
-
path.parent &&
|
|
741
|
-
|
|
1908
|
+
path.coverBoundary.parent &&
|
|
1909
|
+
Tags.getAt(
|
|
1910
|
+
[path.coverBoundary.parentIndex, 0],
|
|
1911
|
+
path.coverBoundary.parent.node.value.tags,
|
|
1912
|
+
)?.type === ShiftTag
|
|
742
1913
|
) {
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
1914
|
+
// while
|
|
1915
|
+
tagsIndex =
|
|
1916
|
+
Tags.getSize(path.parent.node.value.tags) > path.parentIndex + 1
|
|
1917
|
+
? path.parentIndex + 1
|
|
746
1918
|
: null;
|
|
747
1919
|
} else {
|
|
748
|
-
|
|
1920
|
+
tagsIndex = path.parentIndex + 1;
|
|
749
1921
|
}
|
|
750
1922
|
|
|
1923
|
+
propertyIndex = [];
|
|
751
1924
|
path = path.parent;
|
|
752
1925
|
leaving = true;
|
|
753
1926
|
|
|
754
1927
|
if (!path) return null;
|
|
755
|
-
} while (
|
|
1928
|
+
} while (tagsIndex == null);
|
|
756
1929
|
|
|
757
1930
|
leaving = true;
|
|
758
1931
|
continue;
|
|
@@ -763,124 +1936,91 @@ export class TagPath {
|
|
|
763
1936
|
}
|
|
764
1937
|
|
|
765
1938
|
get nextUnshifted() {
|
|
766
|
-
let { path,
|
|
1939
|
+
let { path, tagsIndex, propertyIndex } = this;
|
|
1940
|
+
|
|
1941
|
+
propertyIndex = [...propertyIndex];
|
|
767
1942
|
|
|
768
1943
|
let leaving = false;
|
|
769
1944
|
|
|
770
1945
|
for (;;) {
|
|
771
|
-
let tag =
|
|
772
|
-
let
|
|
1946
|
+
let tag = Tags.getAt(tagsIndex, getTags(path.node));
|
|
1947
|
+
let propTag = tag;
|
|
773
1948
|
let wasLeaving = leaving;
|
|
774
1949
|
leaving = false;
|
|
775
1950
|
|
|
776
1951
|
if (!tag) return null;
|
|
777
1952
|
|
|
778
|
-
if (tag.type ===
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
let tag_ = tag;
|
|
782
|
-
do {
|
|
783
|
-
tag_ = Children.getAt(childrenIndex + offset, path.node.children);
|
|
784
|
-
offset++;
|
|
785
|
-
|
|
786
|
-
if (tag_?.type === InitializerTag) break;
|
|
787
|
-
} while (tag_ && [BindingTag, ShiftTag].includes(tag_.type));
|
|
788
|
-
if (!tag_) {
|
|
789
|
-
return null;
|
|
1953
|
+
if (tag.type === Property) {
|
|
1954
|
+
if (propertyIndex.length === 0 && !leaving) {
|
|
1955
|
+
propertyIndex.push({ index: 0, node: tag.value.tags });
|
|
790
1956
|
}
|
|
791
|
-
}
|
|
792
1957
|
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
// in
|
|
799
|
-
if (
|
|
800
|
-
tag.type === Property &&
|
|
801
|
-
!wasLeaving &&
|
|
802
|
-
!(Children.getAt(childrenIndex + 1, path.node.children)?.type === ShiftTag)
|
|
803
|
-
) {
|
|
804
|
-
// TODO use properties to skip over a lot of tag walking
|
|
805
|
-
path = path.push(tag.value.node, childrenIndex - 2);
|
|
806
|
-
childrenIndex = 0;
|
|
807
|
-
continue;
|
|
1958
|
+
if (propertyIndex != null) {
|
|
1959
|
+
propTag = Tags.getAt(propertyIndex, tag.value.tags);
|
|
1960
|
+
}
|
|
808
1961
|
}
|
|
809
1962
|
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
1963
|
+
if (isArray(propTag)) {
|
|
1964
|
+
if (propTag.length) {
|
|
1965
|
+
// enter bindings array
|
|
1966
|
+
propertyIndex.push({ index: 0, node: propTag });
|
|
1967
|
+
propTag = propTag[propertyIndex[1].index];
|
|
1968
|
+
} else {
|
|
1969
|
+
propertyIndex = [{ index: propertyIndex[0].index + 1, node: tag }];
|
|
1970
|
+
}
|
|
813
1971
|
continue;
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
do {
|
|
819
|
-
childrenIndex = path.referenceIndex + 2;
|
|
820
|
-
|
|
821
|
-
path = path.parent;
|
|
822
|
-
leaving = true;
|
|
823
|
-
} while (childrenIndex == null);
|
|
824
|
-
|
|
825
|
-
leaving = true;
|
|
1972
|
+
} else if (isNodeTag(propTag) && !leaving) {
|
|
1973
|
+
path = path.push(tagsIndex);
|
|
1974
|
+
tagsIndex = 0;
|
|
1975
|
+
propertyIndex = [];
|
|
826
1976
|
continue;
|
|
827
1977
|
}
|
|
828
1978
|
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
get previousSibling() {
|
|
834
|
-
const { path, childrenIndex } = this;
|
|
835
|
-
|
|
836
|
-
const child = childrenIndex - 1 < 0 ? null : btree.getAt(childrenIndex - 1, path.node.children);
|
|
837
|
-
|
|
838
|
-
return child && new TagPath(path, childrenIndex - 1);
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
get previous() {
|
|
842
|
-
throw new Error('not implemented');
|
|
843
|
-
}
|
|
1979
|
+
let isInitialTag =
|
|
1980
|
+
path.node === this.path.node &&
|
|
1981
|
+
tagsIndex === this.tagsIndex &&
|
|
1982
|
+
arraysEqual(propertyIndex, this.propertyIndex);
|
|
844
1983
|
|
|
845
|
-
|
|
846
|
-
|
|
1984
|
+
if (!wasLeaving && propTag.type === ReferenceTag && propTag.value.flags.expression) {
|
|
1985
|
+
// move past shifts
|
|
847
1986
|
|
|
848
|
-
|
|
1987
|
+
let shifts = 0;
|
|
1988
|
+
let shiftedTag = Tags.getAt(tagsIndex + 1, getTags(path.node));
|
|
849
1989
|
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
1990
|
+
while (shiftedTag?.type === Property && shiftedTag.value.shift) {
|
|
1991
|
+
shifts++;
|
|
1992
|
+
propertyIndex = [{ index: 1, node: shiftedTag.value.tags }];
|
|
1993
|
+
shiftedTag = Tags.getAt(tagsIndex + 1 + shifts, path.tags);
|
|
1994
|
+
}
|
|
855
1995
|
|
|
856
|
-
|
|
1996
|
+
if (shifts) {
|
|
1997
|
+
tagsIndex += shifts;
|
|
1998
|
+
continue;
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
857
2001
|
|
|
858
2002
|
// done
|
|
859
|
-
if (!isInitialTag &&
|
|
860
|
-
return
|
|
2003
|
+
if (!isInitialTag && !isNodeTag(propTag) && !isArray(propTag)) {
|
|
2004
|
+
return TagPath.from(path, tagsIndex, propertyIndex);
|
|
861
2005
|
}
|
|
862
2006
|
|
|
863
|
-
|
|
864
|
-
if (tag.type === Property && !wasLeaving) {
|
|
865
|
-
path = path.push(tag.value.node, childrenIndex - 1);
|
|
866
|
-
childrenIndex = Children.getSize(tag.value.children) - 1;
|
|
867
|
-
continue;
|
|
868
|
-
}
|
|
2007
|
+
let { nextSibling } = TagPath.from(path, tagsIndex, propertyIndex);
|
|
869
2008
|
|
|
870
2009
|
// over
|
|
871
|
-
if (
|
|
872
|
-
|
|
2010
|
+
if (nextSibling) {
|
|
2011
|
+
({ tagsIndex, propertyIndex } = nextSibling);
|
|
873
2012
|
continue;
|
|
874
2013
|
}
|
|
875
2014
|
|
|
876
2015
|
// out
|
|
877
|
-
if (path.
|
|
2016
|
+
if (path.parentIndex != null) {
|
|
878
2017
|
do {
|
|
879
|
-
|
|
2018
|
+
tagsIndex = path.parentIndex + 1;
|
|
880
2019
|
|
|
881
2020
|
path = path.parent;
|
|
882
2021
|
leaving = true;
|
|
883
|
-
|
|
2022
|
+
if (!path) return null;
|
|
2023
|
+
} while (tagsIndex == null);
|
|
884
2024
|
|
|
885
2025
|
leaving = true;
|
|
886
2026
|
continue;
|
|
@@ -890,40 +2030,52 @@ export class TagPath {
|
|
|
890
2030
|
}
|
|
891
2031
|
}
|
|
892
2032
|
|
|
893
|
-
get
|
|
894
|
-
|
|
2033
|
+
get previous() {
|
|
2034
|
+
throw new Error('not implemented');
|
|
895
2035
|
}
|
|
896
2036
|
|
|
897
|
-
get
|
|
898
|
-
|
|
2037
|
+
get previousUnshifted() {
|
|
2038
|
+
throw new Error('not implemented');
|
|
2039
|
+
}
|
|
899
2040
|
|
|
900
|
-
|
|
2041
|
+
get propertyPath() {
|
|
2042
|
+
let { path, tagsIndex } = this;
|
|
901
2043
|
|
|
902
|
-
|
|
903
|
-
return null;
|
|
904
|
-
}
|
|
2044
|
+
let tag = Tags.getAt(tagsIndex, getTags(path.node));
|
|
905
2045
|
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
shiftPath = refPath;
|
|
909
|
-
refPath = TagPath.from(this.path, this.childrenIndex - refPath.tag.value.index * 3 - 2);
|
|
910
|
-
}
|
|
2046
|
+
return tag.type === Property ? path.tagPathAt(tagsIndex) : null;
|
|
2047
|
+
}
|
|
911
2048
|
|
|
912
|
-
|
|
2049
|
+
get innerNode() {
|
|
2050
|
+
return this.inner?.node;
|
|
2051
|
+
}
|
|
913
2052
|
|
|
914
|
-
|
|
2053
|
+
get inner() {
|
|
2054
|
+
let { tagsIndex, tag } = this;
|
|
915
2055
|
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
2056
|
+
let node;
|
|
2057
|
+
switch (tag.type) {
|
|
2058
|
+
case Property: {
|
|
2059
|
+
({ node } = tag.value);
|
|
2060
|
+
break;
|
|
2061
|
+
}
|
|
2062
|
+
case TreeNode: {
|
|
2063
|
+
node = tag;
|
|
2064
|
+
break;
|
|
2065
|
+
}
|
|
2066
|
+
default:
|
|
2067
|
+
throw new Error();
|
|
2068
|
+
}
|
|
2069
|
+
return node && this.path.push(tagsIndex);
|
|
924
2070
|
}
|
|
925
2071
|
|
|
926
2072
|
equalTo(tagPath) {
|
|
927
|
-
return
|
|
2073
|
+
return (
|
|
2074
|
+
this.node === tagPath.node &&
|
|
2075
|
+
this.tagsIndex === tagPath.tagsIndex &&
|
|
2076
|
+
arraysEqual(this.propertyIndex, tagPath.propertyIndex)
|
|
2077
|
+
);
|
|
928
2078
|
}
|
|
929
2079
|
}
|
|
2080
|
+
|
|
2081
|
+
Object.freeze(TagPath.prototype);
|