@fluixi/compiler 1.0.0-alpha.104 → 1.0.0-alpha.106

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.
Files changed (71) hide show
  1. package/dist/analyze/static-graph.cjs +1 -1
  2. package/dist/analyze/static-graph.mjs +1 -1
  3. package/dist/{babel-5SX36G76.mjs → babel-HJY4RVAV.mjs} +33 -20
  4. package/dist/{chunk-NWF66YTU.mjs → chunk-4XEOMQ57.mjs} +1 -1
  5. package/dist/{chunk-FMQPBKTW.mjs → chunk-JUFI6IR3.mjs} +1 -1
  6. package/dist/{chunk-NUET3BJB.mjs → chunk-LCQHL2VQ.mjs} +132 -10
  7. package/dist/{chunk-2O2YW5ZO.mjs → chunk-LGUZRHYN.mjs} +2 -2
  8. package/dist/{chunk-RBIYCE6M.mjs → chunk-TDN5MYWI.mjs} +1 -1
  9. package/dist/{chunk-ZDZKJQ5N.mjs → chunk-W7DYOMXJ.mjs} +2 -2
  10. package/dist/{chunk-DN33T5GJ.mjs → chunk-WHEDRMNR.mjs} +1 -1
  11. package/dist/codegen/backends/imperative.cjs +130 -8
  12. package/dist/codegen/backends/imperative.d.ts.map +1 -1
  13. package/dist/codegen/backends/imperative.js +62 -0
  14. package/dist/codegen/backends/imperative.mjs +130 -8
  15. package/dist/codegen/partial-template.cjs +80 -8
  16. package/dist/codegen/partial-template.d.cts +21 -4
  17. package/dist/codegen/partial-template.d.ts +21 -4
  18. package/dist/codegen/partial-template.d.ts.map +1 -1
  19. package/dist/codegen/partial-template.js +0 -0
  20. package/dist/codegen/partial-template.mjs +80 -8
  21. package/dist/codegen/serialize-static.cjs +1 -0
  22. package/dist/codegen/serialize-static.d.cts +8 -0
  23. package/dist/codegen/serialize-static.d.ts +8 -0
  24. package/dist/codegen/serialize-static.d.ts.map +1 -1
  25. package/dist/codegen/serialize-static.js +1 -1
  26. package/dist/codegen/serialize-static.mjs +1 -0
  27. package/dist/frontend/babel/build-ir-html.cjs +149 -21
  28. package/dist/frontend/babel/build-ir-html.d.cts +3 -1
  29. package/dist/frontend/babel/build-ir-html.d.ts +3 -1
  30. package/dist/frontend/babel/build-ir-html.d.ts.map +1 -1
  31. package/dist/frontend/babel/build-ir-html.mjs +149 -21
  32. package/dist/frontend/babel/build-ir.cjs +149 -21
  33. package/dist/frontend/babel/build-ir.d.cts +11 -2
  34. package/dist/frontend/babel/build-ir.d.ts +11 -2
  35. package/dist/frontend/babel/build-ir.d.ts.map +1 -1
  36. package/dist/frontend/babel/build-ir.js +15 -9
  37. package/dist/frontend/babel/build-ir.mjs +149 -21
  38. package/dist/frontend/babel/index.cjs +160 -25
  39. package/dist/frontend/babel/index.mjs +160 -25
  40. package/dist/frontend/babel/lower-template.cjs +149 -21
  41. package/dist/frontend/babel/lower-template.d.cts +2 -1
  42. package/dist/frontend/babel/lower-template.d.ts +2 -1
  43. package/dist/frontend/babel/lower-template.d.ts.map +1 -1
  44. package/dist/frontend/babel/lower-template.js +4 -4
  45. package/dist/frontend/babel/lower-template.mjs +149 -21
  46. package/dist/frontend/babel/plugin.cjs +158 -23
  47. package/dist/frontend/babel/plugin.js +9 -2
  48. package/dist/frontend/babel/plugin.mjs +158 -23
  49. package/dist/index.cjs +131 -9
  50. package/dist/index.mjs +131 -9
  51. package/dist/integrations.cjs +165 -33
  52. package/dist/integrations.mjs +11 -11
  53. package/dist/lower/compile-template.cjs +131 -9
  54. package/dist/lower/compile-template.mjs +131 -9
  55. package/dist/lower/jsx.cjs +130 -8
  56. package/dist/lower/jsx.mjs +130 -8
  57. package/dist/lower/template.cjs +130 -8
  58. package/dist/lower/template.mjs +130 -8
  59. package/dist/resolve/builtins.cjs +1 -1
  60. package/dist/resolve/builtins.mjs +1 -1
  61. package/dist/{server-fns-3Z3ZKJLB.mjs → server-fns-WZJK4BJE.mjs} +5 -5
  62. package/dist/{server-functions-DB7AHWE6.mjs → server-functions-4KTFFEO3.mjs} +3 -3
  63. package/dist/transform/index.cjs +135 -16
  64. package/dist/transform/index.mjs +135 -16
  65. package/dist/transform/templates.cjs +134 -15
  66. package/dist/transform/templates.d.ts.map +1 -1
  67. package/dist/transform/templates.js +4 -8
  68. package/dist/transform/templates.mjs +134 -15
  69. package/dist/{transform-VMK2URDB.mjs → transform-NO46NFQH.mjs} +11 -14
  70. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  71. package/package.json +4 -4
@@ -1,4 +1,4 @@
1
- /*! @fluixi/compiler v1.0.0-alpha.104 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/compiler v1.0.0-alpha.106 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
 
3
3
  // ../../node_modules/.pnpm/@jridgewell+sourcemap-codec@1.6.0/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.mjs
4
4
  var comma = ",".charCodeAt(0);
@@ -368,10 +368,64 @@ function isHole(node) {
368
368
  function isTemplateChild(node) {
369
369
  return node.kind === "text" || node.kind === "element" && isTemplateElement(node);
370
370
  }
371
+ var PROPERTY_BINDS = /* @__PURE__ */ new Set(["indeterminate"]);
372
+ function disposition(prop) {
373
+ if (prop.kind === "spread") return null;
374
+ if (prop.name === "ref") return "ref";
375
+ if (prop.name === "use") return "use";
376
+ if (prop.kind === "event") return prop.event ? "event" : null;
377
+ if (prop.kind === "prop") return "property";
378
+ if (prop.kind !== "attr") return null;
379
+ const name = prop.name;
380
+ if (name.startsWith("on:")) return "nativeEvent";
381
+ if (name.startsWith("prop:")) return "property";
382
+ if (name.startsWith("attr:")) return "attr";
383
+ if (name.startsWith("bool:")) return "boolAttr";
384
+ if (name === "className" || name === "class") {
385
+ return isPlainLiteralAttr(prop) ? "serialize" : "class";
386
+ }
387
+ if (name === "classList") {
388
+ if (isPlainLiteralAttr(prop)) return "serialize";
389
+ return prop.reactive ? "classListDynamic" : "classList";
390
+ }
391
+ if (name === "style") {
392
+ if (isPlainLiteralAttr(prop)) return "serialize";
393
+ return prop.reactive ? "styleDynamic" : "style";
394
+ }
395
+ if (name.includes(":")) return null;
396
+ if (PROPERTY_ONLY.has(name)) return null;
397
+ if (PROPERTY_BINDS.has(name)) return "property";
398
+ if (prop.expr === void 0) return isPlainLiteralAttr(prop) ? "serialize" : null;
399
+ return "attr";
400
+ }
401
+ function effectiveProps(el) {
402
+ const order = [];
403
+ const byName = /* @__PURE__ */ new Map();
404
+ for (const prop of el.props) {
405
+ if (!byName.has(prop.name)) order.push(prop.name);
406
+ byName.set(prop.name, prop);
407
+ }
408
+ return order.map((name) => byName.get(name));
409
+ }
410
+ function propPlan(el) {
411
+ const custom = el.tag.includes("-");
412
+ const plan = { serialize: [], bindings: [] };
413
+ for (const prop of effectiveProps(el)) {
414
+ const kind = disposition(prop);
415
+ if (kind === null) return null;
416
+ if (kind === "serialize") {
417
+ plan.serialize.push(prop);
418
+ continue;
419
+ }
420
+ if (custom) return null;
421
+ plan.bindings.push({ prop, kind });
422
+ }
423
+ return plan;
424
+ }
371
425
  function isTemplateElement(node) {
372
426
  if (node.svg) return false;
373
427
  if (isRawTextElement(node.tag)) return false;
374
- if (!node.props.every((p) => isPlainLiteralAttr(p))) return false;
428
+ if (!propPlan(node)) return false;
375
429
  return node.children.every((c) => isTemplateChild(c) || isHole(c));
376
430
  }
377
431
  function containsHole(node) {
@@ -379,6 +433,15 @@ function containsHole(node) {
379
433
  const children = node.children;
380
434
  return children ? children.some(containsHole) : false;
381
435
  }
436
+ function containsBinding(node) {
437
+ if (node.kind !== "element") return false;
438
+ const plan = propPlan(node);
439
+ if (plan && plan.bindings.length > 0) return true;
440
+ return node.children.some(containsBinding);
441
+ }
442
+ function interesting(node) {
443
+ return containsHole(node) || containsBinding(node);
444
+ }
382
445
  function addressable(el) {
383
446
  for (let i = 0; i < el.children.length; i++) {
384
447
  const child = el.children[i];
@@ -392,9 +455,10 @@ function addressable(el) {
392
455
  function planPartialTemplate(root) {
393
456
  if (!isTemplateElement(root)) return null;
394
457
  if (!addressable(root)) return null;
395
- if (!root.children.some(containsHole)) return null;
458
+ if (!interesting(root)) return null;
396
459
  const steps = [];
397
460
  const holes = [];
461
+ const bindings = [];
398
462
  let refCount = 0;
399
463
  const declare = (expr) => {
400
464
  const ref = `_n$${refCount++}`;
@@ -402,11 +466,17 @@ function planPartialTemplate(root) {
402
466
  return ref;
403
467
  };
404
468
  walk2(root, "_el$");
405
- return { html: serializeWithMarkers(root), tag: root.tag, steps, holes };
469
+ return { html: serializeWithMarkers(root), tag: root.tag, steps, holes, bindings };
406
470
  function walk2(el, elementRef) {
471
+ const plan = propPlan(el);
472
+ if (plan) {
473
+ for (const binding of plan.bindings) {
474
+ bindings.push({ ref: elementRef, prop: binding.prop, kind: binding.kind });
475
+ }
476
+ }
407
477
  let last = -1;
408
478
  el.children.forEach((child, i) => {
409
- if (containsHole(child)) last = i;
479
+ if (interesting(child)) last = i;
410
480
  });
411
481
  let previous = null;
412
482
  for (let i = 0; i <= last; i++) {
@@ -420,19 +490,21 @@ function planPartialTemplate(root) {
420
490
  continue;
421
491
  }
422
492
  const ref = declare(expr);
423
- if (child.kind === "element" && containsHole(child)) walk2(child, ref);
493
+ if (child.kind === "element" && interesting(child)) walk2(child, ref);
424
494
  previous = ref;
425
495
  }
426
496
  }
427
497
  }
428
498
  function serializeWithMarkers(el) {
429
- return serializeStatic(withSentinels(el)).split(SENTINEL).join(HOLE_START + HOLE_END);
499
+ return serializeStatic(templateTree(el)).split(SENTINEL).join(HOLE_START + HOLE_END);
430
500
  }
431
- function withSentinels(el) {
501
+ function templateTree(el) {
502
+ const plan = propPlan(el);
432
503
  return {
433
504
  ...el,
505
+ props: plan ? plan.serialize : [],
434
506
  children: el.children.map(
435
- (child) => isHole(child) ? { kind: "text", value: SENTINEL } : child.kind === "element" ? withSentinels(child) : child
507
+ (child) => isHole(child) ? { kind: "text", value: SENTINEL } : child.kind === "element" ? templateTree(child) : child
436
508
  )
437
509
  };
438
510
  }
@@ -705,6 +777,55 @@ function emitComponent(name, props, children, used, templates, at) {
705
777
  const mark = at ? `globalThis.${SOURCE_MARKER}?.(${JSON.stringify(at.file)},${at.line},${at.column},${JSON.stringify(name)}), ` : "";
706
778
  return `createMemo(${paren(`${mark}() => createComponent(${name}, ${obj})`, "value")})`;
707
779
  }
780
+ function bindingTarget(binding) {
781
+ const name = binding.prop.name;
782
+ if (binding.kind === "boolAttr") return name.slice("bool:".length);
783
+ if (name.startsWith("prop:")) return name.slice("prop:".length);
784
+ if (name.startsWith("attr:")) return name.slice("attr:".length);
785
+ return htmlAttrName(name);
786
+ }
787
+ function bindingStatement(binding, used) {
788
+ const { ref, prop, kind } = binding;
789
+ const value = propValue(prop);
790
+ switch (kind) {
791
+ case "class":
792
+ used.add("setClassName");
793
+ return `setClassName(${ref}, ${value});`;
794
+ case "classList":
795
+ used.add("setClassList");
796
+ return `setClassList(${ref}, ${value}, []);`;
797
+ case "classListDynamic":
798
+ used.add("setDynamicClassList");
799
+ return `setDynamicClassList(${ref}, ${value});`;
800
+ case "style":
801
+ used.add("setStyle");
802
+ return `setStyle(${ref}, ${value}, []);`;
803
+ case "styleDynamic":
804
+ used.add("setDynamicStyle");
805
+ return `setDynamicStyle(${ref}, ${value});`;
806
+ case "attr":
807
+ used.add("setDynamicAttribute");
808
+ return `setDynamicAttribute(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
809
+ case "property":
810
+ used.add("setDynamicProperty");
811
+ return `setDynamicProperty(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
812
+ case "boolAttr":
813
+ used.add("setDynamicBoolAttribute");
814
+ return `setDynamicBoolAttribute(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
815
+ case "event":
816
+ used.add("addDelegatedEventListener");
817
+ return `addDelegatedEventListener(${ref}, ${JSON.stringify(prop.event.name)}, ${value});`;
818
+ case "nativeEvent":
819
+ used.add("addNativeEventListener");
820
+ return `addNativeEventListener(${ref}, ${JSON.stringify(prop.name.slice(3))}, ${value});`;
821
+ case "ref":
822
+ used.add("handleRef");
823
+ return `handleRef(${value}, ${ref});`;
824
+ case "use":
825
+ used.add("applyUse");
826
+ return `applyUse(${ref}, ${value});`;
827
+ }
828
+ }
708
829
  function staticAttrAssignment(el, prop) {
709
830
  const name = htmlAttrName(prop.name);
710
831
  const value = prop.literal;
@@ -755,6 +876,7 @@ function emitNode(node, used, templates) {
755
876
  `const _el$ = templateNode(${id}, ${JSON.stringify(plan.tag)}, true${at ? `, false, ${JSON.stringify(at)}` : ""});`
756
877
  ];
757
878
  for (const step of plan.steps) lines.push(`const ${step.ref} = ${step.expr};`);
879
+ for (const binding of plan.bindings) lines.push(bindingStatement(binding, used));
758
880
  for (const hole of plan.holes) {
759
881
  lines.push(
760
882
  `insert(${hole.parentRef}, holeScope(${hole.startRef}, () => ${paren(emitNode(hole.node, used, templates), "arrowBody")}), ${hole.endRef}, holeContent(${hole.startRef}, ${hole.endRef}));`
@@ -482,10 +482,64 @@ function isHole(node) {
482
482
  function isTemplateChild(node) {
483
483
  return node.kind === "text" || node.kind === "element" && isTemplateElement(node);
484
484
  }
485
+ var PROPERTY_BINDS = /* @__PURE__ */ new Set(["indeterminate"]);
486
+ function disposition(prop) {
487
+ if (prop.kind === "spread") return null;
488
+ if (prop.name === "ref") return "ref";
489
+ if (prop.name === "use") return "use";
490
+ if (prop.kind === "event") return prop.event ? "event" : null;
491
+ if (prop.kind === "prop") return "property";
492
+ if (prop.kind !== "attr") return null;
493
+ const name = prop.name;
494
+ if (name.startsWith("on:")) return "nativeEvent";
495
+ if (name.startsWith("prop:")) return "property";
496
+ if (name.startsWith("attr:")) return "attr";
497
+ if (name.startsWith("bool:")) return "boolAttr";
498
+ if (name === "className" || name === "class") {
499
+ return isPlainLiteralAttr(prop) ? "serialize" : "class";
500
+ }
501
+ if (name === "classList") {
502
+ if (isPlainLiteralAttr(prop)) return "serialize";
503
+ return prop.reactive ? "classListDynamic" : "classList";
504
+ }
505
+ if (name === "style") {
506
+ if (isPlainLiteralAttr(prop)) return "serialize";
507
+ return prop.reactive ? "styleDynamic" : "style";
508
+ }
509
+ if (name.includes(":")) return null;
510
+ if (PROPERTY_ONLY.has(name)) return null;
511
+ if (PROPERTY_BINDS.has(name)) return "property";
512
+ if (prop.expr === void 0) return isPlainLiteralAttr(prop) ? "serialize" : null;
513
+ return "attr";
514
+ }
515
+ function effectiveProps(el) {
516
+ const order = [];
517
+ const byName = /* @__PURE__ */ new Map();
518
+ for (const prop of el.props) {
519
+ if (!byName.has(prop.name)) order.push(prop.name);
520
+ byName.set(prop.name, prop);
521
+ }
522
+ return order.map((name) => byName.get(name));
523
+ }
524
+ function propPlan(el) {
525
+ const custom = el.tag.includes("-");
526
+ const plan = { serialize: [], bindings: [] };
527
+ for (const prop of effectiveProps(el)) {
528
+ const kind = disposition(prop);
529
+ if (kind === null) return null;
530
+ if (kind === "serialize") {
531
+ plan.serialize.push(prop);
532
+ continue;
533
+ }
534
+ if (custom) return null;
535
+ plan.bindings.push({ prop, kind });
536
+ }
537
+ return plan;
538
+ }
485
539
  function isTemplateElement(node) {
486
540
  if (node.svg) return false;
487
541
  if (isRawTextElement(node.tag)) return false;
488
- if (!node.props.every((p) => isPlainLiteralAttr(p))) return false;
542
+ if (!propPlan(node)) return false;
489
543
  return node.children.every((c) => isTemplateChild(c) || isHole(c));
490
544
  }
491
545
  function containsHole(node) {
@@ -493,6 +547,15 @@ function containsHole(node) {
493
547
  const children = node.children;
494
548
  return children ? children.some(containsHole) : false;
495
549
  }
550
+ function containsBinding(node) {
551
+ if (node.kind !== "element") return false;
552
+ const plan = propPlan(node);
553
+ if (plan && plan.bindings.length > 0) return true;
554
+ return node.children.some(containsBinding);
555
+ }
556
+ function interesting(node) {
557
+ return containsHole(node) || containsBinding(node);
558
+ }
496
559
  function addressable(el) {
497
560
  for (let i = 0; i < el.children.length; i++) {
498
561
  const child = el.children[i];
@@ -506,9 +569,10 @@ function addressable(el) {
506
569
  function planPartialTemplate(root) {
507
570
  if (!isTemplateElement(root)) return null;
508
571
  if (!addressable(root)) return null;
509
- if (!root.children.some(containsHole)) return null;
572
+ if (!interesting(root)) return null;
510
573
  const steps = [];
511
574
  const holes = [];
575
+ const bindings = [];
512
576
  let refCount = 0;
513
577
  const declare = (expr) => {
514
578
  const ref = `_n$${refCount++}`;
@@ -516,11 +580,17 @@ function planPartialTemplate(root) {
516
580
  return ref;
517
581
  };
518
582
  walk(root, "_el$");
519
- return { html: serializeWithMarkers(root), tag: root.tag, steps, holes };
583
+ return { html: serializeWithMarkers(root), tag: root.tag, steps, holes, bindings };
520
584
  function walk(el, elementRef) {
585
+ const plan = propPlan(el);
586
+ if (plan) {
587
+ for (const binding of plan.bindings) {
588
+ bindings.push({ ref: elementRef, prop: binding.prop, kind: binding.kind });
589
+ }
590
+ }
521
591
  let last = -1;
522
592
  el.children.forEach((child, i) => {
523
- if (containsHole(child)) last = i;
593
+ if (interesting(child)) last = i;
524
594
  });
525
595
  let previous = null;
526
596
  for (let i = 0; i <= last; i++) {
@@ -534,19 +604,21 @@ function planPartialTemplate(root) {
534
604
  continue;
535
605
  }
536
606
  const ref = declare(expr);
537
- if (child.kind === "element" && containsHole(child)) walk(child, ref);
607
+ if (child.kind === "element" && interesting(child)) walk(child, ref);
538
608
  previous = ref;
539
609
  }
540
610
  }
541
611
  }
542
612
  function serializeWithMarkers(el) {
543
- return serializeStatic(withSentinels(el)).split(SENTINEL).join(HOLE_START + HOLE_END);
613
+ return serializeStatic(templateTree(el)).split(SENTINEL).join(HOLE_START + HOLE_END);
544
614
  }
545
- function withSentinels(el) {
615
+ function templateTree(el) {
616
+ const plan = propPlan(el);
546
617
  return {
547
618
  ...el,
619
+ props: plan ? plan.serialize : [],
548
620
  children: el.children.map(
549
- (child) => isHole(child) ? { kind: "text", value: SENTINEL } : child.kind === "element" ? withSentinels(child) : child
621
+ (child) => isHole(child) ? { kind: "text", value: SENTINEL } : child.kind === "element" ? templateTree(child) : child
550
622
  )
551
623
  };
552
624
  }
@@ -665,6 +737,55 @@ function emitComponent(name, props, children, used, templates, at) {
665
737
  const mark = at ? `globalThis.${SOURCE_MARKER}?.(${JSON.stringify(at.file)},${at.line},${at.column},${JSON.stringify(name)}), ` : "";
666
738
  return `createMemo(${paren(`${mark}() => createComponent(${name}, ${obj})`, "value")})`;
667
739
  }
740
+ function bindingTarget(binding) {
741
+ const name = binding.prop.name;
742
+ if (binding.kind === "boolAttr") return name.slice("bool:".length);
743
+ if (name.startsWith("prop:")) return name.slice("prop:".length);
744
+ if (name.startsWith("attr:")) return name.slice("attr:".length);
745
+ return htmlAttrName(name);
746
+ }
747
+ function bindingStatement(binding, used) {
748
+ const { ref, prop, kind } = binding;
749
+ const value = propValue(prop);
750
+ switch (kind) {
751
+ case "class":
752
+ used.add("setClassName");
753
+ return `setClassName(${ref}, ${value});`;
754
+ case "classList":
755
+ used.add("setClassList");
756
+ return `setClassList(${ref}, ${value}, []);`;
757
+ case "classListDynamic":
758
+ used.add("setDynamicClassList");
759
+ return `setDynamicClassList(${ref}, ${value});`;
760
+ case "style":
761
+ used.add("setStyle");
762
+ return `setStyle(${ref}, ${value}, []);`;
763
+ case "styleDynamic":
764
+ used.add("setDynamicStyle");
765
+ return `setDynamicStyle(${ref}, ${value});`;
766
+ case "attr":
767
+ used.add("setDynamicAttribute");
768
+ return `setDynamicAttribute(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
769
+ case "property":
770
+ used.add("setDynamicProperty");
771
+ return `setDynamicProperty(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
772
+ case "boolAttr":
773
+ used.add("setDynamicBoolAttribute");
774
+ return `setDynamicBoolAttribute(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
775
+ case "event":
776
+ used.add("addDelegatedEventListener");
777
+ return `addDelegatedEventListener(${ref}, ${JSON.stringify(prop.event.name)}, ${value});`;
778
+ case "nativeEvent":
779
+ used.add("addNativeEventListener");
780
+ return `addNativeEventListener(${ref}, ${JSON.stringify(prop.name.slice(3))}, ${value});`;
781
+ case "ref":
782
+ used.add("handleRef");
783
+ return `handleRef(${value}, ${ref});`;
784
+ case "use":
785
+ used.add("applyUse");
786
+ return `applyUse(${ref}, ${value});`;
787
+ }
788
+ }
668
789
  function staticAttrAssignment(el, prop) {
669
790
  const name = htmlAttrName(prop.name);
670
791
  const value = prop.literal;
@@ -715,6 +836,7 @@ function emitNode(node, used, templates) {
715
836
  `const _el$ = templateNode(${id}, ${JSON.stringify(plan.tag)}, true${at ? `, false, ${JSON.stringify(at)}` : ""});`
716
837
  ];
717
838
  for (const step of plan.steps) lines.push(`const ${step.ref} = ${step.expr};`);
839
+ for (const binding of plan.bindings) lines.push(bindingStatement(binding, used));
718
840
  for (const hole of plan.holes) {
719
841
  lines.push(
720
842
  `insert(${hole.parentRef}, holeScope(${hole.startRef}, () => ${paren(emitNode(hole.node, used, templates), "arrowBody")}), ${hole.endRef}, holeContent(${hole.startRef}, ${hole.endRef}));`
@@ -455,10 +455,64 @@ function isHole(node) {
455
455
  function isTemplateChild(node) {
456
456
  return node.kind === "text" || node.kind === "element" && isTemplateElement(node);
457
457
  }
458
+ var PROPERTY_BINDS = /* @__PURE__ */ new Set(["indeterminate"]);
459
+ function disposition(prop) {
460
+ if (prop.kind === "spread") return null;
461
+ if (prop.name === "ref") return "ref";
462
+ if (prop.name === "use") return "use";
463
+ if (prop.kind === "event") return prop.event ? "event" : null;
464
+ if (prop.kind === "prop") return "property";
465
+ if (prop.kind !== "attr") return null;
466
+ const name = prop.name;
467
+ if (name.startsWith("on:")) return "nativeEvent";
468
+ if (name.startsWith("prop:")) return "property";
469
+ if (name.startsWith("attr:")) return "attr";
470
+ if (name.startsWith("bool:")) return "boolAttr";
471
+ if (name === "className" || name === "class") {
472
+ return isPlainLiteralAttr(prop) ? "serialize" : "class";
473
+ }
474
+ if (name === "classList") {
475
+ if (isPlainLiteralAttr(prop)) return "serialize";
476
+ return prop.reactive ? "classListDynamic" : "classList";
477
+ }
478
+ if (name === "style") {
479
+ if (isPlainLiteralAttr(prop)) return "serialize";
480
+ return prop.reactive ? "styleDynamic" : "style";
481
+ }
482
+ if (name.includes(":")) return null;
483
+ if (PROPERTY_ONLY.has(name)) return null;
484
+ if (PROPERTY_BINDS.has(name)) return "property";
485
+ if (prop.expr === void 0) return isPlainLiteralAttr(prop) ? "serialize" : null;
486
+ return "attr";
487
+ }
488
+ function effectiveProps(el) {
489
+ const order = [];
490
+ const byName = /* @__PURE__ */ new Map();
491
+ for (const prop of el.props) {
492
+ if (!byName.has(prop.name)) order.push(prop.name);
493
+ byName.set(prop.name, prop);
494
+ }
495
+ return order.map((name) => byName.get(name));
496
+ }
497
+ function propPlan(el) {
498
+ const custom = el.tag.includes("-");
499
+ const plan = { serialize: [], bindings: [] };
500
+ for (const prop of effectiveProps(el)) {
501
+ const kind = disposition(prop);
502
+ if (kind === null) return null;
503
+ if (kind === "serialize") {
504
+ plan.serialize.push(prop);
505
+ continue;
506
+ }
507
+ if (custom) return null;
508
+ plan.bindings.push({ prop, kind });
509
+ }
510
+ return plan;
511
+ }
458
512
  function isTemplateElement(node) {
459
513
  if (node.svg) return false;
460
514
  if (isRawTextElement(node.tag)) return false;
461
- if (!node.props.every((p) => isPlainLiteralAttr(p))) return false;
515
+ if (!propPlan(node)) return false;
462
516
  return node.children.every((c) => isTemplateChild(c) || isHole(c));
463
517
  }
464
518
  function containsHole(node) {
@@ -466,6 +520,15 @@ function containsHole(node) {
466
520
  const children = node.children;
467
521
  return children ? children.some(containsHole) : false;
468
522
  }
523
+ function containsBinding(node) {
524
+ if (node.kind !== "element") return false;
525
+ const plan = propPlan(node);
526
+ if (plan && plan.bindings.length > 0) return true;
527
+ return node.children.some(containsBinding);
528
+ }
529
+ function interesting(node) {
530
+ return containsHole(node) || containsBinding(node);
531
+ }
469
532
  function addressable(el) {
470
533
  for (let i = 0; i < el.children.length; i++) {
471
534
  const child = el.children[i];
@@ -479,9 +542,10 @@ function addressable(el) {
479
542
  function planPartialTemplate(root) {
480
543
  if (!isTemplateElement(root)) return null;
481
544
  if (!addressable(root)) return null;
482
- if (!root.children.some(containsHole)) return null;
545
+ if (!interesting(root)) return null;
483
546
  const steps = [];
484
547
  const holes = [];
548
+ const bindings = [];
485
549
  let refCount = 0;
486
550
  const declare = (expr) => {
487
551
  const ref = `_n$${refCount++}`;
@@ -489,11 +553,17 @@ function planPartialTemplate(root) {
489
553
  return ref;
490
554
  };
491
555
  walk(root, "_el$");
492
- return { html: serializeWithMarkers(root), tag: root.tag, steps, holes };
556
+ return { html: serializeWithMarkers(root), tag: root.tag, steps, holes, bindings };
493
557
  function walk(el, elementRef) {
558
+ const plan = propPlan(el);
559
+ if (plan) {
560
+ for (const binding of plan.bindings) {
561
+ bindings.push({ ref: elementRef, prop: binding.prop, kind: binding.kind });
562
+ }
563
+ }
494
564
  let last = -1;
495
565
  el.children.forEach((child, i) => {
496
- if (containsHole(child)) last = i;
566
+ if (interesting(child)) last = i;
497
567
  });
498
568
  let previous = null;
499
569
  for (let i = 0; i <= last; i++) {
@@ -507,19 +577,21 @@ function planPartialTemplate(root) {
507
577
  continue;
508
578
  }
509
579
  const ref = declare(expr);
510
- if (child.kind === "element" && containsHole(child)) walk(child, ref);
580
+ if (child.kind === "element" && interesting(child)) walk(child, ref);
511
581
  previous = ref;
512
582
  }
513
583
  }
514
584
  }
515
585
  function serializeWithMarkers(el) {
516
- return serializeStatic(withSentinels(el)).split(SENTINEL).join(HOLE_START + HOLE_END);
586
+ return serializeStatic(templateTree(el)).split(SENTINEL).join(HOLE_START + HOLE_END);
517
587
  }
518
- function withSentinels(el) {
588
+ function templateTree(el) {
589
+ const plan = propPlan(el);
519
590
  return {
520
591
  ...el,
592
+ props: plan ? plan.serialize : [],
521
593
  children: el.children.map(
522
- (child) => isHole(child) ? { kind: "text", value: SENTINEL } : child.kind === "element" ? withSentinels(child) : child
594
+ (child) => isHole(child) ? { kind: "text", value: SENTINEL } : child.kind === "element" ? templateTree(child) : child
523
595
  )
524
596
  };
525
597
  }
@@ -638,6 +710,55 @@ function emitComponent(name, props, children, used, templates, at) {
638
710
  const mark = at ? `globalThis.${SOURCE_MARKER}?.(${JSON.stringify(at.file)},${at.line},${at.column},${JSON.stringify(name)}), ` : "";
639
711
  return `createMemo(${paren(`${mark}() => createComponent(${name}, ${obj})`, "value")})`;
640
712
  }
713
+ function bindingTarget(binding) {
714
+ const name = binding.prop.name;
715
+ if (binding.kind === "boolAttr") return name.slice("bool:".length);
716
+ if (name.startsWith("prop:")) return name.slice("prop:".length);
717
+ if (name.startsWith("attr:")) return name.slice("attr:".length);
718
+ return htmlAttrName(name);
719
+ }
720
+ function bindingStatement(binding, used) {
721
+ const { ref, prop, kind } = binding;
722
+ const value = propValue(prop);
723
+ switch (kind) {
724
+ case "class":
725
+ used.add("setClassName");
726
+ return `setClassName(${ref}, ${value});`;
727
+ case "classList":
728
+ used.add("setClassList");
729
+ return `setClassList(${ref}, ${value}, []);`;
730
+ case "classListDynamic":
731
+ used.add("setDynamicClassList");
732
+ return `setDynamicClassList(${ref}, ${value});`;
733
+ case "style":
734
+ used.add("setStyle");
735
+ return `setStyle(${ref}, ${value}, []);`;
736
+ case "styleDynamic":
737
+ used.add("setDynamicStyle");
738
+ return `setDynamicStyle(${ref}, ${value});`;
739
+ case "attr":
740
+ used.add("setDynamicAttribute");
741
+ return `setDynamicAttribute(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
742
+ case "property":
743
+ used.add("setDynamicProperty");
744
+ return `setDynamicProperty(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
745
+ case "boolAttr":
746
+ used.add("setDynamicBoolAttribute");
747
+ return `setDynamicBoolAttribute(${ref}, ${JSON.stringify(bindingTarget(binding))}, ${value});`;
748
+ case "event":
749
+ used.add("addDelegatedEventListener");
750
+ return `addDelegatedEventListener(${ref}, ${JSON.stringify(prop.event.name)}, ${value});`;
751
+ case "nativeEvent":
752
+ used.add("addNativeEventListener");
753
+ return `addNativeEventListener(${ref}, ${JSON.stringify(prop.name.slice(3))}, ${value});`;
754
+ case "ref":
755
+ used.add("handleRef");
756
+ return `handleRef(${value}, ${ref});`;
757
+ case "use":
758
+ used.add("applyUse");
759
+ return `applyUse(${ref}, ${value});`;
760
+ }
761
+ }
641
762
  function staticAttrAssignment(el, prop) {
642
763
  const name = htmlAttrName(prop.name);
643
764
  const value = prop.literal;
@@ -688,6 +809,7 @@ function emitNode(node, used, templates) {
688
809
  `const _el$ = templateNode(${id}, ${JSON.stringify(plan.tag)}, true${at ? `, false, ${JSON.stringify(at)}` : ""});`
689
810
  ];
690
811
  for (const step of plan.steps) lines.push(`const ${step.ref} = ${step.expr};`);
812
+ for (const binding of plan.bindings) lines.push(bindingStatement(binding, used));
691
813
  for (const hole of plan.holes) {
692
814
  lines.push(
693
815
  `insert(${hole.parentRef}, holeScope(${hole.startRef}, () => ${paren(emitNode(hole.node, used, templates), "arrowBody")}), ${hole.endRef}, holeContent(${hole.startRef}, ${hole.endRef}));`