@fluixi/compiler 1.0.0-alpha.83 → 1.0.0-alpha.85
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.d.ts +2 -2
- package/dist/analyze/expr-shape.js +1 -1
- 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.d.ts +7 -7
- package/dist/analyze/intrinsics.d.ts.map +1 -1
- package/dist/analyze/intrinsics.js +3 -3
- 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.d.ts +3 -3
- package/dist/analyze/props-destructure.d.ts.map +1 -1
- package/dist/analyze/props-destructure.js +4 -4
- 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.d.ts +1 -1
- package/dist/analyze/reactive-bindings.js +2 -2
- 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.d.ts +4 -4
- package/dist/analyze/reactive-expr.d.ts.map +1 -1
- package/dist/analyze/reactive-expr.js +2 -2
- 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.d.ts +1 -1
- package/dist/analyze/static-graph.d.ts.map +1 -1
- package/dist/analyze/static-graph.js +11 -11
- package/dist/analyze/static-graph.mjs +793 -1
- package/dist/babel-TGY76XJ7.mjs +636 -0
- package/dist/chunk-4PLHS2FP.mjs +158 -0
- package/dist/chunk-6DB5FXS4.mjs +1718 -0
- package/dist/chunk-F74GFKSL.mjs +16 -0
- package/dist/chunk-G6QC2WRJ.mjs +11 -0
- package/dist/chunk-RUDJDZAA.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 +1 -1
- package/dist/codegen/backends/imperative.d.ts.map +1 -1
- package/dist/codegen/backends/imperative.js +24 -20
- 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.d.ts +2 -2
- package/dist/codegen/contract.js +2 -2
- 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.d.ts +4 -4
- package/dist/codegen/partial-template.js +0 -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.d.ts +3 -3
- package/dist/codegen/serialize-static.js +6 -6
- 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.d.ts +2 -2
- 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.d.ts +2 -2
- package/dist/frontend/babel/build-ir.js +2 -2
- 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.d.ts +1 -1
- package/dist/frontend/babel/index.js +1 -1
- 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.d.ts +1 -1
- package/dist/frontend/babel/lower-template.js +2 -2
- 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.d.ts +5 -5
- package/dist/frontend/babel/plugin.d.ts.map +1 -1
- package/dist/frontend/babel/plugin.js +14 -14
- 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 +1595 -14
- package/dist/index.d.cts +27 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -4
- package/dist/index.mjs +1575 -14
- package/dist/integrations.cjs +4312 -26
- package/dist/integrations.d.cts +215 -0
- package/dist/integrations.d.ts +9 -9
- package/dist/integrations.d.ts.map +1 -1
- package/dist/integrations.js +29 -8
- package/dist/integrations.mjs +536 -18
- package/dist/ir/nodes.cjs +18 -1
- package/dist/ir/nodes.d.cts +168 -0
- package/dist/ir/nodes.d.ts +6 -6
- package/dist/lower/compile-template.cjs +1356 -1
- package/dist/lower/compile-template.d.cts +69 -0
- package/dist/lower/compile-template.d.ts +3 -3
- package/dist/lower/compile-template.js +1 -1
- 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 +1 -1
- package/dist/lower/jsx.d.ts.map +1 -1
- package/dist/lower/jsx.js +6 -5
- 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 +3 -3
- package/dist/lower/template.d.ts.map +1 -1
- package/dist/lower/template.js +12 -11
- 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.d.ts +2 -2
- package/dist/lower/text.d.ts.map +1 -1
- package/dist/lower/text.js +2 -2
- 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.d.ts +2 -2
- package/dist/optimize/analyze-static.js +2 -2
- 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.d.ts +3 -3
- package/dist/optimize/collapse-strategies.mjs +67 -1
- package/dist/options.cjs +33 -1
- package/dist/options.d.cts +39 -0
- package/dist/options.d.ts +2 -2
- 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.d.ts +8 -8
- package/dist/resolve/builtins.d.ts.map +1 -1
- package/dist/resolve/builtins.js +4 -4
- package/dist/resolve/builtins.mjs +53 -1
- package/dist/resolve/component-globals.cjs +234 -14
- package/dist/resolve/component-globals.d.cts +80 -0
- package/dist/resolve/component-globals.d.ts +5 -5
- package/dist/resolve/component-globals.js +10 -10
- package/dist/resolve/component-globals.mjs +211 -14
- package/dist/resolve/component-resolver.cjs +80 -1
- package/dist/resolve/component-resolver.d.cts +68 -0
- package/dist/resolve/component-resolver.d.ts +3 -3
- package/dist/resolve/component-resolver.d.ts.map +1 -1
- package/dist/resolve/component-resolver.js +3 -3
- 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.d.ts +5 -5
- package/dist/resolve/load-directive.js +6 -6
- 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.d.ts +6 -6
- package/dist/resolve/resolve-ir.d.ts.map +1 -1
- package/dist/resolve/resolve-ir.js +1 -1
- package/dist/resolve/resolve-ir.mjs +85 -1
- package/dist/resolve/write-globals.cjs +319 -14
- package/dist/resolve/write-globals.d.cts +30 -0
- package/dist/resolve/write-globals.js +2 -2
- package/dist/resolve/write-globals.mjs +298 -14
- package/dist/server-fns-ZYWQTSZU.mjs +78 -0
- package/dist/server-functions-PCERFA7A.mjs +82 -0
- package/dist/transform/bindings.cjs +71 -1
- package/dist/transform/bindings.d.cts +16 -0
- package/dist/transform/bindings.d.ts +1 -1
- package/dist/transform/bindings.js +1 -1
- 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.js +1 -1
- 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.d.ts +1 -1
- package/dist/transform/props.d.ts.map +1 -1
- package/dist/transform/props.js +4 -4
- 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.d.ts +1 -1
- package/dist/transform/server-fn-id.js +2 -2
- 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.js +3 -3
- 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.d.ts +1 -1
- package/dist/transform/source-locations.js +5 -5
- 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.d.ts +2 -2
- package/dist/transform/templates.d.ts.map +1 -1
- package/dist/transform/templates.js +7 -7
- package/dist/transform/templates.mjs +3743 -16
- package/dist/transform-RWDTQUF5.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
|
@@ -1 +1,793 @@
|
|
|
1
|
-
import{parse as De}from"@babel/parser";import{parseTemplate as Me}from"@fluixi/template-parser";var L="@fluixi/reactive/signal",W={$signal:{export:"signal",module:L,returns:"signal-handle"},$memo:{export:"memo",module:L,returns:"memo-handle"},$effect:{export:"effect",module:L,returns:"effect"},$store:{export:"store",module:"@fluixi/reactive/store",returns:"store-handle"},$resource:{export:"resource",module:L,returns:"resource-handle"},$selector:{export:"createSelector",module:L,returns:"memo-accessor"},$deferred:{export:"createDeferred",module:L,returns:"memo-accessor"},$untrack:{export:"untrack",module:L,returns:"plain"},$untrackStore:{export:"untrackStore",module:"@fluixi/reactive/store",returns:"plain"}},de={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"},Re=["@fluixi/reactive","@fluixi/reactive/signal","@fluixi/reactive/store","@fluixi/core"],Ve=new RegExp(`\\$(?:${Object.keys(W).map(t=>t.slice(1)).join("|")})\\s*\\(`);function ue(t){return Object.prototype.hasOwnProperty.call(W,t)}function le(t){return Re.includes(t)}function T(t,i){if(t)switch(t.type){case"Identifier":i.add(t.name);return;case"ObjectPattern":for(let r of t.properties??[])r.type==="RestElement"?T(r.argument,i):T(r.value,i);return;case"ArrayPattern":for(let r of t.elements??[])T(r,i);return;case"AssignmentPattern":T(t.left,i);return;case"RestElement":T(t.argument,i);return}}function G(t,i){if(!(!t||typeof t!="object"||typeof t.type!="string")){i(t);for(let r of Object.keys(t)){if(r==="loc"||r==="leadingComments"||r==="trailingComments")continue;let e=t[r];if(Array.isArray(e))for(let o of e)G(o,i);else e&&typeof e=="object"&&G(e,i)}}}function we(t,i){if(t.type!=="CallExpression")return;let r=t.callee;if(r?.type!=="Identifier")return;let e=r.name,o=i.primitives.get(e);if(o)return o;let a=W[e];if(a&&!i.shadowed.has(e))return a.returns}function ke(t,i,r){if(Array.isArray(i)){t.type==="ArrayPattern"&&t.elements.forEach((e,o)=>{let a=i[o];e?.type==="Identifier"&&a&&r.set(e.name,a)});return}t.type==="Identifier"&&r.set(t.name,i)}function fe(t){let i={kinds:new Map,primitives:new Map,shadowed:new Set},r=t;G(r,e=>{let o=new Set;if(e.type==="VariableDeclarator")T(e.id,o);else if(e.type==="FunctionDeclaration"||e.type==="ClassDeclaration")T(e.id,o);else if(e.type==="ImportDefaultSpecifier"||e.type==="ImportNamespaceSpecifier")T(e.local,o);else if(e.type==="ImportSpecifier")T(e.local,o);else if(e.type==="FunctionExpression"||e.type==="ArrowFunctionExpression"||e.type==="FunctionDeclaration")for(let a of e.params??[])T(a,o);for(let a of o)W[a]&&i.shadowed.add(a)});for(let e of r.body??[])if(e.type==="ImportDeclaration"&&le(e.source?.value))for(let o of e.specifiers??[]){if(o.type!=="ImportSpecifier")continue;let a=o.imported,I=a.type==="Identifier"?a.name:a.value,D=de[I];D&&i.primitives.set(o.local.name,D)}return G(r,e=>{if(e.type!=="VariableDeclarator"||!e.init)return;let o=we(e.init,i);o&&ke(e.id,o,i.kinds)}),i}var H=["Show","For","Index","Switch","Match","Portal","Dynamic","ErrorBoundary"],q=["Suspense","SuspenseList","Await"],z=["Router","Outlet","Redirect","Link"],Xe=[...H,...q,...z],We=new Set([...H,...q]);var Oe={signal:"state",createSignal:"state",memo:"memo",createMemo:"memo",effect:"effect",createEffect:"effect",store:"store",createStore:"store",resource:"resource",createResource:"resource"},Te=new Set(["memo","effect","resource"]),pe=new Set([...H,...q,...z]),me={Router:"routes",Link:"href",Redirect:"to",Show:"when",Match:"when",For:"each",Index:"each",Dynamic:"component",Portal:"mount",Await:"value"},Ce=new Set(z),ge=t=>Ce.has(t)?"router":"control",Pe=new Set(["GET","POST","PUT","PATCH","DELETE","HEAD","OPTIONS"]);function Ae(t){return t.replace(/\\/g,"/").replace(/^\.?\/+/,"")}function M(t,i,r=[]){if(!(!t||typeof t.type!="string")){i(t,r),r.push(t);for(let e of Object.keys(t)){if(e==="loc"||e==="parent")continue;let o=t[e];if(Array.isArray(o))for(let a of o)M(a,i,r);else o&&typeof o.type=="string"&&M(o,i,r)}r.pop()}}function $e(t){let r=[...t].reverse().find(e=>e.type==="VariableDeclarator")?.id;if(r?.type==="Identifier")return r.name;if(r?.type==="ArrayPattern"){let e=r.elements?.[0];if(e?.type==="Identifier")return e.name}}function je(t){if(t.type==="FunctionDeclaration"){let i=t.id?.name;return i&&i[0]===i[0]?.toUpperCase()?i:void 0}if(t.type==="VariableDeclarator"){let i=t.id,r=t.init;if(i?.type!=="Identifier"||!r||r.type!=="ArrowFunctionExpression"&&r.type!=="FunctionExpression")return;let e=i.name;return e[0]===e[0]?.toUpperCase()?e:void 0}}function B(t){let i=new Set;return M(t,(r,e)=>{if(r.type!=="Identifier")return;let o=e[e.length-1];o?.type==="MemberExpression"&&o.property===r&&!o.computed||o?.type==="ObjectProperty"&&o.key===r&&!o.computed||i.add(r.name)}),i}function Fe(t){let i=[],r=t.quasis??[],e=t.expressions??[];return r.forEach((o,a)=>{let I=o.value;if(i.push({kind:"static",text:I?.cooked??I?.raw??"",start:o.start??0}),a<e.length){let D=e[a];i.push({kind:"hole",index:a,start:D.start??0,end:D.end??0})}}),i}function _e(t){let i=[0];for(let r=0;r<t.length;r++)t.charCodeAt(r)===10&&i.push(r+1);return r=>{let e=0,o=i.length-1;for(;e<o;){let a=e+o+1>>1;i[a]<=r?e=a:o=a-1}return{line:e+1,column:r-i[e]}}}function he(t){let i="",r=[];for(let e of t.attributes)e.kind!=="Attribute"||e.value?.kind!=="static"||(e.name==="id"?i=`#${e.value.value}`:e.name==="class"&&r.push(...String(e.value.value).split(/\s+/).filter(Boolean).slice(0,2)));return`${t.tag}${i}${r.map(e=>`.${e}`).join("")}`}function Ne(t){return t?t.kind==="hole"?[t.hole]:t.kind==="mixed"?t.parts.flatMap(i=>"hole"in i?[i.hole]:[]):[]:[]}function ye(t){let i=t.name?.name??"element",r="",e=[];for(let o of t.attributes??[]){if(o.type!=="JSXAttribute")continue;let a=o.name?.name,I=o.value;I?.type==="StringLiteral"&&(a==="id"?r=`#${I.value}`:(a==="class"||a==="className")&&e.push(...String(I.value).split(/\s+/).filter(Boolean).slice(0,2)))}return`${i}${r}${e.map(o=>`.${o}`).join("")}`}function Le(t,i){for(let r of t.attributes??[]){if(r.type!=="JSXAttribute"||r.name?.name!==i)continue;let e=r.value;return e?.type==="JSXExpressionContainer"?e.expression:void 0}}function et(t,i={}){let r=(i.routesDir??"src/routes").replace(/^\.?\/+|\/+$/g,""),e=(i.apiDir??"src/api").replace(/^\.?\/+|\/+$/g,""),o=[],a=[],I=new Map,D=new Map,F=new Map,Q=[],te=[],Y=[],Z=new Map,ne=[],re=new Map,J=0;for(let n of t){if(!/\.(tsx?|jsx?)$/.test(n.path))continue;let s;try{s=De(n.code,{sourceType:"module",plugins:["jsx","typescript"],errorRecovery:!0}).program}catch{continue}let{primitives:g,shadowed:R}=fe(s),w=new Map,A=new Map,x=new Map;D.set(n.path,w),I.set(n.path,A),F.set(n.path,x);let Se=Ae(n.path).startsWith(`${r}/`),_=new Map,xe=null,ve=()=>xe??=_e(n.code);M(s,(c,f)=>{let d=je(c),u=c.loc?.start;if(!d||!u)return;let N=J++;_.set(c,N),w.set(d,N),re.set(N,B(c)),Se&&o.push(N),a.push({node:{id:N,label:d,kind:Pe.has(d)?"handler":"component",deps:[],writes:[],runs:0,lastPulse:0,source:{file:n.path,line:u.line,column:u.column}},reads:new Set,file:n.path})}),M(s,(c,f)=>{if(c.type==="ImportDeclaration"){let k=c.source?.value;for(let V of c.specifiers??[]){let $=V.local?.name;$&&k?.startsWith(".")&&x.set($,k)}return}if(c.type!=="CallExpression")return;let d=c.callee;if(d?.type!=="Identifier")return;let u=d.name,N=u.startsWith("$")&&ue(u)&&!R.has(u);if(!N&&!g.has(u))return;let l=Oe[N?u.slice(1):u],p=c.loc?.start;if(!l||!p)return;let y=J++,C=$e(f)??`${l}${y}`;w.set(C,y);let E;for(let k=f.length-1;k>=0;k--){let V=_.get(f[k]);if(V!==void 0){E=V;break}}a.push({node:{id:y,label:C,kind:l,deps:[],writes:[],runs:0,lastPulse:0,source:{file:n.path,line:p.line,column:p.column},...E!==void 0?{createdIn:E}:{}},reads:Te.has(l)?B(c.arguments?.[0]):new Set,file:n.path})}),M(s,(c,f)=>{if(c.type!=="JSXOpeningElement")return;let d=c.name?.name;if(!d||d[0]!==d[0]?.toUpperCase())return;let u;for(let l=f.length-1;l>=0;l--){let p=_.get(f[l]);if(p!==void 0){u=p;break}}if(!(w.has(d)||x.has(d))&&pe.has(d)){let l=c.loc?.start;if(!l)return;let p=J++,y=me[d],C=y?Le(c,y):void 0,E=f[f.length-1];E?.type==="JSXElement"&&_.set(E,p),a.push({node:{id:p,label:d,kind:ge(d),deps:[],writes:[],runs:0,lastPulse:0,source:{file:n.path,line:l.line,column:l.column},...u!==void 0?{createdIn:u}:{}},reads:C?B(C):new Set,file:n.path});return}u!==void 0&&Q.push({tag:d,file:n.path,owner:u})}),M(s,(c,f)=>{if(c.type!=="JSXExpressionContainer")return;let d=c.expression;if(!d||d.type==="JSXEmptyExpression")return;let u=d.loc?.start;if(!u)return;let N=f[f.length-1],l=N?.type==="JSXAttribute"?N.name?.name:void 0,p=[...f].reverse().find(E=>E.type==="JSXElement"||E.type==="JSXOpeningElement"),y=p?.type==="JSXOpeningElement"?p:p?.openingElement;if(!y)return;let C={kind:l?"attribute":"content",...l?{name:l}:{},element:ye(y),source:{file:n.path,line:u.line,column:u.column}};for(let E of B(d))Y.push({file:n.path,name:E,target:C})});let se=c=>{let f=c.openingElement??void 0,d=f?.name?.name;if(!f||!d)return;let u=c.loc?.start,N=u?{file:n.path,line:u.line,column:u.column}:void 0,l=[];for(let p of c.children??[]){if(p?.type!=="JSXElement")continue;let y=se(p);y&&l.push(y)}if(d[0]===d[0]?.toUpperCase()){let p={label:d,children:l,...N?{at:N}:{}},y=_.get(c)??w.get(d);return y!==void 0?p.owner=y:ne.push({node:p,tag:d,file:n.path}),p}return{label:ye(f),children:l,...N?{at:N}:{}}};M(s,(c,f)=>{if(c.type!=="JSXElement")return;let d;for(let l=f.length-1;l>=0;l--){let p=f[l];if(p.type==="JSXElement")return;let y=_.get(p);if(y!==void 0){d=y;break}}if(d===void 0)return;let u=se(c);if(!u)return;let N=Z.get(d);N?N.push(u):Z.set(d,[u])}),M(s,(c,f)=>{if(c.type!=="TaggedTemplateExpression")return;let d=c.tag?.name;if(d!=="html"&&d!=="svg")return;let u=c.quasi,N=u?.expressions??[],l=ve(),p;try{p=Me(Fe(u),{svg:d==="svg"}).root.children}catch{return}let y=v=>v==null?void 0:N[v],C=v=>{let m=y(v);return m?B(m):new Set},E=(v,m,b,h)=>{let S=m!==void 0?l(m):y(b)?.loc?.start??c.loc?.start;if(!S)return;let P=J++;return a.push({node:{id:P,label:v,kind:ge(v),deps:[],writes:[],runs:0,lastPulse:0,source:{file:n.path,line:S.line,column:S.column},...h!==void 0?{createdIn:h}:{}},reads:C(b),file:n.path}),P},k=(v,m,b)=>{let h=y(v),S=h?.loc?.start;if(!h||!S)return;let P={kind:b?"attribute":"content",...b?{name:b}:{},element:m,source:{file:n.path,line:S.line,column:S.column}};for(let j of B(h))Y.push({file:n.path,name:j,target:P})},V=v=>{let m=he(v);for(let b of v.attributes)switch(b.kind){case"Attribute":for(let h of Ne(b.value))k(h,m,b.name);break;case"PropertyBinding":case"BindDirective":k(b.hole,m,b.name);break;case"ClassDirective":k(b.hole,m,"class");break;case"StyleDirective":k(b.hole,m,"style");break;default:break}},$=(v,m,b)=>{for(let h of v)switch(h.kind){case"Element":{let S=h.attributes.find(O=>O.kind==="IfDirective"),P=h.attributes.find(O=>O.kind==="EachDirective"),j=m;S?.kind==="IfDirective"?j=E("Show",h.loc?.start,S.hole,m)??m:P?.kind==="EachDirective"&&(j=E("For",h.loc?.start,P.hole,m)??m),V(h),$(h.children,j,he(h));break}case"Component":{let S=h.tag,P=w.has(S)||x.has(S);if(S&&!P&&pe.has(S)){let j=me[S],O=j?h.attributes.find(ce=>"name"in ce&&ce.name===j):void 0,Ie=O&&"hole"in O?O.hole:O&&"value"in O?Ne(O.value)[0]:void 0,Ee=E(S,h.loc?.start,Ie,m);$(h.children,Ee??m,b);break}S&&m!==void 0&&Q.push({tag:S,file:n.path,owner:m}),$(h.children,m,b);break}case"Fragment":$(h.children,m,b);break;case"Expression":k(h.hole,b,void 0);break;default:break}},ae;for(let v=f.length-1;v>=0;v--){let m=_.get(f[v]);if(m!==void 0){ae=m;break}}$(p,ae,"template")}),M(s,(c,f)=>{if(c.type!=="ObjectProperty"||c.computed)return;let d=c.key?.name??c.key?.value;if(d!=="component"&&d!=="Component")return;let u=c.value;if(u?.type!=="Identifier")return;let l=[...f].reverse().find(p=>p.type==="VariableDeclarator")?.id?.name;l&&te.push({via:l,tag:u.name,file:n.path})}),M(s,c=>{if(!(c.type!=="ExportNamedDeclaration"&&c.type!=="ExportDefaultDeclaration"))for(let f of w.keys())A.set(f,w.get(f))})}let U=(n,s)=>{let g=D.get(n)?.get(s);if(g!==void 0)return g;let R=F.get(n)?.get(s);if(R)for(let[w,A]of I){if(!Ke(n,R,w))continue;let x=A.get(s);if(x!==void 0)return x}};for(let n of a){let s=new Set;for(let g of n.reads){let R=U(n.file,g);R!==void 0&&R!==n.node.id&&s.add(R)}n.node.deps=[...s]}let X=new Map;for(let n of I.values())for(let[s,g]of n)X.set(s,X.has(s)?null:g);let K=new Map(a.map(n=>[n.node.id,n.node]));for(let n of ne){let s=U(n.file,n.tag)??X.get(n.tag)??void 0;s!==void 0&&K.get(s)?.kind==="component"&&(n.node.owner=s)}for(let[n,s]of Z){let g=K.get(n);g&&s.length&&(g.dom=s)}for(let n of Y){let s=U(n.file,n.name),g=s!==void 0?K.get(s):void 0;!g||g.kind==="component"||(g.targets??=[]).push(n.target)}for(let n of te){let s=U(n.file,n.tag)??X.get(n.tag)??void 0;if(s===void 0)continue;let g=a.find(x=>x.file===n.file&&x.node.kind==="router"&&x.node.id!==s&&x.reads.has(n.via))?.node.id,R=a.find(x=>x.file===n.file&&(x.node.kind==="component"||x.node.kind==="handler")&&x.node.id!==s&&re.get(x.node.id)?.has(n.via))?.node.id,w=g??R,A=K.get(s);A&&A.createdIn===void 0&&w!==void 0&&(A.createdIn=w)}for(let n of Q){let s=U(n.file,n.tag)??X.get(n.tag)??void 0;if(s===void 0||s===n.owner)continue;let g=K.get(s);g&&g.kind==="component"&&g.createdIn===void 0&&(g.createdIn=n.owner)}let ie=(n,s)=>{let g=a.filter(R=>R.node.kind===n&&R.node.label===s);return g.length===1?g[0].node.id:void 0},ee=ie("router","Outlet")??ie("router","Router");if(ee!==void 0)for(let n of o){let s=K.get(n);s&&s.kind==="component"&&s.createdIn===void 0&&n!==ee&&(s.createdIn=ee)}let oe=a.filter(n=>n.node.kind==="handler"&&n.node.createdIn===void 0);if(oe.length>0){let n=J++;a.push({node:{id:n,label:"api",kind:"handler",deps:[],writes:[],runs:0,lastPulse:0,source:{file:e,line:1,column:0}},reads:new Set,file:e});for(let s of oe)s.node.createdIn=n}return{t:Date.now(),nodes:a.map(n=>n.node),static:!0}}var be=t=>t.replace(/\.(tsx?|jsx?|mts|cts|mjs|cjs)$/,"");function Ke(t,i,r){let e=t.includes("/")?t.slice(0,t.lastIndexOf("/")):"",o=(e?e.split("/"):[]).concat(i.split("/")),a=[];for(let F of o)F==="."||F===""||(F===".."?a.pop():a.push(F));let I=be(a.join("/")),D=be(r);return D===I||D===`${I}/index`}export{et as analyzeReactiveGraph};
|
|
1
|
+
/*! @fluixi/compiler v1.0.0-alpha.85 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
|
|
2
|
+
|
|
3
|
+
// src/analyze/static-graph.ts
|
|
4
|
+
import { parse } from "@babel/parser";
|
|
5
|
+
import {
|
|
6
|
+
parseTemplate
|
|
7
|
+
} from "@fluixi/template-parser";
|
|
8
|
+
|
|
9
|
+
// src/analyze/intrinsics.ts
|
|
10
|
+
var REACTIVE_MODULE = "@fluixi/reactive/signal";
|
|
11
|
+
var INTRINSICS = {
|
|
12
|
+
$signal: { export: "signal", module: REACTIVE_MODULE, returns: "signal-handle" },
|
|
13
|
+
$memo: { export: "memo", module: REACTIVE_MODULE, returns: "memo-handle" },
|
|
14
|
+
$effect: { export: "effect", module: REACTIVE_MODULE, returns: "effect" },
|
|
15
|
+
$store: { export: "store", module: "@fluixi/reactive/store", returns: "store-handle" },
|
|
16
|
+
$resource: { export: "resource", module: REACTIVE_MODULE, returns: "resource-handle" },
|
|
17
|
+
// No short runtime form for these yet, so the intrinsic stands for the `create*`
|
|
18
|
+
// name. Still worth having: no import to write, and when a shorter form is
|
|
19
|
+
// designed, the change is this line rather than a compiler pass.
|
|
20
|
+
$selector: { export: "createSelector", module: REACTIVE_MODULE, returns: "memo-accessor" },
|
|
21
|
+
$deferred: { export: "createDeferred", module: REACTIVE_MODULE, returns: "memo-accessor" },
|
|
22
|
+
// Not value constructors, but the compiler has to know them: they change what a read
|
|
23
|
+
// does. `untrack` suppresses dependency collection, which is exactly the kind of thing
|
|
24
|
+
// dependency analysis must not guess at.
|
|
25
|
+
$untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
|
|
26
|
+
$untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" }
|
|
27
|
+
};
|
|
28
|
+
var RUNTIME_PRIMITIVES = {
|
|
29
|
+
signal: "signal-handle",
|
|
30
|
+
memo: "memo-handle",
|
|
31
|
+
effect: "effect",
|
|
32
|
+
store: "store-handle",
|
|
33
|
+
createSignal: ["signal-accessor", "signal-setter"],
|
|
34
|
+
createMemo: "memo-accessor",
|
|
35
|
+
createEffect: "effect",
|
|
36
|
+
createRenderEffect: "effect",
|
|
37
|
+
createStore: "reactive-object",
|
|
38
|
+
resource: "resource-handle",
|
|
39
|
+
createResource: "reactive-object",
|
|
40
|
+
createSelector: "memo-accessor",
|
|
41
|
+
createDeferred: "memo-accessor"
|
|
42
|
+
};
|
|
43
|
+
var PRIMITIVE_MODULES = [
|
|
44
|
+
"@fluixi/reactive",
|
|
45
|
+
"@fluixi/reactive/signal",
|
|
46
|
+
"@fluixi/reactive/store",
|
|
47
|
+
"@fluixi/core"
|
|
48
|
+
];
|
|
49
|
+
var INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join("|")})\\s*\\(`);
|
|
50
|
+
function isIntrinsicName(name) {
|
|
51
|
+
return Object.prototype.hasOwnProperty.call(INTRINSICS, name);
|
|
52
|
+
}
|
|
53
|
+
function isPrimitiveModule(source) {
|
|
54
|
+
return PRIMITIVE_MODULES.includes(source);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// src/analyze/reactive-bindings.ts
|
|
58
|
+
function patternNames(node, out) {
|
|
59
|
+
if (!node) return;
|
|
60
|
+
switch (node.type) {
|
|
61
|
+
case "Identifier":
|
|
62
|
+
out.add(node.name);
|
|
63
|
+
return;
|
|
64
|
+
case "ObjectPattern":
|
|
65
|
+
for (const p of node.properties ?? []) {
|
|
66
|
+
if (p.type === "RestElement") patternNames(p.argument, out);
|
|
67
|
+
else patternNames(p.value, out);
|
|
68
|
+
}
|
|
69
|
+
return;
|
|
70
|
+
case "ArrayPattern":
|
|
71
|
+
for (const e of node.elements ?? []) patternNames(e, out);
|
|
72
|
+
return;
|
|
73
|
+
case "AssignmentPattern":
|
|
74
|
+
patternNames(node.left, out);
|
|
75
|
+
return;
|
|
76
|
+
case "RestElement":
|
|
77
|
+
patternNames(node.argument, out);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function walk(root, visit) {
|
|
82
|
+
if (!root || typeof root !== "object" || typeof root.type !== "string") return;
|
|
83
|
+
visit(root);
|
|
84
|
+
for (const key of Object.keys(root)) {
|
|
85
|
+
if (key === "loc" || key === "leadingComments" || key === "trailingComments") continue;
|
|
86
|
+
const value = root[key];
|
|
87
|
+
if (Array.isArray(value)) for (const item of value) walk(item, visit);
|
|
88
|
+
else if (value && typeof value === "object") walk(value, visit);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function calledPrimitive(node, bindings) {
|
|
92
|
+
if (node.type !== "CallExpression") return void 0;
|
|
93
|
+
const callee = node.callee;
|
|
94
|
+
if (callee?.type !== "Identifier") return void 0;
|
|
95
|
+
const name = callee.name;
|
|
96
|
+
const imported = bindings.primitives.get(name);
|
|
97
|
+
if (imported) return imported;
|
|
98
|
+
const intrinsic = INTRINSICS[name];
|
|
99
|
+
if (intrinsic && !bindings.shadowed.has(name)) return intrinsic.returns;
|
|
100
|
+
return void 0;
|
|
101
|
+
}
|
|
102
|
+
function classify(id, returns, kinds) {
|
|
103
|
+
if (Array.isArray(returns)) {
|
|
104
|
+
if (id.type === "ArrayPattern") {
|
|
105
|
+
id.elements.forEach((element, index) => {
|
|
106
|
+
const kind = returns[index];
|
|
107
|
+
if (element?.type === "Identifier" && kind) kinds.set(element.name, kind);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (id.type === "Identifier") kinds.set(id.name, returns);
|
|
113
|
+
}
|
|
114
|
+
function resolveReactiveBindings(program) {
|
|
115
|
+
const bindings = { kinds: /* @__PURE__ */ new Map(), primitives: /* @__PURE__ */ new Map(), shadowed: /* @__PURE__ */ new Set() };
|
|
116
|
+
const root = program;
|
|
117
|
+
walk(root, (node) => {
|
|
118
|
+
const names = /* @__PURE__ */ new Set();
|
|
119
|
+
if (node.type === "VariableDeclarator") patternNames(node.id, names);
|
|
120
|
+
else if (node.type === "FunctionDeclaration" || node.type === "ClassDeclaration") patternNames(node.id, names);
|
|
121
|
+
else if (node.type === "ImportDefaultSpecifier" || node.type === "ImportNamespaceSpecifier") patternNames(node.local, names);
|
|
122
|
+
else if (node.type === "ImportSpecifier") patternNames(node.local, names);
|
|
123
|
+
else if (node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression" || node.type === "FunctionDeclaration") {
|
|
124
|
+
for (const p of node.params ?? []) patternNames(p, names);
|
|
125
|
+
}
|
|
126
|
+
for (const name of names) if (INTRINSICS[name]) bindings.shadowed.add(name);
|
|
127
|
+
});
|
|
128
|
+
for (const statement of root.body ?? []) {
|
|
129
|
+
if (statement.type !== "ImportDeclaration") continue;
|
|
130
|
+
if (!isPrimitiveModule(statement.source?.value)) continue;
|
|
131
|
+
for (const specifier of statement.specifiers ?? []) {
|
|
132
|
+
if (specifier.type !== "ImportSpecifier") continue;
|
|
133
|
+
const importedNode = specifier.imported;
|
|
134
|
+
const imported = importedNode.type === "Identifier" ? importedNode.name : importedNode.value;
|
|
135
|
+
const returns = RUNTIME_PRIMITIVES[imported];
|
|
136
|
+
if (returns) bindings.primitives.set(specifier.local.name, returns);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
walk(root, (node) => {
|
|
140
|
+
if (node.type !== "VariableDeclarator" || !node.init) return;
|
|
141
|
+
const returns = calledPrimitive(node.init, bindings);
|
|
142
|
+
if (returns) classify(node.id, returns, bindings.kinds);
|
|
143
|
+
});
|
|
144
|
+
return bindings;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// src/resolve/builtins.ts
|
|
148
|
+
var DOM_CONTROL_FLOW = [
|
|
149
|
+
"Show",
|
|
150
|
+
"For",
|
|
151
|
+
"Index",
|
|
152
|
+
"Switch",
|
|
153
|
+
"Match",
|
|
154
|
+
"Portal",
|
|
155
|
+
"Dynamic",
|
|
156
|
+
"ErrorBoundary"
|
|
157
|
+
];
|
|
158
|
+
var CORE_CONTROL_FLOW = ["Suspense", "SuspenseList", "Await"];
|
|
159
|
+
var ROUTER_COMPONENTS = ["Router", "Outlet", "Redirect", "Link"];
|
|
160
|
+
var BUILTIN_COMPONENTS = [
|
|
161
|
+
...DOM_CONTROL_FLOW,
|
|
162
|
+
...CORE_CONTROL_FLOW,
|
|
163
|
+
...ROUTER_COMPONENTS
|
|
164
|
+
];
|
|
165
|
+
var RESERVED_COMPONENTS = /* @__PURE__ */ new Set([
|
|
166
|
+
...DOM_CONTROL_FLOW,
|
|
167
|
+
...CORE_CONTROL_FLOW
|
|
168
|
+
]);
|
|
169
|
+
|
|
170
|
+
// src/analyze/static-graph.ts
|
|
171
|
+
var PRIMITIVE_KIND = {
|
|
172
|
+
signal: "state",
|
|
173
|
+
createSignal: "state",
|
|
174
|
+
memo: "memo",
|
|
175
|
+
createMemo: "memo",
|
|
176
|
+
effect: "effect",
|
|
177
|
+
createEffect: "effect",
|
|
178
|
+
store: "store",
|
|
179
|
+
createStore: "store",
|
|
180
|
+
resource: "resource",
|
|
181
|
+
createResource: "resource"
|
|
182
|
+
};
|
|
183
|
+
var READS = /* @__PURE__ */ new Set(["memo", "effect", "resource"]);
|
|
184
|
+
var DIRECTIVES = /* @__PURE__ */ new Set([
|
|
185
|
+
...DOM_CONTROL_FLOW,
|
|
186
|
+
...CORE_CONTROL_FLOW,
|
|
187
|
+
// The router is supplied without an import too. Without these, an app whose root renders
|
|
188
|
+
// `<Router>` has a root component connected to nothing at all.
|
|
189
|
+
...ROUTER_COMPONENTS
|
|
190
|
+
]);
|
|
191
|
+
var TRACKED_PROP = {
|
|
192
|
+
Router: "routes",
|
|
193
|
+
Link: "href",
|
|
194
|
+
Redirect: "to",
|
|
195
|
+
Show: "when",
|
|
196
|
+
Match: "when",
|
|
197
|
+
For: "each",
|
|
198
|
+
Index: "each",
|
|
199
|
+
Dynamic: "component",
|
|
200
|
+
Portal: "mount",
|
|
201
|
+
Await: "value"
|
|
202
|
+
};
|
|
203
|
+
var ROUTER = new Set(ROUTER_COMPONENTS);
|
|
204
|
+
var directiveKind = (tag) => ROUTER.has(tag) ? "router" : "control";
|
|
205
|
+
var HTTP_METHODS = /* @__PURE__ */ new Set([
|
|
206
|
+
"GET",
|
|
207
|
+
"POST",
|
|
208
|
+
"PUT",
|
|
209
|
+
"PATCH",
|
|
210
|
+
"DELETE",
|
|
211
|
+
"HEAD",
|
|
212
|
+
"OPTIONS"
|
|
213
|
+
]);
|
|
214
|
+
function normalizePath(path) {
|
|
215
|
+
return path.replace(/\\/g, "/").replace(/^\.?\/+/, "");
|
|
216
|
+
}
|
|
217
|
+
function walk2(node, visit, stack = []) {
|
|
218
|
+
if (!node || typeof node.type !== "string") return;
|
|
219
|
+
visit(node, stack);
|
|
220
|
+
stack.push(node);
|
|
221
|
+
for (const key of Object.keys(node)) {
|
|
222
|
+
if (key === "loc" || key === "parent") continue;
|
|
223
|
+
const value = node[key];
|
|
224
|
+
if (Array.isArray(value)) for (const child of value) walk2(child, visit, stack);
|
|
225
|
+
else if (value && typeof value.type === "string") walk2(value, visit, stack);
|
|
226
|
+
}
|
|
227
|
+
stack.pop();
|
|
228
|
+
}
|
|
229
|
+
function declaredName(stack) {
|
|
230
|
+
const declarator = [...stack].reverse().find((n) => n.type === "VariableDeclarator");
|
|
231
|
+
const id = declarator?.id;
|
|
232
|
+
if (id?.type === "Identifier") return id.name;
|
|
233
|
+
if (id?.type === "ArrayPattern") {
|
|
234
|
+
const first = id.elements?.[0];
|
|
235
|
+
if (first?.type === "Identifier") return first.name;
|
|
236
|
+
}
|
|
237
|
+
return void 0;
|
|
238
|
+
}
|
|
239
|
+
function componentName(node) {
|
|
240
|
+
if (node.type === "FunctionDeclaration") {
|
|
241
|
+
const name = node.id?.name;
|
|
242
|
+
return name && name[0] === name[0]?.toUpperCase() ? name : void 0;
|
|
243
|
+
}
|
|
244
|
+
if (node.type === "VariableDeclarator") {
|
|
245
|
+
const id = node.id;
|
|
246
|
+
const init = node.init;
|
|
247
|
+
if (id?.type !== "Identifier" || !init) return void 0;
|
|
248
|
+
if (init.type !== "ArrowFunctionExpression" && init.type !== "FunctionExpression") return void 0;
|
|
249
|
+
const name = id.name;
|
|
250
|
+
return name[0] === name[0]?.toUpperCase() ? name : void 0;
|
|
251
|
+
}
|
|
252
|
+
return void 0;
|
|
253
|
+
}
|
|
254
|
+
function mentions(node) {
|
|
255
|
+
const names = /* @__PURE__ */ new Set();
|
|
256
|
+
walk2(node, (n, stack) => {
|
|
257
|
+
if (n.type !== "Identifier") return;
|
|
258
|
+
const parent = stack[stack.length - 1];
|
|
259
|
+
if (parent?.type === "MemberExpression" && parent.property === n && !parent.computed) return;
|
|
260
|
+
if (parent?.type === "ObjectProperty" && parent.key === n && !parent.computed) return;
|
|
261
|
+
names.add(n.name);
|
|
262
|
+
});
|
|
263
|
+
return names;
|
|
264
|
+
}
|
|
265
|
+
function templatePieces(quasi) {
|
|
266
|
+
const pieces = [];
|
|
267
|
+
const quasis = quasi.quasis ?? [];
|
|
268
|
+
const expressions = quasi.expressions ?? [];
|
|
269
|
+
quasis.forEach((q, i) => {
|
|
270
|
+
const value = q.value;
|
|
271
|
+
pieces.push({ kind: "static", text: value?.cooked ?? value?.raw ?? "", start: q.start ?? 0 });
|
|
272
|
+
if (i < expressions.length) {
|
|
273
|
+
const e = expressions[i];
|
|
274
|
+
pieces.push({ kind: "hole", index: i, start: e.start ?? 0, end: e.end ?? 0 });
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
return pieces;
|
|
278
|
+
}
|
|
279
|
+
function positionsIn(code) {
|
|
280
|
+
const starts = [0];
|
|
281
|
+
for (let i = 0; i < code.length; i++) if (code.charCodeAt(i) === 10) starts.push(i + 1);
|
|
282
|
+
return (offset) => {
|
|
283
|
+
let low = 0;
|
|
284
|
+
let high = starts.length - 1;
|
|
285
|
+
while (low < high) {
|
|
286
|
+
const mid = low + high + 1 >> 1;
|
|
287
|
+
if (starts[mid] <= offset) low = mid;
|
|
288
|
+
else high = mid - 1;
|
|
289
|
+
}
|
|
290
|
+
return { line: low + 1, column: offset - starts[low] };
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
function describeTemplateElement(el) {
|
|
294
|
+
let id = "";
|
|
295
|
+
const classes = [];
|
|
296
|
+
for (const attr of el.attributes) {
|
|
297
|
+
if (attr.kind !== "Attribute" || attr.value?.kind !== "static") continue;
|
|
298
|
+
if (attr.name === "id") id = `#${attr.value.value}`;
|
|
299
|
+
else if (attr.name === "class") {
|
|
300
|
+
classes.push(...String(attr.value.value).split(/\s+/).filter(Boolean).slice(0, 2));
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return `${el.tag}${id}${classes.map((c) => `.${c}`).join("")}`;
|
|
304
|
+
}
|
|
305
|
+
function valueHoles(value) {
|
|
306
|
+
if (!value) return [];
|
|
307
|
+
if (value.kind === "hole") return [value.hole];
|
|
308
|
+
if (value.kind === "mixed") return value.parts.flatMap((p) => "hole" in p ? [p.hole] : []);
|
|
309
|
+
return [];
|
|
310
|
+
}
|
|
311
|
+
function describeJsx(opening) {
|
|
312
|
+
const tag = opening.name?.name ?? "element";
|
|
313
|
+
let id = "";
|
|
314
|
+
const classes = [];
|
|
315
|
+
for (const attr of opening.attributes ?? []) {
|
|
316
|
+
if (attr.type !== "JSXAttribute") continue;
|
|
317
|
+
const name = attr.name?.name;
|
|
318
|
+
const value = attr.value;
|
|
319
|
+
if (value?.type !== "StringLiteral") continue;
|
|
320
|
+
if (name === "id") id = `#${value.value}`;
|
|
321
|
+
else if (name === "class" || name === "className") {
|
|
322
|
+
classes.push(...String(value.value).split(/\s+/).filter(Boolean).slice(0, 2));
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return `${tag}${id}${classes.map((c) => `.${c}`).join("")}`;
|
|
326
|
+
}
|
|
327
|
+
function trackedExpression(opening, prop) {
|
|
328
|
+
for (const attr of opening.attributes ?? []) {
|
|
329
|
+
if (attr.type !== "JSXAttribute" || attr.name?.name !== prop) continue;
|
|
330
|
+
const value = attr.value;
|
|
331
|
+
return value?.type === "JSXExpressionContainer" ? value.expression : void 0;
|
|
332
|
+
}
|
|
333
|
+
return void 0;
|
|
334
|
+
}
|
|
335
|
+
function analyzeReactiveGraph(files, options = {}) {
|
|
336
|
+
const routesDir = (options.routesDir ?? "src/routes").replace(/^\.?\/+|\/+$/g, "");
|
|
337
|
+
const apiDir = (options.apiDir ?? "src/api").replace(/^\.?\/+|\/+$/g, "");
|
|
338
|
+
const fileRoutes = [];
|
|
339
|
+
const pending = [];
|
|
340
|
+
const exported = /* @__PURE__ */ new Map();
|
|
341
|
+
const locals = /* @__PURE__ */ new Map();
|
|
342
|
+
const imports = /* @__PURE__ */ new Map();
|
|
343
|
+
const usages = [];
|
|
344
|
+
const routeRefs = [];
|
|
345
|
+
const holes = [];
|
|
346
|
+
const domFor = /* @__PURE__ */ new Map();
|
|
347
|
+
const unresolved = [];
|
|
348
|
+
const componentMentions = /* @__PURE__ */ new Map();
|
|
349
|
+
let seq = 0;
|
|
350
|
+
for (const file of files) {
|
|
351
|
+
if (!/\.(tsx?|jsx?)$/.test(file.path)) continue;
|
|
352
|
+
let program;
|
|
353
|
+
try {
|
|
354
|
+
program = parse(file.code, {
|
|
355
|
+
sourceType: "module",
|
|
356
|
+
plugins: ["jsx", "typescript"],
|
|
357
|
+
errorRecovery: true
|
|
358
|
+
}).program;
|
|
359
|
+
} catch {
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
const { primitives, shadowed } = resolveReactiveBindings(program);
|
|
363
|
+
const here = /* @__PURE__ */ new Map();
|
|
364
|
+
const sold = /* @__PURE__ */ new Map();
|
|
365
|
+
const from = /* @__PURE__ */ new Map();
|
|
366
|
+
locals.set(file.path, here);
|
|
367
|
+
exported.set(file.path, sold);
|
|
368
|
+
imports.set(file.path, from);
|
|
369
|
+
const inRoutesDir = normalizePath(file.path).startsWith(`${routesDir}/`);
|
|
370
|
+
const components = /* @__PURE__ */ new Map();
|
|
371
|
+
let positionAt = null;
|
|
372
|
+
const positionOf = () => positionAt ??= positionsIn(file.code);
|
|
373
|
+
walk2(program, (node, stack) => {
|
|
374
|
+
const name = componentName(node);
|
|
375
|
+
const at = node.loc?.start;
|
|
376
|
+
if (!name || !at) return;
|
|
377
|
+
const id = seq++;
|
|
378
|
+
components.set(node, id);
|
|
379
|
+
here.set(name, id);
|
|
380
|
+
componentMentions.set(id, mentions(node));
|
|
381
|
+
if (inRoutesDir) fileRoutes.push(id);
|
|
382
|
+
pending.push({
|
|
383
|
+
node: {
|
|
384
|
+
id,
|
|
385
|
+
label: name,
|
|
386
|
+
kind: HTTP_METHODS.has(name) ? "handler" : "component",
|
|
387
|
+
deps: [],
|
|
388
|
+
writes: [],
|
|
389
|
+
runs: 0,
|
|
390
|
+
lastPulse: 0,
|
|
391
|
+
source: { file: file.path, line: at.line, column: at.column }
|
|
392
|
+
},
|
|
393
|
+
reads: /* @__PURE__ */ new Set(),
|
|
394
|
+
file: file.path
|
|
395
|
+
});
|
|
396
|
+
});
|
|
397
|
+
walk2(program, (node, stack) => {
|
|
398
|
+
if (node.type === "ImportDeclaration") {
|
|
399
|
+
const source = node.source?.value;
|
|
400
|
+
for (const spec of node.specifiers ?? []) {
|
|
401
|
+
const local = spec.local?.name;
|
|
402
|
+
if (local && source?.startsWith(".")) from.set(local, source);
|
|
403
|
+
}
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
if (node.type !== "CallExpression") return;
|
|
407
|
+
const callee = node.callee;
|
|
408
|
+
if (callee?.type !== "Identifier") return;
|
|
409
|
+
const name = callee.name;
|
|
410
|
+
const intrinsic = name.startsWith("$") && isIntrinsicName(name) && !shadowed.has(name);
|
|
411
|
+
if (!intrinsic && !primitives.has(name)) return;
|
|
412
|
+
const kind = PRIMITIVE_KIND[intrinsic ? name.slice(1) : name];
|
|
413
|
+
const at = node.loc?.start;
|
|
414
|
+
if (!kind || !at) return;
|
|
415
|
+
const id = seq++;
|
|
416
|
+
const label = declaredName(stack) ?? `${kind}${id}`;
|
|
417
|
+
here.set(label, id);
|
|
418
|
+
let owner;
|
|
419
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
420
|
+
const found = components.get(stack[i]);
|
|
421
|
+
if (found !== void 0) {
|
|
422
|
+
owner = found;
|
|
423
|
+
break;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
pending.push({
|
|
427
|
+
node: {
|
|
428
|
+
id,
|
|
429
|
+
label,
|
|
430
|
+
kind,
|
|
431
|
+
deps: [],
|
|
432
|
+
writes: [],
|
|
433
|
+
runs: 0,
|
|
434
|
+
lastPulse: 0,
|
|
435
|
+
source: { file: file.path, line: at.line, column: at.column },
|
|
436
|
+
...owner !== void 0 ? { createdIn: owner } : {}
|
|
437
|
+
},
|
|
438
|
+
// Only what reads can read: a signal's initial value is not a dependency.
|
|
439
|
+
reads: READS.has(kind) ? mentions(node.arguments?.[0]) : /* @__PURE__ */ new Set(),
|
|
440
|
+
file: file.path
|
|
441
|
+
});
|
|
442
|
+
});
|
|
443
|
+
walk2(program, (node, stack) => {
|
|
444
|
+
if (node.type !== "JSXOpeningElement") return;
|
|
445
|
+
const tag = node.name?.name;
|
|
446
|
+
if (!tag || tag[0] !== tag[0]?.toUpperCase()) return;
|
|
447
|
+
let owner;
|
|
448
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
449
|
+
const found = components.get(stack[i]);
|
|
450
|
+
if (found !== void 0) {
|
|
451
|
+
owner = found;
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
const own = here.has(tag) || from.has(tag);
|
|
456
|
+
if (!own && DIRECTIVES.has(tag)) {
|
|
457
|
+
const at = node.loc?.start;
|
|
458
|
+
if (!at) return;
|
|
459
|
+
const id = seq++;
|
|
460
|
+
const prop = TRACKED_PROP[tag];
|
|
461
|
+
const tracked = prop ? trackedExpression(node, prop) : void 0;
|
|
462
|
+
const element = stack[stack.length - 1];
|
|
463
|
+
if (element?.type === "JSXElement") components.set(element, id);
|
|
464
|
+
pending.push({
|
|
465
|
+
node: {
|
|
466
|
+
id,
|
|
467
|
+
label: tag,
|
|
468
|
+
kind: directiveKind(tag),
|
|
469
|
+
deps: [],
|
|
470
|
+
writes: [],
|
|
471
|
+
runs: 0,
|
|
472
|
+
lastPulse: 0,
|
|
473
|
+
source: { file: file.path, line: at.line, column: at.column },
|
|
474
|
+
...owner !== void 0 ? { createdIn: owner } : {}
|
|
475
|
+
},
|
|
476
|
+
reads: tracked ? mentions(tracked) : /* @__PURE__ */ new Set(),
|
|
477
|
+
file: file.path
|
|
478
|
+
});
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
if (owner !== void 0) usages.push({ tag, file: file.path, owner });
|
|
482
|
+
});
|
|
483
|
+
walk2(program, (node, stack) => {
|
|
484
|
+
if (node.type !== "JSXExpressionContainer") return;
|
|
485
|
+
const expr = node.expression;
|
|
486
|
+
if (!expr || expr.type === "JSXEmptyExpression") return;
|
|
487
|
+
const at = expr.loc?.start;
|
|
488
|
+
if (!at) return;
|
|
489
|
+
const parent = stack[stack.length - 1];
|
|
490
|
+
const attribute = parent?.type === "JSXAttribute" ? parent.name?.name : void 0;
|
|
491
|
+
const holder = [...stack].reverse().find((n) => n.type === "JSXElement" || n.type === "JSXOpeningElement");
|
|
492
|
+
const opening = holder?.type === "JSXOpeningElement" ? holder : holder?.openingElement;
|
|
493
|
+
if (!opening) return;
|
|
494
|
+
const target = {
|
|
495
|
+
kind: attribute ? "attribute" : "content",
|
|
496
|
+
...attribute ? { name: attribute } : {},
|
|
497
|
+
element: describeJsx(opening),
|
|
498
|
+
source: { file: file.path, line: at.line, column: at.column }
|
|
499
|
+
};
|
|
500
|
+
for (const name of mentions(expr)) holes.push({ file: file.path, name, target });
|
|
501
|
+
});
|
|
502
|
+
const describeTree = (el) => {
|
|
503
|
+
const opening = el.openingElement ?? void 0;
|
|
504
|
+
const tag = opening?.name?.name;
|
|
505
|
+
if (!opening || !tag) return void 0;
|
|
506
|
+
const at = el.loc?.start;
|
|
507
|
+
const where = at ? { file: file.path, line: at.line, column: at.column } : void 0;
|
|
508
|
+
const children = [];
|
|
509
|
+
for (const child of el.children ?? []) {
|
|
510
|
+
if (child?.type !== "JSXElement") continue;
|
|
511
|
+
const sub = describeTree(child);
|
|
512
|
+
if (sub) children.push(sub);
|
|
513
|
+
}
|
|
514
|
+
if (tag[0] === tag[0]?.toUpperCase()) {
|
|
515
|
+
const node = { label: tag, children, ...where ? { at: where } : {} };
|
|
516
|
+
const id = components.get(el) ?? here.get(tag);
|
|
517
|
+
if (id !== void 0) node.owner = id;
|
|
518
|
+
else unresolved.push({ node, tag, file: file.path });
|
|
519
|
+
return node;
|
|
520
|
+
}
|
|
521
|
+
return { label: describeJsx(opening), children, ...where ? { at: where } : {} };
|
|
522
|
+
};
|
|
523
|
+
walk2(program, (node, stack) => {
|
|
524
|
+
if (node.type !== "JSXElement") return;
|
|
525
|
+
let owner;
|
|
526
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
527
|
+
const found = stack[i];
|
|
528
|
+
if (found.type === "JSXElement") return;
|
|
529
|
+
const id = components.get(found);
|
|
530
|
+
if (id !== void 0) {
|
|
531
|
+
owner = id;
|
|
532
|
+
break;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
if (owner === void 0) return;
|
|
536
|
+
const tree = describeTree(node);
|
|
537
|
+
if (!tree) return;
|
|
538
|
+
const held = domFor.get(owner);
|
|
539
|
+
if (held) held.push(tree);
|
|
540
|
+
else domFor.set(owner, [tree]);
|
|
541
|
+
});
|
|
542
|
+
walk2(program, (node, stack) => {
|
|
543
|
+
if (node.type !== "TaggedTemplateExpression") return;
|
|
544
|
+
const tagName = node.tag?.name;
|
|
545
|
+
if (tagName !== "html" && tagName !== "svg") return;
|
|
546
|
+
const quasi = node.quasi;
|
|
547
|
+
const expressions = quasi?.expressions ?? [];
|
|
548
|
+
const positionAt2 = positionOf();
|
|
549
|
+
let children;
|
|
550
|
+
try {
|
|
551
|
+
children = parseTemplate(templatePieces(quasi), { svg: tagName === "svg" }).root.children;
|
|
552
|
+
} catch {
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
const holeExpr = (index) => index == null ? void 0 : expressions[index];
|
|
556
|
+
const readsOf = (index) => {
|
|
557
|
+
const expr = holeExpr(index);
|
|
558
|
+
return expr ? mentions(expr) : /* @__PURE__ */ new Set();
|
|
559
|
+
};
|
|
560
|
+
const addControl = (tag, offset, hole, owner2) => {
|
|
561
|
+
const at = offset !== void 0 ? positionAt2(offset) : holeExpr(hole)?.loc?.start ?? node.loc?.start;
|
|
562
|
+
if (!at) return void 0;
|
|
563
|
+
const id = seq++;
|
|
564
|
+
pending.push({
|
|
565
|
+
node: {
|
|
566
|
+
id,
|
|
567
|
+
label: tag,
|
|
568
|
+
kind: directiveKind(tag),
|
|
569
|
+
deps: [],
|
|
570
|
+
writes: [],
|
|
571
|
+
runs: 0,
|
|
572
|
+
lastPulse: 0,
|
|
573
|
+
source: { file: file.path, line: at.line, column: at.column },
|
|
574
|
+
...owner2 !== void 0 ? { createdIn: owner2 } : {}
|
|
575
|
+
},
|
|
576
|
+
reads: readsOf(hole),
|
|
577
|
+
file: file.path
|
|
578
|
+
});
|
|
579
|
+
return id;
|
|
580
|
+
};
|
|
581
|
+
const addTarget = (index, element, attribute) => {
|
|
582
|
+
const expr = holeExpr(index);
|
|
583
|
+
const at = expr?.loc?.start;
|
|
584
|
+
if (!expr || !at) return;
|
|
585
|
+
const target = {
|
|
586
|
+
kind: attribute ? "attribute" : "content",
|
|
587
|
+
...attribute ? { name: attribute } : {},
|
|
588
|
+
element,
|
|
589
|
+
source: { file: file.path, line: at.line, column: at.column }
|
|
590
|
+
};
|
|
591
|
+
for (const name of mentions(expr)) holes.push({ file: file.path, name, target });
|
|
592
|
+
};
|
|
593
|
+
const elementTargets = (el) => {
|
|
594
|
+
const element = describeTemplateElement(el);
|
|
595
|
+
for (const attr of el.attributes) {
|
|
596
|
+
switch (attr.kind) {
|
|
597
|
+
case "Attribute":
|
|
598
|
+
for (const hole of valueHoles(attr.value)) addTarget(hole, element, attr.name);
|
|
599
|
+
break;
|
|
600
|
+
case "PropertyBinding":
|
|
601
|
+
case "BindDirective":
|
|
602
|
+
addTarget(attr.hole, element, attr.name);
|
|
603
|
+
break;
|
|
604
|
+
case "ClassDirective":
|
|
605
|
+
addTarget(attr.hole, element, "class");
|
|
606
|
+
break;
|
|
607
|
+
case "StyleDirective":
|
|
608
|
+
addTarget(attr.hole, element, "style");
|
|
609
|
+
break;
|
|
610
|
+
// A handler is not a read, and neither is a ref, a spread or a use.
|
|
611
|
+
default:
|
|
612
|
+
break;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
};
|
|
616
|
+
const visit = (nodes, owner2, holder) => {
|
|
617
|
+
for (const child of nodes) {
|
|
618
|
+
switch (child.kind) {
|
|
619
|
+
case "Element": {
|
|
620
|
+
const ifDir = child.attributes.find((a) => a.kind === "IfDirective");
|
|
621
|
+
const eachDir = child.attributes.find((a) => a.kind === "EachDirective");
|
|
622
|
+
let inner = owner2;
|
|
623
|
+
if (ifDir?.kind === "IfDirective") inner = addControl("Show", child.loc?.start, ifDir.hole, owner2) ?? owner2;
|
|
624
|
+
else if (eachDir?.kind === "EachDirective") inner = addControl("For", child.loc?.start, eachDir.hole, owner2) ?? owner2;
|
|
625
|
+
elementTargets(child);
|
|
626
|
+
visit(child.children, inner, describeTemplateElement(child));
|
|
627
|
+
break;
|
|
628
|
+
}
|
|
629
|
+
case "Component": {
|
|
630
|
+
const tag = child.tag;
|
|
631
|
+
const own = here.has(tag) || from.has(tag);
|
|
632
|
+
if (tag && !own && DIRECTIVES.has(tag)) {
|
|
633
|
+
const prop = TRACKED_PROP[tag];
|
|
634
|
+
const tracked = prop ? child.attributes.find(
|
|
635
|
+
(a) => "name" in a && a.name === prop
|
|
636
|
+
) : void 0;
|
|
637
|
+
const hole = tracked && "hole" in tracked ? tracked.hole : tracked && "value" in tracked ? valueHoles(tracked.value)[0] : void 0;
|
|
638
|
+
const id = addControl(tag, child.loc?.start, hole, owner2);
|
|
639
|
+
visit(child.children, id ?? owner2, holder);
|
|
640
|
+
break;
|
|
641
|
+
}
|
|
642
|
+
if (tag && owner2 !== void 0) usages.push({ tag, file: file.path, owner: owner2 });
|
|
643
|
+
visit(child.children, owner2, holder);
|
|
644
|
+
break;
|
|
645
|
+
}
|
|
646
|
+
case "Fragment":
|
|
647
|
+
visit(child.children, owner2, holder);
|
|
648
|
+
break;
|
|
649
|
+
case "Expression":
|
|
650
|
+
addTarget(child.hole, holder, void 0);
|
|
651
|
+
break;
|
|
652
|
+
default:
|
|
653
|
+
break;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
};
|
|
657
|
+
let owner;
|
|
658
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
659
|
+
const found = components.get(stack[i]);
|
|
660
|
+
if (found !== void 0) {
|
|
661
|
+
owner = found;
|
|
662
|
+
break;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
visit(children, owner, "template");
|
|
666
|
+
});
|
|
667
|
+
walk2(program, (node, stack) => {
|
|
668
|
+
if (node.type !== "ObjectProperty" || node.computed) return;
|
|
669
|
+
const key = node.key?.name ?? node.key?.value;
|
|
670
|
+
if (key !== "component" && key !== "Component") return;
|
|
671
|
+
const value = node.value;
|
|
672
|
+
if (value?.type !== "Identifier") return;
|
|
673
|
+
const holder = [...stack].reverse().find((n) => n.type === "VariableDeclarator");
|
|
674
|
+
const via = holder?.id?.name;
|
|
675
|
+
if (via) routeRefs.push({ via, tag: value.name, file: file.path });
|
|
676
|
+
});
|
|
677
|
+
walk2(program, (node) => {
|
|
678
|
+
if (node.type !== "ExportNamedDeclaration" && node.type !== "ExportDefaultDeclaration") return;
|
|
679
|
+
for (const name of here.keys()) sold.set(name, here.get(name));
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
const resolve = (file, name) => {
|
|
683
|
+
const local = locals.get(file)?.get(name);
|
|
684
|
+
if (local !== void 0) return local;
|
|
685
|
+
const source = imports.get(file)?.get(name);
|
|
686
|
+
if (!source) return void 0;
|
|
687
|
+
for (const [path, names] of exported) {
|
|
688
|
+
if (!sameModule(file, source, path)) continue;
|
|
689
|
+
const id = names.get(name);
|
|
690
|
+
if (id !== void 0) return id;
|
|
691
|
+
}
|
|
692
|
+
return void 0;
|
|
693
|
+
};
|
|
694
|
+
for (const entry of pending) {
|
|
695
|
+
const deps = /* @__PURE__ */ new Set();
|
|
696
|
+
for (const name of entry.reads) {
|
|
697
|
+
const id = resolve(entry.file, name);
|
|
698
|
+
if (id !== void 0 && id !== entry.node.id) deps.add(id);
|
|
699
|
+
}
|
|
700
|
+
entry.node.deps = [...deps];
|
|
701
|
+
}
|
|
702
|
+
const unique = /* @__PURE__ */ new Map();
|
|
703
|
+
for (const names of exported.values()) {
|
|
704
|
+
for (const [name, id] of names) unique.set(name, unique.has(name) ? null : id);
|
|
705
|
+
}
|
|
706
|
+
const byId = new Map(pending.map((p) => [p.node.id, p.node]));
|
|
707
|
+
for (const entry of unresolved) {
|
|
708
|
+
const id = resolve(entry.file, entry.tag) ?? unique.get(entry.tag) ?? void 0;
|
|
709
|
+
if (id !== void 0 && byId.get(id)?.kind === "component") entry.node.owner = id;
|
|
710
|
+
}
|
|
711
|
+
for (const [id, dom] of domFor) {
|
|
712
|
+
const node = byId.get(id);
|
|
713
|
+
if (node && dom.length) node.dom = dom;
|
|
714
|
+
}
|
|
715
|
+
for (const hole of holes) {
|
|
716
|
+
const id = resolve(hole.file, hole.name);
|
|
717
|
+
const node = id !== void 0 ? byId.get(id) : void 0;
|
|
718
|
+
if (!node || node.kind === "component") continue;
|
|
719
|
+
(node.targets ??= []).push(hole.target);
|
|
720
|
+
}
|
|
721
|
+
for (const ref of routeRefs) {
|
|
722
|
+
const named = resolve(ref.file, ref.tag) ?? unique.get(ref.tag) ?? void 0;
|
|
723
|
+
if (named === void 0) continue;
|
|
724
|
+
const router = pending.find(
|
|
725
|
+
(p) => p.file === ref.file && p.node.kind === "router" && p.node.id !== named && p.reads.has(ref.via)
|
|
726
|
+
)?.node.id;
|
|
727
|
+
const mentions2 = pending.find(
|
|
728
|
+
(p) => p.file === ref.file && (p.node.kind === "component" || p.node.kind === "handler") && p.node.id !== named && componentMentions.get(p.node.id)?.has(ref.via)
|
|
729
|
+
)?.node.id;
|
|
730
|
+
const holder = router ?? mentions2;
|
|
731
|
+
const node = byId.get(named);
|
|
732
|
+
if (node && node.createdIn === void 0 && holder !== void 0) node.createdIn = holder;
|
|
733
|
+
}
|
|
734
|
+
for (const use of usages) {
|
|
735
|
+
const id = resolve(use.file, use.tag) ?? unique.get(use.tag) ?? void 0;
|
|
736
|
+
if (id === void 0 || id === use.owner) continue;
|
|
737
|
+
const node = byId.get(id);
|
|
738
|
+
if (node && node.kind === "component" && node.createdIn === void 0) node.createdIn = use.owner;
|
|
739
|
+
}
|
|
740
|
+
const only = (kind, label) => {
|
|
741
|
+
const found = pending.filter((p) => p.node.kind === kind && p.node.label === label);
|
|
742
|
+
return found.length === 1 ? found[0].node.id : void 0;
|
|
743
|
+
};
|
|
744
|
+
const routeOwner = only("router", "Outlet") ?? only("router", "Router");
|
|
745
|
+
if (routeOwner !== void 0) {
|
|
746
|
+
for (const id of fileRoutes) {
|
|
747
|
+
const node = byId.get(id);
|
|
748
|
+
if (node && node.kind === "component" && node.createdIn === void 0 && id !== routeOwner) {
|
|
749
|
+
node.createdIn = routeOwner;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
const loose = pending.filter(
|
|
754
|
+
(p) => p.node.kind === "handler" && p.node.createdIn === void 0
|
|
755
|
+
);
|
|
756
|
+
if (loose.length > 0) {
|
|
757
|
+
const id = seq++;
|
|
758
|
+
pending.push({
|
|
759
|
+
node: {
|
|
760
|
+
id,
|
|
761
|
+
label: "api",
|
|
762
|
+
kind: "handler",
|
|
763
|
+
deps: [],
|
|
764
|
+
writes: [],
|
|
765
|
+
runs: 0,
|
|
766
|
+
lastPulse: 0,
|
|
767
|
+
// The directory, since there is no line of anyone's source to point at.
|
|
768
|
+
source: { file: apiDir, line: 1, column: 0 }
|
|
769
|
+
},
|
|
770
|
+
reads: /* @__PURE__ */ new Set(),
|
|
771
|
+
file: apiDir
|
|
772
|
+
});
|
|
773
|
+
for (const p of loose) p.node.createdIn = id;
|
|
774
|
+
}
|
|
775
|
+
return { t: Date.now(), nodes: pending.map((p) => p.node), static: true };
|
|
776
|
+
}
|
|
777
|
+
var withoutExtension = (path) => path.replace(/\.(tsx?|jsx?|mts|cts|mjs|cjs)$/, "");
|
|
778
|
+
function sameModule(importer, specifier, candidate) {
|
|
779
|
+
const base = importer.includes("/") ? importer.slice(0, importer.lastIndexOf("/")) : "";
|
|
780
|
+
const parts = (base ? base.split("/") : []).concat(specifier.split("/"));
|
|
781
|
+
const stack = [];
|
|
782
|
+
for (const part of parts) {
|
|
783
|
+
if (part === "." || part === "") continue;
|
|
784
|
+
if (part === "..") stack.pop();
|
|
785
|
+
else stack.push(part);
|
|
786
|
+
}
|
|
787
|
+
const resolved = withoutExtension(stack.join("/"));
|
|
788
|
+
const target = withoutExtension(candidate);
|
|
789
|
+
return target === resolved || target === `${resolved}/index`;
|
|
790
|
+
}
|
|
791
|
+
export {
|
|
792
|
+
analyzeReactiveGraph
|
|
793
|
+
};
|