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/jsx.js CHANGED
@@ -1,21 +1,20 @@
1
- export const Fragment = props => props.children
2
-
3
- export const h = (type, props, ...children) => {
4
-
5
- (props ??= {}).nodeName = type
6
-
7
- if (!('children' in props) && children.length) props.children = children.length == 1 ? children[0] : children
8
-
9
- return props
10
- }
11
-
12
- export function jsx(type, props, key) {
13
-
14
- if (key != null) (props ??= {}).key = key
15
-
16
- return h(type, props)
17
- }
18
-
19
- export const jsxs = jsx
20
-
21
- export const jsxDEV = jsx
1
+ const VNode = Symbol.for('ajo.vnode')
2
+
3
+ export const mark = v => (v[VNode] = v, v)
4
+
5
+ export const isVNode = v => v?.[VNode] === v
6
+
7
+ export const Fragment = props => props.children
8
+
9
+ export function jsx(type, props, key) {
10
+
11
+ (props ??= {}).nodeName = type
12
+
13
+ if (key != null) props.key = key
14
+
15
+ return mark(props)
16
+ }
17
+
18
+ export const jsxs = jsx
19
+
20
+ export const jsxDEV = jsx
package/license CHANGED
@@ -1,15 +1,15 @@
1
- ISC License
2
-
3
- Copyright (c) 2022-2026, Cristian Falcone
4
-
5
- Permission to use, copy, modify, and/or distribute this software for any
6
- purpose with or without fee is hereby granted, provided that the above
7
- copyright notice and this permission notice appear in all copies.
8
-
9
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14
- OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15
- PERFORMANCE OF THIS SOFTWARE.
1
+ ISC License
2
+
3
+ Copyright (c) 2022-2026, Cristian Falcone
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14
+ OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15
+ PERFORMANCE OF THIS SOFTWARE.
package/package.json CHANGED
@@ -1,40 +1,34 @@
1
1
  {
2
2
  "name": "ajo",
3
- "version": "0.1.32",
3
+ "version": "0.1.33",
4
4
  "description": "ajo is a JavaScript view library for building user interfaces",
5
5
  "type": "module",
6
6
  "types": "./types.ts",
7
7
  "module": "./dist/index.js",
8
- "main": "./dist/index.cjs",
9
8
  "exports": {
10
9
  ".": {
11
10
  "react-native": "./index.js",
12
11
  "types": "./types.ts",
13
- "import": "./dist/index.js",
14
- "require": "./dist/index.cjs"
12
+ "import": "./dist/index.js"
15
13
  },
16
14
  "./context": {
17
15
  "react-native": "./context.js",
18
16
  "types": "./types.ts",
19
- "import": "./dist/context.js",
20
- "require": "./dist/context.cjs"
17
+ "import": "./dist/context.js"
21
18
  },
22
19
  "./html": {
23
20
  "types": "./types.ts",
24
- "import": "./dist/html.js",
25
- "require": "./dist/html.cjs"
21
+ "import": "./dist/html.js"
26
22
  },
27
23
  "./jsx-runtime": {
28
24
  "react-native": "./jsx.js",
29
25
  "types": "./types.ts",
30
- "import": "./dist/jsx.js",
31
- "require": "./dist/jsx.cjs"
26
+ "import": "./dist/jsx.js"
32
27
  },
33
28
  "./jsx-dev-runtime": {
34
29
  "react-native": "./jsx.js",
35
30
  "types": "./types.ts",
36
- "import": "./dist/jsx.js",
37
- "require": "./dist/jsx.cjs"
31
+ "import": "./dist/jsx.js"
38
32
  }
39
33
  },
40
34
  "files": [
@@ -47,12 +41,12 @@
47
41
  "types.ts"
48
42
  ],
49
43
  "devDependencies": {
50
- "@types/node": "25.3.1",
51
- "happy-dom": "20.7.0",
52
- "typescript": "5.9.3",
53
- "vite": "7.3.1",
54
- "vite-tsconfig-paths": "6.1.1",
55
- "vitest": "4.0.18"
44
+ "@types/node": "26.0.0",
45
+ "happy-dom": "20.10.6",
46
+ "terser": "5.48.0",
47
+ "typescript": "6.0.3",
48
+ "vite": "8.0.16",
49
+ "vitest": "4.1.9"
56
50
  },
57
51
  "keywords": [
58
52
  "ui",
@@ -61,13 +55,19 @@
61
55
  "dom",
62
56
  "jsx"
63
57
  ],
64
- "repository": "cristianfalcone/ajo",
58
+ "repository": {
59
+ "type": "git",
60
+ "url": "cristianfalcone/ajo"
61
+ },
65
62
  "author": "Cristian Falcone",
66
63
  "license": "ISC",
67
64
  "bugs": "https://github.com/cristianfalcone/ajo/issues",
68
65
  "homepage": "https://github.com/cristianfalcone/ajo#readme",
69
66
  "scripts": {
70
67
  "test": "vitest --run",
68
+ "bench": "pnpm --dir bench bench",
69
+ "bench:quick": "pnpm --dir bench bench:quick",
70
+ "bench:ajo": "pnpm --dir bench bench:ajo",
71
71
  "build": "vite build",
72
72
  "bump": "pnpm version patch && git push && git push --tags",
73
73
  "release": "pnpm test && pnpm build && pnpm bump && pnpm publish"
package/readme.md CHANGED
@@ -226,7 +226,7 @@ function* ErrorBoundary() {
226
226
  | `key` | Unique identifier for list reconciliation |
227
227
  | `ref` | Callback receiving DOM element (or `null` on unmount) |
228
228
  | `memo` | Skip reconciliation: `memo={[deps]}`, `memo={value}`, or `memo` (render once) |
229
- | `skip` | Exclude children from reconciliation (required with `set:innerHTML`) |
229
+ | `skip` | Exclude children from reconciliation; not a sanitizer |
230
230
  | `set:*` | Set DOM properties instead of HTML attributes |
231
231
  | `attr:*` | Force HTML attributes on stateful component wrappers |
232
232
 
@@ -243,8 +243,8 @@ function* ErrorBoundary() {
243
243
  <input type="checkbox" set:checked={bool} />
244
244
  <video set:currentTime={0} set:muted />
245
245
 
246
- // innerHTML requires skip
247
- <div set:innerHTML={html} skip />
246
+ // innerHTML is only for trusted/sanitized HTML; skip preserves assigned children
247
+ <div set:innerHTML={trustedHtml} skip />
248
248
  ```
249
249
 
250
250
  ### `ref` - DOM Access
@@ -254,13 +254,13 @@ function* AutoFocus() {
254
254
 
255
255
  let input = null
256
256
 
257
- while (true) yield (
258
- <>
259
- <input ref={el => el?.focus()} />
260
- <button set:onclick={() => input?.select()}>Select</button>
261
- </>
262
- )
263
- }
257
+ while (true) yield (
258
+ <>
259
+ <input ref={el => { input = el; el?.focus() }} />
260
+ <button set:onclick={() => input?.select()}>Select</button>
261
+ </>
262
+ )
263
+ }
264
264
 
265
265
  // Ref to stateful component includes control methods
266
266
  let timer = null
@@ -424,8 +424,9 @@ let ref: ThisParameterType<typeof Counter> | null = null
424
424
  ### `ajo/html`
425
425
  | Export | Description |
426
426
  |--------|-------------|
427
- | `render(children)` | Render to HTML string. |
428
- | `html(children)` | Render to HTML generator (yields strings). |
427
+ | `render(children)` | Render to HTML string. |
428
+ | `html(children, emit)` | Render to HTML chunks by calling `emit(chunk)`. |
429
+ | `defaults` | Default SSR wrapper tag config (`defaults.tag`). |
429
430
 
430
431
  ### Stateful `this`
431
432
  | Property | Description |
@@ -434,7 +435,7 @@ let ref: ThisParameterType<typeof Counter> | null = null
434
435
  | `this.signal` | AbortSignal that aborts on unmount. Pass to `fetch()`, `addEventListener()`, etc. |
435
436
  | `this.next(fn?)` | Re-render. Callback receives current args. Returns callback's result. |
436
437
  | `this.throw(error)` | Throw to parent boundary. |
437
- | `this.return(deep?)` | Terminate generator. Pass `true` to also terminate child generators. |
438
+ | `this.return(deep?)` | Terminate generator. Deep cleanup is the default; pass `false` to skip child generators. |
438
439
 
439
440
  `this` is also the wrapper element (`this.addEventListener()`, etc).
440
441
 
package/types.ts CHANGED
@@ -105,12 +105,11 @@ declare module 'ajo/html' {
105
105
  }
106
106
 
107
107
  declare module 'ajo/jsx-runtime' {
108
- import { Type, Args, VNode, Children, ElementChildrenAttribute, IntrinsicElements as _IE } from 'ajo'
109
- export function Fragment({ children }: ElementChildrenAttribute): typeof children
110
- export function h(tag: Type, attrs?: Args | null, ...children: Children[]): VNode
111
- export function jsx(type: Type, props: Args | null, key?: string | number): VNode
112
- export function jsxs(type: Type, props: Args | null, key?: string | number): VNode
113
- export function jsxDEV(type: Type, props: Args | null, key?: string | number): VNode
108
+ import { Type, Args, VNode, ElementChildrenAttribute, IntrinsicElements as _IE } from 'ajo'
109
+ export function Fragment({ children }: ElementChildrenAttribute): typeof children
110
+ export function jsx(type: Type, props: Args | null, key?: string | number): VNode
111
+ export function jsxs(type: Type, props: Args | null, key?: string | number): VNode
112
+ export function jsxDEV(type: Type, props: Args | null, key?: string | number): VNode
114
113
  export namespace JSX {
115
114
  type ElementChildrenAttribute = import('ajo').ElementChildrenAttribute
116
115
  type LibraryManagedAttributes<C, P> = import('ajo').ManagedAttributes<C, P>
@@ -118,9 +117,9 @@ declare module 'ajo/jsx-runtime' {
118
117
  }
119
118
  }
120
119
 
121
- declare module 'ajo/jsx-dev-runtime' {
122
- import { IntrinsicElements as _IE } from 'ajo'
123
- export { Fragment, h, jsx, jsxs, jsxDEV } from 'ajo/jsx-runtime'
120
+ declare module 'ajo/jsx-dev-runtime' {
121
+ import { IntrinsicElements as _IE } from 'ajo'
122
+ export { Fragment, jsx, jsxs, jsxDEV } from 'ajo/jsx-runtime'
124
123
  export namespace JSX {
125
124
  type ElementChildrenAttribute = import('ajo').ElementChildrenAttribute
126
125
  type LibraryManagedAttributes<C, P> = import('ajo').ManagedAttributes<C, P>
package/dist/context.cjs DELETED
@@ -1 +0,0 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=Symbol.for("ajo.context"),r=(t,e=Symbol())=>function(...l){const n=this??c;return n?l.length?n[o][e]=l[0]:e in n[o]?n[o][e]:t:t};let c=null;const u=(...t)=>t.length?c=t[0]:c;exports.Context=o;exports.context=r;exports.current=u;
package/dist/html.cjs DELETED
@@ -1 +0,0 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("./context.cjs"),$=new Set(["area","base","br","col","command","embed","hr","img","input","keygen","link","meta","param","source","track","wbr"]),y=Symbol.for("ajo.args"),u=e=>e.replace(/[&<>"']/g,t=>`&#${t.charCodeAt(0)};`),m=()=>{},p={tag:"div"},w=e=>{let t="";return c(e,n=>t+=n),t},c=(e,t)=>{if(e==null)return;const n=typeof e;if(n!="boolean")if(n=="string")t(u(e));else if(n=="number"||n=="bigint")t(u(String(e)));else if(Symbol.iterator in e)for(e of e)c(e,t);else"nodeName"in e?typeof e.nodeName=="function"?v(e,t):g(e,t):t(u(String(e)))},g=(e,t)=>{const{nodeName:n,children:s}=e;let l="";for(const o in e)o=="nodeName"||o=="children"||o=="key"||o=="skip"||o=="memo"||o=="ref"||o.startsWith("set:")||e[o]==null||e[o]===!1||(e[o]===!0?l+=` ${o}`:l+=` ${o}="${u(String(e[o]))}"`);$.has(n)?t(`<${n}${l}>`):(t(`<${n}${l}>`),s!=null&&c(s,t),t(`</${n}>`))},v=({nodeName:e,fallback:t=e.fallback,...n},s)=>{e.constructor.name=="GeneratorFunction"?x(e,n,s):c(e(n),s)},x=(e,t,n)=>{const s={...e.attrs},l={...e.args};for(const r in t)r.startsWith("attr:")?s[r.slice(5)]=t[r]:r=="key"||r=="skip"||r=="memo"||r=="ref"||r.startsWith("set:")?s[r]=t[r]:l[r]=t[r];const o=new AbortController,b={*[Symbol.iterator](){for(;;)yield this[y]},[a.Context]:Object.create(a.current()?.[a.Context]??null),[y]:l,signal:o.signal,next:m,return:m,throw:r=>{throw r}},f=e.call(b,l),k=a.current();a.current(b);const d=r=>({...s,nodeName:e.is??p.tag,children:r});let i="";try{g(d(f.next().value),r=>i+=r)}catch(r){i="",g(d(f.throw(r).value),S=>i+=S)}finally{f.return(),o.abort(),a.current(k)}n(i)};exports.defaults=p;exports.html=c;exports.render=w;
package/dist/index.cjs DELETED
@@ -1 +0,0 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=require("./context.cjs"),{isArray:x}=Array,{assign:N,create:A}=Object,a=Symbol.for("ajo.key"),g=Symbol.for("ajo.keyed"),C=Symbol.for("ajo.memo"),u=Symbol.for("ajo.cache"),f=Symbol.for("ajo.generator"),o=Symbol.for("ajo.iterator"),S=Symbol.for("ajo.render"),c=Symbol.for("ajo.args"),h=Symbol.for("ajo.controller"),E={tag:"div"},v=(r,t)=>(t&&(r.is=t),r),m=(r,t,e=t.firstChild,n=null)=>{for(p(r,i=>{const s=typeof i=="string"?M(i,e):W(i,t,e);e==null?b(t,s,n):s==e?e=s.nextSibling:s==e.nextSibling?(b(t,e,n),e=s.nextSibling):b(t,s,e)});e!=n;){const i=e.nextSibling;e.nodeType==1&&O(e),t.removeChild(e),e=i}},p=(r,t)=>{if(r==null)return;const e=typeof r;if(e!="boolean")if(e=="string")t(r);else if(e=="number"||e=="bigint")t(String(r));else if(Symbol.iterator in r)for(r of r)p(r,t);else"nodeName"in r?typeof r.nodeName=="function"?T(r,t):t(r):t(String(r))},T=({nodeName:r,...t},e)=>{r.constructor.name=="GeneratorFunction"?e(G(r,t)):p(r(t),e)},G=(r,t)=>{const e={...r.attrs},n={...r.args};for(const i in t)i.startsWith("attr:")?e[i.slice(5)]=t[i]:i=="key"||i=="skip"||i=="memo"||i=="ref"||i.startsWith("set:")?e[i]=t[i]:n[i]=t[i];return{...e,nodeName:r.is??E.tag,[f]:r,[c]:n}},M=(r,t)=>{for(;t&&t.nodeType!=3;)t=t.nextSibling;return t?t.data!=r&&(t.data=r):t=document.createTextNode(r),t},W=(r,t,e)=>{const{nodeName:n,children:i,key:s,skip:k,memo:w,[f]:y,[c]:j}=r;for(s!=null&&(e=(t[g]??=new Map).get(s)??e);e&&(e.localName!=n||e[a]!=null&&e[a]!=s||e[f]&&e[f]!=y);)e=e[a]!=null?null:e.nextElementSibling;return e??=document.createElementNS(r.xmlns??t.namespaceURI,n),s!=null&&t[g].set(e[a]=s,e),(w==null||I(e[C],e[C]=w))&&(B(e[u],e[u]=r,e),k||(y?R(y,j,e):m(i,e))),e},B=(r,t,e)=>{for(const n in{...r,...t})n=="nodeName"||n=="children"||n=="key"||n=="skip"||n=="memo"||r?.[n]===t[n]||(n=="ref"&&typeof t[n]=="function"?t[n](e):n.startsWith("set:")?e[n.slice(4)]=t[n]:t[n]==null||t[n]===!1?e.removeAttribute(n):e.setAttribute(n,t[n]===!0?"":t[n]))},I=(r,t)=>x(r)&&x(t)?r.some((e,n)=>e!==t[n]):r!==t,K=(r,t)=>{let e=t.firstElementChild;for(;e;)if(r(e)&&e.firstElementChild)e=e.firstElementChild;else{for(;e!=t&&!e.nextElementSibling;)e=e.parentNode??t;e=e!=t&&e.nextElementSibling}},b=(r,t,e)=>{if(t.isConnected&&t.contains(document.activeElement)){const n=t.nextSibling;for(;e&&e!=t;){const i=e.nextSibling;r.insertBefore(e,n),e=i}}else r.insertBefore(t,e)},O=r=>{let t=r;for(;t.firstElementChild;)t=t.firstElementChild;for(;;){const{nextElementSibling:e,parentNode:n}=t;if(t[a]!=null&&n?.[g]?.delete(t[a]),typeof t.return=="function"&&t.return(!1),typeof t[u]?.ref=="function"&&t[u].ref(null),t===r)break;if(t=e??n??r,e)for(;t.firstElementChild;)t=t.firstElementChild}},R=(r,t,e)=>{e[f]??=(N(e,q)[l.Context]=A(l.current()?.[l.Context]??null),r),e[c]=t,e[S]()},q={*[Symbol.iterator](){for(;;)yield this[c]},[S](){const r=l.current();l.current(this);try{this[o]||(this.signal=(this[h]=new AbortController).signal,this[o]=this[f].call(this,this[c]));const{value:t,done:e}=this[o].next();m(t,this),e&&this.return()}catch(t){this.throw(t)}finally{l.current(r)}},next(r,t){if(!this.isConnected)return t;try{typeof r=="function"&&(t=r.call(this,this[c]))}catch(e){return this.throw(e)}return l.current()?.contains(this)||this[S](),t},throw(r){for(let t=this;t;t=t.parentNode)if(t[o]?.throw)try{return m(t[o].throw(r).value,t)}catch(e){r=new Error(e?.message??e,{cause:r})}throw r},return(r=!0){r&&K(t=>typeof t.return=="function"?t.return():!0,this);try{this[o]?.return()}catch(t){this.throw(t)}finally{this[o]=null,this[h]?.abort()}}};exports.defaults=E;exports.render=m;exports.stateful=v;
package/dist/jsx.cjs DELETED
@@ -1 +0,0 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=e=>e.children,c=(e,n,...t)=>((n??={}).nodeName=e,!("children"in n)&&t.length&&(n.children=t.length==1?t[0]:t),n);function s(e,n,t){return t!=null&&((n??={}).key=t),c(e,n)}const j=s,l=s;exports.Fragment=i;exports.h=c;exports.jsx=s;exports.jsxDEV=l;exports.jsxs=j;