@fluixi/compiler 1.0.0-alpha.91 → 1.0.0-alpha.93
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/analyze/intrinsics.cjs +21 -1
- package/dist/analyze/intrinsics.d.ts.map +1 -1
- package/dist/analyze/intrinsics.js +20 -0
- package/dist/analyze/intrinsics.mjs +21 -1
- package/dist/analyze/reactive-bindings.cjs +21 -1
- package/dist/analyze/reactive-bindings.mjs +21 -1
- package/dist/analyze/static-graph.cjs +25 -5
- package/dist/analyze/static-graph.d.ts.map +1 -1
- package/dist/analyze/static-graph.js +6 -4
- package/dist/analyze/static-graph.mjs +25 -5
- package/dist/{babel-VBLQRHQ2.mjs → babel-RJHJQVEM.mjs} +4 -4
- package/dist/{chunk-D53J7ICY.mjs → chunk-56QSOVVL.mjs} +1 -1
- package/dist/{chunk-S4J4OCWK.mjs → chunk-OD53TMER.mjs} +22 -2
- package/dist/{chunk-TWDJUXWZ.mjs → chunk-R7PPFBCL.mjs} +1 -1
- package/dist/{chunk-QX6Y3OAR.mjs → chunk-TJIH7TLX.mjs} +1 -1
- package/dist/{chunk-3JWMCK4A.mjs → chunk-U7HCFLZ2.mjs} +153 -48
- package/dist/codegen/backends/imperative.cjs +27 -7
- package/dist/codegen/backends/imperative.d.ts.map +1 -1
- package/dist/codegen/backends/imperative.js +19 -4
- package/dist/codegen/backends/imperative.mjs +27 -7
- package/dist/frontend/babel/build-ir-lit.cjs +123 -44
- package/dist/frontend/babel/build-ir-lit.mjs +123 -44
- package/dist/frontend/babel/build-ir.cjs +123 -44
- package/dist/frontend/babel/build-ir.mjs +123 -44
- package/dist/frontend/babel/index.cjs +124 -45
- package/dist/frontend/babel/index.mjs +124 -45
- package/dist/frontend/babel/lower-template.cjs +123 -44
- package/dist/frontend/babel/lower-template.mjs +123 -44
- package/dist/frontend/babel/plugin.cjs +123 -44
- package/dist/frontend/babel/plugin.mjs +123 -44
- package/dist/index.cjs +86 -46
- package/dist/index.mjs +88 -48
- package/dist/integrations.cjs +246 -61
- package/dist/integrations.mjs +53 -19
- package/dist/lower/compile-template.cjs +44 -39
- package/dist/lower/compile-template.mjs +44 -39
- package/dist/lower/jsx.cjs +509 -6
- package/dist/lower/jsx.d.ts.map +1 -1
- package/dist/lower/jsx.js +114 -6
- package/dist/lower/jsx.mjs +509 -6
- package/dist/lower/template.cjs +43 -38
- package/dist/lower/template.d.ts.map +1 -1
- package/dist/lower/template.js +22 -30
- package/dist/lower/template.mjs +43 -38
- package/dist/resolve/builtins.cjs +1 -1
- package/dist/resolve/builtins.mjs +1 -1
- package/dist/resolve/component-globals.cjs +33 -8
- package/dist/resolve/component-globals.d.cts +8 -0
- package/dist/resolve/component-globals.d.ts +8 -0
- package/dist/resolve/component-globals.d.ts.map +1 -1
- package/dist/resolve/component-globals.js +21 -12
- package/dist/resolve/component-globals.mjs +33 -8
- package/dist/resolve/write-globals.cjs +59 -8
- package/dist/resolve/write-globals.d.cts +6 -0
- package/dist/resolve/write-globals.d.ts +6 -0
- package/dist/resolve/write-globals.d.ts.map +1 -1
- package/dist/resolve/write-globals.js +35 -2
- package/dist/resolve/write-globals.mjs +61 -10
- package/dist/{server-fns-J56G3PFP.mjs → server-fns-ZFRDIQ2X.mjs} +4 -4
- package/dist/{server-functions-7PUFLRGF.mjs → server-functions-CTDXX67X.mjs} +3 -3
- package/dist/transform/index.cjs +199 -49
- package/dist/transform/index.mjs +199 -49
- package/dist/transform/intrinsics.cjs +47 -2
- package/dist/transform/intrinsics.d.cts +12 -0
- package/dist/transform/intrinsics.d.ts +12 -0
- package/dist/transform/intrinsics.d.ts.map +1 -1
- package/dist/transform/intrinsics.js +43 -1
- package/dist/transform/intrinsics.mjs +47 -2
- package/dist/transform/source-locations.cjs +67 -4
- package/dist/transform/source-locations.d.cts +7 -2
- package/dist/transform/source-locations.d.ts +7 -2
- package/dist/transform/source-locations.d.ts.map +1 -1
- package/dist/transform/source-locations.js +68 -3
- package/dist/transform/source-locations.mjs +67 -4
- package/dist/transform/templates.cjs +198 -48
- package/dist/transform/templates.d.ts.map +1 -1
- package/dist/transform/templates.js +5 -3
- package/dist/transform/templates.mjs +198 -48
- package/dist/{transform-D536WXGM.mjs → transform-QWWQDCXE.mjs} +33 -8
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/package.json +9 -3
|
@@ -469,6 +469,7 @@ var INTRINSICS = {
|
|
|
469
469
|
$effect: { export: "effect", module: REACTIVE_MODULE, returns: "effect" },
|
|
470
470
|
$store: { export: "store", module: "@fluixi/reactive/store", returns: "store-handle" },
|
|
471
471
|
$resource: { export: "resource", module: REACTIVE_MODULE, returns: "resource-handle" },
|
|
472
|
+
$cachedResource: { export: "cachedResource", module: "@fluixi/reactive/cached-resource", returns: "resource-handle" },
|
|
472
473
|
// No short runtime form for these yet, so the intrinsic stands for the `create*`
|
|
473
474
|
// name. Still worth having: no import to write, and when a shorter form is
|
|
474
475
|
// designed, the change is this line rather than a compiler pass.
|
|
@@ -478,7 +479,22 @@ var INTRINSICS = {
|
|
|
478
479
|
// does. `untrack` suppresses dependency collection, which is exactly the kind of thing
|
|
479
480
|
// dependency analysis must not guess at.
|
|
480
481
|
$untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
|
|
481
|
-
$untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" }
|
|
482
|
+
$untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
|
|
483
|
+
// Scopes, scheduling and lifecycle: no value to classify, but the same authoring promise,
|
|
484
|
+
// no import to write. `$cleanup` registers a callback on the current owner (`onCleanup`).
|
|
485
|
+
$batch: { export: "batch", module: REACTIVE_MODULE, returns: "plain" },
|
|
486
|
+
$cleanup: { export: "onCleanup", module: REACTIVE_MODULE, returns: "plain" },
|
|
487
|
+
$root: { export: "root", module: REACTIVE_MODULE, returns: "plain" },
|
|
488
|
+
$context: { export: "context", module: REACTIVE_MODULE, returns: "plain" },
|
|
489
|
+
$renderEffect: { export: "renderEffect", module: REACTIVE_MODULE, returns: "effect" },
|
|
490
|
+
$computed: { export: "computed", module: REACTIVE_MODULE, returns: "effect" },
|
|
491
|
+
// Storage for where the code runs, and a signal kept in it. `$persisted` is a signal
|
|
492
|
+
// handle as far as reads go: the same accessor with `set` on it.
|
|
493
|
+
$storage: { export: "useStorage", module: "@fluixi/core/storage", returns: "plain" },
|
|
494
|
+
$asyncStorage: { export: "useAsyncStorage", module: "@fluixi/core/storage", returns: "plain" },
|
|
495
|
+
$persisted: { export: "persisted", module: "@fluixi/core/storage", returns: "signal-handle" },
|
|
496
|
+
// An environment variable, public or server-only; the browser build refuses a secret.
|
|
497
|
+
$env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
|
|
482
498
|
};
|
|
483
499
|
var INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join("|")})\\s*\\(`);
|
|
484
500
|
|
|
@@ -654,13 +670,16 @@ function emitComponent(name, props, children, used, templates, at) {
|
|
|
654
670
|
used.add("createComponent");
|
|
655
671
|
const spreads = props.filter((p) => p.kind === "spread");
|
|
656
672
|
const normal = props.filter((p) => p.kind !== "spread");
|
|
657
|
-
const
|
|
658
|
-
(p) => `get ${propKey(p.name)}() { return ${componentPropValue(p)}; }`
|
|
659
|
-
);
|
|
673
|
+
const bodies = normal.map((p) => [p.name, componentPropValue(p)]);
|
|
660
674
|
if (children.length > 0) {
|
|
661
|
-
|
|
675
|
+
bodies.push(["children", emitChildren(children, used, templates)]);
|
|
676
|
+
}
|
|
677
|
+
let obj = `{ ${bodies.map(([name2, body]) => `get ${propKey(name2)}() { return ${body}; }`).join(", ")} }`;
|
|
678
|
+
if (bodies.some(([, body]) => /\bthis\b/.test(body))) {
|
|
679
|
+
const thunks = bodies.map(([name2, body]) => `${JSON.stringify(name2)}: () => ${body}`);
|
|
680
|
+
const getters = bodies.map(([name2]) => `get ${propKey(name2)}() { return _$t[${JSON.stringify(name2)}](); }`);
|
|
681
|
+
obj = `((_$t) => ({ ${getters.join(", ")} }))({ ${thunks.join(", ")} })`;
|
|
662
682
|
}
|
|
663
|
-
let obj = `{ ${entries.join(", ")} }`;
|
|
664
683
|
if (spreads.length > 0) {
|
|
665
684
|
used.add("mergeProps");
|
|
666
685
|
obj = `mergeProps(${spreads.map((s) => s.expr).join(", ")}, ${obj})`;
|
|
@@ -742,7 +761,8 @@ function emitNode(node, used, templates) {
|
|
|
742
761
|
} else {
|
|
743
762
|
used.add("spread");
|
|
744
763
|
const svgFlag = node.svg ? ", isSVG: true" : "";
|
|
745
|
-
const
|
|
764
|
+
const accessors = node.props.filter((p) => p.kind !== "spread" && p.expr !== void 0 && p.reactive && p.name !== "ref").map((p) => p.name);
|
|
765
|
+
const customFlag = node.tag.includes("-") ? `, isCustomElement: true, accessors: ${JSON.stringify(accessors)}` : "";
|
|
746
766
|
parts.push(
|
|
747
767
|
`spread({ element: ${el}, props: ${emitProps(node.props, null, used)}${svgFlag}${customFlag} });`
|
|
748
768
|
);
|
|
@@ -820,6 +840,7 @@ var DELEGATED = /* @__PURE__ */ new Set([
|
|
|
820
840
|
function escapeTemplate(s) {
|
|
821
841
|
return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
|
|
822
842
|
}
|
|
843
|
+
var CONTAINER = "container";
|
|
823
844
|
function capitalize(s) {
|
|
824
845
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
825
846
|
}
|
|
@@ -874,10 +895,6 @@ var Lowerer = class {
|
|
|
874
895
|
if (hasElse) i = elseIdx;
|
|
875
896
|
continue;
|
|
876
897
|
}
|
|
877
|
-
if (child.attributes.some((a) => a.kind === "EachDirective")) {
|
|
878
|
-
out.push(this.lowerEach(child));
|
|
879
|
-
continue;
|
|
880
|
-
}
|
|
881
898
|
}
|
|
882
899
|
const node = this.lowerNode(child);
|
|
883
900
|
if (node) out.push(node);
|
|
@@ -919,13 +936,16 @@ var Lowerer = class {
|
|
|
919
936
|
node.props.unshift({ name: "component", kind: "attr", expr: `() => ${paren(this.hole(isAttr.value.hole).code, "arrowBody")}` });
|
|
920
937
|
return node;
|
|
921
938
|
}
|
|
939
|
+
const each = this.lowerEach(el);
|
|
940
|
+
const children = each ? [each] : this.lowerChildren(el.children);
|
|
941
|
+
if (el.tag === CONTAINER) return children.length === 1 ? children[0] : { kind: "fragment", children };
|
|
922
942
|
const at = this.tagAt(el);
|
|
923
943
|
return {
|
|
924
944
|
kind: "element",
|
|
925
945
|
tag: el.tag,
|
|
926
946
|
svg: el.namespace === "svg",
|
|
927
947
|
props: this.lowerAttributes(el.attributes),
|
|
928
|
-
children
|
|
948
|
+
children,
|
|
929
949
|
static: false,
|
|
930
950
|
...at ? { at } : {}
|
|
931
951
|
};
|
|
@@ -997,10 +1017,14 @@ var Lowerer = class {
|
|
|
997
1017
|
const at = this.tagAt(el);
|
|
998
1018
|
return { kind: "component", name: "Show", props, children: [child], ...at ? { at } : {}, ...cond.at ? { bindAt: cond.at } : {} };
|
|
999
1019
|
}
|
|
1000
|
-
/**
|
|
1020
|
+
/**
|
|
1021
|
+
* `<el each=${items} key?>${item => …}</el>` → `<el><For each>{item => …}</For></el>`: the
|
|
1022
|
+
* content is repeated per item. Content that is not a `${item => …}` arrow is repeated as
|
|
1023
|
+
* it is. Null when the element has no `each`.
|
|
1024
|
+
*/
|
|
1001
1025
|
lowerEach(el) {
|
|
1002
1026
|
const eachDir = el.attributes.find((a) => a.kind === "EachDirective");
|
|
1003
|
-
if (!eachDir || eachDir.kind !== "EachDirective") return
|
|
1027
|
+
if (!eachDir || eachDir.kind !== "EachDirective") return null;
|
|
1004
1028
|
const each = this.hole(eachDir.hole);
|
|
1005
1029
|
const props = [{ name: "each", kind: "attr", expr: each.code, reactive: each.reactive, ...each.at ? { at: each.at } : {} }];
|
|
1006
1030
|
if (eachDir.key) {
|
|
@@ -1010,12 +1034,12 @@ var Lowerer = class {
|
|
|
1010
1034
|
const arrow = this.itemArrow(el);
|
|
1011
1035
|
let childrenCode;
|
|
1012
1036
|
if (arrow) {
|
|
1013
|
-
const
|
|
1014
|
-
|
|
1015
|
-
childrenCode = `(${arrow.params.join(", ")}) => ${paren(this.emit(repeated), "arrowBody")}`;
|
|
1037
|
+
const body = arrow.bodyReactive ? `() => ${paren(arrow.body, "arrowBody")}` : paren(arrow.body, "arrowBody");
|
|
1038
|
+
childrenCode = `(${arrow.params.join(", ")}) => ${body}`;
|
|
1016
1039
|
} else {
|
|
1017
|
-
const
|
|
1018
|
-
|
|
1040
|
+
const content = this.lowerChildren(el.children);
|
|
1041
|
+
const ir = content.length === 1 ? content[0] : { kind: "fragment", children: content };
|
|
1042
|
+
childrenCode = `() => ${paren(this.emit(ir), "arrowBody")}`;
|
|
1019
1043
|
}
|
|
1020
1044
|
const children = [{ kind: "expr", code: childrenCode, reactive: false }];
|
|
1021
1045
|
const at = this.tagAt(el);
|
|
@@ -1032,25 +1056,6 @@ var Lowerer = class {
|
|
|
1032
1056
|
const clone = { ...el, attributes: el.attributes.filter((a) => !drop(a)) };
|
|
1033
1057
|
return clone.kind === "Element" ? this.lowerElement(clone) : this.lowerComponent(clone);
|
|
1034
1058
|
}
|
|
1035
|
-
/** Same element (minus each/key) but with explicit IR children. */
|
|
1036
|
-
rebuildWithChildren(el, children) {
|
|
1037
|
-
const props = this.lowerAttributes(
|
|
1038
|
-
el.attributes.filter((a) => a.kind !== "EachDirective")
|
|
1039
|
-
);
|
|
1040
|
-
if (el.kind === "Element") {
|
|
1041
|
-
const at = this.tagAt(el);
|
|
1042
|
-
return {
|
|
1043
|
-
kind: "element",
|
|
1044
|
-
tag: el.tag,
|
|
1045
|
-
svg: el.namespace === "svg",
|
|
1046
|
-
props,
|
|
1047
|
-
children,
|
|
1048
|
-
static: false,
|
|
1049
|
-
...at ? { at } : {}
|
|
1050
|
-
};
|
|
1051
|
-
}
|
|
1052
|
-
return { kind: "component", name: el.tag, props, children };
|
|
1053
|
-
}
|
|
1054
1059
|
// --- attributes ---------------------------------------------------------
|
|
1055
1060
|
lowerAttributes(attrs) {
|
|
1056
1061
|
const props = [];
|
|
@@ -1462,6 +1467,22 @@ var DELEGATED2 = /* @__PURE__ */ new Set([
|
|
|
1462
1467
|
"mouseup"
|
|
1463
1468
|
]);
|
|
1464
1469
|
var isReactive = (node) => isReactiveShape(shapeOf(node));
|
|
1470
|
+
var CONTAINER2 = "container";
|
|
1471
|
+
function directive(node, name) {
|
|
1472
|
+
if (node.type !== "JSXElement") return void 0;
|
|
1473
|
+
const opening = node.openingElement;
|
|
1474
|
+
if (opening.name.type !== "JSXIdentifier" || opening.name.name[0] !== opening.name.name[0].toLowerCase()) return void 0;
|
|
1475
|
+
return opening.attributes.find((a) => a.type === "JSXAttribute" && a.name.type === "JSXIdentifier" && a.name.name === name);
|
|
1476
|
+
}
|
|
1477
|
+
function directiveExpr(attr) {
|
|
1478
|
+
const v = attr.value;
|
|
1479
|
+
return v?.type === "JSXExpressionContainer" && v.expression?.type !== "JSXEmptyExpression" ? v.expression : void 0;
|
|
1480
|
+
}
|
|
1481
|
+
function emitIR(ir, ctx) {
|
|
1482
|
+
const { code, imports, templates } = imperativeBackend.emit(ir, {});
|
|
1483
|
+
for (const s of imports) ctx.used.add(s);
|
|
1484
|
+
return inlineTemplates(code, templates);
|
|
1485
|
+
}
|
|
1465
1486
|
var posOf = (node, ctx) => {
|
|
1466
1487
|
if (!ctx.sourceFile) return void 0;
|
|
1467
1488
|
const at = node.loc?.start;
|
|
@@ -1570,7 +1591,16 @@ function buildProps(attrs, ctx) {
|
|
|
1570
1591
|
}
|
|
1571
1592
|
function buildChildren(children, ctx) {
|
|
1572
1593
|
const out = [];
|
|
1573
|
-
for (
|
|
1594
|
+
for (let i = 0; i < children.length; i++) {
|
|
1595
|
+
const child = children[i];
|
|
1596
|
+
if (directive(child, "if")) {
|
|
1597
|
+
let next = i + 1;
|
|
1598
|
+
while (next < children.length && children[next].type === "JSXText" && !cleanTemplateText(children[next].value)) next++;
|
|
1599
|
+
const fallback = directive(children[next], "else") ? children[next] : null;
|
|
1600
|
+
out.push(buildIf(child, fallback, ctx));
|
|
1601
|
+
if (fallback) i = next;
|
|
1602
|
+
continue;
|
|
1603
|
+
}
|
|
1574
1604
|
if (child.type === "JSXText") {
|
|
1575
1605
|
const text = cleanTemplateText(child.value);
|
|
1576
1606
|
if (text) out.push({ kind: "text", value: text });
|
|
@@ -1607,19 +1637,68 @@ function readLoad(attrs) {
|
|
|
1607
1637
|
}
|
|
1608
1638
|
return void 0;
|
|
1609
1639
|
}
|
|
1640
|
+
function buildIf(node, fallback, ctx) {
|
|
1641
|
+
const cond = directiveExpr(directive(node, "if"));
|
|
1642
|
+
const props = [
|
|
1643
|
+
cond ? { name: "when", kind: "attr", expr: ctx.code(cond), reactive: isReactive(cond), at: posOf(cond, ctx) } : { name: "when", kind: "attr", literal: true }
|
|
1644
|
+
];
|
|
1645
|
+
if (fallback) {
|
|
1646
|
+
props.push({ name: "fallback", kind: "attr", expr: emitIR(buildElement(fallback, ctx, ["else"]), ctx), jsxElement: true });
|
|
1647
|
+
}
|
|
1648
|
+
return { kind: "component", name: "Show", props, children: [buildElement(node, ctx, ["if"])] };
|
|
1649
|
+
}
|
|
1650
|
+
function buildEach(node, ctx) {
|
|
1651
|
+
const attr = directive(node, "each");
|
|
1652
|
+
if (!attr) return null;
|
|
1653
|
+
const list = directiveExpr(attr);
|
|
1654
|
+
const props = [
|
|
1655
|
+
list ? { name: "each", kind: "attr", expr: ctx.code(list), reactive: isReactive(list), at: posOf(list, ctx) } : { name: "each", kind: "attr", expr: "[]" }
|
|
1656
|
+
];
|
|
1657
|
+
const key = directive(node, "key");
|
|
1658
|
+
if (key) {
|
|
1659
|
+
const keyExpr = directiveExpr(key);
|
|
1660
|
+
const by = isString(key.value) ? `(item) => item[${JSON.stringify(literalOf(key.value))}]` : keyExpr ? ctx.code(keyExpr) : void 0;
|
|
1661
|
+
if (by) props.push({ name: "by", kind: "attr", expr: by });
|
|
1662
|
+
}
|
|
1663
|
+
const content = node.children.filter((c) => !(c.type === "JSXText" && !cleanTemplateText(c.value)));
|
|
1664
|
+
const only = content.length === 1 && content[0].type === "JSXExpressionContainer" ? content[0].expression : null;
|
|
1665
|
+
let render;
|
|
1666
|
+
if (only && (only.type === "ArrowFunctionExpression" || only.type === "FunctionExpression")) {
|
|
1667
|
+
const fn = ctx.code(only);
|
|
1668
|
+
const live = only.type === "ArrowFunctionExpression" && only.body.type !== "BlockStatement" && isReactive(only.body);
|
|
1669
|
+
render = live ? `(...args) => () => (${fn})(...args)` : fn;
|
|
1670
|
+
} else {
|
|
1671
|
+
const built = buildChildren(node.children, ctx);
|
|
1672
|
+
const ir = built.length === 1 ? built[0] : { kind: "fragment", children: built };
|
|
1673
|
+
render = `() => ${paren(emitIR(ir, ctx), "arrowBody")}`;
|
|
1674
|
+
}
|
|
1675
|
+
return { kind: "component", name: "For", props, children: [{ kind: "expr", code: render, reactive: false }] };
|
|
1676
|
+
}
|
|
1677
|
+
function buildElement(node, ctx, handled) {
|
|
1678
|
+
const skip = new Set(handled);
|
|
1679
|
+
const directives = /* @__PURE__ */ new Set(["if", "else", "each", ...directive(node, "each") ? ["key"] : []]);
|
|
1680
|
+
const attributes = node.openingElement.attributes.filter(
|
|
1681
|
+
(a) => !(a.type === "JSXAttribute" && a.name.type === "JSXIdentifier" && (skip.has(a.name.name) || directives.has(a.name.name)))
|
|
1682
|
+
);
|
|
1683
|
+
const { tag } = tagInfo(node.openingElement.name, ctx);
|
|
1684
|
+
const each = buildEach(node, ctx);
|
|
1685
|
+
const children = each ? [each] : buildChildren(node.children, ctx);
|
|
1686
|
+
if (tag === CONTAINER2) return children.length === 1 ? children[0] : { kind: "fragment", children };
|
|
1687
|
+
const at = ctx.sourceFile && node.loc?.start ? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column } : void 0;
|
|
1688
|
+
return { kind: "element", tag, svg: SVG_TAGS.has(tag), props: buildProps(attributes, ctx), children, static: false, ...at ? { at } : {} };
|
|
1689
|
+
}
|
|
1610
1690
|
function buildNode(node, ctx) {
|
|
1611
1691
|
if (node.type === "JSXFragment") {
|
|
1612
1692
|
return { kind: "fragment", children: buildChildren(node.children, ctx) };
|
|
1613
1693
|
}
|
|
1694
|
+
if (directive(node, "if")) return buildIf(node, null, ctx);
|
|
1614
1695
|
const { tag, component } = tagInfo(node.openingElement.name, ctx);
|
|
1696
|
+
if (!component) return buildElement(node, ctx, []);
|
|
1615
1697
|
const props = buildProps(node.openingElement.attributes, ctx);
|
|
1616
1698
|
const children = buildChildren(node.children, ctx);
|
|
1617
1699
|
const at = ctx.sourceFile && node.loc?.start ? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column } : void 0;
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
return { kind: "component", name: tag, props, children, ...load ? { load } : {}, ...at ? { at } : {} };
|
|
1621
|
-
}
|
|
1622
|
-
return { kind: "element", tag, svg: SVG_TAGS.has(tag), props, children, static: false, ...at ? { at } : {} };
|
|
1700
|
+
const load = readLoad(node.openingElement.attributes);
|
|
1701
|
+
return { kind: "component", name: tag, props, children, ...load ? { load } : {}, ...at ? { at } : {} };
|
|
1623
1702
|
}
|
|
1624
1703
|
function buildJsxIR(node, ctx) {
|
|
1625
1704
|
const ir = buildNode(node, ctx);
|
|
@@ -435,6 +435,7 @@ var INTRINSICS = {
|
|
|
435
435
|
$effect: { export: "effect", module: REACTIVE_MODULE, returns: "effect" },
|
|
436
436
|
$store: { export: "store", module: "@fluixi/reactive/store", returns: "store-handle" },
|
|
437
437
|
$resource: { export: "resource", module: REACTIVE_MODULE, returns: "resource-handle" },
|
|
438
|
+
$cachedResource: { export: "cachedResource", module: "@fluixi/reactive/cached-resource", returns: "resource-handle" },
|
|
438
439
|
// No short runtime form for these yet, so the intrinsic stands for the `create*`
|
|
439
440
|
// name. Still worth having: no import to write, and when a shorter form is
|
|
440
441
|
// designed, the change is this line rather than a compiler pass.
|
|
@@ -444,7 +445,22 @@ var INTRINSICS = {
|
|
|
444
445
|
// does. `untrack` suppresses dependency collection, which is exactly the kind of thing
|
|
445
446
|
// dependency analysis must not guess at.
|
|
446
447
|
$untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
|
|
447
|
-
$untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" }
|
|
448
|
+
$untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" },
|
|
449
|
+
// Scopes, scheduling and lifecycle: no value to classify, but the same authoring promise,
|
|
450
|
+
// no import to write. `$cleanup` registers a callback on the current owner (`onCleanup`).
|
|
451
|
+
$batch: { export: "batch", module: REACTIVE_MODULE, returns: "plain" },
|
|
452
|
+
$cleanup: { export: "onCleanup", module: REACTIVE_MODULE, returns: "plain" },
|
|
453
|
+
$root: { export: "root", module: REACTIVE_MODULE, returns: "plain" },
|
|
454
|
+
$context: { export: "context", module: REACTIVE_MODULE, returns: "plain" },
|
|
455
|
+
$renderEffect: { export: "renderEffect", module: REACTIVE_MODULE, returns: "effect" },
|
|
456
|
+
$computed: { export: "computed", module: REACTIVE_MODULE, returns: "effect" },
|
|
457
|
+
// Storage for where the code runs, and a signal kept in it. `$persisted` is a signal
|
|
458
|
+
// handle as far as reads go: the same accessor with `set` on it.
|
|
459
|
+
$storage: { export: "useStorage", module: "@fluixi/core/storage", returns: "plain" },
|
|
460
|
+
$asyncStorage: { export: "useAsyncStorage", module: "@fluixi/core/storage", returns: "plain" },
|
|
461
|
+
$persisted: { export: "persisted", module: "@fluixi/core/storage", returns: "signal-handle" },
|
|
462
|
+
// An environment variable, public or server-only; the browser build refuses a secret.
|
|
463
|
+
$env: { export: "env", module: "@fluixi/start/env", returns: "plain" }
|
|
448
464
|
};
|
|
449
465
|
var INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join("|")})\\s*\\(`);
|
|
450
466
|
|
|
@@ -620,13 +636,16 @@ function emitComponent(name, props, children, used, templates, at) {
|
|
|
620
636
|
used.add("createComponent");
|
|
621
637
|
const spreads = props.filter((p) => p.kind === "spread");
|
|
622
638
|
const normal = props.filter((p) => p.kind !== "spread");
|
|
623
|
-
const
|
|
624
|
-
(p) => `get ${propKey(p.name)}() { return ${componentPropValue(p)}; }`
|
|
625
|
-
);
|
|
639
|
+
const bodies = normal.map((p) => [p.name, componentPropValue(p)]);
|
|
626
640
|
if (children.length > 0) {
|
|
627
|
-
|
|
641
|
+
bodies.push(["children", emitChildren(children, used, templates)]);
|
|
642
|
+
}
|
|
643
|
+
let obj = `{ ${bodies.map(([name2, body]) => `get ${propKey(name2)}() { return ${body}; }`).join(", ")} }`;
|
|
644
|
+
if (bodies.some(([, body]) => /\bthis\b/.test(body))) {
|
|
645
|
+
const thunks = bodies.map(([name2, body]) => `${JSON.stringify(name2)}: () => ${body}`);
|
|
646
|
+
const getters = bodies.map(([name2]) => `get ${propKey(name2)}() { return _$t[${JSON.stringify(name2)}](); }`);
|
|
647
|
+
obj = `((_$t) => ({ ${getters.join(", ")} }))({ ${thunks.join(", ")} })`;
|
|
628
648
|
}
|
|
629
|
-
let obj = `{ ${entries.join(", ")} }`;
|
|
630
649
|
if (spreads.length > 0) {
|
|
631
650
|
used.add("mergeProps");
|
|
632
651
|
obj = `mergeProps(${spreads.map((s) => s.expr).join(", ")}, ${obj})`;
|
|
@@ -708,7 +727,8 @@ function emitNode(node, used, templates) {
|
|
|
708
727
|
} else {
|
|
709
728
|
used.add("spread");
|
|
710
729
|
const svgFlag = node.svg ? ", isSVG: true" : "";
|
|
711
|
-
const
|
|
730
|
+
const accessors = node.props.filter((p) => p.kind !== "spread" && p.expr !== void 0 && p.reactive && p.name !== "ref").map((p) => p.name);
|
|
731
|
+
const customFlag = node.tag.includes("-") ? `, isCustomElement: true, accessors: ${JSON.stringify(accessors)}` : "";
|
|
712
732
|
parts.push(
|
|
713
733
|
`spread({ element: ${el}, props: ${emitProps(node.props, null, used)}${svgFlag}${customFlag} });`
|
|
714
734
|
);
|
|
@@ -788,6 +808,7 @@ var DELEGATED = /* @__PURE__ */ new Set([
|
|
|
788
808
|
function escapeTemplate(s) {
|
|
789
809
|
return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
|
|
790
810
|
}
|
|
811
|
+
var CONTAINER = "container";
|
|
791
812
|
function capitalize(s) {
|
|
792
813
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
793
814
|
}
|
|
@@ -842,10 +863,6 @@ var Lowerer = class {
|
|
|
842
863
|
if (hasElse) i = elseIdx;
|
|
843
864
|
continue;
|
|
844
865
|
}
|
|
845
|
-
if (child.attributes.some((a) => a.kind === "EachDirective")) {
|
|
846
|
-
out.push(this.lowerEach(child));
|
|
847
|
-
continue;
|
|
848
|
-
}
|
|
849
866
|
}
|
|
850
867
|
const node = this.lowerNode(child);
|
|
851
868
|
if (node) out.push(node);
|
|
@@ -887,13 +904,16 @@ var Lowerer = class {
|
|
|
887
904
|
node.props.unshift({ name: "component", kind: "attr", expr: `() => ${paren(this.hole(isAttr.value.hole).code, "arrowBody")}` });
|
|
888
905
|
return node;
|
|
889
906
|
}
|
|
907
|
+
const each = this.lowerEach(el);
|
|
908
|
+
const children = each ? [each] : this.lowerChildren(el.children);
|
|
909
|
+
if (el.tag === CONTAINER) return children.length === 1 ? children[0] : { kind: "fragment", children };
|
|
890
910
|
const at = this.tagAt(el);
|
|
891
911
|
return {
|
|
892
912
|
kind: "element",
|
|
893
913
|
tag: el.tag,
|
|
894
914
|
svg: el.namespace === "svg",
|
|
895
915
|
props: this.lowerAttributes(el.attributes),
|
|
896
|
-
children
|
|
916
|
+
children,
|
|
897
917
|
static: false,
|
|
898
918
|
...at ? { at } : {}
|
|
899
919
|
};
|
|
@@ -965,10 +985,14 @@ var Lowerer = class {
|
|
|
965
985
|
const at = this.tagAt(el);
|
|
966
986
|
return { kind: "component", name: "Show", props, children: [child], ...at ? { at } : {}, ...cond.at ? { bindAt: cond.at } : {} };
|
|
967
987
|
}
|
|
968
|
-
/**
|
|
988
|
+
/**
|
|
989
|
+
* `<el each=${items} key?>${item => …}</el>` → `<el><For each>{item => …}</For></el>`: the
|
|
990
|
+
* content is repeated per item. Content that is not a `${item => …}` arrow is repeated as
|
|
991
|
+
* it is. Null when the element has no `each`.
|
|
992
|
+
*/
|
|
969
993
|
lowerEach(el) {
|
|
970
994
|
const eachDir = el.attributes.find((a) => a.kind === "EachDirective");
|
|
971
|
-
if (!eachDir || eachDir.kind !== "EachDirective") return
|
|
995
|
+
if (!eachDir || eachDir.kind !== "EachDirective") return null;
|
|
972
996
|
const each = this.hole(eachDir.hole);
|
|
973
997
|
const props = [{ name: "each", kind: "attr", expr: each.code, reactive: each.reactive, ...each.at ? { at: each.at } : {} }];
|
|
974
998
|
if (eachDir.key) {
|
|
@@ -978,12 +1002,12 @@ var Lowerer = class {
|
|
|
978
1002
|
const arrow = this.itemArrow(el);
|
|
979
1003
|
let childrenCode;
|
|
980
1004
|
if (arrow) {
|
|
981
|
-
const
|
|
982
|
-
|
|
983
|
-
childrenCode = `(${arrow.params.join(", ")}) => ${paren(this.emit(repeated), "arrowBody")}`;
|
|
1005
|
+
const body = arrow.bodyReactive ? `() => ${paren(arrow.body, "arrowBody")}` : paren(arrow.body, "arrowBody");
|
|
1006
|
+
childrenCode = `(${arrow.params.join(", ")}) => ${body}`;
|
|
984
1007
|
} else {
|
|
985
|
-
const
|
|
986
|
-
|
|
1008
|
+
const content = this.lowerChildren(el.children);
|
|
1009
|
+
const ir = content.length === 1 ? content[0] : { kind: "fragment", children: content };
|
|
1010
|
+
childrenCode = `() => ${paren(this.emit(ir), "arrowBody")}`;
|
|
987
1011
|
}
|
|
988
1012
|
const children = [{ kind: "expr", code: childrenCode, reactive: false }];
|
|
989
1013
|
const at = this.tagAt(el);
|
|
@@ -1000,25 +1024,6 @@ var Lowerer = class {
|
|
|
1000
1024
|
const clone = { ...el, attributes: el.attributes.filter((a) => !drop(a)) };
|
|
1001
1025
|
return clone.kind === "Element" ? this.lowerElement(clone) : this.lowerComponent(clone);
|
|
1002
1026
|
}
|
|
1003
|
-
/** Same element (minus each/key) but with explicit IR children. */
|
|
1004
|
-
rebuildWithChildren(el, children) {
|
|
1005
|
-
const props = this.lowerAttributes(
|
|
1006
|
-
el.attributes.filter((a) => a.kind !== "EachDirective")
|
|
1007
|
-
);
|
|
1008
|
-
if (el.kind === "Element") {
|
|
1009
|
-
const at = this.tagAt(el);
|
|
1010
|
-
return {
|
|
1011
|
-
kind: "element",
|
|
1012
|
-
tag: el.tag,
|
|
1013
|
-
svg: el.namespace === "svg",
|
|
1014
|
-
props,
|
|
1015
|
-
children,
|
|
1016
|
-
static: false,
|
|
1017
|
-
...at ? { at } : {}
|
|
1018
|
-
};
|
|
1019
|
-
}
|
|
1020
|
-
return { kind: "component", name: el.tag, props, children };
|
|
1021
|
-
}
|
|
1022
1027
|
// --- attributes ---------------------------------------------------------
|
|
1023
1028
|
lowerAttributes(attrs) {
|
|
1024
1029
|
const props = [];
|
|
@@ -1430,6 +1435,22 @@ var DELEGATED2 = /* @__PURE__ */ new Set([
|
|
|
1430
1435
|
"mouseup"
|
|
1431
1436
|
]);
|
|
1432
1437
|
var isReactive = (node) => isReactiveShape(shapeOf(node));
|
|
1438
|
+
var CONTAINER2 = "container";
|
|
1439
|
+
function directive(node, name) {
|
|
1440
|
+
if (node.type !== "JSXElement") return void 0;
|
|
1441
|
+
const opening = node.openingElement;
|
|
1442
|
+
if (opening.name.type !== "JSXIdentifier" || opening.name.name[0] !== opening.name.name[0].toLowerCase()) return void 0;
|
|
1443
|
+
return opening.attributes.find((a) => a.type === "JSXAttribute" && a.name.type === "JSXIdentifier" && a.name.name === name);
|
|
1444
|
+
}
|
|
1445
|
+
function directiveExpr(attr) {
|
|
1446
|
+
const v = attr.value;
|
|
1447
|
+
return v?.type === "JSXExpressionContainer" && v.expression?.type !== "JSXEmptyExpression" ? v.expression : void 0;
|
|
1448
|
+
}
|
|
1449
|
+
function emitIR(ir, ctx) {
|
|
1450
|
+
const { code, imports, templates } = imperativeBackend.emit(ir, {});
|
|
1451
|
+
for (const s of imports) ctx.used.add(s);
|
|
1452
|
+
return inlineTemplates(code, templates);
|
|
1453
|
+
}
|
|
1433
1454
|
var posOf = (node, ctx) => {
|
|
1434
1455
|
if (!ctx.sourceFile) return void 0;
|
|
1435
1456
|
const at = node.loc?.start;
|
|
@@ -1538,7 +1559,16 @@ function buildProps(attrs, ctx) {
|
|
|
1538
1559
|
}
|
|
1539
1560
|
function buildChildren(children, ctx) {
|
|
1540
1561
|
const out = [];
|
|
1541
|
-
for (
|
|
1562
|
+
for (let i = 0; i < children.length; i++) {
|
|
1563
|
+
const child = children[i];
|
|
1564
|
+
if (directive(child, "if")) {
|
|
1565
|
+
let next = i + 1;
|
|
1566
|
+
while (next < children.length && children[next].type === "JSXText" && !cleanTemplateText(children[next].value)) next++;
|
|
1567
|
+
const fallback = directive(children[next], "else") ? children[next] : null;
|
|
1568
|
+
out.push(buildIf(child, fallback, ctx));
|
|
1569
|
+
if (fallback) i = next;
|
|
1570
|
+
continue;
|
|
1571
|
+
}
|
|
1542
1572
|
if (child.type === "JSXText") {
|
|
1543
1573
|
const text = cleanTemplateText(child.value);
|
|
1544
1574
|
if (text) out.push({ kind: "text", value: text });
|
|
@@ -1575,19 +1605,68 @@ function readLoad(attrs) {
|
|
|
1575
1605
|
}
|
|
1576
1606
|
return void 0;
|
|
1577
1607
|
}
|
|
1608
|
+
function buildIf(node, fallback, ctx) {
|
|
1609
|
+
const cond = directiveExpr(directive(node, "if"));
|
|
1610
|
+
const props = [
|
|
1611
|
+
cond ? { name: "when", kind: "attr", expr: ctx.code(cond), reactive: isReactive(cond), at: posOf(cond, ctx) } : { name: "when", kind: "attr", literal: true }
|
|
1612
|
+
];
|
|
1613
|
+
if (fallback) {
|
|
1614
|
+
props.push({ name: "fallback", kind: "attr", expr: emitIR(buildElement(fallback, ctx, ["else"]), ctx), jsxElement: true });
|
|
1615
|
+
}
|
|
1616
|
+
return { kind: "component", name: "Show", props, children: [buildElement(node, ctx, ["if"])] };
|
|
1617
|
+
}
|
|
1618
|
+
function buildEach(node, ctx) {
|
|
1619
|
+
const attr = directive(node, "each");
|
|
1620
|
+
if (!attr) return null;
|
|
1621
|
+
const list = directiveExpr(attr);
|
|
1622
|
+
const props = [
|
|
1623
|
+
list ? { name: "each", kind: "attr", expr: ctx.code(list), reactive: isReactive(list), at: posOf(list, ctx) } : { name: "each", kind: "attr", expr: "[]" }
|
|
1624
|
+
];
|
|
1625
|
+
const key = directive(node, "key");
|
|
1626
|
+
if (key) {
|
|
1627
|
+
const keyExpr = directiveExpr(key);
|
|
1628
|
+
const by = isString(key.value) ? `(item) => item[${JSON.stringify(literalOf(key.value))}]` : keyExpr ? ctx.code(keyExpr) : void 0;
|
|
1629
|
+
if (by) props.push({ name: "by", kind: "attr", expr: by });
|
|
1630
|
+
}
|
|
1631
|
+
const content = node.children.filter((c) => !(c.type === "JSXText" && !cleanTemplateText(c.value)));
|
|
1632
|
+
const only = content.length === 1 && content[0].type === "JSXExpressionContainer" ? content[0].expression : null;
|
|
1633
|
+
let render;
|
|
1634
|
+
if (only && (only.type === "ArrowFunctionExpression" || only.type === "FunctionExpression")) {
|
|
1635
|
+
const fn = ctx.code(only);
|
|
1636
|
+
const live = only.type === "ArrowFunctionExpression" && only.body.type !== "BlockStatement" && isReactive(only.body);
|
|
1637
|
+
render = live ? `(...args) => () => (${fn})(...args)` : fn;
|
|
1638
|
+
} else {
|
|
1639
|
+
const built = buildChildren(node.children, ctx);
|
|
1640
|
+
const ir = built.length === 1 ? built[0] : { kind: "fragment", children: built };
|
|
1641
|
+
render = `() => ${paren(emitIR(ir, ctx), "arrowBody")}`;
|
|
1642
|
+
}
|
|
1643
|
+
return { kind: "component", name: "For", props, children: [{ kind: "expr", code: render, reactive: false }] };
|
|
1644
|
+
}
|
|
1645
|
+
function buildElement(node, ctx, handled) {
|
|
1646
|
+
const skip = new Set(handled);
|
|
1647
|
+
const directives = /* @__PURE__ */ new Set(["if", "else", "each", ...directive(node, "each") ? ["key"] : []]);
|
|
1648
|
+
const attributes = node.openingElement.attributes.filter(
|
|
1649
|
+
(a) => !(a.type === "JSXAttribute" && a.name.type === "JSXIdentifier" && (skip.has(a.name.name) || directives.has(a.name.name)))
|
|
1650
|
+
);
|
|
1651
|
+
const { tag } = tagInfo(node.openingElement.name, ctx);
|
|
1652
|
+
const each = buildEach(node, ctx);
|
|
1653
|
+
const children = each ? [each] : buildChildren(node.children, ctx);
|
|
1654
|
+
if (tag === CONTAINER2) return children.length === 1 ? children[0] : { kind: "fragment", children };
|
|
1655
|
+
const at = ctx.sourceFile && node.loc?.start ? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column } : void 0;
|
|
1656
|
+
return { kind: "element", tag, svg: SVG_TAGS.has(tag), props: buildProps(attributes, ctx), children, static: false, ...at ? { at } : {} };
|
|
1657
|
+
}
|
|
1578
1658
|
function buildNode(node, ctx) {
|
|
1579
1659
|
if (node.type === "JSXFragment") {
|
|
1580
1660
|
return { kind: "fragment", children: buildChildren(node.children, ctx) };
|
|
1581
1661
|
}
|
|
1662
|
+
if (directive(node, "if")) return buildIf(node, null, ctx);
|
|
1582
1663
|
const { tag, component } = tagInfo(node.openingElement.name, ctx);
|
|
1664
|
+
if (!component) return buildElement(node, ctx, []);
|
|
1583
1665
|
const props = buildProps(node.openingElement.attributes, ctx);
|
|
1584
1666
|
const children = buildChildren(node.children, ctx);
|
|
1585
1667
|
const at = ctx.sourceFile && node.loc?.start ? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column } : void 0;
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
return { kind: "component", name: tag, props, children, ...load ? { load } : {}, ...at ? { at } : {} };
|
|
1589
|
-
}
|
|
1590
|
-
return { kind: "element", tag, svg: SVG_TAGS.has(tag), props, children, static: false, ...at ? { at } : {} };
|
|
1668
|
+
const load = readLoad(node.openingElement.attributes);
|
|
1669
|
+
return { kind: "component", name: tag, props, children, ...load ? { load } : {}, ...at ? { at } : {} };
|
|
1591
1670
|
}
|
|
1592
1671
|
function buildJsxIR(node, ctx) {
|
|
1593
1672
|
const ir = buildNode(node, ctx);
|