what-compiler 0.8.4 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/babel-plugin.js +539 -87
- package/dist/babel-plugin.js.map +2 -2
- package/dist/babel-plugin.min.js +1 -1
- package/dist/babel-plugin.min.js.map +3 -3
- package/dist/file-router.js +78 -2
- package/dist/file-router.js.map +2 -2
- package/dist/file-router.min.js +3 -2
- package/dist/file-router.min.js.map +3 -3
- package/dist/index.js +595 -93
- package/dist/index.js.map +2 -2
- package/dist/index.min.js +6 -6
- package/dist/index.min.js.map +3 -3
- package/dist/vite-plugin.js +595 -93
- package/dist/vite-plugin.js.map +2 -2
- package/dist/vite-plugin.min.js +6 -6
- package/dist/vite-plugin.min.js.map +3 -3
- package/package.json +2 -2
- package/src/babel-plugin.js +898 -105
- package/src/file-router.js +104 -2
- package/src/vite-plugin.js +60 -3
package/dist/babel-plugin.js
CHANGED
|
@@ -61,9 +61,56 @@ var SIGNAL_CREATORS = /* @__PURE__ */ new Set([
|
|
|
61
61
|
"useQuery",
|
|
62
62
|
"useInfiniteQuery"
|
|
63
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
|
+
}
|
|
64
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
|
+
}
|
|
65
111
|
function parseEventModifiers(name) {
|
|
66
|
-
const
|
|
112
|
+
const delimiter = name.includes("|") ? "|" : "__";
|
|
113
|
+
const parts = name.split(delimiter);
|
|
67
114
|
const eventName = parts[0];
|
|
68
115
|
const modifiers = parts.slice(1).filter((m) => EVENT_MODIFIERS.has(m));
|
|
69
116
|
return { eventName, modifiers };
|
|
@@ -193,22 +240,20 @@ function whatBabelPlugin({ types: t }) {
|
|
|
193
240
|
}
|
|
194
241
|
let scope = path.scope;
|
|
195
242
|
while (scope) {
|
|
196
|
-
for (const
|
|
243
|
+
for (const binding of Object.values(scope.bindings)) {
|
|
197
244
|
if (binding.path.isVariableDeclarator()) {
|
|
198
245
|
extractFromDeclarator(binding.path.node);
|
|
199
246
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
}
|
|
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);
|
|
212
257
|
}
|
|
213
258
|
}
|
|
214
259
|
}
|
|
@@ -276,7 +321,7 @@ function whatBabelPlugin({ types: t }) {
|
|
|
276
321
|
return isPotentiallyReactive(expr.callee, signalNames, importedIds) || expr.arguments.some((arg) => isPotentiallyReactive(arg, signalNames, importedIds));
|
|
277
322
|
}
|
|
278
323
|
if (t.isIdentifier(expr)) {
|
|
279
|
-
return isSignalIdentifier(expr.name, signalNames);
|
|
324
|
+
return isSignalIdentifier(expr.name, signalNames) || importedIds && importedIds.has(expr.name);
|
|
280
325
|
}
|
|
281
326
|
if (t.isMemberExpression(expr)) {
|
|
282
327
|
return isPotentiallyReactive(expr.object, signalNames, importedIds);
|
|
@@ -306,6 +351,93 @@ function whatBabelPlugin({ types: t }) {
|
|
|
306
351
|
}
|
|
307
352
|
return false;
|
|
308
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
|
+
}
|
|
309
441
|
function isStaticChild(child) {
|
|
310
442
|
if (t.isJSXText(child)) return true;
|
|
311
443
|
if (t.isJSXExpressionContainer(child)) return false;
|
|
@@ -329,7 +461,7 @@ function whatBabelPlugin({ types: t }) {
|
|
|
329
461
|
}
|
|
330
462
|
function extractStaticHTML(node) {
|
|
331
463
|
if (t.isJSXText(node)) {
|
|
332
|
-
const text = node.value
|
|
464
|
+
const text = normalizeJsxText(node.value);
|
|
333
465
|
return text ? escapeHTML(text) : "";
|
|
334
466
|
}
|
|
335
467
|
if (t.isJSXExpressionContainer(node)) {
|
|
@@ -369,7 +501,7 @@ function whatBabelPlugin({ types: t }) {
|
|
|
369
501
|
html += ">";
|
|
370
502
|
for (const child of node.children) {
|
|
371
503
|
if (t.isJSXText(child)) {
|
|
372
|
-
const text = child.value
|
|
504
|
+
const text = normalizeJsxText(child.value);
|
|
373
505
|
if (text) html += escapeHTML(text);
|
|
374
506
|
} else if (t.isJSXExpressionContainer(child)) {
|
|
375
507
|
if (!t.isJSXEmptyExpression(child.expression)) {
|
|
@@ -396,15 +528,15 @@ function whatBabelPlugin({ types: t }) {
|
|
|
396
528
|
const { node } = path;
|
|
397
529
|
const openingElement = node.openingElement;
|
|
398
530
|
const tagName = openingElement.name.name;
|
|
399
|
-
if (isComponent(tagName)) {
|
|
400
|
-
return transformComponentFineGrained(path, state);
|
|
401
|
-
}
|
|
402
531
|
if (tagName === "For") {
|
|
403
532
|
return transformForFineGrained(path, state);
|
|
404
533
|
}
|
|
405
534
|
if (tagName === "Show") {
|
|
406
535
|
return transformShowFineGrained(path, state);
|
|
407
536
|
}
|
|
537
|
+
if (isComponent(tagName)) {
|
|
538
|
+
return transformComponentFineGrained(path, state);
|
|
539
|
+
}
|
|
408
540
|
const attributes = openingElement.attributes;
|
|
409
541
|
const children = node.children;
|
|
410
542
|
const allChildrenStatic = children.every(isStaticChild);
|
|
@@ -441,7 +573,7 @@ function whatBabelPlugin({ types: t }) {
|
|
|
441
573
|
t.variableDeclarator(t.identifier(elId), t.callExpression(t.identifier(tmplId), []))
|
|
442
574
|
])
|
|
443
575
|
];
|
|
444
|
-
applyDynamicAttrs(statements, elId, attributes, state);
|
|
576
|
+
applyDynamicAttrs(statements, elId, attributes, state, tagName);
|
|
445
577
|
applyDynamicChildren(statements, elId, children, node, state);
|
|
446
578
|
if (!state._pendingSetup) state._pendingSetup = [];
|
|
447
579
|
state._pendingSetup.push(...statements);
|
|
@@ -469,7 +601,7 @@ function whatBabelPlugin({ types: t }) {
|
|
|
469
601
|
const transformedChildren = [];
|
|
470
602
|
for (const child of children) {
|
|
471
603
|
if (t.isJSXText(child)) {
|
|
472
|
-
const text = child.value
|
|
604
|
+
const text = normalizeJsxText(child.value);
|
|
473
605
|
if (text) transformedChildren.push(t.stringLiteral(text));
|
|
474
606
|
} else if (t.isJSXExpressionContainer(child)) {
|
|
475
607
|
if (!t.isJSXEmptyExpression(child.expression)) {
|
|
@@ -484,8 +616,33 @@ function whatBabelPlugin({ types: t }) {
|
|
|
484
616
|
const propsExpr = props.length > 0 ? t.objectExpression(props) : t.nullLiteral();
|
|
485
617
|
return t.callExpression(t.identifier("h"), [t.stringLiteral(tagName), propsExpr, ...transformedChildren]);
|
|
486
618
|
}
|
|
487
|
-
|
|
619
|
+
const VALUE_PROP_TAGS = /* @__PURE__ */ new Set(["input", "textarea", "select", "option"]);
|
|
620
|
+
function applyDynamicAttrs(statements, elId, attributes, state, tagName) {
|
|
488
621
|
function buildSetPropCall(propName, valueExpr) {
|
|
622
|
+
if (propName === "class") {
|
|
623
|
+
state.needsSetClass = true;
|
|
624
|
+
return t.callExpression(t.identifier("_$setClass"), [t.identifier(elId), valueExpr]);
|
|
625
|
+
}
|
|
626
|
+
if (propName === "style") {
|
|
627
|
+
state.needsSetStyle = true;
|
|
628
|
+
return t.callExpression(t.identifier("_$setStyle"), [t.identifier(elId), valueExpr]);
|
|
629
|
+
}
|
|
630
|
+
if (propName === "value" && tagName && VALUE_PROP_TAGS.has(tagName)) {
|
|
631
|
+
state.needsSetValue = true;
|
|
632
|
+
return t.callExpression(t.identifier("_$setValue"), [t.identifier(elId), valueExpr]);
|
|
633
|
+
}
|
|
634
|
+
if (propName === "checked" && tagName === "input") {
|
|
635
|
+
state.needsSetChecked = true;
|
|
636
|
+
return t.callExpression(t.identifier("_$setChecked"), [t.identifier(elId), valueExpr]);
|
|
637
|
+
}
|
|
638
|
+
if (propName.startsWith("data-") || propName.startsWith("aria-")) {
|
|
639
|
+
state.needsSetAttr = true;
|
|
640
|
+
return t.callExpression(t.identifier("_$setAttr"), [
|
|
641
|
+
t.identifier(elId),
|
|
642
|
+
t.stringLiteral(propName),
|
|
643
|
+
valueExpr
|
|
644
|
+
]);
|
|
645
|
+
}
|
|
489
646
|
state.needsSetProp = true;
|
|
490
647
|
return t.callExpression(t.identifier("_$setProp"), [
|
|
491
648
|
t.identifier(elId),
|
|
@@ -493,6 +650,14 @@ function whatBabelPlugin({ types: t }) {
|
|
|
493
650
|
valueExpr
|
|
494
651
|
]);
|
|
495
652
|
}
|
|
653
|
+
let delegateInitEmitted = false;
|
|
654
|
+
function emitDelegateInit() {
|
|
655
|
+
if (delegateInitEmitted) return;
|
|
656
|
+
delegateInitEmitted = true;
|
|
657
|
+
statements.push(
|
|
658
|
+
t.expressionStatement(t.callExpression(t.identifier("_$delegate$"), []))
|
|
659
|
+
);
|
|
660
|
+
}
|
|
496
661
|
for (const attr of attributes) {
|
|
497
662
|
if (t.isJSXSpreadAttribute(attr)) {
|
|
498
663
|
state.needsSpread = true;
|
|
@@ -526,20 +691,21 @@ function whatBabelPlugin({ types: t }) {
|
|
|
526
691
|
);
|
|
527
692
|
continue;
|
|
528
693
|
}
|
|
529
|
-
if (attrName.startsWith("on") && !attrName.includes("|")) {
|
|
694
|
+
if (attrName.startsWith("on") && !attrName.includes("|") && !hasEventModifiers(attrName, state)) {
|
|
530
695
|
const event = attrName.slice(2).toLowerCase();
|
|
531
696
|
const handler = getAttributeValue(attr.value);
|
|
532
697
|
if (DELEGATED_EVENTS.has(event)) {
|
|
533
698
|
state.needsDelegation = true;
|
|
534
699
|
if (!state.delegatedEvents) state.delegatedEvents = /* @__PURE__ */ new Set();
|
|
535
700
|
state.delegatedEvents.add(event);
|
|
701
|
+
emitDelegateInit();
|
|
536
702
|
statements.push(
|
|
537
703
|
t.expressionStatement(
|
|
538
704
|
t.assignmentExpression(
|
|
539
705
|
"=",
|
|
540
706
|
t.memberExpression(
|
|
541
707
|
t.identifier(elId),
|
|
542
|
-
t.identifier(
|
|
708
|
+
t.identifier(`$$${event}`)
|
|
543
709
|
),
|
|
544
710
|
handler
|
|
545
711
|
)
|
|
@@ -557,7 +723,7 @@ function whatBabelPlugin({ types: t }) {
|
|
|
557
723
|
}
|
|
558
724
|
continue;
|
|
559
725
|
}
|
|
560
|
-
if (attrName.startsWith("on") && attrName.includes("|")) {
|
|
726
|
+
if (attrName.startsWith("on") && (attrName.includes("|") || hasEventModifiers(attrName, state))) {
|
|
561
727
|
const { eventName, modifiers } = parseEventModifiers(attrName);
|
|
562
728
|
const handler = getAttributeValue(attr.value);
|
|
563
729
|
const wrappedHandler = createEventHandler(handler, modifiers);
|
|
@@ -657,8 +823,9 @@ function whatBabelPlugin({ types: t }) {
|
|
|
657
823
|
const domName = normalizeAttrName(attrName);
|
|
658
824
|
if (isPotentiallyReactive(expr, state.signalNames, state.importedIdentifiers)) {
|
|
659
825
|
state.needsEffect = true;
|
|
826
|
+
const valueExpr = t.isIdentifier(expr) && (isSignalIdentifier(expr.name, state.signalNames) || state.importedIdentifiers && state.importedIdentifiers.has(expr.name)) ? t.callExpression(expr, []) : expr;
|
|
660
827
|
const effectCall = t.callExpression(t.identifier("_$effect"), [
|
|
661
|
-
t.arrowFunctionExpression([], buildSetPropCall(domName,
|
|
828
|
+
t.arrowFunctionExpression([], buildSetPropCall(domName, valueExpr))
|
|
662
829
|
]);
|
|
663
830
|
if (isUncertainReactive(expr, state.signalNames, state.importedIdentifiers)) {
|
|
664
831
|
t.addComment(
|
|
@@ -675,12 +842,56 @@ function whatBabelPlugin({ types: t }) {
|
|
|
675
842
|
}
|
|
676
843
|
}
|
|
677
844
|
}
|
|
845
|
+
function buildsDOM(node) {
|
|
846
|
+
if (!node || typeof node !== "object") return false;
|
|
847
|
+
if (Array.isArray(node)) return node.some(buildsDOM);
|
|
848
|
+
if (node.type === "JSXElement" || node.type === "JSXFragment") return true;
|
|
849
|
+
if (node.type === "CallExpression" && node.callee && node.callee.type === "Identifier" && (node.callee.name === "_$mapArray" || node.callee.name === "mapArray")) {
|
|
850
|
+
return true;
|
|
851
|
+
}
|
|
852
|
+
for (const key of Object.keys(node)) {
|
|
853
|
+
if (key === "loc" || key === "start" || key === "end" || key === "leadingComments" || key === "trailingComments" || key === "innerComments") continue;
|
|
854
|
+
const v = node[key];
|
|
855
|
+
if (v && typeof v === "object" && buildsDOM(v)) return true;
|
|
856
|
+
}
|
|
857
|
+
return false;
|
|
858
|
+
}
|
|
859
|
+
function memoizeBranchCondition(expr, statements, state) {
|
|
860
|
+
let testExpr = null;
|
|
861
|
+
let isTernary = false;
|
|
862
|
+
if (t.isConditionalExpression(expr)) {
|
|
863
|
+
testExpr = expr.test;
|
|
864
|
+
isTernary = true;
|
|
865
|
+
} else if (t.isLogicalExpression(expr) && (expr.operator === "&&" || expr.operator === "||")) {
|
|
866
|
+
testExpr = expr.left;
|
|
867
|
+
} else {
|
|
868
|
+
return expr;
|
|
869
|
+
}
|
|
870
|
+
if (!isPotentiallyReactive(testExpr, state.signalNames, state.importedIdentifiers)) return expr;
|
|
871
|
+
const branches = isTernary ? [expr.consequent, expr.alternate] : [expr.right];
|
|
872
|
+
if (!branches.some(buildsDOM)) return expr;
|
|
873
|
+
const condId = state.nextMemoId();
|
|
874
|
+
state.needsMemo = true;
|
|
875
|
+
const memoBody = isTernary ? t.unaryExpression("!", t.unaryExpression("!", testExpr)) : testExpr;
|
|
876
|
+
statements.push(
|
|
877
|
+
t.variableDeclaration("const", [
|
|
878
|
+
t.variableDeclarator(
|
|
879
|
+
t.identifier(condId),
|
|
880
|
+
t.callExpression(t.identifier("_$memo"), [
|
|
881
|
+
t.arrowFunctionExpression([], memoBody)
|
|
882
|
+
])
|
|
883
|
+
)
|
|
884
|
+
])
|
|
885
|
+
);
|
|
886
|
+
const condRead = t.callExpression(t.identifier(condId), []);
|
|
887
|
+
return isTernary ? t.conditionalExpression(condRead, expr.consequent, expr.alternate) : t.logicalExpression(expr.operator, condRead, expr.right);
|
|
888
|
+
}
|
|
678
889
|
function applyDynamicChildren(statements, elId, children, parentNode, state) {
|
|
679
890
|
const entries = [];
|
|
680
891
|
let childIndex = 0;
|
|
681
892
|
for (const child of children) {
|
|
682
893
|
if (t.isJSXText(child)) {
|
|
683
|
-
const text = child.value
|
|
894
|
+
const text = normalizeJsxText(child.value);
|
|
684
895
|
if (text) childIndex++;
|
|
685
896
|
continue;
|
|
686
897
|
}
|
|
@@ -709,22 +920,31 @@ function whatBabelPlugin({ types: t }) {
|
|
|
709
920
|
const entriesNeedingRef = entries.filter(
|
|
710
921
|
(e) => e.type === "expression" || e.type === "component" || e.type === "static" && e.hasAnythingDynamic
|
|
711
922
|
);
|
|
712
|
-
const
|
|
713
|
-
const needsPreCapture = entriesNeedingRef.length >= 2 && hasDynamicInsert;
|
|
923
|
+
const needsPreCapture = entriesNeedingRef.length >= 2;
|
|
714
924
|
const markerVars = /* @__PURE__ */ new Map();
|
|
715
925
|
if (needsPreCapture) {
|
|
926
|
+
let prevVar = null;
|
|
927
|
+
let prevIndex = 0;
|
|
716
928
|
for (const entry of entriesNeedingRef) {
|
|
717
|
-
const
|
|
929
|
+
const idx = entry.childIndex;
|
|
718
930
|
const markerVar = state.nextVarId();
|
|
719
|
-
markerVars.set(
|
|
931
|
+
markerVars.set(idx, markerVar);
|
|
932
|
+
let init;
|
|
933
|
+
if (prevVar === null) {
|
|
934
|
+
init = buildChildAccess(elId, idx);
|
|
935
|
+
} else {
|
|
936
|
+
init = t.identifier(prevVar);
|
|
937
|
+
for (let i = prevIndex; i < idx; i++) {
|
|
938
|
+
init = t.memberExpression(init, t.identifier("nextSibling"));
|
|
939
|
+
}
|
|
940
|
+
}
|
|
720
941
|
statements.push(
|
|
721
942
|
t.variableDeclaration("const", [
|
|
722
|
-
t.variableDeclarator(
|
|
723
|
-
t.identifier(markerVar),
|
|
724
|
-
buildChildAccess(elId, entry.childIndex)
|
|
725
|
-
)
|
|
943
|
+
t.variableDeclarator(t.identifier(markerVar), init)
|
|
726
944
|
])
|
|
727
945
|
);
|
|
946
|
+
prevVar = markerVar;
|
|
947
|
+
prevIndex = idx;
|
|
728
948
|
}
|
|
729
949
|
}
|
|
730
950
|
function getMarker(idx) {
|
|
@@ -735,10 +955,48 @@ function whatBabelPlugin({ types: t }) {
|
|
|
735
955
|
}
|
|
736
956
|
for (const entry of entries) {
|
|
737
957
|
if (entry.type === "expression") {
|
|
738
|
-
|
|
958
|
+
let expr = entry.child.expression;
|
|
739
959
|
const marker = getMarker(entry.childIndex);
|
|
740
960
|
state.needsInsert = true;
|
|
961
|
+
let mapResult = tryLowerMapToMapArray(expr, state);
|
|
962
|
+
if (mapResult) {
|
|
963
|
+
state.needsMapArray = true;
|
|
964
|
+
const isBareMapArray = t.isCallExpression(mapResult) && t.isIdentifier(mapResult.callee) && (mapResult.callee.name === "_$mapArray" || mapResult.callee.name === "mapArray");
|
|
965
|
+
const isArrowAlready = t.isArrowFunctionExpression(mapResult);
|
|
966
|
+
if (isArrowAlready && t.isExpression(mapResult.body)) {
|
|
967
|
+
mapResult.body = memoizeBranchCondition(mapResult.body, statements, state);
|
|
968
|
+
} else if (!isBareMapArray && !isArrowAlready) {
|
|
969
|
+
mapResult = memoizeBranchCondition(mapResult, statements, state);
|
|
970
|
+
}
|
|
971
|
+
const insertArg = isBareMapArray || isArrowAlready ? mapResult : t.arrowFunctionExpression([], mapResult);
|
|
972
|
+
statements.push(
|
|
973
|
+
t.expressionStatement(
|
|
974
|
+
t.callExpression(t.identifier("_$insert"), [
|
|
975
|
+
t.identifier(elId),
|
|
976
|
+
insertArg,
|
|
977
|
+
marker
|
|
978
|
+
])
|
|
979
|
+
)
|
|
980
|
+
);
|
|
981
|
+
continue;
|
|
982
|
+
}
|
|
983
|
+
const isMapArrayCall = t.isCallExpression(expr) && t.isIdentifier(expr.callee) && (expr.callee.name === "mapArray" || expr.callee.name === "_$mapArray");
|
|
984
|
+
if (isMapArrayCall) {
|
|
985
|
+
state.needsMapArray = true;
|
|
986
|
+
if (expr.callee.name === "mapArray") expr.callee.name = "_$mapArray";
|
|
987
|
+
statements.push(
|
|
988
|
+
t.expressionStatement(
|
|
989
|
+
t.callExpression(t.identifier("_$insert"), [
|
|
990
|
+
t.identifier(elId),
|
|
991
|
+
expr,
|
|
992
|
+
marker
|
|
993
|
+
])
|
|
994
|
+
)
|
|
995
|
+
);
|
|
996
|
+
continue;
|
|
997
|
+
}
|
|
741
998
|
if (isPotentiallyReactive(expr, state.signalNames, state.importedIdentifiers)) {
|
|
999
|
+
expr = memoizeBranchCondition(expr, statements, state);
|
|
742
1000
|
const insertCall = t.callExpression(t.identifier("_$insert"), [
|
|
743
1001
|
t.identifier(elId),
|
|
744
1002
|
t.arrowFunctionExpression([], expr),
|
|
@@ -796,7 +1054,7 @@ function whatBabelPlugin({ types: t }) {
|
|
|
796
1054
|
])
|
|
797
1055
|
);
|
|
798
1056
|
}
|
|
799
|
-
applyDynamicAttrs(statements, childElRef, entry.child.openingElement.attributes, state);
|
|
1057
|
+
applyDynamicAttrs(statements, childElRef, entry.child.openingElement.attributes, state, entry.child.openingElement.name.name);
|
|
800
1058
|
applyDynamicChildren(statements, childElRef, entry.child.children, entry.child, state);
|
|
801
1059
|
continue;
|
|
802
1060
|
}
|
|
@@ -804,8 +1062,9 @@ function whatBabelPlugin({ types: t }) {
|
|
|
804
1062
|
for (const fChild of entry.child.children) {
|
|
805
1063
|
if (t.isJSXExpressionContainer(fChild) && !t.isJSXEmptyExpression(fChild.expression)) {
|
|
806
1064
|
state.needsInsert = true;
|
|
807
|
-
|
|
1065
|
+
let expr = fChild.expression;
|
|
808
1066
|
if (isPotentiallyReactive(expr, state.signalNames, state.importedIdentifiers)) {
|
|
1067
|
+
expr = memoizeBranchCondition(expr, statements, state);
|
|
809
1068
|
statements.push(
|
|
810
1069
|
t.expressionStatement(
|
|
811
1070
|
t.callExpression(t.identifier("_$insert"), [
|
|
@@ -946,7 +1205,7 @@ function whatBabelPlugin({ types: t }) {
|
|
|
946
1205
|
}
|
|
947
1206
|
continue;
|
|
948
1207
|
}
|
|
949
|
-
if (attrName.startsWith("on") && attrName.includes("|")) {
|
|
1208
|
+
if (attrName.startsWith("on") && (attrName.includes("|") || hasEventModifiers(attrName, state))) {
|
|
950
1209
|
const { eventName, modifiers } = parseEventModifiers(attrName);
|
|
951
1210
|
const handler = getAttributeValue(attr.value);
|
|
952
1211
|
const wrappedHandler = createEventHandler(handler, modifiers);
|
|
@@ -964,7 +1223,7 @@ function whatBabelPlugin({ types: t }) {
|
|
|
964
1223
|
const transformedChildren = [];
|
|
965
1224
|
for (const child of children) {
|
|
966
1225
|
if (t.isJSXText(child)) {
|
|
967
|
-
const text = child.value
|
|
1226
|
+
const text = normalizeJsxText(child.value);
|
|
968
1227
|
if (text) transformedChildren.push(t.stringLiteral(text));
|
|
969
1228
|
} else if (t.isJSXExpressionContainer(child)) {
|
|
970
1229
|
if (!t.isJSXEmptyExpression(child.expression)) {
|
|
@@ -998,10 +1257,24 @@ function whatBabelPlugin({ types: t }) {
|
|
|
998
1257
|
const { node } = path;
|
|
999
1258
|
const attributes = node.openingElement.attributes;
|
|
1000
1259
|
const children = node.children;
|
|
1260
|
+
if (true) {
|
|
1261
|
+
const fileName = state.filename || state.file?.opts?.filename || "<unknown>";
|
|
1262
|
+
if (!_forInfoWarned.has(fileName)) {
|
|
1263
|
+
_forInfoWarned.add(fileName);
|
|
1264
|
+
const loc = node.loc;
|
|
1265
|
+
const lineInfo = loc ? `:${loc.start.line}:${loc.start.column}` : "";
|
|
1266
|
+
console.info(
|
|
1267
|
+
`[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).`
|
|
1268
|
+
);
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1001
1271
|
let eachExpr = null;
|
|
1272
|
+
let keyExpr = null;
|
|
1002
1273
|
for (const attr of attributes) {
|
|
1003
|
-
if (t.isJSXAttribute(attr)
|
|
1004
|
-
|
|
1274
|
+
if (t.isJSXAttribute(attr)) {
|
|
1275
|
+
const name = getAttrName(attr);
|
|
1276
|
+
if (name === "each") eachExpr = getAttributeValue(attr.value);
|
|
1277
|
+
else if (name === "key") keyExpr = getAttributeValue(attr.value);
|
|
1005
1278
|
}
|
|
1006
1279
|
}
|
|
1007
1280
|
if (!eachExpr) {
|
|
@@ -1022,11 +1295,124 @@ function whatBabelPlugin({ types: t }) {
|
|
|
1022
1295
|
return transformElementAsH(path, state);
|
|
1023
1296
|
}
|
|
1024
1297
|
state.needsMapArray = true;
|
|
1025
|
-
|
|
1298
|
+
const args = [eachExpr, renderFn];
|
|
1299
|
+
if (keyExpr) {
|
|
1300
|
+
args.push(t.objectExpression([
|
|
1301
|
+
t.objectProperty(t.identifier("key"), keyExpr)
|
|
1302
|
+
]));
|
|
1303
|
+
}
|
|
1304
|
+
return t.callExpression(t.identifier("_$mapArray"), args);
|
|
1026
1305
|
}
|
|
1027
1306
|
function transformShowFineGrained(path, state) {
|
|
1028
|
-
|
|
1029
|
-
|
|
1307
|
+
const { node } = path;
|
|
1308
|
+
const attributes = node.openingElement.attributes;
|
|
1309
|
+
const children = node.children;
|
|
1310
|
+
let whenExpr = null;
|
|
1311
|
+
let fallbackExpr = null;
|
|
1312
|
+
for (const attr of attributes) {
|
|
1313
|
+
if (t.isJSXAttribute(attr)) {
|
|
1314
|
+
const name = getAttrName(attr);
|
|
1315
|
+
if (name === "when") whenExpr = getAttributeValue(attr.value);
|
|
1316
|
+
else if (name === "fallback") fallbackExpr = getAttributeValue(attr.value);
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
if (!whenExpr) {
|
|
1320
|
+
throw path.buildCodeFrameError(
|
|
1321
|
+
'<Show> requires a "when" prop. Example: <Show when={isOpen} fallback={null}>...</Show>'
|
|
1322
|
+
);
|
|
1323
|
+
}
|
|
1324
|
+
let contentExpr = null;
|
|
1325
|
+
for (const child of children) {
|
|
1326
|
+
if (t.isJSXExpressionContainer(child) && !t.isJSXEmptyExpression(child.expression)) {
|
|
1327
|
+
contentExpr = child.expression;
|
|
1328
|
+
break;
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
if (!contentExpr) {
|
|
1332
|
+
const transformedChildren = [];
|
|
1333
|
+
for (const child of children) {
|
|
1334
|
+
if (t.isJSXText(child)) {
|
|
1335
|
+
const text = normalizeJsxText(child.value);
|
|
1336
|
+
if (text) transformedChildren.push(t.stringLiteral(text));
|
|
1337
|
+
} else if (t.isJSXElement(child)) {
|
|
1338
|
+
transformedChildren.push(transformElementFineGrained({ node: child }, state));
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
if (transformedChildren.length === 1) {
|
|
1342
|
+
contentExpr = transformedChildren[0];
|
|
1343
|
+
} else if (transformedChildren.length > 1) {
|
|
1344
|
+
contentExpr = t.arrayExpression(transformedChildren);
|
|
1345
|
+
} else {
|
|
1346
|
+
contentExpr = t.nullLiteral();
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
let condition;
|
|
1350
|
+
if (t.isCallExpression(whenExpr)) {
|
|
1351
|
+
condition = whenExpr;
|
|
1352
|
+
} else if (t.isArrowFunctionExpression(whenExpr) && t.isExpression(whenExpr.body)) {
|
|
1353
|
+
condition = whenExpr.body;
|
|
1354
|
+
} else if (t.isIdentifier(whenExpr) && (state.signalNames && isSignalIdentifier(whenExpr.name, state.signalNames) || state.importedIdentifiers && state.importedIdentifiers.has(whenExpr.name))) {
|
|
1355
|
+
condition = t.callExpression(whenExpr, []);
|
|
1356
|
+
} else {
|
|
1357
|
+
condition = whenExpr;
|
|
1358
|
+
}
|
|
1359
|
+
const vId = path.scope ? path.scope.generateUidIdentifier("v") : t.identifier("_v");
|
|
1360
|
+
const contentIsFn = t.isFunction(contentExpr);
|
|
1361
|
+
const consequent = contentIsFn ? t.callExpression(contentExpr, [t.cloneNode(vId)]) : contentExpr;
|
|
1362
|
+
const alternate = fallbackExpr || t.nullLiteral();
|
|
1363
|
+
if (isPotentiallyReactive(condition, state.signalNames, state.importedIdentifiers)) {
|
|
1364
|
+
const condId = state.nextMemoId();
|
|
1365
|
+
state.needsMemo = true;
|
|
1366
|
+
const memoBody = contentIsFn ? condition : t.unaryExpression("!", t.unaryExpression("!", condition));
|
|
1367
|
+
if (!state._pendingSetup) state._pendingSetup = [];
|
|
1368
|
+
state._pendingSetup.push(
|
|
1369
|
+
t.variableDeclaration("const", [
|
|
1370
|
+
t.variableDeclarator(
|
|
1371
|
+
t.identifier(condId),
|
|
1372
|
+
t.callExpression(t.identifier("_$memo"), [
|
|
1373
|
+
t.arrowFunctionExpression([], memoBody)
|
|
1374
|
+
])
|
|
1375
|
+
)
|
|
1376
|
+
])
|
|
1377
|
+
);
|
|
1378
|
+
condition = t.callExpression(t.identifier(condId), []);
|
|
1379
|
+
}
|
|
1380
|
+
return t.arrowFunctionExpression([], t.blockStatement([
|
|
1381
|
+
t.variableDeclaration("const", [
|
|
1382
|
+
t.variableDeclarator(vId, condition)
|
|
1383
|
+
]),
|
|
1384
|
+
t.returnStatement(
|
|
1385
|
+
t.conditionalExpression(t.cloneNode(vId), consequent, alternate)
|
|
1386
|
+
)
|
|
1387
|
+
]));
|
|
1388
|
+
}
|
|
1389
|
+
function lowerFragmentExprChild(expr, state) {
|
|
1390
|
+
if (!state._pendingSetup) state._pendingSetup = [];
|
|
1391
|
+
const setup = state._pendingSetup;
|
|
1392
|
+
const mapResult = tryLowerMapToMapArray(expr, state);
|
|
1393
|
+
if (mapResult) {
|
|
1394
|
+
state.needsMapArray = true;
|
|
1395
|
+
const isBareMapArray = t.isCallExpression(mapResult) && t.isIdentifier(mapResult.callee) && (mapResult.callee.name === "_$mapArray" || mapResult.callee.name === "mapArray");
|
|
1396
|
+
const isArrowAlready = t.isArrowFunctionExpression(mapResult);
|
|
1397
|
+
if (isArrowAlready && t.isExpression(mapResult.body)) {
|
|
1398
|
+
mapResult.body = memoizeBranchCondition(mapResult.body, setup, state);
|
|
1399
|
+
return mapResult;
|
|
1400
|
+
}
|
|
1401
|
+
if (isBareMapArray) return mapResult;
|
|
1402
|
+
const memoized = memoizeBranchCondition(mapResult, setup, state);
|
|
1403
|
+
return t.arrowFunctionExpression([], memoized);
|
|
1404
|
+
}
|
|
1405
|
+
const isMapArrayCall = t.isCallExpression(expr) && t.isIdentifier(expr.callee) && (expr.callee.name === "mapArray" || expr.callee.name === "_$mapArray");
|
|
1406
|
+
if (isMapArrayCall) {
|
|
1407
|
+
state.needsMapArray = true;
|
|
1408
|
+
if (expr.callee.name === "mapArray") expr.callee.name = "_$mapArray";
|
|
1409
|
+
return expr;
|
|
1410
|
+
}
|
|
1411
|
+
if (isPotentiallyReactive(expr, state.signalNames, state.importedIdentifiers)) {
|
|
1412
|
+
expr = memoizeBranchCondition(expr, setup, state);
|
|
1413
|
+
return t.arrowFunctionExpression([], expr);
|
|
1414
|
+
}
|
|
1415
|
+
return expr;
|
|
1030
1416
|
}
|
|
1031
1417
|
function transformFragmentFineGrained(path, state) {
|
|
1032
1418
|
const { node } = path;
|
|
@@ -1034,11 +1420,11 @@ function whatBabelPlugin({ types: t }) {
|
|
|
1034
1420
|
const transformed = [];
|
|
1035
1421
|
for (const child of children) {
|
|
1036
1422
|
if (t.isJSXText(child)) {
|
|
1037
|
-
const text = child.value
|
|
1423
|
+
const text = normalizeJsxText(child.value);
|
|
1038
1424
|
if (text) transformed.push(t.stringLiteral(text));
|
|
1039
1425
|
} else if (t.isJSXExpressionContainer(child)) {
|
|
1040
1426
|
if (!t.isJSXEmptyExpression(child.expression)) {
|
|
1041
|
-
transformed.push(child.expression);
|
|
1427
|
+
transformed.push(lowerFragmentExprChild(child.expression, state));
|
|
1042
1428
|
}
|
|
1043
1429
|
} else if (t.isJSXElement(child)) {
|
|
1044
1430
|
transformed.push(transformElementFineGrained({ node: child }, state));
|
|
@@ -1058,6 +1444,46 @@ function whatBabelPlugin({ types: t }) {
|
|
|
1058
1444
|
state.templates.push({ id, html });
|
|
1059
1445
|
return id;
|
|
1060
1446
|
}
|
|
1447
|
+
function transformJsxRoot(path, state, transform) {
|
|
1448
|
+
const scope = path.scope;
|
|
1449
|
+
let cache = state._signalNamesCache;
|
|
1450
|
+
if (!cache) cache = state._signalNamesCache = /* @__PURE__ */ new WeakMap();
|
|
1451
|
+
let names = cache.get(scope);
|
|
1452
|
+
if (!names) {
|
|
1453
|
+
names = collectSignalNamesFromScope(path);
|
|
1454
|
+
cache.set(scope, names);
|
|
1455
|
+
}
|
|
1456
|
+
state.signalNames = names;
|
|
1457
|
+
state._pendingSetup = [];
|
|
1458
|
+
const transformed = transform(path, state);
|
|
1459
|
+
const pending = state._pendingSetup;
|
|
1460
|
+
state._pendingSetup = [];
|
|
1461
|
+
if (pending.length > 0) {
|
|
1462
|
+
let stmtPath = path;
|
|
1463
|
+
let crossedFunctionBoundary = false;
|
|
1464
|
+
while (stmtPath && !stmtPath.isStatement()) {
|
|
1465
|
+
if (stmtPath.isArrowFunctionExpression() || stmtPath.isFunctionExpression()) {
|
|
1466
|
+
crossedFunctionBoundary = true;
|
|
1467
|
+
}
|
|
1468
|
+
stmtPath = stmtPath.parentPath;
|
|
1469
|
+
}
|
|
1470
|
+
const inStatementList = stmtPath && stmtPath.isStatement() && (stmtPath.listKey === "body" || stmtPath.listKey === "consequent") && Array.isArray(stmtPath.container);
|
|
1471
|
+
if (inStatementList && !crossedFunctionBoundary) {
|
|
1472
|
+
stmtPath.insertBefore(pending);
|
|
1473
|
+
path.replaceWith(transformed);
|
|
1474
|
+
} else {
|
|
1475
|
+
pending.push(t.returnStatement(transformed));
|
|
1476
|
+
path.replaceWith(
|
|
1477
|
+
t.callExpression(
|
|
1478
|
+
t.arrowFunctionExpression([], t.blockStatement(pending)),
|
|
1479
|
+
[]
|
|
1480
|
+
)
|
|
1481
|
+
);
|
|
1482
|
+
}
|
|
1483
|
+
} else {
|
|
1484
|
+
path.replaceWith(transformed);
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1061
1487
|
return {
|
|
1062
1488
|
name: "what-jsx-transform",
|
|
1063
1489
|
visitor: {
|
|
@@ -1069,6 +1495,12 @@ function whatBabelPlugin({ types: t }) {
|
|
|
1069
1495
|
state.needsMapArray = false;
|
|
1070
1496
|
state.needsSpread = false;
|
|
1071
1497
|
state.needsSetProp = false;
|
|
1498
|
+
state.needsMemo = false;
|
|
1499
|
+
state.needsSetClass = false;
|
|
1500
|
+
state.needsSetStyle = false;
|
|
1501
|
+
state.needsSetAttr = false;
|
|
1502
|
+
state.needsSetValue = false;
|
|
1503
|
+
state.needsSetChecked = false;
|
|
1072
1504
|
state.needsH = false;
|
|
1073
1505
|
state.needsCreateComponent = false;
|
|
1074
1506
|
state.needsFragment = false;
|
|
@@ -1079,8 +1511,10 @@ function whatBabelPlugin({ types: t }) {
|
|
|
1079
1511
|
state.templateMap = /* @__PURE__ */ new Map();
|
|
1080
1512
|
state.templateCount = 0;
|
|
1081
1513
|
state._varCounter = 0;
|
|
1514
|
+
state._memoCounter = 0;
|
|
1082
1515
|
state._pendingSetup = [];
|
|
1083
1516
|
state.nextVarId = () => `_el$${state._varCounter++}`;
|
|
1517
|
+
state.nextMemoId = () => `_c$${state._memoCounter++}`;
|
|
1084
1518
|
state.signalNames = /* @__PURE__ */ new Set();
|
|
1085
1519
|
state.importedIdentifiers = /* @__PURE__ */ new Set();
|
|
1086
1520
|
for (const node of path.node.body) {
|
|
@@ -1136,20 +1570,19 @@ function whatBabelPlugin({ types: t }) {
|
|
|
1136
1570
|
},
|
|
1137
1571
|
exit(path, state) {
|
|
1138
1572
|
for (const tmpl of state.templates.reverse()) {
|
|
1573
|
+
const tmplCall = t.callExpression(t.identifier("_$template"), [t.stringLiteral(tmpl.html)]);
|
|
1574
|
+
t.addComment(tmplCall, "leading", " @__PURE__ ");
|
|
1139
1575
|
path.unshiftContainer(
|
|
1140
1576
|
"body",
|
|
1141
1577
|
t.variableDeclaration("const", [
|
|
1142
|
-
t.variableDeclarator(
|
|
1143
|
-
t.identifier(tmpl.id),
|
|
1144
|
-
t.callExpression(t.identifier("_$template"), [t.stringLiteral(tmpl.html)])
|
|
1145
|
-
)
|
|
1578
|
+
t.variableDeclarator(t.identifier(tmpl.id), tmplCall)
|
|
1146
1579
|
])
|
|
1147
1580
|
);
|
|
1148
1581
|
}
|
|
1149
1582
|
const fgSpecifiers = [];
|
|
1150
1583
|
if (state.needsTemplate) {
|
|
1151
1584
|
fgSpecifiers.push(
|
|
1152
|
-
t.importSpecifier(t.identifier("_$template"), t.identifier("template"))
|
|
1585
|
+
t.importSpecifier(t.identifier("_$template"), t.identifier("_$template"))
|
|
1153
1586
|
);
|
|
1154
1587
|
}
|
|
1155
1588
|
if (state.needsInsert) {
|
|
@@ -1177,6 +1610,36 @@ function whatBabelPlugin({ types: t }) {
|
|
|
1177
1610
|
t.importSpecifier(t.identifier("_$setProp"), t.identifier("setProp"))
|
|
1178
1611
|
);
|
|
1179
1612
|
}
|
|
1613
|
+
if (state.needsMemo) {
|
|
1614
|
+
fgSpecifiers.push(
|
|
1615
|
+
t.importSpecifier(t.identifier("_$memo"), t.identifier("memo"))
|
|
1616
|
+
);
|
|
1617
|
+
}
|
|
1618
|
+
if (state.needsSetClass) {
|
|
1619
|
+
fgSpecifiers.push(
|
|
1620
|
+
t.importSpecifier(t.identifier("_$setClass"), t.identifier("setClass"))
|
|
1621
|
+
);
|
|
1622
|
+
}
|
|
1623
|
+
if (state.needsSetStyle) {
|
|
1624
|
+
fgSpecifiers.push(
|
|
1625
|
+
t.importSpecifier(t.identifier("_$setStyle"), t.identifier("setStyle"))
|
|
1626
|
+
);
|
|
1627
|
+
}
|
|
1628
|
+
if (state.needsSetAttr) {
|
|
1629
|
+
fgSpecifiers.push(
|
|
1630
|
+
t.importSpecifier(t.identifier("_$setAttr"), t.identifier("setAttr"))
|
|
1631
|
+
);
|
|
1632
|
+
}
|
|
1633
|
+
if (state.needsSetValue) {
|
|
1634
|
+
fgSpecifiers.push(
|
|
1635
|
+
t.importSpecifier(t.identifier("_$setValue"), t.identifier("setValue"))
|
|
1636
|
+
);
|
|
1637
|
+
}
|
|
1638
|
+
if (state.needsSetChecked) {
|
|
1639
|
+
fgSpecifiers.push(
|
|
1640
|
+
t.importSpecifier(t.identifier("_$setChecked"), t.identifier("setChecked"))
|
|
1641
|
+
);
|
|
1642
|
+
}
|
|
1180
1643
|
if (state.needsCreateComponent) {
|
|
1181
1644
|
fgSpecifiers.push(
|
|
1182
1645
|
t.importSpecifier(t.identifier("_$createComponent"), t.identifier("_$createComponent"))
|
|
@@ -1234,47 +1697,36 @@ function whatBabelPlugin({ types: t }) {
|
|
|
1234
1697
|
const eventArray = t.arrayExpression(
|
|
1235
1698
|
[...state.delegatedEvents].map((e) => t.stringLiteral(e))
|
|
1236
1699
|
);
|
|
1237
|
-
|
|
1238
|
-
"
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1700
|
+
const helperFn = t.functionDeclaration(
|
|
1701
|
+
t.identifier("_$delegate$"),
|
|
1702
|
+
[],
|
|
1703
|
+
t.blockStatement([
|
|
1704
|
+
t.ifStatement(
|
|
1705
|
+
t.identifier("_$delegated$"),
|
|
1706
|
+
t.returnStatement()
|
|
1707
|
+
),
|
|
1708
|
+
t.expressionStatement(
|
|
1709
|
+
t.assignmentExpression("=", t.identifier("_$delegated$"), t.booleanLiteral(true))
|
|
1710
|
+
),
|
|
1711
|
+
t.expressionStatement(
|
|
1712
|
+
t.callExpression(t.identifier("_$delegateEvents"), [eventArray])
|
|
1713
|
+
)
|
|
1714
|
+
])
|
|
1242
1715
|
);
|
|
1716
|
+
path.unshiftContainer("body", [
|
|
1717
|
+
t.variableDeclaration("let", [
|
|
1718
|
+
t.variableDeclarator(t.identifier("_$delegated$"), t.booleanLiteral(false))
|
|
1719
|
+
]),
|
|
1720
|
+
helperFn
|
|
1721
|
+
]);
|
|
1243
1722
|
}
|
|
1244
1723
|
}
|
|
1245
1724
|
},
|
|
1246
1725
|
JSXElement(path, state) {
|
|
1247
|
-
state
|
|
1248
|
-
state._pendingSetup = [];
|
|
1249
|
-
const transformed = transformElementFineGrained(path, state);
|
|
1250
|
-
const pending = state._pendingSetup;
|
|
1251
|
-
state._pendingSetup = [];
|
|
1252
|
-
if (pending.length > 0) {
|
|
1253
|
-
let stmtPath = path;
|
|
1254
|
-
while (stmtPath && !stmtPath.isStatement()) {
|
|
1255
|
-
stmtPath = stmtPath.parentPath;
|
|
1256
|
-
}
|
|
1257
|
-
if (stmtPath && stmtPath.isStatement()) {
|
|
1258
|
-
for (const stmt of pending) {
|
|
1259
|
-
stmtPath.insertBefore(stmt);
|
|
1260
|
-
}
|
|
1261
|
-
path.replaceWith(transformed);
|
|
1262
|
-
} else {
|
|
1263
|
-
pending.push(t.returnStatement(transformed));
|
|
1264
|
-
path.replaceWith(
|
|
1265
|
-
t.callExpression(
|
|
1266
|
-
t.arrowFunctionExpression([], t.blockStatement(pending)),
|
|
1267
|
-
[]
|
|
1268
|
-
)
|
|
1269
|
-
);
|
|
1270
|
-
}
|
|
1271
|
-
} else {
|
|
1272
|
-
path.replaceWith(transformed);
|
|
1273
|
-
}
|
|
1726
|
+
transformJsxRoot(path, state, transformElementFineGrained);
|
|
1274
1727
|
},
|
|
1275
1728
|
JSXFragment(path, state) {
|
|
1276
|
-
|
|
1277
|
-
path.replaceWith(transformed);
|
|
1729
|
+
transformJsxRoot(path, state, transformFragmentFineGrained);
|
|
1278
1730
|
}
|
|
1279
1731
|
}
|
|
1280
1732
|
};
|