ajo 0.1.31 → 0.1.32

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/html.js CHANGED
@@ -1,142 +1,137 @@
1
- import { Context, current } from 'ajo/context'
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 = () => { }
10
-
11
- export const render = h => [...html(h)].join('')
12
-
13
- export const html = function* (h) {
14
-
15
- for (h of walk(h)) {
16
-
17
- if (typeof h == 'string') yield escape(h)
18
-
19
- else yield* element(h)
20
- }
21
- }
22
-
23
- const element = function* ({ nodeName, children, ...h }) {
24
-
25
- let attrs = ''
26
-
27
- for (const key in h) {
28
-
29
- if (key.startsWith('set:') || h[key] == null || h[key] === false) continue
30
-
31
- if (h[key] === true) attrs += ` ${key}`
32
-
33
- else attrs += ` ${key}="${escape(String(h[key]))}"`
34
- }
35
-
36
- if (Void.has(nodeName)) yield `<${nodeName}${attrs}>`
37
-
38
- else {
39
-
40
- yield `<${nodeName}${attrs}>`
41
-
42
- if (children != null) yield* html(children)
43
-
44
- yield `</${nodeName}>`
45
- }
46
- }
47
-
48
- const walk = function* (h) {
49
-
50
- if (h == null) return
51
-
52
- const type = typeof h
53
-
54
- if (type == 'boolean') return
55
-
56
- if (type == 'string') yield h
57
-
58
- else if (type == 'number' || type == 'bigint') yield String(h)
59
-
60
- else if (Symbol.iterator in h) for (h of h) yield* walk(h)
61
-
62
- else if ('nodeName' in h) typeof h.nodeName == 'function' ? yield* run(h) : yield vdom(h)
63
-
64
- else yield String(h)
65
- }
66
-
67
- const run = function* ({ nodeName, fallback = nodeName.fallback, ...h }) {
68
-
69
- if (nodeName.constructor.name == 'GeneratorFunction') yield runGenerator(nodeName, h)
70
-
71
- else yield* walk(nodeName(h))
72
- }
73
-
74
- const runGenerator = (fn, h) => {
75
-
76
- const attrs = { ...fn.attrs }, args = { ...fn.args }
77
-
78
- for (const key in h) {
79
-
80
- if (key.startsWith('attr:')) attrs[key.slice(5)] = h[key]
81
-
82
- else if (key == 'key' || key == 'skip' || key == 'memo' || key == 'ref' || key.startsWith('set:')) attrs[key] = h[key]
83
-
84
- else args[key] = h[key]
85
- }
86
-
87
- const controller = new AbortController()
88
-
89
- const instance = {
90
-
91
- [Context]: Object.create(current()?.[Context] ?? null),
92
-
93
- [Args]: args,
94
-
95
- signal: controller.signal,
96
-
97
- next: noop,
98
-
99
- return: noop,
100
-
101
- throw: value => { throw value }
102
- }
103
-
104
- const iterator = fn.call(instance, args)
105
-
106
- const parent = current()
107
-
108
- current(instance)
109
-
110
- const result = children => ({ ...attrs, nodeName: fn.is ?? 'div', ...vdom({ children }) })
111
-
112
- try {
113
-
114
- return result(iterator.next().value)
115
-
116
- } catch (error) {
117
-
118
- return result(iterator.throw(error).value)
119
-
120
- } finally {
121
-
122
- iterator.return()
123
-
124
- controller.abort()
125
-
126
- current(parent)
127
- }
128
- }
129
-
130
- const vdom = ({ key, skip, memo, ref, ...h }) => {
131
-
132
- if ('children' in h) {
133
-
134
- const children = [...walk(h.children)]
135
-
136
- if (children.length) h.children = children.length == 1 ? children[0] : children
137
-
138
- else delete h.children
139
- }
140
-
141
- return h
142
- }
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 = () => { }
10
+
11
+ export const defaults = { tag: 'div' }
12
+
13
+ export const render = h => {
14
+
15
+ let out = ''
16
+
17
+ html(h, chunk => out += chunk)
18
+
19
+ return out
20
+ }
21
+
22
+ export const html = (h, emit) => {
23
+
24
+ if (h == null) return
25
+
26
+ const type = typeof h
27
+
28
+ if (type == 'boolean') return
29
+
30
+ if (type == 'string') emit(escape(h))
31
+
32
+ else if (type == 'number' || type == 'bigint') emit(escape(String(h)))
33
+
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
+ }
40
+
41
+ const element = (h, emit) => {
42
+
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}>`)
65
+ }
66
+ }
67
+
68
+ const run = ({ nodeName, fallback = nodeName.fallback, ...h }, emit) => {
69
+
70
+ if (nodeName.constructor.name == 'GeneratorFunction') runGenerator(nodeName, h, emit)
71
+
72
+ else html(nodeName(h), emit)
73
+ }
74
+
75
+ const runGenerator = (fn, h, emit) => {
76
+
77
+ const attrs = { ...fn.attrs }, args = { ...fn.args }
78
+
79
+ for (const key in h) {
80
+
81
+ if (key.startsWith('attr:')) attrs[key.slice(5)] = h[key]
82
+
83
+ else if (key == 'key' || key == 'skip' || key == 'memo' || key == 'ref' || key.startsWith('set:')) attrs[key] = h[key]
84
+
85
+ else args[key] = h[key]
86
+ }
87
+
88
+ const controller = new AbortController()
89
+
90
+ const instance = {
91
+
92
+ *[Symbol.iterator]() { while (true) yield this[Args] },
93
+
94
+ [Context]: Object.create(current()?.[Context] ?? null),
95
+
96
+ [Args]: args,
97
+
98
+ signal: controller.signal,
99
+
100
+ next: noop,
101
+
102
+ return: noop,
103
+
104
+ throw: value => { throw value }
105
+ }
106
+
107
+ const iterator = fn.call(instance, args)
108
+
109
+ const parent = current()
110
+
111
+ current(instance)
112
+
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)
126
+
127
+ } finally {
128
+
129
+ iterator.return()
130
+
131
+ controller.abort()
132
+
133
+ current(parent)
134
+ }
135
+
136
+ emit(out)
137
+ }