@ohos-ports/hast-to-hyperscript 10.0.1-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +38 -0
- package/index.js +337 -0
- package/license +22 -0
- package/package.json +116 -0
- package/readme.md +253 -0
package/index.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @template {CreateElementLike} H
|
|
3
|
+
* @param {H} h
|
|
4
|
+
* @param {Element|Root} tree
|
|
5
|
+
* @param {string|boolean|Options} [options]
|
|
6
|
+
* @returns {ReturnType<H>}
|
|
7
|
+
*/
|
|
8
|
+
export function toH<H extends CreateElementLike>(
|
|
9
|
+
h: H,
|
|
10
|
+
tree: Element | Root,
|
|
11
|
+
options?: string | boolean | Options | undefined
|
|
12
|
+
): ReturnType<H>
|
|
13
|
+
export type Element = import('hast').Element
|
|
14
|
+
export type Root = import('hast').Root
|
|
15
|
+
export type Text = import('hast').Text
|
|
16
|
+
export type AssertElement = import('unist-util-is').AssertPredicate<Element>
|
|
17
|
+
export type AssertText = import('unist-util-is').AssertPredicate<Text>
|
|
18
|
+
export type AssertRoot = import('unist-util-is').AssertPredicate<Root>
|
|
19
|
+
export type CreateElementLike = (
|
|
20
|
+
name: string,
|
|
21
|
+
attributes: any,
|
|
22
|
+
children?: any[] | undefined
|
|
23
|
+
) => any
|
|
24
|
+
export type Context = {
|
|
25
|
+
schema:
|
|
26
|
+
| import('property-information/lib/util/schema').Schema
|
|
27
|
+
| import('property-information/lib/util/schema').Schema
|
|
28
|
+
prefix: string | null
|
|
29
|
+
key: number
|
|
30
|
+
react: boolean
|
|
31
|
+
vue: boolean
|
|
32
|
+
vdom: boolean
|
|
33
|
+
hyperscript: boolean
|
|
34
|
+
}
|
|
35
|
+
export type Options = {
|
|
36
|
+
prefix?: string | null | undefined
|
|
37
|
+
space?: 'html' | 'svg' | undefined
|
|
38
|
+
}
|
package/index.js
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import('hast').Element} Element
|
|
3
|
+
* @typedef {import('hast').Root} Root
|
|
4
|
+
* @typedef {import('hast').Text} Text
|
|
5
|
+
*
|
|
6
|
+
* @typedef {import('unist-util-is').AssertPredicate<Element>} AssertElement
|
|
7
|
+
* @typedef {import('unist-util-is').AssertPredicate<Text>} AssertText
|
|
8
|
+
* @typedef {import('unist-util-is').AssertPredicate<Root>} AssertRoot
|
|
9
|
+
*
|
|
10
|
+
* @callback CreateElementLike
|
|
11
|
+
* @param {string} name
|
|
12
|
+
* @param {any} attributes
|
|
13
|
+
* @param {Array.<string|any>} [children]
|
|
14
|
+
* @returns {any}
|
|
15
|
+
*
|
|
16
|
+
* @typedef Context
|
|
17
|
+
* @property {html|svg} schema
|
|
18
|
+
* @property {string|null} prefix
|
|
19
|
+
* @property {number} key
|
|
20
|
+
* @property {boolean} react
|
|
21
|
+
* @property {boolean} vue
|
|
22
|
+
* @property {boolean} vdom
|
|
23
|
+
* @property {boolean} hyperscript
|
|
24
|
+
*
|
|
25
|
+
* @typedef Options
|
|
26
|
+
* @property {string|null} [prefix]
|
|
27
|
+
* @property {'html'|'svg'} [space]
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import {html, svg, find, hastToReact} from 'property-information'
|
|
31
|
+
import {stringify as spaces} from 'space-separated-tokens'
|
|
32
|
+
import {stringify as commas} from 'comma-separated-tokens'
|
|
33
|
+
import style from 'style-to-object'
|
|
34
|
+
import {webNamespaces} from 'web-namespaces'
|
|
35
|
+
import {convert} from 'unist-util-is'
|
|
36
|
+
|
|
37
|
+
const ns = /** @type {Record<string, string>} */ (webNamespaces)
|
|
38
|
+
const toReact = /** @type {Record<string, string>} */ (hastToReact)
|
|
39
|
+
|
|
40
|
+
const own = {}.hasOwnProperty
|
|
41
|
+
|
|
42
|
+
/** @type {AssertRoot} */
|
|
43
|
+
// @ts-expect-error it’s correct.
|
|
44
|
+
const root = convert('root')
|
|
45
|
+
/** @type {AssertElement} */
|
|
46
|
+
// @ts-expect-error it’s correct.
|
|
47
|
+
const element = convert('element')
|
|
48
|
+
/** @type {AssertText} */
|
|
49
|
+
// @ts-expect-error it’s correct.
|
|
50
|
+
const text = convert('text')
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @template {CreateElementLike} H
|
|
54
|
+
* @param {H} h
|
|
55
|
+
* @param {Element|Root} tree
|
|
56
|
+
* @param {string|boolean|Options} [options]
|
|
57
|
+
* @returns {ReturnType<H>}
|
|
58
|
+
*/
|
|
59
|
+
export function toH(h, tree, options) {
|
|
60
|
+
if (typeof h !== 'function') {
|
|
61
|
+
throw new TypeError('h is not a function')
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const r = react(h)
|
|
65
|
+
const v = vue(h)
|
|
66
|
+
const vd = vdom(h)
|
|
67
|
+
/** @type {string|boolean|null|undefined} */
|
|
68
|
+
let prefix
|
|
69
|
+
/** @type {Element} */
|
|
70
|
+
let node
|
|
71
|
+
|
|
72
|
+
if (typeof options === 'string' || typeof options === 'boolean') {
|
|
73
|
+
prefix = options
|
|
74
|
+
options = {}
|
|
75
|
+
} else {
|
|
76
|
+
if (!options) options = {}
|
|
77
|
+
prefix = options.prefix
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (root(tree)) {
|
|
81
|
+
// @ts-expect-error Allow `doctypes` in there, we’ll filter them out later.
|
|
82
|
+
node =
|
|
83
|
+
tree.children.length === 1 && element(tree.children[0])
|
|
84
|
+
? tree.children[0]
|
|
85
|
+
: {
|
|
86
|
+
type: 'element',
|
|
87
|
+
tagName: 'div',
|
|
88
|
+
properties: {},
|
|
89
|
+
children: tree.children
|
|
90
|
+
}
|
|
91
|
+
} else if (element(tree)) {
|
|
92
|
+
node = tree
|
|
93
|
+
} else {
|
|
94
|
+
throw new Error(
|
|
95
|
+
// @ts-expect-error runtime.
|
|
96
|
+
'Expected root or element, not `' + ((tree && tree.type) || tree) + '`'
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return transform(h, node, {
|
|
101
|
+
schema: options.space === 'svg' ? svg : html,
|
|
102
|
+
prefix:
|
|
103
|
+
prefix === undefined || prefix === null
|
|
104
|
+
? r || v || vd
|
|
105
|
+
? 'h-'
|
|
106
|
+
: null
|
|
107
|
+
: typeof prefix === 'string'
|
|
108
|
+
? prefix
|
|
109
|
+
: prefix
|
|
110
|
+
? 'h-'
|
|
111
|
+
: null,
|
|
112
|
+
key: 0,
|
|
113
|
+
react: r,
|
|
114
|
+
vue: v,
|
|
115
|
+
vdom: vd,
|
|
116
|
+
hyperscript: hyperscript(h)
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Transform a hast node through a hyperscript interface to *anything*!
|
|
122
|
+
*
|
|
123
|
+
* @template {CreateElementLike} H
|
|
124
|
+
* @param {H} h
|
|
125
|
+
* @param {Element} node
|
|
126
|
+
* @param {Context} ctx
|
|
127
|
+
*/
|
|
128
|
+
function transform(h, node, ctx) {
|
|
129
|
+
const parentSchema = ctx.schema
|
|
130
|
+
let schema = parentSchema
|
|
131
|
+
let name = node.tagName
|
|
132
|
+
/** @type {Record<string, unknown>} */
|
|
133
|
+
const attributes = {}
|
|
134
|
+
/** @type {Array.<ReturnType<H>|string>} */
|
|
135
|
+
const nodes = []
|
|
136
|
+
let index = -1
|
|
137
|
+
/** @type {string} */
|
|
138
|
+
let key
|
|
139
|
+
|
|
140
|
+
if (parentSchema.space === 'html' && name.toLowerCase() === 'svg') {
|
|
141
|
+
schema = svg
|
|
142
|
+
ctx.schema = schema
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
for (key in node.properties) {
|
|
146
|
+
if (node.properties && own.call(node.properties, key)) {
|
|
147
|
+
addAttribute(attributes, key, node.properties[key], ctx, name)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (ctx.vdom) {
|
|
152
|
+
if (schema.space === 'html') {
|
|
153
|
+
name = name.toUpperCase()
|
|
154
|
+
} else if (schema.space) {
|
|
155
|
+
attributes.namespace = ns[schema.space]
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (ctx.prefix) {
|
|
160
|
+
ctx.key++
|
|
161
|
+
attributes.key = ctx.prefix + ctx.key
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (node.children) {
|
|
165
|
+
while (++index < node.children.length) {
|
|
166
|
+
const value = node.children[index]
|
|
167
|
+
|
|
168
|
+
if (element(value)) {
|
|
169
|
+
nodes.push(transform(h, value, ctx))
|
|
170
|
+
} else if (text(value)) {
|
|
171
|
+
nodes.push(value.value)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Restore parent schema.
|
|
177
|
+
ctx.schema = parentSchema
|
|
178
|
+
|
|
179
|
+
// Ensure no React warnings are triggered for void elements having children
|
|
180
|
+
// passed in.
|
|
181
|
+
return nodes.length > 0
|
|
182
|
+
? h.call(node, name, attributes, nodes)
|
|
183
|
+
: h.call(node, name, attributes)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* @param {Record<string, unknown>} props
|
|
188
|
+
* @param {string} prop
|
|
189
|
+
* @param {unknown} value
|
|
190
|
+
* @param {Context} ctx
|
|
191
|
+
* @param {string} name
|
|
192
|
+
*/
|
|
193
|
+
// eslint-disable-next-line complexity, max-params
|
|
194
|
+
function addAttribute(props, prop, value, ctx, name) {
|
|
195
|
+
const info = find(ctx.schema, prop)
|
|
196
|
+
/** @type {string|undefined} */
|
|
197
|
+
let subprop
|
|
198
|
+
|
|
199
|
+
// Ignore nullish and `NaN` values.
|
|
200
|
+
// Ignore `false` and falsey known booleans for hyperlike DSLs.
|
|
201
|
+
if (
|
|
202
|
+
value === undefined ||
|
|
203
|
+
value === null ||
|
|
204
|
+
(typeof value === 'number' && Number.isNaN(value)) ||
|
|
205
|
+
(value === false && (ctx.vue || ctx.vdom || ctx.hyperscript)) ||
|
|
206
|
+
(!value && info.boolean && (ctx.vue || ctx.vdom || ctx.hyperscript))
|
|
207
|
+
) {
|
|
208
|
+
return
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (Array.isArray(value)) {
|
|
212
|
+
// Accept `array`.
|
|
213
|
+
// Most props are space-separated.
|
|
214
|
+
value = info.commaSeparated ? commas(value) : spaces(value)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Treat `true` and truthy known booleans.
|
|
218
|
+
if (info.boolean && ctx.hyperscript) {
|
|
219
|
+
value = ''
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// VDOM, Vue, and React accept `style` as object.
|
|
223
|
+
if (
|
|
224
|
+
info.property === 'style' &&
|
|
225
|
+
typeof value === 'string' &&
|
|
226
|
+
(ctx.react || ctx.vue || ctx.vdom)
|
|
227
|
+
) {
|
|
228
|
+
value = parseStyle(value, name)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (ctx.vue) {
|
|
232
|
+
if (info.property !== 'style') subprop = 'attrs'
|
|
233
|
+
} else if (!info.mustUseProperty) {
|
|
234
|
+
if (ctx.vdom) {
|
|
235
|
+
if (info.property !== 'style') subprop = 'attributes'
|
|
236
|
+
} else if (ctx.hyperscript) {
|
|
237
|
+
subprop = 'attrs'
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (subprop) {
|
|
242
|
+
props[subprop] = Object.assign(props[subprop] || {}, {
|
|
243
|
+
[info.attribute]: value
|
|
244
|
+
})
|
|
245
|
+
} else if (info.space && ctx.react) {
|
|
246
|
+
props[toReact[info.property] || info.property] = value
|
|
247
|
+
} else {
|
|
248
|
+
props[info.attribute] = value
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Check if `h` is `react.createElement`.
|
|
254
|
+
*
|
|
255
|
+
* @param {CreateElementLike} h
|
|
256
|
+
* @returns {boolean}
|
|
257
|
+
*/
|
|
258
|
+
function react(h) {
|
|
259
|
+
/** @type {unknown} */
|
|
260
|
+
const node = h('div', {})
|
|
261
|
+
return Boolean(
|
|
262
|
+
node &&
|
|
263
|
+
// @ts-expect-error Looks like a React node.
|
|
264
|
+
('_owner' in node || '_store' in node) &&
|
|
265
|
+
// @ts-expect-error Looks like a React node.
|
|
266
|
+
(node.key === undefined || node.key === null)
|
|
267
|
+
)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Check if `h` is `hyperscript`.
|
|
272
|
+
*
|
|
273
|
+
* @param {CreateElementLike} h
|
|
274
|
+
* @returns {boolean}
|
|
275
|
+
*/
|
|
276
|
+
function hyperscript(h) {
|
|
277
|
+
return 'context' in h && 'cleanup' in h
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Check if `h` is `virtual-dom/h`.
|
|
282
|
+
*
|
|
283
|
+
* @param {CreateElementLike} h
|
|
284
|
+
* @returns {boolean}
|
|
285
|
+
*/
|
|
286
|
+
function vdom(h) {
|
|
287
|
+
/** @type {unknown} */
|
|
288
|
+
const node = h('div', {})
|
|
289
|
+
// @ts-expect-error Looks like a vnode.
|
|
290
|
+
return node.type === 'VirtualNode'
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Check if `h` is Vue.
|
|
295
|
+
*
|
|
296
|
+
* @param {CreateElementLike} h
|
|
297
|
+
* @returns {boolean}
|
|
298
|
+
*/
|
|
299
|
+
function vue(h) {
|
|
300
|
+
/** @type {unknown} */
|
|
301
|
+
const node = h('div', {})
|
|
302
|
+
// @ts-expect-error Looks like a Vue node.
|
|
303
|
+
return Boolean(node && node.context && node.context._isVue)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* @param {string} value
|
|
308
|
+
* @param {string} tagName
|
|
309
|
+
* @returns {Record<string, string>}
|
|
310
|
+
*/
|
|
311
|
+
function parseStyle(value, tagName) {
|
|
312
|
+
/** @type {Record<string, string>} */
|
|
313
|
+
const result = {}
|
|
314
|
+
|
|
315
|
+
try {
|
|
316
|
+
style(value, (name, value) => {
|
|
317
|
+
if (name.slice(0, 4) === '-ms-') name = 'ms-' + name.slice(4)
|
|
318
|
+
|
|
319
|
+
result[
|
|
320
|
+
name.replace(
|
|
321
|
+
/-([a-z])/g,
|
|
322
|
+
/**
|
|
323
|
+
* @param {string} _
|
|
324
|
+
* @param {string} $1
|
|
325
|
+
* @returns {string}
|
|
326
|
+
*/ (_, $1) => $1.toUpperCase()
|
|
327
|
+
)
|
|
328
|
+
] = value
|
|
329
|
+
})
|
|
330
|
+
} catch (error) {
|
|
331
|
+
error.message =
|
|
332
|
+
tagName + '[style]' + error.message.slice('undefined'.length)
|
|
333
|
+
throw error
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return result
|
|
337
|
+
}
|
package/license
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
(The MIT License)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2016 Titus Wormer <tituswormer@gmail.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
'Software'), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
19
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
20
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
21
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
22
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/package.json
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ohos-ports/hast-to-hyperscript",
|
|
3
|
+
"version": "10.0.1-beta.0",
|
|
4
|
+
"description": "hast utility to transform to something else (react, vue, etc) through a hyperscript DSL",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"unist",
|
|
8
|
+
"hast",
|
|
9
|
+
"hast-util",
|
|
10
|
+
"util",
|
|
11
|
+
"utility",
|
|
12
|
+
"html",
|
|
13
|
+
"change",
|
|
14
|
+
"transform",
|
|
15
|
+
"rehype",
|
|
16
|
+
"vdom",
|
|
17
|
+
"virtual",
|
|
18
|
+
"dom",
|
|
19
|
+
"hyperscript",
|
|
20
|
+
"dsl"
|
|
21
|
+
],
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/ohos-ports/ohos-ports.git",
|
|
25
|
+
"directory": "ports/hast-to-hyperscript/10.0.1"
|
|
26
|
+
},
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/ohos-ports/ohos-ports/issues"
|
|
29
|
+
},
|
|
30
|
+
"funding": {
|
|
31
|
+
"type": "opencollective",
|
|
32
|
+
"url": "https://opencollective.com/unified"
|
|
33
|
+
},
|
|
34
|
+
"author": "Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)",
|
|
35
|
+
"contributors": [
|
|
36
|
+
"Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)",
|
|
37
|
+
"Jannis Redmann <mail@jannisr.de>",
|
|
38
|
+
"Koto Hajime <toxictoxer@gmail.com>",
|
|
39
|
+
"Christian Murphy <christian.murphy.42@gmail.com>"
|
|
40
|
+
],
|
|
41
|
+
"sideEffects": false,
|
|
42
|
+
"type": "module",
|
|
43
|
+
"main": "index.js",
|
|
44
|
+
"types": "index.d.ts",
|
|
45
|
+
"files": [
|
|
46
|
+
"index.d.ts",
|
|
47
|
+
"index.js"
|
|
48
|
+
],
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@types/unist": "^2.0.0",
|
|
51
|
+
"comma-separated-tokens": "^2.0.0",
|
|
52
|
+
"property-information": "^6.0.0",
|
|
53
|
+
"space-separated-tokens": "^2.0.0",
|
|
54
|
+
"style-to-object": "^0.3.0",
|
|
55
|
+
"unist-util-is": "^5.0.0",
|
|
56
|
+
"web-namespaces": "^2.0.0"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@types/hyperscript": "0.0.4",
|
|
60
|
+
"@types/react": "^17.0.0",
|
|
61
|
+
"@types/react-dom": "^17.0.0",
|
|
62
|
+
"@types/tape": "^4.0.0",
|
|
63
|
+
"@types/virtual-dom": "^2.0.0",
|
|
64
|
+
"c8": "^7.0.0",
|
|
65
|
+
"hyperscript": "^2.0.0",
|
|
66
|
+
"prettier": "^2.0.0",
|
|
67
|
+
"react": "^17.0.0",
|
|
68
|
+
"react-dom": "^17.0.0",
|
|
69
|
+
"rehype": "^11.0.0",
|
|
70
|
+
"remark-cli": "^9.0.0",
|
|
71
|
+
"remark-preset-wooorm": "^8.0.0",
|
|
72
|
+
"rimraf": "^3.0.0",
|
|
73
|
+
"tape": "^5.0.0",
|
|
74
|
+
"type-coverage": "^2.0.0",
|
|
75
|
+
"typescript": "^4.0.0",
|
|
76
|
+
"unist-builder": "^3.0.0",
|
|
77
|
+
"vdom-to-html": "^2.0.0",
|
|
78
|
+
"virtual-dom": "^2.0.0",
|
|
79
|
+
"vue": "^2.0.0",
|
|
80
|
+
"vue-server-renderer": "^2.0.0",
|
|
81
|
+
"xo": "^0.42.0"
|
|
82
|
+
},
|
|
83
|
+
"scripts": {
|
|
84
|
+
"prepack": "npm run build && npm run format",
|
|
85
|
+
"build": "rimraf \"*.d.ts\" && tsc && type-coverage",
|
|
86
|
+
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix",
|
|
87
|
+
"test-api": "node test.js",
|
|
88
|
+
"test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov node test.js",
|
|
89
|
+
"test": "npm run build && npm run format && npm run test-coverage"
|
|
90
|
+
},
|
|
91
|
+
"prettier": {
|
|
92
|
+
"tabWidth": 2,
|
|
93
|
+
"useTabs": false,
|
|
94
|
+
"singleQuote": true,
|
|
95
|
+
"bracketSpacing": false,
|
|
96
|
+
"semi": false,
|
|
97
|
+
"trailingComma": "none"
|
|
98
|
+
},
|
|
99
|
+
"xo": {
|
|
100
|
+
"prettier": true
|
|
101
|
+
},
|
|
102
|
+
"remarkConfig": {
|
|
103
|
+
"plugins": [
|
|
104
|
+
"preset-wooorm"
|
|
105
|
+
]
|
|
106
|
+
},
|
|
107
|
+
"typeCoverage": {
|
|
108
|
+
"atLeast": 100,
|
|
109
|
+
"detail": true,
|
|
110
|
+
"strict": true,
|
|
111
|
+
"ignoreCatch": true,
|
|
112
|
+
"ignoreFiles": [
|
|
113
|
+
"index.d.ts"
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# hast-to-hyperscript
|
|
2
|
+
|
|
3
|
+
[![Build][build-badge]][build]
|
|
4
|
+
[![Coverage][coverage-badge]][coverage]
|
|
5
|
+
[![Downloads][downloads-badge]][downloads]
|
|
6
|
+
[![Size][size-badge]][size]
|
|
7
|
+
[![Sponsors][sponsors-badge]][collective]
|
|
8
|
+
[![Backers][backers-badge]][collective]
|
|
9
|
+
[![Chat][chat-badge]][chat]
|
|
10
|
+
|
|
11
|
+
[**hast**][hast] utility to transform a [*tree*][tree] to something else through
|
|
12
|
+
a [hyperscript][] interface.
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
This package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c):
|
|
17
|
+
Node 12+ is needed to use it and it must be `import`ed instead of `require`d.
|
|
18
|
+
|
|
19
|
+
[npm][]:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
npm install hast-to-hyperscript
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Use
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
import {toH} from 'hast-to-hyperscript'
|
|
29
|
+
import h from 'hyperscript'
|
|
30
|
+
|
|
31
|
+
const tree = {
|
|
32
|
+
type: 'element',
|
|
33
|
+
tagName: 'p',
|
|
34
|
+
properties: {id: 'alpha', className: ['bravo']},
|
|
35
|
+
children: [
|
|
36
|
+
{type: 'text', value: 'charlie '},
|
|
37
|
+
{
|
|
38
|
+
type: 'element',
|
|
39
|
+
tagName: 'strong',
|
|
40
|
+
properties: {style: 'color: red;'},
|
|
41
|
+
children: [{type: 'text', value: 'delta'}]
|
|
42
|
+
},
|
|
43
|
+
{type: 'text', value: ' echo.'}
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Transform (`hyperscript` needs `outerHTML` to serialize):
|
|
48
|
+
const doc = toH(h, tree).outerHTML
|
|
49
|
+
|
|
50
|
+
console.log(doc)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Yields:
|
|
54
|
+
|
|
55
|
+
```html
|
|
56
|
+
<p class="bravo" id="alpha">charlie <strong>delta</strong> echo.</p>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## API
|
|
60
|
+
|
|
61
|
+
This package exports the following identifiers: `toH`.
|
|
62
|
+
There is no default export.
|
|
63
|
+
|
|
64
|
+
### `toH(h, tree[, options|prefix])`
|
|
65
|
+
|
|
66
|
+
Transform a [**hast**][hast] [*tree*][tree] to something else through a
|
|
67
|
+
[hyperscript][] interface.
|
|
68
|
+
|
|
69
|
+
###### Parameters
|
|
70
|
+
|
|
71
|
+
* `h` ([`Function`][h]) — Hyperscript function
|
|
72
|
+
* `tree` ([`Node`][node]) — [*Tree*][tree] to transform
|
|
73
|
+
* `prefix` — Treated as `{prefix: prefix}`
|
|
74
|
+
* `options.prefix` (`string` or `boolean`, optional)
|
|
75
|
+
— Prefix to use as a prefix for keys passed in `attrs` to `h()`,
|
|
76
|
+
this behavior is turned off by passing `false`, turned on by passing
|
|
77
|
+
a `string`.
|
|
78
|
+
By default, `h-` is used as a prefix if the given `h` is detected as being
|
|
79
|
+
`virtual-dom/h` or `React.createElement`
|
|
80
|
+
* `options.space` (enum, `'svg'` or `'html'`, default: `'html'`)
|
|
81
|
+
— Whether `node` is in the `'html'` or `'svg'` space.
|
|
82
|
+
If an `svg` element is found when inside the HTML space, `toH` automatically
|
|
83
|
+
switches to the SVG space when entering the element, and switches back when
|
|
84
|
+
exiting
|
|
85
|
+
|
|
86
|
+
###### Returns
|
|
87
|
+
|
|
88
|
+
`*` — Anything returned by invoking `h()`.
|
|
89
|
+
|
|
90
|
+
### `function h(name, attrs, children)`
|
|
91
|
+
|
|
92
|
+
Create an [*element*][element] from the given values.
|
|
93
|
+
|
|
94
|
+
###### Content
|
|
95
|
+
|
|
96
|
+
`h` is called with the node that is currently compiled as the context object
|
|
97
|
+
(`this`).
|
|
98
|
+
|
|
99
|
+
###### Parameters
|
|
100
|
+
|
|
101
|
+
* `name` (`string`) — Tag-name of element to create
|
|
102
|
+
* `attrs` (`Object.<string>`) — Attributes to set
|
|
103
|
+
* `children` (`Array.<* | string>`) — List of children (results of previously
|
|
104
|
+
invoking `h()`)
|
|
105
|
+
|
|
106
|
+
###### Returns
|
|
107
|
+
|
|
108
|
+
`*` — Anything.
|
|
109
|
+
|
|
110
|
+
##### Caveats
|
|
111
|
+
|
|
112
|
+
###### Nodes
|
|
113
|
+
|
|
114
|
+
Most hyperscript implementations only support [*elements*][element] and
|
|
115
|
+
[*texts*][text].
|
|
116
|
+
[**hast**][hast] supports [*doctype*][doctype], [*comment*][comment], and
|
|
117
|
+
[*root*][root] as well.
|
|
118
|
+
|
|
119
|
+
* If anything other than an `element` or `root` node is given, `toH` throws
|
|
120
|
+
* If a [*root*][root] is given with no [*children*][child], an empty `div`
|
|
121
|
+
[*element*][element] is returned
|
|
122
|
+
* If a [*root*][root] is given with one [*element*][element] [*child*][child],
|
|
123
|
+
that element is transformed
|
|
124
|
+
* Otherwise, the children are wrapped in a `div` [*element*][element]
|
|
125
|
+
|
|
126
|
+
If unknown nodes (a node with a [*type*][type] not defined by [**hast**][hast])
|
|
127
|
+
are found as [*descendants*][descendant] of the given [*tree*][tree], they are
|
|
128
|
+
ignored: only [*text*][text] and [*element*][element] are transformed.
|
|
129
|
+
|
|
130
|
+
###### Support
|
|
131
|
+
|
|
132
|
+
Although there are lots of libraries mentioning support for a hyperscript-like
|
|
133
|
+
interface, there are significant differences between them.
|
|
134
|
+
For example, [`hyperscript`][hyperscript] doesn’t support classes in `attrs` and
|
|
135
|
+
[`virtual-dom/h`][vdom] needs an `attributes` object inside `attrs` most of the
|
|
136
|
+
time.
|
|
137
|
+
`toH` works around these differences for:
|
|
138
|
+
|
|
139
|
+
* [`React.createElement`][react]
|
|
140
|
+
* Vue’s [`createElement`][vue]
|
|
141
|
+
* [`virtual-dom/h`][vdom]
|
|
142
|
+
* [`hyperscript`][hyperscript]
|
|
143
|
+
|
|
144
|
+
## Security
|
|
145
|
+
|
|
146
|
+
Use of `hast-to-hyperscript` can open you up to a
|
|
147
|
+
[cross-site scripting (XSS)][xss] attack if the hast tree is unsafe.
|
|
148
|
+
Use [`hast-util-sanitize`][sanitize] to make the hast tree safe.
|
|
149
|
+
|
|
150
|
+
## Related
|
|
151
|
+
|
|
152
|
+
* [`hastscript`][hastscript]
|
|
153
|
+
— Hyperscript compatible interface for creating nodes
|
|
154
|
+
* [`hast-util-sanitize`][sanitize]
|
|
155
|
+
— Sanitize nodes
|
|
156
|
+
* [`hast-util-from-dom`](https://github.com/syntax-tree/hast-util-from-dom)
|
|
157
|
+
— Transform a DOM tree to hast
|
|
158
|
+
* [`unist-builder`](https://github.com/syntax-tree/unist-builder)
|
|
159
|
+
— Create any unist tree
|
|
160
|
+
* [`xastscript`](https://github.com/syntax-tree/xastscript)
|
|
161
|
+
— Create a xast tree
|
|
162
|
+
|
|
163
|
+
## Contribute
|
|
164
|
+
|
|
165
|
+
See [`contributing.md` in `syntax-tree/.github`][contributing] for ways to get
|
|
166
|
+
started.
|
|
167
|
+
See [`support.md`][support] for ways to get help.
|
|
168
|
+
|
|
169
|
+
This project has a [code of conduct][coc].
|
|
170
|
+
By interacting with this repository, organization, or community you agree to
|
|
171
|
+
abide by its terms.
|
|
172
|
+
|
|
173
|
+
## License
|
|
174
|
+
|
|
175
|
+
[MIT][license] © [Titus Wormer][author]
|
|
176
|
+
|
|
177
|
+
<!-- Definitions -->
|
|
178
|
+
|
|
179
|
+
[build-badge]: https://github.com/syntax-tree/hast-to-hyperscript/workflows/main/badge.svg
|
|
180
|
+
|
|
181
|
+
[build]: https://github.com/syntax-tree/hast-to-hyperscript/actions
|
|
182
|
+
|
|
183
|
+
[coverage-badge]: https://img.shields.io/codecov/c/github/syntax-tree/hast-to-hyperscript.svg
|
|
184
|
+
|
|
185
|
+
[coverage]: https://codecov.io/github/syntax-tree/hast-to-hyperscript
|
|
186
|
+
|
|
187
|
+
[downloads-badge]: https://img.shields.io/npm/dm/hast-to-hyperscript.svg
|
|
188
|
+
|
|
189
|
+
[downloads]: https://www.npmjs.com/package/hast-to-hyperscript
|
|
190
|
+
|
|
191
|
+
[size-badge]: https://img.shields.io/bundlephobia/minzip/hast-to-hyperscript.svg
|
|
192
|
+
|
|
193
|
+
[size]: https://bundlephobia.com/result?p=hast-to-hyperscript
|
|
194
|
+
|
|
195
|
+
[sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg
|
|
196
|
+
|
|
197
|
+
[backers-badge]: https://opencollective.com/unified/backers/badge.svg
|
|
198
|
+
|
|
199
|
+
[collective]: https://opencollective.com/unified
|
|
200
|
+
|
|
201
|
+
[chat-badge]: https://img.shields.io/badge/chat-discussions-success.svg
|
|
202
|
+
|
|
203
|
+
[chat]: https://github.com/syntax-tree/unist/discussions
|
|
204
|
+
|
|
205
|
+
[npm]: https://docs.npmjs.com/cli/install
|
|
206
|
+
|
|
207
|
+
[license]: license
|
|
208
|
+
|
|
209
|
+
[author]: https://wooorm.com
|
|
210
|
+
|
|
211
|
+
[contributing]: https://github.com/syntax-tree/.github/blob/HEAD/contributing.md
|
|
212
|
+
|
|
213
|
+
[support]: https://github.com/syntax-tree/.github/blob/HEAD/support.md
|
|
214
|
+
|
|
215
|
+
[coc]: https://github.com/syntax-tree/.github/blob/HEAD/code-of-conduct.md
|
|
216
|
+
|
|
217
|
+
[vdom]: https://github.com/Matt-Esch/virtual-dom/tree/HEAD/virtual-hyperscript
|
|
218
|
+
|
|
219
|
+
[hyperscript]: https://github.com/hyperhype/hyperscript
|
|
220
|
+
|
|
221
|
+
[react]: https://reactjs.org/docs/glossary.html#react-elements
|
|
222
|
+
|
|
223
|
+
[vue]: https://vuejs.org/v2/guide/render-function.html#createElement-Arguments
|
|
224
|
+
|
|
225
|
+
[hastscript]: https://github.com/syntax-tree/hastscript
|
|
226
|
+
|
|
227
|
+
[tree]: https://github.com/syntax-tree/unist#tree
|
|
228
|
+
|
|
229
|
+
[child]: https://github.com/syntax-tree/unist#child
|
|
230
|
+
|
|
231
|
+
[type]: https://github.com/syntax-tree/unist#type
|
|
232
|
+
|
|
233
|
+
[descendant]: https://github.com/syntax-tree/unist#descendant
|
|
234
|
+
|
|
235
|
+
[hast]: https://github.com/syntax-tree/hast
|
|
236
|
+
|
|
237
|
+
[node]: https://github.com/syntax-tree/hast#nodes
|
|
238
|
+
|
|
239
|
+
[text]: https://github.com/syntax-tree/hast#text
|
|
240
|
+
|
|
241
|
+
[doctype]: https://github.com/syntax-tree/hast#doctype
|
|
242
|
+
|
|
243
|
+
[root]: https://github.com/syntax-tree/hast#root
|
|
244
|
+
|
|
245
|
+
[comment]: https://github.com/syntax-tree/hast#comment
|
|
246
|
+
|
|
247
|
+
[element]: https://github.com/syntax-tree/hast#element
|
|
248
|
+
|
|
249
|
+
[h]: #function-hname-attrs-children
|
|
250
|
+
|
|
251
|
+
[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting
|
|
252
|
+
|
|
253
|
+
[sanitize]: https://github.com/syntax-tree/hast-util-sanitize
|