@bablr/boot 0.1.1 → 0.1.3
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/languages/cstml.js +2 -2
- package/lib/languages/instruction.js +4 -4
- package/lib/languages/regex.js +7 -8
- package/lib/languages/spamex.js +2 -2
- package/lib/miniparser.js +9 -12
- package/package.json +4 -3
- package/shorthand.macro.js +224 -0
package/lib/languages/cstml.js
CHANGED
|
@@ -22,7 +22,7 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
22
22
|
Fragment(p) {
|
|
23
23
|
p.eatMatchTrivia(_);
|
|
24
24
|
while (p.match(/<[^/]/y) || p.atExpression) {
|
|
25
|
-
p.eatProduction('Property', { path: 'properties' });
|
|
25
|
+
p.eatProduction('Property', { path: 'properties[]' });
|
|
26
26
|
p.eatMatchTrivia(_);
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -73,7 +73,7 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
73
73
|
if (p.atExpression) {
|
|
74
74
|
p.eatProduction('Attributes'); // ??
|
|
75
75
|
} else {
|
|
76
|
-
p.eatProduction('Attribute', { path: '[
|
|
76
|
+
p.eatProduction('Attribute', { path: 'attributes[]' });
|
|
77
77
|
}
|
|
78
78
|
if (p.match(/\s+\w/y) || (p.match(/\s+$/y) && !p.quasisDone)) {
|
|
79
79
|
sp = p.eatMatchTrivia(_);
|
|
@@ -69,7 +69,7 @@ const grammar = class InstructionMiniparserGrammar {
|
|
|
69
69
|
let first = true;
|
|
70
70
|
let sep;
|
|
71
71
|
while (first || (sep && (p.match(/./y) || p.atExpression))) {
|
|
72
|
-
p.eatProduction('Property', { path: '[
|
|
72
|
+
p.eatProduction('Property', { path: 'properties[]' });
|
|
73
73
|
sep = p.eatMatchTrivia(_);
|
|
74
74
|
first = false;
|
|
75
75
|
}
|
|
@@ -97,7 +97,7 @@ const grammar = class InstructionMiniparserGrammar {
|
|
|
97
97
|
let first = true;
|
|
98
98
|
let sep;
|
|
99
99
|
while (first || (sep && (p.match(/./y) || p.atExpression))) {
|
|
100
|
-
p.eatProduction('Expression', { path: '[
|
|
100
|
+
p.eatProduction('Expression', { path: 'elements[]' });
|
|
101
101
|
sep = p.eatMatchTrivia(_);
|
|
102
102
|
first = false;
|
|
103
103
|
}
|
|
@@ -113,7 +113,7 @@ const grammar = class InstructionMiniparserGrammar {
|
|
|
113
113
|
|
|
114
114
|
let i = 0;
|
|
115
115
|
while (i === 0 || (sep && (p.match(/./y) || p.atExpression))) {
|
|
116
|
-
p.eatProduction('Expression', { path: '[
|
|
116
|
+
p.eatProduction('Expression', { path: 'values[]' });
|
|
117
117
|
sep = p.eatMatchTrivia(_);
|
|
118
118
|
i++;
|
|
119
119
|
}
|
|
@@ -128,7 +128,7 @@ const grammar = class InstructionMiniparserGrammar {
|
|
|
128
128
|
|
|
129
129
|
// @Node
|
|
130
130
|
Null(p) {
|
|
131
|
-
p.eat(
|
|
131
|
+
p.eat('null', KW, { path: 'value' });
|
|
132
132
|
}
|
|
133
133
|
};
|
|
134
134
|
|
package/lib/languages/regex.js
CHANGED
|
@@ -98,9 +98,9 @@ const grammar = class RegexMiniparserGrammar {
|
|
|
98
98
|
// @Node
|
|
99
99
|
Pattern(p) {
|
|
100
100
|
p.eat('/', PN, { path: 'open', balanced: '/' });
|
|
101
|
-
p.eatProduction('Alternatives', { path: '[
|
|
101
|
+
p.eatProduction('Alternatives', { path: 'alternatives[]' });
|
|
102
102
|
p.eat('/', PN, { path: 'close', balancer: true });
|
|
103
|
-
p.eatProduction('Flags', { path: '[
|
|
103
|
+
p.eatProduction('Flags', { path: 'flags[]' });
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
Flags(p) {
|
|
@@ -116,19 +116,18 @@ const grammar = class RegexMiniparserGrammar {
|
|
|
116
116
|
// @Node
|
|
117
117
|
Flag(p) {
|
|
118
118
|
const flag = p.eatMatch(/[gimsuy]/y, KW, { path: 'value' });
|
|
119
|
-
|
|
120
119
|
return { attrs: { kind: flagsReverse[flag] } };
|
|
121
120
|
}
|
|
122
121
|
|
|
123
122
|
Alternatives(p) {
|
|
124
123
|
do {
|
|
125
124
|
p.eatProduction('Alternative');
|
|
126
|
-
} while (p.eatMatch('|', PN, { path: '[
|
|
125
|
+
} while (p.eatMatch('|', PN, { path: 'separators[]' }));
|
|
127
126
|
}
|
|
128
127
|
|
|
129
128
|
// @Node
|
|
130
129
|
Alternative(p) {
|
|
131
|
-
p.eatProduction('Elements', { path: '[
|
|
130
|
+
p.eatProduction('Elements', { path: 'elements[]' });
|
|
132
131
|
}
|
|
133
132
|
|
|
134
133
|
Elements(p) {
|
|
@@ -163,14 +162,14 @@ const grammar = class RegexMiniparserGrammar {
|
|
|
163
162
|
// @Node
|
|
164
163
|
Group(p) {
|
|
165
164
|
p.eat('(?:', PN, { path: 'open', balanced: ')' });
|
|
166
|
-
p.eatProduction('Alternatives', { path: '[
|
|
165
|
+
p.eatProduction('Alternatives', { path: 'alternatives[]' });
|
|
167
166
|
p.eat(')', PN, { path: 'close', balancer: true });
|
|
168
167
|
}
|
|
169
168
|
|
|
170
169
|
// @Node
|
|
171
170
|
CapturingGroup(p) {
|
|
172
171
|
p.eat('(', PN, { path: 'open', balanced: ')' });
|
|
173
|
-
p.eatProduction('Alternatives', { path: '[
|
|
172
|
+
p.eatProduction('Alternatives', { path: 'alternatives[]' });
|
|
174
173
|
p.eat(')', PN, { path: 'close', balancer: true });
|
|
175
174
|
}
|
|
176
175
|
|
|
@@ -226,7 +225,7 @@ const grammar = class RegexMiniparserGrammar {
|
|
|
226
225
|
|
|
227
226
|
let first = !negate;
|
|
228
227
|
while (p.match(/./sy)) {
|
|
229
|
-
p.eatProduction('CharacterClassElement', { path: '[
|
|
228
|
+
p.eatProduction('CharacterClassElement', { path: 'elements[]' }, { first });
|
|
230
229
|
first = false;
|
|
231
230
|
}
|
|
232
231
|
|
package/lib/languages/spamex.js
CHANGED
|
@@ -54,7 +54,7 @@ const grammar = class SpamexMiniparserGrammar {
|
|
|
54
54
|
let sp = p.eatMatchTrivia(_);
|
|
55
55
|
|
|
56
56
|
if ((sp && p.match(/\w+/y)) || p.atExpression) {
|
|
57
|
-
p.eatProduction('Attributes', { path: '[
|
|
57
|
+
p.eatProduction('Attributes', { path: 'attributes[]' });
|
|
58
58
|
sp = p.eatMatchTrivia(_);
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -75,7 +75,7 @@ const grammar = class SpamexMiniparserGrammar {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
if (sp && p.match(/\w+/y)) {
|
|
78
|
-
p.eatProduction('Attributes', { path: '[
|
|
78
|
+
p.eatProduction('Attributes', { path: 'attributes[]' });
|
|
79
79
|
sp = p.eatMatchTrivia(_);
|
|
80
80
|
}
|
|
81
81
|
|
package/lib/miniparser.js
CHANGED
|
@@ -5,7 +5,7 @@ const isString = require('iter-tools-es/methods/is-string');
|
|
|
5
5
|
const isObject = require('iter-tools-es/methods/is-object');
|
|
6
6
|
const sym = require('./symbols.js');
|
|
7
7
|
const { Match } = require('./match.js');
|
|
8
|
-
const { set, isRegex, isArray,
|
|
8
|
+
const { set, isRegex, isArray, getPrototypeOf, buildNode, parsePath } = require('./utils.js');
|
|
9
9
|
|
|
10
10
|
class TemplateParser {
|
|
11
11
|
constructor(rootLanguage, quasis, expressions) {
|
|
@@ -172,9 +172,8 @@ class TemplateParser {
|
|
|
172
172
|
}
|
|
173
173
|
} else if (parentPath?.node && (isNode || covers.has(type))) {
|
|
174
174
|
const { properties, children } = parentPath.node;
|
|
175
|
-
const { pathName } = parsePath(this.m.attrs.path);
|
|
176
175
|
|
|
177
|
-
children.push({ ...ref(
|
|
176
|
+
children.push({ ...ref(this.m.attrs.path), id });
|
|
178
177
|
|
|
179
178
|
set(properties, this.m.attrs.path, result);
|
|
180
179
|
}
|
|
@@ -195,9 +194,7 @@ class TemplateParser {
|
|
|
195
194
|
node.attributes = result.attrs;
|
|
196
195
|
}
|
|
197
196
|
if (parentPath?.node && !covers.has(type)) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
parentPath.node.children.push(ref(pathName));
|
|
197
|
+
parentPath.node.children.push(ref(this.m.attrs.path));
|
|
201
198
|
|
|
202
199
|
set(parentPath.node.properties, this.m.attrs.path, node);
|
|
203
200
|
}
|
|
@@ -280,16 +277,16 @@ class TemplateParser {
|
|
|
280
277
|
}
|
|
281
278
|
|
|
282
279
|
const path = lastChild.value;
|
|
283
|
-
const pathIsArray =
|
|
280
|
+
const { pathIsArray, pathName } = parsePath(path);
|
|
284
281
|
|
|
285
|
-
this.held = pathIsArray ? arrayLast(properties[
|
|
282
|
+
this.held = pathIsArray ? arrayLast(properties[pathName]) : properties[pathName];
|
|
286
283
|
|
|
287
284
|
children.pop();
|
|
288
285
|
|
|
289
286
|
if (pathIsArray) {
|
|
290
|
-
properties[
|
|
287
|
+
properties[pathName].pop();
|
|
291
288
|
} else {
|
|
292
|
-
properties[
|
|
289
|
+
properties[pathName] = null;
|
|
293
290
|
}
|
|
294
291
|
|
|
295
292
|
return this.eval(this.buildId(id), attrs, props);
|
|
@@ -309,7 +306,7 @@ class TemplateParser {
|
|
|
309
306
|
|
|
310
307
|
set(this.node.properties, attrs.path, buildNode(this.buildId(type), [lit(result)]));
|
|
311
308
|
|
|
312
|
-
this.node.children.push(ref(
|
|
309
|
+
this.node.children.push(ref(attrs.path));
|
|
313
310
|
|
|
314
311
|
return result;
|
|
315
312
|
}
|
|
@@ -337,7 +334,7 @@ class TemplateParser {
|
|
|
337
334
|
|
|
338
335
|
set(this.node.properties, attrs.path, buildNode(this.buildId(type), [lit(result)]));
|
|
339
336
|
|
|
340
|
-
this.node.children.push(ref(
|
|
337
|
+
this.node.children.push(ref(attrs.path));
|
|
341
338
|
}
|
|
342
339
|
return result;
|
|
343
340
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bablr/boot",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Compile-time tools for bootstrapping BABLR VM",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=12.0.0"
|
|
@@ -10,14 +10,15 @@
|
|
|
10
10
|
"./shorthand.macro": "./shorthand.macro.js"
|
|
11
11
|
},
|
|
12
12
|
"files": [
|
|
13
|
-
"lib/**/*.js"
|
|
13
|
+
"lib/**/*.js",
|
|
14
|
+
"shorthand.macro.js"
|
|
14
15
|
],
|
|
15
16
|
"sideEffects": false,
|
|
16
17
|
"dependencies": {
|
|
17
18
|
"@babel/helper-module-imports": "^7.22.15",
|
|
18
19
|
"@babel/template": "^7.22.15",
|
|
19
20
|
"@babel/types": "7.23.0",
|
|
20
|
-
"@bablr/boot-helpers": "0.1.
|
|
21
|
+
"@bablr/boot-helpers": "0.1.1",
|
|
21
22
|
"escape-string-regexp": "4.0.0",
|
|
22
23
|
"iter-tools-es": "^7.5.3"
|
|
23
24
|
},
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
const t = require('@babel/types');
|
|
2
|
+
const { expression } = require('@babel/template');
|
|
3
|
+
const isObject = require('iter-tools-es/methods/is-object');
|
|
4
|
+
const isUndefined = require('iter-tools-es/methods/is-undefined');
|
|
5
|
+
const isNull = require('iter-tools-es/methods/is-null');
|
|
6
|
+
const isString = require('iter-tools-es/methods/is-string');
|
|
7
|
+
const concat = require('iter-tools-es/methods/concat');
|
|
8
|
+
const { createMacro } = require('babel-plugin-macros');
|
|
9
|
+
const { TemplateParser } = require('./lib/miniparser.js');
|
|
10
|
+
const i = require('./lib/languages/instruction.js');
|
|
11
|
+
const re = require('./lib/languages/regex.js');
|
|
12
|
+
const spam = require('./lib/languages/spamex.js');
|
|
13
|
+
const str = require('./lib/languages/string.js');
|
|
14
|
+
const cstml = require('./lib/languages/cstml.js');
|
|
15
|
+
const { addNamespace, addNamed } = require('@babel/helper-module-imports');
|
|
16
|
+
const { PathResolver } = require('@bablr/boot-helpers/path');
|
|
17
|
+
|
|
18
|
+
const { hasOwn } = Object;
|
|
19
|
+
const { isArray } = Array;
|
|
20
|
+
const isNumber = (v) => typeof v === 'number';
|
|
21
|
+
const isBoolean = (v) => typeof v === 'boolean';
|
|
22
|
+
|
|
23
|
+
const isPlainObject = (v) => isObject(v) && !isArray(v);
|
|
24
|
+
|
|
25
|
+
const set = (obj, path, value, pathIsArray) => {
|
|
26
|
+
if (pathIsArray) {
|
|
27
|
+
if (!obj[path]) {
|
|
28
|
+
obj[path] = [];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!isArray(obj[path])) throw new Error('bad array value');
|
|
32
|
+
|
|
33
|
+
obj[path].push(value);
|
|
34
|
+
} else {
|
|
35
|
+
if (hasOwn(obj, path)) {
|
|
36
|
+
throw new Error('duplicate child name');
|
|
37
|
+
}
|
|
38
|
+
obj[path] = value;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const getASTValue = (v, exprs, bindings) => {
|
|
43
|
+
return isNull(v)
|
|
44
|
+
? t.nullLiteral()
|
|
45
|
+
: isUndefined(v)
|
|
46
|
+
? t.identifier('undefined')
|
|
47
|
+
: isString(v)
|
|
48
|
+
? t.stringLiteral(v)
|
|
49
|
+
: isNumber(v)
|
|
50
|
+
? t.numericLiteral(v)
|
|
51
|
+
: isBoolean(v)
|
|
52
|
+
? t.booleanLiteral(v)
|
|
53
|
+
: isArray(v)
|
|
54
|
+
? t.arrayExpression(v.map((v) => getASTValue(v, exprs, bindings)))
|
|
55
|
+
: isPlainObject(v) && !v.language
|
|
56
|
+
? t.objectExpression(
|
|
57
|
+
Object.entries(v).map(([k, v]) =>
|
|
58
|
+
t.objectProperty(t.identifier(k), getASTValue(v, exprs, bindings)),
|
|
59
|
+
),
|
|
60
|
+
)
|
|
61
|
+
: generateNode(v, exprs, bindings);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const generateNodeChild = (child, bindings) => {
|
|
65
|
+
if (child.type === 'Reference') {
|
|
66
|
+
return expression(`%%t%%.ref\`${child.value}\``)({ t: bindings.t });
|
|
67
|
+
} else if (child.type === 'Literal') {
|
|
68
|
+
return expression(`%%t%%.lit\`${child.value.replace(/\\/g, '\\\\')}\``)({ t: bindings.t });
|
|
69
|
+
} else if (child.type === 'Trivia') {
|
|
70
|
+
return expression(`%%t%%.trivia\` \``)({ t: bindings.t });
|
|
71
|
+
} else if (child.type === 'Escape') {
|
|
72
|
+
return expression(`%%t%%.esc(%%cooked%%, %%raw%%)`)({
|
|
73
|
+
t: bindings.t,
|
|
74
|
+
cooked: child.cooked,
|
|
75
|
+
raw: child.raw,
|
|
76
|
+
});
|
|
77
|
+
} else {
|
|
78
|
+
throw new Error(`Unknown child type ${child.type}`);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const generateNode = (node, exprs, bindings) => {
|
|
83
|
+
const resolver = new PathResolver(node);
|
|
84
|
+
const { children, type, language, attributes, properties } = node;
|
|
85
|
+
const properties_ = {};
|
|
86
|
+
const children_ = [];
|
|
87
|
+
|
|
88
|
+
if (!children) {
|
|
89
|
+
throw new Error();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
for (const child of children) {
|
|
93
|
+
children_.push(generateNodeChild(child, bindings));
|
|
94
|
+
|
|
95
|
+
if (child.type === 'Reference') {
|
|
96
|
+
const path = child.value;
|
|
97
|
+
const resolved = resolver.get(path);
|
|
98
|
+
const pathIsArray = isArray(properties[path]);
|
|
99
|
+
|
|
100
|
+
let embedded = resolved;
|
|
101
|
+
if (resolved) {
|
|
102
|
+
embedded = generateNode(resolved, exprs, bindings);
|
|
103
|
+
} else {
|
|
104
|
+
embedded = exprs.pop();
|
|
105
|
+
const { interpolateArray, interpolateString } = bindings;
|
|
106
|
+
|
|
107
|
+
if (pathIsArray) {
|
|
108
|
+
embedded = expression('[...%%interpolateArray%%(%%embedded%%)]')({
|
|
109
|
+
interpolateArray,
|
|
110
|
+
embedded,
|
|
111
|
+
}).elements[0];
|
|
112
|
+
} else if (language === 'String' && type === 'String') {
|
|
113
|
+
embedded = expression('%%interpolateString%%(%%embedded%%)')({
|
|
114
|
+
interpolateString,
|
|
115
|
+
embedded,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
set(properties_, path, embedded, pathIsArray);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return expression(
|
|
125
|
+
`%%t%%.node(%%language%%, %%type%%, %%children%%, %%properties%%, %%attributes%%)`,
|
|
126
|
+
)({
|
|
127
|
+
t: bindings.t,
|
|
128
|
+
language: t.stringLiteral(language),
|
|
129
|
+
type: t.stringLiteral(type),
|
|
130
|
+
children: t.arrayExpression(children_),
|
|
131
|
+
properties: t.objectExpression(
|
|
132
|
+
Object.entries(properties_).map(([key, value]) =>
|
|
133
|
+
t.objectProperty(t.identifier(key), isArray(value) ? t.arrayExpression(value) : value),
|
|
134
|
+
),
|
|
135
|
+
),
|
|
136
|
+
attributes: t.objectExpression(
|
|
137
|
+
Object.entries(attributes).map(([key, value]) =>
|
|
138
|
+
t.objectProperty(t.identifier(key), getASTValue(value, exprs, bindings)),
|
|
139
|
+
),
|
|
140
|
+
),
|
|
141
|
+
});
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const languages = {
|
|
145
|
+
i,
|
|
146
|
+
re,
|
|
147
|
+
spam,
|
|
148
|
+
str,
|
|
149
|
+
cst: cstml,
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const topTypes = {
|
|
153
|
+
i: 'Call',
|
|
154
|
+
re: 'Pattern',
|
|
155
|
+
spam: 'Matcher',
|
|
156
|
+
str: 'String',
|
|
157
|
+
cst: 'Node',
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const getTopScope = (scope) => {
|
|
161
|
+
let top = scope;
|
|
162
|
+
while (top.parent) top = top.parent;
|
|
163
|
+
return top;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const shorthandMacro = ({ references }) => {
|
|
167
|
+
const bindings = {};
|
|
168
|
+
|
|
169
|
+
// decorator references
|
|
170
|
+
|
|
171
|
+
for (const ref of concat(
|
|
172
|
+
references.i,
|
|
173
|
+
references.spam,
|
|
174
|
+
references.re,
|
|
175
|
+
references.str,
|
|
176
|
+
references.cst,
|
|
177
|
+
)) {
|
|
178
|
+
if (!bindings.t) {
|
|
179
|
+
bindings.t = addNamespace(getTopScope(ref.scope).path, '@bablr/boot-helpers/types', {
|
|
180
|
+
nameHint: 't',
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (!bindings.interpolateArray) {
|
|
185
|
+
bindings.interpolateArray = addNamed(
|
|
186
|
+
getTopScope(ref.scope).path,
|
|
187
|
+
'interpolateArray',
|
|
188
|
+
'@bablr/boot-helpers/template',
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (!bindings.interpolateString) {
|
|
193
|
+
bindings.interpolateString = addNamed(
|
|
194
|
+
getTopScope(ref.scope).path,
|
|
195
|
+
'interpolateString',
|
|
196
|
+
'@bablr/boot-helpers/template',
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const taggedTemplate =
|
|
201
|
+
ref.parentPath.type === 'MemberExpression' ? ref.parentPath.parentPath : ref.parentPath;
|
|
202
|
+
|
|
203
|
+
const { quasis, expressions } = taggedTemplate.node.quasi;
|
|
204
|
+
|
|
205
|
+
const tagName = ref.node.name;
|
|
206
|
+
const language = languages[tagName];
|
|
207
|
+
const type =
|
|
208
|
+
ref.parentPath.type === 'MemberExpression'
|
|
209
|
+
? ref.parentPath.node.property.name
|
|
210
|
+
: topTypes[tagName];
|
|
211
|
+
|
|
212
|
+
if (!language) throw new Error();
|
|
213
|
+
|
|
214
|
+
const ast = new TemplateParser(
|
|
215
|
+
language,
|
|
216
|
+
quasis.map((q) => q.value.raw),
|
|
217
|
+
expressions.map(() => null),
|
|
218
|
+
).eval({ language: language.name, type });
|
|
219
|
+
|
|
220
|
+
taggedTemplate.replaceWith(generateNode(ast, expressions.reverse(), bindings));
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
module.exports = createMacro(shorthandMacro);
|