hast-util-to-dom
Advanced tools
Comparing version 3.1.0 to 3.1.1
export {toDom} from './lib/index.js' | ||
export type AfterTransform = import('./lib/index.js').AfterTransform | ||
export type Options = import('./lib/index.js').Options |
/** | ||
* @typedef {import('./lib/index.js').AfterTransform} AfterTransform | ||
* @typedef {import('./lib/index.js').Options} Options | ||
@@ -3,0 +4,0 @@ */ |
/** | ||
* Transform a hast tree to a DOM tree | ||
* | ||
* @param {HastNode} node | ||
* @param {Options} [options] | ||
* @returns {Node} | ||
* @param {HastNode} tree | ||
* Tree to transform. | ||
* @param {Options | null | undefined} [options] | ||
* Configuration (optional). | ||
* @returns {XMLDocument | DocumentFragment | Text | DocumentType | Comment | Element} | ||
* Equivalent DOM node. | ||
*/ | ||
export function toDom(node: HastNode, options?: Options | undefined): Node | ||
export type HastParent = import('hast').Parent | ||
export function toDom( | ||
tree: HastNode, | ||
options?: Options | null | undefined | ||
): XMLDocument | DocumentFragment | Text | DocumentType | Comment | Element | ||
export type HastRoot = import('hast').Root | ||
@@ -15,32 +20,53 @@ export type HastDoctype = import('hast').DocType | ||
export type HastComment = import('hast').Comment | ||
export type HastChild = HastParent['children'][number] | ||
export type HastChild = import('hast').Content | ||
export type HastNode = HastChild | HastRoot | ||
/** | ||
* Function called when a hast node is transformed into a DOM node | ||
* callback called when each node is transformed. | ||
*/ | ||
export type AfterTransform = (hastNode: HastNode, domNode: Node) => void | ||
/** | ||
* Configuration. | ||
*/ | ||
export type Options = { | ||
/** | ||
* Whether a DOM fragment should be returned | ||
* Callback called when each node is transformed. | ||
*/ | ||
fragment?: boolean | undefined | ||
afterTransform?: AfterTransform | null | undefined | ||
/** | ||
* Document interface to use (default: `globalThis.document`) | ||
* Document interface to use (default: `globalThis.document`). | ||
*/ | ||
document?: Document | undefined | ||
document?: Document | null | undefined | ||
/** | ||
* `namespace` to use to create elements | ||
* Whether to return a DOM fragment (`true`) or a whole document (`false`). | ||
*/ | ||
namespace?: string | undefined | ||
fragment?: boolean | null | undefined | ||
/** | ||
* Callback invoked after each node transformation | ||
* Namespace to use to create elements. | ||
*/ | ||
afterTransform?: AfterTransform | undefined | ||
namespace?: string | null | undefined | ||
} | ||
export type Context = { | ||
/** | ||
* Info passed around about the current state. | ||
*/ | ||
export type State = { | ||
/** | ||
* Document interface to use. | ||
*/ | ||
doc: Document | ||
fragment?: boolean | undefined | ||
namespace?: string | undefined | ||
impliedNamespace?: string | undefined | ||
afterTransform?: AfterTransform | undefined | ||
/** | ||
* Whether a fragment (`true`) or whole document (`false`) is built. | ||
*/ | ||
fragment: boolean | ||
/** | ||
* Namespace to use. | ||
*/ | ||
namespace: string | undefined | ||
/** | ||
* To do. | ||
*/ | ||
impliedNamespace: string | undefined | ||
/** | ||
* Callback called after each hast node is transformed. | ||
*/ | ||
afterTransform: AfterTransform | undefined | ||
} |
345
lib/index.js
/** | ||
* @typedef {import('hast').Parent} HastParent | ||
* @typedef {import('hast').Root} HastRoot | ||
@@ -8,43 +7,81 @@ * @typedef {import('hast').DocType} HastDoctype | ||
* @typedef {import('hast').Comment} HastComment | ||
* @typedef {HastParent['children'][number]} HastChild | ||
* @typedef {HastChild|HastRoot} HastNode | ||
* @typedef {import('hast').Content} HastChild | ||
*/ | ||
/** | ||
* @typedef {HastChild | HastRoot} HastNode | ||
* | ||
* @callback AfterTransform | ||
* Function called when a hast node is transformed into a DOM node | ||
* Callback called when each node is transformed. | ||
* @param {HastNode} hastNode | ||
* The hast node that was handled | ||
* hast node that was handled. | ||
* @param {Node} domNode | ||
* The corresponding DOM node | ||
* Corresponding DOM node. | ||
* @returns {void} | ||
* Nothing. | ||
* | ||
* @typedef Options | ||
* @property {boolean} [fragment=false] | ||
* Whether a DOM fragment should be returned | ||
* @property {Document} [document] | ||
* Document interface to use (default: `globalThis.document`) | ||
* @property {string} [namespace] | ||
* `namespace` to use to create elements | ||
* @property {AfterTransform} [afterTransform] | ||
* Callback invoked after each node transformation | ||
* Configuration. | ||
* @property {AfterTransform | null | undefined} [afterTransform] | ||
* Callback called when each node is transformed. | ||
* @property {Document | null | undefined} [document] | ||
* Document interface to use (default: `globalThis.document`). | ||
* @property {boolean | null | undefined} [fragment=false] | ||
* Whether to return a DOM fragment (`true`) or a whole document (`false`). | ||
* @property {string | null | undefined} [namespace] | ||
* Namespace to use to create elements. | ||
* | ||
* @typedef Context | ||
* @typedef State | ||
* Info passed around about the current state. | ||
* @property {Document} doc | ||
* @property {boolean} [fragment=false] | ||
* @property {string} [namespace] | ||
* @property {string} [impliedNamespace] | ||
* @property {AfterTransform} [afterTransform] | ||
* Document interface to use. | ||
* @property {boolean} fragment | ||
* Whether a fragment (`true`) or whole document (`false`) is built. | ||
* @property {string | undefined} namespace | ||
* Namespace to use. | ||
* @property {string | undefined} impliedNamespace | ||
* To do. | ||
* @property {AfterTransform | undefined} afterTransform | ||
* Callback called after each hast node is transformed. | ||
*/ | ||
/* eslint-env browser */ | ||
import {webNamespaces} from 'web-namespaces' | ||
import {find, html, svg} from 'property-information' | ||
/* eslint-env browser */ | ||
const own = {}.hasOwnProperty | ||
/** | ||
* Transform a hast tree to a DOM tree | ||
* | ||
* @param {HastNode} tree | ||
* Tree to transform. | ||
* @param {Options | null | undefined} [options] | ||
* Configuration (optional). | ||
* @returns {XMLDocument | DocumentFragment | Text | DocumentType | Comment | Element} | ||
* Equivalent DOM node. | ||
*/ | ||
export function toDom(tree, options) { | ||
const config = options || {} | ||
return transform(tree, { | ||
doc: config.document || document, | ||
fragment: config.fragment || false, | ||
namespace: config.namespace || undefined, | ||
impliedNamespace: undefined, | ||
afterTransform: config.afterTransform || undefined | ||
}) | ||
} | ||
/** | ||
* @param {HastNode} node | ||
* @param {Context} ctx | ||
* Node to transform. | ||
* @param {State} state | ||
* Info passed around about the current state. | ||
* @returns {XMLDocument | DocumentFragment | Text | DocumentType | Comment | Element} | ||
* Equivalent DOM node. | ||
*/ | ||
function transform(node, ctx) { | ||
const transformed = one(node, ctx) | ||
if (ctx.afterTransform) ctx.afterTransform(node, transformed) | ||
function transform(node, state) { | ||
const transformed = one(node, state) | ||
if (state.afterTransform) state.afterTransform(node, transformed) | ||
return transformed | ||
@@ -54,19 +91,33 @@ } | ||
/** | ||
* Transform any hast node. | ||
* | ||
* @param {HastNode} node | ||
* @param {Context} ctx | ||
* Node to transform. | ||
* @param {State} state | ||
* Info passed around about the current state. | ||
* @returns {XMLDocument | DocumentFragment | Text | DocumentType | Comment | Element} | ||
* Equivalent DOM node. | ||
*/ | ||
function one(node, ctx) { | ||
function one(node, state) { | ||
switch (node.type) { | ||
case 'root': | ||
return root(node, ctx) | ||
case 'text': | ||
return text(node, ctx) | ||
case 'element': | ||
return element(node, ctx) | ||
case 'doctype': | ||
return doctype(node, ctx) | ||
case 'comment': | ||
return comment(node, ctx) | ||
default: | ||
return element(node, ctx) | ||
case 'root': { | ||
return root(node, state) | ||
} | ||
case 'text': { | ||
return text(node, state) | ||
} | ||
case 'doctype': { | ||
return doctype(node, state) | ||
} | ||
case 'comment': { | ||
return comment(node, state) | ||
} | ||
default: { | ||
// Important: unknown nodes are passed to `element`. | ||
return element(node, state) | ||
} | ||
} | ||
@@ -79,12 +130,14 @@ } | ||
* @param {HastRoot} node | ||
* @param {Context} ctx | ||
* @returns {XMLDocument|DocumentFragment|HTMLHtmlElement} | ||
* Node to transform. | ||
* @param {State} state | ||
* Info passed around about the current state. | ||
* @returns {XMLDocument | DocumentFragment | HTMLHtmlElement} | ||
* Equivalent DOM node. | ||
*/ | ||
function root(node, ctx) { | ||
const {doc, fragment, namespace: ctxNamespace} = ctx | ||
const {children = []} = node | ||
let namespace = ctxNamespace | ||
function root(node, state) { | ||
const children = node.children || [] | ||
let rootIsDocument = children.length === 0 | ||
let index = -1 | ||
/** @type {string | undefined} */ | ||
let foundNamespace | ||
@@ -95,32 +148,38 @@ while (++index < children.length) { | ||
if (child.type === 'element' && child.tagName === 'html') { | ||
const {properties = {}} = child | ||
// If we have a root HTML node, we don’t need to render as a fragment. | ||
rootIsDocument = true | ||
// Take namespace of the first child. | ||
if (ctxNamespace === undefined) { | ||
namespace = String(properties.xmlns || '') || webNamespaces.html | ||
} | ||
// Take namespace. | ||
foundNamespace = | ||
String((child.properties && child.properties.xmlns) || '') || | ||
webNamespaces.html | ||
break | ||
} | ||
} | ||
// The root node will be a Document, DocumentFragment, or HTMLElement. | ||
/** @type {XMLDocument|DocumentFragment|HTMLHtmlElement} */ | ||
const namespace = state.namespace || foundNamespace | ||
// The root node will be `Document`, `DocumentFragment`, or `HTMLElement`. | ||
/** @type {XMLDocument | DocumentFragment | HTMLHtmlElement} */ | ||
let result | ||
if (rootIsDocument) { | ||
result = doc.implementation.createDocument(namespace || null, '', null) | ||
} else if (fragment) { | ||
result = doc.createDocumentFragment() | ||
result = state.doc.implementation.createDocument( | ||
namespace || null, | ||
'', | ||
null | ||
) | ||
} else if (state.fragment) { | ||
result = state.doc.createDocumentFragment() | ||
} else { | ||
result = doc.createElement('html') | ||
result = state.doc.createElement('html') | ||
} | ||
return appendAll(result, children, { | ||
...ctx, | ||
fragment, | ||
appendAll(result, children, { | ||
...state, | ||
namespace, | ||
impliedNamespace: namespace | ||
}) | ||
return result | ||
} | ||
@@ -132,7 +191,10 @@ | ||
* @param {HastDoctype} _ | ||
* @param {Context} ctx | ||
* Node to transform. | ||
* @param {State} state | ||
* Info passed around about the current state. | ||
* @returns {DocumentType} | ||
* DOM document type. | ||
*/ | ||
function doctype(_, {doc}) { | ||
return doc.implementation.createDocumentType('html', '', '') | ||
function doctype(_, state) { | ||
return state.doc.implementation.createDocumentType('html', '', '') | ||
} | ||
@@ -144,7 +206,10 @@ | ||
* @param {HastText} node | ||
* @param {Context} ctx | ||
* Node to transform. | ||
* @param {State} state | ||
* Info passed around about the current state. | ||
* @returns {Text} | ||
* DOM text. | ||
*/ | ||
function text(node, {doc}) { | ||
return doc.createTextNode(node.value) | ||
function text(node, state) { | ||
return state.doc.createTextNode(node.value) | ||
} | ||
@@ -156,7 +221,10 @@ | ||
* @param {HastComment} node | ||
* @param {Context} ctx | ||
* Node to transform. | ||
* @param {State} state | ||
* Info passed around about the current state. | ||
* @returns {Comment} | ||
* DOM comment. | ||
*/ | ||
function comment(node, {doc}) { | ||
return doc.createComment(node.value) | ||
function comment(node, state) { | ||
return state.doc.createComment(node.value) | ||
} | ||
@@ -168,18 +236,20 @@ | ||
* @param {HastElement} node | ||
* @param {Context} ctx | ||
* Node to transform. | ||
* @param {State} state | ||
* Info passed around about the current state. | ||
* @returns {Element} | ||
* DOM element. | ||
*/ | ||
// eslint-disable-next-line complexity | ||
function element(node, ctx) { | ||
const {namespace, doc} = ctx | ||
let impliedNamespace = ctx.impliedNamespace || namespace | ||
const { | ||
tagName = impliedNamespace === webNamespaces.svg ? 'g' : 'div', | ||
properties = {}, | ||
children = [] | ||
} = node | ||
function element(node, state) { | ||
let impliedNamespace = state.impliedNamespace || state.namespace | ||
// Important: unknown nodes are passed to `element`. | ||
const tagName = | ||
node.tagName || (impliedNamespace === webNamespaces.svg ? 'g' : 'div') | ||
const properties = node.properties || {} | ||
const children = node.children || [] | ||
// Switch automatically from HTML to SVG on `<svg>`. | ||
if ( | ||
(impliedNamespace === null || | ||
impliedNamespace === undefined || | ||
(impliedNamespace === undefined || | ||
impliedNamespace === webNamespaces.html) && | ||
@@ -193,56 +263,50 @@ tagName === 'svg' | ||
const result = | ||
impliedNamespace === null || impliedNamespace === undefined | ||
? doc.createElement(tagName) | ||
: doc.createElementNS(impliedNamespace, tagName) | ||
const result = impliedNamespace | ||
? state.doc.createElementNS(impliedNamespace, tagName) | ||
: state.doc.createElement(tagName) | ||
// Add HTML attributes. | ||
const props = Object.keys(properties) | ||
const {length} = props | ||
/** @type {string} */ | ||
let key | ||
for (let i = 0; i < length; i += 1) { | ||
const key = props[i] | ||
for (key in properties) { | ||
if (own.call(properties, key)) { | ||
const info = find(schema, key) | ||
let value = properties[key] | ||
const { | ||
attribute, | ||
property, | ||
// `mustUseAttribute`, | ||
mustUseProperty, | ||
boolean, | ||
booleanish, | ||
overloadedBoolean, | ||
// `number`, | ||
// `defined`, | ||
commaSeparated | ||
// `spaceSeparated`, | ||
// `commaOrSpaceSeparated`, | ||
} = find(schema, key) | ||
if (Array.isArray(value)) { | ||
value = value.join(info.commaSeparated ? ', ' : ' ') | ||
} | ||
let value = properties[key] | ||
if (info.mustUseProperty) { | ||
// @ts-expect-error: fine. | ||
result[info.property] = value | ||
} | ||
if (Array.isArray(value)) { | ||
value = value.join(commaSeparated ? ', ' : ' ') | ||
} | ||
if (mustUseProperty) { | ||
// @ts-expect-error: fine. | ||
result[property] = value | ||
} | ||
if (boolean || (overloadedBoolean && typeof value === 'boolean')) { | ||
if (value) { | ||
result.setAttribute(attribute, '') | ||
} else { | ||
result.removeAttribute(attribute) | ||
if ( | ||
info.boolean || | ||
(info.overloadedBoolean && typeof value === 'boolean') | ||
) { | ||
if (value) { | ||
result.setAttribute(info.attribute, '') | ||
} else { | ||
result.removeAttribute(info.attribute) | ||
} | ||
} else if (info.booleanish) { | ||
result.setAttribute(info.attribute, String(value)) | ||
} else if (value === true) { | ||
result.setAttribute(info.attribute, '') | ||
} else if (value || value === 0 || value === '') { | ||
result.setAttribute(info.attribute, String(value)) | ||
} | ||
} else if (booleanish) { | ||
result.setAttribute(attribute, String(value)) | ||
} else if (value === true) { | ||
result.setAttribute(attribute, '') | ||
} else if (value || value === 0 || value === '') { | ||
result.setAttribute(attribute, String(value)) | ||
} | ||
} | ||
return appendAll(result, children, {...ctx, impliedNamespace}) | ||
const currentImpliedNamespace = state.impliedNamespace | ||
state.impliedNamespace = impliedNamespace | ||
appendAll(result, children, state) | ||
state.impliedNamespace = currentImpliedNamespace | ||
return result | ||
} | ||
@@ -253,9 +317,12 @@ | ||
* | ||
* @template {Node} N | ||
* @param {N} node | ||
* @param {Array.<HastChild>} children | ||
* @param {Context} ctx | ||
* @returns {N} | ||
* @param {Node} node | ||
* DOM node to append to. | ||
* @param {Array<HastChild>} children | ||
* hast children. | ||
* @param {State} state | ||
* Info passed around about the current state. | ||
* @returns {void} | ||
* Nothing. | ||
*/ | ||
function appendAll(node, children, ctx) { | ||
function appendAll(node, children, state) { | ||
let index = -1 | ||
@@ -265,18 +332,4 @@ | ||
// eslint-disable-next-line unicorn/prefer-dom-node-append | ||
node.appendChild(transform(children[index], ctx)) | ||
node.appendChild(transform(children[index], state)) | ||
} | ||
return node | ||
} | ||
/** | ||
* Transform a hast tree to a DOM tree | ||
* | ||
* @param {HastNode} node | ||
* @param {Options} [options] | ||
* @returns {Node} | ||
*/ | ||
export function toDom(node, options = {}) { | ||
const {document: doc = document, ...rest} = options | ||
return transform(node, {doc, ...rest}) | ||
} |
{ | ||
"name": "hast-util-to-dom", | ||
"version": "3.1.0", | ||
"version": "3.1.1", | ||
"description": "hast utility to transform to the DOM", | ||
@@ -41,26 +41,22 @@ "license": "ISC", | ||
"devDependencies": { | ||
"@types/glob": "^7.0.0", | ||
"@types/jsdom": "^16.0.0", | ||
"@types/tape": "^4.0.0", | ||
"@types/jsdom": "^20.0.0", | ||
"@types/node": "^18.0.0", | ||
"@types/w3c-xmlserializer": "^2.0.0", | ||
"c8": "^7.0.0", | ||
"glob": "^7.0.0", | ||
"hastscript": "^7.0.0", | ||
"jsdom": "^19.0.0", | ||
"jsdom": "^20.0.0", | ||
"prettier": "^2.0.0", | ||
"remark-cli": "^10.0.0", | ||
"remark-cli": "^11.0.0", | ||
"remark-preset-wooorm": "^9.0.0", | ||
"rimraf": "^3.0.0", | ||
"tape": "^5.0.0", | ||
"type-coverage": "^2.0.0", | ||
"typescript": "^4.0.0", | ||
"w3c-xmlserializer": "^3.0.0", | ||
"xo": "^0.47.0" | ||
"w3c-xmlserializer": "^4.0.0", | ||
"xo": "^0.53.0" | ||
}, | ||
"scripts": { | ||
"prepack": "npm run build && npm run format", | ||
"build": "rimraf \"{lib/**,test/**,}*.d.ts\" && tsc && type-coverage", | ||
"build": "tsc --build --clean && tsc --build && type-coverage", | ||
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix", | ||
"test-api": "node test/index.js", | ||
"test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov node test/index.js", | ||
"test-api": "node --conditions development test/index.js", | ||
"test-coverage": "c8 --check-coverage --100 --reporter lcov npm run test-api", | ||
"test": "npm run build && npm run format && npm run test-coverage" | ||
@@ -77,3 +73,13 @@ }, | ||
"xo": { | ||
"prettier": true | ||
"prettier": true, | ||
"overrides": [ | ||
{ | ||
"files": [ | ||
"test/**/*.js" | ||
], | ||
"rules": { | ||
"no-await-in-loop": 0 | ||
} | ||
} | ||
] | ||
}, | ||
@@ -80,0 +86,0 @@ "remarkConfig": { |
212
readme.md
@@ -11,11 +11,46 @@ # hast-util-to-dom | ||
[**hast**][hast] utility to transform to a DOM tree. | ||
[hast][] utility to transform to a [DOM][] tree. | ||
## Contents | ||
* [What is this?](#what-is-this) | ||
* [When should I use this?](#when-should-i-use-this) | ||
* [Install](#install) | ||
* [Use](#use) | ||
* [API](#api) | ||
* [`toDom(tree[, options])`](#todomtree-options) | ||
* [`AfterTransform`](#aftertransform) | ||
* [`Options`](#options) | ||
* [Syntax tree](#syntax-tree) | ||
* [Types](#types) | ||
* [Compatibility](#compatibility) | ||
* [Security](#security) | ||
* [Related](#related) | ||
* [Contribute](#contribute) | ||
* [License](#license) | ||
## What is this? | ||
This package is a utility that creates a DOM tree (defaulting to the actual DOM | ||
but also supporting things like [`jsdom`][jsdom]) from a [hast][] (HTML) syntax | ||
tree. | ||
## When should I use this? | ||
You can use this project when you want to turn hast into a DOM in browsers, | ||
either to use it directly on a page, or to enable the use of DOM APIs (such as | ||
`querySelector` to find things or `innerHTML` to serialize stuff). | ||
The hast utility [`hast-util-from-dom`][hast-util-from-dom] does the inverse of | ||
this utility. | ||
It turns DOM trees into hast. | ||
The rehype plugin [`rehype-dom-stringify`][rehype-dom-stringify] wraps this | ||
utility to serialize as HTML with DOM APIs. | ||
## Install | ||
This package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c): | ||
Node 12+ is needed to use it and it must be `import`ed instead of `require`d. | ||
This package is [ESM only][esm]. | ||
In Node.js (version 14.14+ or 16.0+), install with [npm][]: | ||
[npm][]: | ||
```sh | ||
@@ -25,75 +60,106 @@ npm install hast-util-to-dom | ||
## Use | ||
In Deno with [`esm.sh`][esmsh]: | ||
This utility is intended for browser use! | ||
```js | ||
import {toDom} from 'hast-util-to-dom'; | ||
const el = toDom({ | ||
type: 'element', | ||
tagName: 'h1', | ||
properties: {}, | ||
children: [{type: 'text', value: 'World!'}] | ||
}); | ||
console.log(el); | ||
import {toDom} from 'https://esm.sh/hast-util-to-dom@3' | ||
``` | ||
This will create a DOM node like this: | ||
In browsers with [`esm.sh`][esmsh]: | ||
```html | ||
<h1>World!</h1> | ||
<script type="module"> | ||
import {toDom} from 'https://esm.sh/hast-util-to-dom@3?bundle' | ||
</script> | ||
``` | ||
If you want a string of HTML, you have a few options: | ||
## Use | ||
```js | ||
// Outer HTML, eg. if you want an entire fragment | ||
console.log(el.outerHTML); | ||
// "<h1>World</h1>" | ||
Say our page `example.html` looks as follows: | ||
// Inner HTML, eg. if you have a wrapping element you don't need | ||
console.log(el.innerHTML); | ||
// "World" | ||
```html | ||
<!doctype html> | ||
<title>Example</title> | ||
<body> | ||
<script type="module"> | ||
import {h} from 'https://esm.sh/hastscript?bundle' | ||
import {toDom} from 'https://esm.sh/hast-util-to-dom?bundle' | ||
// Full serialization, eg. when you want the whole document | ||
console.log(new XMLSerializer().serializeToString(el)); | ||
// "<div xmlns="http://www.w3.org/1999/xhtml">World</div>" | ||
const tree = h('main', [ | ||
h('h1', 'Hi'), | ||
h('p', [h('em', 'Hello'), ', world!']) | ||
]) | ||
document.body.append(toDom(tree)) | ||
</script> | ||
``` | ||
Due to the nature of various browser implementations, you may notice | ||
cross-browser differences in the serialized output, especially with respect to | ||
whitespace or self-closing tags. | ||
Buddy, that’s the web! | ||
Now running `open example.html` shows the `main`, `h1`, and `p` elements on the | ||
page. | ||
## API | ||
This package exports the following identifiers: `toDom`. | ||
This package exports the identifier [`toDom`][to-dom]. | ||
There is no default export. | ||
### `toDom(node[, options])` | ||
### `toDom(tree[, options])` | ||
Transform a [**hast**][hast] [*tree*][tree] to a DOM tree. | ||
Turn a hast tree into a DOM tree. | ||
##### `options` | ||
###### Parameters | ||
###### `options.fragment` | ||
* `tree` ([`HastNode`][hast-node]) | ||
— tree to transform | ||
* `options` ([`Options`][options], optional) | ||
— configuration | ||
Whether a DOM fragment should be returned (default: `false`). | ||
###### Returns | ||
###### `options.document` | ||
DOM node ([`DomNode`][dom-node]). | ||
Document interface to use (default: `globalThis.document`). | ||
### `AfterTransform` | ||
###### `options.namespace` | ||
Callback called when each node is transformed (TypeScript type). | ||
`namespace` to use to create [*elements*][element]. | ||
###### Parameters | ||
###### `options.afterTransform` | ||
* `hastNode` ([`HastNode`][hast-node]) | ||
— hast node that was handled | ||
* `domNode` ([`DomNode`][dom-node]) | ||
— corresponding DOM node | ||
Function called when a hast node is transformed into a DOM node (`Function?`). | ||
Given the hast node that was handled as the first parameter and the | ||
corresponding DOM node as the second parameter. | ||
###### Returns | ||
Nothing. | ||
### `Options` | ||
Configuration (TypeScript type). | ||
###### Fields | ||
* `afterTransform` ([`AfterTransform`][aftertransform], optional) | ||
— callback called when each node is transformed | ||
* `document` (`Document`, default: `globalThis.document`) | ||
— document interface to use. | ||
* `fragment` (`boolean`, default: `false`) | ||
— whether to return a DOM fragment (`true`) or a whole document (`false`) | ||
* `namespace` (`string`, default: depends) | ||
— namespace to use to create elements | ||
## Syntax tree | ||
The syntax tree is [hast][]. | ||
## Types | ||
This package is fully typed with [TypeScript][]. | ||
It exports the additional types `AfterTransform` and `Options`. | ||
## Compatibility | ||
Projects maintained by the unified collective are compatible with all maintained | ||
versions of Node.js. | ||
As of now, that is Node.js 14.14+ and 16.0+. | ||
Our projects sometimes work with older versions, but this is not guaranteed. | ||
## Security | ||
@@ -103,3 +169,3 @@ | ||
[cross-site scripting (XSS)][xss] attack if the hast tree is unsafe. | ||
Use [`hast-util-santize`][sanitize] to make the hast tree safe. | ||
Use [`hast-util-santize`][hast-util-sanitize] to make the hast tree safe. | ||
@@ -109,12 +175,12 @@ ## Related | ||
* [`hast-util-sanitize`](https://github.com/syntax-tree/hast-util-sanitize) | ||
— Sanitize hast nodes | ||
— sanitize hast nodes | ||
* [`hast-util-to-html`](https://github.com/syntax-tree/hast-util-to-html) | ||
— Create an HTML string | ||
— serialize as HTML | ||
* [`hast-util-from-dom`](https://github.com/syntax-tree/hast-util-from-dom) | ||
— Create a hast tree from a DOM tree | ||
— create a hast tree from a DOM tree | ||
## Contribute | ||
See [`contributing.md` in `syntax-tree/.github`][contributing] for ways to get | ||
started. | ||
See [`contributing.md`][contributing] in [`syntax-tree/.github`][health] for | ||
ways to get started. | ||
See [`support.md`][support] for ways to get help. | ||
@@ -160,2 +226,8 @@ | ||
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c | ||
[esmsh]: https://esm.sh | ||
[typescript]: https://www.typescriptlang.org | ||
[license]: license | ||
@@ -165,16 +237,32 @@ | ||
[contributing]: https://github.com/syntax-tree/.github/blob/HEAD/contributing.md | ||
[health]: https://github.com/syntax-tree/.github | ||
[support]: https://github.com/syntax-tree/.github/blob/HEAD/support.md | ||
[contributing]: https://github.com/syntax-tree/.github/blob/main/contributing.md | ||
[coc]: https://github.com/syntax-tree/.github/blob/HEAD/code-of-conduct.md | ||
[support]: https://github.com/syntax-tree/.github/blob/main/support.md | ||
[coc]: https://github.com/syntax-tree/.github/blob/main/code-of-conduct.md | ||
[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting | ||
[hast-util-sanitize]: https://github.com/syntax-tree/hast-util-sanitize | ||
[hast-util-from-dom]: https://github.com/syntax-tree/hast-util-from-dom | ||
[jsdom]: https://github.com/jsdom/jsdom | ||
[rehype-dom-stringify]: https://github.com/rehypejs/rehype-dom/tree/main/packages/rehype-dom-stringify | ||
[hast]: https://github.com/syntax-tree/hast | ||
[element]: https://github.com/syntax-tree/hast#element | ||
[hast-node]: https://github.com/syntax-tree/hast#nodes | ||
[tree]: https://github.com/syntax-tree/unist#tree | ||
[dom]: https://developer.mozilla.org/docs/Web/API/Document_Object_Model | ||
[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting | ||
[dom-node]: https://developer.mozilla.org/docs/Web/API/Node | ||
[sanitize]: https://github.com/syntax-tree/hast-util-sanitize | ||
[to-dom]: #todomtree-options | ||
[aftertransform]: #aftertransform | ||
[options]: #options |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
20637
13
365
263
1