@esportsplus/template 0.38.2 → 0.40.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/README.md +5 -26
- package/build/compiler/codegen.d.ts +3 -2
- package/build/compiler/codegen.js +102 -142
- package/build/compiler/constants.d.ts +16 -0
- package/build/compiler/constants.js +19 -0
- package/build/compiler/index.d.ts +6 -3
- package/build/compiler/index.js +29 -38
- package/build/compiler/parser.d.ts +3 -3
- package/build/compiler/parser.js +5 -4
- package/build/compiler/plugins/tsc.d.ts +3 -2
- package/build/compiler/plugins/tsc.js +4 -2
- package/build/compiler/plugins/vite.js +4 -3
- package/build/compiler/{analyzer.d.ts → ts-analyzer.d.ts} +2 -2
- package/build/compiler/{analyzer.js → ts-analyzer.js} +16 -18
- package/build/compiler/ts-parser.d.ts +5 -1
- package/build/compiler/ts-parser.js +27 -45
- package/build/constants.d.ts +1 -16
- package/build/constants.js +1 -19
- package/package.json +7 -3
- package/src/compiler/codegen.ts +135 -217
- package/src/compiler/constants.ts +26 -0
- package/src/compiler/index.ts +33 -58
- package/src/compiler/parser.ts +7 -6
- package/src/compiler/plugins/tsc.ts +4 -2
- package/src/compiler/plugins/vite.ts +4 -3
- package/src/compiler/{analyzer.ts → ts-analyzer.ts} +17 -20
- package/src/compiler/ts-parser.ts +35 -67
- package/src/constants.ts +0 -25
- package/test/counter.ts +113 -0
- package/test/effects.ts +1 -1
- package/test/events.ts +1 -1
- package/test/imported-values.ts +1 -1
- package/test/integration/tsconfig.json +0 -1
- package/test/nested.ts +20 -1
- package/test/slots.ts +1 -1
- package/test/spread.ts +1 -1
- package/test/static.ts +1 -1
- package/test/templates.ts +1 -1
- package/test/vite.config.ts +2 -1
package/src/compiler/codegen.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { ReplacementIntent } from '@esportsplus/typescript/compiler';
|
|
2
|
-
import { ts } from '@esportsplus/typescript';
|
|
3
|
-
import { ast, uid } from '@esportsplus/typescript/compiler';
|
|
4
|
-
import { COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REACTIVITY, COMPILER_NAMESPACE, COMPILER_TYPES, DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS } from '~/constants';
|
|
5
2
|
import type { TemplateInfo } from './ts-parser';
|
|
6
|
-
import { analyze } from './analyzer';
|
|
3
|
+
import { analyze } from './ts-analyzer';
|
|
4
|
+
import { ast, uid } from '@esportsplus/typescript/compiler';
|
|
5
|
+
import { DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS } from '../constants';
|
|
6
|
+
import { ENTRYPOINT, ENTRYPOINT_REACTIVITY, NAMESPACE, TYPES } from './constants';
|
|
7
|
+
import { extractTemplateParts } from './ts-parser';
|
|
8
|
+
import { ts } from '@esportsplus/typescript';
|
|
7
9
|
import parser from './parser';
|
|
8
10
|
|
|
9
11
|
|
|
@@ -13,12 +15,11 @@ type Attribute = {
|
|
|
13
15
|
statics: Record<string, string>;
|
|
14
16
|
};
|
|
15
17
|
path: string[];
|
|
16
|
-
type:
|
|
18
|
+
type: TYPES.Attribute;
|
|
17
19
|
};
|
|
18
20
|
|
|
19
21
|
type CodegenContext = {
|
|
20
22
|
checker?: ts.TypeChecker;
|
|
21
|
-
printer: ts.Printer;
|
|
22
23
|
sourceFile: ts.SourceFile;
|
|
23
24
|
templates: Map<string, string>;
|
|
24
25
|
};
|
|
@@ -31,7 +32,7 @@ type CodegenResult = {
|
|
|
31
32
|
|
|
32
33
|
type Node = {
|
|
33
34
|
path: string[];
|
|
34
|
-
type:
|
|
35
|
+
type: TYPES.Node;
|
|
35
36
|
};
|
|
36
37
|
|
|
37
38
|
type ParseResult = {
|
|
@@ -39,43 +40,51 @@ type ParseResult = {
|
|
|
39
40
|
slots: (Attribute | Node)[] | null;
|
|
40
41
|
};
|
|
41
42
|
|
|
42
|
-
type Replacement = {
|
|
43
|
-
end: number;
|
|
44
|
-
newText: string;
|
|
45
|
-
start: number;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const ARROW_EMPTY_PARAMS = /\(\s*\)\s*=>\s*$/;
|
|
50
|
-
|
|
51
43
|
|
|
52
44
|
let printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
|
53
45
|
|
|
54
46
|
|
|
55
|
-
function collectNestedReplacements(
|
|
56
|
-
ctx: CodegenContext,
|
|
57
|
-
node: ts.Node,
|
|
58
|
-
exprStart: number,
|
|
59
|
-
replacements: Replacement[]
|
|
60
|
-
): void {
|
|
47
|
+
function collectNestedReplacements(ctx: CodegenContext, node: ts.Node, replacements: { end: number; start: number; text: string }[]): void {
|
|
61
48
|
if (isNestedHtmlTemplate(node as ts.Expression)) {
|
|
62
49
|
replacements.push({
|
|
63
|
-
end: node.end
|
|
64
|
-
|
|
65
|
-
|
|
50
|
+
end: node.end,
|
|
51
|
+
start: node.getStart(ctx.sourceFile),
|
|
52
|
+
text: generateNestedTemplateCode(ctx, node as ts.TaggedTemplateExpression)
|
|
66
53
|
});
|
|
54
|
+
|
|
55
|
+
return;
|
|
67
56
|
}
|
|
68
|
-
|
|
69
|
-
|
|
57
|
+
|
|
58
|
+
if (isReactiveCall(node as ts.Expression)) {
|
|
59
|
+
let call = node as ts.CallExpression;
|
|
60
|
+
|
|
70
61
|
replacements.push({
|
|
71
|
-
end: node.end
|
|
72
|
-
|
|
73
|
-
|
|
62
|
+
end: node.end,
|
|
63
|
+
start: node.getStart(ctx.sourceFile),
|
|
64
|
+
text: `new ${NAMESPACE}.ArraySlot(${rewriteExpression(ctx, call.arguments[0] as ts.Expression)}, ${rewriteExpression(ctx, call.arguments[1] as ts.Expression)})`
|
|
74
65
|
});
|
|
66
|
+
|
|
67
|
+
return;
|
|
75
68
|
}
|
|
76
|
-
|
|
77
|
-
|
|
69
|
+
|
|
70
|
+
ts.forEachChild(node, child => collectNestedReplacements(ctx, child, replacements));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function discoverTemplatesInExpression(ctx: CodegenContext, node: ts.Node): void {
|
|
74
|
+
if (isNestedHtmlTemplate(node as ts.Expression)) {
|
|
75
|
+
let { expressions, literals } = extractTemplateParts((node as ts.TaggedTemplateExpression).template),
|
|
76
|
+
parsed = parser.parse(literals) as ParseResult;
|
|
77
|
+
|
|
78
|
+
getOrCreateTemplateId(ctx, parsed.html);
|
|
79
|
+
|
|
80
|
+
for (let i = 0, n = expressions.length; i < n; i++) {
|
|
81
|
+
discoverTemplatesInExpression(ctx, expressions[i]);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return;
|
|
78
85
|
}
|
|
86
|
+
|
|
87
|
+
ts.forEachChild(node, child => discoverTemplatesInExpression(ctx, child));
|
|
79
88
|
}
|
|
80
89
|
|
|
81
90
|
function generateAttributeBinding(element: string, name: string, expr: string, staticValue: string): string {
|
|
@@ -84,46 +93,33 @@ function generateAttributeBinding(element: string, name: string, expr: string, s
|
|
|
84
93
|
key = name.toLowerCase();
|
|
85
94
|
|
|
86
95
|
if (LIFECYCLE_EVENTS.has(key)) {
|
|
87
|
-
return `${
|
|
96
|
+
return `${NAMESPACE}.${key}(${element}, ${expr});`;
|
|
88
97
|
}
|
|
89
98
|
|
|
90
99
|
if (DIRECT_ATTACH_EVENTS.has(key)) {
|
|
91
|
-
return `${
|
|
100
|
+
return `${NAMESPACE}.on(${element}, '${event}', ${expr});`;
|
|
92
101
|
}
|
|
93
102
|
|
|
94
|
-
return `${
|
|
103
|
+
return `${NAMESPACE}.delegate(${element}, '${event}', ${expr});`;
|
|
95
104
|
}
|
|
96
105
|
|
|
97
106
|
if (name === 'class') {
|
|
98
|
-
return `${
|
|
107
|
+
return `${NAMESPACE}.setClass(${element}, '${staticValue}', ${expr});`;
|
|
99
108
|
}
|
|
100
109
|
|
|
101
110
|
if (name === 'style') {
|
|
102
|
-
return `${
|
|
111
|
+
return `${NAMESPACE}.setStyle(${element}, '${staticValue}', ${expr});`;
|
|
103
112
|
}
|
|
104
113
|
|
|
105
|
-
return `${
|
|
114
|
+
return `${NAMESPACE}.setProperty(${element}, '${name}', ${expr});`;
|
|
106
115
|
}
|
|
107
116
|
|
|
108
117
|
function generateNestedTemplateCode(ctx: CodegenContext, node: ts.TaggedTemplateExpression): string {
|
|
109
|
-
let expressions
|
|
110
|
-
exprTexts: string[] = []
|
|
111
|
-
literals: string[] = [],
|
|
112
|
-
template = node.template;
|
|
113
|
-
|
|
114
|
-
if (ts.isNoSubstitutionTemplateLiteral(template)) {
|
|
115
|
-
literals.push(template.text);
|
|
116
|
-
}
|
|
117
|
-
else if (ts.isTemplateExpression(template)) {
|
|
118
|
-
literals.push(template.head.text);
|
|
118
|
+
let { expressions, literals } = extractTemplateParts(node.template),
|
|
119
|
+
exprTexts: string[] = [];
|
|
119
120
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
expressions.push(expr);
|
|
124
|
-
literals.push(template.templateSpans[i].literal.text);
|
|
125
|
-
exprTexts.push(rewriteExpression(ctx, expr));
|
|
126
|
-
}
|
|
121
|
+
for (let i = 0, n = expressions.length; i < n; i++) {
|
|
122
|
+
exprTexts.push(rewriteExpression(ctx, expressions[i]));
|
|
127
123
|
}
|
|
128
124
|
|
|
129
125
|
return generateTemplateCode(
|
|
@@ -131,36 +127,34 @@ function generateNestedTemplateCode(ctx: CodegenContext, node: ts.TaggedTemplate
|
|
|
131
127
|
parser.parse(literals) as ParseResult,
|
|
132
128
|
exprTexts,
|
|
133
129
|
expressions,
|
|
134
|
-
|
|
130
|
+
node
|
|
135
131
|
);
|
|
136
132
|
}
|
|
137
133
|
|
|
138
134
|
function generateNodeBinding(ctx: CodegenContext, anchor: string, exprText: string, exprNode: ts.Expression | undefined): string {
|
|
139
135
|
if (!exprNode) {
|
|
140
|
-
return `${
|
|
136
|
+
return `${NAMESPACE}.slot(${anchor}, ${exprText});`;
|
|
141
137
|
}
|
|
142
138
|
|
|
143
139
|
if (isNestedHtmlTemplate(exprNode)) {
|
|
144
140
|
return `${anchor}.parentNode!.insertBefore(${generateNestedTemplateCode(ctx, exprNode)}, ${anchor});`;
|
|
145
141
|
}
|
|
146
142
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
case COMPILER_TYPES.ArraySlot:
|
|
151
|
-
return `${anchor}.parentNode!.insertBefore(new ${COMPILER_NAMESPACE}.ArraySlot(${exprText}).fragment, ${anchor});`;
|
|
143
|
+
switch (analyze(exprNode, ctx.checker)) {
|
|
144
|
+
case TYPES.ArraySlot:
|
|
145
|
+
return `${anchor}.parentNode!.insertBefore(new ${NAMESPACE}.ArraySlot(${exprText}).fragment, ${anchor});`;
|
|
152
146
|
|
|
153
|
-
case
|
|
147
|
+
case TYPES.DocumentFragment:
|
|
154
148
|
return `${anchor}.parentNode!.insertBefore(${exprText}, ${anchor});`;
|
|
155
149
|
|
|
156
|
-
case
|
|
157
|
-
return `new ${
|
|
150
|
+
case TYPES.Effect:
|
|
151
|
+
return `new ${NAMESPACE}.EffectSlot(${anchor}, ${exprText});`;
|
|
158
152
|
|
|
159
|
-
case
|
|
153
|
+
case TYPES.Static:
|
|
160
154
|
return `${anchor}.textContent = ${exprText};`;
|
|
161
155
|
|
|
162
156
|
default:
|
|
163
|
-
return `${
|
|
157
|
+
return `${NAMESPACE}.slot(${anchor}, ${exprText});`;
|
|
164
158
|
}
|
|
165
159
|
}
|
|
166
160
|
|
|
@@ -169,7 +163,7 @@ function generateTemplateCode(
|
|
|
169
163
|
{ html, slots }: ParseResult,
|
|
170
164
|
exprTexts: string[],
|
|
171
165
|
exprNodes: ts.Expression[],
|
|
172
|
-
|
|
166
|
+
templateNode: ts.Node
|
|
173
167
|
): string {
|
|
174
168
|
if (!slots || slots.length === 0) {
|
|
175
169
|
return `${getOrCreateTemplateId(ctx, html)}()`;
|
|
@@ -178,6 +172,7 @@ function generateTemplateCode(
|
|
|
178
172
|
let code: string[] = [],
|
|
179
173
|
declarations: string[] = [],
|
|
180
174
|
index = 0,
|
|
175
|
+
isArrowBody = isArrowExpressionBody(templateNode),
|
|
181
176
|
nodes = new Map<string, string>(),
|
|
182
177
|
root = uid('root');
|
|
183
178
|
|
|
@@ -215,17 +210,15 @@ function generateTemplateCode(
|
|
|
215
210
|
value = `${ancestor}.${segments.join('!.')}`;
|
|
216
211
|
|
|
217
212
|
if (ancestor === root && segments[0] === 'firstChild') {
|
|
218
|
-
value = value.replace(`${ancestor}.firstChild!`, `(${
|
|
213
|
+
value = value.replace(`${ancestor}.firstChild!`, `(${root}.firstChild! as ${NAMESPACE}.Element)`);
|
|
219
214
|
}
|
|
220
215
|
|
|
221
|
-
declarations.push(`${name} = ${value} as ${
|
|
216
|
+
declarations.push(`${name} = ${value} as ${NAMESPACE}.Element`);
|
|
222
217
|
nodes.set(key, name);
|
|
223
218
|
}
|
|
224
219
|
|
|
225
|
-
code.push(
|
|
226
|
-
|
|
227
|
-
`let ${declarations.join(',\n')};`
|
|
228
|
-
);
|
|
220
|
+
code.push(isArrowBody ? '{' : `(() => {`);
|
|
221
|
+
code.push(`let ${declarations.join(',\n')};`);
|
|
229
222
|
|
|
230
223
|
for (let i = 0, n = slots.length; i < n; i++) {
|
|
231
224
|
let element = slots[i].path.length === 0
|
|
@@ -233,15 +226,15 @@ function generateTemplateCode(
|
|
|
233
226
|
: (nodes.get(slots[i].path.join('.')) || root),
|
|
234
227
|
slot = slots[i];
|
|
235
228
|
|
|
236
|
-
if (slot.type ===
|
|
229
|
+
if (slot.type === TYPES.Attribute) {
|
|
237
230
|
let names = slot.attributes.names;
|
|
238
231
|
|
|
239
232
|
for (let j = 0, m = names.length; j < m; j++) {
|
|
240
233
|
let name = names[j];
|
|
241
234
|
|
|
242
|
-
if (name ===
|
|
235
|
+
if (name === TYPES.Attributes) {
|
|
243
236
|
code.push(
|
|
244
|
-
`${
|
|
237
|
+
`${NAMESPACE}.setProperties(${element}, ${exprTexts[index] || 'undefined'});`
|
|
245
238
|
);
|
|
246
239
|
index++;
|
|
247
240
|
}
|
|
@@ -282,8 +275,12 @@ function getOrCreateTemplateId(ctx: CodegenContext, html: string): string {
|
|
|
282
275
|
return id;
|
|
283
276
|
}
|
|
284
277
|
|
|
278
|
+
function isArrowExpressionBody(node: ts.Node): boolean {
|
|
279
|
+
return ts.isArrowFunction(node.parent) && (node.parent as ts.ArrowFunction).body === node;
|
|
280
|
+
}
|
|
281
|
+
|
|
285
282
|
function isNestedHtmlTemplate(expr: ts.Expression): expr is ts.TaggedTemplateExpression {
|
|
286
|
-
return ts.isTaggedTemplateExpression(expr) && ts.isIdentifier(expr.tag) && expr.tag.text ===
|
|
283
|
+
return ts.isTaggedTemplateExpression(expr) && ts.isIdentifier(expr.tag) && expr.tag.text === ENTRYPOINT;
|
|
287
284
|
}
|
|
288
285
|
|
|
289
286
|
function isReactiveCall(expr: ts.Expression): expr is ts.CallExpression {
|
|
@@ -291,122 +288,48 @@ function isReactiveCall(expr: ts.Expression): expr is ts.CallExpression {
|
|
|
291
288
|
ts.isCallExpression(expr) &&
|
|
292
289
|
ts.isPropertyAccessExpression(expr.expression) &&
|
|
293
290
|
ts.isIdentifier(expr.expression.expression) &&
|
|
294
|
-
expr.expression.expression.text ===
|
|
295
|
-
expr.expression.name.text ===
|
|
291
|
+
expr.expression.expression.text === ENTRYPOINT &&
|
|
292
|
+
expr.expression.name.text === ENTRYPOINT_REACTIVITY
|
|
296
293
|
);
|
|
297
294
|
}
|
|
298
295
|
|
|
299
|
-
function replaceReverse(text: string, replacements: Replacement[]): string {
|
|
300
|
-
let sorted = replacements.slice().sort((a, b) => b.start - a.start);
|
|
301
|
-
|
|
302
|
-
for (let i = 0, n = sorted.length; i < n; i++) {
|
|
303
|
-
let r = sorted[i];
|
|
304
|
-
|
|
305
|
-
text = text.slice(0, r.start) + r.newText + text.slice(r.end);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
return text;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
296
|
function rewriteExpression(ctx: CodegenContext, expr: ts.Expression): string {
|
|
312
297
|
if (isNestedHtmlTemplate(expr)) {
|
|
313
298
|
return generateNestedTemplateCode(ctx, expr);
|
|
314
299
|
}
|
|
315
300
|
|
|
316
301
|
if (isReactiveCall(expr)) {
|
|
317
|
-
return
|
|
302
|
+
return `${rewriteExpression(ctx, expr.arguments[0] as ts.Expression)}, ${rewriteExpression(ctx, expr.arguments[1] as ts.Expression)}`;
|
|
318
303
|
}
|
|
319
304
|
|
|
320
|
-
if (!ast.
|
|
321
|
-
return
|
|
305
|
+
if (!ast.test(expr, n => isNestedHtmlTemplate(n as ts.Expression) || isReactiveCall(n as ts.Expression))) {
|
|
306
|
+
return printer.printNode(ts.EmitHint.Expression, expr, ctx.sourceFile);
|
|
322
307
|
}
|
|
323
308
|
|
|
324
|
-
let
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
return replaceReverse(expr.getText(ctx.sourceFile), replacements);
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// Returns just args "array, callback" - for direct slot usage where generateNodeBinding wraps it
|
|
332
|
-
function rewriteReactiveCall(ctx: CodegenContext, node: ts.CallExpression): string {
|
|
333
|
-
let arrayArg = node.arguments[0],
|
|
334
|
-
arrayText = ctx.printer.printNode(ts.EmitHint.Expression, arrayArg, ctx.sourceFile),
|
|
335
|
-
callbackArg = node.arguments[1],
|
|
336
|
-
callbackText = rewriteExpression(ctx, callbackArg as ts.Expression);
|
|
309
|
+
let exprStart = expr.getStart(ctx.sourceFile),
|
|
310
|
+
replacements: { end: number; start: number; text: string }[] = [],
|
|
311
|
+
text = expr.getText(ctx.sourceFile);
|
|
337
312
|
|
|
338
|
-
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
// Returns full "new ArraySlot(array, callback)" - for nested reactive calls inside expressions
|
|
342
|
-
function rewriteNestedReactiveCall(ctx: CodegenContext, node: ts.CallExpression): string {
|
|
343
|
-
let arrayArg = node.arguments[0],
|
|
344
|
-
arrayText = ctx.printer.printNode(ts.EmitHint.Expression, arrayArg, ctx.sourceFile),
|
|
345
|
-
callbackArg = node.arguments[1],
|
|
346
|
-
callbackText = rewriteExpression(ctx, callbackArg as ts.Expression);
|
|
347
|
-
|
|
348
|
-
return `new ${COMPILER_NAMESPACE}.ArraySlot(${arrayText}, ${callbackText})`;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// Eager discovery - walk all expressions to find templates before prepend generation
|
|
352
|
-
function discoverTemplatesInExpression(ctx: CodegenContext, node: ts.Node): void {
|
|
353
|
-
if (isNestedHtmlTemplate(node as ts.Expression)) {
|
|
354
|
-
let template = node as ts.TaggedTemplateExpression,
|
|
355
|
-
expressions: ts.Expression[] = [],
|
|
356
|
-
literals: string[] = [],
|
|
357
|
-
tpl = template.template;
|
|
358
|
-
|
|
359
|
-
if (ts.isNoSubstitutionTemplateLiteral(tpl)) {
|
|
360
|
-
literals.push(tpl.text);
|
|
361
|
-
}
|
|
362
|
-
else if (ts.isTemplateExpression(tpl)) {
|
|
363
|
-
literals.push(tpl.head.text);
|
|
313
|
+
ts.forEachChild(expr, child => collectNestedReplacements(ctx, child, replacements));
|
|
364
314
|
|
|
365
|
-
|
|
366
|
-
expressions.push(tpl.templateSpans[i].expression);
|
|
367
|
-
literals.push(tpl.templateSpans[i].literal.text);
|
|
368
|
-
}
|
|
369
|
-
}
|
|
315
|
+
replacements.sort((a, b) => b.start - a.start);
|
|
370
316
|
|
|
371
|
-
|
|
317
|
+
for (let i = 0, n = replacements.length; i < n; i++) {
|
|
318
|
+
let r = replacements[i];
|
|
372
319
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
for (let i = 0, n = expressions.length; i < n; i++) {
|
|
376
|
-
discoverTemplatesInExpression(ctx, expressions[i]);
|
|
377
|
-
}
|
|
320
|
+
text = text.slice(0, r.start - exprStart) + r.text + text.slice(r.end - exprStart);
|
|
378
321
|
}
|
|
379
|
-
else if (isReactiveCall(node as ts.Expression)) {
|
|
380
|
-
let call = node as ts.CallExpression;
|
|
381
|
-
|
|
382
|
-
if (call.arguments.length >= 2) {
|
|
383
|
-
discoverTemplatesInExpression(ctx, call.arguments[1]);
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
else {
|
|
387
|
-
ts.forEachChild(node, child => discoverTemplatesInExpression(ctx, child));
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
function discoverAllTemplates(ctx: CodegenContext, templates: TemplateInfo[]): void {
|
|
392
|
-
for (let i = 0, n = templates.length; i < n; i++) {
|
|
393
|
-
let parsed = parser.parse(templates[i].literals) as ParseResult;
|
|
394
|
-
|
|
395
|
-
getOrCreateTemplateId(ctx, parsed.html);
|
|
396
322
|
|
|
397
|
-
|
|
398
|
-
discoverTemplatesInExpression(ctx, templates[i].expressions[j]);
|
|
399
|
-
}
|
|
400
|
-
}
|
|
323
|
+
return text;
|
|
401
324
|
}
|
|
402
325
|
|
|
403
326
|
|
|
404
327
|
const generateCode = (templates: TemplateInfo[], sourceFile: ts.SourceFile, checker?: ts.TypeChecker): CodegenResult => {
|
|
405
328
|
let result: CodegenResult = {
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
329
|
+
prepend: [],
|
|
330
|
+
replacements: [],
|
|
331
|
+
templates: new Map()
|
|
332
|
+
};
|
|
410
333
|
|
|
411
334
|
if (templates.length === 0) {
|
|
412
335
|
return result;
|
|
@@ -422,69 +345,64 @@ const generateCode = (templates: TemplateInfo[], sourceFile: ts.SourceFile, chec
|
|
|
422
345
|
}
|
|
423
346
|
}
|
|
424
347
|
|
|
425
|
-
let
|
|
348
|
+
let root = templates.filter(t => !ast.inRange(ranges, t.node.getStart(sourceFile), t.node.end));
|
|
426
349
|
|
|
427
|
-
if (
|
|
350
|
+
if (root.length === 0) {
|
|
428
351
|
return result;
|
|
429
352
|
}
|
|
430
353
|
|
|
431
354
|
let ctx: CodegenContext = {
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
355
|
+
checker,
|
|
356
|
+
sourceFile,
|
|
357
|
+
templates: result.templates
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
for (let i = 0, n = root.length; i < n; i++) {
|
|
361
|
+
let exprTexts: string[] = [],
|
|
362
|
+
parsed = parser.parse(root[i].literals) as ParseResult,
|
|
363
|
+
template = root[i];
|
|
364
|
+
|
|
365
|
+
for (let j = 0, m = template.expressions.length; j < m; j++) {
|
|
366
|
+
exprTexts.push(rewriteExpression(ctx, template.expressions[j]));
|
|
367
|
+
}
|
|
437
368
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
parsed = parser.parse(template.literals) as ParseResult;
|
|
453
|
-
|
|
454
|
-
for (let j = 0, m = template.expressions.length; j < m; j++) {
|
|
455
|
-
exprTexts.push(rewriteExpression(localCtx, template.expressions[j]));
|
|
456
|
-
}
|
|
369
|
+
if (
|
|
370
|
+
isArrowExpressionBody(template.node) &&
|
|
371
|
+
(template.node.parent as ts.ArrowFunction).parameters.length === 0 &&
|
|
372
|
+
(!parsed.slots || parsed.slots.length === 0)
|
|
373
|
+
) {
|
|
374
|
+
let code = getOrCreateTemplateId(ctx, parsed.html);
|
|
375
|
+
|
|
376
|
+
result.replacements.push({
|
|
377
|
+
generate: () => code,
|
|
378
|
+
node: template.node
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
let code = generateTemplateCode(ctx, parsed, exprTexts, template.expressions, template.node);
|
|
457
383
|
|
|
458
|
-
|
|
459
|
-
|
|
384
|
+
result.replacements.push({
|
|
385
|
+
generate: () => code,
|
|
386
|
+
node: template.node
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
}
|
|
460
390
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
}
|
|
464
|
-
}
|
|
391
|
+
for (let i = 0, n = templates.length; i < n; i++) {
|
|
392
|
+
getOrCreateTemplateId(ctx, parser.parse(templates[i].literals).html);
|
|
465
393
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
exprTexts,
|
|
470
|
-
template.expressions,
|
|
471
|
-
isArrowBody
|
|
472
|
-
);
|
|
473
|
-
},
|
|
474
|
-
node: template.node
|
|
475
|
-
});
|
|
394
|
+
for (let j = 0, m = templates[i].expressions.length; j < m; j++) {
|
|
395
|
+
discoverTemplatesInExpression(ctx, templates[i].expressions[j]);
|
|
396
|
+
}
|
|
476
397
|
}
|
|
477
398
|
|
|
478
|
-
// Eager discovery: find all templates before prepend generation
|
|
479
|
-
discoverAllTemplates(ctx, templates);
|
|
480
|
-
|
|
481
399
|
for (let [html, id] of ctx.templates) {
|
|
482
|
-
result.prepend.push(`const ${id} = ${
|
|
400
|
+
result.prepend.push(`const ${id} = ${NAMESPACE}.template(\`${html}\`);`);
|
|
483
401
|
}
|
|
484
402
|
|
|
485
403
|
return result;
|
|
486
404
|
};
|
|
487
405
|
|
|
488
406
|
|
|
489
|
-
export { generateCode };
|
|
407
|
+
export { generateCode, printer };
|
|
490
408
|
export type { CodegenResult };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { uid } from '@esportsplus/typescript/compiler';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
const ENTRYPOINT = 'html';
|
|
5
|
+
|
|
6
|
+
const ENTRYPOINT_REACTIVITY = 'reactive';
|
|
7
|
+
|
|
8
|
+
const NAMESPACE = uid('template');
|
|
9
|
+
|
|
10
|
+
const PACKAGE = '@esportsplus/template';
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const enum TYPES {
|
|
14
|
+
ArraySlot = 'array-slot',
|
|
15
|
+
Attributes = 'attributes',
|
|
16
|
+
Attribute = 'attribute',
|
|
17
|
+
DocumentFragment = 'document-fragment',
|
|
18
|
+
Effect = 'effect',
|
|
19
|
+
Node = 'node',
|
|
20
|
+
Primitive = 'primitive',
|
|
21
|
+
Static = 'static',
|
|
22
|
+
Unknown = 'unknown'
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
export { ENTRYPOINT, ENTRYPOINT_REACTIVITY, NAMESPACE, PACKAGE, TYPES };
|