3
3
const m = require ( 'mithril/hyperscript' )
4
4
const Vnode = require ( 'mithril/render/vnode' )
5
5
6
- const VOID_TAGS = new RegExp ( '^(?:' +
7
- 'area|' +
8
- 'base|' +
9
- 'br|' +
10
- 'col|' +
11
- 'command|' +
12
- 'embed|' +
13
- 'hr|' +
14
- 'img|' +
15
- 'input|' +
16
- 'keygen|' +
17
- 'link|' +
18
- 'meta|' +
19
- 'param|' +
20
- 'source|' +
21
- 'track|' +
22
- 'wbr|' +
23
- '!doctype' +
24
- ')$' , 'i' )
6
+ const VOID_TAGS = new RegExp (
7
+ '^(?:' +
8
+ 'area|' +
9
+ 'base|' +
10
+ 'br|' +
11
+ 'col|' +
12
+ 'command|' +
13
+ 'embed|' +
14
+ 'hr|' +
15
+ 'img|' +
16
+ 'input|' +
17
+ 'keygen|' +
18
+ 'link|' +
19
+ 'meta|' +
20
+ 'param|' +
21
+ 'source|' +
22
+ 'track|' +
23
+ 'wbr|' +
24
+ '!doctype' +
25
+ ')$' ,
26
+ 'i'
27
+ )
25
28
26
29
const hasOwn = { } . hasOwnProperty
27
30
28
- function toStyleKey ( str ) {
31
+ function toStyleKey ( str ) {
29
32
return str
30
33
. replace ( / \W + / g, '-' )
31
34
. replace ( / ( [ a - z \d ] ) ( [ A - Z ] ) / g, '$1-$2' )
32
35
. toLowerCase ( )
33
36
}
34
37
35
- function replaceHtml ( m ) {
38
+ function replaceHtml ( m ) {
36
39
if ( m === '&' ) return '&'
37
40
if ( m === '<' ) return '<'
38
41
return '>'
39
42
}
40
43
41
- function replaceAttribute ( m ) {
44
+ function replaceAttribute ( m ) {
42
45
if ( m === '&' ) return '&'
43
46
if ( m === '<' ) return '<'
44
47
if ( m === '>' ) return '>'
45
48
return '"'
46
49
}
47
50
48
51
const defaults = {
49
- escapeText ( s ) {
52
+ escapeText ( s ) {
50
53
return s . replace ( / [ & < > ] / g, replaceHtml )
51
54
} ,
52
55
53
- escapeAttribute ( s ) {
56
+ escapeAttribute ( s ) {
54
57
return s . replace ( / [ & < > " ] / g, replaceAttribute )
55
- }
58
+ } ,
56
59
}
57
60
58
- function bindOpt ( options , key ) {
61
+ function bindOpt ( options , key ) {
59
62
return options [ key ] ? options [ key ] . bind ( options ) : defaults [ key ]
60
63
}
61
64
62
65
// Using a generator so I can just yield promises that need awaited. Can't just
63
66
// use `async`/`await` since this is used for both sync and async renders. At
64
67
// least I have generators (read: coroutines), or I'd have to implement this
65
68
// using a giant pushdown automaton. :-)
66
- function * tryRender ( view , attrs , options , allowAwait ) {
69
+ function * tryRender ( view , attrs , options , allowAwait ) {
67
70
// Fast-path a very simple case. Also lets me perform some renderer
68
71
// optimizations later.
69
72
if ( view == null ) return ''
@@ -81,14 +84,17 @@ function * tryRender (view, attrs, options, allowAwait) {
81
84
const xml = ! ! options . xml
82
85
const strict = xml || ! ! options . strict
83
86
84
- function write ( value ) {
87
+ function write ( value ) {
85
88
result = '' + result + value
86
89
}
87
90
88
- function * setHooks ( source , vnode ) {
91
+ function * setHooks ( source , vnode ) {
89
92
const promises = [ ]
90
93
let waitFor
91
- if ( allowAwait ) waitFor = p => { promises . push ( p ) }
94
+ if ( allowAwait )
95
+ waitFor = p => {
96
+ promises . push ( p )
97
+ }
92
98
if ( source . oninit ) {
93
99
source . oninit . call ( vnode . state , vnode , waitFor )
94
100
}
@@ -98,7 +104,7 @@ function * tryRender (view, attrs, options, allowAwait) {
98
104
if ( promises . length ) yield promises
99
105
}
100
106
101
- function createAttrString ( view ) {
107
+ function createAttrString ( view ) {
102
108
for ( const key in view . attrs ) {
103
109
if ( hasOwn . call ( view . attrs , key ) ) {
104
110
let value = view . attrs [ key ]
@@ -132,7 +138,7 @@ function * tryRender (view, attrs, options, allowAwait) {
132
138
}
133
139
}
134
140
135
- function * renderComponent ( vnode ) {
141
+ function * renderComponent ( vnode ) {
136
142
if ( typeof vnode . tag !== 'function' ) {
137
143
vnode . state = Object . create ( vnode . tag )
138
144
} else if ( vnode . tag . prototype && vnode . tag . prototype . view ) {
@@ -141,13 +147,13 @@ function * tryRender (view, attrs, options, allowAwait) {
141
147
vnode . state = vnode . tag ( vnode )
142
148
}
143
149
144
- yield * setHooks ( vnode . state , vnode )
145
- if ( vnode . attrs != null ) yield * setHooks ( vnode . attrs , vnode )
150
+ yield * setHooks ( vnode . state , vnode )
151
+ if ( vnode . attrs != null ) yield * setHooks ( vnode . attrs , vnode )
146
152
vnode . instance = Vnode . normalize ( vnode . state . view ( vnode ) )
147
- if ( vnode . instance != null ) yield * renderNode ( vnode . instance )
153
+ if ( vnode . instance != null ) yield * renderNode ( vnode . instance )
148
154
}
149
155
150
- function * renderElement ( vnode ) {
156
+ function * renderElement ( vnode ) {
151
157
write ( `<${ vnode . tag } ` )
152
158
createAttrString ( vnode )
153
159
// Don't write children for void HTML elements
@@ -159,43 +165,51 @@ function * tryRender (view, attrs, options, allowAwait) {
159
165
const text = '' + vnode . text
160
166
if ( text !== '' ) write ( escapeText ( text ) )
161
167
} else {
162
- yield * renderChildren ( vnode . children )
168
+ yield * renderChildren ( vnode . children )
163
169
}
164
170
write ( `</${ vnode . tag } >` )
165
171
}
166
172
}
167
173
168
- function * renderChildren ( vnodes ) {
174
+ function * renderChildren ( vnodes ) {
169
175
for ( const v of vnodes ) {
170
- if ( v != null ) yield * renderNode ( v )
176
+ if ( v != null ) yield * renderNode ( v )
171
177
}
172
178
}
173
179
174
- function * renderNode ( vnode ) {
180
+ function * renderNode ( vnode ) {
175
181
if ( vnode == null ) return
176
182
if ( typeof vnode . tag === 'string' ) {
177
183
vnode . state = { }
178
- if ( vnode . attrs != null ) yield * setHooks ( vnode . attrs , vnode )
184
+ if ( vnode . attrs != null ) yield * setHooks ( vnode . attrs , vnode )
179
185
switch ( vnode . tag ) {
180
- case '#' : write ( escapeText ( '' + vnode . children ) ) ; break
181
- case '<' : write ( vnode . children ) ; break
182
- case '[' : yield * renderChildren ( vnode . children ) ; break
183
- default : yield * renderElement ( vnode )
186
+ case '#' :
187
+ write ( escapeText ( '' + vnode . children ) )
188
+ break
189
+ case '<' :
190
+ write ( vnode . children )
191
+ break
192
+ case '[' :
193
+ yield * renderChildren ( vnode . children )
194
+ break
195
+ default :
196
+ yield * renderElement ( vnode )
184
197
}
185
198
} else {
186
- yield * renderComponent ( vnode )
199
+ yield * renderComponent ( vnode )
187
200
}
188
201
}
189
202
190
- yield * renderNode ( Vnode . normalize ( view ) )
203
+ yield * renderNode ( Vnode . normalize ( view ) )
191
204
for ( const hook of hooks ) hook ( )
192
205
return result . concat ( ) // hint to flatten
193
206
}
194
207
195
208
module . exports = async ( view , attrs , options ) => {
196
209
const iter = tryRender ( view , attrs , options , true )
210
+ // eslint-disable-next-line no-constant-condition
197
211
while ( true ) {
198
- const { done, value} = iter . next ( )
212
+ const { done, value } = iter . next ( )
199
213
if ( done ) return value
200
214
await Promise . all ( value )
201
215
}
0 commit comments