diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 69924a4..fb63387 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,15 +7,15 @@ jobs: name: ${{matrix.node}} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: dcodeIO/setup-node-nvm@master + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: ${{matrix.node}} - run: npm install - run: npm test - - uses: codecov/codecov-action@v1 + - uses: codecov/codecov-action@v3 strategy: matrix: node: - - lts/fermium + - lts/gallium - node diff --git a/index.js b/index.js index 0081f26..3a0b54d 100644 --- a/index.js +++ b/index.js @@ -1,310 +1,8 @@ /** - * @typedef {import('unist').Node} Node - * @typedef {import('unist').Position} Position - * @typedef {import('unist').Point} Point - * - * @typedef Options - * @property {boolean} [showPositions=true] + * @typedef {import('./lib/index.js')} Options * * @typedef {Options} InspectOptions * Deprecated, use `Options`. */ -import {color} from './color.js' - -/* c8 ignore next */ -export const inspect = color ? inspectColor : inspectNoColor - -const own = {}.hasOwnProperty - -const bold = ansiColor(1, 22) -const dim = ansiColor(2, 22) -const yellow = ansiColor(33, 39) -const green = ansiColor(32, 39) - -// ANSI color regex. -/* eslint-disable no-control-regex */ -const colorExpression = - /(?:(?:\u001B\[)|\u009B)(?:\d{1,3})?(?:(?:;\d{0,3})*)?[A-M|f-m]|\u001B[A-M]/g -/* eslint-enable no-control-regex */ - -/** - * Inspects a node, without using color. - * - * @param {unknown} node - * @param {Options} [options] - * @returns {string} - */ -export function inspectNoColor(node, options) { - return inspectColor(node, options).replace(colorExpression, '') -} - -/** - * Inspects a node, using color. - * - * @param {unknown} tree - * @param {Options} [options] - * @returns {string} - */ -export function inspectColor(tree, options = {}) { - const positions = - options.showPositions === null || options.showPositions === undefined - ? true - : options.showPositions - - return inspectValue(tree) - - /** - * @param {unknown} node - * @returns {string} - */ - function inspectValue(node) { - if (node && typeof node === 'object' && 'length' in node) { - // @ts-expect-error looks like a list of nodes. - return inspectNodes(node) - } - - // @ts-expect-error looks like a single node. - if (node && node.type) { - // @ts-expect-error looks like a single node. - return inspectTree(node) - } - - return inspectNonTree(node) - } - - /** - * @param {unknown} value - * @returns {string} - */ - function inspectNonTree(value) { - return JSON.stringify(value) - } - - /** - * @param {Array} nodes - * @returns {string} - */ - function inspectNodes(nodes) { - const size = String(nodes.length - 1).length - /** @type {Array} */ - const result = [] - let index = -1 - - while (++index < nodes.length) { - result.push( - dim( - (index < nodes.length - 1 ? '├' : '└') + - '─' + - String(index).padEnd(size) - ) + - ' ' + - indent( - inspectValue(nodes[index]), - (index < nodes.length - 1 ? dim('│') : ' ') + ' '.repeat(size + 2), - true - ) - ) - } - - return result.join('\n') - } - - /** - * @param {Record} object - * @returns {string} - */ - // eslint-disable-next-line complexity - function inspectFields(object) { - /** @type {Array} */ - const result = [] - /** @type {string} */ - let key - - for (key in object) { - /* c8 ignore next 1 */ - if (!own.call(object, key)) continue - - const value = object[key] - /** @type {string} */ - let formatted - - if ( - value === undefined || - // Standard keys defined by unist that we format differently. - // - key === 'type' || - key === 'value' || - key === 'children' || - key === 'position' || - // Ignore `name` (from xast) and `tagName` (from `hast`) when string. - (typeof value === 'string' && (key === 'name' || key === 'tagName')) - ) { - continue - } - - // A single node. - if ( - value && - typeof value === 'object' && - // @ts-expect-error looks like a node. - value.type && - key !== 'data' && - key !== 'attributes' && - key !== 'properties' - ) { - // @ts-expect-error looks like a node. - formatted = inspectTree(value) - } - // A list of nodes. - else if ( - value && - Array.isArray(value) && - // Looks like a node. - // type-coverage:ignore-next-line - value[0] && - // Looks like a node. - // type-coverage:ignore-next-line - value[0].type - ) { - formatted = '\n' + inspectNodes(value) - } else { - formatted = inspectNonTree(value) - } - - result.push( - key + dim(':') + (/\s/.test(formatted.charAt(0)) ? '' : ' ') + formatted - ) - } - - return indent( - result.join('\n'), - // @ts-expect-error looks like a parent node. - (object.children && object.children.length > 0 ? dim('│') : ' ') + ' ' - ) - } - - /** - * @param {Node} node - * @returns {string} - */ - function inspectTree(node) { - const result = [formatNode(node)] - // @ts-expect-error: looks like a record. - const fields = inspectFields(node) - // @ts-expect-error looks like a parent. - const content = inspectNodes(node.children || []) - if (fields) result.push(fields) - if (content) result.push(content) - return result.join('\n') - } - - /** - * Colored node formatter. - * - * @param {Node} node - * @returns {string} - */ - function formatNode(node) { - const result = [bold(node.type)] - /** @type {string|undefined} */ - // @ts-expect-error: might be available. - const kind = node.tagName || node.name - const position = positions ? stringifyPosition(node.position) : '' - - if (typeof kind === 'string') { - result.push('<', kind, '>') - } - - // @ts-expect-error: looks like a parent. - if (node.children) { - // @ts-expect-error looks like a parent. - result.push(dim('['), yellow(node.children.length), dim(']')) - // @ts-expect-error: looks like a literal. - } else if (typeof node.value === 'string') { - // @ts-expect-error: looks like a literal. - result.push(' ', green(inspectNonTree(node.value))) - } - - if (position) { - result.push(' ', dim('('), position, dim(')')) - } - - return result.join('') - } -} - -/** - * @param {string} value - * @param {string} indentation - * @param {boolean} [ignoreFirst=false] - * @returns {string} - */ -function indent(value, indentation, ignoreFirst) { - const lines = value.split('\n') - let index = ignoreFirst ? 0 : -1 - - if (!value) return value - - while (++index < lines.length) { - lines[index] = indentation + lines[index] - } - - return lines.join('\n') -} - -/** - * @param {Position|undefined} [value] - * @returns {string} - */ -function stringifyPosition(value) { - /** @type {Position} */ - // @ts-expect-error: fine. - const position = value || {} - /** @type {Array} */ - const result = [] - /** @type {Array} */ - const positions = [] - /** @type {Array} */ - const offsets = [] - - point(position.start) - point(position.end) - - if (positions.length > 0) result.push(positions.join('-')) - if (offsets.length > 0) result.push(offsets.join('-')) - - return result.join(', ') - - /** - * @param {Point} value - */ - function point(value) { - if (value) { - positions.push((value.line || 1) + ':' + (value.column || 1)) - - if ('offset' in value) { - offsets.push(String(value.offset || 0)) - } - } - } -} - -/** - * Factory to wrap values in ANSI colours. - * - * @param {number} open - * @param {number} close - * @returns {function(string): string} - */ -function ansiColor(open, close) { - return color - - /** - * @param {string} value - * @returns {string} - */ - function color(value) { - return '\u001B[' + open + 'm' + value + '\u001B[' + close + 'm' - } -} +export {inspect, inspectColor, inspectNoColor} from './lib/index.js' diff --git a/color-browser.js b/lib/color-browser.js similarity index 100% rename from color-browser.js rename to lib/color-browser.js diff --git a/color.js b/lib/color.js similarity index 100% rename from color.js rename to lib/color.js diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 0000000..477a9e9 --- /dev/null +++ b/lib/index.js @@ -0,0 +1,397 @@ +/** + * @typedef {import('unist').Node} Node + * + * @typedef Options + * Configuration. + * @property {boolean | null | undefined} [showPositions=true] + * Whether to include positional information. + * + * @typedef State + * Info passed around. + * @property {boolean} showPositions + * Whether to include positional information. + */ + +import {color} from './color.js' + +/** + * Inspect a node, with color in Node, without color in browsers. + * + * @param tree + * Tree to inspect. + * @param options + * Configuration. + * @returns + * Pretty printed `tree`. + */ +/* c8 ignore next */ +export const inspect = color ? inspectColor : inspectNoColor + +const own = {}.hasOwnProperty + +const bold = ansiColor(1, 22) +const dim = ansiColor(2, 22) +const yellow = ansiColor(33, 39) +const green = ansiColor(32, 39) + +// ANSI color regex. +/* eslint-disable no-control-regex */ +const colorExpression = + /(?:(?:\u001B\[)|\u009B)(?:\d{1,3})?(?:(?:;\d{0,3})*)?[A-M|f-m]|\u001B[A-M]/g +/* eslint-enable no-control-regex */ + +/** + * Inspect a node, without color. + * + * @param {unknown} tree + * Tree to inspect. + * @param {Options | null | undefined} [options] + * Configuration. + * @returns {string} + * Pretty printed `tree`. + */ +export function inspectNoColor(tree, options) { + return inspectColor(tree, options).replace(colorExpression, '') +} + +/** + * Inspects a node, using color. + * + * @param {unknown} tree + * Tree to inspect. + * @param {Options | null | undefined} [options] + * Configuration. + * @returns {string} + * Pretty printed `tree`. + */ +export function inspectColor(tree, options) { + /** @type {State} */ + const state = { + showPositions: + !options || + options.showPositions === null || + options.showPositions === undefined + ? true + : options.showPositions + } + + return inspectValue(tree, state) +} + +/** + * Format any value. + * + * @param {unknown} node + * Thing to format. + * @param {State} state + * Info passed around. + * @returns {string} + * Formatted thing. + */ +function inspectValue(node, state) { + if (isArrayUnknown(node)) { + return inspectNodes(node, state) + } + + if (isNode(node)) { + return inspectTree(node, state) + } + + return inspectNonTree(node) +} + +/** + * Format an unknown value. + * + * @param {unknown} value + * Thing to format. + * @returns {string} + * Formatted thing. + */ +function inspectNonTree(value) { + return JSON.stringify(value) +} + +/** + * Format a list of nodes. + * + * @param {Array} nodes + * Nodes to format. + * @param {State} state + * Info passed around. + * @returns {string} + * Formatted nodes. + */ +function inspectNodes(nodes, state) { + const size = String(nodes.length - 1).length + /** @type {Array} */ + const result = [] + let index = -1 + + while (++index < nodes.length) { + result.push( + dim( + (index < nodes.length - 1 ? '├' : '└') + + '─' + + String(index).padEnd(size) + ) + + ' ' + + indent( + inspectValue(nodes[index], state), + (index < nodes.length - 1 ? dim('│') : ' ') + ' '.repeat(size + 2), + true + ) + ) + } + + return result.join('\n') +} + +/** + * Format the fields in a node. + * + * @param {Record} object + * Node to format. + * @param {State} state + * Info passed around. + * @returns {string} + * Formatted node. + */ +// eslint-disable-next-line complexity +function inspectFields(object, state) { + /** @type {Array} */ + const result = [] + /** @type {string} */ + let key + + for (key in object) { + /* c8 ignore next 1 */ + if (!own.call(object, key)) continue + + const value = object[key] + /** @type {string} */ + let formatted + + if ( + value === undefined || + // Standard keys defined by unist that we format differently. + // + key === 'type' || + key === 'value' || + key === 'children' || + key === 'position' || + // Ignore `name` (from xast) and `tagName` (from `hast`) when string. + (typeof value === 'string' && (key === 'name' || key === 'tagName')) + ) { + continue + } + + // A single node. + if ( + isNode(value) && + key !== 'data' && + key !== 'attributes' && + key !== 'properties' + ) { + formatted = inspectTree(value, state) + } + // A list of nodes. + else if (value && isArrayUnknown(value) && isNode(value[0])) { + formatted = '\n' + inspectNodes(value, state) + } else { + formatted = inspectNonTree(value) + } + + result.push( + key + dim(':') + (/\s/.test(formatted.charAt(0)) ? '' : ' ') + formatted + ) + } + + return indent( + result.join('\n'), + (isArrayUnknown(object.children) && object.children.length > 0 + ? dim('│') + : ' ') + ' ' + ) +} + +/** + * Format a node, its fields, and its children. + * + * @param {Node} node + * Node to format. + * @param {State} state + * Info passed around. + * @returns {string} + * Formatted node. + */ +function inspectTree(node, state) { + const result = [formatNode(node, state)] + // Cast as record to allow indexing. + const map = /** @type {Record} */ ( + /** @type {unknown} */ (node) + ) + const fields = inspectFields(map, state) + const content = isArrayUnknown(map.children) + ? inspectNodes(map.children, state) + : '' + if (fields) result.push(fields) + if (content) result.push(content) + return result.join('\n') +} + +/** + * Format a node itself. + * + * @param {Node} node + * Node to format. + * @param {State} state + * Info passed around. + * @returns {string} + * Formatted node. + */ +function formatNode(node, state) { + const result = [bold(node.type)] + // Cast as record to allow indexing. + const map = /** @type {Record} */ ( + /** @type {unknown} */ (node) + ) + const kind = map.tagName || map.name + const position = state.showPositions ? stringifyPosition(node.position) : '' + + if (typeof kind === 'string') { + result.push('<', kind, '>') + } + + if (isArrayUnknown(map.children)) { + result.push(dim('['), yellow(String(map.children.length)), dim(']')) + } else if (typeof map.value === 'string') { + result.push(' ', green(inspectNonTree(map.value))) + } + + if (position) { + result.push(' ', dim('('), position, dim(')')) + } + + return result.join('') +} + +/** + * Indent a value. + * + * @param {string} value + * Value to indent. + * @param {string} indentation + * Indent to use. + * @param {boolean | undefined} [ignoreFirst=false] + * Whether to ignore indenting the first line. + * @returns {string} + * Indented `value`. + */ +function indent(value, indentation, ignoreFirst) { + if (!value) return value + + const lines = value.split('\n') + let index = ignoreFirst ? 0 : -1 + + while (++index < lines.length) { + lines[index] = indentation + lines[index] + } + + return lines.join('\n') +} + +/** + * Serialize a position. + * + * @param {unknown | null | undefined} [value] + * Position to serialize. + * @returns {string} + * Serialized position. + */ +function stringifyPosition(value) { + /** @type {Array} */ + const result = [] + /** @type {Array} */ + const positions = [] + /** @type {Array} */ + const offsets = [] + + if (value && typeof value === 'object') { + point('start' in value ? value.start : undefined) + point('end' in value ? value.end : undefined) + } + + if (positions.length > 0) result.push(positions.join('-')) + if (offsets.length > 0) result.push(offsets.join('-')) + + return result.join(', ') + + /** + * Add a point. + * + * @param {unknown} value + * Point to add. + */ + function point(value) { + if (value && typeof value === 'object') { + const line = + 'line' in value && typeof value.line === 'number' ? value.line : 1 + const column = + 'column' in value && typeof value.column === 'number' ? value.column : 1 + + positions.push(line + ':' + column) + + if ('offset' in value && typeof value.offset === 'number') { + offsets.push(String(value.offset || 0)) + } + } + } +} + +/** + * Factory to wrap values in ANSI colours. + * + * @param {number} open + * Opening color code. + * @param {number} close + * Closing color code. + * @returns {(value: string) => string} + * Color `value`. + */ +function ansiColor(open, close) { + return color + + /** + * Color `value`. + * + * @param {string} value + * Value to color. + * @returns {string} + * Colored `value`. + */ + function color(value) { + return '\u001B[' + open + 'm' + value + '\u001B[' + close + 'm' + } +} + +/** + * @param {unknown} value + * @returns {value is Node} + */ +function isNode(value) { + return Boolean( + value && + typeof value === 'object' && + 'type' in value && + typeof value.type === 'string' + ) +} + +/** + * @param {unknown} node + * @returns {node is Array} + */ +function isArrayUnknown(node) { + return Array.isArray(node) +} diff --git a/package.json b/package.json index 6557954..75467aa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "unist-util-inspect", - "version": "7.0.1", + "version": "7.0.2", "description": "unist utility to inspect nodes", "license": "MIT", "keywords": [ @@ -27,17 +27,14 @@ "type": "module", "main": "index.js", "browser": { - "./color.js": "./color-browser.js" + "./lib/color.js": "./lib/color-browser.js" }, "react-native": { - "./color.js": "./color-browser.js" + "./lib/color.js": "./lib/color-browser.js" }, "types": "index.d.ts", "files": [ - "color.d.ts", - "color.js", - "color-browser.d.ts", - "color-browser.js", + "lib/", "index.d.ts", "index.js" ], @@ -45,7 +42,7 @@ "@types/unist": "^2.0.0" }, "devDependencies": { - "@types/tape": "^4.0.0", + "@types/node": "^18.0.0", "c8": "^7.0.0", "chalk": "^5.0.0", "hastscript": "^7.0.0", @@ -53,22 +50,20 @@ "remark-cli": "^11.0.0", "remark-preset-wooorm": "^9.0.0", "retext": "^8.0.0", - "rimraf": "^3.0.0", "strip-ansi": "^7.0.0", - "tape": "^5.0.0", "type-coverage": "^2.0.0", "typescript": "^4.0.0", "unist-builder": "^3.0.0", "xast-util-from-xml": "^2.0.0", "xastscript": "^3.0.0", - "xo": "^0.51.0" + "xo": "^0.53.0" }, "scripts": { "prepack": "npm run build && npm run format", - "build": "rimraf \"*.d.ts\" && tsc && type-coverage", + "build": "tsc --build --clean && tsc --build && type-coverage", "format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix", - "test-api": "node test.js", - "test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov node test.js", + "test-api": "node --conditions development test.js", + "test-coverage": "c8 --check-coverage --100 --reporter lcov npm run test-api", "test": "npm run build && npm run format && npm run test-coverage" }, "prettier": { diff --git a/readme.md b/readme.md index 7b65e77..572a337 100644 --- a/readme.md +++ b/readme.md @@ -17,9 +17,10 @@ * [Install](#install) * [Use](#use) * [API](#api) - * [`inspect(node[, options])`](#inspectnode-options) - * [`inspectColor(node[, options])`](#inspectcolornode-options) - * [`inspectNoColor(node[, options])`](#inspectnocolornode-options) + * [`inspect(tree[, options])`](#inspecttree-options) + * [`inspectColor(tree[, options])`](#inspectcolortree-options) + * [`inspectNoColor(tree[, options])`](#inspectnocolortree-options) + * [`Options`](#options) * [Types](#types) * [Compatibility](#compatibility) * [Contribute](#contribute) @@ -38,7 +39,7 @@ to more easily spot bugs and see what’s going on in the tree. ## Install This package is [ESM only][esm]. -In Node.js (version 12.20+, 14.14+, 16.0+, 18.0+), install with [npm][]: +In Node.js (version 14.14+ and 16.0+), install with [npm][]: ```sh npm install unist-util-inspect @@ -47,14 +48,14 @@ npm install unist-util-inspect In Deno with [`esm.sh`][esmsh]: ```js -import {inspect} from "https://esm.sh/unist-util-inspect@8" +import {inspect} from 'https://esm.sh/unist-util-inspect@7' ``` In browsers with [`esm.sh`][esmsh]: ```html ``` @@ -91,42 +92,54 @@ root[2] ## API -This package exports the identifiers `inspect`, `inspectColor`, and -`inspectNoColor`. +This package exports the identifiers [`inspect`][api-inspect], +[`inspectColor`][api-inspectcolor], and [`inspectNoColor`][api-inspectnocolor]. There is no default export. -### `inspect(node[, options])` +### `inspect(tree[, options])` -Inspect the given `node` ([`Node`][node]). -By default, colors are added in Node, and not in other places. -See below on how to change that. +Inspect a tree, with color in Node, without color in browsers. -###### `options.showPositions` +###### Parameters -Whether to include positional information (`boolean`, default: `true`). +* `tree` ([`Node`][node]) + — tree to inspect +* `options` ([`Options`][api-options], optional) + — configuration -##### Returns +###### Returns -Pretty printed `node` (`string`). +Pretty printed `tree` (`string`). -### `inspectColor(node[, options])` +### `inspectColor(tree[, options])` -Inspect with ANSI color sequences (default in Node, Deno). +Inspect a tree, with color. +Otherwise same as [`inspect`][api-inspect]. -### `inspectNoColor(node[, options])` +### `inspectNoColor(tree[, options])` -Inspect without ANSI color sequences (default in browser, `react-native`). +Inspect a tree, without color. +Otherwise same as [`inspect`][api-inspect]. + +### `Options` + +Configuration (TypeScript type). + +###### Fields + +* `showPositions` (`boolean`, default: `true`) + — whether to include positional information ## Types This package is fully typed with [TypeScript][]. -It exports the additional type `Options`. +It exports the additional type [`Options`][api-options]. ## Compatibility Projects maintained by the unified collective are compatible with all maintained versions of Node.js. -As of now, that is Node.js 12.20+, 14.14+, 16.0+, and 18.0+. +As of now, that is Node.js 14.14+ and 16.0+. Our projects sometimes work with older versions, but this is not guaranteed. ## Contribute @@ -194,3 +207,11 @@ abide by its terms. [unist]: https://github.com/syntax-tree/unist [node]: https://github.com/syntax-tree/unist#node + +[api-inspect]: #inspecttree-options + +[api-inspectcolor]: #inspectcolortree-options + +[api-inspectnocolor]: #inspectnocolortree-options + +[api-options]: #options diff --git a/test.js b/test.js index 2fd5caa..7531e4c 100644 --- a/test.js +++ b/test.js @@ -1,4 +1,5 @@ -import test from 'tape' +import assert from 'node:assert/strict' +import test from 'node:test' /* eslint-disable-next-line unicorn/import-style */ import {Chalk} from 'chalk' import strip from 'strip-ansi' @@ -8,19 +9,22 @@ import {x} from 'xastscript' import {retext} from 'retext' import {fromXml} from 'xast-util-from-xml' import {inspect, inspectColor, inspectNoColor} from './index.js' +import * as mod from './index.js' const chalkEnabled = new Chalk({level: 1}) const paragraph = 'Some simple text. Other “sentence”.' -test('inspect', (t) => { - t.equal(typeof inspect, 'function', 'should be a `function`') - - t.end() +test('core', () => { + assert.deepEqual( + Object.keys(mod).sort(), + ['inspect', 'inspectColor', 'inspectNoColor'], + 'should expose the public api' + ) }) -test('inspect()', (t) => { - t.equal( +test('inspect()', () => { + assert.equal( strip(inspect(retext().parse(paragraph))), [ 'RootNode[1] (1:1-1:36, 0-35)', @@ -49,22 +53,20 @@ test('inspect()', (t) => { 'should work on `RootNode`' ) - t.equal( + assert.equal( strip(inspect([u('SymbolNode', '$'), u('WordNode', [u('text', '5,00')])])), '├─0 SymbolNode "$"\n└─1 WordNode[1]\n └─0 text "5,00"', 'should work with a list of nodes' ) - t.test('should work on non-nodes', (st) => { - st.equal(strip(inspect('foo')), '"foo"') - st.equal(strip(inspect(null)), 'null') - st.equal(strip(inspect(Number.NaN)), 'null') - st.equal(strip(inspect(3)), '3') + assert.doesNotThrow(() => { + assert.equal(strip(inspect('foo')), '"foo"') + assert.equal(strip(inspect(null)), 'null') + assert.equal(strip(inspect(Number.NaN)), 'null') + assert.equal(strip(inspect(3)), '3') + }, 'should work on non-nodes') - st.end() - }) - - t.equal( + assert.equal( strip( inspect( Array.from({length: 11}).map((/** @type {undefined} */ d, i) => ({ @@ -101,7 +103,7 @@ test('inspect()', (t) => { 'should align and indent large numbers' ) - t.equal( + assert.equal( strip( inspect({ type: 'SymbolNode', @@ -113,7 +115,7 @@ test('inspect()', (t) => { 'should work with data attributes' ) - t.equal( + assert.equal( strip( inspect({ type: 'table', @@ -165,7 +167,7 @@ test('inspect()', (t) => { 'should work with other attributes' ) - t.equal( + assert.equal( strip( inspect({ type: 'element', @@ -177,19 +179,19 @@ test('inspect()', (t) => { 'should work on parent nodes without children' ) - t.equal( + assert.equal( strip(inspect({type: 'text', value: ''})), 'text ""', 'should work on text nodes without value' ) - t.equal( + assert.equal( strip(inspect({type: 'thematicBreak'})), 'thematicBreak', 'should work on void nodes' ) - t.equal( + assert.equal( strip(inspect(h('button', {type: 'submit', value: 'Send'}))), [ 'element