@fluixi/compiler 1.0.0-alpha.83 → 1.0.0-alpha.84
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/expr-shape.cjs +62 -1
- package/dist/analyze/expr-shape.d.cts +14 -0
- package/dist/analyze/expr-shape.mjs +41 -1
- package/dist/analyze/intrinsics.cjs +80 -1
- package/dist/analyze/intrinsics.d.cts +66 -0
- package/dist/analyze/intrinsics.mjs +59 -1
- package/dist/analyze/paren.cjs +134 -0
- package/dist/analyze/paren.d.cts +23 -0
- package/dist/analyze/paren.d.ts +24 -0
- package/dist/analyze/paren.d.ts.map +1 -0
- package/dist/analyze/paren.js +168 -0
- package/dist/analyze/paren.mjs +113 -0
- package/dist/analyze/props-destructure.cjs +226 -1
- package/dist/analyze/props-destructure.d.cts +83 -0
- package/dist/analyze/props-destructure.mjs +205 -1
- package/dist/analyze/reactive-bindings.cjs +190 -1
- package/dist/analyze/reactive-bindings.d.cts +42 -0
- package/dist/analyze/reactive-bindings.mjs +167 -1
- package/dist/analyze/reactive-expr.cjs +38 -1
- package/dist/analyze/reactive-expr.d.cts +38 -0
- package/dist/analyze/reactive-expr.mjs +17 -1
- package/dist/analyze/static-graph.cjs +811 -1
- package/dist/analyze/static-graph.d.cts +102 -0
- package/dist/analyze/static-graph.mjs +793 -1
- package/dist/babel-NRW4EFTG.mjs +636 -0
- package/dist/chunk-3YKZ4GNH.mjs +11 -0
- package/dist/chunk-EZR7NZOY.mjs +1718 -0
- package/dist/chunk-FSSWUXUR.mjs +16 -0
- package/dist/chunk-MJV3UXIL.mjs +158 -0
- package/dist/chunk-R2VHAZAX.mjs +1078 -0
- package/dist/codegen/backend.cjs +18 -1
- package/dist/codegen/backend.d.cts +35 -0
- package/dist/codegen/backends/imperative.cjs +542 -1
- package/dist/codegen/backends/imperative.d.cts +11 -0
- package/dist/codegen/backends/imperative.d.ts.map +1 -1
- package/dist/codegen/backends/imperative.js +12 -8
- package/dist/codegen/backends/imperative.mjs +519 -1
- package/dist/codegen/contract.cjs +52 -1
- package/dist/codegen/contract.d.cts +24 -0
- package/dist/codegen/contract.mjs +31 -1
- package/dist/codegen/partial-template.cjs +176 -1
- package/dist/codegen/partial-template.d.cts +61 -0
- package/dist/codegen/partial-template.mjs +153 -1
- package/dist/codegen/serialize-static.cjs +125 -1
- package/dist/codegen/serialize-static.d.cts +38 -0
- package/dist/codegen/serialize-static.mjs +104 -1
- package/dist/frontend/babel/build-ir-lit.cjs +1509 -1
- package/dist/frontend/babel/build-ir-lit.d.cts +26 -0
- package/dist/frontend/babel/build-ir-lit.mjs +1478 -1
- package/dist/frontend/babel/build-ir.cjs +1524 -1
- package/dist/frontend/babel/build-ir.d.cts +35 -0
- package/dist/frontend/babel/build-ir.mjs +1495 -1
- package/dist/frontend/babel/index.cjs +2186 -1
- package/dist/frontend/babel/index.d.cts +33 -0
- package/dist/frontend/babel/index.mjs +2156 -1
- package/dist/frontend/babel/lower-template.cjs +1507 -1
- package/dist/frontend/babel/lower-template.d.cts +23 -0
- package/dist/frontend/babel/lower-template.mjs +1478 -1
- package/dist/frontend/babel/plugin.cjs +2132 -1
- package/dist/frontend/babel/plugin.d.cts +95 -0
- package/dist/frontend/babel/plugin.mjs +2103 -1
- package/dist/frontend/babel/server-functions.cjs +110 -1
- package/dist/frontend/babel/server-functions.d.cts +10 -0
- package/dist/frontend/babel/server-functions.mjs +89 -1
- package/dist/frontend/babel/types.cjs +18 -1
- package/dist/frontend/babel/types.d.cts +33 -0
- package/dist/frontend/types.cjs +18 -1
- package/dist/frontend/types.d.cts +25 -0
- package/dist/frontend/vocabulary.cjs +98 -0
- package/dist/frontend/vocabulary.d.cts +79 -0
- package/dist/frontend/vocabulary.d.ts +80 -0
- package/dist/frontend/vocabulary.d.ts.map +1 -0
- package/dist/frontend/vocabulary.js +124 -0
- package/dist/frontend/vocabulary.mjs +77 -0
- package/dist/index.cjs +1594 -13
- package/dist/index.d.cts +27 -0
- package/dist/index.mjs +1574 -13
- package/dist/integrations.cjs +4307 -25
- package/dist/integrations.d.cts +215 -0
- package/dist/integrations.mjs +531 -17
- package/dist/ir/nodes.cjs +18 -1
- package/dist/ir/nodes.d.cts +168 -0
- package/dist/lower/compile-template.cjs +1356 -1
- package/dist/lower/compile-template.d.cts +69 -0
- package/dist/lower/compile-template.mjs +1336 -1
- package/dist/lower/jsx.cjs +529 -1
- package/dist/lower/jsx.d.cts +25 -0
- package/dist/lower/jsx.d.ts.map +1 -1
- package/dist/lower/jsx.js +2 -1
- package/dist/lower/jsx.mjs +506 -1
- package/dist/lower/template.cjs +1061 -1
- package/dist/lower/template.d.cts +53 -0
- package/dist/lower/template.d.ts.map +1 -1
- package/dist/lower/template.js +5 -4
- package/dist/lower/template.mjs +1042 -1
- package/dist/lower/text.cjs +42 -1
- package/dist/lower/text.d.cts +10 -0
- package/dist/lower/text.mjs +21 -1
- package/dist/optimize/analyze-static.cjs +112 -1
- package/dist/optimize/analyze-static.d.cts +39 -0
- package/dist/optimize/analyze-static.mjs +91 -1
- package/dist/optimize/collapse-strategies.cjs +90 -1
- package/dist/optimize/collapse-strategies.d.cts +30 -0
- package/dist/optimize/collapse-strategies.mjs +67 -1
- package/dist/options.cjs +33 -1
- package/dist/options.d.cts +39 -0
- package/dist/options.mjs +12 -1
- package/dist/resolve/builtins.cjs +73 -1
- package/dist/resolve/builtins.d.cts +68 -0
- package/dist/resolve/builtins.mjs +53 -1
- package/dist/resolve/component-globals.cjs +233 -13
- package/dist/resolve/component-globals.d.cts +80 -0
- package/dist/resolve/component-globals.mjs +210 -13
- package/dist/resolve/component-resolver.cjs +80 -1
- package/dist/resolve/component-resolver.d.cts +68 -0
- package/dist/resolve/component-resolver.mjs +59 -1
- package/dist/resolve/load-directive.cjs +93 -1
- package/dist/resolve/load-directive.d.cts +53 -0
- package/dist/resolve/load-directive.mjs +72 -1
- package/dist/resolve/resolve-ir.cjs +108 -1
- package/dist/resolve/resolve-ir.d.cts +53 -0
- package/dist/resolve/resolve-ir.mjs +85 -1
- package/dist/resolve/write-globals.cjs +318 -13
- package/dist/resolve/write-globals.d.cts +30 -0
- package/dist/resolve/write-globals.mjs +297 -13
- package/dist/server-fns-4ZXN6DYU.mjs +78 -0
- package/dist/server-functions-V6D6DRIA.mjs +82 -0
- package/dist/transform/bindings.cjs +71 -1
- package/dist/transform/bindings.d.cts +16 -0
- package/dist/transform/bindings.mjs +50 -1
- package/dist/transform/index.cjs +2732 -8
- package/dist/transform/index.d.cts +15 -0
- package/dist/transform/index.mjs +3773 -17
- package/dist/transform/intrinsics.cjs +216 -3
- package/dist/transform/intrinsics.d.cts +21 -0
- package/dist/transform/intrinsics.mjs +193 -3
- package/dist/transform/props.cjs +441 -3
- package/dist/transform/props.d.cts +45 -0
- package/dist/transform/props.mjs +1482 -12
- package/dist/transform/server-fn-id.cjs +35 -1
- package/dist/transform/server-fn-id.d.cts +9 -0
- package/dist/transform/server-fn-id.mjs +14 -1
- package/dist/transform/server-fns.cjs +114 -2
- package/dist/transform/server-fns.d.cts +12 -0
- package/dist/transform/server-fns.mjs +1155 -11
- package/dist/transform/source-locations.cjs +330 -1
- package/dist/transform/source-locations.d.cts +43 -0
- package/dist/transform/source-locations.mjs +307 -1
- package/dist/transform/templates.cjs +2701 -7
- package/dist/transform/templates.d.cts +69 -0
- package/dist/transform/templates.mjs +3743 -16
- package/dist/transform-BT4MMASR.mjs +893 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/package.json +6 -5
- package/dist/babel-VXKH6MRQ.mjs +0 -1
- package/dist/chunk-3SAEGOMQ.mjs +0 -1
- package/dist/chunk-5KMMN5QP.mjs +0 -1
- package/dist/chunk-IBRM4W7I.mjs +0 -10
- package/dist/chunk-OHHZCYIQ.mjs +0 -1
- package/dist/chunk-YKZ54NVE.mjs +0 -1
- package/dist/server-fns-6QM243HC.mjs +0 -2
- package/dist/server-functions-E3LKCZ4R.mjs +0 -1
- package/dist/transform-C4ZXRVGP.mjs +0 -8
package/dist/integrations.cjs
CHANGED
|
@@ -1,35 +1,4317 @@
|
|
|
1
|
-
"use strict";var dr=Object.create;var we=Object.defineProperty;var fr=Object.getOwnPropertyDescriptor;var mr=Object.getOwnPropertyNames;var gr=Object.getPrototypeOf,hr=Object.prototype.hasOwnProperty;var N=(e,t)=>()=>(e&&(t=e(e=0)),t);var ae=(e,t)=>{for(var n in t)we(e,n,{get:t[n],enumerable:!0})},Ft=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of mr(t))!hr.call(e,o)&&o!==n&&we(e,o,{get:()=>t[o],enumerable:!(r=fr(t,o))||r.enumerable});return e};var _=(e,t,n)=>(n=e!=null?dr(gr(e)):{},Ft(t||!e||!e.__esModule?we(n,"default",{value:e,enumerable:!0}):n,e)),yr=e=>Ft(we({},"__esModule",{value:!0}),e);function Jt(e,t){return e.replace(/\$(\d+)/g,(n,r)=>t[Number(r)]??n)}function xr(e,t){return typeof t=="string"?{module:t,export:e}:t}function X(e=[]){let t=new Map,n=[],r=[];for(let a of e){if(!vr(a)){r.push(a);continue}for(let[s,l]of Object.entries(a.components)){let p=xr(s,l),c=t.get(s);if(c&&c.module!==p.module){let u=n.find(d=>d.name===s);u?u.modules.push(p.module):n.push({name:s,modules:[c.module,p.module]});continue}t.set(s,p)}}let o=new Map;return{resolve:a=>{if(o.has(a))return o.get(a);let s=t.get(a);if(!s)for(let l of r){let p=a.match(new RegExp(l.match.source,l.match.flags.replace("g","")));if(p){s={module:Jt(l.module,p),export:l.export?Jt(l.export,p):a};break}}return o.set(a,s),s},names:()=>[...t.keys()],conflicts:()=>n}}var vr,le=N(()=>{"use strict";vr=e=>"components"in e});function ke(e={}){let{controlFlowModule:t="@fluixi/dom",coreModule:n="@fluixi/core",routerModule:r="@fluixi/core/router"}=e,o={};for(let i of ce)o[i]=t;for(let i of Y)o[i]=n;for(let i of H)o[i]=r;return o}var ce,Y,H,vi,et,pe=N(()=>{"use strict";ce=["Show","For","Index","Switch","Match","Portal","Dynamic","ErrorBoundary"],Y=["Suspense","SuspenseList","Await"],H=["Router","Outlet","Redirect","Link"],vi=[...ce,...Y,...H],et=new Set([...ce,...Y])});function Bt(e){return Nr.test(e)}function Ie(e){return Object.prototype.hasOwnProperty.call(D,e)}function Xt(e){return br.includes(e)}var Z,D,_t,br,Nr,re=N(()=>{"use strict";Z="@fluixi/reactive/signal",D={$signal:{export:"signal",module:Z,returns:"signal-handle"},$memo:{export:"memo",module:Z,returns:"memo-handle"},$effect:{export:"effect",module:Z,returns:"effect"},$store:{export:"store",module:"@fluixi/reactive/store",returns:"store-handle"},$resource:{export:"resource",module:Z,returns:"resource-handle"},$selector:{export:"createSelector",module:Z,returns:"memo-accessor"},$deferred:{export:"createDeferred",module:Z,returns:"memo-accessor"},$untrack:{export:"untrack",module:Z,returns:"plain"},$untrackStore:{export:"untrackStore",module:"@fluixi/reactive/store",returns:"plain"}},_t={signal:"signal-handle",memo:"memo-handle",effect:"effect",store:"store-handle",createSignal:["signal-accessor","signal-setter"],createMemo:"memo-accessor",createEffect:"effect",createRenderEffect:"effect",createStore:"reactive-object",resource:"resource-handle",createResource:"reactive-object",createSelector:"memo-accessor",createDeferred:"memo-accessor"},br=["@fluixi/reactive","@fluixi/reactive/signal","@fluixi/reactive/store","@fluixi/core"],Nr=new RegExp(`\\$(?:${Object.keys(D).map(e=>e.slice(1)).join("|")})\\s*\\(`)});function nt(e){return e.startsWith("load:")}function Te(e,t){let n=e.slice(5);if(!zt.has(n))throw new V(`Unknown load strategy 'load:${n}'. Expected one of ${[...zt].join(", ")}.`);switch(n){case"eager":return Ce;case"idle":return{kind:"idle"};case"never":return{kind:"never"};case"visible":return t?{kind:"visible",rootMargin:t}:{kind:"visible"};case"interaction":return{kind:"interaction",events:t?$r(t):[...Tr]};case"media":if(!t)throw new V(`'load:media' needs a query, e.g. load:media="(min-width: 1024px)".`);return{kind:"media",query:t};default:throw new V(`Unhandled load strategy '${n}'.`)}}function $r(e){let t=e.split(/[\s,]+/).map(n=>n.trim()).filter(Boolean);if(t.length===0)throw new V("'load:interaction' was given no event names.");return t}function Q(e){return e.kind!=="eager"&&e.kind!=="never"}var Ce,Tr,zt,V,ee=N(()=>{"use strict";Ce={kind:"eager"},Tr=["pointerdown","focusin","keydown"],zt=new Set(["eager","idle","visible","interaction","media","never"]),V=class extends Error{}});function U(e,t={}){let{resolver:n,isBound:r,modules:o,strategyFor:i}=t,a=ke(o),s=new Map,l=new Set,p=u=>{let{name:d}=u;if(!d||d.includes(".")||r?.(d))return;let x=c(d);if(!x){l.add(d);return}let g=x.origin==="builtin"&&et.has(d)?Ce:i?.(u)??Ce;u.source={...x,loading:g},s.set(d,u.source)},c=u=>{if(et.has(u))return{module:a[u],export:u,origin:"builtin"};let d=n?.resolve(u);if(d)return{module:d.module,export:d.export,origin:"rule"};if(H.includes(u))return{module:a[u],export:u,origin:"builtin"}};return $e(e,u=>{u.kind==="component"&&p(u)}),{resolved:s,unresolved:[...l]}}function $e(e,t){let n=Array.isArray(e)?e:[e];for(let r of n){t(r);let o=r.children;o&&$e(o,t)}}var ue=N(()=>{"use strict";pe();ee()});function z(e){let t=[];$e(e,i=>{i.kind==="component"&&i.source&&t.push(i)});let n=new Set,r=new Set;for(let i of t){let{module:a,loading:s}=i.source;s.kind==="eager"&&n.add(a),s.kind==="never"&&r.add(a)}let o=new Map;for(let i of t){let a=i.source;Q(a.loading)&&n.has(a.module)&&(a.loading={kind:"eager"},o.set(a.module,(o.get(a.module)??0)+1))}return{collapsed:o,conflicted:[...r].filter(i=>n.has(i))}}var Me=N(()=>{"use strict";ee();ue()});function rt(e){return Pr.has(e)}function qt(e){return Gt[e]??e}function de(e){return e.kind!=="attr"||e.expr!==void 0||e.name.includes(":")?!1:!Or.has(e.name)}function ot(e){if(!e.static||rt(e.tag))return!1;for(let t of e.props)if(!de(t))return!1;for(let t of e.children)if(t.kind!=="text"&&!(t.kind==="element"&&ot(t)))return!1;return!0}function fe(e){let t=e.props.map(Lr).filter(Boolean).join(""),n=`<${e.tag}${t}>`;return Mr.has(e.tag)?n:`${n}${e.children.map(Dr).join("")}</${e.tag}>`}function Dr(e){if(e.kind==="text")return jr(e.value);if(e.kind!=="element")throw new Error(`serializeStatic: unexpected ${e.kind}`);return fe(e)}function Lr(e){let t=Gt[e.name]??e.name,n=e.literal;return n===!0||n===void 0?` ${t}`:n===!1||n===null?"":` ${t}="${Ar(String(n))}"`}function Ar(e){return e.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}function jr(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}function it(e){let t=[],n,r=o=>{n??=o.at?.file,t.push(o.at?.line??0,o.at?.column??0);for(let i of o.children)i.kind==="element"&&r(i)};return r(e),n&&t.some(o=>o!==0)?{file:n,pos:t}:void 0}var Mr,Gt,Or,Pr,st=N(()=>{"use strict";Mr=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]),Gt={className:"class",htmlFor:"for"},Or=new Set(["innerHTML","outerHTML","innerText","textContent","value","checked","selected","muted","defaultValue","defaultChecked","children","ref"]),Pr=new Set(["script","style","textarea","title"])});function Pe(e){return e.kind==="expr"||e.kind==="component"||e.kind==="control"}function _r(e){return e.kind==="text"||e.kind==="element"&&Kt(e)}function Kt(e){return e.svg||rt(e.tag)||!e.props.every(t=>de(t))?!1:e.children.every(t=>_r(t)||Pe(t))}function Oe(e){if(Pe(e))return!0;let t=e.children;return t?t.some(Oe):!1}function Yt(e){for(let t=0;t<e.children.length;t++){let n=e.children[t];if(n.kind==="text"&&(n.value===""||e.children[t+1]?.kind==="text"))return!1}return e.children.every(t=>t.kind!=="element"||Yt(t))}function Zt(e){if(!Kt(e)||!Yt(e)||!e.children.some(Oe))return null;let t=[],n=[],r=0,o=a=>{let s=`_n$${r++}`;return t.push({ref:s,expr:a}),s};return i(e,"_el$"),{html:Br(e),tag:e.tag,steps:t,holes:n};function i(a,s){let l=-1;a.children.forEach((c,u)=>{Oe(c)&&(l=u)});let p=null;for(let c=0;c<=l;c++){let u=a.children[c],d=p?`${p}.nextSibling`:`${s}.firstChild`;if(Pe(u)){let g=o(d),h=o(`holeEnd(${g})`);n.push({parentRef:s,startRef:g,endRef:h,node:u}),p=h;continue}let x=o(d);u.kind==="element"&&Oe(u)&&i(u,x),p=x}}}function Br(e){return fe(Qt(e)).split(en).join(Fr+Jr)}function Qt(e){return{...e,children:e.children.map(t=>Pe(t)?{kind:"text",value:en}:t.kind==="element"?Qt(t):t)}}var Fr,Jr,en,tn=N(()=>{"use strict";st();Fr="<!--fx-->",Jr="<!--fx/-->";en="\0fx-hole\0"});var at,ji,nn=N(()=>{"use strict";at={version:1,module:"@fluixi/dom",symbols:["createNativeElement","insert","spread","setAttribute","delegateEvents","createComponent","createMemo","untrack","Show","For","Index","Switch","Match","Dynamic","ErrorBoundary"]},ji={version:2,module:"@fluixi/dom",symbols:[...at.symbols,"template","cloneTemplate","walk"]}});function $(e,t){if(e)switch(e.type){case"Identifier":t.add(e.name);return;case"ObjectPattern":for(let n of e.properties??[])n.type==="RestElement"?$(n.argument,t):$(n.value,t);return;case"ArrayPattern":for(let n of e.elements??[])$(n,t);return;case"AssignmentPattern":$(e.left,t);return;case"RestElement":$(e.argument,t);return}}function me(e,t){if(!(!e||typeof e!="object"||typeof e.type!="string")){t(e);for(let n of Object.keys(e)){if(n==="loc"||n==="leadingComments"||n==="trailingComments")continue;let r=e[n];if(Array.isArray(r))for(let o of r)me(o,t);else r&&typeof r=="object"&&me(r,t)}}}function Xr(e,t){if(e.type!=="CallExpression")return;let n=e.callee;if(n?.type!=="Identifier")return;let r=n.name,o=t.primitives.get(r);if(o)return o;let i=D[r];if(i&&!t.shadowed.has(r))return i.returns}function Hr(e,t,n){if(Array.isArray(t)){e.type==="ArrayPattern"&&e.elements.forEach((r,o)=>{let i=t[o];r?.type==="Identifier"&&i&&n.set(r.name,i)});return}e.type==="Identifier"&&n.set(e.name,t)}function rn(e){let t=new Set;return me(e,n=>{switch(n.type){case"VariableDeclarator":$(n.id,t);return;case"FunctionDeclaration":case"FunctionExpression":case"ArrowFunctionExpression":$(n.id,t);for(let r of n.params??[])$(r,t);return;case"ClassDeclaration":case"ClassExpression":$(n.id,t);return;case"ImportSpecifier":case"ImportDefaultSpecifier":case"ImportNamespaceSpecifier":$(n.local,t);return;case"CatchClause":$(n.param,t);return}}),t}function De(e){let t={kinds:new Map,primitives:new Map,shadowed:new Set},n=e;me(n,r=>{let o=new Set;if(r.type==="VariableDeclarator")$(r.id,o);else if(r.type==="FunctionDeclaration"||r.type==="ClassDeclaration")$(r.id,o);else if(r.type==="ImportDefaultSpecifier"||r.type==="ImportNamespaceSpecifier")$(r.local,o);else if(r.type==="ImportSpecifier")$(r.local,o);else if(r.type==="FunctionExpression"||r.type==="ArrowFunctionExpression"||r.type==="FunctionDeclaration")for(let i of r.params??[])$(i,o);for(let i of o)D[i]&&t.shadowed.add(i)});for(let r of n.body??[])if(r.type==="ImportDeclaration"&&Xt(r.source?.value))for(let o of r.specifiers??[]){if(o.type!=="ImportSpecifier")continue;let i=o.imported,a=i.type==="Identifier"?i.name:i.value,s=_t[a];s&&t.primitives.set(o.local.name,s)}return me(n,r=>{if(r.type!=="VariableDeclarator"||!r.init)return;let o=Xr(r.init,t);o&&Hr(r.id,o,t.kinds)}),t}var Le=N(()=>{"use strict";re()});function ln(e){for(let t of an)if(e.includes(t))return!0;return e.includes("$signal")||e.includes("$memo")||e.includes("$effect")||e.includes("$store")}function Gr(e,t){return!t||e.type==="BlockStatement"?!1:zr.has(t.type)}function on(e){return e.type==="ExportNamedDeclaration"||e.type==="ExportDefaultDeclaration"}function qr(e){return e.type.endsWith("Statement")||e.type==="VariableDeclaration"}function lt(e,t,n=[]){if(!(!e||typeof e.type!="string")){t(e,n),n.push(e);for(let r of Object.keys(e)){if(r==="loc"||r==="parent")continue;let o=e[r];if(Array.isArray(o))for(let i of o)lt(i,t,n);else o&&typeof o.type=="string"&<(o,t,n)}n.pop()}}function Kr(e){let t=e[e.length-1];if(t?.type!=="VariableDeclarator")return;let n=t.id;if(n?.type==="Identifier")return n.name;if(n?.type==="ArrayPattern"){let r=n.elements?.[0];if(r?.type==="Identifier")return r.name}}function Yr(e){if(e.type==="FunctionDeclaration"){let t=e.id?.name;return t&&t[0]===t[0]?.toUpperCase()?t:void 0}if(e.type==="VariableDeclarator"){let t=e.id,n=e.init;if(t?.type!=="Identifier"||!n||n.type!=="ArrowFunctionExpression"&&n.type!=="FunctionExpression")return;let r=t.name;return r[0]===r[0]?.toUpperCase()?r:void 0}}function cn(e,t){let n=[],r=new Set,{primitives:o,shadowed:i}=De(e);return lt(e,(a,s)=>{let l=Yr(a);if(l){let b=a.loc?.start,y=a.end;for(let k=s.length-1;k>=0;k--){let I=s[k];if(I.type!=="VariableDeclaration"&&I.type!=="ExportNamedDeclaration"&&I.type!=="ExportDefaultDeclaration")break;y=I.end}b&&n.push({start:y,end:y,code:`;globalThis.${Wr}?.(${JSON.stringify(l)},${JSON.stringify(t)},${b.line},${b.column});`})}if(a.type!=="CallExpression")return;let p=a.callee;if(p?.type!=="Identifier")return;let c=p.name,u=Ie(c)&&!i.has(c)?D[c]:void 0,d=o.has(c)||an.has(c);if(!u&&!d)return;let x=a.loc?.start;if(!x)return;let g,h,v=-1;for(let b=s.length-1;b>=0;b--)if(qr(s[b])||on(s[b])){g=s[b],h=s[b-1],v=b;break}if(!g)return;let R=g.start,C=g.end;for(let b=v-1;b>=0&&on(s[b]);b--)R=s[b].start,C=s[b].end,h=s[b-1];if(r.has(R))return;r.add(R);let E=Kr(s),S=[JSON.stringify(t),String(x.line),String(x.column),E?JSON.stringify(E):void 0].filter(b=>b!==void 0).join(","),w=`globalThis.${ct}?.(${S});`;if(Gr(g,h)){n.push({start:R,end:R,code:`{${w}`}),n.push({start:C,end:C,code:"}"});return}n.push({start:R,end:R,code:w})}),{edits:n,marked:n.length}}var ct,Wr,Vr,ge,Ur,sn,an,zr,pt=N(()=>{"use strict";re();Le();ct="__fx_source",Wr="__fx_component",Vr="__fx_hole",ge=(e,t,n,r)=>`(globalThis.${Vr} ?? ((f) => f))(${e},${t},${n}${r===void 0?"":`,${JSON.stringify(r)}`})`,Ur="__fx_props",sn=(e,t)=>`(globalThis.${Ur} ?? ((p) => p))(${e},${JSON.stringify(t)})`,an=new Set(["signal","memo","effect","store","resource","watch","createSignal","createMemo","createEffect","createStore","createResource"]);zr=new Set(["IfStatement","ForStatement","ForInStatement","ForOfStatement","WhileStatement","DoWhileStatement","LabeledStatement","WithStatement"])});function Qr(e){return/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(e)}function dn(e){return Qr(e)?e:JSON.stringify(e)}function eo(e){if(e.expr!==void 0){if(e.name==="ref"&&e.at)return ge(`(${e.expr})`,e.at.line,e.at.column,e.expr);if(!e.reactive)return`(${e.expr})`;let t=`() => (${e.expr})`;return e.at?ge(t,e.at.line,e.at.column,e.directive):t}return JSON.stringify(e.literal??!0)}function to(e){return e.expr!==void 0?`(${e.expr})`:JSON.stringify(e.literal??!0)}function no(e,t,n){let r=e.filter(s=>s.kind==="spread"),i=e.filter(s=>s.kind!=="spread").map(s=>`${dn(s.name)}: ${eo(s)}`);t!=null&&i.push(`children: ${t}`);let a=`{ ${i.join(", ")} }`;return r.length>0?(n.add("mergeProps"),`mergeProps(${r.map(s=>s.expr).join(", ")}, ${a})`):a}function pn(e,t){return t?ge(e,t.line,t.column):e}function fn(e,t,n){return e.length===1?he(e[0],t,n):`[${e.map(r=>he(r,t,n)).join(", ")}]`}function un(e,t,n,r,o,i){r.add("createMemo"),r.add("createComponent");let a=t.filter(d=>d.kind==="spread"),s=t.filter(d=>d.kind!=="spread"),l=s.map(d=>`get ${dn(d.name)}() { return ${to(d)}; }`);n.length>0&&l.push(`get children() { return ${fn(n,r,o)}; }`);let p=`{ ${l.join(", ")} }`;a.length>0&&(r.add("mergeProps"),p=`mergeProps(${a.map(d=>d.expr).join(", ")}, ${p})`);let c={};for(let d of s)d.at&&(c[d.name]=[d.at.line,d.at.column]);return Object.keys(c).length&&(p=sn(p,c)),`createMemo((${i?`globalThis.${ct}?.(${JSON.stringify(i.file)},${i.line},${i.column},${JSON.stringify(e)}), `:""}() => createComponent(${e}, ${p})))`}function ro(e,t){let n=qt(t.name),r=t.literal;return r===!0||r===void 0?`${e}.setAttribute(${JSON.stringify(n)}, "");`:r===!1||r===null?"":`${e}.setAttribute(${JSON.stringify(n)}, ${JSON.stringify(String(r))});`}function he(e,t,n){switch(e.kind){case"text":return JSON.stringify(e.value);case"expr":{if(!e.reactive)return`(${e.code})`;let r=`() => (${e.code})`;return e.at?ge(r,e.at.line,e.at.column):r}case"fragment":return e.children.length===0?"null":fn(e.children,t,n);case"component":return pn(un(e.name,e.props,e.children,t,n,e.at),e.bindAt??e.at);case"control":{let r=Zr[e.control]??e.control;return t.add(r),pn(un(r,e.props,e.children,t,n),e.bindAt)}case"element":{if(n&&e.static&&!e.svg&&ot(e)){t.add("templateNode");let s=`_tmpl$${n.length}`;n.push({id:s,html:fe(e),tag:e.tag,svg:!1});let l=it(e);return l?`templateNode(${s}, ${JSON.stringify(e.tag)}, false, false, ${JSON.stringify(l)})`:`templateNode(${s}, ${JSON.stringify(e.tag)})`}if(n&&mn){let s=Zt(e);if(s){t.add("templateNode"),t.add("insert"),t.add("holeEnd"),t.add("holeContent"),t.add("holeScope");let l=`_tmpl$${n.length}`;n.push({id:l,html:s.html,tag:s.tag,svg:!1});let p=it(e),c=[`const _el$ = templateNode(${l}, ${JSON.stringify(s.tag)}, true${p?`, false, ${JSON.stringify(p)}`:""});`];for(let u of s.steps)c.push(`const ${u.ref} = ${u.expr};`);for(let u of s.holes)c.push(`insert(${u.parentRef}, holeScope(${u.startRef}, () => (${he(u.node,t,n)})), ${u.endRef}, holeContent(${u.startRef}, ${u.endRef}));`);return c.push("return _el$;"),`(() => { ${c.join(" ")} })()`}}t.add("createNativeElement");let r=JSON.stringify(e.tag),o="_el$",i=[],a=e.at?`${r}, ${e.svg}, ${JSON.stringify(e.at)}`:e.svg?`${r}, true`:r;if(i.push(`const ${o} = createNativeElement(${a});`),e.props.length>0)if(!e.svg&&e.props.every(de))for(let s of e.props)i.push(ro(o,s));else{t.add("spread");let s=e.svg?", isSVG: true":"";i.push(`spread({ element: ${o}, props: ${no(e.props,null,t)}${s} });`)}for(let s of e.children){t.add("insert");let l=he(s,t,n),p=s.kind==="expr"&&s.reactive||s.kind==="component"||s.kind==="control";i.push(p?`insert(${o}, ${l}, null);`:`insert(${o}, ${l});`)}return i.push(`return ${o};`),`(() => { ${i.join(" ")} })()`}}}function te(e,t){if(!t||t.length===0)return e;let n=new Map(t.map(r=>[r.id,JSON.stringify(r.html)]));return e.replace(/_tmpl\$\d+/g,r=>n.get(r)??r)}var Zr,mn,L,oe=N(()=>{"use strict";tn();st();nn();pt();Zr={show:"Show",for:"For",index:"Index",switch:"Switch",match:"Match",dynamic:"Dynamic",errorBoundary:"ErrorBoundary",suspense:"Suspense"};mn=!1;L={name:"imperative",contract:at,emit(e,t){let n=new Set,r=t?.templateClone!==!1?[]:void 0;return mn=t?.partialTemplates===!0,{code:he(e,n,r),imports:Array.from(n),templates:r}}}});function ye(e){let t=e.split(/\r\n|\n|\r/),n=0;for(let o=0;o<t.length;o++)/[^ \t]/.test(t[o])&&(n=o);let r="";for(let o=0;o<t.length;o++){let i=t[o].replace(/\t/g," ");o!==0&&(i=i.replace(/^ +/,"")),o!==t.length-1&&(i=i.replace(/ +$/,"")),i&&(o!==n&&(i+=" "),r+=i)}return r}var ut=N(()=>{"use strict"});function oo(e){return e.replace(/\\/g,"\\\\").replace(/`/g,"\\`").replace(/\$\{/g,"\\${")}function hn(e){return e.charAt(0).toUpperCase()+e.slice(1)}function Ae(e,t,n,r={}){let{root:o}=(0,yn.parseTemplate)(e,{svg:r.svg});return new dt(t,n,r.sourceFile,r.positionAt).lowerRoot(o.children)}var yn,gn,dt,ft=N(()=>{"use strict";yn=require("@fluixi/template-parser");ee();oe();ut();gn=new Set(["click","dblclick","input","change","submit","focus","blur","keydown","keyup","keypress","mousedown","mouseup"]);dt=class{constructor(t,n,r,o){this.holes=t;this.used=n;this.sourceFile=r;this.positionAt=o}tagAt(t){let n=t.loc?.start;if(!this.sourceFile||!this.positionAt||n==null)return;let{line:r,column:o}=this.positionAt(n);return{file:this.sourceFile,line:r,column:o}}hole(t){return this.holes[t]??{code:"undefined",reactive:!1}}emit(t){let{code:n,imports:r,templates:o}=L.emit(t,{});for(let i of r)this.used.add(i);return te(n,o)}lowerRoot(t){let n=this.lowerChildren(t);return n.length===1?n[0]:{kind:"fragment",children:n}}lowerChildren(t){let n=[];for(let r=0;r<t.length;r++){let o=t[r];if(o.kind==="Element"||o.kind==="Component"){let a=o.attributes.find(s=>s.kind==="IfDirective");if(a&&a.kind==="IfDirective"){let s=r+1;s<t.length&&this.isBlankText(t[s])&&s++;let l=t[s],p=l&&(l.kind==="Element"||l.kind==="Component")&&l.attributes.some(c=>c.kind==="ElseDirective");n.push(this.lowerIf(o,a.hole,p?l:null)),p&&(r=s);continue}if(o.attributes.some(s=>s.kind==="EachDirective")){n.push(this.lowerEach(o));continue}}let i=this.lowerNode(o);i&&n.push(i)}return n}isBlankText(t){return t.kind==="Text"&&!t.raw&&ye(t.value)===""}lowerNode(t){switch(t.kind){case"Text":{if(t.raw)return{kind:"text",value:t.value};let n=ye(t.value);return n?{kind:"text",value:n}:null}case"Comment":return null;case"Expression":{let n=this.hole(t.hole);return{kind:"expr",code:n.code,reactive:n.reactive,...n.at?{at:n.at}:{}}}case"Fragment":return{kind:"fragment",children:this.lowerChildren(t.children)};case"Element":return this.lowerElement(t);case"Component":return this.lowerComponent(t);default:return null}}lowerElement(t){let n=t.attributes.find(o=>o.kind==="Attribute"&&o.name==="is");if(t.tag==="component"&&n&&n.value&&n.value.kind==="hole"){let o=t.attributes.filter(a=>a!==n),i=this.lowerComponent({...t,kind:"Component",tag:"Dynamic",tagHole:null,attributes:o});return i.props.unshift({name:"component",kind:"attr",expr:`() => (${this.hole(n.value.hole).code})`}),i}let r=this.tagAt(t);return{kind:"element",tag:t.tag,svg:t.namespace==="svg",props:this.lowerAttributes(t.attributes),children:this.lowerChildren(t.children),static:!1,...r?{at:r}:{}}}lowerComponent(t){let n=t.tagHole!=null?this.hole(t.tagHole).code:t.tag,r=this.lowerAttributes(t.attributes),{slots:o,rest:i}=this.partitionSlots(t.children);for(let[c,u]of o){let d=u.length===1?u[0]:{kind:"fragment",children:u},x={name:c,kind:"attr",expr:this.emit(d),jsxElement:!0},g=r.findIndex(h=>h.name===c);g>=0?r[g]=x:r.push(x)}let a=t.attributes.find(c=>c.kind==="LoadDirective"),s=a?Te(`load:${a.strategy}`,a.modifier):void 0,l=r.find(c=>c.at&&c.reactive)?.at,p=this.tagAt(t);return{kind:"component",name:n,props:r,children:this.lowerChildren(i),...p?{at:p}:{},...l?{bindAt:l}:{},...s?{load:s}:{}}}partitionSlots(t){let n=new Map,r=[];for(let o of t){if(o.kind==="Element"||o.kind==="Component"){let i=o.attributes.find(a=>a.kind==="Attribute"&&a.name==="slot");if(i&&i.value&&i.value.kind==="static"){let a={...o,attributes:o.attributes.filter(p=>p!==i)},s=a.kind==="Element"?this.lowerElement(a):this.lowerComponent(a),l=n.get(i.value.value)??[];l.push(s),n.set(i.value.value,l);continue}}r.push(o)}return{slots:n,rest:r}}lowerIf(t,n,r){let o=this.hole(n),i=[{name:"when",kind:"attr",expr:o.code,reactive:o.reactive,...o.at?{at:o.at}:{}}];if(r){let l=this.stripAndLower(r,p=>p.kind==="ElseDirective");i.push({name:"fallback",kind:"attr",expr:this.emit(l),jsxElement:!0})}let a=this.stripAndLower(t,l=>l.kind==="IfDirective"),s=this.tagAt(t);return{kind:"component",name:"Show",props:i,children:[a],...s?{at:s}:{},...o.at?{bindAt:o.at}:{}}}lowerEach(t){let n=t.attributes.find(p=>p.kind==="EachDirective");if(!n||n.kind!=="EachDirective")return this.lowerNode(t);let r=this.hole(n.hole),o=[{name:"each",kind:"attr",expr:r.code,reactive:r.reactive,...r.at?{at:r.at}:{}}];if(n.key){let p="static"in n.key?`(item) => item[${JSON.stringify(n.key.static)}]`:this.hole(n.key.hole).code;o.push({name:"by",kind:"attr",expr:p})}let i=this.itemArrow(t),a;if(i){let p={kind:"expr",code:i.body,reactive:i.bodyReactive},c=this.rebuildWithChildren(t,[p]);a=`(${i.params.join(", ")}) => (${this.emit(c)})`}else{let p=this.stripAndLower(t,c=>c.kind==="EachDirective");a=`() => (${this.emit(p)})`}let s=[{kind:"expr",code:a,reactive:!1}],l=this.tagAt(t);return{kind:"component",name:"For",props:o,children:s,...l?{at:l}:{},...r.at?{bindAt:r.at}:{}}}itemArrow(t){let n=t.children.filter(r=>!this.isBlankText(r));return n.length!==1||n[0].kind!=="Expression"?null:this.hole(n[0].hole).arrow??null}stripAndLower(t,n){let r={...t,attributes:t.attributes.filter(o=>!n(o))};return r.kind==="Element"?this.lowerElement(r):this.lowerComponent(r)}rebuildWithChildren(t,n){let r=this.lowerAttributes(t.attributes.filter(o=>o.kind!=="EachDirective"));if(t.kind==="Element"){let o=this.tagAt(t);return{kind:"element",tag:t.tag,svg:t.namespace==="svg",props:r,children:n,static:!1,...o?{at:o}:{}}}return{kind:"component",name:t.tag,props:r,children:n}}lowerAttributes(t){let n=[],r=[],o=!1,i,a=[],s=!1,l,p=[];for(let c of t)switch(c.kind){case"IfDirective":case"EachDirective":case"ElseDirective":break;case"Attribute":n.push(this.plainAttr(c));break;case"PropertyBinding":n.push({name:c.name,kind:"prop",expr:this.hole(c.hole).code,reactive:this.hole(c.hole).reactive,...this.hole(c.hole).at?{at:this.hole(c.hole).at}:{}});break;case"EventBinding":n.push(this.eventProp(c));break;case"RefBinding":n.push({name:"ref",kind:"ref",expr:this.hole(c.hole).code,reactive:this.hole(c.hole).reactive,...this.hole(c.hole).at?{at:this.hole(c.hole).at}:{}});break;case"Spread":n.push({name:"",kind:"spread",expr:this.hole(c.hole).code});break;case"ClassDirective":{let u=this.hole(c.hole);r.push(`${JSON.stringify(c.name)}: ${u.code}`),o=o||u.reactive,i??=u.at;break}case"StyleDirective":{let u=this.hole(c.hole);a.push(`${JSON.stringify(c.name)}: ${u.code}`),s=s||u.reactive,l??=u.at;break}case"BindDirective":n.push(...this.bindProps(c.name,this.hole(c.hole)));break;case"UseDirective":{let u=c.name??(c.hole!=null?this.hole(c.hole).code:null);if(!u)break;p.push(c.name!=null&&c.hole!=null?`[${u}, () => (${this.hole(c.hole).code})]`:`[${u}]`);break}}return r.length>0&&n.push({name:"classList",kind:"attr",expr:`{ ${r.join(", ")} }`,reactive:o,...i?{at:i}:{}}),a.length>0&&n.push({name:"style",kind:"attr",expr:`{ ${a.join(", ")} }`,reactive:s,...l?{at:l}:{}}),p.length>0&&n.push({name:"use",kind:"attr",expr:`[${p.join(", ")}]`}),n}eventProp(t){let n=t.name.toLowerCase(),r=this.hole(t.hole).code;if(!(t.syntax==="colon"||t.modifiers.length>0))return{name:"on"+hn(t.name),kind:"event",event:{name:n,delegated:gn.has(n)},expr:r};let i=this.wrapHandler(r,t.modifiers),a=this.eventOptions(t.modifiers),s=a?`[${i}, ${a}]`:i;return{name:"on:"+n,kind:"attr",expr:s}}wrapHandler(t,n){let r=n.includes("self")?"if (e.target !== e.currentTarget) return; ":"",o=[];return n.includes("prevent")&&o.push("e.preventDefault();"),n.includes("stop")&&o.push("e.stopPropagation();"),!r&&o.length===0?t:`(e) => { ${r}${o.join(" ")} return (${t})(e); }`}eventOptions(t){let n=[];return t.includes("capture")&&n.push("capture: true"),t.includes("once")&&n.push("once: true"),t.includes("passive")&&n.push("passive: true"),n.length?`{ ${n.join(", ")} }`:null}bindProps(t,n){let r=n.code,o=t==="checked",i=o?"change":"input",a=o?"checked":"value";this.used.add("bindPair");let s=`bindPair(${r})`;return[{name:t,kind:"attr",expr:`${s}[0]()`,reactive:!0,directive:`bind:${t}`,...n.at?{at:n.at}:{}},{name:"on"+hn(i),kind:"event",event:{name:i,delegated:gn.has(i)},expr:`(e) => ${s}[1](e.target.${a})`}]}plainAttr(t){let n=t.value,r=t.name;t.name==="class"?r=n&&n.kind==="hole"&&this.hole(n.hole).object?"classList":"className":t.name==="html"&&(r="innerHTML");let i={name:r,kind:"attr"};if(n==null)return i.literal=!0,i;if(n.kind==="static")return i.literal=n.value,i;if(n.kind==="hole"){let p=this.hole(n.hole);return i.expr=p.code,i.reactive=p.reactive,p.at&&(i.at=p.at),i}let a=!1,s,l=n.parts.map(p=>{if("text"in p)return oo(p.text);let c=this.hole(p.hole);return a=a||c.reactive,s??=c.at,"${"+c.code+"}"}).join("");return i.expr="`"+l+"`",i.reactive=a,s&&(i.at=s),i}}});function so(e){return io(e,{concise:!0}).code}function ao(e,t,n){let r={code:Fe(e,t,n),reactive:gt(e)};if(je.types.isArrowFunctionExpression(e)&&!je.types.isBlockStatement(e.body)){let o=e.body;r.arrow={params:e.params.map(i=>so(i)),body:Fe(o,t,n),bodyReactive:gt(o)}}return je.types.isObjectExpression(e)&&(r.object=!0),r}function vn(e,t,n={}){let r=e.quasi,o=r.expressions.map(i=>ao(i,t,n.onNested));return Ae(lo(r),o,t,n)}function lo(e){let t=[];return e.quasis.forEach((n,r)=>{let o=n.value.cooked??n.value.raw;if(t.push({kind:"static",text:o,start:n.start??0}),r<e.expressions.length){let i=e.expressions[r];t.push({kind:"hole",index:r,start:i.start??0,end:i.end??0})}}),t}var je,mt,io,xn=N(()=>{"use strict";je=require("@babel/core"),mt=_(require("@babel/generator"),1);ft();ht();io=mt.default.default??mt.default});function co(e){switch(e.kind){case"event":return"event";case"ref":return"ref";case"spread":return"spread";case"class":case"style":return"class-or-style-directive";case"attr":case"prop":return e.reactive?"reactive-prop":e.expr!==void 0?"expression-prop":void 0;default:return"expression-prop"}}function G(e){let t=[],n=new Map,r=o=>{switch(o.kind){case"text":return!0;case"expr":return!1;case"component":case"control":for(let i of o.children)r(i);return!1;case"fragment":for(let i of o.children)r(i);return!1;case"element":{let i=!0;for(let s of o.children)r(s)||(i=!1);let a;for(let s of o.props)if(a=co(s),a)break;return!a&&!i&&(a=po(o)),o.static=!a,a?n.set(o,a):t.push(o),o.static}default:return!1}};for(let o of Array.isArray(e)?e:[e])r(o);return{staticElements:t,reasons:n}}function po(e){for(let t of e.children){if(t.kind==="expr")return"expression-child";if(t.kind==="component")return"component-child";if(t.kind==="control")return"control-child";if(t.kind==="element"&&!t.static||t.kind==="fragment")return"expression-child"}return"expression-child"}var ve=N(()=>{"use strict"});function Je(e,t=new Set,n={}){let r=vn(e,t,n);return G(r),r}var yt=N(()=>{"use strict";xn();ve()});function q(e){switch(e.kind){case"call":return!0;case"member":return e.property!==uo;case"compound":return e.parts.some(q);case"opaque":return!1}}var uo,_e=N(()=>{"use strict";uo="children"});function F(e){if(!e)return{kind:"opaque"};if(fo.has(e.type))return{kind:"call"};if(mo.has(e.type)){let t=e.property;return{kind:"member",property:!(e.computed===!0)&&t?.type==="Identifier"?t.name:null}}return e.type==="ConditionalExpression"?{kind:"compound",parts:[e.test,e.consequent,e.alternate].map(xe)}:e.type==="LogicalExpression"||e.type==="BinaryExpression"?{kind:"compound",parts:[e.left,e.right].map(xe)}:e.type==="TemplateLiteral"?{kind:"compound",parts:e.expressions.map(xe)}:e.type==="ObjectExpression"?{kind:"compound",parts:e.properties.filter(n=>(n.type==="ObjectProperty"||n.type==="Property")&&n.computed!==!0).map(n=>xe(n.value))}:e.type==="ArrayExpression"?{kind:"compound",parts:e.elements.filter(n=>n!=null&&n.type!=="SpreadElement").map(xe)}:{kind:"opaque"}}var fo,mo,xe,be=N(()=>{"use strict";fo=new Set(["CallExpression","OptionalCallExpression"]),mo=new Set(["MemberExpression","OptionalMemberExpression"]);xe=e=>F(e)});function Se(e){if(e.type==="StringLiteral"||e.type==="NumericLiteral"||e.type==="BooleanLiteral"||e.type==="Literal"&&(typeof e.value=="string"||typeof e.value=="number"||typeof e.value=="boolean"))return e.value}function vo(e,t){return e.type==="JSXIdentifier"?{tag:e.name,component:e.name[0]!==e.name[0].toLowerCase()}:e.type==="JSXMemberExpression"?{tag:t.code(e),component:!0}:e.type==="JSXNamespacedName"?{tag:`${e.namespace.name}:${e.name.name}`,component:!1}:{tag:"div",component:!1}}function xt(e){return e.type==="JSXIdentifier"?e.name==="class"?"className":e.name:e.type==="JSXNamespacedName"?`${e.namespace.name}:${e.name.name}`:"unknown"}function xo(e,t){let n=xt(e.name),r=ho.test(n),o=r||n.startsWith("on:")||n==="ref",a={name:n,kind:r?"event":"attr"};if(r){let l=n.slice(2).toLowerCase();a.event={name:l,delegated:yo.has(l)}}let s=e.value;if(s==null)return a.literal=!0,a.at=Ne(e,t),a;if(vt(s))return a.literal=Se(s),a.at=Ne(s,t),a;if(s.type==="JSXExpressionContainer"&&s.expression?.type!=="JSXEmptyExpression"){let l=s.expression,p=Se(l);return p!==void 0?(a.literal=p,a.at=Ne(l,t),a):(a.expr=t.code(l),a.reactive=o?!1:Sn(l),a.at=Ne(l,t),(l.type==="JSXElement"||l.type==="JSXFragment")&&(a.jsxElement=!0),a)}return a.literal=!0,a}function bn(e,t){let n=e.value;return n==null?null:vt(n)?JSON.stringify(Se(n)):n.type==="JSXExpressionContainer"&&n.expression?.type!=="JSXEmptyExpression"?t.code(n.expression):null}function bo(e,t){let n=[],r=[];for(let o of e){if(o.type==="JSXSpreadAttribute"){n.push({name:"",kind:"spread",expr:t.code(o.argument)});continue}if(o.type!=="JSXAttribute"||nt(xt(o.name)))continue;let i=o.name.type==="JSXNamespacedName"?o.name.namespace.name:null;if(i==="use"){let a=o.name.name.name;t.used.add(a);let s=bn(o,t);r.push(s!=null?`[${a}, () => (${s})]`:`[${a}]`);continue}if(i==="oncapture"){let a=o.name.name.name.toLowerCase(),s=bn(o,t)??"undefined";n.push({name:"on:"+a,kind:"attr",expr:`[${s}, { capture: true }]`});continue}n.push(xo(o,t))}return r.length>0&&n.push({name:"use",kind:"attr",expr:`[${r.join(", ")}]`}),n}function Nn(e,t){let n=[];for(let r of e)if(r.type==="JSXText"){let o=ye(r.value);o&&n.push({kind:"text",value:o})}else if(r.type==="JSXExpressionContainer"){if(r.expression?.type!=="JSXEmptyExpression"){let o=r.expression,i=Sn(o);n.push({kind:"expr",code:t.code(o),reactive:i,...i?{at:Ne(o,t)}:{}})}}else r.type==="JSXElement"||r.type==="JSXFragment"?n.push(Rn(r,t)):r.type==="JSXSpreadChild"&&n.push({kind:"expr",code:t.code(r.expression),reactive:!1});return n}function No(e){for(let t of e){if(t.type!=="JSXAttribute")continue;let n=xt(t.name);if(nt(n)){if(t.value&&!vt(t.value))throw new V(`'${n}' needs a literal value, not an expression — the strategy is compile-time.`);return Te(n,t.value?Se(t.value):null)}}}function Rn(e,t){if(e.type==="JSXFragment")return{kind:"fragment",children:Nn(e.children,t)};let{tag:n,component:r}=vo(e.openingElement.name,t),o=bo(e.openingElement.attributes,t),i=Nn(e.children,t),a=t.sourceFile&&e.loc?.start?{file:t.sourceFile,line:e.loc.start.line,column:e.loc.start.column}:void 0;if(r){let s=No(e.openingElement.attributes);return{kind:"component",name:n,props:o,children:i,...s?{load:s}:{},...a?{at:a}:{}}}return{kind:"element",tag:n,svg:go.has(n),props:o,children:i,static:!1,...a?{at:a}:{}}}function Be(e,t){let n=Rn(e,t);return G(n),n}var go,ho,yo,Sn,Ne,vt,bt=N(()=>{"use strict";ee();_e();be();ve();ut();go=new Set(["svg","path","circle","rect","line","polygon","polyline","ellipse","g","defs","clipPath","text"]),ho=/^on[A-Z]/,yo=new Set(["click","dblclick","input","change","submit","focus","blur","keydown","keyup","keypress","mousedown","mouseup"]),Sn=e=>q(F(e)),Ne=(e,t)=>{if(!t.sourceFile)return;let n=e.loc?.start;return n?{line:n.line,column:n.column}:void 0};vt=e=>!!e&&typeof Se(e)=="string"});function En(e){return So(e,{concise:!0}).code}function Ro(e,t,n){let r=J.types.cloneNode(e,!0),o=J.types.file(J.types.program([J.types.expressionStatement(r)])),i=!1,a=(s,l,p)=>{for(let c of p)t.add(c);s.replaceWith(J.template.expression(l,{placeholderPattern:!1,plugins:["typescript"]})()),s.skip(),i=!0};return(0,J.traverse)(o,{"JSXElement|JSXFragment"(s){let l=s.node,p=St(l,t,n);n?.(p);let{code:c,imports:u,templates:d}=L.emit(p,{});a(s,te(c,d),u)},TaggedTemplateExpression(s){let l=s.node.tag;if(!J.types.isIdentifier(l)||l.name!=="html"&&l.name!=="svg")return;let p=Je(s.node,t,{svg:l.name==="svg",onNested:n});n?.(p);let{code:c,imports:u,templates:d}=L.emit(p,{});a(s,te(c,d),u)}}),i?o.program.body[0].expression:e}function Fe(e,t,n){return En(Ro(e,t,n))}function gt(e){return q(F(e))}function St(e,t=new Set,n){return Be(e,{code:o=>o.type==="JSXMemberExpression"?En(o):Fe(o,t,n),used:t})}var J,Nt,So,ht=N(()=>{"use strict";J=require("@babel/core"),Nt=_(require("@babel/generator"),1);oe();yt();bt();_e();be();So=Nt.default.default??Nt.default});function Tn(e){return t=>{U(t,{resolver:e.componentResolver,modules:{controlFlowModule:e.controlFlowModule,coreModule:e.libModule,routerModule:e.routerModule},strategyFor:n=>n.load}),z(t),Xe(t,e)}}function Eo(e){let t=[f.types.objectProperty(f.types.identifier("kind"),f.types.stringLiteral(e.kind))];return e.kind==="visible"&&e.rootMargin&&t.push(f.types.objectProperty(f.types.identifier("rootMargin"),f.types.stringLiteral(e.rootMargin))),e.kind==="interaction"&&t.push(f.types.objectProperty(f.types.identifier("events"),f.types.arrayExpression(e.events.map(n=>f.types.stringLiteral(n))))),e.kind==="media"&&t.push(f.types.objectProperty(f.types.identifier("query"),f.types.stringLiteral(e.query))),f.types.objectExpression(t)}function $n(e,t,n){if(!t||t.length===0)return e;let r=new Map;for(let o of t){let i=`${o.svg?"svg:":""}${o.html}`,a=n.staticTemplates.get(i);a||(a=`_tmpl$${n.staticTemplates.size}`,n.staticTemplates.set(i,a)),r.set(o.id,a)}return e.replace(/_tmpl\$\d+/g,o=>r.get(o)??o)}function In(e,t){let n=new Set,r=St(e,n,Tn(t));U(r,{resolver:t.componentResolver,modules:{controlFlowModule:t.controlFlowModule,coreModule:t.libModule,routerModule:t.routerModule},strategyFor:l=>l.load}),z(r);let{code:o,imports:i,templates:a}=L.emit(r,{templateClone:t.templateClone,partialTemplates:t.partialTemplates});for(let l of i)n.add(l);for(let l of n)t.irImports.add(l);Xe(r,t);let s=$n(o,a,t);return f.template.expression(s,{placeholderPattern:!1,plugins:["typescript"]})()}function wo(e){let t=new Map,n=[];for(let r of e){let o=r.source.value;if(!r.specifiers.every(s=>f.types.isImportSpecifier(s))){n.push(r);continue}let a=t.get(o);if(!a){let s=new Set(r.specifiers.map(l=>l.local.name));t.set(o,{decl:r,names:s}),n.push(r);continue}for(let s of r.specifiers)a.names.has(s.local.name)||(a.names.add(s.local.name),a.decl.specifiers.push(s))}return n}function ko(e,t){let n=new Set,r=f.types.isIdentifier(e.tag)&&e.tag.name==="svg",o=Je(e,n,{svg:r,onNested:Tn(t)});U(o,{resolver:t.componentResolver,modules:{controlFlowModule:t.controlFlowModule,coreModule:t.libModule,routerModule:t.routerModule},strategyFor:p=>p.load}),z(o);let{code:i,imports:a,templates:s}=L.emit(o,{templateClone:t.templateClone,partialTemplates:t.partialTemplates});for(let p of a)n.add(p);for(let p of n)t.irImports.add(p);Xe(o,t),t.hasLitIR=!0;let l=f.template.expression($n(i,s,t),{placeholderPattern:!1,plugins:["typescript"]})();return Io(l,e),l}function Io(e,t){if(!t.loc)return;let n=new Set,r=o=>{if(!n.has(o)){n.add(o),o.loc||(o.loc=t.loc,o.start=t.start,o.end=t.end);for(let i of f.types.VISITOR_KEYS[o.type]??[]){let a=o[i];if(Array.isArray(a))for(let s of a)s&&typeof s=="object"&&"type"in s&&r(s);else a&&typeof a=="object"&&"type"in a&&r(a)}}};r(e)}function Xe(e,t){if(e.kind==="component"&&e.source&&(e.source.origin==="builtin"?(t.controlFlowComponents.add(e.name),t.needsControlFlowImport=!0):Q(e.source.loading)&&!t.resolvedComponents.has(e.name)?t.deferredComponents.set(e.name,{module:e.source.module,export:e.source.export,strategy:e.source.loading}):(t.deferredComponents.delete(e.name),t.resolvedComponents.set(e.name,{module:e.source.module,export:e.source.export}))),(e.kind==="element"||e.kind==="component"||e.kind==="control")&&"props"in e)for(let n of e.props)n.kind==="event"&&n.event?.delegated&&t.delegatedEvents.add(n.event.name);if("children"in e&&e.children)for(let n of e.children)Xe(n,t)}var Cn,f,wn,kn,ie,Rt=N(()=>{"use strict";Cn=require("@babel/helper-plugin-utils");le();ue();Me();ee();pe();f=require("@babel/core");ht();yt();oe();wn=new Set(Y),kn=new Set(H),ie=(0,Cn.declare)((e,t={})=>{e.assertVersion(7);let{delegateEvents:n=!0,signalModule:r="@fluixi/dom",controlFlowModule:o="@fluixi/dom",routerModule:i="@fluixi/core/router",reactiveModule:a="@fluixi/reactive/signal",templateClone:s=!0,partialTemplates:l=!0,format:p="both",litTag:c="html",resolve:u=[]}=t,d=X(u),x=p==="lit"||p==="both",g={irImports:new Set,libModule:"@fluixi/core",controlFlowModule:o,routerModule:i,templateClone:s,partialTemplates:l,hasJSX:!1,hasLitHTML:!1,needsControlFlowImport:!1,needsCreateMemo:!1,controlFlowComponents:new Set,resolvedComponents:new Map,deferredComponents:new Map,componentResolver:d,delegatedEvents:new Set,staticTemplates:new Map,staticCounter:0};return{name:"@fluixi/babel-plugin-jsx",manipulateOptions(h,v){v.plugins.push("jsx","typescript")},pre(h){Object.assign(h,g)},visitor:{Program:{enter(h,v){Object.assign(v,{hasJSX:!1,hasLitHTML:!1,hasLitIR:!1,needsControlFlowImport:!1,needsCreateMemo:!1,controlFlowComponents:new Set,resolvedComponents:new Map,deferredComponents:new Map,componentResolver:d,delegatedEvents:new Set,staticTemplates:new Map,staticCounter:0,libModule:"@fluixi/core",controlFlowModule:o,routerModule:i,templateClone:s,partialTemplates:l,irImports:new Set,needsCreateNativeElement:!1,needsInsert:!1,needsSpread:!1,needsCreateComponent:!1,needsMergeProps:!1})},exit(h,v){let R=[];if(v.hasJSX||v.hasLitIR){if(v.irImports.size>0){let E=new Set(["Show","For","Index","Switch","Match","Dynamic","ErrorBoundary","Portal","Suspense"]),S=new Set(["createMemo","createEffect","createRenderEffect","createRoot","createSignal","onCleanup","batch","untrack"]),w=Array.from(v.irImports),b=T=>f.types.importSpecifier(f.types.identifier(T),f.types.identifier(T)),y=T=>!h.scope.hasBinding(T),k=w.filter(T=>S.has(T)&&y(T)),I=w.filter(T=>!E.has(T)&&!S.has(T)&&y(T)),ne=w.filter(T=>E.has(T)&&y(T));k.length>0&&R.push(f.types.importDeclaration(k.map(b),f.types.stringLiteral(a))),I.length>0&&R.push(f.types.importDeclaration(I.map(b),f.types.stringLiteral(r))),ne.length>0&&R.push(f.types.importDeclaration(ne.map(b),f.types.stringLiteral(o)))}if(v.needsCreateMemo&&!h.scope.hasBinding("createMemo")&&R.push(f.types.importDeclaration([f.types.importSpecifier(f.types.identifier("createMemo"),f.types.identifier("createMemo"))],f.types.stringLiteral(a))),v.needsControlFlowImport&&v.controlFlowComponents.size>0){let E=Array.from(v.controlFlowComponents).filter(I=>!h.scope.hasBinding(I)),S=v.libModule??"@fluixi/core",w=E.filter(I=>kn.has(I)),b=E.filter(I=>wn.has(I)),y=E.filter(I=>!wn.has(I)&&!kn.has(I)),k=(I,ne)=>f.types.importDeclaration(I.map(T=>f.types.importSpecifier(f.types.identifier(T),f.types.identifier(T))),f.types.stringLiteral(ne));y.length>0&&R.push(k(y,o)),b.length>0&&R.push(k(b,S)),w.length>0&&R.push(k(w,i))}let C=[];if(v.deferredComponents.size>0){for(let[E,S]of v.deferredComponents)h.scope.hasBinding(E)||C.push(f.types.variableDeclaration("const",[f.types.variableDeclarator(f.types.identifier(E),f.types.callExpression(f.types.identifier("deferred"),[f.types.arrowFunctionExpression([],f.types.callExpression(f.types.import(),[f.types.stringLiteral(S.module)])),f.types.objectExpression([f.types.objectProperty(f.types.identifier("strategy"),Eo(S.strategy)),f.types.objectProperty(f.types.identifier("export"),f.types.stringLiteral(S.export))])]))]));C.length>0&&!h.scope.hasBinding("deferred")&&R.push(f.types.importDeclaration([f.types.importSpecifier(f.types.identifier("deferred"),f.types.identifier("deferred"))],f.types.stringLiteral(v.libModule??"@fluixi/core")))}if(v.resolvedComponents.size>0){let E=new Map;for(let[S,w]of v.resolvedComponents){if(h.scope.hasBinding(S))continue;let b=E.get(w.module)??[];b.push({local:S,exported:w.export}),E.set(w.module,b)}for(let[S,w]of E)R.push(f.types.importDeclaration(w.map(({local:b,exported:y})=>y==="default"?f.types.importDefaultSpecifier(f.types.identifier(b)):f.types.importSpecifier(f.types.identifier(b),f.types.identifier(y))),f.types.stringLiteral(S)))}if(n&&v.delegatedEvents.size>0){R.push(f.types.importDeclaration([f.types.importSpecifier(f.types.identifier("delegateEvents"),f.types.identifier("delegateEvents"))],f.types.stringLiteral(r)));let E=f.types.arrayExpression(Array.from(v.delegatedEvents).map(w=>f.types.stringLiteral(w))),S=f.types.expressionStatement(f.types.callExpression(f.types.identifier("delegateEvents"),[E]));h.node.body.unshift(S)}if(C.length>0&&h.node.body.unshift(...C),v.staticTemplates.size>0){let E=[];for(let[S,w]of v.staticTemplates){let y=S.startsWith("svg:")?S.slice(4):S;E.push(f.types.variableDeclaration("const",[f.types.variableDeclarator(f.types.identifier(w),f.types.stringLiteral(y))]))}h.node.body.unshift(...E)}}R.length>0&&h.node.body.unshift(...wo(R))}},JSXElement(h,v){v.hasJSX=!0,h.replaceWith(In(h.node,v))},JSXFragment(h,v){v.hasJSX=!0,h.replaceWith(In(h.node,v))},TaggedTemplateExpression(h,v){x&&f.types.isIdentifier(h.node.tag)&&(h.node.tag.name===c||h.node.tag.name==="svg")&&h.replaceWith(ko(h.node,v))}}}})});var Mn=N(()=>{"use strict"});var On={};ae(On,{babelPluginReactiveJSX:()=>Co,createPlugin:()=>To,createPreset:()=>He,default:()=>ie,presets:()=>$o});function To(e){return[ie,e]}function He(e={}){return{plugins:[[ie,{runtime:"automatic",importSource:"@fluixi/jsx",development:!1,detectReactivity:!0,useLitHTML:!0,hoistStatics:!0,delegateEvents:!0,optimizeControlFlow:!0,sourceMaps:!0,...e}]]}}var Co,$o,Pn=N(()=>{"use strict";Rt();Mn();Rt();Co=ie;$o={production:He({development:!1,hoistStatics:!0,delegateEvents:!0,optimizeControlFlow:!0}),development:He({development:!0,hoistStatics:!1,sourceMaps:!0}),minimal:He({detectReactivity:!1,useLitHTML:!1,hoistStatics:!1,delegateEvents:!1,optimizeControlFlow:!1})}});function Dn(e,t,n={}){let r=new Set,o=Ae(e,[...t],r,{svg:n.svg,...n.sourceFile?{sourceFile:n.sourceFile}:{},...n.positionAt?{positionAt:n.positionAt}:{}});G(o),U(o,{resolver:X(n.resolve??[]),modules:{controlFlowModule:n.controlFlowModule??"@fluixi/dom",coreModule:n.coreModule??"@fluixi/core",routerModule:n.routerModule??"@fluixi/core/router"},strategyFor:l=>l.load}),z(o);let{code:i,imports:a,templates:s}=L.emit(o,{templateClone:n.templateClone,partialTemplates:n.partialTemplates});for(let l of a)r.add(l);return n.hoistTemplates?{code:i,imports:[...r],ir:o,templates:s}:{code:te(i,s),imports:[...r],ir:o}}var Ln=N(()=>{"use strict";ve();Me();oe();ue();le();ft()});function K(e,t){if(e)switch(e.type){case"Identifier":t.add(e.name);return;case"ObjectPattern":for(let n of e.properties)n.type==="RestElement"?K(n.argument,t):K(n.value,t);return;case"ArrayPattern":for(let n of e.elements)K(n,t);return;case"AssignmentPattern":K(e.left,t);return;case"RestElement":K(e.argument,t);return}}function An(e,t){switch(e.type){case"ImportDeclaration":for(let n of e.specifiers)K(n.local,t);return;case"VariableDeclaration":for(let n of e.declarations)K(n.id,t);return;case"FunctionDeclaration":case"ClassDeclaration":K(e.id,t);return;case"ExportNamedDeclaration":case"ExportDefaultDeclaration":e.declaration&&An(e.declaration,t);return}}function se(e){let t=new Set;for(let n of e.body)An(n,t);return t}var We=N(()=>{"use strict"});function j(e,t){if(e)switch(e.type){case"Identifier":t.add(e.name);return;case"ObjectPattern":for(let n of e.properties)n.type==="RestElement"?j(n.argument,t):j(n.value,t);return;case"ArrayPattern":for(let n of e.elements)j(n,t);return;case"AssignmentPattern":j(e.left,t);return;case"RestElement":j(e.argument,t);return}}function Et(e){switch(e.type){case"StringLiteral":case"NumericLiteral":case"BooleanLiteral":case"NullLiteral":case"BigIntLiteral":case"RegExpLiteral":case"Identifier":return!0;case"Literal":return!0;case"TemplateLiteral":return e.expressions.every(Et);case"UnaryExpression":return Et(e.argument);case"MemberExpression":return!1;default:return!1}}function Ve(e,t){if(!(!e||typeof e!="object")){t(e);for(let n of Object.keys(e)){if(n==="loc"||n==="range"||n==="leadingComments"||n==="trailingComments")continue;let r=e[n];if(Array.isArray(r))for(let o of r)o&&typeof o=="object"&&Ve(o,t);else r&&typeof r=="object"&&typeof r.type=="string"&&Ve(r,t)}}}function Mo(e){let t=new Set;return Ve(e,n=>{if(n.type==="AssignmentExpression")j(n.left,t);else if(n.type==="UpdateExpression"){let r=n.argument;r?.type==="Identifier"&&t.add(r.name)}}),t}function Oo(e,t){let n=new Set,r=o=>{let i=new Set;j(o,i);for(let a of i)t.has(a)&&n.add(a)};return Ve(e,o=>{switch(o.type){case"VariableDeclarator":r(o.id);return;case"FunctionDeclaration":case"FunctionExpression":case"ArrowFunctionExpression":r(o.id);for(let i of o.params??[])r(i);return;case"CatchClause":r(o.param);return;case"ClassDeclaration":case"ClassExpression":r(o.id);return}}),n}function jn(e,t,n){for(let r of e.properties??[]){if(r.type==="RestElement"){let c=r.argument;if(c?.type!=="Identifier"||t.length>0){let u=new Set;j(c,u);for(let d of u)n.bails.push({name:d,reason:"rest"});continue}n.rest={name:c.name,keys:[]};continue}if(r.computed){let c=new Set;j(r.value,c);for(let u of c)n.bails.push({name:u,reason:"computed"});continue}let o=r.key,i=o.type==="Identifier"?o.name:o.value,a=r.value,s;a.type==="AssignmentPattern"&&(s=a.right,a=a.left);let l=[...t,i];if(a.type==="Identifier"){if(s&&!Et(s)){n.bails.push({name:a.name,reason:"unsafe-default"});continue}n.reads.push({name:a.name,path:l,...s?{fallback:s}:{}});continue}if(a.type==="ObjectPattern"){if(s){let c=new Set;j(a,c);for(let u of c)n.bails.push({name:u,reason:"unsafe-default"});continue}jn(a,l,n);continue}let p=new Set;j(a,p);for(let c of p)n.bails.push({name:c,reason:"computed"})}}function Ue(e,t){let n={reads:[],bails:[]};if(e?.type!=="ObjectPattern"||(jn(e,[],n),n.rest&&(t?.type!=="BlockStatement"?(n.bails.push({name:n.rest.name,reason:"rest"}),delete n.rest):n.rest.keys=(e.properties??[]).filter(s=>s.type!=="RestElement"&&!s.computed).map(s=>{let l=s.key;return l.type==="Identifier"?l.name:l.value})),n.reads.length===0&&!n.rest))return n;let r=new Set(n.reads.map(s=>s.name));n.rest&&r.add(n.rest.name);let o=Mo(t),i=Oo(t,r),a=[];for(let s of n.reads)o.has(s.name)?n.bails.push({name:s.name,reason:"reassigned"}):i.has(s.name)?n.bails.push({name:s.name,reason:"shadowed"}):a.push(s);return n.reads=a,n.rest&&o.has(n.rest.name)?(n.bails.push({name:n.rest.name,reason:"reassigned"}),delete n.rest):n.rest&&i.has(n.rest.name)&&(n.bails.push({name:n.rest.name,reason:"shadowed"}),delete n.rest),n}function ze(e){switch(e){case"rest":return"this rest element cannot be served by splitProps, and copying the props into a plain object would lose the getters";case"computed":return"the property is not known until it runs";case"reassigned":return"the binding is assigned to, and props are read-only";case"shadowed":return"an inner scope binds the same name";case"unsafe-default":return"the default would have to run again on every read"}}var wt=N(()=>{"use strict"});function Re(e,t,n=null){if(!(!e||typeof e!="object"||typeof e.type!="string")&&!e.type.startsWith("TS")&&t(e,n)!==!1)for(let r of Object.keys(e)){if(r==="loc"||r==="leadingComments"||r==="trailingComments")continue;let o=e[r];if(Array.isArray(o))for(let i of o)Re(i,t,e);else o&&typeof o=="object"&&Re(o,t,e)}}function Fn(e){return!!e&&e[0]>="A"&&e[0]<="Z"}function Po(e){let t=[];return Re(e,n=>{if(n.type==="FunctionDeclaration"&&Fn(n.id?.name)){t.push(n);return}if(n.type==="VariableDeclarator"&&Fn(n.id?.name)){let r=n.init;r&&(r.type==="ArrowFunctionExpression"||r.type==="FunctionExpression")&&t.push(r)}}),t}function Do(e){let t=new Set;return Re(e,n=>{n.type==="Identifier"&&t.add(n.name)}),t}function Lo(e,t){if(!t)return!0;switch(t.type){case"MemberExpression":case"OptionalMemberExpression":return!(t.property===e&&!t.computed);case"ObjectProperty":case"ObjectMethod":case"ClassProperty":case"ClassMethod":return!(t.key===e&&!t.computed);case"LabeledStatement":case"BreakStatement":case"ContinueStatement":return t.label!==e;case"ImportSpecifier":case"ExportSpecifier":return!1;default:return!0}}function kt(e,t,n={}){let r=[],o=[],i=new Set;for(let a of Po(e)){let s=a.params?.[0];if(s?.type!=="ObjectPattern")continue;let l=Ue(s,a.body);for(let g of l.bails)o.push({name:g.name,reason:g.reason,message:ze(g.reason),start:s.start});if(l.bails.length>0||l.reads.length===0&&!l.rest)continue;let p=Do(a),c=n.parameterName??"props";for(;p.has(c);)c=`_${c}`;let u=new Map;for(let g of l.reads){let h=`${c}.${g.path.join(".")}`,v=g.fallback;u.set(g.name,v?`(${h} === undefined ? ${t.slice(v.start,v.end)} : ${h})`:h)}let d=s.typeAnnotation;if(r.push({start:s.start,end:d?.start??s.end,code:c}),l.rest){let g=l.rest.keys.map(v=>JSON.stringify(v)).join(", "),h=a.body;r.push({start:h.start+1,end:h.start+1,code:`
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
/*! @fluixi/compiler v1.0.0-alpha.84 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __esm = (fn, res) => function __init() {
|
|
10
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
|
+
};
|
|
12
|
+
var __export = (target, all) => {
|
|
13
|
+
for (var name in all)
|
|
14
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
|
+
};
|
|
16
|
+
var __copyProps = (to, from, except, desc) => {
|
|
17
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
18
|
+
for (let key of __getOwnPropNames(from))
|
|
19
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
20
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
21
|
+
}
|
|
22
|
+
return to;
|
|
23
|
+
};
|
|
24
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
25
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
26
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
27
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
28
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
29
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
30
|
+
mod
|
|
31
|
+
));
|
|
32
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
33
|
+
|
|
34
|
+
// src/resolve/component-resolver.ts
|
|
35
|
+
function substitute(template3, match) {
|
|
36
|
+
return template3.replace(/\$(\d+)/g, (whole, index) => {
|
|
37
|
+
const group = match[Number(index)];
|
|
38
|
+
return group ?? whole;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function normalise(name, entry) {
|
|
42
|
+
return typeof entry === "string" ? { module: entry, export: name } : entry;
|
|
43
|
+
}
|
|
44
|
+
function createComponentResolver(rules = []) {
|
|
45
|
+
const exact = /* @__PURE__ */ new Map();
|
|
46
|
+
const conflicts = [];
|
|
47
|
+
const patterns = [];
|
|
48
|
+
for (const rule of rules) {
|
|
49
|
+
if (!isMapRule(rule)) {
|
|
50
|
+
patterns.push(rule);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
for (const [name, entry] of Object.entries(rule.components)) {
|
|
54
|
+
const resolved = normalise(name, entry);
|
|
55
|
+
const existing = exact.get(name);
|
|
56
|
+
if (existing && existing.module !== resolved.module) {
|
|
57
|
+
const conflict = conflicts.find((c) => c.name === name);
|
|
58
|
+
if (conflict) conflict.modules.push(resolved.module);
|
|
59
|
+
else conflicts.push({ name, modules: [existing.module, resolved.module] });
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
exact.set(name, resolved);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const cache = /* @__PURE__ */ new Map();
|
|
66
|
+
const resolve = (name) => {
|
|
67
|
+
if (cache.has(name)) return cache.get(name);
|
|
68
|
+
let result = exact.get(name);
|
|
69
|
+
if (!result) {
|
|
70
|
+
for (const rule of patterns) {
|
|
71
|
+
const match = name.match(new RegExp(rule.match.source, rule.match.flags.replace("g", "")));
|
|
72
|
+
if (!match) continue;
|
|
73
|
+
result = {
|
|
74
|
+
module: substitute(rule.module, match),
|
|
75
|
+
export: rule.export ? substitute(rule.export, match) : name
|
|
76
|
+
};
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
cache.set(name, result);
|
|
81
|
+
return result;
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
resolve,
|
|
85
|
+
names: () => [...exact.keys()],
|
|
86
|
+
conflicts: () => conflicts
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
var isMapRule;
|
|
90
|
+
var init_component_resolver = __esm({
|
|
91
|
+
"src/resolve/component-resolver.ts"() {
|
|
92
|
+
"use strict";
|
|
93
|
+
isMapRule = (rule) => "components" in rule;
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// src/resolve/builtins.ts
|
|
98
|
+
function builtinComponentMap(modules = {}) {
|
|
99
|
+
const {
|
|
100
|
+
controlFlowModule = "@fluixi/dom",
|
|
101
|
+
coreModule = "@fluixi/core",
|
|
102
|
+
routerModule = "@fluixi/core/router"
|
|
103
|
+
} = modules;
|
|
104
|
+
const map = {};
|
|
105
|
+
for (const name of DOM_CONTROL_FLOW) map[name] = controlFlowModule;
|
|
106
|
+
for (const name of CORE_CONTROL_FLOW) map[name] = coreModule;
|
|
107
|
+
for (const name of ROUTER_COMPONENTS) map[name] = routerModule;
|
|
108
|
+
return map;
|
|
109
|
+
}
|
|
110
|
+
var DOM_CONTROL_FLOW, CORE_CONTROL_FLOW, ROUTER_COMPONENTS, BUILTIN_COMPONENTS, RESERVED_COMPONENTS;
|
|
111
|
+
var init_builtins = __esm({
|
|
112
|
+
"src/resolve/builtins.ts"() {
|
|
113
|
+
"use strict";
|
|
114
|
+
DOM_CONTROL_FLOW = [
|
|
115
|
+
"Show",
|
|
116
|
+
"For",
|
|
117
|
+
"Index",
|
|
118
|
+
"Switch",
|
|
119
|
+
"Match",
|
|
120
|
+
"Portal",
|
|
121
|
+
"Dynamic",
|
|
122
|
+
"ErrorBoundary"
|
|
123
|
+
];
|
|
124
|
+
CORE_CONTROL_FLOW = ["Suspense", "SuspenseList", "Await"];
|
|
125
|
+
ROUTER_COMPONENTS = ["Router", "Outlet", "Redirect", "Link"];
|
|
126
|
+
BUILTIN_COMPONENTS = [
|
|
127
|
+
...DOM_CONTROL_FLOW,
|
|
128
|
+
...CORE_CONTROL_FLOW,
|
|
129
|
+
...ROUTER_COMPONENTS
|
|
130
|
+
];
|
|
131
|
+
RESERVED_COMPONENTS = /* @__PURE__ */ new Set([
|
|
132
|
+
...DOM_CONTROL_FLOW,
|
|
133
|
+
...CORE_CONTROL_FLOW
|
|
134
|
+
]);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// src/analyze/intrinsics.ts
|
|
139
|
+
function mayHaveIntrinsic(code) {
|
|
140
|
+
return INTRINSIC_CALL.test(code);
|
|
141
|
+
}
|
|
142
|
+
function isIntrinsicName(name) {
|
|
143
|
+
return Object.prototype.hasOwnProperty.call(INTRINSICS, name);
|
|
144
|
+
}
|
|
145
|
+
function isPrimitiveModule(source) {
|
|
146
|
+
return PRIMITIVE_MODULES.includes(source);
|
|
147
|
+
}
|
|
148
|
+
var REACTIVE_MODULE, INTRINSICS, RUNTIME_PRIMITIVES, PRIMITIVE_MODULES, INTRINSIC_CALL;
|
|
149
|
+
var init_intrinsics = __esm({
|
|
150
|
+
"src/analyze/intrinsics.ts"() {
|
|
151
|
+
"use strict";
|
|
152
|
+
REACTIVE_MODULE = "@fluixi/reactive/signal";
|
|
153
|
+
INTRINSICS = {
|
|
154
|
+
$signal: { export: "signal", module: REACTIVE_MODULE, returns: "signal-handle" },
|
|
155
|
+
$memo: { export: "memo", module: REACTIVE_MODULE, returns: "memo-handle" },
|
|
156
|
+
$effect: { export: "effect", module: REACTIVE_MODULE, returns: "effect" },
|
|
157
|
+
$store: { export: "store", module: "@fluixi/reactive/store", returns: "store-handle" },
|
|
158
|
+
$resource: { export: "resource", module: REACTIVE_MODULE, returns: "resource-handle" },
|
|
159
|
+
// No short runtime form for these yet, so the intrinsic stands for the `create*`
|
|
160
|
+
// name. Still worth having — no import to write — and when a shorter form is
|
|
161
|
+
// designed, the change is this line rather than a compiler pass.
|
|
162
|
+
$selector: { export: "createSelector", module: REACTIVE_MODULE, returns: "memo-accessor" },
|
|
163
|
+
$deferred: { export: "createDeferred", module: REACTIVE_MODULE, returns: "memo-accessor" },
|
|
164
|
+
// Not value constructors, but the compiler has to know them: they change what a read
|
|
165
|
+
// does. `untrack` suppresses dependency collection, which is exactly the kind of thing
|
|
166
|
+
// dependency analysis must not guess at.
|
|
167
|
+
$untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
|
|
168
|
+
$untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" }
|
|
169
|
+
};
|
|
170
|
+
RUNTIME_PRIMITIVES = {
|
|
171
|
+
signal: "signal-handle",
|
|
172
|
+
memo: "memo-handle",
|
|
173
|
+
effect: "effect",
|
|
174
|
+
store: "store-handle",
|
|
175
|
+
createSignal: ["signal-accessor", "signal-setter"],
|
|
176
|
+
createMemo: "memo-accessor",
|
|
177
|
+
createEffect: "effect",
|
|
178
|
+
createRenderEffect: "effect",
|
|
179
|
+
createStore: "reactive-object",
|
|
180
|
+
resource: "resource-handle",
|
|
181
|
+
createResource: "reactive-object",
|
|
182
|
+
createSelector: "memo-accessor",
|
|
183
|
+
createDeferred: "memo-accessor"
|
|
184
|
+
};
|
|
185
|
+
PRIMITIVE_MODULES = [
|
|
186
|
+
"@fluixi/reactive",
|
|
187
|
+
"@fluixi/reactive/signal",
|
|
188
|
+
"@fluixi/reactive/store",
|
|
189
|
+
"@fluixi/core"
|
|
190
|
+
];
|
|
191
|
+
INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join("|")})\\s*\\(`);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// src/resolve/load-directive.ts
|
|
196
|
+
function isLoadDirective(name) {
|
|
197
|
+
return name.startsWith("load:");
|
|
198
|
+
}
|
|
199
|
+
function parseLoadDirective(name, value) {
|
|
200
|
+
const strategy = name.slice("load:".length);
|
|
201
|
+
if (!STRATEGIES.has(strategy)) {
|
|
202
|
+
throw new LoadDirectiveError(
|
|
203
|
+
`Unknown load strategy 'load:${strategy}'. Expected one of ${[...STRATEGIES].join(", ")}.`
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
switch (strategy) {
|
|
207
|
+
case "eager":
|
|
208
|
+
return EAGER;
|
|
209
|
+
case "idle":
|
|
210
|
+
return { kind: "idle" };
|
|
211
|
+
case "never":
|
|
212
|
+
return { kind: "never" };
|
|
213
|
+
case "visible":
|
|
214
|
+
return value ? { kind: "visible", rootMargin: value } : { kind: "visible" };
|
|
215
|
+
case "interaction":
|
|
216
|
+
return {
|
|
217
|
+
kind: "interaction",
|
|
218
|
+
events: value ? splitEvents(value) : [...DEFAULT_INTERACTION_EVENTS]
|
|
219
|
+
};
|
|
220
|
+
case "media":
|
|
221
|
+
if (!value) {
|
|
222
|
+
throw new LoadDirectiveError(
|
|
223
|
+
`'load:media' needs a query, e.g. load:media="(min-width: 1024px)".`
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
return { kind: "media", query: value };
|
|
227
|
+
default:
|
|
228
|
+
throw new LoadDirectiveError(`Unhandled load strategy '${strategy}'.`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
function splitEvents(value) {
|
|
232
|
+
const events = value.split(/[\s,]+/).map((e) => e.trim()).filter(Boolean);
|
|
233
|
+
if (events.length === 0) {
|
|
234
|
+
throw new LoadDirectiveError(`'load:interaction' was given no event names.`);
|
|
235
|
+
}
|
|
236
|
+
return events;
|
|
237
|
+
}
|
|
238
|
+
function isDeferred(strategy) {
|
|
239
|
+
return strategy.kind !== "eager" && strategy.kind !== "never";
|
|
240
|
+
}
|
|
241
|
+
var EAGER, DEFAULT_INTERACTION_EVENTS, STRATEGIES, LoadDirectiveError;
|
|
242
|
+
var init_load_directive = __esm({
|
|
243
|
+
"src/resolve/load-directive.ts"() {
|
|
244
|
+
"use strict";
|
|
245
|
+
EAGER = { kind: "eager" };
|
|
246
|
+
DEFAULT_INTERACTION_EVENTS = ["pointerdown", "focusin", "keydown"];
|
|
247
|
+
STRATEGIES = /* @__PURE__ */ new Set(["eager", "idle", "visible", "interaction", "media", "never"]);
|
|
248
|
+
LoadDirectiveError = class extends Error {
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// src/resolve/resolve-ir.ts
|
|
254
|
+
function resolveComponentSources(root, options = {}) {
|
|
255
|
+
const { resolver, isBound, modules, strategyFor } = options;
|
|
256
|
+
const builtins = builtinComponentMap(modules);
|
|
257
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
258
|
+
const unresolved = /* @__PURE__ */ new Set();
|
|
259
|
+
const annotate = (node) => {
|
|
260
|
+
const { name } = node;
|
|
261
|
+
if (!name || name.includes(".")) return;
|
|
262
|
+
if (isBound?.(name)) return;
|
|
263
|
+
const source = sourceFor(name);
|
|
264
|
+
if (!source) {
|
|
265
|
+
unresolved.add(name);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
const loading = source.origin === "builtin" && RESERVED_COMPONENTS.has(name) ? EAGER : strategyFor?.(node) ?? EAGER;
|
|
269
|
+
node.source = { ...source, loading };
|
|
270
|
+
resolved.set(name, node.source);
|
|
271
|
+
};
|
|
272
|
+
const sourceFor = (name) => {
|
|
273
|
+
if (RESERVED_COMPONENTS.has(name)) {
|
|
274
|
+
return { module: builtins[name], export: name, origin: "builtin" };
|
|
275
|
+
}
|
|
276
|
+
const rule = resolver?.resolve(name);
|
|
277
|
+
if (rule) return { module: rule.module, export: rule.export, origin: "rule" };
|
|
278
|
+
if (ROUTER_COMPONENTS.includes(name)) {
|
|
279
|
+
return { module: builtins[name], export: name, origin: "builtin" };
|
|
280
|
+
}
|
|
281
|
+
return void 0;
|
|
282
|
+
};
|
|
283
|
+
walk(root, (node) => {
|
|
284
|
+
if (node.kind === "component") annotate(node);
|
|
285
|
+
});
|
|
286
|
+
return { resolved, unresolved: [...unresolved] };
|
|
287
|
+
}
|
|
288
|
+
function walk(root, visit) {
|
|
289
|
+
const nodes = Array.isArray(root) ? root : [root];
|
|
290
|
+
for (const node of nodes) {
|
|
291
|
+
visit(node);
|
|
292
|
+
const children = node.children;
|
|
293
|
+
if (children) walk(children, visit);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
var init_resolve_ir = __esm({
|
|
297
|
+
"src/resolve/resolve-ir.ts"() {
|
|
298
|
+
"use strict";
|
|
299
|
+
init_builtins();
|
|
300
|
+
init_load_directive();
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
// src/optimize/collapse-strategies.ts
|
|
305
|
+
function collapseStrategies(root) {
|
|
306
|
+
const components = [];
|
|
307
|
+
walk(root, (node) => {
|
|
308
|
+
if (node.kind === "component" && node.source) components.push(node);
|
|
309
|
+
});
|
|
310
|
+
const eager = /* @__PURE__ */ new Set();
|
|
311
|
+
const never = /* @__PURE__ */ new Set();
|
|
312
|
+
for (const node of components) {
|
|
313
|
+
const { module: module2, loading } = node.source;
|
|
314
|
+
if (loading.kind === "eager") eager.add(module2);
|
|
315
|
+
if (loading.kind === "never") never.add(module2);
|
|
316
|
+
}
|
|
317
|
+
const collapsed = /* @__PURE__ */ new Map();
|
|
318
|
+
for (const node of components) {
|
|
319
|
+
const source = node.source;
|
|
320
|
+
if (!isDeferred(source.loading)) continue;
|
|
321
|
+
if (!eager.has(source.module)) continue;
|
|
322
|
+
source.loading = { kind: "eager" };
|
|
323
|
+
collapsed.set(source.module, (collapsed.get(source.module) ?? 0) + 1);
|
|
324
|
+
}
|
|
325
|
+
return {
|
|
326
|
+
collapsed,
|
|
327
|
+
conflicted: [...never].filter((m) => eager.has(m))
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
var init_collapse_strategies = __esm({
|
|
331
|
+
"src/optimize/collapse-strategies.ts"() {
|
|
332
|
+
"use strict";
|
|
333
|
+
init_load_directive();
|
|
334
|
+
init_resolve_ir();
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
// src/codegen/serialize-static.ts
|
|
339
|
+
function isRawTextElement(tag) {
|
|
340
|
+
return RAW_TEXT_ELEMENTS.has(tag);
|
|
341
|
+
}
|
|
342
|
+
function htmlAttrName(name) {
|
|
343
|
+
return HTML_NAME[name] ?? name;
|
|
344
|
+
}
|
|
345
|
+
function isPlainLiteralAttr(prop) {
|
|
346
|
+
if (prop.kind !== "attr") return false;
|
|
347
|
+
if (prop.expr !== void 0) return false;
|
|
348
|
+
if (prop.name.includes(":")) return false;
|
|
349
|
+
return !PROPERTY_ONLY.has(prop.name);
|
|
350
|
+
}
|
|
351
|
+
function isSerializable(node) {
|
|
352
|
+
if (!node.static) return false;
|
|
353
|
+
if (isRawTextElement(node.tag)) return false;
|
|
354
|
+
for (const prop of node.props) {
|
|
355
|
+
if (!isPlainLiteralAttr(prop)) return false;
|
|
356
|
+
}
|
|
357
|
+
for (const child of node.children) {
|
|
358
|
+
if (child.kind === "text") continue;
|
|
359
|
+
if (child.kind === "element" && isSerializable(child)) continue;
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
362
|
+
return true;
|
|
363
|
+
}
|
|
364
|
+
function serializeStatic(node) {
|
|
365
|
+
const attrs = node.props.map(serializeProp).filter(Boolean).join("");
|
|
366
|
+
const open = `<${node.tag}${attrs}>`;
|
|
367
|
+
if (VOID_ELEMENTS.has(node.tag)) return open;
|
|
368
|
+
return `${open}${node.children.map(serializeChild).join("")}</${node.tag}>`;
|
|
369
|
+
}
|
|
370
|
+
function serializeChild(child) {
|
|
371
|
+
if (child.kind === "text") return escapeText(child.value);
|
|
372
|
+
if (child.kind !== "element") throw new Error(`serializeStatic: unexpected ${child.kind}`);
|
|
373
|
+
return serializeStatic(child);
|
|
374
|
+
}
|
|
375
|
+
function serializeProp(prop) {
|
|
376
|
+
const name = HTML_NAME[prop.name] ?? prop.name;
|
|
377
|
+
const value = prop.literal;
|
|
378
|
+
if (value === true || value === void 0) return ` ${name}`;
|
|
379
|
+
if (value === false || value === null) return "";
|
|
380
|
+
return ` ${name}="${escapeAttr(String(value))}"`;
|
|
381
|
+
}
|
|
382
|
+
function escapeAttr(value) {
|
|
383
|
+
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
384
|
+
}
|
|
385
|
+
function escapeText(value) {
|
|
386
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
387
|
+
}
|
|
388
|
+
function templatePositions(root) {
|
|
389
|
+
const pos = [];
|
|
390
|
+
let file;
|
|
391
|
+
const walk8 = (el) => {
|
|
392
|
+
file ??= el.at?.file;
|
|
393
|
+
pos.push(el.at?.line ?? 0, el.at?.column ?? 0);
|
|
394
|
+
for (const child of el.children) if (child.kind === "element") walk8(child);
|
|
395
|
+
};
|
|
396
|
+
walk8(root);
|
|
397
|
+
return file && pos.some((n) => n !== 0) ? { file, pos } : void 0;
|
|
398
|
+
}
|
|
399
|
+
var VOID_ELEMENTS, HTML_NAME, PROPERTY_ONLY, RAW_TEXT_ELEMENTS;
|
|
400
|
+
var init_serialize_static = __esm({
|
|
401
|
+
"src/codegen/serialize-static.ts"() {
|
|
402
|
+
"use strict";
|
|
403
|
+
VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
404
|
+
"area",
|
|
405
|
+
"base",
|
|
406
|
+
"br",
|
|
407
|
+
"col",
|
|
408
|
+
"embed",
|
|
409
|
+
"hr",
|
|
410
|
+
"img",
|
|
411
|
+
"input",
|
|
412
|
+
"link",
|
|
413
|
+
"meta",
|
|
414
|
+
"param",
|
|
415
|
+
"source",
|
|
416
|
+
"track",
|
|
417
|
+
"wbr"
|
|
418
|
+
]);
|
|
419
|
+
HTML_NAME = {
|
|
420
|
+
className: "class",
|
|
421
|
+
htmlFor: "for"
|
|
422
|
+
};
|
|
423
|
+
PROPERTY_ONLY = /* @__PURE__ */ new Set([
|
|
424
|
+
"innerHTML",
|
|
425
|
+
"outerHTML",
|
|
426
|
+
"innerText",
|
|
427
|
+
"textContent",
|
|
428
|
+
"value",
|
|
429
|
+
"checked",
|
|
430
|
+
"selected",
|
|
431
|
+
"muted",
|
|
432
|
+
"defaultValue",
|
|
433
|
+
"defaultChecked",
|
|
434
|
+
"children",
|
|
435
|
+
"ref"
|
|
436
|
+
]);
|
|
437
|
+
RAW_TEXT_ELEMENTS = /* @__PURE__ */ new Set(["script", "style", "textarea", "title"]);
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
// src/codegen/partial-template.ts
|
|
442
|
+
function isHole(node) {
|
|
443
|
+
return node.kind === "expr" || node.kind === "component" || node.kind === "control";
|
|
444
|
+
}
|
|
445
|
+
function isTemplateChild(node) {
|
|
446
|
+
return node.kind === "text" || node.kind === "element" && isTemplateElement(node);
|
|
447
|
+
}
|
|
448
|
+
function isTemplateElement(node) {
|
|
449
|
+
if (node.svg) return false;
|
|
450
|
+
if (isRawTextElement(node.tag)) return false;
|
|
451
|
+
if (!node.props.every((p) => isPlainLiteralAttr(p))) return false;
|
|
452
|
+
return node.children.every((c) => isTemplateChild(c) || isHole(c));
|
|
453
|
+
}
|
|
454
|
+
function containsHole(node) {
|
|
455
|
+
if (isHole(node)) return true;
|
|
456
|
+
const children = node.children;
|
|
457
|
+
return children ? children.some(containsHole) : false;
|
|
458
|
+
}
|
|
459
|
+
function addressable(el) {
|
|
460
|
+
for (let i = 0; i < el.children.length; i++) {
|
|
461
|
+
const child = el.children[i];
|
|
462
|
+
if (child.kind === "text") {
|
|
463
|
+
if (child.value === "") return false;
|
|
464
|
+
if (el.children[i + 1]?.kind === "text") return false;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
return el.children.every((c) => c.kind !== "element" || addressable(c));
|
|
468
|
+
}
|
|
469
|
+
function planPartialTemplate(root) {
|
|
470
|
+
if (!isTemplateElement(root)) return null;
|
|
471
|
+
if (!addressable(root)) return null;
|
|
472
|
+
if (!root.children.some(containsHole)) return null;
|
|
473
|
+
const steps = [];
|
|
474
|
+
const holes = [];
|
|
475
|
+
let refCount = 0;
|
|
476
|
+
const declare2 = (expr) => {
|
|
477
|
+
const ref = `_n$${refCount++}`;
|
|
478
|
+
steps.push({ ref, expr });
|
|
479
|
+
return ref;
|
|
480
|
+
};
|
|
481
|
+
walk8(root, "_el$");
|
|
482
|
+
return { html: serializeWithMarkers(root), tag: root.tag, steps, holes };
|
|
483
|
+
function walk8(el, elementRef) {
|
|
484
|
+
let last = -1;
|
|
485
|
+
el.children.forEach((child, i) => {
|
|
486
|
+
if (containsHole(child)) last = i;
|
|
487
|
+
});
|
|
488
|
+
let previous = null;
|
|
489
|
+
for (let i = 0; i <= last; i++) {
|
|
490
|
+
const child = el.children[i];
|
|
491
|
+
const expr = previous ? `${previous}.nextSibling` : `${elementRef}.firstChild`;
|
|
492
|
+
if (isHole(child)) {
|
|
493
|
+
const startRef = declare2(expr);
|
|
494
|
+
const endRef = declare2(`holeEnd(${startRef})`);
|
|
495
|
+
holes.push({ parentRef: elementRef, startRef, endRef, node: child });
|
|
496
|
+
previous = endRef;
|
|
497
|
+
continue;
|
|
498
|
+
}
|
|
499
|
+
const ref = declare2(expr);
|
|
500
|
+
if (child.kind === "element" && containsHole(child)) walk8(child, ref);
|
|
501
|
+
previous = ref;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
function serializeWithMarkers(el) {
|
|
506
|
+
return serializeStatic(withSentinels(el)).split(SENTINEL).join(HOLE_START + HOLE_END);
|
|
507
|
+
}
|
|
508
|
+
function withSentinels(el) {
|
|
509
|
+
return {
|
|
510
|
+
...el,
|
|
511
|
+
children: el.children.map(
|
|
512
|
+
(child) => isHole(child) ? { kind: "text", value: SENTINEL } : child.kind === "element" ? withSentinels(child) : child
|
|
513
|
+
)
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
var HOLE_START, HOLE_END, SENTINEL;
|
|
517
|
+
var init_partial_template = __esm({
|
|
518
|
+
"src/codegen/partial-template.ts"() {
|
|
519
|
+
"use strict";
|
|
520
|
+
init_serialize_static();
|
|
521
|
+
HOLE_START = "<!--fx-->";
|
|
522
|
+
HOLE_END = "<!--fx/-->";
|
|
523
|
+
SENTINEL = "\0fx-hole\0";
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
// src/codegen/contract.ts
|
|
528
|
+
var RUNTIME_CONTRACT_V1, RUNTIME_CONTRACT_V2;
|
|
529
|
+
var init_contract = __esm({
|
|
530
|
+
"src/codegen/contract.ts"() {
|
|
531
|
+
"use strict";
|
|
532
|
+
RUNTIME_CONTRACT_V1 = {
|
|
533
|
+
version: 1,
|
|
534
|
+
module: "@fluixi/dom",
|
|
535
|
+
symbols: [
|
|
536
|
+
"createNativeElement",
|
|
537
|
+
"insert",
|
|
538
|
+
"spread",
|
|
539
|
+
"setAttribute",
|
|
540
|
+
"delegateEvents",
|
|
541
|
+
"createComponent",
|
|
542
|
+
"createMemo",
|
|
543
|
+
"untrack",
|
|
544
|
+
"Show",
|
|
545
|
+
"For",
|
|
546
|
+
"Index",
|
|
547
|
+
"Switch",
|
|
548
|
+
"Match",
|
|
549
|
+
"Dynamic",
|
|
550
|
+
"ErrorBoundary"
|
|
551
|
+
]
|
|
552
|
+
};
|
|
553
|
+
RUNTIME_CONTRACT_V2 = {
|
|
554
|
+
version: 2,
|
|
555
|
+
module: "@fluixi/dom",
|
|
556
|
+
symbols: [...RUNTIME_CONTRACT_V1.symbols, "template", "cloneTemplate", "walk"]
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
// src/analyze/reactive-bindings.ts
|
|
562
|
+
function patternNames(node, out) {
|
|
563
|
+
if (!node) return;
|
|
564
|
+
switch (node.type) {
|
|
565
|
+
case "Identifier":
|
|
566
|
+
out.add(node.name);
|
|
567
|
+
return;
|
|
568
|
+
case "ObjectPattern":
|
|
569
|
+
for (const p of node.properties ?? []) {
|
|
570
|
+
if (p.type === "RestElement") patternNames(p.argument, out);
|
|
571
|
+
else patternNames(p.value, out);
|
|
572
|
+
}
|
|
573
|
+
return;
|
|
574
|
+
case "ArrayPattern":
|
|
575
|
+
for (const e of node.elements ?? []) patternNames(e, out);
|
|
576
|
+
return;
|
|
577
|
+
case "AssignmentPattern":
|
|
578
|
+
patternNames(node.left, out);
|
|
579
|
+
return;
|
|
580
|
+
case "RestElement":
|
|
581
|
+
patternNames(node.argument, out);
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
function walk2(root, visit) {
|
|
586
|
+
if (!root || typeof root !== "object" || typeof root.type !== "string") return;
|
|
587
|
+
visit(root);
|
|
588
|
+
for (const key of Object.keys(root)) {
|
|
589
|
+
if (key === "loc" || key === "leadingComments" || key === "trailingComments") continue;
|
|
590
|
+
const value = root[key];
|
|
591
|
+
if (Array.isArray(value)) for (const item of value) walk2(item, visit);
|
|
592
|
+
else if (value && typeof value === "object") walk2(value, visit);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
function calledPrimitive(node, bindings) {
|
|
596
|
+
if (node.type !== "CallExpression") return void 0;
|
|
597
|
+
const callee = node.callee;
|
|
598
|
+
if (callee?.type !== "Identifier") return void 0;
|
|
599
|
+
const name = callee.name;
|
|
600
|
+
const imported = bindings.primitives.get(name);
|
|
601
|
+
if (imported) return imported;
|
|
602
|
+
const intrinsic = INTRINSICS[name];
|
|
603
|
+
if (intrinsic && !bindings.shadowed.has(name)) return intrinsic.returns;
|
|
604
|
+
return void 0;
|
|
605
|
+
}
|
|
606
|
+
function classify(id, returns, kinds) {
|
|
607
|
+
if (Array.isArray(returns)) {
|
|
608
|
+
if (id.type === "ArrayPattern") {
|
|
609
|
+
id.elements.forEach((element, index) => {
|
|
610
|
+
const kind = returns[index];
|
|
611
|
+
if (element?.type === "Identifier" && kind) kinds.set(element.name, kind);
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
if (id.type === "Identifier") kinds.set(id.name, returns);
|
|
617
|
+
}
|
|
618
|
+
function declaredNames(program) {
|
|
619
|
+
const names = /* @__PURE__ */ new Set();
|
|
620
|
+
walk2(program, (node) => {
|
|
621
|
+
switch (node.type) {
|
|
622
|
+
case "VariableDeclarator":
|
|
623
|
+
patternNames(node.id, names);
|
|
624
|
+
return;
|
|
625
|
+
case "FunctionDeclaration":
|
|
626
|
+
case "FunctionExpression":
|
|
627
|
+
case "ArrowFunctionExpression":
|
|
628
|
+
patternNames(node.id, names);
|
|
629
|
+
for (const p of node.params ?? []) patternNames(p, names);
|
|
630
|
+
return;
|
|
631
|
+
case "ClassDeclaration":
|
|
632
|
+
case "ClassExpression":
|
|
633
|
+
patternNames(node.id, names);
|
|
634
|
+
return;
|
|
635
|
+
case "ImportSpecifier":
|
|
636
|
+
case "ImportDefaultSpecifier":
|
|
637
|
+
case "ImportNamespaceSpecifier":
|
|
638
|
+
patternNames(node.local, names);
|
|
639
|
+
return;
|
|
640
|
+
case "CatchClause":
|
|
641
|
+
patternNames(node.param, names);
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
return names;
|
|
646
|
+
}
|
|
647
|
+
function resolveReactiveBindings(program) {
|
|
648
|
+
const bindings = { kinds: /* @__PURE__ */ new Map(), primitives: /* @__PURE__ */ new Map(), shadowed: /* @__PURE__ */ new Set() };
|
|
649
|
+
const root = program;
|
|
650
|
+
walk2(root, (node) => {
|
|
651
|
+
const names = /* @__PURE__ */ new Set();
|
|
652
|
+
if (node.type === "VariableDeclarator") patternNames(node.id, names);
|
|
653
|
+
else if (node.type === "FunctionDeclaration" || node.type === "ClassDeclaration") patternNames(node.id, names);
|
|
654
|
+
else if (node.type === "ImportDefaultSpecifier" || node.type === "ImportNamespaceSpecifier") patternNames(node.local, names);
|
|
655
|
+
else if (node.type === "ImportSpecifier") patternNames(node.local, names);
|
|
656
|
+
else if (node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression" || node.type === "FunctionDeclaration") {
|
|
657
|
+
for (const p of node.params ?? []) patternNames(p, names);
|
|
658
|
+
}
|
|
659
|
+
for (const name of names) if (INTRINSICS[name]) bindings.shadowed.add(name);
|
|
660
|
+
});
|
|
661
|
+
for (const statement of root.body ?? []) {
|
|
662
|
+
if (statement.type !== "ImportDeclaration") continue;
|
|
663
|
+
if (!isPrimitiveModule(statement.source?.value)) continue;
|
|
664
|
+
for (const specifier of statement.specifiers ?? []) {
|
|
665
|
+
if (specifier.type !== "ImportSpecifier") continue;
|
|
666
|
+
const importedNode = specifier.imported;
|
|
667
|
+
const imported = importedNode.type === "Identifier" ? importedNode.name : importedNode.value;
|
|
668
|
+
const returns = RUNTIME_PRIMITIVES[imported];
|
|
669
|
+
if (returns) bindings.primitives.set(specifier.local.name, returns);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
walk2(root, (node) => {
|
|
673
|
+
if (node.type !== "VariableDeclarator" || !node.init) return;
|
|
674
|
+
const returns = calledPrimitive(node.init, bindings);
|
|
675
|
+
if (returns) classify(node.id, returns, bindings.kinds);
|
|
676
|
+
});
|
|
677
|
+
return bindings;
|
|
678
|
+
}
|
|
679
|
+
var init_reactive_bindings = __esm({
|
|
680
|
+
"src/analyze/reactive-bindings.ts"() {
|
|
681
|
+
"use strict";
|
|
682
|
+
init_intrinsics();
|
|
683
|
+
}
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
// src/transform/source-locations.ts
|
|
687
|
+
function mayHaveReactiveCall(code) {
|
|
688
|
+
for (const name of RUNTIME_PRIMITIVES2) {
|
|
689
|
+
if (code.includes(name)) return true;
|
|
690
|
+
}
|
|
691
|
+
return code.includes("$signal") || code.includes("$memo") || code.includes("$effect") || code.includes("$store");
|
|
692
|
+
}
|
|
693
|
+
function isLoneBranch(statement, parent) {
|
|
694
|
+
if (!parent || statement.type === "BlockStatement") return false;
|
|
695
|
+
return SINGLE_STATEMENT_PARENTS.has(parent.type);
|
|
696
|
+
}
|
|
697
|
+
function isExport(node) {
|
|
698
|
+
return node.type === "ExportNamedDeclaration" || node.type === "ExportDefaultDeclaration";
|
|
699
|
+
}
|
|
700
|
+
function isStatement(node) {
|
|
701
|
+
return node.type.endsWith("Statement") || node.type === "VariableDeclaration";
|
|
702
|
+
}
|
|
703
|
+
function walk3(node, visit, stack = []) {
|
|
704
|
+
if (!node || typeof node.type !== "string") return;
|
|
705
|
+
visit(node, stack);
|
|
706
|
+
stack.push(node);
|
|
707
|
+
for (const key of Object.keys(node)) {
|
|
708
|
+
if (key === "loc" || key === "parent") continue;
|
|
709
|
+
const value = node[key];
|
|
710
|
+
if (Array.isArray(value)) {
|
|
711
|
+
for (const child of value) walk3(child, visit, stack);
|
|
712
|
+
} else if (value && typeof value.type === "string") {
|
|
713
|
+
walk3(value, visit, stack);
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
stack.pop();
|
|
717
|
+
}
|
|
718
|
+
function nameFor(stack) {
|
|
719
|
+
const declarator = stack[stack.length - 1];
|
|
720
|
+
if (declarator?.type !== "VariableDeclarator") return void 0;
|
|
721
|
+
const id = declarator.id;
|
|
722
|
+
if (id?.type === "Identifier") return id.name;
|
|
723
|
+
if (id?.type === "ArrayPattern") {
|
|
724
|
+
const first = id.elements?.[0];
|
|
725
|
+
if (first?.type === "Identifier") return first.name;
|
|
726
|
+
}
|
|
727
|
+
return void 0;
|
|
728
|
+
}
|
|
729
|
+
function componentName(node) {
|
|
730
|
+
if (node.type === "FunctionDeclaration") {
|
|
731
|
+
const name = node.id?.name;
|
|
732
|
+
return name && name[0] === name[0]?.toUpperCase() ? name : void 0;
|
|
733
|
+
}
|
|
734
|
+
if (node.type === "VariableDeclarator") {
|
|
735
|
+
const id = node.id;
|
|
736
|
+
const init = node.init;
|
|
737
|
+
if (id?.type !== "Identifier" || !init) return void 0;
|
|
738
|
+
if (init.type !== "ArrowFunctionExpression" && init.type !== "FunctionExpression") return void 0;
|
|
739
|
+
const name = id.name;
|
|
740
|
+
return name[0] === name[0]?.toUpperCase() ? name : void 0;
|
|
741
|
+
}
|
|
742
|
+
return void 0;
|
|
743
|
+
}
|
|
744
|
+
function collectSourceEdits(program, filename) {
|
|
745
|
+
const edits = [];
|
|
746
|
+
const claimed = /* @__PURE__ */ new Set();
|
|
747
|
+
const { primitives, shadowed } = resolveReactiveBindings(program);
|
|
748
|
+
walk3(program, (node, stack) => {
|
|
749
|
+
const component = componentName(node);
|
|
750
|
+
if (component) {
|
|
751
|
+
const at = node.loc?.start;
|
|
752
|
+
let end2 = node.end;
|
|
753
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
754
|
+
const up = stack[i];
|
|
755
|
+
if (up.type !== "VariableDeclaration" && up.type !== "ExportNamedDeclaration" && up.type !== "ExportDefaultDeclaration") {
|
|
756
|
+
break;
|
|
757
|
+
}
|
|
758
|
+
end2 = up.end;
|
|
759
|
+
}
|
|
760
|
+
if (at) {
|
|
761
|
+
edits.push({
|
|
762
|
+
start: end2,
|
|
763
|
+
end: end2,
|
|
764
|
+
code: `;globalThis.${COMPONENT_MARKER}?.(${JSON.stringify(component)},${JSON.stringify(filename)},${at.line},${at.column});`
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
if (node.type !== "CallExpression") return;
|
|
769
|
+
const callee = node.callee;
|
|
770
|
+
if (callee?.type !== "Identifier") return;
|
|
771
|
+
const name = callee.name;
|
|
772
|
+
const intrinsic = isIntrinsicName(name) && !shadowed.has(name) ? INTRINSICS[name] : void 0;
|
|
773
|
+
const imported = primitives.has(name) || RUNTIME_PRIMITIVES2.has(name);
|
|
774
|
+
if (!intrinsic && !imported) return;
|
|
775
|
+
const position = node.loc?.start;
|
|
776
|
+
if (!position) return;
|
|
777
|
+
let statement;
|
|
778
|
+
let parent;
|
|
779
|
+
let index = -1;
|
|
780
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
781
|
+
if (isStatement(stack[i]) || isExport(stack[i])) {
|
|
782
|
+
statement = stack[i];
|
|
783
|
+
parent = stack[i - 1];
|
|
784
|
+
index = i;
|
|
785
|
+
break;
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
if (!statement) return;
|
|
789
|
+
let start = statement.start;
|
|
790
|
+
let end = statement.end;
|
|
791
|
+
for (let i = index - 1; i >= 0; i--) {
|
|
792
|
+
if (!isExport(stack[i])) break;
|
|
793
|
+
start = stack[i].start;
|
|
794
|
+
end = stack[i].end;
|
|
795
|
+
parent = stack[i - 1];
|
|
796
|
+
}
|
|
797
|
+
if (claimed.has(start)) return;
|
|
798
|
+
claimed.add(start);
|
|
799
|
+
const label = nameFor(stack);
|
|
800
|
+
const args = [
|
|
801
|
+
JSON.stringify(filename),
|
|
802
|
+
String(position.line),
|
|
803
|
+
String(position.column),
|
|
804
|
+
label ? JSON.stringify(label) : void 0
|
|
805
|
+
].filter((a) => a !== void 0).join(",");
|
|
806
|
+
const mark = `globalThis.${SOURCE_MARKER}?.(${args});`;
|
|
807
|
+
if (isLoneBranch(statement, parent)) {
|
|
808
|
+
edits.push({ start, end: start, code: `{${mark}` });
|
|
809
|
+
edits.push({ start: end, end, code: "}" });
|
|
810
|
+
return;
|
|
811
|
+
}
|
|
812
|
+
edits.push({ start, end: start, code: mark });
|
|
813
|
+
});
|
|
814
|
+
return { edits, marked: edits.length };
|
|
815
|
+
}
|
|
816
|
+
var SOURCE_MARKER, COMPONENT_MARKER, HOLE_MARKER, markHole, PROPS_MARKER, markProps, RUNTIME_PRIMITIVES2, SINGLE_STATEMENT_PARENTS;
|
|
817
|
+
var init_source_locations = __esm({
|
|
818
|
+
"src/transform/source-locations.ts"() {
|
|
819
|
+
"use strict";
|
|
820
|
+
init_intrinsics();
|
|
821
|
+
init_reactive_bindings();
|
|
822
|
+
SOURCE_MARKER = "__fx_source";
|
|
823
|
+
COMPONENT_MARKER = "__fx_component";
|
|
824
|
+
HOLE_MARKER = "__fx_hole";
|
|
825
|
+
markHole = (accessor, line, column, name) => `(globalThis.${HOLE_MARKER} ?? ((f) => f))(${accessor},${line},${column}${name === void 0 ? "" : `,${JSON.stringify(name)}`})`;
|
|
826
|
+
PROPS_MARKER = "__fx_props";
|
|
827
|
+
markProps = (object, at) => `(globalThis.${PROPS_MARKER} ?? ((p) => p))(${object},${JSON.stringify(at)})`;
|
|
828
|
+
RUNTIME_PRIMITIVES2 = /* @__PURE__ */ new Set([
|
|
829
|
+
"signal",
|
|
830
|
+
"memo",
|
|
831
|
+
"effect",
|
|
832
|
+
"store",
|
|
833
|
+
"resource",
|
|
834
|
+
"watch",
|
|
835
|
+
"createSignal",
|
|
836
|
+
"createMemo",
|
|
837
|
+
"createEffect",
|
|
838
|
+
"createStore",
|
|
839
|
+
"createResource"
|
|
840
|
+
]);
|
|
841
|
+
SINGLE_STATEMENT_PARENTS = /* @__PURE__ */ new Set([
|
|
842
|
+
"IfStatement",
|
|
843
|
+
"ForStatement",
|
|
844
|
+
"ForInStatement",
|
|
845
|
+
"ForOfStatement",
|
|
846
|
+
"WhileStatement",
|
|
847
|
+
"DoWhileStatement",
|
|
848
|
+
"LabeledStatement",
|
|
849
|
+
"WithStatement"
|
|
850
|
+
]);
|
|
851
|
+
}
|
|
852
|
+
});
|
|
853
|
+
|
|
854
|
+
// src/analyze/paren.ts
|
|
855
|
+
function skipQuoted(src, start) {
|
|
856
|
+
const quote = src[start];
|
|
857
|
+
for (let i = start + 1; i < src.length; i++) {
|
|
858
|
+
const c = src[i];
|
|
859
|
+
if (c === "\\") i++;
|
|
860
|
+
else if (c === quote) return i + 1;
|
|
861
|
+
else if (c === "\n") return -1;
|
|
862
|
+
}
|
|
863
|
+
return -1;
|
|
864
|
+
}
|
|
865
|
+
function skipTemplate(src, start) {
|
|
866
|
+
let i = start + 1;
|
|
867
|
+
while (i < src.length) {
|
|
868
|
+
const c = src[i];
|
|
869
|
+
if (c === "\\") {
|
|
870
|
+
i += 2;
|
|
871
|
+
} else if (c === "`") {
|
|
872
|
+
return i + 1;
|
|
873
|
+
} else if (c === "$" && src[i + 1] === "{") {
|
|
874
|
+
let depth = 1;
|
|
875
|
+
i += 2;
|
|
876
|
+
while (i < src.length && depth > 0) {
|
|
877
|
+
const k = src[i];
|
|
878
|
+
if (k === "\\") i += 2;
|
|
879
|
+
else if (k === "`") {
|
|
880
|
+
const end = skipTemplate(src, i);
|
|
881
|
+
if (end < 0) return -1;
|
|
882
|
+
i = end;
|
|
883
|
+
} else if (k === '"' || k === "'") {
|
|
884
|
+
const end = skipQuoted(src, i);
|
|
885
|
+
if (end < 0) return -1;
|
|
886
|
+
i = end;
|
|
887
|
+
} else {
|
|
888
|
+
if (k === "{") depth++;
|
|
889
|
+
else if (k === "}") depth--;
|
|
890
|
+
i++;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
} else {
|
|
894
|
+
i++;
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
return -1;
|
|
898
|
+
}
|
|
899
|
+
function skipRegex(src, start) {
|
|
900
|
+
let inClass = false;
|
|
901
|
+
for (let i = start + 1; i < src.length; i++) {
|
|
902
|
+
const c = src[i];
|
|
903
|
+
if (c === "\\") i++;
|
|
904
|
+
else if (c === "[") inClass = true;
|
|
905
|
+
else if (c === "]") inClass = false;
|
|
906
|
+
else if (c === "\n") return -1;
|
|
907
|
+
else if (c === "/" && !inClass) {
|
|
908
|
+
let end = i + 1;
|
|
909
|
+
while (end < src.length && /[a-z]/i.test(src[end])) end++;
|
|
910
|
+
return end;
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
return -1;
|
|
914
|
+
}
|
|
915
|
+
function divides(prev) {
|
|
916
|
+
return prev !== "" && /[A-Za-z0-9_$)\]]/.test(prev);
|
|
917
|
+
}
|
|
918
|
+
function topLevelComma(src) {
|
|
919
|
+
let depth = 0;
|
|
920
|
+
let prev = "";
|
|
921
|
+
let i = 0;
|
|
922
|
+
while (i < src.length) {
|
|
923
|
+
const c = src[i];
|
|
924
|
+
if (c === '"' || c === "'") {
|
|
925
|
+
const end = skipQuoted(src, i);
|
|
926
|
+
if (end < 0) return null;
|
|
927
|
+
i = end;
|
|
928
|
+
prev = c;
|
|
929
|
+
} else if (c === "`") {
|
|
930
|
+
const end = skipTemplate(src, i);
|
|
931
|
+
if (end < 0) return null;
|
|
932
|
+
i = end;
|
|
933
|
+
prev = c;
|
|
934
|
+
} else if (c === "/" && src[i + 1] === "/") {
|
|
935
|
+
return null;
|
|
936
|
+
} else if (c === "/" && src[i + 1] === "*") {
|
|
937
|
+
const end = src.indexOf("*/", i + 2);
|
|
938
|
+
if (end < 0) return null;
|
|
939
|
+
i = end + 2;
|
|
940
|
+
} else if (c === "/" && !divides(prev)) {
|
|
941
|
+
const end = skipRegex(src, i);
|
|
942
|
+
if (end < 0) return null;
|
|
943
|
+
i = end;
|
|
944
|
+
prev = "/";
|
|
945
|
+
} else {
|
|
946
|
+
if (c === "(" || c === "[" || c === "{") depth++;
|
|
947
|
+
else if (c === ")" || c === "]" || c === "}") {
|
|
948
|
+
depth--;
|
|
949
|
+
if (depth < 0) return null;
|
|
950
|
+
} else if (c === "," && depth === 0) return true;
|
|
951
|
+
if (!/\s/.test(c)) prev = c;
|
|
952
|
+
i++;
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
return depth === 0 ? false : null;
|
|
956
|
+
}
|
|
957
|
+
function paren(code, position) {
|
|
958
|
+
const src = code.trim();
|
|
959
|
+
if (src === "") return `(${code})`;
|
|
960
|
+
if (position === "arrowBody" && src[0] === "{") return `(${code})`;
|
|
961
|
+
return topLevelComma(src) === false ? code : `(${code})`;
|
|
962
|
+
}
|
|
963
|
+
var init_paren = __esm({
|
|
964
|
+
"src/analyze/paren.ts"() {
|
|
965
|
+
"use strict";
|
|
966
|
+
}
|
|
967
|
+
});
|
|
968
|
+
|
|
969
|
+
// src/codegen/backends/imperative.ts
|
|
970
|
+
function isIdent(name) {
|
|
971
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name);
|
|
972
|
+
}
|
|
973
|
+
function propKey(name) {
|
|
974
|
+
return isIdent(name) ? name : JSON.stringify(name);
|
|
975
|
+
}
|
|
976
|
+
function propValue(p) {
|
|
977
|
+
if (p.expr !== void 0) {
|
|
978
|
+
if (p.name === "ref" && p.at)
|
|
979
|
+
return markHole(paren(p.expr, "value"), p.at.line, p.at.column, p.expr);
|
|
980
|
+
if (!p.reactive) return paren(p.expr, "value");
|
|
981
|
+
const accessor = `() => ${paren(p.expr, "arrowBody")}`;
|
|
982
|
+
return p.at ? markHole(accessor, p.at.line, p.at.column, p.directive) : accessor;
|
|
983
|
+
}
|
|
984
|
+
return JSON.stringify(p.literal ?? true);
|
|
985
|
+
}
|
|
986
|
+
function componentPropValue(p) {
|
|
987
|
+
if (p.expr !== void 0) return paren(p.expr, "value");
|
|
988
|
+
return JSON.stringify(p.literal ?? true);
|
|
989
|
+
}
|
|
990
|
+
function emitProps(props, childrenExpr, used) {
|
|
991
|
+
const spreads = props.filter((p) => p.kind === "spread");
|
|
992
|
+
const normal = props.filter((p) => p.kind !== "spread");
|
|
993
|
+
const entries = normal.map((p) => `${propKey(p.name)}: ${propValue(p)}`);
|
|
994
|
+
if (childrenExpr != null) entries.push(`children: ${childrenExpr}`);
|
|
995
|
+
const obj = `{ ${entries.join(", ")} }`;
|
|
996
|
+
if (spreads.length > 0) {
|
|
997
|
+
used.add("mergeProps");
|
|
998
|
+
return `mergeProps(${spreads.map((s) => s.expr).join(", ")}, ${obj})`;
|
|
999
|
+
}
|
|
1000
|
+
return obj;
|
|
1001
|
+
}
|
|
1002
|
+
function markBind(code, at) {
|
|
1003
|
+
return at ? markHole(code, at.line, at.column) : code;
|
|
1004
|
+
}
|
|
1005
|
+
function emitChildren(children, used, templates) {
|
|
1006
|
+
if (children.length === 1) return emitNode(children[0], used, templates);
|
|
1007
|
+
return `[${children.map((c) => emitNode(c, used, templates)).join(", ")}]`;
|
|
1008
|
+
}
|
|
1009
|
+
function emitComponent(name, props, children, used, templates, at) {
|
|
1010
|
+
used.add("createMemo");
|
|
1011
|
+
used.add("createComponent");
|
|
1012
|
+
const spreads = props.filter((p) => p.kind === "spread");
|
|
1013
|
+
const normal = props.filter((p) => p.kind !== "spread");
|
|
1014
|
+
const entries = normal.map(
|
|
1015
|
+
(p) => `get ${propKey(p.name)}() { return ${componentPropValue(p)}; }`
|
|
1016
|
+
);
|
|
1017
|
+
if (children.length > 0) {
|
|
1018
|
+
entries.push(`get children() { return ${emitChildren(children, used, templates)}; }`);
|
|
1019
|
+
}
|
|
1020
|
+
let obj = `{ ${entries.join(", ")} }`;
|
|
1021
|
+
if (spreads.length > 0) {
|
|
1022
|
+
used.add("mergeProps");
|
|
1023
|
+
obj = `mergeProps(${spreads.map((s) => s.expr).join(", ")}, ${obj})`;
|
|
1024
|
+
}
|
|
1025
|
+
const propAt = {};
|
|
1026
|
+
for (const p of normal) if (p.at) propAt[p.name] = [p.at.line, p.at.column];
|
|
1027
|
+
if (Object.keys(propAt).length) obj = markProps(obj, propAt);
|
|
1028
|
+
const mark = at ? `globalThis.${SOURCE_MARKER}?.(${JSON.stringify(at.file)},${at.line},${at.column},${JSON.stringify(name)}), ` : "";
|
|
1029
|
+
return `createMemo(${paren(`${mark}() => createComponent(${name}, ${obj})`, "value")})`;
|
|
1030
|
+
}
|
|
1031
|
+
function staticAttrAssignment(el, prop) {
|
|
1032
|
+
const name = htmlAttrName(prop.name);
|
|
1033
|
+
const value = prop.literal;
|
|
1034
|
+
if (value === true || value === void 0) return `${el}.setAttribute(${JSON.stringify(name)}, "");`;
|
|
1035
|
+
if (value === false || value === null) return "";
|
|
1036
|
+
return `${el}.setAttribute(${JSON.stringify(name)}, ${JSON.stringify(String(value))});`;
|
|
1037
|
+
}
|
|
1038
|
+
function emitNode(node, used, templates) {
|
|
1039
|
+
switch (node.kind) {
|
|
1040
|
+
case "text":
|
|
1041
|
+
return JSON.stringify(node.value);
|
|
1042
|
+
case "expr": {
|
|
1043
|
+
if (!node.reactive) return paren(node.code, "value");
|
|
1044
|
+
const accessor = `() => ${paren(node.code, "arrowBody")}`;
|
|
1045
|
+
return node.at ? markHole(accessor, node.at.line, node.at.column) : accessor;
|
|
1046
|
+
}
|
|
1047
|
+
case "fragment":
|
|
1048
|
+
if (node.children.length === 0) return "null";
|
|
1049
|
+
return emitChildren(node.children, used, templates);
|
|
1050
|
+
case "component":
|
|
1051
|
+
return markBind(emitComponent(node.name, node.props, node.children, used, templates, node.at), node.bindAt ?? node.at);
|
|
1052
|
+
case "control": {
|
|
1053
|
+
const name = CONTROL_COMPONENT[node.control] ?? node.control;
|
|
1054
|
+
used.add(name);
|
|
1055
|
+
return markBind(emitComponent(name, node.props, node.children, used, templates), node.bindAt);
|
|
1056
|
+
}
|
|
1057
|
+
case "element": {
|
|
1058
|
+
if (templates && node.static && !node.svg && isSerializable(node)) {
|
|
1059
|
+
used.add("templateNode");
|
|
1060
|
+
const id = `_tmpl$${templates.length}`;
|
|
1061
|
+
templates.push({ id, html: serializeStatic(node), tag: node.tag, svg: false });
|
|
1062
|
+
const at = templatePositions(node);
|
|
1063
|
+
return at ? `templateNode(${id}, ${JSON.stringify(node.tag)}, false, false, ${JSON.stringify(at)})` : `templateNode(${id}, ${JSON.stringify(node.tag)})`;
|
|
1064
|
+
}
|
|
1065
|
+
if (templates && partial) {
|
|
1066
|
+
const plan = planPartialTemplate(node);
|
|
1067
|
+
if (plan) {
|
|
1068
|
+
used.add("templateNode");
|
|
1069
|
+
used.add("insert");
|
|
1070
|
+
used.add("holeEnd");
|
|
1071
|
+
used.add("holeContent");
|
|
1072
|
+
used.add("holeScope");
|
|
1073
|
+
const id = `_tmpl$${templates.length}`;
|
|
1074
|
+
templates.push({ id, html: plan.html, tag: plan.tag, svg: false });
|
|
1075
|
+
const at = templatePositions(node);
|
|
1076
|
+
const lines = [
|
|
1077
|
+
`const _el$ = templateNode(${id}, ${JSON.stringify(plan.tag)}, true${at ? `, false, ${JSON.stringify(at)}` : ""});`
|
|
1078
|
+
];
|
|
1079
|
+
for (const step of plan.steps) lines.push(`const ${step.ref} = ${step.expr};`);
|
|
1080
|
+
for (const hole of plan.holes) {
|
|
1081
|
+
lines.push(
|
|
1082
|
+
`insert(${hole.parentRef}, holeScope(${hole.startRef}, () => ${paren(emitNode(hole.node, used, templates), "arrowBody")}), ${hole.endRef}, holeContent(${hole.startRef}, ${hole.endRef}));`
|
|
1083
|
+
);
|
|
1084
|
+
}
|
|
1085
|
+
lines.push("return _el$;");
|
|
1086
|
+
return `(() => { ${lines.join(" ")} })()`;
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
used.add("createNativeElement");
|
|
1090
|
+
const tag = JSON.stringify(node.tag);
|
|
1091
|
+
const el = "_el$";
|
|
1092
|
+
const parts = [];
|
|
1093
|
+
const createArgs = node.at ? `${tag}, ${node.svg}, ${JSON.stringify(node.at)}` : node.svg ? `${tag}, true` : tag;
|
|
1094
|
+
parts.push(`const ${el} = createNativeElement(${createArgs});`);
|
|
1095
|
+
if (node.props.length > 0) {
|
|
1096
|
+
if (!node.svg && node.props.every(isPlainLiteralAttr)) {
|
|
1097
|
+
for (const p of node.props) parts.push(staticAttrAssignment(el, p));
|
|
1098
|
+
} else {
|
|
1099
|
+
used.add("spread");
|
|
1100
|
+
const svgFlag = node.svg ? ", isSVG: true" : "";
|
|
1101
|
+
parts.push(`spread({ element: ${el}, props: ${emitProps(node.props, null, used)}${svgFlag} });`);
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
for (const child of node.children) {
|
|
1105
|
+
used.add("insert");
|
|
1106
|
+
const childCode = emitNode(child, used, templates);
|
|
1107
|
+
const isFn = child.kind === "expr" && child.reactive || child.kind === "component" || child.kind === "control";
|
|
1108
|
+
parts.push(isFn ? `insert(${el}, ${childCode}, null);` : `insert(${el}, ${childCode});`);
|
|
1109
|
+
}
|
|
1110
|
+
parts.push(`return ${el};`);
|
|
1111
|
+
return `(() => { ${parts.join(" ")} })()`;
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
function inlineTemplates(code, templates) {
|
|
1116
|
+
if (!templates || templates.length === 0) return code;
|
|
1117
|
+
const byId = new Map(templates.map((t4) => [t4.id, JSON.stringify(t4.html)]));
|
|
1118
|
+
return code.replace(/_tmpl\$\d+/g, (id) => byId.get(id) ?? id);
|
|
1119
|
+
}
|
|
1120
|
+
var CONTROL_COMPONENT, partial, imperativeBackend;
|
|
1121
|
+
var init_imperative = __esm({
|
|
1122
|
+
"src/codegen/backends/imperative.ts"() {
|
|
1123
|
+
"use strict";
|
|
1124
|
+
init_partial_template();
|
|
1125
|
+
init_serialize_static();
|
|
1126
|
+
init_contract();
|
|
1127
|
+
init_source_locations();
|
|
1128
|
+
init_paren();
|
|
1129
|
+
CONTROL_COMPONENT = {
|
|
1130
|
+
show: "Show",
|
|
1131
|
+
for: "For",
|
|
1132
|
+
index: "Index",
|
|
1133
|
+
switch: "Switch",
|
|
1134
|
+
match: "Match",
|
|
1135
|
+
dynamic: "Dynamic",
|
|
1136
|
+
errorBoundary: "ErrorBoundary",
|
|
1137
|
+
suspense: "Suspense"
|
|
1138
|
+
};
|
|
1139
|
+
partial = false;
|
|
1140
|
+
imperativeBackend = {
|
|
1141
|
+
name: "imperative",
|
|
1142
|
+
contract: RUNTIME_CONTRACT_V1,
|
|
1143
|
+
emit(node, options) {
|
|
1144
|
+
const used = /* @__PURE__ */ new Set();
|
|
1145
|
+
const templates = options?.templateClone !== false ? [] : void 0;
|
|
1146
|
+
partial = options?.partialTemplates === true;
|
|
1147
|
+
const code = emitNode(node, used, templates);
|
|
1148
|
+
return { code, imports: Array.from(used), templates };
|
|
1149
|
+
}
|
|
1150
|
+
};
|
|
1151
|
+
}
|
|
1152
|
+
});
|
|
1153
|
+
|
|
1154
|
+
// src/lower/text.ts
|
|
1155
|
+
function cleanTemplateText(value) {
|
|
1156
|
+
const lines = value.split(/\r\n|\n|\r/);
|
|
1157
|
+
let lastNonEmpty = 0;
|
|
1158
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1159
|
+
if (/[^ \t]/.test(lines[i])) lastNonEmpty = i;
|
|
1160
|
+
}
|
|
1161
|
+
let out = "";
|
|
1162
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1163
|
+
let line = lines[i].replace(/\t/g, " ");
|
|
1164
|
+
if (i !== 0) line = line.replace(/^ +/, "");
|
|
1165
|
+
if (i !== lines.length - 1) line = line.replace(/ +$/, "");
|
|
1166
|
+
if (!line) continue;
|
|
1167
|
+
if (i !== lastNonEmpty) line += " ";
|
|
1168
|
+
out += line;
|
|
1169
|
+
}
|
|
1170
|
+
return out;
|
|
1171
|
+
}
|
|
1172
|
+
var init_text = __esm({
|
|
1173
|
+
"src/lower/text.ts"() {
|
|
1174
|
+
"use strict";
|
|
1175
|
+
}
|
|
1176
|
+
});
|
|
1177
|
+
|
|
1178
|
+
// src/lower/template.ts
|
|
1179
|
+
function escapeTemplate(s) {
|
|
1180
|
+
return s.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
|
|
1181
|
+
}
|
|
1182
|
+
function capitalize(s) {
|
|
1183
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
1184
|
+
}
|
|
1185
|
+
function lowerTemplate(pieces, holes, used, opts = {}) {
|
|
1186
|
+
const { root } = (0, import_template_parser.parseTemplate)(pieces, { svg: opts.svg });
|
|
1187
|
+
return new Lowerer(holes, used, opts.sourceFile, opts.positionAt).lowerRoot(root.children);
|
|
1188
|
+
}
|
|
1189
|
+
var import_template_parser, DELEGATED, Lowerer;
|
|
1190
|
+
var init_template = __esm({
|
|
1191
|
+
"src/lower/template.ts"() {
|
|
1192
|
+
"use strict";
|
|
1193
|
+
import_template_parser = require("@fluixi/template-parser");
|
|
1194
|
+
init_load_directive();
|
|
1195
|
+
init_imperative();
|
|
1196
|
+
init_text();
|
|
1197
|
+
init_paren();
|
|
1198
|
+
DELEGATED = /* @__PURE__ */ new Set([
|
|
1199
|
+
"click",
|
|
1200
|
+
"dblclick",
|
|
1201
|
+
"input",
|
|
1202
|
+
"change",
|
|
1203
|
+
"submit",
|
|
1204
|
+
"focus",
|
|
1205
|
+
"blur",
|
|
1206
|
+
"keydown",
|
|
1207
|
+
"keyup",
|
|
1208
|
+
"keypress",
|
|
1209
|
+
"mousedown",
|
|
1210
|
+
"mouseup"
|
|
1211
|
+
]);
|
|
1212
|
+
Lowerer = class {
|
|
1213
|
+
constructor(holes, used, sourceFile, positionAt) {
|
|
1214
|
+
this.holes = holes;
|
|
1215
|
+
this.used = used;
|
|
1216
|
+
this.sourceFile = sourceFile;
|
|
1217
|
+
this.positionAt = positionAt;
|
|
1218
|
+
}
|
|
1219
|
+
/**
|
|
1220
|
+
* Where a tag is written, for the mark a component node carries.
|
|
1221
|
+
*
|
|
1222
|
+
* The parser reports offsets, and they are offsets into the file: the pieces it was given
|
|
1223
|
+
* carry the positions the front-end recorded. Only built when the host asked for source
|
|
1224
|
+
* locations, which is the only time either of these is set.
|
|
1225
|
+
*/
|
|
1226
|
+
tagAt(node) {
|
|
1227
|
+
const start = node.loc?.start;
|
|
1228
|
+
if (!this.sourceFile || !this.positionAt || start == null) return void 0;
|
|
1229
|
+
const { line, column } = this.positionAt(start);
|
|
1230
|
+
return { file: this.sourceFile, line, column };
|
|
1231
|
+
}
|
|
1232
|
+
hole(i) {
|
|
1233
|
+
return this.holes[i] ?? { code: "undefined", reactive: false };
|
|
1234
|
+
}
|
|
1235
|
+
/** Emit a nested IR subtree to code (for `Show` fallback / `For` children). */
|
|
1236
|
+
emit(node) {
|
|
1237
|
+
const { code, imports, templates } = imperativeBackend.emit(node, {});
|
|
1238
|
+
for (const s of imports) this.used.add(s);
|
|
1239
|
+
return inlineTemplates(code, templates);
|
|
1240
|
+
}
|
|
1241
|
+
// --- content ------------------------------------------------------------
|
|
1242
|
+
lowerRoot(children) {
|
|
1243
|
+
const nodes = this.lowerChildren(children);
|
|
1244
|
+
if (nodes.length === 1) return nodes[0];
|
|
1245
|
+
return { kind: "fragment", children: nodes };
|
|
1246
|
+
}
|
|
1247
|
+
/** Lower a sibling list, handling text-drop and if/else/each restructuring. */
|
|
1248
|
+
lowerChildren(children) {
|
|
1249
|
+
const out = [];
|
|
1250
|
+
for (let i = 0; i < children.length; i++) {
|
|
1251
|
+
const child = children[i];
|
|
1252
|
+
if (child.kind === "Element" || child.kind === "Component") {
|
|
1253
|
+
const ifDir = child.attributes.find((a) => a.kind === "IfDirective");
|
|
1254
|
+
if (ifDir && ifDir.kind === "IfDirective") {
|
|
1255
|
+
let elseIdx = i + 1;
|
|
1256
|
+
if (elseIdx < children.length && this.isBlankText(children[elseIdx])) elseIdx++;
|
|
1257
|
+
const elseNode = children[elseIdx];
|
|
1258
|
+
const hasElse = elseNode && (elseNode.kind === "Element" || elseNode.kind === "Component") && elseNode.attributes.some((a) => a.kind === "ElseDirective");
|
|
1259
|
+
out.push(this.lowerIf(child, ifDir.hole, hasElse ? elseNode : null));
|
|
1260
|
+
if (hasElse) i = elseIdx;
|
|
1261
|
+
continue;
|
|
1262
|
+
}
|
|
1263
|
+
if (child.attributes.some((a) => a.kind === "EachDirective")) {
|
|
1264
|
+
out.push(this.lowerEach(child));
|
|
1265
|
+
continue;
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
const node = this.lowerNode(child);
|
|
1269
|
+
if (node) out.push(node);
|
|
1270
|
+
}
|
|
1271
|
+
return out;
|
|
1272
|
+
}
|
|
1273
|
+
isBlankText(n) {
|
|
1274
|
+
return n.kind === "Text" && !n.raw && cleanTemplateText(n.value) === "";
|
|
1275
|
+
}
|
|
1276
|
+
lowerNode(node) {
|
|
1277
|
+
switch (node.kind) {
|
|
1278
|
+
case "Text": {
|
|
1279
|
+
if (node.raw) return { kind: "text", value: node.value };
|
|
1280
|
+
const cleaned = cleanTemplateText(node.value);
|
|
1281
|
+
return cleaned ? { kind: "text", value: cleaned } : null;
|
|
1282
|
+
}
|
|
1283
|
+
case "Comment":
|
|
1284
|
+
return null;
|
|
1285
|
+
// dropped, like JSX comments
|
|
1286
|
+
case "Expression": {
|
|
1287
|
+
const h = this.hole(node.hole);
|
|
1288
|
+
return { kind: "expr", code: h.code, reactive: h.reactive, ...h.at ? { at: h.at } : {} };
|
|
1289
|
+
}
|
|
1290
|
+
case "Fragment":
|
|
1291
|
+
return { kind: "fragment", children: this.lowerChildren(node.children) };
|
|
1292
|
+
case "Element":
|
|
1293
|
+
return this.lowerElement(node);
|
|
1294
|
+
case "Component":
|
|
1295
|
+
return this.lowerComponent(node);
|
|
1296
|
+
default:
|
|
1297
|
+
return null;
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
lowerElement(el) {
|
|
1301
|
+
const isAttr = el.attributes.find((a) => a.kind === "Attribute" && a.name === "is");
|
|
1302
|
+
if (el.tag === "component" && isAttr && isAttr.value && isAttr.value.kind === "hole") {
|
|
1303
|
+
const rest = el.attributes.filter((a) => a !== isAttr);
|
|
1304
|
+
const node = this.lowerComponent({ ...el, kind: "Component", tag: "Dynamic", tagHole: null, attributes: rest });
|
|
1305
|
+
node.props.unshift({ name: "component", kind: "attr", expr: `() => ${paren(this.hole(isAttr.value.hole).code, "arrowBody")}` });
|
|
1306
|
+
return node;
|
|
1307
|
+
}
|
|
1308
|
+
const at = this.tagAt(el);
|
|
1309
|
+
return {
|
|
1310
|
+
kind: "element",
|
|
1311
|
+
tag: el.tag,
|
|
1312
|
+
svg: el.namespace === "svg",
|
|
1313
|
+
props: this.lowerAttributes(el.attributes),
|
|
1314
|
+
children: this.lowerChildren(el.children),
|
|
1315
|
+
static: false,
|
|
1316
|
+
...at ? { at } : {}
|
|
1317
|
+
};
|
|
1318
|
+
}
|
|
1319
|
+
lowerComponent(el) {
|
|
1320
|
+
const name = el.tagHole != null ? this.hole(el.tagHole).code : el.tag;
|
|
1321
|
+
const props = this.lowerAttributes(el.attributes);
|
|
1322
|
+
const { slots, rest } = this.partitionSlots(el.children);
|
|
1323
|
+
for (const [slotName, nodes] of slots) {
|
|
1324
|
+
const ir = nodes.length === 1 ? nodes[0] : { kind: "fragment", children: nodes };
|
|
1325
|
+
const slotProp = {
|
|
1326
|
+
name: slotName,
|
|
1327
|
+
kind: "attr",
|
|
1328
|
+
expr: this.emit(ir),
|
|
1329
|
+
jsxElement: true
|
|
1330
|
+
};
|
|
1331
|
+
const clash = props.findIndex((p) => p.name === slotName);
|
|
1332
|
+
if (clash >= 0) props[clash] = slotProp;
|
|
1333
|
+
else props.push(slotProp);
|
|
1334
|
+
}
|
|
1335
|
+
const loadAttr = el.attributes.find((a) => a.kind === "LoadDirective");
|
|
1336
|
+
const load = loadAttr ? parseLoadDirective(`load:${loadAttr.strategy}`, loadAttr.modifier) : void 0;
|
|
1337
|
+
const bindAt = props.find((p) => p.at && p.reactive)?.at;
|
|
1338
|
+
const at = this.tagAt(el);
|
|
1339
|
+
return {
|
|
1340
|
+
kind: "component",
|
|
1341
|
+
name,
|
|
1342
|
+
props,
|
|
1343
|
+
children: this.lowerChildren(rest),
|
|
1344
|
+
...at ? { at } : {},
|
|
1345
|
+
...bindAt ? { bindAt } : {},
|
|
1346
|
+
...load ? { load } : {}
|
|
1347
|
+
};
|
|
1348
|
+
}
|
|
1349
|
+
/** Split a component's children into named slots (`slot="x"`) and the rest. */
|
|
1350
|
+
partitionSlots(children) {
|
|
1351
|
+
const slots = /* @__PURE__ */ new Map();
|
|
1352
|
+
const rest = [];
|
|
1353
|
+
for (const child of children) {
|
|
1354
|
+
if (child.kind === "Element" || child.kind === "Component") {
|
|
1355
|
+
const slot = child.attributes.find(
|
|
1356
|
+
(a) => a.kind === "Attribute" && a.name === "slot"
|
|
1357
|
+
);
|
|
1358
|
+
if (slot && slot.value && slot.value.kind === "static") {
|
|
1359
|
+
const stripped = { ...child, attributes: child.attributes.filter((a) => a !== slot) };
|
|
1360
|
+
const ir = stripped.kind === "Element" ? this.lowerElement(stripped) : this.lowerComponent(stripped);
|
|
1361
|
+
const bucket = slots.get(slot.value.value) ?? [];
|
|
1362
|
+
bucket.push(ir);
|
|
1363
|
+
slots.set(slot.value.value, bucket);
|
|
1364
|
+
continue;
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
rest.push(child);
|
|
1368
|
+
}
|
|
1369
|
+
return { slots, rest };
|
|
1370
|
+
}
|
|
1371
|
+
// --- control-flow sugar -------------------------------------------------
|
|
1372
|
+
/** `<el if=${cond}>…</el>` (+ optional `<el else>`) → `<Show when fallback>`. */
|
|
1373
|
+
lowerIf(el, condHole, elseEl) {
|
|
1374
|
+
const cond = this.hole(condHole);
|
|
1375
|
+
const props = [
|
|
1376
|
+
{ name: "when", kind: "attr", expr: cond.code, reactive: cond.reactive, ...cond.at ? { at: cond.at } : {} }
|
|
1377
|
+
];
|
|
1378
|
+
if (elseEl) {
|
|
1379
|
+
const elseIR = this.stripAndLower(elseEl, (a) => a.kind === "ElseDirective");
|
|
1380
|
+
props.push({ name: "fallback", kind: "attr", expr: this.emit(elseIR), jsxElement: true });
|
|
1381
|
+
}
|
|
1382
|
+
const child = this.stripAndLower(el, (a) => a.kind === "IfDirective");
|
|
1383
|
+
const at = this.tagAt(el);
|
|
1384
|
+
return { kind: "component", name: "Show", props, children: [child], ...at ? { at } : {}, ...cond.at ? { bindAt: cond.at } : {} };
|
|
1385
|
+
}
|
|
1386
|
+
/** `<el each=${items} key?>${item => …}</el>` → `<For each>{item => <el>…</el>}</For>`. */
|
|
1387
|
+
lowerEach(el) {
|
|
1388
|
+
const eachDir = el.attributes.find((a) => a.kind === "EachDirective");
|
|
1389
|
+
if (!eachDir || eachDir.kind !== "EachDirective") return this.lowerNode(el);
|
|
1390
|
+
const each = this.hole(eachDir.hole);
|
|
1391
|
+
const props = [{ name: "each", kind: "attr", expr: each.code, reactive: each.reactive, ...each.at ? { at: each.at } : {} }];
|
|
1392
|
+
if (eachDir.key) {
|
|
1393
|
+
const by = "static" in eachDir.key ? `(item) => item[${JSON.stringify(eachDir.key.static)}]` : this.hole(eachDir.key.hole).code;
|
|
1394
|
+
props.push({ name: "by", kind: "attr", expr: by });
|
|
1395
|
+
}
|
|
1396
|
+
const arrow = this.itemArrow(el);
|
|
1397
|
+
let childrenCode;
|
|
1398
|
+
if (arrow) {
|
|
1399
|
+
const bodyIR = { kind: "expr", code: arrow.body, reactive: arrow.bodyReactive };
|
|
1400
|
+
const repeated = this.rebuildWithChildren(el, [bodyIR]);
|
|
1401
|
+
childrenCode = `(${arrow.params.join(", ")}) => ${paren(this.emit(repeated), "arrowBody")}`;
|
|
1402
|
+
} else {
|
|
1403
|
+
const repeated = this.stripAndLower(el, (a) => a.kind === "EachDirective");
|
|
1404
|
+
childrenCode = `() => ${paren(this.emit(repeated), "arrowBody")}`;
|
|
1405
|
+
}
|
|
1406
|
+
const children = [{ kind: "expr", code: childrenCode, reactive: false }];
|
|
1407
|
+
const at = this.tagAt(el);
|
|
1408
|
+
return { kind: "component", name: "For", props, children, ...at ? { at } : {}, ...each.at ? { bindAt: each.at } : {} };
|
|
1409
|
+
}
|
|
1410
|
+
/** The single `${item => expr}` child arrow, if that's the element's content. */
|
|
1411
|
+
itemArrow(el) {
|
|
1412
|
+
const kids = el.children.filter((c) => !this.isBlankText(c));
|
|
1413
|
+
if (kids.length !== 1 || kids[0].kind !== "Expression") return null;
|
|
1414
|
+
return this.hole(kids[0].hole).arrow ?? null;
|
|
1415
|
+
}
|
|
1416
|
+
/** Lower an element to IR, dropping the directive attribute matched by `drop`. */
|
|
1417
|
+
stripAndLower(el, drop) {
|
|
1418
|
+
const clone = { ...el, attributes: el.attributes.filter((a) => !drop(a)) };
|
|
1419
|
+
return clone.kind === "Element" ? this.lowerElement(clone) : this.lowerComponent(clone);
|
|
1420
|
+
}
|
|
1421
|
+
/** Same element (minus each/key) but with explicit IR children. */
|
|
1422
|
+
rebuildWithChildren(el, children) {
|
|
1423
|
+
const props = this.lowerAttributes(
|
|
1424
|
+
el.attributes.filter((a) => a.kind !== "EachDirective")
|
|
1425
|
+
);
|
|
1426
|
+
if (el.kind === "Element") {
|
|
1427
|
+
const at = this.tagAt(el);
|
|
1428
|
+
return {
|
|
1429
|
+
kind: "element",
|
|
1430
|
+
tag: el.tag,
|
|
1431
|
+
svg: el.namespace === "svg",
|
|
1432
|
+
props,
|
|
1433
|
+
children,
|
|
1434
|
+
static: false,
|
|
1435
|
+
...at ? { at } : {}
|
|
1436
|
+
};
|
|
1437
|
+
}
|
|
1438
|
+
return { kind: "component", name: el.tag, props, children };
|
|
1439
|
+
}
|
|
1440
|
+
// --- attributes ---------------------------------------------------------
|
|
1441
|
+
lowerAttributes(attrs) {
|
|
1442
|
+
const props = [];
|
|
1443
|
+
const classEntries = [];
|
|
1444
|
+
let classReactive = false;
|
|
1445
|
+
let classAt;
|
|
1446
|
+
const styleEntries = [];
|
|
1447
|
+
let styleReactive = false;
|
|
1448
|
+
let styleAt;
|
|
1449
|
+
const usePairs = [];
|
|
1450
|
+
for (const a of attrs) {
|
|
1451
|
+
switch (a.kind) {
|
|
1452
|
+
case "IfDirective":
|
|
1453
|
+
case "EachDirective":
|
|
1454
|
+
case "ElseDirective":
|
|
1455
|
+
break;
|
|
1456
|
+
// handled as control-flow at the parent level
|
|
1457
|
+
case "Attribute":
|
|
1458
|
+
props.push(this.plainAttr(a));
|
|
1459
|
+
break;
|
|
1460
|
+
case "PropertyBinding":
|
|
1461
|
+
props.push({
|
|
1462
|
+
name: a.name,
|
|
1463
|
+
kind: "prop",
|
|
1464
|
+
expr: this.hole(a.hole).code,
|
|
1465
|
+
reactive: this.hole(a.hole).reactive,
|
|
1466
|
+
...this.hole(a.hole).at ? { at: this.hole(a.hole).at } : {}
|
|
1467
|
+
});
|
|
1468
|
+
break;
|
|
1469
|
+
case "EventBinding":
|
|
1470
|
+
props.push(this.eventProp(a));
|
|
1471
|
+
break;
|
|
1472
|
+
case "RefBinding":
|
|
1473
|
+
props.push({
|
|
1474
|
+
name: "ref",
|
|
1475
|
+
kind: "ref",
|
|
1476
|
+
expr: this.hole(a.hole).code,
|
|
1477
|
+
reactive: this.hole(a.hole).reactive,
|
|
1478
|
+
// Which variable ends up holding the element, and where it was written.
|
|
1479
|
+
...this.hole(a.hole).at ? { at: this.hole(a.hole).at } : {}
|
|
1480
|
+
});
|
|
1481
|
+
break;
|
|
1482
|
+
case "Spread":
|
|
1483
|
+
props.push({ name: "", kind: "spread", expr: this.hole(a.hole).code });
|
|
1484
|
+
break;
|
|
1485
|
+
case "ClassDirective": {
|
|
1486
|
+
const h = this.hole(a.hole);
|
|
1487
|
+
classEntries.push(`${JSON.stringify(a.name)}: ${h.code}`);
|
|
1488
|
+
classReactive = classReactive || h.reactive;
|
|
1489
|
+
classAt ??= h.at;
|
|
1490
|
+
break;
|
|
1491
|
+
}
|
|
1492
|
+
case "StyleDirective": {
|
|
1493
|
+
const h = this.hole(a.hole);
|
|
1494
|
+
styleEntries.push(`${JSON.stringify(a.name)}: ${h.code}`);
|
|
1495
|
+
styleReactive = styleReactive || h.reactive;
|
|
1496
|
+
styleAt ??= h.at;
|
|
1497
|
+
break;
|
|
1498
|
+
}
|
|
1499
|
+
case "BindDirective":
|
|
1500
|
+
props.push(...this.bindProps(a.name, this.hole(a.hole)));
|
|
1501
|
+
break;
|
|
1502
|
+
case "UseDirective": {
|
|
1503
|
+
const dir = a.name ?? (a.hole != null ? this.hole(a.hole).code : null);
|
|
1504
|
+
if (!dir) break;
|
|
1505
|
+
usePairs.push(a.name != null && a.hole != null ? `[${dir}, () => ${paren(this.hole(a.hole).code, "arrowBody")}]` : `[${dir}]`);
|
|
1506
|
+
break;
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
if (classEntries.length > 0) {
|
|
1511
|
+
props.push({
|
|
1512
|
+
name: "classList",
|
|
1513
|
+
kind: "attr",
|
|
1514
|
+
expr: `{ ${classEntries.join(", ")} }`,
|
|
1515
|
+
reactive: classReactive,
|
|
1516
|
+
...classAt ? { at: classAt } : {}
|
|
1517
|
+
});
|
|
1518
|
+
}
|
|
1519
|
+
if (styleEntries.length > 0) {
|
|
1520
|
+
props.push({
|
|
1521
|
+
name: "style",
|
|
1522
|
+
kind: "attr",
|
|
1523
|
+
expr: `{ ${styleEntries.join(", ")} }`,
|
|
1524
|
+
reactive: styleReactive,
|
|
1525
|
+
...styleAt ? { at: styleAt } : {}
|
|
1526
|
+
});
|
|
1527
|
+
}
|
|
1528
|
+
if (usePairs.length > 0) {
|
|
1529
|
+
props.push({ name: "use", kind: "attr", expr: `[${usePairs.join(", ")}]` });
|
|
1530
|
+
}
|
|
1531
|
+
return props;
|
|
1532
|
+
}
|
|
1533
|
+
/**
|
|
1534
|
+
* Lower an event binding. Plain `@click`/`onClick` (no modifiers) stays a
|
|
1535
|
+
* DELEGATED handler (unchanged, byte-identical with JSX). `on:click` or any
|
|
1536
|
+
* modifier (`.capture`/`.once`/`.passive`/`.prevent`/`.stop`/`.self`) emits a
|
|
1537
|
+
* NATIVE `on:name` prop the runtime attaches via addEventListener.
|
|
1538
|
+
*/
|
|
1539
|
+
eventProp(a) {
|
|
1540
|
+
const dom = a.name.toLowerCase();
|
|
1541
|
+
const handler = this.hole(a.hole).code;
|
|
1542
|
+
const native = a.syntax === "colon" || a.modifiers.length > 0;
|
|
1543
|
+
if (!native) {
|
|
1544
|
+
return {
|
|
1545
|
+
name: "on" + capitalize(a.name),
|
|
1546
|
+
kind: "event",
|
|
1547
|
+
event: { name: dom, delegated: DELEGATED.has(dom) },
|
|
1548
|
+
expr: handler
|
|
1549
|
+
};
|
|
1550
|
+
}
|
|
1551
|
+
const wrapped = this.wrapHandler(handler, a.modifiers);
|
|
1552
|
+
const options = this.eventOptions(a.modifiers);
|
|
1553
|
+
const value = options ? `[${wrapped}, ${options}]` : wrapped;
|
|
1554
|
+
return { name: "on:" + dom, kind: "attr", expr: value };
|
|
1555
|
+
}
|
|
1556
|
+
/** Wrap a handler for `.prevent`/`.stop`/`.self` (no wrap when none apply). */
|
|
1557
|
+
wrapHandler(handler, mods) {
|
|
1558
|
+
const guard = mods.includes("self") ? "if (e.target !== e.currentTarget) return; " : "";
|
|
1559
|
+
const pre = [];
|
|
1560
|
+
if (mods.includes("prevent")) pre.push("e.preventDefault();");
|
|
1561
|
+
if (mods.includes("stop")) pre.push("e.stopPropagation();");
|
|
1562
|
+
if (!guard && pre.length === 0) return handler;
|
|
1563
|
+
return `(e) => { ${guard}${pre.join(" ")} return (${handler})(e); }`;
|
|
1564
|
+
}
|
|
1565
|
+
/** addEventListener options object from `.capture`/`.once`/`.passive`, or null. */
|
|
1566
|
+
eventOptions(mods) {
|
|
1567
|
+
const opts = [];
|
|
1568
|
+
if (mods.includes("capture")) opts.push("capture: true");
|
|
1569
|
+
if (mods.includes("once")) opts.push("once: true");
|
|
1570
|
+
if (mods.includes("passive")) opts.push("passive: true");
|
|
1571
|
+
return opts.length ? `{ ${opts.join(", ")} }` : null;
|
|
1572
|
+
}
|
|
1573
|
+
/** `bind:value=${sig}` → `value={read()}` + `onInput={e => write(e…value)}`. */
|
|
1574
|
+
bindProps(prop, h) {
|
|
1575
|
+
const sigCode = h.code;
|
|
1576
|
+
const checked = prop === "checked";
|
|
1577
|
+
const evt = checked ? "change" : "input";
|
|
1578
|
+
const accessor = checked ? "checked" : "value";
|
|
1579
|
+
this.used.add("bindPair");
|
|
1580
|
+
const sig = `bindPair(${sigCode})`;
|
|
1581
|
+
return [
|
|
1582
|
+
{
|
|
1583
|
+
name: prop,
|
|
1584
|
+
kind: "attr",
|
|
1585
|
+
expr: `${sig}[0]()`,
|
|
1586
|
+
reactive: true,
|
|
1587
|
+
directive: `bind:${prop}`,
|
|
1588
|
+
...h.at ? { at: h.at } : {}
|
|
1589
|
+
},
|
|
1590
|
+
{
|
|
1591
|
+
name: "on" + capitalize(evt),
|
|
1592
|
+
kind: "event",
|
|
1593
|
+
event: { name: evt, delegated: DELEGATED.has(evt) },
|
|
1594
|
+
// delegated handler: `target` is the bound element (currentTarget is the root)
|
|
1595
|
+
expr: `(e) => ${sig}[1](e.target.${accessor})`
|
|
1596
|
+
}
|
|
1597
|
+
];
|
|
1598
|
+
}
|
|
1599
|
+
/** A plain attribute (incl. lit `?bool`, mixed values) — old `mkProp` behavior. */
|
|
1600
|
+
plainAttr(a) {
|
|
1601
|
+
const v = a.value;
|
|
1602
|
+
let name = a.name;
|
|
1603
|
+
if (a.name === "class") {
|
|
1604
|
+
name = v && v.kind === "hole" && this.hole(v.hole).object ? "classList" : "className";
|
|
1605
|
+
} else if (a.name === "html") {
|
|
1606
|
+
name = "innerHTML";
|
|
1607
|
+
}
|
|
1608
|
+
const kind = "attr";
|
|
1609
|
+
const base = { name, kind };
|
|
1610
|
+
if (v == null) {
|
|
1611
|
+
base.literal = true;
|
|
1612
|
+
return base;
|
|
1613
|
+
}
|
|
1614
|
+
if (v.kind === "static") {
|
|
1615
|
+
base.literal = v.value;
|
|
1616
|
+
return base;
|
|
1617
|
+
}
|
|
1618
|
+
if (v.kind === "hole") {
|
|
1619
|
+
const h = this.hole(v.hole);
|
|
1620
|
+
base.expr = h.code;
|
|
1621
|
+
base.reactive = h.reactive;
|
|
1622
|
+
if (h.at) base.at = h.at;
|
|
1623
|
+
return base;
|
|
1624
|
+
}
|
|
1625
|
+
let reactive = false;
|
|
1626
|
+
let at;
|
|
1627
|
+
const body = v.parts.map((p) => {
|
|
1628
|
+
if ("text" in p) return escapeTemplate(p.text);
|
|
1629
|
+
const h = this.hole(p.hole);
|
|
1630
|
+
reactive = reactive || h.reactive;
|
|
1631
|
+
at ??= h.at;
|
|
1632
|
+
return "${" + h.code + "}";
|
|
1633
|
+
}).join("");
|
|
1634
|
+
base.expr = "`" + body + "`";
|
|
1635
|
+
base.reactive = reactive;
|
|
1636
|
+
if (at) base.at = at;
|
|
1637
|
+
return base;
|
|
1638
|
+
}
|
|
1639
|
+
};
|
|
1640
|
+
}
|
|
1641
|
+
});
|
|
1642
|
+
|
|
1643
|
+
// src/frontend/babel/lower-template.ts
|
|
1644
|
+
function gen(node) {
|
|
1645
|
+
return generate(node, { concise: true }).code;
|
|
1646
|
+
}
|
|
1647
|
+
function bindHole(expr, used, onNested) {
|
|
1648
|
+
const hole = {
|
|
1649
|
+
code: genExpr(expr, used, onNested),
|
|
1650
|
+
reactive: isReactiveExpr(expr)
|
|
1651
|
+
};
|
|
1652
|
+
if (import_core.types.isArrowFunctionExpression(expr) && !import_core.types.isBlockStatement(expr.body)) {
|
|
1653
|
+
const body = expr.body;
|
|
1654
|
+
hole.arrow = {
|
|
1655
|
+
params: expr.params.map((p) => gen(p)),
|
|
1656
|
+
body: genExpr(body, used, onNested),
|
|
1657
|
+
bodyReactive: isReactiveExpr(body)
|
|
1658
|
+
};
|
|
1659
|
+
}
|
|
1660
|
+
if (import_core.types.isObjectExpression(expr)) hole.object = true;
|
|
1661
|
+
return hole;
|
|
1662
|
+
}
|
|
1663
|
+
function lowerLitTemplate(node, used, opts = {}) {
|
|
1664
|
+
const quasi = node.quasi;
|
|
1665
|
+
const holes = quasi.expressions.map((e) => bindHole(e, used, opts.onNested));
|
|
1666
|
+
return lowerTemplate(buildPieces(quasi), holes, used, opts);
|
|
1667
|
+
}
|
|
1668
|
+
function buildPieces(quasi) {
|
|
1669
|
+
const pieces = [];
|
|
1670
|
+
quasi.quasis.forEach((q, i) => {
|
|
1671
|
+
const text = q.value.cooked ?? q.value.raw;
|
|
1672
|
+
pieces.push({ kind: "static", text, start: q.start ?? 0 });
|
|
1673
|
+
if (i < quasi.expressions.length) {
|
|
1674
|
+
const e = quasi.expressions[i];
|
|
1675
|
+
pieces.push({ kind: "hole", index: i, start: e.start ?? 0, end: e.end ?? 0 });
|
|
1676
|
+
}
|
|
1677
|
+
});
|
|
1678
|
+
return pieces;
|
|
1679
|
+
}
|
|
1680
|
+
var import_core, import_generator, generate;
|
|
1681
|
+
var init_lower_template = __esm({
|
|
1682
|
+
"src/frontend/babel/lower-template.ts"() {
|
|
1683
|
+
"use strict";
|
|
1684
|
+
import_core = require("@babel/core");
|
|
1685
|
+
import_generator = __toESM(require("@babel/generator"), 1);
|
|
1686
|
+
init_template();
|
|
1687
|
+
init_build_ir();
|
|
1688
|
+
generate = import_generator.default.default ?? import_generator.default;
|
|
1689
|
+
}
|
|
1690
|
+
});
|
|
1691
|
+
|
|
1692
|
+
// src/optimize/analyze-static.ts
|
|
1693
|
+
function propReason(prop) {
|
|
1694
|
+
switch (prop.kind) {
|
|
1695
|
+
case "event":
|
|
1696
|
+
return "event";
|
|
1697
|
+
case "ref":
|
|
1698
|
+
return "ref";
|
|
1699
|
+
case "spread":
|
|
1700
|
+
return "spread";
|
|
1701
|
+
case "class":
|
|
1702
|
+
case "style":
|
|
1703
|
+
return "class-or-style-directive";
|
|
1704
|
+
case "attr":
|
|
1705
|
+
case "prop":
|
|
1706
|
+
if (prop.reactive) return "reactive-prop";
|
|
1707
|
+
if (prop.expr !== void 0) return "expression-prop";
|
|
1708
|
+
return void 0;
|
|
1709
|
+
/* c8 ignore next 2 */
|
|
1710
|
+
default:
|
|
1711
|
+
return "expression-prop";
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
function analyzeStatic(root) {
|
|
1715
|
+
const staticElements = [];
|
|
1716
|
+
const reasons = /* @__PURE__ */ new Map();
|
|
1717
|
+
const visit = (node) => {
|
|
1718
|
+
switch (node.kind) {
|
|
1719
|
+
case "text":
|
|
1720
|
+
return true;
|
|
1721
|
+
case "expr":
|
|
1722
|
+
return false;
|
|
1723
|
+
case "component":
|
|
1724
|
+
case "control":
|
|
1725
|
+
for (const child of node.children) visit(child);
|
|
1726
|
+
return false;
|
|
1727
|
+
case "fragment":
|
|
1728
|
+
for (const child of node.children) visit(child);
|
|
1729
|
+
return false;
|
|
1730
|
+
case "element": {
|
|
1731
|
+
let childrenStatic = true;
|
|
1732
|
+
for (const child of node.children) {
|
|
1733
|
+
if (!visit(child)) childrenStatic = false;
|
|
1734
|
+
}
|
|
1735
|
+
let reason;
|
|
1736
|
+
for (const prop of node.props) {
|
|
1737
|
+
reason = propReason(prop);
|
|
1738
|
+
if (reason) break;
|
|
1739
|
+
}
|
|
1740
|
+
if (!reason && !childrenStatic) {
|
|
1741
|
+
reason = childReason(node);
|
|
1742
|
+
}
|
|
1743
|
+
node.static = !reason;
|
|
1744
|
+
if (reason) reasons.set(node, reason);
|
|
1745
|
+
else staticElements.push(node);
|
|
1746
|
+
return node.static;
|
|
1747
|
+
}
|
|
1748
|
+
/* c8 ignore next 2 */
|
|
1749
|
+
default:
|
|
1750
|
+
return false;
|
|
1751
|
+
}
|
|
1752
|
+
};
|
|
1753
|
+
for (const node of Array.isArray(root) ? root : [root]) visit(node);
|
|
1754
|
+
return { staticElements, reasons };
|
|
1755
|
+
}
|
|
1756
|
+
function childReason(node) {
|
|
1757
|
+
for (const child of node.children) {
|
|
1758
|
+
if (child.kind === "expr") return "expression-child";
|
|
1759
|
+
if (child.kind === "component") return "component-child";
|
|
1760
|
+
if (child.kind === "control") return "control-child";
|
|
1761
|
+
if (child.kind === "element" && !child.static) return "expression-child";
|
|
1762
|
+
if (child.kind === "fragment") return "expression-child";
|
|
1763
|
+
}
|
|
1764
|
+
return "expression-child";
|
|
1765
|
+
}
|
|
1766
|
+
var init_analyze_static = __esm({
|
|
1767
|
+
"src/optimize/analyze-static.ts"() {
|
|
1768
|
+
"use strict";
|
|
1769
|
+
}
|
|
1770
|
+
});
|
|
1771
|
+
|
|
1772
|
+
// src/frontend/babel/build-ir-lit.ts
|
|
1773
|
+
function buildIRFromLit(node, used = /* @__PURE__ */ new Set(), opts = {}) {
|
|
1774
|
+
const ir = lowerLitTemplate(node, used, opts);
|
|
1775
|
+
analyzeStatic(ir);
|
|
1776
|
+
return ir;
|
|
1777
|
+
}
|
|
1778
|
+
var init_build_ir_lit = __esm({
|
|
1779
|
+
"src/frontend/babel/build-ir-lit.ts"() {
|
|
1780
|
+
"use strict";
|
|
1781
|
+
init_lower_template();
|
|
1782
|
+
init_analyze_static();
|
|
1783
|
+
}
|
|
1784
|
+
});
|
|
1785
|
+
|
|
1786
|
+
// src/analyze/reactive-expr.ts
|
|
1787
|
+
function isReactiveShape(shape) {
|
|
1788
|
+
switch (shape.kind) {
|
|
1789
|
+
case "call":
|
|
1790
|
+
return true;
|
|
1791
|
+
case "member":
|
|
1792
|
+
return shape.property !== STABLE_MEMBER;
|
|
1793
|
+
case "compound":
|
|
1794
|
+
return shape.parts.some(isReactiveShape);
|
|
1795
|
+
case "opaque":
|
|
1796
|
+
return false;
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
var STABLE_MEMBER;
|
|
1800
|
+
var init_reactive_expr = __esm({
|
|
1801
|
+
"src/analyze/reactive-expr.ts"() {
|
|
1802
|
+
"use strict";
|
|
1803
|
+
STABLE_MEMBER = "children";
|
|
1804
|
+
}
|
|
1805
|
+
});
|
|
1806
|
+
|
|
1807
|
+
// src/analyze/expr-shape.ts
|
|
1808
|
+
function shapeOf(node) {
|
|
1809
|
+
if (!node) return { kind: "opaque" };
|
|
1810
|
+
if (CALL.has(node.type)) return { kind: "call" };
|
|
1811
|
+
if (MEMBER.has(node.type)) {
|
|
1812
|
+
const property = node.property;
|
|
1813
|
+
const computed = node.computed === true;
|
|
1814
|
+
return {
|
|
1815
|
+
kind: "member",
|
|
1816
|
+
property: !computed && property?.type === "Identifier" ? property.name : null
|
|
1817
|
+
};
|
|
1818
|
+
}
|
|
1819
|
+
if (node.type === "ConditionalExpression") {
|
|
1820
|
+
return { kind: "compound", parts: [node.test, node.consequent, node.alternate].map(part) };
|
|
1821
|
+
}
|
|
1822
|
+
if (node.type === "LogicalExpression" || node.type === "BinaryExpression") {
|
|
1823
|
+
return { kind: "compound", parts: [node.left, node.right].map(part) };
|
|
1824
|
+
}
|
|
1825
|
+
if (node.type === "TemplateLiteral") {
|
|
1826
|
+
return { kind: "compound", parts: node.expressions.map(part) };
|
|
1827
|
+
}
|
|
1828
|
+
if (node.type === "ObjectExpression") {
|
|
1829
|
+
const props = node.properties.filter(
|
|
1830
|
+
(p) => (p.type === "ObjectProperty" || p.type === "Property") && p.computed !== true
|
|
1831
|
+
);
|
|
1832
|
+
return { kind: "compound", parts: props.map((p) => part(p.value)) };
|
|
1833
|
+
}
|
|
1834
|
+
if (node.type === "ArrayExpression") {
|
|
1835
|
+
const items = node.elements.filter(
|
|
1836
|
+
(e) => e != null && e.type !== "SpreadElement"
|
|
1837
|
+
);
|
|
1838
|
+
return { kind: "compound", parts: items.map(part) };
|
|
1839
|
+
}
|
|
1840
|
+
return { kind: "opaque" };
|
|
1841
|
+
}
|
|
1842
|
+
var CALL, MEMBER, part;
|
|
1843
|
+
var init_expr_shape = __esm({
|
|
1844
|
+
"src/analyze/expr-shape.ts"() {
|
|
1845
|
+
"use strict";
|
|
1846
|
+
CALL = /* @__PURE__ */ new Set(["CallExpression", "OptionalCallExpression"]);
|
|
1847
|
+
MEMBER = /* @__PURE__ */ new Set(["MemberExpression", "OptionalMemberExpression"]);
|
|
1848
|
+
part = (n) => shapeOf(n);
|
|
1849
|
+
}
|
|
1850
|
+
});
|
|
1851
|
+
|
|
1852
|
+
// src/lower/jsx.ts
|
|
1853
|
+
function literalOf(node) {
|
|
1854
|
+
if (node.type === "StringLiteral" || node.type === "NumericLiteral" || node.type === "BooleanLiteral") {
|
|
1855
|
+
return node.value;
|
|
1856
|
+
}
|
|
1857
|
+
if (node.type === "Literal" && (typeof node.value === "string" || typeof node.value === "number" || typeof node.value === "boolean")) {
|
|
1858
|
+
return node.value;
|
|
1859
|
+
}
|
|
1860
|
+
return void 0;
|
|
1861
|
+
}
|
|
1862
|
+
function tagInfo(name, ctx) {
|
|
1863
|
+
if (name.type === "JSXIdentifier") {
|
|
1864
|
+
return { tag: name.name, component: name.name[0] !== name.name[0].toLowerCase() };
|
|
1865
|
+
}
|
|
1866
|
+
if (name.type === "JSXMemberExpression") return { tag: ctx.code(name), component: true };
|
|
1867
|
+
if (name.type === "JSXNamespacedName") {
|
|
1868
|
+
return { tag: `${name.namespace.name}:${name.name.name}`, component: false };
|
|
1869
|
+
}
|
|
1870
|
+
return { tag: "div", component: false };
|
|
1871
|
+
}
|
|
1872
|
+
function attrName(name) {
|
|
1873
|
+
if (name.type === "JSXIdentifier") return name.name === "class" ? "className" : name.name;
|
|
1874
|
+
if (name.type === "JSXNamespacedName") return `${name.namespace.name}:${name.name.name}`;
|
|
1875
|
+
return "unknown";
|
|
1876
|
+
}
|
|
1877
|
+
function buildAttr(attr, ctx) {
|
|
1878
|
+
const name = attrName(attr.name);
|
|
1879
|
+
const isEvent = EVENT_RE.test(name);
|
|
1880
|
+
const isHandler = isEvent || name.startsWith("on:") || name === "ref";
|
|
1881
|
+
const kind = isEvent ? "event" : "attr";
|
|
1882
|
+
const base = { name, kind };
|
|
1883
|
+
if (isEvent) {
|
|
1884
|
+
const evt = name.slice(2).toLowerCase();
|
|
1885
|
+
base.event = { name: evt, delegated: DELEGATED2.has(evt) };
|
|
1886
|
+
}
|
|
1887
|
+
const v = attr.value;
|
|
1888
|
+
if (v == null) {
|
|
1889
|
+
base.literal = true;
|
|
1890
|
+
base.at = posOf(attr, ctx);
|
|
1891
|
+
return base;
|
|
1892
|
+
}
|
|
1893
|
+
if (isString(v)) {
|
|
1894
|
+
base.literal = literalOf(v);
|
|
1895
|
+
base.at = posOf(v, ctx);
|
|
1896
|
+
return base;
|
|
1897
|
+
}
|
|
1898
|
+
if (v.type === "JSXExpressionContainer" && v.expression?.type !== "JSXEmptyExpression") {
|
|
1899
|
+
const expr = v.expression;
|
|
1900
|
+
const literal = literalOf(expr);
|
|
1901
|
+
if (literal !== void 0) {
|
|
1902
|
+
base.literal = literal;
|
|
1903
|
+
base.at = posOf(expr, ctx);
|
|
1904
|
+
return base;
|
|
1905
|
+
}
|
|
1906
|
+
base.expr = ctx.code(expr);
|
|
1907
|
+
base.reactive = isHandler ? false : isReactive(expr);
|
|
1908
|
+
base.at = posOf(expr, ctx);
|
|
1909
|
+
if (expr.type === "JSXElement" || expr.type === "JSXFragment") base.jsxElement = true;
|
|
1910
|
+
return base;
|
|
1911
|
+
}
|
|
1912
|
+
base.literal = true;
|
|
1913
|
+
return base;
|
|
1914
|
+
}
|
|
1915
|
+
function attrExprCode(attr, ctx) {
|
|
1916
|
+
const v = attr.value;
|
|
1917
|
+
if (v == null) return null;
|
|
1918
|
+
if (isString(v)) return JSON.stringify(literalOf(v));
|
|
1919
|
+
if (v.type === "JSXExpressionContainer" && v.expression?.type !== "JSXEmptyExpression") {
|
|
1920
|
+
return ctx.code(v.expression);
|
|
1921
|
+
}
|
|
1922
|
+
return null;
|
|
1923
|
+
}
|
|
1924
|
+
function buildProps(attrs, ctx) {
|
|
1925
|
+
const props = [];
|
|
1926
|
+
const usePairs = [];
|
|
1927
|
+
for (const a of attrs) {
|
|
1928
|
+
if (a.type === "JSXSpreadAttribute") {
|
|
1929
|
+
props.push({ name: "", kind: "spread", expr: ctx.code(a.argument) });
|
|
1930
|
+
continue;
|
|
1931
|
+
}
|
|
1932
|
+
if (a.type !== "JSXAttribute") continue;
|
|
1933
|
+
if (isLoadDirective(attrName(a.name))) continue;
|
|
1934
|
+
const ns = a.name.type === "JSXNamespacedName" ? a.name.namespace.name : null;
|
|
1935
|
+
if (ns === "use") {
|
|
1936
|
+
const dir = a.name.name.name;
|
|
1937
|
+
ctx.used.add(dir);
|
|
1938
|
+
const opts = attrExprCode(a, ctx);
|
|
1939
|
+
usePairs.push(opts != null ? `[${dir}, () => ${paren(opts, "arrowBody")}]` : `[${dir}]`);
|
|
1940
|
+
continue;
|
|
1941
|
+
}
|
|
1942
|
+
if (ns === "oncapture") {
|
|
1943
|
+
const evt = a.name.name.name.toLowerCase();
|
|
1944
|
+
const h = attrExprCode(a, ctx) ?? "undefined";
|
|
1945
|
+
props.push({ name: "on:" + evt, kind: "attr", expr: `[${h}, { capture: true }]` });
|
|
1946
|
+
continue;
|
|
1947
|
+
}
|
|
1948
|
+
props.push(buildAttr(a, ctx));
|
|
1949
|
+
}
|
|
1950
|
+
if (usePairs.length > 0) props.push({ name: "use", kind: "attr", expr: `[${usePairs.join(", ")}]` });
|
|
1951
|
+
return props;
|
|
1952
|
+
}
|
|
1953
|
+
function buildChildren(children, ctx) {
|
|
1954
|
+
const out = [];
|
|
1955
|
+
for (const child of children) {
|
|
1956
|
+
if (child.type === "JSXText") {
|
|
1957
|
+
const text = cleanTemplateText(child.value);
|
|
1958
|
+
if (text) out.push({ kind: "text", value: text });
|
|
1959
|
+
} else if (child.type === "JSXExpressionContainer") {
|
|
1960
|
+
if (child.expression?.type !== "JSXEmptyExpression") {
|
|
1961
|
+
const expr = child.expression;
|
|
1962
|
+
const reactive = isReactive(expr);
|
|
1963
|
+
out.push({
|
|
1964
|
+
kind: "expr",
|
|
1965
|
+
code: ctx.code(expr),
|
|
1966
|
+
reactive,
|
|
1967
|
+
...reactive ? { at: posOf(expr, ctx) } : {}
|
|
1968
|
+
});
|
|
1969
|
+
}
|
|
1970
|
+
} else if (child.type === "JSXElement" || child.type === "JSXFragment") {
|
|
1971
|
+
out.push(buildNode(child, ctx));
|
|
1972
|
+
} else if (child.type === "JSXSpreadChild") {
|
|
1973
|
+
out.push({ kind: "expr", code: ctx.code(child.expression), reactive: false });
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
return out;
|
|
1977
|
+
}
|
|
1978
|
+
function readLoad(attrs) {
|
|
1979
|
+
for (const a of attrs) {
|
|
1980
|
+
if (a.type !== "JSXAttribute") continue;
|
|
1981
|
+
const name = attrName(a.name);
|
|
1982
|
+
if (!isLoadDirective(name)) continue;
|
|
1983
|
+
if (a.value && !isString(a.value)) {
|
|
1984
|
+
throw new LoadDirectiveError(
|
|
1985
|
+
`'${name}' needs a literal value, not an expression — the strategy is compile-time.`
|
|
1986
|
+
);
|
|
1987
|
+
}
|
|
1988
|
+
return parseLoadDirective(name, a.value ? literalOf(a.value) : null);
|
|
1989
|
+
}
|
|
1990
|
+
return void 0;
|
|
1991
|
+
}
|
|
1992
|
+
function buildNode(node, ctx) {
|
|
1993
|
+
if (node.type === "JSXFragment") {
|
|
1994
|
+
return { kind: "fragment", children: buildChildren(node.children, ctx) };
|
|
1995
|
+
}
|
|
1996
|
+
const { tag, component } = tagInfo(node.openingElement.name, ctx);
|
|
1997
|
+
const props = buildProps(node.openingElement.attributes, ctx);
|
|
1998
|
+
const children = buildChildren(node.children, ctx);
|
|
1999
|
+
const at = ctx.sourceFile && node.loc?.start ? { file: ctx.sourceFile, line: node.loc.start.line, column: node.loc.start.column } : void 0;
|
|
2000
|
+
if (component) {
|
|
2001
|
+
const load = readLoad(node.openingElement.attributes);
|
|
2002
|
+
return { kind: "component", name: tag, props, children, ...load ? { load } : {}, ...at ? { at } : {} };
|
|
2003
|
+
}
|
|
2004
|
+
return { kind: "element", tag, svg: SVG_TAGS.has(tag), props, children, static: false, ...at ? { at } : {} };
|
|
2005
|
+
}
|
|
2006
|
+
function buildJsxIR(node, ctx) {
|
|
2007
|
+
const ir = buildNode(node, ctx);
|
|
2008
|
+
analyzeStatic(ir);
|
|
2009
|
+
return ir;
|
|
2010
|
+
}
|
|
2011
|
+
var SVG_TAGS, EVENT_RE, DELEGATED2, isReactive, posOf, isString;
|
|
2012
|
+
var init_jsx = __esm({
|
|
2013
|
+
"src/lower/jsx.ts"() {
|
|
2014
|
+
"use strict";
|
|
2015
|
+
init_load_directive();
|
|
2016
|
+
init_reactive_expr();
|
|
2017
|
+
init_expr_shape();
|
|
2018
|
+
init_analyze_static();
|
|
2019
|
+
init_text();
|
|
2020
|
+
init_paren();
|
|
2021
|
+
SVG_TAGS = /* @__PURE__ */ new Set([
|
|
2022
|
+
"svg",
|
|
2023
|
+
"path",
|
|
2024
|
+
"circle",
|
|
2025
|
+
"rect",
|
|
2026
|
+
"line",
|
|
2027
|
+
"polygon",
|
|
2028
|
+
"polyline",
|
|
2029
|
+
"ellipse",
|
|
2030
|
+
"g",
|
|
2031
|
+
"defs",
|
|
2032
|
+
"clipPath",
|
|
2033
|
+
"text"
|
|
2034
|
+
]);
|
|
2035
|
+
EVENT_RE = /^on[A-Z]/;
|
|
2036
|
+
DELEGATED2 = /* @__PURE__ */ new Set([
|
|
2037
|
+
"click",
|
|
2038
|
+
"dblclick",
|
|
2039
|
+
"input",
|
|
2040
|
+
"change",
|
|
2041
|
+
"submit",
|
|
2042
|
+
"focus",
|
|
2043
|
+
"blur",
|
|
2044
|
+
"keydown",
|
|
2045
|
+
"keyup",
|
|
2046
|
+
"keypress",
|
|
2047
|
+
"mousedown",
|
|
2048
|
+
"mouseup"
|
|
2049
|
+
]);
|
|
2050
|
+
isReactive = (node) => isReactiveShape(shapeOf(node));
|
|
2051
|
+
posOf = (node, ctx) => {
|
|
2052
|
+
if (!ctx.sourceFile) return void 0;
|
|
2053
|
+
const at = node.loc?.start;
|
|
2054
|
+
return at ? { line: at.line, column: at.column } : void 0;
|
|
2055
|
+
};
|
|
2056
|
+
isString = (node) => !!node && typeof literalOf(node) === "string";
|
|
2057
|
+
}
|
|
2058
|
+
});
|
|
2059
|
+
|
|
2060
|
+
// src/frontend/babel/build-ir.ts
|
|
2061
|
+
function gen2(node) {
|
|
2062
|
+
return generate2(node, { concise: true }).code;
|
|
2063
|
+
}
|
|
2064
|
+
function transformNestedJSX(node, used, onNested) {
|
|
2065
|
+
const clone = import_core2.types.cloneNode(node, true);
|
|
2066
|
+
const file = import_core2.types.file(import_core2.types.program([import_core2.types.expressionStatement(clone)]));
|
|
2067
|
+
let changed = false;
|
|
2068
|
+
const emitInto = (path, code, imports) => {
|
|
2069
|
+
for (const s of imports) used.add(s);
|
|
2070
|
+
path.replaceWith(import_core2.template.expression(code, { placeholderPattern: false, plugins: ["typescript"] })());
|
|
2071
|
+
path.skip();
|
|
2072
|
+
changed = true;
|
|
2073
|
+
};
|
|
2074
|
+
(0, import_core2.traverse)(file, {
|
|
2075
|
+
"JSXElement|JSXFragment"(path) {
|
|
2076
|
+
const jsx = path.node;
|
|
2077
|
+
const nestedIR = buildIR(jsx, used, onNested);
|
|
2078
|
+
onNested?.(nestedIR);
|
|
2079
|
+
const { code, imports, templates } = imperativeBackend.emit(nestedIR, {});
|
|
2080
|
+
emitInto(path, inlineTemplates(code, templates), imports);
|
|
2081
|
+
},
|
|
2082
|
+
// Nested lit templates compose: ${cond ? html`…` : html`…`},
|
|
2083
|
+
// ${list.map(x => html`<li>${x}</li>`)}. Compile them the same way.
|
|
2084
|
+
TaggedTemplateExpression(path) {
|
|
2085
|
+
const tag = path.node.tag;
|
|
2086
|
+
if (!import_core2.types.isIdentifier(tag) || tag.name !== "html" && tag.name !== "svg") return;
|
|
2087
|
+
const ir = buildIRFromLit(path.node, used, { svg: tag.name === "svg", onNested });
|
|
2088
|
+
onNested?.(ir);
|
|
2089
|
+
const { code, imports, templates } = imperativeBackend.emit(ir, {});
|
|
2090
|
+
emitInto(path, inlineTemplates(code, templates), imports);
|
|
2091
|
+
}
|
|
2092
|
+
});
|
|
2093
|
+
return changed ? file.program.body[0].expression : node;
|
|
2094
|
+
}
|
|
2095
|
+
function genExpr(node, used, onNested) {
|
|
2096
|
+
return gen2(transformNestedJSX(node, used, onNested));
|
|
2097
|
+
}
|
|
2098
|
+
function isReactiveExpr(node) {
|
|
2099
|
+
return isReactiveShape(shapeOf(node));
|
|
2100
|
+
}
|
|
2101
|
+
function buildIR(node, used = /* @__PURE__ */ new Set(), onNested) {
|
|
2102
|
+
const ir = buildJsxIR(node, {
|
|
2103
|
+
code: (n) => (
|
|
2104
|
+
// A member-expression tag (`<ns.Foo/>`) is not an Expression, so it cannot go
|
|
2105
|
+
// through the nested-JSX compile — it only ever needs printing.
|
|
2106
|
+
n.type === "JSXMemberExpression" ? gen2(n) : genExpr(n, used, onNested)
|
|
2107
|
+
),
|
|
2108
|
+
used
|
|
2109
|
+
});
|
|
2110
|
+
return ir;
|
|
2111
|
+
}
|
|
2112
|
+
var import_core2, import_generator2, generate2;
|
|
2113
|
+
var init_build_ir = __esm({
|
|
2114
|
+
"src/frontend/babel/build-ir.ts"() {
|
|
2115
|
+
"use strict";
|
|
2116
|
+
import_core2 = require("@babel/core");
|
|
2117
|
+
import_generator2 = __toESM(require("@babel/generator"), 1);
|
|
2118
|
+
init_imperative();
|
|
2119
|
+
init_build_ir_lit();
|
|
2120
|
+
init_jsx();
|
|
2121
|
+
init_reactive_expr();
|
|
2122
|
+
init_expr_shape();
|
|
2123
|
+
generate2 = import_generator2.default.default ?? import_generator2.default;
|
|
2124
|
+
}
|
|
2125
|
+
});
|
|
2126
|
+
|
|
2127
|
+
// src/frontend/babel/plugin.ts
|
|
2128
|
+
function nestedHook(state) {
|
|
2129
|
+
return (ir) => {
|
|
2130
|
+
resolveComponentSources(ir, {
|
|
2131
|
+
resolver: state.componentResolver,
|
|
2132
|
+
modules: {
|
|
2133
|
+
controlFlowModule: state.controlFlowModule,
|
|
2134
|
+
coreModule: state.libModule,
|
|
2135
|
+
routerModule: state.routerModule
|
|
2136
|
+
},
|
|
2137
|
+
strategyFor: (node) => node.load
|
|
2138
|
+
});
|
|
2139
|
+
collapseStrategies(ir);
|
|
2140
|
+
collectRuntimeNeeds(ir, state);
|
|
2141
|
+
};
|
|
2142
|
+
}
|
|
2143
|
+
function strategyLiteral(strategy) {
|
|
2144
|
+
const props = [
|
|
2145
|
+
import_core3.types.objectProperty(import_core3.types.identifier("kind"), import_core3.types.stringLiteral(strategy.kind))
|
|
2146
|
+
];
|
|
2147
|
+
if (strategy.kind === "visible" && strategy.rootMargin) {
|
|
2148
|
+
props.push(import_core3.types.objectProperty(import_core3.types.identifier("rootMargin"), import_core3.types.stringLiteral(strategy.rootMargin)));
|
|
2149
|
+
}
|
|
2150
|
+
if (strategy.kind === "interaction") {
|
|
2151
|
+
props.push(
|
|
2152
|
+
import_core3.types.objectProperty(
|
|
2153
|
+
import_core3.types.identifier("events"),
|
|
2154
|
+
import_core3.types.arrayExpression(strategy.events.map((e) => import_core3.types.stringLiteral(e)))
|
|
2155
|
+
)
|
|
2156
|
+
);
|
|
2157
|
+
}
|
|
2158
|
+
if (strategy.kind === "media") {
|
|
2159
|
+
props.push(import_core3.types.objectProperty(import_core3.types.identifier("query"), import_core3.types.stringLiteral(strategy.query)));
|
|
2160
|
+
}
|
|
2161
|
+
return import_core3.types.objectExpression(props);
|
|
2162
|
+
}
|
|
2163
|
+
function adoptTemplates(code, templates, state) {
|
|
2164
|
+
if (!templates || templates.length === 0) return code;
|
|
2165
|
+
const rename = /* @__PURE__ */ new Map();
|
|
2166
|
+
for (const tpl of templates) {
|
|
2167
|
+
const key = `${tpl.svg ? "svg:" : ""}${tpl.html}`;
|
|
2168
|
+
let name = state.staticTemplates.get(key);
|
|
2169
|
+
if (!name) {
|
|
2170
|
+
name = `_tmpl$${state.staticTemplates.size}`;
|
|
2171
|
+
state.staticTemplates.set(key, name);
|
|
2172
|
+
}
|
|
2173
|
+
rename.set(tpl.id, name);
|
|
2174
|
+
}
|
|
2175
|
+
return code.replace(/_tmpl\$\d+/g, (id) => rename.get(id) ?? id);
|
|
2176
|
+
}
|
|
2177
|
+
function emitViaIR(node, state) {
|
|
2178
|
+
const used = /* @__PURE__ */ new Set();
|
|
2179
|
+
const ir = buildIR(node, used, nestedHook(state));
|
|
2180
|
+
resolveComponentSources(ir, {
|
|
2181
|
+
resolver: state.componentResolver,
|
|
2182
|
+
modules: {
|
|
2183
|
+
controlFlowModule: state.controlFlowModule,
|
|
2184
|
+
coreModule: state.libModule,
|
|
2185
|
+
routerModule: state.routerModule
|
|
2186
|
+
},
|
|
2187
|
+
strategyFor: (n) => n.load
|
|
2188
|
+
});
|
|
2189
|
+
collapseStrategies(ir);
|
|
2190
|
+
const { code, imports, templates } = imperativeBackend.emit(ir, { templateClone: state.templateClone, partialTemplates: state.partialTemplates });
|
|
2191
|
+
for (const s of imports) used.add(s);
|
|
2192
|
+
for (const s of used) state.irImports.add(s);
|
|
2193
|
+
collectRuntimeNeeds(ir, state);
|
|
2194
|
+
const adopted = adoptTemplates(code, templates, state);
|
|
2195
|
+
return import_core3.template.expression(adopted, { placeholderPattern: false, plugins: ["typescript"] })();
|
|
2196
|
+
}
|
|
2197
|
+
function dedupeImports(imports) {
|
|
2198
|
+
const byModule = /* @__PURE__ */ new Map();
|
|
2199
|
+
const out = [];
|
|
2200
|
+
for (const decl of imports) {
|
|
2201
|
+
const source = decl.source.value;
|
|
2202
|
+
const allNamed = decl.specifiers.every((s) => import_core3.types.isImportSpecifier(s));
|
|
2203
|
+
if (!allNamed) {
|
|
2204
|
+
out.push(decl);
|
|
2205
|
+
continue;
|
|
2206
|
+
}
|
|
2207
|
+
const existing = byModule.get(source);
|
|
2208
|
+
if (!existing) {
|
|
2209
|
+
const names = new Set(
|
|
2210
|
+
decl.specifiers.map((s) => s.local.name)
|
|
2211
|
+
);
|
|
2212
|
+
byModule.set(source, { decl, names });
|
|
2213
|
+
out.push(decl);
|
|
2214
|
+
continue;
|
|
2215
|
+
}
|
|
2216
|
+
for (const s of decl.specifiers) {
|
|
2217
|
+
if (!existing.names.has(s.local.name)) {
|
|
2218
|
+
existing.names.add(s.local.name);
|
|
2219
|
+
existing.decl.specifiers.push(s);
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
}
|
|
2223
|
+
return out;
|
|
2224
|
+
}
|
|
2225
|
+
function emitLitViaIR(node, state) {
|
|
2226
|
+
const used = /* @__PURE__ */ new Set();
|
|
2227
|
+
const svg = import_core3.types.isIdentifier(node.tag) && node.tag.name === "svg";
|
|
2228
|
+
const ir = buildIRFromLit(node, used, { svg, onNested: nestedHook(state) });
|
|
2229
|
+
resolveComponentSources(ir, {
|
|
2230
|
+
resolver: state.componentResolver,
|
|
2231
|
+
modules: {
|
|
2232
|
+
controlFlowModule: state.controlFlowModule,
|
|
2233
|
+
coreModule: state.libModule,
|
|
2234
|
+
routerModule: state.routerModule
|
|
2235
|
+
},
|
|
2236
|
+
strategyFor: (node2) => node2.load
|
|
2237
|
+
});
|
|
2238
|
+
collapseStrategies(ir);
|
|
2239
|
+
const { code, imports, templates } = imperativeBackend.emit(ir, { templateClone: state.templateClone, partialTemplates: state.partialTemplates });
|
|
2240
|
+
for (const s of imports) used.add(s);
|
|
2241
|
+
for (const s of used) state.irImports.add(s);
|
|
2242
|
+
collectRuntimeNeeds(ir, state);
|
|
2243
|
+
state.hasLitIR = true;
|
|
2244
|
+
const expression = import_core3.template.expression(adoptTemplates(code, templates, state), {
|
|
2245
|
+
placeholderPattern: false,
|
|
2246
|
+
plugins: ["typescript"]
|
|
2247
|
+
})();
|
|
2248
|
+
inheritLocation(expression, node);
|
|
2249
|
+
return expression;
|
|
2250
|
+
}
|
|
2251
|
+
function inheritLocation(target, source) {
|
|
2252
|
+
if (!source.loc) return;
|
|
2253
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2254
|
+
const walk8 = (node) => {
|
|
2255
|
+
if (seen.has(node)) return;
|
|
2256
|
+
seen.add(node);
|
|
2257
|
+
if (!node.loc) {
|
|
2258
|
+
node.loc = source.loc;
|
|
2259
|
+
node.start = source.start;
|
|
2260
|
+
node.end = source.end;
|
|
2261
|
+
}
|
|
2262
|
+
for (const key of import_core3.types.VISITOR_KEYS[node.type] ?? []) {
|
|
2263
|
+
const child = node[key];
|
|
2264
|
+
if (Array.isArray(child)) {
|
|
2265
|
+
for (const c of child) if (c && typeof c === "object" && "type" in c) walk8(c);
|
|
2266
|
+
} else if (child && typeof child === "object" && "type" in child) {
|
|
2267
|
+
walk8(child);
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
};
|
|
2271
|
+
walk8(target);
|
|
2272
|
+
}
|
|
2273
|
+
function collectRuntimeNeeds(node, state) {
|
|
2274
|
+
if (node.kind === "component" && node.source) {
|
|
2275
|
+
if (node.source.origin === "builtin") {
|
|
2276
|
+
state.controlFlowComponents.add(node.name);
|
|
2277
|
+
state.needsControlFlowImport = true;
|
|
2278
|
+
} else if (isDeferred(node.source.loading) && !state.resolvedComponents.has(node.name)) {
|
|
2279
|
+
state.deferredComponents.set(node.name, {
|
|
2280
|
+
module: node.source.module,
|
|
2281
|
+
export: node.source.export,
|
|
2282
|
+
strategy: node.source.loading
|
|
2283
|
+
});
|
|
2284
|
+
} else {
|
|
2285
|
+
state.deferredComponents.delete(node.name);
|
|
2286
|
+
state.resolvedComponents.set(node.name, {
|
|
2287
|
+
module: node.source.module,
|
|
2288
|
+
export: node.source.export
|
|
2289
|
+
});
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2292
|
+
if (node.kind === "element" || node.kind === "component" || node.kind === "control") {
|
|
2293
|
+
if ("props" in node) {
|
|
2294
|
+
for (const p of node.props) {
|
|
2295
|
+
if (p.kind === "event" && p.event?.delegated) state.delegatedEvents.add(p.event.name);
|
|
2296
|
+
}
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2299
|
+
if ("children" in node && node.children) {
|
|
2300
|
+
for (const c of node.children) collectRuntimeNeeds(c, state);
|
|
2301
|
+
}
|
|
2302
|
+
}
|
|
2303
|
+
var import_helper_plugin_utils, import_core3, CORE_ONLY_CONTROL_FLOW, ROUTER_COMPONENTS2, plugin_default;
|
|
2304
|
+
var init_plugin = __esm({
|
|
2305
|
+
"src/frontend/babel/plugin.ts"() {
|
|
2306
|
+
"use strict";
|
|
2307
|
+
import_helper_plugin_utils = require("@babel/helper-plugin-utils");
|
|
2308
|
+
init_component_resolver();
|
|
2309
|
+
init_resolve_ir();
|
|
2310
|
+
init_collapse_strategies();
|
|
2311
|
+
init_load_directive();
|
|
2312
|
+
init_builtins();
|
|
2313
|
+
import_core3 = require("@babel/core");
|
|
2314
|
+
init_build_ir();
|
|
2315
|
+
init_build_ir_lit();
|
|
2316
|
+
init_imperative();
|
|
2317
|
+
CORE_ONLY_CONTROL_FLOW = new Set(CORE_CONTROL_FLOW);
|
|
2318
|
+
ROUTER_COMPONENTS2 = new Set(ROUTER_COMPONENTS);
|
|
2319
|
+
plugin_default = (0, import_helper_plugin_utils.declare)((api, options = {}) => {
|
|
2320
|
+
api.assertVersion(7);
|
|
2321
|
+
const {
|
|
2322
|
+
delegateEvents = true,
|
|
2323
|
+
signalModule = "@fluixi/dom",
|
|
2324
|
+
controlFlowModule = "@fluixi/dom",
|
|
2325
|
+
routerModule = "@fluixi/core/router",
|
|
2326
|
+
reactiveModule = "@fluixi/reactive/signal",
|
|
2327
|
+
templateClone = true,
|
|
2328
|
+
partialTemplates = true,
|
|
2329
|
+
// `both` by default: JSX and html`` are compiled out of the box, so
|
|
2330
|
+
// `fluixi()` needs no `format` option. Injected imports are deduped, so a
|
|
2331
|
+
// file mixing the two styles won't redeclare a binding.
|
|
2332
|
+
format = "both",
|
|
2333
|
+
litTag = "html",
|
|
2334
|
+
resolve: resolveRules = []
|
|
2335
|
+
} = options;
|
|
2336
|
+
const componentResolver = createComponentResolver(resolveRules);
|
|
2337
|
+
const compileLit = format === "lit" || format === "both";
|
|
2338
|
+
const pluginState = {
|
|
2339
|
+
irImports: /* @__PURE__ */ new Set(),
|
|
2340
|
+
libModule: "@fluixi/core",
|
|
2341
|
+
controlFlowModule,
|
|
2342
|
+
routerModule,
|
|
2343
|
+
templateClone,
|
|
2344
|
+
partialTemplates,
|
|
2345
|
+
hasJSX: false,
|
|
2346
|
+
hasLitHTML: false,
|
|
2347
|
+
needsControlFlowImport: false,
|
|
2348
|
+
needsCreateMemo: false,
|
|
2349
|
+
controlFlowComponents: /* @__PURE__ */ new Set(),
|
|
2350
|
+
resolvedComponents: /* @__PURE__ */ new Map(),
|
|
2351
|
+
deferredComponents: /* @__PURE__ */ new Map(),
|
|
2352
|
+
componentResolver,
|
|
2353
|
+
delegatedEvents: /* @__PURE__ */ new Set(),
|
|
2354
|
+
staticTemplates: /* @__PURE__ */ new Map(),
|
|
2355
|
+
staticCounter: 0
|
|
2356
|
+
};
|
|
2357
|
+
return {
|
|
2358
|
+
name: "@fluixi/babel-plugin-jsx",
|
|
2359
|
+
manipulateOptions(opts, parserOpts) {
|
|
2360
|
+
parserOpts.plugins.push("jsx", "typescript");
|
|
2361
|
+
},
|
|
2362
|
+
pre(state) {
|
|
2363
|
+
Object.assign(state, pluginState);
|
|
2364
|
+
},
|
|
2365
|
+
visitor: {
|
|
2366
|
+
Program: {
|
|
2367
|
+
enter(path, state) {
|
|
2368
|
+
Object.assign(state, {
|
|
2369
|
+
hasJSX: false,
|
|
2370
|
+
hasLitHTML: false,
|
|
2371
|
+
hasLitIR: false,
|
|
2372
|
+
needsControlFlowImport: false,
|
|
2373
|
+
needsCreateMemo: false,
|
|
2374
|
+
controlFlowComponents: /* @__PURE__ */ new Set(),
|
|
2375
|
+
resolvedComponents: /* @__PURE__ */ new Map(),
|
|
2376
|
+
deferredComponents: /* @__PURE__ */ new Map(),
|
|
2377
|
+
componentResolver,
|
|
2378
|
+
delegatedEvents: /* @__PURE__ */ new Set(),
|
|
2379
|
+
staticTemplates: /* @__PURE__ */ new Map(),
|
|
2380
|
+
staticCounter: 0,
|
|
2381
|
+
libModule: "@fluixi/core",
|
|
2382
|
+
controlFlowModule,
|
|
2383
|
+
routerModule,
|
|
2384
|
+
templateClone,
|
|
2385
|
+
partialTemplates,
|
|
2386
|
+
irImports: /* @__PURE__ */ new Set(),
|
|
2387
|
+
needsCreateNativeElement: false,
|
|
2388
|
+
needsInsert: false,
|
|
2389
|
+
needsSpread: false,
|
|
2390
|
+
needsCreateComponent: false,
|
|
2391
|
+
needsMergeProps: false
|
|
2392
|
+
});
|
|
2393
|
+
},
|
|
2394
|
+
exit(path, state) {
|
|
2395
|
+
const imports = [];
|
|
2396
|
+
if (state.hasJSX || state.hasLitIR) {
|
|
2397
|
+
if (state.irImports.size > 0) {
|
|
2398
|
+
const CF = /* @__PURE__ */ new Set([
|
|
2399
|
+
"Show",
|
|
2400
|
+
"For",
|
|
2401
|
+
"Index",
|
|
2402
|
+
"Switch",
|
|
2403
|
+
"Match",
|
|
2404
|
+
"Dynamic",
|
|
2405
|
+
"ErrorBoundary",
|
|
2406
|
+
"Portal",
|
|
2407
|
+
"Suspense"
|
|
2408
|
+
]);
|
|
2409
|
+
const REACTIVE2 = /* @__PURE__ */ new Set([
|
|
2410
|
+
"createMemo",
|
|
2411
|
+
"createEffect",
|
|
2412
|
+
"createRenderEffect",
|
|
2413
|
+
"createRoot",
|
|
2414
|
+
"createSignal",
|
|
2415
|
+
"onCleanup",
|
|
2416
|
+
"batch",
|
|
2417
|
+
"untrack"
|
|
2418
|
+
]);
|
|
2419
|
+
const all = Array.from(state.irImports);
|
|
2420
|
+
const spec = (n) => import_core3.types.importSpecifier(import_core3.types.identifier(n), import_core3.types.identifier(n));
|
|
2421
|
+
const unbound = (s) => !path.scope.hasBinding(s);
|
|
2422
|
+
const reactive = all.filter((s) => REACTIVE2.has(s) && unbound(s));
|
|
2423
|
+
const core = all.filter((s) => !CF.has(s) && !REACTIVE2.has(s) && unbound(s));
|
|
2424
|
+
const cf = all.filter((s) => CF.has(s) && unbound(s));
|
|
2425
|
+
if (reactive.length > 0) {
|
|
2426
|
+
imports.push(
|
|
2427
|
+
import_core3.types.importDeclaration(reactive.map(spec), import_core3.types.stringLiteral(reactiveModule))
|
|
2428
|
+
);
|
|
2429
|
+
}
|
|
2430
|
+
if (core.length > 0) {
|
|
2431
|
+
imports.push(
|
|
2432
|
+
import_core3.types.importDeclaration(core.map(spec), import_core3.types.stringLiteral(signalModule))
|
|
2433
|
+
);
|
|
2434
|
+
}
|
|
2435
|
+
if (cf.length > 0) {
|
|
2436
|
+
imports.push(
|
|
2437
|
+
import_core3.types.importDeclaration(cf.map(spec), import_core3.types.stringLiteral(controlFlowModule))
|
|
2438
|
+
);
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
if (state.needsCreateMemo && !path.scope.hasBinding("createMemo")) {
|
|
2442
|
+
imports.push(
|
|
2443
|
+
import_core3.types.importDeclaration(
|
|
2444
|
+
[import_core3.types.importSpecifier(import_core3.types.identifier("createMemo"), import_core3.types.identifier("createMemo"))],
|
|
2445
|
+
import_core3.types.stringLiteral(reactiveModule)
|
|
2446
|
+
)
|
|
2447
|
+
);
|
|
2448
|
+
}
|
|
2449
|
+
if (state.needsControlFlowImport && state.controlFlowComponents.size > 0) {
|
|
2450
|
+
const unbound = Array.from(state.controlFlowComponents).filter(
|
|
2451
|
+
(name) => !path.scope.hasBinding(name)
|
|
2452
|
+
);
|
|
2453
|
+
const coreModule = state.libModule ?? "@fluixi/core";
|
|
2454
|
+
const fromRouter = unbound.filter((n) => ROUTER_COMPONENTS2.has(n));
|
|
2455
|
+
const fromCore = unbound.filter((n) => CORE_ONLY_CONTROL_FLOW.has(n));
|
|
2456
|
+
const fromDom = unbound.filter(
|
|
2457
|
+
(n) => !CORE_ONLY_CONTROL_FLOW.has(n) && !ROUTER_COMPONENTS2.has(n)
|
|
2458
|
+
);
|
|
2459
|
+
const declFor = (names, mod) => import_core3.types.importDeclaration(
|
|
2460
|
+
names.map((name) => import_core3.types.importSpecifier(import_core3.types.identifier(name), import_core3.types.identifier(name))),
|
|
2461
|
+
import_core3.types.stringLiteral(mod)
|
|
2462
|
+
);
|
|
2463
|
+
if (fromDom.length > 0) imports.push(declFor(fromDom, controlFlowModule));
|
|
2464
|
+
if (fromCore.length > 0) imports.push(declFor(fromCore, coreModule));
|
|
2465
|
+
if (fromRouter.length > 0) imports.push(declFor(fromRouter, routerModule));
|
|
2466
|
+
}
|
|
2467
|
+
const deferredDecls = [];
|
|
2468
|
+
if (state.deferredComponents.size > 0) {
|
|
2469
|
+
for (const [local, entry] of state.deferredComponents) {
|
|
2470
|
+
if (path.scope.hasBinding(local)) continue;
|
|
2471
|
+
deferredDecls.push(
|
|
2472
|
+
import_core3.types.variableDeclaration("const", [
|
|
2473
|
+
import_core3.types.variableDeclarator(
|
|
2474
|
+
import_core3.types.identifier(local),
|
|
2475
|
+
import_core3.types.callExpression(import_core3.types.identifier("deferred"), [
|
|
2476
|
+
import_core3.types.arrowFunctionExpression(
|
|
2477
|
+
[],
|
|
2478
|
+
import_core3.types.callExpression(import_core3.types.import(), [import_core3.types.stringLiteral(entry.module)])
|
|
2479
|
+
),
|
|
2480
|
+
import_core3.types.objectExpression([
|
|
2481
|
+
import_core3.types.objectProperty(
|
|
2482
|
+
import_core3.types.identifier("strategy"),
|
|
2483
|
+
strategyLiteral(entry.strategy)
|
|
2484
|
+
),
|
|
2485
|
+
import_core3.types.objectProperty(
|
|
2486
|
+
import_core3.types.identifier("export"),
|
|
2487
|
+
import_core3.types.stringLiteral(entry.export)
|
|
2488
|
+
)
|
|
2489
|
+
])
|
|
2490
|
+
])
|
|
2491
|
+
)
|
|
2492
|
+
])
|
|
2493
|
+
);
|
|
2494
|
+
}
|
|
2495
|
+
if (deferredDecls.length > 0 && !path.scope.hasBinding("deferred")) {
|
|
2496
|
+
imports.push(
|
|
2497
|
+
import_core3.types.importDeclaration(
|
|
2498
|
+
[import_core3.types.importSpecifier(import_core3.types.identifier("deferred"), import_core3.types.identifier("deferred"))],
|
|
2499
|
+
import_core3.types.stringLiteral(state.libModule ?? "@fluixi/core")
|
|
2500
|
+
)
|
|
2501
|
+
);
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
if (state.resolvedComponents.size > 0) {
|
|
2505
|
+
const byModule = /* @__PURE__ */ new Map();
|
|
2506
|
+
for (const [local, resolved] of state.resolvedComponents) {
|
|
2507
|
+
if (path.scope.hasBinding(local)) continue;
|
|
2508
|
+
const list = byModule.get(resolved.module) ?? [];
|
|
2509
|
+
list.push({ local, exported: resolved.export });
|
|
2510
|
+
byModule.set(resolved.module, list);
|
|
2511
|
+
}
|
|
2512
|
+
for (const [mod, entries] of byModule) {
|
|
2513
|
+
imports.push(
|
|
2514
|
+
import_core3.types.importDeclaration(
|
|
2515
|
+
entries.map(
|
|
2516
|
+
({ local, exported }) => exported === "default" ? import_core3.types.importDefaultSpecifier(import_core3.types.identifier(local)) : import_core3.types.importSpecifier(import_core3.types.identifier(local), import_core3.types.identifier(exported))
|
|
2517
|
+
),
|
|
2518
|
+
import_core3.types.stringLiteral(mod)
|
|
2519
|
+
)
|
|
2520
|
+
);
|
|
2521
|
+
}
|
|
2522
|
+
}
|
|
2523
|
+
if (delegateEvents && state.delegatedEvents.size > 0) {
|
|
2524
|
+
imports.push(
|
|
2525
|
+
import_core3.types.importDeclaration(
|
|
2526
|
+
[
|
|
2527
|
+
import_core3.types.importSpecifier(
|
|
2528
|
+
import_core3.types.identifier("delegateEvents"),
|
|
2529
|
+
import_core3.types.identifier("delegateEvents")
|
|
2530
|
+
)
|
|
2531
|
+
],
|
|
2532
|
+
import_core3.types.stringLiteral(signalModule)
|
|
2533
|
+
)
|
|
2534
|
+
);
|
|
2535
|
+
const eventsArray = import_core3.types.arrayExpression(
|
|
2536
|
+
Array.from(state.delegatedEvents).map(
|
|
2537
|
+
(event) => import_core3.types.stringLiteral(event)
|
|
2538
|
+
)
|
|
2539
|
+
);
|
|
2540
|
+
const delegateCall = import_core3.types.expressionStatement(
|
|
2541
|
+
import_core3.types.callExpression(import_core3.types.identifier("delegateEvents"), [eventsArray])
|
|
2542
|
+
);
|
|
2543
|
+
path.node.body.unshift(delegateCall);
|
|
2544
|
+
}
|
|
2545
|
+
if (deferredDecls.length > 0) {
|
|
2546
|
+
path.node.body.unshift(...deferredDecls);
|
|
2547
|
+
}
|
|
2548
|
+
if (state.staticTemplates.size > 0) {
|
|
2549
|
+
const decls = [];
|
|
2550
|
+
for (const [key, name] of state.staticTemplates) {
|
|
2551
|
+
const svg = key.startsWith("svg:");
|
|
2552
|
+
const html = svg ? key.slice(4) : key;
|
|
2553
|
+
decls.push(
|
|
2554
|
+
import_core3.types.variableDeclaration("const", [
|
|
2555
|
+
import_core3.types.variableDeclarator(
|
|
2556
|
+
import_core3.types.identifier(name),
|
|
2557
|
+
// Just the HTML. Parsing is deferred to `templateNode`, which
|
|
2558
|
+
// knows whether this is a server render, a hydration or a fresh
|
|
2559
|
+
// client render — a module-scope `createTemplate` would touch
|
|
2560
|
+
// `document` at import time and break SSR outright.
|
|
2561
|
+
import_core3.types.stringLiteral(html)
|
|
2562
|
+
)
|
|
2563
|
+
])
|
|
2564
|
+
);
|
|
2565
|
+
}
|
|
2566
|
+
path.node.body.unshift(...decls);
|
|
2567
|
+
}
|
|
2568
|
+
}
|
|
2569
|
+
if (imports.length > 0) {
|
|
2570
|
+
path.node.body.unshift(...dedupeImports(imports));
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
},
|
|
2574
|
+
// Both JSX forms take the one path: build IR, run the imperative backend,
|
|
2575
|
+
// splice the emitted code back in. It handles the whole subtree, so nothing
|
|
2576
|
+
// below this node needs its own visitor.
|
|
2577
|
+
JSXElement(path, state) {
|
|
2578
|
+
state.hasJSX = true;
|
|
2579
|
+
path.replaceWith(emitViaIR(path.node, state));
|
|
2580
|
+
},
|
|
2581
|
+
JSXFragment(path, state) {
|
|
2582
|
+
state.hasJSX = true;
|
|
2583
|
+
path.replaceWith(emitViaIR(path.node, state));
|
|
2584
|
+
},
|
|
2585
|
+
TaggedTemplateExpression(path, state) {
|
|
2586
|
+
if (compileLit && import_core3.types.isIdentifier(path.node.tag) && (path.node.tag.name === litTag || path.node.tag.name === "svg")) {
|
|
2587
|
+
path.replaceWith(emitLitViaIR(path.node, state));
|
|
2588
|
+
}
|
|
2589
|
+
}
|
|
2590
|
+
}
|
|
2591
|
+
};
|
|
2592
|
+
});
|
|
2593
|
+
}
|
|
2594
|
+
});
|
|
2595
|
+
|
|
2596
|
+
// src/frontend/babel/types.ts
|
|
2597
|
+
var init_types = __esm({
|
|
2598
|
+
"src/frontend/babel/types.ts"() {
|
|
2599
|
+
"use strict";
|
|
2600
|
+
}
|
|
2601
|
+
});
|
|
2602
|
+
|
|
2603
|
+
// src/frontend/babel/index.ts
|
|
2604
|
+
var babel_exports = {};
|
|
2605
|
+
__export(babel_exports, {
|
|
2606
|
+
babelPluginReactiveJSX: () => babelPluginReactiveJSX,
|
|
2607
|
+
createPlugin: () => createPlugin,
|
|
2608
|
+
createPreset: () => createPreset,
|
|
2609
|
+
default: () => plugin_default,
|
|
2610
|
+
presets: () => presets
|
|
2611
|
+
});
|
|
2612
|
+
function createPlugin(options) {
|
|
2613
|
+
return [plugin_default, options];
|
|
2614
|
+
}
|
|
2615
|
+
function createPreset(options = {}) {
|
|
2616
|
+
return {
|
|
2617
|
+
plugins: [
|
|
2618
|
+
[
|
|
2619
|
+
plugin_default,
|
|
2620
|
+
{
|
|
2621
|
+
runtime: "automatic",
|
|
2622
|
+
importSource: "@fluixi/jsx",
|
|
2623
|
+
development: false,
|
|
2624
|
+
detectReactivity: true,
|
|
2625
|
+
useLitHTML: true,
|
|
2626
|
+
hoistStatics: true,
|
|
2627
|
+
delegateEvents: true,
|
|
2628
|
+
optimizeControlFlow: true,
|
|
2629
|
+
sourceMaps: true,
|
|
2630
|
+
...options
|
|
2631
|
+
}
|
|
2632
|
+
]
|
|
2633
|
+
]
|
|
2634
|
+
};
|
|
2635
|
+
}
|
|
2636
|
+
var babelPluginReactiveJSX, presets;
|
|
2637
|
+
var init_babel = __esm({
|
|
2638
|
+
"src/frontend/babel/index.ts"() {
|
|
2639
|
+
"use strict";
|
|
2640
|
+
init_plugin();
|
|
2641
|
+
init_types();
|
|
2642
|
+
init_plugin();
|
|
2643
|
+
babelPluginReactiveJSX = plugin_default;
|
|
2644
|
+
presets = {
|
|
2645
|
+
production: createPreset({
|
|
2646
|
+
development: false,
|
|
2647
|
+
hoistStatics: true,
|
|
2648
|
+
delegateEvents: true,
|
|
2649
|
+
optimizeControlFlow: true
|
|
2650
|
+
}),
|
|
2651
|
+
development: createPreset({
|
|
2652
|
+
development: true,
|
|
2653
|
+
hoistStatics: false,
|
|
2654
|
+
sourceMaps: true
|
|
2655
|
+
}),
|
|
2656
|
+
minimal: createPreset({
|
|
2657
|
+
detectReactivity: false,
|
|
2658
|
+
useLitHTML: false,
|
|
2659
|
+
hoistStatics: false,
|
|
2660
|
+
delegateEvents: false,
|
|
2661
|
+
optimizeControlFlow: false
|
|
2662
|
+
})
|
|
2663
|
+
};
|
|
2664
|
+
}
|
|
2665
|
+
});
|
|
2666
|
+
|
|
2667
|
+
// src/lower/compile-template.ts
|
|
2668
|
+
function compilePieces(pieces, holes, options = {}) {
|
|
2669
|
+
const used = /* @__PURE__ */ new Set();
|
|
2670
|
+
const ir = lowerTemplate(pieces, [...holes], used, {
|
|
2671
|
+
svg: options.svg,
|
|
2672
|
+
...options.sourceFile ? { sourceFile: options.sourceFile } : {},
|
|
2673
|
+
...options.positionAt ? { positionAt: options.positionAt } : {}
|
|
2674
|
+
});
|
|
2675
|
+
analyzeStatic(ir);
|
|
2676
|
+
resolveComponentSources(ir, {
|
|
2677
|
+
resolver: createComponentResolver(options.resolve ?? []),
|
|
2678
|
+
modules: {
|
|
2679
|
+
controlFlowModule: options.controlFlowModule ?? "@fluixi/dom",
|
|
2680
|
+
coreModule: options.coreModule ?? "@fluixi/core",
|
|
2681
|
+
routerModule: options.routerModule ?? "@fluixi/core/router"
|
|
2682
|
+
},
|
|
2683
|
+
strategyFor: (node) => node.load
|
|
2684
|
+
});
|
|
2685
|
+
collapseStrategies(ir);
|
|
2686
|
+
const { code, imports, templates } = imperativeBackend.emit(ir, {
|
|
2687
|
+
templateClone: options.templateClone,
|
|
2688
|
+
partialTemplates: options.partialTemplates
|
|
2689
|
+
});
|
|
2690
|
+
for (const symbol of imports) used.add(symbol);
|
|
2691
|
+
if (options.hoistTemplates) return { code, imports: [...used], ir, templates };
|
|
2692
|
+
return { code: inlineTemplates(code, templates), imports: [...used], ir };
|
|
2693
|
+
}
|
|
2694
|
+
var init_compile_template = __esm({
|
|
2695
|
+
"src/lower/compile-template.ts"() {
|
|
2696
|
+
"use strict";
|
|
2697
|
+
init_analyze_static();
|
|
2698
|
+
init_collapse_strategies();
|
|
2699
|
+
init_imperative();
|
|
2700
|
+
init_resolve_ir();
|
|
2701
|
+
init_component_resolver();
|
|
2702
|
+
init_template();
|
|
2703
|
+
}
|
|
2704
|
+
});
|
|
2705
|
+
|
|
2706
|
+
// src/transform/bindings.ts
|
|
2707
|
+
function patternNames2(node, out) {
|
|
2708
|
+
if (!node) return;
|
|
2709
|
+
switch (node.type) {
|
|
2710
|
+
case "Identifier":
|
|
2711
|
+
out.add(node.name);
|
|
2712
|
+
return;
|
|
2713
|
+
case "ObjectPattern":
|
|
2714
|
+
for (const p of node.properties) {
|
|
2715
|
+
if (p.type === "RestElement") patternNames2(p.argument, out);
|
|
2716
|
+
else patternNames2(p.value, out);
|
|
2717
|
+
}
|
|
2718
|
+
return;
|
|
2719
|
+
case "ArrayPattern":
|
|
2720
|
+
for (const e of node.elements) patternNames2(e, out);
|
|
2721
|
+
return;
|
|
2722
|
+
case "AssignmentPattern":
|
|
2723
|
+
patternNames2(node.left, out);
|
|
2724
|
+
return;
|
|
2725
|
+
case "RestElement":
|
|
2726
|
+
patternNames2(node.argument, out);
|
|
2727
|
+
return;
|
|
2728
|
+
}
|
|
2729
|
+
}
|
|
2730
|
+
function declared(node, out) {
|
|
2731
|
+
switch (node.type) {
|
|
2732
|
+
case "ImportDeclaration":
|
|
2733
|
+
for (const s of node.specifiers) patternNames2(s.local, out);
|
|
2734
|
+
return;
|
|
2735
|
+
case "VariableDeclaration":
|
|
2736
|
+
for (const d of node.declarations) patternNames2(d.id, out);
|
|
2737
|
+
return;
|
|
2738
|
+
case "FunctionDeclaration":
|
|
2739
|
+
case "ClassDeclaration":
|
|
2740
|
+
patternNames2(node.id, out);
|
|
2741
|
+
return;
|
|
2742
|
+
case "ExportNamedDeclaration":
|
|
2743
|
+
case "ExportDefaultDeclaration":
|
|
2744
|
+
if (node.declaration) declared(node.declaration, out);
|
|
2745
|
+
return;
|
|
2746
|
+
}
|
|
2747
|
+
}
|
|
2748
|
+
function moduleBindings(program) {
|
|
2749
|
+
const names = /* @__PURE__ */ new Set();
|
|
2750
|
+
for (const statement of program.body) declared(statement, names);
|
|
2751
|
+
return names;
|
|
2752
|
+
}
|
|
2753
|
+
var init_bindings = __esm({
|
|
2754
|
+
"src/transform/bindings.ts"() {
|
|
2755
|
+
"use strict";
|
|
2756
|
+
}
|
|
2757
|
+
});
|
|
2758
|
+
|
|
2759
|
+
// src/analyze/props-destructure.ts
|
|
2760
|
+
function patternNames3(node, out) {
|
|
2761
|
+
if (!node) return;
|
|
2762
|
+
switch (node.type) {
|
|
2763
|
+
case "Identifier":
|
|
2764
|
+
out.add(node.name);
|
|
2765
|
+
return;
|
|
2766
|
+
case "ObjectPattern":
|
|
2767
|
+
for (const p of node.properties) {
|
|
2768
|
+
if (p.type === "RestElement") patternNames3(p.argument, out);
|
|
2769
|
+
else patternNames3(p.value, out);
|
|
2770
|
+
}
|
|
2771
|
+
return;
|
|
2772
|
+
case "ArrayPattern":
|
|
2773
|
+
for (const e of node.elements) patternNames3(e, out);
|
|
2774
|
+
return;
|
|
2775
|
+
case "AssignmentPattern":
|
|
2776
|
+
patternNames3(node.left, out);
|
|
2777
|
+
return;
|
|
2778
|
+
case "RestElement":
|
|
2779
|
+
patternNames3(node.argument, out);
|
|
2780
|
+
return;
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2783
|
+
function isSafeDefault(node) {
|
|
2784
|
+
switch (node.type) {
|
|
2785
|
+
case "StringLiteral":
|
|
2786
|
+
case "NumericLiteral":
|
|
2787
|
+
case "BooleanLiteral":
|
|
2788
|
+
case "NullLiteral":
|
|
2789
|
+
case "BigIntLiteral":
|
|
2790
|
+
case "RegExpLiteral":
|
|
2791
|
+
case "Identifier":
|
|
2792
|
+
return true;
|
|
2793
|
+
// ESTree spells every literal as `Literal`; both shapes reach this analysis.
|
|
2794
|
+
case "Literal":
|
|
2795
|
+
return true;
|
|
2796
|
+
case "TemplateLiteral":
|
|
2797
|
+
return node.expressions.every(isSafeDefault);
|
|
2798
|
+
case "UnaryExpression":
|
|
2799
|
+
return isSafeDefault(node.argument);
|
|
2800
|
+
case "MemberExpression":
|
|
2801
|
+
return false;
|
|
2802
|
+
default:
|
|
2803
|
+
return false;
|
|
2804
|
+
}
|
|
2805
|
+
}
|
|
2806
|
+
function walk4(root, visit) {
|
|
2807
|
+
if (!root || typeof root !== "object") return;
|
|
2808
|
+
visit(root);
|
|
2809
|
+
for (const key of Object.keys(root)) {
|
|
2810
|
+
if (key === "loc" || key === "range" || key === "leadingComments" || key === "trailingComments") continue;
|
|
2811
|
+
const value = root[key];
|
|
2812
|
+
if (Array.isArray(value)) {
|
|
2813
|
+
for (const item of value) if (item && typeof item === "object") walk4(item, visit);
|
|
2814
|
+
} else if (value && typeof value === "object" && typeof value.type === "string") {
|
|
2815
|
+
walk4(value, visit);
|
|
2816
|
+
}
|
|
2817
|
+
}
|
|
2818
|
+
}
|
|
2819
|
+
function reassignedNames(body) {
|
|
2820
|
+
const written = /* @__PURE__ */ new Set();
|
|
2821
|
+
walk4(body, (node) => {
|
|
2822
|
+
if (node.type === "AssignmentExpression") patternNames3(node.left, written);
|
|
2823
|
+
else if (node.type === "UpdateExpression") {
|
|
2824
|
+
const arg = node.argument;
|
|
2825
|
+
if (arg?.type === "Identifier") written.add(arg.name);
|
|
2826
|
+
}
|
|
2827
|
+
});
|
|
2828
|
+
return written;
|
|
2829
|
+
}
|
|
2830
|
+
function shadowedNames(body, candidates) {
|
|
2831
|
+
const shadowed = /* @__PURE__ */ new Set();
|
|
2832
|
+
const note = (node) => {
|
|
2833
|
+
const names = /* @__PURE__ */ new Set();
|
|
2834
|
+
patternNames3(node, names);
|
|
2835
|
+
for (const n of names) if (candidates.has(n)) shadowed.add(n);
|
|
2836
|
+
};
|
|
2837
|
+
walk4(body, (node) => {
|
|
2838
|
+
switch (node.type) {
|
|
2839
|
+
case "VariableDeclarator":
|
|
2840
|
+
note(node.id);
|
|
2841
|
+
return;
|
|
2842
|
+
case "FunctionDeclaration":
|
|
2843
|
+
case "FunctionExpression":
|
|
2844
|
+
case "ArrowFunctionExpression":
|
|
2845
|
+
note(node.id);
|
|
2846
|
+
for (const p of node.params ?? []) note(p);
|
|
2847
|
+
return;
|
|
2848
|
+
case "CatchClause":
|
|
2849
|
+
note(node.param);
|
|
2850
|
+
return;
|
|
2851
|
+
case "ClassDeclaration":
|
|
2852
|
+
case "ClassExpression":
|
|
2853
|
+
note(node.id);
|
|
2854
|
+
return;
|
|
2855
|
+
}
|
|
2856
|
+
});
|
|
2857
|
+
return shadowed;
|
|
2858
|
+
}
|
|
2859
|
+
function collect(pattern, path, plan) {
|
|
2860
|
+
for (const property of pattern.properties ?? []) {
|
|
2861
|
+
if (property.type === "RestElement") {
|
|
2862
|
+
const argument = property.argument;
|
|
2863
|
+
if (argument?.type !== "Identifier" || path.length > 0) {
|
|
2864
|
+
const names2 = /* @__PURE__ */ new Set();
|
|
2865
|
+
patternNames3(argument, names2);
|
|
2866
|
+
for (const name of names2) plan.bails.push({ name, reason: "rest" });
|
|
2867
|
+
continue;
|
|
2868
|
+
}
|
|
2869
|
+
plan.rest = { name: argument.name, keys: [] };
|
|
2870
|
+
continue;
|
|
2871
|
+
}
|
|
2872
|
+
if (property.computed) {
|
|
2873
|
+
const names2 = /* @__PURE__ */ new Set();
|
|
2874
|
+
patternNames3(property.value, names2);
|
|
2875
|
+
for (const name of names2) plan.bails.push({ name, reason: "computed" });
|
|
2876
|
+
continue;
|
|
2877
|
+
}
|
|
2878
|
+
const key = property.key;
|
|
2879
|
+
const propertyName = key.type === "Identifier" ? key.name : key.value;
|
|
2880
|
+
let value = property.value;
|
|
2881
|
+
let fallback;
|
|
2882
|
+
if (value.type === "AssignmentPattern") {
|
|
2883
|
+
fallback = value.right;
|
|
2884
|
+
value = value.left;
|
|
2885
|
+
}
|
|
2886
|
+
const here = [...path, propertyName];
|
|
2887
|
+
if (value.type === "Identifier") {
|
|
2888
|
+
if (fallback && !isSafeDefault(fallback)) {
|
|
2889
|
+
plan.bails.push({ name: value.name, reason: "unsafe-default" });
|
|
2890
|
+
continue;
|
|
2891
|
+
}
|
|
2892
|
+
plan.reads.push({ name: value.name, path: here, ...fallback ? { fallback } : {} });
|
|
2893
|
+
continue;
|
|
2894
|
+
}
|
|
2895
|
+
if (value.type === "ObjectPattern") {
|
|
2896
|
+
if (fallback) {
|
|
2897
|
+
const names2 = /* @__PURE__ */ new Set();
|
|
2898
|
+
patternNames3(value, names2);
|
|
2899
|
+
for (const name of names2) plan.bails.push({ name, reason: "unsafe-default" });
|
|
2900
|
+
continue;
|
|
2901
|
+
}
|
|
2902
|
+
collect(value, here, plan);
|
|
2903
|
+
continue;
|
|
2904
|
+
}
|
|
2905
|
+
const names = /* @__PURE__ */ new Set();
|
|
2906
|
+
patternNames3(value, names);
|
|
2907
|
+
for (const name of names) plan.bails.push({ name, reason: "computed" });
|
|
2908
|
+
}
|
|
2909
|
+
}
|
|
2910
|
+
function planPropsDestructure(pattern, body) {
|
|
2911
|
+
const plan = { reads: [], bails: [] };
|
|
2912
|
+
if (pattern?.type !== "ObjectPattern") return plan;
|
|
2913
|
+
collect(pattern, [], plan);
|
|
2914
|
+
if (plan.rest) {
|
|
2915
|
+
if (body?.type !== "BlockStatement") {
|
|
2916
|
+
plan.bails.push({ name: plan.rest.name, reason: "rest" });
|
|
2917
|
+
delete plan.rest;
|
|
2918
|
+
} else {
|
|
2919
|
+
plan.rest.keys = (pattern.properties ?? []).filter((p) => p.type !== "RestElement" && !p.computed).map((p) => {
|
|
2920
|
+
const key = p.key;
|
|
2921
|
+
return key.type === "Identifier" ? key.name : key.value;
|
|
2922
|
+
});
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
if (plan.reads.length === 0 && !plan.rest) return plan;
|
|
2926
|
+
const candidates = new Set(plan.reads.map((r) => r.name));
|
|
2927
|
+
if (plan.rest) candidates.add(plan.rest.name);
|
|
2928
|
+
const written = reassignedNames(body);
|
|
2929
|
+
const shadowed = shadowedNames(body, candidates);
|
|
2930
|
+
const kept = [];
|
|
2931
|
+
for (const read of plan.reads) {
|
|
2932
|
+
if (written.has(read.name)) plan.bails.push({ name: read.name, reason: "reassigned" });
|
|
2933
|
+
else if (shadowed.has(read.name)) plan.bails.push({ name: read.name, reason: "shadowed" });
|
|
2934
|
+
else kept.push(read);
|
|
2935
|
+
}
|
|
2936
|
+
plan.reads = kept;
|
|
2937
|
+
if (plan.rest && written.has(plan.rest.name)) {
|
|
2938
|
+
plan.bails.push({ name: plan.rest.name, reason: "reassigned" });
|
|
2939
|
+
delete plan.rest;
|
|
2940
|
+
} else if (plan.rest && shadowed.has(plan.rest.name)) {
|
|
2941
|
+
plan.bails.push({ name: plan.rest.name, reason: "shadowed" });
|
|
2942
|
+
delete plan.rest;
|
|
2943
|
+
}
|
|
2944
|
+
return plan;
|
|
2945
|
+
}
|
|
2946
|
+
function explainBail(reason) {
|
|
2947
|
+
switch (reason) {
|
|
2948
|
+
case "rest":
|
|
2949
|
+
return "this rest element cannot be served by splitProps, and copying the props into a plain object would lose the getters";
|
|
2950
|
+
case "computed":
|
|
2951
|
+
return "the property is not known until it runs";
|
|
2952
|
+
case "reassigned":
|
|
2953
|
+
return "the binding is assigned to, and props are read-only";
|
|
2954
|
+
case "shadowed":
|
|
2955
|
+
return "an inner scope binds the same name";
|
|
2956
|
+
case "unsafe-default":
|
|
2957
|
+
return "the default would have to run again on every read";
|
|
2958
|
+
}
|
|
2959
|
+
}
|
|
2960
|
+
var init_props_destructure = __esm({
|
|
2961
|
+
"src/analyze/props-destructure.ts"() {
|
|
2962
|
+
"use strict";
|
|
2963
|
+
}
|
|
2964
|
+
});
|
|
2965
|
+
|
|
2966
|
+
// src/transform/props.ts
|
|
2967
|
+
function walk5(root, visit, parent = null) {
|
|
2968
|
+
if (!root || typeof root !== "object" || typeof root.type !== "string") return;
|
|
2969
|
+
if (root.type.startsWith("TS")) return;
|
|
2970
|
+
if (visit(root, parent) === false) return;
|
|
2971
|
+
for (const key of Object.keys(root)) {
|
|
2972
|
+
if (key === "loc" || key === "leadingComments" || key === "trailingComments") continue;
|
|
2973
|
+
const value = root[key];
|
|
2974
|
+
if (Array.isArray(value)) {
|
|
2975
|
+
for (const item of value) walk5(item, visit, root);
|
|
2976
|
+
} else if (value && typeof value === "object") {
|
|
2977
|
+
walk5(value, visit, root);
|
|
2978
|
+
}
|
|
2979
|
+
}
|
|
2980
|
+
}
|
|
2981
|
+
function isComponentName(name) {
|
|
2982
|
+
return !!name && name[0] >= "A" && name[0] <= "Z";
|
|
2983
|
+
}
|
|
2984
|
+
function componentFunctions(program) {
|
|
2985
|
+
const found = [];
|
|
2986
|
+
walk5(program, (node) => {
|
|
2987
|
+
if (node.type === "FunctionDeclaration" && isComponentName(node.id?.name)) {
|
|
2988
|
+
found.push(node);
|
|
2989
|
+
return;
|
|
2990
|
+
}
|
|
2991
|
+
if (node.type === "VariableDeclarator" && isComponentName(node.id?.name)) {
|
|
2992
|
+
const init = node.init;
|
|
2993
|
+
if (init && (init.type === "ArrowFunctionExpression" || init.type === "FunctionExpression")) found.push(init);
|
|
2994
|
+
}
|
|
2995
|
+
});
|
|
2996
|
+
return found;
|
|
2997
|
+
}
|
|
2998
|
+
function usedNames(fn) {
|
|
2999
|
+
const names = /* @__PURE__ */ new Set();
|
|
3000
|
+
walk5(fn, (node) => {
|
|
3001
|
+
if (node.type === "Identifier") names.add(node.name);
|
|
3002
|
+
});
|
|
3003
|
+
return names;
|
|
3004
|
+
}
|
|
3005
|
+
function isReferencePosition(node, parent) {
|
|
3006
|
+
if (!parent) return true;
|
|
3007
|
+
switch (parent.type) {
|
|
3008
|
+
case "MemberExpression":
|
|
3009
|
+
case "OptionalMemberExpression":
|
|
3010
|
+
return !(parent.property === node && !parent.computed);
|
|
3011
|
+
case "ObjectProperty":
|
|
3012
|
+
case "ObjectMethod":
|
|
3013
|
+
case "ClassProperty":
|
|
3014
|
+
case "ClassMethod":
|
|
3015
|
+
return !(parent.key === node && !parent.computed);
|
|
3016
|
+
case "LabeledStatement":
|
|
3017
|
+
case "BreakStatement":
|
|
3018
|
+
case "ContinueStatement":
|
|
3019
|
+
return parent.label !== node;
|
|
3020
|
+
case "ImportSpecifier":
|
|
3021
|
+
case "ExportSpecifier":
|
|
3022
|
+
return false;
|
|
3023
|
+
default:
|
|
3024
|
+
return true;
|
|
3025
|
+
}
|
|
3026
|
+
}
|
|
3027
|
+
function collectPropsEdits(program, code, options = {}) {
|
|
3028
|
+
const edits = [];
|
|
3029
|
+
const diagnostics = [];
|
|
3030
|
+
const used = /* @__PURE__ */ new Set();
|
|
3031
|
+
for (const fn of componentFunctions(program)) {
|
|
3032
|
+
const pattern = fn.params?.[0];
|
|
3033
|
+
if (pattern?.type !== "ObjectPattern") continue;
|
|
3034
|
+
const plan = planPropsDestructure(pattern, fn.body);
|
|
3035
|
+
for (const b of plan.bails) {
|
|
3036
|
+
diagnostics.push({ name: b.name, reason: b.reason, message: explainBail(b.reason), start: pattern.start });
|
|
3037
|
+
}
|
|
3038
|
+
if (plan.bails.length > 0) continue;
|
|
3039
|
+
if (plan.reads.length === 0 && !plan.rest) continue;
|
|
3040
|
+
const taken = usedNames(fn);
|
|
3041
|
+
let parameter = options.parameterName ?? "props";
|
|
3042
|
+
while (taken.has(parameter)) parameter = `_${parameter}`;
|
|
3043
|
+
const replacement = /* @__PURE__ */ new Map();
|
|
3044
|
+
for (const read of plan.reads) {
|
|
3045
|
+
const access = `${parameter}.${read.path.join(".")}`;
|
|
3046
|
+
const fallback = read.fallback;
|
|
3047
|
+
replacement.set(
|
|
3048
|
+
read.name,
|
|
3049
|
+
fallback ? `(${access} === undefined ? ${code.slice(fallback.start, fallback.end)} : ${access})` : access
|
|
3050
|
+
);
|
|
3051
|
+
}
|
|
3052
|
+
const annotation = pattern.typeAnnotation;
|
|
3053
|
+
edits.push({ start: pattern.start, end: annotation?.start ?? pattern.end, code: parameter });
|
|
3054
|
+
if (plan.rest) {
|
|
3055
|
+
const keys = plan.rest.keys.map((k) => JSON.stringify(k)).join(", ");
|
|
3056
|
+
const body = fn.body;
|
|
3057
|
+
edits.push({
|
|
3058
|
+
start: body.start + 1,
|
|
3059
|
+
end: body.start + 1,
|
|
3060
|
+
code: `
|
|
3061
|
+
const [, ${plan.rest.name}] = splitProps(${parameter}, [${keys}]);`
|
|
3062
|
+
});
|
|
3063
|
+
used.add("splitProps");
|
|
3064
|
+
}
|
|
3065
|
+
const matches = [];
|
|
3066
|
+
walk5(fn.body, (node, parent) => {
|
|
3067
|
+
if (node.type !== "Identifier") return void 0;
|
|
3068
|
+
const text = replacement.get(node.name);
|
|
3069
|
+
if (!text) return void 0;
|
|
3070
|
+
const shorthand = parent?.type === "ObjectProperty" && parent.shorthand && parent.value === node;
|
|
3071
|
+
if (!shorthand && !isReferencePosition(node, parent)) return void 0;
|
|
3072
|
+
const path = plan.reads.find((r) => r.name === node.name).path;
|
|
3073
|
+
matches.push({ node, parent: shorthand ? parent : null, text, property: path[path.length - 1] });
|
|
3074
|
+
return void 0;
|
|
3075
|
+
});
|
|
3076
|
+
for (const match of matches) {
|
|
3077
|
+
if (match.parent) {
|
|
3078
|
+
edits.push({ start: match.parent.start, end: match.parent.end, code: `${match.node.name}: ${match.text}` });
|
|
3079
|
+
} else {
|
|
3080
|
+
edits.push({ start: match.node.start, end: match.node.end, code: match.text });
|
|
3081
|
+
}
|
|
3082
|
+
asMemberRead(match.node, parameter, match.property);
|
|
3083
|
+
}
|
|
3084
|
+
}
|
|
3085
|
+
return { edits, diagnostics, used };
|
|
3086
|
+
}
|
|
3087
|
+
function asMemberRead(node, parameter, property) {
|
|
3088
|
+
node.type = "MemberExpression";
|
|
3089
|
+
node.computed = false;
|
|
3090
|
+
node.optional = false;
|
|
3091
|
+
node.object = { type: "Identifier", name: parameter, start: node.start, end: node.start };
|
|
3092
|
+
node.property = { type: "Identifier", name: property, start: node.end, end: node.end };
|
|
3093
|
+
delete node["name"];
|
|
3094
|
+
}
|
|
3095
|
+
function transformProps(code, filename = "module.tsx", options = {}) {
|
|
3096
|
+
const ast = (0, import_parser.parse)(code, {
|
|
3097
|
+
sourceType: "module",
|
|
3098
|
+
plugins: ["typescript", "jsx"],
|
|
3099
|
+
errorRecovery: true
|
|
3100
|
+
});
|
|
3101
|
+
const { edits, diagnostics, used } = collectPropsEdits(ast.program, code, options);
|
|
3102
|
+
const source = new import_magic_string.default(code);
|
|
3103
|
+
for (const e of edits) {
|
|
3104
|
+
if (e.start === e.end) source.appendLeft(e.start, e.code);
|
|
3105
|
+
else source.overwrite(e.start, e.end, e.code);
|
|
3106
|
+
}
|
|
3107
|
+
if (used.has("splitProps") && !moduleBindings(ast.program).has("splitProps")) {
|
|
3108
|
+
source.prepend(`import { splitProps } from ${JSON.stringify(options.runtimeModule ?? "@fluixi/dom")};
|
|
3109
|
+
`);
|
|
3110
|
+
}
|
|
3111
|
+
return {
|
|
3112
|
+
code: source.toString(),
|
|
3113
|
+
map: source.generateMap({ source: filename, includeContent: true, hires: true }),
|
|
3114
|
+
diagnostics,
|
|
3115
|
+
rewritten: edits.filter((e) => e.code !== (options.parameterName ?? "props")).length
|
|
3116
|
+
};
|
|
3117
|
+
}
|
|
3118
|
+
var import_parser, import_magic_string;
|
|
3119
|
+
var init_props = __esm({
|
|
3120
|
+
"src/transform/props.ts"() {
|
|
3121
|
+
"use strict";
|
|
3122
|
+
import_parser = require("@babel/parser");
|
|
3123
|
+
import_magic_string = __toESM(require("magic-string"), 1);
|
|
3124
|
+
init_props_destructure();
|
|
3125
|
+
init_bindings();
|
|
3126
|
+
}
|
|
3127
|
+
});
|
|
3128
|
+
|
|
3129
|
+
// src/transform/intrinsics.ts
|
|
3130
|
+
function walk6(root, visit) {
|
|
3131
|
+
if (!root || typeof root !== "object" || typeof root.type !== "string") return;
|
|
3132
|
+
visit(root);
|
|
3133
|
+
for (const key of Object.keys(root)) {
|
|
3134
|
+
if (key === "loc" || key === "leadingComments" || key === "trailingComments") continue;
|
|
3135
|
+
const value = root[key];
|
|
3136
|
+
if (Array.isArray(value)) for (const item of value) walk6(item, visit);
|
|
3137
|
+
else if (value && typeof value === "object") walk6(value, visit);
|
|
3138
|
+
}
|
|
3139
|
+
}
|
|
3140
|
+
function collectIntrinsicEdits(program) {
|
|
3141
|
+
const edits = [];
|
|
3142
|
+
const diagnostics = [];
|
|
3143
|
+
const imports = /* @__PURE__ */ new Map();
|
|
3144
|
+
const reported2 = /* @__PURE__ */ new Set();
|
|
3145
|
+
const { shadowed } = resolveReactiveBindings(program);
|
|
3146
|
+
walk6(program, (node) => {
|
|
3147
|
+
if (node.type !== "CallExpression") return;
|
|
3148
|
+
const callee = node.callee;
|
|
3149
|
+
if (callee?.type !== "Identifier") return;
|
|
3150
|
+
const name = callee.name;
|
|
3151
|
+
if (!isIntrinsicName(name)) return;
|
|
3152
|
+
if (shadowed.has(name)) {
|
|
3153
|
+
if (!reported2.has(name)) {
|
|
3154
|
+
reported2.add(name);
|
|
3155
|
+
diagnostics.push({
|
|
3156
|
+
name,
|
|
3157
|
+
message: `${name} is reserved for the compiler, and this module binds it. The call keeps your binding's meaning; rename it to use the intrinsic.`,
|
|
3158
|
+
start: callee.start
|
|
3159
|
+
});
|
|
3160
|
+
}
|
|
3161
|
+
return;
|
|
3162
|
+
}
|
|
3163
|
+
const intrinsic = INTRINSICS[name];
|
|
3164
|
+
edits.push({ start: callee.start, end: callee.end, code: intrinsic.export });
|
|
3165
|
+
const forModule = imports.get(intrinsic.module) ?? /* @__PURE__ */ new Set();
|
|
3166
|
+
forModule.add(intrinsic.export);
|
|
3167
|
+
imports.set(intrinsic.module, forModule);
|
|
3168
|
+
});
|
|
3169
|
+
return { edits, diagnostics, imports };
|
|
3170
|
+
}
|
|
3171
|
+
function intrinsicImports(result, bound) {
|
|
3172
|
+
const lines = [];
|
|
3173
|
+
for (const [module2, names] of [...result.imports].sort(([a], [b]) => a.localeCompare(b))) {
|
|
3174
|
+
const wanted = [...names].filter((name) => !bound.has(name)).sort();
|
|
3175
|
+
if (wanted.length) lines.push(`import { ${wanted.join(", ")} } from ${JSON.stringify(module2)};`);
|
|
3176
|
+
}
|
|
3177
|
+
return lines.length ? `${lines.join("\n")}
|
|
3178
|
+
` : "";
|
|
3179
|
+
}
|
|
3180
|
+
var init_intrinsics2 = __esm({
|
|
3181
|
+
"src/transform/intrinsics.ts"() {
|
|
3182
|
+
"use strict";
|
|
3183
|
+
init_intrinsics();
|
|
3184
|
+
init_reactive_bindings();
|
|
3185
|
+
}
|
|
3186
|
+
});
|
|
3187
|
+
|
|
3188
|
+
// src/transform/templates.ts
|
|
3189
|
+
function walk7(node, visit, parent = null, key = "") {
|
|
3190
|
+
if (!node || typeof node !== "object") return;
|
|
3191
|
+
if (Array.isArray(node)) {
|
|
3192
|
+
for (const child of node) walk7(child, visit, parent, key);
|
|
3193
|
+
return;
|
|
3194
|
+
}
|
|
3195
|
+
if (typeof node.type === "string") visit(node, parent, key);
|
|
3196
|
+
for (const k of Object.keys(node)) {
|
|
3197
|
+
if (k === "loc" || k === "leadingComments" || k === "trailingComments") continue;
|
|
3198
|
+
walk7(node[k], visit, typeof node.type === "string" ? node : parent, k);
|
|
3199
|
+
}
|
|
3200
|
+
}
|
|
3201
|
+
function isJsxRoot(node, parent, key) {
|
|
3202
|
+
if (!isJsx(node)) return false;
|
|
3203
|
+
return !(parent && isJsx(parent) && key === "children");
|
|
3204
|
+
}
|
|
3205
|
+
function isTemplateTag(node, litTag) {
|
|
3206
|
+
return node.type === "TaggedTemplateExpression" && node.tag?.type === "Identifier" && (node.tag.name === litTag || node.tag.name === "svg");
|
|
3207
|
+
}
|
|
3208
|
+
function outermost(list) {
|
|
3209
|
+
return list.filter(
|
|
3210
|
+
(e) => !list.some(
|
|
3211
|
+
(o) => o !== e && o.start <= e.start && o.end >= e.end && o.end - o.start > e.end - e.start && // An insertion at either edge of the container sits beside it, not inside it, so
|
|
3212
|
+
// it is not something the container's code already folded in. A statement can
|
|
3213
|
+
// start where its callee starts (`$effect(…)`) and a declarator can end where its
|
|
3214
|
+
// JSX ends (`const Row = () => <b/>`).
|
|
3215
|
+
!(e.start === e.end && (e.start === o.start || e.start === o.end))
|
|
3216
|
+
)
|
|
3217
|
+
);
|
|
3218
|
+
}
|
|
3219
|
+
function slice(code, start, end, edits) {
|
|
3220
|
+
const inside = outermost(edits.filter((e) => e.start >= start && e.end <= end)).sort((a, b) => b.start - a.start);
|
|
3221
|
+
let out = code.slice(start, end);
|
|
3222
|
+
for (const e of inside) out = out.slice(0, e.start - start) + e.code + out.slice(e.end - start);
|
|
3223
|
+
return out;
|
|
3224
|
+
}
|
|
3225
|
+
function bindHole2(code, expr, edits, keepPosition = false) {
|
|
3226
|
+
const at = keepPosition ? expr.loc?.start : void 0;
|
|
3227
|
+
const hole = {
|
|
3228
|
+
code: slice(code, expr.start, expr.end, edits),
|
|
3229
|
+
reactive: isReactiveShape(shapeOf(expr)),
|
|
3230
|
+
// Where the `${…}` is, so a binding made from it can say so. The source map cannot:
|
|
3231
|
+
// the whole template is one overwrite. Only when source locations were asked for.
|
|
3232
|
+
...at ? { at: { line: at.line, column: at.column } } : {}
|
|
3233
|
+
};
|
|
3234
|
+
if (expr.type === "ArrowFunctionExpression" && expr.body?.type !== "BlockStatement") {
|
|
3235
|
+
hole.arrow = {
|
|
3236
|
+
params: expr.params.map((p) => slice(code, p.start, p.end, edits)),
|
|
3237
|
+
body: slice(code, expr.body.start, expr.body.end, edits),
|
|
3238
|
+
bodyReactive: isReactiveShape(shapeOf(expr.body))
|
|
3239
|
+
};
|
|
3240
|
+
}
|
|
3241
|
+
if (expr.type === "ObjectExpression") hole.object = true;
|
|
3242
|
+
return hole;
|
|
3243
|
+
}
|
|
3244
|
+
function adoptTemplates2(code, templates, hoisted) {
|
|
3245
|
+
if (!templates || templates.length === 0) return code;
|
|
3246
|
+
const rename = /* @__PURE__ */ new Map();
|
|
3247
|
+
for (const tpl of templates) {
|
|
3248
|
+
const key = `${tpl.svg ? "svg:" : ""}${tpl.html}`;
|
|
3249
|
+
let name = hoisted.get(key);
|
|
3250
|
+
if (!name) {
|
|
3251
|
+
name = `_fxTmpl$${hoisted.size}`;
|
|
3252
|
+
hoisted.set(key, name);
|
|
3253
|
+
}
|
|
3254
|
+
rename.set(tpl.id, name);
|
|
3255
|
+
}
|
|
3256
|
+
return code.replace(/_tmpl\$\d+/g, (id) => rename.get(id) ?? id);
|
|
3257
|
+
}
|
|
3258
|
+
function collectNeeds(node, out) {
|
|
3259
|
+
if (node.kind === "component" && node.load && !node.source && isDeferred(node.load)) {
|
|
3260
|
+
if (!out.ignoredLoad.has(node.name)) out.ignoredLoad.set(node.name, node.load);
|
|
3261
|
+
}
|
|
3262
|
+
if (node.kind === "component" && node.source) {
|
|
3263
|
+
const src = node.source;
|
|
3264
|
+
if (src.origin === "builtin") out.builtins.add(node.name);
|
|
3265
|
+
else if (isDeferred(src.loading) && !out.resolved.has(node.name)) out.deferred.set(node.name, src);
|
|
3266
|
+
else {
|
|
3267
|
+
out.deferred.delete(node.name);
|
|
3268
|
+
out.resolved.set(node.name, src);
|
|
3269
|
+
}
|
|
3270
|
+
}
|
|
3271
|
+
if ("props" in node && node.props) {
|
|
3272
|
+
for (const p of node.props) {
|
|
3273
|
+
if (p.kind === "event" && p.event?.delegated) out.delegatedEvents.add(p.event.name);
|
|
3274
|
+
}
|
|
3275
|
+
}
|
|
3276
|
+
if ("children" in node && node.children) for (const c of node.children) collectNeeds(c, out);
|
|
3277
|
+
}
|
|
3278
|
+
function deferrableImport(program, name) {
|
|
3279
|
+
for (const statement of program.body ?? []) {
|
|
3280
|
+
if (statement.type !== "ImportDeclaration") continue;
|
|
3281
|
+
for (const specifier of statement.specifiers ?? []) {
|
|
3282
|
+
if (specifier.local?.name !== name) continue;
|
|
3283
|
+
if (specifier.type === "ImportNamespaceSpecifier") return void 0;
|
|
3284
|
+
const exported = specifier.type === "ImportDefaultSpecifier" ? "default" : specifier.imported?.name ?? specifier.imported?.value;
|
|
3285
|
+
return { module: statement.source.value, export: exported, declaration: statement, specifier };
|
|
3286
|
+
}
|
|
3287
|
+
}
|
|
3288
|
+
return void 0;
|
|
3289
|
+
}
|
|
3290
|
+
function hasNamespaceImport(program, name) {
|
|
3291
|
+
for (const statement of program.body ?? []) {
|
|
3292
|
+
if (statement.type !== "ImportDeclaration") continue;
|
|
3293
|
+
for (const specifier of statement.specifiers ?? []) {
|
|
3294
|
+
if (specifier.type === "ImportNamespaceSpecifier" && specifier.local?.name === name) return true;
|
|
3295
|
+
}
|
|
3296
|
+
}
|
|
3297
|
+
return false;
|
|
3298
|
+
}
|
|
3299
|
+
function usedAsValue(program, name, specifier) {
|
|
3300
|
+
let seen = false;
|
|
3301
|
+
walk7(program, (node) => {
|
|
3302
|
+
if (seen || node.type !== "Identifier" || node.name !== name) return;
|
|
3303
|
+
if (node.start === specifier.local?.start && node.end === specifier.local?.end) return;
|
|
3304
|
+
seen = true;
|
|
3305
|
+
});
|
|
3306
|
+
return seen;
|
|
3307
|
+
}
|
|
3308
|
+
function strategyLiteral2(s) {
|
|
3309
|
+
const parts = [`kind: ${JSON.stringify(s.kind)}`];
|
|
3310
|
+
if (s.kind === "visible" && s.rootMargin) parts.push(`rootMargin: ${JSON.stringify(s.rootMargin)}`);
|
|
3311
|
+
if (s.kind === "interaction") parts.push(`events: ${JSON.stringify(s.events)}`);
|
|
3312
|
+
if (s.kind === "media") parts.push(`query: ${JSON.stringify(s.query)}`);
|
|
3313
|
+
return `{ ${parts.join(", ")} }`;
|
|
3314
|
+
}
|
|
3315
|
+
function positionsIn(code) {
|
|
3316
|
+
const starts = [0];
|
|
3317
|
+
for (let i = 0; i < code.length; i++) if (code.charCodeAt(i) === 10) starts.push(i + 1);
|
|
3318
|
+
return (offset) => {
|
|
3319
|
+
let low = 0;
|
|
3320
|
+
let high = starts.length - 1;
|
|
3321
|
+
while (low < high) {
|
|
3322
|
+
const mid = low + high + 1 >> 1;
|
|
3323
|
+
if (starts[mid] <= offset) low = mid;
|
|
3324
|
+
else high = mid - 1;
|
|
3325
|
+
}
|
|
3326
|
+
return { line: low + 1, column: offset - starts[low] };
|
|
3327
|
+
};
|
|
3328
|
+
}
|
|
3329
|
+
function toPieces(node) {
|
|
3330
|
+
const pieces = [];
|
|
3331
|
+
node.quasi.quasis.forEach((q, i) => {
|
|
3332
|
+
pieces.push({ kind: "static", text: q.value.cooked ?? q.value.raw, start: q.start });
|
|
3333
|
+
if (i < node.quasi.expressions.length) {
|
|
3334
|
+
const e = node.quasi.expressions[i];
|
|
3335
|
+
pieces.push({ kind: "hole", index: i, start: e.start, end: e.end });
|
|
3336
|
+
}
|
|
3337
|
+
});
|
|
3338
|
+
return pieces;
|
|
3339
|
+
}
|
|
3340
|
+
function relativeToRoot(id, root) {
|
|
3341
|
+
if (!root) return id;
|
|
3342
|
+
const base = root.endsWith("/") ? root : `${root}/`;
|
|
3343
|
+
return id.startsWith(base) ? id.slice(base.length) : id;
|
|
3344
|
+
}
|
|
3345
|
+
function transformTemplates(code, id, options = {}) {
|
|
3346
|
+
const litTag = options.litTag ?? "html";
|
|
3347
|
+
const format = options.format ?? "both";
|
|
3348
|
+
const wantsLit = format !== "jsx";
|
|
3349
|
+
const wantsJsx = format !== "lit";
|
|
3350
|
+
const mayHaveTemplate = wantsLit && (code.includes(`${litTag}\``) || code.includes("svg`"));
|
|
3351
|
+
const wantsIntrinsics = options.intrinsics !== false && mayHaveIntrinsic(code);
|
|
3352
|
+
const wantsSources = options.sourceLocations === true && mayHaveReactiveCall(code);
|
|
3353
|
+
const sourceName = relativeToRoot(id, options.sourceRoot);
|
|
3354
|
+
if (!mayHaveTemplate && !(wantsJsx && code.includes("<")) && !wantsIntrinsics && !wantsSources) return null;
|
|
3355
|
+
const ast = (0, import_parser2.parse)(code, {
|
|
3356
|
+
sourceType: "module",
|
|
3357
|
+
plugins: ["jsx", "typescript"],
|
|
3358
|
+
errorRecovery: true
|
|
3359
|
+
});
|
|
3360
|
+
const found = [];
|
|
3361
|
+
walk7(ast.program, (n, parent, key) => {
|
|
3362
|
+
if (wantsLit && isTemplateTag(n, litTag)) found.push(n);
|
|
3363
|
+
else if (wantsJsx && isJsxRoot(n, parent, key)) found.push(n);
|
|
3364
|
+
});
|
|
3365
|
+
const props = options.propsDestructure === false ? { edits: [], diagnostics: [], used: /* @__PURE__ */ new Set() } : collectPropsEdits(ast.program, code, { runtimeModule: options.runtimeModule });
|
|
3366
|
+
const intrinsics = options.intrinsics === false ? { edits: [], diagnostics: [], imports: /* @__PURE__ */ new Map() } : collectIntrinsicEdits(ast.program);
|
|
3367
|
+
const sources = options.sourceLocations === true ? collectSourceEdits(ast.program, sourceName) : { edits: [], marked: 0 };
|
|
3368
|
+
const silent = found.length === 0 && props.edits.length === 0 && sources.edits.length === 0 && intrinsics.edits.length === 0 && intrinsics.diagnostics.length === 0 && props.diagnostics.length === 0;
|
|
3369
|
+
if (silent) return null;
|
|
3370
|
+
found.sort((a, b) => b.start - a.start || a.end - b.end);
|
|
3371
|
+
const used = new Set(props.used);
|
|
3372
|
+
const needs = {
|
|
3373
|
+
builtins: /* @__PURE__ */ new Set(),
|
|
3374
|
+
resolved: /* @__PURE__ */ new Map(),
|
|
3375
|
+
deferred: /* @__PURE__ */ new Map(),
|
|
3376
|
+
delegatedEvents: /* @__PURE__ */ new Set(),
|
|
3377
|
+
ignoredLoad: /* @__PURE__ */ new Map(),
|
|
3378
|
+
unresolved: /* @__PURE__ */ new Set(),
|
|
3379
|
+
declared: declaredNames(ast.program)
|
|
3380
|
+
};
|
|
3381
|
+
const hoisted = /* @__PURE__ */ new Map();
|
|
3382
|
+
const edits = [...props.edits, ...intrinsics.edits, ...sources.edits];
|
|
3383
|
+
for (const node of found) {
|
|
3384
|
+
const nested = found.some(
|
|
3385
|
+
(o) => o !== node && o.start <= node.start && o.end >= node.end && o.end - o.start > node.end - node.start
|
|
3386
|
+
);
|
|
3387
|
+
if (isJsx(node)) {
|
|
3388
|
+
edits.push({ start: node.start, end: node.end, code: compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceName) });
|
|
3389
|
+
continue;
|
|
3390
|
+
}
|
|
3391
|
+
const holes = node.quasi.expressions.map(
|
|
3392
|
+
(e) => bindHole2(code, e, edits, options.sourceLocations === true)
|
|
3393
|
+
);
|
|
3394
|
+
const result = compilePieces(toPieces(node), holes, {
|
|
3395
|
+
...options,
|
|
3396
|
+
hoistTemplates: true,
|
|
3397
|
+
// A tag inside a template gets the same mark a JSX tag does. Without one, the nodes it
|
|
3398
|
+
// makes are the only ones in the module carrying no mark, and they take whichever was
|
|
3399
|
+
// left behind by the last declaration that did.
|
|
3400
|
+
...options.sourceLocations === true ? { sourceFile: sourceName, positionAt: positionsIn(code) } : {},
|
|
3401
|
+
// Same defaults as the plugin, so moving a build over is not a rendering change.
|
|
3402
|
+
templateClone: options.templateClone ?? true,
|
|
3403
|
+
partialTemplates: nested ? false : options.partialTemplates ?? true,
|
|
3404
|
+
svg: node.tag.name === "svg"
|
|
3405
|
+
});
|
|
3406
|
+
for (const symbol of result.imports) used.add(symbol);
|
|
3407
|
+
collectNeeds(result.ir, needs);
|
|
3408
|
+
edits.push({ start: node.start, end: node.end, code: adoptTemplates2(result.code, result.templates, hoisted) });
|
|
3409
|
+
}
|
|
3410
|
+
const out = new import_magic_string2.default(code);
|
|
3411
|
+
for (const e of outermost(edits)) {
|
|
3412
|
+
if (e.start === e.end) out.appendLeft(e.start, e.code);
|
|
3413
|
+
else out.overwrite(e.start, e.end, e.code);
|
|
3414
|
+
}
|
|
3415
|
+
const bound = moduleBindings(ast.program);
|
|
3416
|
+
const why = /* @__PURE__ */ new Map();
|
|
3417
|
+
for (const [name] of needs.ignoredLoad) {
|
|
3418
|
+
if (!bound.has(name)) why.set(name, "unsupplied");
|
|
3419
|
+
}
|
|
3420
|
+
for (const [name, strategy] of [...needs.ignoredLoad]) {
|
|
3421
|
+
if (!bound.has(name)) continue;
|
|
3422
|
+
const found2 = deferrableImport(ast.program, name);
|
|
3423
|
+
if (!found2) {
|
|
3424
|
+
why.set(name, hasNamespaceImport(ast.program, name) ? "namespace" : "local");
|
|
3425
|
+
continue;
|
|
3426
|
+
}
|
|
3427
|
+
if (usedAsValue(ast.program, name, found2.specifier)) {
|
|
3428
|
+
why.set(name, "value");
|
|
3429
|
+
continue;
|
|
3430
|
+
}
|
|
3431
|
+
const rest = found2.declaration.specifiers.filter((sp) => sp !== found2.specifier);
|
|
3432
|
+
const end = rest.length === 0 && code[found2.declaration.end] === "\n" ? found2.declaration.end + 1 : found2.declaration.end;
|
|
3433
|
+
out.overwrite(
|
|
3434
|
+
found2.declaration.start,
|
|
3435
|
+
end,
|
|
3436
|
+
rest.length === 0 ? "" : `import { ${rest.map((sp) => code.slice(sp.start, sp.end)).join(", ")} } from ${JSON.stringify(found2.declaration.source.value)};`
|
|
3437
|
+
);
|
|
3438
|
+
needs.deferred.set(name, { module: found2.module, export: found2.export, origin: "rule", loading: strategy });
|
|
3439
|
+
bound.delete(name);
|
|
3440
|
+
needs.ignoredLoad.delete(name);
|
|
3441
|
+
}
|
|
3442
|
+
const prologue = buildPrologue(used, needs, hoisted, bound, options);
|
|
3443
|
+
if (prologue) out.prepend(prologue);
|
|
3444
|
+
const runtimeImports = intrinsicImports(intrinsics, bound);
|
|
3445
|
+
if (runtimeImports) out.prepend(runtimeImports);
|
|
3446
|
+
const reasons = {
|
|
3447
|
+
value: (name) => `${name} is used as a value here, not only as a tag, so its import has to stay — deferring would hand those references a lazy wrapper instead of the component. Defer it at the point it is rendered, or keep it eager.`,
|
|
3448
|
+
namespace: (name) => `${name} came in through a namespace import, which has no single export to defer. Import ${name} by name.`,
|
|
3449
|
+
local: (name) => `${name} is declared in this file, so there is no module to load separately. Move it to its own file and import it.`,
|
|
3450
|
+
unsupplied: (name) => `nothing supplies ${name}, so there is no import to defer. Import it, or add a \`resolve\` rule for it.`
|
|
3451
|
+
};
|
|
3452
|
+
const loadDiagnostics = [...needs.ignoredLoad].map(([name, strategy]) => ({
|
|
3453
|
+
name,
|
|
3454
|
+
strategy,
|
|
3455
|
+
message: `load:${strategy.kind} has no effect on <${name}>: ${reasons[why.get(name) ?? "unsupplied"](name)}`
|
|
3456
|
+
}));
|
|
3457
|
+
const unresolvedDiagnostics = [...needs.unresolved].map((name) => ({
|
|
3458
|
+
name,
|
|
3459
|
+
message: `<${name}> is not defined: nothing imports it and no \`resolve\` rule supplies it. This compiles to a reference to a name that does not exist, so the component renders nothing. Import ${name}, or add a \`resolve\` rule for it.`
|
|
3460
|
+
}));
|
|
3461
|
+
return {
|
|
3462
|
+
code: out.toString(),
|
|
3463
|
+
map: out.generateMap({ source: id, includeContent: true, hires: true }),
|
|
3464
|
+
...loadDiagnostics.length ? { loadDiagnostics } : {},
|
|
3465
|
+
...unresolvedDiagnostics.length ? { unresolvedDiagnostics } : {},
|
|
3466
|
+
...props.diagnostics.length ? { propsDiagnostics: props.diagnostics } : {},
|
|
3467
|
+
...intrinsics.diagnostics.length ? { intrinsicDiagnostics: intrinsics.diagnostics } : {}
|
|
3468
|
+
};
|
|
3469
|
+
}
|
|
3470
|
+
function compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceFile) {
|
|
3471
|
+
const ir = buildJsxIR(node, {
|
|
3472
|
+
code: (n) => slice(code, n.start, n.end, edits),
|
|
3473
|
+
used,
|
|
3474
|
+
...options.sourceLocations === true && sourceFile ? { sourceFile } : {}
|
|
3475
|
+
});
|
|
3476
|
+
analyzeStatic(ir);
|
|
3477
|
+
const report = resolveComponentSources(ir, {
|
|
3478
|
+
resolver: createComponentResolver(options.resolve ?? []),
|
|
3479
|
+
// Without this the pass calls every author-imported component unresolved, and the
|
|
3480
|
+
// report is unusable for diagnostics.
|
|
3481
|
+
isBound: (name) => needs.declared.has(name),
|
|
3482
|
+
modules: {
|
|
3483
|
+
controlFlowModule: options.controlFlowModule ?? options.runtimeModule ?? "@fluixi/dom",
|
|
3484
|
+
coreModule: options.coreModule ?? "@fluixi/core",
|
|
3485
|
+
routerModule: options.routerModule ?? "@fluixi/core/router"
|
|
3486
|
+
},
|
|
3487
|
+
strategyFor: (n) => n.load
|
|
3488
|
+
});
|
|
3489
|
+
for (const name of report.unresolved) needs.unresolved.add(name);
|
|
3490
|
+
collapseStrategies(ir);
|
|
3491
|
+
const emitted = imperativeBackend.emit(ir, {
|
|
3492
|
+
templateClone: options.templateClone ?? true,
|
|
3493
|
+
partialTemplates: nested ? false : options.partialTemplates ?? true
|
|
3494
|
+
});
|
|
3495
|
+
for (const symbol of emitted.imports) used.add(symbol);
|
|
3496
|
+
collectNeeds(ir, needs);
|
|
3497
|
+
return adoptTemplates2(emitted.code, emitted.templates, hoisted);
|
|
3498
|
+
}
|
|
3499
|
+
function buildPrologue(used, needs, hoisted, bound, options) {
|
|
3500
|
+
const runtime = options.runtimeModule ?? "@fluixi/dom";
|
|
3501
|
+
const core = options.coreModule ?? "@fluixi/core";
|
|
3502
|
+
const groups = /* @__PURE__ */ new Map();
|
|
3503
|
+
const add = (mod, name) => groups.set(mod, [...groups.get(mod) ?? [], name]);
|
|
3504
|
+
const wanted = new Set(used);
|
|
3505
|
+
for (const name of needs.builtins) wanted.add(name);
|
|
3506
|
+
if (needs.delegatedEvents.size > 0) wanted.add("delegateEvents");
|
|
3507
|
+
for (const name of [...wanted].sort()) {
|
|
3508
|
+
if (bound.has(name)) continue;
|
|
3509
|
+
if (REACTIVE.has(name)) add(options.reactiveModule ?? "@fluixi/reactive/signal", name);
|
|
3510
|
+
else if (ROUTER.has(name)) add(options.routerModule ?? "@fluixi/core/router", name);
|
|
3511
|
+
else if (CORE_ONLY.has(name)) add(core, name);
|
|
3512
|
+
else if (CONTROL_FLOW.has(name)) add(options.controlFlowModule ?? runtime, name);
|
|
3513
|
+
else add(runtime, name);
|
|
3514
|
+
}
|
|
3515
|
+
for (const [name, src] of needs.resolved) {
|
|
3516
|
+
if (!bound.has(name)) add(src.module, src.export === "default" ? `default as ${name}` : name === src.export ? name : `${src.export} as ${name}`);
|
|
3517
|
+
}
|
|
3518
|
+
const lines = [];
|
|
3519
|
+
for (const [mod, names] of groups) {
|
|
3520
|
+
lines.push(`import { ${names.join(", ")} } from ${JSON.stringify(mod)};`);
|
|
3521
|
+
}
|
|
3522
|
+
const lazy = [...needs.deferred].filter(([name]) => !bound.has(name));
|
|
3523
|
+
if (lazy.length > 0) {
|
|
3524
|
+
if (!bound.has("deferred")) lines.push(`import { deferred } from ${JSON.stringify(core)};`);
|
|
3525
|
+
for (const [name, src] of lazy) {
|
|
3526
|
+
lines.push(
|
|
3527
|
+
`const ${name} = deferred(() => import(${JSON.stringify(src.module)}), { strategy: ${strategyLiteral2(src.loading)}, export: ${JSON.stringify(src.export)} });`
|
|
3528
|
+
);
|
|
3529
|
+
}
|
|
3530
|
+
}
|
|
3531
|
+
for (const [key, name] of hoisted) {
|
|
3532
|
+
lines.push(`const ${name} = ${JSON.stringify(key.startsWith("svg:") ? key.slice(4) : key)};`);
|
|
3533
|
+
}
|
|
3534
|
+
if (needs.delegatedEvents.size > 0) {
|
|
3535
|
+
lines.push(`delegateEvents(${JSON.stringify([...needs.delegatedEvents])});`);
|
|
3536
|
+
}
|
|
3537
|
+
return lines.length > 0 ? lines.join("\n") + "\n" : null;
|
|
3538
|
+
}
|
|
3539
|
+
var import_parser2, import_magic_string2, CONTROL_FLOW, CORE_ONLY, ROUTER, REACTIVE, isJsx;
|
|
3540
|
+
var init_templates = __esm({
|
|
3541
|
+
"src/transform/templates.ts"() {
|
|
3542
|
+
"use strict";
|
|
3543
|
+
import_parser2 = require("@babel/parser");
|
|
3544
|
+
import_magic_string2 = __toESM(require("magic-string"), 1);
|
|
3545
|
+
init_compile_template();
|
|
3546
|
+
init_load_directive();
|
|
3547
|
+
init_reactive_expr();
|
|
3548
|
+
init_expr_shape();
|
|
3549
|
+
init_jsx();
|
|
3550
|
+
init_analyze_static();
|
|
3551
|
+
init_collapse_strategies();
|
|
3552
|
+
init_resolve_ir();
|
|
3553
|
+
init_component_resolver();
|
|
3554
|
+
init_imperative();
|
|
3555
|
+
init_bindings();
|
|
3556
|
+
init_props();
|
|
3557
|
+
init_intrinsics2();
|
|
3558
|
+
init_source_locations();
|
|
3559
|
+
init_intrinsics();
|
|
3560
|
+
init_reactive_bindings();
|
|
3561
|
+
init_builtins();
|
|
3562
|
+
CONTROL_FLOW = new Set(DOM_CONTROL_FLOW);
|
|
3563
|
+
CORE_ONLY = new Set(CORE_CONTROL_FLOW);
|
|
3564
|
+
ROUTER = new Set(ROUTER_COMPONENTS);
|
|
3565
|
+
REACTIVE = /* @__PURE__ */ new Set([
|
|
3566
|
+
"createMemo",
|
|
3567
|
+
"createEffect",
|
|
3568
|
+
"createRenderEffect",
|
|
3569
|
+
"createRoot",
|
|
3570
|
+
"createSignal",
|
|
3571
|
+
"onCleanup",
|
|
3572
|
+
"batch",
|
|
3573
|
+
"untrack"
|
|
3574
|
+
]);
|
|
3575
|
+
isJsx = (node) => node.type === "JSXElement" || node.type === "JSXFragment";
|
|
3576
|
+
}
|
|
3577
|
+
});
|
|
3578
|
+
|
|
3579
|
+
// src/transform/index.ts
|
|
3580
|
+
var transform_exports = {};
|
|
3581
|
+
__export(transform_exports, {
|
|
3582
|
+
explainBail: () => explainBail,
|
|
3583
|
+
moduleBindings: () => moduleBindings,
|
|
3584
|
+
planPropsDestructure: () => planPropsDestructure,
|
|
3585
|
+
shapeOf: () => shapeOf,
|
|
3586
|
+
transformProps: () => transformProps,
|
|
3587
|
+
transformTemplates: () => transformTemplates
|
|
3588
|
+
});
|
|
3589
|
+
var init_transform = __esm({
|
|
3590
|
+
"src/transform/index.ts"() {
|
|
3591
|
+
"use strict";
|
|
3592
|
+
init_templates();
|
|
3593
|
+
init_bindings();
|
|
3594
|
+
init_expr_shape();
|
|
3595
|
+
init_props();
|
|
3596
|
+
init_props_destructure();
|
|
3597
|
+
}
|
|
3598
|
+
});
|
|
3599
|
+
|
|
3600
|
+
// src/transform/server-fn-id.ts
|
|
3601
|
+
function hash(s) {
|
|
3602
|
+
let h = 5381;
|
|
3603
|
+
for (let i = 0; i < s.length; i++) h = h * 33 ^ s.charCodeAt(i);
|
|
3604
|
+
return (h >>> 0).toString(16);
|
|
3605
|
+
}
|
|
3606
|
+
function serverFnId(filename, root, index) {
|
|
3607
|
+
const rel = (filename || "unknown").replace(root ? root + "/" : "", "");
|
|
3608
|
+
return `${hash(rel)}:${index}`;
|
|
3609
|
+
}
|
|
3610
|
+
var init_server_fn_id = __esm({
|
|
3611
|
+
"src/transform/server-fn-id.ts"() {
|
|
3612
|
+
"use strict";
|
|
3613
|
+
}
|
|
3614
|
+
});
|
|
3615
|
+
|
|
3616
|
+
// src/frontend/babel/server-functions.ts
|
|
3617
|
+
var server_functions_exports = {};
|
|
3618
|
+
__export(server_functions_exports, {
|
|
3619
|
+
transformServerFunctions: () => transformServerFunctions
|
|
3620
|
+
});
|
|
3621
|
+
function serverFunctionsBabelPlugin({ types: t4 }) {
|
|
3622
|
+
return {
|
|
3623
|
+
name: "fluixi-server-functions",
|
|
3624
|
+
visitor: {
|
|
3625
|
+
Program: {
|
|
3626
|
+
enter(_path, state) {
|
|
3627
|
+
state.fxIndex = 0;
|
|
3628
|
+
state.fxUsed = null;
|
|
3629
|
+
},
|
|
3630
|
+
exit(path, state) {
|
|
3631
|
+
if (!state.fxUsed) return;
|
|
3632
|
+
path.unshiftContainer(
|
|
3633
|
+
"body",
|
|
3634
|
+
t4.importDeclaration(
|
|
3635
|
+
[t4.importSpecifier(t4.identifier(state.fxUsed), t4.identifier(state.fxUsed))],
|
|
3636
|
+
t4.stringLiteral(state.opts.runtimeModule || RUNTIME)
|
|
3637
|
+
)
|
|
3638
|
+
);
|
|
3639
|
+
}
|
|
3640
|
+
},
|
|
3641
|
+
"FunctionDeclaration|FunctionExpression|ArrowFunctionExpression": (path, state) => {
|
|
3642
|
+
const body = path.node.body;
|
|
3643
|
+
if (!t4.isBlockStatement(body)) return;
|
|
3644
|
+
const dirs = body.directives || [];
|
|
3645
|
+
const di = dirs.findIndex((d) => d.value.value === "use server");
|
|
3646
|
+
if (di < 0) return;
|
|
3647
|
+
body.directives.splice(di, 1);
|
|
3648
|
+
const id = serverFnId(
|
|
3649
|
+
state.opts.filename || state.filename || "unknown",
|
|
3650
|
+
state.opts.root,
|
|
3651
|
+
state.fxIndex++
|
|
3652
|
+
);
|
|
3653
|
+
const ssr = !!state.opts.ssr;
|
|
3654
|
+
const helper = ssr ? "$$registerServerFn" : "$$createServerReference";
|
|
3655
|
+
state.fxUsed = helper;
|
|
3656
|
+
const replacement = ssr ? t4.callExpression(t4.identifier(helper), [
|
|
3657
|
+
t4.stringLiteral(id),
|
|
3658
|
+
path.isFunctionDeclaration() ? t4.functionExpression(
|
|
3659
|
+
null,
|
|
3660
|
+
path.node.params,
|
|
3661
|
+
body,
|
|
3662
|
+
path.node.generator,
|
|
3663
|
+
path.node.async
|
|
3664
|
+
) : path.node
|
|
3665
|
+
]) : t4.callExpression(t4.identifier(helper), [t4.stringLiteral(id)]);
|
|
3666
|
+
if (path.isFunctionDeclaration()) {
|
|
3667
|
+
path.replaceWith(
|
|
3668
|
+
t4.variableDeclaration("const", [t4.variableDeclarator(path.node.id, replacement)])
|
|
3669
|
+
);
|
|
3670
|
+
} else {
|
|
3671
|
+
path.replaceWith(replacement);
|
|
3672
|
+
}
|
|
3673
|
+
path.skip();
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3676
|
+
};
|
|
3677
|
+
}
|
|
3678
|
+
function transformServerFunctions(code, opts) {
|
|
3679
|
+
if (!code.includes("use server")) return null;
|
|
3680
|
+
const result = (0, import_core4.transformSync)(code, {
|
|
3681
|
+
filename: opts.filename,
|
|
3682
|
+
configFile: false,
|
|
3683
|
+
babelrc: false,
|
|
3684
|
+
sourceMaps: true,
|
|
3685
|
+
parserOpts: { plugins: ["typescript", "jsx"] },
|
|
3686
|
+
plugins: [[serverFunctionsBabelPlugin, opts]]
|
|
3687
|
+
});
|
|
3688
|
+
if (!result?.code) return null;
|
|
3689
|
+
return { code: result.code, map: result.map };
|
|
3690
|
+
}
|
|
3691
|
+
var import_core4, RUNTIME;
|
|
3692
|
+
var init_server_functions = __esm({
|
|
3693
|
+
"src/frontend/babel/server-functions.ts"() {
|
|
3694
|
+
"use strict";
|
|
3695
|
+
import_core4 = require("@babel/core");
|
|
3696
|
+
init_server_fn_id();
|
|
3697
|
+
RUNTIME = "@fluixi/start/server-fn";
|
|
3698
|
+
}
|
|
3699
|
+
});
|
|
3700
|
+
|
|
3701
|
+
// src/transform/server-fns.ts
|
|
3702
|
+
var server_fns_exports = {};
|
|
3703
|
+
__export(server_fns_exports, {
|
|
3704
|
+
transformServerFns: () => transformServerFns
|
|
3705
|
+
});
|
|
3706
|
+
function directive(node) {
|
|
3707
|
+
if (!FUNCTION_TYPES.has(node.type)) return null;
|
|
3708
|
+
const body = node.body;
|
|
3709
|
+
if (!body || body.type !== "BlockStatement") return null;
|
|
3710
|
+
for (const d of body.directives ?? []) {
|
|
3711
|
+
if (d.value?.value === "use server") return d;
|
|
3712
|
+
}
|
|
3713
|
+
return null;
|
|
3714
|
+
}
|
|
3715
|
+
function findServerFns(node, out) {
|
|
3716
|
+
if (!node || typeof node !== "object") return;
|
|
3717
|
+
if (Array.isArray(node)) {
|
|
3718
|
+
for (const child of node) findServerFns(child, out);
|
|
3719
|
+
return;
|
|
3720
|
+
}
|
|
3721
|
+
if (typeof node.type === "string") {
|
|
3722
|
+
const found = directive(node);
|
|
3723
|
+
if (found) {
|
|
3724
|
+
out.push({ fn: node, directive: found });
|
|
3725
|
+
return;
|
|
3726
|
+
}
|
|
3727
|
+
}
|
|
3728
|
+
for (const key of Object.keys(node)) {
|
|
3729
|
+
if (key === "loc" || key === "leadingComments" || key === "trailingComments") continue;
|
|
3730
|
+
findServerFns(node[key], out);
|
|
3731
|
+
}
|
|
3732
|
+
}
|
|
3733
|
+
function transformServerFns(code, options) {
|
|
3734
|
+
if (!code.includes("use server")) return null;
|
|
3735
|
+
const ast = (0, import_parser3.parse)(code, {
|
|
3736
|
+
sourceType: "module",
|
|
3737
|
+
plugins: ["jsx", "typescript"],
|
|
3738
|
+
errorRecovery: true
|
|
3739
|
+
});
|
|
3740
|
+
const found = [];
|
|
3741
|
+
findServerFns(ast.program, found);
|
|
3742
|
+
if (found.length === 0) return null;
|
|
3743
|
+
const helper = options.ssr ? "$$registerServerFn" : "$$createServerReference";
|
|
3744
|
+
const out = new import_magic_string3.default(code);
|
|
3745
|
+
found.forEach(({ fn, directive: dir }, index) => {
|
|
3746
|
+
const id = serverFnId(options.filename, options.root, index);
|
|
3747
|
+
const declaration = fn.type === "FunctionDeclaration";
|
|
3748
|
+
if (!options.ssr) {
|
|
3749
|
+
const stub = `${helper}(${JSON.stringify(id)})`;
|
|
3750
|
+
out.overwrite(fn.start, fn.end, declaration ? `const ${fn.id.name} = ${stub};` : stub);
|
|
3751
|
+
return;
|
|
3752
|
+
}
|
|
3753
|
+
out.remove(dir.start, dir.end);
|
|
3754
|
+
out.appendLeft(fn.start, declaration ? `const ${fn.id.name} = ${helper}(${JSON.stringify(id)}, ` : `${helper}(${JSON.stringify(id)}, `);
|
|
3755
|
+
out.appendRight(fn.end, declaration ? ");" : ")");
|
|
3756
|
+
});
|
|
3757
|
+
out.prepend(`import { ${helper} } from ${JSON.stringify(options.runtimeModule ?? RUNTIME2)};
|
|
3758
|
+
`);
|
|
3759
|
+
return {
|
|
3760
|
+
code: out.toString(),
|
|
3761
|
+
map: out.generateMap({ source: options.filename, includeContent: true, hires: true })
|
|
3762
|
+
};
|
|
3763
|
+
}
|
|
3764
|
+
var import_parser3, import_magic_string3, RUNTIME2, FUNCTION_TYPES;
|
|
3765
|
+
var init_server_fns = __esm({
|
|
3766
|
+
"src/transform/server-fns.ts"() {
|
|
3767
|
+
"use strict";
|
|
3768
|
+
import_parser3 = require("@babel/parser");
|
|
3769
|
+
import_magic_string3 = __toESM(require("magic-string"), 1);
|
|
3770
|
+
init_server_fn_id();
|
|
3771
|
+
RUNTIME2 = "@fluixi/start/server-fn";
|
|
3772
|
+
FUNCTION_TYPES = /* @__PURE__ */ new Set([
|
|
3773
|
+
"FunctionDeclaration",
|
|
3774
|
+
"FunctionExpression",
|
|
3775
|
+
"ArrowFunctionExpression"
|
|
3776
|
+
]);
|
|
3777
|
+
}
|
|
3778
|
+
});
|
|
3779
|
+
|
|
3780
|
+
// src/integrations.ts
|
|
3781
|
+
var integrations_exports = {};
|
|
3782
|
+
__export(integrations_exports, {
|
|
3783
|
+
createBabelPlugin: () => createBabelPlugin,
|
|
3784
|
+
createESBuildPlugin: () => createESBuildPlugin,
|
|
3785
|
+
createRollupPlugin: () => createRollupPlugin,
|
|
3786
|
+
createTypeScriptTransformer: () => createTypeScriptTransformer,
|
|
3787
|
+
createVitePlugin: () => createVitePlugin,
|
|
3788
|
+
createWebpackLoader: () => createWebpackLoader,
|
|
3789
|
+
default: () => integrations_default,
|
|
3790
|
+
serverFunctionsVitePlugin: () => serverFunctionsVitePlugin
|
|
3791
|
+
});
|
|
3792
|
+
module.exports = __toCommonJS(integrations_exports);
|
|
3793
|
+
|
|
3794
|
+
// src/resolve/write-globals.ts
|
|
3795
|
+
var import_node_fs = require("node:fs");
|
|
3796
|
+
var import_node_path = require("node:path");
|
|
3797
|
+
|
|
3798
|
+
// src/resolve/component-globals.ts
|
|
3799
|
+
init_component_resolver();
|
|
3800
|
+
init_builtins();
|
|
3801
|
+
init_intrinsics();
|
|
3802
|
+
var DOM_GLOBALS = /* @__PURE__ */ new Set([
|
|
3803
|
+
"Text",
|
|
3804
|
+
"Image",
|
|
3805
|
+
"Option",
|
|
3806
|
+
"Audio",
|
|
3807
|
+
"Comment",
|
|
3808
|
+
"Range",
|
|
3809
|
+
"Selection",
|
|
3810
|
+
"Notification",
|
|
3811
|
+
"Event",
|
|
3812
|
+
"Document",
|
|
3813
|
+
"Element",
|
|
3814
|
+
"Node",
|
|
3815
|
+
"Screen",
|
|
3816
|
+
"Window",
|
|
3817
|
+
"Location",
|
|
3818
|
+
"History",
|
|
3819
|
+
"Storage",
|
|
3820
|
+
"Response",
|
|
3821
|
+
"Request",
|
|
3822
|
+
"Headers"
|
|
3823
|
+
]);
|
|
3824
|
+
function packageOf(specifier) {
|
|
3825
|
+
if (specifier.startsWith(".") || specifier.startsWith("/")) return void 0;
|
|
3826
|
+
if (/^[~@]\//.test(specifier)) return void 0;
|
|
3827
|
+
const parts = specifier.split("/");
|
|
3828
|
+
return specifier.startsWith("@") ? parts.slice(0, 2).join("/") : parts[0];
|
|
3829
|
+
}
|
|
3830
|
+
function namespaceAlias(module2) {
|
|
3831
|
+
return `_${module2.replace(/[^A-Za-z0-9]/g, "_")}`;
|
|
3832
|
+
}
|
|
3833
|
+
function componentGlobals(rules, options = {}) {
|
|
3834
|
+
const {
|
|
3835
|
+
available: availableList,
|
|
3836
|
+
builtins = true,
|
|
3837
|
+
intrinsics = true,
|
|
3838
|
+
generator = "@fluixi/compiler",
|
|
3839
|
+
specifier = (module2) => module2
|
|
3840
|
+
} = options;
|
|
3841
|
+
const all = [...rules];
|
|
3842
|
+
if (builtins) {
|
|
3843
|
+
all.push({ components: builtinComponentMap() });
|
|
3844
|
+
}
|
|
3845
|
+
const resolver = createComponentResolver(all);
|
|
3846
|
+
const available = availableList ? new Set(availableList) : void 0;
|
|
3847
|
+
const declared2 = [];
|
|
3848
|
+
const shadowedByDom = [];
|
|
3849
|
+
const unavailable = [];
|
|
3850
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
3851
|
+
for (const name of [...resolver.names()].sort()) {
|
|
3852
|
+
const target = resolver.resolve(name);
|
|
3853
|
+
if (!target) continue;
|
|
3854
|
+
const pkg = packageOf(target.module);
|
|
3855
|
+
if (DOM_GLOBALS.has(name)) shadowedByDom.push(name);
|
|
3856
|
+
else if (available && pkg && !available.has(pkg)) unavailable.push(name);
|
|
3857
|
+
else {
|
|
3858
|
+
declared2.push(name);
|
|
3859
|
+
resolved.set(name, target);
|
|
3860
|
+
}
|
|
3861
|
+
}
|
|
3862
|
+
const intrinsicModules = intrinsics ? [...new Set(Object.values(INTRINSICS).map((i) => i.module))] : [];
|
|
3863
|
+
const modules = [
|
|
3864
|
+
.../* @__PURE__ */ new Set([...declared2.map((name) => resolved.get(name).module), ...intrinsicModules])
|
|
3865
|
+
].sort();
|
|
3866
|
+
const imports = modules.map(
|
|
3867
|
+
(m) => `import * as ${namespaceAlias(m)} from '${specifier(m)}';`
|
|
3868
|
+
);
|
|
3869
|
+
const lines = declared2.map((name) => {
|
|
3870
|
+
const target = resolved.get(name);
|
|
3871
|
+
const ns = namespaceAlias(target.module);
|
|
3872
|
+
return target.export === "default" ? ` const ${name}: typeof ${ns}.default;` : ` export import ${name} = ${ns}.${target.export};`;
|
|
3873
|
+
});
|
|
3874
|
+
const note = shadowedByDom.length > 0 ? `//
|
|
10
3875
|
// Import these explicitly — lib.dom already declares the name, so an ambient
|
|
11
3876
|
// declaration cannot win:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
3877
|
+
` + shadowedByDom.map((n) => {
|
|
3878
|
+
const module2 = resolver.resolve(n)?.module;
|
|
3879
|
+
return `// import { ${n} } from '${module2 ? specifier(module2) : ""}';
|
|
3880
|
+
`;
|
|
3881
|
+
}).join("") : "";
|
|
3882
|
+
const intrinsicLines = intrinsics ? Object.entries(INTRINSICS).map(
|
|
3883
|
+
([name, intrinsic]) => ` const ${name}: typeof ${namespaceAlias(intrinsic.module)}.${intrinsic.export};`
|
|
3884
|
+
) : [];
|
|
3885
|
+
const patternRules = rules.filter((rule) => "match" in rule).length;
|
|
3886
|
+
const patternNote = patternRules > 0 ? `//
|
|
3887
|
+
// ${patternRules} pattern rule${patternRules === 1 ? "" : "s"} cannot be declared:
|
|
15
3888
|
// a pattern matches unboundedly many names, so there is no list to emit. Those
|
|
16
3889
|
// tags still resolve at build time; declare them by hand if the editor needs them.
|
|
17
|
-
|
|
3890
|
+
` : "";
|
|
3891
|
+
const source = `// GENERATED by ${generator} — do not edit.
|
|
18
3892
|
//
|
|
19
3893
|
// The components \`resolve\` supplies without an import. This describes what the
|
|
20
3894
|
// compiler already does; it does not enable it.
|
|
21
|
-
|
|
22
|
-
${
|
|
23
|
-
`)
|
|
24
|
-
`:`
|
|
25
|
-
`)+`
|
|
3895
|
+
` + note + patternNote + (imports.length > 0 ? `
|
|
3896
|
+
${imports.join("\n")}
|
|
3897
|
+
` : "\n") + `
|
|
26
3898
|
declare global {
|
|
27
|
-
${[...
|
|
28
|
-
|
|
3899
|
+
${[...lines, ...intrinsicLines].join("\n")}
|
|
3900
|
+
}
|
|
3901
|
+
`;
|
|
3902
|
+
return { source, declared: declared2, shadowedByDom, unavailable, patternRules };
|
|
29
3903
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
3904
|
+
|
|
3905
|
+
// src/resolve/write-globals.ts
|
|
3906
|
+
var GENERATED_MARKER = "GENERATED by @fluixi/compiler";
|
|
3907
|
+
var DEFAULT_GLOBALS_PATH = "fluixi.d.ts";
|
|
3908
|
+
function coveredByInclude(root, target) {
|
|
3909
|
+
let config;
|
|
3910
|
+
try {
|
|
3911
|
+
const raw = (0, import_node_fs.readFileSync)((0, import_node_path.resolve)(root, "tsconfig.json"), "utf8");
|
|
3912
|
+
config = JSON.parse(raw.replace(/^\s*\/\/.*$/gm, ""));
|
|
3913
|
+
} catch {
|
|
3914
|
+
return void 0;
|
|
3915
|
+
}
|
|
3916
|
+
if (config.extends !== void 0) return void 0;
|
|
3917
|
+
if (!Array.isArray(config.include)) return true;
|
|
3918
|
+
const relative2 = relativePosix(root, target);
|
|
3919
|
+
return config.include.some((entry) => {
|
|
3920
|
+
if (typeof entry !== "string") return false;
|
|
3921
|
+
const pattern = entry.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*\//g, "(?:.*/)?").replace(/\*/g, "[^/]*");
|
|
3922
|
+
return new RegExp(`^${pattern}(?:/.*)?$`).test(relative2);
|
|
3923
|
+
});
|
|
3924
|
+
}
|
|
3925
|
+
function relativePosix(from, to) {
|
|
3926
|
+
return (0, import_node_path.relative)(from, to).split(import_node_path.sep).join("/");
|
|
3927
|
+
}
|
|
3928
|
+
function forTypeScript(module2, outDir, root) {
|
|
3929
|
+
if (!module2.startsWith("/")) return module2;
|
|
3930
|
+
const absolute = (0, import_node_path.resolve)(root, module2.slice(1));
|
|
3931
|
+
let rel = (0, import_node_path.relative)(outDir, absolute).split(import_node_path.sep).join("/");
|
|
3932
|
+
if (!rel.startsWith(".")) rel = `./${rel}`;
|
|
3933
|
+
return rel.replace(/\.(tsx|ts|jsx|mts|cts)$/, ".js");
|
|
3934
|
+
}
|
|
3935
|
+
function projectDependencies(root) {
|
|
3936
|
+
try {
|
|
3937
|
+
const manifest = JSON.parse((0, import_node_fs.readFileSync)((0, import_node_path.resolve)(root, "package.json"), "utf8"));
|
|
3938
|
+
return [
|
|
3939
|
+
...Object.keys(manifest.dependencies ?? {}),
|
|
3940
|
+
...Object.keys(manifest.devDependencies ?? {}),
|
|
3941
|
+
...Object.keys(manifest.peerDependencies ?? {})
|
|
3942
|
+
];
|
|
3943
|
+
} catch {
|
|
3944
|
+
return void 0;
|
|
3945
|
+
}
|
|
3946
|
+
}
|
|
3947
|
+
function writeComponentGlobals(options, root) {
|
|
3948
|
+
if (options.globals === false) return { status: "skipped", reason: "disabled" };
|
|
3949
|
+
const rules = options.resolve ?? [];
|
|
3950
|
+
const target = (0, import_node_path.resolve)(root, options.globals ?? DEFAULT_GLOBALS_PATH);
|
|
3951
|
+
let existing;
|
|
3952
|
+
try {
|
|
3953
|
+
existing = (0, import_node_fs.readFileSync)(target, "utf8");
|
|
3954
|
+
} catch {
|
|
3955
|
+
existing = void 0;
|
|
3956
|
+
}
|
|
3957
|
+
if (existing !== void 0 && !existing.includes(GENERATED_MARKER)) {
|
|
3958
|
+
return { status: "skipped", reason: "foreign-file", path: target };
|
|
3959
|
+
}
|
|
3960
|
+
const { source, declared: declared2 } = componentGlobals(rules, {
|
|
3961
|
+
available: projectDependencies(root),
|
|
3962
|
+
specifier: (module2) => forTypeScript(module2, (0, import_node_path.dirname)(target), root)
|
|
3963
|
+
});
|
|
3964
|
+
if (existing === source) {
|
|
3965
|
+
return {
|
|
3966
|
+
status: "unchanged",
|
|
3967
|
+
path: target,
|
|
3968
|
+
declared: declared2.length,
|
|
3969
|
+
warning: warnIfUnreachable(root, target)
|
|
3970
|
+
};
|
|
3971
|
+
}
|
|
3972
|
+
(0, import_node_fs.mkdirSync)((0, import_node_path.dirname)(target), { recursive: true });
|
|
3973
|
+
(0, import_node_fs.writeFileSync)(target, source);
|
|
3974
|
+
return {
|
|
3975
|
+
status: "written",
|
|
3976
|
+
path: target,
|
|
3977
|
+
declared: declared2.length,
|
|
3978
|
+
warning: warnIfUnreachable(root, target)
|
|
3979
|
+
};
|
|
3980
|
+
}
|
|
3981
|
+
function warnIfUnreachable(root, target) {
|
|
3982
|
+
if (coveredByInclude(root, target) !== false) return void 0;
|
|
3983
|
+
const relative2 = relativePosix(root, target);
|
|
3984
|
+
return `[fluixi] ${relative2} is not covered by "include" in tsconfig.json, so TypeScript will ignore it and every resolved component stays "Cannot find name". Add "${relative2}" to "include".`;
|
|
3985
|
+
}
|
|
3986
|
+
|
|
3987
|
+
// src/integrations.ts
|
|
3988
|
+
var import_node_fs2 = require("node:fs");
|
|
3989
|
+
var import_node_path2 = require("node:path");
|
|
3990
|
+
async function createBabelPlugin(options = {}) {
|
|
3991
|
+
let pluginModule = null;
|
|
3992
|
+
try {
|
|
3993
|
+
pluginModule = await Promise.resolve().then(() => (init_babel(), babel_exports));
|
|
3994
|
+
} catch (e) {
|
|
3995
|
+
console.warn("Could not load the babel front-end:", e);
|
|
3996
|
+
}
|
|
3997
|
+
return {
|
|
3998
|
+
name: "babel-fluixi-jsx",
|
|
3999
|
+
plugin: pluginModule ? pluginModule.default || pluginModule : null,
|
|
4000
|
+
// Provide options mapping
|
|
4001
|
+
getOptions() {
|
|
4002
|
+
return {
|
|
4003
|
+
importSource: options.importSource || "@fluixi/jsx",
|
|
4004
|
+
development: options.development || false,
|
|
4005
|
+
delegateEvents: options.delegateEvents !== false,
|
|
4006
|
+
...options.format ? { format: options.format } : {},
|
|
4007
|
+
// Forwarded explicitly: getOptions() is an allowlist, so an option missing
|
|
4008
|
+
// here is silently dropped rather than rejected.
|
|
4009
|
+
...options.resolve ? { resolve: options.resolve } : {},
|
|
4010
|
+
...options.templateClone !== void 0 ? { templateClone: options.templateClone } : {},
|
|
4011
|
+
...options.partialTemplates !== void 0 ? { partialTemplates: options.partialTemplates } : {},
|
|
4012
|
+
...options.litTag ? { litTag: options.litTag } : {},
|
|
4013
|
+
...options.signalModule ? { signalModule: options.signalModule } : {},
|
|
4014
|
+
...options.controlFlowModule ? { controlFlowModule: options.controlFlowModule } : {},
|
|
4015
|
+
...options.routerModule ? { routerModule: options.routerModule } : {},
|
|
4016
|
+
...options.reactiveModule ? { reactiveModule: options.reactiveModule } : {}
|
|
4017
|
+
};
|
|
4018
|
+
}
|
|
4019
|
+
};
|
|
4020
|
+
}
|
|
4021
|
+
function createTypeScriptTransformer(options = {}) {
|
|
4022
|
+
const ts = tryRequire("typescript");
|
|
4023
|
+
if (!ts) {
|
|
4024
|
+
console.warn("TypeScript not found, transformer unavailable");
|
|
4025
|
+
return (context) => (sourceFile) => sourceFile;
|
|
4026
|
+
}
|
|
4027
|
+
return (context) => {
|
|
4028
|
+
const visitor = (node) => {
|
|
4029
|
+
if (ts.isJsxElement(node) || ts.isJsxSelfClosingElement(node)) {
|
|
4030
|
+
return transformTSJSXNode(node, options, ts);
|
|
4031
|
+
}
|
|
4032
|
+
return ts.visitEachChild(node, visitor, context);
|
|
4033
|
+
};
|
|
4034
|
+
return (sourceFile) => {
|
|
4035
|
+
return ts.visitNode(sourceFile, visitor);
|
|
4036
|
+
};
|
|
4037
|
+
};
|
|
4038
|
+
}
|
|
4039
|
+
function transformTSJSXNode(node, options, ts) {
|
|
4040
|
+
return node;
|
|
4041
|
+
}
|
|
4042
|
+
function tryRequire(moduleName) {
|
|
4043
|
+
try {
|
|
4044
|
+
return require(moduleName);
|
|
4045
|
+
} catch (e) {
|
|
4046
|
+
return null;
|
|
4047
|
+
}
|
|
4048
|
+
}
|
|
4049
|
+
var RETIRED_SUBPATHS = {
|
|
4050
|
+
"@fluixi/core/router-next": "is now @fluixi/core/router",
|
|
4051
|
+
"@fluixi/core/rx": "is gone — import signals and effects from @fluixi/reactive, or the server primitives it resolved to under node from @fluixi/core/server"
|
|
4052
|
+
};
|
|
4053
|
+
function createVitePlugin(options = {}) {
|
|
4054
|
+
return {
|
|
4055
|
+
name: "vite-fluixi-jsx",
|
|
4056
|
+
enforce: "pre",
|
|
4057
|
+
config() {
|
|
4058
|
+
return {
|
|
4059
|
+
esbuild: {
|
|
4060
|
+
jsx: "automatic",
|
|
4061
|
+
jsxImportSource: options.importSource || "@fluixi/jsx"
|
|
4062
|
+
}
|
|
4063
|
+
};
|
|
4064
|
+
},
|
|
4065
|
+
// Written once per build, and on dev-server start, rather than per transform: the
|
|
4066
|
+
// set of resolvable names comes from config, so nothing a file does can change it.
|
|
4067
|
+
configResolved(config) {
|
|
4068
|
+
const outcome = writeComponentGlobals(options, config?.root ?? process.cwd());
|
|
4069
|
+
if (outcome.warning) console.warn(outcome.warning);
|
|
4070
|
+
},
|
|
4071
|
+
// A subpath we retired resolves to nothing, and the bundler reports that as
|
|
4072
|
+
// `Missing "./x" specifier`, which names neither the replacement nor the file
|
|
4073
|
+
// that asked. Answer it here, where the rename is known.
|
|
4074
|
+
resolveId(id, importer) {
|
|
4075
|
+
const moved = RETIRED_SUBPATHS[id];
|
|
4076
|
+
if (!moved) return null;
|
|
4077
|
+
throw new Error(
|
|
4078
|
+
`[fluixi] ${id} ${moved}` + (importer ? `
|
|
4079
|
+
imported by ${importer}` : "")
|
|
4080
|
+
);
|
|
4081
|
+
},
|
|
4082
|
+
async transform(code, id) {
|
|
4083
|
+
if (!/\.(jsx|tsx|ts)$/i.test(id)) {
|
|
4084
|
+
return null;
|
|
4085
|
+
}
|
|
4086
|
+
if (!options.babel) return compileModule(code, id, options);
|
|
4087
|
+
const babelPlugin = await createBabelPlugin(options);
|
|
4088
|
+
try {
|
|
4089
|
+
const babel = await import("@babel/core").catch(() => null);
|
|
4090
|
+
if (!babel) {
|
|
4091
|
+
throw new Error(
|
|
4092
|
+
`[fluixi] @babel/core is required to compile ${id} but could not be loaded. Install it alongside @fluixi/compiler.`
|
|
4093
|
+
);
|
|
4094
|
+
}
|
|
4095
|
+
const isTSX = /\.tsx$/.test(id);
|
|
4096
|
+
const isTS = /\.ts$/.test(id);
|
|
4097
|
+
const presets2 = [];
|
|
4098
|
+
const plugins = [];
|
|
4099
|
+
if (isTSX || isTS) {
|
|
4100
|
+
const tsPreset = await import("@babel/preset-typescript").then((m) => m.default || m).catch(() => null);
|
|
4101
|
+
if (tsPreset) {
|
|
4102
|
+
presets2.push([
|
|
4103
|
+
tsPreset,
|
|
4104
|
+
{
|
|
4105
|
+
isTSX,
|
|
4106
|
+
allExtensions: true,
|
|
4107
|
+
// Important: preserve JSX so our plugin can transform it
|
|
4108
|
+
jsxPragma: "jsx",
|
|
4109
|
+
jsxPragmaFrag: "Fragment",
|
|
4110
|
+
onlyRemoveTypeImports: true
|
|
4111
|
+
}
|
|
4112
|
+
]);
|
|
4113
|
+
}
|
|
4114
|
+
}
|
|
4115
|
+
if (babelPlugin && babelPlugin.plugin) {
|
|
4116
|
+
plugins.push([babelPlugin.plugin, babelPlugin.getOptions()]);
|
|
4117
|
+
} else {
|
|
4118
|
+
console.warn("[createVitePlugin] custom babel plugin not found");
|
|
4119
|
+
}
|
|
4120
|
+
const result = await babel.transformAsync(code, {
|
|
4121
|
+
filename: id,
|
|
4122
|
+
configFile: false,
|
|
4123
|
+
babelrc: false,
|
|
4124
|
+
presets: presets2,
|
|
4125
|
+
plugins,
|
|
4126
|
+
sourceMaps: options.sourceMaps !== false
|
|
4127
|
+
});
|
|
4128
|
+
return {
|
|
4129
|
+
code: result?.code || code,
|
|
4130
|
+
map: result?.map
|
|
4131
|
+
};
|
|
4132
|
+
} catch (e) {
|
|
4133
|
+
throw e;
|
|
4134
|
+
}
|
|
4135
|
+
}
|
|
4136
|
+
};
|
|
4137
|
+
}
|
|
4138
|
+
function marks(options, id) {
|
|
4139
|
+
if (options.sourceLocations !== true) return false;
|
|
4140
|
+
if (options.sourceLocationsExternal) return true;
|
|
4141
|
+
if (!id || id.includes("/node_modules/")) return false;
|
|
4142
|
+
const root = options.sourceRoot;
|
|
4143
|
+
if (!root) return true;
|
|
4144
|
+
const base = root.endsWith("/") ? root : `${root}/`;
|
|
4145
|
+
return id.startsWith(base);
|
|
4146
|
+
}
|
|
4147
|
+
function transformOptions(options, id) {
|
|
4148
|
+
return {
|
|
4149
|
+
resolve: options.resolve,
|
|
4150
|
+
litTag: options.litTag,
|
|
4151
|
+
sourceLocations: marks(options, id),
|
|
4152
|
+
sourceRoot: options.sourceRoot,
|
|
4153
|
+
templateClone: options.templateClone,
|
|
4154
|
+
partialTemplates: options.partialTemplates,
|
|
4155
|
+
runtimeModule: options.signalModule,
|
|
4156
|
+
controlFlowModule: options.controlFlowModule,
|
|
4157
|
+
routerModule: options.routerModule,
|
|
4158
|
+
reactiveModule: options.reactiveModule,
|
|
4159
|
+
propsDestructure: options.propsDestructure
|
|
4160
|
+
};
|
|
4161
|
+
}
|
|
4162
|
+
async function rewriteProps(code, id, options) {
|
|
4163
|
+
if (options.propsDestructure === false) return code;
|
|
4164
|
+
const { transformProps: transformProps2 } = await Promise.resolve().then(() => (init_transform(), transform_exports));
|
|
4165
|
+
const result = transformProps2(code, id);
|
|
4166
|
+
reportDiagnostics({ propsDiagnostics: result.diagnostics }, id);
|
|
4167
|
+
return result.rewritten > 0 ? result.code : code;
|
|
4168
|
+
}
|
|
4169
|
+
var reported = /* @__PURE__ */ new Set();
|
|
4170
|
+
function reportDiagnostics(result, id) {
|
|
4171
|
+
const r = result;
|
|
4172
|
+
const say = (message) => {
|
|
4173
|
+
const key = `${id}\0${message}`;
|
|
4174
|
+
if (reported.has(key)) return;
|
|
4175
|
+
reported.add(key);
|
|
4176
|
+
console.warn(`[fluixi] ${id}: ${message}`);
|
|
4177
|
+
};
|
|
4178
|
+
for (const d of r?.unresolvedDiagnostics ?? []) say(d.message);
|
|
4179
|
+
for (const d of r?.loadDiagnostics ?? []) say(d.message);
|
|
4180
|
+
for (const d of r?.intrinsicDiagnostics ?? []) say(d.message);
|
|
4181
|
+
for (const d of r?.propsDiagnostics ?? []) {
|
|
4182
|
+
say(`\`${d.name}\` was left destructured: ${d.message}. It reads once instead of tracking.`);
|
|
4183
|
+
}
|
|
4184
|
+
}
|
|
4185
|
+
async function compileModule(code, id, options) {
|
|
4186
|
+
if (!options.babel) {
|
|
4187
|
+
const { transformTemplates: transformTemplates2 } = await Promise.resolve().then(() => (init_transform(), transform_exports));
|
|
4188
|
+
const result2 = transformTemplates2(code, id, transformOptions(options, id));
|
|
4189
|
+
reportDiagnostics(result2, id);
|
|
4190
|
+
return result2;
|
|
4191
|
+
}
|
|
4192
|
+
const source = await rewriteProps(code, id, options);
|
|
4193
|
+
const babel = await import("@babel/core").catch(() => null);
|
|
4194
|
+
const plugin = await createBabelPlugin(options);
|
|
4195
|
+
if (!babel || !plugin.plugin) {
|
|
4196
|
+
throw new Error(
|
|
4197
|
+
`[fluixi] babel: true needs @babel/core, which could not be loaded for ${id}. Install it, or drop the option to use the built-in compiler.`
|
|
4198
|
+
);
|
|
4199
|
+
}
|
|
4200
|
+
const result = await babel.transformAsync(source, {
|
|
4201
|
+
filename: id,
|
|
4202
|
+
configFile: false,
|
|
4203
|
+
babelrc: false,
|
|
4204
|
+
plugins: [[plugin.plugin, plugin.getOptions()]],
|
|
4205
|
+
sourceMaps: options.sourceMaps !== false
|
|
4206
|
+
});
|
|
4207
|
+
return result?.code ? { code: result.code, map: result.map } : null;
|
|
4208
|
+
}
|
|
4209
|
+
function createWebpackLoader(options = {}) {
|
|
4210
|
+
return async function(source) {
|
|
4211
|
+
const callback = this.async();
|
|
4212
|
+
compileModule(source, this.resourcePath, options).then((result) => {
|
|
4213
|
+
callback(null, result?.code, result?.map);
|
|
4214
|
+
}).catch((err) => {
|
|
4215
|
+
callback(err);
|
|
4216
|
+
});
|
|
4217
|
+
};
|
|
4218
|
+
}
|
|
4219
|
+
function createRollupPlugin(options = {}) {
|
|
4220
|
+
return {
|
|
4221
|
+
name: "rollup-fluixi-jsx",
|
|
4222
|
+
async transform(code, id) {
|
|
4223
|
+
if (!/\.[jt]sx?$/.test(id)) return null;
|
|
4224
|
+
return compileModule(code, id, options);
|
|
4225
|
+
}
|
|
4226
|
+
};
|
|
4227
|
+
}
|
|
4228
|
+
function createESBuildPlugin(options = {}) {
|
|
4229
|
+
return {
|
|
4230
|
+
name: "esbuild-fluixi-jsx",
|
|
4231
|
+
setup(build) {
|
|
4232
|
+
build.onLoad({ filter: /\.[jt]sx?$/ }, async (args) => {
|
|
4233
|
+
const { readFileSync: readFileSync3 } = await import("node:fs");
|
|
4234
|
+
const source = readFileSync3(args.path, "utf8");
|
|
4235
|
+
try {
|
|
4236
|
+
const result = await compileModule(source, args.path, options);
|
|
4237
|
+
return {
|
|
4238
|
+
contents: result?.code ?? source,
|
|
4239
|
+
loader: args.path.endsWith("x") ? "tsx" : "ts"
|
|
4240
|
+
};
|
|
4241
|
+
} catch (e) {
|
|
4242
|
+
return {
|
|
4243
|
+
errors: [
|
|
4244
|
+
{
|
|
4245
|
+
text: `Transform error: ${e}`
|
|
4246
|
+
}
|
|
4247
|
+
]
|
|
4248
|
+
};
|
|
4249
|
+
}
|
|
4250
|
+
});
|
|
4251
|
+
}
|
|
4252
|
+
};
|
|
4253
|
+
}
|
|
4254
|
+
var SERVER_FNS_VMOD = "virtual:fluixi-server-fns";
|
|
4255
|
+
function findServerFnModules(dir, out = []) {
|
|
4256
|
+
let entries;
|
|
4257
|
+
try {
|
|
4258
|
+
entries = (0, import_node_fs2.readdirSync)(dir, { withFileTypes: true });
|
|
4259
|
+
} catch {
|
|
4260
|
+
return out;
|
|
4261
|
+
}
|
|
4262
|
+
for (const e of entries) {
|
|
4263
|
+
if (e.name === "node_modules" || e.name === "dist" || e.name.startsWith(".")) continue;
|
|
4264
|
+
const full = (0, import_node_path2.join)(dir, e.name);
|
|
4265
|
+
if (e.isDirectory()) findServerFnModules(full, out);
|
|
4266
|
+
else if (/\.[jt]sx?$/.test(e.name)) {
|
|
4267
|
+
try {
|
|
4268
|
+
if ((0, import_node_fs2.readFileSync)(full, "utf8").includes("use server")) out.push(full);
|
|
4269
|
+
} catch {
|
|
4270
|
+
}
|
|
4271
|
+
}
|
|
4272
|
+
}
|
|
4273
|
+
return out;
|
|
4274
|
+
}
|
|
4275
|
+
function serverFunctionsVitePlugin(options = {}) {
|
|
4276
|
+
let root = process.cwd();
|
|
4277
|
+
return {
|
|
4278
|
+
name: "fluixi-server-functions",
|
|
4279
|
+
enforce: "pre",
|
|
4280
|
+
configResolved(config) {
|
|
4281
|
+
root = config.root || root;
|
|
4282
|
+
},
|
|
4283
|
+
resolveId(id) {
|
|
4284
|
+
return id === SERVER_FNS_VMOD || id === "@fluixi/start/server-fns" ? "\0" + SERVER_FNS_VMOD : null;
|
|
4285
|
+
},
|
|
4286
|
+
load(id) {
|
|
4287
|
+
if (id !== "\0" + SERVER_FNS_VMOD) return null;
|
|
4288
|
+
const mods = findServerFnModules((0, import_node_path2.join)(root, "src"));
|
|
4289
|
+
const setup = `import '@fluixi/start/server-fn-setup';
|
|
4290
|
+
`;
|
|
4291
|
+
const imports = mods.map((m) => `import ${JSON.stringify(m)};`).join("\n");
|
|
4292
|
+
const dispatcher = `
|
|
34
4293
|
export { isServerFnRequest, handleServerFn } from '@fluixi/start/server-fn';
|
|
35
|
-
|
|
4294
|
+
`;
|
|
4295
|
+
return setup + imports + dispatcher;
|
|
4296
|
+
},
|
|
4297
|
+
async transform(code, id, opts) {
|
|
4298
|
+
if (!/\.[jt]sx?$/.test(id)) return null;
|
|
4299
|
+
if (!code.includes("use server")) return null;
|
|
4300
|
+
const args = { ssr: !!opts?.ssr, filename: id, root };
|
|
4301
|
+
if (options.babel) {
|
|
4302
|
+
const { transformServerFunctions: transformServerFunctions2 } = await Promise.resolve().then(() => (init_server_functions(), server_functions_exports));
|
|
4303
|
+
return transformServerFunctions2(code, args);
|
|
4304
|
+
}
|
|
4305
|
+
const { transformServerFns: transformServerFns2 } = await Promise.resolve().then(() => (init_server_fns(), server_fns_exports));
|
|
4306
|
+
return transformServerFns2(code, args);
|
|
4307
|
+
}
|
|
4308
|
+
};
|
|
4309
|
+
}
|
|
4310
|
+
var integrations_default = {
|
|
4311
|
+
createBabelPlugin,
|
|
4312
|
+
createTypeScriptTransformer,
|
|
4313
|
+
createVitePlugin,
|
|
4314
|
+
createWebpackLoader,
|
|
4315
|
+
createRollupPlugin,
|
|
4316
|
+
createESBuildPlugin
|
|
4317
|
+
};
|