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+
133import { stringify as commas } from 'comma-separated-tokens'
234import { stringify as spaces } from 'space-separated-tokens'
335import { html , svg , find } from 'property-information'
@@ -13,52 +45,86 @@ var one = zwitch('type', {
1345 unknown
1446} )
1547
48+ /**
49+ * @param {unknown } value
50+ */
1651function invalid ( value ) {
1752 throw new Error ( 'Expected node, not `' + value + '`' )
1853}
1954
55+ /**
56+ * @param {Node } value
57+ */
2058function unknown ( value ) {
2159 throw new Error ( 'Cannot transform node of type `' + value . type + '`' )
2260}
2361
62+ /**
63+ * @param {HastNode } tree
64+ * @param {Space|Options } [options]
65+ */
2466export function toXast ( tree , options ) {
2567 var space = typeof options === 'string' ? options : ( options || { } ) . space
68+ // @ts -ignore types are wrong.
2669 return one ( tree , { schema : space === 'svg' ? svg : html , ns : null } )
2770}
2871
72+ /**
73+ * @param {HastRoot } node
74+ * @param {Context } config
75+ * @returns {XastRoot }
76+ */
2977function root ( node , config ) {
30- return patch ( node , { type : 'root' } , config )
78+ return patch ( node , { type : 'root' , children : all ( node , config ) } )
3179}
3280
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 || '' } )
3587}
3688
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 || '' } )
3995}
4096
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+ } )
52108}
53109
110+ /**
111+ * @param {HastElement } node
112+ * @param {Context } parentConfig
113+ * @returns {XastElement }
114+ */
54115// eslint-disable-next-line complexity
55116function element ( node , parentConfig ) {
56117 var props = node . properties || { }
57118 var schema = parentConfig . schema
119+ /** @type {XastAttributes } */
58120 var attributes = { }
121+ /** @type {Context } */
59122 var config
123+ /** @type {HastPropertyValue } */
60124 var value
125+ /** @type {string } */
61126 var key
127+ /** @type {Info } */
62128 var info
63129
64130 if ( props . xmlns === webNamespaces . html ) {
@@ -81,6 +147,7 @@ function element(node, parentConfig) {
81147 }
82148
83149 for ( key in props ) {
150+ /* c8 ignore next 3 */
84151 if ( ! own . call ( props , key ) ) {
85152 continue
86153 }
@@ -105,7 +172,7 @@ function element(node, parentConfig) {
105172 }
106173 // Accept `array`.
107174 // Most props are space-separated.
108- else if ( typeof value === 'object' && 'length' in value ) {
175+ else if ( Array . isArray ( value ) ) {
109176 value = info . commaSeparated ? commas ( value ) : spaces ( value )
110177 }
111178 // Cast everything else to string.
@@ -116,33 +183,50 @@ function element(node, parentConfig) {
116183 attributes [ info . attribute ] = value
117184 }
118185
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+ } )
120193}
121194
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
124204
125205 if (
126206 config . schema === html &&
127207 origin . type === 'element' &&
128- origin . tagName === 'template'
208+ origin . tagName === 'template' &&
209+ origin . content
129210 ) {
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
141212 }
142213
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 )
145217 }
146218
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+
147231 return node
148232}
0 commit comments