what-compiler 0.10.0 → 0.11.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/dist/babel-plugin.min.js +1 -2
- package/dist/file-router.min.js +0 -1
- package/dist/index.min.js +6 -7
- package/dist/runtime.min.js +0 -1
- package/dist/vite-plugin.min.js +6 -7
- package/package.json +3 -3
- package/src/babel-plugin.js +433 -89
- package/src/vite-plugin.js +75 -5
- package/dist/babel-plugin.js +0 -1576
- package/dist/babel-plugin.js.map +0 -7
- package/dist/babel-plugin.min.js.map +0 -7
- package/dist/file-router.js +0 -271
- package/dist/file-router.js.map +0 -7
- package/dist/file-router.min.js.map +0 -7
- package/dist/index.js +0 -2370
- package/dist/index.js.map +0 -7
- package/dist/index.min.js.map +0 -7
- package/dist/runtime.js +0 -9
- package/dist/runtime.js.map +0 -7
- package/dist/runtime.min.js.map +0 -7
- package/dist/vite-plugin.js +0 -2359
- package/dist/vite-plugin.js.map +0 -7
- package/dist/vite-plugin.min.js.map +0 -7
package/dist/babel-plugin.js
DELETED
|
@@ -1,1576 +0,0 @@
|
|
|
1
|
-
// packages/compiler/src/babel-plugin.js
|
|
2
|
-
var EVENT_MODIFIERS = /* @__PURE__ */ new Set(["preventDefault", "stopPropagation", "once", "capture", "passive", "self"]);
|
|
3
|
-
var EVENT_OPTION_MODIFIERS = /* @__PURE__ */ new Set(["once", "capture", "passive"]);
|
|
4
|
-
var VOID_HTML_ELEMENTS = /* @__PURE__ */ new Set([
|
|
5
|
-
"area",
|
|
6
|
-
"base",
|
|
7
|
-
"br",
|
|
8
|
-
"col",
|
|
9
|
-
"embed",
|
|
10
|
-
"hr",
|
|
11
|
-
"img",
|
|
12
|
-
"input",
|
|
13
|
-
"link",
|
|
14
|
-
"meta",
|
|
15
|
-
"param",
|
|
16
|
-
"source",
|
|
17
|
-
"track",
|
|
18
|
-
"wbr"
|
|
19
|
-
]);
|
|
20
|
-
var DELEGATED_EVENTS = /* @__PURE__ */ new Set([
|
|
21
|
-
"click",
|
|
22
|
-
"input",
|
|
23
|
-
"change",
|
|
24
|
-
"keydown",
|
|
25
|
-
"keyup",
|
|
26
|
-
"submit",
|
|
27
|
-
"focusin",
|
|
28
|
-
"focusout",
|
|
29
|
-
"mousedown",
|
|
30
|
-
"mouseup"
|
|
31
|
-
]);
|
|
32
|
-
var SAFE_GLOBAL_CALLS = /* @__PURE__ */ new Set([
|
|
33
|
-
"Math",
|
|
34
|
-
"Number",
|
|
35
|
-
"String",
|
|
36
|
-
"Boolean",
|
|
37
|
-
"parseInt",
|
|
38
|
-
"parseFloat",
|
|
39
|
-
"isNaN",
|
|
40
|
-
"isFinite",
|
|
41
|
-
"encodeURIComponent",
|
|
42
|
-
"decodeURIComponent",
|
|
43
|
-
"encodeURI",
|
|
44
|
-
"decodeURI",
|
|
45
|
-
"JSON",
|
|
46
|
-
"Date",
|
|
47
|
-
"Array",
|
|
48
|
-
"Object",
|
|
49
|
-
"console",
|
|
50
|
-
"RegExp"
|
|
51
|
-
]);
|
|
52
|
-
var SIGNAL_CREATORS = /* @__PURE__ */ new Set([
|
|
53
|
-
"useSignal",
|
|
54
|
-
"signal",
|
|
55
|
-
"computed",
|
|
56
|
-
"useComputed",
|
|
57
|
-
"useState",
|
|
58
|
-
"useReducer",
|
|
59
|
-
"createResource",
|
|
60
|
-
"useSWR",
|
|
61
|
-
"useQuery",
|
|
62
|
-
"useInfiniteQuery"
|
|
63
|
-
]);
|
|
64
|
-
function normalizeJsxText(value) {
|
|
65
|
-
if (!/[\r\n]/.test(value)) {
|
|
66
|
-
return value.replace(/\t/g, " ");
|
|
67
|
-
}
|
|
68
|
-
const lines = value.split(/\r\n|\n|\r/);
|
|
69
|
-
let lastNonEmpty = -1;
|
|
70
|
-
for (let i = 0; i < lines.length; i++) {
|
|
71
|
-
if (/[^ \t]/.test(lines[i])) lastNonEmpty = i;
|
|
72
|
-
}
|
|
73
|
-
if (lastNonEmpty === -1) return "";
|
|
74
|
-
let out = "";
|
|
75
|
-
for (let i = 0; i < lines.length; i++) {
|
|
76
|
-
let line = lines[i].replace(/\t/g, " ");
|
|
77
|
-
const isFirst = i === 0;
|
|
78
|
-
const isLast = i === lines.length - 1;
|
|
79
|
-
if (!isFirst) line = line.replace(/^ +/, "");
|
|
80
|
-
if (!isLast) line = line.replace(/ +$/, "");
|
|
81
|
-
if (!line) continue;
|
|
82
|
-
if (i !== lastNonEmpty) line += " ";
|
|
83
|
-
out += line;
|
|
84
|
-
}
|
|
85
|
-
return out;
|
|
86
|
-
}
|
|
87
|
-
function whatBabelPlugin({ types: t }) {
|
|
88
|
-
const _unknownModifierWarned = /* @__PURE__ */ new Set();
|
|
89
|
-
const _forInfoWarned = /* @__PURE__ */ new Set();
|
|
90
|
-
function hasEventModifiers(name, state) {
|
|
91
|
-
if (!name.includes("__")) return false;
|
|
92
|
-
if (!name.startsWith("on")) return false;
|
|
93
|
-
const parts = name.split("__");
|
|
94
|
-
const tail = parts.slice(1).filter((s) => s !== "");
|
|
95
|
-
if (tail.length === 0) return false;
|
|
96
|
-
if (true) {
|
|
97
|
-
const unknown = tail.filter((m) => !EVENT_MODIFIERS.has(m));
|
|
98
|
-
const filename = state && (state.filename || state.file && state.file.opts && state.file.opts.filename) || "<unknown>";
|
|
99
|
-
for (const m of unknown) {
|
|
100
|
-
const key = `${filename}::${m}`;
|
|
101
|
-
if (!_unknownModifierWarned.has(key)) {
|
|
102
|
-
_unknownModifierWarned.add(key);
|
|
103
|
-
console.warn(
|
|
104
|
-
`[what-compiler] Unknown event modifier "__${m}" in attribute "${name}" (${filename}). Known modifiers: ${[...EVENT_MODIFIERS].join(", ")}. Unknown segments are ignored.`
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return true;
|
|
110
|
-
}
|
|
111
|
-
function parseEventModifiers(name) {
|
|
112
|
-
const delimiter = name.includes("|") ? "|" : "__";
|
|
113
|
-
const parts = name.split(delimiter);
|
|
114
|
-
const eventName = parts[0];
|
|
115
|
-
const modifiers = parts.slice(1).filter((m) => EVENT_MODIFIERS.has(m));
|
|
116
|
-
return { eventName, modifiers };
|
|
117
|
-
}
|
|
118
|
-
function isBindingAttribute(name) {
|
|
119
|
-
return name.startsWith("bind:");
|
|
120
|
-
}
|
|
121
|
-
function getBindingProperty(name) {
|
|
122
|
-
return name.slice(5);
|
|
123
|
-
}
|
|
124
|
-
function isComponent(name) {
|
|
125
|
-
return /^[A-Z]/.test(name);
|
|
126
|
-
}
|
|
127
|
-
function isVoidHtmlElement(name) {
|
|
128
|
-
return VOID_HTML_ELEMENTS.has(String(name).toLowerCase());
|
|
129
|
-
}
|
|
130
|
-
function getAttributeValue(value) {
|
|
131
|
-
if (!value) return t.booleanLiteral(true);
|
|
132
|
-
if (t.isJSXExpressionContainer(value)) return value.expression;
|
|
133
|
-
if (t.isStringLiteral(value)) return value;
|
|
134
|
-
return t.stringLiteral(value.value || "");
|
|
135
|
-
}
|
|
136
|
-
function normalizeAttrName(attrName) {
|
|
137
|
-
if (attrName === "className") return "class";
|
|
138
|
-
if (attrName === "htmlFor") return "for";
|
|
139
|
-
return attrName;
|
|
140
|
-
}
|
|
141
|
-
function getAttrName(attr) {
|
|
142
|
-
if (t.isJSXNamespacedName(attr.name)) {
|
|
143
|
-
return `${attr.name.namespace.name}:${attr.name.name.name}`;
|
|
144
|
-
}
|
|
145
|
-
return typeof attr.name.name === "string" ? attr.name.name : String(attr.name.name);
|
|
146
|
-
}
|
|
147
|
-
function createEventHandler(handler, modifiers) {
|
|
148
|
-
if (modifiers.length === 0) return handler;
|
|
149
|
-
let wrappedHandler = handler;
|
|
150
|
-
for (const mod of modifiers) {
|
|
151
|
-
switch (mod) {
|
|
152
|
-
case "preventDefault":
|
|
153
|
-
wrappedHandler = t.arrowFunctionExpression(
|
|
154
|
-
[t.identifier("e")],
|
|
155
|
-
t.blockStatement([
|
|
156
|
-
t.expressionStatement(
|
|
157
|
-
t.callExpression(
|
|
158
|
-
t.memberExpression(t.identifier("e"), t.identifier("preventDefault")),
|
|
159
|
-
[]
|
|
160
|
-
)
|
|
161
|
-
),
|
|
162
|
-
t.expressionStatement(
|
|
163
|
-
t.callExpression(wrappedHandler, [t.identifier("e")])
|
|
164
|
-
)
|
|
165
|
-
])
|
|
166
|
-
);
|
|
167
|
-
break;
|
|
168
|
-
case "stopPropagation":
|
|
169
|
-
wrappedHandler = t.arrowFunctionExpression(
|
|
170
|
-
[t.identifier("e")],
|
|
171
|
-
t.blockStatement([
|
|
172
|
-
t.expressionStatement(
|
|
173
|
-
t.callExpression(
|
|
174
|
-
t.memberExpression(t.identifier("e"), t.identifier("stopPropagation")),
|
|
175
|
-
[]
|
|
176
|
-
)
|
|
177
|
-
),
|
|
178
|
-
t.expressionStatement(
|
|
179
|
-
t.callExpression(wrappedHandler, [t.identifier("e")])
|
|
180
|
-
)
|
|
181
|
-
])
|
|
182
|
-
);
|
|
183
|
-
break;
|
|
184
|
-
case "self":
|
|
185
|
-
wrappedHandler = t.arrowFunctionExpression(
|
|
186
|
-
[t.identifier("e")],
|
|
187
|
-
t.blockStatement([
|
|
188
|
-
t.ifStatement(
|
|
189
|
-
t.binaryExpression(
|
|
190
|
-
"===",
|
|
191
|
-
t.memberExpression(t.identifier("e"), t.identifier("target")),
|
|
192
|
-
t.memberExpression(t.identifier("e"), t.identifier("currentTarget"))
|
|
193
|
-
),
|
|
194
|
-
t.expressionStatement(
|
|
195
|
-
t.callExpression(wrappedHandler, [t.identifier("e")])
|
|
196
|
-
)
|
|
197
|
-
)
|
|
198
|
-
])
|
|
199
|
-
);
|
|
200
|
-
break;
|
|
201
|
-
case "once":
|
|
202
|
-
case "capture":
|
|
203
|
-
case "passive":
|
|
204
|
-
break;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
return wrappedHandler;
|
|
208
|
-
}
|
|
209
|
-
function isSignalIdentifier(name, signalNames) {
|
|
210
|
-
return signalNames.has(name);
|
|
211
|
-
}
|
|
212
|
-
function collectSignalNamesFromScope(path) {
|
|
213
|
-
const signalNames = /* @__PURE__ */ new Set();
|
|
214
|
-
function extractFromDeclarator(decl) {
|
|
215
|
-
const init = decl.init;
|
|
216
|
-
if (!init || !t.isCallExpression(init)) return;
|
|
217
|
-
const callee = init.callee;
|
|
218
|
-
let calleeName = "";
|
|
219
|
-
if (t.isIdentifier(callee)) {
|
|
220
|
-
calleeName = callee.name;
|
|
221
|
-
} else if (t.isMemberExpression(callee) && t.isIdentifier(callee.property)) {
|
|
222
|
-
calleeName = callee.property.name;
|
|
223
|
-
}
|
|
224
|
-
if (SIGNAL_CREATORS.has(calleeName)) {
|
|
225
|
-
const id = decl.id;
|
|
226
|
-
if (t.isIdentifier(id)) {
|
|
227
|
-
signalNames.add(id.name);
|
|
228
|
-
} else if (t.isArrayPattern(id)) {
|
|
229
|
-
for (const el of id.elements) {
|
|
230
|
-
if (t.isIdentifier(el)) signalNames.add(el.name);
|
|
231
|
-
}
|
|
232
|
-
} else if (t.isObjectPattern(id)) {
|
|
233
|
-
for (const prop of id.properties) {
|
|
234
|
-
if (t.isObjectProperty(prop) && t.isIdentifier(prop.value)) {
|
|
235
|
-
signalNames.add(prop.value.name);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
let scope = path.scope;
|
|
242
|
-
while (scope) {
|
|
243
|
-
for (const binding of Object.values(scope.bindings)) {
|
|
244
|
-
if (binding.path.isVariableDeclarator()) {
|
|
245
|
-
extractFromDeclarator(binding.path.node);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
const fnNode = scope.path && scope.path.node;
|
|
249
|
-
if (fnNode && fnNode.params) {
|
|
250
|
-
for (const param of fnNode.params) {
|
|
251
|
-
if (t.isObjectPattern(param)) {
|
|
252
|
-
for (const prop of param.properties) {
|
|
253
|
-
if (t.isObjectProperty(prop) && t.isIdentifier(prop.value)) {
|
|
254
|
-
signalNames.add(prop.value.name);
|
|
255
|
-
} else if (t.isRestElement(prop) && t.isIdentifier(prop.argument)) {
|
|
256
|
-
signalNames.add(prop.argument.name);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
scope = scope.parent;
|
|
263
|
-
}
|
|
264
|
-
return signalNames;
|
|
265
|
-
}
|
|
266
|
-
function collectSignalNames(path) {
|
|
267
|
-
return collectSignalNamesFromScope(path);
|
|
268
|
-
}
|
|
269
|
-
function isSafeGlobalCall(expr) {
|
|
270
|
-
if (!t.isCallExpression(expr)) return false;
|
|
271
|
-
const callee = expr.callee;
|
|
272
|
-
if (t.isMemberExpression(callee) && t.isIdentifier(callee.object)) {
|
|
273
|
-
return SAFE_GLOBAL_CALLS.has(callee.object.name);
|
|
274
|
-
}
|
|
275
|
-
if (t.isIdentifier(callee)) {
|
|
276
|
-
return SAFE_GLOBAL_CALLS.has(callee.name);
|
|
277
|
-
}
|
|
278
|
-
return false;
|
|
279
|
-
}
|
|
280
|
-
function isUncertainReactive(expr, signalNames, importedIds) {
|
|
281
|
-
if (!signalNames) return false;
|
|
282
|
-
if (t.isCallExpression(expr)) {
|
|
283
|
-
if (t.isIdentifier(expr.callee) && isSignalIdentifier(expr.callee.name, signalNames)) {
|
|
284
|
-
return false;
|
|
285
|
-
}
|
|
286
|
-
if (importedIds && t.isIdentifier(expr.callee) && importedIds.has(expr.callee.name) && !SAFE_GLOBAL_CALLS.has(expr.callee.name)) {
|
|
287
|
-
return false;
|
|
288
|
-
}
|
|
289
|
-
if (t.isMemberExpression(expr.callee) && t.isIdentifier(expr.callee.object) && isSignalIdentifier(expr.callee.object.name, signalNames)) {
|
|
290
|
-
return false;
|
|
291
|
-
}
|
|
292
|
-
if (isSafeGlobalCall(expr)) return false;
|
|
293
|
-
if (expr.arguments.some((arg) => isPotentiallyReactive(arg, signalNames, importedIds))) {
|
|
294
|
-
return true;
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
return false;
|
|
298
|
-
}
|
|
299
|
-
function isPotentiallyReactive(expr, signalNames, importedIds) {
|
|
300
|
-
if (!signalNames) signalNames = /* @__PURE__ */ new Set();
|
|
301
|
-
if (t.isCallExpression(expr)) {
|
|
302
|
-
if (t.isIdentifier(expr.callee) && isSignalIdentifier(expr.callee.name, signalNames)) {
|
|
303
|
-
return true;
|
|
304
|
-
}
|
|
305
|
-
if (importedIds && t.isIdentifier(expr.callee) && importedIds.has(expr.callee.name)) {
|
|
306
|
-
if (!SAFE_GLOBAL_CALLS.has(expr.callee.name)) {
|
|
307
|
-
return true;
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
if (t.isMemberExpression(expr.callee)) {
|
|
311
|
-
if (t.isIdentifier(expr.callee.object) && isSignalIdentifier(expr.callee.object.name, signalNames)) {
|
|
312
|
-
return true;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
if (isSafeGlobalCall(expr)) {
|
|
316
|
-
return expr.arguments.some((arg) => isPotentiallyReactive(arg, signalNames, importedIds));
|
|
317
|
-
}
|
|
318
|
-
if (t.isIdentifier(expr.callee)) {
|
|
319
|
-
return expr.arguments.some((arg) => isPotentiallyReactive(arg, signalNames, importedIds));
|
|
320
|
-
}
|
|
321
|
-
return isPotentiallyReactive(expr.callee, signalNames, importedIds) || expr.arguments.some((arg) => isPotentiallyReactive(arg, signalNames, importedIds));
|
|
322
|
-
}
|
|
323
|
-
if (t.isIdentifier(expr)) {
|
|
324
|
-
return isSignalIdentifier(expr.name, signalNames) || importedIds && importedIds.has(expr.name);
|
|
325
|
-
}
|
|
326
|
-
if (t.isMemberExpression(expr)) {
|
|
327
|
-
return isPotentiallyReactive(expr.object, signalNames, importedIds);
|
|
328
|
-
}
|
|
329
|
-
if (t.isConditionalExpression(expr)) {
|
|
330
|
-
return isPotentiallyReactive(expr.test, signalNames, importedIds) || isPotentiallyReactive(expr.consequent, signalNames, importedIds) || isPotentiallyReactive(expr.alternate, signalNames, importedIds);
|
|
331
|
-
}
|
|
332
|
-
if (t.isBinaryExpression(expr) || t.isLogicalExpression(expr)) {
|
|
333
|
-
return isPotentiallyReactive(expr.left, signalNames, importedIds) || isPotentiallyReactive(expr.right, signalNames, importedIds);
|
|
334
|
-
}
|
|
335
|
-
if (t.isUnaryExpression(expr)) {
|
|
336
|
-
return isPotentiallyReactive(expr.argument, signalNames, importedIds);
|
|
337
|
-
}
|
|
338
|
-
if (t.isTemplateLiteral(expr)) {
|
|
339
|
-
return expr.expressions.some((e) => isPotentiallyReactive(e, signalNames, importedIds));
|
|
340
|
-
}
|
|
341
|
-
if (t.isObjectExpression(expr)) {
|
|
342
|
-
return expr.properties.some(
|
|
343
|
-
(prop) => t.isObjectProperty(prop) && isPotentiallyReactive(prop.value, signalNames, importedIds)
|
|
344
|
-
);
|
|
345
|
-
}
|
|
346
|
-
if (t.isArrayExpression(expr)) {
|
|
347
|
-
return expr.elements.some((el) => el && isPotentiallyReactive(el, signalNames, importedIds));
|
|
348
|
-
}
|
|
349
|
-
if (t.isArrowFunctionExpression(expr) || t.isFunctionExpression(expr)) {
|
|
350
|
-
return false;
|
|
351
|
-
}
|
|
352
|
-
return false;
|
|
353
|
-
}
|
|
354
|
-
function tryLowerMapToMapArray(expr, state) {
|
|
355
|
-
let mapCall = expr;
|
|
356
|
-
let wrappedInArrow = false;
|
|
357
|
-
if (t.isArrowFunctionExpression(expr) && expr.params.length === 0) {
|
|
358
|
-
mapCall = expr.body;
|
|
359
|
-
wrappedInArrow = true;
|
|
360
|
-
}
|
|
361
|
-
if (t.isConditionalExpression(mapCall)) {
|
|
362
|
-
const loweredCon = tryLowerMapCall(mapCall.consequent, state);
|
|
363
|
-
const loweredAlt = tryLowerMapCall(mapCall.alternate, state);
|
|
364
|
-
if (loweredCon || loweredAlt) {
|
|
365
|
-
const result = t.conditionalExpression(
|
|
366
|
-
mapCall.test,
|
|
367
|
-
loweredCon || mapCall.consequent,
|
|
368
|
-
loweredAlt || mapCall.alternate
|
|
369
|
-
);
|
|
370
|
-
return wrappedInArrow ? t.arrowFunctionExpression([], result) : result;
|
|
371
|
-
}
|
|
372
|
-
return null;
|
|
373
|
-
}
|
|
374
|
-
if (t.isLogicalExpression(mapCall) && (mapCall.operator === "&&" || mapCall.operator === "||")) {
|
|
375
|
-
const loweredRight = tryLowerMapCall(mapCall.right, state);
|
|
376
|
-
if (loweredRight) {
|
|
377
|
-
const result = t.logicalExpression(mapCall.operator, mapCall.left, loweredRight);
|
|
378
|
-
return wrappedInArrow ? t.arrowFunctionExpression([], result) : result;
|
|
379
|
-
}
|
|
380
|
-
return null;
|
|
381
|
-
}
|
|
382
|
-
const lowered = tryLowerMapCall(mapCall, state);
|
|
383
|
-
return lowered;
|
|
384
|
-
}
|
|
385
|
-
function tryLowerMapCall(mapCall, state) {
|
|
386
|
-
if (!t.isCallExpression(mapCall)) return null;
|
|
387
|
-
if (!t.isMemberExpression(mapCall.callee)) return null;
|
|
388
|
-
if (!t.isIdentifier(mapCall.callee.property, { name: "map" })) return null;
|
|
389
|
-
if (mapCall.arguments.length < 1) return null;
|
|
390
|
-
const mapFn = mapCall.arguments[0];
|
|
391
|
-
if (!t.isArrowFunctionExpression(mapFn) && !t.isFunctionExpression(mapFn)) return null;
|
|
392
|
-
let returnExpr = null;
|
|
393
|
-
if (t.isArrowFunctionExpression(mapFn)) {
|
|
394
|
-
if (t.isExpression(mapFn.body)) {
|
|
395
|
-
returnExpr = mapFn.body;
|
|
396
|
-
} else if (t.isBlockStatement(mapFn.body)) {
|
|
397
|
-
const ret = mapFn.body.body.find((s) => t.isReturnStatement(s));
|
|
398
|
-
if (ret) returnExpr = ret.argument;
|
|
399
|
-
}
|
|
400
|
-
} else if (t.isFunctionExpression(mapFn)) {
|
|
401
|
-
const ret = mapFn.body.body.find((s) => t.isReturnStatement(s));
|
|
402
|
-
if (ret) returnExpr = ret.argument;
|
|
403
|
-
}
|
|
404
|
-
if (!returnExpr) return null;
|
|
405
|
-
if (!t.isJSXElement(returnExpr)) return null;
|
|
406
|
-
const attrs = returnExpr.openingElement.attributes;
|
|
407
|
-
let keyAttr = null;
|
|
408
|
-
for (const attr of attrs) {
|
|
409
|
-
if (t.isJSXAttribute(attr) && getAttrName(attr) === "key") {
|
|
410
|
-
keyAttr = attr;
|
|
411
|
-
break;
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
if (!keyAttr) {
|
|
415
|
-
if (true) {
|
|
416
|
-
const loc = returnExpr.loc;
|
|
417
|
-
const fileName = state.filename || state.file?.opts?.filename || "<unknown>";
|
|
418
|
-
const lineInfo = loc ? `:${loc.start.line}:${loc.start.column}` : "";
|
|
419
|
-
console.warn(
|
|
420
|
-
`[what-compiler] .map() returning JSX without a \`key\` prop at ${fileName}${lineInfo}. Without a key, the list cannot use keyed reconciliation \u2014 items are re-created on every update. Add key={...} to enable efficient updates.`
|
|
421
|
-
);
|
|
422
|
-
}
|
|
423
|
-
return null;
|
|
424
|
-
}
|
|
425
|
-
const keyValue = getAttributeValue(keyAttr.value);
|
|
426
|
-
if (!keyValue) return null;
|
|
427
|
-
returnExpr.openingElement.attributes = attrs.filter((a) => a !== keyAttr);
|
|
428
|
-
const sourceObj = mapCall.callee.object;
|
|
429
|
-
const source = t.arrowFunctionExpression([], sourceObj);
|
|
430
|
-
const itemParam = mapFn.params[0] ? t.cloneNode(mapFn.params[0], true) : t.identifier("_item");
|
|
431
|
-
const keyFn = t.arrowFunctionExpression([itemParam], t.cloneNode(keyValue, true));
|
|
432
|
-
return t.callExpression(t.identifier("_$mapArray"), [
|
|
433
|
-
source,
|
|
434
|
-
mapFn,
|
|
435
|
-
t.objectExpression([
|
|
436
|
-
t.objectProperty(t.identifier("key"), keyFn),
|
|
437
|
-
t.objectProperty(t.identifier("raw"), t.booleanLiteral(true))
|
|
438
|
-
])
|
|
439
|
-
]);
|
|
440
|
-
}
|
|
441
|
-
function isStaticChild(child) {
|
|
442
|
-
if (t.isJSXText(child)) return true;
|
|
443
|
-
if (t.isJSXExpressionContainer(child)) return false;
|
|
444
|
-
if (t.isJSXElement(child)) {
|
|
445
|
-
const el = child.openingElement;
|
|
446
|
-
const tagName = el.name.name;
|
|
447
|
-
if (isComponent(tagName)) return false;
|
|
448
|
-
for (const attr of el.attributes) {
|
|
449
|
-
if (t.isJSXSpreadAttribute(attr)) return false;
|
|
450
|
-
const value = attr.value;
|
|
451
|
-
if (t.isJSXExpressionContainer(value)) return false;
|
|
452
|
-
}
|
|
453
|
-
return child.children.every(isStaticChild);
|
|
454
|
-
}
|
|
455
|
-
return false;
|
|
456
|
-
}
|
|
457
|
-
function isDynamicAttr(attr) {
|
|
458
|
-
if (t.isJSXSpreadAttribute(attr)) return true;
|
|
459
|
-
if (!attr.value) return false;
|
|
460
|
-
return t.isJSXExpressionContainer(attr.value);
|
|
461
|
-
}
|
|
462
|
-
function extractStaticHTML(node) {
|
|
463
|
-
if (t.isJSXText(node)) {
|
|
464
|
-
const text = normalizeJsxText(node.value);
|
|
465
|
-
return text ? escapeHTML(text) : "";
|
|
466
|
-
}
|
|
467
|
-
if (t.isJSXExpressionContainer(node)) {
|
|
468
|
-
if (t.isJSXEmptyExpression(node.expression)) return "";
|
|
469
|
-
return "<!--$-->";
|
|
470
|
-
}
|
|
471
|
-
if (!t.isJSXElement(node)) return "";
|
|
472
|
-
const el = node.openingElement;
|
|
473
|
-
const tagName = el.name.name;
|
|
474
|
-
if (isComponent(tagName)) return "";
|
|
475
|
-
let html = `<${tagName}`;
|
|
476
|
-
for (const attr of el.attributes) {
|
|
477
|
-
if (t.isJSXSpreadAttribute(attr)) continue;
|
|
478
|
-
const name = getAttrName(attr);
|
|
479
|
-
if (name === "key") continue;
|
|
480
|
-
if (name.startsWith("on") || name.startsWith("bind:") || name.includes("|")) continue;
|
|
481
|
-
let domName = name;
|
|
482
|
-
if (name === "className") domName = "class";
|
|
483
|
-
if (name === "htmlFor") domName = "for";
|
|
484
|
-
if (!attr.value) {
|
|
485
|
-
html += ` ${domName}`;
|
|
486
|
-
} else if (t.isStringLiteral(attr.value)) {
|
|
487
|
-
html += ` ${domName}="${escapeAttr(attr.value.value)}"`;
|
|
488
|
-
} else if (t.isJSXExpressionContainer(attr.value)) {
|
|
489
|
-
continue;
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
const selfClosing = node.openingElement.selfClosing;
|
|
493
|
-
if (selfClosing && isVoidHtmlElement(tagName)) {
|
|
494
|
-
html += ">";
|
|
495
|
-
return html;
|
|
496
|
-
}
|
|
497
|
-
if (selfClosing) {
|
|
498
|
-
html += `></${tagName}>`;
|
|
499
|
-
return html;
|
|
500
|
-
}
|
|
501
|
-
html += ">";
|
|
502
|
-
for (const child of node.children) {
|
|
503
|
-
if (t.isJSXText(child)) {
|
|
504
|
-
const text = normalizeJsxText(child.value);
|
|
505
|
-
if (text) html += escapeHTML(text);
|
|
506
|
-
} else if (t.isJSXExpressionContainer(child)) {
|
|
507
|
-
if (!t.isJSXEmptyExpression(child.expression)) {
|
|
508
|
-
html += "<!--$-->";
|
|
509
|
-
}
|
|
510
|
-
} else if (t.isJSXElement(child)) {
|
|
511
|
-
if (isComponent(child.openingElement.name.name)) {
|
|
512
|
-
html += "<!--$-->";
|
|
513
|
-
} else {
|
|
514
|
-
html += extractStaticHTML(child);
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
html += `</${tagName}>`;
|
|
519
|
-
return html;
|
|
520
|
-
}
|
|
521
|
-
function escapeHTML(str) {
|
|
522
|
-
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
523
|
-
}
|
|
524
|
-
function escapeAttr(str) {
|
|
525
|
-
return str.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
526
|
-
}
|
|
527
|
-
function transformElementFineGrained(path, state) {
|
|
528
|
-
const { node } = path;
|
|
529
|
-
const openingElement = node.openingElement;
|
|
530
|
-
const tagName = openingElement.name.name;
|
|
531
|
-
if (tagName === "For") {
|
|
532
|
-
return transformForFineGrained(path, state);
|
|
533
|
-
}
|
|
534
|
-
if (tagName === "Show") {
|
|
535
|
-
return transformShowFineGrained(path, state);
|
|
536
|
-
}
|
|
537
|
-
if (isComponent(tagName)) {
|
|
538
|
-
return transformComponentFineGrained(path, state);
|
|
539
|
-
}
|
|
540
|
-
const attributes = openingElement.attributes;
|
|
541
|
-
const children = node.children;
|
|
542
|
-
const allChildrenStatic = children.every(isStaticChild);
|
|
543
|
-
const allAttrsStatic = attributes.every((attr) => !isDynamicAttr(attr));
|
|
544
|
-
const noEvents = attributes.every((attr) => {
|
|
545
|
-
if (t.isJSXSpreadAttribute(attr)) return false;
|
|
546
|
-
const name = getAttrName(attr);
|
|
547
|
-
return !name?.startsWith("on") && !name?.startsWith("bind:");
|
|
548
|
-
});
|
|
549
|
-
if (allChildrenStatic && allAttrsStatic && noEvents) {
|
|
550
|
-
const html2 = extractStaticHTML(node);
|
|
551
|
-
if (html2) {
|
|
552
|
-
const tmplId2 = getOrCreateTemplate(state, html2);
|
|
553
|
-
state.needsTemplate = true;
|
|
554
|
-
return t.callExpression(t.identifier(tmplId2), []);
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
const html = extractStaticHTML(node);
|
|
558
|
-
if (!html) {
|
|
559
|
-
const loc = node.loc;
|
|
560
|
-
const fileName = state.filename || state.file?.opts?.filename || "<unknown>";
|
|
561
|
-
const lineInfo = loc ? `:${loc.start.line}:${loc.start.column}` : "";
|
|
562
|
-
console.warn(
|
|
563
|
-
`[what-compiler] Could not extract template for <${tagName}> at ${fileName}${lineInfo}. Falling back to h() for this element. This element could not be statically analyzed. Consider simplifying the JSX.`
|
|
564
|
-
);
|
|
565
|
-
state.needsH = true;
|
|
566
|
-
return transformElementAsH(path, state);
|
|
567
|
-
}
|
|
568
|
-
const tmplId = getOrCreateTemplate(state, html);
|
|
569
|
-
state.needsTemplate = true;
|
|
570
|
-
const elId = state.nextVarId();
|
|
571
|
-
const statements = [
|
|
572
|
-
t.variableDeclaration("const", [
|
|
573
|
-
t.variableDeclarator(t.identifier(elId), t.callExpression(t.identifier(tmplId), []))
|
|
574
|
-
])
|
|
575
|
-
];
|
|
576
|
-
applyDynamicAttrs(statements, elId, attributes, state);
|
|
577
|
-
applyDynamicChildren(statements, elId, children, node, state);
|
|
578
|
-
if (!state._pendingSetup) state._pendingSetup = [];
|
|
579
|
-
state._pendingSetup.push(...statements);
|
|
580
|
-
return t.identifier(elId);
|
|
581
|
-
}
|
|
582
|
-
function transformElementAsH(path, state) {
|
|
583
|
-
const { node } = path;
|
|
584
|
-
const openingElement = node.openingElement;
|
|
585
|
-
const tagName = openingElement.name.name;
|
|
586
|
-
const attributes = openingElement.attributes;
|
|
587
|
-
const children = node.children;
|
|
588
|
-
const props = [];
|
|
589
|
-
for (const attr of attributes) {
|
|
590
|
-
if (t.isJSXSpreadAttribute(attr)) continue;
|
|
591
|
-
const attrName = getAttrName(attr);
|
|
592
|
-
const value = getAttributeValue(attr.value);
|
|
593
|
-
let domAttrName = normalizeAttrName(attrName);
|
|
594
|
-
props.push(
|
|
595
|
-
t.objectProperty(
|
|
596
|
-
/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(domAttrName) ? t.identifier(domAttrName) : t.stringLiteral(domAttrName),
|
|
597
|
-
value
|
|
598
|
-
)
|
|
599
|
-
);
|
|
600
|
-
}
|
|
601
|
-
const transformedChildren = [];
|
|
602
|
-
for (const child of children) {
|
|
603
|
-
if (t.isJSXText(child)) {
|
|
604
|
-
const text = normalizeJsxText(child.value);
|
|
605
|
-
if (text) transformedChildren.push(t.stringLiteral(text));
|
|
606
|
-
} else if (t.isJSXExpressionContainer(child)) {
|
|
607
|
-
if (!t.isJSXEmptyExpression(child.expression)) {
|
|
608
|
-
transformedChildren.push(child.expression);
|
|
609
|
-
}
|
|
610
|
-
} else if (t.isJSXElement(child)) {
|
|
611
|
-
transformedChildren.push(transformElementFineGrained({ node: child }, state));
|
|
612
|
-
} else if (t.isJSXFragment(child)) {
|
|
613
|
-
transformedChildren.push(transformFragmentFineGrained({ node: child }, state));
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
const propsExpr = props.length > 0 ? t.objectExpression(props) : t.nullLiteral();
|
|
617
|
-
return t.callExpression(t.identifier("h"), [t.stringLiteral(tagName), propsExpr, ...transformedChildren]);
|
|
618
|
-
}
|
|
619
|
-
function applyDynamicAttrs(statements, elId, attributes, state) {
|
|
620
|
-
function buildSetPropCall(propName, valueExpr) {
|
|
621
|
-
state.needsSetProp = true;
|
|
622
|
-
return t.callExpression(t.identifier("_$setProp"), [
|
|
623
|
-
t.identifier(elId),
|
|
624
|
-
t.stringLiteral(propName),
|
|
625
|
-
valueExpr
|
|
626
|
-
]);
|
|
627
|
-
}
|
|
628
|
-
for (const attr of attributes) {
|
|
629
|
-
if (t.isJSXSpreadAttribute(attr)) {
|
|
630
|
-
state.needsSpread = true;
|
|
631
|
-
statements.push(
|
|
632
|
-
t.expressionStatement(
|
|
633
|
-
t.callExpression(t.identifier("_$spread"), [t.identifier(elId), attr.argument])
|
|
634
|
-
)
|
|
635
|
-
);
|
|
636
|
-
continue;
|
|
637
|
-
}
|
|
638
|
-
const attrName = getAttrName(attr);
|
|
639
|
-
if (attrName === "key") continue;
|
|
640
|
-
if (attrName === "ref") {
|
|
641
|
-
const refExpr = getAttributeValue(attr.value);
|
|
642
|
-
statements.push(
|
|
643
|
-
t.expressionStatement(
|
|
644
|
-
t.conditionalExpression(
|
|
645
|
-
t.binaryExpression(
|
|
646
|
-
"===",
|
|
647
|
-
t.unaryExpression("typeof", refExpr),
|
|
648
|
-
t.stringLiteral("function")
|
|
649
|
-
),
|
|
650
|
-
t.callExpression(t.cloneNode(refExpr), [t.identifier(elId)]),
|
|
651
|
-
t.assignmentExpression(
|
|
652
|
-
"=",
|
|
653
|
-
t.memberExpression(t.cloneNode(refExpr), t.identifier("current")),
|
|
654
|
-
t.identifier(elId)
|
|
655
|
-
)
|
|
656
|
-
)
|
|
657
|
-
)
|
|
658
|
-
);
|
|
659
|
-
continue;
|
|
660
|
-
}
|
|
661
|
-
if (attrName.startsWith("on") && !attrName.includes("|") && !hasEventModifiers(attrName, state)) {
|
|
662
|
-
const event = attrName.slice(2).toLowerCase();
|
|
663
|
-
const handler = getAttributeValue(attr.value);
|
|
664
|
-
if (DELEGATED_EVENTS.has(event)) {
|
|
665
|
-
state.needsDelegation = true;
|
|
666
|
-
if (!state.delegatedEvents) state.delegatedEvents = /* @__PURE__ */ new Set();
|
|
667
|
-
state.delegatedEvents.add(event);
|
|
668
|
-
statements.push(
|
|
669
|
-
t.expressionStatement(
|
|
670
|
-
t.assignmentExpression(
|
|
671
|
-
"=",
|
|
672
|
-
t.memberExpression(
|
|
673
|
-
t.identifier(elId),
|
|
674
|
-
t.identifier(`$$${event}`)
|
|
675
|
-
),
|
|
676
|
-
handler
|
|
677
|
-
)
|
|
678
|
-
)
|
|
679
|
-
);
|
|
680
|
-
} else {
|
|
681
|
-
statements.push(
|
|
682
|
-
t.expressionStatement(
|
|
683
|
-
t.callExpression(
|
|
684
|
-
t.memberExpression(t.identifier(elId), t.identifier("addEventListener")),
|
|
685
|
-
[t.stringLiteral(event), handler]
|
|
686
|
-
)
|
|
687
|
-
)
|
|
688
|
-
);
|
|
689
|
-
}
|
|
690
|
-
continue;
|
|
691
|
-
}
|
|
692
|
-
if (attrName.startsWith("on") && (attrName.includes("|") || hasEventModifiers(attrName, state))) {
|
|
693
|
-
const { eventName, modifiers } = parseEventModifiers(attrName);
|
|
694
|
-
const handler = getAttributeValue(attr.value);
|
|
695
|
-
const wrappedHandler = createEventHandler(handler, modifiers);
|
|
696
|
-
const event = eventName.slice(2).toLowerCase();
|
|
697
|
-
const optionMods = modifiers.filter((m) => EVENT_OPTION_MODIFIERS.has(m));
|
|
698
|
-
const addEventArgs = [t.stringLiteral(event), wrappedHandler];
|
|
699
|
-
if (optionMods.length > 0) {
|
|
700
|
-
const optsProps = optionMods.map(
|
|
701
|
-
(m) => t.objectProperty(t.identifier(m), t.booleanLiteral(true))
|
|
702
|
-
);
|
|
703
|
-
addEventArgs.push(t.objectExpression(optsProps));
|
|
704
|
-
}
|
|
705
|
-
statements.push(
|
|
706
|
-
t.expressionStatement(
|
|
707
|
-
t.callExpression(
|
|
708
|
-
t.memberExpression(t.identifier(elId), t.identifier("addEventListener")),
|
|
709
|
-
addEventArgs
|
|
710
|
-
)
|
|
711
|
-
)
|
|
712
|
-
);
|
|
713
|
-
continue;
|
|
714
|
-
}
|
|
715
|
-
if (isBindingAttribute(attrName)) {
|
|
716
|
-
const bindProp = getBindingProperty(attrName);
|
|
717
|
-
const signalExpr = attr.value.expression;
|
|
718
|
-
state.needsEffect = true;
|
|
719
|
-
if (bindProp === "value") {
|
|
720
|
-
statements.push(
|
|
721
|
-
t.expressionStatement(
|
|
722
|
-
t.callExpression(t.identifier("_$effect"), [
|
|
723
|
-
t.arrowFunctionExpression([], t.assignmentExpression(
|
|
724
|
-
"=",
|
|
725
|
-
t.memberExpression(t.identifier(elId), t.identifier("value")),
|
|
726
|
-
t.callExpression(t.cloneNode(signalExpr), [])
|
|
727
|
-
))
|
|
728
|
-
])
|
|
729
|
-
)
|
|
730
|
-
);
|
|
731
|
-
statements.push(
|
|
732
|
-
t.expressionStatement(
|
|
733
|
-
t.callExpression(
|
|
734
|
-
t.memberExpression(t.identifier(elId), t.identifier("addEventListener")),
|
|
735
|
-
[
|
|
736
|
-
t.stringLiteral("input"),
|
|
737
|
-
t.arrowFunctionExpression(
|
|
738
|
-
[t.identifier("e")],
|
|
739
|
-
t.callExpression(
|
|
740
|
-
t.memberExpression(t.cloneNode(signalExpr), t.identifier("set")),
|
|
741
|
-
[t.memberExpression(
|
|
742
|
-
t.memberExpression(t.identifier("e"), t.identifier("target")),
|
|
743
|
-
t.identifier("value")
|
|
744
|
-
)]
|
|
745
|
-
)
|
|
746
|
-
)
|
|
747
|
-
]
|
|
748
|
-
)
|
|
749
|
-
)
|
|
750
|
-
);
|
|
751
|
-
} else if (bindProp === "checked") {
|
|
752
|
-
state.needsEffect = true;
|
|
753
|
-
statements.push(
|
|
754
|
-
t.expressionStatement(
|
|
755
|
-
t.callExpression(t.identifier("_$effect"), [
|
|
756
|
-
t.arrowFunctionExpression([], t.assignmentExpression(
|
|
757
|
-
"=",
|
|
758
|
-
t.memberExpression(t.identifier(elId), t.identifier("checked")),
|
|
759
|
-
t.callExpression(t.cloneNode(signalExpr), [])
|
|
760
|
-
))
|
|
761
|
-
])
|
|
762
|
-
)
|
|
763
|
-
);
|
|
764
|
-
statements.push(
|
|
765
|
-
t.expressionStatement(
|
|
766
|
-
t.callExpression(
|
|
767
|
-
t.memberExpression(t.identifier(elId), t.identifier("addEventListener")),
|
|
768
|
-
[
|
|
769
|
-
t.stringLiteral("change"),
|
|
770
|
-
t.arrowFunctionExpression(
|
|
771
|
-
[t.identifier("e")],
|
|
772
|
-
t.callExpression(
|
|
773
|
-
t.memberExpression(t.cloneNode(signalExpr), t.identifier("set")),
|
|
774
|
-
[t.memberExpression(
|
|
775
|
-
t.memberExpression(t.identifier("e"), t.identifier("target")),
|
|
776
|
-
t.identifier("checked")
|
|
777
|
-
)]
|
|
778
|
-
)
|
|
779
|
-
)
|
|
780
|
-
]
|
|
781
|
-
)
|
|
782
|
-
)
|
|
783
|
-
);
|
|
784
|
-
}
|
|
785
|
-
continue;
|
|
786
|
-
}
|
|
787
|
-
if (t.isJSXExpressionContainer(attr.value)) {
|
|
788
|
-
const expr = attr.value.expression;
|
|
789
|
-
const domName = normalizeAttrName(attrName);
|
|
790
|
-
if (isPotentiallyReactive(expr, state.signalNames, state.importedIdentifiers)) {
|
|
791
|
-
state.needsEffect = true;
|
|
792
|
-
const valueExpr = t.isIdentifier(expr) && (isSignalIdentifier(expr.name, state.signalNames) || state.importedIdentifiers && state.importedIdentifiers.has(expr.name)) ? t.callExpression(expr, []) : expr;
|
|
793
|
-
const effectCall = t.callExpression(t.identifier("_$effect"), [
|
|
794
|
-
t.arrowFunctionExpression([], buildSetPropCall(domName, valueExpr))
|
|
795
|
-
]);
|
|
796
|
-
if (isUncertainReactive(expr, state.signalNames, state.importedIdentifiers)) {
|
|
797
|
-
t.addComment(
|
|
798
|
-
effectCall,
|
|
799
|
-
"leading",
|
|
800
|
-
" @what-dev: effect wrapping may be unnecessary \u2014 expression contains a non-signal function call with reactive args ",
|
|
801
|
-
false
|
|
802
|
-
);
|
|
803
|
-
}
|
|
804
|
-
statements.push(t.expressionStatement(effectCall));
|
|
805
|
-
} else {
|
|
806
|
-
statements.push(t.expressionStatement(buildSetPropCall(domName, expr)));
|
|
807
|
-
}
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
function applyDynamicChildren(statements, elId, children, parentNode, state) {
|
|
812
|
-
const entries = [];
|
|
813
|
-
let childIndex = 0;
|
|
814
|
-
for (const child of children) {
|
|
815
|
-
if (t.isJSXText(child)) {
|
|
816
|
-
const text = normalizeJsxText(child.value);
|
|
817
|
-
if (text) childIndex++;
|
|
818
|
-
continue;
|
|
819
|
-
}
|
|
820
|
-
if (t.isJSXExpressionContainer(child)) {
|
|
821
|
-
if (t.isJSXEmptyExpression(child.expression)) continue;
|
|
822
|
-
entries.push({ type: "expression", child, childIndex });
|
|
823
|
-
childIndex++;
|
|
824
|
-
continue;
|
|
825
|
-
}
|
|
826
|
-
if (t.isJSXElement(child)) {
|
|
827
|
-
const childTag = child.openingElement.name.name;
|
|
828
|
-
if (isComponent(childTag) || childTag === "For" || childTag === "Show") {
|
|
829
|
-
entries.push({ type: "component", child, childIndex });
|
|
830
|
-
childIndex++;
|
|
831
|
-
} else {
|
|
832
|
-
const hasAnythingDynamic = child.openingElement.attributes.some(isDynamicAttr) || child.openingElement.attributes.some((a) => !t.isJSXSpreadAttribute(a) && getAttrName(a)?.startsWith("on")) || !child.children.every(isStaticChild);
|
|
833
|
-
entries.push({ type: "static", child, childIndex, hasAnythingDynamic });
|
|
834
|
-
childIndex++;
|
|
835
|
-
}
|
|
836
|
-
continue;
|
|
837
|
-
}
|
|
838
|
-
if (t.isJSXFragment(child)) {
|
|
839
|
-
entries.push({ type: "fragment", child });
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
const entriesNeedingRef = entries.filter(
|
|
843
|
-
(e) => e.type === "expression" || e.type === "component" || e.type === "static" && e.hasAnythingDynamic
|
|
844
|
-
);
|
|
845
|
-
const needsPreCapture = entriesNeedingRef.length >= 2;
|
|
846
|
-
const markerVars = /* @__PURE__ */ new Map();
|
|
847
|
-
if (needsPreCapture) {
|
|
848
|
-
let prevVar = null;
|
|
849
|
-
let prevIndex = 0;
|
|
850
|
-
for (const entry of entriesNeedingRef) {
|
|
851
|
-
const idx = entry.childIndex;
|
|
852
|
-
const markerVar = state.nextVarId();
|
|
853
|
-
markerVars.set(idx, markerVar);
|
|
854
|
-
let init;
|
|
855
|
-
if (prevVar === null) {
|
|
856
|
-
init = buildChildAccess(elId, idx);
|
|
857
|
-
} else {
|
|
858
|
-
init = t.identifier(prevVar);
|
|
859
|
-
for (let i = prevIndex; i < idx; i++) {
|
|
860
|
-
init = t.memberExpression(init, t.identifier("nextSibling"));
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
statements.push(
|
|
864
|
-
t.variableDeclaration("const", [
|
|
865
|
-
t.variableDeclarator(t.identifier(markerVar), init)
|
|
866
|
-
])
|
|
867
|
-
);
|
|
868
|
-
prevVar = markerVar;
|
|
869
|
-
prevIndex = idx;
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
function getMarker(idx) {
|
|
873
|
-
if (markerVars.has(idx)) {
|
|
874
|
-
return t.identifier(markerVars.get(idx));
|
|
875
|
-
}
|
|
876
|
-
return buildChildAccess(elId, idx);
|
|
877
|
-
}
|
|
878
|
-
for (const entry of entries) {
|
|
879
|
-
if (entry.type === "expression") {
|
|
880
|
-
let expr = entry.child.expression;
|
|
881
|
-
const marker = getMarker(entry.childIndex);
|
|
882
|
-
state.needsInsert = true;
|
|
883
|
-
const mapResult = tryLowerMapToMapArray(expr, state);
|
|
884
|
-
if (mapResult) {
|
|
885
|
-
state.needsMapArray = true;
|
|
886
|
-
const isBareMapArray = t.isCallExpression(mapResult) && t.isIdentifier(mapResult.callee) && (mapResult.callee.name === "_$mapArray" || mapResult.callee.name === "mapArray");
|
|
887
|
-
const isArrowAlready = t.isArrowFunctionExpression(mapResult);
|
|
888
|
-
const insertArg = isBareMapArray || isArrowAlready ? mapResult : t.arrowFunctionExpression([], mapResult);
|
|
889
|
-
statements.push(
|
|
890
|
-
t.expressionStatement(
|
|
891
|
-
t.callExpression(t.identifier("_$insert"), [
|
|
892
|
-
t.identifier(elId),
|
|
893
|
-
insertArg,
|
|
894
|
-
marker
|
|
895
|
-
])
|
|
896
|
-
)
|
|
897
|
-
);
|
|
898
|
-
continue;
|
|
899
|
-
}
|
|
900
|
-
const isMapArrayCall = t.isCallExpression(expr) && t.isIdentifier(expr.callee) && (expr.callee.name === "mapArray" || expr.callee.name === "_$mapArray");
|
|
901
|
-
if (isMapArrayCall) {
|
|
902
|
-
state.needsMapArray = true;
|
|
903
|
-
if (expr.callee.name === "mapArray") expr.callee.name = "_$mapArray";
|
|
904
|
-
statements.push(
|
|
905
|
-
t.expressionStatement(
|
|
906
|
-
t.callExpression(t.identifier("_$insert"), [
|
|
907
|
-
t.identifier(elId),
|
|
908
|
-
expr,
|
|
909
|
-
marker
|
|
910
|
-
])
|
|
911
|
-
)
|
|
912
|
-
);
|
|
913
|
-
continue;
|
|
914
|
-
}
|
|
915
|
-
if (isPotentiallyReactive(expr, state.signalNames, state.importedIdentifiers)) {
|
|
916
|
-
const insertCall = t.callExpression(t.identifier("_$insert"), [
|
|
917
|
-
t.identifier(elId),
|
|
918
|
-
t.arrowFunctionExpression([], expr),
|
|
919
|
-
marker
|
|
920
|
-
]);
|
|
921
|
-
if (isUncertainReactive(expr, state.signalNames, state.importedIdentifiers)) {
|
|
922
|
-
t.addComment(
|
|
923
|
-
insertCall,
|
|
924
|
-
"leading",
|
|
925
|
-
" @what-dev: reactive wrapping may be unnecessary \u2014 expression contains a non-signal function call with reactive args ",
|
|
926
|
-
false
|
|
927
|
-
);
|
|
928
|
-
}
|
|
929
|
-
statements.push(t.expressionStatement(insertCall));
|
|
930
|
-
} else {
|
|
931
|
-
statements.push(
|
|
932
|
-
t.expressionStatement(
|
|
933
|
-
t.callExpression(t.identifier("_$insert"), [
|
|
934
|
-
t.identifier(elId),
|
|
935
|
-
expr,
|
|
936
|
-
marker
|
|
937
|
-
])
|
|
938
|
-
)
|
|
939
|
-
);
|
|
940
|
-
}
|
|
941
|
-
continue;
|
|
942
|
-
}
|
|
943
|
-
if (entry.type === "component") {
|
|
944
|
-
const transformed = transformElementFineGrained({ node: entry.child }, state);
|
|
945
|
-
const marker = getMarker(entry.childIndex);
|
|
946
|
-
state.needsInsert = true;
|
|
947
|
-
statements.push(
|
|
948
|
-
t.expressionStatement(
|
|
949
|
-
t.callExpression(t.identifier("_$insert"), [
|
|
950
|
-
t.identifier(elId),
|
|
951
|
-
transformed,
|
|
952
|
-
marker
|
|
953
|
-
])
|
|
954
|
-
)
|
|
955
|
-
);
|
|
956
|
-
continue;
|
|
957
|
-
}
|
|
958
|
-
if (entry.type === "static" && entry.hasAnythingDynamic) {
|
|
959
|
-
let childElRef;
|
|
960
|
-
if (markerVars.has(entry.childIndex)) {
|
|
961
|
-
childElRef = markerVars.get(entry.childIndex);
|
|
962
|
-
} else {
|
|
963
|
-
childElRef = state.nextVarId();
|
|
964
|
-
statements.push(
|
|
965
|
-
t.variableDeclaration("const", [
|
|
966
|
-
t.variableDeclarator(
|
|
967
|
-
t.identifier(childElRef),
|
|
968
|
-
buildChildAccess(elId, entry.childIndex)
|
|
969
|
-
)
|
|
970
|
-
])
|
|
971
|
-
);
|
|
972
|
-
}
|
|
973
|
-
applyDynamicAttrs(statements, childElRef, entry.child.openingElement.attributes, state);
|
|
974
|
-
applyDynamicChildren(statements, childElRef, entry.child.children, entry.child, state);
|
|
975
|
-
continue;
|
|
976
|
-
}
|
|
977
|
-
if (entry.type === "fragment") {
|
|
978
|
-
for (const fChild of entry.child.children) {
|
|
979
|
-
if (t.isJSXExpressionContainer(fChild) && !t.isJSXEmptyExpression(fChild.expression)) {
|
|
980
|
-
state.needsInsert = true;
|
|
981
|
-
const expr = fChild.expression;
|
|
982
|
-
if (isPotentiallyReactive(expr, state.signalNames, state.importedIdentifiers)) {
|
|
983
|
-
statements.push(
|
|
984
|
-
t.expressionStatement(
|
|
985
|
-
t.callExpression(t.identifier("_$insert"), [
|
|
986
|
-
t.identifier(elId),
|
|
987
|
-
t.arrowFunctionExpression([], expr)
|
|
988
|
-
])
|
|
989
|
-
)
|
|
990
|
-
);
|
|
991
|
-
} else {
|
|
992
|
-
statements.push(
|
|
993
|
-
t.expressionStatement(
|
|
994
|
-
t.callExpression(t.identifier("_$insert"), [
|
|
995
|
-
t.identifier(elId),
|
|
996
|
-
expr
|
|
997
|
-
])
|
|
998
|
-
)
|
|
999
|
-
);
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
1006
|
-
function buildChildAccess(elId, index) {
|
|
1007
|
-
if (index === 0) {
|
|
1008
|
-
return t.memberExpression(t.identifier(elId), t.identifier("firstChild"));
|
|
1009
|
-
}
|
|
1010
|
-
let expr = t.memberExpression(t.identifier(elId), t.identifier("firstChild"));
|
|
1011
|
-
for (let i = 0; i < index; i++) {
|
|
1012
|
-
expr = t.memberExpression(expr, t.identifier("nextSibling"));
|
|
1013
|
-
}
|
|
1014
|
-
return expr;
|
|
1015
|
-
}
|
|
1016
|
-
function transformComponentFineGrained(path, state) {
|
|
1017
|
-
const { node } = path;
|
|
1018
|
-
const openingElement = node.openingElement;
|
|
1019
|
-
const componentName = openingElement.name.name;
|
|
1020
|
-
const attributes = openingElement.attributes;
|
|
1021
|
-
const children = node.children;
|
|
1022
|
-
let clientDirective = null;
|
|
1023
|
-
const filteredAttrs = [];
|
|
1024
|
-
for (const attr of attributes) {
|
|
1025
|
-
if (t.isJSXAttribute(attr)) {
|
|
1026
|
-
let name;
|
|
1027
|
-
if (t.isJSXNamespacedName(attr.name)) {
|
|
1028
|
-
name = `${attr.name.namespace.name}:${attr.name.name.name}`;
|
|
1029
|
-
} else {
|
|
1030
|
-
name = attr.name.name;
|
|
1031
|
-
}
|
|
1032
|
-
if (name && typeof name === "string" && name.startsWith("client:")) {
|
|
1033
|
-
const mode = name.slice(7);
|
|
1034
|
-
if (attr.value) {
|
|
1035
|
-
clientDirective = { type: mode, value: attr.value.value };
|
|
1036
|
-
} else {
|
|
1037
|
-
clientDirective = { type: mode };
|
|
1038
|
-
}
|
|
1039
|
-
continue;
|
|
1040
|
-
}
|
|
1041
|
-
}
|
|
1042
|
-
filteredAttrs.push(attr);
|
|
1043
|
-
}
|
|
1044
|
-
if (clientDirective) {
|
|
1045
|
-
state.needsCreateComponent = true;
|
|
1046
|
-
state.needsIsland = true;
|
|
1047
|
-
const islandProps = [
|
|
1048
|
-
t.objectProperty(t.identifier("component"), t.identifier(componentName)),
|
|
1049
|
-
t.objectProperty(t.identifier("mode"), t.stringLiteral(clientDirective.type))
|
|
1050
|
-
];
|
|
1051
|
-
if (clientDirective.value) {
|
|
1052
|
-
islandProps.push(
|
|
1053
|
-
t.objectProperty(t.identifier("mediaQuery"), t.stringLiteral(clientDirective.value))
|
|
1054
|
-
);
|
|
1055
|
-
}
|
|
1056
|
-
for (const attr of filteredAttrs) {
|
|
1057
|
-
if (t.isJSXSpreadAttribute(attr)) continue;
|
|
1058
|
-
const attrName = getAttrName(attr);
|
|
1059
|
-
const value = getAttributeValue(attr.value);
|
|
1060
|
-
islandProps.push(t.objectProperty(t.identifier(attrName), value));
|
|
1061
|
-
}
|
|
1062
|
-
return t.callExpression(
|
|
1063
|
-
t.identifier("_$createComponent"),
|
|
1064
|
-
[t.identifier("Island"), t.objectExpression(islandProps), t.arrayExpression([])]
|
|
1065
|
-
);
|
|
1066
|
-
}
|
|
1067
|
-
state.needsCreateComponent = true;
|
|
1068
|
-
const props = [];
|
|
1069
|
-
let hasSpread = false;
|
|
1070
|
-
let spreadExpr = null;
|
|
1071
|
-
for (const attr of filteredAttrs) {
|
|
1072
|
-
if (t.isJSXSpreadAttribute(attr)) {
|
|
1073
|
-
hasSpread = true;
|
|
1074
|
-
spreadExpr = attr.argument;
|
|
1075
|
-
continue;
|
|
1076
|
-
}
|
|
1077
|
-
const attrName = getAttrName(attr);
|
|
1078
|
-
if (attrName === "key") continue;
|
|
1079
|
-
if (isBindingAttribute(attrName)) {
|
|
1080
|
-
const bindProp = getBindingProperty(attrName);
|
|
1081
|
-
const signalExpr = attr.value.expression;
|
|
1082
|
-
if (bindProp === "value") {
|
|
1083
|
-
props.push(
|
|
1084
|
-
t.objectProperty(t.identifier("value"), t.callExpression(t.cloneNode(signalExpr), []))
|
|
1085
|
-
);
|
|
1086
|
-
props.push(
|
|
1087
|
-
t.objectProperty(
|
|
1088
|
-
t.identifier("onInput"),
|
|
1089
|
-
t.arrowFunctionExpression(
|
|
1090
|
-
[t.identifier("e")],
|
|
1091
|
-
t.callExpression(
|
|
1092
|
-
t.memberExpression(t.cloneNode(signalExpr), t.identifier("set")),
|
|
1093
|
-
[t.memberExpression(
|
|
1094
|
-
t.memberExpression(t.identifier("e"), t.identifier("target")),
|
|
1095
|
-
t.identifier("value")
|
|
1096
|
-
)]
|
|
1097
|
-
)
|
|
1098
|
-
)
|
|
1099
|
-
)
|
|
1100
|
-
);
|
|
1101
|
-
} else if (bindProp === "checked") {
|
|
1102
|
-
props.push(
|
|
1103
|
-
t.objectProperty(t.identifier("checked"), t.callExpression(t.cloneNode(signalExpr), []))
|
|
1104
|
-
);
|
|
1105
|
-
props.push(
|
|
1106
|
-
t.objectProperty(
|
|
1107
|
-
t.identifier("onChange"),
|
|
1108
|
-
t.arrowFunctionExpression(
|
|
1109
|
-
[t.identifier("e")],
|
|
1110
|
-
t.callExpression(
|
|
1111
|
-
t.memberExpression(t.cloneNode(signalExpr), t.identifier("set")),
|
|
1112
|
-
[t.memberExpression(
|
|
1113
|
-
t.memberExpression(t.identifier("e"), t.identifier("target")),
|
|
1114
|
-
t.identifier("checked")
|
|
1115
|
-
)]
|
|
1116
|
-
)
|
|
1117
|
-
)
|
|
1118
|
-
)
|
|
1119
|
-
);
|
|
1120
|
-
}
|
|
1121
|
-
continue;
|
|
1122
|
-
}
|
|
1123
|
-
if (attrName.startsWith("on") && (attrName.includes("|") || hasEventModifiers(attrName, state))) {
|
|
1124
|
-
const { eventName, modifiers } = parseEventModifiers(attrName);
|
|
1125
|
-
const handler = getAttributeValue(attr.value);
|
|
1126
|
-
const wrappedHandler = createEventHandler(handler, modifiers);
|
|
1127
|
-
props.push(t.objectProperty(t.identifier(eventName), wrappedHandler));
|
|
1128
|
-
continue;
|
|
1129
|
-
}
|
|
1130
|
-
const value = getAttributeValue(attr.value);
|
|
1131
|
-
props.push(
|
|
1132
|
-
t.objectProperty(
|
|
1133
|
-
/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(attrName) ? t.identifier(attrName) : t.stringLiteral(attrName),
|
|
1134
|
-
value
|
|
1135
|
-
)
|
|
1136
|
-
);
|
|
1137
|
-
}
|
|
1138
|
-
const transformedChildren = [];
|
|
1139
|
-
for (const child of children) {
|
|
1140
|
-
if (t.isJSXText(child)) {
|
|
1141
|
-
const text = normalizeJsxText(child.value);
|
|
1142
|
-
if (text) transformedChildren.push(t.stringLiteral(text));
|
|
1143
|
-
} else if (t.isJSXExpressionContainer(child)) {
|
|
1144
|
-
if (!t.isJSXEmptyExpression(child.expression)) {
|
|
1145
|
-
transformedChildren.push(child.expression);
|
|
1146
|
-
}
|
|
1147
|
-
} else if (t.isJSXElement(child)) {
|
|
1148
|
-
transformedChildren.push(transformElementFineGrained({ node: child }, state));
|
|
1149
|
-
} else if (t.isJSXFragment(child)) {
|
|
1150
|
-
transformedChildren.push(transformFragmentFineGrained({ node: child }, state));
|
|
1151
|
-
}
|
|
1152
|
-
}
|
|
1153
|
-
let propsExpr;
|
|
1154
|
-
if (hasSpread) {
|
|
1155
|
-
if (props.length > 0) {
|
|
1156
|
-
propsExpr = t.callExpression(
|
|
1157
|
-
t.memberExpression(t.identifier("Object"), t.identifier("assign")),
|
|
1158
|
-
[t.objectExpression([]), spreadExpr, t.objectExpression(props)]
|
|
1159
|
-
);
|
|
1160
|
-
} else {
|
|
1161
|
-
propsExpr = spreadExpr;
|
|
1162
|
-
}
|
|
1163
|
-
} else if (props.length > 0) {
|
|
1164
|
-
propsExpr = t.objectExpression(props);
|
|
1165
|
-
} else {
|
|
1166
|
-
propsExpr = t.nullLiteral();
|
|
1167
|
-
}
|
|
1168
|
-
const childrenArray = transformedChildren.length > 0 ? t.arrayExpression(transformedChildren) : t.arrayExpression([]);
|
|
1169
|
-
return t.callExpression(t.identifier("_$createComponent"), [t.identifier(componentName), propsExpr, childrenArray]);
|
|
1170
|
-
}
|
|
1171
|
-
function transformForFineGrained(path, state) {
|
|
1172
|
-
const { node } = path;
|
|
1173
|
-
const attributes = node.openingElement.attributes;
|
|
1174
|
-
const children = node.children;
|
|
1175
|
-
if (true) {
|
|
1176
|
-
const fileName = state.filename || state.file?.opts?.filename || "<unknown>";
|
|
1177
|
-
if (!_forInfoWarned.has(fileName)) {
|
|
1178
|
-
_forInfoWarned.add(fileName);
|
|
1179
|
-
const loc = node.loc;
|
|
1180
|
-
const lineInfo = loc ? `:${loc.start.line}:${loc.start.column}` : "";
|
|
1181
|
-
console.info(
|
|
1182
|
-
`[what-compiler] <For> at ${fileName}${lineInfo}: consider using .map() with a key prop instead. The compiler auto-lowers .map() to efficient keyed reconciliation. <For> is only needed for signal-wrapped item accessors (advanced).`
|
|
1183
|
-
);
|
|
1184
|
-
}
|
|
1185
|
-
}
|
|
1186
|
-
let eachExpr = null;
|
|
1187
|
-
let keyExpr = null;
|
|
1188
|
-
for (const attr of attributes) {
|
|
1189
|
-
if (t.isJSXAttribute(attr)) {
|
|
1190
|
-
const name = getAttrName(attr);
|
|
1191
|
-
if (name === "each") eachExpr = getAttributeValue(attr.value);
|
|
1192
|
-
else if (name === "key") keyExpr = getAttributeValue(attr.value);
|
|
1193
|
-
}
|
|
1194
|
-
}
|
|
1195
|
-
if (!eachExpr) {
|
|
1196
|
-
console.warn('[what-compiler] <For> element missing "each" attribute.');
|
|
1197
|
-
state.needsH = true;
|
|
1198
|
-
return transformElementAsH(path, state);
|
|
1199
|
-
}
|
|
1200
|
-
let renderFn = null;
|
|
1201
|
-
for (const child of children) {
|
|
1202
|
-
if (t.isJSXExpressionContainer(child) && !t.isJSXEmptyExpression(child.expression)) {
|
|
1203
|
-
renderFn = child.expression;
|
|
1204
|
-
break;
|
|
1205
|
-
}
|
|
1206
|
-
}
|
|
1207
|
-
if (!renderFn) {
|
|
1208
|
-
console.warn("[what-compiler] <For> element missing render function child.");
|
|
1209
|
-
state.needsH = true;
|
|
1210
|
-
return transformElementAsH(path, state);
|
|
1211
|
-
}
|
|
1212
|
-
state.needsMapArray = true;
|
|
1213
|
-
const args = [eachExpr, renderFn];
|
|
1214
|
-
if (keyExpr) {
|
|
1215
|
-
args.push(t.objectExpression([
|
|
1216
|
-
t.objectProperty(t.identifier("key"), keyExpr)
|
|
1217
|
-
]));
|
|
1218
|
-
}
|
|
1219
|
-
return t.callExpression(t.identifier("_$mapArray"), args);
|
|
1220
|
-
}
|
|
1221
|
-
function transformShowFineGrained(path, state) {
|
|
1222
|
-
const { node } = path;
|
|
1223
|
-
const attributes = node.openingElement.attributes;
|
|
1224
|
-
const children = node.children;
|
|
1225
|
-
let whenExpr = null;
|
|
1226
|
-
let fallbackExpr = null;
|
|
1227
|
-
for (const attr of attributes) {
|
|
1228
|
-
if (t.isJSXAttribute(attr)) {
|
|
1229
|
-
const name = getAttrName(attr);
|
|
1230
|
-
if (name === "when") whenExpr = getAttributeValue(attr.value);
|
|
1231
|
-
else if (name === "fallback") fallbackExpr = getAttributeValue(attr.value);
|
|
1232
|
-
}
|
|
1233
|
-
}
|
|
1234
|
-
if (!whenExpr) {
|
|
1235
|
-
throw path.buildCodeFrameError(
|
|
1236
|
-
'<Show> requires a "when" prop. Example: <Show when={isOpen} fallback={null}>...</Show>'
|
|
1237
|
-
);
|
|
1238
|
-
}
|
|
1239
|
-
let contentExpr = null;
|
|
1240
|
-
for (const child of children) {
|
|
1241
|
-
if (t.isJSXExpressionContainer(child) && !t.isJSXEmptyExpression(child.expression)) {
|
|
1242
|
-
contentExpr = child.expression;
|
|
1243
|
-
break;
|
|
1244
|
-
}
|
|
1245
|
-
}
|
|
1246
|
-
if (!contentExpr) {
|
|
1247
|
-
const transformedChildren = [];
|
|
1248
|
-
for (const child of children) {
|
|
1249
|
-
if (t.isJSXText(child)) {
|
|
1250
|
-
const text = normalizeJsxText(child.value);
|
|
1251
|
-
if (text) transformedChildren.push(t.stringLiteral(text));
|
|
1252
|
-
} else if (t.isJSXElement(child)) {
|
|
1253
|
-
transformedChildren.push(transformElementFineGrained({ node: child }, state));
|
|
1254
|
-
}
|
|
1255
|
-
}
|
|
1256
|
-
if (transformedChildren.length === 1) {
|
|
1257
|
-
contentExpr = transformedChildren[0];
|
|
1258
|
-
} else if (transformedChildren.length > 1) {
|
|
1259
|
-
contentExpr = t.arrayExpression(transformedChildren);
|
|
1260
|
-
} else {
|
|
1261
|
-
contentExpr = t.nullLiteral();
|
|
1262
|
-
}
|
|
1263
|
-
}
|
|
1264
|
-
let condition;
|
|
1265
|
-
if (t.isCallExpression(whenExpr)) {
|
|
1266
|
-
condition = whenExpr;
|
|
1267
|
-
} else if (t.isArrowFunctionExpression(whenExpr) && t.isExpression(whenExpr.body)) {
|
|
1268
|
-
condition = whenExpr.body;
|
|
1269
|
-
} else if (t.isIdentifier(whenExpr) && (state.signalNames && isSignalIdentifier(whenExpr.name, state.signalNames) || state.importedIdentifiers && state.importedIdentifiers.has(whenExpr.name))) {
|
|
1270
|
-
condition = t.callExpression(whenExpr, []);
|
|
1271
|
-
} else {
|
|
1272
|
-
condition = whenExpr;
|
|
1273
|
-
}
|
|
1274
|
-
const vId = path.scope ? path.scope.generateUidIdentifier("v") : t.identifier("_v");
|
|
1275
|
-
const consequent = t.isFunction(contentExpr) ? t.callExpression(contentExpr, [t.cloneNode(vId)]) : contentExpr;
|
|
1276
|
-
const alternate = fallbackExpr || t.nullLiteral();
|
|
1277
|
-
return t.arrowFunctionExpression([], t.blockStatement([
|
|
1278
|
-
t.variableDeclaration("const", [
|
|
1279
|
-
t.variableDeclarator(vId, condition)
|
|
1280
|
-
]),
|
|
1281
|
-
t.returnStatement(
|
|
1282
|
-
t.conditionalExpression(t.cloneNode(vId), consequent, alternate)
|
|
1283
|
-
)
|
|
1284
|
-
]));
|
|
1285
|
-
}
|
|
1286
|
-
function transformFragmentFineGrained(path, state) {
|
|
1287
|
-
const { node } = path;
|
|
1288
|
-
const children = node.children;
|
|
1289
|
-
const transformed = [];
|
|
1290
|
-
for (const child of children) {
|
|
1291
|
-
if (t.isJSXText(child)) {
|
|
1292
|
-
const text = normalizeJsxText(child.value);
|
|
1293
|
-
if (text) transformed.push(t.stringLiteral(text));
|
|
1294
|
-
} else if (t.isJSXExpressionContainer(child)) {
|
|
1295
|
-
if (!t.isJSXEmptyExpression(child.expression)) {
|
|
1296
|
-
transformed.push(child.expression);
|
|
1297
|
-
}
|
|
1298
|
-
} else if (t.isJSXElement(child)) {
|
|
1299
|
-
transformed.push(transformElementFineGrained({ node: child }, state));
|
|
1300
|
-
} else if (t.isJSXFragment(child)) {
|
|
1301
|
-
transformed.push(transformFragmentFineGrained({ node: child }, state));
|
|
1302
|
-
}
|
|
1303
|
-
}
|
|
1304
|
-
if (transformed.length === 1) return transformed[0];
|
|
1305
|
-
return t.arrayExpression(transformed);
|
|
1306
|
-
}
|
|
1307
|
-
function getOrCreateTemplate(state, html) {
|
|
1308
|
-
if (state.templateMap.has(html)) {
|
|
1309
|
-
return state.templateMap.get(html);
|
|
1310
|
-
}
|
|
1311
|
-
const id = `_tmpl$${state.templateCount++}`;
|
|
1312
|
-
state.templateMap.set(html, id);
|
|
1313
|
-
state.templates.push({ id, html });
|
|
1314
|
-
return id;
|
|
1315
|
-
}
|
|
1316
|
-
return {
|
|
1317
|
-
name: "what-jsx-transform",
|
|
1318
|
-
visitor: {
|
|
1319
|
-
Program: {
|
|
1320
|
-
enter(path, state) {
|
|
1321
|
-
state.needsTemplate = false;
|
|
1322
|
-
state.needsInsert = false;
|
|
1323
|
-
state.needsEffect = false;
|
|
1324
|
-
state.needsMapArray = false;
|
|
1325
|
-
state.needsSpread = false;
|
|
1326
|
-
state.needsSetProp = false;
|
|
1327
|
-
state.needsH = false;
|
|
1328
|
-
state.needsCreateComponent = false;
|
|
1329
|
-
state.needsFragment = false;
|
|
1330
|
-
state.needsIsland = false;
|
|
1331
|
-
state.needsDelegation = false;
|
|
1332
|
-
state.delegatedEvents = /* @__PURE__ */ new Set();
|
|
1333
|
-
state.templates = [];
|
|
1334
|
-
state.templateMap = /* @__PURE__ */ new Map();
|
|
1335
|
-
state.templateCount = 0;
|
|
1336
|
-
state._varCounter = 0;
|
|
1337
|
-
state._pendingSetup = [];
|
|
1338
|
-
state.nextVarId = () => `_el$${state._varCounter++}`;
|
|
1339
|
-
state.signalNames = /* @__PURE__ */ new Set();
|
|
1340
|
-
state.importedIdentifiers = /* @__PURE__ */ new Set();
|
|
1341
|
-
for (const node of path.node.body) {
|
|
1342
|
-
if (t.isImportDeclaration(node)) {
|
|
1343
|
-
const source = node.source.value;
|
|
1344
|
-
const isReactiveSource = source === "what-framework" || source.startsWith("what-framework/") || source === "what-core" || source.startsWith("what-core/") || source.startsWith("./") || source.startsWith("../");
|
|
1345
|
-
for (const spec of node.specifiers) {
|
|
1346
|
-
let localName = null;
|
|
1347
|
-
if (t.isImportSpecifier(spec) && t.isIdentifier(spec.local)) {
|
|
1348
|
-
localName = spec.local.name;
|
|
1349
|
-
} else if (t.isImportDefaultSpecifier(spec) && t.isIdentifier(spec.local)) {
|
|
1350
|
-
localName = spec.local.name;
|
|
1351
|
-
} else if (t.isImportNamespaceSpecifier(spec) && t.isIdentifier(spec.local)) {
|
|
1352
|
-
localName = spec.local.name;
|
|
1353
|
-
}
|
|
1354
|
-
if (localName) {
|
|
1355
|
-
if (isReactiveSource || /^(use|create)[A-Z]/.test(localName)) {
|
|
1356
|
-
state.importedIdentifiers.add(localName);
|
|
1357
|
-
}
|
|
1358
|
-
}
|
|
1359
|
-
}
|
|
1360
|
-
}
|
|
1361
|
-
}
|
|
1362
|
-
path.traverse({
|
|
1363
|
-
VariableDeclarator(declPath) {
|
|
1364
|
-
const init = declPath.node.init;
|
|
1365
|
-
if (!init || !t.isCallExpression(init)) return;
|
|
1366
|
-
const callee = init.callee;
|
|
1367
|
-
let calleeName = "";
|
|
1368
|
-
if (t.isIdentifier(callee)) {
|
|
1369
|
-
calleeName = callee.name;
|
|
1370
|
-
} else if (t.isMemberExpression(callee) && t.isIdentifier(callee.property)) {
|
|
1371
|
-
calleeName = callee.property.name;
|
|
1372
|
-
}
|
|
1373
|
-
if (SIGNAL_CREATORS.has(calleeName)) {
|
|
1374
|
-
const id = declPath.node.id;
|
|
1375
|
-
if (t.isIdentifier(id)) {
|
|
1376
|
-
state.signalNames.add(id.name);
|
|
1377
|
-
} else if (t.isArrayPattern(id)) {
|
|
1378
|
-
for (const el of id.elements) {
|
|
1379
|
-
if (t.isIdentifier(el)) state.signalNames.add(el.name);
|
|
1380
|
-
}
|
|
1381
|
-
} else if (t.isObjectPattern(id)) {
|
|
1382
|
-
for (const prop of id.properties) {
|
|
1383
|
-
if (t.isObjectProperty(prop) && t.isIdentifier(prop.value)) {
|
|
1384
|
-
state.signalNames.add(prop.value.name);
|
|
1385
|
-
}
|
|
1386
|
-
}
|
|
1387
|
-
}
|
|
1388
|
-
}
|
|
1389
|
-
}
|
|
1390
|
-
});
|
|
1391
|
-
},
|
|
1392
|
-
exit(path, state) {
|
|
1393
|
-
for (const tmpl of state.templates.reverse()) {
|
|
1394
|
-
path.unshiftContainer(
|
|
1395
|
-
"body",
|
|
1396
|
-
t.variableDeclaration("const", [
|
|
1397
|
-
t.variableDeclarator(
|
|
1398
|
-
t.identifier(tmpl.id),
|
|
1399
|
-
t.callExpression(t.identifier("_$template"), [t.stringLiteral(tmpl.html)])
|
|
1400
|
-
)
|
|
1401
|
-
])
|
|
1402
|
-
);
|
|
1403
|
-
}
|
|
1404
|
-
const fgSpecifiers = [];
|
|
1405
|
-
if (state.needsTemplate) {
|
|
1406
|
-
fgSpecifiers.push(
|
|
1407
|
-
t.importSpecifier(t.identifier("_$template"), t.identifier("template"))
|
|
1408
|
-
);
|
|
1409
|
-
}
|
|
1410
|
-
if (state.needsInsert) {
|
|
1411
|
-
fgSpecifiers.push(
|
|
1412
|
-
t.importSpecifier(t.identifier("_$insert"), t.identifier("insert"))
|
|
1413
|
-
);
|
|
1414
|
-
}
|
|
1415
|
-
if (state.needsEffect) {
|
|
1416
|
-
fgSpecifiers.push(
|
|
1417
|
-
t.importSpecifier(t.identifier("_$effect"), t.identifier("effect"))
|
|
1418
|
-
);
|
|
1419
|
-
}
|
|
1420
|
-
if (state.needsMapArray) {
|
|
1421
|
-
fgSpecifiers.push(
|
|
1422
|
-
t.importSpecifier(t.identifier("_$mapArray"), t.identifier("mapArray"))
|
|
1423
|
-
);
|
|
1424
|
-
}
|
|
1425
|
-
if (state.needsSpread) {
|
|
1426
|
-
fgSpecifiers.push(
|
|
1427
|
-
t.importSpecifier(t.identifier("_$spread"), t.identifier("spread"))
|
|
1428
|
-
);
|
|
1429
|
-
}
|
|
1430
|
-
if (state.needsSetProp) {
|
|
1431
|
-
fgSpecifiers.push(
|
|
1432
|
-
t.importSpecifier(t.identifier("_$setProp"), t.identifier("setProp"))
|
|
1433
|
-
);
|
|
1434
|
-
}
|
|
1435
|
-
if (state.needsCreateComponent) {
|
|
1436
|
-
fgSpecifiers.push(
|
|
1437
|
-
t.importSpecifier(t.identifier("_$createComponent"), t.identifier("_$createComponent"))
|
|
1438
|
-
);
|
|
1439
|
-
}
|
|
1440
|
-
if (state.needsDelegation) {
|
|
1441
|
-
fgSpecifiers.push(
|
|
1442
|
-
t.importSpecifier(t.identifier("_$delegateEvents"), t.identifier("delegateEvents"))
|
|
1443
|
-
);
|
|
1444
|
-
}
|
|
1445
|
-
const coreSpecifiers = [];
|
|
1446
|
-
if (state.needsH) {
|
|
1447
|
-
coreSpecifiers.push(
|
|
1448
|
-
t.importSpecifier(t.identifier("h"), t.identifier("h"))
|
|
1449
|
-
);
|
|
1450
|
-
}
|
|
1451
|
-
if (state.needsFragment) {
|
|
1452
|
-
coreSpecifiers.push(
|
|
1453
|
-
t.importSpecifier(t.identifier("Fragment"), t.identifier("Fragment"))
|
|
1454
|
-
);
|
|
1455
|
-
}
|
|
1456
|
-
if (state.needsIsland) {
|
|
1457
|
-
coreSpecifiers.push(
|
|
1458
|
-
t.importSpecifier(t.identifier("Island"), t.identifier("Island"))
|
|
1459
|
-
);
|
|
1460
|
-
}
|
|
1461
|
-
if (fgSpecifiers.length > 0) {
|
|
1462
|
-
let existingRenderImport = null;
|
|
1463
|
-
for (const node of path.node.body) {
|
|
1464
|
-
if (t.isImportDeclaration(node) && (node.source.value === "what-framework/render" || node.source.value === "what-core/render")) {
|
|
1465
|
-
existingRenderImport = node;
|
|
1466
|
-
break;
|
|
1467
|
-
}
|
|
1468
|
-
}
|
|
1469
|
-
if (existingRenderImport) {
|
|
1470
|
-
const existingNames = new Set(
|
|
1471
|
-
existingRenderImport.specifiers.filter((s) => t.isImportSpecifier(s)).map((s) => s.imported.name)
|
|
1472
|
-
);
|
|
1473
|
-
for (const spec of fgSpecifiers) {
|
|
1474
|
-
if (!existingNames.has(spec.imported.name)) {
|
|
1475
|
-
existingRenderImport.specifiers.push(spec);
|
|
1476
|
-
}
|
|
1477
|
-
}
|
|
1478
|
-
} else {
|
|
1479
|
-
path.unshiftContainer(
|
|
1480
|
-
"body",
|
|
1481
|
-
t.importDeclaration(fgSpecifiers, t.stringLiteral("what-framework/render"))
|
|
1482
|
-
);
|
|
1483
|
-
}
|
|
1484
|
-
}
|
|
1485
|
-
if (coreSpecifiers.length > 0) {
|
|
1486
|
-
addCoreImports(path, t, coreSpecifiers);
|
|
1487
|
-
}
|
|
1488
|
-
if (state.needsDelegation && state.delegatedEvents && state.delegatedEvents.size > 0) {
|
|
1489
|
-
const eventArray = t.arrayExpression(
|
|
1490
|
-
[...state.delegatedEvents].map((e) => t.stringLiteral(e))
|
|
1491
|
-
);
|
|
1492
|
-
path.pushContainer(
|
|
1493
|
-
"body",
|
|
1494
|
-
t.expressionStatement(
|
|
1495
|
-
t.callExpression(t.identifier("_$delegateEvents"), [eventArray])
|
|
1496
|
-
)
|
|
1497
|
-
);
|
|
1498
|
-
}
|
|
1499
|
-
}
|
|
1500
|
-
},
|
|
1501
|
-
JSXElement(path, state) {
|
|
1502
|
-
const scope = path.scope;
|
|
1503
|
-
let cache = state._signalNamesCache;
|
|
1504
|
-
if (!cache) cache = state._signalNamesCache = /* @__PURE__ */ new WeakMap();
|
|
1505
|
-
let names = cache.get(scope);
|
|
1506
|
-
if (!names) {
|
|
1507
|
-
names = collectSignalNamesFromScope(path);
|
|
1508
|
-
cache.set(scope, names);
|
|
1509
|
-
}
|
|
1510
|
-
state.signalNames = names;
|
|
1511
|
-
state._pendingSetup = [];
|
|
1512
|
-
const transformed = transformElementFineGrained(path, state);
|
|
1513
|
-
const pending = state._pendingSetup;
|
|
1514
|
-
state._pendingSetup = [];
|
|
1515
|
-
if (pending.length > 0) {
|
|
1516
|
-
let stmtPath = path;
|
|
1517
|
-
let crossedFunctionBoundary = false;
|
|
1518
|
-
while (stmtPath && !stmtPath.isStatement()) {
|
|
1519
|
-
if (stmtPath.isArrowFunctionExpression() || stmtPath.isFunctionExpression()) {
|
|
1520
|
-
crossedFunctionBoundary = true;
|
|
1521
|
-
}
|
|
1522
|
-
stmtPath = stmtPath.parentPath;
|
|
1523
|
-
}
|
|
1524
|
-
const inStatementList = stmtPath && stmtPath.isStatement() && (stmtPath.listKey === "body" || stmtPath.listKey === "consequent") && Array.isArray(stmtPath.container);
|
|
1525
|
-
if (inStatementList && !crossedFunctionBoundary) {
|
|
1526
|
-
stmtPath.insertBefore(pending);
|
|
1527
|
-
path.replaceWith(transformed);
|
|
1528
|
-
} else {
|
|
1529
|
-
pending.push(t.returnStatement(transformed));
|
|
1530
|
-
path.replaceWith(
|
|
1531
|
-
t.callExpression(
|
|
1532
|
-
t.arrowFunctionExpression([], t.blockStatement(pending)),
|
|
1533
|
-
[]
|
|
1534
|
-
)
|
|
1535
|
-
);
|
|
1536
|
-
}
|
|
1537
|
-
} else {
|
|
1538
|
-
path.replaceWith(transformed);
|
|
1539
|
-
}
|
|
1540
|
-
},
|
|
1541
|
-
JSXFragment(path, state) {
|
|
1542
|
-
const transformed = transformFragmentFineGrained(path, state);
|
|
1543
|
-
path.replaceWith(transformed);
|
|
1544
|
-
}
|
|
1545
|
-
}
|
|
1546
|
-
};
|
|
1547
|
-
}
|
|
1548
|
-
function addCoreImports(path, t, coreSpecifiers) {
|
|
1549
|
-
let existingImport = null;
|
|
1550
|
-
for (const node of path.node.body) {
|
|
1551
|
-
if (t.isImportDeclaration(node) && (node.source.value === "what-core" || node.source.value === "what-framework")) {
|
|
1552
|
-
existingImport = node;
|
|
1553
|
-
break;
|
|
1554
|
-
}
|
|
1555
|
-
}
|
|
1556
|
-
if (existingImport) {
|
|
1557
|
-
const existingNames = new Set(
|
|
1558
|
-
existingImport.specifiers.filter((s) => t.isImportSpecifier(s)).map((s) => s.imported.name)
|
|
1559
|
-
);
|
|
1560
|
-
for (const spec of coreSpecifiers) {
|
|
1561
|
-
if (!existingNames.has(spec.imported.name)) {
|
|
1562
|
-
existingImport.specifiers.push(spec);
|
|
1563
|
-
}
|
|
1564
|
-
}
|
|
1565
|
-
} else {
|
|
1566
|
-
const importDecl = t.importDeclaration(
|
|
1567
|
-
coreSpecifiers,
|
|
1568
|
-
t.stringLiteral("what-framework")
|
|
1569
|
-
);
|
|
1570
|
-
path.unshiftContainer("body", importDecl);
|
|
1571
|
-
}
|
|
1572
|
-
}
|
|
1573
|
-
export {
|
|
1574
|
-
whatBabelPlugin as default
|
|
1575
|
-
};
|
|
1576
|
-
//# sourceMappingURL=babel-plugin.js.map
|