diff --git a/.editorconfig b/.editorconfig index c6c8b36..0f17867 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,9 +1,9 @@ root = true [*] -indent_style = space -indent_size = 2 -end_of_line = lf charset = utf-8 -trim_trailing_whitespace = true +end_of_line = lf +indent_size = 2 +indent_style = space insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.github/workflows/bb.yml b/.github/workflows/bb.yml index 0198fc3..3dbfce5 100644 --- a/.github/workflows/bb.yml +++ b/.github/workflows/bb.yml @@ -1,9 +1,3 @@ -name: bb -on: - issues: - types: [opened, reopened, edited, closed, labeled, unlabeled] - pull_request_target: - types: [opened, reopened, edited, closed, labeled, unlabeled] jobs: main: runs-on: ubuntu-latest @@ -11,3 +5,9 @@ jobs: - uses: unifiedjs/beep-boop-beta@main with: repo-token: ${{secrets.GITHUB_TOKEN}} +name: bb +on: + issues: + types: [closed, edited, labeled, opened, reopened, unlabeled] + pull_request_target: + types: [closed, edited, labeled, opened, reopened, unlabeled] diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fb63387..ade3921 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,21 +1,21 @@ -name: main -on: - - pull_request - - push jobs: main: name: ${{matrix.node}} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: node-version: ${{matrix.node}} - run: npm install - run: npm test - - uses: codecov/codecov-action@v3 + - uses: codecov/codecov-action@v5 strategy: matrix: node: - - lts/gallium + - lts/hydrogen - node +name: main +on: + - pull_request + - push diff --git a/.gitignore b/.gitignore index c977c85..388388c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ -.DS_Store *.d.ts *.log +*.map +*.tsbuildinfo +.DS_Store coverage/ node_modules/ yarn.lock diff --git a/lib/handle/comment.js b/lib/handle/comment.js index 6e16d1f..3a49064 100644 --- a/lib/handle/comment.js +++ b/lib/handle/comment.js @@ -1,12 +1,16 @@ /** - * @typedef {import('hast').Comment} Comment - * @typedef {import('hast').Parents} Parents - * - * @typedef {import('../index.js').State} State + * @import {Comment, Parents} from 'hast' + * @import {State} from '../index.js' */ import {stringifyEntities} from 'stringify-entities' +const htmlCommentRegex = /^>|^->||--!>|'] +const commentEntitySubset = ['<', '>'] + /** * Serialize a comment. * @@ -27,10 +31,12 @@ export function comment(node, _1, _2, state) { ? '']}) + Object.assign({}, state.settings.characterReferences, { + subset: bogusCommentEntitySubset + }) ) + '>' - : '|--!>|' + : '' /** * @param {string} $0 @@ -39,7 +45,7 @@ export function comment(node, _1, _2, state) { return stringifyEntities( $0, Object.assign({}, state.settings.characterReferences, { - subset: ['<', '>'] + subset: commentEntitySubset }) ) } diff --git a/lib/handle/doctype.js b/lib/handle/doctype.js index d2b9c4a..36b43ad 100644 --- a/lib/handle/doctype.js +++ b/lib/handle/doctype.js @@ -1,13 +1,8 @@ /** - * @typedef {import('hast').Doctype} Doctype - * @typedef {import('hast').Parents} Parents - * - * @typedef {import('../index.js').State} State + * @import {Doctype, Parents} from 'hast' + * @import {State} from '../index.js' */ -// Make VS code see references to the above types. -'' - /** * Serialize a doctype. * diff --git a/lib/handle/element.js b/lib/handle/element.js index 0d78677..17d9470 100644 --- a/lib/handle/element.js +++ b/lib/handle/element.js @@ -1,9 +1,6 @@ /** - * @typedef {import('hast').Element} Element - * @typedef {import('hast').Parents} Parents - * @typedef {import('hast').Properties} Properties - * - * @typedef {import('../index.js').State} State + * @import {Element, Parents, Properties} from 'hast' + * @import {State} from '../index.js' */ import {ccount} from 'ccount' @@ -76,7 +73,7 @@ export function element(node, index, parent, state) { state.schema = svg } - const attrs = serializeAttributes(state, node.properties) + const attributes = serializeAttributes(state, node.properties) const content = state.all( schema.space === 'html' && node.tagName === 'template' ? node.content : node @@ -92,14 +89,14 @@ export function element(node, index, parent, state) { // longer void. if (content) selfClosing = false - if (attrs || !omit || !opening(node, index, parent)) { - parts.push('<', node.tagName, attrs ? ' ' + attrs : '') + if (attributes || !omit || !opening(node, index, parent)) { + parts.push('<', node.tagName, attributes ? ' ' + attributes : '') if ( selfClosing && (schema.space === 'svg' || state.settings.closeSelfClosing) ) { - last = attrs.charAt(attrs.length - 1) + last = attributes.charAt(attributes.length - 1) if ( !state.settings.tightSelfClosing || last === '/' || @@ -125,20 +122,20 @@ export function element(node, index, parent, state) { /** * @param {State} state - * @param {Properties | null | undefined} props + * @param {Properties | null | undefined} properties * @returns {string} */ -function serializeAttributes(state, props) { +function serializeAttributes(state, properties) { /** @type {Array} */ const values = [] let index = -1 /** @type {string} */ let key - if (props) { - for (key in props) { - if (props[key] !== null && props[key] !== undefined) { - const value = serializeAttribute(state, key, props[key]) + if (properties) { + for (key in properties) { + if (properties[key] !== null && properties[key] !== undefined) { + const value = serializeAttribute(state, key, properties[key]) if (value) values.push(value) } } @@ -176,8 +173,8 @@ function serializeAttribute(state, key, value) { if (info.overloadedBoolean && (value === info.attribute || value === '')) { value = true } else if ( - info.boolean || - (info.overloadedBoolean && typeof value !== 'string') + (info.boolean || info.overloadedBoolean) && + (typeof value !== 'string' || value === info.attribute || value === '') ) { value = Boolean(value) } diff --git a/lib/handle/index.js b/lib/handle/index.js index e861c01..31401e1 100644 --- a/lib/handle/index.js +++ b/lib/handle/index.js @@ -1,8 +1,6 @@ /** - * @typedef {import('hast').Nodes} Nodes - * @typedef {import('hast').Parents} Parents - * - * @typedef {import('../index.js').State} State + * @import {Nodes, Parents} from 'hast' + * @import {State} from '../index.js' */ import {zwitch} from 'zwitch' diff --git a/lib/handle/raw.js b/lib/handle/raw.js index 6c89a11..834ab92 100644 --- a/lib/handle/raw.js +++ b/lib/handle/raw.js @@ -1,9 +1,7 @@ /** - * @typedef {import('hast').Parents} Parents - * - * @typedef {import('mdast-util-to-hast').Raw} Raw - * - * @typedef {import('../index.js').State} State + * @import {Parents} from 'hast' + * @import {Raw} from 'mdast-util-to-hast' + * @import {State} from '../index.js' */ import {text} from './text.js' diff --git a/lib/handle/root.js b/lib/handle/root.js index ccd84e1..97ef35b 100644 --- a/lib/handle/root.js +++ b/lib/handle/root.js @@ -1,13 +1,8 @@ /** - * @typedef {import('hast').Parents} Parents - * @typedef {import('hast').Root} Root - * - * @typedef {import('../index.js').State} State + * @import {Parents, Root} from 'hast' + * @import {State} from '../index.js' */ -// Make VS code see references to the above types. -'' - /** * Serialize a root. * diff --git a/lib/handle/text.js b/lib/handle/text.js index de25941..03cefde 100644 --- a/lib/handle/text.js +++ b/lib/handle/text.js @@ -1,14 +1,14 @@ /** - * @typedef {import('hast').Parents} Parents - * @typedef {import('hast').Text} Text - * - * @typedef {import('mdast-util-to-hast').Raw} Raw - * - * @typedef {import('../index.js').State} State + * @import {Parents, Text} from 'hast' + * @import {Raw} from 'mdast-util-to-hast' + * @import {State} from '../index.js' */ import {stringifyEntities} from 'stringify-entities' +// Declare array as variable so it can be cached by `stringifyEntities` +const textEntitySubset = ['<', '&'] + /** * Serialize a text node. * @@ -32,7 +32,7 @@ export function text(node, _, parent, state) { : stringifyEntities( node.value, Object.assign({}, state.settings.characterReferences, { - subset: ['<', '&'] + subset: textEntitySubset }) ) } diff --git a/lib/index.js b/lib/index.js index 93bb730..05da5b5 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,11 +1,7 @@ /** - * @typedef {import('hast').Nodes} Nodes - * @typedef {import('hast').Parents} Parents - * @typedef {import('hast').RootContent} RootContent - * - * @typedef {import('property-information').Schema} Schema - * - * @typedef {import('stringify-entities').Options} StringifyEntitiesOptions + * @import {Nodes, Parents, RootContent} from 'hast' + * @import {Schema} from 'property-information' + * @import {Options as StringifyEntitiesOptions} from 'stringify-entities' */ /** @@ -77,10 +73,10 @@ * Leave attributes unquoted if that results in less bytes (default: `false`). * * Not used in the SVG space. - * @property {Quote | null | undefined} [quote='"'] - * Preferred quote to use (default: `'"'`). * @property {boolean | null | undefined} [quoteSmart=false] * Use the other quote if that results in less bytes (default: `false`). + * @property {Quote | null | undefined} [quote='"'] + * Preferred quote to use (default: `'"'`). * @property {Space | null | undefined} [space='html'] * When an `` element is found in the HTML space, this package already * automatically switches to and from the SVG space when entering and exiting @@ -138,18 +134,18 @@ * * @typedef State * Info passed around about the current state. - * @property {(node: Nodes, index: number | undefined, parent: Parents | undefined) => string} one - * Serialize one node. * @property {(node: Parents | undefined) => string} all * Serialize the children of a parent node. - * @property {Settings} settings - * User configuration. - * @property {Schema} schema - * Current schema. - * @property {Quote} quote - * Preferred quote. * @property {Quote} alternative * Alternative quote. + * @property {(node: Nodes, index: number | undefined, parent: Parents | undefined) => string} one + * Serialize one node. + * @property {Quote} quote + * Preferred quote. + * @property {Schema} schema + * Current schema. + * @property {Settings} settings + * User configuration. */ import {htmlVoidElements} from 'html-void-elements' diff --git a/lib/omission/closing.js b/lib/omission/closing.js index a7cd1a1..b30baf7 100644 --- a/lib/omission/closing.js +++ b/lib/omission/closing.js @@ -1,6 +1,5 @@ /** - * @typedef {import('hast').Element} Element - * @typedef {import('hast').Parents} Parents + * @import {Element, Parents} from 'hast' */ import {whitespace} from 'hast-util-whitespace' diff --git a/lib/omission/omission.js b/lib/omission/omission.js index 692101c..902f38f 100644 --- a/lib/omission/omission.js +++ b/lib/omission/omission.js @@ -1,6 +1,5 @@ /** - * @typedef {import('hast').Element} Element - * @typedef {import('hast').Parents} Parents + * @import {Element, Parents} from 'hast' */ /** diff --git a/lib/omission/opening.js b/lib/omission/opening.js index 65c9964..54e3520 100644 --- a/lib/omission/opening.js +++ b/lib/omission/opening.js @@ -1,6 +1,5 @@ /** - * @typedef {import('hast').Element} Element - * @typedef {import('hast').Parents} Parents + * @import {Element, Parents} from 'hast' */ import {whitespace} from 'hast-util-whitespace' @@ -38,23 +37,25 @@ function html(node) { * Whether the opening tag can be omitted. */ function head(node) { - const children = node.children - /** @type {Array} */ - const seen = [] - let index = -1 + /** @type {Set} */ + const seen = new Set() - while (++index < children.length) { - const child = children[index] + // Whether `srcdoc` or not, + // make sure the content model at least doesn’t have too many `base`s/`title`s. + for (const child of node.children) { if ( child.type === 'element' && - (child.tagName === 'title' || child.tagName === 'base') + (child.tagName === 'base' || child.tagName === 'title') ) { - if (seen.includes(child.tagName)) return false - seen.push(child.tagName) + if (seen.has(child.tagName)) return false + seen.add(child.tagName) } } - return children.length > 0 + // “May be omitted if the element is empty, + // or if the first thing inside the head element is an element.” + const child = node.children[0] + return !child || child.type === 'element' } /** diff --git a/lib/omission/util/siblings.js b/lib/omission/util/siblings.js index c686a17..09edae4 100644 --- a/lib/omission/util/siblings.js +++ b/lib/omission/util/siblings.js @@ -1,6 +1,5 @@ /** - * @typedef {import('hast').Parents} Parents - * @typedef {import('hast').RootContent} RootContent + * @import {Parents, RootContent} from 'hast' */ import {whitespace} from 'hast-util-whitespace' diff --git a/license b/license index 8d8660d..bc8f165 100644 --- a/license +++ b/license @@ -1,6 +1,6 @@ (The MIT License) -Copyright (c) 2016 Titus Wormer +Copyright (c) Titus Wormer Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/package.json b/package.json index 7596569..b1ea5a1 100644 --- a/package.json +++ b/package.json @@ -1,71 +1,58 @@ { - "name": "hast-util-to-html", - "version": "9.0.0", - "description": "hast utility to serialize to HTML", - "license": "MIT", - "keywords": [ - "unist", - "hast", - "hast-util", - "util", - "utility", - "html", - "serialize", - "stringify", - "tostring" - ], - "repository": "syntax-tree/hast-util-to-html", - "bugs": "https://github.com/syntax-tree/hast-util-to-html/issues", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - }, "author": "Titus Wormer (https://wooorm.com)", + "bugs": "https://github.com/syntax-tree/hast-util-to-html/issues", "contributors": [ "Titus Wormer (https://wooorm.com)" ], - "sideEffects": false, - "type": "module", - "exports": "./index.js", - "files": [ - "lib/", - "index.d.ts", - "index.js" - ], "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "comma-separated-tokens": "^2.0.0", - "hast-util-raw": "^9.0.0", "hast-util-whitespace": "^3.0.0", "html-void-elements": "^3.0.0", "mdast-util-to-hast": "^13.0.0", - "property-information": "^6.0.0", + "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "stringify-entities": "^4.0.0", "zwitch": "^2.0.4" }, + "description": "hast utility to serialize to HTML", "devDependencies": { - "@types/node": "^20.0.0", - "c8": "^8.0.0", - "hastscript": "^8.0.0", + "@types/node": "^22.0.0", + "c8": "^10.0.0", + "hastscript": "^9.0.0", "prettier": "^3.0.0", - "remark-cli": "^11.0.0", - "remark-preset-wooorm": "^9.0.0", + "remark-cli": "^12.0.0", + "remark-preset-wooorm": "^11.0.0", "type-coverage": "^2.0.0", "typescript": "^5.0.0", - "unist-builder": "^4.0.0", - "xo": "^0.55.0" + "xo": "^0.60.0" }, - "scripts": { - "prepack": "npm run build && npm run format", - "build": "tsc --build --clean && tsc --build && type-coverage", - "format": "remark . -qfo && prettier . -w --log-level warn && xo --fix", - "test-api": "node --conditions development test/index.js", - "test-coverage": "c8 --100 --reporter lcov npm run test-api", - "test": "npm run build && npm run format && npm run test-coverage" + "exports": "./index.js", + "files": [ + "index.d.ts.map", + "index.d.ts", + "index.js", + "lib/" + ], + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" }, + "keywords": [ + "hast-util", + "hast", + "html", + "serialize", + "stringify", + "tostring", + "unist", + "utility", + "util" + ], + "license": "MIT", + "name": "hast-util-to-html", "prettier": { "bracketSpacing": false, "semi": false, @@ -83,12 +70,21 @@ ] ] }, + "repository": "syntax-tree/hast-util-to-html", + "scripts": { + "build": "tsc --build --clean && tsc --build && type-coverage", + "format": "remark --frail --output --quiet -- . && prettier --log-level warn --write -- . && xo --fix", + "test-api": "node --conditions development test/index.js", + "test-coverage": "c8 --100 --reporter lcov -- npm run test-api", + "test": "npm run build && npm run format && npm run test-coverage" + }, + "sideEffects": false, "typeCoverage": { "atLeast": 100, - "detail": true, - "ignoreCatch": true, "strict": true }, + "type": "module", + "version": "9.0.5", "xo": { "overrides": [ { diff --git a/readme.md b/readme.md index 8790ee5..9a48597 100644 --- a/readme.md +++ b/readme.md @@ -1,34 +1,31 @@ # hast-util-to-html -[![Build][build-badge]][build] -[![Coverage][coverage-badge]][coverage] -[![Downloads][downloads-badge]][downloads] -[![Size][size-badge]][size] -[![Sponsors][sponsors-badge]][collective] -[![Backers][backers-badge]][collective] -[![Chat][chat-badge]][chat] +[![Build][badge-build-image]][badge-build-url] +[![Coverage][badge-coverage-image]][badge-coverage-url] +[![Downloads][badge-downloads-image]][badge-downloads-url] +[![Size][badge-size-image]][badge-size-url] -[hast][] utility to serialize hast as HTML. +[hast][github-hast] utility to serialize hast as HTML. ## Contents -* [What is this?](#what-is-this) -* [When should I use this?](#when-should-i-use-this) -* [Install](#install) -* [Use](#use) -* [API](#api) - * [`toHtml(tree[, options])`](#tohtmltree-options) - * [`CharacterReferences`](#characterreferences) - * [`Options`](#options) - * [`Quote`](#quote-1) - * [`Space`](#space-1) -* [Syntax](#syntax) -* [Types](#types) -* [Compatibility](#compatibility) -* [Security](#security) -* [Related](#related) -* [Contribute](#contribute) -* [License](#license) +* [What is this?](#what-is-this) +* [When should I use this?](#when-should-i-use-this) +* [Install](#install) +* [Use](#use) +* [API](#api) + * [`toHtml(tree[, options])`](#tohtmltree-options) + * [`CharacterReferences`](#characterreferences) + * [`Options`](#options) + * [`Quote`](#quote-1) + * [`Space`](#space-1) +* [Syntax](#syntax) +* [Types](#types) +* [Compatibility](#compatibility) +* [Security](#security) +* [Related](#related) +* [Contribute](#contribute) +* [License](#license) ## What is this? @@ -37,25 +34,27 @@ This package is a utility that turns a hast tree into a string of HTML. ## When should I use this? You can use this utility when you want to get the serialized HTML that is -represented by the syntax tree, either because you’re done with the syntax -tree, or because you’re integrating with another tool that does not support -syntax trees. +represented by the syntax tree, +either because you’re done with the syntax tree, +or because you’re integrating with another tool that does not support syntax +trees. This utility has many options to configure how the HTML is serialized. These options help when building tools that make output pretty (such as formatters) or ugly (such as minifiers). -The utility [`hast-util-from-html`][hast-util-from-html] does the inverse of -this utility. +The utility [`hast-util-from-html`][github-hast-util-from-html] does the +inverse of this utility. It turns HTML into hast. -The rehype plugin [`rehype-stringify`][rehype-stringify] wraps this utility to -also serialize HTML at a higher-level (easier) abstraction. +The rehype plugin [`rehype-stringify`][github-rehype-stringify] wraps this +utility to also serialize HTML at a higher-level (easier) abstraction. ## Install -This package is [ESM only][esm]. -In Node.js (version 16+), install with [npm][]: +This package is [ESM only][github-gist-esm]. +In Node.js (version 16+), +install with [npm][npmjs-install]: ```sh npm install hast-util-to-html @@ -64,32 +63,24 @@ npm install hast-util-to-html In Deno with [`esm.sh`][esmsh]: ```js -import {toHtml} from "https://esm.sh/hast-util-to-html@9" +import {toHtml} from 'https://esm.sh/hast-util-to-html@9' ``` In browsers with [`esm.sh`][esmsh]: ```html ``` ## Use -
Show install command for this example - -```sh -npm install hastscript hast-util-to-html -``` - -
- ```js import {h} from 'hastscript' import {toHtml} from 'hast-util-to-html' -var tree = h('.alpha', [ +const tree = h('.alpha', [ 'bravo ', h('b', 'charlie'), ' delta ', @@ -116,10 +107,12 @@ Serialize hast as HTML. ###### Parameters -* `tree` ([`Node`][node] or `Array`) - — tree to serialize -* `options` ([`Options`][api-options], optional) - — configuration +* `tree` + ([`Node`][github-hast-nodes] or `Array`) + — tree to serialize +* `options` + ([`Options`][api-options], optional) + — configuration ###### Returns @@ -133,25 +126,28 @@ How to serialize character references (TypeScript type). ###### `useNamedReferences` -Prefer named character references (`&`) where possible (`boolean`, default: -`false`). +Prefer named character references (`&`) where possible +(`boolean`, default: `false`). ###### `omitOptionalSemicolons` -Whether to omit semicolons when possible (`boolean`, default: `false`). +Whether to omit semicolons when possible +(`boolean`, default: `false`). -> ⚠️ **Note**: this creates what HTML calls “parse errors” but is otherwise -> still valid HTML — don’t use this except when building a minifier. -> Omitting semicolons is possible for certain named and numeric references in +> ⚠️ **Note**: +> this creates what HTML calls “parse errors” but is otherwise still valid HTML: +> don’t use this except when building a minifier; +> omitting semicolons is possible for certain named and numeric references in > some cases. ###### `useShortestReferences` -Prefer the shortest possible reference, if that results in less bytes +Prefer the shortest possible reference, +if that results in less bytes (`boolean`, default: `false`). -> ⚠️ **Note**: `useNamedReferences` can be omitted when using -> `useShortestReferences`. +> ⚠️ **Note**: +> `useNamedReferences` can be omitted when using `useShortestReferences`. ### `Options` @@ -164,33 +160,44 @@ Configuration (TypeScript type). Do not encode some characters which cause XSS vulnerabilities in older browsers (`boolean`, default: `false`). -> ⚠️ **Danger**: only set this if you completely trust the content. +> ⚠️ **Danger**: +> only set this if you completely trust the content. ###### `allowDangerousHtml` -Allow `raw` nodes and insert them as raw HTML (`boolean`, default: `false`). +Allow `raw` nodes and insert them as raw HTML +(`boolean`, default: `false`). -When `false`, `Raw` nodes are encoded. +When `false`, +`Raw` nodes are encoded. -> ⚠️ **Danger**: only set this if you completely trust the content. +> ⚠️ **Danger**: +> only set this if you completely trust the content. ###### `allowParseErrors` -Do not encode characters which cause parse errors (even though they work), to -save bytes (`boolean`, default: `false`). +Do not encode characters which cause parse errors +(even though they work), +to save bytes +(`boolean`, default: `false`). Not used in the SVG space. -> 👉 **Note**: intentionally creates parse errors in markup (how parse errors -> are handled is well defined, so this works but isn’t pretty). +> 👉 **Note**: +> intentionally creates parse errors in markup +> (how parse errors are handled is well defined, +> so this works but isn’t pretty). ###### `bogusComments` -Use “bogus comments” instead of comments to save byes: `` instead of -`` (`boolean`, default: `false`). +Use “bogus comments” instead of comments to save byes: +`` instead of `` +(`boolean`, default: `false`). -> 👉 **Note**: intentionally creates parse errors in markup (how parse errors -> are handled is well defined, so this works but isn’t pretty). +> 👉 **Note**: +> intentionally creates parse errors in markup +> (how parse errors are handled is well defined, +> so this works but isn’t pretty). ###### `characterReferences` @@ -200,8 +207,9 @@ Configure how to serialize character references ###### `closeEmptyElements` Close SVG elements without any content with slash (`/`) on the opening tag -instead of an end tag: `` instead of `` (`boolean`, -default: `false`). +instead of an end tag: +`` instead of `` +(`boolean`, default: `false`). See `tightSelfClosing` to control whether a space is used before the slash. @@ -209,8 +217,9 @@ Not used in the HTML space. ###### `closeSelfClosing` -Close self-closing nodes with an extra slash (`/`): `
` instead of -`` (`boolean`, default: `false`). +Close self-closing nodes with an extra slash (`/`): +`` instead of `` +(`boolean`, default: `false`). See `tightSelfClosing` to control whether a space is used before the slash. @@ -218,100 +227,124 @@ Not used in the SVG space. ###### `collapseEmptyAttributes` -Collapse empty attributes: get `class` instead of `class=""` (`boolean`, -default: `false`). +Collapse empty attributes: +get `class` instead of `class=""` +(`boolean`, default: `false`). Not used in the SVG space. -> 👉 **Note**: boolean attributes (such as `hidden`) are always collapsed. +> 👉 **Note**: +> boolean attributes +> (such as `hidden`) +> are always collapsed. ###### `omitOptionalTags` -Omit optional opening and closing tags (`boolean`, default: `false`). +Omit optional opening and closing tags +(`boolean`, default: `false`). -For example, in `
  1. one
  2. two
`, both `` closing tags -can be omitted. -The first because it’s followed by another `li`, the last because it’s followed -by nothing. +For example, +in `
  1. one
  2. two
`, +both `` closing tags can be omitted. +The first because it’s followed by another `li`, +the last because it’s followed by nothing. Not used in the SVG space. ###### `preferUnquoted` -Leave attributes unquoted if that results in less bytes (`boolean`, default: -`false`). +Leave attributes unquoted if that results in less bytes +(`boolean`, default: `false`). Not used in the SVG space. ###### `quote` -Preferred quote to use ([`Quote`][api-quote], default: `'"'`). +Preferred quote to use +([`Quote`][api-quote], default: `'"'`). ###### `quoteSmart` -Use the other quote if that results in less bytes (`boolean`, default: `false`). +Use the other quote if that results in less bytes +(`boolean`, default: `false`). ###### `space` -Which space the document is in ([`Space`][api-space], default: `'html'`). +Which space the document is in +([`Space`][api-space], default: `'html'`). -When an `` element is found in the HTML space, this package already -automatically switches to and from the SVG space when entering and exiting it. +When an `` element is found in the HTML space, +this package already automatically switches to and from the SVG space when +entering and exiting it. -> 👉 **Note**: hast is not XML. +> 👉 **Note**: +> hast is not XML. > It supports SVG as embedded in HTML. > It does not support the features available in XML. > Passing SVG might break but fragments of modern SVG should be fine. -> Use [`xast`][xast] if you need to support SVG as XML. +> Use [`xast`][github-xast] if you need to support SVG as XML. ###### `tightAttributes` -Join attributes together, without whitespace, if possible: get -`class="a b"title="c d"` instead of `class="a b" title="c d"` to save bytes +Join attributes together, +without whitespace, +if possible: +get `class="a b"title="c d"` instead of `class="a b" title="c d"` to save bytes (`boolean`, default: `false`). Not used in the SVG space. -> 👉 **Note**: intentionally creates parse errors in markup (how parse errors -> are handled is well defined, so this works but isn’t pretty). +> 👉 **Note**: +> intentionally creates parse errors in markup +> (how parse errors are handled is well defined, +> so this works but isn’t pretty). ###### `tightCommaSeparatedLists` -Join known comma-separated attribute values with just a comma (`,`), instead of -padding them on the right as well (`,␠`, where `␠` represents a space) +Join known comma-separated attribute values with just a comma (`,`), +instead of padding them on the right as well +(`,␠`, where `␠` represents a space) (`boolean`, default: `false`). ###### `tightDoctype` -Drop unneeded spaces in doctypes: `` instead of `` -to save bytes (`boolean`, default: `false`). +Drop unneeded spaces in doctypes: +`` instead of `` to save bytes +(`boolean`, default: `false`). -> 👉 **Note**: intentionally creates parse errors in markup (how parse errors -> are handled is well defined, so this works but isn’t pretty). +> 👉 **Note**: +> intentionally creates parse errors in markup +> (how parse errors are handled is well defined, +> so this works but isn’t pretty). ###### `tightSelfClosing` -Do not use an extra space when closing self-closing elements: `` instead -of `` (`boolean`, default: `false`). +Do not use an extra space when closing self-closing elements: +`` instead of `` +(`boolean`, default: `false`). -> 👉 **Note**: only used if `closeSelfClosing: true` or -> `closeEmptyElements: true`. +> 👉 **Note**: +> only used if `closeSelfClosing: true` or `closeEmptyElements: true`. ###### `upperDoctype` -Use a ``, -default: [`html-void-elements`][html-void-elements]). +Tag names of elements to serialize without closing tag +(`Array`, +default: [`html-void-elements`][github-html-void-elements]). Not used in the SVG space. -> 👉 **Note**: It’s highly unlikely that you want to pass this, because hast is -> not for XML, and HTML will not add more void elements. +> 👉 **Note**: +> it’s highly unlikely that you want to pass this, +> because hast is not for XML, +> and HTML will not add more void elements. ### `Quote` @@ -335,8 +368,8 @@ type Space = 'html' | 'svg' ## Syntax -HTML is serialized according to WHATWG HTML (the living standard), which is also -followed by browsers such as Chrome and Firefox. +HTML is serialized according to WHATWG HTML (the living standard), +which is also followed by browsers such as Chrome and Firefox. ## Types @@ -344,7 +377,8 @@ This package is fully typed with [TypeScript][]. It exports the additional types [`CharacterReferences`][api-character-references], [`Options`][api-options], -[`Quote`][api-quote], and +[`Quote`][api-quote], +and [`Space`][api-space]. ## Compatibility @@ -352,106 +386,101 @@ It exports the additional types Projects maintained by the unified collective are compatible with maintained versions of Node.js. -When we cut a new major release, we drop support for unmaintained versions of -Node. -This means we try to keep the current release line, `hast-util-to-html@^9`, +When we cut a new major release, +we drop support for unmaintained versions of Node. +This means we try to keep the current release line, +`hast-util-to-html@9`, compatible with Node.js 16. ## Security Use of `hast-util-to-html` can open you up to a -[cross-site scripting (XSS)][xss] attack if the hast tree is unsafe. -Use [`hast-util-santize`][hast-util-sanitize] to make the hast tree safe. +[cross-site scripting (XSS)][wikipedia-xss] attack if the hast tree is unsafe. +Use [`hast-util-santize`][github-hast-util-sanitize] to make the hast tree +safe. ## Related -* [`hast-util-sanitize`](https://github.com/syntax-tree/hast-util-sanitize) - — sanitize hast +* [`hast-util-sanitize`][github-hast-util-sanitize] + — sanitize hast ## Contribute -See [`contributing.md`][contributing] in [`syntax-tree/.github`][health] for -ways to get started. -See [`support.md`][support] for ways to get help. +See [`contributing.md`][health-contributing] +in +[`syntax-tree/.github`][health] +for ways to get started. +See [`support.md`][health-support] for ways to get help. -This project has a [code of conduct][coc]. -By interacting with this repository, organization, or community you agree to -abide by its terms. +This project has a [code of conduct][health-coc]. +By interacting with this repository, +organization, +or community you agree to abide by its terms. ## License -[MIT][license] © [Titus Wormer][author] +[MIT][file-license] © [Titus Wormer][wooorm] -[build-badge]: https://github.com/syntax-tree/hast-util-to-html/workflows/main/badge.svg - -[build]: https://github.com/syntax-tree/hast-util-to-html/actions - -[coverage-badge]: https://img.shields.io/codecov/c/github/syntax-tree/hast-util-to-html.svg +[api-character-references]: #characterreferences -[coverage]: https://codecov.io/github/syntax-tree/hast-util-to-html +[api-options]: #options -[downloads-badge]: https://img.shields.io/npm/dm/hast-util-to-html.svg +[api-quote]: #quote-1 -[downloads]: https://www.npmjs.com/package/hast-util-to-html +[api-space]: #space-1 -[size-badge]: https://img.shields.io/badge/dynamic/json?label=minzipped%20size&query=$.size.compressedSize&url=https://deno.bundlejs.com/?q=hast-util-to-html +[api-to-html]: #tohtmltree-options -[size]: https://bundlejs.com/?q=hast-util-to-html +[badge-build-image]: https://github.com/syntax-tree/hast-util-to-html/workflows/main/badge.svg -[sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg +[badge-build-url]: https://github.com/syntax-tree/hast-util-to-html/actions -[backers-badge]: https://opencollective.com/unified/backers/badge.svg +[badge-coverage-image]: https://img.shields.io/codecov/c/github/syntax-tree/hast-util-to-html.svg -[collective]: https://opencollective.com/unified +[badge-coverage-url]: https://codecov.io/github/syntax-tree/hast-util-to-html -[chat-badge]: https://img.shields.io/badge/chat-discussions-success.svg +[badge-downloads-image]: https://img.shields.io/npm/dm/hast-util-to-html.svg -[chat]: https://github.com/syntax-tree/unist/discussions +[badge-downloads-url]: https://www.npmjs.com/package/hast-util-to-html -[npm]: https://docs.npmjs.com/cli/install +[badge-size-image]: https://img.shields.io/bundlejs/size/hast-util-to-html -[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c +[badge-size-url]: https://bundlejs.com/?q=hast-util-to-html [esmsh]: https://esm.sh -[typescript]: https://www.typescriptlang.org +[file-license]: license -[license]: license +[github-gist-esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c -[author]: https://wooorm.com - -[health]: https://github.com/syntax-tree/.github +[github-hast]: https://github.com/syntax-tree/hast -[contributing]: https://github.com/syntax-tree/.github/blob/main/contributing.md +[github-hast-nodes]: https://github.com/syntax-tree/hast#nodes -[support]: https://github.com/syntax-tree/.github/blob/main/support.md +[github-hast-util-from-html]: https://github.com/syntax-tree/hast-util-from-html -[coc]: https://github.com/syntax-tree/.github/blob/main/code-of-conduct.md +[github-hast-util-sanitize]: https://github.com/syntax-tree/hast-util-sanitize -[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting +[github-html-void-elements]: https://github.com/wooorm/html-void-elements -[hast]: https://github.com/syntax-tree/hast +[github-rehype-stringify]: https://github.com/rehypejs/rehype/tree/main/packages/rehype-stringify#readme -[node]: https://github.com/syntax-tree/hast#nodes +[github-xast]: https://github.com/syntax-tree/xast -[html-void-elements]: https://github.com/wooorm/html-void-elements - -[hast-util-sanitize]: https://github.com/syntax-tree/hast-util-sanitize +[health]: https://github.com/syntax-tree/.github -[hast-util-from-html]: https://github.com/syntax-tree/hast-util-from-html +[health-coc]: https://github.com/syntax-tree/.github/blob/main/code-of-conduct.md -[rehype-stringify]: https://github.com/rehypejs/rehype/tree/main/packages/rehype-stringify#readme +[health-contributing]: https://github.com/syntax-tree/.github/blob/main/contributing.md -[xast]: https://github.com/syntax-tree/xast +[health-support]: https://github.com/syntax-tree/.github/blob/main/support.md -[api-to-html]: #tohtmltree-options - -[api-character-references]: #characterreferences +[npmjs-install]: https://docs.npmjs.com/cli/install -[api-options]: #options +[typescript]: https://www.typescriptlang.org -[api-space]: #space-1 +[wikipedia-xss]: https://en.wikipedia.org/wiki/Cross-site_scripting -[api-quote]: #quote-1 +[wooorm]: https://wooorm.com diff --git a/test/attribute.js b/test/attribute.js index 99e2a5e..bdf6366 100644 --- a/test/attribute.js +++ b/test/attribute.js @@ -2,20 +2,29 @@ import assert from 'node:assert/strict' import test from 'node:test' import {h} from 'hastscript' import {toHtml} from 'hast-util-to-html' -import {u} from 'unist-builder' test('`element` attributes', async (t) => { await t.test('should support unknown properties', async function (t) { await t.test('should ignore unknowns set to `false`', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {unknown: false}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {unknown: false}, + children: [] + }), '' ) }) await t.test('should ignore unknowns set to `null`', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {unknown: null}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {unknown: null}, + children: [] + }), '' ) }) @@ -24,9 +33,12 @@ test('`element` attributes', async (t) => { 'should ignore unknowns set to `undefined`', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {unknown: undefined}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {unknown: undefined}, + children: [] + }), '' ) } @@ -34,9 +46,12 @@ test('`element` attributes', async (t) => { await t.test('should ignore unknowns set to `NaN`', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {unknown: Number.NaN}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {unknown: Number.NaN}, + children: [] + }), '' ) }) @@ -45,7 +60,12 @@ test('`element` attributes', async (t) => { 'should serialize unknowns set to `true` without value', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {unknown: true}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {unknown: true}, + children: [] + }), '' ) } @@ -55,9 +75,12 @@ test('`element` attributes', async (t) => { 'should serialize unknowns set to their name as their name', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {unknown: 'unknown'}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {unknown: 'unknown'}, + children: [] + }), '' ) } @@ -67,9 +90,12 @@ test('`element` attributes', async (t) => { 'should serialize unknown lists as space-separated', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {unknown: ['a', 'b']}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {unknown: ['a', 'b']}, + children: [] + }), '' ) } @@ -79,7 +105,12 @@ test('`element` attributes', async (t) => { 'should serialize unknowns set to an integer as it’s string version', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {unknown: 1}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {unknown: 1}, + children: [] + }), '' ) } @@ -87,17 +118,25 @@ test('`element` attributes', async (t) => { await t.test('should serialize unknowns set to `0`', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {unknown: 0}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {unknown: 0}, + children: [] + }), '' ) }) await t.test('should serialize unknowns set to objects', async function () { assert.deepEqual( - toHtml( + toHtml({ + type: 'element', + tagName: 'i', // @ts-expect-error: check how the runtime handles a `toString` method on an object. - u('element', {tagName: 'i', properties: {unknown: {toString}}}, []) - ), + properties: {unknown: {toString}}, + children: [] + }), '' ) }) @@ -108,7 +147,12 @@ test('`element` attributes', async (t) => { 'should ignore known booleans set to `false`', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {hidden: false}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {hidden: false}, + children: [] + }), '' ) } @@ -116,16 +160,24 @@ test('`element` attributes', async (t) => { await t.test('should ignore falsey known booleans', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {hidden: 0}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {hidden: 0}, + children: [] + }), '' ) }) await t.test('should ignore NaN known booleans', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {hidden: Number.NaN}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {hidden: Number.NaN}, + children: [] + }), '' ) }) @@ -134,7 +186,12 @@ test('`element` attributes', async (t) => { 'should serialize known booleans set to `true` without value', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {hidden: true}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {hidden: true}, + children: [] + }), '' ) } @@ -144,9 +201,12 @@ test('`element` attributes', async (t) => { 'should serialize known booleans set to their name without value', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {hidden: 'hidden'}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {hidden: 'hidden'}, + children: [] + }), '' ) } @@ -156,11 +216,46 @@ test('`element` attributes', async (t) => { 'should serialize truthy known booleans without value', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {hidden: 1}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {hidden: 1}, + children: [] + }), '' ) } ) + + await t.test( + 'should serialize known booleans set to arbitrary strings with value', + async function () { + assert.deepEqual( + toHtml(h('div', {selected: 'something'})), + '
' + ) + } + ) + + await t.test( + 'should serialize known booleans set to an empty string without value', + async function () { + assert.deepEqual( + toHtml(h('div', {selected: ''})), + '
' + ) + } + ) + + await t.test( + 'should serialize known overloaded booleans set to arbitrary strings with value', + async function () { + assert.deepEqual( + toHtml(h('div', {download: 'something'})), + '
' + ) + } + ) }) await t.test('should support known overloaded booleans', async function (t) { @@ -168,9 +263,12 @@ test('`element` attributes', async (t) => { 'should ignore known overloaded booleans set to `false`', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'a', properties: {download: false}}, []) - ), + toHtml({ + type: 'element', + tagName: 'a', + properties: {download: false}, + children: [] + }), '' ) } @@ -180,7 +278,12 @@ test('`element` attributes', async (t) => { 'should ignore falsey known overloaded booleans', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'a', properties: {download: 0}}, [])), + toHtml({ + type: 'element', + tagName: 'a', + properties: {download: 0}, + children: [] + }), '' ) } @@ -190,9 +293,12 @@ test('`element` attributes', async (t) => { 'should ignore NaN known overloaded booleans', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'a', properties: {download: Number.NaN}}, []) - ), + toHtml({ + type: 'element', + tagName: 'a', + properties: {download: Number.NaN}, + children: [] + }), '' ) } @@ -202,9 +308,12 @@ test('`element` attributes', async (t) => { 'should serialize known overloaded booleans set to `true` without value', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'a', properties: {download: true}}, []) - ), + toHtml({ + type: 'element', + tagName: 'a', + properties: {download: true}, + children: [] + }), '' ) } @@ -214,9 +323,12 @@ test('`element` attributes', async (t) => { 'should serialize known overloaded booleans set to their name without value', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'a', properties: {download: 'download'}}, []) - ), + toHtml({ + type: 'element', + tagName: 'a', + properties: {download: 'download'}, + children: [] + }), '' ) } @@ -226,7 +338,12 @@ test('`element` attributes', async (t) => { 'should serialize known overloaded booleans set to an empty string without value', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'a', properties: {download: ''}}, [])), + toHtml({ + type: 'element', + tagName: 'a', + properties: {download: ''}, + children: [] + }), '' ) } @@ -236,7 +353,12 @@ test('`element` attributes', async (t) => { 'should serialize truthy known overloaded booleans without value', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'a', properties: {download: 1}}, [])), + toHtml({ + type: 'element', + tagName: 'a', + properties: {download: 1}, + children: [] + }), '' ) } @@ -246,9 +368,12 @@ test('`element` attributes', async (t) => { 'should serialize known overloaded booleans set to another string', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'a', properties: {download: 'another'}}, []) - ), + toHtml({ + type: 'element', + tagName: 'a', + properties: {download: 'another'}, + children: [] + }), '' ) } @@ -259,7 +384,12 @@ test('`element` attributes', async (t) => { 'should ignore known numbers set to `false`', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {cols: false}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {cols: false}, + children: [] + }), '' ) } @@ -267,9 +397,12 @@ test('`element` attributes', async (t) => { await t.test('should ignore NaN known numbers', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'a', properties: {cols: Number.NaN}}, []) - ), + toHtml({ + type: 'element', + tagName: 'a', + properties: {cols: Number.NaN}, + children: [] + }), '' ) }) @@ -278,7 +411,12 @@ test('`element` attributes', async (t) => { 'should serialize known numbers set to `0`', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {cols: 0}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {cols: 0}, + children: [] + }), '' ) } @@ -288,7 +426,12 @@ test('`element` attributes', async (t) => { 'should serialize known numbers set to `-1`', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {cols: -1}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {cols: -1}, + children: [] + }), '' ) } @@ -298,7 +441,12 @@ test('`element` attributes', async (t) => { 'should serialize known numbers set to `1`', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {cols: 1}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {cols: 1}, + children: [] + }), '' ) } @@ -308,7 +456,12 @@ test('`element` attributes', async (t) => { 'should serialize known numbers set to `Math.PI`', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {cols: Math.PI}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {cols: Math.PI}, + children: [] + }), '' ) } @@ -318,7 +471,12 @@ test('`element` attributes', async (t) => { 'should serialize known numbers set to `true` as without value', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {cols: true}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {cols: true}, + children: [] + }), '' ) } @@ -328,7 +486,12 @@ test('`element` attributes', async (t) => { 'should serialize known numbers set to an empty string', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {cols: ''}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {cols: ''}, + children: [] + }), '' ) } @@ -338,7 +501,12 @@ test('`element` attributes', async (t) => { 'should serialize known numbers set to their name', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {cols: 'cols'}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {cols: 'cols'}, + children: [] + }), '' ) } @@ -348,9 +516,12 @@ test('`element` attributes', async (t) => { 'should serialize known numbers set to a string', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {cols: 'another'}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {cols: 'another'}, + children: [] + }), '' ) } @@ -360,10 +531,13 @@ test('`element` attributes', async (t) => { 'should serialize known numbers set to an object', async function () { assert.deepEqual( - toHtml( + toHtml({ + type: 'element', + tagName: 'i', // @ts-expect-error: check how the runtime handles a `toString` method on an object. - u('element', {tagName: 'i', properties: {cols: {toString}}}, []) - ), + properties: {cols: {toString}}, + children: [] + }), '' ) } @@ -373,9 +547,12 @@ test('`element` attributes', async (t) => { 'should serialize known numbers set to an array of strings', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {cols: ['a', 'b']}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {cols: ['a', 'b']}, + children: [] + }), '' ) } @@ -385,7 +562,12 @@ test('`element` attributes', async (t) => { 'should serialize known numbers set to an array of numbers', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {cols: [0, 50]}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {cols: [0, 50]}, + children: [] + }), '' ) } @@ -395,10 +577,13 @@ test('`element` attributes', async (t) => { 'should serialize known numbers set to an array of booleans', async function () { assert.deepEqual( - toHtml( + toHtml({ + type: 'element', + tagName: 'i', // @ts-expect-error: check how the runtime handles booleans in an array. - u('element', {tagName: 'i', properties: {cols: [true, false]}}, []) - ), + properties: {cols: [true, false]}, + children: [] + }), '' ) } @@ -412,9 +597,12 @@ test('`element` attributes', async (t) => { 'should ignore known space-separated lists set to `false`', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {className: false}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {className: false}, + children: [] + }), '' ) } @@ -424,13 +612,12 @@ test('`element` attributes', async (t) => { 'should ignore NaN known space-separated lists', async function () { assert.deepEqual( - toHtml( - u( - 'element', - {tagName: 'a', properties: {className: Number.NaN}}, - [] - ) - ), + toHtml({ + type: 'element', + tagName: 'a', + properties: {className: Number.NaN}, + children: [] + }), '' ) } @@ -440,9 +627,12 @@ test('`element` attributes', async (t) => { 'should serialize known space-separated lists set to `0`', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {className: 0}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {className: 0}, + children: [] + }), '' ) } @@ -452,9 +642,12 @@ test('`element` attributes', async (t) => { 'should serialize known space-separated lists set to `true` as without value', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {className: true}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {className: true}, + children: [] + }), '' ) } @@ -464,9 +657,12 @@ test('`element` attributes', async (t) => { 'should serialize known space-separated lists set to an empty string', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {className: ''}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {className: ''}, + children: [] + }), '' ) } @@ -476,9 +672,12 @@ test('`element` attributes', async (t) => { 'should serialize known space-separated lists set to their attribute name', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {className: 'class'}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {className: 'class'}, + children: [] + }), '' ) } @@ -488,13 +687,12 @@ test('`element` attributes', async (t) => { 'should serialize known space-separated lists set to their property name', async function () { assert.deepEqual( - toHtml( - u( - 'element', - {tagName: 'i', properties: {className: 'className'}}, - [] - ) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {className: 'className'}, + children: [] + }), '' ) } @@ -504,13 +702,12 @@ test('`element` attributes', async (t) => { 'should serialize known space-separated lists set to a string', async function () { assert.deepEqual( - toHtml( - u( - 'element', - {tagName: 'i', properties: {className: 'another'}}, - [] - ) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {className: 'another'}, + children: [] + }), '' ) } @@ -520,14 +717,13 @@ test('`element` attributes', async (t) => { 'should serialize known space-separated lists set to an object', async function () { assert.deepEqual( - toHtml( + toHtml({ + type: 'element', + tagName: 'i', // @ts-expect-error: check how the runtime handles a `toString` method on an object. - u( - 'element', - {tagName: 'i', properties: {className: {toString}}}, - [] - ) - ), + properties: {className: {toString}}, + children: [] + }), '' ) } @@ -537,13 +733,12 @@ test('`element` attributes', async (t) => { 'should serialize known space-separated lists set to an array of strings', async function () { assert.deepEqual( - toHtml( - u( - 'element', - {tagName: 'i', properties: {className: ['a', 'b']}}, - [] - ) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {className: ['a', 'b']}, + children: [] + }), '' ) } @@ -553,9 +748,12 @@ test('`element` attributes', async (t) => { 'should serialize known space-separated lists set to an array of numbers', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {className: [0, 50]}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {className: [0, 50]}, + children: [] + }), '' ) } @@ -565,14 +763,13 @@ test('`element` attributes', async (t) => { 'should serialize known space-separated lists set to an array of booleans', async function () { assert.deepEqual( - toHtml( + toHtml({ + type: 'element', + tagName: 'i', // @ts-expect-error: check how the runtime handles booleans in an array. - u( - 'element', - {tagName: 'i', properties: {className: [true, false]}}, - [] - ) - ), + properties: {className: [true, false]}, + children: [] + }), '' ) } @@ -587,9 +784,12 @@ test('`element` attributes', async (t) => { 'should ignore known comma-separated lists set to `false`', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {accept: false}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {accept: false}, + children: [] + }), '' ) } @@ -599,9 +799,12 @@ test('`element` attributes', async (t) => { 'should ignore NaN known comma-separated lists', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'a', properties: {accept: Number.NaN}}, []) - ), + toHtml({ + type: 'element', + tagName: 'a', + properties: {accept: Number.NaN}, + children: [] + }), '' ) } @@ -611,7 +814,12 @@ test('`element` attributes', async (t) => { 'should serialize known comma-separated lists set to `0`', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {accept: 0}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {accept: 0}, + children: [] + }), '' ) } @@ -621,9 +829,12 @@ test('`element` attributes', async (t) => { 'should serialize known comma-separated lists set to `true` as without value', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {accept: true}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {accept: true}, + children: [] + }), '' ) } @@ -633,7 +844,12 @@ test('`element` attributes', async (t) => { 'should serialize known comma-separated lists set to an empty string', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {accept: ''}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {accept: ''}, + children: [] + }), '' ) } @@ -643,9 +859,12 @@ test('`element` attributes', async (t) => { 'should serialize known comma-separated lists set to their name', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {accept: 'accept'}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {accept: 'accept'}, + children: [] + }), '' ) } @@ -655,9 +874,12 @@ test('`element` attributes', async (t) => { 'should serialize known comma-separated lists set to a string', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {accept: 'another'}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {accept: 'another'}, + children: [] + }), '' ) } @@ -667,10 +889,13 @@ test('`element` attributes', async (t) => { 'should serialize known comma-separated lists set to an object', async function () { assert.deepEqual( - toHtml( + toHtml({ + type: 'element', + tagName: 'i', // @ts-expect-error: check how the runtime handles a `toString` method on an object. - u('element', {tagName: 'i', properties: {accept: {toString}}}, []) - ), + properties: {accept: {toString}}, + children: [] + }), '' ) } @@ -680,9 +905,12 @@ test('`element` attributes', async (t) => { 'should serialize known comma-separated lists set to an array of strings', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {accept: ['a', 'b']}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {accept: ['a', 'b']}, + children: [] + }), '' ) } @@ -692,9 +920,12 @@ test('`element` attributes', async (t) => { 'should serialize known comma-separated lists set to an array of numbers', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {accept: [0, 50]}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {accept: [0, 50]}, + children: [] + }), '' ) } @@ -704,14 +935,13 @@ test('`element` attributes', async (t) => { 'should serialize known comma-separated lists set to an array of booleans', async function () { assert.deepEqual( - toHtml( + toHtml({ + type: 'element', + tagName: 'i', // @ts-expect-error: check how the runtime handles booleans in an array. - u( - 'element', - {tagName: 'i', properties: {accept: [true, false]}}, - [] - ) - ), + properties: {accept: [true, false]}, + children: [] + }), '' ) } @@ -724,7 +954,12 @@ test('`element` attributes', async (t) => { 'should ignore known normals set to `false`', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {id: false}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {id: false}, + children: [] + }), '' ) } @@ -732,7 +967,12 @@ test('`element` attributes', async (t) => { await t.test('should ignore NaN known normals', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {id: Number.NaN}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {id: Number.NaN}, + children: [] + }), '' ) }) @@ -741,7 +981,12 @@ test('`element` attributes', async (t) => { 'should serialize known normals set to `0`', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {id: 0}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {id: 0}, + children: [] + }), '' ) } @@ -751,7 +996,12 @@ test('`element` attributes', async (t) => { 'should serialize known normals set to `true` as without value', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {id: true}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {id: true}, + children: [] + }), '' ) } @@ -761,7 +1011,12 @@ test('`element` attributes', async (t) => { 'should serialize known normals set to an empty string', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {id: ''}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {id: ''}, + children: [] + }), '' ) } @@ -771,7 +1026,12 @@ test('`element` attributes', async (t) => { 'should serialize known normals set to their name', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {id: 'id'}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {id: 'id'}, + children: [] + }), '' ) } @@ -781,7 +1041,12 @@ test('`element` attributes', async (t) => { 'should serialize known normals set to a string', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {id: 'another'}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {id: 'another'}, + children: [] + }), '' ) } @@ -791,10 +1056,13 @@ test('`element` attributes', async (t) => { 'should serialize known normals set to an object', async function () { assert.deepEqual( - toHtml( + toHtml({ + type: 'element', + tagName: 'i', // @ts-expect-error: check how the runtime handles a `toString` method on an object. - u('element', {tagName: 'i', properties: {id: {toString}}}, []) - ), + properties: {id: {toString}}, + children: [] + }), '' ) } @@ -804,9 +1072,12 @@ test('`element` attributes', async (t) => { 'should serialize known normals set to an array of strings as a space-separated list', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {id: ['a', 'b']}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {id: ['a', 'b']}, + children: [] + }), '' ) } @@ -816,7 +1087,12 @@ test('`element` attributes', async (t) => { 'should serialize known normals set to an array of numbers as a space-separated list', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {id: [0, 50]}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {id: [0, 50]}, + children: [] + }), '' ) } @@ -826,10 +1102,13 @@ test('`element` attributes', async (t) => { 'should serialize known normals set to an array of booleans as a space-separated list', async function () { assert.deepEqual( - toHtml( + toHtml({ + type: 'element', + tagName: 'i', // @ts-expect-error: check how the runtime handles booleans in an array. - u('element', {tagName: 'i', properties: {id: [true, false]}}, []) - ), + properties: {id: [true, false]}, + children: [] + }), '' ) } @@ -841,7 +1120,12 @@ test('`element` attributes', async (t) => { 'should ignore data properties set to `false`', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {dataId: false}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {dataId: false}, + children: [] + }), '' ) } @@ -849,9 +1133,12 @@ test('`element` attributes', async (t) => { await t.test('should ignore NaN data properties', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {dataId: Number.NaN}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {dataId: Number.NaN}, + children: [] + }), '' ) }) @@ -860,7 +1147,12 @@ test('`element` attributes', async (t) => { 'should serialize data properties set to `0`', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {dataId: 0}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {dataId: 0}, + children: [] + }), '' ) } @@ -870,7 +1162,12 @@ test('`element` attributes', async (t) => { 'should serialize data properties set to `true` as without value', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {dataId: true}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {dataId: true}, + children: [] + }), '' ) } @@ -880,7 +1177,12 @@ test('`element` attributes', async (t) => { 'should serialize data properties set to an empty string', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {dataId: ''}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {dataId: ''}, + children: [] + }), '' ) } @@ -890,9 +1192,12 @@ test('`element` attributes', async (t) => { 'should serialize data properties set to their property name', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {dataId: 'dataId'}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {dataId: 'dataId'}, + children: [] + }), '' ) } @@ -902,9 +1207,12 @@ test('`element` attributes', async (t) => { 'should serialize data properties set to their attribute name', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {dataId: 'data-id'}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {dataId: 'data-id'}, + children: [] + }), '' ) } @@ -914,9 +1222,12 @@ test('`element` attributes', async (t) => { 'should serialize data properties set to a string', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {dataId: 'another'}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {dataId: 'another'}, + children: [] + }), '' ) } @@ -926,7 +1237,12 @@ test('`element` attributes', async (t) => { 'should serialize numeric-first data properties set to a string', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {data123: 'a'}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {data123: 'a'}, + children: [] + }), '' ) } @@ -936,10 +1252,13 @@ test('`element` attributes', async (t) => { 'should serialize data properties set to an object', async function () { assert.deepEqual( - toHtml( + toHtml({ + type: 'element', + tagName: 'i', // @ts-expect-error: check how the runtime handles a `toString` method on an object. - u('element', {tagName: 'i', properties: {dataId: {toString}}}, []) - ), + properties: {dataId: {toString}}, + children: [] + }), '' ) } @@ -949,9 +1268,12 @@ test('`element` attributes', async (t) => { 'should serialize data properties set to an array of strings as a space-separated list', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {dataId: ['a', 'b']}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {dataId: ['a', 'b']}, + children: [] + }), '' ) } @@ -961,9 +1283,12 @@ test('`element` attributes', async (t) => { 'should serialize data properties set to an array of numbers as a space-separated list', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {dataId: [0, 50]}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {dataId: [0, 50]}, + children: [] + }), '' ) } @@ -973,14 +1298,13 @@ test('`element` attributes', async (t) => { 'should serialize data properties set to an array of booleans as a space-separated list', async function () { assert.deepEqual( - toHtml( + toHtml({ + type: 'element', + tagName: 'i', // @ts-expect-error: check how the runtime handles booleans in an array. - u( - 'element', - {tagName: 'i', properties: {dataId: [true, false]}}, - [] - ) - ), + properties: {dataId: [true, false]}, + children: [] + }), '' ) } @@ -990,7 +1314,12 @@ test('`element` attributes', async (t) => { await t.test('should support `collapseEmptyAttributes`', async function (t) { await t.test('should show empty string attributes', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {id: ''}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {id: ''}, + children: [] + }), '' ) }) @@ -999,9 +1328,12 @@ test('`element` attributes', async (t) => { 'should collapse empty string attributes in `collapseEmptyAttributes` mode', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {id: ''}}, []), { - collapseEmptyAttributes: true - }), + toHtml( + {type: 'element', tagName: 'i', properties: {id: ''}, children: []}, + { + collapseEmptyAttributes: true + } + ), '' ) } @@ -1011,9 +1343,12 @@ test('`element` attributes', async (t) => { await t.test('should support `tightAttributes`', async function (t) { await t.test('should serialize multiple properties', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {title: 'a', id: 'b'}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {title: 'a', id: 'b'}, + children: [] + }), '' ) }) @@ -1023,7 +1358,12 @@ test('`element` attributes', async (t) => { async function () { assert.deepEqual( toHtml( - u('element', {tagName: 'i', properties: {title: 'a', id: 'b'}}, []), + { + type: 'element', + tagName: 'i', + properties: {title: 'a', id: 'b'}, + children: [] + }, { tightAttributes: true } @@ -1039,9 +1379,12 @@ test('`element` attributes', async (t) => { 'should serialize comma-separated attributes', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {accept: ['a', 'b']}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {accept: ['a', 'b']}, + children: [] + }), '' ) } @@ -1052,7 +1395,12 @@ test('`element` attributes', async (t) => { async function () { assert.deepEqual( toHtml( - u('element', {tagName: 'i', properties: {accept: ['a', 'b']}}, []), + { + type: 'element', + tagName: 'i', + properties: {accept: ['a', 'b']}, + children: [] + }, { tightCommaSeparatedLists: true } @@ -1068,7 +1416,12 @@ test('`element` attributes', async (t) => { 'should quote attribute values with double quotes by default', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {title: 'a'}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {title: 'a'}, + children: [] + }), '' ) } @@ -1078,9 +1431,17 @@ test('`element` attributes', async (t) => { "should quote attribute values with single quotes if `quote: '\\''`", async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {title: 'a'}}, []), { - quote: "'" - }), + toHtml( + { + type: 'element', + tagName: 'i', + properties: {title: 'a'}, + children: [] + }, + { + quote: "'" + } + ), "" ) } @@ -1090,9 +1451,17 @@ test('`element` attributes', async (t) => { "should quote attribute values with double quotes if `quote: '\\\"'`", async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {title: 'a'}}, []), { - quote: '"' - }), + toHtml( + { + type: 'element', + tagName: 'i', + properties: {title: 'a'}, + children: [] + }, + { + quote: '"' + } + ), '' ) } @@ -1102,9 +1471,17 @@ test('`element` attributes', async (t) => { "should quote attribute values with single quotes if `quote: '\\''` even if they occur in value", async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {title: "'a'"}}, []), { - quote: "'" - }), + toHtml( + { + type: 'element', + tagName: 'i', + properties: {title: "'a'"}, + children: [] + }, + { + quote: "'" + } + ), "" ) } @@ -1114,9 +1491,17 @@ test('`element` attributes', async (t) => { "should quote attribute values with double quotes if `quote: '\\\"'` even if they occur in value", async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {title: '"a"'}}, []), { - quote: '"' - }), + toHtml( + { + type: 'element', + tagName: 'i', + properties: {title: '"a"'}, + children: [] + }, + { + quote: '"' + } + ), '' ) } @@ -1138,10 +1523,18 @@ test('`element` attributes', async (t) => { 'should quote attribute values with primary quotes by default', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {title: 'a'}}, []), { - allowDangerousCharacters: true, - quoteSmart: true - }), + toHtml( + { + type: 'element', + tagName: 'i', + properties: {title: 'a'}, + children: [] + }, + { + allowDangerousCharacters: true, + quoteSmart: true + } + ), '' ) } @@ -1151,10 +1544,18 @@ test('`element` attributes', async (t) => { 'should quote attribute values with primary quotes if the alternative occurs', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {title: "'a'"}}, []), { - allowDangerousCharacters: true, - quoteSmart: true - }), + toHtml( + { + type: 'element', + tagName: 'i', + properties: {title: "'a'"}, + children: [] + }, + { + allowDangerousCharacters: true, + quoteSmart: true + } + ), '' ) } @@ -1165,7 +1566,12 @@ test('`element` attributes', async (t) => { async function () { assert.deepEqual( toHtml( - u('element', {tagName: 'i', properties: {title: "'\"a'"}}, []), + { + type: 'element', + tagName: 'i', + properties: {title: "'\"a'"}, + children: [] + }, { allowDangerousCharacters: true, quoteSmart: true @@ -1181,7 +1587,12 @@ test('`element` attributes', async (t) => { async function () { assert.deepEqual( toHtml( - u('element', {tagName: 'i', properties: {title: '"a\''}}, []), + { + type: 'element', + tagName: 'i', + properties: {title: '"a\''}, + children: [] + }, { allowDangerousCharacters: true, quoteSmart: true @@ -1197,7 +1608,12 @@ test('`element` attributes', async (t) => { async function () { assert.deepEqual( toHtml( - u('element', {tagName: 'i', properties: {title: '"\'a\'"'}}, []), + { + type: 'element', + tagName: 'i', + properties: {title: '"\'a\'"'}, + children: [] + }, { allowDangerousCharacters: true, quoteSmart: true @@ -1212,10 +1628,18 @@ test('`element` attributes', async (t) => { 'should quote attribute values with alternative quotes if the primary occurs', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {title: '"a"'}}, []), { - allowDangerousCharacters: true, - quoteSmart: true - }), + toHtml( + { + type: 'element', + tagName: 'i', + properties: {title: '"a"'}, + children: [] + }, + { + allowDangerousCharacters: true, + quoteSmart: true + } + ), '' ) } @@ -1226,7 +1650,12 @@ test('`element` attributes', async (t) => { async function () { assert.deepEqual( toHtml( - u('element', {tagName: 'i', properties: {title: '"\'a"'}}, []), + { + type: 'element', + tagName: 'i', + properties: {title: '"\'a"'}, + children: [] + }, { allowDangerousCharacters: true, quoteSmart: true @@ -1241,9 +1670,12 @@ test('`element` attributes', async (t) => { await t.test('should support `preferUnquoted`', async function (t) { await t.test('should omit quotes in `preferUnquoted`', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {id: 'a'}}, []), { - preferUnquoted: true - }), + toHtml( + {type: 'element', tagName: 'i', properties: {id: 'a'}, children: []}, + { + preferUnquoted: true + } + ), '' ) }) @@ -1252,9 +1684,17 @@ test('`element` attributes', async (t) => { 'should keep quotes in `preferUnquoted` and impossible', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {id: 'a b'}}, []), { - preferUnquoted: true - }), + toHtml( + { + type: 'element', + tagName: 'i', + properties: {id: 'a b'}, + children: [] + }, + { + preferUnquoted: true + } + ), '' ) } @@ -1264,9 +1704,12 @@ test('`element` attributes', async (t) => { 'should not add `=` when omitting quotes on empty values', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {id: ''}}, []), { - preferUnquoted: true - }), + toHtml( + {type: 'element', tagName: 'i', properties: {id: ''}, children: []}, + { + preferUnquoted: true + } + ), '' ) } @@ -1278,7 +1721,12 @@ test('`element` attributes', async (t) => { 'should encode entities in attribute names', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {'3<5\0': 'a'}}, [])), + toHtml({ + type: 'element', + tagName: 'i', + properties: {'3<5\0': 'a'}, + children: [] + }), '' ) } @@ -1288,9 +1736,12 @@ test('`element` attributes', async (t) => { 'should encode entities in attribute values', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'i', properties: {title: '3<5\0'}}, []) - ), + toHtml({ + type: 'element', + tagName: 'i', + properties: {title: '3<5\0'}, + children: [] + }), '' ) } @@ -1300,9 +1751,17 @@ test('`element` attributes', async (t) => { 'should not encode characters in attribute names which cause parse errors, but work, in `allowParseErrors` mode', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {'3=5\0': 'a'}}, []), { - allowParseErrors: true - }), + toHtml( + { + type: 'element', + tagName: 'i', + properties: {'3=5\0': 'a'}, + children: [] + }, + { + allowParseErrors: true + } + ), '' ) } @@ -1313,7 +1772,12 @@ test('`element` attributes', async (t) => { async function () { assert.deepEqual( toHtml( - u('element', {tagName: 'i', properties: {title: '3=5\0'}}, []), + { + type: 'element', + tagName: 'i', + properties: {title: '3=5\0'}, + children: [] + }, { allowParseErrors: true } @@ -1327,9 +1791,17 @@ test('`element` attributes', async (t) => { 'should not encode characters which cause XSS issues in older browsers, in `allowDangerousCharacters` mode', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'i', properties: {title: "3'5"}}, []), { - allowDangerousCharacters: true - }), + toHtml( + { + type: 'element', + tagName: 'i', + properties: {title: "3'5"}, + children: [] + }, + { + allowDangerousCharacters: true + } + ), '' ) } diff --git a/test/comment.js b/test/comment.js index eb0004f..ffe7244 100644 --- a/test/comment.js +++ b/test/comment.js @@ -1,22 +1,21 @@ import assert from 'node:assert/strict' import test from 'node:test' import {toHtml} from 'hast-util-to-html' -import {u} from 'unist-builder' test('`comment`', async function (t) { await t.test('should serialize `comment`s', async function () { - assert.deepEqual(toHtml(u('comment', 'alpha')), '') + assert.deepEqual(toHtml({type: 'comment', value: 'alpha'}), '') }) await t.test('should not encode `comment`s', async function () { - assert.deepEqual(toHtml(u('comment', 'AT&T')), '') + assert.deepEqual(toHtml({type: 'comment', value: 'AT&T'}), '') }) await t.test( 'should serialize bogus comments (`bogusComments`)', async function () { assert.deepEqual( - toHtml(u('comment', 'asd'), {bogusComments: true}), + toHtml({type: 'comment', value: 'asd'}, {bogusComments: true}), '' ) } @@ -26,7 +25,7 @@ test('`comment`', async function (t) { 'should prevent breaking out of bogus comments (`bogusComments`)', async function () { assert.deepEqual( - toHtml(u('comment', 'ad'), {bogusComments: true}), + toHtml({type: 'comment', value: 'ad'}, {bogusComments: true}), '' ) } @@ -36,6 +35,7 @@ test('`comment`', async function (t) { // Optionally, text, with the additional restriction that the text must not // start with the string `>`, nor start with the string `->`, nor contain the // strings ``, or `--!>`, nor end with the string `} */ const matrix = [ ['>a', '>a'], ['->a', '->a'], @@ -49,19 +49,18 @@ test('`comment`', async function (t) { // Not at end: ['a' + toHtml({type: 'comment', value: open}), + '' ) } ) diff --git a/test/core.js b/test/core.js index 38129e7..c205ba8 100644 --- a/test/core.js +++ b/test/core.js @@ -2,7 +2,6 @@ import assert from 'node:assert/strict' import test from 'node:test' import {h} from 'hastscript' import {toHtml} from 'hast-util-to-html' -import {u} from 'unist-builder' test('toHtml()', async function (t) { await t.test('should expose the public api', async function () { @@ -21,7 +20,7 @@ test('toHtml()', async function (t) { await t.test('should throw on unknown nodes', async function () { assert.throws(function () { // @ts-expect-error: check how the runtime handles an unknown node. - toHtml(u('foo', [])) + toHtml({type: 'foo', children: []}) }, /Cannot compile unknown node `foo`/) }) diff --git a/test/doctype.js b/test/doctype.js index 031e23b..d40efb8 100644 --- a/test/doctype.js +++ b/test/doctype.js @@ -1,18 +1,17 @@ import assert from 'node:assert/strict' import test from 'node:test' import {toHtml} from 'hast-util-to-html' -import {u} from 'unist-builder' test('`doctype`', async function (t) { await t.test('should serialize doctypes', async function () { - assert.deepEqual(toHtml(u('doctype')), '') + assert.deepEqual(toHtml({type: 'doctype'}), '') }) await t.test( 'should serialize doctypes tightly in `tightDoctype` mode', async function () { assert.deepEqual( - toHtml(u('doctype'), {tightDoctype: true}), + toHtml({type: 'doctype'}, {tightDoctype: true}), '' ) } @@ -22,7 +21,7 @@ test('`doctype`', async function (t) { 'should serialize uppercase doctypes in `upperDoctype` mode', async function () { assert.deepEqual( - toHtml(u('doctype'), {upperDoctype: true}), + toHtml({type: 'doctype'}, {upperDoctype: true}), '' ) } diff --git a/test/omission-closing-body.js b/test/omission-closing-body.js index 8ac965d..241548a 100644 --- a/test/omission-closing-body.js +++ b/test/omission-closing-body.js @@ -2,7 +2,6 @@ import assert from 'node:assert/strict' import test from 'node:test' import {h} from 'hastscript' import {toHtml} from 'hast-util-to-html' -import {u} from 'unist-builder' test('`body` (closing)', async function (t) { await t.test('should omit tag without following', async function () { @@ -13,7 +12,7 @@ test('`body` (closing)', async function (t) { 'should not omit tag if followed by `comment`', async function () { assert.deepEqual( - toHtml(h('html', [h('body'), u('comment', 'alpha')]), { + toHtml(h('html', [h('body'), {type: 'comment', value: 'alpha'}]), { omitOptionalTags: true }), '' @@ -25,7 +24,7 @@ test('`body` (closing)', async function (t) { 'should omit tag if not followed by `comment`', async function () { assert.deepEqual( - toHtml(h('html', [h('body'), u('text', 'alpha')]), { + toHtml(h('html', [h('body'), {type: 'text', value: 'alpha'}]), { omitOptionalTags: true }), 'alpha' diff --git a/test/omission-closing-caption.js b/test/omission-closing-caption.js index 25b409e..eab6e65 100644 --- a/test/omission-closing-caption.js +++ b/test/omission-closing-caption.js @@ -2,7 +2,6 @@ import assert from 'node:assert/strict' import test from 'node:test' import {h} from 'hastscript' import {toHtml} from 'hast-util-to-html' -import {u} from 'unist-builder' test('`caption` (closing)', async function (t) { await t.test('should not omit tag without children', async function () { @@ -21,7 +20,7 @@ test('`caption` (closing)', async function (t) { await t.test('should not omit tag followed by `comment`', async function () { assert.deepEqual( - toHtml(h('table', [h('caption'), u('comment', 'alpha')]), { + toHtml(h('table', [h('caption'), {type: 'comment', value: 'alpha'}]), { omitOptionalTags: true }), '
' diff --git a/test/omission-closing-colgroup.js b/test/omission-closing-colgroup.js index c4564f7..2327c68 100644 --- a/test/omission-closing-colgroup.js +++ b/test/omission-closing-colgroup.js @@ -2,7 +2,6 @@ import assert from 'node:assert/strict' import test from 'node:test' import {h} from 'hastscript' import {toHtml} from 'hast-util-to-html' -import {u} from 'unist-builder' test('`colgroup` (closing)', async function (t) { await t.test('should not omit tag without children', async function () { @@ -21,7 +20,9 @@ test('`colgroup` (closing)', async function (t) { await t.test('should not omit tag if head is not `col`', async function () { assert.deepEqual( - toHtml(h('colgroup', [u('comment', 'alpha')]), {omitOptionalTags: true}), + toHtml(h('colgroup', [{type: 'comment', value: 'alpha'}]), { + omitOptionalTags: true + }), '' ) }) diff --git a/test/omission-closing-head.js b/test/omission-closing-head.js index 3460d52..c5ed5eb 100644 --- a/test/omission-closing-head.js +++ b/test/omission-closing-head.js @@ -2,21 +2,20 @@ import assert from 'node:assert/strict' import test from 'node:test' import {h} from 'hastscript' import {toHtml} from 'hast-util-to-html' -import {u} from 'unist-builder' test('`head` (closing)', async function (t) { await t.test('should omit tag without following', async function () { - assert.deepEqual(toHtml(h('head'), {omitOptionalTags: true}), '') + assert.deepEqual(toHtml(h('head'), {omitOptionalTags: true}), '') }) await t.test( 'should not omit tag if followed by `comment`', async function () { assert.deepEqual( - toHtml(h('html', [h('head'), u('comment', 'alpha')]), { + toHtml(h('html', [h('head'), {type: 'comment', value: 'alpha'}]), { omitOptionalTags: true }), - '' + '' ) } ) @@ -26,7 +25,7 @@ test('`head` (closing)', async function (t) { async function () { assert.deepEqual( toHtml(h('html', [h('head'), ' alpha']), {omitOptionalTags: true}), - ' alpha' + ' alpha' ) } ) @@ -35,10 +34,10 @@ test('`head` (closing)', async function (t) { 'should omit tag if not followed by `comment`', async function () { assert.deepEqual( - toHtml(h('html', [h('head'), u('text', 'alpha')]), { + toHtml(h('html', [h('head'), {type: 'text', value: 'alpha'}]), { omitOptionalTags: true }), - 'alpha' + 'alpha' ) } ) diff --git a/test/omission-closing-html.js b/test/omission-closing-html.js index a14820d..cb19331 100644 --- a/test/omission-closing-html.js +++ b/test/omission-closing-html.js @@ -2,7 +2,6 @@ import assert from 'node:assert/strict' import test from 'node:test' import {h} from 'hastscript' import {toHtml} from 'hast-util-to-html' -import {u} from 'unist-builder' test('`html` (closing)', async function (t) { await t.test('should omit tag without following', async function () { @@ -13,9 +12,13 @@ test('`html` (closing)', async function (t) { 'should not omit tag if followed by `comment`', async function () { assert.deepEqual( - toHtml(u('root', [h('html'), u('comment', 'alpha')]), { - omitOptionalTags: true - }), + toHtml( + { + type: 'root', + children: [h('html'), {type: 'comment', value: 'alpha'}] + }, + {omitOptionalTags: true} + ), '' ) } @@ -25,9 +28,10 @@ test('`html` (closing)', async function (t) { 'should omit tag if not followed by `comment`', async function () { assert.deepEqual( - toHtml(u('root', [h('html'), u('text', 'alpha')]), { - omitOptionalTags: true - }), + toHtml( + {type: 'root', children: [h('html'), {type: 'text', value: 'alpha'}]}, + {omitOptionalTags: true} + ), 'alpha' ) } diff --git a/test/omission-closing-p.js b/test/omission-closing-p.js index 1c242f4..4c8790c 100644 --- a/test/omission-closing-p.js +++ b/test/omission-closing-p.js @@ -2,40 +2,51 @@ import assert from 'node:assert/strict' import test from 'node:test' import {h} from 'hastscript' import {toHtml} from 'hast-util-to-html' -import {u} from 'unist-builder' test('`p` (closing)', async function (t) { await t.test('should omit tag without following', async function () { assert.deepEqual( - toHtml(u('root', [h('p')]), {omitOptionalTags: true}), + toHtml({type: 'root', children: [h('p')]}, {omitOptionalTags: true}), '

' ) }) await t.test('should omit tag if followed by `address`', async function () { assert.deepEqual( - toHtml(u('root', [h('p'), h('address')]), {omitOptionalTags: true}), + toHtml( + {type: 'root', children: [h('p'), h('address')]}, + {omitOptionalTags: true} + ), '

' ) }) await t.test('should omit tag if followed by `ul`', async function () { assert.deepEqual( - toHtml(u('root', [h('p'), h('ul')]), {omitOptionalTags: true}), + toHtml( + {type: 'root', children: [h('p'), h('ul')]}, + {omitOptionalTags: true} + ), '

    ' ) }) await t.test('should not omit tag if followed by `a`', async function () { assert.deepEqual( - toHtml(u('root', [h('p'), h('a')]), {omitOptionalTags: true}), + toHtml( + {type: 'root', children: [h('p'), h('a')]}, + {omitOptionalTags: true} + ), '

    ' ) }) await t.test('should not omit tag if followed by `xmp`', async function () { assert.deepEqual( - toHtml(u('root', [h('p'), h('xmp')]), {omitOptionalTags: true}), + toHtml( + {type: 'root', children: [h('p'), h('xmp')]}, + {omitOptionalTags: true} + ), '

    ' ) }) diff --git a/test/omission-opening-body.js b/test/omission-opening-body.js index cd2e509..4a69962 100644 --- a/test/omission-opening-body.js +++ b/test/omission-opening-body.js @@ -2,7 +2,6 @@ import assert from 'node:assert/strict' import test from 'node:test' import {h} from 'hastscript' import {toHtml} from 'hast-util-to-html' -import {u} from 'unist-builder' test('`body` (opening)', async function (t) { await t.test('should omit tag without children', async function () { @@ -13,7 +12,9 @@ test('`body` (opening)', async function (t) { 'should not omit tag if the head is a `comment`', async function () { assert.deepEqual( - toHtml(h('body', u('comment', 'alpha')), {omitOptionalTags: true}), + toHtml(h('body', [{type: 'comment', value: 'alpha'}]), { + omitOptionalTags: true + }), '' ) } diff --git a/test/omission-opening-colgroup.js b/test/omission-opening-colgroup.js index 1c294d2..48c6701 100644 --- a/test/omission-opening-colgroup.js +++ b/test/omission-opening-colgroup.js @@ -2,7 +2,6 @@ import assert from 'node:assert/strict' import test from 'node:test' import {h} from 'hastscript' import {toHtml} from 'hast-util-to-html' -import {u} from 'unist-builder' test('`colgroup` (opening)', async function (t) { await t.test('should not omit tag without children', async function () { @@ -28,7 +27,7 @@ test('`colgroup` (opening)', async function (t) { await t.test('should not omit tag followed by `comment`', async function () { assert.deepEqual( - toHtml(h('table', [h('colgroup'), u('comment', 'alpha')]), { + toHtml(h('table', [h('colgroup'), {type: 'comment', value: 'alpha'}]), { omitOptionalTags: true }), '
    ' diff --git a/test/omission-opening-head.js b/test/omission-opening-head.js index c53c799..0932964 100644 --- a/test/omission-opening-head.js +++ b/test/omission-opening-head.js @@ -11,9 +11,12 @@ test('`head` (opening)', async function (t) { ) }) - await t.test('should not omit tag without children', async function () { - assert.deepEqual(toHtml(h('head'), {omitOptionalTags: true}), '') - }) + await t.test( + 'should omit tag without children (could be fine in `srcdoc`)', + async function () { + assert.deepEqual(toHtml(h('head'), {omitOptionalTags: true}), '') + } + ) await t.test('should omit tag with `title`', async function () { assert.deepEqual( diff --git a/test/omission-opening-html.js b/test/omission-opening-html.js index 94cb6ac..8465b0c 100644 --- a/test/omission-opening-html.js +++ b/test/omission-opening-html.js @@ -2,7 +2,6 @@ import assert from 'node:assert/strict' import test from 'node:test' import {h} from 'hastscript' import {toHtml} from 'hast-util-to-html' -import {u} from 'unist-builder' test('`html` (opening)', async function (t) { await t.test('should omit tag without first child', async function () { @@ -11,7 +10,7 @@ test('`html` (opening)', async function (t) { await t.test('should not omit tag if head is `comment`', async function () { assert.deepEqual( - toHtml(h('html', [u('comment', 'alpha'), 'bravo']), { + toHtml(h('html', [{type: 'comment', value: 'alpha'}, 'bravo']), { omitOptionalTags: true }), 'bravo' diff --git a/test/raw.js b/test/raw.js index 3ad8b94..c9cc1d7 100644 --- a/test/raw.js +++ b/test/raw.js @@ -1,16 +1,15 @@ /** - * @typedef {import('hast-util-raw')} DoNotTouchThisRegistersRawInTheTree + * @import {} from 'mdast-util-to-hast' */ import assert from 'node:assert/strict' import test from 'node:test' import {toHtml} from 'hast-util-to-html' -import {u} from 'unist-builder' test('`raw`', async function (t) { await t.test('should encode `raw`s', async function () { assert.deepEqual( - toHtml(u('raw', '')), + toHtml({type: 'raw', value: ''}), '<script>alert("XSS!")</script>' ) }) @@ -19,9 +18,10 @@ test('`raw`', async function (t) { 'should not encode `raw`s in `allowDangerousHtml` mode', async function () { assert.deepEqual( - toHtml(u('raw', ''), { - allowDangerousHtml: true - }), + toHtml( + {type: 'raw', value: ''}, + {allowDangerousHtml: true} + ), '' ) } diff --git a/test/root.js b/test/root.js index f80541a..afd87c0 100644 --- a/test/root.js +++ b/test/root.js @@ -2,14 +2,18 @@ import assert from 'node:assert/strict' import test from 'node:test' import {h} from 'hastscript' import {toHtml} from 'hast-util-to-html' -import {u} from 'unist-builder' test('`root`', async function (t) { await t.test('should serialize `root`s', async function () { assert.deepEqual( - toHtml( - u('root', [u('text', 'alpha '), h('i', 'bravo'), u('text', ' charlie')]) - ), + toHtml({ + type: 'root', + children: [ + {type: 'text', value: 'alpha '}, + h('i', 'bravo'), + {type: 'text', value: ' charlie'} + ] + }), 'alpha bravo charlie' ) }) @@ -17,7 +21,7 @@ test('`root`', async function (t) { await t.test('should serialize `root`s w/o children', async function () { assert.deepEqual( // @ts-expect-error: check how the runtime handles missing `children`. - toHtml(u('root')), + toHtml({type: 'root'}), '' ) }) diff --git a/test/security.js b/test/security.js index 0c8ee59..0b2df61 100644 --- a/test/security.js +++ b/test/security.js @@ -2,14 +2,18 @@ import assert from 'node:assert/strict' import test from 'node:test' import {h} from 'hastscript' import {toHtml} from 'hast-util-to-html' -import {u} from 'unist-builder' test('security', async function (t) { await t.test( 'should make sure comments cannot break out of their context (safe)', async function () { assert.equal( - toHtml(u('root', [u('comment', '-->' ) } @@ -17,7 +21,7 @@ test('security', async function (t) { await t.test('should make sure scripts render (unsafe)', async function () { assert.equal( - toHtml(u('root', [h('script', 'alert(1)')])), + toHtml({type: 'root', children: [h('script', 'alert(1)')]}), '' ) }) @@ -34,7 +38,10 @@ test('security', async function (t) { await t.test('should make sure texts are encoded (safe)', async function () { assert.equal( - toHtml(u('root', u('text', ''))), + toHtml({ + type: 'root', + children: [{type: 'text', value: ''}] + }), '<script>alert(1)</script>' ) }) diff --git a/test/svg.js b/test/svg.js index 2408efe..00af190 100644 --- a/test/svg.js +++ b/test/svg.js @@ -2,7 +2,6 @@ import assert from 'node:assert/strict' import test from 'node:test' import {h, s} from 'hastscript' import {toHtml} from 'hast-util-to-html' -import {u} from 'unist-builder' test('svg', async function (t) { await t.test('should serialize `element`s', async function () { @@ -401,7 +400,12 @@ test('svg', async function (t) { await t.test('should ignore attributes set to `null`', async function () { assert.deepEqual( - toHtml(u('element', {tagName: 'circle', properties: {id: null}}, [])), + toHtml({ + type: 'element', + tagName: 'circle', + properties: {id: null}, + children: [] + }), '' ) }) @@ -410,9 +414,12 @@ test('svg', async function (t) { 'should ignore attributes set to `undefined`', async function () { assert.deepEqual( - toHtml( - u('element', {tagName: 'circle', properties: {id: undefined}}, []) - ), + toHtml({ + type: 'element', + tagName: 'circle', + properties: {id: undefined}, + children: [] + }), '' ) } @@ -473,9 +480,10 @@ test('svg', async function (t) { 'should serialize an HTML tree with embedded HTML', async function () { assert.deepEqual( - toHtml( - u('root', [ - u('doctype', {name: 'html'}), + toHtml({ + type: 'root', + children: [ + {type: 'doctype'}, h('head', h('title', 'The SVG `` element')), h('body', [ s( @@ -487,8 +495,8 @@ test('svg', async function (t) { s('circle', {cx: 120, cy: 120, r: 100}) ) ]) - ]) - ), + ] + }), [ '', 'Codestin Search App', diff --git a/test/text.js b/test/text.js index 748d8f6..a614c3d 100644 --- a/test/text.js +++ b/test/text.js @@ -1,33 +1,40 @@ import assert from 'node:assert/strict' import test from 'node:test' import {h} from 'hastscript' -import {u} from 'unist-builder' import {toHtml} from 'hast-util-to-html' test('`text`', async function (t) { await t.test('should serialize `text`s', async function () { - assert.deepEqual(toHtml(u('text', 'alpha')), 'alpha') + assert.deepEqual(toHtml({type: 'text', value: 'alpha'}), 'alpha') }) await t.test('should encode `text`s', async function () { - assert.deepEqual(toHtml(u('text', '3 < 5 & 7')), '3 < 5 & 7') + assert.deepEqual( + toHtml({type: 'text', value: '3 < 5 & 7'}), + '3 < 5 & 7' + ) }) await t.test('should not encode `text`s in `style`', async function () { assert.deepEqual( - toHtml(h('style', u('text', '*:before {content: "3 < 5"}'))), + toHtml( + h('style', [{type: 'text', value: '*:before {content: "3 < 5"}'}]) + ), '' ) }) await t.test('should not encode `text`s in `script`', async function () { assert.deepEqual( - toHtml(h('script', u('text', 'alert("3 < 5")'))), + toHtml(h('script', [{type: 'text', value: 'alert("3 < 5")'}])), '' ) }) await t.test('should encode `text`s in other nodes', async function () { - assert.deepEqual(toHtml(h('b', u('text', '3 < 5'))), '3 < 5') + assert.deepEqual( + toHtml(h('b', [{type: 'text', value: '3 < 5'}])), + '3 < 5' + ) }) }) diff --git a/tsconfig.json b/tsconfig.json index 82cc749..4d9161a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,6 +3,7 @@ "checkJs": true, "customConditions": ["development"], "declaration": true, + "declarationMap": true, "emitDeclarationOnly": true, "exactOptionalPropertyTypes": true, "lib": ["es2022"],