@vesk/compiler 0.0.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 +23 -0
- package/dist/acorn-ts-plugin/index.d.ts +482 -0
- package/dist/acorn-ts-plugin/index.d.ts.map +1 -0
- package/dist/acorn-ts-plugin/index.js +5028 -0
- package/dist/actions.d.ts +22 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +167 -0
- package/dist/api-routes.d.ts +30 -0
- package/dist/api-routes.d.ts.map +1 -0
- package/dist/api-routes.js +350 -0
- package/dist/client-codegen.d.ts +19 -0
- package/dist/client-codegen.d.ts.map +1 -0
- package/dist/client-codegen.js +1523 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +106 -0
- package/dist/errors.d.ts +33 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +210 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/ir-generator.d.ts +10 -0
- package/dist/ir-generator.d.ts.map +1 -0
- package/dist/ir-generator.js +1062 -0
- package/dist/ir.d.ts +160 -0
- package/dist/ir.d.ts.map +1 -0
- package/dist/ir.js +219 -0
- package/dist/middleware.d.ts +15 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +183 -0
- package/dist/package.json +15 -0
- package/dist/parser.d.ts +38 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +242 -0
- package/dist/router.d.ts +31 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +451 -0
- package/dist/scan.d.ts +106 -0
- package/dist/scan.d.ts.map +1 -0
- package/dist/scan.js +438 -0
- package/dist/server-codegen.d.ts +5 -0
- package/dist/server-codegen.d.ts.map +1 -0
- package/dist/server-codegen.js +4 -0
- package/dist/server-cookies.d.ts +2 -0
- package/dist/server-cookies.d.ts.map +1 -0
- package/dist/server-cookies.js +15 -0
- package/dist/server-head.d.ts +10 -0
- package/dist/server-head.d.ts.map +1 -0
- package/dist/server-head.js +289 -0
- package/dist/server-jsgen.d.ts +6 -0
- package/dist/server-jsgen.d.ts.map +1 -0
- package/dist/server-jsgen.js +446 -0
- package/dist/server-render.d.ts +16 -0
- package/dist/server-render.d.ts.map +1 -0
- package/dist/server-render.js +397 -0
- package/dist/server-utils.d.ts +93 -0
- package/dist/server-utils.d.ts.map +1 -0
- package/dist/server-utils.js +747 -0
- package/dist/ssr-store.d.ts +4 -0
- package/dist/ssr-store.d.ts.map +1 -0
- package/dist/ssr-store.js +29 -0
- package/dist/strip-ts.d.ts +25 -0
- package/dist/strip-ts.d.ts.map +1 -0
- package/dist/strip-ts.js +171 -0
- package/dist/tokens.d.ts +50 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +334 -0
- package/dist/typecheck.d.ts +19 -0
- package/dist/typecheck.d.ts.map +1 -0
- package/dist/typecheck.js +365 -0
- package/dist/types.d.ts +147 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +13 -0
- package/dist/vesk-plugin.d.ts +53 -0
- package/dist/vesk-plugin.d.ts.map +1 -0
- package/dist/vesk-plugin.js +413 -0
- package/dist/vsk-imports.d.ts +30 -0
- package/dist/vsk-imports.d.ts.map +1 -0
- package/dist/vsk-imports.js +141 -0
- package/dist/vsk-tsx.d.ts +3 -0
- package/dist/vsk-tsx.d.ts.map +1 -0
- package/dist/vsk-tsx.js +604 -0
- package/package.json +52 -0
|
@@ -0,0 +1,1523 @@
|
|
|
1
|
+
import { walk } from 'zimmerframe';
|
|
2
|
+
import { print } from 'esrap';
|
|
3
|
+
import ts from 'esrap/languages/ts';
|
|
4
|
+
import { StaticNode, TextNode, DynamicBinding, OpaqueDynamicRegion, MapRegion, WhileLoop, SwitchBlock, TryCatch, ForLoop, TrackDecl, RuntimeStatement, ComponentRef, ComponentCall, ServerBlock, ClientBlock, HeadBlock, SlotNode, } from '@vesk/compiler/src/ir';
|
|
5
|
+
import { parse } from '@vesk/compiler/src/parser';
|
|
6
|
+
import { generateIR } from '@vesk/compiler/src/ir-generator';
|
|
7
|
+
import { transformTopLevelForActions } from '@vesk/compiler/src/actions';
|
|
8
|
+
import { extractRuntimeNames } from '@vesk/compiler/src/server-utils';
|
|
9
|
+
import { stripTrackGeneric } from '@vesk/compiler/src/scan';
|
|
10
|
+
import { stripTsTypes, hasTsSyntax } from '@vesk/compiler/src/strip-ts';
|
|
11
|
+
function memberExpr(object, property) {
|
|
12
|
+
return {
|
|
13
|
+
type: 'MemberExpression',
|
|
14
|
+
object: { type: 'Identifier', name: object },
|
|
15
|
+
property: { type: 'Identifier', name: property },
|
|
16
|
+
computed: false,
|
|
17
|
+
optional: false,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function callExpr(callee, args = []) {
|
|
21
|
+
return { type: 'CallExpression', callee, arguments: args, optional: false };
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* When `expr` is exactly `get(<word>)`, returns the word; otherwise `null`.
|
|
25
|
+
* Used to substitute `get(tracked)` back to the raw tracked cell name.
|
|
26
|
+
*/
|
|
27
|
+
function simpleGetName(expr) {
|
|
28
|
+
if (!expr.startsWith('get(') || !expr.endsWith(')'))
|
|
29
|
+
return null;
|
|
30
|
+
const inner = expr.slice(4, -1);
|
|
31
|
+
if (inner.length === 0)
|
|
32
|
+
return null;
|
|
33
|
+
for (let i = 0; i < inner.length; i++) {
|
|
34
|
+
const code = inner.charCodeAt(i);
|
|
35
|
+
const ok = (code >= 48 && code <= 57) || (code >= 65 && code <= 90) || (code >= 97 && code <= 122) || code === 95;
|
|
36
|
+
if (!ok)
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
return inner;
|
|
40
|
+
}
|
|
41
|
+
export function semicolonizeStatement(code) {
|
|
42
|
+
const trimmed = code.trimEnd();
|
|
43
|
+
if (!trimmed || trimmed.endsWith(';') || trimmed.endsWith('}'))
|
|
44
|
+
return code;
|
|
45
|
+
return code + ';';
|
|
46
|
+
}
|
|
47
|
+
export function transformTracked(irNode, tracked) {
|
|
48
|
+
const ast = irNode.ast;
|
|
49
|
+
if (!ast)
|
|
50
|
+
return irNode.raw;
|
|
51
|
+
if (tracked.size === 0) {
|
|
52
|
+
if (!hasTsSyntax(ast))
|
|
53
|
+
return irNode.raw;
|
|
54
|
+
return print(stripTsTypes(ast), ts()).code;
|
|
55
|
+
}
|
|
56
|
+
const stripped = stripTsTypes(ast);
|
|
57
|
+
const transformed = walk(stripped, tracked, {
|
|
58
|
+
AssignmentExpression(node, context) {
|
|
59
|
+
if (node.left.type === 'Identifier') {
|
|
60
|
+
const info = context.state.get(node.left.name);
|
|
61
|
+
if (info) {
|
|
62
|
+
const right = context.visit(node.right);
|
|
63
|
+
const setCall = { type: 'Identifier', name: 'set' };
|
|
64
|
+
if (node.operator === '=') {
|
|
65
|
+
return callExpr(setCall, [
|
|
66
|
+
{ type: 'Identifier', name: info.cellName },
|
|
67
|
+
right,
|
|
68
|
+
]);
|
|
69
|
+
}
|
|
70
|
+
const op = node.operator.slice(0, -1);
|
|
71
|
+
const getCall = { type: 'Identifier', name: 'get' };
|
|
72
|
+
return callExpr(setCall, [
|
|
73
|
+
{ type: 'Identifier', name: info.cellName },
|
|
74
|
+
{
|
|
75
|
+
type: 'BinaryExpression',
|
|
76
|
+
operator: op,
|
|
77
|
+
left: callExpr(getCall, [
|
|
78
|
+
{ type: 'Identifier', name: info.cellName },
|
|
79
|
+
]),
|
|
80
|
+
right,
|
|
81
|
+
},
|
|
82
|
+
]);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return context.next();
|
|
86
|
+
},
|
|
87
|
+
UpdateExpression(node, context) {
|
|
88
|
+
if (node.argument.type === 'Identifier') {
|
|
89
|
+
const info = context.state.get(node.argument.name);
|
|
90
|
+
if (info) {
|
|
91
|
+
const delta = node.operator === '++' ? 1 : -1;
|
|
92
|
+
const setCall = { type: 'Identifier', name: 'set' };
|
|
93
|
+
const getCall = { type: 'Identifier', name: 'get' };
|
|
94
|
+
return callExpr(setCall, [
|
|
95
|
+
{ type: 'Identifier', name: info.cellName },
|
|
96
|
+
{
|
|
97
|
+
type: 'BinaryExpression',
|
|
98
|
+
operator: '+',
|
|
99
|
+
left: callExpr(getCall, [
|
|
100
|
+
{ type: 'Identifier', name: info.cellName },
|
|
101
|
+
]),
|
|
102
|
+
right: { type: 'Literal', value: delta },
|
|
103
|
+
},
|
|
104
|
+
]);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return context.next();
|
|
108
|
+
},
|
|
109
|
+
Identifier(node, context) {
|
|
110
|
+
const parent = context.path.at(-1);
|
|
111
|
+
if (parent) {
|
|
112
|
+
if (parent.type === 'AssignmentExpression' &&
|
|
113
|
+
parent.left === node)
|
|
114
|
+
return context.next();
|
|
115
|
+
if (parent.type === 'UpdateExpression' &&
|
|
116
|
+
parent.argument === node)
|
|
117
|
+
return context.next();
|
|
118
|
+
if (parent.type === 'Property' &&
|
|
119
|
+
parent.value === node &&
|
|
120
|
+
parent.key &&
|
|
121
|
+
parent.key.type === 'Identifier' &&
|
|
122
|
+
parent.key.name === 'into')
|
|
123
|
+
return context.next();
|
|
124
|
+
if (parent.type === 'MemberExpression' &&
|
|
125
|
+
!parent.computed &&
|
|
126
|
+
parent.object === node &&
|
|
127
|
+
parent.property &&
|
|
128
|
+
parent.property.type === 'Identifier' &&
|
|
129
|
+
parent.property.name === 'set')
|
|
130
|
+
return context.next();
|
|
131
|
+
}
|
|
132
|
+
const info = context.state.get(node.name);
|
|
133
|
+
if (info && info.kind === 'virtual') {
|
|
134
|
+
const getCall = { type: 'Identifier', name: 'get' };
|
|
135
|
+
return callExpr(getCall, [
|
|
136
|
+
{ type: 'Identifier', name: info.cellName },
|
|
137
|
+
]);
|
|
138
|
+
}
|
|
139
|
+
return context.next();
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
return print(transformed, ts()).code;
|
|
143
|
+
}
|
|
144
|
+
export function collectTrackedNames(body) {
|
|
145
|
+
const names = new Map();
|
|
146
|
+
for (const node of body) {
|
|
147
|
+
if (node instanceof TrackDecl) {
|
|
148
|
+
const cellName = node.rawName || node.name;
|
|
149
|
+
names.set(node.name, { cellName, kind: 'virtual' });
|
|
150
|
+
if (node.rawName)
|
|
151
|
+
names.set(node.rawName, { cellName, kind: 'cell' });
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return names;
|
|
155
|
+
}
|
|
156
|
+
const NON_BUBBLING_EVENTS = new Set([
|
|
157
|
+
'focus', 'blur',
|
|
158
|
+
'mouseenter', 'mouseleave',
|
|
159
|
+
'scroll', 'resize',
|
|
160
|
+
'load', 'error', 'unload', 'abort',
|
|
161
|
+
'play', 'pause', 'ended', 'waiting',
|
|
162
|
+
'canplay', 'canplaythrough', 'durationchange', 'emptied',
|
|
163
|
+
'loadeddata', 'loadedmetadata', 'loadstart',
|
|
164
|
+
'playing', 'progress', 'ratechange', 'seeked', 'seeking',
|
|
165
|
+
'stalled', 'suspend', 'timeupdate', 'volumechange',
|
|
166
|
+
'toggle',
|
|
167
|
+
]);
|
|
168
|
+
function indent(code, level = 1) {
|
|
169
|
+
const pad = '\t'.repeat(level);
|
|
170
|
+
return code.split('\n').map((l) => (l ? pad + l : '')).join('\n');
|
|
171
|
+
}
|
|
172
|
+
class Ctx {
|
|
173
|
+
lines = [];
|
|
174
|
+
effects = [];
|
|
175
|
+
c = 0;
|
|
176
|
+
importedNames = new Set();
|
|
177
|
+
delegatedEvents = new Set();
|
|
178
|
+
directEvents = new Set();
|
|
179
|
+
hydrate = false;
|
|
180
|
+
inTryBody = false;
|
|
181
|
+
claimStatic = false;
|
|
182
|
+
walker = '__hydrate';
|
|
183
|
+
asyncComps = new Set();
|
|
184
|
+
isAsyncScope = false;
|
|
185
|
+
push(...args) {
|
|
186
|
+
for (const a of args)
|
|
187
|
+
if (a)
|
|
188
|
+
this.lines.push(a);
|
|
189
|
+
}
|
|
190
|
+
n() { return `$n${this.c++}`; }
|
|
191
|
+
getCode() { return this.lines.join('\n'); }
|
|
192
|
+
flushEffects() {
|
|
193
|
+
if (this.effects.length === 0)
|
|
194
|
+
return '';
|
|
195
|
+
return '\n' + this.effects.join('\n');
|
|
196
|
+
}
|
|
197
|
+
emitDelegates() {
|
|
198
|
+
if (this.delegatedEvents.size === 0 && this.directEvents.size === 0)
|
|
199
|
+
return '';
|
|
200
|
+
const lines = [];
|
|
201
|
+
for (const type of this.delegatedEvents) {
|
|
202
|
+
const guard = `__vesk_dlg_${type}`;
|
|
203
|
+
const prop = `__evh_${type}`;
|
|
204
|
+
lines.push(`if (!document.${guard}) {`);
|
|
205
|
+
lines.push(`\tdocument.${guard} = true;`);
|
|
206
|
+
lines.push(`\tdocument.addEventListener(${JSON.stringify(type)}, (e) => {`);
|
|
207
|
+
lines.push(`\t\tvar el = e.target.closest('[data-vsk-ev]');`);
|
|
208
|
+
lines.push(`\t\tif (el && el.${prop}) el.${prop}(e);`);
|
|
209
|
+
lines.push(`\t});`);
|
|
210
|
+
lines.push(`}`);
|
|
211
|
+
}
|
|
212
|
+
return '\n' + lines.join('\n');
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
function emitNode(ctx, node, tracked, effectsVar, parentVar, compPrefix = '__components') {
|
|
216
|
+
if (node instanceof StaticNode)
|
|
217
|
+
return emitStatic(ctx, node, tracked, effectsVar);
|
|
218
|
+
if (node instanceof TextNode) {
|
|
219
|
+
if (!node.value)
|
|
220
|
+
return null;
|
|
221
|
+
const v = ctx.n();
|
|
222
|
+
ctx.push(`const ${v} = document.createTextNode(${JSON.stringify(node.value)});`);
|
|
223
|
+
return v;
|
|
224
|
+
}
|
|
225
|
+
if (node instanceof DynamicBinding)
|
|
226
|
+
return emitDynamicBinding(ctx, node, tracked, effectsVar);
|
|
227
|
+
if (node instanceof TrackDecl) {
|
|
228
|
+
const cellName = node.rawName || node.name;
|
|
229
|
+
const init = stripTrackGeneric(node.init);
|
|
230
|
+
ctx.push(`const ${cellName} = ${init};`);
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
if (node instanceof ComponentRef)
|
|
234
|
+
return null;
|
|
235
|
+
if (node instanceof ComponentCall)
|
|
236
|
+
return emitComponentCall(ctx, node, tracked, effectsVar, parentVar, compPrefix);
|
|
237
|
+
if (node instanceof OpaqueDynamicRegion)
|
|
238
|
+
return emitOpaque(ctx, node, tracked, parentVar);
|
|
239
|
+
if (node instanceof MapRegion)
|
|
240
|
+
return emitMap(ctx, node, tracked, parentVar);
|
|
241
|
+
if (node instanceof ServerBlock)
|
|
242
|
+
return null;
|
|
243
|
+
if (node instanceof ClientBlock) {
|
|
244
|
+
const savedHydrate = ctx.hydrate;
|
|
245
|
+
ctx.hydrate = false;
|
|
246
|
+
let lastVar = null;
|
|
247
|
+
for (const n of node.children) {
|
|
248
|
+
lastVar = emitNode(ctx, n, tracked, null, parentVar);
|
|
249
|
+
}
|
|
250
|
+
ctx.hydrate = savedHydrate;
|
|
251
|
+
return lastVar;
|
|
252
|
+
}
|
|
253
|
+
if (node instanceof HeadBlock) {
|
|
254
|
+
emitClientHead(ctx, node, tracked);
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
if (node instanceof RuntimeStatement) {
|
|
258
|
+
ctx.push(semicolonizeStatement(transformTracked(node, tracked)));
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
if (node instanceof SlotNode) {
|
|
262
|
+
if (!parentVar)
|
|
263
|
+
return null;
|
|
264
|
+
if (ctx.hydrate) {
|
|
265
|
+
ctx.push(`if (props.children !== undefined && props.children !== null) {`);
|
|
266
|
+
ctx.push(` if (typeof props.children === 'function') {`);
|
|
267
|
+
ctx.push(` const __child = props.children(${ctx.walker}.subWalker(${parentVar}));`);
|
|
268
|
+
ctx.push(` if (__child && typeof __child.then === 'function') __pendingChild = __child.then(() => $root);`);
|
|
269
|
+
ctx.push(` } else {`);
|
|
270
|
+
ctx.push(` ${parentVar}.appendChild(props.children);`);
|
|
271
|
+
ctx.push(` }`);
|
|
272
|
+
ctx.push(`}`);
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
ctx.push(`if (props.children !== undefined && props.children !== null) ${parentVar}.appendChild(props.children);`);
|
|
276
|
+
}
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
if (node instanceof TryCatch)
|
|
280
|
+
return emitTryCatch(ctx, node, tracked, effectsVar, parentVar);
|
|
281
|
+
if (node instanceof WhileLoop)
|
|
282
|
+
return emitWhileLoop(ctx, node, tracked, parentVar);
|
|
283
|
+
if (node instanceof ForLoop)
|
|
284
|
+
return emitForLoop(ctx, node, tracked, parentVar);
|
|
285
|
+
if (node instanceof SwitchBlock)
|
|
286
|
+
return emitSwitchBlock(ctx, node, tracked, parentVar);
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
const PROPERTY_ATTRS = {
|
|
290
|
+
input: new Set(['value', 'checked', 'indeterminate']),
|
|
291
|
+
textarea: new Set(['value']),
|
|
292
|
+
select: new Set(['value']),
|
|
293
|
+
option: new Set(['selected']),
|
|
294
|
+
progress: new Set(['value']),
|
|
295
|
+
};
|
|
296
|
+
function emitStatic(ctx, node, tracked, effectsVar) {
|
|
297
|
+
const el = ctx.n();
|
|
298
|
+
if (ctx.hydrate) {
|
|
299
|
+
const claim = ctx.claimStatic;
|
|
300
|
+
ctx.claimStatic = false;
|
|
301
|
+
if (!claim && isStaticIR(node.children))
|
|
302
|
+
return null;
|
|
303
|
+
ctx.push(`const ${el} = ${ctx.walker}.nextElement(${JSON.stringify(node.tag)});`);
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
ctx.push(`const ${el} = document.createElement(${JSON.stringify(node.tag)});`);
|
|
307
|
+
}
|
|
308
|
+
const dynAttrs = [];
|
|
309
|
+
const children = [];
|
|
310
|
+
for (const child of node.children) {
|
|
311
|
+
if (child instanceof DynamicBinding && child.kind === 'attribute') {
|
|
312
|
+
dynAttrs.push(child);
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
children.push(child);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
for (const attr of node.attributes) {
|
|
319
|
+
if (attr.name.startsWith('on') && attr.name.length > 2)
|
|
320
|
+
continue;
|
|
321
|
+
if (attr.value === '') {
|
|
322
|
+
ctx.push(`${el}.setAttribute(${JSON.stringify(attr.name)}, '');`);
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
ctx.push(`${el}.setAttribute(${JSON.stringify(attr.name)}, ${JSON.stringify(escapeHtml(attr.value))});`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
for (const child of children) {
|
|
329
|
+
const childVar = emitNode(ctx, child, tracked, effectsVar, el);
|
|
330
|
+
if (childVar)
|
|
331
|
+
ctx.push(`${el}.appendChild(${childVar});`);
|
|
332
|
+
}
|
|
333
|
+
for (const attr of dynAttrs) {
|
|
334
|
+
const target = attr.target || '';
|
|
335
|
+
const isEvent = target.startsWith('on') && target.length > 2;
|
|
336
|
+
if (target === 'ref') {
|
|
337
|
+
const expr = transformTracked(attr.expression, tracked);
|
|
338
|
+
ctx.push(`(${expr})(${el});`);
|
|
339
|
+
}
|
|
340
|
+
else if (isEvent) {
|
|
341
|
+
const eventName = target.slice(2).toLowerCase();
|
|
342
|
+
const handler = transformTracked(attr.expression, tracked);
|
|
343
|
+
if (NON_BUBBLING_EVENTS.has(eventName)) {
|
|
344
|
+
ctx.directEvents.add(eventName);
|
|
345
|
+
ctx.push(`${el}.addEventListener(${JSON.stringify(eventName)}, ${handler});`);
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
const prop = `__evh_${eventName}`;
|
|
349
|
+
ctx.delegatedEvents.add(eventName);
|
|
350
|
+
ctx.push(`${el}.${prop} = ${handler};`);
|
|
351
|
+
}
|
|
352
|
+
ctx.push(`${el}.setAttribute('data-vsk-ev', '');`);
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
const expr = transformTracked(attr.expression, tracked);
|
|
356
|
+
const useProp = PROPERTY_ATTRS[node.tag]?.has(target);
|
|
357
|
+
const eff = useProp
|
|
358
|
+
? `effect(() => { ${el}.${target} = ${expr}; })`
|
|
359
|
+
: `effect(() => { ${el}.setAttribute(${JSON.stringify(target)}, String(${expr})); })`;
|
|
360
|
+
if (effectsVar) {
|
|
361
|
+
ctx.push(`${effectsVar}.push(${eff});`);
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
364
|
+
ctx.effects.push(`${eff};`);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return el;
|
|
369
|
+
}
|
|
370
|
+
function emitClientHead(ctx, node, tracked) {
|
|
371
|
+
for (const child of node.children) {
|
|
372
|
+
if (child instanceof StaticNode) {
|
|
373
|
+
const tag = child.tag;
|
|
374
|
+
const dynAttrs = new Map();
|
|
375
|
+
const staticAttrs = new Map(child.attributes.map((a) => [a.name, a.value]));
|
|
376
|
+
for (const c of child.children) {
|
|
377
|
+
if (c instanceof DynamicBinding && c.kind === 'attribute' && c.target && c.target !== 'ref') {
|
|
378
|
+
dynAttrs.set(c.target, transformTracked(c.expression, tracked));
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
const textParts = [];
|
|
382
|
+
let hasDynamicText = false;
|
|
383
|
+
for (const c of child.children) {
|
|
384
|
+
if (c instanceof TextNode)
|
|
385
|
+
textParts.push(JSON.stringify(c.value));
|
|
386
|
+
else if (c instanceof DynamicBinding && c.kind === 'text') {
|
|
387
|
+
hasDynamicText = true;
|
|
388
|
+
textParts.push(transformTracked(c.expression, tracked));
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
const hasDynamic = dynAttrs.size > 0 || hasDynamicText;
|
|
392
|
+
if (ctx.hydrate && (tag === 'script' || tag === 'link' || tag === 'style') && !hasDynamic) {
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
if (tag === 'title') {
|
|
396
|
+
if (hasDynamicText) {
|
|
397
|
+
ctx.push(`effect(() => { document.title = String(${textParts.join(' + ')}); });`);
|
|
398
|
+
}
|
|
399
|
+
else if (textParts.length > 0) {
|
|
400
|
+
ctx.push(`document.title = ${textParts[0]};`);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
else if (tag === 'meta') {
|
|
404
|
+
const nameVal = staticAttrs.get('name') || dynAttrs.get('name') || staticAttrs.get('property') || dynAttrs.get('property') || 'charset';
|
|
405
|
+
const selector = staticAttrs.has('name') || dynAttrs.has('name')
|
|
406
|
+
? `meta[name="${nameVal}"]`
|
|
407
|
+
: staticAttrs.has('property') || dynAttrs.has('property')
|
|
408
|
+
? `meta[property="${nameVal}"]`
|
|
409
|
+
: `meta[charset]`;
|
|
410
|
+
if (hasDynamic) {
|
|
411
|
+
ctx.push(`effect(() => { let el = document.querySelector(${JSON.stringify(selector)}); if (!el) { el = document.createElement('meta'); document.head.appendChild(el); }`);
|
|
412
|
+
for (const [k, v] of staticAttrs)
|
|
413
|
+
if (!dynAttrs.has(k))
|
|
414
|
+
ctx.push(`el.setAttribute(${JSON.stringify(k)}, ${JSON.stringify(v)});`);
|
|
415
|
+
for (const [k, v] of dynAttrs)
|
|
416
|
+
ctx.push(`el.setAttribute(${JSON.stringify(k)}, String(${v}));`);
|
|
417
|
+
ctx.push(`});`);
|
|
418
|
+
}
|
|
419
|
+
else {
|
|
420
|
+
for (const [k, v] of staticAttrs) {
|
|
421
|
+
ctx.push(`{ let el = document.querySelector(${JSON.stringify(selector)}); if (!el) { el = document.createElement('meta'); document.head.appendChild(el); } el.setAttribute(${JSON.stringify(k)}, ${JSON.stringify(v)}); }`);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
else if (tag === 'script') {
|
|
426
|
+
const srcAttr = child.attributes.find((a) => a.name === 'src');
|
|
427
|
+
const textChild = child.children.find((c) => c instanceof TextNode);
|
|
428
|
+
if (srcAttr) {
|
|
429
|
+
const src = srcAttr.value;
|
|
430
|
+
ctx.push(`{ if (!document.querySelector('script[src=${JSON.stringify(src)}]')) { let el = document.createElement('script');`);
|
|
431
|
+
for (const a of child.attributes)
|
|
432
|
+
ctx.push(`el.setAttribute(${JSON.stringify(a.name)}, ${JSON.stringify(a.value)});`);
|
|
433
|
+
ctx.push(`document.head.appendChild(el); } }`);
|
|
434
|
+
}
|
|
435
|
+
else if (textChild) {
|
|
436
|
+
ctx.push(`{ let el = document.createElement('script');`);
|
|
437
|
+
for (const a of child.attributes)
|
|
438
|
+
ctx.push(`el.setAttribute(${JSON.stringify(a.name)}, ${JSON.stringify(a.value)});`);
|
|
439
|
+
ctx.push(`el.textContent = ${JSON.stringify(textChild.value)};`);
|
|
440
|
+
ctx.push(`document.head.appendChild(el); }`);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
else {
|
|
444
|
+
const textChild = child.children.find((c) => c instanceof TextNode);
|
|
445
|
+
let selector = tag;
|
|
446
|
+
if (tag === 'link' && staticAttrs.has('href'))
|
|
447
|
+
selector = `link[href="${staticAttrs.get('href')}"]`;
|
|
448
|
+
else if (tag === 'base')
|
|
449
|
+
selector = 'base';
|
|
450
|
+
if (hasDynamic) {
|
|
451
|
+
ctx.push(`effect(() => { let el = document.querySelector(${JSON.stringify(selector)}) || (() => { const e = document.createElement(${JSON.stringify(tag)}); document.head.appendChild(e); return e; })();`);
|
|
452
|
+
for (const [k, v] of staticAttrs)
|
|
453
|
+
if (!dynAttrs.has(k))
|
|
454
|
+
ctx.push(`el.setAttribute(${JSON.stringify(k)}, ${JSON.stringify(v)});`);
|
|
455
|
+
for (const [k, v] of dynAttrs)
|
|
456
|
+
ctx.push(`el.setAttribute(${JSON.stringify(k)}, String(${v}));`);
|
|
457
|
+
if (hasDynamicText)
|
|
458
|
+
ctx.push(`el.textContent = String(${textParts.join(' + ')});`);
|
|
459
|
+
else if (textChild)
|
|
460
|
+
ctx.push(`el.textContent = ${JSON.stringify(textChild.value)};`);
|
|
461
|
+
ctx.push(`});`);
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
ctx.push(`{ let el = document.querySelector(${JSON.stringify(selector)}); if (!el) { el = document.createElement(${JSON.stringify(tag)}); document.head.appendChild(el); }`);
|
|
465
|
+
for (const [k, v] of staticAttrs)
|
|
466
|
+
ctx.push(`el.setAttribute(${JSON.stringify(k)}, ${JSON.stringify(v)});`);
|
|
467
|
+
if (textChild)
|
|
468
|
+
ctx.push(`el.textContent = ${JSON.stringify(textChild.value)};`);
|
|
469
|
+
ctx.push(`}`);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
function isReactiveExpression(node, tracked) {
|
|
476
|
+
const ast = node && (node.ast || node);
|
|
477
|
+
if (!ast)
|
|
478
|
+
return false;
|
|
479
|
+
let reactive = false;
|
|
480
|
+
walk(ast, tracked, {
|
|
481
|
+
Identifier(n, context) {
|
|
482
|
+
if (reactive)
|
|
483
|
+
return;
|
|
484
|
+
const parent = context.path.at(-1);
|
|
485
|
+
if (parent) {
|
|
486
|
+
if (parent.type === 'AssignmentExpression' &&
|
|
487
|
+
parent.left === n)
|
|
488
|
+
return;
|
|
489
|
+
if (parent.type === 'UpdateExpression' &&
|
|
490
|
+
parent.argument === n)
|
|
491
|
+
return;
|
|
492
|
+
if (parent.type === 'Property' &&
|
|
493
|
+
parent.value === n &&
|
|
494
|
+
parent.key &&
|
|
495
|
+
parent.key.type === 'Identifier' &&
|
|
496
|
+
parent.key.name === 'into')
|
|
497
|
+
return;
|
|
498
|
+
if (parent.type === 'MemberExpression' &&
|
|
499
|
+
!parent.computed &&
|
|
500
|
+
parent.property === n)
|
|
501
|
+
return;
|
|
502
|
+
if (parent.type === 'Property' &&
|
|
503
|
+
parent.key === n &&
|
|
504
|
+
!parent.shorthand)
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
const info = context.state.get(n.name);
|
|
508
|
+
if (n.name === 'props' || (info && info.kind === 'virtual'))
|
|
509
|
+
reactive = true;
|
|
510
|
+
},
|
|
511
|
+
});
|
|
512
|
+
return reactive;
|
|
513
|
+
}
|
|
514
|
+
function emitDynamicBinding(ctx, node, tracked, effectsVar) {
|
|
515
|
+
if (node.kind === 'attribute')
|
|
516
|
+
return null;
|
|
517
|
+
const expr = transformTracked(node.expression, tracked);
|
|
518
|
+
const v = ctx.n();
|
|
519
|
+
if (!isReactiveExpression(node.expression, tracked)) {
|
|
520
|
+
ctx.push(`const ${v} = document.createTextNode(String(${expr}));`);
|
|
521
|
+
return v;
|
|
522
|
+
}
|
|
523
|
+
ctx.push(`const ${v} = document.createTextNode('');`);
|
|
524
|
+
const eff = `effect(() => { ${v}.data = String(${expr}); })`;
|
|
525
|
+
if (effectsVar) {
|
|
526
|
+
ctx.push(`${effectsVar}.push(${eff});`);
|
|
527
|
+
}
|
|
528
|
+
else {
|
|
529
|
+
ctx.effects.push(`${eff};`);
|
|
530
|
+
}
|
|
531
|
+
return v;
|
|
532
|
+
}
|
|
533
|
+
function emitComponentCall(ctx, node, tracked, effectsVar, parentVar, compPrefix = '__components') {
|
|
534
|
+
const propsEntries = node.props.map((p) => {
|
|
535
|
+
if (typeof p.value === 'string')
|
|
536
|
+
return `${JSON.stringify(p.name)}: ${JSON.stringify(p.value)}`;
|
|
537
|
+
const expr = transformTracked(p.value, tracked);
|
|
538
|
+
const simpleGet = simpleGetName(expr);
|
|
539
|
+
if (simpleGet !== null && tracked.has(simpleGet)) {
|
|
540
|
+
return `${JSON.stringify(p.name)}: ${simpleGet}`;
|
|
541
|
+
}
|
|
542
|
+
return `${JSON.stringify(p.name)}: ${expr}`;
|
|
543
|
+
});
|
|
544
|
+
for (const sp of node.spreadProps) {
|
|
545
|
+
const expr = transformTracked(sp, tracked);
|
|
546
|
+
propsEntries.push(`...${expr}`);
|
|
547
|
+
}
|
|
548
|
+
const propsObj = `{ ${propsEntries.join(', ')} }`;
|
|
549
|
+
const v = ctx.n();
|
|
550
|
+
const awaitKw = ctx.asyncComps.has(node.componentName) ? 'await ' : '';
|
|
551
|
+
if (ctx.hydrate) {
|
|
552
|
+
const access = ctx.importedNames.has(node.componentName)
|
|
553
|
+
? node.componentName
|
|
554
|
+
: `__components[${JSON.stringify(node.componentName)}]`;
|
|
555
|
+
const subScope = () => ctx.inTryBody
|
|
556
|
+
? `${ctx.walker}.subWalker(${parentVar})`
|
|
557
|
+
: `${ctx.walker}.subWalker(${ctx.walker}.nextElement())`;
|
|
558
|
+
if (node.children.length > 0) {
|
|
559
|
+
const walkerVar = ctx.n();
|
|
560
|
+
ctx.push(`const ${walkerVar} = ${subScope()};`);
|
|
561
|
+
const frag = ctx.n();
|
|
562
|
+
ctx.push(`const ${frag} = (() => { const $f = document.createDocumentFragment();`);
|
|
563
|
+
const savedWalker = ctx.walker;
|
|
564
|
+
const savedEffects = ctx.effects;
|
|
565
|
+
ctx.walker = walkerVar;
|
|
566
|
+
ctx.effects = [];
|
|
567
|
+
for (const child of node.children) {
|
|
568
|
+
const childVar = emitNode(ctx, child, tracked, effectsVar, '$f');
|
|
569
|
+
if (childVar)
|
|
570
|
+
ctx.push(`$f.appendChild(${childVar});`);
|
|
571
|
+
}
|
|
572
|
+
for (const eff of ctx.effects)
|
|
573
|
+
ctx.push(effectsVar ? `${effectsVar}.push(${eff});` : eff);
|
|
574
|
+
ctx.effects = savedEffects;
|
|
575
|
+
ctx.walker = savedWalker;
|
|
576
|
+
ctx.push(`return $f; })();`);
|
|
577
|
+
propsEntries.push(`children: ${frag}`);
|
|
578
|
+
ctx.push(`const ${v} = ${awaitKw}${access}({ ${propsEntries.join(', ')} }, __registry, ${walkerVar});`);
|
|
579
|
+
return v;
|
|
580
|
+
}
|
|
581
|
+
ctx.push(`const ${v} = ${awaitKw}${access}(${propsObj}, __registry, ${subScope()});`);
|
|
582
|
+
return v;
|
|
583
|
+
}
|
|
584
|
+
else {
|
|
585
|
+
if (node.children.length > 0) {
|
|
586
|
+
const frag = ctx.n();
|
|
587
|
+
ctx.push(`const ${frag} = (() => { const $f = document.createDocumentFragment();`);
|
|
588
|
+
const savedEffects = ctx.effects;
|
|
589
|
+
ctx.effects = [];
|
|
590
|
+
for (const child of node.children) {
|
|
591
|
+
const childVar = emitNode(ctx, child, tracked, effectsVar, '$f');
|
|
592
|
+
if (childVar)
|
|
593
|
+
ctx.push(`$f.appendChild(${childVar});`);
|
|
594
|
+
}
|
|
595
|
+
for (const eff of ctx.effects)
|
|
596
|
+
ctx.push(effectsVar ? `${effectsVar}.push(${eff});` : eff);
|
|
597
|
+
ctx.effects = savedEffects;
|
|
598
|
+
ctx.push(`return $f; })();`);
|
|
599
|
+
propsEntries.push(`children: ${frag}`);
|
|
600
|
+
}
|
|
601
|
+
if (ctx.importedNames.has(node.componentName)) {
|
|
602
|
+
ctx.push(`const ${v} = ${awaitKw}${node.componentName}({ ${propsEntries.join(', ')} });`);
|
|
603
|
+
}
|
|
604
|
+
else {
|
|
605
|
+
ctx.push(`const ${v} = ${awaitKw}${compPrefix}[${JSON.stringify(node.componentName)}]({ ${propsEntries.join(', ')} });`);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
return v;
|
|
609
|
+
}
|
|
610
|
+
function emitTryCatch(ctx, node, tracked, effectsVar, parentVar) {
|
|
611
|
+
const anchor = ctx.n();
|
|
612
|
+
const endAnchor = ctx.n();
|
|
613
|
+
const effArr = ctx.n();
|
|
614
|
+
const catchParam = node.catchParamName || '__e';
|
|
615
|
+
const parent = parentVar || '$root';
|
|
616
|
+
ctx.push(`const ${anchor} = document.createComment('try');`);
|
|
617
|
+
if (!ctx.hydrate)
|
|
618
|
+
ctx.push(`${parent}.appendChild(${anchor});`);
|
|
619
|
+
ctx.push(`let ${effArr} = [];`);
|
|
620
|
+
ctx.push(`const ${endAnchor} = document.createComment('try-end');`);
|
|
621
|
+
const asyncKw = ctx.isAsyncScope ? 'await ' : '';
|
|
622
|
+
function emitRenderFunc(name, isCatch, hydMode, compPrefix = '__components') {
|
|
623
|
+
const savedHydrate = ctx.hydrate;
|
|
624
|
+
const savedInTryBody = ctx.inTryBody;
|
|
625
|
+
ctx.hydrate = hydMode;
|
|
626
|
+
if (hydMode && !isCatch) {
|
|
627
|
+
ctx.inTryBody = true;
|
|
628
|
+
}
|
|
629
|
+
ctx.push(`const ${name} = ${isCatch ? (ctx.isAsyncScope ? `async (${catchParam}) => {` : `(${catchParam}) => {`) : (ctx.isAsyncScope ? `async () => {` : `() => {`)}`);
|
|
630
|
+
ctx.push(indent(`const __p = ${anchor}.parentNode;`));
|
|
631
|
+
const savedEffects = ctx.effects;
|
|
632
|
+
ctx.effects = [];
|
|
633
|
+
const body = isCatch ? node.catchBody : node.bodyTemplate;
|
|
634
|
+
if (hydMode) {
|
|
635
|
+
ctx.push(indent(`const __cl = [];`));
|
|
636
|
+
}
|
|
637
|
+
for (const child of body) {
|
|
638
|
+
const childVar = emitNode(ctx, child, tracked, isCatch ? null : effArr, undefined, compPrefix);
|
|
639
|
+
if (childVar) {
|
|
640
|
+
if (hydMode)
|
|
641
|
+
ctx.push(indent(`__cl.push(${childVar});`));
|
|
642
|
+
else
|
|
643
|
+
ctx.push(indent(`__p.insertBefore(${childVar}, ${endAnchor});`));
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
if (hydMode) {
|
|
647
|
+
ctx.push(indent(`__place(${anchor}, ${endAnchor}, __cl, ${parent});`));
|
|
648
|
+
}
|
|
649
|
+
for (const eff of ctx.effects)
|
|
650
|
+
ctx.push(indent(eff));
|
|
651
|
+
ctx.effects = savedEffects;
|
|
652
|
+
ctx.hydrate = savedHydrate;
|
|
653
|
+
ctx.inTryBody = savedInTryBody;
|
|
654
|
+
ctx.push(`};`);
|
|
655
|
+
}
|
|
656
|
+
const tryRender = ctx.n();
|
|
657
|
+
emitRenderFunc(tryRender, false, ctx.hydrate);
|
|
658
|
+
let catchRender = null;
|
|
659
|
+
const hasCatch = node.catchBody.length > 0;
|
|
660
|
+
if (hasCatch) {
|
|
661
|
+
catchRender = ctx.n();
|
|
662
|
+
emitRenderFunc(catchRender, true, ctx.hydrate);
|
|
663
|
+
}
|
|
664
|
+
if (!ctx.hydrate)
|
|
665
|
+
ctx.push(`${parent}.appendChild(${endAnchor});`);
|
|
666
|
+
if (hasCatch) {
|
|
667
|
+
ctx.push(`try { ${asyncKw}${tryRender}(); } catch(${catchParam}) { ${asyncKw}${catchRender}(${catchParam}); }`);
|
|
668
|
+
}
|
|
669
|
+
else {
|
|
670
|
+
ctx.push(`${asyncKw}${tryRender}();`);
|
|
671
|
+
}
|
|
672
|
+
const tryRenderComp = ctx.n();
|
|
673
|
+
emitRenderFunc(tryRenderComp, false, false, '__runtime_comps');
|
|
674
|
+
let catchRenderComp = null;
|
|
675
|
+
if (hasCatch) {
|
|
676
|
+
catchRenderComp = ctx.n();
|
|
677
|
+
emitRenderFunc(catchRenderComp, true, false, '__runtime_comps');
|
|
678
|
+
}
|
|
679
|
+
ctx.effects.push(`{
|
|
680
|
+
effect(${ctx.isAsyncScope ? 'async () => {' : '() => {'}
|
|
681
|
+
for (const e of ${effArr}) destroy_block(e);
|
|
682
|
+
${effArr}.length = 0;
|
|
683
|
+
__cleanup(${anchor}, ${endAnchor});
|
|
684
|
+
try { ${asyncKw}${tryRenderComp}(); } catch(${catchParam}) { ${hasCatch ? `${asyncKw}${catchRenderComp}(${catchParam});` : 'throw ${catchParam};'} }
|
|
685
|
+
});
|
|
686
|
+
}`);
|
|
687
|
+
return null;
|
|
688
|
+
}
|
|
689
|
+
function emitOpaque(ctx, node, tracked, parentVar) {
|
|
690
|
+
const condExpr = transformTracked(node.condition, tracked);
|
|
691
|
+
const hasElse = node.alternateNodes.length > 0;
|
|
692
|
+
const anchor = ctx.n();
|
|
693
|
+
const endAnchor = ctx.n();
|
|
694
|
+
const effectsVar = ctx.n();
|
|
695
|
+
const hyd = ctx.hydrate;
|
|
696
|
+
const parent = parentVar || '$root';
|
|
697
|
+
ctx.push(`const ${anchor} = document.createComment('if');`);
|
|
698
|
+
if (!hyd)
|
|
699
|
+
ctx.push(`${parent}.appendChild(${anchor});`);
|
|
700
|
+
ctx.push(`let ${effectsVar} = [];`);
|
|
701
|
+
ctx.push(`const ${endAnchor} = document.createComment('if-end');`);
|
|
702
|
+
const asyncKw = ctx.isAsyncScope ? 'await ' : '';
|
|
703
|
+
const fnOpen = ctx.isAsyncScope ? 'async () => {' : '() => {';
|
|
704
|
+
const conRenderName = ctx.n();
|
|
705
|
+
ctx.push(`const ${conRenderName} = ${fnOpen}`);
|
|
706
|
+
if (!hyd)
|
|
707
|
+
ctx.push(indent(`const __p = ${anchor}.parentNode;`));
|
|
708
|
+
const conFrag = ctx.n();
|
|
709
|
+
if (!hyd)
|
|
710
|
+
ctx.push(indent(`const ${conFrag} = document.createDocumentFragment();`));
|
|
711
|
+
if (hyd)
|
|
712
|
+
ctx.push(indent(`const __cl = [];`));
|
|
713
|
+
for (const n of node.consequentNodes) {
|
|
714
|
+
const v = emitNode(ctx, n, tracked, effectsVar, hyd ? parentVar : conFrag);
|
|
715
|
+
if (v) {
|
|
716
|
+
if (hyd)
|
|
717
|
+
ctx.push(indent(`__cl.push(${v});`));
|
|
718
|
+
else
|
|
719
|
+
ctx.push(indent(`${conFrag}.appendChild(${v});`));
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
if (hyd)
|
|
723
|
+
ctx.push(indent(`__place(${anchor}, ${endAnchor}, __cl, ${parent});`));
|
|
724
|
+
else
|
|
725
|
+
ctx.push(indent(`__p.insertBefore(${conFrag}, ${endAnchor});`));
|
|
726
|
+
ctx.push(`};`);
|
|
727
|
+
let altRenderName = null;
|
|
728
|
+
if (hasElse) {
|
|
729
|
+
altRenderName = ctx.n();
|
|
730
|
+
ctx.push(`const ${altRenderName} = ${fnOpen}`);
|
|
731
|
+
if (!hyd)
|
|
732
|
+
ctx.push(indent(`const __p = ${anchor}.parentNode;`));
|
|
733
|
+
const altFrag = ctx.n();
|
|
734
|
+
if (!hyd)
|
|
735
|
+
ctx.push(indent(`const ${altFrag} = document.createDocumentFragment();`));
|
|
736
|
+
if (hyd)
|
|
737
|
+
ctx.push(indent(`const __cl = [];`));
|
|
738
|
+
for (const n of node.alternateNodes) {
|
|
739
|
+
const v = emitNode(ctx, n, tracked, effectsVar, hyd ? parentVar : altFrag);
|
|
740
|
+
if (v) {
|
|
741
|
+
if (hyd)
|
|
742
|
+
ctx.push(indent(`__cl.push(${v});`));
|
|
743
|
+
else
|
|
744
|
+
ctx.push(indent(`${altFrag}.appendChild(${v});`));
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
if (hyd)
|
|
748
|
+
ctx.push(indent(`__place(${anchor}, ${endAnchor}, __cl, ${parent});`));
|
|
749
|
+
else
|
|
750
|
+
ctx.push(indent(`__p.insertBefore(${altFrag}, ${endAnchor});`));
|
|
751
|
+
ctx.push(`};`);
|
|
752
|
+
}
|
|
753
|
+
if (!hyd)
|
|
754
|
+
ctx.push(`${parent}.appendChild(${endAnchor});`);
|
|
755
|
+
ctx.push(`if (${condExpr}) { ${asyncKw}${conRenderName}(); }` + (hasElse ? ` else { ${asyncKw}${altRenderName}(); }` : ''));
|
|
756
|
+
ctx.effects.push(`{
|
|
757
|
+
let __iv = ${condExpr};
|
|
758
|
+
let __first = true;
|
|
759
|
+
effect(${ctx.isAsyncScope ? 'async () => {' : '() => {'}
|
|
760
|
+
if (__first) { __first = false; return; }
|
|
761
|
+
const __nv = ${condExpr};
|
|
762
|
+
if (__nv !== __iv) {
|
|
763
|
+
for (const e of ${effectsVar}) destroy_block(e);
|
|
764
|
+
${effectsVar}.length = 0;
|
|
765
|
+
__cleanup(${anchor}, ${endAnchor});
|
|
766
|
+
if (__nv) { ${asyncKw}${conRenderName}(); }` + (hasElse ? ` else { ${asyncKw}${altRenderName}(); }` : '') + `
|
|
767
|
+
__iv = __nv;
|
|
768
|
+
}
|
|
769
|
+
});
|
|
770
|
+
}`);
|
|
771
|
+
return null;
|
|
772
|
+
}
|
|
773
|
+
function emitWhileLoop(ctx, node, tracked, parentVar) {
|
|
774
|
+
const condExpr = transformTracked(node.condition, tracked);
|
|
775
|
+
const anchor = ctx.n();
|
|
776
|
+
const endAnchor = ctx.n();
|
|
777
|
+
const effectsVar = ctx.n();
|
|
778
|
+
const hyd = ctx.hydrate;
|
|
779
|
+
const parent = parentVar || '$root';
|
|
780
|
+
ctx.push(`const ${anchor} = document.createComment('while');`);
|
|
781
|
+
if (!hyd)
|
|
782
|
+
ctx.push(`${parent}.appendChild(${anchor});`);
|
|
783
|
+
ctx.push(`let ${effectsVar} = [];`);
|
|
784
|
+
ctx.push(`const ${endAnchor} = document.createComment('while-end');`);
|
|
785
|
+
const renderLoop = ctx.n();
|
|
786
|
+
ctx.push(`const ${renderLoop} = ${ctx.isAsyncScope ? 'async () => {' : '() => {'}`);
|
|
787
|
+
if (!hyd)
|
|
788
|
+
ctx.push(indent(`const __p = ${anchor}.parentNode;`));
|
|
789
|
+
if (hyd)
|
|
790
|
+
ctx.push(indent(`const __cl = [];`));
|
|
791
|
+
if (node.isDoWhile) {
|
|
792
|
+
ctx.push(indent(`do {`));
|
|
793
|
+
for (const n of node.bodyTemplate) {
|
|
794
|
+
const v = emitNode(ctx, n, tracked, effectsVar, hyd ? parentVar : undefined);
|
|
795
|
+
if (v) {
|
|
796
|
+
if (hyd)
|
|
797
|
+
ctx.push(indent(`__cl.push(${v});`));
|
|
798
|
+
else
|
|
799
|
+
ctx.push(indent(`__p.insertBefore(${v}, ${endAnchor});`));
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
ctx.push(indent(`} while (${condExpr});`));
|
|
803
|
+
}
|
|
804
|
+
else {
|
|
805
|
+
ctx.push(indent(`while (${condExpr}) {`));
|
|
806
|
+
for (const n of node.bodyTemplate) {
|
|
807
|
+
const v = emitNode(ctx, n, tracked, effectsVar, hyd ? parentVar : undefined);
|
|
808
|
+
if (v) {
|
|
809
|
+
if (hyd)
|
|
810
|
+
ctx.push(indent(`__cl.push(${v});`));
|
|
811
|
+
else
|
|
812
|
+
ctx.push(indent(`__p.insertBefore(${v}, ${endAnchor});`));
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
ctx.push(indent(`}`));
|
|
816
|
+
}
|
|
817
|
+
if (hyd)
|
|
818
|
+
ctx.push(indent(`__place(${anchor}, ${endAnchor}, __cl, ${parent});`));
|
|
819
|
+
ctx.push(`};`);
|
|
820
|
+
if (!hyd)
|
|
821
|
+
ctx.push(`${parent}.appendChild(${endAnchor});`);
|
|
822
|
+
ctx.push(`${ctx.isAsyncScope ? 'await ' : ''}${renderLoop}();`);
|
|
823
|
+
ctx.effects.push(`{
|
|
824
|
+
let __busy = false;
|
|
825
|
+
let __iv = (${condExpr});
|
|
826
|
+
let __first = true;
|
|
827
|
+
effect(${ctx.isAsyncScope ? 'async () => {' : '() => {'}
|
|
828
|
+
if (__first) { __first = false; return; }
|
|
829
|
+
if (__busy) return;
|
|
830
|
+
const __nv = (${condExpr});
|
|
831
|
+
if (__nv !== __iv) {
|
|
832
|
+
for (const e of ${effectsVar}) destroy_block(e);
|
|
833
|
+
${effectsVar}.length = 0;
|
|
834
|
+
__cleanup(${anchor}, ${endAnchor});
|
|
835
|
+
__busy = true;
|
|
836
|
+
${ctx.isAsyncScope ? 'await ' : ''}${renderLoop}();
|
|
837
|
+
__busy = false;
|
|
838
|
+
__iv = (${condExpr});
|
|
839
|
+
}
|
|
840
|
+
});
|
|
841
|
+
}`);
|
|
842
|
+
return null;
|
|
843
|
+
}
|
|
844
|
+
function emitForLoop(ctx, node, tracked, parentVar) {
|
|
845
|
+
const anchor = ctx.n();
|
|
846
|
+
const endAnchor = ctx.n();
|
|
847
|
+
const effectsVar = ctx.n();
|
|
848
|
+
const hyd = ctx.hydrate;
|
|
849
|
+
const parent = parentVar || '$root';
|
|
850
|
+
ctx.push(`const ${anchor} = document.createComment('for');`);
|
|
851
|
+
if (!hyd)
|
|
852
|
+
ctx.push(`${parent}.appendChild(${anchor});`);
|
|
853
|
+
ctx.push(`let ${effectsVar} = [];`);
|
|
854
|
+
ctx.push(`const ${endAnchor} = document.createComment('for-end');`);
|
|
855
|
+
const renderLoop = ctx.n();
|
|
856
|
+
ctx.push(`const ${renderLoop} = ${ctx.isAsyncScope ? 'async () => {' : '() => {'}`);
|
|
857
|
+
if (!hyd)
|
|
858
|
+
ctx.push(indent(`const __p = ${anchor}.parentNode;`));
|
|
859
|
+
if (hyd)
|
|
860
|
+
ctx.push(indent(`const __cl = [];`));
|
|
861
|
+
if (node.kind === 'for-in') {
|
|
862
|
+
const srcExpr = transformTracked(node.condition, tracked);
|
|
863
|
+
ctx.push(indent(`for (${node.init} of (Array.isArray(${srcExpr}) ? ${srcExpr} : (${srcExpr} == null ? [] : Object.keys(${srcExpr})))) {`));
|
|
864
|
+
for (const n of node.bodyTemplate) {
|
|
865
|
+
const v = emitNode(ctx, n, tracked, effectsVar, hyd ? parentVar : undefined);
|
|
866
|
+
if (v) {
|
|
867
|
+
if (hyd)
|
|
868
|
+
ctx.push(indent(`__cl.push(${v});`));
|
|
869
|
+
else
|
|
870
|
+
ctx.push(indent(`__p.insertBefore(${v}, ${endAnchor});`));
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
ctx.push(indent(`}`));
|
|
874
|
+
}
|
|
875
|
+
else {
|
|
876
|
+
const condExpr = transformTracked(node.condition, tracked);
|
|
877
|
+
if (node.init)
|
|
878
|
+
ctx.push(indent(`${node.init}`));
|
|
879
|
+
ctx.push(indent(`while (${condExpr}) {`));
|
|
880
|
+
for (const n of node.bodyTemplate) {
|
|
881
|
+
const v = emitNode(ctx, n, tracked, effectsVar, hyd ? parentVar : undefined);
|
|
882
|
+
if (v) {
|
|
883
|
+
if (hyd)
|
|
884
|
+
ctx.push(indent(`__cl.push(${v});`));
|
|
885
|
+
else
|
|
886
|
+
ctx.push(indent(`__p.insertBefore(${v}, ${endAnchor});`));
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
if (node.update)
|
|
890
|
+
ctx.push(indent(`${node.update}`));
|
|
891
|
+
ctx.push(indent(`}`));
|
|
892
|
+
}
|
|
893
|
+
if (hyd)
|
|
894
|
+
ctx.push(indent(`__place(${anchor}, ${endAnchor}, __cl, ${parent});`));
|
|
895
|
+
ctx.push(`};`);
|
|
896
|
+
if (!hyd)
|
|
897
|
+
ctx.push(`${parent}.appendChild(${endAnchor});`);
|
|
898
|
+
ctx.push(`${ctx.isAsyncScope ? 'await ' : ''}${renderLoop}();`);
|
|
899
|
+
if (node.kind === 'for-in') {
|
|
900
|
+
const srcExpr = transformTracked(node.condition, tracked);
|
|
901
|
+
ctx.effects.push(`{
|
|
902
|
+
let __busy = false;
|
|
903
|
+
let __iv = undefined;
|
|
904
|
+
let __first = true;
|
|
905
|
+
effect(${ctx.isAsyncScope ? 'async () => {' : '() => {'}
|
|
906
|
+
if (__first) { __first = false; return; }
|
|
907
|
+
if (__busy) return;
|
|
908
|
+
const __nv = (${srcExpr});
|
|
909
|
+
if (__nv !== __iv) {
|
|
910
|
+
for (const e of ${effectsVar}) destroy_block(e);
|
|
911
|
+
${effectsVar}.length = 0;
|
|
912
|
+
__cleanup(${anchor}, ${endAnchor});
|
|
913
|
+
__busy = true;
|
|
914
|
+
${ctx.isAsyncScope ? 'await ' : ''}${renderLoop}();
|
|
915
|
+
__busy = false;
|
|
916
|
+
__iv = (${srcExpr});
|
|
917
|
+
}
|
|
918
|
+
});
|
|
919
|
+
}`);
|
|
920
|
+
}
|
|
921
|
+
else {
|
|
922
|
+
// Classic `for` loops declare their loop variable in the init clause, so the
|
|
923
|
+
// condition only refers to loop-local bindings. The loop renders once and is
|
|
924
|
+
// not reactive, so no re-render effect is emitted.
|
|
925
|
+
}
|
|
926
|
+
return null;
|
|
927
|
+
}
|
|
928
|
+
function emitSwitchBlock(ctx, node, tracked, parentVar) {
|
|
929
|
+
const discExpr = transformTracked(node.discriminant, tracked);
|
|
930
|
+
const anchor = ctx.n();
|
|
931
|
+
const endAnchor = ctx.n();
|
|
932
|
+
const effectsVar = ctx.n();
|
|
933
|
+
const hyd = ctx.hydrate;
|
|
934
|
+
const parent = parentVar || '$root';
|
|
935
|
+
ctx.push(`const ${anchor} = document.createComment('switch');`);
|
|
936
|
+
if (!hyd)
|
|
937
|
+
ctx.push(`${parent}.appendChild(${anchor});`);
|
|
938
|
+
ctx.push(`let ${effectsVar} = [];`);
|
|
939
|
+
ctx.push(`const ${endAnchor} = document.createComment('switch-end');`);
|
|
940
|
+
const renderSwitch = ctx.n();
|
|
941
|
+
ctx.push(`const ${renderSwitch} = ${ctx.isAsyncScope ? 'async () => {' : '() => {'}`);
|
|
942
|
+
if (!hyd)
|
|
943
|
+
ctx.push(indent(`const __p = ${anchor}.parentNode;`));
|
|
944
|
+
if (hyd)
|
|
945
|
+
ctx.push(indent(`const __cl = [];`));
|
|
946
|
+
ctx.push(indent(`switch (${discExpr}) {`));
|
|
947
|
+
for (const c of node.cases) {
|
|
948
|
+
if (c.test) {
|
|
949
|
+
ctx.push(indent(`case ${transformTracked(c.test, tracked)}:`));
|
|
950
|
+
}
|
|
951
|
+
else {
|
|
952
|
+
ctx.push(indent(`default:`));
|
|
953
|
+
}
|
|
954
|
+
for (const n of c.body) {
|
|
955
|
+
const v = emitNode(ctx, n, tracked, effectsVar, hyd ? parentVar : undefined);
|
|
956
|
+
if (v) {
|
|
957
|
+
if (hyd)
|
|
958
|
+
ctx.push(indent(`__cl.push(${v});`));
|
|
959
|
+
else
|
|
960
|
+
ctx.push(indent(`__p.insertBefore(${v}, ${endAnchor});`));
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
ctx.push(indent(`break;`));
|
|
964
|
+
}
|
|
965
|
+
ctx.push(indent(`}`));
|
|
966
|
+
if (hyd)
|
|
967
|
+
ctx.push(indent(`__place(${anchor}, ${endAnchor}, __cl, ${parent});`));
|
|
968
|
+
ctx.push(`};`);
|
|
969
|
+
if (!hyd)
|
|
970
|
+
ctx.push(`${parent}.appendChild(${endAnchor});`);
|
|
971
|
+
ctx.push(`${ctx.isAsyncScope ? 'await ' : ''}${renderSwitch}();`);
|
|
972
|
+
ctx.effects.push(`{
|
|
973
|
+
let __busy = false;
|
|
974
|
+
let __iv = (${discExpr});
|
|
975
|
+
let __first = true;
|
|
976
|
+
effect(${ctx.isAsyncScope ? 'async () => {' : '() => {'}
|
|
977
|
+
if (__first) { __first = false; return; }
|
|
978
|
+
if (__busy) return;
|
|
979
|
+
const __nv = (${discExpr});
|
|
980
|
+
if (__nv !== __iv) {
|
|
981
|
+
for (const e of ${effectsVar}) destroy_block(e);
|
|
982
|
+
${effectsVar}.length = 0;
|
|
983
|
+
__cleanup(${anchor}, ${endAnchor});
|
|
984
|
+
__busy = true;
|
|
985
|
+
${ctx.isAsyncScope ? 'await ' : ''}${renderSwitch}();
|
|
986
|
+
__busy = false;
|
|
987
|
+
__iv = (${discExpr});
|
|
988
|
+
}
|
|
989
|
+
});
|
|
990
|
+
}`);
|
|
991
|
+
return null;
|
|
992
|
+
}
|
|
993
|
+
function emitMap(ctx, node, tracked, parentVar) {
|
|
994
|
+
const arrExpr = transformTracked(node.expression, tracked);
|
|
995
|
+
const itemVar = node.itemVariable;
|
|
996
|
+
const anchor = ctx.n();
|
|
997
|
+
const endAnchor = ctx.n();
|
|
998
|
+
const effectsVar = ctx.n();
|
|
999
|
+
const aw = ctx.isAsyncScope ? 'await ' : '';
|
|
1000
|
+
const effOpen = ctx.isAsyncScope ? 'async () => {' : '() => {';
|
|
1001
|
+
const keyed = !!node.keyExpr;
|
|
1002
|
+
const hyd = ctx.hydrate && !keyed;
|
|
1003
|
+
const parent = parentVar || '$root';
|
|
1004
|
+
ctx.push(`const ${anchor} = document.createComment('map');`);
|
|
1005
|
+
if (!hyd)
|
|
1006
|
+
ctx.push(`${parent}.appendChild(${anchor});`);
|
|
1007
|
+
ctx.push(`let ${effectsVar} = [];`);
|
|
1008
|
+
ctx.push(`const ${endAnchor} = document.createComment('map-end');`);
|
|
1009
|
+
const renderItem = ctx.n();
|
|
1010
|
+
const indexParam = node.indexVariable ? ', __i' : '';
|
|
1011
|
+
ctx.push(`const ${renderItem} = ${ctx.isAsyncScope ? 'async ' : ''}(${itemVar}${indexParam}, __e, __r${hyd ? ', __cl' : ''}) => {`);
|
|
1012
|
+
ctx.push(indent(`__r = __r || ${endAnchor};`));
|
|
1013
|
+
if (node.indexVariable)
|
|
1014
|
+
ctx.push(indent(`const ${node.indexVariable} = __i;`));
|
|
1015
|
+
ctx.push(indent(`const __p = ${anchor}.parentNode;`));
|
|
1016
|
+
for (const n of node.bodyTemplate) {
|
|
1017
|
+
const v = emitNode(ctx, n, tracked, '__e');
|
|
1018
|
+
if (v) {
|
|
1019
|
+
if (hyd)
|
|
1020
|
+
ctx.push(indent(`if (__cl) __cl.push(${v}); else __p.insertBefore(${v}, __r);`));
|
|
1021
|
+
else
|
|
1022
|
+
ctx.push(indent(`__p.insertBefore(${v}, __r);`));
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
ctx.push(`};`);
|
|
1026
|
+
let emptyRenderName = null;
|
|
1027
|
+
if (node.alternateNodes.length > 0) {
|
|
1028
|
+
emptyRenderName = ctx.n();
|
|
1029
|
+
const emptySig = hyd
|
|
1030
|
+
? (ctx.isAsyncScope ? 'async (__cl) => {' : '(__cl) => {')
|
|
1031
|
+
: (ctx.isAsyncScope ? 'async () => {' : '() => {');
|
|
1032
|
+
ctx.push(`const ${emptyRenderName} = ${emptySig}`);
|
|
1033
|
+
ctx.push(indent(`const __p = ${anchor}.parentNode;`));
|
|
1034
|
+
const frag = ctx.n();
|
|
1035
|
+
if (!hyd)
|
|
1036
|
+
ctx.push(indent(`const ${frag} = document.createDocumentFragment();`));
|
|
1037
|
+
const savedClaim = ctx.claimStatic;
|
|
1038
|
+
for (const n of node.alternateNodes) {
|
|
1039
|
+
ctx.claimStatic = true;
|
|
1040
|
+
const v = emitNode(ctx, n, tracked, effectsVar, hyd ? undefined : frag);
|
|
1041
|
+
if (v) {
|
|
1042
|
+
if (hyd)
|
|
1043
|
+
ctx.push(indent(`if (__cl) __cl.push(${v}); else __p.insertBefore(${v}, ${endAnchor});`));
|
|
1044
|
+
else
|
|
1045
|
+
ctx.push(indent(`${frag}.appendChild(${v});`));
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
ctx.claimStatic = savedClaim;
|
|
1049
|
+
if (!hyd)
|
|
1050
|
+
ctx.push(indent(`__p.insertBefore(${frag}, ${endAnchor});`));
|
|
1051
|
+
ctx.push(`};`);
|
|
1052
|
+
}
|
|
1053
|
+
if (!hyd)
|
|
1054
|
+
ctx.push(`${parent}.appendChild(${endAnchor});`);
|
|
1055
|
+
const hasItems = ctx.n();
|
|
1056
|
+
ctx.push(`const ${hasItems} = () => { const __l = ${arrExpr}; return __l != null && __l.length > 0; };`);
|
|
1057
|
+
if (node.keyExpr) {
|
|
1058
|
+
const keyExpr = transformTracked(node.keyExpr, tracked);
|
|
1059
|
+
const reconciler = ctx.n();
|
|
1060
|
+
const initList = ctx.n();
|
|
1061
|
+
ctx.push(`let ${reconciler} = () => {};`);
|
|
1062
|
+
ctx.push(`const ${initList} = () => { ${reconciler} = reconcile(${anchor}, ${endAnchor}, ${arrExpr}, ${itemVar} => ${keyExpr}, (${itemVar}, __i, __e) => ${renderItem}(${itemVar}${indexParam ? ', __i, __e' : ', __e'})); };`);
|
|
1063
|
+
if (emptyRenderName) {
|
|
1064
|
+
const isEmptyVar = ctx.n();
|
|
1065
|
+
ctx.push(`let ${isEmptyVar} = !${hasItems}();`);
|
|
1066
|
+
ctx.push(`if (!${isEmptyVar}) { ${initList}(); } else { ${aw}${emptyRenderName}(); }`);
|
|
1067
|
+
ctx.effects.push(`{
|
|
1068
|
+
let __first = true;
|
|
1069
|
+
effect(${effOpen}
|
|
1070
|
+
const __new = ${hasItems}();
|
|
1071
|
+
if (__first) { __first = false; return; }
|
|
1072
|
+
if (__new !== ${isEmptyVar}) {
|
|
1073
|
+
if (__new) ${reconciler}(${arrExpr});
|
|
1074
|
+
return;
|
|
1075
|
+
}
|
|
1076
|
+
${isEmptyVar} = !__new;
|
|
1077
|
+
for (const e of ${effectsVar}) destroy_block(e);
|
|
1078
|
+
${effectsVar}.length = 0;
|
|
1079
|
+
__cleanup(${anchor}, ${endAnchor});
|
|
1080
|
+
if (__new) { ${initList}(); } else { ${aw}${emptyRenderName}(); }
|
|
1081
|
+
});
|
|
1082
|
+
}`);
|
|
1083
|
+
}
|
|
1084
|
+
else {
|
|
1085
|
+
ctx.push(`${initList}();`);
|
|
1086
|
+
ctx.effects.push(`{
|
|
1087
|
+
let __first = true;
|
|
1088
|
+
effect(() => {
|
|
1089
|
+
const __nv = ${arrExpr};
|
|
1090
|
+
if (__first) { __first = false; return; }
|
|
1091
|
+
${reconciler}(${arrExpr});
|
|
1092
|
+
});
|
|
1093
|
+
}`);
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
else {
|
|
1097
|
+
const renderAllItems = (ind, collect) => {
|
|
1098
|
+
const lines = [];
|
|
1099
|
+
if (node.indexVariable) {
|
|
1100
|
+
lines.push(`${ind}let __i = 0;`);
|
|
1101
|
+
lines.push(`${ind}for (const ${itemVar} of ${arrExpr}) {`);
|
|
1102
|
+
lines.push(`${ind}\t${aw}${renderItem}(${itemVar}, __i, ${effectsVar}${collect ? `, null, ${collect}` : ''});`);
|
|
1103
|
+
lines.push(`${ind}\t__i++;`);
|
|
1104
|
+
lines.push(`${ind}}`);
|
|
1105
|
+
}
|
|
1106
|
+
else {
|
|
1107
|
+
lines.push(`${ind}for (const ${itemVar} of ${arrExpr}) {`);
|
|
1108
|
+
lines.push(`${ind}\t${aw}${renderItem}(${itemVar}, ${effectsVar}${collect ? `, null, ${collect}` : ''});`);
|
|
1109
|
+
lines.push(`${ind}}`);
|
|
1110
|
+
}
|
|
1111
|
+
return lines.join('\n');
|
|
1112
|
+
};
|
|
1113
|
+
if (emptyRenderName) {
|
|
1114
|
+
const collectVar = hyd ? ctx.n() : null;
|
|
1115
|
+
const isEmptyVar = ctx.n();
|
|
1116
|
+
ctx.push(`let ${isEmptyVar} = !${hasItems}();`);
|
|
1117
|
+
if (collectVar)
|
|
1118
|
+
ctx.push(`const ${collectVar} = [];`);
|
|
1119
|
+
ctx.push(`if (!${isEmptyVar}) {`);
|
|
1120
|
+
ctx.push(indent(renderAllItems('', collectVar)));
|
|
1121
|
+
ctx.push(indent(`} else { ${aw}${emptyRenderName}(${collectVar ? collectVar : ''}); }`));
|
|
1122
|
+
if (collectVar)
|
|
1123
|
+
ctx.push(`__place(${anchor}, ${endAnchor}, ${collectVar}, ${parent});`);
|
|
1124
|
+
ctx.effects.push(`{
|
|
1125
|
+
let __first = true;
|
|
1126
|
+
effect(${effOpen}
|
|
1127
|
+
const __new = ${hasItems}();
|
|
1128
|
+
if (__first) { __first = false; return; }
|
|
1129
|
+
if (__new !== ${isEmptyVar}) {
|
|
1130
|
+
if (__new) {
|
|
1131
|
+
for (const e of ${effectsVar}) destroy_block(e);
|
|
1132
|
+
${effectsVar}.length = 0;
|
|
1133
|
+
__cleanup(${anchor}, ${endAnchor});
|
|
1134
|
+
${renderAllItems(' ', null)}
|
|
1135
|
+
}
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
${isEmptyVar} = !__new;
|
|
1139
|
+
for (const e of ${effectsVar}) destroy_block(e);
|
|
1140
|
+
${effectsVar}.length = 0;
|
|
1141
|
+
__cleanup(${anchor}, ${endAnchor});
|
|
1142
|
+
if (__new) {
|
|
1143
|
+
${renderAllItems(' ', null)}
|
|
1144
|
+
} else { ${aw}${emptyRenderName}(${collectVar ? collectVar : ''}); }
|
|
1145
|
+
});
|
|
1146
|
+
}`);
|
|
1147
|
+
}
|
|
1148
|
+
else {
|
|
1149
|
+
const collectVar = hyd ? ctx.n() : null;
|
|
1150
|
+
if (collectVar)
|
|
1151
|
+
ctx.push(`const ${collectVar} = [];`);
|
|
1152
|
+
ctx.push(renderAllItems('', collectVar));
|
|
1153
|
+
if (collectVar)
|
|
1154
|
+
ctx.push(`__place(${anchor}, ${endAnchor}, ${collectVar}, ${parent});`);
|
|
1155
|
+
ctx.effects.push(`{
|
|
1156
|
+
let __first = true;
|
|
1157
|
+
effect(${effOpen}
|
|
1158
|
+
const __nv = ${arrExpr};
|
|
1159
|
+
if (__first) { __first = false; return; }
|
|
1160
|
+
for (const e of ${effectsVar}) destroy_block(e);
|
|
1161
|
+
${effectsVar}.length = 0;
|
|
1162
|
+
__cleanup(${anchor}, ${endAnchor});
|
|
1163
|
+
${renderAllItems(' ', null)}
|
|
1164
|
+
});
|
|
1165
|
+
}`);
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
return null;
|
|
1169
|
+
}
|
|
1170
|
+
function computeAsyncComponents(comps) {
|
|
1171
|
+
return new Set(comps.filter((c) => c.isAsync).map((c) => c.name));
|
|
1172
|
+
}
|
|
1173
|
+
function generateComponent(comp, importedNames = new Set(), hydrate = false, asyncComps = new Set()) {
|
|
1174
|
+
const tracked = collectTrackedNames(comp.body);
|
|
1175
|
+
const ctx = new Ctx();
|
|
1176
|
+
ctx.importedNames = importedNames;
|
|
1177
|
+
ctx.hydrate = hydrate;
|
|
1178
|
+
ctx.asyncComps = asyncComps;
|
|
1179
|
+
ctx.isAsyncScope = comp.isAsync || asyncComps.has(comp.name);
|
|
1180
|
+
ctx.push(hydrate ? (ctx.isAsyncScope ? 'async (props, __registry, __hydrate) => {' : '(props, __registry, __hydrate) => {') : (ctx.isAsyncScope ? 'async (props) => {' : '(props) => {'));
|
|
1181
|
+
ctx.push(indent(`props = reactiveProps(props);`));
|
|
1182
|
+
ctx.push(indent(`const __prev = getActiveComponent();`));
|
|
1183
|
+
ctx.push(indent(`setActiveComponent({ c: null, p: __prev });`));
|
|
1184
|
+
ctx.push(indent(`try {`));
|
|
1185
|
+
if (comp.style) {
|
|
1186
|
+
const key = `vesk-${comp.name}`;
|
|
1187
|
+
ctx.push(indent(`if (!document.getElementById(${JSON.stringify(key)})) {`));
|
|
1188
|
+
ctx.push(indent(`\tconst s = document.createElement('style'); s.id = ${JSON.stringify(key)}; s.textContent = ${JSON.stringify(comp.style)}; document.head.appendChild(s);`, 2));
|
|
1189
|
+
ctx.push(indent(`}`));
|
|
1190
|
+
}
|
|
1191
|
+
if (ctx.hydrate) {
|
|
1192
|
+
ctx.push(indent(`const $root = __hydrate.root;`));
|
|
1193
|
+
}
|
|
1194
|
+
else {
|
|
1195
|
+
ctx.push(indent(`const $root = document.createDocumentFragment();`));
|
|
1196
|
+
}
|
|
1197
|
+
ctx.push(indent(`let __pendingChild = null;`));
|
|
1198
|
+
const paramInit = buildParamInit(comp.paramNames);
|
|
1199
|
+
if (paramInit)
|
|
1200
|
+
ctx.push(indent(paramInit));
|
|
1201
|
+
for (const node of comp.body) {
|
|
1202
|
+
const v = emitNode(ctx, node, tracked, null);
|
|
1203
|
+
if (v) {
|
|
1204
|
+
if (ctx.hydrate) {
|
|
1205
|
+
ctx.push(indent(`if (${v}.parentNode !== $root) $root.appendChild(${v});`));
|
|
1206
|
+
}
|
|
1207
|
+
else {
|
|
1208
|
+
ctx.push(indent(`$root.appendChild(${v});`));
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
const effCode = ctx.flushEffects();
|
|
1213
|
+
if (effCode)
|
|
1214
|
+
ctx.push(indent(effCode.trim()));
|
|
1215
|
+
const delCode = ctx.emitDelegates();
|
|
1216
|
+
if (delCode)
|
|
1217
|
+
ctx.push(indent(delCode.trim()));
|
|
1218
|
+
ctx.push(indent(`return __pendingChild || $root;`));
|
|
1219
|
+
ctx.push(indent(`} finally {`));
|
|
1220
|
+
ctx.push(indent(`\tsetActiveComponent(__prev);`));
|
|
1221
|
+
ctx.push(indent(`}`));
|
|
1222
|
+
ctx.push(`}`);
|
|
1223
|
+
return ctx.getCode();
|
|
1224
|
+
}
|
|
1225
|
+
function buildParamInit(paramNames) {
|
|
1226
|
+
if (paramNames.length === 1 && paramNames[0] === 'props')
|
|
1227
|
+
return '';
|
|
1228
|
+
if (paramNames.length === 0)
|
|
1229
|
+
return '';
|
|
1230
|
+
return `const { ${paramNames.join(', ')} } = props;`;
|
|
1231
|
+
}
|
|
1232
|
+
function buildComponentMap(irRoot, hydrate = false) {
|
|
1233
|
+
const mapLines = [];
|
|
1234
|
+
mapLines.push(`const __components = {};`);
|
|
1235
|
+
const asyncComps = computeAsyncComponents(irRoot.components);
|
|
1236
|
+
for (const comp of irRoot.components) {
|
|
1237
|
+
if (hydrate && isStaticComponent(comp)) {
|
|
1238
|
+
const stub = `(props, __registry, __hydrate) => { return __hydrate.root; }`;
|
|
1239
|
+
mapLines.push(`__components[${JSON.stringify(comp.name)}] = ${stub};`);
|
|
1240
|
+
continue;
|
|
1241
|
+
}
|
|
1242
|
+
const code = generateComponent(comp, new Set(extractRuntimeNames(irRoot.imports)), hydrate, asyncComps);
|
|
1243
|
+
mapLines.push(`__components[${JSON.stringify(comp.name)}] = ${code};`);
|
|
1244
|
+
}
|
|
1245
|
+
mapLines.push(`function __cleanup(start, end) {`);
|
|
1246
|
+
mapLines.push(`\tlet n = start.nextSibling;`);
|
|
1247
|
+
mapLines.push(`\twhile (n && n !== end) {`);
|
|
1248
|
+
mapLines.push(`\t\tconst next = n.nextSibling;`);
|
|
1249
|
+
mapLines.push(`\t\tn.remove();`);
|
|
1250
|
+
mapLines.push(`\t\tn = next;`);
|
|
1251
|
+
mapLines.push(`\t}`);
|
|
1252
|
+
mapLines.push(`}`);
|
|
1253
|
+
mapLines.push(`function __place(start, end, nodes, fallback) {`);
|
|
1254
|
+
mapLines.push(`\tif (start.parentNode !== null) {`);
|
|
1255
|
+
mapLines.push(`\t\tconst p = start.parentNode;`);
|
|
1256
|
+
mapLines.push(`\t\tfor (let i = 0; i < nodes.length; i++) p.insertBefore(nodes[i], end);`);
|
|
1257
|
+
mapLines.push(`\t\treturn;`);
|
|
1258
|
+
mapLines.push(`\t}`);
|
|
1259
|
+
mapLines.push(`\tif (nodes.length > 0 && nodes[0].parentNode) {`);
|
|
1260
|
+
mapLines.push(`\t\tconst p = nodes[0].parentNode;`);
|
|
1261
|
+
mapLines.push(`\t\tp.insertBefore(start, nodes[0]);`);
|
|
1262
|
+
mapLines.push(`\t\tp.insertBefore(end, nodes[nodes.length - 1].nextSibling);`);
|
|
1263
|
+
mapLines.push(`\t\treturn;`);
|
|
1264
|
+
mapLines.push(`\t}`);
|
|
1265
|
+
mapLines.push(`\tfallback.appendChild(start);`);
|
|
1266
|
+
mapLines.push(`\tfallback.appendChild(end);`);
|
|
1267
|
+
mapLines.push(`\tfor (let i = 0; i < nodes.length; i++) fallback.insertBefore(nodes[i], end);`);
|
|
1268
|
+
mapLines.push(`}`);
|
|
1269
|
+
return mapLines.join('\n\n');
|
|
1270
|
+
}
|
|
1271
|
+
function isStaticIR(body) {
|
|
1272
|
+
for (const node of body) {
|
|
1273
|
+
if (node instanceof StaticNode) {
|
|
1274
|
+
for (const child of node.children) {
|
|
1275
|
+
if (child instanceof DynamicBinding && child.kind === 'attribute' && child.target) {
|
|
1276
|
+
if (child.target.startsWith('on') && child.target.length > 2)
|
|
1277
|
+
return false;
|
|
1278
|
+
return false;
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
if (!isStaticIR(node.children))
|
|
1282
|
+
return false;
|
|
1283
|
+
}
|
|
1284
|
+
else if (!(node instanceof TextNode)) {
|
|
1285
|
+
return false;
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
return true;
|
|
1289
|
+
}
|
|
1290
|
+
function isStaticComponent(comp) {
|
|
1291
|
+
if (comp.style)
|
|
1292
|
+
return false;
|
|
1293
|
+
return isStaticIR(comp.body);
|
|
1294
|
+
}
|
|
1295
|
+
function usedRuntimeBindings(ir) {
|
|
1296
|
+
const found = new Set();
|
|
1297
|
+
const allNames = ['bindValue', 'bindChecked', 'bindGroup'];
|
|
1298
|
+
for (const comp of ir.components) {
|
|
1299
|
+
for (const name of allNames) {
|
|
1300
|
+
if (found.has(name))
|
|
1301
|
+
continue;
|
|
1302
|
+
if (findBindingInIR(comp.body, new Set([name])))
|
|
1303
|
+
found.add(name);
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
return found;
|
|
1307
|
+
}
|
|
1308
|
+
function findBindingInIR(nodes, names) {
|
|
1309
|
+
for (const node of nodes) {
|
|
1310
|
+
if (node instanceof DynamicBinding) {
|
|
1311
|
+
if (astHasBinding(node.expression.ast, names))
|
|
1312
|
+
return true;
|
|
1313
|
+
}
|
|
1314
|
+
else if (node instanceof OpaqueDynamicRegion) {
|
|
1315
|
+
if (astHasBinding(node.condition.ast, names))
|
|
1316
|
+
return true;
|
|
1317
|
+
if (findBindingInIR(node.consequentNodes, names))
|
|
1318
|
+
return true;
|
|
1319
|
+
if (findBindingInIR(node.alternateNodes, names))
|
|
1320
|
+
return true;
|
|
1321
|
+
}
|
|
1322
|
+
else if (node instanceof MapRegion) {
|
|
1323
|
+
if (astHasBinding(node.expression.ast, names))
|
|
1324
|
+
return true;
|
|
1325
|
+
if (findBindingInIR(node.bodyTemplate, names))
|
|
1326
|
+
return true;
|
|
1327
|
+
if (findBindingInIR(node.alternateNodes, names))
|
|
1328
|
+
return true;
|
|
1329
|
+
}
|
|
1330
|
+
else if (node instanceof WhileLoop) {
|
|
1331
|
+
if (astHasBinding(node.condition.ast, names))
|
|
1332
|
+
return true;
|
|
1333
|
+
if (findBindingInIR(node.bodyTemplate, names))
|
|
1334
|
+
return true;
|
|
1335
|
+
}
|
|
1336
|
+
else if (node instanceof SwitchBlock) {
|
|
1337
|
+
if (astHasBinding(node.discriminant.ast, names))
|
|
1338
|
+
return true;
|
|
1339
|
+
for (const c of node.cases) {
|
|
1340
|
+
if (c.test && astHasBinding(c.test.ast, names))
|
|
1341
|
+
return true;
|
|
1342
|
+
if (findBindingInIR(c.body, names))
|
|
1343
|
+
return true;
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
else if (node instanceof TryCatch) {
|
|
1347
|
+
if (findBindingInIR(node.bodyTemplate, names))
|
|
1348
|
+
return true;
|
|
1349
|
+
if (findBindingInIR(node.catchBody, names))
|
|
1350
|
+
return true;
|
|
1351
|
+
}
|
|
1352
|
+
else if (node instanceof ForLoop) {
|
|
1353
|
+
if (astHasBinding(node.condition.ast, names))
|
|
1354
|
+
return true;
|
|
1355
|
+
if (findBindingInIR(node.bodyTemplate, names))
|
|
1356
|
+
return true;
|
|
1357
|
+
}
|
|
1358
|
+
else if (node instanceof ComponentCall) {
|
|
1359
|
+
for (const prop of node.props) {
|
|
1360
|
+
if (astHasBinding(prop.value.ast, names))
|
|
1361
|
+
return true;
|
|
1362
|
+
}
|
|
1363
|
+
if (findBindingInIR(node.children, names))
|
|
1364
|
+
return true;
|
|
1365
|
+
}
|
|
1366
|
+
else if (node instanceof RuntimeStatement) {
|
|
1367
|
+
if (astHasBinding(node.ast, names))
|
|
1368
|
+
return true;
|
|
1369
|
+
}
|
|
1370
|
+
else if (node instanceof StaticNode) {
|
|
1371
|
+
if (findBindingInIR(node.children, names))
|
|
1372
|
+
return true;
|
|
1373
|
+
}
|
|
1374
|
+
else if (node instanceof ServerBlock || node instanceof ClientBlock || node instanceof HeadBlock) {
|
|
1375
|
+
if (findBindingInIR(node.children, names))
|
|
1376
|
+
return true;
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
return false;
|
|
1380
|
+
}
|
|
1381
|
+
function findFormNameInIR(nodes, name) {
|
|
1382
|
+
const fnPattern = name + '(';
|
|
1383
|
+
for (const node of nodes) {
|
|
1384
|
+
if (node instanceof ComponentCall) {
|
|
1385
|
+
if (node.componentName === name)
|
|
1386
|
+
return true;
|
|
1387
|
+
for (const prop of node.props) {
|
|
1388
|
+
if (prop.value && prop.value.raw && prop.value.raw.includes(fnPattern))
|
|
1389
|
+
return true;
|
|
1390
|
+
}
|
|
1391
|
+
if (findFormNameInIR(node.children, name))
|
|
1392
|
+
return true;
|
|
1393
|
+
}
|
|
1394
|
+
if (node instanceof DynamicBinding && node.expression && node.expression.raw) {
|
|
1395
|
+
if (node.expression.raw.includes(fnPattern))
|
|
1396
|
+
return true;
|
|
1397
|
+
}
|
|
1398
|
+
if (node instanceof RuntimeStatement && node.raw) {
|
|
1399
|
+
if (node.raw.includes(fnPattern))
|
|
1400
|
+
return true;
|
|
1401
|
+
}
|
|
1402
|
+
if (node instanceof StaticNode || node instanceof ServerBlock || node instanceof ClientBlock || node instanceof HeadBlock) {
|
|
1403
|
+
if (findFormNameInIR(node.children, name))
|
|
1404
|
+
return true;
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
return false;
|
|
1408
|
+
}
|
|
1409
|
+
function astHasBinding(ast, names) {
|
|
1410
|
+
if (!ast)
|
|
1411
|
+
return false;
|
|
1412
|
+
let found = false;
|
|
1413
|
+
walk(ast, null, {
|
|
1414
|
+
Identifier(node, context) {
|
|
1415
|
+
if (names.has(node.name))
|
|
1416
|
+
found = true;
|
|
1417
|
+
context.next();
|
|
1418
|
+
},
|
|
1419
|
+
});
|
|
1420
|
+
return found;
|
|
1421
|
+
}
|
|
1422
|
+
function hasKeyedMap(nodes) {
|
|
1423
|
+
for (const node of nodes) {
|
|
1424
|
+
if (node instanceof MapRegion && node.keyExpr)
|
|
1425
|
+
return true;
|
|
1426
|
+
if (node instanceof MapRegion && hasKeyedMap(node.bodyTemplate))
|
|
1427
|
+
return true;
|
|
1428
|
+
if (node instanceof MapRegion && hasKeyedMap(node.alternateNodes))
|
|
1429
|
+
return true;
|
|
1430
|
+
if (node instanceof WhileLoop && hasKeyedMap(node.bodyTemplate))
|
|
1431
|
+
return true;
|
|
1432
|
+
if (node instanceof SwitchBlock) {
|
|
1433
|
+
for (const c of node.cases) {
|
|
1434
|
+
if (hasKeyedMap(c.body))
|
|
1435
|
+
return true;
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
if (node instanceof TryCatch) {
|
|
1439
|
+
if (hasKeyedMap(node.bodyTemplate))
|
|
1440
|
+
return true;
|
|
1441
|
+
if (hasKeyedMap(node.catchBody))
|
|
1442
|
+
return true;
|
|
1443
|
+
}
|
|
1444
|
+
if (node instanceof ForLoop && hasKeyedMap(node.bodyTemplate))
|
|
1445
|
+
return true;
|
|
1446
|
+
if (node instanceof StaticNode && hasKeyedMap(node.children))
|
|
1447
|
+
return true;
|
|
1448
|
+
if (node instanceof ComponentCall && hasKeyedMap(node.children))
|
|
1449
|
+
return true;
|
|
1450
|
+
if (node instanceof OpaqueDynamicRegion) {
|
|
1451
|
+
if (hasKeyedMap(node.consequentNodes))
|
|
1452
|
+
return true;
|
|
1453
|
+
if (hasKeyedMap(node.alternateNodes))
|
|
1454
|
+
return true;
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
return false;
|
|
1458
|
+
}
|
|
1459
|
+
export function escapeHtml(str) {
|
|
1460
|
+
return str
|
|
1461
|
+
.replace(/&/g, '&')
|
|
1462
|
+
.replace(/</g, '<')
|
|
1463
|
+
.replace(/>/g, '>')
|
|
1464
|
+
.replace(/"/g, '"')
|
|
1465
|
+
.replace(/'/g, ''');
|
|
1466
|
+
}
|
|
1467
|
+
export function compileClient(source, _componentName, options = {}) {
|
|
1468
|
+
const ast = parse(source);
|
|
1469
|
+
const ir = generateIR(ast, source);
|
|
1470
|
+
const needsClient = ir.components.some((c) => c.isClient || !isStaticComponent(c));
|
|
1471
|
+
if (!options.forceClient && !needsClient) {
|
|
1472
|
+
return '';
|
|
1473
|
+
}
|
|
1474
|
+
const componentMapCode = buildComponentMap(ir, options.hydrate);
|
|
1475
|
+
const importLines = ir.imports.length > 0 ? ir.imports.join('\n') + '\n' : '';
|
|
1476
|
+
const topCode = (options.includeTopLevel === false ? [] : transformTopLevelForActions(ir.topLevelCode, 'client')).join('\n') + '\n';
|
|
1477
|
+
const exportLines = [];
|
|
1478
|
+
for (const comp of ir.components) {
|
|
1479
|
+
if (comp.exported) {
|
|
1480
|
+
if (comp.defaultExport) {
|
|
1481
|
+
exportLines.push(`export default __components[${JSON.stringify(comp.name)}];`);
|
|
1482
|
+
}
|
|
1483
|
+
else {
|
|
1484
|
+
exportLines.push(`export const ${comp.name} = __components[${JSON.stringify(comp.name)}];`);
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
const exportCode = exportLines.join('\n');
|
|
1489
|
+
const runtimeNames = ['track', 'get', 'set', 'destroy_block', 'getActiveComponent', 'setActiveComponent', 'reactiveProps'];
|
|
1490
|
+
if (ir.components.some(c => !isStaticIR(c.body)))
|
|
1491
|
+
runtimeNames.push('effect');
|
|
1492
|
+
for (const name of usedRuntimeBindings(ir))
|
|
1493
|
+
runtimeNames.push(name);
|
|
1494
|
+
for (const name of ['derived']) {
|
|
1495
|
+
if (findBindingInIR(ir.components.flatMap(c => c.body), new Set([name])))
|
|
1496
|
+
runtimeNames.push(name);
|
|
1497
|
+
}
|
|
1498
|
+
if (ir.components.some(c => hasKeyedMap(c.body)))
|
|
1499
|
+
runtimeNames.push('reconcile');
|
|
1500
|
+
if (options.hydrate) {
|
|
1501
|
+
const hydrateNames = ['hydrate', 'hydrateViewport', 'hydrateIdle', 'hydrateOnInteraction', 'needsHydration', 'createHydrateWalker', 'collectVskMarkers', 'reactiveProps'];
|
|
1502
|
+
for (const name of hydrateNames) {
|
|
1503
|
+
if (!runtimeNames.includes(name))
|
|
1504
|
+
runtimeNames.push(name);
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
const formNames = ['Form', 'Field', 'required', 'email', 'minLength', 'maxLength', 'pattern', 'custom'];
|
|
1508
|
+
for (const name of formNames) {
|
|
1509
|
+
if (!runtimeNames.includes(name) && findFormNameInIR(ir.components.flatMap(c => c.body), name)) {
|
|
1510
|
+
runtimeNames.push(name);
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
const runtimeImport = `import { ${runtimeNames.join(', ')} } from '@vesk/runtime';`;
|
|
1514
|
+
const moduleCode = `
|
|
1515
|
+
${runtimeImport}
|
|
1516
|
+
${importLines}
|
|
1517
|
+
${topCode}
|
|
1518
|
+
${componentMapCode}
|
|
1519
|
+
${exportCode}
|
|
1520
|
+
`;
|
|
1521
|
+
return moduleCode.trim();
|
|
1522
|
+
}
|
|
1523
|
+
export { compileClient as compile, isStaticIR };
|