@bablr/boot 0.6.3 → 0.7.1

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.
@@ -1,132 +1,69 @@
1
- const objectEntries = require('iter-tools/methods/object-entries');
2
-
3
- const { buildCovers } = require('../utils.js');
4
- const sym = require('@bablr/boot-helpers/symbols');
1
+ import * as sym from '@bablr/agast-helpers/symbols';
2
+ import * as JSON from './json.js';
5
3
 
6
4
  const _ = /\s+/y;
7
5
  const PN = 'Punctuator';
8
- const ID = 'Identifier';
9
6
  const KW = 'Keyword';
10
- const LIT = 'Literal';
11
-
12
- const name = 'CSTML';
13
-
14
- const canonicalURL = 'https://bablr.org/languages/core/en/cstml';
15
-
16
- const dependencies = {};
17
-
18
- const escapables = new Map(
19
- objectEntries({
20
- n: '\n',
21
- r: '\r',
22
- t: '\t',
23
- 0: '\0',
24
- }),
25
- );
26
-
27
- const cookEscape = (escape, span) => {
28
- let hexMatch;
29
-
30
- if (!escape.startsWith('\\')) {
31
- throw new Error('string escape must start with \\');
32
- }
33
-
34
- if ((hexMatch = /\\u([0-9a-f]{4})/iy.exec(escape))) {
35
- //continue
36
- } else if ((hexMatch = /\\u{([0-9a-f]+)}/iy.exec(escape))) {
37
- //continue
38
- }
39
7
 
40
- if (hexMatch) {
41
- return String.fromCodePoint(parseInt(hexMatch[1], 16));
42
- }
43
-
44
- const litPattern = span === 'Single' ? /\\([\\gnrt0'])/y : /\\([\\gnrt0"])/y;
45
- const litMatch = litPattern.exec(escape);
8
+ export const name = 'CSTML';
46
9
 
47
- if (litMatch) {
48
- if (litMatch[1] === 'g') {
49
- return null;
50
- } else {
51
- return escapables.get(litMatch[1]) || litMatch[1];
52
- }
53
- }
10
+ export const canonicalURL = 'https://bablr.org/languages/core/en/cstml';
54
11
 
55
- throw new Error('unable to cook string escape');
12
+ export const dependencies = {
13
+ JSON,
56
14
  };
57
15
 
58
- const covers = buildCovers({
59
- [sym.node]: [
60
- 'Document',
61
- 'DocumentVersion',
62
- 'DoctypeTag',
63
- 'Attribute',
64
- 'Property',
65
- 'ReferenceTag',
66
- 'TagType',
67
- 'NullTag',
68
- 'GapTag',
69
- 'Node',
70
- 'Fragment',
71
- 'IdentifierPath',
72
- 'OpenNodeTag',
73
- 'CloseNodeTag',
74
- 'OpenFragmentTag',
75
- 'CloseFragmentTag',
76
- 'Tag',
77
- 'Number',
78
- 'Digit',
79
- 'String',
80
- 'Content',
81
- 'UnsignedInteger',
82
- 'Flags',
83
- 'Array',
84
- 'Object',
85
- 'Boolean',
86
- 'Null',
87
- 'Identifier',
88
- 'JSONProperty',
89
- 'JSONExpression',
16
+ export const covers = new Map([
17
+ [
18
+ sym.node,
19
+ new Set([
20
+ 'Document',
21
+ 'DocumentVersion',
22
+ 'DoctypeTag',
23
+ 'Property',
24
+ 'ReferenceTag',
25
+ 'ReferenceFlags',
26
+ 'Identifier',
27
+ 'GlobalIdentifier',
28
+ 'NullTag',
29
+ 'GapTag',
30
+ 'Node',
31
+ 'IdentifierPath',
32
+ 'OpenNodeTag',
33
+ 'CloseNodeTag',
34
+ 'LiteralTag',
35
+ 'Trivia',
36
+ 'Number',
37
+ 'Digit',
38
+ 'Content',
39
+ 'NodeFlags',
40
+ ]),
90
41
  ],
91
- [sym.fragment]: ['Attributes'],
92
- Attribute: ['MappingAttribute', 'BooleanAttribute'],
93
- JSONExpression: [
94
- 'Boolean',
95
- 'Null',
96
- 'Number',
97
- 'String',
98
- 'Array',
99
- 'Object',
100
- 'Identifier',
101
- 'Separator',
102
- ],
103
- TagType: ['Identifier', 'GlobalIdentifier'],
104
- Tag: ['LiteralTag', 'Trivia'],
105
- PropertyValue: ['GapTag', 'Node', 'NullTag'],
106
- EmbeddedTag: ['LiteralTag'],
107
- Number: ['Integer', 'Infinity'],
108
- });
109
-
110
- const grammar = class CSTMLMiniparserGrammar {
42
+ ['TagType', new Set(['Identifier', 'GlobalIdentifier'])],
43
+ ['Tag', new Set(['LiteralTag', 'Trivia'])],
44
+ ['PropertyValue', new Set(['GapTag', 'Node', 'NullTag'])],
45
+ ]);
46
+
47
+ export const grammar = class CSTMLMiniparserGrammar {
111
48
  // @Node
112
49
  Document(p) {
113
50
  p.eatProduction('DoctypeTag', { path: 'doctype' });
114
51
  p.eatMatchTrivia(_);
115
- p.eatProduction('Fragment', { path: 'tree' });
52
+ p.eatProduction('Node', { path: 'tree' });
116
53
  }
117
54
 
118
55
  // @Node
119
56
  DoctypeTag(p) {
120
57
  p.eat('<!', PN, { path: 'openToken' });
121
- p.eatProduction('UnsignedInteger', { path: 'version' });
58
+ p.eatProduction('JSON:UnsignedInteger', { path: 'version' });
122
59
  p.eat(':', PN, { path: 'versionSeparatorToken' });
123
60
  p.eat('cstml', KW, { path: 'doctypeToken' });
124
61
 
125
- let sp = p.eatMatchTrivia(_);
62
+ p.eatMatchTrivia(_);
126
63
 
127
- if ((sp && p.match(/!?[a-zA-Z]/y)) || p.atExpression) {
128
- p.eatProduction('Attributes');
129
- sp = p.eatMatchTrivia(_);
64
+ if (p.match('{') || p.atExpression) {
65
+ p.eatProduction('JSON:Object', { path: 'attributes' });
66
+ p.eatMatchTrivia(_);
130
67
  }
131
68
 
132
69
  p.eat('>', PN, { path: 'closeToken' });
@@ -175,7 +112,7 @@ const grammar = class CSTMLMiniparserGrammar {
175
112
  } else {
176
113
  if (p.match(/<\*?#/y)) {
177
114
  p.eatProduction('Node');
178
- } else if (p.match(/[a-zA-Z]|\./y)) {
115
+ } else if (p.match(/[a-zA-Z]|[.#@]/y)) {
179
116
  p.eatProduction('Property');
180
117
  } else if (p.match(/['"]/y)) {
181
118
  p.eatProduction('LiteralTag');
@@ -183,25 +120,6 @@ const grammar = class CSTMLMiniparserGrammar {
183
120
  }
184
121
  }
185
122
 
186
- // @Node
187
- Fragment(p) {
188
- let open = p.eatProduction('OpenFragmentTag', { path: 'open' });
189
-
190
- p.eatMatchTrivia(_);
191
-
192
- if (open.properties.flags?.token) {
193
- p.eatProduction('NodeChild', { path: 'children[]' }, { token: true });
194
- p.eatMatchTrivia(_);
195
- }
196
-
197
- while (!(p.match('</') || p.done)) {
198
- p.eatProduction('NodeChild', { path: 'children[]' });
199
- p.eatMatchTrivia(_);
200
- }
201
-
202
- p.eatProduction('CloseFragmentTag', { path: 'close' });
203
- }
204
-
205
123
  // @Node
206
124
  Property(p) {
207
125
  p.eatProduction('ReferenceTag', { path: 'reference' });
@@ -220,14 +138,9 @@ const grammar = class CSTMLMiniparserGrammar {
220
138
  }
221
139
 
222
140
  // @Node
223
- Flags(p) {
224
- let tr = p.eatMatch('#', PN, { path: 'triviaToken' });
141
+ NodeFlags(p) {
225
142
  p.eatMatch('*', PN, { path: 'tokenToken' });
226
- let esc = p.eatMatch('@', PN, { path: 'escapeToken' });
227
- let exp = p.eatMatch('+', PN, { path: 'expressionToken' });
228
143
  p.eatMatch('$', PN, { path: 'hasGapToken' });
229
-
230
- if ((tr && esc) || (exp && (tr || esc))) throw new Error();
231
144
  }
232
145
 
233
146
  // @Node
@@ -236,36 +149,36 @@ const grammar = class CSTMLMiniparserGrammar {
236
149
 
237
150
  let flags = null;
238
151
  if (!p.atExpression) {
239
- flags = p.eatProduction('Flags', { path: 'flags' });
152
+ flags = p.eatProduction('NodeFlags', { path: 'flags' });
240
153
  }
241
154
 
242
- if (p.done) {
243
- p.eat('>', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
244
- return;
245
- }
155
+ let sp = null;
156
+ let isFragment = !p.match(/['"a-zA-Z]/y);
246
157
 
247
- p.eatProduction('TagType', { path: 'type' });
158
+ if (!isFragment) {
159
+ p.eatProduction('TagType', { path: 'type' });
248
160
 
249
- let sp = p.eatMatchTrivia(_);
161
+ sp = p.eatMatchTrivia(_);
250
162
 
251
- let iv;
163
+ let iv;
252
164
 
253
- if (sp && (p.match(/['"]/y) || p.atExpression)) {
254
- iv = p.eatProduction('String', { path: 'intrinsicValue' });
165
+ if (sp && (p.match(/['"]/y) || p.atExpression)) {
166
+ iv = p.eatProduction('JSON:String', { path: 'intrinsicValue' });
255
167
 
256
- sp = p.eatMatchTrivia(_);
257
- }
168
+ sp = p.eatMatchTrivia(_);
169
+ }
258
170
 
259
- if (!flags.properties.tokenToken && iv) {
260
- throw new Error();
261
- }
171
+ if (!flags.properties.tokenToken && iv) {
172
+ throw new Error();
173
+ }
262
174
 
263
- if ((sp && p.match(/[a-zA-Z]+/y)) || p.atExpression) {
264
- p.eatProduction('Attributes');
265
- sp = p.eatMatchTrivia(_);
266
- }
175
+ if (p.match('{') || p.atExpression) {
176
+ p.eatProduction('Object');
177
+ sp = p.eatMatchTrivia(_);
178
+ }
267
179
 
268
- p.eatMatchTrivia(_);
180
+ p.eatMatchTrivia(_);
181
+ }
269
182
  p.eatMatch('/', PN, { path: 'selfClosingTagToken' });
270
183
  p.eat('>', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
271
184
  }
@@ -276,87 +189,8 @@ const grammar = class CSTMLMiniparserGrammar {
276
189
  p.eat('>', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
277
190
  }
278
191
 
279
- // @Node
280
- OpenFragmentTag(p) {
281
- p.eat('<', PN, { path: 'openToken', startSpan: 'Tag', balanced: '>' });
282
-
283
- let flags = null;
284
- if (!p.atExpression) {
285
- flags = p.eatProduction('Flags', { path: 'flags' });
286
- }
287
-
288
- if (p.done) {
289
- p.eat('>', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
290
- return;
291
- }
292
- }
293
-
294
- // @Node
295
- CloseFragmentTag(p) {
296
- p.eat('</', PN, { path: 'openToken', startSpan: 'Tag', balanced: '>' });
297
- p.eat('>', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
298
- }
299
-
300
- // @Fragment
301
- Attributes(p) {
302
- let sp = true;
303
- while (sp && (p.match(/!?[a-zA-Z]/y) || p.atExpression)) {
304
- if (p.atExpression) {
305
- p.eatProduction('Attributes'); // ??
306
- } else {
307
- p.eatProduction('Attribute', { path: 'attributes[]' });
308
- }
309
- if (p.match(/\s+!?[a-zA-Z]/y) || (p.match(/\s+$/y) && !p.quasisDone)) {
310
- sp = p.eatMatchTrivia(_);
311
- } else {
312
- sp = false;
313
- }
314
- }
315
- }
316
-
317
- // @Cover
318
- Attribute(p) {
319
- if (p.match(/[a-zA-Z][a-zA-Z-_]*\s*=/y)) {
320
- p.eatProduction('MappingAttribute');
321
- } else {
322
- p.eatProduction('BooleanAttribute');
323
- }
324
- }
325
-
326
- // @Node
327
- BooleanAttribute(p) {
328
- p.eatMatch('!', KW, { path: 'negateToken' });
329
- p.eat(/[a-zA-Z][a-zA-Z-_]*/y, ID, { path: 'key' });
330
- }
331
-
332
- // @Node
333
- MappingAttribute(p) {
334
- p.eat(/[a-zA-Z][a-zA-Z-_]*/y, ID, { path: 'key' });
335
- p.eatMatchTrivia(_);
336
- p.eat('=', PN, { path: 'mapToken' });
337
- p.eatMatchTrivia(_);
338
- p.eatProduction('JSONExpression', { path: 'value' });
339
- }
340
-
341
- // @Cover
342
- JSONExpression(p) {
343
- if (p.match(/['"]/y)) {
344
- p.eatProduction('String');
345
- } else if (p.match(/[\d+-]/y)) {
346
- p.eatProduction('Number');
347
- } else if (p.match('[')) {
348
- p.eatProduction('Array');
349
- } else if (p.match('{')) {
350
- p.eatProduction('Object');
351
- } else if (p.match(/true|false/y)) {
352
- p.eatProduction('Boolean');
353
- } else if (p.match('null')) {
354
- p.eatProduction('Null');
355
- }
356
- }
357
-
358
192
  TagType(p) {
359
- if (p.match(/['"]|[a-zA-Z\.]+:/y)) {
193
+ if (p.match(/['"]|[a-zA-Z.]+:/y) || (p.atExpression && p.quasis[p.quasiIdx + 1][0] === ':')) {
360
194
  p.eatProduction('LanguageReference', { path: 'language' });
361
195
  p.eat(':', PN, { path: 'namespaceSeparatorToken' });
362
196
  p.eatProduction('Identifier', { path: 'type' });
@@ -367,7 +201,7 @@ const grammar = class CSTMLMiniparserGrammar {
367
201
 
368
202
  LanguageReference(p) {
369
203
  if (p.match(/['"]/y)) {
370
- p.eatProduction('String');
204
+ p.eatProduction('JSON:String');
371
205
  } else {
372
206
  p.eatProduction('IdentifierPath');
373
207
  }
@@ -376,7 +210,7 @@ const grammar = class CSTMLMiniparserGrammar {
376
210
  IdentifierPath(p) {
377
211
  p.eatProduction('Identifier', { path: 'segments[]' });
378
212
  while (p.match('.')) {
379
- p.eat('.', PN, { path: 'separators[]' });
213
+ p.eat('.', PN, { path: 'separatorTokens[]' });
380
214
  p.eatProduction('Identifier', { path: 'segments[]' });
381
215
  }
382
216
  }
@@ -397,164 +231,41 @@ const grammar = class CSTMLMiniparserGrammar {
397
231
 
398
232
  // @Node
399
233
  ReferenceTag(p) {
400
- if (p.match('.')) {
401
- p.eat('.', PN, { path: 'name' });
234
+ let name;
235
+ if ((name = p.match(/[.#@]/y))) {
236
+ p.eat(name, PN, { path: 'name' });
402
237
  } else {
403
238
  p.eatProduction('Identifier', { path: 'name' });
404
239
  }
405
240
  p.eatMatchTrivia(_);
406
- p.eatMatch('[]', PN, { path: 'arrayToken' });
407
- p.eatMatchTrivia(_);
408
- p.eat(':', PN, { path: 'mapToken' });
409
- }
410
-
411
- // @Cover
412
- EmbeddedTag(p) {
413
- if (p.match(/!['"]/y)) {
414
- p.eatProduction('Escape');
415
- } else if (p.match(/['"]/y)) {
416
- p.eatProduction('LiteralTag');
417
- } else {
418
- throw new Error();
419
- }
420
- }
241
+ let open = p.eatMatch('[', PN, { path: 'openIndex', startSpan: 'Index', balanced: ']' });
421
242
 
422
- // @Node
423
- Array(p) {
424
- p.eat('[', PN, { path: 'openToken', balanced: ']' });
425
-
426
- p.eatMatchTrivia(_);
243
+ if (open) {
244
+ p.eatMatchTrivia(_);
427
245
 
428
- let first = true;
429
- let sep;
430
- while (first || (sep && (p.match(/./y) || p.atExpression))) {
431
- p.eatProduction('JSONExpression', { path: 'elements[]' });
432
- if (p.match(/\s*,?/y)) {
433
- sep = p.eatProduction('Separator', { path: 'separators[]' });
246
+ if (p.match(/\d/)) {
247
+ p.eatProduction('UnsignedInteger', { path: 'index' });
434
248
  }
435
249
 
436
- first = false;
250
+ p.eatMatchTrivia(_);
251
+ p.eat(']', PN, { path: 'closeIndex', endSpan: 'Index', balancer: true });
437
252
  }
438
-
439
- p.eat(']', PN, { path: 'closeToken', balancer: true });
440
- }
441
-
442
- // @Node
443
- Object(p) {
444
- p.eat('{', PN, { path: 'openToken', balanced: '}' });
445
-
446
253
  p.eatMatchTrivia(_);
447
-
448
- let first = true;
449
- let sep;
450
- while (first || (sep && (p.match(/./y) || p.atExpression))) {
451
- p.eatProduction('JSONProperty', { path: 'properties[]' });
452
- if (p.match(/\s*,?/y)) {
453
- sep = p.eatProduction('Separator', { path: 'separators[]' });
454
- }
455
- first = false;
254
+ if (p.match(/[+$]/y)) {
255
+ p.eatProduction('ReferenceFlags', { path: 'flags' });
256
+ p.eatMatchTrivia(_);
456
257
  }
457
-
458
- p.eatMatchTrivia(_);
459
-
460
- p.eat('}', PN, { path: 'closeToken', balancer: true });
461
- }
462
-
463
- // @Node
464
- JSONProperty(p) {
465
- p.eat(/[a-zA-Z]+/y, LIT, { path: 'key' });
466
- p.eatMatchTrivia(_);
467
258
  p.eat(':', PN, { path: 'mapToken' });
468
- p.eatMatchTrivia(_);
469
- p.eatProduction('JSONExpression', { path: 'value' });
470
- }
471
-
472
- // @Node
473
- Boolean(p) {
474
- p.eat(/true|false/y, KW, { path: 'sigilToken' });
475
- }
476
-
477
- // @Node
478
- Null(p) {
479
- p.eat('null', KW, { path: 'sigilToken' });
480
- }
481
-
482
- //@Node
483
- Separator(p) {
484
- p.eatMatchTrivia(_);
485
- p.eatMatch(/,/y, PN, { path: 'separators[]' });
486
- p.eatMatchTrivia(_);
487
- }
488
-
489
- //@Node
490
- Number(p) {
491
- if (p.match(/-?\d/y)) {
492
- p.eatProduction('Integer');
493
- } else {
494
- p.eatProduction('Infinity');
495
- }
496
259
  }
497
260
 
498
261
  // @Node
499
- Integer(p) {
500
- p.eatMatch('-', 'Punctuator', { path: 'negative' });
501
- p.eatProduction('Digits', { path: 'digits[]' });
502
- }
503
-
504
- // @Node
505
- UnsignedInteger(p) {
506
- p.eatProduction('Digits', { path: 'digits[]' });
507
- }
508
-
509
- // @Node
510
- Infinity(p) {
511
- p.eatMatch(/[+-]/, 'Punctuator', { path: 'sign' });
512
- p.eat('Infinity', 'Keyword', { path: 'value' });
513
- }
514
-
515
- Digits(p) {
516
- while (p.match(/\d/y)) {
517
- p.eatProduction('Digit');
518
- }
519
- }
520
-
521
- // @Node
522
- Digit(p) {
523
- p.eatLiteral(/\d/y);
524
- }
525
-
526
- // @Node
527
- String(p) {
528
- const q = p.match(/['"]/y) || '"';
529
-
530
- const span = q === '"' ? 'Double' : 'Single';
531
-
532
- p.eat(q, PN, { path: 'openToken', startSpan: span, balanced: q });
533
- while (p.match(/./sy) || p.atExpression) {
534
- p.eatProduction('Content', { path: 'content' });
535
- }
536
- p.eat(q, PN, { path: 'closeToken', endSpan: span, balancer: true });
262
+ ReferenceFlags(p) {
263
+ p.eatMatch('+', PN, { path: 'expressionToken' });
264
+ p.eatMatch('$', PN, { path: 'hasGapToken' });
537
265
  }
538
266
 
539
267
  // @Node
540
- Content(p) {
541
- let esc, lit;
542
- let i = 0;
543
- do {
544
- esc =
545
- p.span.type === 'Single'
546
- ? p.eatMatchEscape(/\\(u(\{\d{1,6}\}|\d{4})|[\\gnrt0'])/y)
547
- : p.eatMatchEscape(/\\(u(\{\d{1,6}\}|\d{4})|[\\gnrt0"])/y);
548
- lit =
549
- p.span.type === 'Single'
550
- ? p.eatMatchLiteral(/[^\r\n\0\\']+/y)
551
- : p.eatMatchLiteral(/[^\r\n\0\\"]+/y);
552
- i++;
553
- } while (esc || lit);
554
- if (i === 1 && !esc && !lit) {
555
- throw new Error('Invalid string content');
556
- }
268
+ Literal(p) {
269
+ p.eatProduction('JSON:String', { path: 'value' });
557
270
  }
558
271
  };
559
-
560
- module.exports = { name, canonicalURL, dependencies, covers, grammar, cookEscape, escapables };