@bablr/agast-helpers 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/builders.js +70 -27
- package/lib/children.js +120 -0
- package/lib/object.js +86 -0
- package/lib/path-facade.js +39 -0
- package/lib/path.js +386 -448
- package/lib/print.js +51 -87
- package/lib/shorthand.js +26 -1
- package/lib/stream.js +33 -13
- package/lib/symbols.js +3 -1
- package/lib/template.js +23 -36
- package/lib/tree.js +368 -122
- package/package.json +8 -5
- package/lib/sumtree.js +0 -62
package/lib/path.js
CHANGED
|
@@ -1,31 +1,67 @@
|
|
|
1
1
|
import { WeakStackFrame } from '@bablr/weak-stack';
|
|
2
2
|
import * as btree from '@bablr/agast-helpers/btree';
|
|
3
|
-
import * as
|
|
3
|
+
import * as Children from './children.js';
|
|
4
4
|
import {
|
|
5
5
|
ReferenceTag,
|
|
6
6
|
InitializerTag,
|
|
7
|
-
EmbeddedNode,
|
|
8
7
|
DoctypeTag,
|
|
9
8
|
OpenNodeTag,
|
|
10
9
|
CloseNodeTag,
|
|
11
10
|
GapTag,
|
|
12
11
|
NullTag,
|
|
13
12
|
ShiftTag,
|
|
13
|
+
BindingTag,
|
|
14
|
+
Property,
|
|
14
15
|
} from './symbols.js';
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
import { isString } from './object.js';
|
|
17
|
+
|
|
18
|
+
export const buildPathSegment = (name, index = null, shiftIndex = null) => {
|
|
19
|
+
if (!name) throw new Error();
|
|
20
|
+
return { type: null, name, index, shiftIndex };
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const buildTypePathSegment = (type, index = null, shiftIndex = null) => {
|
|
24
|
+
if (!type) throw new Error();
|
|
25
|
+
return { type, name: null, index, shiftIndex };
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const buildFullPathSegment = (type, name, index = null, shiftIndex = null) => {
|
|
29
|
+
return { type, name, index, shiftIndex };
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const getRoot = (node, index = 0) => {
|
|
33
|
+
if (node == null || !isFragmentNode(node)) {
|
|
34
|
+
return node;
|
|
35
|
+
}
|
|
36
|
+
let idx = getPropertyChildrenIndex(node, '.', null, index);
|
|
37
|
+
|
|
38
|
+
if (idx == null) return null;
|
|
39
|
+
|
|
40
|
+
let tag = Children.getAt(idx + 2, node.children);
|
|
41
|
+
|
|
42
|
+
if (tag.type !== Property) throw new Error();
|
|
43
|
+
return tag.value.node;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const getRootArray = (node) => {
|
|
47
|
+
let arr = [];
|
|
48
|
+
for (let i = 0; ; i++) {
|
|
49
|
+
let root = getRoot(node, i);
|
|
50
|
+
if (root) {
|
|
51
|
+
arr.push(root);
|
|
52
|
+
} else {
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return arr;
|
|
57
|
+
};
|
|
22
58
|
|
|
23
59
|
export const getOpenTag = (node) => {
|
|
24
60
|
if (!node.children.length) return null;
|
|
25
|
-
let tag =
|
|
61
|
+
let tag = Children.getAt(0, node.children);
|
|
26
62
|
if (tag.type === NullTag || tag.type === GapTag) return null;
|
|
27
63
|
if (tag.type === DoctypeTag) {
|
|
28
|
-
tag =
|
|
64
|
+
tag = Children.getAt(1, node.children);
|
|
29
65
|
}
|
|
30
66
|
if (tag && tag.type !== OpenNodeTag) throw new Error();
|
|
31
67
|
return tag;
|
|
@@ -33,13 +69,13 @@ export const getOpenTag = (node) => {
|
|
|
33
69
|
|
|
34
70
|
export const getCloseTag = (node) => {
|
|
35
71
|
const { children } = node;
|
|
36
|
-
const tag =
|
|
72
|
+
const tag = Children.getAt(-1, children);
|
|
37
73
|
if (tag.type !== CloseNodeTag) return null;
|
|
38
74
|
return tag;
|
|
39
75
|
};
|
|
40
76
|
|
|
41
77
|
export const isNullNode = (node) => {
|
|
42
|
-
return node && node.type === null &&
|
|
78
|
+
return node && node.type === null && Children.getAt(0, node.children).type === NullTag;
|
|
43
79
|
};
|
|
44
80
|
|
|
45
81
|
export const isFragmentNode = (node) => {
|
|
@@ -47,13 +83,23 @@ export const isFragmentNode = (node) => {
|
|
|
47
83
|
};
|
|
48
84
|
|
|
49
85
|
export const isGapNode = (node) => {
|
|
50
|
-
return node && node.type === null &&
|
|
86
|
+
return node && node.type === null && Children.getAt(0, node.children).type === GapTag;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export const isStubNode = (node) => {
|
|
90
|
+
return (
|
|
91
|
+
node && node.type === null && [GapTag, NullTag].includes(Children.getAt(0, node.children).type)
|
|
92
|
+
);
|
|
51
93
|
};
|
|
52
94
|
|
|
53
95
|
export const getChildPropertyIndex = (agAstNode, childrenIndex) => {
|
|
54
|
-
let
|
|
96
|
+
let child = Children.getAt(childrenIndex, agAstNode.children);
|
|
97
|
+
|
|
98
|
+
let refIndex = child.type === ShiftTag ? childrenIndex - child.value.index * 3 : childrenIndex;
|
|
99
|
+
|
|
100
|
+
let stack = Children.findPath(refIndex, agAstNode.children);
|
|
55
101
|
let { node, index: leafIdx } = stack.value;
|
|
56
|
-
let leaf =
|
|
102
|
+
let leaf = Children.getAt(leafIdx, node);
|
|
57
103
|
|
|
58
104
|
if (leaf.type !== ReferenceTag) return null;
|
|
59
105
|
|
|
@@ -63,7 +109,7 @@ export const getChildPropertyIndex = (agAstNode, childrenIndex) => {
|
|
|
63
109
|
if (!isArray) return null;
|
|
64
110
|
|
|
65
111
|
for (let i = leafIdx; i >= 0; i--) {
|
|
66
|
-
let value =
|
|
112
|
+
let value = Children.getAt(i, node);
|
|
67
113
|
|
|
68
114
|
if (value.type === ReferenceTag && value.value.name === name) {
|
|
69
115
|
count++;
|
|
@@ -77,8 +123,8 @@ export const getChildPropertyIndex = (agAstNode, childrenIndex) => {
|
|
|
77
123
|
|
|
78
124
|
do {
|
|
79
125
|
for (let i = leafIdx - 1; i >= 0; i--) {
|
|
80
|
-
let childNode =
|
|
81
|
-
let { references } =
|
|
126
|
+
let childNode = Children.getValues(node)[i];
|
|
127
|
+
let { references } = Children.getSums(childNode);
|
|
82
128
|
|
|
83
129
|
if (hasOwn(references, name)) {
|
|
84
130
|
count += references[name];
|
|
@@ -95,61 +141,69 @@ export const getChildPropertyIndex = (agAstNode, childrenIndex) => {
|
|
|
95
141
|
return count - 1;
|
|
96
142
|
};
|
|
97
143
|
|
|
98
|
-
export const getPropertyChildrenIndex = (agAstNode,
|
|
99
|
-
let
|
|
144
|
+
export const getPropertyChildrenIndex = (agAstNode, type, name, index) => {
|
|
145
|
+
let firstRefIndex = __getPropertyChildrenIndex(agAstNode, type, name, 0);
|
|
146
|
+
let nextTag = Children.getAt(firstRefIndex + 1, agAstNode.children);
|
|
147
|
+
let initializerOffset = nextTag.type === InitializerTag ? 1 : 0;
|
|
148
|
+
|
|
100
149
|
if (isArray) {
|
|
101
150
|
if (index == null) {
|
|
102
|
-
|
|
151
|
+
if (type) {
|
|
152
|
+
index = btree.getSums(agAstNode.children).specialTypes[type] - 1 - initializerOffset;
|
|
153
|
+
} else {
|
|
154
|
+
index = btree.getSums(agAstNode.children).references[name] - 1 - initializerOffset;
|
|
155
|
+
}
|
|
103
156
|
}
|
|
104
157
|
}
|
|
105
158
|
|
|
106
|
-
|
|
107
|
-
let nextTag = sumtree.getAt(firstRefIndex + 1, agAstNode.children);
|
|
108
|
-
|
|
109
|
-
return __getPropertyChildrenIndex(
|
|
110
|
-
agAstNode,
|
|
111
|
-
name,
|
|
112
|
-
index + (nextTag.type === InitializerTag ? 1 : 0),
|
|
113
|
-
);
|
|
159
|
+
return __getPropertyChildrenIndex(agAstNode, type, name, index + initializerOffset);
|
|
114
160
|
};
|
|
115
161
|
|
|
116
162
|
export const getInitializerChildrenIndex = (agAstNode, reference) => {
|
|
117
|
-
|
|
163
|
+
let { type, name } = reference.value;
|
|
164
|
+
return __getPropertyChildrenIndex(agAstNode, type, name, 0);
|
|
118
165
|
};
|
|
119
166
|
|
|
120
|
-
const __getPropertyChildrenIndex = (agAstNode, name, index) => {
|
|
167
|
+
const __getPropertyChildrenIndex = (agAstNode, type, name, index) => {
|
|
121
168
|
let nameCount = 0;
|
|
122
169
|
let node = agAstNode.children;
|
|
123
170
|
let idx = -1;
|
|
124
171
|
|
|
125
172
|
// drill into subtrees, passing over subtrees with too few references of the desired name
|
|
126
173
|
outer: while (node) {
|
|
127
|
-
let isLeaf =
|
|
128
|
-
let sums =
|
|
129
|
-
let valueNameCount = sums.references[name];
|
|
174
|
+
let isLeaf = Children.isLeafNode(node);
|
|
175
|
+
let sums = Children.getSums(node);
|
|
176
|
+
let valueNameCount = type == null ? sums.references[name] : sums.specialTypes[type];
|
|
130
177
|
|
|
131
178
|
if (nameCount + valueNameCount < index) {
|
|
132
179
|
return null;
|
|
133
180
|
}
|
|
134
181
|
|
|
135
|
-
for (const value of
|
|
182
|
+
for (const value of Children.getValues(node)) {
|
|
136
183
|
if (isLeaf) {
|
|
137
184
|
idx++;
|
|
138
185
|
let tag = value;
|
|
139
|
-
if (
|
|
186
|
+
if (
|
|
187
|
+
tag.type === ReferenceTag &&
|
|
188
|
+
((name != null && tag.value.name === name) || (type != null && tag.value.type === type))
|
|
189
|
+
) {
|
|
140
190
|
nameCount += 1;
|
|
141
191
|
if (nameCount > index) {
|
|
142
192
|
return idx;
|
|
143
193
|
}
|
|
144
194
|
}
|
|
145
195
|
} else {
|
|
146
|
-
let valueSums =
|
|
147
|
-
if (
|
|
196
|
+
let valueSums = Children.getSums(value);
|
|
197
|
+
if (
|
|
198
|
+
nameCount + (type == null ? valueSums.references[name] : valueSums.specialTypes[type]) >
|
|
199
|
+
index
|
|
200
|
+
) {
|
|
148
201
|
node = value;
|
|
149
202
|
continue outer;
|
|
150
203
|
} else {
|
|
151
|
-
nameCount +=
|
|
152
|
-
|
|
204
|
+
nameCount +=
|
|
205
|
+
(type == null ? valueSums.references[name] : valueSums.specialTypes[type]) ?? 0;
|
|
206
|
+
idx += Children.getSize(value);
|
|
153
207
|
}
|
|
154
208
|
}
|
|
155
209
|
}
|
|
@@ -160,9 +214,49 @@ const __getPropertyChildrenIndex = (agAstNode, name, index) => {
|
|
|
160
214
|
return null;
|
|
161
215
|
};
|
|
162
216
|
|
|
163
|
-
const { hasOwn } = Object;
|
|
217
|
+
const { hasOwn, freeze } = Object;
|
|
164
218
|
const { isArray } = Array;
|
|
165
219
|
|
|
220
|
+
export const getOriginalFirstNode = (node, height = 1) => {
|
|
221
|
+
for (let child of Children.traverse(node.children)) {
|
|
222
|
+
if (child.type === Property) {
|
|
223
|
+
return getProperties(buildPathSegment(child.value.reference.name, 0, height), node.properties)
|
|
224
|
+
.node;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return null;
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
export const getFirstNode = (node) => {
|
|
231
|
+
return getFirstNodeProperty(node)?.node;
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
export const getFirstNodeProperty = (node) => {
|
|
235
|
+
for (let child of Children.traverse(node.children)) {
|
|
236
|
+
if (child.type === Property) {
|
|
237
|
+
return child.value;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return null;
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
export const getFirstNodeShiftStack = (node) => {
|
|
244
|
+
for (let child of Children.traverse(node.children)) {
|
|
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;
|
|
258
|
+
};
|
|
259
|
+
|
|
166
260
|
export const referencesAreEqual = (a, b) => {
|
|
167
261
|
return (
|
|
168
262
|
a === b ||
|
|
@@ -173,163 +267,85 @@ export const referencesAreEqual = (a, b) => {
|
|
|
173
267
|
);
|
|
174
268
|
};
|
|
175
269
|
|
|
176
|
-
export const getProperties = (
|
|
177
|
-
|
|
270
|
+
export const getProperties = (pathSegment, properties) => {
|
|
271
|
+
let pathSegment_ = typeof pathSegment === 'string' ? buildPathSegment(pathSegment) : pathSegment;
|
|
272
|
+
if (!hasOwn(pathSegment_, 'shiftIndex')) throw new Error();
|
|
273
|
+
let { name, index, shiftIndex } = pathSegment_;
|
|
178
274
|
|
|
179
|
-
if (name
|
|
180
|
-
|
|
181
|
-
return null;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
275
|
+
if (hasOwn(properties, name)) {
|
|
276
|
+
let prop = properties[name];
|
|
184
277
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
return properties[name];
|
|
189
|
-
}
|
|
190
|
-
};
|
|
278
|
+
if (prop.reference.isArray) {
|
|
279
|
+
prop = btree.getAt(index ?? -1, prop.node);
|
|
280
|
+
}
|
|
191
281
|
|
|
192
|
-
|
|
193
|
-
const { name, index, isArray } = ref.value;
|
|
282
|
+
if (!prop) return null;
|
|
194
283
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
284
|
+
if (prop.reference.flags.expression) {
|
|
285
|
+
prop = btree.getAt(shiftIndex ?? -1, prop.node);
|
|
286
|
+
}
|
|
198
287
|
|
|
199
|
-
|
|
200
|
-
return properties[name][index == null ? properties[name].length - 1 : index];
|
|
201
|
-
} else {
|
|
202
|
-
return properties[name];
|
|
288
|
+
return prop;
|
|
203
289
|
}
|
|
290
|
+
return null;
|
|
204
291
|
};
|
|
205
292
|
|
|
206
293
|
export const isDefined = (obj, key) => hasOwn(obj, key) && obj[key] !== undefined;
|
|
207
294
|
export const isUndefined = (obj, key) => !hasOwn(obj, key) || obj[key] === undefined;
|
|
208
295
|
|
|
209
|
-
export const get = (
|
|
210
|
-
|
|
211
|
-
const { flags } = result.reference.value;
|
|
212
|
-
|
|
213
|
-
return flags.expression ? btree.getAt(-1, result.node) : result?.node;
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
export const getShifted = (shiftIndex, ref, node) => {
|
|
217
|
-
const { flags } = ref.value;
|
|
296
|
+
export const get = (path, node) => {
|
|
297
|
+
if (!node) throw new Error();
|
|
218
298
|
|
|
219
|
-
|
|
220
|
-
return flags.expression ? btree.getAt(shiftIndex ?? -1, result.node) : result?.node;
|
|
221
|
-
};
|
|
299
|
+
if (path == null) throw new Error('Bad path');
|
|
222
300
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
if (value === node) {
|
|
226
|
-
throw new Error('cannot add a node to itself');
|
|
301
|
+
if (!isArray(path)) {
|
|
302
|
+
path = [path];
|
|
227
303
|
}
|
|
228
304
|
|
|
229
|
-
|
|
230
|
-
|
|
305
|
+
let node_ = node;
|
|
306
|
+
for (let i = 0; i < path.length; i++) {
|
|
307
|
+
let nameOrSeg = path[i];
|
|
308
|
+
let isName = typeof nameOrSeg === 'string';
|
|
309
|
+
let property;
|
|
231
310
|
|
|
232
|
-
|
|
233
|
-
throw new Error('Only fragments can have . properties');
|
|
234
|
-
}
|
|
311
|
+
if (!isName && (!nameOrSeg || !hasOwn(nameOrSeg, 'shiftIndex'))) throw new Error('Bad path');
|
|
235
312
|
|
|
236
|
-
|
|
237
|
-
if (Array.isArray(value) && value.length) throw new Error();
|
|
313
|
+
let name = isName ? nameOrSeg : nameOrSeg.name;
|
|
238
314
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
const lastChild = sumtree.getAt(-1, node.children);
|
|
242
|
-
|
|
243
|
-
if (lastChild.type === ReferenceTag) {
|
|
244
|
-
if (!referencesAreEqual(lastChild, reference)) throw new Error();
|
|
245
|
-
} else if (lastChild.type !== ShiftTag) {
|
|
246
|
-
if ([ShiftTag, ReferenceTag].includes(sumtree.getAt(-1, node.children).type)) throw new Error();
|
|
247
|
-
node.children = sumtree.push(node.children, shift > 0 ? buildShiftTag(shift) : reference);
|
|
248
|
-
}
|
|
315
|
+
if (name) {
|
|
316
|
+
let { index } = nameOrSeg;
|
|
249
317
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
let isInitializer = Array.isArray(value);
|
|
255
|
-
let exists = !isInitializer && isDefined(properties, name);
|
|
256
|
-
|
|
257
|
-
let existed = exists;
|
|
258
|
-
if (!existed) {
|
|
259
|
-
if (isInitializer && value.length)
|
|
260
|
-
throw new Error('Array value only allowed for initialization');
|
|
318
|
+
property = getProperties(
|
|
319
|
+
isName ? buildPathSegment(name, index) : nameOrSeg,
|
|
320
|
+
node_.properties,
|
|
321
|
+
);
|
|
261
322
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
323
|
+
({ node: node_ } = property || {});
|
|
324
|
+
} else if (!isName) {
|
|
325
|
+
let { type } = nameOrSeg;
|
|
326
|
+
if (type !== '.') throw new Error('not implemented');
|
|
266
327
|
|
|
267
|
-
|
|
268
|
-
if (!existed) {
|
|
269
|
-
if (sumtree.getAt(-1, node.children).type === ReferenceTag) throw new Error();
|
|
270
|
-
node.children = sumtree.push(node.children, reference);
|
|
271
|
-
}
|
|
328
|
+
let refIndex = getPropertyChildrenIndex(node_, '.');
|
|
272
329
|
|
|
273
|
-
|
|
274
|
-
if (flags.expression) {
|
|
275
|
-
let shiftedNodes = shift > 0 ? btree.getAt(-1, properties[name])?.node : [];
|
|
330
|
+
if (refIndex == null) return null;
|
|
276
331
|
|
|
277
|
-
|
|
278
|
-
reference,
|
|
279
|
-
node: btree.push(shiftedNodes, value),
|
|
280
|
-
};
|
|
281
|
-
} else {
|
|
282
|
-
newBinding = { reference, node: value };
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
properties[name] =
|
|
286
|
-
shift > 0
|
|
287
|
-
? btree.replaceAt(-1, properties[name], newBinding)
|
|
288
|
-
: btree.push(properties[name], newBinding);
|
|
289
|
-
|
|
290
|
-
node.children = sumtree.push(node.children, buildGapTag(value));
|
|
291
|
-
}
|
|
332
|
+
node_ = Children.getAt(refIndex + 2, node_.children).value.node;
|
|
292
333
|
} else {
|
|
293
|
-
|
|
294
|
-
if (isUndefined(properties, name)) {
|
|
295
|
-
let newBinding;
|
|
296
|
-
if (flags.expression) {
|
|
297
|
-
let shiftedNodes = shift > 0 ? btree.getAt(-1, properties[name])?.node : [];
|
|
298
|
-
|
|
299
|
-
newBinding = {
|
|
300
|
-
reference,
|
|
301
|
-
node: btree.push(shiftedNodes, undefined),
|
|
302
|
-
};
|
|
303
|
-
} else {
|
|
304
|
-
newBinding = { reference, node: undefined };
|
|
305
|
-
}
|
|
306
|
-
properties[name] = newBinding;
|
|
307
|
-
node.children = sumtree.push(node.children, buildInitializerTag());
|
|
308
|
-
}
|
|
309
|
-
} else {
|
|
310
|
-
if (flags.expression) {
|
|
311
|
-
if (shift == null) {
|
|
312
|
-
throw new Error();
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
let shiftedNodes = shift ? properties[name]?.node : [];
|
|
316
|
-
properties[name] = { reference, node: btree.push(shiftedNodes, value) };
|
|
317
|
-
} else {
|
|
318
|
-
if (shift != null) throw new Error();
|
|
319
|
-
if (hasOwn(properties, name) && properties[name].node !== undefined) {
|
|
320
|
-
throw new Error();
|
|
321
|
-
}
|
|
322
|
-
properties[name] = { reference, node: value };
|
|
323
|
-
}
|
|
324
|
-
node.children = sumtree.push(node.children, buildGapTag(value));
|
|
325
|
-
}
|
|
334
|
+
throw new Error();
|
|
326
335
|
}
|
|
336
|
+
|
|
337
|
+
if (!node_) return null;
|
|
327
338
|
}
|
|
339
|
+
|
|
340
|
+
return node_;
|
|
328
341
|
};
|
|
329
342
|
|
|
330
343
|
export function* allTagPathsFor(range, options = {}) {
|
|
331
344
|
if (range == null) return;
|
|
332
345
|
|
|
346
|
+
if (range[0] && !(range[0] instanceof TagPath)) throw new Error();
|
|
347
|
+
if (range[1] && !(range[1] instanceof TagPath)) throw new Error();
|
|
348
|
+
|
|
333
349
|
const { unshift = false } = options;
|
|
334
350
|
let startPath = range[0];
|
|
335
351
|
let endPath = range[1];
|
|
@@ -337,7 +353,7 @@ export function* allTagPathsFor(range, options = {}) {
|
|
|
337
353
|
|
|
338
354
|
while (path) {
|
|
339
355
|
if (path.inner && path.previousSibling.tag.type === ReferenceTag) {
|
|
340
|
-
path = new TagPath(path.
|
|
356
|
+
path = new TagPath(path.inner, 0);
|
|
341
357
|
}
|
|
342
358
|
|
|
343
359
|
if (path.path.depth < startPath.path.depth) {
|
|
@@ -370,25 +386,25 @@ export function* allTagPathsFor(range, options = {}) {
|
|
|
370
386
|
}
|
|
371
387
|
|
|
372
388
|
export function* allTagsFor(range, options = {}) {
|
|
373
|
-
for (
|
|
389
|
+
for (let path of allTagPathsFor(range, options)) {
|
|
374
390
|
yield path.tag;
|
|
375
391
|
}
|
|
376
392
|
}
|
|
377
393
|
|
|
378
394
|
export const buildFullRange = (node) => {
|
|
379
|
-
|
|
395
|
+
let sum = Children.getSize(node.children);
|
|
380
396
|
return sum ? [0, sum - 1] : null;
|
|
381
397
|
};
|
|
382
398
|
|
|
383
399
|
export function* ownTagPathsFor(range) {
|
|
384
400
|
if (!isArray(range)) throw new Error();
|
|
385
401
|
|
|
386
|
-
|
|
387
|
-
|
|
402
|
+
let startPath = range[0];
|
|
403
|
+
let endPath = range[1];
|
|
388
404
|
|
|
389
|
-
if (startPath.
|
|
405
|
+
if (startPath.parent.node !== endPath.parent.node) throw new Error();
|
|
390
406
|
|
|
391
|
-
|
|
407
|
+
let { children } = startPath.parent.node;
|
|
392
408
|
|
|
393
409
|
for (let i = startPath.childrenIndex; i < endPath.childrenIndex; i++) {
|
|
394
410
|
yield children[i];
|
|
@@ -397,7 +413,7 @@ export function* ownTagPathsFor(range) {
|
|
|
397
413
|
|
|
398
414
|
const findRight = (arr, predicate) => {
|
|
399
415
|
for (let i = arr.length - 1; i >= 0; i--) {
|
|
400
|
-
|
|
416
|
+
let value = arr[i];
|
|
401
417
|
if (predicate(value)) return value;
|
|
402
418
|
}
|
|
403
419
|
return null;
|
|
@@ -420,7 +436,7 @@ const buildSkips = (frame) => {
|
|
|
420
436
|
skipsByFrame.set(frame, skips);
|
|
421
437
|
}
|
|
422
438
|
|
|
423
|
-
skips[skipIdx] = frame.
|
|
439
|
+
skips[skipIdx] = frame.atDepth(frame.depth - skipAmount);
|
|
424
440
|
|
|
425
441
|
skipIdx++;
|
|
426
442
|
skipAmount = skipAmounts[skipIdx];
|
|
@@ -441,15 +457,33 @@ const skipToDepth = (depth, frame) => {
|
|
|
441
457
|
return parent;
|
|
442
458
|
};
|
|
443
459
|
|
|
460
|
+
export let pathForTagPath = (tagPath) => {
|
|
461
|
+
let refTagPath = tagPath;
|
|
462
|
+
let isShift = tagPath.tag.type === ShiftTag;
|
|
463
|
+
|
|
464
|
+
if (isShift) {
|
|
465
|
+
refTagPath = tagPath.siblingAt(tagPath.childrenIndex - tagPath.tag.value.index * 3);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
let { type, name } = refTagPath.tag.value;
|
|
469
|
+
|
|
470
|
+
if (refTagPath.tag.type !== ReferenceTag) throw new Error();
|
|
471
|
+
|
|
472
|
+
let index = getChildPropertyIndex(tagPath.node, refTagPath.childrenIndex);
|
|
473
|
+
let shiftIndex = isShift ? (tagPath.tag.value.index ?? 0) + 1 : null;
|
|
474
|
+
|
|
475
|
+
return [{ type, name, index, shiftIndex }];
|
|
476
|
+
};
|
|
477
|
+
|
|
444
478
|
export const Path = class AgastPath extends WeakStackFrame {
|
|
445
479
|
static from(node) {
|
|
446
|
-
return this.create(node);
|
|
480
|
+
return node && this.create(node);
|
|
447
481
|
}
|
|
448
482
|
|
|
449
483
|
constructor(parent, node, referenceIndex = null) {
|
|
450
484
|
super(parent);
|
|
451
485
|
|
|
452
|
-
if (!(hasOwn(node, 'type') && hasOwn(node, '
|
|
486
|
+
if (!(hasOwn(node, 'type') && hasOwn(node, 'properties'))) throw new Error();
|
|
453
487
|
|
|
454
488
|
if (parent && referenceIndex == null) throw new Error();
|
|
455
489
|
if (!node) throw new Error();
|
|
@@ -458,10 +492,10 @@ export const Path = class AgastPath extends WeakStackFrame {
|
|
|
458
492
|
this.node = node;
|
|
459
493
|
this.referenceIndex = referenceIndex; // in the parent
|
|
460
494
|
|
|
461
|
-
|
|
462
|
-
referenceIndex != null &&
|
|
463
|
-
|
|
464
|
-
) {
|
|
495
|
+
let referenceTag =
|
|
496
|
+
referenceIndex != null && Children.getAt(referenceIndex, parent.node.children);
|
|
497
|
+
|
|
498
|
+
if (referenceTag && ![ReferenceTag, ShiftTag].includes(referenceTag.type)) {
|
|
465
499
|
throw new Error();
|
|
466
500
|
}
|
|
467
501
|
|
|
@@ -469,13 +503,28 @@ export const Path = class AgastPath extends WeakStackFrame {
|
|
|
469
503
|
throw new Error();
|
|
470
504
|
}
|
|
471
505
|
|
|
506
|
+
// if (
|
|
507
|
+
// parent &&
|
|
508
|
+
// (['#', '@'].includes(this.reference.value.type)
|
|
509
|
+
// ? parent.tagPathAt(referenceIndex + 1).tag.value
|
|
510
|
+
// : get(pathForTagPath(parent.tagPathAt(referenceIndex)), parent.node)) !== node
|
|
511
|
+
// ) {
|
|
512
|
+
// throw new Error('Path not reachable');
|
|
513
|
+
// }
|
|
514
|
+
|
|
472
515
|
if (!Number.isFinite(this.depth)) throw new Error();
|
|
473
516
|
|
|
474
517
|
buildSkips(this);
|
|
518
|
+
|
|
519
|
+
freeze(this);
|
|
475
520
|
}
|
|
476
521
|
|
|
477
522
|
get openTagPath() {
|
|
478
|
-
|
|
523
|
+
let tagPath = TagPath.from(this, 0);
|
|
524
|
+
if (tagPath.tag.type === DoctypeTag) {
|
|
525
|
+
tagPath = tagPath.nextSibling;
|
|
526
|
+
}
|
|
527
|
+
return tagPath;
|
|
479
528
|
}
|
|
480
529
|
|
|
481
530
|
get openTag() {
|
|
@@ -483,42 +532,71 @@ export const Path = class AgastPath extends WeakStackFrame {
|
|
|
483
532
|
}
|
|
484
533
|
|
|
485
534
|
get closeTagPath() {
|
|
486
|
-
|
|
535
|
+
let tagPath = TagPath.from(this, -1);
|
|
536
|
+
if (tagPath.tag.type !== CloseNodeTag) return null;
|
|
537
|
+
return tagPath;
|
|
487
538
|
}
|
|
488
539
|
|
|
489
540
|
get closeTag() {
|
|
490
541
|
return this.closeTagPath.tag;
|
|
491
542
|
}
|
|
492
543
|
|
|
493
|
-
|
|
494
|
-
return
|
|
544
|
+
tagPathAt(idx) {
|
|
545
|
+
return TagPath.from(this, idx);
|
|
495
546
|
}
|
|
496
547
|
|
|
497
|
-
get
|
|
498
|
-
return
|
|
548
|
+
get reference() {
|
|
549
|
+
return (
|
|
550
|
+
(this.parent?.node ?? null) && Children.getAt(this.referenceIndex, this.parent.node.children)
|
|
551
|
+
);
|
|
499
552
|
}
|
|
500
553
|
|
|
501
|
-
get
|
|
502
|
-
return this.
|
|
554
|
+
get referenceTagPath() {
|
|
555
|
+
return (this.parent?.node ?? null) && new TagPath(this.parent, this.referenceIndex);
|
|
503
556
|
}
|
|
504
557
|
|
|
505
|
-
get
|
|
506
|
-
|
|
507
|
-
|
|
558
|
+
get(path) {
|
|
559
|
+
let path_ = path;
|
|
560
|
+
if (typeof path_ === 'string') {
|
|
561
|
+
path_ = [path_];
|
|
562
|
+
}
|
|
563
|
+
if (!isArray(path_)) throw new Error();
|
|
508
564
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
565
|
+
let pathInst = this;
|
|
566
|
+
for (let i = 0; i < path_.length; i++) {
|
|
567
|
+
let nameOrSeg = path_[i];
|
|
512
568
|
|
|
513
|
-
|
|
514
|
-
|
|
569
|
+
if (isString(nameOrSeg)) {
|
|
570
|
+
nameOrSeg = { type: null, name: nameOrSeg, index: null, shiftIndex: null };
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
let property = getProperties(nameOrSeg, pathInst.node.properties);
|
|
574
|
+
|
|
575
|
+
if (!property) return null;
|
|
576
|
+
|
|
577
|
+
let { node, reference: ref } = property;
|
|
578
|
+
|
|
579
|
+
let shiftIndex_ = nameOrSeg.shiftIndex;
|
|
580
|
+
|
|
581
|
+
if (shiftIndex_ && shiftIndex_ < 0) {
|
|
582
|
+
shiftIndex_ = btree.getSize(node) + shiftIndex_;
|
|
583
|
+
} else if (shiftIndex_ == null && ref.flags.expression) {
|
|
584
|
+
shiftIndex_ = 0;
|
|
585
|
+
}
|
|
515
586
|
|
|
516
|
-
|
|
587
|
+
let shiftOffset = shiftIndex_ ? (shiftIndex_ - 1) * 3 : 0;
|
|
517
588
|
|
|
518
|
-
|
|
589
|
+
pathInst = pathInst.push(
|
|
590
|
+
node,
|
|
591
|
+
getPropertyChildrenIndex(pathInst.node, nameOrSeg.type, nameOrSeg.name, nameOrSeg.index) +
|
|
592
|
+
shiftOffset,
|
|
593
|
+
);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
return pathInst;
|
|
519
597
|
}
|
|
520
598
|
|
|
521
|
-
|
|
599
|
+
atDepth(depth) {
|
|
522
600
|
return skipToDepth(depth, this);
|
|
523
601
|
}
|
|
524
602
|
};
|
|
@@ -532,14 +610,20 @@ export class TagPath {
|
|
|
532
610
|
constructor(path, childrenIndex) {
|
|
533
611
|
if (path == null || childrenIndex == null) throw new Error();
|
|
534
612
|
|
|
613
|
+
let tag = Children.getAt(childrenIndex, path.node.children);
|
|
614
|
+
|
|
615
|
+
if (tag == null) throw new Error();
|
|
616
|
+
|
|
535
617
|
this.path = path;
|
|
618
|
+
this.node = path.node;
|
|
619
|
+
this.tag = tag;
|
|
536
620
|
this.childrenIndex = childrenIndex;
|
|
537
621
|
|
|
538
|
-
|
|
622
|
+
freeze(this);
|
|
539
623
|
}
|
|
540
624
|
|
|
541
625
|
static from(path, childrenIndex) {
|
|
542
|
-
let size =
|
|
626
|
+
let size = Children.getSize(path.node.children);
|
|
543
627
|
let index = childrenIndex < 0 ? size + childrenIndex : childrenIndex;
|
|
544
628
|
|
|
545
629
|
return index >= 0 && index < size ? new TagPath(path, index) : null;
|
|
@@ -549,33 +633,21 @@ export class TagPath {
|
|
|
549
633
|
return TagPath.from(Path.from(node), childrenIndex);
|
|
550
634
|
}
|
|
551
635
|
|
|
552
|
-
get tag() {
|
|
553
|
-
return this.child;
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
get node() {
|
|
557
|
-
return this.path.node;
|
|
558
|
-
}
|
|
559
|
-
|
|
560
636
|
get child() {
|
|
561
|
-
return
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
siblingPathAt(index) {
|
|
565
|
-
return TagPath.from(this.path, index);
|
|
637
|
+
return this.tag;
|
|
566
638
|
}
|
|
567
639
|
|
|
568
640
|
siblingAt(index) {
|
|
569
|
-
return this.
|
|
641
|
+
return TagPath.from(this.path, index);
|
|
570
642
|
}
|
|
571
643
|
|
|
572
644
|
get nextSibling() {
|
|
573
645
|
const { path, childrenIndex } = this;
|
|
574
646
|
|
|
575
647
|
const child =
|
|
576
|
-
childrenIndex + 1 >=
|
|
648
|
+
childrenIndex + 1 >= Children.getSize(path.node.children)
|
|
577
649
|
? null
|
|
578
|
-
:
|
|
650
|
+
: Children.getAt(childrenIndex + 1, path.node.children);
|
|
579
651
|
|
|
580
652
|
return child && new TagPath(path, childrenIndex + 1);
|
|
581
653
|
}
|
|
@@ -586,8 +658,8 @@ export class TagPath {
|
|
|
586
658
|
let leaving = false;
|
|
587
659
|
|
|
588
660
|
for (;;) {
|
|
589
|
-
let prevTag =
|
|
590
|
-
let tag =
|
|
661
|
+
let prevTag = Children.getAt(childrenIndex - 1, path.node.children);
|
|
662
|
+
let tag = Children.getAt(childrenIndex, path.node.children);
|
|
591
663
|
let isInitialTag = path.node === this.path.node && childrenIndex === this.childrenIndex;
|
|
592
664
|
let wasLeaving = leaving;
|
|
593
665
|
leaving = false;
|
|
@@ -595,130 +667,58 @@ export class TagPath {
|
|
|
595
667
|
if (!tag) return null;
|
|
596
668
|
|
|
597
669
|
// done
|
|
598
|
-
if (
|
|
599
|
-
!isInitialTag &&
|
|
600
|
-
tag.type !== EmbeddedNode &&
|
|
601
|
-
(tag.type !== GapTag || isGapNode(path.node) || prevTag.type === ShiftTag)
|
|
602
|
-
) {
|
|
670
|
+
if (!isInitialTag && tag.type !== Property) {
|
|
603
671
|
return new TagPath(path, childrenIndex);
|
|
604
672
|
}
|
|
605
673
|
|
|
606
674
|
// in
|
|
607
|
-
if (tag.type ===
|
|
608
|
-
|
|
609
|
-
childrenIndex = 0;
|
|
610
|
-
continue;
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
// in
|
|
614
|
-
if (tag.type === GapTag && !wasLeaving && !isGapNode(path.node)) {
|
|
615
|
-
let refIndex = childrenIndex - 1;
|
|
616
|
-
let refTag;
|
|
617
|
-
let prevTag = sumtree.getAt(childrenIndex - 1, path.node.children);
|
|
618
|
-
let nextTag = sumtree.getAt(childrenIndex + 1, path.node.children);
|
|
619
|
-
|
|
675
|
+
if (tag.type === Property && !wasLeaving) {
|
|
676
|
+
// jump to gap tag?
|
|
620
677
|
if (
|
|
621
678
|
path.parent &&
|
|
622
|
-
|
|
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
|
|
623
684
|
) {
|
|
624
|
-
let
|
|
625
|
-
|
|
626
|
-
childrenIndex = path.referenceIndex + 1;
|
|
627
|
-
path = path.parent;
|
|
628
|
-
leaving = true;
|
|
629
|
-
continue;
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
if (prevTag.type === ReferenceTag) {
|
|
634
|
-
refTag = prevTag;
|
|
635
|
-
|
|
636
|
-
if (nextTag && nextTag.type === ShiftTag) {
|
|
637
|
-
const shifts = getProperties(refTag, path.node.properties).node;
|
|
685
|
+
let { reference: ref } = tag.value;
|
|
686
|
+
let shiftStack = path.node.properties[ref.name].node;
|
|
638
687
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
const { name, isArray, flags } = refTag.value;
|
|
642
|
-
let resolvedReference = refTag;
|
|
643
|
-
if (isArray) {
|
|
644
|
-
let index = getChildPropertyIndex(path.node, refIndex);
|
|
645
|
-
resolvedReference =
|
|
646
|
-
index === -1 ? null : buildReferenceTag(name, index != null, flags, index);
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
path = path.get(resolvedReference, 0);
|
|
650
|
-
childrenIndex = 0;
|
|
651
|
-
|
|
652
|
-
if (!path) {
|
|
653
|
-
return null;
|
|
654
|
-
}
|
|
655
|
-
continue;
|
|
656
|
-
} else {
|
|
657
|
-
if (
|
|
658
|
-
!['#', '@'].includes(refTag.value.name) &&
|
|
659
|
-
(!refTag.value.isArray || getChildPropertyIndex(path.node, refIndex) != null)
|
|
660
|
-
) {
|
|
661
|
-
const { name, isArray, flags } = refTag.value;
|
|
662
|
-
let resolvedReference = refTag;
|
|
663
|
-
if (isArray) {
|
|
664
|
-
let index = getChildPropertyIndex(path.node, refIndex);
|
|
665
|
-
resolvedReference =
|
|
666
|
-
index === -1 ? null : buildReferenceTag(name, index != null, flags, index);
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
if (resolvedReference) {
|
|
670
|
-
path = path.get(resolvedReference);
|
|
671
|
-
childrenIndex = 0;
|
|
672
|
-
|
|
673
|
-
if (!path) {
|
|
674
|
-
return null;
|
|
675
|
-
}
|
|
676
|
-
continue;
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
} else if (prevTag.type === ShiftTag) {
|
|
681
|
-
let refIndex = childrenIndex - prevTag.value.index * 2 - 1;
|
|
682
|
-
let refTag = sumtree.getAt(refIndex, path.node.children);
|
|
683
|
-
|
|
684
|
-
const { name, isArray, flags } = refTag.value;
|
|
685
|
-
let resolvedReference = refTag;
|
|
686
|
-
if (isArray) {
|
|
687
|
-
let index = getChildPropertyIndex(path.node, refIndex);
|
|
688
|
-
resolvedReference =
|
|
689
|
-
index === -1 ? null : buildReferenceTag(name, index != null, flags, index);
|
|
688
|
+
if (ref.isArray) {
|
|
689
|
+
shiftStack = btree.getAt(-1, shiftStack).node;
|
|
690
690
|
}
|
|
691
|
+
let gapNode = btree.getAt(0, shiftStack).node;
|
|
691
692
|
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
// caused us to return to a point before we left
|
|
696
|
-
path.referenceIndex = childrenIndex;
|
|
697
|
-
childrenIndex = sumtree.getAt(2, path.node.children).type === InitializerTag ? 5 : 3;
|
|
698
|
-
continue;
|
|
699
|
-
}
|
|
700
|
-
} else {
|
|
701
|
-
throw new Error();
|
|
693
|
+
path = new Path(path, gapNode, childrenIndex - 2);
|
|
694
|
+
childrenIndex = 0;
|
|
695
|
+
continue;
|
|
702
696
|
}
|
|
697
|
+
|
|
698
|
+
path = path.push(tag.value.node, childrenIndex - 2);
|
|
699
|
+
childrenIndex = 0;
|
|
700
|
+
continue;
|
|
703
701
|
}
|
|
704
702
|
|
|
705
703
|
// shift
|
|
706
|
-
if (tag.type === ShiftTag) {
|
|
707
|
-
let refIndex = childrenIndex -
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
704
|
+
if (tag.type === BindingTag && prevTag.type === ShiftTag) {
|
|
705
|
+
let refIndex = childrenIndex - 1 - prevTag.value.index * 3;
|
|
706
|
+
if (refIndex < 0) throw new Error();
|
|
707
|
+
let refTag = Children.getAt(refIndex, path.node.children);
|
|
708
|
+
|
|
709
|
+
const { name, isArray } = refTag.value;
|
|
710
|
+
let pathDesc = buildPathSegment(name);
|
|
711
|
+
let index;
|
|
712
712
|
if (isArray) {
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
index === -1 ? null : buildReferenceTag(name, index != null, flags, index);
|
|
716
|
-
} else {
|
|
717
|
-
resolvedReference = refTag;
|
|
713
|
+
index = getChildPropertyIndex(path.node, refIndex);
|
|
714
|
+
pathDesc = buildPathSegment(name, index);
|
|
718
715
|
}
|
|
719
716
|
|
|
720
|
-
|
|
721
|
-
|
|
717
|
+
// HMM
|
|
718
|
+
pathDesc.shiftIndex = prevTag.value.height;
|
|
719
|
+
|
|
720
|
+
if (index !== -1) {
|
|
721
|
+
path = path.get([pathDesc]);
|
|
722
722
|
|
|
723
723
|
if (!path) return null;
|
|
724
724
|
|
|
@@ -728,25 +728,30 @@ export class TagPath {
|
|
|
728
728
|
}
|
|
729
729
|
|
|
730
730
|
// over
|
|
731
|
-
if (path.node && childrenIndex + 1 <
|
|
731
|
+
if (path.node && childrenIndex + 1 < Children.getSize(path.node.children)) {
|
|
732
732
|
childrenIndex++;
|
|
733
733
|
continue;
|
|
734
734
|
}
|
|
735
735
|
|
|
736
736
|
// out
|
|
737
|
-
if (path.referenceIndex != null) {
|
|
737
|
+
if (path.referenceIndex != null && path.parent) {
|
|
738
738
|
do {
|
|
739
|
-
if (
|
|
739
|
+
if (
|
|
740
|
+
path.parent &&
|
|
741
|
+
Children.getAt(path.referenceIndex, path.parent.node.children)?.type === ShiftTag
|
|
742
|
+
) {
|
|
740
743
|
childrenIndex =
|
|
741
|
-
|
|
744
|
+
Children.getSize(path.parent.node.children) > path.referenceIndex + 2
|
|
742
745
|
? path.referenceIndex + 2
|
|
743
746
|
: null;
|
|
744
747
|
} else {
|
|
745
|
-
childrenIndex = path.referenceIndex +
|
|
748
|
+
childrenIndex = path.referenceIndex + 2;
|
|
746
749
|
}
|
|
747
750
|
|
|
748
751
|
path = path.parent;
|
|
749
752
|
leaving = true;
|
|
753
|
+
|
|
754
|
+
if (!path) return null;
|
|
750
755
|
} while (childrenIndex == null);
|
|
751
756
|
|
|
752
757
|
leaving = true;
|
|
@@ -763,70 +768,47 @@ export class TagPath {
|
|
|
763
768
|
let leaving = false;
|
|
764
769
|
|
|
765
770
|
for (;;) {
|
|
766
|
-
let tag =
|
|
771
|
+
let tag = Children.getAt(childrenIndex, path.node.children);
|
|
767
772
|
let isInitialTag = path.node === this.path.node && childrenIndex === this.childrenIndex;
|
|
768
773
|
let wasLeaving = leaving;
|
|
769
774
|
leaving = false;
|
|
770
775
|
|
|
771
776
|
if (!tag) return null;
|
|
772
777
|
|
|
778
|
+
if (tag.type === ReferenceTag && tag.value.flags.expression) {
|
|
779
|
+
// look forward for another reference
|
|
780
|
+
let offset = 1;
|
|
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;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
|
|
773
793
|
// done
|
|
774
|
-
if (
|
|
775
|
-
!isInitialTag &&
|
|
776
|
-
tag.type !== EmbeddedNode &&
|
|
777
|
-
tag.type !== ShiftTag &&
|
|
778
|
-
(tag.type !== GapTag || isGapNode(path.node))
|
|
779
|
-
) {
|
|
794
|
+
if (!isInitialTag && tag.type !== Property) {
|
|
780
795
|
return new TagPath(path, childrenIndex);
|
|
781
796
|
}
|
|
782
797
|
|
|
783
798
|
// in
|
|
784
|
-
if (
|
|
785
|
-
|
|
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);
|
|
786
806
|
childrenIndex = 0;
|
|
787
807
|
continue;
|
|
788
808
|
}
|
|
789
809
|
|
|
790
|
-
// in
|
|
791
|
-
if (tag.type === GapTag && !wasLeaving && !isGapNode(path.node)) {
|
|
792
|
-
let refIndex = childrenIndex - 1;
|
|
793
|
-
let refTag;
|
|
794
|
-
let prevTag = sumtree.getAt(childrenIndex - 1, path.node.children);
|
|
795
|
-
|
|
796
|
-
if (prevTag.type === ShiftTag) {
|
|
797
|
-
// continue
|
|
798
|
-
} else if (prevTag.type === ReferenceTag) {
|
|
799
|
-
refTag = prevTag;
|
|
800
|
-
|
|
801
|
-
if (
|
|
802
|
-
!['#', '@'].includes(refTag.value.name) &&
|
|
803
|
-
(!refTag.value.isArray || getChildPropertyIndex(path.node, refIndex) != null)
|
|
804
|
-
) {
|
|
805
|
-
const { name, isArray, flags } = refTag.value;
|
|
806
|
-
let resolvedReference = refTag;
|
|
807
|
-
if (isArray) {
|
|
808
|
-
let index = getChildPropertyIndex(path.node, refIndex);
|
|
809
|
-
resolvedReference =
|
|
810
|
-
index === -1 ? null : buildReferenceTag(name, index != null, flags, index);
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
if (resolvedReference) {
|
|
814
|
-
path = path.get(resolvedReference);
|
|
815
|
-
childrenIndex = 0;
|
|
816
|
-
|
|
817
|
-
if (!path) {
|
|
818
|
-
return null;
|
|
819
|
-
}
|
|
820
|
-
continue;
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
} else {
|
|
824
|
-
throw new Error();
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
|
|
828
810
|
// over
|
|
829
|
-
if (path.node && childrenIndex + 1 <
|
|
811
|
+
if (path.node && childrenIndex + 1 < Children.getSize(path.node.children)) {
|
|
830
812
|
childrenIndex++;
|
|
831
813
|
continue;
|
|
832
814
|
}
|
|
@@ -834,7 +816,7 @@ export class TagPath {
|
|
|
834
816
|
// out
|
|
835
817
|
if (path.referenceIndex != null) {
|
|
836
818
|
do {
|
|
837
|
-
childrenIndex = path.referenceIndex +
|
|
819
|
+
childrenIndex = path.referenceIndex + 2;
|
|
838
820
|
|
|
839
821
|
path = path.parent;
|
|
840
822
|
leaving = true;
|
|
@@ -866,7 +848,7 @@ export class TagPath {
|
|
|
866
848
|
let leaving = false;
|
|
867
849
|
|
|
868
850
|
for (;;) {
|
|
869
|
-
let tag =
|
|
851
|
+
let tag = Children.getAt(childrenIndex, path.node.children);
|
|
870
852
|
let isInitialTag = path.node === this.path.node && childrenIndex === this.childrenIndex;
|
|
871
853
|
let wasLeaving = leaving;
|
|
872
854
|
leaving = false;
|
|
@@ -874,62 +856,19 @@ export class TagPath {
|
|
|
874
856
|
if (!tag) return null;
|
|
875
857
|
|
|
876
858
|
// done
|
|
877
|
-
if (
|
|
878
|
-
!isInitialTag &&
|
|
879
|
-
tag.type !== EmbeddedNode &&
|
|
880
|
-
tag.type !== ShiftTag &&
|
|
881
|
-
(tag.type !== GapTag || isGapNode(path.node))
|
|
882
|
-
) {
|
|
859
|
+
if (!isInitialTag && tag.type !== ShiftTag && tag.type !== Property) {
|
|
883
860
|
return new TagPath(path, childrenIndex);
|
|
884
861
|
}
|
|
885
862
|
|
|
886
863
|
// in
|
|
887
|
-
if (tag.type ===
|
|
888
|
-
path = path.push(tag.value, childrenIndex - 1);
|
|
889
|
-
childrenIndex =
|
|
864
|
+
if (tag.type === Property && !wasLeaving) {
|
|
865
|
+
path = path.push(tag.value.node, childrenIndex - 1);
|
|
866
|
+
childrenIndex = Children.getSize(tag.value.children) - 1;
|
|
890
867
|
continue;
|
|
891
868
|
}
|
|
892
869
|
|
|
893
|
-
// in
|
|
894
|
-
if (tag.type === GapTag && !wasLeaving && !isGapNode(path.node)) {
|
|
895
|
-
let refIndex = childrenIndex - 1;
|
|
896
|
-
let refTag;
|
|
897
|
-
let prevTag = sumtree.getAt(childrenIndex - 1, path.node.children);
|
|
898
|
-
|
|
899
|
-
if (prevTag.type === ShiftTag) {
|
|
900
|
-
// continue
|
|
901
|
-
} else if (prevTag.type === ReferenceTag) {
|
|
902
|
-
refTag = prevTag;
|
|
903
|
-
|
|
904
|
-
if (
|
|
905
|
-
!['#', '@'].includes(refTag.value.name) &&
|
|
906
|
-
(!refTag.value.isArray || getChildPropertyIndex(path.node, refIndex) != null)
|
|
907
|
-
) {
|
|
908
|
-
const { name, isArray, flags } = refTag.value;
|
|
909
|
-
let resolvedReference = refTag;
|
|
910
|
-
if (isArray) {
|
|
911
|
-
let index = getChildPropertyIndex(path.node, refIndex);
|
|
912
|
-
resolvedReference =
|
|
913
|
-
index === -1 ? null : buildReferenceTag(name, index != null, flags, index);
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
if (resolvedReference) {
|
|
917
|
-
path = path.get(resolvedReference);
|
|
918
|
-
childrenIndex = 0;
|
|
919
|
-
|
|
920
|
-
if (!path) {
|
|
921
|
-
return null;
|
|
922
|
-
}
|
|
923
|
-
continue;
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
} else {
|
|
927
|
-
throw new Error();
|
|
928
|
-
}
|
|
929
|
-
}
|
|
930
|
-
|
|
931
870
|
// over
|
|
932
|
-
if (path.node && childrenIndex + 1 <
|
|
871
|
+
if (path.node && childrenIndex + 1 < Children.getSize(path.node.children)) {
|
|
933
872
|
childrenIndex--;
|
|
934
873
|
continue;
|
|
935
874
|
}
|
|
@@ -951,38 +890,37 @@ export class TagPath {
|
|
|
951
890
|
}
|
|
952
891
|
}
|
|
953
892
|
|
|
954
|
-
get
|
|
955
|
-
return this.
|
|
893
|
+
get innerNode() {
|
|
894
|
+
return this.inner?.node;
|
|
956
895
|
}
|
|
957
896
|
|
|
958
|
-
get
|
|
959
|
-
let { tag, previousSibling
|
|
897
|
+
get inner() {
|
|
898
|
+
let { tag, previousSibling } = this;
|
|
899
|
+
|
|
900
|
+
let refPath = previousSibling?.previousSibling;
|
|
960
901
|
|
|
961
|
-
if (tag.type !==
|
|
902
|
+
if (tag.type !== Property) {
|
|
962
903
|
return null;
|
|
963
904
|
}
|
|
964
905
|
|
|
965
906
|
let shiftPath = null;
|
|
966
907
|
if (refPath.tag.type === ShiftTag) {
|
|
967
908
|
shiftPath = refPath;
|
|
968
|
-
refPath = TagPath.from(this.path, this.childrenIndex - refPath.tag.value.index *
|
|
909
|
+
refPath = TagPath.from(this.path, this.childrenIndex - refPath.tag.value.index * 3 - 2);
|
|
969
910
|
}
|
|
970
911
|
|
|
971
912
|
if (refPath.tag.type !== ReferenceTag) throw new Error();
|
|
972
913
|
|
|
973
|
-
|
|
914
|
+
const { type, name } = refPath.tag.value;
|
|
974
915
|
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
916
|
+
return this.path.get([
|
|
917
|
+
buildFullPathSegment(
|
|
918
|
+
type,
|
|
978
919
|
name,
|
|
979
|
-
isArray,
|
|
980
|
-
flags,
|
|
981
920
|
getChildPropertyIndex(refPath.path.node, refPath.childrenIndex),
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
return this.path.get(resolvedRef, shiftPath?.tag.value.index);
|
|
921
|
+
shiftPath?.tag.value.index,
|
|
922
|
+
),
|
|
923
|
+
]);
|
|
986
924
|
}
|
|
987
925
|
|
|
988
926
|
equalTo(tagPath) {
|