1
1
/**
2
+ * @typedef {import('property-information').Schema } Schema
3
+ * @typedef {import('hast').Content } Content
2
4
* @typedef {import('hast').Element } Element
3
5
* @typedef {import('hast').Root } Root
4
- * @typedef {import('hast').Text } Text
5
- * @typedef {import('hast').Root|import('hast').Content } Node
6
+ */
7
+
8
+ /**
9
+ * @typedef {Root | Content } Node
6
10
*
7
11
* @callback CreateElementLike
12
+ * Function that works somewhat like `React.createElement`.
8
13
* @param {string } name
14
+ * Element name.
9
15
* @param {any } attributes
16
+ * Properties.
10
17
* @param {Array<any> } [children]
18
+ * Children.
11
19
* @returns {any }
20
+ * Something.
12
21
*
13
- * @typedef Context
14
- * @property {html|svg } schema
15
- * @property {string|null } prefix
22
+ * @typedef State
23
+ * Info passed around.
24
+ * @property {Schema } schema
25
+ * Current schema.
26
+ * @property {string | undefined } prefix
27
+ * Prefix to use.
16
28
* @property {number } key
29
+ * Current key.
17
30
* @property {boolean } react
31
+ * Looks like React.
18
32
* @property {boolean } vue
33
+ * Looks like Vue.
19
34
* @property {boolean } vdom
35
+ * Looks like vdom.
20
36
* @property {boolean } hyperscript
37
+ * Looks like `hyperscript`.
21
38
*
22
39
* @typedef Options
23
- * Configuration (optional) .
24
- * @property {string| null } [prefix]
40
+ * Configuration.
41
+ * @property {string | null | undefined } [prefix]
25
42
* Prefix to use as a prefix for keys passed in `props` to `h()`, this
26
43
* behavior is turned off by passing `false` and turned on by passing a
27
44
* `string`.
28
45
* By default, `h-` is used as a prefix if the given `h` is detected as being
29
46
* `virtual-dom/h` or `React.createElement`
30
- * @property {'html'| 'svg' } [space]
47
+ * @property {'html' | 'svg' | null | undefined } [space]
31
48
* Whether `node` is in the `'html'` or `'svg'` space.
32
49
* If an `<svg>` element is found when inside the HTML space, `toH`
33
50
* automatically switches to the SVG space when entering the element, and
@@ -44,19 +61,19 @@ import {webNamespaces} from 'web-namespaces'
44
61
/** @type {(value: string, replacer: ((key: string, value: string) => void)) => void } */
45
62
const style = styleToObject
46
63
47
- const toReact = /** @type {Record<string, string> } */ ( hastToReact )
48
-
49
64
const own = { } . hasOwnProperty
50
65
51
66
/**
52
67
* @template {CreateElementLike} H
68
+ * Type of hyperscript function.
53
69
* @param {H } h
54
70
* HyperScript function.
55
71
* @param {Node } tree
56
72
* Tree to transform.
57
- * @param {string| boolean| Options } [options]
73
+ * @param {string | boolean | Options | null | undefined } [options]
58
74
* Configuration (optional).
59
75
* @returns {ReturnType<H> }
76
+ * Return type of the hyperscript function.
60
77
*/
61
78
// eslint-disable-next-line complexity
62
79
export function toH ( h , tree , options ) {
@@ -106,12 +123,12 @@ export function toH(h, tree, options) {
106
123
prefix === undefined || prefix === null
107
124
? r || v || vd
108
125
? 'h-'
109
- : null
126
+ : undefined
110
127
: typeof prefix === 'string'
111
128
? prefix
112
129
: prefix
113
130
? 'h-'
114
- : null ,
131
+ : undefined ,
115
132
key : 0 ,
116
133
react : r ,
117
134
vue : v ,
@@ -124,12 +141,18 @@ export function toH(h, tree, options) {
124
141
* Transform a hast node through a hyperscript interface to *anything*!
125
142
*
126
143
* @template {CreateElementLike} H
144
+ * Type of hyperscript function.
127
145
* @param {H } h
146
+ * HyperScript function.
128
147
* @param {Element } node
129
- * @param {Context } ctx
148
+ * Node to transform.
149
+ * @param {State } state
150
+ * Info passed around.
151
+ * @returns {ReturnType<H> }
152
+ * Return type of the hyperscript function.
130
153
*/
131
- function transform ( h , node , ctx ) {
132
- const parentSchema = ctx . schema
154
+ function transform ( h , node , state ) {
155
+ const parentSchema = state . schema
133
156
let schema = parentSchema
134
157
let name = node . tagName
135
158
/** @type {Record<string, unknown> } */
@@ -142,42 +165,42 @@ function transform(h, node, ctx) {
142
165
143
166
if ( parentSchema . space === 'html' && name . toLowerCase ( ) === 'svg' ) {
144
167
schema = svg
145
- ctx . schema = schema
168
+ state . schema = schema
146
169
}
147
170
148
171
for ( key in node . properties ) {
149
172
if ( node . properties && own . call ( node . properties , key ) ) {
150
- addAttribute ( attributes , key , node . properties [ key ] , ctx , name )
173
+ addAttribute ( attributes , key , node . properties [ key ] , state , name )
151
174
}
152
175
}
153
176
154
- if ( ctx . vdom ) {
177
+ if ( state . vdom ) {
155
178
if ( schema . space === 'html' ) {
156
179
name = name . toUpperCase ( )
157
180
} else if ( schema . space ) {
158
181
attributes . namespace = webNamespaces [ schema . space ]
159
182
}
160
183
}
161
184
162
- if ( ctx . prefix ) {
163
- ctx . key ++
164
- attributes . key = ctx . prefix + ctx . key
185
+ if ( state . prefix ) {
186
+ state . key ++
187
+ attributes . key = state . prefix + state . key
165
188
}
166
189
167
190
if ( node . children ) {
168
191
while ( ++ index < node . children . length ) {
169
192
const value = node . children [ index ]
170
193
171
194
if ( value . type === 'element' ) {
172
- nodes . push ( transform ( h , value , ctx ) )
195
+ nodes . push ( transform ( h , value , state ) )
173
196
} else if ( value . type === 'text' ) {
174
197
nodes . push ( value . value )
175
198
}
176
199
}
177
200
}
178
201
179
202
// Restore parent schema.
180
- ctx . schema = parentSchema
203
+ state . schema = parentSchema
181
204
182
205
// Ensure no React warnings are triggered for void elements having children
183
206
// passed in.
@@ -187,16 +210,25 @@ function transform(h, node, ctx) {
187
210
}
188
211
189
212
/**
213
+ * Add an attribute to `props`.
214
+ *
190
215
* @param {Record<string, unknown> } props
216
+ * Map.
191
217
* @param {string } prop
218
+ * Key.
192
219
* @param {unknown } value
193
- * @param {Context } ctx
220
+ * Value.
221
+ * @param {State } state
222
+ * Info passed around.
194
223
* @param {string } name
224
+ * Element name.
225
+ * @returns {void }
226
+ * Nothing.
195
227
*/
196
228
// eslint-disable-next-line complexity, max-params
197
- function addAttribute ( props , prop , value , ctx , name ) {
198
- const info = find ( ctx . schema , prop )
199
- /** @type {string| undefined } */
229
+ function addAttribute ( props , prop , value , state , name ) {
230
+ const info = find ( state . schema , prop )
231
+ /** @type {string | undefined } */
200
232
let subprop
201
233
202
234
// Ignore nullish and `NaN` values.
@@ -205,8 +237,8 @@ function addAttribute(props, prop, value, ctx, name) {
205
237
value === undefined ||
206
238
value === null ||
207
239
( typeof value === 'number' && Number . isNaN ( value ) ) ||
208
- ( value === false && ( ctx . vue || ctx . vdom || ctx . hyperscript ) ) ||
209
- ( ! value && info . boolean && ( ctx . vue || ctx . vdom || ctx . hyperscript ) )
240
+ ( value === false && ( state . vue || state . vdom || state . hyperscript ) ) ||
241
+ ( ! value && info . boolean && ( state . vue || state . vdom || state . hyperscript ) )
210
242
) {
211
243
return
212
244
}
@@ -218,28 +250,28 @@ function addAttribute(props, prop, value, ctx, name) {
218
250
}
219
251
220
252
// Treat `true` and truthy known booleans.
221
- if ( info . boolean && ctx . hyperscript ) {
253
+ if ( info . boolean && state . hyperscript ) {
222
254
value = ''
223
255
}
224
256
225
257
// VDOM, Vue, and React accept `style` as object.
226
258
if (
227
259
info . property === 'style' &&
228
260
typeof value === 'string' &&
229
- ( ctx . react || ctx . vue || ctx . vdom )
261
+ ( state . react || state . vue || state . vdom )
230
262
) {
231
263
value = parseStyle ( value , name )
232
264
}
233
265
234
266
// Vue 3 (used in our tests) doesn’t need this anymore.
235
267
// Some major in the future we can drop Vue 2 support.
236
268
/* c8 ignore next 2 */
237
- if ( ctx . vue ) {
269
+ if ( state . vue ) {
238
270
if ( info . property !== 'style' ) subprop = 'attrs'
239
271
} else if ( ! info . mustUseProperty ) {
240
- if ( ctx . vdom ) {
272
+ if ( state . vdom ) {
241
273
if ( info . property !== 'style' ) subprop = 'attributes'
242
- } else if ( ctx . hyperscript ) {
274
+ } else if ( state . hyperscript ) {
243
275
subprop = 'attrs'
244
276
}
245
277
}
@@ -248,8 +280,8 @@ function addAttribute(props, prop, value, ctx, name) {
248
280
props [ subprop ] = Object . assign ( props [ subprop ] || { } , {
249
281
[ info . attribute ] : value
250
282
} )
251
- } else if ( info . space && ctx . react ) {
252
- props [ toReact [ info . property ] || info . property ] = value
283
+ } else if ( info . space && state . react ) {
284
+ props [ hastToReact [ info . property ] || info . property ] = value
253
285
} else {
254
286
props [ info . attribute ] = value
255
287
}
@@ -259,7 +291,9 @@ function addAttribute(props, prop, value, ctx, name) {
259
291
* Check if `h` is `react.createElement`.
260
292
*
261
293
* @param {CreateElementLike } h
294
+ * HyperScript function.
262
295
* @returns {boolean }
296
+ * Looks like React.
263
297
*/
264
298
function react ( h ) {
265
299
const node = /** @type {unknown } */ ( h ( 'div' , { } ) )
@@ -276,7 +310,9 @@ function react(h) {
276
310
* Check if `h` is `hyperscript`.
277
311
*
278
312
* @param {CreateElementLike } h
313
+ * HyperScript function.
279
314
* @returns {boolean }
315
+ * Looks like `hyperscript`.
280
316
*/
281
317
function hyperscript ( h ) {
282
318
return 'context' in h && 'cleanup' in h
@@ -286,7 +322,9 @@ function hyperscript(h) {
286
322
* Check if `h` is `virtual-dom/h`.
287
323
*
288
324
* @param {CreateElementLike } h
325
+ * HyperScript function.
289
326
* @returns {boolean }
327
+ * Looks like `virtual-dom`
290
328
*/
291
329
function vdom ( h ) {
292
330
const node = /** @type {unknown } */ ( h ( 'div' , { } ) )
@@ -298,7 +336,9 @@ function vdom(h) {
298
336
* Check if `h` is Vue.
299
337
*
300
338
* @param {CreateElementLike } h
339
+ * HyperScript function.
301
340
* @returns {boolean }
341
+ * Looks like Vue.
302
342
*/
303
343
function vue ( h ) {
304
344
// Vue 3 (used in our tests) doesn’t need this anymore.
@@ -310,9 +350,14 @@ function vue(h) {
310
350
}
311
351
312
352
/**
353
+ * Parse a declaration into an object.
354
+ *
313
355
* @param {string } value
356
+ * CSS declarations.
314
357
* @param {string } tagName
358
+ * Tag name.
315
359
* @returns {Record<string, string> }
360
+ * Properties.
316
361
*/
317
362
function parseStyle ( value , tagName ) {
318
363
/** @type {Record<string, string> } */
0 commit comments