@muten/core 0.0.11 → 0.0.12

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.
@@ -1 +1 @@
1
- import p from"node:fs";import{dirname as m,join as u}from"node:path";import{parse as f}from"#engine/lang/parse.js";import{composeDoc as D}from"#engine/ir/compose.js";import{validate as y}from"#engine/ir/validate.js";import{closest as k,diag as g,ParseError as b}from"#engine/shared/diagnostics.js";import{PRIMITIVE_NAMES as O}from"#engine/lang/manifest.js";import{mergeTheme as d}from"#engine/style/tokens.js";function h(r){const e=l(r);if(!e)return d({});try{return d(f(p.readFileSync(u(e,"theme.muten"),"utf8")).theme||{})}catch{return d({})}}function S(r){const e={};let t;try{t=p.readdirSync(r)}catch{return e}for(const s of t){if(!s.endsWith(".muten"))continue;let i;try{i=f(p.readFileSync(u(r,s),"utf8"))}catch{continue}for(const[o,c]of Object.entries(i.parts||{}))e[o]={...c,state:i.state||{},entities:i.entities||{}}}return e}function l(r){let e=m(r);for(let t=0;t<30;t++){if(p.existsSync(u(e,"src","pages")))return e;const s=m(e);if(s===e)break;e=s}return null}function T(r){const e=[],t=s=>{let i;try{i=p.readdirSync(s,{withFileTypes:!0})}catch{return}for(const o of i){if(!o.isDirectory())continue;const c=u(s,o.name);o.name==="parts"?e.push(c):t(c)}};return t(u(r,"src")),e}function w(r){const e=l(r);if(!e)return[];const t=[],s=i=>{let o;try{o=p.readdirSync(i,{withFileTypes:!0})}catch{return}for(const c of o){const n=u(i,c.name);c.isDirectory()?s(n):c.name.endsWith(".store")&&t.push(c.name.slice(0,-6))}};return s(u(e,"src")),t}function R(r){const e=l(r);if(!e)return S(u(m(r),"parts"));const t={};for(const s of T(e))Object.assign(t,S(s));return t}function x(r,e){const t=l(r),s=t?u(t,"src","pages"):null;let i=[];if(s)try{i=p.readdirSync(s,{withFileTypes:!0}).filter(n=>n.isDirectory()).map(n=>n.name)}catch{}const o=[],c=new Set;for(const n of e)c.has(n.url)&&o.push(g("dup-route",`duplicate route "${n.url}"`,{loc:n.loc})),c.add(n.url),s&&!i.includes(n.page)&&o.push(g("unknown-page",`route "${n.url}" \u2192 page "${n.page}" not found in src/pages/`,{loc:n.loc,suggestion:k(n.page,i)}));return{ok:o.length===0,diagnostics:o}}function L(r,e){let t;try{t=f(e)}catch(o){return o instanceof b&&o.loc?{ok:!1,diagnostics:[g("syntax",o.message,{loc:o.loc})]}:{ok:!0,diagnostics:[]}}if(t.routes)return x(r,t.routes);if(t.theme)return{ok:!0,diagnostics:[]};if(r.endsWith(".store"))return y({screen:"store",state:t.state||{},actions:t.actions||{},entities:t.entities||{},gets:t.gets||{},effects:t.effects||[],consts:{},constraints:{},rootId:void 0,nodes:{}},{kind:"store"});const s=R(r),{doc:i}=D(t,s);return y(i,{parts:Object.keys(s),stores:w(r),theme:h(r)})}function $(r,e){let t=null;try{t=f(e)}catch{}const s=R(r),i=Object.entries(s).map(([n,a])=>({name:n,params:a.params||[]})),o=[],c=(n,a)=>{o.push({name:n,type:a.type||"",query:typeof a.source=="string"&&a.source.startsWith("query:")})};for(const[n,a]of Object.entries(t?.state||{}))c(n,a);for(const n of Object.values(s))for(const[a,j]of Object.entries(n.state||{}))c(a,j);return{parts:i,state:o,actions:Object.keys(t?.actions||{}),primitives:O,theme:h(r)}}export{L as analyze,$ as completion,R as projectParts,w as projectStores,h as projectTheme};
1
+ import p from"node:fs";import{dirname as g,join as u}from"node:path";import{parse as l}from"#engine/lang/parse.js";import{composeDoc as R}from"#engine/ir/compose.js";import{validate as h}from"#engine/ir/validate.js";import{closest as b,diag as d,ParseError as D}from"#engine/shared/diagnostics.js";import{PRIMITIVE_NAMES as O}from"#engine/lang/manifest.js";import{mergeTheme as y}from"#engine/style/tokens.js";function S(r){const e=m(r);if(!e)return y({});try{return y(l(p.readFileSync(u(e,"theme.muten"),"utf8")).theme||{})}catch{return y({})}}function j(r){const e={};let t;try{t=p.readdirSync(r)}catch{return e}for(const s of t){if(!s.endsWith(".muten"))continue;let i;try{i=l(p.readFileSync(u(r,s),"utf8"))}catch{continue}for(const[o,c]of Object.entries(i.parts||{}))e[o]={...c,state:i.state||{},entities:i.entities||{}}}return e}function m(r){let e=g(r);for(let t=0;t<30;t++){if(p.existsSync(u(e,"src","pages")))return e;const s=g(e);if(s===e)break;e=s}return null}function w(r){const e=[],t=s=>{let i;try{i=p.readdirSync(s,{withFileTypes:!0})}catch{return}for(const o of i){if(!o.isDirectory())continue;const c=u(s,o.name);o.name==="parts"?e.push(c):t(c)}};return t(u(r,"src")),e}function T(r){const e=m(r);if(!e)return[];const t=[],s=i=>{let o;try{o=p.readdirSync(i,{withFileTypes:!0})}catch{return}for(const c of o){const n=u(i,c.name);c.isDirectory()?s(n):c.name.endsWith(".store")&&t.push(c.name.slice(0,-6))}};return s(u(e,"src")),t}function x(r){const e=m(r);if(!e)return{};const t={},s=i=>{let o;try{o=p.readdirSync(i,{withFileTypes:!0})}catch{return}for(const c of o){const n=u(i,c.name);if(c.isDirectory())s(n);else if(c.name.endsWith(".store")){const a=c.name.slice(0,-6);try{const f=l(p.readFileSync(n,"utf8"));t[a]=[...Object.keys(f.state||{}),...Object.keys(f.gets||{}),...Object.keys(f.actions||{})]}catch{t[a]=[]}}}};return s(u(e,"src")),t}function k(r){const e=m(r);if(!e)return j(u(g(r),"parts"));const t={};for(const s of w(e))Object.assign(t,j(s));return t}function v(r,e){const t=m(r),s=t?u(t,"src","pages"):null;let i=[];if(s)try{i=p.readdirSync(s,{withFileTypes:!0}).filter(n=>n.isDirectory()).map(n=>n.name)}catch{}const o=[],c=new Set;for(const n of e)c.has(n.url)&&o.push(d("dup-route",`duplicate route "${n.url}"`,{loc:n.loc})),c.add(n.url),s&&!i.includes(n.page)&&o.push(d("unknown-page",`route "${n.url}" \u2192 page "${n.page}" not found in src/pages/`,{loc:n.loc,suggestion:b(n.page,i)}));return{ok:o.length===0,diagnostics:o}}function L(r,e){let t;try{t=l(e)}catch(o){return o instanceof D&&o.loc?{ok:!1,diagnostics:[d("syntax",o.message,{loc:o.loc})]}:{ok:!0,diagnostics:[]}}if(t.routes)return v(r,t.routes);if(t.theme)return{ok:!0,diagnostics:[]};if(r.endsWith(".store"))return h({screen:"store",state:t.state||{},actions:t.actions||{},entities:t.entities||{},gets:t.gets||{},effects:t.effects||[],consts:{},constraints:{},rootId:void 0,nodes:{}},{kind:"store"});const s=k(r),{doc:i}=R(t,s);return h(i,{parts:Object.keys(s),stores:T(r),storeMembers:x(r),theme:S(r)})}function $(r,e){let t=null;try{t=l(e)}catch{}const s=k(r),i=Object.entries(s).map(([n,a])=>({name:n,params:a.params||[]})),o=[],c=(n,a)=>{o.push({name:n,type:a.type||"",query:typeof a.source=="string"&&a.source.startsWith("query:")})};for(const[n,a]of Object.entries(t?.state||{}))c(n,a);for(const n of Object.values(s))for(const[a,f]of Object.entries(n.state||{}))c(a,f);return{parts:i,state:o,actions:Object.keys(t?.actions||{}),primitives:O,theme:S(r)}}export{L as analyze,$ as completion,k as projectParts,x as projectStoreMembers,T as projectStores,S as projectTheme};
@@ -1,15 +1,15 @@
1
- import{readFileSync as f,existsSync as g}from"node:fs";import{fileURLToPath as P}from"node:url";import{dirname as C,join as l}from"node:path";import{parse as b}from"#engine/lang/parse.js";import{toDoc as D}from"#engine/ir/flatten.js";import{load as M,loadAllParts as E,findStores as H}from"#engine/project/load.js";import{validate as F}from"#engine/ir/validate.js";import{compileModule as k,compileStore as J}from"#engine/compile/compile.js";import{mergeTheme as j}from"#engine/style/tokens.js";import{Nt as $}from"#engine/shared/vocab.js";const O="virtual:muten/runtime",h="virtual:muten/store/",R="virtual:muten/shell",L=C(P(import.meta.url)),U=f(l(L,"runtime.js"),"utf8");function V(y={}){const I=y.store!==!1;let p=j(y.theme),i=process.cwd(),w={},S={};const c={};let m,d=null;const N=()=>{const e=new Set,t=(m?.routes||[]).map(o=>{const r=JSON.stringify("/"+o.url.replace(/^\//,"")),a=`() => import(${JSON.stringify("/src/pages/"+o.page+"/"+o.page+".muten")})`;if(o.guard){const[u,n]=o.guard.split(".");return e.add(u),` ${r}: { load: ${a}, guard: () => ${o.guardNeg?"!":""}__store_${u}.${n}.get(), redirect: ${JSON.stringify(o.redirect)} },`}return` ${r}: { load: ${a} },`}).join(`
2
- `),s=[...e].map(o=>`import * as __store_${o} from '${h}${o}';`).join(`
3
- `);return`import * as __shell from '${R}';
4
- import { route, injectCss } from '${O}';
1
+ import{readFileSync as h,existsSync as y}from"node:fs";import{fileURLToPath as P}from"node:url";import{dirname as C,join as m}from"node:path";import{parse as k}from"#engine/lang/parse.js";import{toDoc as D}from"#engine/ir/flatten.js";import{load as E,loadAllParts as H,findStores as F}from"#engine/project/load.js";import{validate as J}from"#engine/ir/validate.js";import{compileModule as I,compileStore as L}from"#engine/compile/compile.js";import{mergeTheme as O}from"#engine/style/tokens.js";import{Nt as R}from"#engine/shared/vocab.js";const w="virtual:muten/runtime",S="virtual:muten/store/",T="virtual:muten/shell",U=C(P(import.meta.url)),V=h(m(U,"runtime.js"),"utf8");function B(j={}){const M=j.store!==!1;let p=O(j.theme),i=process.cwd(),_={},v={};const a={};let u,d=null;const N=()=>{const t=new Set,e=(u?.routes||[]).map(s=>{const r=JSON.stringify("/"+s.url.replace(/^\//,"")),c=`() => import(${JSON.stringify("/src/pages/"+s.page+"/"+s.page+".muten")})`;if(s.guard){const[f,g]=s.guard.split(".");return t.add(f),` ${r}: { load: ${c}, guard: () => ${s.guardNeg?"!":""}__store_${f}.${g}.get(), redirect: ${JSON.stringify(s.redirect)} },`}return` ${r}: { load: ${c} },`}).join(`
2
+ `),o=[...t].map(s=>`import * as __store_${s} from '${S}${s}';`).join(`
3
+ `);return`import * as __shell from '${T}';
4
+ import { route, injectCss } from '${w}';
5
5
  ${d?`import ${JSON.stringify(d)};
6
- `:""}${s}
6
+ `:""}${o}
7
7
  const routes = {
8
- ${t}
8
+ ${e}
9
9
  };
10
10
  const root = document.getElementById('app');
11
11
  if (root) {
12
12
  injectCss(__shell.css);
13
13
  const outlet = __shell.mount(root);
14
14
  route(outlet, routes);
15
- }`},T=async()=>{w=await E(i);for(const s of Object.keys(c))delete c[s];if(I){S=H(l(i,"src"));for(const[s,o]of Object.entries(S))c[s]={state:Object.keys(o.state||{}),gets:Object.keys(o.gets||{}),actions:Object.keys(o.actions||{})}}const e=l(i,"src","app.muten");m=g(e)?b(f(e,"utf8")):void 0;const t=l(i,"theme.muten");p=g(t)?j(b(f(t,"utf8")).theme||{}):j(y.theme),d=null;for(const s of["styles.css","styles.scss"])if(g(l(i,"src",s))){d="/src/"+s;break}};let v=null;const _=e=>{v&&clearTimeout(v),v=setTimeout(()=>{T().then(()=>{for(const t of e.moduleGraph.idToModuleMap.values()){const s=t.id||"";(s.endsWith(".muten")||s.includes("virtual:muten/shell")||s.includes("virtual:muten/store/"))&&e.moduleGraph.invalidateModule(t)}e.ws.send({type:"full-reload"})})},30)};return{name:"vite-plugin-muten",enforce:"pre",async configResolved(e){i=e.root,await T()},resolveId(e){if(e===O||e===R||e.startsWith(h))return"\0"+e},load(e){if(e==="\0"+O)return U;if(e.startsWith("\0"+h)){const t=S[e.slice(("\0"+h).length)];if(t)return J({state:t.state||{},gets:t.gets||{},actions:t.actions||{},effects:t.effects||[],entities:t.entities||{},imports:t.imports||[]},t.mock||{},t.sources||{})}if(e==="\0"+R){const t=m?.shell||{type:$.Shell,props:{},children:[{type:$.Slot,props:{}}]},s=D({...m||{},screen:"shell",entities:{},state:{},actions:{},tree:t});return k(s,{},"",{},{},{stores:c,theme:p})}},async transform(e,t){if(!t.endsWith(".muten"))return null;if(t.replace(/\\/g,"/").endsWith("/src/app.muten"))return{code:N(),map:null};const s=await M(t,w),{ok:o,diagnostics:r}=F(s.doc,{parts:s.partNames,stores:Object.keys(c),theme:p});if(!o)throw new Error("muten: "+r.map(n=>n.message).join(" \xB7 "));const a=[...new Set(Object.values(s.doc.nodes).filter(n=>n.type===$.Custom).map(n=>n.props?.component))],u={};for(const n of a){if(!n)continue;const W=l(i,"src","components",n+".js");g(W)&&(u[n]=f(W,"utf8"))}return{code:k(s.doc,s.data,s.styles.css,u,s.sources,{stores:c,theme:p,api:m?.api||{}}),map:null}},handleHotUpdate(e){if(e.file.endsWith(".muten")||e.file.endsWith(".store"))return _(e.server),[]},configureServer(e){const t=s=>{const o=s.replace(/\\/g,"/");(o.endsWith(".muten")||o.endsWith(".store")||o.endsWith("/styles.css")||o.endsWith("/styles.scss")||o.includes("/components/")&&o.endsWith(".js"))&&_(e)};e.watcher.on("add",t),e.watcher.on("change",t),e.watcher.on("unlink",t),e.middlewares.use((s,o,r)=>{if((s.url||"").split("?")[0]!=="/src/app.muten"){r();return}e.transformRequest("/src/app.muten").then(a=>{if(!a){r();return}o.setHeader("Content-Type","text/javascript"),o.end(a.code)},r)})}}}export{V as default};
15
+ }`},b=async()=>{_=await H(i);for(const o of Object.keys(a))delete a[o];if(M){v=F(m(i,"src"));for(const[o,s]of Object.entries(v))a[o]={state:Object.keys(s.state||{}),gets:Object.keys(s.gets||{}),actions:Object.keys(s.actions||{})}}const t=m(i,"src","app.muten");u=y(t)?k(h(t,"utf8")):void 0;const e=m(i,"theme.muten");p=y(e)?O(k(h(e,"utf8")).theme||{}):O(j.theme),d=null;for(const o of["styles.css","styles.scss"])if(y(m(i,"src",o))){d="/src/"+o;break}};let $=null;const W=t=>{$&&clearTimeout($),$=setTimeout(()=>{b().then(()=>{for(const e of t.moduleGraph.idToModuleMap.values()){const o=e.id||"";(o.endsWith(".muten")||o.includes("virtual:muten/shell")||o.includes("virtual:muten/store/"))&&t.moduleGraph.invalidateModule(e)}t.ws.send({type:"full-reload"})})},30)};return{name:"vite-plugin-muten",enforce:"pre",async configResolved(t){i=t.root,await b()},resolveId(t){if(t===w||t===T||t.startsWith(S))return"\0"+t},load(t){if(t==="\0"+w)return V;if(t.startsWith("\0"+S)){const e=v[t.slice(("\0"+S).length)];if(e)return L({state:e.state||{},gets:e.gets||{},actions:e.actions||{},effects:e.effects||[],entities:e.entities||{},imports:e.imports||[]},e.mock||{},e.sources||{})}if(t==="\0"+T){const e=u?.shell||{type:R.Shell,props:{},children:[{type:R.Slot,props:{}}]},o=D({...u||{},screen:"shell",entities:{},state:{},actions:{},tree:e});return I(o,{},"",{},{},{stores:a,theme:p})}},async transform(t,e){if(!e.endsWith(".muten"))return null;if(e.replace(/\\/g,"/").endsWith("/src/app.muten"))return{code:N(),map:null};const o=await E(e,_),s={};for(const[n,l]of Object.entries(a))s[n]=[...l.state||[],...l.gets||[],...l.actions||[]];const{ok:r,diagnostics:c}=J(o.doc,{parts:o.partNames,stores:Object.keys(a),storeMembers:s,theme:p});if(!r)throw new Error("muten: "+c.map(n=>n.message).join(" \xB7 "));const f=[...new Set(Object.values(o.doc.nodes).filter(n=>n.type===R.Custom).map(n=>n.props?.component))],g={};for(const n of f){if(!n)continue;const l=m(i,"src","components",n+".js");y(l)&&(g[n]=h(l,"utf8"))}return{code:I(o.doc,o.data,o.styles.css,g,o.sources,{stores:a,theme:p,api:u?.api||{}}),map:null}},handleHotUpdate(t){if(t.file.endsWith(".muten")||t.file.endsWith(".store"))return W(t.server),[]},configureServer(t){const e=o=>{const s=o.replace(/\\/g,"/");(s.endsWith(".muten")||s.endsWith(".store")||s.endsWith("/styles.css")||s.endsWith("/styles.scss")||s.includes("/components/")&&s.endsWith(".js"))&&W(t)};t.watcher.on("add",e),t.watcher.on("change",e),t.watcher.on("unlink",e),t.middlewares.use((o,s,r)=>{if((o.url||"").split("?")[0]!=="/src/app.muten"){r();return}t.transformRequest("/src/app.muten").then(c=>{if(!c){r();return}s.setHeader("Content-Type","text/javascript"),s.end(c.code)},r)})}}}export{B as default};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@muten/core",
3
- "version": "0.0.11",
3
+ "version": "0.0.12",
4
4
  "description": "AI-first frontend framework — compiles .muten files to vanilla JS + signals.",
5
5
  "repository": {
6
6
  "type": "git",