@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/builders.js +148 -95
- package/lib/path.js +1303 -437
- package/lib/print.js +66 -43
- package/lib/shorthand.js +17 -13
- package/lib/stream.js +433 -32
- package/lib/symbols.js +3 -2
- package/lib/tags.js +106 -57
- package/lib/template.js +44 -42
- package/lib/tree.js +59 -513
- package/package.json +3 -3
- package/lib/path-facade.js +0 -44
package/lib/path.js
CHANGED
|
@@ -3,27 +3,193 @@ import * as BTree from '@bablr/agast-helpers/btree';
|
|
|
3
3
|
import * as Tags from './tags.js';
|
|
4
4
|
import {
|
|
5
5
|
ReferenceTag,
|
|
6
|
-
InitializerTag,
|
|
7
|
-
DoctypeTag,
|
|
8
6
|
CloseNodeTag,
|
|
9
7
|
GapTag,
|
|
10
8
|
NullTag,
|
|
11
9
|
ShiftTag,
|
|
12
10
|
BindingTag,
|
|
13
|
-
PropertyWrapper,
|
|
14
11
|
Property,
|
|
12
|
+
OpenNodeTag,
|
|
13
|
+
AttributeDefinition,
|
|
14
|
+
LiteralTag,
|
|
15
|
+
TreeNode,
|
|
16
|
+
NullNode,
|
|
17
|
+
GapNode,
|
|
18
|
+
Document,
|
|
15
19
|
} from './symbols.js';
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
|
|
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);
|
|
19
49
|
|
|
20
|
-
|
|
21
|
-
|
|
50
|
+
return node;
|
|
51
|
+
};
|
|
22
52
|
|
|
23
|
-
|
|
24
|
-
|
|
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
|
+
});
|
|
25
90
|
} else {
|
|
26
|
-
|
|
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();
|
|
27
193
|
}
|
|
28
194
|
};
|
|
29
195
|
|
|
@@ -31,11 +197,33 @@ export const offsetForTag = (tag) => {
|
|
|
31
197
|
switch (tag.type) {
|
|
32
198
|
case ReferenceTag:
|
|
33
199
|
case ShiftTag:
|
|
34
|
-
return 0;
|
|
200
|
+
return [0];
|
|
35
201
|
case BindingTag:
|
|
36
|
-
|
|
37
|
-
|
|
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;
|
|
38
224
|
}
|
|
225
|
+
|
|
226
|
+
return true;
|
|
39
227
|
};
|
|
40
228
|
|
|
41
229
|
export const buildPathSegment = (name, index = null, shiftIndex = null) => {
|
|
@@ -52,63 +240,72 @@ export const buildFullPathSegment = (type, name, index = null, shiftIndex = null
|
|
|
52
240
|
return { type, name, index, shiftIndex };
|
|
53
241
|
};
|
|
54
242
|
|
|
55
|
-
export const getRootProperty = (node
|
|
56
|
-
if (node == null || !
|
|
243
|
+
export const getRootProperty = (node) => {
|
|
244
|
+
if (node == null || !isCover(node)) {
|
|
57
245
|
return null;
|
|
58
246
|
}
|
|
59
|
-
let idx = getPropertyTagsIndex(node, '
|
|
247
|
+
let idx = getPropertyTagsIndex(node, '_', null);
|
|
60
248
|
|
|
61
249
|
if (idx == null) return null;
|
|
62
250
|
|
|
63
|
-
let tag = Tags.getAt(idx, node
|
|
251
|
+
let tag = Tags.getAt(idx, getTags(node));
|
|
64
252
|
|
|
65
|
-
if (tag.type !==
|
|
66
|
-
return tag
|
|
253
|
+
if (tag.type !== Property) throw new Error();
|
|
254
|
+
return tag;
|
|
67
255
|
};
|
|
68
256
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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++;
|
|
72
265
|
}
|
|
73
266
|
|
|
74
|
-
return
|
|
267
|
+
return node_;
|
|
75
268
|
};
|
|
76
269
|
|
|
77
|
-
export const
|
|
78
|
-
|
|
79
|
-
for (let i = 0; ; i++) {
|
|
80
|
-
let root = getRoot(node, i);
|
|
81
|
-
if (root) {
|
|
82
|
-
arr.push(root);
|
|
83
|
-
} else {
|
|
84
|
-
break;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
return arr;
|
|
270
|
+
export const getSigilTag = (node) => {
|
|
271
|
+
return Tags.getValues(getTags(node))[0];
|
|
88
272
|
};
|
|
89
273
|
|
|
90
274
|
export const getOpenTag = (node) => {
|
|
91
|
-
|
|
275
|
+
let tag = Tags.getValues(getTags(node))[0];
|
|
276
|
+
return tag.type === OpenNodeTag ? tag : null;
|
|
92
277
|
};
|
|
93
278
|
|
|
94
279
|
export const getCloseTag = (node) => {
|
|
95
|
-
return Tags.getValues(node
|
|
280
|
+
return Tags.getValues(getTags(node))[2];
|
|
96
281
|
};
|
|
97
282
|
|
|
98
283
|
export const isNullNode = (node) => {
|
|
99
|
-
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 : [];
|
|
100
293
|
};
|
|
101
294
|
|
|
102
|
-
export const
|
|
103
|
-
return node
|
|
295
|
+
export const isFragment = (node) => {
|
|
296
|
+
return node?.type === TreeNode && [Symbol.for('__'), Symbol.for('_')].includes(node.value.type);
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
export const isMultiFragment = (node) => {
|
|
300
|
+
return node?.type === TreeNode && node.value.type === Symbol.for('__');
|
|
104
301
|
};
|
|
105
302
|
|
|
106
303
|
export const isGapNode = (node) => {
|
|
107
|
-
return node &&
|
|
304
|
+
return node && Tags.getAt(0, getTags(node)).type === GapTag;
|
|
108
305
|
};
|
|
109
306
|
|
|
110
307
|
export const isStubNode = (node) => {
|
|
111
|
-
return node &&
|
|
308
|
+
return node && [GapTag, NullTag].includes(Tags.getAt(0, getTags(node)).type);
|
|
112
309
|
};
|
|
113
310
|
|
|
114
311
|
export const isStubTag = (tag) => {
|
|
@@ -116,19 +313,19 @@ export const isStubTag = (tag) => {
|
|
|
116
313
|
};
|
|
117
314
|
|
|
118
315
|
export const getChildPropertyIndex = (agAstNode, tagsIndex) => {
|
|
119
|
-
let child = Tags.getAt(tagsIndex, agAstNode.tags);
|
|
316
|
+
let child = Tags.getAt(tagsIndex, agAstNode.value.tags);
|
|
120
317
|
|
|
121
|
-
if (child.type !==
|
|
318
|
+
if (child.type !== Property) return null;
|
|
122
319
|
|
|
123
320
|
let tag = child.value.tags[0];
|
|
124
321
|
|
|
125
322
|
let refIndex = tag.type === ShiftTag ? tagsIndex - tag.value.index : tagsIndex;
|
|
126
323
|
|
|
127
|
-
let stack = Tags.findPath(refIndex, agAstNode.tags);
|
|
324
|
+
let stack = Tags.findPath(refIndex, agAstNode.value.tags);
|
|
128
325
|
let { node, index: leafIdx } = stack.value;
|
|
129
326
|
let leaf = Tags.getAt(leafIdx, node);
|
|
130
327
|
|
|
131
|
-
if (leaf.type !==
|
|
328
|
+
if (leaf.type !== Property) {
|
|
132
329
|
return null;
|
|
133
330
|
}
|
|
134
331
|
|
|
@@ -136,14 +333,16 @@ export const getChildPropertyIndex = (agAstNode, tagsIndex) => {
|
|
|
136
333
|
|
|
137
334
|
if (leafRefTag.type !== ReferenceTag) return null;
|
|
138
335
|
|
|
139
|
-
let { name,
|
|
336
|
+
let { name, flags } = leafRefTag.value;
|
|
140
337
|
let count = -1;
|
|
141
338
|
|
|
142
|
-
if (!
|
|
339
|
+
if (!name) throw new Error();
|
|
340
|
+
|
|
341
|
+
if (!flags.array) return null;
|
|
143
342
|
|
|
144
343
|
for (let i = leafIdx; i >= 0; i--) {
|
|
145
344
|
let value = Tags.getAt(i, node);
|
|
146
|
-
if (value.type ===
|
|
345
|
+
if (value.type === Property) {
|
|
147
346
|
let firstTag = value.value.tags[0];
|
|
148
347
|
|
|
149
348
|
if (firstTag.type === ReferenceTag && firstTag.value.name === name) {
|
|
@@ -169,7 +368,6 @@ export const getChildPropertyIndex = (agAstNode, tagsIndex) => {
|
|
|
169
368
|
if ((res = Tags.getAtName(name, references))) {
|
|
170
369
|
count += res;
|
|
171
370
|
}
|
|
172
|
-
} else {
|
|
173
371
|
}
|
|
174
372
|
}
|
|
175
373
|
stack = stack.pop();
|
|
@@ -185,39 +383,31 @@ export const getChildPropertyIndex = (agAstNode, tagsIndex) => {
|
|
|
185
383
|
|
|
186
384
|
export const getPropertyTagsIndex = (agAstNode, type, name, index, shiftIndex) => {
|
|
187
385
|
let firstPropsIndex = __getPropertyTagsIndex(agAstNode, type, name, 0);
|
|
188
|
-
let prop = firstPropsIndex == null ? null : Tags.getAt(firstPropsIndex, agAstNode
|
|
189
|
-
let
|
|
190
|
-
let
|
|
191
|
-
let
|
|
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;
|
|
192
390
|
|
|
193
|
-
if (ref?.
|
|
391
|
+
if (ref?.flags.array) {
|
|
194
392
|
if (index < 0) {
|
|
195
|
-
|
|
196
|
-
index = Tags.getAtName(name, sums.references) - initializerOffset + index;
|
|
197
|
-
} else {
|
|
198
|
-
index = Tags.getAtName(type, sums.specialTypes) - initializerOffset + index;
|
|
199
|
-
}
|
|
393
|
+
index = Tags.getAtName(type, counts) + index;
|
|
200
394
|
} else if (index == null) {
|
|
201
|
-
|
|
202
|
-
index = Tags.getAtName(name, sums.references) - 1 - initializerOffset;
|
|
203
|
-
} else {
|
|
204
|
-
index = Tags.getAtName(type, sums.specialTypes) - 1 - initializerOffset;
|
|
205
|
-
}
|
|
395
|
+
index = Tags.getAtName(name, counts) - 1;
|
|
206
396
|
|
|
207
397
|
if (index < 0) return null;
|
|
208
398
|
}
|
|
209
399
|
}
|
|
210
400
|
|
|
211
|
-
let parentIndex = __getPropertyTagsIndex(agAstNode, type, name,
|
|
401
|
+
let parentIndex = __getPropertyTagsIndex(agAstNode, type, name, index ?? 0);
|
|
212
402
|
|
|
213
|
-
if (ref?.flags.expression) {
|
|
403
|
+
if (parentIndex != null && ref?.flags.expression) {
|
|
214
404
|
let shiftIndex_ = shiftIndex == null ? -1 : shiftIndex;
|
|
215
405
|
if (shiftIndex_ < 0) {
|
|
216
406
|
let shifts = 0;
|
|
217
407
|
// TODO speed this up for deeply nested shifts
|
|
218
408
|
// algorithm: make big jump forward, then look at shift index to see if we overshot completely
|
|
219
409
|
// works because we know the size of the thing and a bigger thing doesn't fit in a smaller one
|
|
220
|
-
while (Tags.getAt(parentIndex + shifts
|
|
410
|
+
while (Tags.getAt(parentIndex + shifts, agAstNode.value.children)?.value.shift) {
|
|
221
411
|
shifts++;
|
|
222
412
|
}
|
|
223
413
|
|
|
@@ -225,7 +415,7 @@ export const getPropertyTagsIndex = (agAstNode, type, name, index, shiftIndex) =
|
|
|
225
415
|
|
|
226
416
|
return parentIndex + shifts + shiftIndex_ + 1;
|
|
227
417
|
} else {
|
|
228
|
-
if (parentIndex + shiftIndex_ >= Tags.getSize(agAstNode.tags)) {
|
|
418
|
+
if (parentIndex + shiftIndex_ >= Tags.getSize(agAstNode.value.tags)) {
|
|
229
419
|
return null;
|
|
230
420
|
}
|
|
231
421
|
|
|
@@ -236,23 +426,9 @@ export const getPropertyTagsIndex = (agAstNode, type, name, index, shiftIndex) =
|
|
|
236
426
|
return parentIndex;
|
|
237
427
|
};
|
|
238
428
|
|
|
239
|
-
export const getInitializerTagsIndex = (agAstNode, referenceTag) => {
|
|
240
|
-
let { type, name } = referenceTag.value;
|
|
241
|
-
|
|
242
|
-
if (type === '#') return null;
|
|
243
|
-
|
|
244
|
-
let index = __getPropertyTagsIndex(agAstNode, type, name, 0);
|
|
245
|
-
|
|
246
|
-
if (index == null) return null;
|
|
247
|
-
|
|
248
|
-
let nextTag = Tags.getAt(index, agAstNode.tags, 1);
|
|
249
|
-
|
|
250
|
-
return nextTag?.type === InitializerTag ? index : null;
|
|
251
|
-
};
|
|
252
|
-
|
|
253
429
|
const __getPropertyTagsIndex = (agAstNode, type, name, index) => {
|
|
254
430
|
let nameCount = 0;
|
|
255
|
-
let node = Tags.getValues(agAstNode.tags)[1];
|
|
431
|
+
let node = Tags.getValues(agAstNode.value.tags)[1];
|
|
256
432
|
let idx = -1;
|
|
257
433
|
|
|
258
434
|
// drill into subtrees, passing over subtrees with too few references of the desired name
|
|
@@ -274,9 +450,8 @@ const __getPropertyTagsIndex = (agAstNode, type, name, index) => {
|
|
|
274
450
|
if (!isArray(value)) {
|
|
275
451
|
idx++;
|
|
276
452
|
let tag = value;
|
|
277
|
-
if (tag.type ===
|
|
278
|
-
let { tags,
|
|
279
|
-
let { reference } = property;
|
|
453
|
+
if (tag.type === Property) {
|
|
454
|
+
let { tags, reference } = tag.value;
|
|
280
455
|
if (tags[0].type === ReferenceTag) {
|
|
281
456
|
if (
|
|
282
457
|
(name != null && reference.name === name) ||
|
|
@@ -319,10 +494,12 @@ const __getPropertyTagsIndex = (agAstNode, type, name, index) => {
|
|
|
319
494
|
const { hasOwn, freeze } = Object;
|
|
320
495
|
const { isArray } = Array;
|
|
321
496
|
|
|
322
|
-
export const getOriginalFirstNode = (node
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
497
|
+
export const getOriginalFirstNode = (node) => {
|
|
498
|
+
if (node.type !== TreeNode) return;
|
|
499
|
+
|
|
500
|
+
for (let child of Tags.traverse(getTags(node))) {
|
|
501
|
+
if (child.type === Property) {
|
|
502
|
+
return child.value.node;
|
|
326
503
|
}
|
|
327
504
|
}
|
|
328
505
|
return null;
|
|
@@ -333,14 +510,14 @@ export const getFirstNode = (node) => {
|
|
|
333
510
|
};
|
|
334
511
|
|
|
335
512
|
export const getFirstNodeProperty = (node) => {
|
|
336
|
-
for (let child of Tags.traverse(node
|
|
337
|
-
if (child.type ===
|
|
513
|
+
for (let child of Tags.traverse(getTags(node))) {
|
|
514
|
+
if (child.type === Property) {
|
|
338
515
|
let ref = child.value.reference;
|
|
339
516
|
if (!ref.flags.expression) {
|
|
340
|
-
return child
|
|
517
|
+
return child;
|
|
341
518
|
} else {
|
|
342
519
|
let tagsIndex = getPropertyTagsIndex(node, ref.type, ref.name, 0, -1);
|
|
343
|
-
return Tags.getAt(tagsIndex, node
|
|
520
|
+
return Tags.getAt(tagsIndex, getTags(node), 2)?.value;
|
|
344
521
|
}
|
|
345
522
|
// is it shifted?
|
|
346
523
|
}
|
|
@@ -348,12 +525,17 @@ export const getFirstNodeProperty = (node) => {
|
|
|
348
525
|
return null;
|
|
349
526
|
};
|
|
350
527
|
|
|
528
|
+
export const referenceIsSingular = (ref) => {
|
|
529
|
+
return (ref.name && !['#', '@'].includes(ref.type)) || ref.type === '_';
|
|
530
|
+
};
|
|
531
|
+
|
|
351
532
|
export const referencesAreEqual = (a, b) => {
|
|
352
533
|
return (
|
|
353
534
|
a === b ||
|
|
354
535
|
(a.type === b.type &&
|
|
355
536
|
a.name === b.name &&
|
|
356
|
-
a.
|
|
537
|
+
a.flags.array === b.flags.array &&
|
|
538
|
+
a.flags.intrinsic === b.flags.intrinsic &&
|
|
357
539
|
a.flags.hasGap === b.flags.hasGap &&
|
|
358
540
|
a.flags.expression === b.flags.expression)
|
|
359
541
|
);
|
|
@@ -363,15 +545,15 @@ export const isDefined = (obj, key) => hasOwn(obj, key) && obj[key] !== undefine
|
|
|
363
545
|
export const isUndefined = (obj, key) => !hasOwn(obj, key) || obj[key] === undefined;
|
|
364
546
|
|
|
365
547
|
export function* relatedNodes(node) {
|
|
366
|
-
for (const child of Tags.traverse(node
|
|
367
|
-
if (child.type ===
|
|
548
|
+
for (const child of Tags.traverse(getTags(node))) {
|
|
549
|
+
if (child.type === Property) {
|
|
368
550
|
yield child.node;
|
|
369
551
|
}
|
|
370
552
|
}
|
|
371
553
|
}
|
|
372
554
|
|
|
373
555
|
export const getProperty = (pathSegment, node) => {
|
|
374
|
-
if (!node
|
|
556
|
+
if (!node || node.type !== TreeNode) return null;
|
|
375
557
|
|
|
376
558
|
if (pathSegment == null) throw new Error('Bad path segment');
|
|
377
559
|
|
|
@@ -382,7 +564,7 @@ export const getProperty = (pathSegment, node) => {
|
|
|
382
564
|
|
|
383
565
|
if (propIndex == null) return null;
|
|
384
566
|
|
|
385
|
-
return Tags.getAt(propIndex, node
|
|
567
|
+
return Tags.getAt(propIndex, getTags(node));
|
|
386
568
|
};
|
|
387
569
|
|
|
388
570
|
export const has = (path, node) => {
|
|
@@ -393,20 +575,15 @@ export const has = (path, node) => {
|
|
|
393
575
|
let pathArr = [...path];
|
|
394
576
|
let node_ = get(pathArr.slice(0, -1), node);
|
|
395
577
|
let seg = pathArr[pathArr.length - 1];
|
|
396
|
-
let name = typeof seg === 'string' ? seg : seg.name;
|
|
397
578
|
|
|
398
|
-
return (
|
|
399
|
-
!!getProperty(seg, node_) ||
|
|
400
|
-
getInitializerTagsIndex(node_, buildReferenceTag(null, name)) != null
|
|
401
|
-
);
|
|
579
|
+
return !!getProperty(seg, node_);
|
|
402
580
|
};
|
|
403
581
|
|
|
404
582
|
export const get = (path, node) => getOr(null, path, node);
|
|
405
583
|
|
|
406
584
|
export const getOr = (defaultValue, path, node) => {
|
|
407
|
-
if (!node) throw new Error();
|
|
408
|
-
|
|
409
585
|
if (path == null) throw new Error('Bad path');
|
|
586
|
+
if (!node) return null;
|
|
410
587
|
|
|
411
588
|
if (!isArray(path)) {
|
|
412
589
|
path = [path];
|
|
@@ -416,7 +593,8 @@ export const getOr = (defaultValue, path, node) => {
|
|
|
416
593
|
let result = root || node;
|
|
417
594
|
|
|
418
595
|
let start = 0;
|
|
419
|
-
|
|
596
|
+
// TODO allow dot dot at all levels
|
|
597
|
+
if (path[0]?.type === '_') {
|
|
420
598
|
if (!root) return null;
|
|
421
599
|
start = 1;
|
|
422
600
|
}
|
|
@@ -441,10 +619,10 @@ export const getOr = (defaultValue, path, node) => {
|
|
|
441
619
|
|
|
442
620
|
if (!property) return defaultValue;
|
|
443
621
|
|
|
444
|
-
result = property.node;
|
|
622
|
+
result = getRoot(property.value.node);
|
|
445
623
|
}
|
|
446
624
|
|
|
447
|
-
return result;
|
|
625
|
+
return isNullNode(result) ? null : result;
|
|
448
626
|
};
|
|
449
627
|
|
|
450
628
|
export function* list(name, node) {
|
|
@@ -460,9 +638,7 @@ export const countList = (name, node) => {
|
|
|
460
638
|
|
|
461
639
|
if (name == null) throw new Error('Bad path');
|
|
462
640
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
return Tags.getAtName(name, Tags.getSums(node.tags).references) - (hasInitializer ? 1 : 0);
|
|
641
|
+
return Tags.getAtName(name, Tags.getSums(getTags(node)).references);
|
|
466
642
|
};
|
|
467
643
|
|
|
468
644
|
export function* allTagPathsFor(range, options = {}) {
|
|
@@ -478,7 +654,7 @@ export function* allTagPathsFor(range, options = {}) {
|
|
|
478
654
|
|
|
479
655
|
while (path) {
|
|
480
656
|
if (path.inner && path.previousSibling.tag.type === ReferenceTag) {
|
|
481
|
-
path =
|
|
657
|
+
path = TagPath.from(path.inner, 0);
|
|
482
658
|
}
|
|
483
659
|
|
|
484
660
|
if (path.path.depth < startPath.path.depth) {
|
|
@@ -513,7 +689,7 @@ export function* allTagsFor(range, options = {}) {
|
|
|
513
689
|
}
|
|
514
690
|
|
|
515
691
|
export const buildFullRange = (node) => {
|
|
516
|
-
let sum = Tags.getSize(node
|
|
692
|
+
let sum = Tags.getSize(getTags(node));
|
|
517
693
|
return sum ? [0, sum - 1] : null;
|
|
518
694
|
};
|
|
519
695
|
|
|
@@ -532,6 +708,10 @@ export function* ownTagPathsFor(range) {
|
|
|
532
708
|
}
|
|
533
709
|
}
|
|
534
710
|
|
|
711
|
+
export const buildNullNode = () => {
|
|
712
|
+
return buildNode(buildNullTag());
|
|
713
|
+
};
|
|
714
|
+
|
|
535
715
|
const findRight = (arr, predicate) => {
|
|
536
716
|
for (let i = arr.length - 1; i >= 0; i--) {
|
|
537
717
|
let value = arr[i];
|
|
@@ -578,6 +758,28 @@ const skipToDepth = (depth, frame) => {
|
|
|
578
758
|
return parent;
|
|
579
759
|
};
|
|
580
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
|
+
|
|
581
783
|
export let pathForTagPath = (tagPath) => {
|
|
582
784
|
let refTagPath = tagPath;
|
|
583
785
|
let isShift = tagPath.tag.type === ShiftTag;
|
|
@@ -596,34 +798,77 @@ export let pathForTagPath = (tagPath) => {
|
|
|
596
798
|
return [{ type, name, index, shiftIndex }];
|
|
597
799
|
};
|
|
598
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
|
+
|
|
599
816
|
export const Path = class AgastPath extends WeakStackFrame {
|
|
817
|
+
static create(node) {
|
|
818
|
+
return node && new Path(node);
|
|
819
|
+
}
|
|
820
|
+
|
|
600
821
|
static from(node) {
|
|
601
|
-
|
|
602
|
-
return node_ && this.create(node_);
|
|
822
|
+
return node && new Path(node);
|
|
603
823
|
}
|
|
604
824
|
|
|
605
|
-
|
|
606
|
-
|
|
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;
|
|
607
841
|
|
|
608
|
-
if (
|
|
842
|
+
if (isGap) {
|
|
843
|
+
({ node } = BTree.getAt(-1, node.value.bounds[0]).value);
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
if (!node || ![TreeNode, NullNode, GapNode].includes(node.type)) throw new Error();
|
|
609
847
|
|
|
610
|
-
if (parent && parentIndex == null) throw new Error();
|
|
611
848
|
if (!node) throw new Error();
|
|
849
|
+
if (!Object.isFrozen(node)) throw new Error();
|
|
612
850
|
if (isArray(node)) throw new Error();
|
|
613
851
|
|
|
852
|
+
super(parent);
|
|
853
|
+
|
|
614
854
|
this.node = node;
|
|
615
|
-
this.parentIndex = parentIndex;
|
|
855
|
+
this.parentIndex = parentIndex;
|
|
856
|
+
this.isGap = isGap;
|
|
616
857
|
|
|
617
|
-
|
|
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);
|
|
618
863
|
|
|
619
|
-
|
|
864
|
+
let parentTag = parentIndex == null ? null : Tags.getAt(parentIndex, getTags(parent.node));
|
|
865
|
+
|
|
866
|
+
if (parentTag && parentTag.type !== Property) {
|
|
620
867
|
throw new Error();
|
|
621
868
|
}
|
|
622
869
|
|
|
623
|
-
parentIndex != null && parentTag?.value.tags[0];
|
|
624
|
-
|
|
625
870
|
if (
|
|
626
|
-
|
|
871
|
+
parentIndex != null &&
|
|
627
872
|
(!this.referenceTag || ![ReferenceTag, ShiftTag].includes(this.referenceTag.type))
|
|
628
873
|
) {
|
|
629
874
|
throw new Error();
|
|
@@ -645,42 +890,74 @@ export const Path = class AgastPath extends WeakStackFrame {
|
|
|
645
890
|
freeze(this);
|
|
646
891
|
}
|
|
647
892
|
|
|
648
|
-
|
|
649
|
-
let
|
|
650
|
-
if (
|
|
651
|
-
|
|
652
|
-
}
|
|
653
|
-
return tagPath;
|
|
893
|
+
getChild(childrenIndex) {
|
|
894
|
+
let { node } = this;
|
|
895
|
+
if (isStubNode(node)) return null;
|
|
896
|
+
return Tags.getAt(childrenIndex, getChildren(node)) || null;
|
|
654
897
|
}
|
|
655
898
|
|
|
656
|
-
|
|
657
|
-
return this
|
|
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
|
+
|
|
933
|
+
get openTagPath() {
|
|
934
|
+
let tagPath = TagPath.from(this, 0);
|
|
935
|
+
return tagPath.tag.type === OpenNodeTag ? tagPath : null;
|
|
658
936
|
}
|
|
659
937
|
|
|
660
938
|
get closeTagPath() {
|
|
661
939
|
let tagPath = TagPath.from(this, -1);
|
|
662
|
-
|
|
663
|
-
return tagPath;
|
|
940
|
+
return tagPath.tag.type === CloseNodeTag ? tagPath : null;
|
|
664
941
|
}
|
|
665
942
|
|
|
666
|
-
get
|
|
667
|
-
return this.
|
|
943
|
+
get openTag() {
|
|
944
|
+
return this.openTagPath.tag;
|
|
668
945
|
}
|
|
669
946
|
|
|
670
|
-
|
|
671
|
-
return
|
|
947
|
+
get open() {
|
|
948
|
+
return this.openTag.value;
|
|
672
949
|
}
|
|
673
950
|
|
|
674
|
-
get
|
|
675
|
-
return this.
|
|
951
|
+
get closeTag() {
|
|
952
|
+
return this.closeTagPath.tag;
|
|
676
953
|
}
|
|
677
954
|
|
|
678
|
-
get
|
|
679
|
-
return this.
|
|
955
|
+
get bindings() {
|
|
956
|
+
return this.parentPropertyPath?.tag.value.bindings;
|
|
680
957
|
}
|
|
681
958
|
|
|
682
|
-
get
|
|
683
|
-
return
|
|
959
|
+
get bindingTags() {
|
|
960
|
+
return this.parentPropertyPath?.tag.value.tags[1];
|
|
684
961
|
}
|
|
685
962
|
|
|
686
963
|
get reference() {
|
|
@@ -695,20 +972,23 @@ export const Path = class AgastPath extends WeakStackFrame {
|
|
|
695
972
|
if (!this.parent?.node) {
|
|
696
973
|
return null;
|
|
697
974
|
}
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
975
|
+
return TagPath.from(this.parent, this.parentIndex, 0).referenceTagPath;
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
get propertyKeyTagPath() {
|
|
979
|
+
if (!this.parent?.node) {
|
|
980
|
+
return null;
|
|
701
981
|
}
|
|
702
|
-
return
|
|
982
|
+
return TagPath.from(this.parent, this.parentIndex, 0);
|
|
703
983
|
}
|
|
704
984
|
|
|
705
985
|
get parentPropertyPath() {
|
|
706
|
-
if (!this.parent?.node) {
|
|
986
|
+
if (!this.parent?.node || this.parentIndex == null) {
|
|
707
987
|
return null;
|
|
708
988
|
}
|
|
709
|
-
let path =
|
|
989
|
+
let path = TagPath.from(this.parent, this.parentIndex);
|
|
710
990
|
if (path.tag.type === ShiftTag) {
|
|
711
|
-
path =
|
|
991
|
+
path = TagPath.from(this.parent, this.parentIndex - path.tag.value.index);
|
|
712
992
|
}
|
|
713
993
|
return path;
|
|
714
994
|
}
|
|
@@ -717,86 +997,63 @@ export const Path = class AgastPath extends WeakStackFrame {
|
|
|
717
997
|
return this.parentPropertyPath?.tag ?? null;
|
|
718
998
|
}
|
|
719
999
|
|
|
720
|
-
get(
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
path_ = [path_];
|
|
724
|
-
}
|
|
725
|
-
if (!isArray(path_)) throw new Error();
|
|
726
|
-
|
|
727
|
-
let pathInst = this;
|
|
1000
|
+
get parentNode() {
|
|
1001
|
+
return this.parent.node;
|
|
1002
|
+
}
|
|
728
1003
|
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
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;
|
|
1010
|
+
}
|
|
735
1011
|
}
|
|
1012
|
+
return tagPath;
|
|
1013
|
+
}
|
|
736
1014
|
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
if (
|
|
742
|
-
|
|
743
|
-
if (typeof index === 'number') {
|
|
744
|
-
i++;
|
|
745
|
-
} else {
|
|
746
|
-
index = undefined;
|
|
747
|
-
}
|
|
748
|
-
seg = buildPathSegment(nameOrSeg, index);
|
|
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;
|
|
749
1021
|
}
|
|
750
|
-
|
|
751
|
-
let tagsIndex = getPropertyTagsIndex(
|
|
752
|
-
pathInst.node,
|
|
753
|
-
seg.type,
|
|
754
|
-
seg.name,
|
|
755
|
-
seg.index,
|
|
756
|
-
seg.shiftIndex,
|
|
757
|
-
);
|
|
758
|
-
|
|
759
|
-
let { property } = Tags.getAt(tagsIndex, pathInst.node.tags).value;
|
|
760
|
-
|
|
761
|
-
if (!property) return null;
|
|
762
|
-
|
|
763
|
-
let { node } = property;
|
|
764
|
-
|
|
765
|
-
pathInst = pathInst.push(node, tagsIndex);
|
|
766
1022
|
}
|
|
767
|
-
|
|
768
|
-
return pathInst;
|
|
1023
|
+
return tagPath;
|
|
769
1024
|
}
|
|
770
1025
|
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
}
|
|
1026
|
+
get coverBoundary() {
|
|
1027
|
+
let path = this;
|
|
774
1028
|
|
|
775
|
-
|
|
776
|
-
|
|
1029
|
+
if (path.parent && !isFragment(this.node) && isCover(path.parent.node)) {
|
|
1030
|
+
path = path.parent;
|
|
1031
|
+
}
|
|
777
1032
|
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
if (typeof path_ === 'string') {
|
|
781
|
-
path_ = [path_];
|
|
1033
|
+
while (path && isCover(path.node) && path.parent && isCover(path.parent.node)) {
|
|
1034
|
+
path = path.parent;
|
|
782
1035
|
}
|
|
783
|
-
if (!isArray(path_)) throw new Error();
|
|
784
1036
|
|
|
1037
|
+
return path;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
get(path) {
|
|
1041
|
+
let path_ = typeof path === 'string' ? [path] : [...path];
|
|
785
1042
|
let pathInst = this;
|
|
786
1043
|
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
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
|
+
}
|
|
793
1052
|
}
|
|
794
1053
|
|
|
795
1054
|
for (let i = 0; i < path_.length; i++) {
|
|
796
1055
|
let nameOrSeg = path_[i];
|
|
797
1056
|
|
|
798
|
-
built = { ...pathInst.node };
|
|
799
|
-
|
|
800
1057
|
let seg = nameOrSeg;
|
|
801
1058
|
if (isString(nameOrSeg)) {
|
|
802
1059
|
let index = path_[i + 1];
|
|
@@ -808,6 +1065,8 @@ export const Path = class AgastPath extends WeakStackFrame {
|
|
|
808
1065
|
seg = buildPathSegment(nameOrSeg, index);
|
|
809
1066
|
}
|
|
810
1067
|
|
|
1068
|
+
if (i === 0 && seg.type === '_' && skippedRootFragment) continue;
|
|
1069
|
+
|
|
811
1070
|
let tagsIndex = getPropertyTagsIndex(
|
|
812
1071
|
pathInst.node,
|
|
813
1072
|
seg.type,
|
|
@@ -816,258 +1075,852 @@ export const Path = class AgastPath extends WeakStackFrame {
|
|
|
816
1075
|
seg.shiftIndex,
|
|
817
1076
|
);
|
|
818
1077
|
|
|
819
|
-
|
|
1078
|
+
if (tagsIndex == null) return null;
|
|
820
1079
|
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
tags: { 0: refTag },
|
|
824
|
-
} = tagPath.tag.value;
|
|
825
|
-
|
|
826
|
-
if (refTag.type === ShiftTag) {
|
|
827
|
-
let { index } = refTag.value;
|
|
1080
|
+
pathInst = pathInst.push(tagsIndex);
|
|
1081
|
+
}
|
|
828
1082
|
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
}
|
|
832
|
-
tagsIndex -= index;
|
|
833
|
-
pathInst = pathInst.replace(built, tagsIndex);
|
|
834
|
-
}
|
|
1083
|
+
return pathInst;
|
|
1084
|
+
}
|
|
835
1085
|
|
|
836
|
-
|
|
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();
|
|
837
1090
|
|
|
838
|
-
|
|
1091
|
+
if (!node) throw new Error();
|
|
839
1092
|
|
|
840
|
-
|
|
1093
|
+
if (!this.parent) {
|
|
1094
|
+
return Path.from(node);
|
|
841
1095
|
}
|
|
842
1096
|
|
|
843
|
-
let
|
|
844
|
-
|
|
845
|
-
if (!node_) throw new Error();
|
|
846
|
-
|
|
847
|
-
path = pathInst.parent;
|
|
1097
|
+
let built = node;
|
|
1098
|
+
let path = this.parent;
|
|
848
1099
|
let replacementPath = [];
|
|
849
1100
|
|
|
850
|
-
let
|
|
851
|
-
let
|
|
852
|
-
let
|
|
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;
|
|
853
1109
|
|
|
854
1110
|
while (path) {
|
|
855
|
-
|
|
856
|
-
built =
|
|
857
|
-
|
|
858
|
-
let { tags } = Tags.getAt(targetParentIndex, path.node.tags).value;
|
|
859
|
-
let property = buildProperty(targetReference, targetBinding, value);
|
|
1111
|
+
value = built;
|
|
1112
|
+
built = buildNode(getTags(path.node));
|
|
860
1113
|
|
|
861
|
-
let
|
|
1114
|
+
let { tags, shift } = Tags.getAt(targetParentIndex, getTags(path.node)).value;
|
|
862
1115
|
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
buildChild(
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
finalizeNode(built);
|
|
1116
|
+
let firstTag = tags[0];
|
|
1117
|
+
let newFirstTag = firstTag;
|
|
1118
|
+
if (shift) {
|
|
1119
|
+
newFirstTag = buildChild(ReferenceTag, targetReference);
|
|
1120
|
+
}
|
|
870
1121
|
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
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_)),
|
|
876
1134
|
),
|
|
877
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
|
+
}
|
|
878
1187
|
}
|
|
879
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_);
|
|
880
1194
|
targetReference = path.reference;
|
|
881
|
-
|
|
1195
|
+
targetBindings = path.bindings;
|
|
882
1196
|
targetParentIndex = path.parentIndex;
|
|
883
1197
|
path = path.parent;
|
|
884
1198
|
}
|
|
885
1199
|
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
return Path.from(built).get(replacementPath).atDepth(this.depth);
|
|
1200
|
+
return this.mapOnto(built);
|
|
889
1201
|
}
|
|
890
1202
|
|
|
891
|
-
|
|
892
|
-
return
|
|
1203
|
+
replaceAt(path, node, bindings) {
|
|
1204
|
+
return this.get(path).replaceWith(node, bindings).atDepth(0);
|
|
893
1205
|
}
|
|
894
|
-
};
|
|
895
|
-
|
|
896
|
-
export const tagPathsAreEqual = (a, b) => {
|
|
897
|
-
if (a == null || b == null) return b == a;
|
|
898
|
-
return a.path.node === b.path.node && a.tagsIndex === b.tagsIndex;
|
|
899
|
-
};
|
|
900
1206
|
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
if (path == null || tagsIndex == null) throw new Error();
|
|
904
|
-
|
|
905
|
-
let tag = Tags.getAt(tagsIndex, path.node.tags);
|
|
1207
|
+
mapOnto(rootNode) {
|
|
1208
|
+
let path = Path.from(rootNode);
|
|
906
1209
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
tag = tag.value.tags[wrapperIndex];
|
|
1210
|
+
for (let i = 1; i <= this.depth; i++) {
|
|
1211
|
+
let { parentIndex, isGap } = this.atDepth(i);
|
|
1212
|
+
path = path.push(parentIndex, isGap);
|
|
911
1213
|
}
|
|
912
1214
|
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
this.tag = tag;
|
|
916
|
-
this.tagsIndex = tagsIndex;
|
|
917
|
-
this.wrapperIndex = wrapperIndex;
|
|
1215
|
+
return path;
|
|
1216
|
+
}
|
|
918
1217
|
|
|
919
|
-
|
|
1218
|
+
atDepth(depth) {
|
|
1219
|
+
return skipToDepth(depth, this);
|
|
920
1220
|
}
|
|
921
1221
|
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
1222
|
+
get rootNode() {
|
|
1223
|
+
return this.atDepth(0).node;
|
|
1224
|
+
}
|
|
925
1225
|
|
|
926
|
-
|
|
1226
|
+
get done() {
|
|
1227
|
+
let { parent, node } = this;
|
|
1228
|
+
let sigilTag = getSigilTag(node);
|
|
927
1229
|
|
|
928
|
-
|
|
1230
|
+
return !parent && sigilTag && !!(isSelfClosingTag(sigilTag) || getCloseTag(node));
|
|
1231
|
+
}
|
|
929
1232
|
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
? null
|
|
933
|
-
: wrapperIndex < 0
|
|
934
|
-
? tag.value.tags.length + wrapperIndex
|
|
935
|
-
: wrapperIndex;
|
|
1233
|
+
get held() {
|
|
1234
|
+
let tagPath = this.tagPathAt(-1);
|
|
936
1235
|
|
|
937
|
-
|
|
938
|
-
|
|
1236
|
+
// TODO is this safe
|
|
1237
|
+
if (tagPath.tag.type !== Property) return null;
|
|
939
1238
|
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
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
|
+
}
|
|
1619
|
+
};
|
|
1620
|
+
|
|
1621
|
+
Object.freeze(Path.prototype);
|
|
1622
|
+
|
|
1623
|
+
export const tagPathsAreEqual = (a, b) => {
|
|
1624
|
+
if (a == null || b == null) return b == a;
|
|
1625
|
+
return a.path.node === b.path.node && a.tagsIndex === b.tagsIndex;
|
|
1626
|
+
};
|
|
1627
|
+
|
|
1628
|
+
export class TagPath {
|
|
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]);
|
|
1667
|
+
|
|
1668
|
+
let tag = Tags.getAt(tagsIndex, getTags(path.node));
|
|
1669
|
+
|
|
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
|
+
}
|
|
1679
|
+
|
|
1680
|
+
this.path = path;
|
|
1681
|
+
this.tagsIndex = tagsIndex;
|
|
1682
|
+
this.propertyIndex = propertyIndex_;
|
|
1683
|
+
|
|
1684
|
+
this.node = path.node;
|
|
1685
|
+
this.tag = tag;
|
|
1686
|
+
|
|
1687
|
+
if (tag.type === Property && propertyIndex_.length) throw new Error();
|
|
1688
|
+
|
|
1689
|
+
freeze(this);
|
|
1690
|
+
}
|
|
943
1691
|
|
|
944
1692
|
get child() {
|
|
945
1693
|
return this.tag;
|
|
946
1694
|
}
|
|
947
1695
|
|
|
1696
|
+
get parentNode() {
|
|
1697
|
+
return this.path.parentNode;
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
get depth() {
|
|
1701
|
+
return this.path.depth;
|
|
1702
|
+
}
|
|
1703
|
+
|
|
948
1704
|
siblingAt(index) {
|
|
949
1705
|
return TagPath.from(this.path, index);
|
|
950
1706
|
}
|
|
951
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
|
+
|
|
952
1733
|
get nextSibling() {
|
|
953
|
-
|
|
1734
|
+
let { path, tagsIndex, propertyIndex } = this;
|
|
1735
|
+
|
|
1736
|
+
let propertyIndex0 = propertyIndex[0]?.index;
|
|
954
1737
|
|
|
955
|
-
let
|
|
1738
|
+
let nextChildIndex = tagsIndex === 0 ? 0 : tagsIndex - 1 + 1;
|
|
1739
|
+
let nextChild = path.getChild(nextChildIndex);
|
|
956
1740
|
|
|
957
|
-
if (
|
|
958
|
-
return
|
|
959
|
-
} else if (tagsIndex + 1 < Tags.getSize(path.node.tags)) {
|
|
960
|
-
return new TagPath(path, tagsIndex + 1, 0);
|
|
1741
|
+
if (propertyIndex0 == null && !nextChild) {
|
|
1742
|
+
return this.tag.type === CloseNodeTag ? null : path.closeTagPath;
|
|
961
1743
|
}
|
|
962
1744
|
|
|
963
|
-
|
|
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;
|
|
964
1798
|
}
|
|
965
1799
|
|
|
966
1800
|
get next() {
|
|
967
|
-
let { path, tagsIndex,
|
|
1801
|
+
let { path, tagsIndex, propertyIndex } = this;
|
|
1802
|
+
|
|
1803
|
+
propertyIndex = [...propertyIndex];
|
|
968
1804
|
|
|
969
1805
|
let leaving = false;
|
|
970
1806
|
|
|
971
1807
|
for (;;) {
|
|
972
|
-
let
|
|
973
|
-
let
|
|
974
|
-
let
|
|
975
|
-
let isInitialTag =
|
|
976
|
-
path.node === this.path.node &&
|
|
977
|
-
tagsIndex === this.tagsIndex &&
|
|
978
|
-
wrapperIndex === this.wrapperIndex;
|
|
979
|
-
let wasLeaving = leaving;
|
|
1808
|
+
let tag = Tags.getAt(tagsIndex, getTags(path.node));
|
|
1809
|
+
let propTag = tag;
|
|
1810
|
+
let lastRef = null;
|
|
980
1811
|
leaving = false;
|
|
981
1812
|
|
|
982
1813
|
if (!tag) return null;
|
|
983
1814
|
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
wrapperTag = tag.value.tags[wrapperIndex];
|
|
989
|
-
}
|
|
1815
|
+
if (tag.type === Property) {
|
|
1816
|
+
if (propertyIndex.length === 0 && !leaving) {
|
|
1817
|
+
propertyIndex.push({ index: 0, node: tag.value.tags });
|
|
1818
|
+
}
|
|
990
1819
|
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
1820
|
+
if (propertyIndex != null) {
|
|
1821
|
+
propTag = Tags.getAt(propertyIndex, tag.value.tags);
|
|
1822
|
+
lastRef = Tags.getAt(0, tag.value.tags);
|
|
1823
|
+
}
|
|
994
1824
|
}
|
|
995
1825
|
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
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];
|
|
999
1831
|
} else {
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
tag.value.property.reference.flags.expression &&
|
|
1005
|
-
(tagsIndex === 1 ||
|
|
1006
|
-
(tagsIndex === 2 &&
|
|
1007
|
-
(tag1 = Tags.getAt(1, path.node.tags)).type === PropertyWrapper &&
|
|
1008
|
-
tag1.value.tags[1].type === InitializerTag)) &&
|
|
1009
|
-
Tags.getAt(path.parentIndex, path.parent.node.tags, 0)?.type === ShiftTag
|
|
1010
|
-
) {
|
|
1011
|
-
let shiftStack = tag.value.property.node.bounds[0];
|
|
1012
|
-
|
|
1013
|
-
let gapNode = BTree.getAt(-1, shiftStack).node;
|
|
1832
|
+
propertyIndex = [{ index: propertyIndex[0].index + 1, node: tag }];
|
|
1833
|
+
}
|
|
1834
|
+
continue;
|
|
1835
|
+
}
|
|
1014
1836
|
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1837
|
+
let isInitialTag =
|
|
1838
|
+
path.node === this.path.node &&
|
|
1839
|
+
tagsIndex === this.tagsIndex &&
|
|
1840
|
+
arraysEqual(propertyIndex, this.propertyIndex);
|
|
1019
1841
|
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
}
|
|
1842
|
+
// done
|
|
1843
|
+
if (!isInitialTag && !isNodeTag(propTag)) {
|
|
1844
|
+
return TagPath.from(path, tagsIndex, propertyIndex);
|
|
1024
1845
|
}
|
|
1025
1846
|
|
|
1026
|
-
tag;
|
|
1027
1847
|
// shift
|
|
1028
|
-
if (
|
|
1029
|
-
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;
|
|
1030
1852
|
if (refIndex < 0) throw new Error();
|
|
1031
|
-
let refTag = Tags.getAt(refIndex, path.
|
|
1853
|
+
let refTag = Tags.getAt(refIndex, path.tags, 0);
|
|
1032
1854
|
|
|
1033
1855
|
if (refTag.type !== ReferenceTag) throw new Error();
|
|
1034
1856
|
|
|
1035
|
-
|
|
1036
|
-
|
|
1857
|
+
let { node } = tag.value;
|
|
1858
|
+
if (!node) return null;
|
|
1037
1859
|
|
|
1038
|
-
|
|
1860
|
+
path = new Path(path, tagsIndex);
|
|
1039
1861
|
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1862
|
+
if (!path) return null;
|
|
1863
|
+
|
|
1864
|
+
tagsIndex = 0;
|
|
1865
|
+
propertyIndex = [];
|
|
1866
|
+
continue;
|
|
1043
1867
|
}
|
|
1044
1868
|
|
|
1869
|
+
let { nextSibling } = this;
|
|
1870
|
+
|
|
1045
1871
|
// over
|
|
1046
|
-
if (
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
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
|
+
}
|
|
1053
1902
|
}
|
|
1054
1903
|
|
|
1055
1904
|
// out
|
|
1056
1905
|
if (path.parentIndex != null && path.parent) {
|
|
1057
1906
|
do {
|
|
1058
1907
|
if (
|
|
1059
|
-
path.parent &&
|
|
1060
|
-
Tags.getAt(
|
|
1908
|
+
path.coverBoundary.parent &&
|
|
1909
|
+
Tags.getAt(
|
|
1910
|
+
[path.coverBoundary.parentIndex, 0],
|
|
1911
|
+
path.coverBoundary.parent.node.value.tags,
|
|
1912
|
+
)?.type === ShiftTag
|
|
1061
1913
|
) {
|
|
1914
|
+
// while
|
|
1062
1915
|
tagsIndex =
|
|
1063
|
-
Tags.getSize(path.parent.node.tags) > path.parentIndex + 1
|
|
1916
|
+
Tags.getSize(path.parent.node.value.tags) > path.parentIndex + 1
|
|
1064
1917
|
? path.parentIndex + 1
|
|
1065
1918
|
: null;
|
|
1066
1919
|
} else {
|
|
1067
1920
|
tagsIndex = path.parentIndex + 1;
|
|
1068
1921
|
}
|
|
1069
1922
|
|
|
1070
|
-
|
|
1923
|
+
propertyIndex = [];
|
|
1071
1924
|
path = path.parent;
|
|
1072
1925
|
leaving = true;
|
|
1073
1926
|
|
|
@@ -1083,40 +1936,63 @@ export class TagPath {
|
|
|
1083
1936
|
}
|
|
1084
1937
|
|
|
1085
1938
|
get nextUnshifted() {
|
|
1086
|
-
let { path, tagsIndex,
|
|
1939
|
+
let { path, tagsIndex, propertyIndex } = this;
|
|
1940
|
+
|
|
1941
|
+
propertyIndex = [...propertyIndex];
|
|
1087
1942
|
|
|
1088
1943
|
let leaving = false;
|
|
1089
1944
|
|
|
1090
1945
|
for (;;) {
|
|
1091
|
-
let tag = Tags.getAt(tagsIndex, path.node
|
|
1092
|
-
let
|
|
1093
|
-
let isInitialTag =
|
|
1094
|
-
path.node === this.path.node &&
|
|
1095
|
-
tagsIndex === this.tagsIndex &&
|
|
1096
|
-
wrapperIndex === this.wrapperIndex;
|
|
1946
|
+
let tag = Tags.getAt(tagsIndex, getTags(path.node));
|
|
1947
|
+
let propTag = tag;
|
|
1097
1948
|
let wasLeaving = leaving;
|
|
1098
1949
|
leaving = false;
|
|
1099
1950
|
|
|
1100
1951
|
if (!tag) return null;
|
|
1101
1952
|
|
|
1102
|
-
|
|
1103
|
-
|
|
1953
|
+
if (tag.type === Property) {
|
|
1954
|
+
if (propertyIndex.length === 0 && !leaving) {
|
|
1955
|
+
propertyIndex.push({ index: 0, node: tag.value.tags });
|
|
1956
|
+
}
|
|
1104
1957
|
|
|
1105
|
-
|
|
1106
|
-
|
|
1958
|
+
if (propertyIndex != null) {
|
|
1959
|
+
propTag = Tags.getAt(propertyIndex, tag.value.tags);
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
|
|
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
|
+
}
|
|
1971
|
+
continue;
|
|
1972
|
+
} else if (isNodeTag(propTag) && !leaving) {
|
|
1973
|
+
path = path.push(tagsIndex);
|
|
1974
|
+
tagsIndex = 0;
|
|
1975
|
+
propertyIndex = [];
|
|
1976
|
+
continue;
|
|
1107
1977
|
}
|
|
1108
1978
|
|
|
1109
|
-
|
|
1979
|
+
let isInitialTag =
|
|
1980
|
+
path.node === this.path.node &&
|
|
1981
|
+
tagsIndex === this.tagsIndex &&
|
|
1982
|
+
arraysEqual(propertyIndex, this.propertyIndex);
|
|
1983
|
+
|
|
1984
|
+
if (!wasLeaving && propTag.type === ReferenceTag && propTag.value.flags.expression) {
|
|
1110
1985
|
// move past shifts
|
|
1111
1986
|
|
|
1112
1987
|
let shifts = 0;
|
|
1113
|
-
let
|
|
1988
|
+
let shiftedTag = Tags.getAt(tagsIndex + 1, getTags(path.node));
|
|
1114
1989
|
|
|
1115
|
-
while (
|
|
1990
|
+
while (shiftedTag?.type === Property && shiftedTag.value.shift) {
|
|
1116
1991
|
shifts++;
|
|
1117
|
-
|
|
1118
|
-
|
|
1992
|
+
propertyIndex = [{ index: 1, node: shiftedTag.value.tags }];
|
|
1993
|
+
shiftedTag = Tags.getAt(tagsIndex + 1 + shifts, path.tags);
|
|
1119
1994
|
}
|
|
1995
|
+
|
|
1120
1996
|
if (shifts) {
|
|
1121
1997
|
tagsIndex += shifts;
|
|
1122
1998
|
continue;
|
|
@@ -1124,25 +2000,15 @@ export class TagPath {
|
|
|
1124
2000
|
}
|
|
1125
2001
|
|
|
1126
2002
|
// done
|
|
1127
|
-
if (!isInitialTag &&
|
|
1128
|
-
return
|
|
2003
|
+
if (!isInitialTag && !isNodeTag(propTag) && !isArray(propTag)) {
|
|
2004
|
+
return TagPath.from(path, tagsIndex, propertyIndex);
|
|
1129
2005
|
}
|
|
1130
2006
|
|
|
1131
|
-
|
|
1132
|
-
if (tag.type === PropertyWrapper) {
|
|
1133
|
-
if (wrapperIndex + 1 < tag.value.tags.length) {
|
|
1134
|
-
wrapperIndex++;
|
|
1135
|
-
continue;
|
|
1136
|
-
} else if (!wasLeaving && tag.value.tags[1] && tag.value.tags[1].type !== InitializerTag) {
|
|
1137
|
-
path = path.push(tag.value.property.node, tagsIndex);
|
|
1138
|
-
tagsIndex = 0;
|
|
1139
|
-
continue;
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
2007
|
+
let { nextSibling } = TagPath.from(path, tagsIndex, propertyIndex);
|
|
1142
2008
|
|
|
1143
2009
|
// over
|
|
1144
|
-
if (
|
|
1145
|
-
tagsIndex
|
|
2010
|
+
if (nextSibling) {
|
|
2011
|
+
({ tagsIndex, propertyIndex } = nextSibling);
|
|
1146
2012
|
continue;
|
|
1147
2013
|
}
|
|
1148
2014
|
|
|
@@ -1153,6 +2019,7 @@ export class TagPath {
|
|
|
1153
2019
|
|
|
1154
2020
|
path = path.parent;
|
|
1155
2021
|
leaving = true;
|
|
2022
|
+
if (!path) return null;
|
|
1156
2023
|
} while (tagsIndex == null);
|
|
1157
2024
|
|
|
1158
2025
|
leaving = true;
|
|
@@ -1163,16 +2030,20 @@ export class TagPath {
|
|
|
1163
2030
|
}
|
|
1164
2031
|
}
|
|
1165
2032
|
|
|
1166
|
-
get
|
|
1167
|
-
|
|
2033
|
+
get previous() {
|
|
2034
|
+
throw new Error('not implemented');
|
|
2035
|
+
}
|
|
1168
2036
|
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
2037
|
+
get previousUnshifted() {
|
|
2038
|
+
throw new Error('not implemented');
|
|
2039
|
+
}
|
|
1172
2040
|
|
|
1173
|
-
|
|
2041
|
+
get propertyPath() {
|
|
2042
|
+
let { path, tagsIndex } = this;
|
|
1174
2043
|
|
|
1175
|
-
|
|
2044
|
+
let tag = Tags.getAt(tagsIndex, getTags(path.node));
|
|
2045
|
+
|
|
2046
|
+
return tag.type === Property ? path.tagPathAt(tagsIndex) : null;
|
|
1176
2047
|
}
|
|
1177
2048
|
|
|
1178
2049
|
get innerNode() {
|
|
@@ -1180,36 +2051,31 @@ export class TagPath {
|
|
|
1180
2051
|
}
|
|
1181
2052
|
|
|
1182
2053
|
get inner() {
|
|
1183
|
-
let {
|
|
1184
|
-
|
|
1185
|
-
let refPath = TagPath.from(path, tagsIndex, 0);
|
|
2054
|
+
let { tagsIndex, tag } = this;
|
|
1186
2055
|
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
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();
|
|
1196
2068
|
}
|
|
1197
|
-
|
|
1198
|
-
if (refPath.tag.type !== ReferenceTag) throw new Error();
|
|
1199
|
-
|
|
1200
|
-
const { type, name } = refPath.tag.value;
|
|
1201
|
-
|
|
1202
|
-
return this.path.get([
|
|
1203
|
-
buildFullPathSegment(
|
|
1204
|
-
type,
|
|
1205
|
-
name,
|
|
1206
|
-
getChildPropertyIndex(refPath.path.node, refPath.tagsIndex),
|
|
1207
|
-
shiftPath?.tag.value.index,
|
|
1208
|
-
),
|
|
1209
|
-
]);
|
|
2069
|
+
return node && this.path.push(tagsIndex);
|
|
1210
2070
|
}
|
|
1211
2071
|
|
|
1212
2072
|
equalTo(tagPath) {
|
|
1213
|
-
return
|
|
2073
|
+
return (
|
|
2074
|
+
this.node === tagPath.node &&
|
|
2075
|
+
this.tagsIndex === tagPath.tagsIndex &&
|
|
2076
|
+
arraysEqual(this.propertyIndex, tagPath.propertyIndex)
|
|
2077
|
+
);
|
|
1214
2078
|
}
|
|
1215
2079
|
}
|
|
2080
|
+
|
|
2081
|
+
Object.freeze(TagPath.prototype);
|