@bablr/agast-helpers 0.3.2 → 0.4.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/btree.js +1 -0
- package/lib/builders.js +100 -81
- package/lib/path.js +1 -1
- package/lib/print.js +75 -51
- package/lib/shorthand.js +12 -8
- package/lib/stream.js +140 -97
- package/lib/symbols.js +16 -0
- package/lib/template.js +18 -11
- package/lib/tree.js +320 -178
- package/package.json +3 -1
package/lib/stream.js
CHANGED
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
import { Coroutine } from '@bablr/coroutine';
|
|
2
2
|
import emptyStack from '@iter-tools/imm-stack';
|
|
3
|
-
import { printSelfClosingNodeTag,
|
|
3
|
+
import { printSelfClosingNodeTag, printTag } from './print.js';
|
|
4
4
|
import { buildWriteEffect, buildTokenGroup } from './builders.js';
|
|
5
|
+
import {
|
|
6
|
+
DoctypeTag,
|
|
7
|
+
OpenNodeTag,
|
|
8
|
+
CloseNodeTag,
|
|
9
|
+
ReferenceTag,
|
|
10
|
+
ShiftTag,
|
|
11
|
+
GapTag,
|
|
12
|
+
NullTag,
|
|
13
|
+
ArrayTag,
|
|
14
|
+
LiteralTag,
|
|
15
|
+
EmbeddedExpression,
|
|
16
|
+
TokenGroup,
|
|
17
|
+
} from './symbols.js';
|
|
18
|
+
|
|
5
19
|
export * from './print.js';
|
|
6
20
|
|
|
7
21
|
const getEmbeddedExpression = (obj) => {
|
|
8
|
-
if (obj.type !==
|
|
22
|
+
if (obj.type !== EmbeddedExpression) throw new Error();
|
|
9
23
|
return obj.value;
|
|
10
24
|
};
|
|
11
25
|
|
|
@@ -89,10 +103,8 @@ export class AsyncGenerator {
|
|
|
89
103
|
}
|
|
90
104
|
}
|
|
91
105
|
|
|
92
|
-
export const isIntrinsicToken = (
|
|
93
|
-
return
|
|
94
|
-
terminal.type === 'OpenNodeTag' && terminal.value.flags.intrinsic && terminal.value.flags.token
|
|
95
|
-
);
|
|
106
|
+
export const isIntrinsicToken = (tag) => {
|
|
107
|
+
return tag.type === OpenNodeTag && tag.value.flags.intrinsic && tag.value.flags.token;
|
|
96
108
|
};
|
|
97
109
|
|
|
98
110
|
export class StreamGenerator {
|
|
@@ -149,8 +161,8 @@ export const maybeWait = (maybePromise, callback) => {
|
|
|
149
161
|
}
|
|
150
162
|
};
|
|
151
163
|
|
|
152
|
-
function* __generateStandardOutput(
|
|
153
|
-
const co = new Coroutine(getStreamIterator(
|
|
164
|
+
function* __generateStandardOutput(tags) {
|
|
165
|
+
const co = new Coroutine(getStreamIterator(tags));
|
|
154
166
|
|
|
155
167
|
for (;;) {
|
|
156
168
|
co.advance();
|
|
@@ -160,10 +172,10 @@ function* __generateStandardOutput(terminals) {
|
|
|
160
172
|
}
|
|
161
173
|
if (co.done) break;
|
|
162
174
|
|
|
163
|
-
const
|
|
175
|
+
const tag = co.value;
|
|
164
176
|
|
|
165
|
-
if (
|
|
166
|
-
const effect = getEmbeddedExpression(
|
|
177
|
+
if (tag.type === 'Effect') {
|
|
178
|
+
const effect = getEmbeddedExpression(tag.value);
|
|
167
179
|
if (effect.verb === 'write') {
|
|
168
180
|
const writeEffect = getEmbeddedExpression(effect.value);
|
|
169
181
|
if (writeEffect.stream == null || writeEffect.stream === 1) {
|
|
@@ -174,11 +186,10 @@ function* __generateStandardOutput(terminals) {
|
|
|
174
186
|
}
|
|
175
187
|
}
|
|
176
188
|
|
|
177
|
-
export const generateStandardOutput = (
|
|
178
|
-
new StreamIterable(__generateStandardOutput(terminals));
|
|
189
|
+
export const generateStandardOutput = (tags) => new StreamIterable(__generateStandardOutput(tags));
|
|
179
190
|
|
|
180
|
-
function* __generateAllOutput(
|
|
181
|
-
const co = new Coroutine(getStreamIterator(
|
|
191
|
+
function* __generateAllOutput(tags) {
|
|
192
|
+
const co = new Coroutine(getStreamIterator(tags));
|
|
182
193
|
|
|
183
194
|
let currentStream = null;
|
|
184
195
|
|
|
@@ -190,10 +201,10 @@ function* __generateAllOutput(terminals) {
|
|
|
190
201
|
}
|
|
191
202
|
if (co.done) break;
|
|
192
203
|
|
|
193
|
-
const
|
|
204
|
+
const tag = co.value;
|
|
194
205
|
|
|
195
|
-
if (
|
|
196
|
-
const effect = getEmbeddedExpression(
|
|
206
|
+
if (tag.type === 'Effect') {
|
|
207
|
+
const effect = getEmbeddedExpression(tag.value);
|
|
197
208
|
if (effect.verb === 'write') {
|
|
198
209
|
const writeEffect = getEmbeddedExpression(effect.value);
|
|
199
210
|
const prevStream = currentStream;
|
|
@@ -207,10 +218,10 @@ function* __generateAllOutput(terminals) {
|
|
|
207
218
|
}
|
|
208
219
|
}
|
|
209
220
|
|
|
210
|
-
export const generateAllOutput = (
|
|
221
|
+
export const generateAllOutput = (tags) => new StreamIterable(__generateAllOutput(tags));
|
|
211
222
|
|
|
212
|
-
export const printCSTML = (
|
|
213
|
-
return stringFromStream(generateStandardOutput(generateCSTMLStrategy(
|
|
223
|
+
export const printCSTML = (tags) => {
|
|
224
|
+
return stringFromStream(generateStandardOutput(generateCSTMLStrategy(tags)));
|
|
214
225
|
};
|
|
215
226
|
|
|
216
227
|
function* __emptyStreamIterator() {}
|
|
@@ -230,9 +241,9 @@ export const asyncStringFromStream = async (stream) => {
|
|
|
230
241
|
|
|
231
242
|
if (co.done) break;
|
|
232
243
|
|
|
233
|
-
const
|
|
244
|
+
const tag = co.value;
|
|
234
245
|
|
|
235
|
-
str +=
|
|
246
|
+
str += printTag(tag);
|
|
236
247
|
}
|
|
237
248
|
|
|
238
249
|
return str;
|
|
@@ -255,17 +266,17 @@ export const stringFromStream = (stream) => {
|
|
|
255
266
|
return str;
|
|
256
267
|
};
|
|
257
268
|
|
|
258
|
-
function* __generateCSTMLStrategy(
|
|
269
|
+
function* __generateCSTMLStrategy(tags, options) {
|
|
259
270
|
let { emitEffects = false, inline: inlineOption = true } = options;
|
|
260
271
|
|
|
261
|
-
if (!
|
|
272
|
+
if (!tags) {
|
|
262
273
|
yield buildWriteEffect('<//>');
|
|
263
274
|
return;
|
|
264
275
|
}
|
|
265
276
|
|
|
266
|
-
let
|
|
277
|
+
let prevTag = null;
|
|
267
278
|
|
|
268
|
-
const co = new Coroutine(getStreamIterator(prettyGroupTokens(
|
|
279
|
+
const co = new Coroutine(getStreamIterator(prettyGroupTokens(tags)));
|
|
269
280
|
|
|
270
281
|
for (;;) {
|
|
271
282
|
co.advance();
|
|
@@ -275,43 +286,43 @@ function* __generateCSTMLStrategy(terminals, options) {
|
|
|
275
286
|
}
|
|
276
287
|
if (co.done) break;
|
|
277
288
|
|
|
278
|
-
const
|
|
289
|
+
const tag = co.value;
|
|
279
290
|
|
|
280
|
-
if (
|
|
291
|
+
if (tag.type === ReferenceTag && prevTag.type === NullTag) {
|
|
281
292
|
yield buildWriteEffect(' ');
|
|
282
293
|
}
|
|
283
294
|
|
|
284
|
-
if (
|
|
285
|
-
const effect =
|
|
295
|
+
if (tag.type === 'Effect') {
|
|
296
|
+
const effect = tag.value;
|
|
286
297
|
if (emitEffects && effect.verb === 'write') {
|
|
287
298
|
yield buildWriteEffect(effect.value.text, effect.value.options);
|
|
288
299
|
}
|
|
289
300
|
continue;
|
|
290
301
|
}
|
|
291
302
|
|
|
292
|
-
if (
|
|
293
|
-
const intrinsicValue = getCooked(
|
|
294
|
-
yield buildWriteEffect(printSelfClosingNodeTag(
|
|
303
|
+
if (tag.type === TokenGroup) {
|
|
304
|
+
const intrinsicValue = getCooked(tag.value);
|
|
305
|
+
yield buildWriteEffect(printSelfClosingNodeTag(tag.value[0], intrinsicValue));
|
|
295
306
|
} else {
|
|
296
|
-
yield buildWriteEffect(
|
|
307
|
+
yield buildWriteEffect(printTag(tag));
|
|
297
308
|
}
|
|
298
309
|
|
|
299
|
-
|
|
310
|
+
prevTag = tag;
|
|
300
311
|
}
|
|
301
312
|
|
|
302
313
|
yield buildWriteEffect('\n');
|
|
303
314
|
}
|
|
304
315
|
|
|
305
|
-
export const generateCSTMLStrategy = (
|
|
306
|
-
new StreamIterable(__generateCSTMLStrategy(
|
|
316
|
+
export const generateCSTMLStrategy = (tags, options = {}) =>
|
|
317
|
+
new StreamIterable(__generateCSTMLStrategy(tags, options));
|
|
307
318
|
|
|
308
|
-
export const prettyGroupTokens = (
|
|
319
|
+
export const prettyGroupTokens = (tags) => new StreamIterable(__prettyGroupTokens(tags));
|
|
309
320
|
|
|
310
|
-
function* __prettyGroupTokens(
|
|
321
|
+
function* __prettyGroupTokens(tags) {
|
|
311
322
|
let states = emptyStack.push({ holding: [], broken: false, open: null });
|
|
312
323
|
let state = states.value;
|
|
313
324
|
|
|
314
|
-
const co = new Coroutine(getStreamIterator(
|
|
325
|
+
const co = new Coroutine(getStreamIterator(tags));
|
|
315
326
|
|
|
316
327
|
for (;;) {
|
|
317
328
|
co.advance();
|
|
@@ -322,18 +333,16 @@ function* __prettyGroupTokens(terminals) {
|
|
|
322
333
|
co.current = yield co.current;
|
|
323
334
|
}
|
|
324
335
|
|
|
325
|
-
const
|
|
326
|
-
const isOpenClose =
|
|
327
|
-
terminal.type === 'CloseNodeTag' || (terminal.type === 'OpenNodeTag' && terminal.value.type);
|
|
336
|
+
const tag = co.value;
|
|
337
|
+
const isOpenClose = tag.type === CloseNodeTag || (tag.type === OpenNodeTag && tag.value.type);
|
|
328
338
|
|
|
329
339
|
if (
|
|
330
|
-
(
|
|
331
|
-
[
|
|
332
|
-
(
|
|
340
|
+
(tag.type === 'Effect' && tag.value.verb === 'write') ||
|
|
341
|
+
[ReferenceTag, DoctypeTag, GapTag, NullTag, ArrayTag, ShiftTag].includes(tag.type) ||
|
|
342
|
+
(tag.type === OpenNodeTag && !tag.value.type) ||
|
|
333
343
|
(state.open &&
|
|
334
344
|
!isIntrinsicToken(state.open) &&
|
|
335
|
-
(
|
|
336
|
-
(terminal.type === 'OpenNodeTag' && terminal.value.flags.escape)))
|
|
345
|
+
(tag.type === LiteralTag || (tag.type === OpenNodeTag && tag.value.flags.escape)))
|
|
337
346
|
) {
|
|
338
347
|
state.broken = true;
|
|
339
348
|
|
|
@@ -342,48 +351,48 @@ function* __prettyGroupTokens(terminals) {
|
|
|
342
351
|
state.holding = [];
|
|
343
352
|
}
|
|
344
353
|
|
|
345
|
-
if (!isOpenClose &&
|
|
346
|
-
yield
|
|
354
|
+
if (!isOpenClose && tag.type !== 'Effect') {
|
|
355
|
+
yield tag;
|
|
347
356
|
}
|
|
348
|
-
} else if (!isOpenClose &&
|
|
349
|
-
state.holding.push(
|
|
357
|
+
} else if (!isOpenClose && tag.type !== 'Effect') {
|
|
358
|
+
state.holding.push(tag);
|
|
350
359
|
}
|
|
351
360
|
|
|
352
|
-
if (
|
|
353
|
-
yield
|
|
361
|
+
if (tag.type === 'Effect') {
|
|
362
|
+
yield tag;
|
|
354
363
|
}
|
|
355
364
|
|
|
356
|
-
if (
|
|
365
|
+
if (tag.type === CloseNodeTag) {
|
|
357
366
|
if (!state.broken && (isIntrinsicToken(state.open) || state.holding.length === 1)) {
|
|
358
|
-
state.holding.push(
|
|
367
|
+
state.holding.push(tag);
|
|
359
368
|
yield buildTokenGroup(state.holding);
|
|
360
369
|
} else {
|
|
361
370
|
if (state.holding.length) {
|
|
362
371
|
yield* state.holding;
|
|
363
372
|
}
|
|
364
|
-
yield
|
|
373
|
+
yield tag;
|
|
365
374
|
}
|
|
366
375
|
|
|
367
376
|
states = states.pop();
|
|
368
377
|
state = states.value;
|
|
369
378
|
}
|
|
370
379
|
|
|
371
|
-
if (
|
|
372
|
-
states = states.push({ holding: [
|
|
380
|
+
if (tag.type === OpenNodeTag && tag.value.type) {
|
|
381
|
+
states = states.push({ holding: [tag], broken: false, open: tag });
|
|
373
382
|
state = states.value;
|
|
374
383
|
}
|
|
375
384
|
}
|
|
376
385
|
}
|
|
377
386
|
|
|
378
|
-
function* __generatePrettyCSTMLStrategy(
|
|
387
|
+
function* __generatePrettyCSTMLStrategy(tags, options) {
|
|
379
388
|
let { indent = ' ', emitEffects = false, inline: inlineOption = true } = options;
|
|
380
389
|
|
|
381
|
-
if (!
|
|
390
|
+
if (!tags) {
|
|
382
391
|
yield buildWriteEffect('<//>');
|
|
383
392
|
return;
|
|
384
393
|
}
|
|
385
394
|
|
|
386
|
-
const co = new Coroutine(getStreamIterator(prettyGroupTokens(
|
|
395
|
+
const co = new Coroutine(getStreamIterator(prettyGroupTokens(tags)));
|
|
387
396
|
let indentLevel = 0;
|
|
388
397
|
let first = true;
|
|
389
398
|
let inline = false;
|
|
@@ -397,10 +406,10 @@ function* __generatePrettyCSTMLStrategy(terminals, options) {
|
|
|
397
406
|
co.current = yield co.current;
|
|
398
407
|
}
|
|
399
408
|
|
|
400
|
-
const
|
|
409
|
+
const tag = co.value;
|
|
401
410
|
|
|
402
|
-
if (
|
|
403
|
-
const effect = getEmbeddedExpression(
|
|
411
|
+
if (tag.type === 'Effect') {
|
|
412
|
+
const effect = getEmbeddedExpression(tag.value);
|
|
404
413
|
if (emitEffects && effect.verb === 'write') {
|
|
405
414
|
const writeEffect = getEmbeddedExpression(effect.value);
|
|
406
415
|
yield buildWriteEffect(
|
|
@@ -417,13 +426,16 @@ function* __generatePrettyCSTMLStrategy(terminals, options) {
|
|
|
417
426
|
inline =
|
|
418
427
|
inlineOption &&
|
|
419
428
|
inline &&
|
|
420
|
-
(
|
|
429
|
+
(tag.type === NullTag ||
|
|
430
|
+
tag.type === GapTag ||
|
|
431
|
+
tag.type === ArrayTag ||
|
|
432
|
+
tag.type === TokenGroup);
|
|
421
433
|
|
|
422
434
|
if (!first && !inline) {
|
|
423
435
|
yield buildWriteEffect('\n');
|
|
424
436
|
}
|
|
425
437
|
|
|
426
|
-
if (
|
|
438
|
+
if (tag.type === CloseNodeTag) {
|
|
427
439
|
if (indentLevel === 0) {
|
|
428
440
|
throw new Error('imbalanced tag stack');
|
|
429
441
|
}
|
|
@@ -437,18 +449,18 @@ function* __generatePrettyCSTMLStrategy(terminals, options) {
|
|
|
437
449
|
yield buildWriteEffect(' ');
|
|
438
450
|
}
|
|
439
451
|
|
|
440
|
-
if (
|
|
441
|
-
const intrinsicValue = getCooked(
|
|
442
|
-
yield buildWriteEffect(printSelfClosingNodeTag(
|
|
452
|
+
if (tag.type === TokenGroup) {
|
|
453
|
+
const intrinsicValue = tag.value[0].value.flags.token ? getCooked(tag.value) : null;
|
|
454
|
+
yield buildWriteEffect(printSelfClosingNodeTag(tag.value[0], intrinsicValue));
|
|
443
455
|
} else {
|
|
444
|
-
yield buildWriteEffect(
|
|
456
|
+
yield buildWriteEffect(printTag(tag));
|
|
445
457
|
}
|
|
446
458
|
|
|
447
|
-
if (
|
|
459
|
+
if (tag.type === ReferenceTag) {
|
|
448
460
|
inline = true;
|
|
449
461
|
}
|
|
450
462
|
|
|
451
|
-
if (
|
|
463
|
+
if (tag.type === OpenNodeTag) {
|
|
452
464
|
indentLevel++;
|
|
453
465
|
}
|
|
454
466
|
|
|
@@ -458,32 +470,51 @@ function* __generatePrettyCSTMLStrategy(terminals, options) {
|
|
|
458
470
|
yield buildWriteEffect('\n');
|
|
459
471
|
}
|
|
460
472
|
|
|
461
|
-
export const generatePrettyCSTMLStrategy = (
|
|
462
|
-
return new StreamIterable(__generatePrettyCSTMLStrategy(
|
|
473
|
+
export const generatePrettyCSTMLStrategy = (tags, options = {}) => {
|
|
474
|
+
return new StreamIterable(__generatePrettyCSTMLStrategy(tags, options));
|
|
463
475
|
};
|
|
464
476
|
|
|
465
|
-
export const printPrettyCSTML = (
|
|
466
|
-
return stringFromStream(generateStandardOutput(generatePrettyCSTMLStrategy(
|
|
477
|
+
export const printPrettyCSTML = (tags, options = {}) => {
|
|
478
|
+
return stringFromStream(generateStandardOutput(generatePrettyCSTMLStrategy(tags, options)));
|
|
467
479
|
};
|
|
468
480
|
|
|
469
|
-
export const getCooked = (
|
|
481
|
+
export const getCooked = (tags) => {
|
|
470
482
|
let cooked = '';
|
|
471
483
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
484
|
+
let first = true;
|
|
485
|
+
let foundLast = false;
|
|
486
|
+
let depth = 0;
|
|
487
|
+
|
|
488
|
+
for (const tag of tags) {
|
|
489
|
+
if (foundLast) throw new Error();
|
|
490
|
+
|
|
491
|
+
switch (tag.type) {
|
|
492
|
+
case ReferenceTag: {
|
|
493
|
+
if (depth === 1) {
|
|
494
|
+
throw new Error('cookable nodes must not contain other nodes');
|
|
495
|
+
}
|
|
496
|
+
break;
|
|
476
497
|
}
|
|
477
498
|
|
|
478
|
-
case
|
|
479
|
-
const { flags, attributes } =
|
|
499
|
+
case OpenNodeTag: {
|
|
500
|
+
const { flags, attributes } = tag.value;
|
|
501
|
+
|
|
502
|
+
depth++;
|
|
503
|
+
|
|
504
|
+
if (first) {
|
|
505
|
+
if (flags.token) {
|
|
506
|
+
break;
|
|
507
|
+
} else {
|
|
508
|
+
throw new Error(JSON.stringify(flags));
|
|
509
|
+
}
|
|
510
|
+
}
|
|
480
511
|
|
|
481
512
|
if (!(flags.trivia || (flags.escape && attributes.cooked))) {
|
|
482
513
|
throw new Error('cookable nodes must not contain other nodes');
|
|
483
514
|
}
|
|
484
515
|
|
|
485
516
|
if (flags.escape) {
|
|
486
|
-
const { cooked: cookedValue } =
|
|
517
|
+
const { cooked: cookedValue } = tag.value.attributes;
|
|
487
518
|
|
|
488
519
|
if (!cookedValue) throw new Error('cannot cook string: it contains uncooked escapes');
|
|
489
520
|
|
|
@@ -493,8 +524,18 @@ export const getCooked = (terminals) => {
|
|
|
493
524
|
break;
|
|
494
525
|
}
|
|
495
526
|
|
|
496
|
-
case
|
|
497
|
-
|
|
527
|
+
case CloseNodeTag: {
|
|
528
|
+
if (depth === 1) {
|
|
529
|
+
foundLast = true;
|
|
530
|
+
}
|
|
531
|
+
depth--;
|
|
532
|
+
break;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
case LiteralTag: {
|
|
536
|
+
if (depth === 1) {
|
|
537
|
+
cooked += tag.value;
|
|
538
|
+
}
|
|
498
539
|
break;
|
|
499
540
|
}
|
|
500
541
|
|
|
@@ -502,29 +543,31 @@ export const getCooked = (terminals) => {
|
|
|
502
543
|
throw new Error();
|
|
503
544
|
}
|
|
504
545
|
}
|
|
546
|
+
|
|
547
|
+
first = false;
|
|
505
548
|
}
|
|
506
549
|
|
|
507
550
|
return cooked;
|
|
508
551
|
};
|
|
509
552
|
|
|
510
|
-
export const printSource = (
|
|
553
|
+
export const printSource = (tags) => {
|
|
511
554
|
let printed = '';
|
|
512
555
|
|
|
513
|
-
if (!
|
|
556
|
+
if (!tags) return printed;
|
|
514
557
|
|
|
515
|
-
for (const
|
|
516
|
-
if (
|
|
517
|
-
printed +=
|
|
558
|
+
for (const tag of tags) {
|
|
559
|
+
if (tag.type === LiteralTag) {
|
|
560
|
+
printed += tag.value;
|
|
518
561
|
}
|
|
519
562
|
}
|
|
520
563
|
|
|
521
564
|
return printed;
|
|
522
565
|
};
|
|
523
566
|
|
|
524
|
-
export function* generateSourceTextFor(
|
|
525
|
-
for (const
|
|
526
|
-
if (
|
|
527
|
-
yield*
|
|
567
|
+
export function* generateSourceTextFor(tags) {
|
|
568
|
+
for (const tag of tags) {
|
|
569
|
+
if (tag.type === LiteralTag) {
|
|
570
|
+
yield* tag.value;
|
|
528
571
|
}
|
|
529
572
|
}
|
|
530
573
|
}
|
package/lib/symbols.js
CHANGED
|
@@ -6,4 +6,20 @@ export const fragment = Symbol.for('@bablr/fragment');
|
|
|
6
6
|
|
|
7
7
|
export const null_ = Symbol.for('@bablr/null');
|
|
8
8
|
|
|
9
|
+
export const DoctypeTag = Symbol.for('DoctypeTag');
|
|
10
|
+
export const OpenNodeTag = Symbol.for('OpenNodeTag');
|
|
11
|
+
export const CloseNodeTag = Symbol.for('CloseNodeTag');
|
|
12
|
+
export const ReferenceTag = Symbol.for('ReferenceTag');
|
|
13
|
+
export const ShiftTag = Symbol.for('ShiftTag');
|
|
14
|
+
export const GapTag = Symbol.for('GapTag');
|
|
15
|
+
export const NullTag = Symbol.for('NullTag');
|
|
16
|
+
export const ArrayTag = Symbol.for('ArrayTag');
|
|
17
|
+
export const LiteralTag = Symbol.for('LiteralTag');
|
|
18
|
+
|
|
19
|
+
export const EmbeddedNode = Symbol.for('EmbeddedNode');
|
|
20
|
+
export const EmbeddedTag = Symbol.for('EmbeddedTag');
|
|
21
|
+
export const EmbeddedExpression = Symbol.for('EmbeddedExpression');
|
|
22
|
+
|
|
23
|
+
export const TokenGroup = Symbol.for('TokenGroup');
|
|
24
|
+
|
|
9
25
|
export { null_ as null };
|
package/lib/template.js
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import * as t from './builders.js';
|
|
2
|
+
import { LiteralTag, EmbeddedNode } from './symbols.js';
|
|
3
|
+
import * as btree from './btree.js';
|
|
2
4
|
|
|
3
5
|
const { isArray } = Array;
|
|
4
6
|
const { freeze } = Object;
|
|
7
|
+
const { isFinite } = Number;
|
|
5
8
|
|
|
6
9
|
export const interpolateArray = (value) => {
|
|
7
10
|
if (isArray(value)) {
|
|
8
|
-
|
|
11
|
+
if (isFinite(value[0])) {
|
|
12
|
+
return [...btree.traverse(value)];
|
|
13
|
+
} else {
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
9
16
|
} else {
|
|
10
17
|
return [value];
|
|
11
18
|
}
|
|
@@ -27,28 +34,28 @@ export const interpolateArrayChildren = (value, ref, sep) => {
|
|
|
27
34
|
}
|
|
28
35
|
};
|
|
29
36
|
|
|
30
|
-
const
|
|
31
|
-
if (!
|
|
32
|
-
throw new Error('Invalid
|
|
37
|
+
const validateTag = (tag) => {
|
|
38
|
+
if (!tag || (tag.type !== LiteralTag && tag.type !== EmbeddedNode)) {
|
|
39
|
+
throw new Error('Invalid tag');
|
|
33
40
|
}
|
|
34
|
-
if (
|
|
41
|
+
if (tag.type === EmbeddedNode && !tag.value.flags.escape) {
|
|
35
42
|
throw new Error();
|
|
36
43
|
}
|
|
37
44
|
};
|
|
38
45
|
|
|
39
46
|
export const interpolateString = (value) => {
|
|
40
|
-
const
|
|
47
|
+
const tags = [];
|
|
41
48
|
if (isArray(value)) {
|
|
42
49
|
for (const element of value) {
|
|
43
|
-
|
|
50
|
+
validateTag(element);
|
|
44
51
|
|
|
45
|
-
|
|
52
|
+
tags.push(element);
|
|
46
53
|
}
|
|
47
54
|
} else {
|
|
48
55
|
// we can't safely interpolate strings here, though I wish we could
|
|
49
|
-
|
|
50
|
-
|
|
56
|
+
validateTag(value);
|
|
57
|
+
tags.push(value);
|
|
51
58
|
}
|
|
52
59
|
|
|
53
|
-
return t.buildNode('String', 'Content',
|
|
60
|
+
return t.buildNode('String', 'Content', tags);
|
|
54
61
|
};
|