ajo 0.1.32 → 0.1.33

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/LLMs.md CHANGED
@@ -58,7 +58,7 @@ const Counter: Stateful<Args, 'section'> = function* ({ initial }) {
58
58
  <>
59
59
  <input
60
60
  ref={el => inputRef = el}
61
- value={count}
61
+ set:value={count}
62
62
  set:oninput={e => this.next(() => count = +(e.target as HTMLInputElement).value)}
63
63
  />
64
64
  <button set:onclick={inc}>+{step}</button>
@@ -119,7 +119,7 @@ ref?.next() // trigger re-render from outside
119
119
  | **Lists** | Always provide unique `key` on elements |
120
120
  | **Refs** | `ref={el => ...}` on elements. Receives `null` on unmount. Stateful ref type: `ThisParameterType<typeof Component>` |
121
121
  | **Memo** | `memo={[deps]}` array, `memo={value}` single, or just `memo` (never re-render). Skips subtree if unchanged |
122
- | **Skip** | `skip` excludes children from reconciliation. Use for `set:textContent`/`set:innerHTML` or third-party managed DOM |
122
+ | **Skip** | `skip` excludes children from reconciliation; it does not sanitize `set:innerHTML` |
123
123
  | **Custom wrapper** | `stateful(fn, 'tagname')` sets `.is` and infers `this` type. Or manually: `Stateful<Args, 'tagname'>` + `.is = 'tagname'`. Default is `div` (no need to set) |
124
124
  | **Default attrs** | `.attrs = { class: '...' }` on stateful component generator function |
125
125
  | **Default args** | `.args = { prop: value }` on stateful component generator function |
@@ -224,7 +224,7 @@ counterRef?.next() // trigger re-render from outside
224
224
  <input type="checkbox" set:checked={bool} /> // DOM property: syncs with state
225
225
  <video set:currentTime={0} set:muted /> // DOM properties
226
226
  <div set:textContent={str} skip /> // DOM property + skip (required!)
227
- <div set:innerHTML={html} skip /> // DOM property + skip (required!)
227
+ <div set:innerHTML={trustedHtml} skip /> // trusted/sanitized HTML + skip
228
228
 
229
229
  // Post-render work (DOM is updated by the time the microtask runs)
230
230
  const ScrollList: Stateful<{ items: Item[] }> = function* () {
@@ -321,9 +321,12 @@ const inc = () => count++ // won't re-render
321
321
  // ❌ set:textContent/innerHTML without skip: content gets cleared
322
322
  <div set:innerHTML={html} />
323
323
 
324
+ // ❌ skip is not sanitization
325
+ <div set:innerHTML={userHtml} skip />
326
+
324
327
  // ✅ Correct
325
328
  const inc = () => this.next(() => count++)
326
- <div set:innerHTML={html} skip />
329
+ <div set:innerHTML={trustedHtml} skip />
327
330
  ```
328
331
 
329
332
  ## Setup
@@ -346,4 +349,4 @@ export default defineConfig({
346
349
  })
347
350
  ```
348
351
 
349
- For other build systems: `jsx: 'react-jsx'` (or `'automatic'`), `jsxImportSource: 'ajo'`. No manual imports needed — the build tool auto-imports from `ajo/jsx-runtime`.
352
+ For other build systems: `jsx: 'react-jsx'` (or `'automatic'`), `jsxImportSource: 'ajo'`. No manual imports needed — the build tool auto-imports from `ajo/jsx-runtime`.
package/context.js CHANGED
@@ -1,18 +1,18 @@
1
- export const Context = Symbol.for('ajo.context')
2
-
3
- export const context = (fallback, key = Symbol()) => function (...args) {
4
-
5
- const self = this ?? component
6
-
7
- return self
8
- ? args.length
9
- ? self[Context][key] = args[0]
10
- : key in self[Context]
11
- ? self[Context][key]
12
- : fallback
13
- : fallback
14
- }
15
-
16
- let component = null
17
-
18
- export const current = (...args) => args.length ? (component = args[0]) : component
1
+ export const Context = Symbol.for('ajo.context')
2
+
3
+ export const context = (fallback, key = Symbol()) => function (...args) {
4
+
5
+ const self = this ?? component
6
+
7
+ return self
8
+ ? args.length
9
+ ? self[Context][key] = args[0]
10
+ : key in self[Context]
11
+ ? self[Context][key]
12
+ : fallback
13
+ : fallback
14
+ }
15
+
16
+ let component = null
17
+
18
+ export const current = (...args) => args.length ? (component = args[0]) : component
package/dist/context.js CHANGED
@@ -1,11 +1 @@
1
- const e = /* @__PURE__ */ Symbol.for("ajo.context"), r = (t, o = /* @__PURE__ */ Symbol()) => function(...l) {
2
- const n = this ?? c;
3
- return n ? l.length ? n[e][o] = l[0] : o in n[e] ? n[e][o] : t : t;
4
- };
5
- let c = null;
6
- const s = (...t) => t.length ? c = t[0] : c;
7
- export {
8
- e as Context,
9
- r as context,
10
- s as current
11
- };
1
+ var t=Symbol.for("ajo.context"),n=(n,o=Symbol())=>function(...l){let r=this??e;return r?l.length?r[t][o]=l[0]:o in r[t]?r[t][o]:n:n},e=null,o=(...t)=>t.length?e=t[0]:e;export{t as Context,n as context,o as current};
package/dist/html.js CHANGED
@@ -1,55 +1 @@
1
- import { Context as d, current as c } from "./context.js";
2
- const w = /* @__PURE__ */ new Set(["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr"]), p = /* @__PURE__ */ Symbol.for("ajo.args"), i = (t) => t.replace(/[&<>"']/g, (e) => `&#${e.charCodeAt(0)};`), m = () => {
3
- }, S = { tag: "div" }, C = (t) => {
4
- let e = "";
5
- return f(t, (n) => e += n), e;
6
- }, f = (t, e) => {
7
- if (t == null) return;
8
- const n = typeof t;
9
- if (n != "boolean")
10
- if (n == "string") e(i(t));
11
- else if (n == "number" || n == "bigint") e(i(String(t)));
12
- else if (Symbol.iterator in t) for (t of t) f(t, e);
13
- else "nodeName" in t ? typeof t.nodeName == "function" ? v(t, e) : g(t, e) : e(i(String(t)));
14
- }, g = (t, e) => {
15
- const { nodeName: n, children: s } = t;
16
- let l = "";
17
- for (const o in t)
18
- o == "nodeName" || o == "children" || o == "key" || o == "skip" || o == "memo" || o == "ref" || o.startsWith("set:") || t[o] == null || t[o] === !1 || (t[o] === !0 ? l += ` ${o}` : l += ` ${o}="${i(String(t[o]))}"`);
19
- w.has(n) ? e(`<${n}${l}>`) : (e(`<${n}${l}>`), s != null && f(s, e), e(`</${n}>`));
20
- }, v = ({ nodeName: t, fallback: e = t.fallback, ...n }, s) => {
21
- t.constructor.name == "GeneratorFunction" ? x(t, n, s) : f(t(n), s);
22
- }, x = (t, e, n) => {
23
- const s = { ...t.attrs }, l = { ...t.args };
24
- for (const r in e)
25
- r.startsWith("attr:") ? s[r.slice(5)] = e[r] : r == "key" || r == "skip" || r == "memo" || r == "ref" || r.startsWith("set:") ? s[r] = e[r] : l[r] = e[r];
26
- const o = new AbortController(), b = {
27
- *[Symbol.iterator]() {
28
- for (; ; ) yield this[p];
29
- },
30
- [d]: Object.create(c()?.[d] ?? null),
31
- [p]: l,
32
- signal: o.signal,
33
- next: m,
34
- return: m,
35
- throw: (r) => {
36
- throw r;
37
- }
38
- }, u = t.call(b, l), k = c();
39
- c(b);
40
- const y = (r) => ({ ...s, nodeName: t.is ?? S.tag, children: r });
41
- let a = "";
42
- try {
43
- g(y(u.next().value), (r) => a += r);
44
- } catch (r) {
45
- a = "", g(y(u.throw(r).value), ($) => a += $);
46
- } finally {
47
- u.return(), o.abort(), c(k);
48
- }
49
- n(a);
50
- };
51
- export {
52
- S as defaults,
53
- f as html,
54
- C as render
55
- };
1
+ import{isVNode as t,mark as n}from"./jsx.js";import{Context as e,current as o}from"./context.js";var{keys:r}=Object,a=new Set(["area","base","br","col","command","embed","hr","img","input","keygen","link","meta","param","source","track","wbr"]),l=Symbol.for("ajo.args"),s=e=>e.replace(/[&<>"']/g,e=>`&#${e.charCodeAt(0)};`),i=/^[A-Za-z][\w:.-]*$/,m=/^[^\s"'/>=\0-\x1F\x7F]+$/,f=()=>{},c={tag:"div"},u=e=>{let t="";return d(e,e=>t+=e),t},d=(e,r)=>{if(null==e)return;let a=typeof e;if("boolean"!=a)if("string"==a)r(s(e));else if("number"==a||"bigint"==a)r(s(String(e)));else if(t(e))"function"==typeof e.nodeName?b(e,r):g(e,r);else if(Symbol.iterator in Object(e))for(e of e)d(e,r);else r(s(String(e)))},g=(e,t)=>{let{nodeName:o,children:n}=e;o="string"==typeof o&&i.test(o)?o:c.tag;let l="";for(let t of r(e))"nodeName"==t||"children"==t||"key"==t||"skip"==t||"memo"==t||"ref"==t||t.startsWith("set:")||!m.test(t)||null==e[t]||!1===e[t]||(!0===e[t]?l+=` ${t}`:l+=` ${t}="${s(String(e[t]))}"`);t(`<${o}${l}>`),a.has(o)||(null!=n&&d(n,t),t(`</${o}>`))},b=({nodeName:e,...t},r)=>{"GeneratorFunction"==e.constructor.name?h(e,t,r):d(e(t),r)},h=(t,a,s)=>{let i={...t.attrs},m={...t.args};for(let e of r(a))e.startsWith("attr:")?i[e.slice(5)]=a[e]:"key"==e||"skip"==e||"memo"==e||"ref"==e||e.startsWith("set:")?i[e]=a[e]:m[e]=a[e];let u=new AbortController,d={*[Symbol.iterator](){for(;;)yield this[l]},[e]:Object.create(o()?.[e]??null),[l]:m,signal:u.signal,next:f,return:f,throw:e=>{throw e}},b=t.call(d,m),h=o();o(d);let y=e=>n({...i,nodeName:t.is??c.tag,children:e}),p="";try{g(y(b.next().value),e=>p+=e)}catch(t){p="",g(y(b.throw(t).value),e=>p+=e)}finally{b.return(),u.abort(),o(h)}s(p)};export{c as defaults,d as html,u as render};
package/dist/index.js CHANGED
@@ -1,110 +1 @@
1
- import { Context as x, current as c } from "./context.js";
2
- const { isArray: h } = Array, { assign: N, create: A } = Object, l = /* @__PURE__ */ Symbol.for("ajo.key"), b = /* @__PURE__ */ Symbol.for("ajo.keyed"), C = /* @__PURE__ */ Symbol.for("ajo.memo"), u = /* @__PURE__ */ Symbol.for("ajo.cache"), a = /* @__PURE__ */ Symbol.for("ajo.generator"), o = /* @__PURE__ */ Symbol.for("ajo.iterator"), g = /* @__PURE__ */ Symbol.for("ajo.render"), f = /* @__PURE__ */ Symbol.for("ajo.args"), E = /* @__PURE__ */ Symbol.for("ajo.controller"), v = { tag: "div" }, q = (r, t) => (t && (r.is = t), r), S = (r, t, e = t.firstChild, i = null) => {
3
- for (p(r, (n) => {
4
- const s = typeof n == "string" ? W(n, e) : B(n, t, e);
5
- e == null ? y(t, s, i) : s == e ? e = s.nextSibling : s == e.nextSibling ? (y(t, e, i), e = s.nextSibling) : y(t, s, e);
6
- }); e != i; ) {
7
- const n = e.nextSibling;
8
- e.nodeType == 1 && R(e), t.removeChild(e), e = n;
9
- }
10
- }, p = (r, t) => {
11
- if (r == null) return;
12
- const e = typeof r;
13
- if (e != "boolean")
14
- if (e == "string") t(r);
15
- else if (e == "number" || e == "bigint") t(String(r));
16
- else if (Symbol.iterator in r) for (r of r) p(r, t);
17
- else "nodeName" in r ? typeof r.nodeName == "function" ? G(r, t) : t(r) : t(String(r));
18
- }, G = ({ nodeName: r, ...t }, e) => {
19
- r.constructor.name == "GeneratorFunction" ? e(T(r, t)) : p(r(t), e);
20
- }, T = (r, t) => {
21
- const e = { ...r.attrs }, i = { ...r.args };
22
- for (const n in t)
23
- n.startsWith("attr:") ? e[n.slice(5)] = t[n] : n == "key" || n == "skip" || n == "memo" || n == "ref" || n.startsWith("set:") ? e[n] = t[n] : i[n] = t[n];
24
- return { ...e, nodeName: r.is ?? v.tag, [a]: r, [f]: i };
25
- }, W = (r, t) => {
26
- for (; t && t.nodeType != 3; ) t = t.nextSibling;
27
- return t ? t.data != r && (t.data = r) : t = document.createTextNode(r), t;
28
- }, B = (r, t, e) => {
29
- const { nodeName: i, children: n, key: s, skip: k, memo: w, [a]: m, [f]: j } = r;
30
- for (s != null && (e = (t[b] ??= /* @__PURE__ */ new Map()).get(s) ?? e); e && (e.localName != i || e[l] != null && e[l] != s || e[a] && e[a] != m); ) e = e[l] != null ? null : e.nextElementSibling;
31
- return e ??= document.createElementNS(r.xmlns ?? t.namespaceURI, i), s != null && t[b].set(e[l] = s, e), (w == null || K(e[C], e[C] = w)) && (I(e[u], e[u] = r, e), k || (m ? F(m, j, e) : S(n, e))), e;
32
- }, I = (r, t, e) => {
33
- for (const i in { ...r, ...t })
34
- i == "nodeName" || i == "children" || i == "key" || i == "skip" || i == "memo" || r?.[i] === t[i] || (i == "ref" && typeof t[i] == "function" ? t[i](e) : i.startsWith("set:") ? e[i.slice(4)] = t[i] : t[i] == null || t[i] === !1 ? e.removeAttribute(i) : e.setAttribute(i, t[i] === !0 ? "" : t[i]));
35
- }, K = (r, t) => h(r) && h(t) ? r.some((e, i) => e !== t[i]) : r !== t, M = (r, t) => {
36
- let e = t.firstElementChild;
37
- for (; e; )
38
- if (r(e) && e.firstElementChild) e = e.firstElementChild;
39
- else {
40
- for (; e != t && !e.nextElementSibling; ) e = e.parentNode ?? t;
41
- e = e != t && e.nextElementSibling;
42
- }
43
- }, y = (r, t, e) => {
44
- if (t.isConnected && t.contains(document.activeElement)) {
45
- const i = t.nextSibling;
46
- for (; e && e != t; ) {
47
- const n = e.nextSibling;
48
- r.insertBefore(e, i), e = n;
49
- }
50
- } else r.insertBefore(t, e);
51
- }, R = (r) => {
52
- let t = r;
53
- for (; t.firstElementChild; ) t = t.firstElementChild;
54
- for (; ; ) {
55
- const { nextElementSibling: e, parentNode: i } = t;
56
- if (t[l] != null && i?.[b]?.delete(t[l]), typeof t.return == "function" && t.return(!1), typeof t[u]?.ref == "function" && t[u].ref(null), t === r) break;
57
- if (t = e ?? i ?? r, e) for (; t.firstElementChild; ) t = t.firstElementChild;
58
- }
59
- }, F = (r, t, e) => {
60
- e[a] ??= (N(e, O)[x] = A(c()?.[x] ?? null), r), e[f] = t, e[g]();
61
- }, O = {
62
- *[Symbol.iterator]() {
63
- for (; ; ) yield this[f];
64
- },
65
- [g]() {
66
- const r = c();
67
- c(this);
68
- try {
69
- this[o] || (this.signal = (this[E] = new AbortController()).signal, this[o] = this[a].call(this, this[f]));
70
- const { value: t, done: e } = this[o].next();
71
- S(t, this), e && this.return();
72
- } catch (t) {
73
- this.throw(t);
74
- } finally {
75
- c(r);
76
- }
77
- },
78
- next(r, t) {
79
- if (!this.isConnected) return t;
80
- try {
81
- typeof r == "function" && (t = r.call(this, this[f]));
82
- } catch (e) {
83
- return this.throw(e);
84
- }
85
- return c()?.contains(this) || this[g](), t;
86
- },
87
- throw(r) {
88
- for (let t = this; t; t = t.parentNode) if (t[o]?.throw) try {
89
- return S(t[o].throw(r).value, t);
90
- } catch (e) {
91
- r = new Error(e?.message ?? e, { cause: r });
92
- }
93
- throw r;
94
- },
95
- return(r = !0) {
96
- r && M((t) => typeof t.return == "function" ? t.return() : !0, this);
97
- try {
98
- this[o]?.return();
99
- } catch (t) {
100
- this.throw(t);
101
- } finally {
102
- this[o] = null, this[E]?.abort();
103
- }
104
- }
105
- };
106
- export {
107
- v as defaults,
108
- S as render,
109
- q as stateful
110
- };
1
+ import{isVNode as t,mark as n}from"./jsx.js";import{Context as e,current as o}from"./context.js";var y,{isArray:r}=Array,{assign:a,hasOwn:l,keys:s}=Object,i=Symbol.for("ajo.key"),m=Symbol.for("ajo.keyed"),f=Symbol.for("ajo.memo"),c=Symbol.for("ajo.cache"),u=Symbol.for("ajo.generator"),d=Symbol.for("ajo.iterator"),g=Symbol.for("ajo.render"),b=Symbol.for("ajo.args"),h=Symbol.for("ajo.controller"),p={tag:"div"},S=(e,t)=>(t&&(e.is=t),e),x=(e,t,r=t.firstChild,n=null)=>{if(C(e,e=>{let i="string"==typeof e?E(e,r,n):k(e,t,r,n);null==r?A(t,i,n):i==r?r=i.nextSibling:i==r.nextSibling?(A(t,r,n),r=i.nextSibling):A(t,i,r)}),r&&!n&&r==t.firstChild){let e=[];for(t[m]?.clear();r;)e.push(r),r=r.nextSibling;for(r of(t.textContent="",e))1==r.nodeType&&O(r)}else for(;r&&r!=n;){let e=r.nextSibling,n=t.removeChild(r);1==n.nodeType&&O(n,t),r=e}},C=(e,r)=>{if(null==e)return;let n=typeof e;if("boolean"!=n)if("string"==n)r(e);else if("number"==n||"bigint"==n)r(String(e));else if(t(e))"function"==typeof e.nodeName?N(e,r):r(e);else if(Symbol.iterator in Object(e))for(e of e)C(e,r);else r(String(e))},N=({nodeName:e,...t},r)=>{"GeneratorFunction"==e.constructor.name?r(j(e,t)):C(e(t),r)},j=(e,t)=>{let r={...e.attrs},i={...e.args};for(let e of s(t))e.startsWith("attr:")?r[e.slice(5)]=t[e]:"key"==e||"skip"==e||"memo"==e||"ref"==e||e.startsWith("set:")?r[e]=t[e]:i[e]=t[e];return n({...r,nodeName:e.is??p.tag,[u]:e,[b]:i})},E=(e,t,r)=>{for(;t&&t!=r&&3!=t.nodeType;)t=t.nextSibling;return t&&t!=r?t.data!=e&&(t.data=e):t=document.createTextNode(e),t},k=(e,t,r,n)=>{let o=e.nodeName,l=e.key,s=e[u];for(r&&null!=l&&null==n&&(r=(t[m]??=new Map).get(l)??r);r&&r!=n&&(r.localName!=o||null!=r[i]&&r[i]!=l||r[u]&&r[u]!=s);)r=null==r[i]?r.nextElementSibling:null;return r==n&&(r=null),r??=document.createElementNS(e.xmlns??t.namespaceURI,o),null!=l&&(t[m]??=new Map).set(r[i]=l,r),(!r[c]||null==e.memo||w(r[f],e.memo))&&(v(r[c],e,r),e.skip||(s?T(s,e[b],r):r[c]||"string"!=typeof e.children&&"number"!=typeof e.children?x(e.children,r):r.textContent=e.children+""),r[f]=e.memo,r[c]=e),r},v=(e,t,r)=>{if(!e)for(let e=r.attributes.length;e--;)l(t,r.attributes[e].name)||r.removeAttribute(r.attributes[e].name);for(let n in t)if(l(t,n)){let i=t[n];if(e&&e[n]===i||"nodeName"==n||"children"==n||"key"==n||"skip"==n||"memo"==n)continue;"ref"==n&&"function"==typeof i?i(r):n.startsWith("set:")?r[n.slice(4)]=i:null==i||!1===i?r.removeAttribute(n):"class"==n&&"string"==typeof r.className?r.className=!0===i?"":i:r.setAttribute(n,!0===i?"":i)}if(e)for(let n in e)if(l(e,n)){if(l(t,n)||"nodeName"==n||"children"==n||"key"==n||"skip"==n||"memo"==n)continue;n.startsWith("set:")?r[n.slice(4)]=void 0:r.removeAttribute(n)}},w=(e,t)=>{if(r(e)&&r(t)){if(e.length!=t.length)return!0;for(let r=e.length;r--;)if(e[r]!==t[r])return!0;return!1}return e!==t},A=(e,t,r)=>{if(t.isConnected&&t.contains(document.activeElement)){let n=t.nextSibling;for(;r&&r!=t;){let t=r.nextSibling;e.insertBefore(r,n),r=t}}else e.insertBefore(t,r)},O=(e,t)=>{if(e[f]==O)return;e[f]=O;let r=e;for(;r.firstElementChild;)r=r.firstElementChild;for(;;){let{nextElementSibling:n,parentNode:o}=r;if(null!=r[i]&&(o??t)?.[m]?.delete(r[i]),"function"==typeof r.return&&r.return(!1),"function"==typeof r[c]?.ref&&r[c].ref(null),r===e)break;if(r=n??o??e,n)for(;r.firstElementChild;)r=r.firstElementChild}},T=(t,r,n)=>{n[u]??=(W(),a(n,M)[e]=Object.create(o()?.[e]??null),t);for(let e of s(n[b]??=r))l(r,e)||delete n[b][e];a(n[b],r),n[g]()},W=()=>y||(y=new MutationObserver(e=>{for(let t of e)for(let e of t.removedNodes)1==e.nodeType&&!e.isConnected&&O(e,t.target)})).observe(document,{childList:!0,subtree:!0}),M={*[Symbol.iterator](){for(;;)yield this[b]},[g](){let e=o();o(this);try{this[d]||(this.signal=(this[h]=new AbortController).signal,this[d]=this[u].call(this,this[b]));let{value:e,done:t}=this[d].next();x(e,this),t&&this.return()}catch(e){this.throw(e)}finally{o(e)}},next(e,t){if(!1===this[d]||!this.isConnected)return t;try{"function"==typeof e&&(t=e.call(this,this[b]))}catch(e){return this.throw(e)}return o()?.contains(this)||this[g](),t},throw(e){for(let t=this;t;t=t.parentNode)if(t[d]?.throw)try{return x(t[d].throw(e).value,t)}catch(t){e=Error(t?.message??t,{cause:e})}throw e},return(e=!0){if(!1===this[d])return;let t=this[d];this[d]=!1,e&&((e,t)=>{let r=t.firstElementChild;for(;r;)if(e(r)&&r.firstElementChild)r=r.firstElementChild;else{for(;r!=t&&!r.nextElementSibling;)r=r.parentNode??t;r=r!=t&&r.nextElementSibling}})(e=>"function"!=typeof e.return||e.return(),this);try{t?.return()}catch(e){this.throw(e)}finally{this[d]=null,this[h]?.abort()}}};export{p as defaults,x as render,S as stateful};
package/dist/jsx.js CHANGED
@@ -1,12 +1 @@
1
- const l = (e) => e.children, i = (e, n, ...t) => ((n ??= {}).nodeName = e, !("children" in n) && t.length && (n.children = t.length == 1 ? t[0] : t), n);
2
- function c(e, n, t) {
3
- return t != null && ((n ??= {}).key = t), i(e, n);
4
- }
5
- const s = c, u = c;
6
- export {
7
- l as Fragment,
8
- i as h,
9
- c as jsx,
10
- u as jsxDEV,
11
- s as jsxs
12
- };
1
+ var t=Symbol.for("ajo.vnode"),n=a=>(a[t]=a,a),e=a=>a?.[t]===a,o=a=>a.children;function r(a,s,e){return(s??={}).nodeName=a,null!=e&&(s.key=e),n(s)}var a=r,l=r;export{o as Fragment,e as isVNode,r as jsx,l as jsxDEV,a as jsxs,n as mark};
package/html.js CHANGED
@@ -1,12 +1,17 @@
1
- import { Context, current } from './context.js'
2
-
3
- const Void = new Set(['area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'])
4
-
5
- const Args = Symbol.for('ajo.args')
6
-
7
- const escape = s => s.replace(/[&<>"']/g, c => `&#${c.charCodeAt(0)};`)
8
-
9
- const noop = () => { }
1
+ import { Context, current } from './context.js'
2
+ import { isVNode, mark } from './jsx.js'
3
+
4
+ const { keys } = Object
5
+
6
+ const Void = new Set(['area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'])
7
+
8
+ const Args = Symbol.for('ajo.args')
9
+
10
+ const escape = s => s.replace(/[&<>"']/g, c => `&#${c.charCodeAt(0)};`)
11
+
12
+ const Tag = /^[A-Za-z][\w:.-]*$/, Attr = /^[^\s"'/>=\0-\x1F\x7F]+$/
13
+
14
+ const noop = () => { }
10
15
 
11
16
  export const defaults = { tag: 'div' }
12
17
 
@@ -19,53 +24,53 @@ export const render = h => {
19
24
  return out
20
25
  }
21
26
 
22
- export const html = (h, emit) => {
23
-
24
- if (h == null) return
25
-
26
- const type = typeof h
27
-
28
- if (type == 'boolean') return
27
+ export const html = (h, emit) => {
28
+
29
+ if (h == null) return
30
+
31
+ const type = typeof h
32
+
33
+ if (type == 'boolean') return
29
34
 
30
35
  if (type == 'string') emit(escape(h))
31
36
 
32
- else if (type == 'number' || type == 'bigint') emit(escape(String(h)))
37
+ else if (type == 'number' || type == 'bigint') emit(escape(String(h)))
33
38
 
34
- else if (Symbol.iterator in h) for (h of h) html(h, emit)
35
-
36
- else if ('nodeName' in h) typeof h.nodeName == 'function' ? run(h, emit) : element(h, emit)
37
-
38
- else emit(escape(String(h)))
39
- }
39
+ else if (isVNode(h)) typeof h.nodeName == 'function' ? run(h, emit) : element(h, emit)
40
+
41
+ else if (Symbol.iterator in Object(h)) for (h of h) html(h, emit)
42
+
43
+ else emit(escape(String(h)))
44
+ }
40
45
 
41
46
  const element = (h, emit) => {
42
47
 
43
- const { nodeName, children } = h
44
-
45
- let a = ''
46
-
47
- for (const key in h) {
48
-
49
- if (key == 'nodeName' || key == 'children' || key == 'key' || key == 'skip' || key == 'memo' || key == 'ref' || key.startsWith('set:') || h[key] == null || h[key] === false) continue
50
-
51
- if (h[key] === true) a += ` ${key}`
52
-
53
- else a += ` ${key}="${escape(String(h[key]))}"`
54
- }
55
-
56
- if (Void.has(nodeName)) emit(`<${nodeName}${a}>`)
57
-
58
- else {
59
-
60
- emit(`<${nodeName}${a}>`)
61
-
62
- if (children != null) html(children, emit)
63
-
64
- emit(`</${nodeName}>`)
48
+ let { nodeName, children } = h
49
+
50
+ nodeName = typeof nodeName == 'string' && Tag.test(nodeName) ? nodeName : defaults.tag
51
+
52
+ let a = ''
53
+
54
+ for (const key of keys(h)) {
55
+
56
+ if (key == 'nodeName' || key == 'children' || key == 'key' || key == 'skip' || key == 'memo' || key == 'ref' || key.startsWith('set:') || !Attr.test(key) || h[key] == null || h[key] === false) continue
57
+
58
+ if (h[key] === true) a += ` ${key}`
59
+
60
+ else a += ` ${key}="${escape(String(h[key]))}"`
61
+ }
62
+
63
+ emit(`<${nodeName}${a}>`)
64
+
65
+ if (!Void.has(nodeName)) {
66
+
67
+ if (children != null) html(children, emit)
68
+
69
+ emit(`</${nodeName}>`)
65
70
  }
66
71
  }
67
72
 
68
- const run = ({ nodeName, fallback = nodeName.fallback, ...h }, emit) => {
73
+ const run = ({ nodeName, ...h }, emit) => {
69
74
 
70
75
  if (nodeName.constructor.name == 'GeneratorFunction') runGenerator(nodeName, h, emit)
71
76
 
@@ -76,7 +81,7 @@ const runGenerator = (fn, h, emit) => {
76
81
 
77
82
  const attrs = { ...fn.attrs }, args = { ...fn.args }
78
83
 
79
- for (const key in h) {
84
+ for (const key of keys(h)) {
80
85
 
81
86
  if (key.startsWith('attr:')) attrs[key.slice(5)] = h[key]
82
87
 
@@ -89,7 +94,7 @@ const runGenerator = (fn, h, emit) => {
89
94
 
90
95
  const instance = {
91
96
 
92
- *[Symbol.iterator]() { while (true) yield this[Args] },
97
+ *[Symbol.iterator]() { while (true) yield this[Args] },
93
98
 
94
99
  [Context]: Object.create(current()?.[Context] ?? null),
95
100
 
@@ -110,19 +115,19 @@ const runGenerator = (fn, h, emit) => {
110
115
 
111
116
  current(instance)
112
117
 
113
- const vnode = children => ({ ...attrs, nodeName: fn.is ?? defaults.tag, children })
114
-
115
- let out = ''
116
-
117
- try {
118
-
119
- element(vnode(iterator.next().value), chunk => out += chunk)
120
-
121
- } catch (error) {
122
-
123
- out = ''
124
-
125
- element(vnode(iterator.throw(error).value), chunk => out += chunk)
118
+ const vnode = children => mark({ ...attrs, nodeName: fn.is ?? defaults.tag, children })
119
+
120
+ let out = ''
121
+
122
+ try {
123
+
124
+ element(vnode(iterator.next().value), chunk => out += chunk)
125
+
126
+ } catch (error) {
127
+
128
+ out = ''
129
+
130
+ element(vnode(iterator.throw(error).value), chunk => out += chunk)
126
131
 
127
132
  } finally {
128
133