@muten/core 0.0.4 → 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.
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{tokenClass as Z,resolveToken as ge,defaultTheme as _e}from"#engine/style/tokens.js";import{Nt as l,Ek as de,Fmt as y,Fk as q}from"#engine/shared/vocab.js";import{customValue as ye,CONTAINERS as ee,parseClause as be,editableFields as Se}from"#engine/compile/helpers.js";import{emitStore as Ne,emitStatic as Ce,emitStaticHtml as Ee,emitSsr as ve,emitModule as Oe,emitHtml as xe}from"#engine/compile/emit.js";import{Logic as ke}from"#engine/compile/logic.js";function Te(m,x={},k="",w={},J={},$={}){return te(m,x,k,w,J,{...$,format:y.Module})}function Fe(m={},x={},k={}){const{state:w={},gets:J={},actions:$={},effects:d=[],entities:N={}}=m;return te({screen:"store",entities:N,state:w,actions:$,gets:J,effects:d,consts:{},constraints:{},rootId:void 0,nodes:{}},x,"",{},k,{format:y.Store})}function te(m,x={},k="",w={},J={},$={}){const{nodes:d,rootId:N,state:j,entities:A,screen:ne}=m,B=$.theme||_e;let t=[],M=!1;const H=e=>{const s=t;t=[],e();const o=t;return t=s,o},W=new Set,h=(e,s)=>{for(const o of s.style||[])W.add(o);return[e,...(s.style||[]).map(Z),...(s.class||[]).filter(o=>typeof o=="string")].join(" ")},se=new Set(Object.keys(j)),K=new Set(Object.entries(j).filter(([,e])=>typeof e.source=="string"&&e.source.startsWith("query:")).map(([e])=>e)),U=new Set,oe={state:j,entities:A,actions:m.actions,consts:m.consts||{},gets:m.gets||{},effects:m.effects||[],stateKeys:se,queryStates:K,stores:$.stores||{},usedStores:U,params:new Set(m.params||[]),format:$.format},u=new ke(oe),C={locals:new Set},E=(e,s)=>{for(const o of s.class||[])typeof o!="string"&&t.push(`effect(() => el_${e}.classList.toggle(${JSON.stringify(o.name)}, !!(${u.compileExpr(o.cond,C)})));`);for(const[o,n]of Object.entries(s.on||{}))typeof n=="string"&&t.push(`el_${e}.addEventListener(${JSON.stringify(o)}, () => ${u.actionRef(n)}());`)},D=(e,s)=>{for(const o of d[e].children)G(o,s)},z=e=>e.parts.map(s=>typeof s=="string"?JSON.stringify(s):`String(${u.compileExpr(s,C)} ?? '')`).join(" + ");function R(e,s,o,n,f){if(t.push(`const el_${e} = document.createElement('${s}');`),t.push(`el_${e}.className = ${JSON.stringify(o)};`),typeof n=="string")t.push(`el_${e}.textContent = ${JSON.stringify(n)};`);else if(n&&"kind"in n){const c=z(n),i=n.parts.some(p=>typeof p!="string");t.push(i?`effect(() => { el_${e}.textContent = ${c}; });`:`el_${e}.textContent = ${c};`)}t.push(`${f}.appendChild(el_${e});`)}function L(e,s,o){if(typeof o=="string")t.push(`el_${e}.${s} = ${JSON.stringify(o)};`);else if(o&&"kind"in o){const n=z(o),f=o.parts.some(c=>typeof c!="string");t.push(f?`effect(() => { el_${e}.${s} = ${n}; });`:`el_${e}.${s} = ${n};`)}}function G(e,s){const o=d[e],n=o.props||{},f=ee[o.type];if(f){const[c,i]=f;t.push(`const el_${e} = document.createElement('${c}');`),t.push(`el_${e}.className = ${JSON.stringify(h(i,n))};`),o.type===l.Nav&&typeof n.label=="string"&&t.push(`el_${e}.setAttribute('aria-label', ${JSON.stringify(n.label)});`),t.push(`${s}.appendChild(el_${e});`),E(e,n),D(e,`el_${e}`);return}switch(o.type){case l.SearchField:{const c=u.bindSig(n.bind);t.push(`const el_${e} = document.createElement('input');`),t.push(`el_${e}.type = 'search';`),t.push(`el_${e}.className = ${JSON.stringify(h("search",n))};`),typeof n.placeholder=="string"&&t.push(`el_${e}.placeholder = ${JSON.stringify(n.placeholder)};`),t.push(`el_${e}.value = ${c}.get();`),t.push(`el_${e}.addEventListener('input', (e) => ${c}.set(e.target.value));`),t.push(`${s}.appendChild(el_${e});`);break}case l.DataTable:{const c=u.bindSig(n.data),i=K.has(c)?`${c}.get().data`:`${c}.get()`,p=n.columns||[],_=(n.where||[]).map(be),F=_.filter(r=>!r.dynamic).map(r=>`.filter((row) => ${r.expr})`).join(""),b=_.filter(r=>r.dynamic).map(r=>`.filter((row) => ${r.expr})`).join(""),a=o.children.map(r=>d[r]).filter(r=>r.type===l.RowAction);t.push(`const el_${e} = document.createElement('table');`),t.push(`el_${e}.className = ${JSON.stringify(h("datatable",n))};`),t.push(`const head_${e} = el_${e}.createTHead().insertRow();`);for(const r of p)t.push(`{ const th = document.createElement('th'); th.textContent = ${JSON.stringify(r)}; head_${e}.appendChild(th); }`);a.length&&t.push(`head_${e}.appendChild(document.createElement('th'));`),t.push(`const body_${e} = el_${e}.createTBody();`),t.push(`${s}.appendChild(el_${e});`),t.push(`function renderRow_${e}(row) {`),t.push(" const tr = document.createElement('tr');");for(const r of p)t.push(` { const td = document.createElement('td'); td.textContent = row[${JSON.stringify(r)}] ?? ''; tr.appendChild(td); }`);for(const r of a){const g=r.props||{},he=g.arg!==void 0?u.compileExpr(g.arg,{locals:new Set(["row"])}):"";t.push(` { const td = document.createElement('td'); const b = document.createElement('button'); b.className = ${JSON.stringify(h("row-action",g))}; b.textContent = ${JSON.stringify(g.label)}; b.addEventListener('click', () => ${u.actionRef(g.action)}(${he})); td.appendChild(b); tr.appendChild(td); }`)}t.push(" return tr;"),t.push("}"),t.push(`function base_${e}() { return ${i}${F}; }`),t.push("effect(() => {"),t.push(` const rows = base_${e}()${b};`),t.push(` body_${e}.replaceChildren(...rows.map(renderRow_${e}));`),t.push("});");break}case l.Form:{const c=u.bindSig(n.bind),i=j[c].type,p=Se(A[i]),_=(m.constraints||{})[i]||{};t.push(`const el_${e} = document.createElement('form');`),t.push(`el_${e}.className = ${JSON.stringify(h("form",n))};`),t.push(`{ const t = document.createElement('div'); t.className = 'form-title'; t.textContent = ${JSON.stringify("New "+i)}; el_${e}.appendChild(t); }`);const F=[];for(const a of p){const r=`f_${e}_${a.name}`;if(F.push({...a,var:r,c:_[a.name]}),a.kind===q.Enum){t.push(`const ${r} = document.createElement('select');`),t.push(`${r}.className = 'field';`);for(const g of a.options)t.push(`{ const o = document.createElement('option'); o.value = ${JSON.stringify(g)}; o.textContent = ${JSON.stringify(g)}; ${r}.appendChild(o); }`)}else t.push(`const ${r} = document.createElement('input');`),t.push(`${r}.type = ${JSON.stringify(a.kind===q.Email?"email":"text")};`),t.push(`${r}.className = 'field';`),t.push(`${r}.placeholder = ${JSON.stringify(a.name)};`);t.push(`${r}.addEventListener('input', (e) => ${c}.set({ ...${c}.get(), ${JSON.stringify(a.name)}: e.target.value }));`),t.push(`el_${e}.appendChild(${r});`),_[a.name]&&t.push(`const err_${r} = document.createElement('small'); err_${r}.className = 'field-error'; el_${e}.appendChild(err_${r});`)}t.push(`{ const sb = document.createElement('button'); sb.type = 'submit'; sb.className = 'submit'; sb.textContent = ${JSON.stringify(typeof n.submitLabel=="string"?n.submitLabel:"Submit")}; el_${e}.appendChild(sb); }`);const b=[];for(const a of F){if(!a.c)continue;const r=`err_${a.var}`,g=`String(__d[${JSON.stringify(a.name)}] ?? '')`;b.push(`${r}.textContent = '';`),a.c.required&&b.push(`if (!${g}.trim()) { ${r}.textContent = 'Required'; __ok = false; }`),a.c.min!=null&&b.push(`if (${g} && ${g}.length < ${a.c.min}) { ${r}.textContent = 'Min ${a.c.min} characters'; __ok = false; }`),a.c.max!=null&&b.push(`if (${g}.length > ${a.c.max}) { ${r}.textContent = 'Max ${a.c.max} characters'; __ok = false; }`)}b.length?t.push(`el_${e}.addEventListener('submit', (e) => { e.preventDefault(); const __d = ${c}.get(); let __ok = true; ${b.join(" ")} if (__ok) ${u.actionRef(n.submit)}(); });`):t.push(`el_${e}.addEventListener('submit', (e) => { e.preventDefault(); ${u.actionRef(n.submit)}(); });`),t.push("effect(() => {"),t.push(` const d = ${c}.get();`);for(const a of F){const r=a.kind===q.Enum?JSON.stringify(a.options[0]):"''";t.push(` { const v = d[${JSON.stringify(a.name)}] ?? ${r}; if (${a.var}.value !== v) ${a.var}.value = v; }`)}t.push("});"),t.push(`${s}.appendChild(el_${e});`);break}case l.Text:R(e,"p",h("text",n),n.value,s),E(e,n);break;case l.Span:R(e,"span",h("span",n),n.value,s),E(e,n);break;case l.Title:R(e,n.level||"h1",h("title",n),n.value,s),E(e,n);break;case l.Image:{t.push(`const el_${e} = document.createElement('img');`),t.push(`el_${e}.className = ${JSON.stringify(h("image",n))};`),L(e,"src",n.src),L(e,"alt",n.alt??""),t.push(`${s}.appendChild(el_${e});`);break}case l.When:{if(!n.cond)throw new Error("when without a condition");const c=u.compileExpr(n.cond,C),i=H(()=>D(e,"__p"));t.push(`function build_${e}(__p) {`);for(const p of i)t.push(" "+p);t.push("}"),t.push(`const anchor_${e} = document.createComment('when');`),t.push(`${s}.appendChild(anchor_${e});`),t.push(`let shown_${e} = [];`),t.push("effect(() => {"),t.push(` if (${c}) {`),t.push(` if (!shown_${e}.length) { const __f = document.createDocumentFragment(); build_${e}(__f); shown_${e} = [...__f.childNodes]; anchor_${e}.parentNode.insertBefore(__f, anchor_${e}); }`),t.push(` } else if (shown_${e}.length) { for (const __n of shown_${e}) __n.remove(); shown_${e} = []; }`),t.push("});");break}case l.Each:{if(!n.list||!n.as)throw new Error("each without a list or item variable");const c=u.compileExpr(n.list,C),i=H(()=>D(e,"__p"));t.push(`function buildItem_${e}(__p, ${n.as}) {`);for(const p of i)t.push(" "+p);t.push("}"),t.push(`const anchor_${e} = document.createComment('each');`),t.push(`${s}.appendChild(anchor_${e});`),t.push(`let items_${e} = [];`),t.push("effect(() => {"),t.push(` for (const __n of items_${e}) __n.remove();`),t.push(" const __f = document.createDocumentFragment();"),t.push(` for (const ${n.as} of (${c} ?? [])) buildItem_${e}(__f, ${n.as});`),t.push(` items_${e} = [...__f.childNodes];`),t.push(` anchor_${e}.parentNode.insertBefore(__f, anchor_${e});`),t.push("});");break}case l.Custom:{t.push(`const el_${e} = document.createElement('div');`),t.push(`el_${e}.className = ${JSON.stringify(h("custom",n))};`),t.push(`${s}.appendChild(el_${e});`);const c=Object.entries(n.inputs||{}).map(([p,_])=>`${JSON.stringify(p)}: ${ye(_)}`).join(", "),i=Object.entries(n.on||{}).map(([p,_])=>`${JSON.stringify(p)}: (...__a) => ${u.actionRef(typeof _=="string"?_:"")}(...__a)`).join(", ");t.push(`if (typeof __custom_${n.component} === 'function') __custom_${n.component}(el_${e}, { ${c} }, { ${i} });`);break}case l.Button:{if(t.push(`const el_${e} = document.createElement('button');`),t.push(`el_${e}.className = ${JSON.stringify(h("button",n))};`),o.children&&o.children.length?D(e,`el_${e}`):n.label!==void 0&&L(e,"textContent",n.label),n.action){const c=n.arg!==void 0?u.compileExpr(n.arg,C):"";t.push(`el_${e}.addEventListener('click', () => ${u.actionRef(n.action)}(${c}));`)}E(e,n),t.push(`${s}.appendChild(el_${e});`);break}case l.Link:{t.push(`const el_${e} = document.createElement('a');`),t.push(`el_${e}.className = ${JSON.stringify(h("link",n))};`),t.push(`el_${e}.href = ${JSON.stringify(n.to||"/")};`),o.children&&o.children.length?D(e,`el_${e}`):n.label!==void 0&&L(e,"textContent",n.label),E(e,n),t.push(`${s}.appendChild(el_${e});`);break}case l.Slot:{M=!0,t.push("const __outlet = document.createElement('div');"),t.push("__outlet.className = 'muten-outlet';"),t.push(`${s}.appendChild(__outlet);`);break}default:throw new Error("unsupported primitive: "+o.type)}}const v=e=>String(e??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"),P=e=>v(e).replace(/"/g,"""),S=e=>typeof e=="string"?e:"";function re(){if($.format===y.Store||(m.params||[]).length)return!1;const e=new Set([l.When,l.Each,l.Custom,l.Form,l.SearchField,l.DataTable,l.Slot]),s=["action","bind","submit","on","inputs","data"],o=["value","src","alt","label"];for(const n of Object.keys(d)){const f=d[n],c=f.props||{};if(e.has(f.type)||s.some(i=>c[i]!==void 0)||(c.class||[]).some(i=>typeof i!="string")||o.some(i=>{const p=c[i];return!!p&&typeof p=="object"&&"kind"in p&&p.kind===de.Interp}))return!1}return!0}function Q(e){const s=d[e],o=s.props||{},n=()=>(d[e].children||[]).map(Q).join(""),f=i=>` class="${P(h(i,o))}"`,c=ee[s.type];if(c){const[i,p]=c;return`<${i}${f(p)}>${n()}</${i}>`}switch(s.type){case l.Text:return`<p${f("text")}>${v(S(o.value))}</p>`;case l.Span:return`<span${f("span")}>${v(S(o.value))}</span>`;case l.Title:{const i=o.level||"h1";return`<${i}${f("title")}>${v(S(o.value))}</${i}>`}case l.Image:return`<img${f("image")} src="${P(S(o.src))}" alt="${P(S(o.alt))}">`;case l.Link:return`<a${f("link")} href="${P(o.to||"/")}">${s.children&&s.children.length?n():v(S(o.label))}</a>`;case l.Button:return`<button${f("button")}>${s.children&&s.children.length?n():v(S(o.label))}</button>`;default:return""}}const V=$.format===y.Ssr?!1:re(),ce=(m.params||[]).map(e=>`const ${e} = (__params || {})[${JSON.stringify(e)}] ?? '';`).join(`
|
|
1
|
+
import{tokenClass as Z,resolveToken as ge,defaultTheme as _e}from"#engine/style/tokens.js";import{Nt as l,Ek as de,Fmt as y,Fk as q}from"#engine/shared/vocab.js";import{customValue as ye,CONTAINERS as ee,parseClause as be,editableFields as Se}from"#engine/compile/helpers.js";import{emitStore as Ne,emitStatic as Ce,emitStaticHtml as Ee,emitSsr as ve,emitModule as Oe,emitHtml as xe}from"#engine/compile/emit.js";import{Logic as ke}from"#engine/compile/logic.js";function Te(m,x={},k="",w={},J={},$={}){return te(m,x,k,w,J,{...$,format:y.Module})}function Fe(m={},x={},k={}){const{state:w={},gets:J={},actions:$={},effects:d=[],entities:N={}}=m;return te({screen:"store",entities:N,state:w,actions:$,gets:J,effects:d,consts:{},constraints:{},rootId:void 0,nodes:{}},x,"",{},k,{format:y.Store})}function te(m,x={},k="",w={},J={},$={}){const{nodes:d,rootId:N,state:j,entities:A,screen:ne}=m,B=$.theme||_e;let t=[],M=!1;const H=e=>{const s=t;t=[],e();const o=t;return t=s,o},W=new Set,h=(e,s)=>{for(const o of s.style||[])W.add(o);return[e,...(s.style||[]).map(Z),...(s.class||[]).filter(o=>typeof o=="string")].join(" ")},se=new Set(Object.keys(j)),K=new Set(Object.entries(j).filter(([,e])=>typeof e.source=="string"&&e.source.startsWith("query:")).map(([e])=>e)),U=new Set,oe={state:j,entities:A,actions:m.actions,consts:m.consts||{},gets:m.gets||{},effects:m.effects||[],stateKeys:se,queryStates:K,stores:$.stores||{},usedStores:U,params:new Set(m.params||[]),format:$.format},u=new ke(oe),C={locals:new Set},E=(e,s)=>{for(const o of s.class||[])typeof o!="string"&&t.push(`effect(() => el_${e}.classList.toggle(${JSON.stringify(o.name)}, !!(${u.compileExpr(o.cond,C)})));`);for(const[o,n]of Object.entries(s.on||{}))typeof n=="string"&&t.push(`el_${e}.addEventListener(${JSON.stringify(o)}, () => ${u.actionRef(n)}());`)},D=(e,s)=>{for(const o of d[e].children)G(o,s)},z=e=>e.parts.map(s=>typeof s=="string"?JSON.stringify(s):`String(${u.compileExpr(s,C)} ?? '')`).join(" + ");function R(e,s,o,n,f){if(t.push(`const el_${e} = document.createElement('${s}');`),t.push(`el_${e}.className = ${JSON.stringify(o)};`),typeof n=="string")t.push(`el_${e}.textContent = ${JSON.stringify(n)};`);else if(n&&"kind"in n){const c=z(n),i=n.parts.some(p=>typeof p!="string");t.push(i?`effect(() => { el_${e}.textContent = ${c}; });`:`el_${e}.textContent = ${c};`)}t.push(`${f}.appendChild(el_${e});`)}function I(e,s,o){if(typeof o=="string")t.push(`el_${e}.${s} = ${JSON.stringify(o)};`);else if(o&&"kind"in o){const n=z(o),f=o.parts.some(c=>typeof c!="string");t.push(f?`effect(() => { el_${e}.${s} = ${n}; });`:`el_${e}.${s} = ${n};`)}}function G(e,s){const o=d[e],n=o.props||{},f=ee[o.type];if(f){const[c,i]=f;t.push(`const el_${e} = document.createElement('${c}');`),t.push(`el_${e}.className = ${JSON.stringify(h(i,n))};`),o.type===l.Nav&&typeof n.label=="string"&&t.push(`el_${e}.setAttribute('aria-label', ${JSON.stringify(n.label)});`),t.push(`${s}.appendChild(el_${e});`),E(e,n),D(e,`el_${e}`);return}switch(o.type){case l.SearchField:{const c=u.bindSig(n.bind);t.push(`const el_${e} = document.createElement('input');`),t.push(`el_${e}.type = 'search';`),t.push(`el_${e}.className = ${JSON.stringify(h("search",n))};`),typeof n.placeholder=="string"&&t.push(`el_${e}.placeholder = ${JSON.stringify(n.placeholder)};`),t.push(`el_${e}.value = ${c}.get();`),t.push(`el_${e}.addEventListener('input', (e) => ${c}.set(e.target.value));`),t.push(`${s}.appendChild(el_${e});`);break}case l.DataTable:{const c=u.bindSig(n.data),i=K.has(c)?`${c}.get().data`:`${c}.get()`,p=n.columns||[],_=(n.where||[]).map(be),L=_.filter(r=>!r.dynamic).map(r=>`.filter((row) => ${r.expr})`).join(""),S=_.filter(r=>r.dynamic).map(r=>`.filter((row) => ${r.expr})`).join(""),a=o.children.map(r=>d[r]).filter(r=>r.type===l.RowAction);t.push(`const el_${e} = document.createElement('table');`),t.push(`el_${e}.className = ${JSON.stringify(h("datatable",n))};`),t.push(`const head_${e} = el_${e}.createTHead().insertRow();`);for(const r of p)t.push(`{ const th = document.createElement('th'); th.textContent = ${JSON.stringify(r)}; head_${e}.appendChild(th); }`);a.length&&t.push(`head_${e}.appendChild(document.createElement('th'));`),t.push(`const body_${e} = el_${e}.createTBody();`),t.push(`${s}.appendChild(el_${e});`),t.push(`function renderRow_${e}(row) {`),t.push(" const tr = document.createElement('tr');");for(const r of p)t.push(` { const td = document.createElement('td'); td.textContent = row[${JSON.stringify(r)}] ?? ''; tr.appendChild(td); }`);for(const r of a){const g=r.props||{},he=g.arg!==void 0?u.compileExpr(g.arg,{locals:new Set(["row"])}):"";t.push(` { const td = document.createElement('td'); const b = document.createElement('button'); b.className = ${JSON.stringify(h("row-action",g))}; b.textContent = ${JSON.stringify(g.label)}; b.addEventListener('click', () => ${u.actionRef(g.action)}(${he})); td.appendChild(b); tr.appendChild(td); }`)}t.push(" return tr;"),t.push("}"),t.push(`function base_${e}() { return ${i}${L}; }`),t.push("effect(() => {"),t.push(` const rows = base_${e}()${S};`),t.push(` body_${e}.replaceChildren(...rows.map(renderRow_${e}));`),t.push("});");break}case l.Form:{const c=u.bindSig(n.bind),i=j[c].type,p=Se(A[i]),_=(m.constraints||{})[i]||{};t.push(`const el_${e} = document.createElement('form');`),t.push(`el_${e}.className = ${JSON.stringify(h("form",n))};`),t.push(`{ const t = document.createElement('div'); t.className = 'form-title'; t.textContent = ${JSON.stringify("New "+i)}; el_${e}.appendChild(t); }`);const L=[];for(const a of p){const r=`f_${e}_${a.name}`;if(L.push({...a,var:r,c:_[a.name]}),a.kind===q.Enum){t.push(`const ${r} = document.createElement('select');`),t.push(`${r}.className = 'field';`);for(const g of a.options)t.push(`{ const o = document.createElement('option'); o.value = ${JSON.stringify(g)}; o.textContent = ${JSON.stringify(g)}; ${r}.appendChild(o); }`)}else t.push(`const ${r} = document.createElement('input');`),t.push(`${r}.type = ${JSON.stringify(a.kind===q.Email?"email":"text")};`),t.push(`${r}.className = 'field';`),t.push(`${r}.placeholder = ${JSON.stringify(a.name)};`);t.push(`${r}.addEventListener('input', (e) => ${c}.set({ ...${c}.get(), ${JSON.stringify(a.name)}: e.target.value }));`),t.push(`el_${e}.appendChild(${r});`),_[a.name]&&t.push(`const err_${r} = document.createElement('small'); err_${r}.className = 'field-error'; el_${e}.appendChild(err_${r});`)}t.push(`{ const sb = document.createElement('button'); sb.type = 'submit'; sb.className = 'submit'; sb.textContent = ${JSON.stringify(typeof n.submitLabel=="string"?n.submitLabel:"Submit")}; el_${e}.appendChild(sb); }`);const S=[];for(const a of L){if(!a.c)continue;const r=`err_${a.var}`,g=`String(__d[${JSON.stringify(a.name)}] ?? '')`;S.push(`${r}.textContent = '';`),a.c.required&&S.push(`if (!${g}.trim()) { ${r}.textContent = 'Required'; __ok = false; }`),a.c.min!=null&&S.push(`if (${g} && ${g}.length < ${a.c.min}) { ${r}.textContent = 'Min ${a.c.min} characters'; __ok = false; }`),a.c.max!=null&&S.push(`if (${g}.length > ${a.c.max}) { ${r}.textContent = 'Max ${a.c.max} characters'; __ok = false; }`)}S.length?t.push(`el_${e}.addEventListener('submit', (e) => { e.preventDefault(); const __d = ${c}.get(); let __ok = true; ${S.join(" ")} if (__ok) ${u.actionRef(n.submit)}(); });`):t.push(`el_${e}.addEventListener('submit', (e) => { e.preventDefault(); ${u.actionRef(n.submit)}(); });`),t.push("effect(() => {"),t.push(` const d = ${c}.get();`);for(const a of L){const r=a.kind===q.Enum?JSON.stringify(a.options[0]):"''";t.push(` { const v = d[${JSON.stringify(a.name)}] ?? ${r}; if (${a.var}.value !== v) ${a.var}.value = v; }`)}t.push("});"),t.push(`${s}.appendChild(el_${e});`);break}case l.Text:R(e,"p",h("text",n),n.value,s),E(e,n);break;case l.Span:R(e,"span",h("span",n),n.value,s),E(e,n);break;case l.Title:R(e,n.level||"h1",h("title",n),n.value,s),E(e,n);break;case l.Image:{t.push(`const el_${e} = document.createElement('img');`),t.push(`el_${e}.className = ${JSON.stringify(h("image",n))};`),I(e,"src",n.src),I(e,"alt",n.alt??""),t.push(`${s}.appendChild(el_${e});`);break}case l.When:{if(!n.cond)throw new Error("when without a condition");const c=u.compileExpr(n.cond,C),i=H(()=>D(e,"__p"));t.push(`function build_${e}(__p) {`);for(const p of i)t.push(" "+p);t.push("}"),t.push(`const anchor_${e} = document.createComment('when');`),t.push(`${s}.appendChild(anchor_${e});`),t.push(`let shown_${e} = [];`),t.push("effect(() => {"),t.push(` if (${c}) {`),t.push(` if (!shown_${e}.length) { const __f = document.createDocumentFragment(); build_${e}(__f); shown_${e} = [...__f.childNodes]; anchor_${e}.parentNode.insertBefore(__f, anchor_${e}); }`),t.push(` } else if (shown_${e}.length) { for (const __n of shown_${e}) __n.remove(); shown_${e} = []; }`),t.push("});");break}case l.Each:{if(!n.list||!n.as)throw new Error("each without a list or item variable");const c=u.compileExpr(n.list,C),i=H(()=>D(e,"__p"));t.push(`function buildItem_${e}(__p, ${n.as}) {`);for(const p of i)t.push(" "+p);t.push("}"),t.push(`const anchor_${e} = document.createComment('each');`),t.push(`${s}.appendChild(anchor_${e});`),t.push(`let items_${e} = [];`),t.push("effect(() => {"),t.push(` for (const __n of items_${e}) __n.remove();`),t.push(" const __f = document.createDocumentFragment();"),t.push(` for (const ${n.as} of (${c} ?? [])) buildItem_${e}(__f, ${n.as});`),t.push(` items_${e} = [...__f.childNodes];`),t.push(` anchor_${e}.parentNode.insertBefore(__f, anchor_${e});`),t.push("});");break}case l.Custom:{t.push(`const el_${e} = document.createElement('div');`),t.push(`el_${e}.className = ${JSON.stringify(h("custom",n))};`),t.push(`${s}.appendChild(el_${e});`);const c=Object.entries(n.inputs||{}).map(([p,_])=>`${JSON.stringify(p)}: ${ye(_)}`).join(", "),i=Object.entries(n.on||{}).map(([p,_])=>`${JSON.stringify(p)}: (...__a) => ${u.actionRef(typeof _=="string"?_:"")}(...__a)`).join(", ");t.push(`if (typeof __custom_${n.component} === 'function') __custom_${n.component}(el_${e}, { ${c} }, { ${i} });`);break}case l.Button:{if(t.push(`const el_${e} = document.createElement('button');`),t.push(`el_${e}.className = ${JSON.stringify(h("button",n))};`),o.children&&o.children.length?D(e,`el_${e}`):n.label!==void 0&&I(e,"textContent",n.label),n.action){const c=n.arg!==void 0?u.compileExpr(n.arg,C):"";t.push(`el_${e}.addEventListener('click', () => ${u.actionRef(n.action)}(${c}));`)}E(e,n),t.push(`${s}.appendChild(el_${e});`);break}case l.Link:{t.push(`const el_${e} = document.createElement('a');`),t.push(`el_${e}.className = ${JSON.stringify(h("link",n))};`),I(e,"href",n.to??"/"),o.children&&o.children.length?D(e,`el_${e}`):n.label!==void 0&&I(e,"textContent",n.label),E(e,n),t.push(`${s}.appendChild(el_${e});`);break}case l.Slot:{M=!0,t.push("const __outlet = document.createElement('div');"),t.push("__outlet.className = 'muten-outlet';"),t.push(`${s}.appendChild(__outlet);`);break}default:throw new Error("unsupported primitive: "+o.type)}}const v=e=>String(e??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"),P=e=>v(e).replace(/"/g,"""),b=e=>typeof e=="string"?e:"";function re(){if($.format===y.Store||(m.params||[]).length)return!1;const e=new Set([l.When,l.Each,l.Custom,l.Form,l.SearchField,l.DataTable,l.Slot]),s=["action","bind","submit","on","inputs","data"],o=["value","src","alt","label","to"];for(const n of Object.keys(d)){const f=d[n],c=f.props||{};if(e.has(f.type)||s.some(i=>c[i]!==void 0)||(c.class||[]).some(i=>typeof i!="string")||o.some(i=>{const p=c[i];return!!p&&typeof p=="object"&&"kind"in p&&p.kind===de.Interp}))return!1}return!0}function Q(e){const s=d[e],o=s.props||{},n=()=>(d[e].children||[]).map(Q).join(""),f=i=>` class="${P(h(i,o))}"`,c=ee[s.type];if(c){const[i,p]=c;return`<${i}${f(p)}>${n()}</${i}>`}switch(s.type){case l.Text:return`<p${f("text")}>${v(b(o.value))}</p>`;case l.Span:return`<span${f("span")}>${v(b(o.value))}</span>`;case l.Title:{const i=o.level||"h1";return`<${i}${f("title")}>${v(b(o.value))}</${i}>`}case l.Image:return`<img${f("image")} src="${P(b(o.src))}" alt="${P(b(o.alt))}">`;case l.Link:return`<a${f("link")} href="${P(b(o.to)||"/")}">${s.children&&s.children.length?n():v(b(o.label))}</a>`;case l.Button:return`<button${f("button")}>${s.children&&s.children.length?n():v(b(o.label))}</button>`;default:return""}}const V=$.format===y.Ssr?!1:re(),ce=(m.params||[]).map(e=>`const ${e} = (__params || {})[${JSON.stringify(e)}] ?? '';`).join(`
|
|
2
2
|
`),ie=u.genState(),ae=u.genActions(),le=Object.entries(m.gets||{}).map(([e,s])=>`export const ${e} = computed(() => ${u.compileExpr(s,C)});`).join(`
|
|
3
3
|
`),pe=u.genEffects();let X=null;V?X=N?Q(N):"":$.format!==y.Store&&N&&G(N,"app");const ue=t.join(`
|
|
4
4
|
`),Y={};for(const e of Object.values(j))if(typeof e.source=="string"&&e.source.startsWith("query:")){const s=e.source.slice(6),o=(e.type.match(/^list<(.+)>$/)||[])[1];Y[s]=o?u.uuidFields(o):[]}const fe=[...W].map(e=>{const s=ge(e,B);if(!s)return"";const o=`.${Z(e)}{${s}}`,n=e.indexOf(":"),f=n>0&&B.breakpoints[e.slice(0,n)];return f?`@media (min-width:${f}){${o}}`:o}).filter(Boolean).join(`
|
|
@@ -8,4 +8,4 @@ ${s}
|
|
|
8
8
|
})();`).join(`
|
|
9
9
|
|
|
10
10
|
`),$e=[...U].map(e=>`import * as __store_${e} from 'virtual:muten/store/${e}';`).join(`
|
|
11
|
-
`),
|
|
11
|
+
`),T=m.meta||{},F={...T};T.title&&!F["og:title"]&&(F["og:title"]=T.title),T.description&&!F["og:description"]&&(F["og:description"]=T.description);const O={screen:ne,tokenCss:fe,projectCss:k,data:x,sources:J,api:$.api||{},meta:F,queryUuids:Y,stateDecls:ie,paramDecls:ce,actionDecls:ae,getDecls:le,effectDecls:pe,componentDecls:me,storeImports:$e,renderBody:ue,staticHtml:X??"",hasSlot:M};return $.format===y.Store?Ne(O):$.format===y.Ssr?ve(O):V?$.format===y.Module?Ce(O):Ee(O):$.format===y.Module?Oe(O):xe(O)}export{te as compile,Te as compileModule,Fe as compileStore};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{Ek as f}from"#engine/shared/vocab.js";function A(t,n){const e=new Set;return{tree:t&&o(t,n,e),used:[...e]}}function o(t,n,e){const u=n[t.type];if(u){e.add(t.type);const c=s(u.tree,t.args||{});return o(c,n,e)}const i={type:t.type};return t.loc&&(i.loc=t.loc),t.args&&(i.args=t.args),t.props&&(i.props=t.props),t.children&&(i.children=t.children.map(c=>o(c,n,e))),i}function s(t,n){const e={type:t.type};return t.props&&(e.props=
|
|
1
|
+
import{Ek as f}from"#engine/shared/vocab.js";function A(t,n){const e=new Set;return{tree:t&&o(t,n,e),used:[...e]}}function o(t,n,e){const u=n[t.type];if(u){e.add(t.type);const c=s(u.tree,t.args||{});return o(c,n,e)}const i={type:t.type};return t.loc&&(i.loc=t.loc),t.args&&(i.args=t.args),t.props&&(i.props=t.props),t.children&&(i.children=t.children.map(c=>o(c,n,e))),i}function s(t,n){const e={type:t.type};return t.props&&(e.props=g(t.props,n)),t.args&&(e.args=a(t.args,n)),t.children&&(e.children=t.children.map(u=>s(u,n))),e}function g(t,n){const e={...t};return t.value!==void 0&&(e.value=d(t.value,n)),t.label!==void 0&&(e.label=d(t.label,n)),t.src!==void 0&&(e.src=d(t.src,n)),t.alt!==void 0&&(e.alt=d(t.alt,n)),t.placeholder!==void 0&&(e.placeholder=d(t.placeholder,n)),t.submitLabel!==void 0&&(e.submitLabel=d(t.submitLabel,n)),t.cond!==void 0&&(e.cond=r(t.cond,n)),t.list!==void 0&&(e.list=r(t.list,n)),t.arg!==void 0&&(e.arg=r(t.arg,n)),t.action!==void 0&&(e.action=l(t.action,n)),t.submit!==void 0&&(e.submit=l(t.submit,n)),t.bind!==void 0&&(e.bind=l(t.bind,n)),t.to!==void 0&&(e.to=typeof t.to=="string"?t.to:b(t.to,n)),t.inputs!==void 0&&(e.inputs=a(t.inputs,n)),t.on!==void 0&&(e.on=a(t.on,n)),e}function d(t,n){if(typeof t=="string")return t;if("$param"in t){const e=n[t.$param];return typeof e=="number"?String(e):e}return b(t,n)}function r(t,n){return t.kind===f.Ref?{kind:f.Ref,name:l(t.name,n)}:t.kind===f.Bin?{...t,left:r(t.left,n),right:r(t.right,n)}:t.kind===f.Un?{...t,operand:r(t.operand,n)}:t.kind===f.Tern?{...t,cond:r(t.cond,n),then:r(t.then,n),else:r(t.else,n)}:t}function b(t,n){return{kind:f.Interp,parts:t.parts.map(e=>typeof e=="string"?e:r(e,n))}}function a(t,n){const e={};for(const[u,i]of Object.entries(t))e[u]=m(i,n);return e}function m(t,n){return typeof t=="string"?t.startsWith("$")?l(t,n):t:typeof t=="number"?t:n[t.$param]}function l(t,n){if(!t.startsWith("$"))return t;const e=t.slice(1).split(".")[0],u=t.slice(1+e.length),i=n[e];return(typeof i=="string"?i:e)+u}export{A as compose};
|
|
@@ -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
|
|
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};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ParseError as f}from"#engine/shared/diagnostics.js";import{PRIMITIVES as g}from"#engine/lang/manifest.js";import{Grammar as R}from"#engine/lang/grammar.js";import{Tk as t,Pn as i,Kw as a,Nt as P,Mod as u,StOp as o}from"#engine/shared/vocab.js";const v={};for(const[c,e]of Object.entries(g))e.string&&(v[c]=e.string);const x=new Set(Object.entries(g).filter(([,c])=>c.interp).map(([c])=>c)),S=c=>c==="text"?"string":c,y=c=>/^h[1-6]$/.test(c);class k extends R{modifiers;statements;constructor(e){super(e),this.modifiers=new Map([[u.Bind,s=>{s.bind=this.at(t.Ref)?this.eat(t.Ref).v:this.parseDotted()}],[u.Submit,s=>{s.submit=this.parseDotted()}],[u.Where,s=>{s.where=this.parseParenList(()=>this.rebuildClause())}],[u.Columns,s=>{s.columns=this.parseParenList(()=>this.eat(t.Ident).v)}],[u.Style,s=>{s.style=this.parseParenList(()=>this.parseStyleToken())}],[u.Class,s=>{s.class=this.parseParenList(()=>{const n=this.at(t.String)?this.next().v:this.eat(t.Ident).v;return this.at(t.Ident,a.When)?(this.next(),{name:n,cond:this.parseExpr()}):n})}],[u.Alt,s=>{s.alt=this.parseInterpolation(this.eat(t.String).v)}],[u.Inputs,s=>{s.inputs=this.parseArgs()}],[u.On,s=>{s.on=this.parseArgs()}]]),this.statements=new Map([[o.Push,s=>({op:o.Push,target:s,arg:this.parseExpr()})],[o.Set,s=>({op:o.Set,target:s,arg:this.parseExpr()})],[o.Reset,s=>({op:o.Reset,target:s})],[o.Remove,s=>{const n=this.eat(t.Ident).v;return this.eat(t.FatArrow),{op:o.Remove,target:s,param:n,pred:this.parseExpr()}}],[o.Create,s=>({op:o.Create,target:s,arg:this.parseExpr()})],[o.Update,s=>({op:o.Update,target:s,arg:this.parseExpr()})],[o.Delete,s=>({op:o.Delete,target:s,arg:this.parseExpr()})],[o.Refetch,s=>{const n={};for(;!this.at(t.Punct,i.ParenR);){const r=this.eat(t.Ident).v;this.eat(t.Punct,i.Colon),n[r]=this.parseExpr(),this.at(t.Punct,i.Comma)&&this.next()}return{op:o.Refetch,target:s,params:n}}]])}parse(){const e={screen:"",entities:{},state:{},actions:{},tree:null},s=new Map([[a.Screen,()=>{this.next(),e.screen=this.eat(t.Ident).v}],[a.Entity,()=>this.parseEntity(e)],[a.State,()=>this.parseState(a.State,e.state)],[a.Store,()=>{e.store=e.store||{},this.parseState(a.Store,e.store)}],[a.Get,()=>this.parseGet(e)],[a.Effect,()=>{this.next(),(e.effects=e.effects||[]).push(this.parseActionBody())}],[a.Action,()=>this.parseAction(e)],[a.Mock,()=>this.parseMock(e)],[a.Sources,()=>this.parseSources(e)],[a.Api,()=>this.parseApi(e)],[a.Meta,()=>this.parseMeta(e)],[a.Routes,()=>this.parseRoutes(e)],[a.Shell,()=>this.parseShell(e)],[a.Part,()=>this.parsePart(e)],[a.Const,()=>this.parseConst(e)],[a.Theme,()=>this.parseTheme(e)],[a.Param,()=>{this.next(),(e.params=e.params||[]).push(this.eat(t.Ident).v)}]]);for(;!this.at(t.Eof);){const n=this.peek(),r=n.t===t.Ident?s.get(n.v):void 0;r?r():e.tree=this.parseNode()}return e}parseEntity(e){this.eat(t.Ident,a.Entity);const s=this.eat(t.Ident).v;this.eat(t.Punct,i.BraceL);const n={id:"uuid"},r={};for(;!this.at(t.Punct,i.BraceR);){const p=this.eat(t.Ident).v,h=[this.eat(t.Ident).v];for(;this.at(t.Punct,i.Pipe);)this.next(),h.push(this.eat(t.Ident).v);n[p]=h.length>1?"enum:"+h.join("|"):S(h[0]);const d=this.parseConstraints();Object.keys(d).length&&(r[p]=d)}this.eat(t.Punct,i.BraceR),e.entities[s]=n,Object.keys(r).length&&((e.constraints=e.constraints||{})[s]=r)}parseConstraints(){const e={};for(;this.at(t.Ident,a.Required)||this.at(t.Ident,a.Min)||this.at(t.Ident,a.Max);){const s=this.next().v;if(s===a.Required){e.required=!0;continue}this.eat(t.Punct,i.Colon);const n=Number(this.eat(t.Number).v);s===a.Min?e.min=n:e.max=n}return e}parseState(e,s){for(this.eat(t.Ident,e),this.eat(t.Punct,i.BraceL);!this.at(t.Punct,i.BraceR);){const n=this.eat(t.Ident);this.eat(t.Punct,i.Assign);let r,p,h=!1;this.at(t.Ident,a.Query)?(this.next(),r="query:"+this.eat(t.Ident).v):this.at(t.Punct,i.BraceL)||this.at(t.Punct,i.BrackL)?(p=this.parseValue(),h=!0):this.at(t.String)?(p=this.next().v,h=!0):this.at(t.Number)?(p=Number(this.next().v),h=!0):this.at(t.Ident,a.True)||this.at(t.Ident,a.False)?(p=this.next().v===a.True,h=!0):(p=this.next().v,h=!0),this.eat(t.Punct,i.Colon);const d=this.parseType(),m=this.locOf(n.pos);s[n.v]=r?{type:d,source:r,loc:m}:{type:d,initial:h?p:null,loc:m}}this.eat(t.Punct,i.BraceR)}parseGet(e){this.eat(t.Ident,a.Get);const s=this.eat(t.Ident).v;this.eat(t.Punct,i.Assign),(e.gets=e.gets||{})[s]=this.parseExpr()}parseAction(e){this.eat(t.Ident,a.Action);const s=this.eat(t.Ident).v,n=[];if(this.at(t.Ident,a.Mutates))for(this.next(),n.push(this.eat(t.Ident).v);this.at(t.Punct,i.Comma);)this.next(),n.push(this.eat(t.Ident).v);let r="";this.at(t.LArrow)&&(this.next(),r=this.eat(t.Ident).v),e.actions[s]={mutates:n,input:r,body:this.parseActionBody()}}parseActionBody(){this.eat(t.Punct,i.BraceL);const e=[];for(;!this.at(t.Punct,i.BraceR);)e.push(this.parseStatement());return this.eat(t.Punct,i.BraceR),e}parseIf(){this.eat(t.Ident,a.If);const e=this.parseExpr(),s=this.parseActionBody(),n=this.at(t.Ident,a.Else)?(this.next(),this.parseActionBody()):null;return{op:o.If,cond:e,then:s,else:n}}parseRequest(){const e=this.eat(t.Ident).v.toUpperCase(),s=this.parseInterpolation(this.eat(t.String).v);let n=null;return this.at(t.Ident,a.Body)&&(this.next(),n=this.parseExpr()),{op:o.Request,method:e,url:s,body:n}}parseStatement(){if(this.at(t.Ident,a.If))return this.parseIf();if(this.at(t.Ident,"post")||this.at(t.Ident,"put")||this.at(t.Ident,"delete"))return this.parseRequest();const e=this.eat(t.Ident).v;this.eat(t.Punct,i.Dot);const s=this.eat(t.Ident).v;this.eat(t.Punct,i.ParenL);const n=this.statements.get(s);if(!n)throw new f(`unknown action method "${s}" on "${e}"`,this.locOf(this.peek().pos));const r=n(e);return this.eat(t.Punct,i.ParenR),r}parseMock(e){this.eat(t.Ident,a.Mock);const s=e.mock||{};this.parseEntries(n=>{s[n]=this.parseValue()}),e.mock=s}parseSources(e){this.eat(t.Ident,a.Sources);const s=e.sources||{};this.parseEntries(n=>{s[n]=this.parseValue()}),e.sources=s}parseApi(e){this.eat(t.Ident,a.Api);const s=e.api||{};this.parseEntries(n=>{s[n]=this.parseValue()}),e.api=s}parseMeta(e){this.eat(t.Ident,a.Meta),this.eat(t.Punct,i.BraceL);const s=e.meta||{};for(;!this.at(t.Punct,i.BraceR);){const n=this.eat(t.Ident).v;s[n]=this.eat(t.String).v}this.eat(t.Punct,i.BraceR),e.meta=s}parseRoutes(e){this.eat(t.Ident,a.Routes),this.eat(t.Punct,i.BraceL);const s=e.routes||[];for(;!this.at(t.Punct,i.BraceR);){const n=this.peek(),r=this.locOf(n.pos).line,p=this.pathOnLine(r);this.eat(t.Arrow);const h={url:p,page:this.eat(t.Ident).v,loc:this.locOf(n.pos)};this.at(t.Ident,a.Guard)&&(this.next(),h.guardNeg=this.at(t.Ident,a.Not)?(this.next(),!0):!1,h.guard=this.parseDotted(),this.eat(t.Ident,a.Else),h.redirect=this.pathOnLine(r)),s.push(h)}this.eat(t.Punct,i.BraceR),e.routes=s}parseShell(e){this.eat(t.Ident,a.Shell),e.shell={type:P.Shell,props:{},children:this.parseChildren()}}parseConst(e){this.eat(t.Ident,a.Const);const s=this.eat(t.Ident).v;if(this.eat(t.Punct,i.Assign),this.at(t.Punct,i.BraceL)||this.at(t.Punct,i.BrackL))throw new f("const holds a single value (string/number/bool) \u2014 use a block like `theme { \u2026 }` for structured data",this.locOf(this.peek().pos));(e.consts=e.consts||{})[s]=this.parseScalar()}parseTheme(e){this.eat(t.Ident,a.Theme),this.eat(t.Punct,i.BraceL);const s={};for(;!this.at(t.Punct,i.BraceR);){const n=this.eat(t.Ident).v;this.eat(t.Punct,i.BraceL);const r={};for(;!this.at(t.Punct,i.BraceR);)r[this.eat(t.Ident).v]=this.eat(t.String).v;this.eat(t.Punct,i.BraceR),s[n]=r}this.eat(t.Punct,i.BraceR),e.theme=s}parsePart(e){this.eat(t.Ident,a.Part);const s=this.eat(t.Ident).v;this.eat(t.Punct,i.ParenL);const n=[];for(;!this.at(t.Punct,i.ParenR);){const p=this.eat(t.Ident).v;this.eat(t.Punct,i.Colon),n.push({name:p,type:this.parseType()}),this.at(t.Punct,i.Comma)&&this.next()}this.eat(t.Punct,i.ParenR);const r=this.parseChildren();e.parts=e.parts||{},e.parts[s]={params:n,tree:r.length===1?r[0]:{type:P.Stack,props:{},children:r}}}parseWhen(){const e=this.eat(t.Ident,a.When),s=this.parseExpr();return{type:P.When,props:{cond:s},children:this.parseChildren(),loc:this.locOf(e.pos)}}parseEach(){const e=this.eat(t.Ident,a.Each),s=this.parseExpr();this.eat(t.Ident,a.As);const n=this.eat(t.Ident).v;return{type:P.Each,props:{list:s,as:n},children:this.parseChildren(),loc:this.locOf(e.pos)}}parseNode(){if(this.at(t.Ident,a.When))return this.parseWhen();if(this.at(t.Ident,a.Each))return this.parseEach();const e=this.eat(t.Ident),s=e.v,n=this.locOf(e.pos);if(this.at(t.Punct,i.ParenL))return{type:s,args:this.parseArgs(),loc:n};const r={},p=[];s===P.Custom&&(r.component=this.eat(t.Ident).v);let h=!0;for(;h;){const m=this.peek();switch(m.t){case t.String:{const l=v[s]||"label";r[l]=x.has(s)?this.parseInterpolation(this.next().v):this.next().v;break}case t.Param:{const l=v[s]||"label";r[l]={$param:this.next().v};break}case t.Ref:r.data=this.next().v;break;case t.Arrow:this.parseArrow(s,r);break;case t.Ident:{const l=m.v;if(s===P.Title&&y(l)){this.next(),r.level=l;break}const I=this.modifiers.get(l);if(!I){h=!1;break}this.next(),I(r);break}case t.Punct:if(m.v===i.BraceL){for(this.next();!this.at(t.Punct,i.BraceR);)p.push(this.parseNode());this.eat(t.Punct,i.BraceR)}h=!1;break;default:h=!1}}const d={type:s,props:r,loc:n};return p.length&&(d.children=p),d}parseArrow(e,s){if(this.next(),e===P.Link){s.to=this.parsePath();return}s.action=this.parseDotted(),this.at(t.Punct,i.ParenL)&&(this.next(),this.at(t.Punct,i.ParenR)||(s.arg=this.parseExpr()),this.eat(t.Punct,i.ParenR))}parseChildren(){this.eat(t.Punct,i.BraceL);const e=[];for(;!this.at(t.Punct,i.BraceR);)e.push(this.parseNode());return this.eat(t.Punct,i.BraceR),e}parseType(){let e=this.eat(t.Ident).v;return this.at(t.Punct,i.Lt)&&(this.next(),e+="<"+this.eat(t.Ident).v+">",this.eat(t.Punct,i.Gt)),e}parseStyleToken(){const e=()=>this.at(t.Number)?this.next().v:this.eat(t.Ident).v;let s=e();for(this.at(t.Punct,i.Colon)&&(this.next(),s+=":"+e());this.at(t.Punct,i.Dot);)this.next(),s+="."+e();return s}parseDotted(){let e=this.at(t.Param)?"$"+this.next().v:this.eat(t.Ident).v;for(;this.at(t.Punct,i.Dot);)this.next(),e+="."+this.eat(t.Ident).v;return e}parseParenList(e){this.eat(t.Punct,i.ParenL);const s=[];for(;!this.at(t.Punct,i.ParenR);)s.push(e()),this.at(t.Punct,i.Comma)&&this.next();return this.eat(t.Punct,i.ParenR),s}rebuildClause(){const e=[];for(;!this.at(t.Punct,i.Comma)&&!this.at(t.Punct,i.ParenR);)e.push(this.next().v);return e.join(" ")}parseEntries(e){for(this.eat(t.Punct,i.BraceL);!this.at(t.Punct,i.BraceR);){const s=this.eat(t.Ident).v;this.eat(t.Punct,i.Colon),e(s),this.at(t.Punct,i.Comma)&&this.next()}this.eat(t.Punct,i.BraceR)}parsePath(){let e="";for(;this.at(t.Punct,i.Slash);){const s=this.next();e+="/",this.at(t.Ident)&&this.peek().pos===s.pos+1&&(e+=this.eat(t.Ident).v)}return e}pathOnLine(e){let s="";for(;this.at(t.Punct,i.Slash)&&this.locOf(this.peek().pos).line===e;)this.next(),s+="/",this.at(t.Punct,i.Colon)?(this.next(),s+=":"+this.eat(t.Ident).v):this.at(t.Ident)&&(s+=this.eat(t.Ident).v);return s}parseArgs(){this.eat(t.Punct,i.ParenL);const e={};for(;!this.at(t.Punct,i.ParenR);){const s=this.eat(t.Ident).v;this.eat(t.Punct,i.Colon),e[s]=this.parseArgValue(),this.at(t.Punct,i.Comma)&&this.next()}return this.eat(t.Punct,i.ParenR),e}parseArgValue(){return this.at(t.String)?this.next().v:this.at(t.Number)?Number(this.next().v):this.at(t.Ref)?this.next().v:this.at(t.Param)?{$param:this.next().v}:this.parseDotted()}}function C(c){return new k(c).parse()}export{k as Parser,C as parse};
|
|
1
|
+
import{ParseError as f}from"#engine/shared/diagnostics.js";import{PRIMITIVES as g}from"#engine/lang/manifest.js";import{Grammar as R}from"#engine/lang/grammar.js";import{Tk as t,Pn as i,Kw as n,Nt as P,Mod as u,StOp as o,Ek as x}from"#engine/shared/vocab.js";const v={};for(const[c,e]of Object.entries(g))e.string&&(v[c]=e.string);const S=new Set(Object.entries(g).filter(([,c])=>c.interp).map(([c])=>c)),y=c=>c==="text"?"string":c,k=c=>/^h[1-6]$/.test(c);class w extends R{modifiers;statements;constructor(e){super(e),this.modifiers=new Map([[u.Bind,s=>{s.bind=this.at(t.Ref)?this.eat(t.Ref).v:this.parseDotted()}],[u.Submit,s=>{s.submit=this.parseDotted()}],[u.Where,s=>{s.where=this.parseParenList(()=>this.rebuildClause())}],[u.Columns,s=>{s.columns=this.parseParenList(()=>this.eat(t.Ident).v)}],[u.Style,s=>{s.style=this.parseParenList(()=>this.parseStyleToken())}],[u.Class,s=>{s.class=this.parseParenList(()=>{const a=this.at(t.String)?this.next().v:this.eat(t.Ident).v;return this.at(t.Ident,n.When)?(this.next(),{name:a,cond:this.parseExpr()}):a})}],[u.Alt,s=>{s.alt=this.parseInterpolation(this.eat(t.String).v)}],[u.Inputs,s=>{s.inputs=this.parseArgs()}],[u.On,s=>{s.on=this.parseArgs()}]]),this.statements=new Map([[o.Push,s=>({op:o.Push,target:s,arg:this.parseExpr()})],[o.Set,s=>({op:o.Set,target:s,arg:this.parseExpr()})],[o.Reset,s=>({op:o.Reset,target:s})],[o.Remove,s=>{const a=this.eat(t.Ident).v;return this.eat(t.FatArrow),{op:o.Remove,target:s,param:a,pred:this.parseExpr()}}],[o.Create,s=>({op:o.Create,target:s,arg:this.parseExpr()})],[o.Update,s=>({op:o.Update,target:s,arg:this.parseExpr()})],[o.Delete,s=>({op:o.Delete,target:s,arg:this.parseExpr()})],[o.Refetch,s=>{const a={};for(;!this.at(t.Punct,i.ParenR);){const r=this.eat(t.Ident).v;this.eat(t.Punct,i.Colon),a[r]=this.parseExpr(),this.at(t.Punct,i.Comma)&&this.next()}return{op:o.Refetch,target:s,params:a}}]])}parse(){const e={screen:"",entities:{},state:{},actions:{},tree:null},s=new Map([[n.Screen,()=>{this.next(),e.screen=this.eat(t.Ident).v}],[n.Entity,()=>this.parseEntity(e)],[n.State,()=>this.parseState(n.State,e.state)],[n.Store,()=>{e.store=e.store||{},this.parseState(n.Store,e.store)}],[n.Get,()=>this.parseGet(e)],[n.Effect,()=>{this.next(),(e.effects=e.effects||[]).push(this.parseActionBody())}],[n.Action,()=>this.parseAction(e)],[n.Mock,()=>this.parseMock(e)],[n.Sources,()=>this.parseSources(e)],[n.Api,()=>this.parseApi(e)],[n.Meta,()=>this.parseMeta(e)],[n.Routes,()=>this.parseRoutes(e)],[n.Shell,()=>this.parseShell(e)],[n.Part,()=>this.parsePart(e)],[n.Const,()=>this.parseConst(e)],[n.Theme,()=>this.parseTheme(e)],[n.Param,()=>{this.next(),(e.params=e.params||[]).push(this.eat(t.Ident).v)}]]);for(;!this.at(t.Eof);){const a=this.peek(),r=a.t===t.Ident?s.get(a.v):void 0;r?r():e.tree=this.parseNode()}return e}parseEntity(e){this.eat(t.Ident,n.Entity);const s=this.eat(t.Ident).v;this.eat(t.Punct,i.BraceL);const a={id:"uuid"},r={};for(;!this.at(t.Punct,i.BraceR);){const p=this.eat(t.Ident).v,h=[this.eat(t.Ident).v];for(;this.at(t.Punct,i.Pipe);)this.next(),h.push(this.eat(t.Ident).v);a[p]=h.length>1?"enum:"+h.join("|"):y(h[0]);const d=this.parseConstraints();Object.keys(d).length&&(r[p]=d)}this.eat(t.Punct,i.BraceR),e.entities[s]=a,Object.keys(r).length&&((e.constraints=e.constraints||{})[s]=r)}parseConstraints(){const e={};for(;this.at(t.Ident,n.Required)||this.at(t.Ident,n.Min)||this.at(t.Ident,n.Max);){const s=this.next().v;if(s===n.Required){e.required=!0;continue}this.eat(t.Punct,i.Colon);const a=Number(this.eat(t.Number).v);s===n.Min?e.min=a:e.max=a}return e}parseState(e,s){for(this.eat(t.Ident,e),this.eat(t.Punct,i.BraceL);!this.at(t.Punct,i.BraceR);){const a=this.eat(t.Ident);this.eat(t.Punct,i.Assign);let r,p,h=!1;this.at(t.Ident,n.Query)?(this.next(),r="query:"+this.eat(t.Ident).v):this.at(t.Punct,i.BraceL)||this.at(t.Punct,i.BrackL)?(p=this.parseValue(),h=!0):this.at(t.String)?(p=this.next().v,h=!0):this.at(t.Number)?(p=Number(this.next().v),h=!0):this.at(t.Ident,n.True)||this.at(t.Ident,n.False)?(p=this.next().v===n.True,h=!0):(p=this.next().v,h=!0),this.eat(t.Punct,i.Colon);const d=this.parseType(),m=this.locOf(a.pos);s[a.v]=r?{type:d,source:r,loc:m}:{type:d,initial:h?p:null,loc:m}}this.eat(t.Punct,i.BraceR)}parseGet(e){this.eat(t.Ident,n.Get);const s=this.eat(t.Ident).v;this.eat(t.Punct,i.Assign),(e.gets=e.gets||{})[s]=this.parseExpr()}parseAction(e){this.eat(t.Ident,n.Action);const s=this.eat(t.Ident).v,a=[];if(this.at(t.Ident,n.Mutates))for(this.next(),a.push(this.eat(t.Ident).v);this.at(t.Punct,i.Comma);)this.next(),a.push(this.eat(t.Ident).v);let r="";this.at(t.LArrow)&&(this.next(),r=this.eat(t.Ident).v),e.actions[s]={mutates:a,input:r,body:this.parseActionBody()}}parseActionBody(){this.eat(t.Punct,i.BraceL);const e=[];for(;!this.at(t.Punct,i.BraceR);)e.push(this.parseStatement());return this.eat(t.Punct,i.BraceR),e}parseIf(){this.eat(t.Ident,n.If);const e=this.parseExpr(),s=this.parseActionBody(),a=this.at(t.Ident,n.Else)?(this.next(),this.parseActionBody()):null;return{op:o.If,cond:e,then:s,else:a}}parseRequest(){const e=this.eat(t.Ident).v.toUpperCase(),s=this.parseInterpolation(this.eat(t.String).v);let a=null;return this.at(t.Ident,n.Body)&&(this.next(),a=this.parseExpr()),{op:o.Request,method:e,url:s,body:a}}parseStatement(){if(this.at(t.Ident,n.If))return this.parseIf();if(this.at(t.Ident,"post")||this.at(t.Ident,"put")||this.at(t.Ident,"delete"))return this.parseRequest();const e=this.eat(t.Ident).v;this.eat(t.Punct,i.Dot);const s=this.eat(t.Ident).v;this.eat(t.Punct,i.ParenL);const a=this.statements.get(s);if(!a)throw new f(`unknown action method "${s}" on "${e}"`,this.locOf(this.peek().pos));const r=a(e);return this.eat(t.Punct,i.ParenR),r}parseMock(e){this.eat(t.Ident,n.Mock);const s=e.mock||{};this.parseEntries(a=>{s[a]=this.parseValue()}),e.mock=s}parseSources(e){this.eat(t.Ident,n.Sources);const s=e.sources||{};this.parseEntries(a=>{s[a]=this.parseValue()}),e.sources=s}parseApi(e){this.eat(t.Ident,n.Api);const s=e.api||{};this.parseEntries(a=>{s[a]=this.parseValue()}),e.api=s}parseMeta(e){this.eat(t.Ident,n.Meta),this.eat(t.Punct,i.BraceL);const s=e.meta||{};for(;!this.at(t.Punct,i.BraceR);){const a=this.eat(t.Ident).v;s[a]=this.eat(t.String).v}this.eat(t.Punct,i.BraceR),e.meta=s}parseRoutes(e){this.eat(t.Ident,n.Routes),this.eat(t.Punct,i.BraceL);const s=e.routes||[];for(;!this.at(t.Punct,i.BraceR);){const a=this.peek(),r=this.locOf(a.pos).line,p=this.pathOnLine(r);this.eat(t.Arrow);const h={url:p,page:this.eat(t.Ident).v,loc:this.locOf(a.pos)};this.at(t.Ident,n.Guard)&&(this.next(),h.guardNeg=this.at(t.Ident,n.Not)?(this.next(),!0):!1,h.guard=this.parseDotted(),this.eat(t.Ident,n.Else),h.redirect=this.pathOnLine(r)),s.push(h)}this.eat(t.Punct,i.BraceR),e.routes=s}parseShell(e){this.eat(t.Ident,n.Shell),e.shell={type:P.Shell,props:{},children:this.parseChildren()}}parseConst(e){this.eat(t.Ident,n.Const);const s=this.eat(t.Ident).v;if(this.eat(t.Punct,i.Assign),this.at(t.Punct,i.BraceL)||this.at(t.Punct,i.BrackL))throw new f("const holds a single value (string/number/bool) \u2014 use a block like `theme { \u2026 }` for structured data",this.locOf(this.peek().pos));(e.consts=e.consts||{})[s]=this.parseScalar()}parseTheme(e){this.eat(t.Ident,n.Theme),this.eat(t.Punct,i.BraceL);const s={};for(;!this.at(t.Punct,i.BraceR);){const a=this.eat(t.Ident).v;this.eat(t.Punct,i.BraceL);const r={};for(;!this.at(t.Punct,i.BraceR);)r[this.eat(t.Ident).v]=this.eat(t.String).v;this.eat(t.Punct,i.BraceR),s[a]=r}this.eat(t.Punct,i.BraceR),e.theme=s}parsePart(e){this.eat(t.Ident,n.Part);const s=this.eat(t.Ident).v;this.eat(t.Punct,i.ParenL);const a=[];for(;!this.at(t.Punct,i.ParenR);){const p=this.eat(t.Ident).v;this.eat(t.Punct,i.Colon),a.push({name:p,type:this.parseType()}),this.at(t.Punct,i.Comma)&&this.next()}this.eat(t.Punct,i.ParenR);const r=this.parseChildren();e.parts=e.parts||{},e.parts[s]={params:a,tree:r.length===1?r[0]:{type:P.Stack,props:{},children:r}}}parseWhen(){const e=this.eat(t.Ident,n.When),s=this.parseExpr();return{type:P.When,props:{cond:s},children:this.parseChildren(),loc:this.locOf(e.pos)}}parseEach(){const e=this.eat(t.Ident,n.Each),s=this.parseExpr();this.eat(t.Ident,n.As);const a=this.eat(t.Ident).v;return{type:P.Each,props:{list:s,as:a},children:this.parseChildren(),loc:this.locOf(e.pos)}}parseNode(){if(this.at(t.Ident,n.When))return this.parseWhen();if(this.at(t.Ident,n.Each))return this.parseEach();const e=this.eat(t.Ident),s=e.v,a=this.locOf(e.pos);if(this.at(t.Punct,i.ParenL))return{type:s,args:this.parseArgs(),loc:a};const r={},p=[];s===P.Custom&&(r.component=this.eat(t.Ident).v);let h=!0;for(;h;){const m=this.peek();switch(m.t){case t.String:{const l=v[s]||"label";r[l]=S.has(s)?this.parseInterpolation(this.next().v):this.next().v;break}case t.Param:{const l=v[s]||"label";r[l]={$param:this.next().v};break}case t.Ref:r.data=this.next().v;break;case t.Arrow:this.parseArrow(s,r);break;case t.Ident:{const l=m.v;if(s===P.Title&&k(l)){this.next(),r.level=l;break}const I=this.modifiers.get(l);if(!I){h=!1;break}this.next(),I(r);break}case t.Punct:if(m.v===i.BraceL){for(this.next();!this.at(t.Punct,i.BraceR);)p.push(this.parseNode());this.eat(t.Punct,i.BraceR)}h=!1;break;default:h=!1}}const d={type:s,props:r,loc:a};return p.length&&(d.children=p),d}parseArrow(e,s){if(this.next(),e===P.Link){s.to=this.parsePath();return}s.action=this.parseDotted(),this.at(t.Punct,i.ParenL)&&(this.next(),this.at(t.Punct,i.ParenR)||(s.arg=this.parseExpr()),this.eat(t.Punct,i.ParenR))}parseChildren(){this.eat(t.Punct,i.BraceL);const e=[];for(;!this.at(t.Punct,i.BraceR);)e.push(this.parseNode());return this.eat(t.Punct,i.BraceR),e}parseType(){let e=this.eat(t.Ident).v;return this.at(t.Punct,i.Lt)&&(this.next(),e+="<"+this.eat(t.Ident).v+">",this.eat(t.Punct,i.Gt)),e}parseStyleToken(){const e=()=>this.at(t.Number)?this.next().v:this.eat(t.Ident).v;let s=e();for(this.at(t.Punct,i.Colon)&&(this.next(),s+=":"+e());this.at(t.Punct,i.Dot);)this.next(),s+="."+e();return s}parseDotted(){let e=this.at(t.Param)?"$"+this.next().v:this.eat(t.Ident).v;for(;this.at(t.Punct,i.Dot);)this.next(),e+="."+this.eat(t.Ident).v;return e}parseParenList(e){this.eat(t.Punct,i.ParenL);const s=[];for(;!this.at(t.Punct,i.ParenR);)s.push(e()),this.at(t.Punct,i.Comma)&&this.next();return this.eat(t.Punct,i.ParenR),s}rebuildClause(){const e=[];for(;!this.at(t.Punct,i.Comma)&&!this.at(t.Punct,i.ParenR);)e.push(this.next().v);return e.join(" ")}parseEntries(e){for(this.eat(t.Punct,i.BraceL);!this.at(t.Punct,i.BraceR);){const s=this.eat(t.Ident).v;this.eat(t.Punct,i.Colon),e(s),this.at(t.Punct,i.Comma)&&this.next()}this.eat(t.Punct,i.BraceR)}parsePath(){const e=[];let s="";for(;this.at(t.Punct,i.Slash);){const a=this.next();s+="/",this.at(t.Punct,i.BraceL)&&this.peek().pos===a.pos+1?(e.push(s),s="",this.next(),e.push(this.parseExpr()),this.eat(t.Punct,i.BraceR)):this.at(t.Ident)&&this.peek().pos===a.pos+1&&(s+=this.eat(t.Ident).v)}return e.length?(s&&e.push(s),{kind:x.Interp,parts:e}):s}pathOnLine(e){let s="";for(;this.at(t.Punct,i.Slash)&&this.locOf(this.peek().pos).line===e;)this.next(),s+="/",this.at(t.Punct,i.Colon)?(this.next(),s+=":"+this.eat(t.Ident).v):this.at(t.Ident)&&(s+=this.eat(t.Ident).v);return s}parseArgs(){this.eat(t.Punct,i.ParenL);const e={};for(;!this.at(t.Punct,i.ParenR);){const s=this.eat(t.Ident).v;this.eat(t.Punct,i.Colon),e[s]=this.parseArgValue(),this.at(t.Punct,i.Comma)&&this.next()}return this.eat(t.Punct,i.ParenR),e}parseArgValue(){return this.at(t.String)?this.next().v:this.at(t.Number)?Number(this.next().v):this.at(t.Ref)?this.next().v:this.at(t.Param)?{$param:this.next().v}:this.parseDotted()}}function A(c){return new w(c).parse()}export{w as Parser,A as parse};
|
package/dist/lint.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{join as
|
|
2
|
-
\u2716 ${
|
|
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};
|