Skip to content

Commit 6b2e753

Browse files
committed
Refactor to move core to lib/
1 parent 099ea89 commit 6b2e753

File tree

4 files changed

+240
-233
lines changed

4 files changed

+240
-233
lines changed

index.js

Lines changed: 3 additions & 231 deletions
Original file line numberDiff line numberDiff line change
@@ -1,234 +1,6 @@
11
/**
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').Info} Info
10-
* @typedef {import('property-information').Schema} Schema
11-
* @typedef {import('xast').Root} BaseXastRoot
12-
* @typedef {import('xast').Element} XastElement
13-
* @typedef {import('xast').Text} XastText
14-
* @typedef {import('xast').Comment} XastComment
15-
* @typedef {import('xast').Doctype} XastDoctype
16-
* @typedef {import('xast').Attributes} XastAttributes
17-
* @typedef {import('xast').RootChildMap} RootChildMap
18-
* @typedef {HastRoot|HastDoctype|HastElement|HastComment|HastText} HastNode
19-
* @typedef {BaseXastRoot & {children: Array<XastElement|XastText|XastComment|XastDoctype>}} XastRoot
20-
* @typedef {XastRoot|XastElement|XastText|XastComment|XastDoctype} XastNode
21-
*
22-
* @typedef {'html'|'svg'} Space
23-
* @typedef Options
24-
* @property {Space} [space]
25-
*
26-
* @typedef {webNamespaces[Space]} Namespace
27-
*
28-
* @typedef Context
29-
* @property {Schema} schema
30-
* @property {Namespace} ns
2+
* @typedef {import('./lib/index.js').Space} Space
3+
* @typedef {import('./lib/index.js').Options} Options
314
*/
325

33-
import {stringify as commas} from 'comma-separated-tokens'
34-
import {stringify as spaces} from 'space-separated-tokens'
35-
import {html, svg, find} from 'property-information'
36-
import {position} from 'unist-util-position'
37-
import {webNamespaces} from 'web-namespaces'
38-
import {zwitch} from 'zwitch'
39-
40-
const ns = /** @type {Record<string, string>} */ (webNamespaces)
41-
42-
const own = {}.hasOwnProperty
43-
44-
const one = zwitch('type', {
45-
// @ts-expect-error: hush.
46-
handlers: {root, element, text, comment, doctype},
47-
invalid,
48-
// @ts-expect-error: hush.
49-
unknown
50-
})
51-
52-
/**
53-
* @param {unknown} value
54-
*/
55-
function invalid(value) {
56-
throw new Error('Expected node, not `' + value + '`')
57-
}
58-
59-
/**
60-
* @param {Node} value
61-
*/
62-
function unknown(value) {
63-
throw new Error('Cannot transform node of type `' + value.type + '`')
64-
}
65-
66-
/**
67-
* @param {HastNode} tree
68-
* @param {Space|Options} [options]
69-
*/
70-
export function toXast(tree, options) {
71-
const space = typeof options === 'string' ? options : (options || {}).space
72-
return one(tree, {schema: space === 'svg' ? svg : html, ns: null})
73-
}
74-
75-
/**
76-
* @param {HastRoot} node
77-
* @param {Context} config
78-
* @returns {XastRoot}
79-
*/
80-
function root(node, config) {
81-
return patch(node, {type: 'root', children: all(node, config)})
82-
}
83-
84-
/**
85-
* @param {HastText} node
86-
* @returns {XastText}
87-
*/
88-
function text(node) {
89-
return patch(node, {type: 'text', value: node.value || ''})
90-
}
91-
92-
/**
93-
* @param {HastComment} node
94-
* @returns {XastComment}
95-
*/
96-
function comment(node) {
97-
return patch(node, {type: 'comment', value: node.value || ''})
98-
}
99-
100-
/**
101-
* @param {HastDoctype} node
102-
* @returns {XastDoctype}
103-
*/
104-
function doctype(node) {
105-
return patch(node, {
106-
type: 'doctype',
107-
name: 'html',
108-
public: undefined,
109-
system: undefined
110-
})
111-
}
112-
113-
/**
114-
* @param {HastElement} node
115-
* @param {Context} parentConfig
116-
* @returns {XastElement}
117-
*/
118-
// eslint-disable-next-line complexity
119-
function element(node, parentConfig) {
120-
const props = node.properties || {}
121-
let schema = parentConfig.schema
122-
/** @type {XastAttributes} */
123-
const attributes = {}
124-
/** @type {HastPropertyValue} */
125-
let value
126-
/** @type {string} */
127-
let key
128-
/** @type {Info} */
129-
let info
130-
131-
if (props.xmlns === webNamespaces.html) {
132-
schema = html
133-
} else if (props.xmlns === webNamespaces.svg) {
134-
schema = svg
135-
} else if (props.xmlns) {
136-
// We don’t support non-HTML, non-SVG namespaces, so stay in the same.
137-
} else if (schema === html && node.tagName === 'svg') {
138-
schema = svg
139-
}
140-
141-
/** @type {Context} */
142-
// @ts-expect-error: `schema.space` is set because html, svg have it set.
143-
const config = Object.assign({}, parentConfig, {schema, ns: ns[schema.space]})
144-
145-
if (parentConfig.ns !== config.ns) {
146-
attributes.xmlns = config.ns
147-
}
148-
149-
for (key in props) {
150-
/* c8 ignore next 3 */
151-
if (!own.call(props, key)) {
152-
continue
153-
}
154-
155-
info = find(schema, key)
156-
value = props[key]
157-
158-
// Ignore nullish, false, and `NaN` values, and falsey known booleans.
159-
if (
160-
value === undefined ||
161-
value === null ||
162-
value === false ||
163-
(typeof value === 'number' && Number.isNaN(value)) ||
164-
(!value && info.boolean)
165-
) {
166-
continue
167-
}
168-
169-
// Treat `true` and truthy known booleans.
170-
if (value === true || info.boolean) {
171-
value = ''
172-
}
173-
// Accept `array`.
174-
// Most props are space-separated.
175-
else if (Array.isArray(value)) {
176-
value = info.commaSeparated ? commas(value) : spaces(value)
177-
}
178-
// Cast everything else to string.
179-
else if (typeof value !== 'string') {
180-
value = String(value)
181-
}
182-
183-
attributes[info.attribute] = value
184-
}
185-
186-
return patch(
187-
node,
188-
/** @type {XastElement} */ ({
189-
type: 'element',
190-
name: node.tagName,
191-
attributes,
192-
children: all(node, config)
193-
})
194-
)
195-
}
196-
197-
/**
198-
* @param {HastRoot|HastElement} origin
199-
* @param {Context} config
200-
* @returns {Array<XastElement|XastText|XastComment|XastDoctype>}
201-
*/
202-
function all(origin, config) {
203-
/** @type {Array<XastElement|XastText|XastComment|XastDoctype>} */
204-
const result = []
205-
let index = -1
206-
207-
if (
208-
config.schema === html &&
209-
origin.type === 'element' &&
210-
origin.tagName === 'template' &&
211-
origin.content
212-
) {
213-
return root(origin.content, config).children
214-
}
215-
216-
while (++index < origin.children.length) {
217-
// @ts-expect-error `zwitch` types are wrong.
218-
result[index] = one(origin.children[index], config)
219-
}
220-
221-
return result
222-
}
223-
224-
/**
225-
* @template {XastNode} X
226-
* @param {HastNode} origin
227-
* @param {X} node
228-
* @returns {X}
229-
*/
230-
function patch(origin, node) {
231-
if (origin.position) node.position = position(origin)
232-
233-
return node
234-
}
6+
export {toXast} from './lib/index.js'

0 commit comments

Comments
 (0)