@bablr/boot 0.3.0 → 0.5.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 +94 -55
- package/lib/index.js +108 -34
- package/lib/index.mjs +15 -1
- package/lib/languages/cstml.js +34 -29
- package/lib/languages/instruction.js +1 -1
- package/lib/languages/regex.js +2 -2
- package/lib/languages/spamex.js +41 -8
- package/lib/match.js +1 -1
- package/lib/miniparser.js +5 -4
- package/lib/print.js +199 -125
- package/package.json +3 -2
- package/shorthand.macro.js +111 -63
- package/lib/symbols.js +0 -4
package/lib/languages/cstml.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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';
|
|
@@ -62,15 +62,15 @@ const covers = buildCovers({
|
|
|
62
62
|
'DoctypeTag',
|
|
63
63
|
'Attribute',
|
|
64
64
|
'Property',
|
|
65
|
-
'
|
|
65
|
+
'ReferenceTag',
|
|
66
66
|
'TagType',
|
|
67
|
-
'
|
|
68
|
-
'
|
|
67
|
+
'NullTag',
|
|
68
|
+
'GapTag',
|
|
69
69
|
'Node',
|
|
70
70
|
'IdentifierPath',
|
|
71
71
|
'OpenNodeTag',
|
|
72
72
|
'CloseNodeTag',
|
|
73
|
-
'
|
|
73
|
+
'Tag',
|
|
74
74
|
'Number',
|
|
75
75
|
'Digit',
|
|
76
76
|
'String',
|
|
@@ -82,9 +82,9 @@ const covers = buildCovers({
|
|
|
82
82
|
Attribute: ['MappingAttribute', 'BooleanAttribute'],
|
|
83
83
|
AttributeValue: ['String', 'Number'],
|
|
84
84
|
TagType: ['Identifier', 'GlobalIdentifier'],
|
|
85
|
-
|
|
86
|
-
PropertyValue: ['
|
|
87
|
-
|
|
85
|
+
Tag: ['LiteralTag', 'Trivia'],
|
|
86
|
+
PropertyValue: ['GapTag', 'Node', 'NullTag'],
|
|
87
|
+
EmbeddedTag: ['LiteralTag'],
|
|
88
88
|
Number: ['Integer', 'Infinity'],
|
|
89
89
|
});
|
|
90
90
|
|
|
@@ -92,6 +92,7 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
92
92
|
// @Node
|
|
93
93
|
Document(p) {
|
|
94
94
|
p.eatProduction('DoctypeTag', { path: 'doctype' });
|
|
95
|
+
p.eatMatchTrivia(_);
|
|
95
96
|
p.eatProduction('Node', { path: 'tree' });
|
|
96
97
|
}
|
|
97
98
|
|
|
@@ -113,12 +114,12 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
// @Node
|
|
116
|
-
|
|
117
|
+
NullTag(p) {
|
|
117
118
|
p.eat('null', KW, { path: 'sigilToken' });
|
|
118
119
|
}
|
|
119
120
|
|
|
120
121
|
// @Node
|
|
121
|
-
|
|
122
|
+
GapTag(p) {
|
|
122
123
|
p.eat('<//>', PN, { path: 'sigilToken' });
|
|
123
124
|
}
|
|
124
125
|
|
|
@@ -131,14 +132,16 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
131
132
|
if (open.properties.flags?.token) {
|
|
132
133
|
p.eatProduction('NodeChild', { path: 'children[]' }, { token: true });
|
|
133
134
|
p.eatMatchTrivia(_);
|
|
134
|
-
} else {
|
|
135
|
-
while (!p.match('</')) {
|
|
135
|
+
} else if (!open.properties.selfClosingTagToken) {
|
|
136
|
+
while (!(p.match('</') || p.done)) {
|
|
136
137
|
p.eatProduction('NodeChild', { path: 'children[]' });
|
|
137
138
|
p.eatMatchTrivia(_);
|
|
138
139
|
}
|
|
139
140
|
}
|
|
140
141
|
|
|
141
|
-
|
|
142
|
+
if (!open.properties.selfClosingTagToken) {
|
|
143
|
+
p.eatProduction('CloseNodeTag', { path: 'close' });
|
|
144
|
+
}
|
|
142
145
|
}
|
|
143
146
|
|
|
144
147
|
NodeChild(p, _, props) {
|
|
@@ -148,7 +151,7 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
148
151
|
if (p.match(/<\*?@/y)) {
|
|
149
152
|
p.eatProduction('Node');
|
|
150
153
|
} else {
|
|
151
|
-
p.eatProduction('
|
|
154
|
+
p.eatProduction('LiteralTag');
|
|
152
155
|
}
|
|
153
156
|
} else {
|
|
154
157
|
if (p.match(/<\*?#/y)) {
|
|
@@ -156,23 +159,23 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
156
159
|
} else if (p.match(/[a-zA-Z]/y)) {
|
|
157
160
|
p.eatProduction('Property');
|
|
158
161
|
} else if (p.match(/['"]/y)) {
|
|
159
|
-
p.eatProduction('
|
|
162
|
+
p.eatProduction('LiteralTag');
|
|
160
163
|
}
|
|
161
164
|
}
|
|
162
165
|
}
|
|
163
166
|
|
|
164
167
|
// @Node
|
|
165
168
|
Property(p) {
|
|
166
|
-
p.eatProduction('
|
|
169
|
+
p.eatProduction('ReferenceTag', { path: 'reference' });
|
|
167
170
|
p.eatMatchTrivia(_);
|
|
168
171
|
p.eatProduction('PropertyValue', { path: 'value' });
|
|
169
172
|
}
|
|
170
173
|
|
|
171
174
|
PropertyValue(p) {
|
|
172
175
|
if (p.match('null')) {
|
|
173
|
-
p.eatProduction('
|
|
176
|
+
p.eatProduction('NullTag');
|
|
174
177
|
} else if (p.match('<//>')) {
|
|
175
|
-
p.eatProduction('
|
|
178
|
+
p.eatProduction('GapTag');
|
|
176
179
|
} else {
|
|
177
180
|
p.eatProduction('Node');
|
|
178
181
|
}
|
|
@@ -198,13 +201,17 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
198
201
|
flags = p.eatProduction('Flags', { path: 'flags' });
|
|
199
202
|
}
|
|
200
203
|
|
|
204
|
+
if (p.done) {
|
|
205
|
+
p.eat('>', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
|
|
201
209
|
p.eatProduction('TagType', { path: 'type' });
|
|
202
210
|
|
|
203
211
|
let sp = p.eatMatchTrivia(_);
|
|
204
212
|
|
|
205
|
-
let iv;
|
|
206
213
|
if (flags.properties.intrinsic && sp && (p.match(/['"/]/y) || p.atExpression)) {
|
|
207
|
-
|
|
214
|
+
p.eatProduction('String', { path: 'intrinsicValue' });
|
|
208
215
|
|
|
209
216
|
sp = p.eatMatchTrivia(_);
|
|
210
217
|
}
|
|
@@ -215,9 +222,7 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
215
222
|
}
|
|
216
223
|
|
|
217
224
|
p.eatMatchTrivia(_);
|
|
218
|
-
|
|
219
|
-
p.eat('/', PN, { path: 'selfClosingTagToken' });
|
|
220
|
-
}
|
|
225
|
+
p.eatMatch('/', PN, { path: 'selfClosingTagToken' });
|
|
221
226
|
p.eat('>', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
|
|
222
227
|
}
|
|
223
228
|
|
|
@@ -305,20 +310,20 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
305
310
|
|
|
306
311
|
// @Node
|
|
307
312
|
Identifier(p) {
|
|
308
|
-
p.eatLiteral(/[a-zA-Z][
|
|
313
|
+
p.eatLiteral(/[a-zA-Z][a-zA-Z-_]*/y);
|
|
309
314
|
}
|
|
310
315
|
|
|
311
316
|
// @Cover
|
|
312
|
-
|
|
317
|
+
Tag(p) {
|
|
313
318
|
if (p.match(/['"]/y)) {
|
|
314
|
-
p.eatProduction('
|
|
319
|
+
p.eatProduction('LiteralTag');
|
|
315
320
|
} else {
|
|
316
321
|
throw new Error();
|
|
317
322
|
}
|
|
318
323
|
}
|
|
319
324
|
|
|
320
325
|
// @Node
|
|
321
|
-
|
|
326
|
+
ReferenceTag(p) {
|
|
322
327
|
p.eatProduction('Identifier', { path: 'name' });
|
|
323
328
|
p.eatMatchTrivia(_);
|
|
324
329
|
p.eatMatch('[]', PN, { path: 'arrayToken' });
|
|
@@ -327,11 +332,11 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
327
332
|
}
|
|
328
333
|
|
|
329
334
|
// @Cover
|
|
330
|
-
|
|
335
|
+
EmbeddedTag(p) {
|
|
331
336
|
if (p.match(/!['"]/y)) {
|
|
332
337
|
p.eatProduction('Escape');
|
|
333
338
|
} else if (p.match(/['"]/y)) {
|
|
334
|
-
p.eatProduction('
|
|
339
|
+
p.eatProduction('LiteralTag');
|
|
335
340
|
} else {
|
|
336
341
|
throw new Error();
|
|
337
342
|
}
|
|
@@ -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') {
|
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) {
|
|
@@ -210,11 +211,11 @@ class TemplateParser {
|
|
|
210
211
|
this.m = this.m.parent;
|
|
211
212
|
|
|
212
213
|
if (this.path?.node) {
|
|
213
|
-
const
|
|
214
|
+
const isTag = (child) => [LiteralTag, Escape].includes(child.type);
|
|
214
215
|
|
|
215
216
|
const { children } = this.path.node;
|
|
216
217
|
|
|
217
|
-
if (children.find(
|
|
218
|
+
if (children.find(isTag) && !children.every(isTag)) {
|
|
218
219
|
throw new Error('strings must be wrapped in nodes');
|
|
219
220
|
}
|
|
220
221
|
}
|
|
@@ -280,7 +281,7 @@ class TemplateParser {
|
|
|
280
281
|
|
|
281
282
|
const lastChild = arrayLast(children);
|
|
282
283
|
|
|
283
|
-
if (lastChild.type !==
|
|
284
|
+
if (lastChild.type !== ReferenceTag) {
|
|
284
285
|
throw new Error();
|
|
285
286
|
}
|
|
286
287
|
|