@bablr/boot 0.4.0 → 0.6.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 +122 -55
- package/lib/index.js +131 -39
- package/lib/index.mjs +15 -1
- package/lib/languages/cstml.js +54 -40
- package/lib/languages/instruction.js +1 -1
- package/lib/languages/regex.js +3 -3
- package/lib/languages/spamex.js +41 -8
- package/lib/match.js +1 -1
- package/lib/miniparser.js +18 -6
- package/lib/print.js +196 -128
- package/package.json +3 -2
- package/shorthand.macro.js +108 -69
- package/lib/symbols.js +0 -4
package/lib/languages/cstml.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
const objectEntries = require('iter-tools/methods/object-entries');
|
|
2
2
|
|
|
3
3
|
const { buildCovers } = require('../utils.js');
|
|
4
|
-
const sym = require('
|
|
4
|
+
const sym = require('@bablr/boot-helpers/symbols');
|
|
5
5
|
|
|
6
6
|
const _ = /\s+/y;
|
|
7
7
|
const PN = 'Punctuator';
|
|
8
8
|
const ID = 'Identifier';
|
|
9
9
|
const KW = 'Keyword';
|
|
10
|
-
const LIT = 'Literal';
|
|
11
10
|
|
|
12
11
|
const name = 'CSTML';
|
|
13
12
|
|
|
@@ -62,15 +61,15 @@ const covers = buildCovers({
|
|
|
62
61
|
'DoctypeTag',
|
|
63
62
|
'Attribute',
|
|
64
63
|
'Property',
|
|
65
|
-
'
|
|
64
|
+
'ReferenceTag',
|
|
66
65
|
'TagType',
|
|
67
|
-
'
|
|
68
|
-
'
|
|
66
|
+
'NullTag',
|
|
67
|
+
'GapTag',
|
|
69
68
|
'Node',
|
|
70
69
|
'IdentifierPath',
|
|
71
70
|
'OpenNodeTag',
|
|
72
71
|
'CloseNodeTag',
|
|
73
|
-
'
|
|
72
|
+
'Tag',
|
|
74
73
|
'Number',
|
|
75
74
|
'Digit',
|
|
76
75
|
'String',
|
|
@@ -82,9 +81,9 @@ const covers = buildCovers({
|
|
|
82
81
|
Attribute: ['MappingAttribute', 'BooleanAttribute'],
|
|
83
82
|
AttributeValue: ['String', 'Number'],
|
|
84
83
|
TagType: ['Identifier', 'GlobalIdentifier'],
|
|
85
|
-
|
|
86
|
-
PropertyValue: ['
|
|
87
|
-
|
|
84
|
+
Tag: ['LiteralTag', 'Trivia'],
|
|
85
|
+
PropertyValue: ['GapTag', 'Node', 'NullTag'],
|
|
86
|
+
EmbeddedTag: ['LiteralTag'],
|
|
88
87
|
Number: ['Integer', 'Infinity'],
|
|
89
88
|
});
|
|
90
89
|
|
|
@@ -92,6 +91,7 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
92
91
|
// @Node
|
|
93
92
|
Document(p) {
|
|
94
93
|
p.eatProduction('DoctypeTag', { path: 'doctype' });
|
|
94
|
+
p.eatMatchTrivia(_);
|
|
95
95
|
p.eatProduction('Node', { path: 'tree' });
|
|
96
96
|
}
|
|
97
97
|
|
|
@@ -104,7 +104,7 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
104
104
|
|
|
105
105
|
let sp = p.eatMatchTrivia(_);
|
|
106
106
|
|
|
107
|
-
if ((sp && p.match(
|
|
107
|
+
if ((sp && p.match(/!?[a-zA-Z]/y)) || p.atExpression) {
|
|
108
108
|
p.eatProduction('Attributes');
|
|
109
109
|
sp = p.eatMatchTrivia(_);
|
|
110
110
|
}
|
|
@@ -113,12 +113,12 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
// @Node
|
|
116
|
-
|
|
116
|
+
NullTag(p) {
|
|
117
117
|
p.eat('null', KW, { path: 'sigilToken' });
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
// @Node
|
|
121
|
-
|
|
121
|
+
GapTag(p) {
|
|
122
122
|
p.eat('<//>', PN, { path: 'sigilToken' });
|
|
123
123
|
}
|
|
124
124
|
|
|
@@ -131,14 +131,16 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
131
131
|
if (open.properties.flags?.token) {
|
|
132
132
|
p.eatProduction('NodeChild', { path: 'children[]' }, { token: true });
|
|
133
133
|
p.eatMatchTrivia(_);
|
|
134
|
-
} else {
|
|
135
|
-
while (!p.match('</')) {
|
|
134
|
+
} else if (!open.properties.selfClosingTagToken) {
|
|
135
|
+
while (!(p.match('</') || p.done)) {
|
|
136
136
|
p.eatProduction('NodeChild', { path: 'children[]' });
|
|
137
137
|
p.eatMatchTrivia(_);
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
-
|
|
141
|
+
if (!open.properties.selfClosingTagToken) {
|
|
142
|
+
p.eatProduction('CloseNodeTag', { path: 'close' });
|
|
143
|
+
}
|
|
142
144
|
}
|
|
143
145
|
|
|
144
146
|
NodeChild(p, _, props) {
|
|
@@ -148,31 +150,31 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
148
150
|
if (p.match(/<\*?@/y)) {
|
|
149
151
|
p.eatProduction('Node');
|
|
150
152
|
} else {
|
|
151
|
-
p.eatProduction('
|
|
153
|
+
p.eatProduction('LiteralTag');
|
|
152
154
|
}
|
|
153
155
|
} else {
|
|
154
156
|
if (p.match(/<\*?#/y)) {
|
|
155
157
|
p.eatProduction('Node');
|
|
156
|
-
} else if (p.match(/[a-zA-Z]
|
|
158
|
+
} else if (p.match(/[a-zA-Z]|\./y)) {
|
|
157
159
|
p.eatProduction('Property');
|
|
158
160
|
} else if (p.match(/['"]/y)) {
|
|
159
|
-
p.eatProduction('
|
|
161
|
+
p.eatProduction('LiteralTag');
|
|
160
162
|
}
|
|
161
163
|
}
|
|
162
164
|
}
|
|
163
165
|
|
|
164
166
|
// @Node
|
|
165
167
|
Property(p) {
|
|
166
|
-
p.eatProduction('
|
|
168
|
+
p.eatProduction('ReferenceTag', { path: 'reference' });
|
|
167
169
|
p.eatMatchTrivia(_);
|
|
168
170
|
p.eatProduction('PropertyValue', { path: 'value' });
|
|
169
171
|
}
|
|
170
172
|
|
|
171
173
|
PropertyValue(p) {
|
|
172
174
|
if (p.match('null')) {
|
|
173
|
-
p.eatProduction('
|
|
175
|
+
p.eatProduction('NullTag');
|
|
174
176
|
} else if (p.match('<//>')) {
|
|
175
|
-
p.eatProduction('
|
|
177
|
+
p.eatProduction('GapTag');
|
|
176
178
|
} else {
|
|
177
179
|
p.eatProduction('Node');
|
|
178
180
|
}
|
|
@@ -181,10 +183,10 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
181
183
|
// @Node
|
|
182
184
|
Flags(p) {
|
|
183
185
|
let tr = p.eatMatch('#', PN, { path: 'triviaToken' });
|
|
184
|
-
p.eatMatch('~', PN, { path: 'intrinsicToken' });
|
|
185
186
|
p.eatMatch('*', PN, { path: 'tokenToken' });
|
|
186
187
|
let esc = p.eatMatch('@', PN, { path: 'escapeToken' });
|
|
187
188
|
let exp = p.eatMatch('+', PN, { path: 'expressionToken' });
|
|
189
|
+
p.eatMatch('$', PN, { path: 'hasGapToken' });
|
|
188
190
|
|
|
189
191
|
if ((tr && esc) || (exp && (tr || esc))) throw new Error();
|
|
190
192
|
}
|
|
@@ -198,26 +200,34 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
198
200
|
flags = p.eatProduction('Flags', { path: 'flags' });
|
|
199
201
|
}
|
|
200
202
|
|
|
203
|
+
if (p.done) {
|
|
204
|
+
p.eat('>', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
201
208
|
p.eatProduction('TagType', { path: 'type' });
|
|
202
209
|
|
|
203
210
|
let sp = p.eatMatchTrivia(_);
|
|
204
211
|
|
|
205
212
|
let iv;
|
|
206
|
-
|
|
213
|
+
|
|
214
|
+
if (sp && (p.match(/['"]/y) || p.atExpression)) {
|
|
207
215
|
iv = p.eatProduction('String', { path: 'intrinsicValue' });
|
|
208
216
|
|
|
209
217
|
sp = p.eatMatchTrivia(_);
|
|
210
218
|
}
|
|
211
219
|
|
|
220
|
+
if (!flags.properties.tokenToken && iv) {
|
|
221
|
+
throw new Error();
|
|
222
|
+
}
|
|
223
|
+
|
|
212
224
|
if ((sp && p.match(/[a-zA-Z]+/y)) || p.atExpression) {
|
|
213
225
|
p.eatProduction('Attributes');
|
|
214
226
|
sp = p.eatMatchTrivia(_);
|
|
215
227
|
}
|
|
216
228
|
|
|
217
229
|
p.eatMatchTrivia(_);
|
|
218
|
-
|
|
219
|
-
p.eat('/', PN, { path: 'selfClosingTagToken' });
|
|
220
|
-
}
|
|
230
|
+
p.eatMatch('/', PN, { path: 'selfClosingTagToken' });
|
|
221
231
|
p.eat('>', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
|
|
222
232
|
}
|
|
223
233
|
|
|
@@ -230,13 +240,13 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
230
240
|
// @Fragment
|
|
231
241
|
Attributes(p) {
|
|
232
242
|
let sp = true;
|
|
233
|
-
while (sp && (p.match(
|
|
243
|
+
while (sp && (p.match(/!?[a-zA-Z]/y) || p.atExpression)) {
|
|
234
244
|
if (p.atExpression) {
|
|
235
245
|
p.eatProduction('Attributes'); // ??
|
|
236
246
|
} else {
|
|
237
247
|
p.eatProduction('Attribute', { path: 'attributes[]' });
|
|
238
248
|
}
|
|
239
|
-
if (p.match(/\s
|
|
249
|
+
if (p.match(/\s+!?[a-zA-Z]/y) || (p.match(/\s+$/y) && !p.quasisDone)) {
|
|
240
250
|
sp = p.eatMatchTrivia(_);
|
|
241
251
|
} else {
|
|
242
252
|
sp = false;
|
|
@@ -246,7 +256,7 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
246
256
|
|
|
247
257
|
// @Cover
|
|
248
258
|
Attribute(p) {
|
|
249
|
-
if (p.match(/[a-zA-Z][
|
|
259
|
+
if (p.match(/[a-zA-Z][a-zA-Z-_]*\s*=/y)) {
|
|
250
260
|
p.eatProduction('MappingAttribute');
|
|
251
261
|
} else {
|
|
252
262
|
p.eatProduction('BooleanAttribute');
|
|
@@ -255,13 +265,13 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
255
265
|
|
|
256
266
|
// @Node
|
|
257
267
|
BooleanAttribute(p) {
|
|
258
|
-
p.
|
|
259
|
-
p.eat(/[a-zA-Z]
|
|
268
|
+
p.eatMatch('!', KW, { path: 'negateToken' });
|
|
269
|
+
p.eat(/[a-zA-Z][a-zA-Z-_]*/y, ID, { path: 'key' });
|
|
260
270
|
}
|
|
261
271
|
|
|
262
272
|
// @Node
|
|
263
273
|
MappingAttribute(p) {
|
|
264
|
-
p.eat(/[a-zA-Z]
|
|
274
|
+
p.eat(/[a-zA-Z][a-zA-Z-_]*/y, ID, { path: 'key' });
|
|
265
275
|
p.eatMatchTrivia(_);
|
|
266
276
|
p.eat('=', PN, { path: 'mapToken' });
|
|
267
277
|
p.eatMatchTrivia(_);
|
|
@@ -278,7 +288,7 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
278
288
|
}
|
|
279
289
|
|
|
280
290
|
TagType(p) {
|
|
281
|
-
if (p.match(/[
|
|
291
|
+
if (p.match(/[a-zA-Z\.]+:/y)) {
|
|
282
292
|
p.eatProduction('LanguageReference', { path: 'language' });
|
|
283
293
|
p.eat(':', PN, { path: 'namespaceSeparatorToken' });
|
|
284
294
|
p.eatProduction('Identifier', { path: 'type' });
|
|
@@ -305,21 +315,25 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
305
315
|
|
|
306
316
|
// @Node
|
|
307
317
|
Identifier(p) {
|
|
308
|
-
p.eatLiteral(/[a-zA-Z][
|
|
318
|
+
p.eatLiteral(/[a-zA-Z][a-zA-Z-_]*/y);
|
|
309
319
|
}
|
|
310
320
|
|
|
311
321
|
// @Cover
|
|
312
|
-
|
|
322
|
+
Tag(p) {
|
|
313
323
|
if (p.match(/['"]/y)) {
|
|
314
|
-
p.eatProduction('
|
|
324
|
+
p.eatProduction('LiteralTag');
|
|
315
325
|
} else {
|
|
316
326
|
throw new Error();
|
|
317
327
|
}
|
|
318
328
|
}
|
|
319
329
|
|
|
320
330
|
// @Node
|
|
321
|
-
|
|
322
|
-
p.
|
|
331
|
+
ReferenceTag(p) {
|
|
332
|
+
if (p.match('.')) {
|
|
333
|
+
p.eat('.', PN, { path: 'name' });
|
|
334
|
+
} else {
|
|
335
|
+
p.eatProduction('Identifier', { path: 'name' });
|
|
336
|
+
}
|
|
323
337
|
p.eatMatchTrivia(_);
|
|
324
338
|
p.eatMatch('[]', PN, { path: 'arrayToken' });
|
|
325
339
|
p.eatMatchTrivia(_);
|
|
@@ -327,11 +341,11 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
327
341
|
}
|
|
328
342
|
|
|
329
343
|
// @Cover
|
|
330
|
-
|
|
344
|
+
EmbeddedTag(p) {
|
|
331
345
|
if (p.match(/!['"]/y)) {
|
|
332
346
|
p.eatProduction('Escape');
|
|
333
347
|
} else if (p.match(/['"]/y)) {
|
|
334
|
-
p.eatProduction('
|
|
348
|
+
p.eatProduction('LiteralTag');
|
|
335
349
|
} else {
|
|
336
350
|
throw new Error();
|
|
337
351
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const Spamex = require('./spamex.js');
|
|
2
2
|
const CSTML = require('./cstml.js');
|
|
3
3
|
const Regex = require('./regex.js');
|
|
4
|
-
const { node } = require('
|
|
4
|
+
const { node } = require('@bablr/boot-helpers/symbols');
|
|
5
5
|
const { buildCovers } = require('../utils.js');
|
|
6
6
|
|
|
7
7
|
const _ = /\s+/y;
|
package/lib/languages/regex.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const when = require('iter-tools/methods/when');
|
|
2
2
|
const { escapables } = require('./cstml.js');
|
|
3
3
|
const { buildCovers } = require('../utils.js');
|
|
4
|
-
const { node } = require('
|
|
4
|
+
const { node } = require('@bablr/boot-helpers/symbols');
|
|
5
5
|
|
|
6
6
|
const name = 'Regex';
|
|
7
7
|
|
|
@@ -65,7 +65,7 @@ const unique = (flags) => flags.length === new Set(flags).size;
|
|
|
65
65
|
const getSpecialPattern = (span) => {
|
|
66
66
|
const { type } = span;
|
|
67
67
|
if (type === 'Bare') {
|
|
68
|
-
return /[*+{}\[\]()\.^$|\\\n
|
|
68
|
+
return /[*+{}\[\]()\.^$|\\\n\/><]/y;
|
|
69
69
|
} else if (type === 'CharacterClass') {
|
|
70
70
|
return /[\]\\]/y;
|
|
71
71
|
} else if (type === 'CharacterClass:First') {
|
|
@@ -154,7 +154,7 @@ const grammar = class RegexMiniparserGrammar {
|
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
Elements(p) {
|
|
157
|
-
while (p.match(/[^|]/y || p.atExpression)
|
|
157
|
+
while (p.match(/[^|]/y) || p.atExpression) {
|
|
158
158
|
p.eatProduction('Element');
|
|
159
159
|
}
|
|
160
160
|
}
|
package/lib/languages/spamex.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
const Regex = require('./regex.js');
|
|
2
2
|
const CSTML = require('./cstml.js');
|
|
3
3
|
const { buildCovers } = require('../utils.js');
|
|
4
|
-
const sym = require('
|
|
4
|
+
const sym = require('@bablr/boot-helpers/symbols');
|
|
5
5
|
|
|
6
6
|
const _ = /\s+/y;
|
|
7
7
|
const PN = 'Punctuator';
|
|
8
8
|
const ID = 'Identifier';
|
|
9
|
-
const LIT = 'Literal';
|
|
10
9
|
|
|
11
10
|
const name = 'Spamex';
|
|
12
11
|
|
|
@@ -15,14 +14,18 @@ const canonicalURL = 'https://bablr.org/languages/core/en/spamex';
|
|
|
15
14
|
const dependencies = { CSTML, Regex };
|
|
16
15
|
|
|
17
16
|
const covers = buildCovers({
|
|
18
|
-
[sym.node]: ['Attribute', 'Identifier', 'Matcher', 'Literal', 'CSTML:Flags'],
|
|
17
|
+
[sym.node]: ['Attribute', 'Identifier', 'Pattern', 'Matcher', 'Literal', 'CSTML:Flags'],
|
|
19
18
|
Attribute: ['MappingAttribute', 'BooleanAttribute'],
|
|
20
19
|
AttributeValue: ['CSTML:String', 'CSTML:Number'],
|
|
21
|
-
Matcher: ['NodeMatcher', 'StringMatcher'],
|
|
20
|
+
Matcher: ['NodeMatcher', 'OpenNodeMatcher', 'CloseNodeMatcher', 'StringMatcher'],
|
|
22
21
|
StringMatcher: ['CSTML:String', 'Regex:Pattern'],
|
|
23
22
|
});
|
|
24
23
|
|
|
25
24
|
const grammar = class SpamexMiniparserGrammar {
|
|
25
|
+
Pattern(p) {
|
|
26
|
+
p.eatProduction('Matcher', { path: 'matcher' });
|
|
27
|
+
}
|
|
28
|
+
|
|
26
29
|
// @Cover
|
|
27
30
|
Matcher(p) {
|
|
28
31
|
if (p.match(/<[^!/]/y)) {
|
|
@@ -36,8 +39,28 @@ const grammar = class SpamexMiniparserGrammar {
|
|
|
36
39
|
}
|
|
37
40
|
}
|
|
38
41
|
|
|
39
|
-
// @Node
|
|
40
42
|
NodeMatcher(p) {
|
|
43
|
+
let open = p.eatProduction('OpenNodeMatcher', { path: 'open' });
|
|
44
|
+
|
|
45
|
+
if (!open.properties.selfClosingTagToken) {
|
|
46
|
+
p.eatMatchTrivia(_);
|
|
47
|
+
|
|
48
|
+
if (open.properties.flags?.token) {
|
|
49
|
+
// p.eatProduction('NodeChild', { path: 'children[]' }, { token: true });
|
|
50
|
+
// p.eatMatchTrivia(_);
|
|
51
|
+
} else {
|
|
52
|
+
// while (!(p.match('</') || p.done)) {
|
|
53
|
+
// p.eatProduction('NodeChild', { path: 'children[]' });
|
|
54
|
+
// p.eatMatchTrivia(_);
|
|
55
|
+
// }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
p.eatProduction('CloseNodeMatcher', { path: 'close' });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// @Node
|
|
63
|
+
OpenNodeMatcher(p) {
|
|
41
64
|
p.eat('<', PN, { path: 'openToken', startSpan: 'Tag', balanced: '>' });
|
|
42
65
|
|
|
43
66
|
if (!p.atExpression) {
|
|
@@ -48,6 +71,10 @@ const grammar = class SpamexMiniparserGrammar {
|
|
|
48
71
|
p.eat(/[a-zA-Z]+/y, ID, { path: 'language' });
|
|
49
72
|
p.eat(':', PN, { path: 'namespaceSeparatorToken' });
|
|
50
73
|
p.eat(/[a-zA-Z]+/y, ID, { path: 'type' });
|
|
74
|
+
} else if (p.match('?')) {
|
|
75
|
+
p.eat('?', PN, { path: 'type' });
|
|
76
|
+
} else if (p.match(' ')) {
|
|
77
|
+
p.eatMatchTrivia(_);
|
|
51
78
|
} else {
|
|
52
79
|
if (p.atExpression) {
|
|
53
80
|
p.eatProduction('Identifier', { path: 'type' });
|
|
@@ -58,7 +85,7 @@ const grammar = class SpamexMiniparserGrammar {
|
|
|
58
85
|
|
|
59
86
|
let sp = p.eatMatchTrivia(_);
|
|
60
87
|
|
|
61
|
-
if (sp && (p.match(/['"/]/y) || p.atExpression)) {
|
|
88
|
+
if (sp && ((p.match(/['"/]/y) && !p.match('/>')) || p.atExpression)) {
|
|
62
89
|
p.eatProduction('StringMatcher', { path: 'intrinsicValue' });
|
|
63
90
|
|
|
64
91
|
sp = p.eatMatchTrivia(_);
|
|
@@ -70,6 +97,12 @@ const grammar = class SpamexMiniparserGrammar {
|
|
|
70
97
|
}
|
|
71
98
|
|
|
72
99
|
p.eatMatchTrivia(_);
|
|
100
|
+
p.eatMatch('/', PN, { path: 'selfClosingTagToken' });
|
|
101
|
+
p.eat('>', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
CloseNodeMatcher(p) {
|
|
105
|
+
p.eat('</', PN, { path: 'openToken', startSpan: 'Tag', balanced: '>' });
|
|
73
106
|
p.eat('>', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
|
|
74
107
|
}
|
|
75
108
|
|
|
@@ -94,12 +127,12 @@ const grammar = class SpamexMiniparserGrammar {
|
|
|
94
127
|
|
|
95
128
|
// @Node
|
|
96
129
|
BooleanAttribute(p) {
|
|
97
|
-
p.eat(/[a-zA-Z]+/y,
|
|
130
|
+
p.eat(/[a-zA-Z]+/y, ID, { path: 'key' });
|
|
98
131
|
}
|
|
99
132
|
|
|
100
133
|
// @Node
|
|
101
134
|
MappingAttribute(p) {
|
|
102
|
-
p.eat(/[a-zA-Z]+/y,
|
|
135
|
+
p.eat(/[a-zA-Z]+/y, ID, { path: 'key' });
|
|
103
136
|
p.eatMatchTrivia(_);
|
|
104
137
|
p.eat('=', PN, { path: 'mapToken' });
|
|
105
138
|
p.eatMatchTrivia(_);
|
package/lib/match.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const { Path, buildNode } = require('./path.js');
|
|
2
2
|
const { resolveDependentLanguage } = require('./utils.js');
|
|
3
|
-
const sym = require('
|
|
3
|
+
const sym = require('@bablr/boot-helpers/symbols');
|
|
4
4
|
|
|
5
5
|
class Match {
|
|
6
6
|
constructor(parent, resolvedLanguage, id, attributes, path) {
|
package/lib/miniparser.js
CHANGED
|
@@ -3,10 +3,11 @@ const escapeRegex = require('escape-string-regexp');
|
|
|
3
3
|
const arrayLast = require('iter-tools/methods/array-last');
|
|
4
4
|
const isString = require('iter-tools/methods/is-string');
|
|
5
5
|
const isObject = require('iter-tools/methods/is-object');
|
|
6
|
-
const sym = require('
|
|
6
|
+
const sym = require('@bablr/boot-helpers/symbols');
|
|
7
7
|
const { Match } = require('./match.js');
|
|
8
8
|
const { parsePath } = require('./path.js');
|
|
9
9
|
const { set, isRegex, isArray, getPrototypeOf, buildNode } = require('./utils.js');
|
|
10
|
+
const { ReferenceTag, LiteralTag, Escape } = require('@bablr/boot-helpers/symbols');
|
|
10
11
|
|
|
11
12
|
class TemplateParser {
|
|
12
13
|
constructor(rootLanguage, quasis, expressions) {
|
|
@@ -177,9 +178,19 @@ class TemplateParser {
|
|
|
177
178
|
const { properties, children } = parentPath.node;
|
|
178
179
|
const path = parsePath(this.m.attrs.path);
|
|
179
180
|
|
|
180
|
-
|
|
181
|
+
if (isArray(result)) {
|
|
182
|
+
for (const value of result) {
|
|
183
|
+
children.push(ref(path));
|
|
181
184
|
|
|
182
|
-
|
|
185
|
+
// TODO interpolate separators!
|
|
186
|
+
|
|
187
|
+
set(properties, path, value);
|
|
188
|
+
}
|
|
189
|
+
} else {
|
|
190
|
+
children.push(ref(path));
|
|
191
|
+
|
|
192
|
+
set(properties, path, result);
|
|
193
|
+
}
|
|
183
194
|
}
|
|
184
195
|
} else {
|
|
185
196
|
if (isEmbedded) {
|
|
@@ -197,6 +208,7 @@ class TemplateParser {
|
|
|
197
208
|
if (result?.attrs) {
|
|
198
209
|
node.attributes = result.attrs;
|
|
199
210
|
}
|
|
211
|
+
|
|
200
212
|
if (parentPath?.node && !covers.has(type)) {
|
|
201
213
|
const path = parsePath(this.m.attrs.path);
|
|
202
214
|
|
|
@@ -210,11 +222,11 @@ class TemplateParser {
|
|
|
210
222
|
this.m = this.m.parent;
|
|
211
223
|
|
|
212
224
|
if (this.path?.node) {
|
|
213
|
-
const
|
|
225
|
+
const isTag = (child) => [LiteralTag, Escape].includes(child.type);
|
|
214
226
|
|
|
215
227
|
const { children } = this.path.node;
|
|
216
228
|
|
|
217
|
-
if (children.find(
|
|
229
|
+
if (children.find(isTag) && !children.every(isTag)) {
|
|
218
230
|
throw new Error('strings must be wrapped in nodes');
|
|
219
231
|
}
|
|
220
232
|
}
|
|
@@ -280,7 +292,7 @@ class TemplateParser {
|
|
|
280
292
|
|
|
281
293
|
const lastChild = arrayLast(children);
|
|
282
294
|
|
|
283
|
-
if (lastChild.type !==
|
|
295
|
+
if (lastChild.type !== ReferenceTag) {
|
|
284
296
|
throw new Error();
|
|
285
297
|
}
|
|
286
298
|
|