@bablr/agast-vm-helpers 0.5.0 → 0.5.2

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/deembed.js CHANGED
@@ -1,4 +1,4 @@
1
- import { EmbeddedExpression } from '@bablr/agast-helpers/symbols';
1
+ import { EmbeddedExpression, EmbeddedTag } from '@bablr/agast-helpers/symbols';
2
2
 
3
3
  const { isArray } = Array;
4
4
  const isString = (val) => typeof val === 'string';
@@ -23,3 +23,9 @@ export const getEmbeddedExpression = (expr) => {
23
23
  if (expr.type !== EmbeddedExpression) throw new Error();
24
24
  return expr.value;
25
25
  };
26
+
27
+ export const getEmbeddedTag = (expr) => {
28
+ if (!expr) return expr;
29
+ if (expr.type !== EmbeddedTag) throw new Error();
30
+ return expr.value;
31
+ };
package/lib/index.js CHANGED
@@ -5,6 +5,8 @@ import { buildNodeCloseTag, buildLiteralTag, buildDoctypeTag } from '@bablr/agas
5
5
  import {
6
6
  DoctypeTag,
7
7
  OpenNodeTag,
8
+ OpenFragmentTag,
9
+ CloseFragmentTag,
8
10
  CloseNodeTag,
9
11
  ReferenceTag,
10
12
  ShiftTag,
@@ -14,8 +16,6 @@ import {
14
16
  LiteralTag,
15
17
  } from '@bablr/agast-helpers/symbols';
16
18
 
17
- export * from './builders.js';
18
-
19
19
  export const effectsFor = (verb) => {
20
20
  switch (verb) {
21
21
  case 'eat':
@@ -84,6 +84,31 @@ export const reifyProperties = (properties = []) => {
84
84
  return built;
85
85
  };
86
86
 
87
+ export const buildFragmentChildren = (node) => {
88
+ let { open, children = [], close } = node.properties;
89
+
90
+ let built = [];
91
+
92
+ open = reifyExpression(open);
93
+ close = reifyExpression(close);
94
+
95
+ built = btree.push(built, open);
96
+
97
+ for (const child of btree.traverse(children)) {
98
+ if (child.type !== 'Property') throw new Error('umimplemented');
99
+
100
+ let { reference } = child.properties;
101
+
102
+ reference = reifyExpression(reference);
103
+
104
+ built = btree.push(built, reference);
105
+ }
106
+
107
+ built = btree.push(built, close);
108
+
109
+ return built;
110
+ };
111
+
87
112
  export const buildChildren = (node) => {
88
113
  let { open, children = [], close } = node.properties;
89
114
 
@@ -144,7 +169,7 @@ export const reifyExpression = (node) => {
144
169
  type: null,
145
170
  children: btree.addAt(
146
171
  0,
147
- buildChildren(node.properties.tree),
172
+ buildFragmentChildren(node.properties.tree),
148
173
  buildDoctypeTag(attributes),
149
174
  ),
150
175
  properties,
@@ -171,6 +196,25 @@ export const reifyExpression = (node) => {
171
196
  };
172
197
  }
173
198
 
199
+ case 'Fragment': {
200
+ let { open, children } = node.properties;
201
+
202
+ open = reifyExpression(open);
203
+
204
+ let { flags } = open.value;
205
+
206
+ const properties = reifyProperties(children);
207
+
208
+ return {
209
+ flags,
210
+ language: null,
211
+ type: null,
212
+ children: buildChildren(node),
213
+ properties,
214
+ attributes: {},
215
+ };
216
+ }
217
+
174
218
  case 'DoctypeTag': {
175
219
  let { doctype, version, attributes } = node.properties;
176
220
  return {
@@ -229,6 +273,21 @@ export const reifyExpression = (node) => {
229
273
  return { type: CloseNodeTag, value: { language, type } };
230
274
  }
231
275
 
276
+ case 'OpenFragmentTag': {
277
+ let { flags } = node.properties;
278
+
279
+ flags = reifyFlags(flags);
280
+
281
+ return {
282
+ type: OpenFragmentTag,
283
+ value: { flags },
284
+ };
285
+ }
286
+
287
+ case 'CloseFragmentTag': {
288
+ return { type: CloseFragmentTag, value: undefined };
289
+ }
290
+
232
291
  case 'Integer': {
233
292
  let { digits } = node.properties;
234
293
  return parseInt(digits.map((digit) => getCooked(digit)).join(''), 10);
package/package.json CHANGED
@@ -1,12 +1,10 @@
1
1
  {
2
2
  "name": "@bablr/agast-vm-helpers",
3
3
  "description": "Helper functions for working with the BABLR VM",
4
- "version": "0.5.0",
4
+ "version": "0.5.2",
5
5
  "author": "Conrad Buck<conartist6@gmail.com>",
6
6
  "type": "module",
7
- "files": [
8
- "lib"
9
- ],
7
+ "files": ["lib"],
10
8
  "exports": {
11
9
  ".": "./lib/index.js",
12
10
  "./builders": "./lib/builders.js",
package/lib/builders.js DELETED
@@ -1,696 +0,0 @@
1
- // import { i } from '@bablr/boot/shorthand.macro';
2
- import { interpolateFragmentChildren, interpolateString } from '@bablr/agast-helpers/template';
3
- import { isNull } from '@bablr/agast-helpers/tree';
4
- import { buildLiteralTag as agastBuildLiteralTag } from '@bablr/agast-helpers/builders';
5
- import * as t from '@bablr/agast-helpers/shorthand';
6
- import * as btree from '@bablr/agast-helpers/btree';
7
- import * as l from './languages.js';
8
-
9
- const { getPrototypeOf, freeze } = Object;
10
- const { isArray } = Array;
11
-
12
- const when = (condition, value) => (condition ? value : { *[Symbol.iterator]() {} });
13
-
14
- const isString = (val) => typeof val === 'string';
15
- const isBoolean = (val) => typeof val === 'boolean';
16
-
17
- function* repeat(times, ...values) {
18
- for (let i = 0; i < times; i++) for (const value of values) yield value;
19
- }
20
-
21
- function* concat(...iterables) {
22
- for (const iterable of iterables) yield* iterable;
23
- }
24
-
25
- export const buildSeparatedListChildren = (list, ref, sep) => {
26
- const children = [];
27
- let first = true;
28
- for (const _ of list) {
29
- if (!first && sep) {
30
- children.push(freeze({ ...sep }));
31
- }
32
- children.push(freeze({ ...ref }));
33
- first = false;
34
- }
35
- return children;
36
- };
37
-
38
- export const buildReferenceTag = (name, isArray, hasGap) => {
39
- return t.node(
40
- l.CSTML,
41
- 'ReferenceTag',
42
- btree.fromValues(
43
- concat(
44
- [t.ref`name`],
45
- when(isArray, [t.ref`arrayOperatorToken`]),
46
- when(hasGap, [t.ref`hasGapToken`]),
47
- [t.ref`sigilToken`],
48
- ),
49
- ),
50
- {
51
- name: buildIdentifier(name),
52
- arrayOperatorToken: isArray ? t.s_node(l.CSTML, 'Punctuator', '[]') : t.null_node(),
53
- hasGapToken: hasGap ? t.s_node(l.CSTML, 'Punctuator', '$') : t.null_node(),
54
- sigilToken: t.s_node(l.CSTML, 'Punctuator', ':'),
55
- },
56
- );
57
- };
58
-
59
- export const buildGapTag = () => {
60
- return t.node(l.CSTML, 'GapTag', [t.ref`sigilToken`], {
61
- sigilToken: t.s_node(l.CSTML, 'Punctuator', '<//>'),
62
- });
63
- };
64
-
65
- export const buildShiftTag = () => {
66
- return t.node(l.CSTML, 'ShiftTag', [t.ref`sigilToken`], {
67
- sigilToken: t.s_node(l.CSTML, 'Punctuator', '^^^'),
68
- });
69
- };
70
-
71
- export const buildFlags = (flags = {}) => {
72
- const { token = null, escape = null, trivia = null, expression = null, hasGap = null } = flags;
73
-
74
- if ((trivia && escape) || (expression && (trivia || escape))) {
75
- throw new Error('invalid flags');
76
- }
77
-
78
- return t.node(
79
- l.CSTML,
80
- 'Flags',
81
- btree.fromValues(
82
- concat(
83
- when(trivia, [t.ref`triviaToken`]),
84
- when(token, [t.ref`tokenToken`]),
85
- when(escape, [t.ref`escapeToken`]),
86
- when(expression, [t.ref`expressionToken`]),
87
- when(hasGap, [t.ref`hasGapToken`]),
88
- ),
89
- ),
90
- {
91
- triviaToken: trivia ? t.s_node(l.CSTML, 'Punctuator', '#') : t.null_node(),
92
- tokenToken: token ? t.s_node(l.CSTML, 'Punctuator', '*') : t.null_node(),
93
- escapeToken: escape ? t.s_node(l.CSTML, 'Punctuator', '@') : t.null_node(),
94
- expressionToken: expression ? t.s_node(l.CSTML, 'Punctuator', '+') : t.null_node(),
95
- hasGapToken: hasGap ? t.s_node(l.CSTML, 'Punctuator', '$') : t.null_node(),
96
- },
97
- );
98
- };
99
-
100
- export const buildSpamMatcher = (type = null, value = null, attributes = {}) => {
101
- return buildFullyQualifiedSpamMatcher({}, null, type, value, attributes);
102
- };
103
-
104
- export const buildFullyQualifiedSpamMatcher = (
105
- flags,
106
- language,
107
- type,
108
- intrinsicValue,
109
- attributes = {},
110
- ) => {
111
- const attributes_ = buildAttributes(attributes);
112
-
113
- let language_;
114
-
115
- if (isString(language)) {
116
- language_ = language;
117
- } else {
118
- let lArr = isString(language) ? language : language ? [...language] : [];
119
-
120
- language_ = lArr.length === 0 ? null : lArr;
121
- }
122
-
123
- return t.node(l.Spamex, 'NodeMatcher', [t.ref`open`], {
124
- open: t.node(
125
- l.Spamex,
126
- 'NodeMatcher',
127
- btree.fromValues(
128
- concat(
129
- [t.ref`openToken`, t.ref`flags`],
130
- when(language_, [t.ref`language`, t.ref`languageSeparator`]),
131
- when(type, [t.ref`type`]),
132
- when(intrinsicValue, [t.embedded(buildSpace()), t.ref`intrinsicValue`]),
133
- when(attributes_.length, [t.embedded(buildSpace())]),
134
- interpolateFragmentChildren(attributes_, t.ref`attributes[]`),
135
- when(!type, [t.embedded(buildSpace())]),
136
- [t.ref`selfClosingTagToken`, t.ref`closeToken`],
137
- ),
138
- ),
139
- {
140
- openToken: t.s_node(l.CSTML, 'Punctuator', '<'),
141
- flags: buildFlags(flags),
142
- language: language_ ? buildLanguage(language_) : t.null_node(),
143
- languageSeparator: language_ && type ? t.s_node(l.CSTML, 'Punctuator', ':') : t.null_node(),
144
- type: type ? buildIdentifier(type) : t.null_node(),
145
- intrinsicValue: intrinsicValue ? buildString(intrinsicValue) : t.null_node(),
146
- attributes: attributes_.properties['.'],
147
- selfClosingTagToken: t.s_node(l.CSTML, 'Punctuator', '/'),
148
- closeToken: t.s_node(l.CSTML, 'Punctuator', '>'),
149
- },
150
- ),
151
- });
152
- };
153
-
154
- export const buildNodeOpenTag = (flags, language, type = null, attributes = {}) => {
155
- const attributes_ = buildAttributes(attributes);
156
-
157
- let language_ = !language || language.length === 0 ? null : language;
158
-
159
- return t.node(
160
- l.CSTML,
161
- 'OpenNodeTag',
162
- btree.fromValues(
163
- concat(
164
- [t.ref`openToken`, t.ref`flags`],
165
- when(language_, [t.ref`language`, t.ref`languageSeparator`]),
166
- when(type, [t.ref`type`]),
167
- when(attributes_.length, [t.embedded(buildSpace())]),
168
- interpolateFragmentChildren(attributes_, t.ref`attributes[]`),
169
- [t.ref`closeToken`],
170
- ),
171
- ),
172
- {
173
- openToken: t.s_node(l.CSTML, 'Punctuator', '<'),
174
- flags: buildFlags(flags),
175
- language: language_ && type ? buildLanguage(language_) : t.null_node(),
176
- languageSeparator: language_ && type ? t.s_node(l.CSTML, 'Punctuator', ':') : t.null_node(),
177
- type: type ? buildIdentifier(type) : t.null_node(),
178
- attributes: attributes_.properties['.'],
179
- closeToken: t.s_node(l.CSTML, 'Punctuator', '>'),
180
- },
181
- );
182
- };
183
-
184
- export const buildDoctypeTag = (attributes) => {
185
- const attributes_ = buildAttributes(attributes);
186
-
187
- return t.node(
188
- l.CSTML,
189
- 'DoctypeTag',
190
- btree.fromValues(
191
- concat(
192
- [t.ref`openToken`, t.ref`version`, t.ref`versionSeparator`, t.ref`doctype`],
193
- when(attributes_.length, [t.embedded(buildSpace())]),
194
- interpolateFragmentChildren(attributes_, t.ref`attributes[]`),
195
- [t.ref`closeToken`],
196
- ),
197
- ),
198
- {
199
- openToken: t.s_node(l.CSTML, 'Punctuator', '<!'),
200
- version: t.s_node(l.CSTML, 'PositiveInteger', '0'),
201
- versionSeparator: t.s_node(l.CSTML, 'Punctuator', ':'),
202
- doctype: t.s_node(l.CSTML, 'Keyword', 'cstml'),
203
- attributes: attributes_.properties['.'],
204
- closeToken: t.s_node(l.CSTML, 'Punctuator', '>'),
205
- },
206
- );
207
- };
208
-
209
- export const buildIdentifierPath = (path) => {
210
- const path_ = isString(path) ? [path] : [...path];
211
- const segments = path_.map((name) => buildIdentifier(name));
212
- const separators = path_.slice(0, -1).map((_) => t.s_node(l.CSTML, 'Punctuator', '.'));
213
-
214
- if (!path_.length) {
215
- return null;
216
- }
217
-
218
- return t.node(
219
- l.CSTML,
220
- 'IdentifierPath',
221
- btree.fromValues(
222
- concat(
223
- [t.ref`segments[]`, t.arr()],
224
- repeat(segments.length - 1, t.ref`segments[]`, t.ref`separators[]`),
225
- [t.ref`segments[]`],
226
- ),
227
- ),
228
- {
229
- segments,
230
- separators,
231
- },
232
- );
233
- };
234
-
235
- export const buildLanguage = (language) => {
236
- return language && isString(language) && language.startsWith('https://')
237
- ? buildString(language)
238
- : buildIdentifierPath(language);
239
- };
240
-
241
- export const buildNodeCloseTag = (type, language) => {
242
- return t.node(
243
- l.CSTML,
244
- 'CloseNodeTag',
245
- btree.fromValues(
246
- concat(
247
- [t.ref`openToken`],
248
- when(language, [t.ref`language`]),
249
- when(type && language, [t.ref`languageSeparator`]),
250
- when(type, [t.ref`type`]),
251
- [t.ref`closeToken`],
252
- ),
253
- ),
254
- {
255
- openToken: t.s_node(l.CSTML, 'Punctuator', '</'),
256
- language: language ? buildLanguage(language) : t.null_node(),
257
- languageSeparator: language && type ? t.s_node(l.CSTML, 'Punctuator', ':') : t.null_node(),
258
- type: type ? buildIdentifier(type) : t.null_node(),
259
- closeToken: t.s_node(l.CSTML, 'Punctuator', '>'),
260
- },
261
- );
262
- };
263
-
264
- export const buildLiteralTag = (value) => {
265
- return t.node(l.CSTML, 'LiteralTag', [t.ref`value`], { value });
266
- };
267
-
268
- export const buildTerminalProps = (matcher) => {
269
- const { attributes, value } = matcher.properties;
270
-
271
- return buildObject({ value, attributes });
272
- };
273
-
274
- export const buildSpace = () => {
275
- return t.t_node(l.Comment, null, [t.embedded(t.t_node(l.Space, 'Space', [t.lit(' ')]))]);
276
- };
277
-
278
- export const buildIdentifier = (name) => {
279
- return t.s_node(l.Instruction, 'Identifier', name);
280
- };
281
-
282
- export const buildKeyword = (name) => {
283
- return t.s_node(l.Instruction, 'Identifier', name);
284
- };
285
-
286
- export const buildCall = (verb, ...args) => {
287
- return t.node(l.Instruction, 'Call', [t.ref`verb`, t.ref`arguments`], {
288
- verb: buildIdentifier(verb),
289
- arguments: buildTuple(args),
290
- });
291
- };
292
-
293
- export const buildProperty = (key, value) => {
294
- return t.node(
295
- l.Instruction,
296
- 'Property',
297
- btree.from(t.ref`key`, t.ref`mapOperator`, t.embedded(buildSpace()), t.ref`value`),
298
- {
299
- key: buildIdentifier(key),
300
- mapOperator: t.s_node(l.Instruction, 'Punctuator', ':'),
301
- value: buildExpression(value),
302
- },
303
- );
304
- };
305
-
306
- const escapables = {
307
- '\r': 'r',
308
- '\n': 'n',
309
- '\t': 't',
310
- '\0': '0',
311
- };
312
-
313
- export const buildDigit = (value) => {
314
- return t.s_node(l.CSTML, 'Digit', value);
315
- };
316
-
317
- export const buildInteger = (value, base = 10) => {
318
- const digits = value.toString(base).split('');
319
-
320
- return t.node(
321
- l.CSTML,
322
- 'Integer',
323
- btree.fromValues(
324
- concat(
325
- [t.ref`digits[]`, t.arr()],
326
- digits.map(() => t.ref`digits[]`),
327
- ),
328
- ),
329
- {
330
- digits: digits.map((digit) => buildDigit(digit)),
331
- },
332
- );
333
- };
334
-
335
- export const buildInfinity = (value) => {
336
- let sign;
337
- if (value === Infinity) {
338
- sign = '+';
339
- } else if (value === -Infinity) {
340
- sign = '-';
341
- } else {
342
- throw new Error();
343
- }
344
-
345
- return t.node(l.CSTML, 'Infinity', [t.ref`sign`, t.ref`value`], {
346
- sign: t.s_node(l.CSTML, 'Punctuator', sign),
347
- value: t.s_node(l.CSTML, 'Keyword', 'Infinity'),
348
- });
349
- };
350
-
351
- export const buildNumber = (value) => {
352
- if (Number.isFinite(value)) {
353
- return buildInteger(value);
354
- } else {
355
- return buildInfinity(value);
356
- }
357
- };
358
-
359
- export const buildString = (value) => {
360
- const pieces = isArray(value) ? value : [value];
361
- const tags = [];
362
- let lit = '';
363
-
364
- if (pieces.length === 1 && pieces[0] === "'") {
365
- return t.node(
366
- l.CSTML,
367
- 'String',
368
- btree.from(t.ref`openToken`, t.ref`content`, t.ref`closeToken`),
369
- {
370
- openToken: t.s_node(l.CSTML, 'Punctuator', '"'),
371
- content: interpolateString(agastBuildLiteralTag(value)),
372
- closeToken: t.s_node(l.CSTML, 'Punctuator', '"'),
373
- },
374
- );
375
- }
376
-
377
- for (const piece of pieces) {
378
- if (isString(piece)) {
379
- const value = piece;
380
-
381
- for (const chr of value) {
382
- if (
383
- chr === '\\' ||
384
- chr === "'" ||
385
- chr === '\n' ||
386
- chr === '\r' ||
387
- chr === '\t' ||
388
- chr === '\0' ||
389
- chr.charCodeAt(0) < 32
390
- ) {
391
- if (lit) {
392
- tags.push(agastBuildLiteralTag(lit));
393
- lit = '';
394
- }
395
-
396
- let value;
397
-
398
- if (escapables[chr]) {
399
- value = t.node(l.CSTML, 'EscapeCode', [t.ref`sigilToken`], {
400
- sigilToken: buildKeyword(escapables[chr]),
401
- digits: t.null_node(),
402
- });
403
- } else if (chr.charCodeAt(0) < 32) {
404
- const hexDigits = chr.charCodeAt(0).toString(16).padStart(4, '0');
405
- value = t.node(
406
- l.CSTML,
407
- 'EscapeCode',
408
- btree.fromValues(
409
- concat(
410
- [t.ref`sigilToken`, t.ref`digits[]`, t.arr()],
411
- [...hexDigits].map((d) => t.ref`digits[]`),
412
- ),
413
- ),
414
- {
415
- sigilToken: buildKeyword('u'),
416
- digits: [...hexDigits].map((digit) => buildDigit(digit)),
417
- },
418
- );
419
- } else {
420
- value = buildKeyword(chr);
421
- }
422
-
423
- tags.push(
424
- t.buildEmbeddedNode(
425
- t.e_node(
426
- l.CSTML,
427
- 'EscapeSequence',
428
- [t.ref`escape`, t.ref`value`],
429
- {
430
- escape: t.s_node(l.CSTML, 'Punctuator', '\\'),
431
- value,
432
- },
433
- { cooked: chr },
434
- ),
435
- ),
436
- );
437
- } else {
438
- lit += chr;
439
- }
440
- }
441
- } else {
442
- tags.push(agastBuildLiteralTag(lit));
443
- lit = '';
444
-
445
- if (piece == null) {
446
- throw new Error('not implemented');
447
- } else if (isString(piece.type)) {
448
- tags.push(piece);
449
- } else {
450
- throw new Error();
451
- }
452
- }
453
- }
454
-
455
- if (lit) tags.push(agastBuildLiteralTag(lit));
456
- lit = '';
457
-
458
- return t.node(
459
- l.CSTML,
460
- 'String',
461
- btree.from(t.ref`openToken`, t.ref`content`, t.ref`closeToken`),
462
- {
463
- openToken: t.s_node(l.CSTML, 'Punctuator', "'"),
464
- content: interpolateString(tags),
465
- closeToken: t.s_node(l.CSTML, 'Punctuator', "'"),
466
- },
467
- );
468
- };
469
-
470
- export const buildBoolean = (value) => {
471
- return t.node(l.Instruction, 'Boolean', [t.ref`sigilToken`], {
472
- sigilToken: t.s_node(l.Instruction, 'Keyword', value ? 'true' : 'false'),
473
- });
474
- };
475
-
476
- export const buildNullTag = () => {
477
- return t.node(l.Instruction, 'Null', [t.ref`sigilToken`], {
478
- sigilToken: t.s_node(l.Instruction, 'Keyword', 'null'),
479
- });
480
- };
481
-
482
- export const buildArray = (elements) => {
483
- const elements_ = buildArrayElements(elements);
484
- return t.node(
485
- l.Instruction,
486
- 'Array',
487
- btree.fromValues(
488
- concat([t.ref`openToken`], interpolateFragmentChildren(elements_, t.ref`elements[]`), [
489
- t.ref`closeToken`,
490
- ]),
491
- ),
492
- {
493
- openToken: t.s_node(l.Instruction, 'Punctuator', '['),
494
- elements: elements_.properties['.'],
495
- closeToken: t.s_node(l.Instruction, 'Punctuator', ']'),
496
- },
497
- );
498
- };
499
-
500
- export const buildArrayElements = (values) => {
501
- return buildSpaceSeparatedList(values.map((value) => buildExpression(value)));
502
- };
503
-
504
- export const buildTupleValues = buildArrayElements;
505
-
506
- export const buildTuple = (values) => {
507
- const values_ = buildTupleValues(values);
508
- return t.node(
509
- l.Instruction,
510
- 'Tuple',
511
- btree.fromValues(
512
- concat([t.ref`openToken`], interpolateFragmentChildren(values_, t.ref`values[]`), [
513
- t.ref`closeToken`,
514
- ]),
515
- ),
516
- {
517
- openToken: t.s_node(l.Instruction, 'Punctuator', '('),
518
- values: values_.properties['.'],
519
- closeToken: t.s_node(l.Instruction, 'Punctuator', ')'),
520
- },
521
- );
522
- };
523
-
524
- export const buildSpaceSeparatedList = (values) => {
525
- return t.frag(
526
- btree.fromValues(
527
- concat(
528
- [t.ref`.`, t.arr()],
529
- buildSeparatedListChildren(values, t.ref`.`, t.embedded(buildSpace())),
530
- ),
531
- ),
532
- {
533
- ['.']: values,
534
- },
535
- );
536
- };
537
-
538
- export const buildObjectProperties = (properties) => {
539
- return buildSpaceSeparatedList(
540
- Object.entries(properties).map(({ 0: key, 1: value }) => buildProperty(key, value)),
541
- );
542
- };
543
-
544
- export const buildObject = (properties) => {
545
- const properties_ = buildObjectProperties(properties);
546
- return t.node(
547
- l.Instruction,
548
- 'Object',
549
- btree.fromValues(
550
- concat([t.ref`openToken`], interpolateFragmentChildren(properties_, t.ref`properties[]`), [
551
- t.ref`closeToken`,
552
- ]),
553
- ),
554
- {
555
- openToken: t.s_node(l.Instruction, 'Punctuator', '{'),
556
- properties: properties_.properties['.'],
557
- closeToken: t.s_node(l.Instruction, 'Punctuator', '}'),
558
- },
559
- {},
560
- );
561
- };
562
-
563
- export const buildMappingAttribute = (key, value) => {
564
- return t.node(
565
- l.CSTML,
566
- 'MappingAttribute',
567
- btree.from(t.ref`key`, t.ref`mapOperator`, t.ref`value`),
568
- {
569
- key: buildIdentifier(key),
570
- mapOperator: t.s_node(l.CSTML, 'Punctuator', '='),
571
- value: buildExpression(value),
572
- },
573
- );
574
- };
575
-
576
- export const buildBooleanAttribute = (key, value) => {
577
- return t.node(l.CSTML, 'BooleanAttribute', [...when(!value, [t.ref`negateToken`]), t.ref`key`], {
578
- negateToken: !value ? t.s_node(l.CSTML, 'Puncutator', '!') : t.null_node(),
579
- key: buildIdentifier(key),
580
- });
581
- };
582
-
583
- export const buildAttribute = (key, value) => {
584
- return isBoolean(value) ? buildBooleanAttribute(key, value) : buildMappingAttribute(key, value);
585
- };
586
-
587
- export const buildPattern = (alternatives, flags) => {
588
- return t.node(
589
- l.Regex,
590
- 'Pattern',
591
- btree.fromValues(
592
- concat(
593
- [t.ref`openToken`],
594
- buildSeparatedListChildren(alternatives, t.ref`alternatives[]`, t.ref`separators[]`),
595
- [t.ref`closeToken`, t.ref`flags`],
596
- ),
597
- ),
598
- {
599
- openToken: t.s_node(l.Regex, 'Punctuator', '/'),
600
- alternatives,
601
- separators: alternatives.slice(0, -1).map((alt) => t.s_node(l.Regex, 'Punctuator', '|')),
602
- closeToken: t.s_node(l.Regex, 'Punctuator', '/'),
603
- flags: buildFlags(flags),
604
- },
605
- );
606
- };
607
-
608
- export const buildAlternative = (elements) => {
609
- return t.node(
610
- l.Regex,
611
- 'Pattern',
612
- btree.fromValues(
613
- concat([t.ref`openToken`], buildSeparatedListChildren(elements, t.ref`elements[]`), [
614
- t.ref`closeToken`,
615
- ]),
616
- ),
617
- {
618
- elements,
619
- },
620
- );
621
- };
622
-
623
- export const buildExpression = (expr) => {
624
- if (isNull(expr)) return buildNullTag();
625
-
626
- switch (typeof expr) {
627
- case 'boolean':
628
- return buildBoolean(expr);
629
- case 'string':
630
- return buildString(expr);
631
- case 'number':
632
- return buildInteger(expr);
633
- case 'object': {
634
- switch (getPrototypeOf(expr)) {
635
- case Array.prototype:
636
- return buildArray(expr);
637
- case Object.prototype:
638
- if (expr.type && expr.language && expr.children && expr.properties) {
639
- return expr;
640
- }
641
- return buildObject(expr);
642
- default:
643
- throw new Error();
644
- }
645
- }
646
- default:
647
- throw new Error();
648
- }
649
- };
650
-
651
- export const buildAttributes = (attributes = {}) => {
652
- const attributes_ = Object.entries(attributes).map(({ 0: key, 1: value }) =>
653
- buildAttribute(key, value),
654
- );
655
-
656
- return t.frag(
657
- btree.fromValues(
658
- [t.ref`.[]`, t.arr()],
659
- buildSeparatedListChildren(attributes_, t.ref`.[]`, t.embedded(buildSpace())),
660
- ),
661
- {
662
- ['.']: attributes_,
663
- },
664
- );
665
- };
666
-
667
- export const buildNodeMatcher = (flags, language, type, attributes) => {
668
- let language_ = !language || language.length === 0 ? null : language;
669
-
670
- const flags_ = buildFlags(flags);
671
-
672
- return t.node(
673
- l.Spamex,
674
- 'NodeMatcher',
675
- btree.fromValues(
676
- concat(
677
- [t.ref`openToken`],
678
- when(flags_, [t.ref`flags`]),
679
- when(language_, [t.ref`language`, t.ref`languageSeparator`]),
680
- [t.ref`type`],
681
- when(attributes.length, [t.embedded(buildSpace())]),
682
- [...btree.traverse(attributes.children)].slice(1, -1),
683
- [t.ref`closeToken`],
684
- ),
685
- ),
686
- {
687
- openToken: t.s_node(l.CSTML, 'Punctuator', '<'),
688
- language: buildLanguage(language_),
689
- languageSeparator: language_ && type ? t.s_node(l.CSTML, 'Punctuator', ':') : t.null_node(),
690
- flags: flags_,
691
- type: buildIdentifier(type),
692
- attributes: attributes.properties.attributes,
693
- closeToken: t.s_node(l.CSTML, 'Punctuator', '>'),
694
- },
695
- );
696
- };