1
1
'use strict'
2
2
3
3
var trim = require ( 'trim' )
4
- var paramCase = require ( 'kebab-case' )
5
- var information = require ( 'property-information' )
4
+ var html = require ( 'property-information/html' )
5
+ var svg = require ( 'property-information/svg' )
6
+ var find = require ( 'property-information/find' )
6
7
var spaces = require ( 'space-separated-tokens' )
7
8
var commas = require ( 'comma-separated-tokens' )
8
9
var nan = require ( 'is-nan' )
10
+ var ns = require ( 'web-namespaces' )
9
11
var is = require ( 'unist-util-is' )
10
12
13
+ var dashes = / - ( [ a - z ] ) / g
14
+
11
15
module . exports = wrapper
12
16
13
- function wrapper ( h , node , prefix ) {
17
+ function wrapper ( h , node , options ) {
18
+ var settings = options || { }
19
+ var prefix
14
20
var r
15
21
var v
16
22
17
23
if ( typeof h !== 'function' ) {
18
24
throw new Error ( 'h is not a function' )
19
25
}
20
26
27
+ if ( typeof settings === 'string' || typeof settings === 'boolean' ) {
28
+ prefix = settings
29
+ settings = { }
30
+ } else {
31
+ prefix = settings . prefix
32
+ }
33
+
21
34
r = react ( h )
22
35
v = vdom ( h )
23
36
@@ -43,6 +56,7 @@ function wrapper(h, node, prefix) {
43
56
}
44
57
45
58
return toH ( h , node , {
59
+ schema : settings . space === 'svg' ? svg : html ,
46
60
prefix : prefix ,
47
61
key : 0 ,
48
62
react : r ,
@@ -51,10 +65,12 @@ function wrapper(h, node, prefix) {
51
65
} )
52
66
}
53
67
54
- /* Transform a HAST node through a hyperscript interface
55
- * to *anything*! */
68
+ // Transform a HAST node through a hyperscript interface
69
+ // to *anything*!
56
70
function toH ( h , node , ctx ) {
57
- var selector = node . tagName
71
+ var parentSchema = ctx . schema
72
+ var schema = parentSchema
73
+ var name = node . tagName
58
74
var properties
59
75
var attributes
60
76
var children
@@ -63,53 +79,44 @@ function toH(h, node, ctx) {
63
79
var length
64
80
var index
65
81
var value
82
+ var result
66
83
67
- properties = node . properties
68
- attributes = { }
69
-
70
- for ( property in properties ) {
71
- addAttribute ( attributes , property , properties [ property ] , ctx )
84
+ if ( parentSchema . space === 'html' && lower ( name ) === 'svg' ) {
85
+ schema = svg
86
+ ctx . schema = schema
72
87
}
73
88
74
- if ( ctx . vdom === true ) {
75
- selector = selector . toUpperCase ( )
89
+ if ( ctx . vdom === true && schema . space === 'html' ) {
90
+ name = upper ( name )
76
91
}
77
92
78
- if ( ctx . hyperscript === true && attributes . id ) {
79
- selector += '#' + attributes . id
80
- delete attributes . id
81
- }
93
+ properties = node . properties
94
+ attributes = { }
82
95
83
- if ( ( ctx . hyperscript === true || ctx . vdom === true ) && attributes . className ) {
84
- selector += '.' + spaces . parse ( attributes . className ) . join ( '.' )
85
- delete attributes . className
96
+ for ( property in properties ) {
97
+ addAttribute ( attributes , property , properties [ property ] , ctx )
86
98
}
87
99
88
- if ( typeof attributes . style === 'string' ) {
89
- /* VDOM expects a `string` style in `attributes`
90
- * See https://github.com/Matt-Esch/virtual-dom/blob/947ecf9/
91
- * docs/vnode.md#propertiesstyle-vs-propertiesattributesstyle */
92
- if ( ctx . vdom === true ) {
93
- if ( ! attributes . attributes ) {
94
- attributes . attributes = { }
95
- }
96
-
97
- attributes . attributes . style = attributes . style
98
- delete attributes . style
99
- /* React only accepts `style` as object. */
100
- } else if ( ctx . react === true ) {
101
- attributes . style = parseStyle ( attributes . style )
102
- }
100
+ if (
101
+ typeof attributes . style === 'string' &&
102
+ ( ctx . vdom === true || ctx . react === true )
103
+ ) {
104
+ // VDOM and React accept `style` as object.
105
+ attributes . style = parseStyle ( attributes . style )
103
106
}
104
107
105
108
if ( ctx . prefix ) {
106
109
ctx . key ++
107
110
attributes . key = ctx . prefix + ctx . key
108
111
}
109
112
113
+ if ( ctx . vdom && schema . space !== 'html' ) {
114
+ attributes . namespace = ns [ schema . space ]
115
+ }
116
+
110
117
elements = [ ]
111
- children = node . children || [ ]
112
- length = children . length
118
+ children = node . children
119
+ length = children ? children . length : 0
113
120
index = - 1
114
121
115
122
while ( ++ index < length ) {
@@ -122,20 +129,23 @@ function toH(h, node, ctx) {
122
129
}
123
130
}
124
131
125
- /* Ensure no React warnings are triggered for
126
- * void elements having children passed in. */
127
- return elements . length === 0
128
- ? h ( selector , attributes )
129
- : h ( selector , attributes , elements )
132
+ // Ensure no React warnings are triggered for
133
+ // void elements having children passed in.
134
+ result =
135
+ elements . length === 0 ? h ( name , attributes ) : h ( name , attributes , elements )
136
+
137
+ // Restore parent schema.
138
+ ctx . schema = parentSchema
139
+
140
+ return result
130
141
}
131
142
132
- /* Add `name` and its ` value` to `props`. */
133
- function addAttribute ( props , name , value , ctx ) {
134
- var info = information ( name ) || { }
143
+ function addAttribute ( props , prop , value , ctx ) {
144
+ var schema = ctx . schema
145
+ var info = find ( schema , prop )
135
146
var subprop
136
147
137
- /* Ignore nully, `false`, `NaN`, and falsey known
138
- * booleans. */
148
+ // Ignore nully, `false`, `NaN`, and falsey known booleans.
139
149
if (
140
150
value === null ||
141
151
value === undefined ||
@@ -146,73 +156,51 @@ function addAttribute(props, name, value, ctx) {
146
156
return
147
157
}
148
158
149
- if ( info . name ) {
150
- name = info . name
151
- } else if ( ctx . react && ! paramCasedReactProp ( name ) ) {
152
- name = camelCase ( name )
153
- } else {
154
- name = paramCase ( name )
155
- }
156
-
157
159
if ( value !== null && typeof value === 'object' && 'length' in value ) {
158
- /* Accept `array`. Most props are space-separater. */
160
+ // Accept `array`. Most props are space-separater.
159
161
value = ( info . commaSeparated ? commas : spaces ) . stringify ( value )
160
162
}
161
163
162
- /* Treat `true` and truthy known booleans. */
164
+ // Treat `true` and truthy known booleans.
163
165
if ( info . boolean && ctx . hyperscript === true ) {
164
166
value = ''
165
167
}
166
168
167
- if ( info . name !== 'class' && ( info . mustUseAttribute || ! info . name ) ) {
169
+ if ( ! info . mustUseProperty ) {
168
170
if ( ctx . vdom === true ) {
169
171
subprop = 'attributes'
170
172
} else if ( ctx . hyperscript === true ) {
171
173
subprop = 'attrs'
172
174
}
175
+ }
173
176
174
- if ( subprop ) {
175
- if ( props [ subprop ] === undefined ) {
176
- props [ subprop ] = { }
177
- }
178
-
179
- props [ subprop ] [ name ] = value
180
-
181
- return
177
+ if ( subprop ) {
178
+ if ( props [ subprop ] === undefined ) {
179
+ props [ subprop ] = { }
182
180
}
183
- }
184
181
185
- props [ info . propertyName || name ] = value
182
+ props [ subprop ] [ info . attribute ] = value
183
+ } else {
184
+ props [ ctx . react && info . space ? info . property : info . attribute ] = value
185
+ }
186
186
}
187
187
188
- /* Check if `h` is `react.createElement`. It doesn’t accept
189
- * `class` as an attribute, it must be added through the
190
- * `selector`. */
188
+ // Check if `h` is `react.createElement`.
191
189
function react ( h ) {
192
190
var node = h && h ( 'div' )
193
191
return Boolean (
194
192
node && ( '_owner' in node || '_store' in node ) && node . key === null
195
193
)
196
194
}
197
195
198
- /* Check if `h` is `hyperscript`. It doesn’t accept
199
- * `class` as an attribute, it must be added through the
200
- * `selector`. */
196
+ // Check if `h` is `hyperscript`.
201
197
function hyperscript ( h ) {
202
198
return Boolean ( h && h . context && h . cleanup )
203
199
}
204
200
205
- /* Check if `h` is `virtual-dom/h`. It’s the only
206
- * hyperscript “compatible” interface needing `attributes`. */
201
+ // Check if `h` is `virtual-dom/h`.
207
202
function vdom ( h ) {
208
- try {
209
- return h ( 'div' ) . type === 'VirtualNode'
210
- } catch ( err ) {
211
- /* Empty */
212
- }
213
-
214
- /* istanbul ignore next */
215
- return false
203
+ return h && h ( 'div' ) . type === 'VirtualNode'
216
204
}
217
205
218
206
function parseStyle ( value ) {
@@ -228,27 +216,30 @@ function parseStyle(value) {
228
216
declaration = declarations [ index ]
229
217
pos = declaration . indexOf ( ':' )
230
218
if ( pos !== - 1 ) {
231
- prop = camelCase ( trim ( declaration . slice ( 0 , pos ) ) )
219
+ prop = styleCase ( trim ( declaration . slice ( 0 , pos ) ) )
232
220
result [ prop ] = trim ( declaration . slice ( pos + 1 ) )
233
221
}
234
222
}
235
223
236
224
return result
237
225
}
238
226
239
- function paramCasedReactProp ( name ) {
240
- var head = name . slice ( 0 , 4 )
241
- return ( head === 'data' || head === 'aria' ) && name . length > 4
242
- }
243
-
244
- function camelCase ( val ) {
227
+ function styleCase ( val ) {
245
228
if ( val . slice ( 0 , 4 ) === '-ms-' ) {
246
229
val = 'ms-' + val . slice ( 4 )
247
230
}
248
231
249
- return val . replace ( / - ( [ a - z ] ) / g, replace )
232
+ return val . replace ( dashes , styleReplacer )
233
+ }
234
+
235
+ function styleReplacer ( $0 , $1 ) {
236
+ return upper ( $1 )
237
+ }
238
+
239
+ function lower ( value ) {
240
+ return value . toLowerCase ( )
250
241
}
251
242
252
- function replace ( $0 , $1 ) {
253
- return $1 . toUpperCase ( )
243
+ function upper ( value ) {
244
+ return value . toUpperCase ( )
254
245
}
0 commit comments