@muten/core 0.0.5 → 0.0.6

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.
@@ -0,0 +1,27 @@
1
+ import{Ek as $,StOp as o,Nt as y,Mod as c}from"#engine/shared/vocab.js";const a=" ",B=t=>!!t&&typeof t=="object"&&"kind"in t&&t.kind===$.Interp,A=t=>typeof t=="object"&&"$param"in t,O=t=>/^[A-Za-z_][A-Za-z0-9_.]*$/.test(t);function s(t){switch(t.kind){case $.Lit:return j(t.value);case $.Ref:return t.name;case $.Un:return`${t.op} ${f(t.operand)}`;case $.Bin:return`${f(t.left)} ${t.op} ${f(t.right)}`;case $.Tern:return`${f(t.cond)} ? ${f(t.then)} : ${f(t.else)}`}}const f=t=>t.kind===$.Bin||t.kind===$.Tern?`(${s(t)})`:s(t),j=t=>typeof t=="string"?JSON.stringify(t):String(t);function l(t){return t===null?"null":Array.isArray(t)?`[${t.map(l).join(", ")}]`:typeof t=="object"?`{ ${Object.entries(t).map(([r,e])=>`${r}: ${l(e)}`).join(", ")} }`:j(t)}const S=t=>'"'+t.parts.map(r=>typeof r=="string"?r:`{${s(r)}}`).join("")+'"',R=t=>typeof t=="string"?t:t.parts.map(r=>typeof r=="string"?r:`{${s(r)}}`).join("");function I(t){return typeof t=="string"?JSON.stringify(t):A(t)?"$"+t.$param:S(t)}const E=t=>typeof t=="number"?String(t):typeof t=="string"?t:"$"+t.$param,h=t=>Object.entries(t).map(([r,e])=>`${r}: ${E(e)}`).join(", "),N=t=>typeof t=="string"?O(t)?t:JSON.stringify(t):`${O(t.name)?t.name:JSON.stringify(t.name)} when ${s(t.cond)}`;function m(t,r){switch(t.op){case o.Push:return`${t.target}.push(${s(t.arg)})`;case o.Set:return`${t.target}.set(${s(t.arg)})`;case o.Reset:return`${t.target}.reset()`;case o.Remove:return`${t.target}.remove(${t.param} => ${s(t.pred)})`;case o.Create:return`${t.target}.create(${s(t.arg)})`;case o.Update:return`${t.target}.update(${s(t.arg)})`;case o.Delete:return`${t.target}.delete(${s(t.arg)})`;case o.Refetch:return`${t.target}.refetch(${Object.entries(t.params).map(([e,n])=>`${e}: ${s(n)}`).join(", ")})`;case o.Request:return`${t.method.toLowerCase()} ${typeof t.url=="string"?JSON.stringify(t.url):S(t.url)}${t.body?` body ${s(t.body)}`:""}`;case o.If:{const e=t.then.map(i=>r+a+m(i,r+a)).join(`
2
+ `),n=t.else?` else {
3
+ ${t.else.map(i=>r+a+m(i,r+a)).join(`
4
+ `)}
5
+ ${r}}`:"";return`if ${s(t.cond)} {
6
+ ${e}
7
+ ${r}}${n}`}}}function d(t,r){if(t.args)return`${r}${t.type}(${h(t.args)})`;if(t.type===y.Slot)return`${r}slot`;const e=t.props||{};let n;if(t.type===y.When)n=`when ${s(e.cond)}`;else if(t.type===y.Each)n=`each ${s(e.list)} as ${e.as}`;else{n=t.type;const i=e.value??e.label??e.src??e.placeholder??e.submitLabel;i!==void 0&&(n+=` ${I(i)}`),e.to!==void 0?n+=` -> ${R(e.to)}`:e.action&&(n+=` -> ${e.action}${e.arg!==void 0?`(${s(e.arg)})`:""}`),e.data&&(n+=` @${e.data}`),e.bind&&(n+=` bind ${e.bind.includes(".")?e.bind:"@"+e.bind}`),e.where&&(n+=` ${c.Where}(${e.where.join(", ")})`),e.columns&&(n+=` ${c.Columns}(${e.columns.join(", ")})`),e.style&&(n+=` ${c.Style}(${e.style.join(", ")})`),e.class&&(n+=` ${c.Class}(${e.class.map(N).join(", ")})`),e.alt!==void 0&&(n+=` ${c.Alt} ${I(e.alt)}`),e.inputs&&(n+=` ${c.Inputs}(${h(e.inputs)})`),e.on&&(n+=` ${c.On}(${h(e.on)})`),e.submit&&(n+=` ${c.Submit} ${e.submit}`)}return t.children&&t.children.length?`${r}${n} {
8
+ ${t.children.map(i=>d(i,r+a)).join(`
9
+ `)}
10
+ ${r}}`:`${r}${n}`}const C=(t,r,e)=>{const n=Object.entries(r).map(([i,k])=>{let g=`${i} ${k}`;const u=e?.[i];return u?.required&&(g+=" required"),u?.min!==void 0&&(g+=` min:${u.min}`),u?.max!==void 0&&(g+=` max:${u.max}`),g});return`entity ${t} { ${n.join(" ")} }`},P=(t,r)=>{const e=r.source?.startsWith("query:")?`query ${r.source.slice(6)}`:l(r.initial??null);return`${t} = ${e} : ${r.type}`},V=(t,r)=>`${`action ${t}${r.mutates.length?` mutates ${r.mutates.join(", ")}`:""}${r.input?` <- ${r.input}`:""}`} {
11
+ ${r.body.map(n=>a+m(n,a)).join(`
12
+ `)}
13
+ }`,x=t=>`${t.url} -> ${t.page}${t.guard?` guard ${t.guardNeg?"not ":""}${t.guard}${t.redirect?` else ${t.redirect}`:""}`:""}`,w=(t,r)=>`part ${t}(${r.params.map(e=>`${e.name}: ${e.type}`).join(", ")}) {
14
+ ${d(r.tree,a)}
15
+ }`,p=(t,r)=>`${t} {
16
+ ${r}
17
+ }`,b=(t,r,e)=>p(t,r.map(([n,i])=>`${a}${n}${e} ${l(i)}`).join(`
18
+ `));function M(t){const r=[],e=n=>{n&&r.push(n)};if(t.consts)for(const[n,i]of Object.entries(t.consts))e(`const ${n} = ${j(i)}`);if(e(t.screen?`screen ${t.screen}`:void 0),t.meta&&e(p("meta",Object.entries(t.meta).map(([n,i])=>`${a}${n} ${JSON.stringify(i)}`).join(`
19
+ `))),t.params)for(const n of t.params)e(`param ${n}`);if(t.api&&e(b("api",Object.entries(t.api),":")),t.entities)for(const[n,i]of Object.entries(t.entities))e(C(n,i,t.constraints?.[n]));if(t.state&&Object.keys(t.state).length&&e(p("state",Object.entries(t.state).map(([n,i])=>a+P(n,i)).join(`
20
+ `))),t.store&&Object.keys(t.store).length&&e(p("store",Object.entries(t.store).map(([n,i])=>a+P(n,i)).join(`
21
+ `))),t.gets)for(const[n,i]of Object.entries(t.gets))e(`get ${n} = ${s(i)}`);if(t.sources&&e(b("sources",Object.entries(t.sources),":")),t.mock&&e(b("mock",Object.entries(t.mock),":")),t.actions)for(const[n,i]of Object.entries(t.actions))e(V(n,i));if(t.effects)for(const n of t.effects)e(p("effect",n.map(i=>a+m(i,a)).join(`
22
+ `)));if(t.parts)for(const[n,i]of Object.entries(t.parts))e(w(n,i));return t.shell&&e(p("shell",(t.shell.children||[]).map(n=>d(n,a)).join(`
23
+ `))),t.tree&&e(d(t.tree,"")),t.routes&&e(p("routes",t.routes.map(n=>a+x(n)).join(`
24
+ `))),r.join(`
25
+
26
+ `)+`
27
+ `}export{M as print};
@@ -1 +1 @@
1
- import{resolveToken as x,SUGGESTED as b,defaultTheme as A,isKnownTokenShape as D}from"#engine/style/tokens.js";import{diag as p,closest as l}from"#engine/shared/diagnostics.js";import{PRIMITIVE_NAMES as W,ACTION_OPS as _,PRIMITIVES as C}from"#engine/lang/manifest.js";import{Nt as u,Ek as y,StOp as F}from"#engine/shared/vocab.js";const O=new Set(W),K=["bind","data"],E=new Set(_),N=["text","number","bool","uuid","email","string"];function h(s,c=[]){return s.kind===y.Ref?c.push(s.name):s.kind===y.Un?h(s.operand,c):s.kind===y.Bin?(h(s.left,c),h(s.right,c)):s.kind===y.Tern&&(h(s.cond,c),h(s.then,c),h(s.else,c)),c}function q(s,c={}){const r=[],g=new Set(Object.keys(s.state||{})),I=new Set(c.stores||[]),j=new Set(Object.keys(s.consts||{})),T=new Set(s.params||[]),R=new Set(Object.keys(s.actions||{})),P=s.nodes||{},S=Object.keys(s.entities||{});for(const[o,i]of Object.entries(s.state||{})){const t=i.type;if(t==="list")r.push(p("untyped-list",`state "${o}" is an untyped "list" \u2014 declare the element type, e.g. list<uuid> or list<User>`,{loc:i.loc,suggestion:"list<uuid>"}));else if(t.startsWith("list<")){const e=t.slice(5,-1);!N.includes(e)&&!S.includes(e)&&r.push(p("unknown-type",`list element "${e}" is not a known entity or scalar type`,{loc:i.loc,suggestion:l(e,[...S,...N])}))}}const V=(o,i)=>{if(typeof o=="string"&&o.startsWith("@")){const t=o.slice(1).split(".")[0];if(!g.has(t)){const e=l(t,[...g]);r.push(p("unknown-ref",`"@${t}" is not a declared state`,{loc:i.loc,suggestion:e?"@"+e:null}))}}},k=(o,i,t)=>{for(const e of h(o)){const n=e.split(".")[0];if(t.has(n)||g.has(n)||I.has(n)||j.has(n)||T.has(n)||R.has(n))continue;const d=l(n,[...g,...t]);r.push(p("unknown-ref",`"${n}" is not a known state or item variable here`,{loc:i.loc,suggestion:d}))}},w=new Set,$=(o,i)=>{const t=P[o];if(!t){r.push(p("missing-node",`node ${o} does not exist`));return}if(w.has(o)){r.push(p("dup-node",`${o} is referenced twice`,{loc:t.loc}));return}if(w.add(o),!O.has(t.type))t.args?r.push(p("unknown-part",`"${t.type}" is not a known part`,{loc:t.loc,suggestion:l(t.type,c.parts||[])})):r.push(p("unknown-type",`"${t.type}" is not a known primitive`,{loc:t.loc,suggestion:l(t.type,[...O])}));else{const a=C[t.type],m=a?a.props:{};for(const[f,v]of Object.entries(m))!v.endsWith("?")&&!(f in(t.props||{}))&&r.push(p("missing-prop",`${t.type} is missing the required "${f}"`,{loc:t.loc}))}const e=t.props||{};for(const a of K)a in e&&V(e[a],t);if(Array.isArray(e.style)){const a=c.theme||A,m=Object.keys(a.space||{}).length>0;for(const f of e.style)D(f)?m&&x(f,a)===null&&r.push(p("unknown-token",`"${f}": that step isn't in your theme scale`,{loc:t.loc,suggestion:l(f,b)})):r.push(p("unknown-token",`"${f}" is not an accepted style token`,{loc:t.loc,suggestion:l(f,b)}))}t.type===u.When&&e.cond&&k(e.cond,t,i),t.type===u.Each&&e.list&&k(e.list,t,i);const n=[];(t.type===u.Text||t.type===u.Title||t.type===u.Span)&&e.value&&n.push(e.value),t.type===u.Image&&(e.src&&n.push(e.src),e.alt&&n.push(e.alt)),t.type===u.Link&&e.to&&n.push(e.to);for(const a of n)if(typeof a=="object"&&"kind"in a&&a.kind===y.Interp)for(const m of a.parts)typeof m!="string"&&k(m,t,i);const d=t.type===u.Each&&e.as?new Set([...i,e.as]):i;for(const a of t.children||[])$(a,d)};if(s.rootId?$(s.rootId,new Set):c.kind!=="store"&&r.push(p("no-root","the doc is missing a rootId")),c.kind==="store")for(const[o,i]of Object.entries(s.gets||{}))for(const t of h(i)){const e=t.split(".")[0];g.has(e)||r.push(p("unknown-ref",`get "${o}": "${e}" is not a state of this store`,{suggestion:l(e,[...g])}))}for(const[o,i]of Object.entries(s.actions||{})){const t=new Set(i.mutates||[]),e=n=>{if(n.op===F.If){for(const d of n.then||[])e(d);for(const d of n.else||[])e(d);return}E.has(n.op)||r.push(p("unknown-op",`action "${o}" uses unknown op "${n.op}"`,{suggestion:l(n.op,[...E])})),"target"in n&&n.target&&!t.has(n.target)&&r.push(p("undeclared-mutation",`action "${o}" mutates "${n.target}" but only declares mutates(${[...t].join(", ")||"\u2205"})`,{suggestion:l(n.target,[...t])}))};for(const n of i.body||[])e(n)}return{ok:r.length===0,diagnostics:r}}export{q as validate};
1
+ import{resolveToken as F,SUGGESTED as I,defaultTheme as q,isKnownTokenShape as _}from"#engine/style/tokens.js";import{diag as a,closest as p}from"#engine/shared/diagnostics.js";import{PRIMITIVE_NAMES as C,ACTION_OPS as K,PRIMITIVES as U}from"#engine/lang/manifest.js";import{Nt as g,Ek as y,StOp as v}from"#engine/shared/vocab.js";const T=new Set([...C,g.Shell]),G=["bind","data"],M=new Set(K),R=["text","number","bool","uuid","email","string"];function d(i,c=[]){return i.kind===y.Ref?c.push(i.name):i.kind===y.Un?d(i.operand,c):i.kind===y.Bin?(d(i.left,c),d(i.right,c)):i.kind===y.Tern&&(d(i.cond,c),d(i.then,c),d(i.else,c)),c}function H(i,c={}){const r=[],h=new Set(Object.keys(i.state||{})),P=new Set(c.stores||[]),V=new Set(Object.keys(i.consts||{})),x=new Set(i.params||[]),k=new Set(Object.keys(i.actions||{})),A=i.nodes||{},w=new Map;for(const[s,n]of Object.entries(i.state||{})){if(!n.source?.startsWith("query:"))continue;const t=new Set(["loading","error","data"]),e=i.entities?.[n.type];if(e){t.add("id");for(const o of Object.keys(e))t.add(o)}w.set(s,t)}const b=new Map;for(const[s,n]of Object.entries(c.storeMembers||{}))b.set(s,new Set(n));const $=(s,n,t)=>{const e=w.get(s);if(e){e.has(n)||r.push(a("unknown-member",`"${n}" is not a member of query "${s}"`,{loc:t.loc,suggestion:p(n,[...e])}));return}const o=b.get(s);o&&!o.has(n)&&r.push(a("unknown-member",`"${n}" is not a member of store "${s}"`,{loc:t.loc,suggestion:p(n,[...o])}))},O=Object.keys(i.entities||{});for(const[s,n]of Object.entries(i.state||{})){const t=n.type;if(t==="list")r.push(a("untyped-list",`state "${s}" is an untyped "list" \u2014 declare the element type, e.g. list<uuid> or list<User>`,{loc:n.loc,suggestion:"list<uuid>"}));else if(t.startsWith("list<")){const e=t.slice(5,-1);!R.includes(e)&&!O.includes(e)&&r.push(a("unknown-type",`list element "${e}" is not a known entity or scalar type`,{loc:n.loc,suggestion:p(e,[...O,...R])}))}}const W=(s,n)=>{if(typeof s=="string"&&s.startsWith("@")){const t=s.slice(1).split(".")[0];if(!h.has(t)){const e=p(t,[...h]);r.push(a("unknown-ref",`"@${t}" is not a declared state`,{loc:n.loc,suggestion:e?"@"+e:null}))}}},N=(s,n)=>{if(!(!s||s.startsWith("$"))){if(s.includes(".")){const t=s.indexOf(".");$(s.slice(0,t),s.slice(t+1).split(".")[0],n);return}k.has(s)||r.push(a("unknown-action",`"${s}" is not a declared action`,{loc:n.loc,suggestion:p(s,[...k])}))}},S=(s,n,t)=>{for(const e of d(s)){const o=e.indexOf("."),f=o===-1?e:e.slice(0,o);if(!(t.has(f)||h.has(f)||P.has(f)||V.has(f)||x.has(f)||k.has(f))){r.push(a("unknown-ref",`"${f}" is not a known state or item variable here`,{loc:n.loc,suggestion:p(f,[...h,...t])}));continue}o!==-1&&$(f,e.slice(o+1).split(".")[0],n)}},j=new Set,E=(s,n)=>{const t=A[s];if(!t){r.push(a("missing-node",`node ${s} does not exist`));return}if(j.has(s)){r.push(a("dup-node",`${s} is referenced twice`,{loc:t.loc}));return}if(j.add(s),!T.has(t.type))t.args?r.push(a("unknown-part",`"${t.type}" is not a known part`,{loc:t.loc,suggestion:p(t.type,c.parts||[])})):r.push(a("unknown-type",`"${t.type}" is not a known primitive`,{loc:t.loc,suggestion:p(t.type,[...T])}));else{const l=U[t.type],m=l?l.props:{};for(const[u,D]of Object.entries(m))!D.endsWith("?")&&!(u in(t.props||{}))&&r.push(a("missing-prop",`${t.type} is missing the required "${u}"`,{loc:t.loc}))}const e=t.props||{};for(const l of G)l in e&&W(e[l],t);if(e.action&&N(e.action,t),e.submit&&N(e.submit,t),Array.isArray(e.style)){const l=c.theme||q,m=Object.keys(l.space||{}).length>0;for(const u of e.style)_(u)?m&&F(u,l)===null&&r.push(a("unknown-token",`"${u}": that step isn't in your theme scale`,{loc:t.loc,suggestion:p(u,I)})):r.push(a("unknown-token",`"${u}" is not an accepted style token`,{loc:t.loc,suggestion:p(u,I)}))}t.type===g.When&&e.cond&&S(e.cond,t,n),t.type===g.Each&&e.list&&S(e.list,t,n);const o=[];(t.type===g.Text||t.type===g.Title||t.type===g.Span)&&e.value&&o.push(e.value),t.type===g.Image&&(e.src&&o.push(e.src),e.alt&&o.push(e.alt)),t.type===g.Link&&e.to&&o.push(e.to),e.label&&o.push(e.label);for(const l of o)if(typeof l=="object"&&"kind"in l&&l.kind===y.Interp)for(const m of l.parts)typeof m!="string"&&S(m,t,n);const f=t.type===g.Each&&e.as?new Set([...n,e.as]):n;for(const l of t.children||[])E(l,f)};if(i.rootId?E(i.rootId,new Set):c.kind!=="store"&&r.push(a("no-root","the doc is missing a rootId")),c.kind==="store")for(const[s,n]of Object.entries(i.gets||{}))for(const t of d(n)){const e=t.split(".")[0];h.has(e)||r.push(a("unknown-ref",`get "${s}": "${e}" is not a state of this store`,{suggestion:p(e,[...h])}))}for(const[s,n]of Object.entries(i.actions||{})){const t=new Set(n.mutates||[]),e=o=>{if(o.op===v.If){for(const f of o.then||[])e(f);for(const f of o.else||[])e(f);return}M.has(o.op)||r.push(a("unknown-op",`action "${s}" uses unknown op "${o.op}"`,{suggestion:p(o.op,[...M])})),"target"in o&&o.target&&!t.has(o.target)&&r.push(a("undeclared-mutation",`action "${s}" mutates "${o.target}" but only declares mutates(${[...t].join(", ")||"\u2205"})`,{suggestion:p(o.target,[...t])}))};for(const o of n.body||[])e(o)}return{ok:r.length===0,diagnostics:r}}export{H as validate};
package/dist/lint.js CHANGED
@@ -1,2 +1,2 @@
1
- import{join as a,relative as m}from"node:path";import{readRoutes as d}from"#engine/project/routes.js";import{load as p,loadParts as h,findStores as u}from"#engine/project/load.js";import{validate as y}from"#engine/ir/validate.js";import{formatDiagnostic as P,ParseError as b}from"#engine/shared/diagnostics.js";async function N(r,n=!1){const i=o=>m(r,o),c=await h(a(r,"src","parts")),l=Object.keys(u(a(r,"src"))),g=d(r),e=[];for(const o of g){let t=[];try{const{doc:s,partNames:f}=await p(o.screenPath,c);t=y(s,{parts:f,stores:l}).diagnostics}catch(s){if(!(s instanceof b))throw s;t=[{code:s.code,severity:"error",message:s.message,loc:s.loc,suggestion:null}]}for(const s of t)n||console.log(P(s,i(o.screenPath))),e.push({file:i(o.screenPath),...s})}return console.log(n?JSON.stringify(e,null,2):e.length?`
2
- \u2716 ${e.length} problem(s)`:"\u2713 no problems"),e.length}export{N as lintApp};
1
+ import{join as l,relative as b}from"node:path";import{readFileSync as P,existsSync as O}from"node:fs";import{readRoutes as j}from"#engine/project/routes.js";import{load as D,loadParts as k,findStores as w}from"#engine/project/load.js";import{parse as S}from"#engine/lang/parse.js";import{toDoc as v}from"#engine/ir/flatten.js";import{validate as m}from"#engine/ir/validate.js";import{formatDiagnostic as p,ParseError as d}from"#engine/shared/diagnostics.js";async function $(r,c=!1){const i=s=>b(r,s),h=await k(l(r,"src","parts")),f=w(l(r,"src")),g=Object.keys(f),a={};for(const[s,e]of Object.entries(f))a[s]=[...Object.keys(e.state||{}),...Object.keys(e.gets||{}),...Object.keys(e.actions||{})];const y=j(r),o=[];for(const s of y){let e=[];try{const{doc:t,partNames:u}=await D(s.screenPath,h);e=m(t,{parts:u,stores:g,storeMembers:a}).diagnostics}catch(t){if(!(t instanceof d))throw t;e=[{code:t.code,severity:"error",message:t.message,loc:t.loc,suggestion:null}]}for(const t of e)c||console.log(p(t,i(s.screenPath))),o.push({file:i(s.screenPath),...t})}const n=l(r,"src","app.muten");if(O(n))try{const s=S(P(n,"utf8"));if(s.shell)for(const e of m(v({...s,tree:s.shell}),{stores:g,storeMembers:a}).diagnostics)c||console.log(p(e,i(n))),o.push({file:i(n),...e})}catch(s){if(!(s instanceof d))throw s}return console.log(c?JSON.stringify(o,null,2):o.length?`
2
+ \u2716 ${o.length} problem(s)`:"\u2713 no problems"),o.length}export{$ as lintApp};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@muten/core",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "AI-first frontend framework — compiles .muten files to vanilla JS + signals.",
5
5
  "repository": {
6
6
  "type": "git",