@esportsplus/template 0.39.0 → 0.40.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.
- package/README.md +5 -26
- package/build/compiler/codegen.d.ts +1 -1
- package/build/compiler/codegen.js +100 -141
- 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 +23 -24
- package/build/compiler/parser.d.ts +3 -3
- package/build/compiler/parser.js +6 -5
- package/build/compiler/plugins/tsc.d.ts +3 -2
- package/build/compiler/plugins/tsc.js +4 -2
- package/build/compiler/plugins/vite.js +5 -4
- package/build/compiler/ts-analyzer.d.ts +2 -2
- package/build/compiler/ts-analyzer.js +15 -16
- package/build/compiler/ts-parser.js +6 -6
- package/build/constants.d.ts +1 -16
- package/build/constants.js +1 -19
- package/package.json +7 -3
- package/src/compiler/codegen.ts +126 -192
- package/src/compiler/constants.ts +26 -0
- package/src/compiler/index.ts +25 -36
- package/src/compiler/parser.ts +8 -7
- package/src/compiler/plugins/tsc.ts +4 -2
- package/src/compiler/plugins/vite.ts +5 -4
- package/src/compiler/ts-analyzer.ts +16 -18
- package/src/compiler/ts-parser.ts +6 -7
- 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
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REACTIVITY, COMPILER_TYPES } from '../constants.js';
|
|
2
1
|
import { ts } from '@esportsplus/typescript';
|
|
2
|
+
import { ENTRYPOINT, ENTRYPOINT_REACTIVITY, TYPES } from './constants.js';
|
|
3
3
|
function isTypeFunction(type, checker) {
|
|
4
4
|
if (type.isUnion()) {
|
|
5
5
|
for (let i = 0, n = type.types.length; i < n; i++) {
|
|
@@ -16,17 +16,17 @@ const analyze = (expr, checker) => {
|
|
|
16
16
|
expr = expr.expression;
|
|
17
17
|
}
|
|
18
18
|
if (ts.isArrowFunction(expr) || ts.isFunctionExpression(expr)) {
|
|
19
|
-
return
|
|
19
|
+
return TYPES.Effect;
|
|
20
20
|
}
|
|
21
21
|
if (ts.isCallExpression(expr) &&
|
|
22
22
|
ts.isPropertyAccessExpression(expr.expression) &&
|
|
23
23
|
ts.isIdentifier(expr.expression.expression) &&
|
|
24
|
-
expr.expression.expression.text ===
|
|
25
|
-
expr.expression.name.text ===
|
|
26
|
-
return
|
|
24
|
+
expr.expression.expression.text === ENTRYPOINT &&
|
|
25
|
+
expr.expression.name.text === ENTRYPOINT_REACTIVITY) {
|
|
26
|
+
return TYPES.ArraySlot;
|
|
27
27
|
}
|
|
28
|
-
if (ts.isTaggedTemplateExpression(expr) && ts.isIdentifier(expr.tag) && expr.tag.text ===
|
|
29
|
-
return
|
|
28
|
+
if (ts.isTaggedTemplateExpression(expr) && ts.isIdentifier(expr.tag) && expr.tag.text === ENTRYPOINT) {
|
|
29
|
+
return TYPES.DocumentFragment;
|
|
30
30
|
}
|
|
31
31
|
if (ts.isNumericLiteral(expr) ||
|
|
32
32
|
ts.isStringLiteral(expr) ||
|
|
@@ -35,30 +35,29 @@ const analyze = (expr, checker) => {
|
|
|
35
35
|
expr.kind === ts.SyntaxKind.FalseKeyword ||
|
|
36
36
|
expr.kind === ts.SyntaxKind.NullKeyword ||
|
|
37
37
|
expr.kind === ts.SyntaxKind.UndefinedKeyword) {
|
|
38
|
-
return
|
|
38
|
+
return TYPES.Static;
|
|
39
39
|
}
|
|
40
40
|
if (ts.isTemplateExpression(expr)) {
|
|
41
|
-
return
|
|
41
|
+
return TYPES.Primitive;
|
|
42
42
|
}
|
|
43
43
|
if (ts.isConditionalExpression(expr)) {
|
|
44
44
|
let whenFalse = analyze(expr.whenFalse, checker), whenTrue = analyze(expr.whenTrue, checker);
|
|
45
45
|
if (whenTrue === whenFalse) {
|
|
46
46
|
return whenTrue;
|
|
47
47
|
}
|
|
48
|
-
if (whenTrue ===
|
|
49
|
-
return
|
|
48
|
+
if (whenTrue === TYPES.Effect || whenFalse === TYPES.Effect) {
|
|
49
|
+
return TYPES.Effect;
|
|
50
50
|
}
|
|
51
|
-
return
|
|
51
|
+
return TYPES.Unknown;
|
|
52
52
|
}
|
|
53
53
|
if (checker && (ts.isIdentifier(expr) || ts.isPropertyAccessExpression(expr) || ts.isCallExpression(expr))) {
|
|
54
54
|
try {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return COMPILER_TYPES.Effect;
|
|
55
|
+
if (isTypeFunction(checker.getTypeAtLocation(expr), checker)) {
|
|
56
|
+
return TYPES.Effect;
|
|
58
57
|
}
|
|
59
58
|
}
|
|
60
59
|
catch { }
|
|
61
60
|
}
|
|
62
|
-
return
|
|
61
|
+
return TYPES.Unknown;
|
|
63
62
|
};
|
|
64
63
|
export { analyze };
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { ts } from '@esportsplus/typescript';
|
|
2
2
|
import { imports } from '@esportsplus/typescript/compiler';
|
|
3
|
-
import {
|
|
3
|
+
import { ENTRYPOINT, ENTRYPOINT_REACTIVITY, PACKAGE_NAME } from './constants.js';
|
|
4
4
|
function visitReactiveCalls(node, calls, checker) {
|
|
5
5
|
if (ts.isCallExpression(node) &&
|
|
6
6
|
ts.isPropertyAccessExpression(node.expression) &&
|
|
7
7
|
ts.isIdentifier(node.expression.expression) &&
|
|
8
|
-
node.expression.name.text ===
|
|
8
|
+
node.expression.name.text === ENTRYPOINT_REACTIVITY &&
|
|
9
9
|
node.arguments.length === 2 &&
|
|
10
|
-
node.expression.expression.text ===
|
|
11
|
-
(!checker || imports.
|
|
10
|
+
node.expression.expression.text === ENTRYPOINT &&
|
|
11
|
+
(!checker || imports.includes(checker, node.expression.expression, PACKAGE_NAME, ENTRYPOINT))) {
|
|
12
12
|
calls.push({
|
|
13
13
|
arrayArg: node.arguments[0],
|
|
14
14
|
callbackArg: node.arguments[1],
|
|
@@ -25,8 +25,8 @@ function visitTemplates(node, depth, templates, checker) {
|
|
|
25
25
|
: depth;
|
|
26
26
|
if (ts.isTaggedTemplateExpression(node) &&
|
|
27
27
|
ts.isIdentifier(node.tag) &&
|
|
28
|
-
node.tag.text ===
|
|
29
|
-
(!checker || imports.
|
|
28
|
+
node.tag.text === ENTRYPOINT &&
|
|
29
|
+
(!checker || imports.includes(checker, node.tag, PACKAGE_NAME, ENTRYPOINT))) {
|
|
30
30
|
let { expressions, literals } = extractTemplateParts(node.template);
|
|
31
31
|
templates.push({
|
|
32
32
|
depth,
|
package/build/constants.d.ts
CHANGED
|
@@ -1,25 +1,10 @@
|
|
|
1
1
|
declare const ARRAY_SLOT: unique symbol;
|
|
2
2
|
declare const CLEANUP: unique symbol;
|
|
3
|
-
declare const COMPILER_ENTRYPOINT = "html";
|
|
4
|
-
declare const COMPILER_ENTRYPOINT_REACTIVITY = "reactive";
|
|
5
|
-
declare const COMPILER_NAMESPACE: string;
|
|
6
|
-
declare const enum COMPILER_TYPES {
|
|
7
|
-
ArraySlot = "array-slot",
|
|
8
|
-
Attributes = "attributes",
|
|
9
|
-
Attribute = "attribute",
|
|
10
|
-
DocumentFragment = "document-fragment",
|
|
11
|
-
Effect = "effect",
|
|
12
|
-
Node = "node",
|
|
13
|
-
Primitive = "primitive",
|
|
14
|
-
Static = "static",
|
|
15
|
-
Unknown = "unknown"
|
|
16
|
-
}
|
|
17
3
|
declare const DIRECT_ATTACH_EVENTS: Set<string>;
|
|
18
4
|
declare const LIFECYCLE_EVENTS: Set<string>;
|
|
19
|
-
declare const PACKAGE = "@esportsplus/template";
|
|
20
5
|
declare const SLOT_HTML = "<!--$-->";
|
|
21
6
|
declare const STATE_HYDRATING = 0;
|
|
22
7
|
declare const STATE_NONE = 1;
|
|
23
8
|
declare const STATE_WAITING = 2;
|
|
24
9
|
declare const STORE: unique symbol;
|
|
25
|
-
export { ARRAY_SLOT, CLEANUP,
|
|
10
|
+
export { ARRAY_SLOT, CLEANUP, DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS, SLOT_HTML, STATE_HYDRATING, STATE_NONE, STATE_WAITING, STORE, };
|
package/build/constants.js
CHANGED
|
@@ -1,22 +1,5 @@
|
|
|
1
|
-
import { uid } from '@esportsplus/typescript/compiler';
|
|
2
1
|
const ARRAY_SLOT = Symbol('template.array.slot');
|
|
3
2
|
const CLEANUP = Symbol('template.cleanup');
|
|
4
|
-
const COMPILER_ENTRYPOINT = 'html';
|
|
5
|
-
const COMPILER_ENTRYPOINT_REACTIVITY = 'reactive';
|
|
6
|
-
const COMPILER_NAMESPACE = uid('template');
|
|
7
|
-
var COMPILER_TYPES;
|
|
8
|
-
(function (COMPILER_TYPES) {
|
|
9
|
-
COMPILER_TYPES["ArraySlot"] = "array-slot";
|
|
10
|
-
COMPILER_TYPES["Attributes"] = "attributes";
|
|
11
|
-
COMPILER_TYPES["Attribute"] = "attribute";
|
|
12
|
-
COMPILER_TYPES["DocumentFragment"] = "document-fragment";
|
|
13
|
-
COMPILER_TYPES["Effect"] = "effect";
|
|
14
|
-
COMPILER_TYPES["Node"] = "node";
|
|
15
|
-
COMPILER_TYPES["Primitive"] = "primitive";
|
|
16
|
-
COMPILER_TYPES["Static"] = "static";
|
|
17
|
-
COMPILER_TYPES["Unknown"] = "unknown";
|
|
18
|
-
})(COMPILER_TYPES || (COMPILER_TYPES = {}));
|
|
19
|
-
;
|
|
20
3
|
const DIRECT_ATTACH_EVENTS = new Set([
|
|
21
4
|
'onblur',
|
|
22
5
|
'onerror',
|
|
@@ -29,10 +12,9 @@ const DIRECT_ATTACH_EVENTS = new Set([
|
|
|
29
12
|
const LIFECYCLE_EVENTS = new Set([
|
|
30
13
|
'onconnect', 'ondisconnect', 'onrender', 'onresize', 'ontick'
|
|
31
14
|
]);
|
|
32
|
-
const PACKAGE = '@esportsplus/template';
|
|
33
15
|
const SLOT_HTML = '<!--$-->';
|
|
34
16
|
const STATE_HYDRATING = 0;
|
|
35
17
|
const STATE_NONE = 1;
|
|
36
18
|
const STATE_WAITING = 2;
|
|
37
19
|
const STORE = Symbol('template.store');
|
|
38
|
-
export { ARRAY_SLOT, CLEANUP,
|
|
20
|
+
export { ARRAY_SLOT, CLEANUP, DIRECT_ATTACH_EVENTS, LIFECYCLE_EVENTS, SLOT_HTML, STATE_HYDRATING, STATE_NONE, STATE_WAITING, STORE, };
|
package/package.json
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"author": "ICJR",
|
|
3
3
|
"dependencies": {
|
|
4
4
|
"@esportsplus/queue": "^0.2.0",
|
|
5
|
-
"@esportsplus/reactivity": "^0.29.
|
|
6
|
-
"@esportsplus/typescript": "^0.
|
|
5
|
+
"@esportsplus/reactivity": "^0.29.9",
|
|
6
|
+
"@esportsplus/typescript": "^0.27.0",
|
|
7
7
|
"@esportsplus/utilities": "^0.27.2",
|
|
8
8
|
"serve": "^14.2.5"
|
|
9
9
|
},
|
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
"types": "./build/index.d.ts",
|
|
18
18
|
"default": "./build/index.js"
|
|
19
19
|
},
|
|
20
|
+
"./compiler": {
|
|
21
|
+
"types": "./build/compiler/index.d.ts",
|
|
22
|
+
"default": "./build/compiler/index.js"
|
|
23
|
+
},
|
|
20
24
|
"./compiler/tsc": {
|
|
21
25
|
"types": "./build/compiler/plugins/tsc.d.ts",
|
|
22
26
|
"default": "./build/compiler/plugins/tsc.js"
|
|
@@ -35,7 +39,7 @@
|
|
|
35
39
|
},
|
|
36
40
|
"type": "module",
|
|
37
41
|
"types": "./build/index.d.ts",
|
|
38
|
-
"version": "0.
|
|
42
|
+
"version": "0.40.1",
|
|
39
43
|
"scripts": {
|
|
40
44
|
"build": "tsc",
|
|
41
45
|
"build:test": "vite build --config test/vite.config.ts",
|
package/src/compiler/codegen.ts
CHANGED
|
@@ -1,10 +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
|
-
import { extractTemplateParts } from './ts-parser';
|
|
6
2
|
import type { TemplateInfo } from './ts-parser';
|
|
7
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';
|
|
8
9
|
import parser from './parser';
|
|
9
10
|
|
|
10
11
|
|
|
@@ -14,7 +15,7 @@ type Attribute = {
|
|
|
14
15
|
statics: Record<string, string>;
|
|
15
16
|
};
|
|
16
17
|
path: string[];
|
|
17
|
-
type:
|
|
18
|
+
type: TYPES.Attribute;
|
|
18
19
|
};
|
|
19
20
|
|
|
20
21
|
type CodegenContext = {
|
|
@@ -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 = {
|
|
@@ -43,31 +44,74 @@ type ParseResult = {
|
|
|
43
44
|
let printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
|
44
45
|
|
|
45
46
|
|
|
47
|
+
function collectNestedReplacements(ctx: CodegenContext, node: ts.Node, replacements: { end: number; start: number; text: string }[]): void {
|
|
48
|
+
if (isNestedHtmlTemplate(node as ts.Expression)) {
|
|
49
|
+
replacements.push({
|
|
50
|
+
end: node.end,
|
|
51
|
+
start: node.getStart(ctx.sourceFile),
|
|
52
|
+
text: generateNestedTemplateCode(ctx, node as ts.TaggedTemplateExpression)
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (isReactiveCall(node as ts.Expression)) {
|
|
59
|
+
let call = node as ts.CallExpression;
|
|
60
|
+
|
|
61
|
+
replacements.push({
|
|
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)})`
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
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;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
ts.forEachChild(node, child => discoverTemplatesInExpression(ctx, child));
|
|
88
|
+
}
|
|
89
|
+
|
|
46
90
|
function generateAttributeBinding(element: string, name: string, expr: string, staticValue: string): string {
|
|
47
91
|
if (name.startsWith('on') && name.length > 2) {
|
|
48
92
|
let event = name.slice(2).toLowerCase(),
|
|
49
93
|
key = name.toLowerCase();
|
|
50
94
|
|
|
51
95
|
if (LIFECYCLE_EVENTS.has(key)) {
|
|
52
|
-
return `${
|
|
96
|
+
return `${NAMESPACE}.${key}(${element}, ${expr});`;
|
|
53
97
|
}
|
|
54
98
|
|
|
55
99
|
if (DIRECT_ATTACH_EVENTS.has(key)) {
|
|
56
|
-
return `${
|
|
100
|
+
return `${NAMESPACE}.on(${element}, '${event}', ${expr});`;
|
|
57
101
|
}
|
|
58
102
|
|
|
59
|
-
return `${
|
|
103
|
+
return `${NAMESPACE}.delegate(${element}, '${event}', ${expr});`;
|
|
60
104
|
}
|
|
61
105
|
|
|
62
106
|
if (name === 'class') {
|
|
63
|
-
return `${
|
|
107
|
+
return `${NAMESPACE}.setClass(${element}, '${staticValue}', ${expr});`;
|
|
64
108
|
}
|
|
65
109
|
|
|
66
110
|
if (name === 'style') {
|
|
67
|
-
return `${
|
|
111
|
+
return `${NAMESPACE}.setStyle(${element}, '${staticValue}', ${expr});`;
|
|
68
112
|
}
|
|
69
113
|
|
|
70
|
-
return `${
|
|
114
|
+
return `${NAMESPACE}.setProperty(${element}, '${name}', ${expr});`;
|
|
71
115
|
}
|
|
72
116
|
|
|
73
117
|
function generateNestedTemplateCode(ctx: CodegenContext, node: ts.TaggedTemplateExpression): string {
|
|
@@ -89,7 +133,7 @@ function generateNestedTemplateCode(ctx: CodegenContext, node: ts.TaggedTemplate
|
|
|
89
133
|
|
|
90
134
|
function generateNodeBinding(ctx: CodegenContext, anchor: string, exprText: string, exprNode: ts.Expression | undefined): string {
|
|
91
135
|
if (!exprNode) {
|
|
92
|
-
return `${
|
|
136
|
+
return `${NAMESPACE}.slot(${anchor}, ${exprText});`;
|
|
93
137
|
}
|
|
94
138
|
|
|
95
139
|
if (isNestedHtmlTemplate(exprNode)) {
|
|
@@ -97,20 +141,20 @@ function generateNodeBinding(ctx: CodegenContext, anchor: string, exprText: stri
|
|
|
97
141
|
}
|
|
98
142
|
|
|
99
143
|
switch (analyze(exprNode, ctx.checker)) {
|
|
100
|
-
case
|
|
101
|
-
return `${anchor}.parentNode!.insertBefore(new ${
|
|
144
|
+
case TYPES.ArraySlot:
|
|
145
|
+
return `${anchor}.parentNode!.insertBefore(new ${NAMESPACE}.ArraySlot(${exprText}).fragment, ${anchor});`;
|
|
102
146
|
|
|
103
|
-
case
|
|
147
|
+
case TYPES.DocumentFragment:
|
|
104
148
|
return `${anchor}.parentNode!.insertBefore(${exprText}, ${anchor});`;
|
|
105
149
|
|
|
106
|
-
case
|
|
107
|
-
return `new ${
|
|
150
|
+
case TYPES.Effect:
|
|
151
|
+
return `new ${NAMESPACE}.EffectSlot(${anchor}, ${exprText});`;
|
|
108
152
|
|
|
109
|
-
case
|
|
153
|
+
case TYPES.Static:
|
|
110
154
|
return `${anchor}.textContent = ${exprText};`;
|
|
111
155
|
|
|
112
156
|
default:
|
|
113
|
-
return `${
|
|
157
|
+
return `${NAMESPACE}.slot(${anchor}, ${exprText});`;
|
|
114
158
|
}
|
|
115
159
|
}
|
|
116
160
|
|
|
@@ -166,17 +210,15 @@ function generateTemplateCode(
|
|
|
166
210
|
value = `${ancestor}.${segments.join('!.')}`;
|
|
167
211
|
|
|
168
212
|
if (ancestor === root && segments[0] === 'firstChild') {
|
|
169
|
-
value = value.replace(`${ancestor}.firstChild!`, `(${
|
|
213
|
+
value = value.replace(`${ancestor}.firstChild!`, `(${root}.firstChild! as ${NAMESPACE}.Element)`);
|
|
170
214
|
}
|
|
171
215
|
|
|
172
|
-
declarations.push(`${name} = ${value} as ${
|
|
216
|
+
declarations.push(`${name} = ${value} as ${NAMESPACE}.Element`);
|
|
173
217
|
nodes.set(key, name);
|
|
174
218
|
}
|
|
175
219
|
|
|
176
|
-
code.push(
|
|
177
|
-
|
|
178
|
-
`let ${declarations.join(',\n')};`
|
|
179
|
-
);
|
|
220
|
+
code.push(isArrowBody ? '{' : `(() => {`);
|
|
221
|
+
code.push(`let ${declarations.join(',\n')};`);
|
|
180
222
|
|
|
181
223
|
for (let i = 0, n = slots.length; i < n; i++) {
|
|
182
224
|
let element = slots[i].path.length === 0
|
|
@@ -184,15 +226,15 @@ function generateTemplateCode(
|
|
|
184
226
|
: (nodes.get(slots[i].path.join('.')) || root),
|
|
185
227
|
slot = slots[i];
|
|
186
228
|
|
|
187
|
-
if (slot.type ===
|
|
229
|
+
if (slot.type === TYPES.Attribute) {
|
|
188
230
|
let names = slot.attributes.names;
|
|
189
231
|
|
|
190
232
|
for (let j = 0, m = names.length; j < m; j++) {
|
|
191
233
|
let name = names[j];
|
|
192
234
|
|
|
193
|
-
if (name ===
|
|
235
|
+
if (name === TYPES.Attributes) {
|
|
194
236
|
code.push(
|
|
195
|
-
`${
|
|
237
|
+
`${NAMESPACE}.setProperties(${element}, ${exprTexts[index] || 'undefined'});`
|
|
196
238
|
);
|
|
197
239
|
index++;
|
|
198
240
|
}
|
|
@@ -233,21 +275,21 @@ function getOrCreateTemplateId(ctx: CodegenContext, html: string): string {
|
|
|
233
275
|
return id;
|
|
234
276
|
}
|
|
235
277
|
|
|
236
|
-
function isNestedHtmlTemplate(expr: ts.Expression): expr is ts.TaggedTemplateExpression {
|
|
237
|
-
return ts.isTaggedTemplateExpression(expr) && ts.isIdentifier(expr.tag) && expr.tag.text === COMPILER_ENTRYPOINT;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
278
|
function isArrowExpressionBody(node: ts.Node): boolean {
|
|
241
279
|
return ts.isArrowFunction(node.parent) && (node.parent as ts.ArrowFunction).body === node;
|
|
242
280
|
}
|
|
243
281
|
|
|
282
|
+
function isNestedHtmlTemplate(expr: ts.Expression): expr is ts.TaggedTemplateExpression {
|
|
283
|
+
return ts.isTaggedTemplateExpression(expr) && ts.isIdentifier(expr.tag) && expr.tag.text === ENTRYPOINT;
|
|
284
|
+
}
|
|
285
|
+
|
|
244
286
|
function isReactiveCall(expr: ts.Expression): expr is ts.CallExpression {
|
|
245
287
|
return (
|
|
246
288
|
ts.isCallExpression(expr) &&
|
|
247
289
|
ts.isPropertyAccessExpression(expr.expression) &&
|
|
248
290
|
ts.isIdentifier(expr.expression.expression) &&
|
|
249
|
-
expr.expression.expression.text ===
|
|
250
|
-
expr.expression.name.text ===
|
|
291
|
+
expr.expression.expression.text === ENTRYPOINT &&
|
|
292
|
+
expr.expression.name.text === ENTRYPOINT_REACTIVITY
|
|
251
293
|
);
|
|
252
294
|
}
|
|
253
295
|
|
|
@@ -256,138 +298,29 @@ function rewriteExpression(ctx: CodegenContext, expr: ts.Expression): string {
|
|
|
256
298
|
return generateNestedTemplateCode(ctx, expr);
|
|
257
299
|
}
|
|
258
300
|
|
|
259
|
-
// Returns just args "array, callback" - for direct slot usage where generateNodeBinding wraps it
|
|
260
301
|
if (isReactiveCall(expr)) {
|
|
261
|
-
return
|
|
262
|
-
${printer.printNode(ts.EmitHint.Expression, expr.arguments[0], ctx.sourceFile)},
|
|
263
|
-
${rewriteExpression(ctx, expr.arguments[1] as ts.Expression)}
|
|
264
|
-
`;
|
|
302
|
+
return `${rewriteExpression(ctx, expr.arguments[0] as ts.Expression)}, ${rewriteExpression(ctx, expr.arguments[1] as ts.Expression)}`;
|
|
265
303
|
}
|
|
266
304
|
|
|
267
|
-
if (!ast.
|
|
305
|
+
if (!ast.test(expr, n => isNestedHtmlTemplate(n as ts.Expression) || isReactiveCall(n as ts.Expression))) {
|
|
268
306
|
return printer.printNode(ts.EmitHint.Expression, expr, ctx.sourceFile);
|
|
269
307
|
}
|
|
270
308
|
|
|
271
|
-
|
|
272
|
-
}
|
|
309
|
+
let exprStart = expr.getStart(ctx.sourceFile),
|
|
310
|
+
replacements: { end: number; start: number; text: string }[] = [],
|
|
311
|
+
text = expr.getText(ctx.sourceFile);
|
|
273
312
|
|
|
274
|
-
|
|
275
|
-
// Intercept special nodes
|
|
276
|
-
if (isNestedHtmlTemplate(node as ts.Expression)) {
|
|
277
|
-
return generateNestedTemplateCode(ctx, node as ts.TaggedTemplateExpression);
|
|
278
|
-
}
|
|
313
|
+
ts.forEachChild(expr, child => collectNestedReplacements(ctx, child, replacements));
|
|
279
314
|
|
|
280
|
-
|
|
281
|
-
let call = node as ts.CallExpression;
|
|
282
|
-
|
|
283
|
-
return `new ${COMPILER_NAMESPACE}.ArraySlot(${printer.printNode(ts.EmitHint.Expression, call.arguments[0], ctx.sourceFile)}, ${rewriteExpression(ctx, call.arguments[1] as ts.Expression)})`;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// No nested constructs - use printer
|
|
287
|
-
if (!ast.hasMatch(node, n => isNestedHtmlTemplate(n as ts.Expression) || isReactiveCall(n as ts.Expression))) {
|
|
288
|
-
return printer.printNode(ts.EmitHint.Expression, node as ts.Expression, ctx.sourceFile);
|
|
289
|
-
}
|
|
315
|
+
replacements.sort((a, b) => b.start - a.start);
|
|
290
316
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
return `${walkExpression(ctx, node.condition)} ? ${walkExpression(ctx, node.whenTrue)} : ${walkExpression(ctx, node.whenFalse)}`;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
if (ts.isBinaryExpression(node)) {
|
|
297
|
-
return `${walkExpression(ctx, node.left)} ${node.operatorToken.getText(ctx.sourceFile)} ${walkExpression(ctx, node.right)}`;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
if (ts.isCallExpression(node)) {
|
|
301
|
-
let args: string[] = [];
|
|
302
|
-
|
|
303
|
-
for (let i = 0, n = node.arguments.length; i < n; i++) {
|
|
304
|
-
args.push(walkExpression(ctx, node.arguments[i]));
|
|
305
|
-
}
|
|
317
|
+
for (let i = 0, n = replacements.length; i < n; i++) {
|
|
318
|
+
let r = replacements[i];
|
|
306
319
|
|
|
307
|
-
|
|
320
|
+
text = text.slice(0, r.start - exprStart) + r.text + text.slice(r.end - exprStart);
|
|
308
321
|
}
|
|
309
322
|
|
|
310
|
-
|
|
311
|
-
return `${walkExpression(ctx, node.expression)}.${node.name.text}`;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
if (ts.isElementAccessExpression(node)) {
|
|
315
|
-
return `${walkExpression(ctx, node.expression)}[${walkExpression(ctx, node.argumentExpression)}]`;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
if (ts.isParenthesizedExpression(node)) {
|
|
319
|
-
return `(${walkExpression(ctx, node.expression)})`;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
if (ts.isArrowFunction(node)) {
|
|
323
|
-
return `(${node.parameters.map(p => p.getText(ctx.sourceFile)).join(', ')}) => ${
|
|
324
|
-
ts.isBlock(node.body) ? node.body.getText(ctx.sourceFile) : walkExpression(ctx, node.body)
|
|
325
|
-
}`;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
if (ts.isArrayLiteralExpression(node)) {
|
|
329
|
-
let elements: string[] = [];
|
|
330
|
-
|
|
331
|
-
for (let i = 0, n = node.elements.length; i < n; i++) {
|
|
332
|
-
elements.push( walkExpression(ctx, node.elements[i]) );
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
return `[${elements.join(', ')}]`;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
if (ts.isObjectLiteralExpression(node)) {
|
|
339
|
-
let properties: string[] = [];
|
|
340
|
-
|
|
341
|
-
for (let i = 0, n = node.properties.length; i < n; i++) {
|
|
342
|
-
let prop = node.properties[i];
|
|
343
|
-
|
|
344
|
-
if (ts.isPropertyAssignment(prop)) {
|
|
345
|
-
properties.push(`${prop.name.getText(ctx.sourceFile)}: ${walkExpression(ctx, prop.initializer)}`);
|
|
346
|
-
}
|
|
347
|
-
else if (ts.isShorthandPropertyAssignment(prop)) {
|
|
348
|
-
properties.push(prop.name.text);
|
|
349
|
-
}
|
|
350
|
-
else if (ts.isSpreadAssignment(prop)) {
|
|
351
|
-
properties.push(`...${walkExpression(ctx, prop.expression)}`);
|
|
352
|
-
}
|
|
353
|
-
else {
|
|
354
|
-
properties.push(prop.getText(ctx.sourceFile));
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
return `{ ${properties.join(', ')} }`;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
if (ts.isPrefixUnaryExpression(node)) {
|
|
362
|
-
return `${ts.tokenToString(node.operator)}${walkExpression(ctx, node.operand)}`;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
if (ts.isPostfixUnaryExpression(node)) {
|
|
366
|
-
return `${walkExpression(ctx, node.operand)}${ts.tokenToString(node.operator)}`;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
if (ts.isTemplateExpression(node)) {
|
|
370
|
-
let parts = [node.head.text];
|
|
371
|
-
|
|
372
|
-
for (let i = 0, n = node.templateSpans.length; i < n; i++) {
|
|
373
|
-
let span = node.templateSpans[i];
|
|
374
|
-
|
|
375
|
-
parts.push('${' + walkExpression(ctx, span.expression) + '}' + span.literal.text);
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
return '`' + parts.join('') + '`';
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
if (ts.isAsExpression(node) || ts.isTypeAssertionExpression(node)) {
|
|
382
|
-
return walkExpression(ctx, node.expression);
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
if (ts.isNonNullExpression(node)) {
|
|
386
|
-
return `${walkExpression(ctx, node.expression)}!`;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
// Fallback - use printer
|
|
390
|
-
return printer.printNode(ts.EmitHint.Expression, node as ts.Expression, ctx.sourceFile);
|
|
323
|
+
return text;
|
|
391
324
|
}
|
|
392
325
|
|
|
393
326
|
|
|
@@ -412,9 +345,9 @@ const generateCode = (templates: TemplateInfo[], sourceFile: ts.SourceFile, chec
|
|
|
412
345
|
}
|
|
413
346
|
}
|
|
414
347
|
|
|
415
|
-
let
|
|
348
|
+
let root = templates.filter(t => !ast.inRange(ranges, t.node.getStart(sourceFile), t.node.end));
|
|
416
349
|
|
|
417
|
-
if (
|
|
350
|
+
if (root.length === 0) {
|
|
418
351
|
return result;
|
|
419
352
|
}
|
|
420
353
|
|
|
@@ -424,46 +357,47 @@ const generateCode = (templates: TemplateInfo[], sourceFile: ts.SourceFile, chec
|
|
|
424
357
|
templates: result.templates
|
|
425
358
|
};
|
|
426
359
|
|
|
427
|
-
for (let i = 0, n =
|
|
428
|
-
let
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
generate: (sf) => {
|
|
432
|
-
let exprTexts: string[] = [],
|
|
433
|
-
localCtx: CodegenContext = {
|
|
434
|
-
checker,
|
|
435
|
-
sourceFile: sf,
|
|
436
|
-
templates: ctx.templates
|
|
437
|
-
},
|
|
438
|
-
parsed = parser.parse(template.literals) as ParseResult;
|
|
439
|
-
|
|
440
|
-
for (let j = 0, m = template.expressions.length; j < m; j++) {
|
|
441
|
-
exprTexts.push(rewriteExpression(localCtx, template.expressions[j]));
|
|
442
|
-
}
|
|
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];
|
|
443
364
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
(template.node.parent as ts.ArrowFunction).parameters.length === 0 &&
|
|
448
|
-
(!parsed.slots || parsed.slots.length === 0)
|
|
449
|
-
) {
|
|
450
|
-
return getOrCreateTemplateId(localCtx, parsed.html);
|
|
451
|
-
}
|
|
365
|
+
for (let j = 0, m = template.expressions.length; j < m; j++) {
|
|
366
|
+
exprTexts.push(rewriteExpression(ctx, template.expressions[j]));
|
|
367
|
+
}
|
|
452
368
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
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);
|
|
383
|
+
|
|
384
|
+
result.replacements.push({
|
|
385
|
+
generate: () => code,
|
|
386
|
+
node: template.node
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
for (let i = 0, n = templates.length; i < n; i++) {
|
|
392
|
+
getOrCreateTemplateId(ctx, parser.parse(templates[i].literals).html);
|
|
393
|
+
|
|
394
|
+
for (let j = 0, m = templates[i].expressions.length; j < m; j++) {
|
|
395
|
+
discoverTemplatesInExpression(ctx, templates[i].expressions[j]);
|
|
396
|
+
}
|
|
463
397
|
}
|
|
464
398
|
|
|
465
399
|
for (let [html, id] of ctx.templates) {
|
|
466
|
-
result.prepend.push(`const ${id} = ${
|
|
400
|
+
result.prepend.push(`const ${id} = ${NAMESPACE}.template(\`${html}\`);`);
|
|
467
401
|
}
|
|
468
402
|
|
|
469
403
|
return result;
|