|
1 | 1 | /**
|
2 |
| - * @typedef {import('hast').Root} Root |
3 |
| - * @typedef {import('hast').Content} Content |
4 | 2 | * @typedef {import('hast').Element} Element
|
| 3 | + * @typedef {import('hast').Nodes} Nodes |
5 | 4 | * @typedef {import('hast').Properties} Properties
|
| 5 | + * @typedef {import('hast').Root} Root |
| 6 | + * @typedef {import('hast').RootContent} RootContent |
| 7 | + * |
6 | 8 | * @typedef {import('property-information').Info} Info
|
7 | 9 | * @typedef {import('property-information').Schema} Schema
|
8 | 10 | */
|
9 | 11 |
|
10 | 12 | /**
|
11 |
| - * @typedef {Content | Root} Node |
12 |
| - * Any concrete `hast` node. |
13 |
| - * @typedef {Root | Element} HResult |
| 13 | + * @typedef {Element | Root} HResult |
14 | 14 | * Result from a `h` (or `s`) call.
|
15 | 15 | *
|
16 |
| - * @typedef {string | number} HStyleValue |
| 16 | + * @typedef {number | string} HStyleValue |
17 | 17 | * Value for a CSS style field.
|
18 | 18 | * @typedef {Record<string, HStyleValue>} HStyle
|
19 | 19 | * Supported value of a `style` prop.
|
20 |
| - * @typedef {string | number | boolean | null | undefined} HPrimitiveValue |
| 20 | + * @typedef {boolean | number | string | null | undefined} HPrimitiveValue |
21 | 21 | * Primitive property value.
|
22 |
| - * @typedef {Array<string | number>} HArrayValue |
| 22 | + * @typedef {Array<number | string>} HArrayValue |
23 | 23 | * List of property values for space- or comma separated values (such as `className`).
|
24 |
| - * @typedef {HPrimitiveValue | HArrayValue} HPropertyValue |
| 24 | + * @typedef {HArrayValue | HPrimitiveValue} HPropertyValue |
25 | 25 | * Primitive value or list value.
|
26 | 26 | * @typedef {{[property: string]: HPropertyValue | HStyle}} HProperties
|
27 | 27 | * Acceptable value for element properties.
|
28 | 28 | *
|
29 |
| - * @typedef {string | number | null | undefined} HPrimitiveChild |
| 29 | + * @typedef {number | string | null | undefined} HPrimitiveChild |
30 | 30 | * Primitive children, either ignored (nullish), or turned into text nodes.
|
31 |
| - * @typedef {Array<Node | HPrimitiveChild>} HArrayChild |
| 31 | + * @typedef {Array<HPrimitiveChild | Nodes>} HArrayChildNested |
32 | 32 | * List of children.
|
33 |
| - * @typedef {Node | HPrimitiveChild | HArrayChild} HChild |
| 33 | + * @typedef {Array<HArrayChildNested | HPrimitiveChild | Nodes>} HArrayChild |
| 34 | + * List of children. |
| 35 | + * @typedef {HArrayChild | HPrimitiveChild | Nodes} HChild |
34 | 36 | * Acceptable child value.
|
35 | 37 | */
|
36 | 38 |
|
37 |
| -import {find, normalize} from 'property-information' |
| 39 | +import {parse as commas} from 'comma-separated-tokens' |
38 | 40 | import {parseSelector} from 'hast-util-parse-selector'
|
| 41 | +import {find, normalize} from 'property-information' |
39 | 42 | import {parse as spaces} from 'space-separated-tokens'
|
40 |
| -import {parse as commas} from 'comma-separated-tokens' |
41 | 43 |
|
42 |
| -const buttonTypes = new Set(['menu', 'submit', 'reset', 'button']) |
| 44 | +const buttonTypes = new Set(['button', 'menu', 'reset', 'submit']) |
43 | 45 |
|
44 | 46 | const own = {}.hasOwnProperty
|
45 | 47 |
|
46 | 48 | /**
|
47 | 49 | * @param {Schema} schema
|
| 50 | + * Schema to use. |
48 | 51 | * @param {string} defaultTagName
|
49 |
| - * @param {Array<string>} [caseSensitive] |
| 52 | + * Default tag name. |
| 53 | + * @param {Array<string> | undefined} [caseSensitive] |
| 54 | + * Case-sensitive tag names (default: `undefined`). |
| 55 | + * @returns |
| 56 | + * `h`. |
50 | 57 | */
|
51 | 58 | export function core(schema, defaultTagName, caseSensitive) {
|
52 | 59 | const adjust = caseSensitive && createAdjustMap(caseSensitive)
|
53 | 60 |
|
54 |
| - const h = |
55 |
| - /** |
56 |
| - * @type {{ |
57 |
| - * (): Root |
58 |
| - * (selector: null | undefined, ...children: Array<HChild>): Root |
59 |
| - * (selector: string, properties: HProperties, ...children: Array<HChild>): Element |
60 |
| - * (selector: string, ...children: Array<HChild>): Element |
61 |
| - * }} |
62 |
| - */ |
63 |
| - ( |
64 |
| - /** |
65 |
| - * Hyperscript compatible DSL for creating virtual hast trees. |
66 |
| - * |
67 |
| - * @param {string | null | undefined} [selector] |
68 |
| - * @param {HProperties | HChild | null | undefined} [properties] |
69 |
| - * @param {Array<HChild>} children |
70 |
| - * @returns {HResult} |
71 |
| - */ |
72 |
| - function (selector, properties, ...children) { |
73 |
| - let index = -1 |
74 |
| - /** @type {HResult} */ |
75 |
| - let node |
76 |
| - |
77 |
| - if (selector === undefined || selector === null) { |
78 |
| - node = {type: 'root', children: []} |
79 |
| - // @ts-expect-error Properties are not supported for roots. |
80 |
| - children.unshift(properties) |
81 |
| - } else { |
82 |
| - node = parseSelector(selector, defaultTagName) |
83 |
| - // Normalize the name. |
84 |
| - node.tagName = node.tagName.toLowerCase() |
85 |
| - if (adjust && own.call(adjust, node.tagName)) { |
86 |
| - node.tagName = adjust[node.tagName] |
87 |
| - } |
| 61 | + /** |
| 62 | + * Hyperscript compatible DSL for creating virtual hast trees. |
| 63 | + * |
| 64 | + * @overload |
| 65 | + * @param {null | undefined} [selector] |
| 66 | + * @param {...HChild} children |
| 67 | + * @returns {Root} |
| 68 | + * |
| 69 | + * @overload |
| 70 | + * @param {string} selector |
| 71 | + * @param {HProperties} properties |
| 72 | + * @param {...HChild} children |
| 73 | + * @returns {Element} |
| 74 | + * |
| 75 | + * @overload |
| 76 | + * @param {string} selector |
| 77 | + * @param {...HChild} children |
| 78 | + * @returns {Element} |
| 79 | + * |
| 80 | + * @param {string | null | undefined} [selector] |
| 81 | + * Selector. |
| 82 | + * @param {HChild | HProperties | null | undefined} [properties] |
| 83 | + * Properties (or first child) (default: `undefined`). |
| 84 | + * @param {...HChild} children |
| 85 | + * Children. |
| 86 | + * @returns {HResult} |
| 87 | + * Result. |
| 88 | + */ |
| 89 | + function h(selector, properties, ...children) { |
| 90 | + let index = -1 |
| 91 | + /** @type {HResult} */ |
| 92 | + let node |
| 93 | + |
| 94 | + if (selector === undefined || selector === null) { |
| 95 | + node = {type: 'root', children: []} |
| 96 | + // Properties are not supported for roots. |
| 97 | + const child = /** @type {HChild} */ (properties) |
| 98 | + children.unshift(child) |
| 99 | + } else { |
| 100 | + node = parseSelector(selector, defaultTagName) |
| 101 | + // Normalize the name. |
| 102 | + node.tagName = node.tagName.toLowerCase() |
| 103 | + if (adjust && own.call(adjust, node.tagName)) { |
| 104 | + node.tagName = adjust[node.tagName] |
| 105 | + } |
88 | 106 |
|
89 |
| - // Handle props. |
90 |
| - if (isProperties(properties, node.tagName)) { |
91 |
| - /** @type {string} */ |
92 |
| - let key |
93 |
| - |
94 |
| - for (key in properties) { |
95 |
| - if (own.call(properties, key)) { |
96 |
| - addProperty(schema, node.properties, key, properties[key]) |
97 |
| - } |
98 |
| - } |
99 |
| - } else { |
100 |
| - children.unshift(properties) |
| 107 | + // Handle props. |
| 108 | + if (isProperties(properties, node.tagName)) { |
| 109 | + /** @type {string} */ |
| 110 | + let key |
| 111 | + |
| 112 | + for (key in properties) { |
| 113 | + if (own.call(properties, key)) { |
| 114 | + addProperty(schema, node.properties, key, properties[key]) |
101 | 115 | }
|
102 | 116 | }
|
| 117 | + } else { |
| 118 | + children.unshift(properties) |
| 119 | + } |
| 120 | + } |
103 | 121 |
|
104 |
| - // Handle children. |
105 |
| - while (++index < children.length) { |
106 |
| - addChild(node.children, children[index]) |
107 |
| - } |
| 122 | + // Handle children. |
| 123 | + while (++index < children.length) { |
| 124 | + addChild(node.children, children[index]) |
| 125 | + } |
108 | 126 |
|
109 |
| - if (node.type === 'element' && node.tagName === 'template') { |
110 |
| - node.content = {type: 'root', children: node.children} |
111 |
| - node.children = [] |
112 |
| - } |
| 127 | + if (node.type === 'element' && node.tagName === 'template') { |
| 128 | + node.content = {type: 'root', children: node.children} |
| 129 | + node.children = [] |
| 130 | + } |
113 | 131 |
|
114 |
| - return node |
115 |
| - } |
116 |
| - ) |
| 132 | + return node |
| 133 | + } |
117 | 134 |
|
118 | 135 | return h
|
119 | 136 | }
|
120 | 137 |
|
121 | 138 | /**
|
122 |
| - * @param {HProperties | HChild} value |
| 139 | + * Check if something is properties or a child. |
| 140 | + * |
| 141 | + * @param {HChild | HProperties} value |
| 142 | + * Value to check. |
123 | 143 | * @param {string} name
|
| 144 | + * Tag name. |
124 | 145 | * @returns {value is HProperties}
|
| 146 | + * Whether `value` is a properties object. |
125 | 147 | */
|
126 | 148 | function isProperties(value, name) {
|
127 | 149 | if (
|
@@ -150,10 +172,15 @@ function isProperties(value, name) {
|
150 | 172 |
|
151 | 173 | /**
|
152 | 174 | * @param {Schema} schema
|
| 175 | + * Schema. |
153 | 176 | * @param {Properties} properties
|
| 177 | + * Properties object. |
154 | 178 | * @param {string} key
|
155 |
| - * @param {HStyle | HPropertyValue} value |
156 |
| - * @returns {void} |
| 179 | + * Property name. |
| 180 | + * @param {HPropertyValue | HStyle} value |
| 181 | + * Property value. |
| 182 | + * @returns {undefined} |
| 183 | + * Nothing. |
157 | 184 | */
|
158 | 185 | function addProperty(schema, properties, key, value) {
|
159 | 186 | const info = find(schema, key)
|
@@ -192,30 +219,37 @@ function addProperty(schema, properties, key, value) {
|
192 | 219 | }
|
193 | 220 |
|
194 | 221 | if (Array.isArray(result)) {
|
195 |
| - /** @type {Array<string | number>} */ |
| 222 | + /** @type {Array<number | string>} */ |
196 | 223 | const finalResult = []
|
197 | 224 |
|
198 | 225 | while (++index < result.length) {
|
199 |
| - // @ts-expect-error Assume no booleans in array. |
200 |
| - finalResult[index] = parsePrimitive(info, info.property, result[index]) |
| 226 | + // Assume no booleans in array. |
| 227 | + const value = /** @type {number | string} */ ( |
| 228 | + parsePrimitive(info, info.property, result[index]) |
| 229 | + ) |
| 230 | + finalResult[index] = value |
201 | 231 | }
|
202 | 232 |
|
203 | 233 | result = finalResult
|
204 | 234 | }
|
205 | 235 |
|
206 | 236 | // Class names (which can be added both on the `selector` and here).
|
207 | 237 | if (info.property === 'className' && Array.isArray(properties.className)) {
|
208 |
| - // @ts-expect-error Assume no booleans in `className`. |
209 |
| - result = properties.className.concat(result) |
| 238 | + // Assume no booleans in `className`. |
| 239 | + const value = /** @type {number | string} */ (result) |
| 240 | + result = properties.className.concat(value) |
210 | 241 | }
|
211 | 242 |
|
212 | 243 | properties[info.property] = result
|
213 | 244 | }
|
214 | 245 |
|
215 | 246 | /**
|
216 |
| - * @param {Array<Content>} nodes |
| 247 | + * @param {Array<RootContent>} nodes |
| 248 | + * Children. |
217 | 249 | * @param {HChild} value
|
218 |
| - * @returns {void} |
| 250 | + * Child. |
| 251 | + * @returns {undefined} |
| 252 | + * Nothing. |
219 | 253 | */
|
220 | 254 | function addChild(nodes, value) {
|
221 | 255 | let index = -1
|
@@ -243,9 +277,13 @@ function addChild(nodes, value) {
|
243 | 277 | * Parse a single primitives.
|
244 | 278 | *
|
245 | 279 | * @param {Info} info
|
| 280 | + * Property information. |
246 | 281 | * @param {string} name
|
| 282 | + * Property name. |
247 | 283 | * @param {HPrimitiveValue} value
|
| 284 | + * Property value. |
248 | 285 | * @returns {HPrimitiveValue}
|
| 286 | + * Property value. |
249 | 287 | */
|
250 | 288 | function parsePrimitive(info, name, value) {
|
251 | 289 | if (typeof value === 'string') {
|
|
0 commit comments