@memoized-dom/runtime 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -0
- package/dist/access.d.ts +61 -0
- package/dist/access.d.ts.map +1 -0
- package/dist/chunks/chunk-FX3LH6HS.js +1 -0
- package/dist/cleanup.d.ts +19 -0
- package/dist/cleanup.d.ts.map +1 -0
- package/dist/cond.d.ts +37 -0
- package/dist/cond.d.ts.map +1 -0
- package/dist/delegated-events.d.ts +9 -0
- package/dist/delegated-events.d.ts.map +1 -0
- package/dist/dirty-reasons.d.ts +14 -0
- package/dist/dirty-reasons.d.ts.map +1 -0
- package/dist/dom-props.d.ts +13 -0
- package/dist/dom-props.d.ts.map +1 -0
- package/dist/dom-values.d.ts +14 -0
- package/dist/dom-values.d.ts.map +1 -0
- package/dist/effect.d.ts +21 -0
- package/dist/effect.d.ts.map +1 -0
- package/dist/events.d.ts +36 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/jsx-dom.d.ts +9 -0
- package/dist/jsx-dom.d.ts.map +1 -0
- package/dist/kernel.d.ts +129 -0
- package/dist/kernel.d.ts.map +1 -0
- package/dist/list.d.ts +64 -0
- package/dist/list.d.ts.map +1 -0
- package/dist/props.d.ts +27 -0
- package/dist/props.d.ts.map +1 -0
- package/dist/refs.d.ts +11 -0
- package/dist/refs.d.ts.map +1 -0
- package/dist/setters.d.ts +49 -0
- package/dist/setters.d.ts.map +1 -0
- package/dist/testing.d.ts +10 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +1 -0
- package/package.json +28 -0
package/README.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# @memoized-dom/runtime
|
|
2
|
+
|
|
3
|
+
Dependency-free registry, scheduling, optional dirty-reason batching, access
|
|
4
|
+
routing, keyed regions, props boxes, cleanup/ref ownership, and DOM value helpers
|
|
5
|
+
for memoized-dom compiler output.
|
|
6
|
+
|
|
7
|
+
Application source does not need to import reactive primitives. Generated
|
|
8
|
+
modules import this package as one namespace:
|
|
9
|
+
|
|
10
|
+
```js
|
|
11
|
+
import * as MD from '@memoized-dom/runtime';
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
The package is independently buildable:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
bun run build
|
|
18
|
+
```
|
package/dist/access.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file access.ts
|
|
3
|
+
* M3 — The static access table: compile-time read/write knowledge.
|
|
4
|
+
*
|
|
5
|
+
* In the real pipeline (M5) the COMPILER emits this table per app by analyzing
|
|
6
|
+
* component bodies. In the bootstrap we hand-write it — we are the compiler.
|
|
7
|
+
*
|
|
8
|
+
* readers: canonical module-qualified state key -> entity id patterns that
|
|
9
|
+
* READ it (`./state.ts#store.selectedId`).
|
|
10
|
+
* - exact id: 'App/Header/Badge'
|
|
11
|
+
* - '*' wildcard: 'App/SelectList/Row[*]' ('*' matches within one segment)
|
|
12
|
+
*
|
|
13
|
+
* opaque: variables the analysis cannot prove (dynamic member access, state
|
|
14
|
+
* escaping to third-party code). Writing an opaque variable falls back to a
|
|
15
|
+
* root-subtree commit — exactly Imba's behavior. Never incorrect, just not
|
|
16
|
+
* scoped (spec §4.5 fallback rule).
|
|
17
|
+
*
|
|
18
|
+
* HONEST LIMITATION: ordinary 'Row[*]' readers over-approximate and dirty all
|
|
19
|
+
* matching live rows. Parametrized payload patterns can narrow this when the
|
|
20
|
+
* compiler has a precise target; otherwise guarded writes absorb the slack.
|
|
21
|
+
*/
|
|
22
|
+
import { type EntityId } from './kernel';
|
|
23
|
+
export interface AccessTable {
|
|
24
|
+
readers: Record<string, string[]>;
|
|
25
|
+
opaque?: string[];
|
|
26
|
+
/** L2 precision patterns, interpolated from commitWrites(..., payload). */
|
|
27
|
+
params?: Record<string, readonly {
|
|
28
|
+
pattern: string;
|
|
29
|
+
}[]>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Install a table fragment. Fragments MERGE app-wide (spec §4.6): every
|
|
33
|
+
* compiled module installs its own fragment at init, and readers from all
|
|
34
|
+
* of them must stay live — a write in module A can target a component
|
|
35
|
+
* declared in module B. Re-installing the same fragment is idempotent.
|
|
36
|
+
*/
|
|
37
|
+
export declare function installAccessTable(table: AccessTable, root: EntityId): void;
|
|
38
|
+
/** Clear every installed fragment — test isolation, not app code. */
|
|
39
|
+
export declare function resetAccessTable(): void;
|
|
40
|
+
export declare function isOpaque(variable: string): boolean;
|
|
41
|
+
export declare function getRootId(): EntityId;
|
|
42
|
+
/**
|
|
43
|
+
* Fast path used by compiler-generated commits without an L2 payload.
|
|
44
|
+
* Kept separate so parameter interpolation can tree-shake out of ordinary
|
|
45
|
+
* applications.
|
|
46
|
+
*/
|
|
47
|
+
export declare function resolveStaticWrites(writes: readonly string[]): EntityId[] | 'root-subtree';
|
|
48
|
+
/**
|
|
49
|
+
* Resolve written variables to the entity ids that must be dirtied.
|
|
50
|
+
* Exact readers are returned as-is (markDirty no-ops dead letters).
|
|
51
|
+
* Wildcards are expanded by the caller against live registry ids.
|
|
52
|
+
*
|
|
53
|
+
* Path granularity (M5.3): a write matches a read key when their dotted
|
|
54
|
+
* paths are equal OR one is a segment-wise prefix of the other — writing
|
|
55
|
+
* 'store.items' invalidates readers of 'store.items.length' (descendant)
|
|
56
|
+
* and of 'store' (ancestor). Segment boundaries prevent 'items' ↔ 'items1'.
|
|
57
|
+
*
|
|
58
|
+
* Returns 'root-subtree' when any write is opaque — the Imba fallback.
|
|
59
|
+
*/
|
|
60
|
+
export declare function resolveWrites(writes: readonly string[], _liveIds: readonly EntityId[], payload?: Record<string, any>): EntityId[] | 'root-subtree';
|
|
61
|
+
//# sourceMappingURL=access.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access.d.ts","sourceRoot":"","sources":["../src/access.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAmC,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAE1E,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC,CAAC;CACzD;AA+ED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI,CAoC3E;AAED,qEAAqE;AACrE,wBAAgB,gBAAgB,IAAI,IAAI,CAWvC;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAElD;AAED,wBAAgB,SAAS,IAAI,QAAQ,CAEpC;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,MAAM,EAAE,GACxB,QAAQ,EAAE,GAAG,cAAc,CAG7B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,QAAQ,EAAE,SAAS,QAAQ,EAAE,EAC7B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC5B,QAAQ,EAAE,GAAG,cAAc,CAuD7B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var b=new Map;function xe(e,t,n){if(n===void 0||Array.isArray(n)&&n.length===0){b.size!==0&&b.delete(e);return}if(!t){typeof n=="number"?b.set(e,n):n.length===1?b.set(e,n[0]):b.set(e,new Set(n));return}let r=b.get(e);if(r===void 0)return;let o=typeof n=="number"?[n]:n;if(typeof r=="number"){o.some(i=>i!==r)&&b.set(e,new Set([r,...o]));return}for(let i of o)r.add(i)}function ke(e){if(b.size===0)return null;let t=b.get(e)??null;return b.delete(e),t}function O(e){b.size!==0&&b.delete(e)}var m=new Map,x=new Set,ve=typeof requestAnimationFrame=="function"?e=>requestAnimationFrame(e):e=>setTimeout(e,0),te=ve;function Xe(e){te=e}function Qe(){te=ve}function Ye(e){let t=0;for(let n=0;n<e.length;n++)e.charCodeAt(n)===47&&t++;return t}var z=null,Re=0;var Ie=[],Y=[];function Se(e){Y.includes(e)||Y.push(e)}function F(e){Ie.push(e)}function Te(e,t){for(let n of Ie)n(e,t)}function H(e){let t=e.parent!==null?m.get(e.parent):void 0;e.depth=e.depth??(t&&t.depth!==void 0?t.depth+1:Ye(e.id)),m.set(e.id,e),t&&(t.children??=new Set).add(e.id),z=null,Re++,Te(e.id,"add")}function v(e){let t=m.get(e);if(!t)return;t.parent!==null&&m.get(t.parent)?.children?.delete(e);let n=[e],r=[],o=[];for(;n.length>0;){let i=n.pop(),s=m.get(i);if(s&&(r.push(i),s.children))for(let d of s.children)n.push(d)}r.reverse();for(let i of r)m.delete(i),x.delete(i),O(i),Te(i,"remove");for(let i of r)for(let s of Y){let d=s(i);d!==void 0&&o.push(...d)}if(z=null,Re++,o.length===1)throw o[0];if(o.length>1)throw new AggregateError(o,`[memo-dom] ${o.length} cleanup disposers failed while unregistering '${e}'`)}function et(e){v(e)}function W(e){return m.has(e)}function ne(e){return m.get(e)}function tt(e){let t=o=>{if(o.children!==void 0)for(let i of o.children){let s=m.get(i);s!==void 0&&(s.phase!=="effect"&&(s.render(),M(i)),t(s))}},n=o=>{if(o.children!==void 0)for(let i of o.children){let s=m.get(i);s!==void 0&&(s.phase==="effect"&&(s.render(),M(i)),n(s))}},r=m.get(e);r!==void 0&&(t(r),n(r))}function re(){return z??=[...m.keys()],z}function I(e,t){if(!m.has(e))return;let n=x.has(e);(t!==void 0||n)&&xe(e,n,t),x.add(e),Ce()}function M(e){x.size!==0&&x.delete(e)&&O(e)}function C(e){let t=e+"/",n=!1;for(let r of m.keys())(r===e||r.startsWith(t))&&(x.add(r),O(r),n=!0);n&&Ce()}var ee=!1,j=!1;function Ce(){ee||j||(ee=!0,te(De))}function De(){if(ee=!1,!j){j=!0;try{for(let e=0;e<100&&x.size>0;e++){let t=[];for(let o of x){let i=m.get(o);i?t.push(i):(x.delete(o),O(o))}let r=t.some(o=>o.phase!=="effect")?t.filter(o=>o.phase!=="effect"):t;r.sort((o,i)=>(o.depth??0)-(i.depth??0));for(let o of r)x.delete(o.id)&&o.render(ke(o.id))}if(x.size>0)throw new Error("[memo-dom] commit cascade exceeded 100 passes \u2014 an update is dirtying its own readers (cycle)")}finally{j=!1}}}function Gt(){return{registry:m,dirtySet:x}}var _=new Map,oe=new Set,Le=!1;function nt(){Le||(Le=!0,Se(rt))}function B(e,t){if(typeof t!="function")throw new TypeError("[memo-dom] cleanup(disposer) requires a function");if(oe.has(e))throw new Error(`[memo-dom] cannot register cleanup while '${e}' is being unregistered`);nt();let n=_.get(e);return n===void 0&&(n=[],_.set(e,n)),n.push(t),t}function rt(e){let t=_.get(e);if(t===void 0)return[];_.delete(e),oe.add(e);let n=[];try{for(let r=t.length-1;r>=0;r--)try{t[r]()}catch(o){n.push(o)}}finally{oe.delete(e)}return n}function ot(e,t){let n=[],r=!0;try{Ae(e,t,n)}catch(o){let i=Me(n);throw i.length>0?new AggregateError([o,...i],"[memo-dom] ref setup and rollback failed"):o}return()=>{if(!r)return;r=!1;let o=Me(n);if(o.length===1)throw o[0];if(o.length>1)throw new AggregateError(o,"[memo-dom] multiple ref cleanups failed")}}function Ae(e,t,n){if(t==null||t===!1)return;if(Array.isArray(t)){for(let o of t)Ae(e,o,n);return}if(typeof t!="function")throw new TypeError("[memo-dom] ref value must be a callback, an assignable JSX target, or an array of refs");let r=t(e);if(r!=null){if(typeof r!="function")throw new TypeError("[memo-dom] ref callback must return a cleanup function or nothing");n.push(r)}}function Me(e){let t=[];for(let n=e.length-1;n>=0;n--)try{e[n]()}catch(r){t.push(r)}return e.length=0,t}function Ne(e,t,n){let r;W(e)&&v(e),H({id:e,parent:t,phase:"effect",render(){let o=r;r=void 0,o?.();let i=n();if(i!==void 0&&typeof i!="function")throw new TypeError(`[memo-dom] effect '${e}' must return a cleanup function or undefined`);r=typeof i=="function"?i:void 0}}),B(e,()=>{let o=r;r=void 0,o?.()}),I(e)}function it(e,t,n,r){let o=`${e}/$active`,i=!1;W(e)&&v(e),H({id:e,parent:t,phase:"effect",render(){let s=!!n();s!==i&&(i=s,i?Ne(o,e,r):v(o))}}),B(e,()=>{i=!1,W(o)&&v(o)}),I(e)}function st(e,t,n,r){e[t]!==r&&(e[t]=r,n.data=r==null||typeof r=="boolean"?"":String(r))}function dt(e,t,n,r){e[t]!==r&&(e[t]=r,n.className=r)}function ct(e,t,n,r,o){e[t]!==o&&(e[t]=o,n.classList.toggle(r,o))}function lt(e,t,n,r,o){e[t]!==o&&(e[t]=o,o==null||o===!1?n.removeAttribute(r):o===!0?n.setAttribute(r,""):n.setAttribute(r,String(o)))}function ft(e,t,n,r,o){e[t]!==o&&(e[t]=o,n[r]=o)}function at(e,t,n,r,o){e[t]!==o&&(e[t]=o,o==null?n.style.removeProperty(r):n.style.setProperty(r,o))}function ut(e,t){if(Array.isArray(e)&&Array.isArray(t)){if(e===t||e.length!==t.length)return!0;for(let n=0;n<e.length;n++)if(!Object.is(e[n],t[n])||ie(e[n]))return!0;return!1}return ie(e)||ie(t)?!0:!Object.is(e,t)}function ie(e){return typeof e=="object"&&e!==null||typeof e=="function"}var se="",A=new Map,D=new Map,K=new Map,de=new Set,ce=[],N=new Map,$=0,q=new Map,U=new Map;function pt(){N=new Map;let e=re();for(let[t,n]of D){let r=new Set;for(let o of n)for(let i of e)o.test(i)&&r.add(i);N.set(t,r)}}F((e,t)=>{if(D.size===0)return;let n=!1;if(t==="add")for(let[r,o]of D){let i=N.get(r);if(i){for(let s of o)if(s.test(e)){i.add(e),n=!0;break}}}else for(let r of N.values())r.delete(e)&&(n=!0);n&&$++});function yt(e){if(!e.includes("*"))return null;let t=e.split("*").map(n=>n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")).join("[^/]*");return new RegExp(`^${t}$`)}function gt(e,t){se=t;let n=new Set;for(let[r,o]of Object.entries(e.readers))for(let i of o){let s=`${r}${i}`;if(n.has(s))continue;n.add(s);let d=yt(i);if(d===null){let c=A.get(r)??[];c.includes(i)||c.push(i),A.set(r,c)}else{let c=D.get(r)??[];c.some(a=>a.source===d.source)||c.push(d),D.set(r,c)}}for(let[r,o]of Object.entries(e.params??{})){let i=K.get(r)??[];for(let s of o)i.includes(s.pattern)||i.push(s.pattern);K.set(r,i)}for(let r of e.opaque??[])de.add(r);ce=[...new Set([...A.keys(),...D.keys()])],q.clear(),U.clear(),pt(),$++}function ht(){se="",A=new Map,D=new Map,K=new Map,de=new Set,ce=[],N=new Map,q.clear(),U.clear(),$++}function le(e){return de.has(e)}function G(){return se}function fe(e){return e.some(le)?"root-subtree":Pe(e)}function ae(e,t,n){if(e.some(le))return"root-subtree";if(n){let r=new Set,o=!0;for(let i of e){let s=K.get(i);if(s===void 0||s.length===0){o=!1;break}for(let d of s){let c=!1,a=d.replace(/\{([^}]+)\}/g,(h,u)=>{let S=u.trim();if(!S.startsWith("payload."))return c=!0,"";let w=n;for(let T of S.slice(8).split(".")){if(w===null||typeof w!="object")return c=!0,"";w=w[T]}return w==null?(c=!0,""):String(w)});if(c){o=!1;break}r.add(a)}if(!o)break;for(let d of A.get(i)??[])r.add(d)}if(o&&r.size>0)return[...r]}return Pe(e)}function Pe(e){let t=e.length===1?e[0]:e.join(" "),n=U.get(t);if(n!==void 0&&n.v===$)return n.result;let r=new Set,o=new Set;for(let s of e){let d=q.get(s);if(d===void 0){d=[];for(let c of ce)(c===s||c.startsWith(`${s}.`)||s.startsWith(`${c}.`))&&d.push(c);q.set(s,d)}for(let c of d)o.add(c)}for(let s of o){for(let d of A.get(s)??[])r.add(d);for(let d of N.get(s)??[])r.add(d)}let i=[...r];return U.set(t,{v:$,result:i}),i}var mt=1e3,V=[];function Et(){return V}function wt(){V.length=0}function Oe(e){let t=fe(e);if(t==="root-subtree"){C(G());return}for(let n of t)I(n)}function bt(e,t){let n=ae(e,[],t);if(n==="root-subtree"){C(G());return}for(let r of n)I(r)}function xt(e,t,n){return r=>{n(r),V.push({origin:e,writes:t,at:Date.now()}),V.length>mt&&V.shift(),Oe(t)}}var kt=e=>e,vt=[],Rt=[],It=[];function St(e){let t=e.length,n=vt,r=Rt,o=It;n.length=t,o.length=t,r.length=0;for(let s=0;s<t;s++)n[s]=!1,o[s]=-1;for(let s=0;s<t;s++){let d=e[s];if(d<0)continue;let c=0,a=r.length;for(;c<a;){let h=c+a>>1;e[r[h]]<d?c=h+1:a=h}r[c]=s,c>0&&(o[s]=r[c-1])}let i=r.length>0?r[r.length-1]:-1;for(;i>=0;)n[i]=!0,i=o[i];return n}function Tt(e,t,n,r=kt){let o=document.createComment(`list:${t}`);e.appendChild(o);let i=new Map,s=new Map,d=0,c=[],a=[],h=[],u=new Map,S=[],w=[],T=[];function ye(p,g,y,L){if(p.updateProps?.(g,L),p.update!==void 0)p.update(),M(y);else{let R=ne(y);R&&(R.render(),M(y))}}function Ke(p){let g=typeof p;if(g==="string"||g==="number"||g==="boolean"||g==="bigint")return`${t}/Row[${String(p)}]`;let y=s.get(p);return y===void 0&&(y=`#${++d}`,s.set(p,y)),`${t}/Row[${y}]`}function qe(p){if(p.length===c.length){let l=!0;for(let f=0;f<p.length;f++)if(p[f]!==c[f]){l=!1;break}if(l){for(let f=0;f<p.length;f++)ye(a[f],p[f],h[f],f);return}}let g=i;u.clear();let y=u,L=w,R=S,Q=p.length;L.length=Q,R.length=Q,T.length=Q;let ge=!1,he=!0,me=-1;for(let l=0;l<p.length;l++){let f=p[l],E=r(f,l);if(y.has(E))throw new Error(`[memo-dom] duplicate list key: ${String(E)}`);let k=g.get(E);if(k!==void 0)g.delete(E),T[l]=k.pos,k.pos<=me?he=!1:me=k.pos,k.pos=l,ye(k.e,f,k.id,l);else{let be=Ke(E);k={e:n(f,be,l),id:be,pos:l},T[l]=-1,ge=!0}y.set(E,k),R[l]=k.e,L[l]=k.id}if(!ge&&g.size===0&&he){i=y,u=g;let l=a;a=R,S=l;let f=h;h=L,w=f,c=p.slice();return}for(let[l,f]of g){f.e.dispose?.();for(let E of f.e.nodes)E.parentNode?.removeChild(E);for(let E of f.e.entities)v(E);s.delete(l)}let Ge=St(T),Ee=o,P=null,we=()=>{if(P===null)return;let l=document.createDocumentFragment();for(let f=P.length-1;f>=0;f--)for(let E of P[f].nodes)l.appendChild(E);e.insertBefore(l,Ee),P=null};for(let l=R.length-1;l>=0;l--){let f=R[l];T[l]===-1||!Ge[l]?(P??=[]).push(f):(we(),Ee=f.nodes[0])}we(),i=y,u=g;let Ze=a;a=R,S=Ze;let Je=h;h=L,w=Je,c=p.slice()}function Ue(){for(let[p,g]of i){g.e.dispose?.();for(let y of g.e.nodes)y.parentNode?.removeChild(y);for(let y of g.e.entities)v(y);s.delete(p)}i.clear(),u.clear(),c=[],a.length=0,h.length=0,S.length=0,w.length=0,o.parentNode?.removeChild(o)}return{reconcile:qe,size:()=>i.size,dispose:Ue}}function Ct(e){return e.nodeType===Node.DOCUMENT_FRAGMENT_NODE?Array.from(e.childNodes):[e]}var We=new Map;function Dt(e,t,n,r){let o=Mt(n),i=We.get(o);i===void 0&&(i={captureRoots:new WeakSet,handler:Symbol(`memo-dom:${o}:handler`),root:Symbol(`memo-dom:${o}:root`),bubbleRoots:new WeakSet},We.set(o,i));let s=t;s[i.handler]=r,s[i.root]=e,i.bubbleRoots.has(e)||(i.bubbleRoots.add(e),e.addEventListener(o,d=>{d.bubbles&&$e(e,i,d)})),i.captureRoots.has(e)||(i.captureRoots.add(e),e.addEventListener(o,d=>{d.bubbles||$e(e,i,d)},!0))}function $e(e,t,n){let r=typeof n.composedPath=="function"?n.composedPath():Lt(n.target,e);for(let o of r){let i=o;if(i[t.root]===e){let s=i[t.handler];s!==void 0&&s.call(o,n)===!1&&n.preventDefault()}if(o===e||n.cancelBubble)break}}function Lt(e,t){let n=[],r=e;for(;r!==null&&(n.push(r),r!==t);)r="parentNode"in r?r.parentNode:null;return n}function Mt(e){let t=e.startsWith("on")?e.slice(2).toLowerCase():e.toLowerCase();return t==="doubleclick"?"dblclick":t}var Z=new WeakMap,At=new Set(["animation-iteration-count","border-image-outset","border-image-slice","border-image-width","column-count","flex","flex-grow","flex-shrink","font-weight","grid-column","grid-row","line-height","opacity","order","orphans","scale","tab-size","widows","z-index","zoom"]);function J(e){let t=[];return Ve(e,t),t.join(" ")}function ue(e,t){let n=J(t);e.namespaceURI==="http://www.w3.org/2000/svg"?n===""?e.removeAttribute("class"):e.setAttribute("class",n):e.className=n}function pe(e,t){let n=e.style;if(n===void 0)return;if(typeof t=="string"){let i=Z.get(e);if(i?.size===1&&i.get("$cssText")===t)return;n.cssText=t,Z.set(e,new Map([["$cssText",t]]));return}let r=new Map;if(t!==null&&typeof t=="object")for(let[i,s]of Object.entries(t)){if(s==null)continue;let d=Nt(i);r.set(d,Pt(d,s))}let o=Z.get(e)??new Map;o.has("$cssText")&&(n.cssText="");for(let i of o.keys())i!=="$cssText"&&!r.has(i)&&n.removeProperty(i);for(let[i,s]of r)o.get(i)!==s&&n.setProperty(i,s);Z.set(e,r)}function Ve(e,t){if(e==null||e===!1||e===!0)return;if(Array.isArray(e)){for(let r of e)Ve(r,t);return}if(typeof e=="object"){for(let[r,o]of Object.entries(e))o&&t.push(r);return}let n=String(e).trim();n!==""&&t.push(n)}function Nt(e){return e.startsWith("--")||e.includes("-")?e:e.replace(/^ms([A-Z])/,"ms-$1").replace(/[A-Z]/g,t=>`-${t.toLowerCase()}`)}function Pt(e,t){return typeof t=="number"&&t!==0&&!e.startsWith("--")&&!At.has(e)?`${t}px`:String(t)}var je=new WeakMap,ze=new WeakMap,Ot=new Set(["innerHTML","checked","value","selected","disabled","hidden","multiple","required","readOnly","muted","open","controls","loop","autoFocus","autoPlay","tabIndex"]),Fe={className:"class",htmlFor:"for",readOnly:"readonly",autoFocus:"autofocus",autoPlay:"autoplay",tabIndex:"tabindex",crossOrigin:"crossorigin"},Wt={className:"class",clipPath:"clip-path",clipRule:"clip-rule",colorInterpolation:"color-interpolation",colorInterpolationFilters:"color-interpolation-filters",dominantBaseline:"dominant-baseline",fillOpacity:"fill-opacity",fillRule:"fill-rule",floodColor:"flood-color",floodOpacity:"flood-opacity",fontFamily:"font-family",fontSize:"font-size",markerEnd:"marker-end",markerMid:"marker-mid",markerStart:"marker-start",stopColor:"stop-color",stopOpacity:"stop-opacity",strokeDasharray:"stroke-dasharray",strokeDashoffset:"stroke-dashoffset",strokeLinecap:"stroke-linecap",strokeLinejoin:"stroke-linejoin",strokeMiterlimit:"stroke-miterlimit",strokeOpacity:"stroke-opacity",strokeWidth:"stroke-width",textAnchor:"text-anchor",vectorEffect:"vector-effect",xlinkHref:"xlink:href"},$t={doubleclick:"dblclick"};function Vt(e,t,n,r=[]){let o=t!==null&&typeof t=="object"?t:{},i=je.get(e)??new Map,s=new Set(r);for(let c of i.keys())Object.prototype.hasOwnProperty.call(o,c)||He(e,c,null,i,n,s);for(let[c,a]of Object.entries(o))He(e,c,a,i,n,s);let d=new Map;for(let[c,a]of Object.entries(o))d.set(c,Be(c,a));je.set(e,d)}function _e(e,t,n){if(t==="class"||t==="className"){ue(e,n);return}if(t==="style"){pe(e,n);return}Ft(e,t,n)}function He(e,t,n,r,o,i){if(t==="key"||t==="children"||t==="ref")return;if(/^on[A-Z]/.test(t)){jt(e,t,typeof n=="function"?n:null,o,i.has(t));return}let s=Be(t,n);Object.is(r.get(t),s)||_e(e,t,n)}function Be(e,t){return e==="class"||e==="className"?J(t):e==="style"?Symbol("style-snapshot"):t==null||typeof t=="string"||typeof t=="number"||typeof t=="boolean"?t:String(t)}function jt(e,t,n,r,o){let i=ze.get(e);i===void 0&&(i=new Map,ze.set(e,i));let s=i.get(t);if(s?.source===n||(s!==void 0&&(e.removeEventListener(s.type,s.listener),i.delete(t)),n===null))return;let d=zt(t),c=o?n:function(h){let u=n.call(this,h);return C(r),u!==null&&typeof u=="object"&&"then"in u&&typeof u.then=="function"&&u.then(()=>{C(r)}),u};e.addEventListener(d,c),i.set(t,{source:n,listener:c,type:d})}function zt(e){let t=e.slice(2).toLowerCase();return $t[t]??t}function Ft(e,t,n){let r=e.namespaceURI!=="http://www.w3.org/2000/svg";if(r&&Ot.has(t)){if(t==="tabIndex"&&n==null){e.removeAttribute("tabindex");return}e[t]=n??Ht(t);return}let o=r?Fe[t]??t:Wt[t]??Fe[t]??t;n==null||n===!1?e.removeAttribute(o):n===!0?e.setAttribute(o,""):!r&&t==="xlinkHref"?e.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",String(n)):e.setAttribute(o,String(n))}function Ht(e){return e==="value"||e==="innerHTML"?"":!1}function _t(e,t,n,r){let o=document.createComment(`when:${t}`);e.appendChild(o);let i=-1,s=null;function d(){let a=n();if(a===i){s?.update();return}if(s!==null){s.dispose?.();for(let u of s.nodes)u.parentNode?.removeChild(u);s=null}let h=r[a]??null;if(h!==null){s=h();for(let u=s.nodes.length-1;u>=0;u--)o.parentNode.insertBefore(s.nodes[u],o)}i=a}function c(){if(s!==null){s.dispose?.();for(let a of s.nodes)a.parentNode?.removeChild(a);s=null}o.parentNode?.removeChild(o),i=-1}return d(),{update:d,index:()=>i,dispose:c}}var X=new Map;function Bt(e,t){X.set(e,t)}function Kt(e,t){let n=X.get(e);if(n===void 0)return;let r=n.length!==t.length;if(!r){for(let o=0;o<t.length;o++)if(!Object.is(n[o],t[o])){r=!0;break}}if(r){n.length=t.length;for(let o=0;o<t.length;o++)n[o]=t[o];I(e)}}function wn(e){return X.get(e)}F((e,t)=>{t==="remove"&&X.delete(e)});export{Xe as a,Qe as b,H as c,v as d,et as e,W as f,ne as g,tt as h,re as i,I as j,M as k,C as l,De as m,Gt as n,B as o,ot as p,Ne as q,it as r,st as s,dt as t,ct as u,lt as v,ft as w,at as x,ut as y,gt as z,ht as A,le as B,G as C,fe as D,ae as E,Et as F,wt as G,Oe as H,bt as I,xt as J,Tt as K,Ct as L,Dt as M,J as N,ue as O,pe as P,Vt as Q,_e as R,_t as S,Bt as T,Kt as U,wn as V};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cleanup.ts - explicit component-owned teardown.
|
|
3
|
+
*
|
|
4
|
+
* The compiler lowers source `cleanup(disposer)` calls to
|
|
5
|
+
* `cleanup(componentId, disposer)`. Registrations may happen before the
|
|
6
|
+
* component enters the entity registry; unregistering the entity owns and
|
|
7
|
+
* synchronously drains its disposers.
|
|
8
|
+
*/
|
|
9
|
+
import { type EntityId } from './kernel';
|
|
10
|
+
export type CleanupDisposer = () => void;
|
|
11
|
+
/** Register one disposer for an entity and return it unchanged. */
|
|
12
|
+
export declare function cleanup(owner: EntityId, disposer: CleanupDisposer): CleanupDisposer;
|
|
13
|
+
/**
|
|
14
|
+
* Drain an owner's disposers in reverse registration order.
|
|
15
|
+
* Teardown continues after individual failures; the kernel reports them once
|
|
16
|
+
* the complete subtree has been removed.
|
|
17
|
+
*/
|
|
18
|
+
export declare function disposeOwnerCleanups(owner: EntityId): unknown[];
|
|
19
|
+
//# sourceMappingURL=cleanup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cleanup.d.ts","sourceRoot":"","sources":["../src/cleanup.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAmB,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAE1D,MAAM,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC;AAYzC,mEAAmE;AACnE,wBAAgB,OAAO,CACrB,KAAK,EAAE,QAAQ,EACf,QAAQ,EAAE,eAAe,GACxB,eAAe,CAiBjB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,EAAE,CAmB/D"}
|
package/dist/cond.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cond.ts — R8 conditional regions: anchored branch swapping.
|
|
3
|
+
*
|
|
4
|
+
* The mirror of list.ts for conditionals. A conditional region owns the DOM
|
|
5
|
+
* between its insertion point and an anchor comment; the compiler emits one
|
|
6
|
+
* per `{cond ? <A/> : <B/>}` site and registers it as an entity, so the
|
|
7
|
+
* access table routes the region's variables to it — a condition write
|
|
8
|
+
* dirties the region, never the whole owner.
|
|
9
|
+
*
|
|
10
|
+
* Branch semantics (spec §R8):
|
|
11
|
+
* - update() re-evaluates pick(). Same branch → the branch's own guarded
|
|
12
|
+
* update closure runs. Different branch → compiler-owned components and
|
|
13
|
+
* list regions drain, the old nodes are removed, and the new branch
|
|
14
|
+
* factory runs before the anchor.
|
|
15
|
+
* - A swap destroys branch-local DOM state (focus, scroll); module state
|
|
16
|
+
* survives, so re-mounting a branch reflects current state.
|
|
17
|
+
*/
|
|
18
|
+
import type { EntityId } from './kernel';
|
|
19
|
+
export interface CondEntry {
|
|
20
|
+
/** Root nodes of the mounted branch (elements or fragment children). */
|
|
21
|
+
nodes: Node[];
|
|
22
|
+
/** The branch's guarded update closure. */
|
|
23
|
+
update: () => void;
|
|
24
|
+
/** Drain structural regions retained by this branch before replacement. */
|
|
25
|
+
dispose?: () => void;
|
|
26
|
+
}
|
|
27
|
+
export type CondBranchFactory = () => CondEntry;
|
|
28
|
+
export interface CondRegion {
|
|
29
|
+
/** Re-pick and re-render: same branch → guarded update; swap → rebuild. */
|
|
30
|
+
update(): void;
|
|
31
|
+
/** Currently mounted branch index. */
|
|
32
|
+
index(): number;
|
|
33
|
+
/** Drain the mounted branch and remove the stable anchor. */
|
|
34
|
+
dispose(): void;
|
|
35
|
+
}
|
|
36
|
+
export declare function createCondRegion(parent: Node, id: EntityId, pick: () => number, branches: readonly (CondBranchFactory | null)[]): CondRegion;
|
|
37
|
+
//# sourceMappingURL=cond.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cond.d.ts","sourceRoot":"","sources":["../src/cond.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,WAAW,SAAS;IACxB,wEAAwE;IACxE,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,2CAA2C;IAC3C,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,2EAA2E;IAC3E,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,MAAM,MAAM,iBAAiB,GAAG,MAAM,SAAS,CAAC;AAEhD,MAAM,WAAW,UAAU;IACzB,2EAA2E;IAC3E,MAAM,IAAI,IAAI,CAAC;IACf,sCAAsC;IACtC,KAAK,IAAI,MAAM,CAAC;IAChB,6DAA6D;IAC7D,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,IAAI,EACZ,EAAE,EAAE,QAAQ,EACZ,IAAI,EAAE,MAAM,MAAM,EAClB,QAAQ,EAAE,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,EAAE,GAC9C,UAAU,CA8CZ"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Root-scoped event delegation for compiler-owned repeated DOM.
|
|
3
|
+
*
|
|
4
|
+
* Elements carry two symbol-keyed slots per event type: their handler and the
|
|
5
|
+
* root that owns it. This avoids a listener and a handler-record allocation
|
|
6
|
+
* per row while allowing nested delegated roots to dispatch independently.
|
|
7
|
+
*/
|
|
8
|
+
export declare function setDelegatedEvent(root: EventTarget, element: EventTarget, jsxName: string, handler: EventListener): void;
|
|
9
|
+
//# sourceMappingURL=delegated-events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delegated-events.d.ts","sourceRoot":"","sources":["../src/delegated-events.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,aAAa,GACrB,IAAI,CAiCN"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batches exact numeric causes for dirty entities until their next render.
|
|
3
|
+
*/
|
|
4
|
+
export type DirtyReasonInput = number | readonly number[];
|
|
5
|
+
export type DirtyReasons = number | ReadonlySet<number> | null;
|
|
6
|
+
type EntityId = string;
|
|
7
|
+
/** Merge an exact cause, or clear causes when the update must be full. */
|
|
8
|
+
export declare function mergeDirtyReasons(id: EntityId, wasDirty: boolean, reason: DirtyReasonInput | undefined): void;
|
|
9
|
+
/** Consume pending causes; absence is the full-update sentinel. */
|
|
10
|
+
export declare function takeDirtyReasons(id: EntityId): DirtyReasons;
|
|
11
|
+
/** Discard causes for an update that was cancelled or became conservative. */
|
|
12
|
+
export declare function clearDirtyReasons(id: EntityId): void;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=dirty-reasons.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dirty-reasons.d.ts","sourceRoot":"","sources":["../src/dirty-reasons.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;AAC1D,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;AAE/D,KAAK,QAAQ,GAAG,MAAM,CAAC;AAGvB,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,QAAQ,EACZ,QAAQ,EAAE,OAAO,EACjB,MAAM,EAAE,gBAAgB,GAAG,SAAS,GACnC,IAAI,CA8BN;AAED,mEAAmE;AACnE,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,GAAG,YAAY,CAK3D;AAED,8EAA8E;AAC9E,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAEpD"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dom-props.ts - ordered JSX spread-property patching.
|
|
3
|
+
*
|
|
4
|
+
* Elements containing a spread are patched as one ordered object so later
|
|
5
|
+
* explicit or spread values override earlier ones exactly as authored.
|
|
6
|
+
* Unknown spread event handlers receive a root fallback on normal completion;
|
|
7
|
+
* explicit compiler-instrumented handlers can be marked safe by key.
|
|
8
|
+
*/
|
|
9
|
+
/** Patch all properties represented by one ordered spread object. */
|
|
10
|
+
export declare function patchDomProps(element: Element, nextValue: unknown, eventRootId: string, safeEventKeys?: readonly string[]): void;
|
|
11
|
+
/** Set one mapped JSX DOM value outside a spread-bearing element. */
|
|
12
|
+
export declare function setDomValue(element: Element, name: string, value: unknown): void;
|
|
13
|
+
//# sourceMappingURL=dom-props.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom-props.d.ts","sourceRoot":"","sources":["../src/dom-props.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAyEH,qEAAqE;AACrE,wBAAgB,aAAa,CAC3B,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,OAAO,EAClB,WAAW,EAAE,MAAM,EACnB,aAAa,GAAE,SAAS,MAAM,EAAO,GACpC,IAAI,CAsBN;AAED,qEAAqE;AACrE,wBAAgB,WAAW,CACzB,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,GACb,IAAI,CAUN"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dom-values.ts - normalization and snapshot updates for JSX class/style.
|
|
3
|
+
*
|
|
4
|
+
* Mutable arrays and objects may retain identity between renders. These
|
|
5
|
+
* helpers compare normalized snapshots rather than references, preserving
|
|
6
|
+
* guarded DOM writes without requiring compiler knowledge of their methods.
|
|
7
|
+
*/
|
|
8
|
+
/** Normalize strings, nested arrays, and conditional class objects. */
|
|
9
|
+
export declare function classValue(value: unknown): string;
|
|
10
|
+
/** Apply a normalized class value to HTML or SVG elements. */
|
|
11
|
+
export declare function setClassValue(element: Element, value: unknown): void;
|
|
12
|
+
/** Diff a string or object style value against a content snapshot. */
|
|
13
|
+
export declare function setStyleValue(element: Element, value: unknown): void;
|
|
14
|
+
//# sourceMappingURL=dom-values.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom-values.d.ts","sourceRoot":"","sources":["../src/dom-values.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA6BH,uEAAuE;AACvE,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAIjD;AAED,8DAA8D;AAC9D,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAQpE;AAED,sEAAsE;AACtE,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAqCpE"}
|
package/dist/effect.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component-owned reactive effects.
|
|
3
|
+
*
|
|
4
|
+
* The compiler supplies static subscriptions through the access table and
|
|
5
|
+
* emits local invalidations. The runtime owns only phase ordering and the
|
|
6
|
+
* latest teardown returned by each callback.
|
|
7
|
+
*/
|
|
8
|
+
import { type CleanupDisposer } from './cleanup';
|
|
9
|
+
import { type EntityId } from './kernel';
|
|
10
|
+
export type EffectCallback = () => void | CleanupDisposer;
|
|
11
|
+
export type EffectCondition = () => unknown;
|
|
12
|
+
export declare function registerEffect(id: EntityId, parent: EntityId | null, callback: EffectCallback): void;
|
|
13
|
+
/**
|
|
14
|
+
* Stable activation controller for a conditionally-owned effect.
|
|
15
|
+
*
|
|
16
|
+
* Re-evaluating a truthy condition keeps the existing child registration.
|
|
17
|
+
* A truthy/false transition is the only operation that creates or disposes
|
|
18
|
+
* the active effect lifecycle.
|
|
19
|
+
*/
|
|
20
|
+
export declare function registerConditionalEffect(id: EntityId, parent: EntityId | null, condition: EffectCondition, callback: EffectCallback): void;
|
|
21
|
+
//# sourceMappingURL=effect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effect.d.ts","sourceRoot":"","sources":["../src/effect.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAW,KAAK,eAAe,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EAKL,KAAK,QAAQ,EACd,MAAM,UAAU,CAAC;AAElB,MAAM,MAAM,cAAc,GAAG,MAAM,IAAI,GAAG,eAAe,CAAC;AAC1D,MAAM,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC;AAE5C,wBAAgB,cAAc,CAC5B,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,QAAQ,GAAG,IAAI,EACvB,QAAQ,EAAE,cAAc,GACvB,IAAI,CAiCN;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,QAAQ,GAAG,IAAI,EACvB,SAAS,EAAE,eAAe,EAC1B,QAAQ,EAAE,cAAc,GACvB,IAAI,CAyBN"}
|
package/dist/events.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file events.ts
|
|
3
|
+
* M3 — Origin-aware handler wrapping + the event log.
|
|
4
|
+
* M4 — commitWrites() extracted: programmatic ops (non-DOM-event sources like
|
|
5
|
+
* websocket messages, timers, or benchmark scenarios) route their
|
|
6
|
+
* effects through the exact same table as event handlers.
|
|
7
|
+
*
|
|
8
|
+
* handle() is the optional provenance-recording event boundary:
|
|
9
|
+
* 1. run user code (plain assignments — no interception, no proxies)
|
|
10
|
+
* 2. record provenance in the event log (origin, writes, timestamp)
|
|
11
|
+
* 3. route the handler's static exact/bounded effects through the access
|
|
12
|
+
* table; a table-level unbounded result selects the root subtree.
|
|
13
|
+
*
|
|
14
|
+
* The user never sees this. Their handler is a plain closure; the wrapper and
|
|
15
|
+
* the write-set are compiler-generated.
|
|
16
|
+
*/
|
|
17
|
+
import { type EntityId } from './kernel';
|
|
18
|
+
export interface EventRecord {
|
|
19
|
+
origin: EntityId;
|
|
20
|
+
writes: readonly string[];
|
|
21
|
+
at: number;
|
|
22
|
+
}
|
|
23
|
+
/** Provenance for every routed event — devtools, tests, debugging. */
|
|
24
|
+
export declare function getEventLog(): readonly EventRecord[];
|
|
25
|
+
export declare function clearEventLog(): void;
|
|
26
|
+
/**
|
|
27
|
+
* Route exact or bounded effects through the static access table and dirty
|
|
28
|
+
* their readers.
|
|
29
|
+
* This is THE invalidation entry point — handlers and programmatic sources
|
|
30
|
+
* share it, so there is exactly one routing code path in the runtime.
|
|
31
|
+
*/
|
|
32
|
+
export declare function commitWrites(writes: readonly string[]): void;
|
|
33
|
+
/** Route an L2 payload through parameterized access patterns. */
|
|
34
|
+
export declare function commitWritesWithPayload(writes: readonly string[], payload: Record<string, any>): void;
|
|
35
|
+
export declare function handle<T extends Event>(origin: EntityId, writes: readonly string[], fn: (ev: T) => void): (ev: T) => void;
|
|
36
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAA+B,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAGtE,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,QAAQ,CAAC;IACjB,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,EAAE,EAAE,MAAM,CAAC;CACZ;AAKD,sEAAsE;AACtE,wBAAgB,WAAW,IAAI,SAAS,WAAW,EAAE,CAEpD;AAED,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAO5D;AAED,iEAAiE;AACjE,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC3B,IAAI,CAON;AAED,wBAAgB,MAAM,CAAC,CAAC,SAAS,KAAK,EACpC,MAAM,EAAE,QAAQ,EAChB,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,IAAI,GAClB,CAAC,EAAE,EAAE,CAAC,KAAK,IAAI,CASjB"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime package entry imported by compiler output.
|
|
3
|
+
*
|
|
4
|
+
* The compiler emits `import * as MD from '<runtimePath>'` and calls every
|
|
5
|
+
* primitive through the `MD.` namespace, so this barrel must re-export the
|
|
6
|
+
* full runtime surface. User code never imports from here directly; only
|
|
7
|
+
* compiler-emitted modules do.
|
|
8
|
+
*/
|
|
9
|
+
export { register, unregister, unregisterSubtree, registeredIds, has, markDirty, undirty, markDirtySubtree, commit, setScheduler, resetScheduler, getEntity, renderDescendants, } from './kernel';
|
|
10
|
+
export type { DirtyReasonInput, DirtyReasons, Entity, EntityId, } from './kernel';
|
|
11
|
+
export { cleanup } from './cleanup';
|
|
12
|
+
export type { CleanupDisposer } from './cleanup';
|
|
13
|
+
export { mountRef } from './refs';
|
|
14
|
+
export type { RefCallback, RefValue } from './refs';
|
|
15
|
+
export { registerConditionalEffect, registerEffect } from './effect';
|
|
16
|
+
export type { EffectCallback, EffectCondition } from './effect';
|
|
17
|
+
export { setText, setClassName, setClass, setAttr, setProp, setStyle, computedChanged, } from './setters';
|
|
18
|
+
export type { SlotCache } from './setters';
|
|
19
|
+
export { installAccessTable, resetAccessTable, resolveWrites, resolveStaticWrites, isOpaque, getRootId, } from './access';
|
|
20
|
+
export type { AccessTable } from './access';
|
|
21
|
+
export { commitWrites, commitWritesWithPayload, handle, getEventLog, clearEventLog, } from './events';
|
|
22
|
+
export type { EventRecord } from './events';
|
|
23
|
+
export { createListRegion } from './list';
|
|
24
|
+
export type { ListRegion, ListEntry, KeyFn } from './list';
|
|
25
|
+
export { rootNodes } from './jsx-dom';
|
|
26
|
+
export { setDelegatedEvent } from './delegated-events';
|
|
27
|
+
export { patchDomProps, setDomValue } from './dom-props';
|
|
28
|
+
export { classValue, setClassValue, setStyleValue } from './dom-values';
|
|
29
|
+
export { createCondRegion } from './cond';
|
|
30
|
+
export { registerProps, setProps } from './props';
|
|
31
|
+
export type { CondRegion, CondEntry, CondBranchFactory } from './cond';
|
|
32
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,QAAQ,EACR,UAAU,EACV,iBAAiB,EACjB,aAAa,EACb,GAAG,EACH,SAAS,EACT,OAAO,EACP,gBAAgB,EAChB,MAAM,EACN,YAAY,EACZ,cAAc,EACd,SAAS,EACT,iBAAiB,GAClB,MAAM,UAAU,CAAC;AAClB,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,MAAM,EACN,QAAQ,GACT,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,YAAY,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAClC,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACpD,OAAO,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACrE,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAEhE,OAAO,EACL,OAAO,EACP,YAAY,EACZ,QAAQ,EACR,OAAO,EACP,OAAO,EACP,QAAQ,EACR,eAAe,GAChB,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,EACb,mBAAmB,EACnB,QAAQ,EACR,SAAS,GACV,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,OAAO,EACL,YAAY,EACZ,uBAAuB,EACvB,MAAM,EACN,WAAW,EACX,aAAa,GACd,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAC1C,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAExE,OAAO,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAClD,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{A as z,B as A,C as B,D as C,E as D,F as E,G as F,H as G,I as H,J as I,K as J,L as K,M as L,N as M,O as N,P as O,Q as P,R as Q,S as R,T as S,U as T,a,b,c,d,e,f,g,h,i,j,k,l,m,o as n,p as o,q as p,r as q,s as r,t as s,u as t,v as u,w as v,x as w,y as x,z as y}from"./chunks/chunk-FX3LH6HS.js";export{M as classValue,n as cleanup,F as clearEventLog,m as commit,G as commitWrites,H as commitWritesWithPayload,x as computedChanged,R as createCondRegion,J as createListRegion,g as getEntity,E as getEventLog,B as getRootId,I as handle,f as has,y as installAccessTable,A as isOpaque,j as markDirty,l as markDirtySubtree,o as mountRef,P as patchDomProps,c as register,q as registerConditionalEffect,p as registerEffect,S as registerProps,i as registeredIds,h as renderDescendants,z as resetAccessTable,b as resetScheduler,C as resolveStaticWrites,D as resolveWrites,K as rootNodes,u as setAttr,t as setClass,s as setClassName,N as setClassValue,L as setDelegatedEvent,Q as setDomValue,v as setProp,T as setProps,a as setScheduler,w as setStyle,O as setStyleValue,r as setText,k as undirty,e as unregister,d as unregisterSubtree};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* jsx-dom.ts - DOM structure helpers required by compiled JSX.
|
|
3
|
+
*
|
|
4
|
+
* DocumentFragment nodes disappear into their parent when inserted. Keyed
|
|
5
|
+
* reconciliation snapshots their children beforehand so removal and movement
|
|
6
|
+
* retain the same multi-node ownership semantics as a single element root.
|
|
7
|
+
*/
|
|
8
|
+
export declare function rootNodes(root: Node): Node[];
|
|
9
|
+
//# sourceMappingURL=jsx-dom.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsx-dom.d.ts","sourceRoot":"","sources":["../src/jsx-dom.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,CAI5C"}
|
package/dist/kernel.d.ts
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file kernel.ts
|
|
3
|
+
* M0 — Runtime kernel of the Analyzed Memoized DOM.
|
|
4
|
+
*
|
|
5
|
+
* The kernel owns exactly four things (see memoized-dom-paradigm.md §5–§6):
|
|
6
|
+
* 1. The entity registry — Map<id, Entity>, O(1) lookup by hierarchical id
|
|
7
|
+
* 2. The dirty set — Set<id>, dedupes any number of triggers into one render
|
|
8
|
+
* 3. The frame scheduler — batches all dirty marks into one commit per frame
|
|
9
|
+
* 4. The commit cycle — re-renders exactly the dirty set, parent-before-child
|
|
10
|
+
*
|
|
11
|
+
* It knows NOTHING about components, state, or events. Those are compiler
|
|
12
|
+
* concerns layered on top. Keep this file focused on entity lifetime.
|
|
13
|
+
*
|
|
14
|
+
* M4 hardening (benchmark-driven):
|
|
15
|
+
* - Entity carries `children` + precomputed `depth`: subtree teardown is
|
|
16
|
+
* O(subtree) — was O(registry) per entity, i.e. O(n^2) on mass removal
|
|
17
|
+
* (clear-10k took 1510ms before this fix)
|
|
18
|
+
* - commit sorts NUMERIC depths, not string paths
|
|
19
|
+
* - registeredIds() returns a cached array, rebuilt only on register/unregister
|
|
20
|
+
*
|
|
21
|
+
* INVARIANT (the M5 compiler guarantees this): parents register BEFORE their
|
|
22
|
+
* children, so child links exist. Violations don't corrupt rendering — they
|
|
23
|
+
* only orphan children from subtree teardown.
|
|
24
|
+
*/
|
|
25
|
+
import { type DirtyReasonInput, type DirtyReasons } from './dirty-reasons';
|
|
26
|
+
export type EntityId = string;
|
|
27
|
+
export type { DirtyReasonInput, DirtyReasons } from './dirty-reasons';
|
|
28
|
+
/**
|
|
29
|
+
* A mounted component instance.
|
|
30
|
+
* `render` is the UPDATE branch only — the creation branch ran once at mount
|
|
31
|
+
* and cached its nodes in a closure.
|
|
32
|
+
* `depth` and `children` are managed by register(); callers only provide
|
|
33
|
+
* id, parent, render.
|
|
34
|
+
*/
|
|
35
|
+
export interface Entity {
|
|
36
|
+
id: EntityId;
|
|
37
|
+
parent: EntityId | null;
|
|
38
|
+
render: (reasons?: DirtyReasons) => void;
|
|
39
|
+
/** Effects drain only after all ordinary render work is complete. */
|
|
40
|
+
phase?: 'render' | 'effect';
|
|
41
|
+
depth?: number;
|
|
42
|
+
children?: Set<EntityId>;
|
|
43
|
+
}
|
|
44
|
+
type Scheduler = (fn: () => void) => void;
|
|
45
|
+
/** Swap the scheduling policy (tests, SSR, custom frame loops). */
|
|
46
|
+
export declare function setScheduler(fn: Scheduler): void;
|
|
47
|
+
/** Restore the environment default (rAF / setTimeout). */
|
|
48
|
+
export declare function resetScheduler(): void;
|
|
49
|
+
/** Current registry generation (see above). Introspection/resolver only. */
|
|
50
|
+
export declare function registryGeneration(): number;
|
|
51
|
+
/**
|
|
52
|
+
* M5.6: registry-change listeners — push-based notification so the access
|
|
53
|
+
* resolver can keep wildcard expansions incrementally updated instead of
|
|
54
|
+
* re-matching every pattern against every id on every commit. Listeners
|
|
55
|
+
* run synchronously; they must be cheap (a few regex tests).
|
|
56
|
+
*/
|
|
57
|
+
type RegistryListener = (id: EntityId, kind: 'add' | 'remove') => void;
|
|
58
|
+
/**
|
|
59
|
+
* Lifecycle features install their disposer lazily on first use. Keeping the
|
|
60
|
+
* kernel independent of cleanup/effect/ref modules lets applications that do
|
|
61
|
+
* not use those features tree-shake their storage and disposal machinery.
|
|
62
|
+
*/
|
|
63
|
+
export type EntityDisposeHook = (id: EntityId) => readonly unknown[] | void;
|
|
64
|
+
export declare function onEntityDispose(fn: EntityDisposeHook): void;
|
|
65
|
+
export declare function onRegistryChange(fn: RegistryListener): void;
|
|
66
|
+
export declare function register(entity: Entity): void;
|
|
67
|
+
/**
|
|
68
|
+
* Unregister an entity and ALL its descendants — O(subtree), not O(registry).
|
|
69
|
+
* Walks the children links; also detaches from the parent's children set.
|
|
70
|
+
*/
|
|
71
|
+
export declare function unregisterSubtree(id: EntityId): void;
|
|
72
|
+
/** Single-id unregister takes its subtree with it — same thing. */
|
|
73
|
+
export declare function unregister(id: EntityId): void;
|
|
74
|
+
export declare function has(id: EntityId): boolean;
|
|
75
|
+
export declare function getEntity(id: EntityId): Entity | undefined;
|
|
76
|
+
/**
|
|
77
|
+
* Render the already-mounted descendants of one compiler-owned structural
|
|
78
|
+
* entity, parent before child, and cancel duplicate scheduled renders.
|
|
79
|
+
* Render-callback rows use this when their JSX contains component entities
|
|
80
|
+
* whose lexical dependencies belong to the callback caller.
|
|
81
|
+
*/
|
|
82
|
+
export declare function renderDescendants(id: EntityId): void;
|
|
83
|
+
/**
|
|
84
|
+
* Live entity ids for the access-table resolver. Cached — the array is
|
|
85
|
+
* rebuilt only when the registry mutates, so per-event cost is zero.
|
|
86
|
+
* Callers MUST NOT mutate the returned array.
|
|
87
|
+
*/
|
|
88
|
+
export declare function registeredIds(): readonly EntityId[];
|
|
89
|
+
/**
|
|
90
|
+
* Mark one entity dirty and schedule a commit.
|
|
91
|
+
*
|
|
92
|
+
* Dead letters (spec §9.7): marking an unmounted id is a silent no-op.
|
|
93
|
+
* Dev builds may warn here later.
|
|
94
|
+
*/
|
|
95
|
+
export declare function markDirty(id: EntityId, reason?: DirtyReasonInput): void;
|
|
96
|
+
/**
|
|
97
|
+
* Cancel a pending dirty (M5.7): a list row that just rendered through the
|
|
98
|
+
* reconcile resync (M5.5 entry.update) must not render a second, identical
|
|
99
|
+
* time when the commit batch reaches it. Only removes a PENDING entry —
|
|
100
|
+
* if the row is re-dirtied later (cascade), it renders again as usual.
|
|
101
|
+
*/
|
|
102
|
+
export declare function undirty(id: EntityId): void;
|
|
103
|
+
/**
|
|
104
|
+
* Mark an entity and ALL its descendants dirty — the fallback for an
|
|
105
|
+
* unbounded effect (spec §4.4). Equivalent to re-rendering from the mounted
|
|
106
|
+
* root: correct under any circumstance, just not scoped.
|
|
107
|
+
*
|
|
108
|
+
* NOTE: prefix scan (rare fallback path); teardown uses the children links.
|
|
109
|
+
*/
|
|
110
|
+
export declare function markDirtySubtree(id: EntityId): void;
|
|
111
|
+
/**
|
|
112
|
+
* Run commit passes until the dirty set is empty: re-render the dirty set,
|
|
113
|
+
* parents before children (numeric depth sort — cheap even for 10k dirty
|
|
114
|
+
* entities). R10: renders may dirty further ids (props re-push); those join
|
|
115
|
+
* the SAME commit via the drain loop — no one-frame lag for prop flow.
|
|
116
|
+
*
|
|
117
|
+
* PUBLIC API (M5.6): this is the "flush now" entry point — the memo-dom
|
|
118
|
+
* equivalent of React's flushSync / Svelte 5's flushSync. With the default
|
|
119
|
+
* frame scheduler, `markDirty`/`commitWrites` only SCHEDULE a commit; call
|
|
120
|
+
* `commit()` to run it synchronously (tests, boundary integrations where a
|
|
121
|
+
* host requires synchronous DOM, e.g. the dom-reconciler-bench contract).
|
|
122
|
+
* Prefer `setScheduler(fn => fn())` when the WHOLE app should be sync.
|
|
123
|
+
*/
|
|
124
|
+
export declare function commit(): void;
|
|
125
|
+
export declare function _internals(): {
|
|
126
|
+
registry: ReadonlyMap<EntityId, Entity>;
|
|
127
|
+
dirtySet: ReadonlySet<EntityId>;
|
|
128
|
+
};
|
|
129
|
+
//# sourceMappingURL=kernel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kernel.d.ts","sourceRoot":"","sources":["../src/kernel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAIL,KAAK,gBAAgB,EACrB,KAAK,YAAY,EAClB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC;AAC9B,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEtE;;;;;;GAMG;AACH,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,QAAQ,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,YAAY,KAAK,IAAI,CAAC;IACzC,qEAAqE;IACrE,KAAK,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;CAC1B;AAWD,KAAK,SAAS,GAAG,CAAC,EAAE,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;AAS1C,mEAAmE;AACnE,wBAAgB,YAAY,CAAC,EAAE,EAAE,SAAS,GAAG,IAAI,CAEhD;AAED,0DAA0D;AAC1D,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAwBD,4EAA4E;AAC5E,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED;;;;;GAKG;AACH,KAAK,gBAAgB,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,GAAG,QAAQ,KAAK,IAAI,CAAC;AAGvE;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,EAAE,EAAE,QAAQ,KAAK,SAAS,OAAO,EAAE,GAAG,IAAI,CAAC;AAG5E,wBAAgB,eAAe,CAAC,EAAE,EAAE,iBAAiB,GAAG,IAAI,CAE3D;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,gBAAgB,GAAG,IAAI,CAE3D;AAMD,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAgB7C;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAgDpD;AAED,mEAAmE;AACnE,wBAAgB,UAAU,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAE7C;AAED,wBAAgB,GAAG,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,CAEzC;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAE1D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CA8BpD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,SAAS,QAAQ,EAAE,CAGnD;AAKD;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,EAAE,EAAE,QAAQ,EACZ,MAAM,CAAC,EAAE,gBAAgB,GACxB,IAAI,CAQN;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAM1C;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,QAAQ,GAAG,IAAI,CAWnD;AAcD;;;;;;;;;;;;GAYG;AACH,wBAAgB,MAAM,IAAI,IAAI,CA8C7B;AAKD,wBAAgB,UAAU,IAAI;IAC5B,QAAQ,EAAE,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACxC,QAAQ,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;CACjC,CAEA"}
|
package/dist/list.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file list.ts
|
|
3
|
+
* M2 — Keyed list reconciliation.
|
|
4
|
+
* M4 — LIS-based move minimization (benchmark-driven).
|
|
5
|
+
*
|
|
6
|
+
* The list region owns a stretch of DOM ending at an explicit end anchor
|
|
7
|
+
* (a comment node). Items are cached BY KEY: a reconcile with the same keys
|
|
8
|
+
* reuses the exact same nodes and row entities — reordering MOVES nodes
|
|
9
|
+
* (insertBefore on an attached node relocates it), never recreates them.
|
|
10
|
+
* Focus, open <details>, playing video inside a row all survive moves.
|
|
11
|
+
*
|
|
12
|
+
* Algorithm per reconcile:
|
|
13
|
+
* pass 1 (forward): reuse-or-create each entry; duplicate keys throw
|
|
14
|
+
* removals: stale keys' nodes removed, entity subtrees unregistered
|
|
15
|
+
* pass 2 (reverse): LIS-guided placement. Compute each new position's old
|
|
16
|
+
* index, take the longest increasing subsequence (rows
|
|
17
|
+
* already in correct relative order — never moved), and
|
|
18
|
+
* insert/move only the rest before a running cursor.
|
|
19
|
+
* A 2-row swap costs exactly 2 moves; an unchanged list
|
|
20
|
+
* costs ZERO DOM operations.
|
|
21
|
+
*
|
|
22
|
+
* Why LIS matters (measured in M4): the earlier naive guard
|
|
23
|
+
* (`nextSibling === cursor`) broke down across displaced regions — one moved
|
|
24
|
+
* row made EVERY intermediate row fail the guard, so a swap of 2 rows in 1000
|
|
25
|
+
* caused ~996 moves (~15ms). With LIS the same swap is 2 moves.
|
|
26
|
+
*
|
|
27
|
+
* Keys: default is item identity (reference for objects, value for primitives)
|
|
28
|
+
* — Imba-style. A key function (item => item.id) survives re-fetched data.
|
|
29
|
+
* Object identity keys get stable synthetic id segments (#1, #2, ...).
|
|
30
|
+
*/
|
|
31
|
+
import { type EntityId } from './kernel';
|
|
32
|
+
export interface ListEntry {
|
|
33
|
+
/** Detached or attached DOM nodes owned by this item (usually one root). */
|
|
34
|
+
nodes: Node[];
|
|
35
|
+
/** Entity ids created for this item — unregistered on removal. */
|
|
36
|
+
entities: EntityId[];
|
|
37
|
+
/**
|
|
38
|
+
* M5.5: re-run the row's guarded update on every reconcile that REUSES
|
|
39
|
+
* this entry. Rows read their item (a factory param), not module state,
|
|
40
|
+
* so item-field mutations are otherwise invisible to the access table —
|
|
41
|
+
* this is what keeps `{todo.title}` honest when an outside source (or a
|
|
42
|
+
* handler) mutates a retained row's item. Guarded setters make a no-op
|
|
43
|
+
* sync nearly free; DOM is only touched when data actually changed.
|
|
44
|
+
*/
|
|
45
|
+
update?: () => void;
|
|
46
|
+
/**
|
|
47
|
+
* R10: component rows only — re-push the row's props box from the current
|
|
48
|
+
* item on every reconcile that retains this entry. Item replacement AND
|
|
49
|
+
* item-field mutation both reach the row entity (setProps shallow-compares,
|
|
50
|
+
* so an unchanged item costs one comparison pass and nothing else).
|
|
51
|
+
*/
|
|
52
|
+
updateProps?: (item: unknown, index: number) => void;
|
|
53
|
+
/** Allocation-free rows may own mount lifecycle without an entity record. */
|
|
54
|
+
dispose?: () => void;
|
|
55
|
+
}
|
|
56
|
+
export type KeyFn<T> = (item: T, index: number) => unknown;
|
|
57
|
+
export interface ListRegion<T> {
|
|
58
|
+
reconcile(items: readonly T[]): void;
|
|
59
|
+
size(): number;
|
|
60
|
+
/** Remove retained nodes and unregister every entity owned by the region. */
|
|
61
|
+
dispose(): void;
|
|
62
|
+
}
|
|
63
|
+
export declare function createListRegion<T>(parent: Node, idPrefix: EntityId, create: (item: T, rowId: EntityId, index: number) => ListEntry, key?: KeyFn<T>): ListRegion<T>;
|
|
64
|
+
//# sourceMappingURL=list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../src/list.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAyC,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEhF,MAAM,WAAW,SAAS;IACxB,4EAA4E;IAC5E,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,kEAAkE;IAClE,QAAQ,EAAE,QAAQ,EAAE,CAAC;IACrB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,MAAM,MAAM,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;AAK3D,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,SAAS,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,GAAG,IAAI,CAAC;IACrC,IAAI,IAAI,MAAM,CAAC;IACf,6EAA6E;IAC7E,OAAO,IAAI,IAAI,CAAC;CACjB;AAiDD,wBAAgB,gBAAgB,CAAC,CAAC,EAChC,MAAM,EAAE,IAAI,EACZ,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,EAC9D,GAAG,GAAE,KAAK,CAAC,CAAC,CAAe,GAC1B,UAAU,CAAC,CAAC,CAAC,CAuNf"}
|
package/dist/props.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file props.ts
|
|
3
|
+
* R10 — Props-down reactivity: the props box registry.
|
|
4
|
+
*
|
|
5
|
+
* A component's positional props are boxed in ONE mutable array at the call
|
|
6
|
+
* site (`Row(childId, id, [todo, sel])`) and registered here under the child
|
|
7
|
+
* entity id. The parent re-pushes inside its update closure via setProps;
|
|
8
|
+
* the child's update closure re-syncs its locals from the box before running
|
|
9
|
+
* its guarded setters. No subscriptions, no VDOM — a second write channel
|
|
10
|
+
* using the same dirty/mark machinery as state.
|
|
11
|
+
*
|
|
12
|
+
* setProps is the ONLY writer; the box identity never changes (the child's
|
|
13
|
+
* `__p` binding stays valid for the entity's whole lifetime).
|
|
14
|
+
*/
|
|
15
|
+
import { type EntityId } from './kernel';
|
|
16
|
+
/** Called by compiled child factories right after register(). */
|
|
17
|
+
export declare function registerProps(id: EntityId, box: unknown[]): void;
|
|
18
|
+
/**
|
|
19
|
+
* Re-push a child's props. Shallow-compares per index: identical values →
|
|
20
|
+
* no dirty, zero work (the common case — parent updated for other reasons).
|
|
21
|
+
* Changed → mutate the box in place and dirty the child entity.
|
|
22
|
+
* Dead letters (unmounted child) are silent no-ops, like markDirty.
|
|
23
|
+
*/
|
|
24
|
+
export declare function setProps(id: EntityId, next: readonly unknown[]): void;
|
|
25
|
+
/** Test/devtool introspection only. */
|
|
26
|
+
export declare function _propsBox(id: EntityId): readonly unknown[] | undefined;
|
|
27
|
+
//# sourceMappingURL=props.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"props.d.ts","sourceRoot":"","sources":["../src/props.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAA+B,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAItE,iEAAiE;AACjE,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,IAAI,CAEhE;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,OAAO,EAAE,GAAG,IAAI,CAgBrE;AAED,uCAAuC;AACvC,wBAAgB,SAAS,CAAC,EAAE,EAAE,QAAQ,GAAG,SAAS,OAAO,EAAE,GAAG,SAAS,CAEtE"}
|
package/dist/refs.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* refs.ts - mount-only DOM ref callbacks with deterministic teardown.
|
|
3
|
+
*
|
|
4
|
+
* Assignable refs are compiled into this callback contract, so the runtime
|
|
5
|
+
* never needs to understand source l-values or allocate JSX/ref objects.
|
|
6
|
+
*/
|
|
7
|
+
export type RefCallback<T extends Node = Node> = (node: T) => void | (() => void);
|
|
8
|
+
export type RefValue<T extends Node = Node> = RefCallback<T> | readonly RefValue<T>[] | null | undefined | false;
|
|
9
|
+
/** Mount refs left-to-right and return one idempotent reverse-order disposer. */
|
|
10
|
+
export declare function mountRef<T extends Node>(node: T, value: RefValue<T>): () => void;
|
|
11
|
+
//# sourceMappingURL=refs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refs.d.ts","sourceRoot":"","sources":["../src/refs.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,IAAI,GAAG,IAAI,IAAI,CAC/C,IAAI,EAAE,CAAC,KACJ,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC;AACzB,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,IAAI,GAAG,IAAI,IACtC,WAAW,CAAC,CAAC,CAAC,GACd,SAAS,QAAQ,CAAC,CAAC,CAAC,EAAE,GACtB,IAAI,GACJ,SAAS,GACT,KAAK,CAAC;AAEV,iFAAiF;AACjF,wBAAgB,QAAQ,CAAC,CAAC,SAAS,IAAI,EACrC,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,GACjB,MAAM,IAAI,CA0BZ"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file setters.ts
|
|
3
|
+
* M1 — Value-cached setter helpers.
|
|
4
|
+
*
|
|
5
|
+
* Every dynamic DOM write in compiled output goes through one of these.
|
|
6
|
+
* The guard (previous-value comparison) lives HERE, in one place, instead of
|
|
7
|
+
* being emitted inline at every call site.
|
|
8
|
+
*
|
|
9
|
+
* Contract with the compiler (M5):
|
|
10
|
+
* - each dynamic slot gets a unique cache key within the component's `$`
|
|
11
|
+
* - the creation branch calls the SAME helpers as the update branch, so the
|
|
12
|
+
* value cache is always seeded with exactly what was written
|
|
13
|
+
* (the invariant M0's failing test taught us — now structural, not a rule)
|
|
14
|
+
*
|
|
15
|
+
* Semantics:
|
|
16
|
+
* - guards use strict equality on the RAW value (===)
|
|
17
|
+
* - NaN never compares equal -> always writes (documented, acceptable)
|
|
18
|
+
* - objects compare by identity -> new reference means "changed"
|
|
19
|
+
*/
|
|
20
|
+
export type SlotCache = Record<string, unknown>;
|
|
21
|
+
/** Text node data. null/undefined/booleans render as empty string (JSX semantics). */
|
|
22
|
+
export declare function setText($: SlotCache, key: string, node: Text, value: unknown): void;
|
|
23
|
+
/** Full className string replacement. */
|
|
24
|
+
export declare function setClassName($: SlotCache, key: string, el: HTMLElement, value: string): void;
|
|
25
|
+
/** Toggle a single class by boolean condition. */
|
|
26
|
+
export declare function setClass($: SlotCache, key: string, el: HTMLElement, name: string, cond: boolean): void;
|
|
27
|
+
/**
|
|
28
|
+
* Attribute write.
|
|
29
|
+
* null / undefined / false -> attribute removed.
|
|
30
|
+
* true -> present with empty value (HTML boolean-attribute convention).
|
|
31
|
+
*/
|
|
32
|
+
export declare function setAttr($: SlotCache, key: string, el: Element, name: string, value: unknown): void;
|
|
33
|
+
/**
|
|
34
|
+
* DOM property write (input.value, checkbox.checked, ...).
|
|
35
|
+
* Bypasses attributes entirely — for state that lives on the element object.
|
|
36
|
+
*/
|
|
37
|
+
export declare function setProp($: SlotCache, key: string, obj: object, prop: string, value: unknown): void;
|
|
38
|
+
/**
|
|
39
|
+
* Inline style property (kebab-case name, e.g. 'background-color').
|
|
40
|
+
* null / undefined -> property removed.
|
|
41
|
+
*/
|
|
42
|
+
export declare function setStyle($: SlotCache, key: string, el: HTMLElement, prop: string, value: string | null | undefined): void;
|
|
43
|
+
/**
|
|
44
|
+
* R13: primitives compare by Object.is and distinct primitive arrays compare
|
|
45
|
+
* element-wise. Mutable references propagate because identity cannot reveal
|
|
46
|
+
* an in-place change.
|
|
47
|
+
*/
|
|
48
|
+
export declare function computedChanged(prev: unknown, next: unknown): boolean;
|
|
49
|
+
//# sourceMappingURL=setters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setters.d.ts","sourceRoot":"","sources":["../src/setters.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEhD,sFAAsF;AACtF,wBAAgB,OAAO,CACrB,CAAC,EAAE,SAAS,EACZ,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,OAAO,GACb,IAAI,CAIN;AAED,yCAAyC;AACzC,wBAAgB,YAAY,CAC1B,CAAC,EAAE,SAAS,EACZ,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,WAAW,EACf,KAAK,EAAE,MAAM,GACZ,IAAI,CAIN;AAED,kDAAkD;AAClD,wBAAgB,QAAQ,CACtB,CAAC,EAAE,SAAS,EACZ,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,WAAW,EACf,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,GACZ,IAAI,CAIN;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CACrB,CAAC,EAAE,SAAS,EACZ,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,OAAO,EACX,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,GACb,IAAI,CAMN;AAED;;;GAGG;AACH,wBAAgB,OAAO,CACrB,CAAC,EAAE,SAAS,EACZ,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,GACb,IAAI,CAIN;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CACtB,CAAC,EAAE,SAAS,EACZ,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,WAAW,EACf,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,IAAI,CAKN;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAYrE"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Testing-only runtime entry with registry and props-box introspection.
|
|
3
|
+
*
|
|
4
|
+
* Keeping these exports out of the production entry prevents test diagnostics
|
|
5
|
+
* from becoming part of application bundles.
|
|
6
|
+
*/
|
|
7
|
+
export * from './index';
|
|
8
|
+
export { _internals } from './kernel';
|
|
9
|
+
export { _propsBox } from './props';
|
|
10
|
+
//# sourceMappingURL=testing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/testing.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{A as z,B as A,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V as r,a as p,b as e,c as t,d as x,e as f,f as m,g as n,h as s,i as _,j as a,k as i,l,m as B,n as o,o as b,p as c,q as d,r as g,s as h,t as j,u as k,v as q,w as u,x as v,y as w,z as y}from"./chunks/chunk-FX3LH6HS.js";export{o as _internals,r as _propsBox,N as classValue,b as cleanup,G as clearEventLog,B as commit,H as commitWrites,I as commitWritesWithPayload,w as computedChanged,S as createCondRegion,K as createListRegion,n as getEntity,F as getEventLog,C as getRootId,J as handle,m as has,y as installAccessTable,A as isOpaque,a as markDirty,l as markDirtySubtree,c as mountRef,Q as patchDomProps,t as register,g as registerConditionalEffect,d as registerEffect,T as registerProps,_ as registeredIds,s as renderDescendants,z as resetAccessTable,e as resetScheduler,D as resolveStaticWrites,E as resolveWrites,L as rootNodes,q as setAttr,k as setClass,j as setClassName,O as setClassValue,M as setDelegatedEvent,R as setDomValue,u as setProp,U as setProps,p as setScheduler,v as setStyle,P as setStyleValue,h as setText,i as undirty,f as unregister,x as unregisterSubtree};
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@memoized-dom/runtime",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Dependency-free runtime for compiler-analyzed memoized DOM updates",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./testing": {
|
|
17
|
+
"types": "./dist/testing.d.ts",
|
|
18
|
+
"import": "./dist/testing.js",
|
|
19
|
+
"default": "./dist/testing.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "bun run ./scripts/clean.ts && esbuild ./src/index.ts ./src/testing.ts --bundle --outdir=./dist --platform=browser --format=esm --target=es2022 --minify --splitting --entry-names=[name] --chunk-names=chunks/[name]-[hash] && tsc -p tsconfig.build.json"
|
|
24
|
+
},
|
|
25
|
+
"publishConfig": {
|
|
26
|
+
"access": "public"
|
|
27
|
+
}
|
|
28
|
+
}
|