1+ /**
2+ * @typedef {import('hast').Element } Element
3+ * @typedef {import('hast').Root } Root
4+ * @typedef {import('hast').Text } Text
5+ *
6+ * @typedef {import('unist-util-is').AssertPredicate<Element> } AssertElement
7+ * @typedef {import('unist-util-is').AssertPredicate<Text> } AssertText
8+ * @typedef {import('unist-util-is').AssertPredicate<Root> } AssertRoot
9+ *
10+ * @callback CreateElementLike
11+ * @param {string } name
12+ * @param {Object<string, any> } [attributes]
13+ * @param {Array.<string|any> } [children]
14+ * @returns {any }
15+ *
16+ * @typedef Context
17+ * @property {html|svg } schema
18+ * @property {string|null } prefix
19+ * @property {number } key
20+ * @property {boolean } react
21+ * @property {boolean } vue
22+ * @property {boolean } vdom
23+ * @property {boolean } hyperscript
24+ *
25+ * @typedef Options
26+ * @property {string|null } [prefix]
27+ * @property {'html'|'svg' } [space]
28+ */
29+
130import { html , svg , find , hastToReact } from 'property-information'
231import { stringify as spaces } from 'space-separated-tokens'
332import { stringify as commas } from 'comma-separated-tokens'
@@ -7,52 +36,76 @@ import {convert} from 'unist-util-is'
736
837var own = { } . hasOwnProperty
938
39+ /** @type {AssertRoot } */
40+ // @ts -ignore it’s correct.
1041var root = convert ( 'root' )
42+ /** @type {AssertElement } */
43+ // @ts -ignore it’s correct.
1144var element = convert ( 'element' )
45+ /** @type {AssertText } */
46+ // @ts -ignore it’s correct.
1247var text = convert ( 'text' )
1348
14- export function toH ( h , node , options ) {
15- var settings = options || { }
49+ /**
50+ * @template {CreateElementLike} H
51+ * @param {H } h
52+ * @param {Element|Root } tree
53+ * @param {string|boolean|Options } [options]
54+ * @returns {ReturnType<H> }
55+ */
56+ export function toH ( h , tree , options ) {
57+ if ( typeof h !== 'function' ) {
58+ throw new TypeError ( 'h is not a function' )
59+ }
60+
1661 var r = react ( h )
1762 var v = vue ( h )
1863 var vd = vdom ( h )
64+ /** @type {string|boolean } */
1965 var prefix
66+ /** @type {Element } */
67+ var node
2068
21- if ( typeof h !== 'function' ) {
22- throw new TypeError ( 'h is not a function' )
23- }
24-
25- if ( typeof settings === 'string' || typeof settings === 'boolean' ) {
26- prefix = settings
27- settings = { }
69+ if ( typeof options === 'string' || typeof options === 'boolean' ) {
70+ prefix = options
71+ options = { }
2872 } else {
29- prefix = settings . prefix
73+ if ( ! options ) options = { }
74+ prefix = options . prefix
3075 }
3176
32- if ( root ( node ) ) {
77+ if ( root ( tree ) ) {
78+ // @ts -ignore Allow `doctypes` in there, we’ll filter them out later.
3379 node =
34- node . children . length === 1 && element ( node . children [ 0 ] )
35- ? node . children [ 0 ]
80+ tree . children . length === 1 && element ( tree . children [ 0 ] )
81+ ? tree . children [ 0 ]
3682 : {
3783 type : 'element' ,
3884 tagName : 'div' ,
3985 properties : { } ,
40- children : node . children
86+ children : tree . children
4187 }
42- } else if ( ! element ( node ) ) {
88+ } else if ( element ( tree ) ) {
89+ node = tree
90+ } else {
4391 throw new Error (
44- 'Expected root or element, not `' + ( ( node && node . type ) || node ) + '`'
92+ // @ts -ignore runtime.
93+ 'Expected root or element, not `' + ( ( tree && tree . type ) || tree ) + '`'
4594 )
4695 }
4796
4897 return transform ( h , node , {
49- schema : settings . space === 'svg' ? svg : html ,
98+ schema : options . space === 'svg' ? svg : html ,
5099 prefix :
51100 prefix === undefined || prefix === null
52101 ? r || v || vd
53102 ? 'h-'
54103 : null
55- : prefix ,
104+ : typeof prefix === 'string'
105+ ? prefix
106+ : prefix
107+ ? 'h-'
108+ : null ,
56109 key : 0 ,
57110 react : r ,
58111 vue : v ,
@@ -61,15 +114,26 @@ export function toH(h, node, options) {
61114 } )
62115}
63116
64- // Transform a hast node through a hyperscript interface to *anything*!
117+ /**
118+ * Transform a hast node through a hyperscript interface to *anything*!
119+ *
120+ * @template {CreateElementLike} H
121+ * @param {H } h
122+ * @param {Element } node
123+ * @param {Context } ctx
124+ */
65125function transform ( h , node , ctx ) {
66126 var parentSchema = ctx . schema
67127 var schema = parentSchema
68128 var name = node . tagName
129+ /** @type {Object.<string, unknown> } */
69130 var attributes = { }
131+ /** @type {Array.<ReturnType<H>|string> } */
70132 var nodes = [ ]
71133 var index = - 1
134+ /** @type {string } */
72135 var key
136+ /** @type {Element['children'][number] } */
73137 var value
74138
75139 if ( parentSchema . space === 'html' && name . toLowerCase ( ) === 'svg' ) {
@@ -118,9 +182,17 @@ function transform(h, node, ctx) {
118182 : h . call ( node , name , attributes )
119183}
120184
185+ /**
186+ * @param {Object.<string, unknown> } props
187+ * @param {string } prop
188+ * @param {unknown } value
189+ * @param {Context } ctx
190+ * @param {string } name
191+ */
121192// eslint-disable-next-line complexity, max-params
122193function addAttribute ( props , prop , value , ctx , name ) {
123194 var info = find ( ctx . schema , prop )
195+ /** @type {string } */
124196 var subprop
125197
126198 // Ignore nullish and `NaN` values.
@@ -135,7 +207,7 @@ function addAttribute(props, prop, value, ctx, name) {
135207 return
136208 }
137209
138- if ( value && typeof value === 'object' && 'length' in value ) {
210+ if ( Array . isArray ( value ) ) {
139211 // Accept `array`.
140212 // Most props are space-separated.
141213 value = info . commaSeparated ? commas ( value ) : spaces ( value )
@@ -175,32 +247,67 @@ function addAttribute(props, prop, value, ctx, name) {
175247 }
176248}
177249
178- // Check if `h` is `react.createElement`.
250+ /**
251+ * Check if `h` is `react.createElement`.
252+ *
253+ * @param {CreateElementLike } h
254+ * @returns {boolean }
255+ */
179256function react ( h ) {
180- var node = h && h ( 'div' )
257+ /** @type {unknown } */
258+ var node = h ( 'div' )
181259 return Boolean (
182260 node &&
261+ // @ts -ignore Looks like a React node.
183262 ( '_owner' in node || '_store' in node ) &&
263+ // @ts -ignore Looks like a React node.
184264 ( node . key === undefined || node . key === null )
185265 )
186266}
187267
188- // Check if `h` is `hyperscript`.
268+ /**
269+ * Check if `h` is `hyperscript`.
270+ *
271+ * @param {CreateElementLike } h
272+ * @returns {boolean }
273+ */
189274function hyperscript ( h ) {
190- return Boolean ( h && h . context && h . cleanup )
275+ return 'context' in h && ' cleanup' in h
191276}
192277
193- // Check if `h` is `virtual-dom/h`.
278+ /**
279+ * Check if `h` is `virtual-dom/h`.
280+ *
281+ * @param {CreateElementLike } h
282+ * @returns {boolean }
283+ */
194284function vdom ( h ) {
195- return h && h ( 'div' ) . type === 'VirtualNode'
285+ /** @type {unknown } */
286+ var node = h ( 'div' )
287+ // @ts -ignore Looks like a vnode.
288+ return node . type === 'VirtualNode'
196289}
197290
291+ /**
292+ * Check if `h` is Vue.
293+ *
294+ * @param {CreateElementLike } h
295+ * @returns {boolean }
296+ */
198297function vue ( h ) {
199- var node = h && h ( 'div' )
298+ /** @type {unknown } */
299+ var node = h ( 'div' )
300+ // @ts -ignore Looks like a Vue node.
200301 return Boolean ( node && node . context && node . context . _isVue )
201302}
202303
304+ /**
305+ * @param {string } value
306+ * @param {string } tagName
307+ * @returns {Object.<string, string> }
308+ */
203309function parseStyle ( value , tagName ) {
310+ /** @type {Object.<string, string> } */
204311 var result = { }
205312
206313 try {
@@ -213,12 +320,22 @@ function parseStyle(value, tagName) {
213320
214321 return result
215322
323+ /**
324+ * @param {string } name
325+ * @param {string } value
326+ * @returns {void }
327+ */
216328 function iterator ( name , value ) {
217329 if ( name . slice ( 0 , 4 ) === '-ms-' ) name = 'ms-' + name . slice ( 4 )
218330 result [ name . replace ( / - ( [ a - z ] ) / g, styleReplacer ) ] = value
219331 }
220332}
221333
222- function styleReplacer ( $0 , $1 ) {
334+ /**
335+ * @param {string } _
336+ * @param {string } $1
337+ * @returns {string }
338+ */
339+ function styleReplacer ( _ , $1 ) {
223340 return $1 . toUpperCase ( )
224341}
0 commit comments