|
1 | | -/** |
2 | | - * @typedef {import('hast').Root} HastRoot |
3 | | - * @typedef {import('hast').Element} HastElement |
4 | | - * @typedef {import('hast').Properties} Properties |
5 | | - * @typedef {HastRoot['children'][number]} HastChild |
6 | | - * @typedef {import('property-information').html['property'][string]} Info |
7 | | - * @typedef {html|svg} Schema |
8 | | - */ |
9 | | - |
10 | | -/** |
11 | | - * @typedef {string|number} HStyleValue |
12 | | - * @typedef {Object.<string, HStyleValue>} HStyle |
13 | | - * @typedef {string|number|boolean|null|undefined} HPrimitiveValue |
14 | | - * @typedef {Array.<string|number>} HArrayValue |
15 | | - * @typedef {HPrimitiveValue|HArrayValue} HPropertyValue |
16 | | - * @typedef {{[property: string]: HPropertyValue|HStyle}} HProperties |
17 | | - * |
18 | | - * @typedef {string|number|null|undefined} HPrimitiveChild |
19 | | - * @typedef {HastChild|HastRoot} HNodeChild |
20 | | - * @typedef {Array.<HPrimitiveChild|HNodeChild>} HArrayChild |
21 | | - * @typedef {HPrimitiveChild|HNodeChild|HArrayChild} HChild |
22 | | - */ |
23 | | - |
24 | | -import {html, svg, find, normalize} from 'property-information' |
25 | | -import {parseSelector} from 'hast-util-parse-selector' |
26 | | -import {parse as spaces} from 'space-separated-tokens' |
27 | | -import {parse as commas} from 'comma-separated-tokens' |
28 | | -import {svgCaseSensitiveTagNames} from './svg-case-sensitive-tag-names.js' |
29 | | - |
30 | | -var buttonTypes = new Set(['menu', 'submit', 'reset', 'button']) |
31 | | - |
32 | | -var own = {}.hasOwnProperty |
33 | | - |
34 | | -export const h = factory(html, 'div') |
35 | | - |
36 | | -export const s = factory(svg, 'g', svgCaseSensitiveTagNames) |
37 | | - |
38 | | -/** |
39 | | - * @param {Schema} schema |
40 | | - * @param {string} defaultTagName |
41 | | - * @param {Array.<string>} [caseSensitive] |
42 | | - */ |
43 | | -function factory(schema, defaultTagName, caseSensitive) { |
44 | | - var adjust = caseSensitive && createAdjustMap(caseSensitive) |
45 | | - |
46 | | - const h = |
47 | | - /** |
48 | | - * @type {{ |
49 | | - * (): HastRoot |
50 | | - * (selector: null|undefined, ...children: HChild[]): HastRoot |
51 | | - * (selector: string, properties: HProperties, ...children: HChild[]): HastElement |
52 | | - * (selector: string, ...children: HChild[]): HastElement |
53 | | - * }} |
54 | | - */ |
55 | | - ( |
56 | | - /** |
57 | | - * Hyperscript compatible DSL for creating virtual hast trees. |
58 | | - * |
59 | | - * @param {string|null} [selector] |
60 | | - * @param {HProperties|HChild} [properties] |
61 | | - * @param {...HChild} [children] |
62 | | - */ |
63 | | - function (selector, properties, ...children) { |
64 | | - var index = -1 |
65 | | - /** @type {HastRoot|HastElement} */ |
66 | | - var node |
67 | | - /** @type {string} */ |
68 | | - var name |
69 | | - /** @type {string} */ |
70 | | - var key |
71 | | - |
72 | | - if (selector === undefined || selector === null) { |
73 | | - node = {type: 'root', children: []} |
74 | | - // @ts-ignore Properties are not supported for roots. |
75 | | - children.unshift(properties) |
76 | | - } else { |
77 | | - node = parseSelector(selector, defaultTagName) |
78 | | - // Normalize the name. |
79 | | - name = node.tagName.toLowerCase() |
80 | | - if (adjust && own.call(adjust, name)) name = adjust[name] |
81 | | - node.tagName = name |
82 | | - |
83 | | - // Handle props. |
84 | | - if (isProperties(properties, name)) { |
85 | | - for (key in properties) { |
86 | | - if (own.call(properties, key)) { |
87 | | - addProperty(schema, node.properties, key, properties[key]) |
88 | | - } |
89 | | - } |
90 | | - } else { |
91 | | - children.unshift(properties) |
92 | | - } |
93 | | - } |
94 | | - |
95 | | - // Handle children. |
96 | | - while (++index < children.length) { |
97 | | - addChild(node.children, children[index]) |
98 | | - } |
99 | | - |
100 | | - if (name === 'template') { |
101 | | - node.content = {type: 'root', children: node.children} |
102 | | - node.children = [] |
103 | | - } |
104 | | - |
105 | | - return node |
106 | | - } |
107 | | - ) |
108 | | - |
109 | | - return h |
110 | | -} |
111 | | - |
112 | | -/** |
113 | | - * @param {HProperties|HChild} value |
114 | | - * @param {string} name |
115 | | - * @returns {value is HProperties} |
116 | | - */ |
117 | | -function isProperties(value, name) { |
118 | | - if ( |
119 | | - value === null || |
120 | | - value === undefined || |
121 | | - typeof value !== 'object' || |
122 | | - Array.isArray(value) |
123 | | - ) { |
124 | | - return false |
125 | | - } |
126 | | - |
127 | | - if (name === 'input' || !value.type || typeof value.type !== 'string') { |
128 | | - return true |
129 | | - } |
130 | | - |
131 | | - if (Array.isArray(value.children)) { |
132 | | - return false |
133 | | - } |
134 | | - |
135 | | - if (name === 'button') { |
136 | | - return buttonTypes.has(value.type.toLowerCase()) |
137 | | - } |
138 | | - |
139 | | - return !('value' in value) |
140 | | -} |
141 | | - |
142 | | -/** |
143 | | - * @param {Schema} schema |
144 | | - * @param {Properties} properties |
145 | | - * @param {string} key |
146 | | - * @param {HStyle|HPropertyValue} value |
147 | | - * @returns {void} |
148 | | - */ |
149 | | -function addProperty(schema, properties, key, value) { |
150 | | - var info = find(schema, key) |
151 | | - var index = -1 |
152 | | - /** @type {HPropertyValue} */ |
153 | | - var result |
154 | | - /** @type {Array.<string|number>} */ |
155 | | - var finalResult |
156 | | - |
157 | | - // Ignore nullish and NaN values. |
158 | | - if (value === undefined || value === null) return |
159 | | - |
160 | | - if (typeof value === 'number') { |
161 | | - // Ignore NaN. |
162 | | - if (Number.isNaN(value)) return |
163 | | - |
164 | | - result = value |
165 | | - } |
166 | | - // Booleans. |
167 | | - else if (typeof value === 'boolean') { |
168 | | - result = value |
169 | | - } |
170 | | - // Handle list values. |
171 | | - else if (typeof value === 'string') { |
172 | | - if (info.spaceSeparated) { |
173 | | - result = spaces(value) |
174 | | - } else if (info.commaSeparated) { |
175 | | - result = commas(value) |
176 | | - } else if (info.commaOrSpaceSeparated) { |
177 | | - result = spaces(commas(value).join(' ')) |
178 | | - } else { |
179 | | - result = parsePrimitive(info, info.property, value) |
180 | | - } |
181 | | - } else if (Array.isArray(value)) { |
182 | | - result = value.concat() |
183 | | - } else { |
184 | | - result = info.property === 'style' ? style(value) : String(value) |
185 | | - } |
186 | | - |
187 | | - if (Array.isArray(result)) { |
188 | | - finalResult = [] |
189 | | - |
190 | | - while (++index < result.length) { |
191 | | - // @ts-ignore Assume no booleans in array. |
192 | | - finalResult[index] = parsePrimitive(info, info.property, result[index]) |
193 | | - } |
194 | | - |
195 | | - result = finalResult |
196 | | - } |
197 | | - |
198 | | - // Class names (which can be added both on the `selector` and here). |
199 | | - if (info.property === 'className' && Array.isArray(properties.className)) { |
200 | | - // @ts-ignore Assume no booleans in `className`. |
201 | | - result = properties.className.concat(result) |
202 | | - } |
203 | | - |
204 | | - properties[info.property] = result |
205 | | -} |
206 | | - |
207 | | -/** |
208 | | - * @param {Array.<HastChild>} nodes |
209 | | - * @param {HChild} value |
210 | | - * @returns {void} |
211 | | - */ |
212 | | -function addChild(nodes, value) { |
213 | | - var index = -1 |
214 | | - |
215 | | - if (value === undefined || value === null) { |
216 | | - // Empty. |
217 | | - } else if (typeof value === 'string' || typeof value === 'number') { |
218 | | - nodes.push({type: 'text', value: String(value)}) |
219 | | - } else if (Array.isArray(value)) { |
220 | | - while (++index < value.length) { |
221 | | - addChild(nodes, value[index]) |
222 | | - } |
223 | | - } else if (typeof value === 'object' && 'type' in value) { |
224 | | - if (value.type === 'root') { |
225 | | - // @ts-ignore it looks like a root, TS… |
226 | | - addChild(nodes, value.children) |
227 | | - } else { |
228 | | - nodes.push(value) |
229 | | - } |
230 | | - } else { |
231 | | - throw new Error('Expected node, nodes, or string, got `' + value + '`') |
232 | | - } |
233 | | -} |
234 | | - |
235 | | -/** |
236 | | - * Parse a single primitives. |
237 | | - * |
238 | | - * @param {Info} info |
239 | | - * @param {string} name |
240 | | - * @param {HPrimitiveValue} value |
241 | | - * @returns {HPrimitiveValue} |
242 | | - */ |
243 | | -function parsePrimitive(info, name, value) { |
244 | | - if (typeof value === 'string') { |
245 | | - if (info.number && value && !Number.isNaN(Number(value))) { |
246 | | - return Number(value) |
247 | | - } |
248 | | - |
249 | | - if ( |
250 | | - (info.boolean || info.overloadedBoolean) && |
251 | | - (value === '' || normalize(value) === normalize(name)) |
252 | | - ) { |
253 | | - return true |
254 | | - } |
255 | | - } |
256 | | - |
257 | | - return value |
258 | | -} |
259 | | - |
260 | | -/** |
261 | | - * @param {HStyle} value |
262 | | - * @returns {string} |
263 | | - */ |
264 | | -function style(value) { |
265 | | - /** @type {Array.<string>} */ |
266 | | - var result = [] |
267 | | - /** @type {string} */ |
268 | | - var key |
269 | | - |
270 | | - for (key in value) { |
271 | | - if (own.call(value, key)) { |
272 | | - result.push([key, value[key]].join(': ')) |
273 | | - } |
274 | | - } |
275 | | - |
276 | | - return result.join('; ') |
277 | | -} |
278 | | - |
279 | | -/** |
280 | | - * @param {Array.<string>} values |
281 | | - * @returns {Object.<string, string>} |
282 | | - */ |
283 | | -function createAdjustMap(values) { |
284 | | - /** @type {Object.<string, string>} */ |
285 | | - var result = {} |
286 | | - var index = -1 |
287 | | - |
288 | | - while (++index < values.length) { |
289 | | - result[values[index].toLowerCase()] = values[index] |
290 | | - } |
291 | | - |
292 | | - return result |
293 | | -} |
| 1 | +export {h, s} from './lib/index.js' |
0 commit comments