@bablr/agast-helpers 0.8.0 → 0.9.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 +62 -44
- package/lib/path-facade.js +18 -13
- package/lib/path.js +631 -345
- package/lib/print.js +34 -20
- package/lib/shorthand.js +1 -1
- package/lib/stream.js +37 -165
- package/lib/symbols.js +3 -1
- package/lib/tags.js +236 -0
- package/lib/template.js +11 -7
- package/lib/tree.js +224 -292
- package/package.json +6 -4
- package/lib/children.js +0 -120
package/lib/print.js
CHANGED
|
@@ -10,18 +10,15 @@ import {
|
|
|
10
10
|
LiteralTag,
|
|
11
11
|
AttributeDefinition,
|
|
12
12
|
BindingTag,
|
|
13
|
+
Document,
|
|
13
14
|
} from './symbols.js';
|
|
14
|
-
import { referenceFlags } from './
|
|
15
|
+
import { referenceFlags } from './builders.js';
|
|
15
16
|
|
|
16
17
|
let { isInteger, isFinite } = Number;
|
|
17
18
|
let { isArray } = Array;
|
|
18
19
|
let isString = (val) => typeof val === 'string';
|
|
19
20
|
let isNumber = (val) => typeof val === 'number';
|
|
20
21
|
let isObject = (val) => val && typeof val === 'object' && !isArray(val);
|
|
21
|
-
let isFunction = (val) => typeof val === 'function';
|
|
22
|
-
|
|
23
|
-
let when = (condition, value) =>
|
|
24
|
-
condition ? (isFunction(value) ? value() : value) : { *[Symbol.iterator]() {} };
|
|
25
22
|
|
|
26
23
|
export const printArray = (arr) => `[${arr.map((v) => printExpression(v)).join(', ')}]`;
|
|
27
24
|
|
|
@@ -122,23 +119,29 @@ export const printShiftTag = (tag) => {
|
|
|
122
119
|
return `^^^`;
|
|
123
120
|
};
|
|
124
121
|
|
|
125
|
-
export const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
let { type, name, isArray, flags } = tag.value;
|
|
122
|
+
export const printReference = (ref) => {
|
|
123
|
+
let { type, name, isArray, flags } = ref;
|
|
129
124
|
let pathBraces = isArray ? `[]` : '';
|
|
130
125
|
|
|
131
|
-
if (type && name) throw new Error();
|
|
132
|
-
if (type && !['.', '#', '@'].includes(type)) throw new Error();
|
|
126
|
+
if (type && type !== '#' && name) throw new Error();
|
|
127
|
+
if (type && !['.', '#', '@', '_'].includes(type)) throw new Error();
|
|
133
128
|
|
|
134
|
-
return `${type || printIdentifier(name) || ''}${pathBraces}${printReferenceFlags(flags)}:`;
|
|
129
|
+
return `${type || ''}${printIdentifier(name) || ''}${pathBraces}${printReferenceFlags(flags)}:`;
|
|
135
130
|
};
|
|
136
131
|
|
|
137
|
-
export const
|
|
138
|
-
let { languagePath } =
|
|
132
|
+
export const printBinding = (binding) => {
|
|
133
|
+
let { languagePath } = binding;
|
|
139
134
|
return `:${languagePath ? printIdentifierPath(languagePath) : ''}:`;
|
|
140
135
|
};
|
|
141
136
|
|
|
137
|
+
export const printReferenceTag = (tag) => {
|
|
138
|
+
return printReference(tag.value);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export const printBindingTag = (tag) => {
|
|
142
|
+
return printBinding(tag.value);
|
|
143
|
+
};
|
|
144
|
+
|
|
142
145
|
export const printNullTag = (tag) => {
|
|
143
146
|
if (tag && tag.type !== NullTag) {
|
|
144
147
|
throw new Error();
|
|
@@ -181,35 +184,45 @@ export const printReferenceFlags = (flags = referenceFlags) => {
|
|
|
181
184
|
|
|
182
185
|
export const printNodeFlags = (flags) => {
|
|
183
186
|
if (flags.cover && !flags.fragment) throw new Error();
|
|
187
|
+
|
|
184
188
|
let star = flags.token ? '*' : '';
|
|
185
189
|
let dollar = flags.hasGap ? '$' : '';
|
|
190
|
+
let fragment = flags.fragment ? '_' : '';
|
|
191
|
+
let multiFragment = fragment && !flags.cover ? '_' : '';
|
|
186
192
|
|
|
187
|
-
return `${star}${dollar}`;
|
|
193
|
+
return `${star}${dollar}${fragment}${multiFragment}`;
|
|
188
194
|
};
|
|
189
195
|
|
|
190
196
|
export const printOpenNodeTag = (tag) => {
|
|
191
197
|
if (tag?.type !== OpenNodeTag) throw new Error();
|
|
192
198
|
|
|
193
|
-
let { flags, type, attributes } = tag.value;
|
|
199
|
+
let { flags, type, literalValue, attributes, selfClosing } = tag.value;
|
|
200
|
+
|
|
201
|
+
if (!type && !flags.fragment) throw new Error();
|
|
202
|
+
if (literalValue && !selfClosing) throw new Error();
|
|
194
203
|
|
|
195
204
|
if (!type) {
|
|
196
|
-
return `<${printNodeFlags(flags)}
|
|
205
|
+
return `<${printNodeFlags(flags)}>`;
|
|
197
206
|
}
|
|
198
207
|
|
|
199
208
|
let printedAttributes = printAttributes(attributes);
|
|
200
209
|
let attributesFrag = printedAttributes ? ` ${printedAttributes}` : '';
|
|
210
|
+
let literalFrag = literalValue ? ` ${printString(literalValue)}` : '';
|
|
211
|
+
let selfClosingFrag = selfClosing ? ' /' : '';
|
|
201
212
|
|
|
202
|
-
return `<${printNodeFlags(flags)}${printType(
|
|
213
|
+
return `<${printNodeFlags(flags)}${printType(
|
|
214
|
+
type,
|
|
215
|
+
)}${literalFrag}${attributesFrag}${selfClosingFrag}>`;
|
|
203
216
|
};
|
|
204
217
|
|
|
205
|
-
export const printSelfClosingNodeTag = (tag,
|
|
218
|
+
export const printSelfClosingNodeTag = (tag, literalValue) => {
|
|
206
219
|
if (tag?.type !== OpenNodeTag) throw new Error();
|
|
207
220
|
|
|
208
221
|
let { flags, type, attributes } = tag.value;
|
|
209
222
|
|
|
210
223
|
let printedAttributes = printAttributes(attributes);
|
|
211
224
|
let attributesFrag = printedAttributes ? ` ${printedAttributes}` : '';
|
|
212
|
-
let intrinsicFrag =
|
|
225
|
+
let intrinsicFrag = literalValue ? ` ${printString(literalValue)}` : '';
|
|
213
226
|
|
|
214
227
|
return `<${printNodeFlags(flags)}${printType(type)}${intrinsicFrag}${attributesFrag} />`;
|
|
215
228
|
};
|
|
@@ -222,6 +235,7 @@ export const printCloseNodeTag = (tag) => {
|
|
|
222
235
|
|
|
223
236
|
export const printAttributeDefinition = (tag) => {
|
|
224
237
|
if (tag?.type !== AttributeDefinition) throw new Error();
|
|
238
|
+
if (!tag.value.path?.length) throw new Error();
|
|
225
239
|
let { path, value } = tag.value;
|
|
226
240
|
|
|
227
241
|
return `{ ${printIdentifierPath(path)}: ${printExpression(value)} }`;
|
package/lib/shorthand.js
CHANGED
|
@@ -31,7 +31,7 @@ export const parseReference = (str) => {
|
|
|
31
31
|
4: index,
|
|
32
32
|
5: expressionToken,
|
|
33
33
|
6: hasGapToken,
|
|
34
|
-
} = /^\s*(?:([.#@])|([a-zA-Z\u{80}-\u{10ffff}][a-zA-Z0-9_\u{80}-\u{10ffff}-]*))\s*(\[\s*(\d+\s*)?\])?\s*(\+)?(\$)?\s*$/u.exec(
|
|
34
|
+
} = /^\s*(?:([.#@_])|([a-zA-Z\u{80}-\u{10ffff}][a-zA-Z0-9_\u{80}-\u{10ffff}-]*))\s*(\[\s*(\d+\s*)?\])?\s*(\+)?(\$)?\s*$/u.exec(
|
|
35
35
|
str,
|
|
36
36
|
);
|
|
37
37
|
|
package/lib/stream.js
CHANGED
|
@@ -1,153 +1,25 @@
|
|
|
1
1
|
import { Coroutine } from '@bablr/coroutine';
|
|
2
2
|
import emptyStack from '@iter-tools/imm-stack';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { getStreamIterator, StreamIterable, StreamGenerator } from '@bablr/stream-iterator';
|
|
4
|
+
import { printTag } from './print.js';
|
|
5
|
+
import { buildOpenNodeTag } from './builders.js';
|
|
5
6
|
import {
|
|
6
|
-
DoctypeTag,
|
|
7
7
|
OpenNodeTag,
|
|
8
8
|
CloseNodeTag,
|
|
9
9
|
ReferenceTag,
|
|
10
|
-
ShiftTag,
|
|
11
10
|
GapTag,
|
|
12
11
|
NullTag,
|
|
13
12
|
InitializerTag,
|
|
14
13
|
LiteralTag,
|
|
15
|
-
TokenGroup,
|
|
16
14
|
BindingTag,
|
|
15
|
+
DoctypeTag,
|
|
16
|
+
ShiftTag,
|
|
17
17
|
AttributeDefinition,
|
|
18
18
|
} from './symbols.js';
|
|
19
19
|
|
|
20
|
-
export
|
|
21
|
-
|
|
22
|
-
export const getStreamIterator = (obj) => {
|
|
23
|
-
return obj[Symbol.for('@@streamIterator')]?.() || obj[Symbol.iterator]?.();
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export class SyncGenerator {
|
|
27
|
-
constructor(embeddedGenerator) {
|
|
28
|
-
if (!embeddedGenerator.next) throw new Error();
|
|
29
|
-
|
|
30
|
-
this.generator = embeddedGenerator;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
next(value) {
|
|
34
|
-
const step = this.generator.next(value);
|
|
35
|
-
|
|
36
|
-
if (step instanceof Promise) {
|
|
37
|
-
throw new Error('invalid embedded generator');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (step.done) {
|
|
41
|
-
return step;
|
|
42
|
-
} else if (step.value instanceof Promise) {
|
|
43
|
-
throw new Error('sync generators cannot resolve promises');
|
|
44
|
-
} else {
|
|
45
|
-
return step;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return(value) {
|
|
50
|
-
const step = this.generator.return(value);
|
|
51
|
-
if (step instanceof Promise) {
|
|
52
|
-
throw new Error('invalid embedded generator');
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (step.value instanceof Promise) {
|
|
56
|
-
throw new Error('sync generators cannot resolve promises');
|
|
57
|
-
}
|
|
58
|
-
return step;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
[Symbol.iterator]() {
|
|
62
|
-
return this;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export class AsyncGenerator {
|
|
67
|
-
constructor(embeddedGenerator) {
|
|
68
|
-
this.generator = embeddedGenerator;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
next(value) {
|
|
72
|
-
const step = this.generator.next(value);
|
|
73
|
-
|
|
74
|
-
if (step instanceof Promise) {
|
|
75
|
-
throw new Error('invalid embedded generator');
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (step.done) {
|
|
79
|
-
return Promise.resolve(step);
|
|
80
|
-
} else if (step.value instanceof Promise) {
|
|
81
|
-
return step.value.then((value) => {
|
|
82
|
-
return this.next(value);
|
|
83
|
-
});
|
|
84
|
-
} else {
|
|
85
|
-
return Promise.resolve(step);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return(value) {
|
|
90
|
-
const result = this.generator.return(value);
|
|
91
|
-
if (result instanceof Promise) {
|
|
92
|
-
throw new Error('sync generators cannot resolve promises');
|
|
93
|
-
}
|
|
94
|
-
return result;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
[Symbol.asyncIterator]() {
|
|
98
|
-
return this;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export class StreamGenerator {
|
|
103
|
-
constructor(embeddedGenerator) {
|
|
104
|
-
this.generator = embeddedGenerator;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
next(value) {
|
|
108
|
-
const step = this.generator.next(value);
|
|
109
|
-
|
|
110
|
-
if (step.done) {
|
|
111
|
-
return step;
|
|
112
|
-
} else if (step.value instanceof Promise) {
|
|
113
|
-
return step.value.then((value) => {
|
|
114
|
-
return this.next(value);
|
|
115
|
-
});
|
|
116
|
-
} else {
|
|
117
|
-
return step;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return(value) {
|
|
122
|
-
return this.generator.return(value);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
[Symbol.iterator]() {
|
|
126
|
-
return this;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
[Symbol.for('@@streamIterator')]() {
|
|
130
|
-
return this;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export class StreamIterable {
|
|
135
|
-
constructor(embeddedStreamIterable) {
|
|
136
|
-
this.iterable = embeddedStreamIterable;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
[Symbol.iterator]() {
|
|
140
|
-
return new SyncGenerator(this.iterable);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
[Symbol.asyncIterator]() {
|
|
144
|
-
return new AsyncGenerator(this.iterable);
|
|
145
|
-
}
|
|
20
|
+
export { getStreamIterator, StreamIterable, StreamGenerator };
|
|
146
21
|
|
|
147
|
-
|
|
148
|
-
return new StreamGenerator(this.iterable);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
22
|
+
export * from './print.js';
|
|
151
23
|
|
|
152
24
|
export const maybeWait = (maybePromise, callback) => {
|
|
153
25
|
if (maybePromise instanceof Promise) {
|
|
@@ -181,6 +53,8 @@ function* __isEmpty(tags) {
|
|
|
181
53
|
case OpenNodeTag:
|
|
182
54
|
++depth;
|
|
183
55
|
|
|
56
|
+
if (tag.value.literalValue) return false;
|
|
57
|
+
|
|
184
58
|
if (depth === 0 && ref.value.type === '@') {
|
|
185
59
|
return false;
|
|
186
60
|
}
|
|
@@ -224,9 +98,9 @@ export const asyncStringFromStream = async (stream) => {
|
|
|
224
98
|
|
|
225
99
|
if (co.done) break;
|
|
226
100
|
|
|
227
|
-
const
|
|
101
|
+
const chr = co.value;
|
|
228
102
|
|
|
229
|
-
str +=
|
|
103
|
+
str += chr;
|
|
230
104
|
}
|
|
231
105
|
|
|
232
106
|
return str;
|
|
@@ -277,12 +151,7 @@ function* __generateCSTML(tags, options) {
|
|
|
277
151
|
continue;
|
|
278
152
|
}
|
|
279
153
|
|
|
280
|
-
|
|
281
|
-
const intrinsicValue = getCooked(tag.value);
|
|
282
|
-
yield* printSelfClosingNodeTag(tag.value[0], intrinsicValue);
|
|
283
|
-
} else {
|
|
284
|
-
yield* printTag(tag);
|
|
285
|
-
}
|
|
154
|
+
yield* printTag(tag);
|
|
286
155
|
|
|
287
156
|
prevTag = tag;
|
|
288
157
|
}
|
|
@@ -353,8 +222,14 @@ function* __prettyGroupTags(tags) {
|
|
|
353
222
|
|
|
354
223
|
if (tag.type === CloseNodeTag) {
|
|
355
224
|
if (!state.broken && (isToken(state.open) || state.holding.length === 1)) {
|
|
356
|
-
state.holding.
|
|
357
|
-
|
|
225
|
+
let { flags, type, attributes } = state.holding[0].value;
|
|
226
|
+
|
|
227
|
+
let literal = state.holding
|
|
228
|
+
.slice(1)
|
|
229
|
+
.map((lit) => lit.value)
|
|
230
|
+
.join('');
|
|
231
|
+
|
|
232
|
+
yield buildOpenNodeTag(flags, type, attributes, literal, true);
|
|
358
233
|
} else {
|
|
359
234
|
if (state.holding.length) {
|
|
360
235
|
yield* state.holding;
|
|
@@ -367,9 +242,13 @@ function* __prettyGroupTags(tags) {
|
|
|
367
242
|
}
|
|
368
243
|
|
|
369
244
|
if (tag.type === OpenNodeTag) {
|
|
370
|
-
|
|
245
|
+
if (tag.value.literalValue) {
|
|
246
|
+
yield tag;
|
|
247
|
+
} else {
|
|
248
|
+
states = states.push({ holding: [tag], broken: false, open: tag });
|
|
371
249
|
|
|
372
|
-
|
|
250
|
+
state = states.value;
|
|
251
|
+
}
|
|
373
252
|
}
|
|
374
253
|
}
|
|
375
254
|
}
|
|
@@ -415,7 +294,7 @@ function* __generatePrettyCSTML(tags, options) {
|
|
|
415
294
|
tag.type === GapTag ||
|
|
416
295
|
tag.type === BindingTag ||
|
|
417
296
|
tag.type === InitializerTag ||
|
|
418
|
-
tag.type ===
|
|
297
|
+
(tag.type === OpenNodeTag && tag.value.selfClosing));
|
|
419
298
|
|
|
420
299
|
if (!first && !inline) {
|
|
421
300
|
yield* '\n';
|
|
@@ -428,23 +307,12 @@ function* __generatePrettyCSTML(tags, options) {
|
|
|
428
307
|
}
|
|
429
308
|
|
|
430
309
|
if (!inline) {
|
|
431
|
-
yield* indent.repeat(indentLevel);
|
|
310
|
+
yield* indent.repeat(Math.max(0, indentLevel));
|
|
432
311
|
} else {
|
|
433
312
|
yield* ' ';
|
|
434
313
|
}
|
|
435
314
|
|
|
436
|
-
|
|
437
|
-
ref = null;
|
|
438
|
-
const intrinsicValue = tag.value[0].value.flags.token ? getCooked(tag.value) : null;
|
|
439
|
-
let openTag = tag.value[0];
|
|
440
|
-
let { flags, type, attributes } = openTag.value;
|
|
441
|
-
yield* printSelfClosingNodeTag(buildOpenNodeTag(flags, type, attributes), intrinsicValue);
|
|
442
|
-
} else if (tag.type === OpenNodeTag) {
|
|
443
|
-
let { flags, type, attributes } = tag.value;
|
|
444
|
-
yield* printTag(buildOpenNodeTag(flags, type, attributes));
|
|
445
|
-
} else {
|
|
446
|
-
yield* printTag(tag);
|
|
447
|
-
}
|
|
315
|
+
yield* printTag(tag);
|
|
448
316
|
|
|
449
317
|
if (tag.type === ReferenceTag) {
|
|
450
318
|
inline = true;
|
|
@@ -452,7 +320,7 @@ function* __generatePrettyCSTML(tags, options) {
|
|
|
452
320
|
}
|
|
453
321
|
|
|
454
322
|
if (tag.type === OpenNodeTag) {
|
|
455
|
-
indentLevel
|
|
323
|
+
indentLevel += tag.value.selfClosing ? 0 : 1;
|
|
456
324
|
}
|
|
457
325
|
|
|
458
326
|
first = false;
|
|
@@ -494,9 +362,9 @@ export const getCooked = (tags) => {
|
|
|
494
362
|
}
|
|
495
363
|
|
|
496
364
|
case OpenNodeTag: {
|
|
497
|
-
const { flags, attributes } = tag.value;
|
|
365
|
+
const { flags, attributes, literalValue, selfClosing } = tag.value;
|
|
498
366
|
|
|
499
|
-
depth
|
|
367
|
+
depth += selfClosing ? 0 : 1;
|
|
500
368
|
|
|
501
369
|
if (first) {
|
|
502
370
|
if (flags.token) {
|
|
@@ -516,6 +384,8 @@ export const getCooked = (tags) => {
|
|
|
516
384
|
if (!cookedValue) throw new Error('cannot cook string: it contains uncooked escapes');
|
|
517
385
|
|
|
518
386
|
cooked += cookedValue;
|
|
387
|
+
} else if (literalValue) {
|
|
388
|
+
cooked += literalValue;
|
|
519
389
|
}
|
|
520
390
|
|
|
521
391
|
break;
|
|
@@ -553,7 +423,9 @@ export const printSource = (tags) => {
|
|
|
553
423
|
if (!tags) return printed;
|
|
554
424
|
|
|
555
425
|
for (const tag of tags) {
|
|
556
|
-
if (tag.type ===
|
|
426
|
+
if (tag.type === OpenNodeTag && tag.value.literalValue) {
|
|
427
|
+
printed += tag.value.literalValue;
|
|
428
|
+
} else if (tag.type === LiteralTag) {
|
|
557
429
|
printed += tag.value;
|
|
558
430
|
} else if (tag.type === GapTag) {
|
|
559
431
|
throw new Error('use generateSourceTextFor');
|
package/lib/symbols.js
CHANGED
|
@@ -10,6 +10,8 @@ export const InitializerTag = Symbol.for('InitializerTag');
|
|
|
10
10
|
export const AttributeDefinition = Symbol.for('AttributeDefinition');
|
|
11
11
|
export const LiteralTag = Symbol.for('LiteralTag');
|
|
12
12
|
|
|
13
|
-
export const
|
|
13
|
+
export const Document = Symbol.for('Document');
|
|
14
|
+
export const Node = Symbol.for('Node');
|
|
14
15
|
|
|
15
16
|
export const Property = Symbol.for('Property');
|
|
17
|
+
export const PropertyWrapper = Symbol.for('PropertyWrapper');
|
package/lib/tags.js
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { buildModule, defaultNodeSize } from '@bablr/btree/enhanceable';
|
|
2
|
+
import { CloseNodeTag, LiteralTag, OpenNodeTag, PropertyWrapper, ReferenceTag } from './symbols.js';
|
|
3
|
+
import { isObject } from './object.js';
|
|
4
|
+
|
|
5
|
+
const { isArray } = Array;
|
|
6
|
+
const { freeze } = Object;
|
|
7
|
+
|
|
8
|
+
export { defaultNodeSize };
|
|
9
|
+
|
|
10
|
+
const __getAtName = (name, sortedArray, startIdx = 0, endIdx = sortedArray.length - 1) => {
|
|
11
|
+
if (!sortedArray.length || endIdx < startIdx) return null;
|
|
12
|
+
|
|
13
|
+
let idx = startIdx + Math.floor((endIdx - startIdx) / 2 + 0.1);
|
|
14
|
+
let entry = sortedArray[idx];
|
|
15
|
+
let { 0: key, 1: value } = entry;
|
|
16
|
+
|
|
17
|
+
let direction = compareNames(name, key);
|
|
18
|
+
|
|
19
|
+
if (direction === 0) {
|
|
20
|
+
return value;
|
|
21
|
+
} else {
|
|
22
|
+
if (startIdx === endIdx) return null;
|
|
23
|
+
|
|
24
|
+
if (direction > 0) {
|
|
25
|
+
return __getAtName(name, sortedArray, idx + 1, endIdx);
|
|
26
|
+
} else {
|
|
27
|
+
return __getAtName(name, sortedArray, startIdx, idx - 1);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const getAtName = (name, sortedArray, startIdx = 0, endIdx = sortedArray.length - 1) => {
|
|
33
|
+
return __getAtName(name, sortedArray, startIdx, endIdx);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const compareNames = (a, b) => (a > b ? 1 : b > a ? -1 : 0);
|
|
37
|
+
|
|
38
|
+
const module_ = buildModule(
|
|
39
|
+
defaultNodeSize,
|
|
40
|
+
(acc, val) => {
|
|
41
|
+
const { references, specialTypes } = acc;
|
|
42
|
+
if (isArray(val)) {
|
|
43
|
+
acc.lineBreaks += getSums(val).lineBreaks;
|
|
44
|
+
|
|
45
|
+
for (const { 0: key, 1: value } of getSums(val).references) {
|
|
46
|
+
references.set(key, (references.get(key) ?? 0) + value);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
for (const { 0: key, 1: value } of getSums(val).specialTypes) {
|
|
50
|
+
specialTypes.set(key, (specialTypes.get(key) ?? 0) + value);
|
|
51
|
+
}
|
|
52
|
+
} else if (val) {
|
|
53
|
+
if (val.type === LiteralTag) {
|
|
54
|
+
let text = val.value;
|
|
55
|
+
let idx = 0;
|
|
56
|
+
while ((idx = text.indexOf('\n', idx + 1)) >= 0) {
|
|
57
|
+
acc.lineBreaks++;
|
|
58
|
+
}
|
|
59
|
+
} else if (val.type === PropertyWrapper) {
|
|
60
|
+
let { tags } = val.value;
|
|
61
|
+
let refOrShiftTag = tags[0];
|
|
62
|
+
|
|
63
|
+
if (refOrShiftTag.type === ReferenceTag) {
|
|
64
|
+
const { type, name } = refOrShiftTag.value;
|
|
65
|
+
if (name) {
|
|
66
|
+
references.set(name, (references.get(name) ?? 0) + 1);
|
|
67
|
+
} else {
|
|
68
|
+
specialTypes.set(type, (specialTypes.get(type) ?? 0) + 1);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return acc;
|
|
74
|
+
},
|
|
75
|
+
() => ({
|
|
76
|
+
lineBreaks: 0,
|
|
77
|
+
references: new Map(),
|
|
78
|
+
specialTypes: new Map(),
|
|
79
|
+
}),
|
|
80
|
+
(mapStats) => {
|
|
81
|
+
let { lineBreaks } = mapStats;
|
|
82
|
+
let stats = {
|
|
83
|
+
lineBreaks,
|
|
84
|
+
references: [...mapStats.references].sort((a, b) => compareNames(a[0], b[0])),
|
|
85
|
+
specialTypes: [...mapStats.specialTypes].sort((a, b) => compareNames(a[0], b[0])),
|
|
86
|
+
};
|
|
87
|
+
freeze(stats);
|
|
88
|
+
freeze(stats.references);
|
|
89
|
+
freeze(stats.specialTypes);
|
|
90
|
+
return stats;
|
|
91
|
+
},
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
const {
|
|
95
|
+
from,
|
|
96
|
+
fromValues,
|
|
97
|
+
addAt,
|
|
98
|
+
isValidNode,
|
|
99
|
+
assertValidNode,
|
|
100
|
+
getValues,
|
|
101
|
+
getSums,
|
|
102
|
+
setValues,
|
|
103
|
+
traverse,
|
|
104
|
+
getSize,
|
|
105
|
+
findPath,
|
|
106
|
+
} = module_;
|
|
107
|
+
|
|
108
|
+
const getAt = (idx, tags, wrapperIndex) => {
|
|
109
|
+
let result = module_.getAt(idx, tags);
|
|
110
|
+
return wrapperIndex == null || result?.type !== PropertyWrapper
|
|
111
|
+
? result
|
|
112
|
+
: result.value.tags[wrapperIndex];
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const push = (tags, tag) => {
|
|
116
|
+
let firstTag = getAt(0, tags);
|
|
117
|
+
if (isArray(tag)) {
|
|
118
|
+
if (!firstTag || firstTag.type !== OpenNodeTag) {
|
|
119
|
+
return module_.concat(tags, tag);
|
|
120
|
+
}
|
|
121
|
+
let children = getValues(tags)[1] ?? module_.fromValues([]);
|
|
122
|
+
|
|
123
|
+
let { 0: open } = getValues(tags);
|
|
124
|
+
|
|
125
|
+
children = module_.concat(children, tag);
|
|
126
|
+
|
|
127
|
+
return module_.fromValues([open, children]);
|
|
128
|
+
} else {
|
|
129
|
+
if (tag.type === OpenNodeTag) {
|
|
130
|
+
if (getSize(tags) !== 0) throw new Error();
|
|
131
|
+
return module_.push(tags, tag);
|
|
132
|
+
} else {
|
|
133
|
+
if (!firstTag || firstTag.type !== OpenNodeTag) {
|
|
134
|
+
return module_.push(tags, tag);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
let children = getValues(tags)[1] ?? [];
|
|
138
|
+
|
|
139
|
+
// sometimes this is the top level
|
|
140
|
+
if (firstTag) {
|
|
141
|
+
if (tag.type === CloseNodeTag) {
|
|
142
|
+
let { 0: open, 1: children = module_.fromValues([]) } = getValues(tags);
|
|
143
|
+
|
|
144
|
+
return module_.fromValues([open, children, tag]);
|
|
145
|
+
} else {
|
|
146
|
+
let { 0: open } = getValues(tags);
|
|
147
|
+
|
|
148
|
+
children = module_.push(children, tag);
|
|
149
|
+
|
|
150
|
+
return module_.fromValues([open, children]);
|
|
151
|
+
}
|
|
152
|
+
} else {
|
|
153
|
+
return module_.push(tags, tag);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const replaceAt = (idx, tree, value) => {
|
|
160
|
+
let idx_ = idx < 0 ? getSize(tree) + idx : idx;
|
|
161
|
+
|
|
162
|
+
if (value.type !== getAt(idx_, tree).type) throw new Error();
|
|
163
|
+
let firstTag = getAt(0, tree);
|
|
164
|
+
|
|
165
|
+
if (firstTag && firstTag.type === OpenNodeTag) {
|
|
166
|
+
let newTags = [...getValues(tree)];
|
|
167
|
+
if (idx_ === 0) {
|
|
168
|
+
newTags[0] = value;
|
|
169
|
+
} else if (isObject(value) && value.type === CloseNodeTag) {
|
|
170
|
+
if (idx_ !== getSize(tree) - 1) throw new Error();
|
|
171
|
+
newTags[2] = value;
|
|
172
|
+
} else {
|
|
173
|
+
let children = getValues(tree)[1];
|
|
174
|
+
|
|
175
|
+
children = module_.replaceAt(idx_ - 1, children, value);
|
|
176
|
+
|
|
177
|
+
newTags[1] = children;
|
|
178
|
+
}
|
|
179
|
+
return module_.fromValues(newTags);
|
|
180
|
+
} else {
|
|
181
|
+
return module_.replaceAt(idx_, tree, value);
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const removeAt = (idx, tree) => {
|
|
186
|
+
let idx_ = idx < 0 ? getSize(tree) + idx : idx;
|
|
187
|
+
|
|
188
|
+
let firstTag = getAt(0, tree);
|
|
189
|
+
|
|
190
|
+
if (firstTag && firstTag.type === OpenNodeTag) {
|
|
191
|
+
let newTags = [...getValues(tree)];
|
|
192
|
+
if (idx_ === 0) {
|
|
193
|
+
newTags.splice(0, 1);
|
|
194
|
+
} else if (idx_ === getSize(tree - 1)) {
|
|
195
|
+
newTags.splice(2, 1);
|
|
196
|
+
} else {
|
|
197
|
+
let children = getValues(tree)[1];
|
|
198
|
+
|
|
199
|
+
children = module_.removeAt(idx_ - 1, children);
|
|
200
|
+
|
|
201
|
+
newTags[1] = children;
|
|
202
|
+
}
|
|
203
|
+
return module_.fromValues(newTags);
|
|
204
|
+
} else {
|
|
205
|
+
return module_.removeAt(idx_, tree);
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
function* traverseInner(tree) {
|
|
210
|
+
for (let tag of module_.traverse(tree)) {
|
|
211
|
+
if (tag.type === PropertyWrapper) {
|
|
212
|
+
yield* tag.value.tags;
|
|
213
|
+
} else {
|
|
214
|
+
yield tag;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export {
|
|
220
|
+
from,
|
|
221
|
+
fromValues,
|
|
222
|
+
push,
|
|
223
|
+
addAt,
|
|
224
|
+
isValidNode,
|
|
225
|
+
assertValidNode,
|
|
226
|
+
getSize,
|
|
227
|
+
getValues,
|
|
228
|
+
getSums,
|
|
229
|
+
setValues,
|
|
230
|
+
traverse,
|
|
231
|
+
traverseInner,
|
|
232
|
+
findPath,
|
|
233
|
+
getAt,
|
|
234
|
+
replaceAt,
|
|
235
|
+
removeAt,
|
|
236
|
+
};
|