ajo 0.1.25 → 0.1.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/html.cjs +1 -1
- package/dist/html.js +50 -54
- package/dist/index.cjs +1 -1
- package/dist/index.js +74 -82
- package/package.json +4 -4
- package/readme.md +313 -7
- package/types.ts +4 -5
package/dist/html.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("./context.cjs"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("./context.cjs"),g=new Set(["area","base","br","col","command","embed","hr","img","input","keygen","link","meta","param","source","track","wbr"]),m=Symbol.for("ajo.args"),y=e=>e.replace(/[&<>"']/g,r=>`&#${r.charCodeAt(0)};`),o=()=>{},b=e=>[...f(e)].join(""),f=function*(e,{alloc:r=o,push:t=o,placeholder:n=o}={}){for(e of d(e,{alloc:r,push:t,placeholder:n}))typeof e=="string"?yield y(e):yield*$(e,{alloc:r,push:t,placeholder:n})},$=function*({nodeName:e,children:r,...t},n){let l="";for(const i in t)i.startsWith("set:")||t[i]==null||t[i]===!1||(t[i]===!0?l+=` ${i}`:l+=` ${i}="${y(String(t[i]))}"`);g.has(e)?yield`<${e}${l}>`:(yield`<${e}${l}>`,r!=null&&(yield*f(r,n)),yield`</${e}>`)},d=function*(e,r){if(e==null)return;const t=typeof e;if(t!="boolean")if(t=="string")yield e;else if(t=="number"||t=="bigint")yield String(e);else if(Symbol.iterator in e)for(e of e)yield*d(e,r);else"nodeName"in e?typeof e.nodeName=="function"?yield*v(e,r):yield u(e,r):yield String(e)},v=function*({nodeName:e,fallback:r=e.fallback,...t},n){const l=e.constructor.name;e.src?yield w(e.src,t,n):l=="GeneratorFunction"?yield S(e,t,n):l=="AsyncGeneratorFunction"?yield x(e,r,t,n):(t=e(t),typeof t?.then=="function"?yield A(r,t,n):yield*d(t,n))},w=(e,r,t)=>{const n=t.alloc();return t.push({id:n,src:e,h:u(r,t),done:!0}),t.placeholder(n)},S=(e,r,t)=>{const n={...e.attrs},l={...e.args};for(const c in r)c.startsWith("attr:")?n[c.slice(5)]=r[c]:c=="key"||c=="skip"||c=="memo"||c=="ref"||c.startsWith("set:")?n[c]=r[c]:l[c]=r[c];const i={[a.Context]:Object.create(a.current()?.[a.Context]??null),[m]:l,next:o,return:o,throw:c=>{throw c}},s=e.call(i,l),p=a.current();a.current(i);try{const c=[...d(s.next().value,t)];return{...n,nodeName:e.is??"div",children:c.length==1?c[0]:c}}finally{s.return?.(),a.current(p)}},x=(e,r,t,n)=>{const l=n.alloc();return Promise.resolve().then(async()=>{const i=e(t);n={...n,alloc:(s=l)=>n.alloc(s)};try{for(t=await i.next();!t.done;)n.push({id:l,h:u(t.value,n),done:!1}),t=await i.next();n.push({id:l,h:u(t.value,n),done:!0})}catch(s){n.push({id:l,h:u(s,n),done:!0})}finally{i.return?.()}}),n.placeholder(l,r)},A=(e,r,t)=>{const n=t.alloc();return r.then(l=>t.push({id:n,h:u(l,{...t,alloc:(i=n)=>t.alloc(i)}),done:!0})),t.placeholder(n,e)},u=({key:e,skip:r,memo:t,ref:n,...l},i)=>{if("children"in l){const s=[...d(l.children,i)];s.length?l.children=s.length==1?s[0]:s:delete l.children}return l};exports.html=f;exports.render=b;
|
package/dist/html.js
CHANGED
|
@@ -1,77 +1,73 @@
|
|
|
1
|
-
import { Context as
|
|
2
|
-
const
|
|
3
|
-
},
|
|
4
|
-
for (e of
|
|
5
|
-
typeof e == "string" ? yield
|
|
6
|
-
},
|
|
7
|
-
const { nodeName: n, children: t } = e;
|
|
1
|
+
import { Context as y, current as f } from "./context.js";
|
|
2
|
+
const m = /* @__PURE__ */ new Set(["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr"]), b = Symbol.for("ajo.args"), d = (e) => e.replace(/[&<>"']/g, (r) => `&#${r.charCodeAt(0)};`), u = () => {
|
|
3
|
+
}, j = (e) => [...p(e)].join(""), p = function* (e, { alloc: r = u, push: t = u, placeholder: n = u } = {}) {
|
|
4
|
+
for (e of o(e, { alloc: r, push: t, placeholder: n }))
|
|
5
|
+
typeof e == "string" ? yield d(e) : yield* $(e, { alloc: r, push: t, placeholder: n });
|
|
6
|
+
}, $ = function* ({ nodeName: e, children: r, ...t }, n) {
|
|
8
7
|
let l = "";
|
|
9
|
-
for (const i in
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
},
|
|
8
|
+
for (const i in t)
|
|
9
|
+
i.startsWith("set:") || t[i] == null || t[i] === !1 || (t[i] === !0 ? l += ` ${i}` : l += ` ${i}="${d(String(t[i]))}"`);
|
|
10
|
+
m.has(e) ? yield `<${e}${l}>` : (yield `<${e}${l}>`, r != null && (yield* p(r, n)), yield `</${e}>`);
|
|
11
|
+
}, o = function* (e, r) {
|
|
13
12
|
if (e == null) return;
|
|
14
|
-
const
|
|
15
|
-
if (
|
|
16
|
-
if (
|
|
17
|
-
else if (
|
|
18
|
-
else if (Symbol.iterator in e) for (e of e) yield*
|
|
19
|
-
else "nodeName" in e ? typeof e.nodeName == "function" ? yield*
|
|
20
|
-
},
|
|
13
|
+
const t = typeof e;
|
|
14
|
+
if (t != "boolean")
|
|
15
|
+
if (t == "string") yield e;
|
|
16
|
+
else if (t == "number" || t == "bigint") yield String(e);
|
|
17
|
+
else if (Symbol.iterator in e) for (e of e) yield* o(e, r);
|
|
18
|
+
else "nodeName" in e ? typeof e.nodeName == "function" ? yield* w(e, r) : yield a(e, r) : yield String(e);
|
|
19
|
+
}, w = function* ({ nodeName: e, fallback: r = e.fallback, ...t }, n) {
|
|
21
20
|
const l = e.constructor.name;
|
|
22
|
-
e.src ? yield
|
|
23
|
-
},
|
|
24
|
-
const
|
|
25
|
-
return
|
|
26
|
-
},
|
|
27
|
-
|
|
28
|
-
const t = { ...e.attrs }, l = { ...e.args };
|
|
21
|
+
e.src ? yield v(e.src, t, n) : l == "GeneratorFunction" ? yield x(e, t, n) : l == "AsyncGeneratorFunction" ? yield S(e, r, t, n) : (t = e(t), typeof t?.then == "function" ? yield A(r, t, n) : yield* o(t, n));
|
|
22
|
+
}, v = (e, r, t) => {
|
|
23
|
+
const n = t.alloc();
|
|
24
|
+
return t.push({ id: n, src: e, h: a(r, t), done: !0 }), t.placeholder(n);
|
|
25
|
+
}, x = (e, r, t) => {
|
|
26
|
+
const n = { ...e.attrs }, l = { ...e.args };
|
|
29
27
|
for (const c in r)
|
|
30
|
-
c.startsWith("attr:") ?
|
|
28
|
+
c.startsWith("attr:") ? n[c.slice(5)] = r[c] : c == "key" || c == "skip" || c == "memo" || c == "ref" || c.startsWith("set:") ? n[c] = r[c] : l[c] = r[c];
|
|
31
29
|
const i = {
|
|
32
|
-
[
|
|
33
|
-
[
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
return: a,
|
|
30
|
+
[y]: Object.create(f()?.[y] ?? null),
|
|
31
|
+
[b]: l,
|
|
32
|
+
next: u,
|
|
33
|
+
return: u,
|
|
37
34
|
throw: (c) => {
|
|
38
35
|
throw c;
|
|
39
36
|
}
|
|
40
|
-
}, s = e.call(i, l),
|
|
37
|
+
}, s = e.call(i, l), g = f();
|
|
41
38
|
f(i);
|
|
42
39
|
try {
|
|
43
|
-
const c = [...
|
|
44
|
-
return { ...
|
|
40
|
+
const c = [...o(s.next().value, t)];
|
|
41
|
+
return { ...n, nodeName: e.is ?? "div", children: c.length == 1 ? c[0] : c };
|
|
45
42
|
} finally {
|
|
46
|
-
|
|
43
|
+
s.return?.(), f(g);
|
|
47
44
|
}
|
|
48
|
-
},
|
|
49
|
-
const l =
|
|
45
|
+
}, S = (e, r, t, n) => {
|
|
46
|
+
const l = n.alloc();
|
|
50
47
|
return Promise.resolve().then(async () => {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
t = { ...t, alloc: (d = l) => t.alloc(d) };
|
|
48
|
+
const i = e(t);
|
|
49
|
+
n = { ...n, alloc: (s = l) => n.alloc(s) };
|
|
54
50
|
try {
|
|
55
|
-
for (
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
} catch (
|
|
59
|
-
|
|
51
|
+
for (t = await i.next(); !t.done; )
|
|
52
|
+
n.push({ id: l, h: a(t.value, n), done: !1 }), t = await i.next();
|
|
53
|
+
n.push({ id: l, h: a(t.value, n), done: !0 });
|
|
54
|
+
} catch (s) {
|
|
55
|
+
n.push({ id: l, h: a(s, n), done: !0 });
|
|
60
56
|
} finally {
|
|
61
|
-
|
|
57
|
+
i.return?.();
|
|
62
58
|
}
|
|
63
|
-
}),
|
|
64
|
-
},
|
|
65
|
-
const
|
|
66
|
-
return r.then((l) =>
|
|
67
|
-
},
|
|
59
|
+
}), n.placeholder(l, r);
|
|
60
|
+
}, A = (e, r, t) => {
|
|
61
|
+
const n = t.alloc();
|
|
62
|
+
return r.then((l) => t.push({ id: n, h: a(l, { ...t, alloc: (i = n) => t.alloc(i) }), done: !0 })), t.placeholder(n, e);
|
|
63
|
+
}, a = ({ key: e, skip: r, memo: t, ref: n, ...l }, i) => {
|
|
68
64
|
if ("children" in l) {
|
|
69
|
-
const s = [...
|
|
65
|
+
const s = [...o(l.children, i)];
|
|
70
66
|
s.length ? l.children = s.length == 1 ? s[0] : s : delete l.children;
|
|
71
67
|
}
|
|
72
68
|
return l;
|
|
73
69
|
};
|
|
74
70
|
export {
|
|
75
|
-
|
|
76
|
-
|
|
71
|
+
p as html,
|
|
72
|
+
j as render
|
|
77
73
|
};
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./context.cjs"),y=Symbol.for("ajo.key"),h=Symbol.for("ajo.memo"),b=Symbol.for("ajo.ref"),p=Symbol.for("ajo.cache"),c=Symbol.for("ajo.generator"),l=Symbol.for("ajo.iterator"),m=Symbol.for("ajo.render"),a=Symbol.for("ajo.args"),v=t=>t.children,C=(t,e,...r)=>((e??={}).nodeName=t,!("children"in e)&&r.length&&(e.children=r.length==1?r[0]:r),e),f=(t,e)=>{let r=e.firstChild;for(t of g(t)){const n=E(t,e,r);r==null?e.appendChild(n):n==r?r=n.nextSibling:n==r.nextSibling?(e.appendChild(r),r=n.nextSibling):W(e,n,r)}for(;r;){const n=r.nextSibling;r.nodeType==1&&w(r),e.removeChild(r),r=n}},g=function*(t){if(t==null)return;const e=typeof t;if(e!="boolean")if(e=="string")yield t;else if(e=="number"||e=="bigint")yield String(t);else if(Symbol.iterator in t)for(t of t)yield*g(t);else"nodeName"in t?typeof t.nodeName=="function"?yield*N(t):yield t:yield String(t)},N=function*({nodeName:t,...e}){t.constructor.name=="GeneratorFunction"?yield k(t,e):yield*g(t(e))},k=function(t,e){const r={...t.attrs},n={...t.args};for(const s in e)s.startsWith("attr:")?r[s.slice(5)]=e[s]:s=="key"||s=="skip"||s=="memo"||s=="ref"||s.startsWith("set:")?r[s]=e[s]:n[s]=e[s];return{...r,nodeName:t.is??"div",[c]:t,[a]:n}},E=(t,e,r)=>typeof t=="string"?O(t,r):T(t,e,r),O=(t,e)=>{for(;e&&e.nodeType!=3;)e=e.nextSibling;return e?e.data!=t&&(e.data=t):e=document.createTextNode(t),e},T=({nodeName:t,children:e,key:r,skip:n,memo:s,ref:S,[c]:u,[a]:j,...x},A,i)=>{for(;i&&(i.localName!=t||i[y]!=null&&i[y]!=r||i[c]&&i[c]!=u);)i=i.nextSibling;return i??=document.createElementNS(x.xmlns??A.namespaceURI,t),r!=null&&(i[y]=r),(s==null||G(i[h],i[h]=s))&&(F(i[p]??R(i),i[p]=x,i),n||(u?B(u,j,i):f(e,i)),typeof S=="function"&&(i[b]=S)(i)),i},F=(t,e,r)=>{for(const n in{...t,...e})t[n]!==e[n]&&(n.startsWith("set:")?r[n.slice(4)]=e[n]:e[n]==null||e[n]===!1?r.removeAttribute(n):r.setAttribute(n,e[n]===!0?"":e[n]))},G=(t,e)=>Array.isArray(t)&&Array.isArray(e)?t.some((r,n)=>r!==e[n]):t!==e,R=t=>Array.from(t.attributes).reduce((e,r)=>(e[r.name]=r.value,e),{}),W=(t,e,r)=>{if(e.contains(document.activeElement)){const n=e.nextSibling;for(;r&&r!=e;){const s=r.nextSibling;t.insertBefore(r,n),r=s}}else t.insertBefore(e,r)},w=t=>{for(const e of t.children)w(e);typeof t.return=="function"&&t.return(),t[b]?.(null)},B=(t,e,r)=>{r[c]??=(I(r),t),Object.assign(r[a]??={},e),r[m]()},I=t=>{Object.assign(t,M),t[o.Context]=Object.create(o.current()?.[o.Context]??null)},M={[m](){const t=o.current();o.current(this);try{const{value:e,done:r}=(this[l]??=this[c].call(this,this[a])).next();f(e,this),this[b]?.(this),r&&this.return()}catch(e){this.throw(e)}finally{o.current(t)}},next(t){if(typeof t=="function")try{t.call(this,this[a])}catch(e){this.throw(e)}o.current()?.contains(this)||this[m]()},throw(t){for(let e=this;e;e=e.parentNode)if(typeof e[l]?.throw=="function")try{return f(e[l].throw(t).value,e)}catch(r){t=new Error(r instanceof Error?r.message:r,{cause:t})}throw t},return(){try{this[l]?.return()}catch(t){this.throw(t)}finally{this[l]=null}}};exports.Fragment=v;exports.h=C;exports.render=f;
|
package/dist/index.js
CHANGED
|
@@ -1,102 +1,94 @@
|
|
|
1
|
-
import { Context as
|
|
2
|
-
const u = Symbol.for("ajo.
|
|
3
|
-
let
|
|
4
|
-
for (t of
|
|
5
|
-
const i =
|
|
6
|
-
|
|
1
|
+
import { Context as h, current as l } from "./context.js";
|
|
2
|
+
const u = Symbol.for("ajo.key"), p = Symbol.for("ajo.memo"), b = Symbol.for("ajo.ref"), w = Symbol.for("ajo.cache"), o = Symbol.for("ajo.generator"), c = Symbol.for("ajo.iterator"), y = Symbol.for("ajo.render"), a = Symbol.for("ajo.args"), M = (t) => t.children, U = (t, e, ...r) => ((e ??= {}).nodeName = t, !("children" in e) && r.length && (e.children = r.length == 1 ? r[0] : r), e), m = (t, e) => {
|
|
3
|
+
let r = e.firstChild;
|
|
4
|
+
for (t of g(t)) {
|
|
5
|
+
const i = k(t, e, r);
|
|
6
|
+
r == null ? e.appendChild(i) : i == r ? r = i.nextSibling : i == r.nextSibling ? (e.appendChild(r), r = i.nextSibling) : W(e, i, r);
|
|
7
7
|
}
|
|
8
|
-
for (;
|
|
9
|
-
const i =
|
|
10
|
-
r.removeChild(
|
|
8
|
+
for (; r; ) {
|
|
9
|
+
const i = r.nextSibling;
|
|
10
|
+
r.nodeType == 1 && j(r), e.removeChild(r), r = i;
|
|
11
11
|
}
|
|
12
|
-
},
|
|
13
|
-
const n = r.nextSibling;
|
|
14
|
-
return g(t, r), n.nextSibling;
|
|
15
|
-
}, x = function* (t) {
|
|
12
|
+
}, g = function* (t) {
|
|
16
13
|
if (t == null) return;
|
|
17
|
-
const
|
|
18
|
-
if (
|
|
19
|
-
if (
|
|
20
|
-
else if (
|
|
21
|
-
else if (Symbol.iterator in t) for (t of t) yield*
|
|
22
|
-
else "nodeName" in t ? typeof t.nodeName == "function" ? yield*
|
|
23
|
-
},
|
|
24
|
-
t.constructor.name == "GeneratorFunction" ? yield N(t,
|
|
25
|
-
}, N = function(t,
|
|
26
|
-
const
|
|
27
|
-
for (const
|
|
28
|
-
|
|
29
|
-
return { ...
|
|
30
|
-
},
|
|
31
|
-
for (;
|
|
32
|
-
return
|
|
33
|
-
},
|
|
34
|
-
for (n
|
|
35
|
-
return
|
|
36
|
-
},
|
|
37
|
-
for (const i in { ...t, ...
|
|
38
|
-
t[i] !==
|
|
39
|
-
},
|
|
40
|
-
if (
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
for (const
|
|
49
|
-
|
|
50
|
-
}, B = (t,
|
|
51
|
-
|
|
14
|
+
const e = typeof t;
|
|
15
|
+
if (e != "boolean")
|
|
16
|
+
if (e == "string") yield t;
|
|
17
|
+
else if (e == "number" || e == "bigint") yield String(t);
|
|
18
|
+
else if (Symbol.iterator in t) for (t of t) yield* g(t);
|
|
19
|
+
else "nodeName" in t ? typeof t.nodeName == "function" ? yield* C(t) : yield t : yield String(t);
|
|
20
|
+
}, C = function* ({ nodeName: t, ...e }) {
|
|
21
|
+
t.constructor.name == "GeneratorFunction" ? yield N(t, e) : yield* g(t(e));
|
|
22
|
+
}, N = function(t, e) {
|
|
23
|
+
const r = { ...t.attrs }, i = { ...t.args };
|
|
24
|
+
for (const s in e)
|
|
25
|
+
s.startsWith("attr:") ? r[s.slice(5)] = e[s] : s == "key" || s == "skip" || s == "memo" || s == "ref" || s.startsWith("set:") ? r[s] = e[s] : i[s] = e[s];
|
|
26
|
+
return { ...r, nodeName: t.is ?? "div", [o]: t, [a]: i };
|
|
27
|
+
}, k = (t, e, r) => typeof t == "string" ? E(t, r) : G(t, e, r), E = (t, e) => {
|
|
28
|
+
for (; e && e.nodeType != 3; ) e = e.nextSibling;
|
|
29
|
+
return e ? e.data != t && (e.data = t) : e = document.createTextNode(t), e;
|
|
30
|
+
}, G = ({ nodeName: t, children: e, key: r, skip: i, memo: s, ref: S, [o]: f, [a]: A, ...x }, v, n) => {
|
|
31
|
+
for (; n && (n.localName != t || n[u] != null && n[u] != r || n[o] && n[o] != f); ) n = n.nextSibling;
|
|
32
|
+
return n ??= document.createElementNS(x.xmlns ?? v.namespaceURI, t), r != null && (n[u] = r), (s == null || R(n[p], n[p] = s)) && (O(n[w] ?? T(n), n[w] = x, n), i || (f ? B(f, A, n) : m(e, n)), typeof S == "function" && (n[b] = S)(n)), n;
|
|
33
|
+
}, O = (t, e, r) => {
|
|
34
|
+
for (const i in { ...t, ...e })
|
|
35
|
+
t[i] !== e[i] && (i.startsWith("set:") ? r[i.slice(4)] = e[i] : e[i] == null || e[i] === !1 ? r.removeAttribute(i) : r.setAttribute(i, e[i] === !0 ? "" : e[i]));
|
|
36
|
+
}, R = (t, e) => Array.isArray(t) && Array.isArray(e) ? t.some((r, i) => r !== e[i]) : t !== e, T = (t) => Array.from(t.attributes).reduce((e, r) => (e[r.name] = r.value, e), {}), W = (t, e, r) => {
|
|
37
|
+
if (e.contains(document.activeElement)) {
|
|
38
|
+
const i = e.nextSibling;
|
|
39
|
+
for (; r && r != e; ) {
|
|
40
|
+
const s = r.nextSibling;
|
|
41
|
+
t.insertBefore(r, i), r = s;
|
|
42
|
+
}
|
|
43
|
+
} else t.insertBefore(e, r);
|
|
44
|
+
}, j = (t) => {
|
|
45
|
+
for (const e of t.children) j(e);
|
|
46
|
+
typeof t.return == "function" && t.return(), t[b]?.(null);
|
|
47
|
+
}, B = (t, e, r) => {
|
|
48
|
+
r[o] ??= (F(r), t), Object.assign(r[a] ??= {}, e), r[y]();
|
|
52
49
|
}, F = (t) => {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
render() {
|
|
59
|
-
var t;
|
|
60
|
-
(t = a()) != null && t.contains(this) || this.next();
|
|
61
|
-
},
|
|
62
|
-
next() {
|
|
63
|
-
var r;
|
|
64
|
-
const t = a();
|
|
65
|
-
a(this);
|
|
50
|
+
Object.assign(t, I), t[h] = Object.create(l()?.[h] ?? null);
|
|
51
|
+
}, I = {
|
|
52
|
+
[y]() {
|
|
53
|
+
const t = l();
|
|
54
|
+
l(this);
|
|
66
55
|
try {
|
|
67
|
-
const { value:
|
|
68
|
-
|
|
69
|
-
} catch (
|
|
70
|
-
this.throw(
|
|
56
|
+
const { value: e, done: r } = (this[c] ??= this[o].call(this, this[a])).next();
|
|
57
|
+
m(e, this), this[b]?.(this), r && this.return();
|
|
58
|
+
} catch (e) {
|
|
59
|
+
this.throw(e);
|
|
71
60
|
} finally {
|
|
72
|
-
|
|
61
|
+
l(t);
|
|
73
62
|
}
|
|
74
63
|
},
|
|
64
|
+
next(t) {
|
|
65
|
+
if (typeof t == "function") try {
|
|
66
|
+
t.call(this, this[a]);
|
|
67
|
+
} catch (e) {
|
|
68
|
+
this.throw(e);
|
|
69
|
+
}
|
|
70
|
+
l()?.contains(this) || this[y]();
|
|
71
|
+
},
|
|
75
72
|
throw(t) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
t = new Error(i instanceof Error ? i.message : i, { cause: t });
|
|
73
|
+
for (let e = this; e; e = e.parentNode) if (typeof e[c]?.throw == "function") try {
|
|
74
|
+
return m(e[c].throw(t).value, e);
|
|
75
|
+
} catch (r) {
|
|
76
|
+
t = new Error(r instanceof Error ? r.message : r, { cause: t });
|
|
81
77
|
}
|
|
82
78
|
throw t;
|
|
83
79
|
},
|
|
84
80
|
return() {
|
|
85
|
-
var t;
|
|
86
81
|
try {
|
|
87
|
-
|
|
88
|
-
} catch (
|
|
89
|
-
this.throw(
|
|
82
|
+
this[c]?.return();
|
|
83
|
+
} catch (t) {
|
|
84
|
+
this.throw(t);
|
|
90
85
|
} finally {
|
|
91
|
-
this[
|
|
86
|
+
this[c] = null;
|
|
92
87
|
}
|
|
93
88
|
}
|
|
94
89
|
};
|
|
95
|
-
"MutationObserver" in globalThis && new MutationObserver(
|
|
96
|
-
(t) => t.forEach((r) => r.removedNodes.forEach((n) => n.isConnected || n.nodeType == 1 && S(n)))
|
|
97
|
-
).observe(document, { childList: !0, subtree: !0 });
|
|
98
90
|
export {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
91
|
+
M as Fragment,
|
|
92
|
+
U as h,
|
|
93
|
+
m as render
|
|
102
94
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ajo",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.27",
|
|
4
4
|
"description": "ajo is a JavaScript view library for building user interfaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./types.ts",
|
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
"types.ts"
|
|
34
34
|
],
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@types/node": "24.
|
|
36
|
+
"@types/node": "24.3.0",
|
|
37
37
|
"happy-dom": "18.0.1",
|
|
38
|
-
"vite": "
|
|
38
|
+
"vite": "7.1.4",
|
|
39
39
|
"vite-tsconfig-paths": "5.1.4",
|
|
40
|
-
"vitest": "3.2.
|
|
40
|
+
"vitest": "3.2.4"
|
|
41
41
|
},
|
|
42
42
|
"keywords": [
|
|
43
43
|
"ui",
|
package/readme.md
CHANGED
|
@@ -13,15 +13,321 @@
|
|
|
13
13
|
</a>
|
|
14
14
|
</div>
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
A modern JavaScript library for building user interfaces with generator-based state management, efficient DOM updates, and streaming server-side rendering.
|
|
17
17
|
|
|
18
|
-
##
|
|
18
|
+
## Features
|
|
19
19
|
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
- JSX syntax support
|
|
23
|
-
-
|
|
24
|
-
-
|
|
20
|
+
- **Generator-Based Components**: Use JavaScript generator functions (`function*`) for stateful components with built-in lifecycle management
|
|
21
|
+
- **Efficient DOM Updates**: In-place DOM reconciliation minimizes DOM manipulation and maximizes performance
|
|
22
|
+
- **Declarative JSX**: Write components using familiar JSX syntax with full TypeScript support
|
|
23
|
+
- **Performance Optimization**: Built-in `memo` attribute for fine-grained performance optimization
|
|
24
|
+
- **Context API**: Share state across component trees without prop drilling
|
|
25
|
+
- **Server-Side Rendering**: Complete SSR solution with streaming and hydration support
|
|
26
|
+
- **Islands Architecture**: Selective hydration for maximum performance with minimal client-side JavaScript
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
Install Ajo using your preferred package manager:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install ajo
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Create your first component:
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
import { render } from 'ajo'
|
|
40
|
+
|
|
41
|
+
// Stateless component
|
|
42
|
+
const Greeting = ({ name }) => <p>Hello, {name}!</p>
|
|
43
|
+
|
|
44
|
+
// Stateful component
|
|
45
|
+
function* Counter() {
|
|
46
|
+
|
|
47
|
+
let count = 0
|
|
48
|
+
|
|
49
|
+
const increment = () => this.next(() => count++)
|
|
50
|
+
|
|
51
|
+
while (true) yield (
|
|
52
|
+
<button set:onclick={increment}>
|
|
53
|
+
Count: {count}
|
|
54
|
+
</button>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Render to DOM
|
|
59
|
+
render(<Counter />, document.body)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Core Concepts
|
|
63
|
+
|
|
64
|
+
### Component Types
|
|
65
|
+
|
|
66
|
+
**Stateless Components** are pure functions:
|
|
67
|
+
```javascript
|
|
68
|
+
const UserCard = ({ user }) => (
|
|
69
|
+
<div class="user-card">
|
|
70
|
+
<h3>{user.name}</h3>
|
|
71
|
+
<p>{user.email}</p>
|
|
72
|
+
</div>
|
|
73
|
+
);
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**Stateful Components** use generator functions with automatic wrapper elements:
|
|
77
|
+
```javascript
|
|
78
|
+
function* TodoList() {
|
|
79
|
+
|
|
80
|
+
let todos = []
|
|
81
|
+
|
|
82
|
+
const addTodo = text => this.next(() => todos.push({ id: Date.now(), text }))
|
|
83
|
+
|
|
84
|
+
while (true) yield (
|
|
85
|
+
<>
|
|
86
|
+
<input set:onkeydown={e => e.key === 'Enter' && addTodo(e.target.value)} />
|
|
87
|
+
<ul>
|
|
88
|
+
{todos.map(todo => <li key={todo.id}>{todo.text}</li>)}
|
|
89
|
+
</ul>
|
|
90
|
+
</>
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### State Management Pattern
|
|
96
|
+
|
|
97
|
+
The generator structure provides a natural mental model:
|
|
98
|
+
- **Before the loop**: Persistent state, handlers, and utilities
|
|
99
|
+
- **Inside the loop**: Re-executed on each render for derived values
|
|
100
|
+
|
|
101
|
+
```javascript
|
|
102
|
+
function* ShoppingCart(args) {
|
|
103
|
+
|
|
104
|
+
// Persistent state (like useState)
|
|
105
|
+
let items = []
|
|
106
|
+
|
|
107
|
+
// Persistent handlers (like useCallback)
|
|
108
|
+
const addItem = product => this.next(() => items.push(product))
|
|
109
|
+
|
|
110
|
+
// Main render loop
|
|
111
|
+
while (true) {
|
|
112
|
+
|
|
113
|
+
// Derived values computed fresh each render
|
|
114
|
+
const total = items.reduce((sum, item) => sum + item.price, 0)
|
|
115
|
+
const itemCount = items.length
|
|
116
|
+
|
|
117
|
+
yield (
|
|
118
|
+
<>
|
|
119
|
+
<h2>Cart ({itemCount} items)</h2>
|
|
120
|
+
<p>Total: ${total}</p>
|
|
121
|
+
{/* ... */}
|
|
122
|
+
</>
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Special Attributes
|
|
129
|
+
|
|
130
|
+
- **`key`**: List reconciliation
|
|
131
|
+
- **`ref`**: DOM element access
|
|
132
|
+
- **`memo`**: Performance optimization
|
|
133
|
+
- **`skip`**: Third-party DOM management
|
|
134
|
+
- **`set:`**: Direct property setting
|
|
135
|
+
- **`attr:`**: Force HTML attributes
|
|
136
|
+
|
|
137
|
+
```javascript
|
|
138
|
+
function* MapComponent(args) {
|
|
139
|
+
|
|
140
|
+
let mapRef = null
|
|
141
|
+
|
|
142
|
+
while (true) yield (
|
|
143
|
+
<div
|
|
144
|
+
ref={el => {
|
|
145
|
+
if (el && !mapRef) {
|
|
146
|
+
mapRef = el
|
|
147
|
+
// Third-party map library controls this DOM
|
|
148
|
+
new GoogleMap(el, args.config)
|
|
149
|
+
}
|
|
150
|
+
}}
|
|
151
|
+
skip={true}
|
|
152
|
+
>
|
|
153
|
+
{/* Google Maps API manages children elements */}
|
|
154
|
+
</div>
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Server-Side Rendering
|
|
160
|
+
|
|
161
|
+
### Static SSR
|
|
162
|
+
```javascript
|
|
163
|
+
import { render } from 'ajo/html'
|
|
164
|
+
|
|
165
|
+
const html = render(<App />)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Streaming SSR
|
|
169
|
+
```javascript
|
|
170
|
+
import { stream } from 'ajo/stream'
|
|
171
|
+
|
|
172
|
+
for await (const chunk of stream(<App />)) response.write(chunk)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Best Practices
|
|
176
|
+
|
|
177
|
+
1. **Use fragments in stateful components** to avoid unnecessary DOM nesting
|
|
178
|
+
2. **Don't destructure props in function signatures** - use `args` parameter or destructure inside the render loop
|
|
179
|
+
3. **Leverage the generator structure** for natural state and lifecycle management
|
|
180
|
+
4. **Use TypeScript** for enhanced developer experience
|
|
181
|
+
|
|
182
|
+
## API Reference
|
|
183
|
+
|
|
184
|
+
### Core Module (`ajo`)
|
|
185
|
+
|
|
186
|
+
#### `render(children: Children, container: Element): void`
|
|
187
|
+
Renders JSX into a DOM container element.
|
|
188
|
+
|
|
189
|
+
```javascript
|
|
190
|
+
import { render } from 'ajo'
|
|
191
|
+
|
|
192
|
+
render(<App />, document.getElementById('root'))
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
#### `h(type: Type, props?: Props, ...children: Children[]): VNode`
|
|
196
|
+
JSX factory function (rarely used directly).
|
|
197
|
+
|
|
198
|
+
#### `Fragment({ children }: { children: Children }): Children`
|
|
199
|
+
JSX fragment component for rendering multiple elements without a wrapper.
|
|
200
|
+
|
|
201
|
+
```javascript
|
|
202
|
+
const List = () => (
|
|
203
|
+
<>
|
|
204
|
+
<li>Item 1</li>
|
|
205
|
+
<li>Item 2</li>
|
|
206
|
+
</>
|
|
207
|
+
)
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Stateful Component Instance Methods
|
|
211
|
+
|
|
212
|
+
Stateful components have access to several instance methods through `this`:
|
|
213
|
+
|
|
214
|
+
#### `this.next(callback?: (args: ComponentArgs) => void): void`
|
|
215
|
+
Triggers a re-render of the component by advancing to the next yield point. Optionally accepts a callback function that receives the component's current props/args as the first parameter.
|
|
216
|
+
|
|
217
|
+
```javascript
|
|
218
|
+
function* Counter(args) {
|
|
219
|
+
|
|
220
|
+
let count = 0
|
|
221
|
+
|
|
222
|
+
const increment = () => {
|
|
223
|
+
// Simple re-render
|
|
224
|
+
this.next(() => count++)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const incrementByStep = () => {
|
|
228
|
+
// Access current props in callback
|
|
229
|
+
this.next(({ step }) => count += step)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ... rest of component
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
#### `this.throw(error: unknown): void`
|
|
237
|
+
Throws an error that can be caught by parent error boundaries.
|
|
238
|
+
|
|
239
|
+
#### `this.return(): void`
|
|
240
|
+
Terminates the generator and triggers cleanup (rarely used directly).
|
|
241
|
+
|
|
242
|
+
### Context Module (`ajo/context`)
|
|
243
|
+
|
|
244
|
+
#### `context<T>(fallback?: T): ContextFunction<T>`
|
|
245
|
+
Creates a context for sharing data across component trees.
|
|
246
|
+
|
|
247
|
+
```javascript
|
|
248
|
+
import { context } from 'ajo/context'
|
|
249
|
+
|
|
250
|
+
const ThemeContext = context('light')
|
|
251
|
+
|
|
252
|
+
// Set value
|
|
253
|
+
ThemeContext('dark')
|
|
254
|
+
|
|
255
|
+
// Get value
|
|
256
|
+
const theme = ThemeContext() // 'dark'
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### HTML Module (`ajo/html`)
|
|
260
|
+
|
|
261
|
+
#### `render(children: Children): string`
|
|
262
|
+
Renders JSX to an HTML string for static site generation.
|
|
263
|
+
|
|
264
|
+
```javascript
|
|
265
|
+
import { render } from 'ajo/html'
|
|
266
|
+
|
|
267
|
+
const html = render(<HomePage title="Welcome" />)
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
#### `html(children: Children, hooks?: Hooks): IterableIterator<string>`
|
|
271
|
+
Low-level HTML streaming function with custom hooks.
|
|
272
|
+
|
|
273
|
+
### Stream Module (`ajo/stream`)
|
|
274
|
+
|
|
275
|
+
#### `stream(children: Children): AsyncIterableIterator<string>`
|
|
276
|
+
Renders components to an async stream for progressive SSR.
|
|
277
|
+
|
|
278
|
+
```javascript
|
|
279
|
+
import { stream } from 'ajo/stream'
|
|
280
|
+
|
|
281
|
+
for await (const chunk of stream(<App />)) response.write(chunk)
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
#### `hydrate(patch: Patch): Promise<void>`
|
|
285
|
+
Client-side function for applying streamed patches during hydration.
|
|
286
|
+
|
|
287
|
+
```javascript
|
|
288
|
+
import { hydrate } from 'ajo/stream'
|
|
289
|
+
|
|
290
|
+
window.$stream = { push: hydrate }
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### TypeScript Support
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
// Component types
|
|
297
|
+
type Stateless<Props = {}> = (props: Props) => Children
|
|
298
|
+
type Stateful<Props = {}, Tag = 'div'> = {
|
|
299
|
+
(this: StatefulElement<Tag>, props: Props): Iterator<Children>
|
|
300
|
+
is?: Tag
|
|
301
|
+
attrs?: Record<string, unknown>
|
|
302
|
+
args?: Partial<Props>
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Stateful component instance
|
|
306
|
+
type StatefulElement<Tag> = HTMLElement & {
|
|
307
|
+
next: (callback?: (args: ComponentArgs) => void) => void
|
|
308
|
+
throw: (error: unknown) => void
|
|
309
|
+
return: () => void
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
// Element types
|
|
313
|
+
type Children = unknown
|
|
314
|
+
type VNode<Type, Props> = Props & {
|
|
315
|
+
nodeName: Type
|
|
316
|
+
children?: Children
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
// Special attributes
|
|
320
|
+
type SpecialAttributes = {
|
|
321
|
+
key?: unknown
|
|
322
|
+
ref?: (element: Element | null) => void
|
|
323
|
+
memo?: unknown[]
|
|
324
|
+
skip?: boolean
|
|
325
|
+
};
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## Documentation
|
|
329
|
+
|
|
330
|
+
For comprehensive guides, advanced patterns, and detailed examples, see [documentation.md](./documentation.md).
|
|
25
331
|
|
|
26
332
|
## License
|
|
27
333
|
|
package/types.ts
CHANGED
|
@@ -39,17 +39,16 @@ declare module 'ajo' {
|
|
|
39
39
|
type Stateless<TArguments extends Props = {}> = (args: TArguments) => Children
|
|
40
40
|
|
|
41
41
|
type Stateful<TArguments extends Props = {}, TTag extends Tag = 'div'> = {
|
|
42
|
-
(this: StatefulElement<TTag>, args: StatefulProps<TArguments, TTag>): Iterator<Children>
|
|
42
|
+
(this: StatefulElement<TArguments, TTag>, args: StatefulProps<TArguments, TTag>): Iterator<Children>
|
|
43
43
|
} & (TTag extends 'div' ? { is?: TTag } : { is: TTag }) & { attrs?: Partial<PropSetter<TTag>> & Props, args?: Partial<TArguments> }
|
|
44
44
|
|
|
45
45
|
type StatefulProps<TArguments, TTag> =
|
|
46
|
-
Partial<SpecialProps<StatefulElement<TTag>> & PropSetter<TTag>> &
|
|
46
|
+
Partial<SpecialProps<StatefulElement<TArguments, TTag>> & PropSetter<TTag>> &
|
|
47
47
|
AttrSetter &
|
|
48
48
|
TArguments
|
|
49
49
|
|
|
50
|
-
type StatefulElement<TTag> = ElementType<TTag> & {
|
|
51
|
-
|
|
52
|
-
next: () => void,
|
|
50
|
+
type StatefulElement<TArguments, TTag> = ElementType<TTag> & {
|
|
51
|
+
next: (fn?: (this: StatefulElement<TArguments, TTag>, args: StatefulProps<TArguments, TTag>) => void) => void,
|
|
53
52
|
throw: (value?: unknown) => void,
|
|
54
53
|
return: () => void,
|
|
55
54
|
}
|