1
+ /**
2
+ * @typedef {import('unist').Node } Node
3
+ * @typedef {import('hast').Root } HastRoot
4
+ * @typedef {import('hast').DocType } HastDoctype
5
+ * @typedef {import('hast').Element } HastElement
6
+ * @typedef {import('hast').Comment } HastComment
7
+ * @typedef {import('hast').Text } HastText
8
+ * @typedef {import('hast').Properties[string] } HastPropertyValue
9
+ * @typedef {import('property-information').html['property'][string] } Info
10
+ * @typedef {import('xast').Root } BaseXastRoot
11
+ * @typedef {import('xast').Element } XastElement
12
+ * @typedef {import('xast').Text } XastText
13
+ * @typedef {import('xast').Comment } XastComment
14
+ * @typedef {import('xast').Doctype } XastDoctype
15
+ * @typedef {import('xast').Attributes } XastAttributes
16
+ * @typedef {import('xast').RootChildMap } RootChildMap
17
+ * @typedef {HastRoot|HastDoctype|HastElement|HastComment|HastText } HastNode
18
+ * @typedef {BaseXastRoot & {children: Array<XastElement|XastText|XastComment|XastDoctype>} } XastRoot
19
+ * @typedef {XastRoot|XastElement|XastText|XastComment|XastDoctype } XastNode
20
+ *
21
+ * @typedef {'html'|'svg' } Space
22
+ * @typedef Options
23
+ * @property {Space } [space]
24
+ *
25
+ * @typedef {html|svg } Schema
26
+ * @typedef {webNamespaces[Space] } Namespace
27
+ *
28
+ * @typedef Context
29
+ * @property {Schema } schema
30
+ * @property {Namespace } ns
31
+ */
32
+
1
33
import { stringify as commas } from 'comma-separated-tokens'
2
34
import { stringify as spaces } from 'space-separated-tokens'
3
35
import { html , svg , find } from 'property-information'
@@ -13,52 +45,86 @@ var one = zwitch('type', {
13
45
unknown
14
46
} )
15
47
48
+ /**
49
+ * @param {unknown } value
50
+ */
16
51
function invalid ( value ) {
17
52
throw new Error ( 'Expected node, not `' + value + '`' )
18
53
}
19
54
55
+ /**
56
+ * @param {Node } value
57
+ */
20
58
function unknown ( value ) {
21
59
throw new Error ( 'Cannot transform node of type `' + value . type + '`' )
22
60
}
23
61
62
+ /**
63
+ * @param {HastNode } tree
64
+ * @param {Space|Options } [options]
65
+ */
24
66
export function toXast ( tree , options ) {
25
67
var space = typeof options === 'string' ? options : ( options || { } ) . space
68
+ // @ts -ignore types are wrong.
26
69
return one ( tree , { schema : space === 'svg' ? svg : html , ns : null } )
27
70
}
28
71
72
+ /**
73
+ * @param {HastRoot } node
74
+ * @param {Context } config
75
+ * @returns {XastRoot }
76
+ */
29
77
function root ( node , config ) {
30
- return patch ( node , { type : 'root' } , config )
78
+ return patch ( node , { type : 'root' , children : all ( node , config ) } )
31
79
}
32
80
33
- function text ( node , config ) {
34
- return patch ( node , { type : 'text' , value : node . value || '' } , config )
81
+ /**
82
+ * @param {HastText } node
83
+ * @returns {XastText }
84
+ */
85
+ function text ( node ) {
86
+ return patch ( node , { type : 'text' , value : node . value || '' } )
35
87
}
36
88
37
- function comment ( node , config ) {
38
- return patch ( node , { type : 'comment' , value : node . value || '' } , config )
89
+ /**
90
+ * @param {HastComment } node
91
+ * @returns {XastComment }
92
+ */
93
+ function comment ( node ) {
94
+ return patch ( node , { type : 'comment' , value : node . value || '' } )
39
95
}
40
96
41
- function doctype ( node , config ) {
42
- return patch (
43
- node ,
44
- {
45
- type : ' doctype' ,
46
- name : node . name || '' ,
47
- public : node . public ,
48
- system : node . system
49
- } ,
50
- config
51
- )
97
+ /**
98
+ * @param { HastDoctype } node
99
+ * @returns { XastDoctype }
100
+ */
101
+ function doctype ( node ) {
102
+ return patch ( node , {
103
+ type : 'doctype' ,
104
+ name : 'html' ,
105
+ public : undefined ,
106
+ system : undefined
107
+ } )
52
108
}
53
109
110
+ /**
111
+ * @param {HastElement } node
112
+ * @param {Context } parentConfig
113
+ * @returns {XastElement }
114
+ */
54
115
// eslint-disable-next-line complexity
55
116
function element ( node , parentConfig ) {
56
117
var props = node . properties || { }
57
118
var schema = parentConfig . schema
119
+ /** @type {XastAttributes } */
58
120
var attributes = { }
121
+ /** @type {Context } */
59
122
var config
123
+ /** @type {HastPropertyValue } */
60
124
var value
125
+ /** @type {string } */
61
126
var key
127
+ /** @type {Info } */
62
128
var info
63
129
64
130
if ( props . xmlns === webNamespaces . html ) {
@@ -81,6 +147,7 @@ function element(node, parentConfig) {
81
147
}
82
148
83
149
for ( key in props ) {
150
+ /* c8 ignore next 3 */
84
151
if ( ! own . call ( props , key ) ) {
85
152
continue
86
153
}
@@ -105,7 +172,7 @@ function element(node, parentConfig) {
105
172
}
106
173
// Accept `array`.
107
174
// Most props are space-separated.
108
- else if ( typeof value === 'object' && 'length' in value ) {
175
+ else if ( Array . isArray ( value ) ) {
109
176
value = info . commaSeparated ? commas ( value ) : spaces ( value )
110
177
}
111
178
// Cast everything else to string.
@@ -116,33 +183,50 @@ function element(node, parentConfig) {
116
183
attributes [ info . attribute ] = value
117
184
}
118
185
119
- return patch ( node , { type : 'element' , name : node . tagName , attributes} , config )
186
+ // @ts -ignore Assume no `doctypes` in `element.`
187
+ return patch ( node , {
188
+ type : 'element' ,
189
+ name : node . tagName ,
190
+ attributes,
191
+ children : all ( node , config )
192
+ } )
120
193
}
121
194
122
- function patch ( origin , node , config ) {
123
- var index
195
+ /**
196
+ * @param {HastRoot|HastElement } origin
197
+ * @param {Context } config
198
+ * @returns {Array.<XastElement|XastText|XastComment|XastDoctype> }
199
+ */
200
+ function all ( origin , config ) {
201
+ /** @type {Array.<XastElement|XastText|XastComment|XastDoctype> } */
202
+ var result = [ ]
203
+ var index = - 1
124
204
125
205
if (
126
206
config . schema === html &&
127
207
origin . type === 'element' &&
128
- origin . tagName === 'template'
208
+ origin . tagName === 'template' &&
209
+ origin . content
129
210
) {
130
- node . children = root ( origin . content , config ) . children
131
- } else if (
132
- origin . children &&
133
- ( origin . type === 'element' || origin . type === 'root' )
134
- ) {
135
- node . children = [ ]
136
- index = - 1
137
-
138
- while ( ++ index < origin . children . length ) {
139
- node . children [ index ] = one ( origin . children [ index ] , config )
140
- }
211
+ return root ( origin . content , config ) . children
141
212
}
142
213
143
- if ( origin . position ) {
144
- node . position = position ( origin )
214
+ while ( ++ index < origin . children . length ) {
215
+ // @ts -ignore `zwitch` types are wrong.
216
+ result [ index ] = one ( origin . children [ index ] , config )
145
217
}
146
218
219
+ return result
220
+ }
221
+
222
+ /**
223
+ * @template {XastNode} X
224
+ * @param {HastNode } origin
225
+ * @param {X } node
226
+ * @returns {X }
227
+ */
228
+ function patch ( origin , node ) {
229
+ if ( origin . position ) node . position = position ( origin )
230
+
147
231
return node
148
232
}
0 commit comments