diff --git a/.npmrc b/.npmrc
index 9951b11..3757b30 100644
--- a/.npmrc
+++ b/.npmrc
@@ -1,2 +1,2 @@
-package-lock=false
ignore-scripts=true
+package-lock=false
diff --git a/lib/color-browser.js b/lib/color.default.js
similarity index 100%
rename from lib/color-browser.js
rename to lib/color.default.js
diff --git a/lib/color.js b/lib/color.node.js
similarity index 100%
rename from lib/color.js
rename to lib/color.node.js
diff --git a/lib/index.js b/lib/index.js
index 477a9e9..5388cde 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -1,10 +1,12 @@
/**
* @typedef {import('unist').Node} Node
- *
+ */
+
+/**
* @typedef Options
* Configuration.
* @property {boolean | null | undefined} [showPositions=true]
- * Whether to include positional information.
+ * Whether to include positional information (default: `true`).
*
* @typedef State
* Info passed around.
@@ -12,7 +14,7 @@
* Whether to include positional information.
*/
-import {color} from './color.js'
+import {color} from 'unist-util-inspect/do-not-use-conditional-color'
/**
* Inspect a node, with color in Node, without color in browsers.
@@ -20,7 +22,7 @@ import {color} from './color.js'
* @param tree
* Tree to inspect.
* @param options
- * Configuration.
+ * Configuration (optional).
* @returns
* Pretty printed `tree`.
*/
@@ -60,7 +62,7 @@ export function inspectNoColor(tree, options) {
* @param {unknown} tree
* Tree to inspect.
* @param {Options | null | undefined} [options]
- * Configuration.
+ * Configuration (optional).
* @returns {string}
* Pretty printed `tree`.
*/
@@ -284,7 +286,7 @@ function formatNode(node, state) {
* @param {string} indentation
* Indent to use.
* @param {boolean | undefined} [ignoreFirst=false]
- * Whether to ignore indenting the first line.
+ * Whether to ignore indenting the first line (default: `false`).
* @returns {string}
* Indented `value`.
*/
@@ -304,7 +306,7 @@ function indent(value, indentation, ignoreFirst) {
/**
* Serialize a position.
*
- * @param {unknown | null | undefined} [value]
+ * @param {unknown} [value]
* Position to serialize.
* @returns {string}
* Serialized position.
diff --git a/package.json b/package.json
index 75467aa..dc61f9b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "unist-util-inspect",
- "version": "7.0.2",
+ "version": "8.0.0",
"description": "unist utility to inspect nodes",
"license": "MIT",
"keywords": [
@@ -25,25 +25,25 @@
],
"sideEffects": false,
"type": "module",
- "main": "index.js",
- "browser": {
- "./lib/color.js": "./lib/color-browser.js"
+ "exports": {
+ ".": "./index.js",
+ "./do-not-use-conditional-color": {
+ "node": "./lib/color.node.js",
+ "default": "./lib/color.default.js"
+ }
},
- "react-native": {
- "./lib/color.js": "./lib/color-browser.js"
- },
- "types": "index.d.ts",
"files": [
"lib/",
"index.d.ts",
"index.js"
],
"dependencies": {
- "@types/unist": "^2.0.0"
+ "@types/unist": "^3.0.0"
},
"devDependencies": {
- "@types/node": "^18.0.0",
- "c8": "^7.0.0",
+ "@types/nlcst": "^2.0.0",
+ "@types/node": "^20.0.0",
+ "c8": "^8.0.0",
"chalk": "^5.0.0",
"hastscript": "^7.0.0",
"prettier": "^2.0.0",
@@ -52,39 +52,40 @@
"retext": "^8.0.0",
"strip-ansi": "^7.0.0",
"type-coverage": "^2.0.0",
- "typescript": "^4.0.0",
- "unist-builder": "^3.0.0",
- "xast-util-from-xml": "^2.0.0",
+ "typescript": "^5.0.0",
+ "unist-builder": "^4.0.0",
+ "xast-util-from-xml": "^3.0.0",
"xastscript": "^3.0.0",
- "xo": "^0.53.0"
+ "xo": "^0.54.0"
},
"scripts": {
"prepack": "npm run build && npm run format",
"build": "tsc --build --clean && tsc --build && type-coverage",
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix",
"test-api": "node --conditions development test.js",
- "test-coverage": "c8 --check-coverage --100 --reporter lcov npm run test-api",
+ "test-coverage": "c8 --100 --reporter lcov npm run test-api",
"test": "npm run build && npm run format && npm run test-coverage"
},
"prettier": {
- "tabWidth": 2,
- "useTabs": false,
- "singleQuote": true,
"bracketSpacing": false,
"semi": false,
- "trailingComma": "none"
- },
- "xo": {
- "prettier": true
+ "singleQuote": true,
+ "tabWidth": 2,
+ "trailingComma": "none",
+ "useTabs": false
},
"remarkConfig": {
"plugins": [
- "preset-wooorm"
+ "remark-preset-wooorm"
]
},
"typeCoverage": {
"atLeast": 100,
"detail": true,
+ "ignoreCatch": true,
"strict": true
+ },
+ "xo": {
+ "prettier": true
}
}
diff --git a/readme.md b/readme.md
index 572a337..7216c78 100644
--- a/readme.md
+++ b/readme.md
@@ -39,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 14.14+ and 16.0+), install with [npm][]:
+In Node.js (version 16+), install with [npm][]:
```sh
npm install unist-util-inspect
@@ -48,14 +48,14 @@ npm install unist-util-inspect
In Deno with [`esm.sh`][esmsh]:
```js
-import {inspect} from 'https://esm.sh/unist-util-inspect@7'
+import {inspect} from 'https://esm.sh/unist-util-inspect@8'
```
In browsers with [`esm.sh`][esmsh]:
```html
```
@@ -137,10 +137,13 @@ It exports the additional type [`Options`][api-options].
## Compatibility
-Projects maintained by the unified collective are compatible with all maintained
+Projects maintained by the unified collective are compatible with maintained
versions of Node.js.
-As of now, that is Node.js 14.14+ and 16.0+.
-Our projects sometimes work with older versions, but this is not guaranteed.
+
+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, `unist-util-inspect@^8`,
+compatible with Node.js 16.
## Contribute
@@ -170,9 +173,9 @@ abide by its terms.
[downloads]: https://www.npmjs.com/package/unist-util-inspect
-[size-badge]: https://img.shields.io/bundlephobia/minzip/unist-util-inspect.svg
+[size-badge]: https://img.shields.io/badge/dynamic/json?label=minzipped%20size&query=$.size.compressedSize&url=https://deno.bundlejs.com/?q=unist-util-inspect
-[size]: https://bundlephobia.com/result?p=unist-util-inspect
+[size]: https://bundlejs.com/?q=unist-util-inspect
[sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg
diff --git a/test.js b/test.js
index 7531e4c..3451006 100644
--- a/test.js
+++ b/test.js
@@ -1,384 +1,428 @@
+/**
+ * @typedef {import('nlcst').Root} NlcstRoot
+ */
+
import assert from 'node:assert/strict'
import test from 'node:test'
/* eslint-disable-next-line unicorn/import-style */
import {Chalk} from 'chalk'
+import {h} from 'hastscript'
+import {retext} from 'retext'
import strip from 'strip-ansi'
import {u} from 'unist-builder'
-import {h} from 'hastscript'
+import {inspect, inspectColor, inspectNoColor} from 'unist-util-inspect'
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('core', () => {
- assert.deepEqual(
- Object.keys(mod).sort(),
- ['inspect', 'inspectColor', 'inspectNoColor'],
- 'should expose the public api'
- )
-})
+test('inspect()', async function (t) {
+ await t.test('should expose the public api', async function () {
+ assert.deepEqual(Object.keys(await import('unist-util-inspect')).sort(), [
+ 'inspect',
+ 'inspectColor',
+ 'inspectNoColor'
+ ])
+ })
-test('inspect()', () => {
- assert.equal(
- strip(inspect(retext().parse(paragraph))),
- [
- 'RootNode[1] (1:1-1:36, 0-35)',
- '└─0 ParagraphNode[3] (1:1-1:36, 0-35)',
- ' ├─0 SentenceNode[6] (1:1-1:18, 0-17)',
- ' │ ├─0 WordNode[1] (1:1-1:5, 0-4)',
- ' │ │ └─0 TextNode "Some" (1:1-1:5, 0-4)',
- ' │ ├─1 WhiteSpaceNode " " (1:5-1:6, 4-5)',
- ' │ ├─2 WordNode[1] (1:6-1:12, 5-11)',
- ' │ │ └─0 TextNode "simple" (1:6-1:12, 5-11)',
- ' │ ├─3 WhiteSpaceNode " " (1:12-1:13, 11-12)',
- ' │ ├─4 WordNode[1] (1:13-1:17, 12-16)',
- ' │ │ └─0 TextNode "text" (1:13-1:17, 12-16)',
- ' │ └─5 PunctuationNode "." (1:17-1:18, 16-17)',
- ' ├─1 WhiteSpaceNode " " (1:18-1:19, 17-18)',
- ' └─2 SentenceNode[6] (1:19-1:36, 18-35)',
- ' ├─0 WordNode[1] (1:19-1:24, 18-23)',
- ' │ └─0 TextNode "Other" (1:19-1:24, 18-23)',
- ' ├─1 WhiteSpaceNode " " (1:24-1:25, 23-24)',
- ' ├─2 PunctuationNode "“" (1:25-1:26, 24-25)',
- ' ├─3 WordNode[1] (1:26-1:34, 25-33)',
- ' │ └─0 TextNode "sentence" (1:26-1:34, 25-33)',
- ' ├─4 PunctuationNode "”" (1:34-1:35, 33-34)',
- ' └─5 PunctuationNode "." (1:35-1:36, 34-35)'
- ].join('\n'),
- 'should work on `RootNode`'
- )
+ await t.test('should work on `RootNode`', async function () {
+ assert.equal(
+ strip(inspect(retext().parse(paragraph))),
+ [
+ 'RootNode[1] (1:1-1:36, 0-35)',
+ '└─0 ParagraphNode[3] (1:1-1:36, 0-35)',
+ ' ├─0 SentenceNode[6] (1:1-1:18, 0-17)',
+ ' │ ├─0 WordNode[1] (1:1-1:5, 0-4)',
+ ' │ │ └─0 TextNode "Some" (1:1-1:5, 0-4)',
+ ' │ ├─1 WhiteSpaceNode " " (1:5-1:6, 4-5)',
+ ' │ ├─2 WordNode[1] (1:6-1:12, 5-11)',
+ ' │ │ └─0 TextNode "simple" (1:6-1:12, 5-11)',
+ ' │ ├─3 WhiteSpaceNode " " (1:12-1:13, 11-12)',
+ ' │ ├─4 WordNode[1] (1:13-1:17, 12-16)',
+ ' │ │ └─0 TextNode "text" (1:13-1:17, 12-16)',
+ ' │ └─5 PunctuationNode "." (1:17-1:18, 16-17)',
+ ' ├─1 WhiteSpaceNode " " (1:18-1:19, 17-18)',
+ ' └─2 SentenceNode[6] (1:19-1:36, 18-35)',
+ ' ├─0 WordNode[1] (1:19-1:24, 18-23)',
+ ' │ └─0 TextNode "Other" (1:19-1:24, 18-23)',
+ ' ├─1 WhiteSpaceNode " " (1:24-1:25, 23-24)',
+ ' ├─2 PunctuationNode "“" (1:25-1:26, 24-25)',
+ ' ├─3 WordNode[1] (1:26-1:34, 25-33)',
+ ' │ └─0 TextNode "sentence" (1:26-1:34, 25-33)',
+ ' ├─4 PunctuationNode "”" (1:34-1:35, 33-34)',
+ ' └─5 PunctuationNode "." (1:35-1:36, 34-35)'
+ ].join('\n')
+ )
+ })
- 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'
- )
+ await t.test('should work with a list of nodes', async function () {
+ assert.equal(
+ strip(
+ inspect([u('SymbolNode', '$'), u('WordNode', [u('text', '5,00')])])
+ ),
+ '├─0 SymbolNode "$"\n└─1 WordNode[1]\n └─0 text "5,00"'
+ )
+ })
- 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')
+ await t.test('should work on non-nodes', async function () {
+ assert.doesNotThrow(function () {
+ 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')
+ })
+ })
- assert.equal(
- strip(
- inspect(
- Array.from({length: 11}).map((/** @type {undefined} */ d, i) => ({
- type: 'text',
- value: String(i),
- data: {id: String.fromCodePoint(97 + i)}
- }))
+ await t.test('should align and indent large numbers', async function () {
+ assert.equal(
+ strip(
+ inspect(
+ Array.from({length: 11}).map(function (
+ /** @type {undefined} */ d,
+ i
+ ) {
+ return {
+ type: 'text',
+ value: String(i),
+ data: {id: String.fromCodePoint(97 + i)}
+ }
+ })
+ )
+ ),
+ [
+ '├─0 text "0"',
+ '│ data: {"id":"a"}',
+ '├─1 text "1"',
+ '│ data: {"id":"b"}',
+ '├─2 text "2"',
+ '│ data: {"id":"c"}',
+ '├─3 text "3"',
+ '│ data: {"id":"d"}',
+ '├─4 text "4"',
+ '│ data: {"id":"e"}',
+ '├─5 text "5"',
+ '│ data: {"id":"f"}',
+ '├─6 text "6"',
+ '│ data: {"id":"g"}',
+ '├─7 text "7"',
+ '│ data: {"id":"h"}',
+ '├─8 text "8"',
+ '│ data: {"id":"i"}',
+ '├─9 text "9"',
+ '│ data: {"id":"j"}',
+ '└─10 text "10"',
+ ' data: {"id":"k"}'
+ ].join('\n')
+ )
+ })
+
+ await t.test('should work with data attributes', async function () {
+ assert.equal(
+ strip(
+ inspect({
+ type: 'SymbolNode',
+ value: '$',
+ data: {test: true}
+ })
+ ),
+ 'SymbolNode "$"\n data: {"test":true}'
+ )
+ })
+
+ await t.test('should work with other attributes', async function () {
+ assert.equal(
+ strip(
+ inspect({
+ type: 'table',
+ align: ['left', 'center'],
+ children: [
+ {
+ type: 'tableRow',
+ children: [
+ {
+ type: 'tableCell',
+ children: [{type: 'text', value: 'foo'}]
+ },
+ {
+ type: 'tableCell',
+ children: [{type: 'text', value: 'bar'}]
+ }
+ ]
+ },
+ {
+ type: 'tableRow',
+ children: [
+ {
+ type: 'tableCell',
+ children: [{type: 'text', value: 'baz'}]
+ },
+ {
+ type: 'tableCell',
+ children: [{type: 'text', value: 'qux'}]
+ }
+ ]
+ }
+ ]
+ })
+ ),
+ [
+ 'table[2]',
+ '│ align: ["left","center"]',
+ '├─0 tableRow[2]',
+ '│ ├─0 tableCell[1]',
+ '│ │ └─0 text "foo"',
+ '│ └─1 tableCell[1]',
+ '│ └─0 text "bar"',
+ '└─1 tableRow[2]',
+ ' ├─0 tableCell[1]',
+ ' │ └─0 text "baz"',
+ ' └─1 tableCell[1]',
+ ' └─0 text "qux"'
+ ].join('\n')
+ )
+ })
+
+ await t.test(
+ 'should work on parent nodes without children',
+ async function () {
+ assert.equal(
+ strip(
+ inspect({
+ type: 'element',
+ tagName: 'br',
+ children: []
+ })
+ ),
+ 'element
[0]'
)
- ),
- [
- '├─0 text "0"',
- '│ data: {"id":"a"}',
- '├─1 text "1"',
- '│ data: {"id":"b"}',
- '├─2 text "2"',
- '│ data: {"id":"c"}',
- '├─3 text "3"',
- '│ data: {"id":"d"}',
- '├─4 text "4"',
- '│ data: {"id":"e"}',
- '├─5 text "5"',
- '│ data: {"id":"f"}',
- '├─6 text "6"',
- '│ data: {"id":"g"}',
- '├─7 text "7"',
- '│ data: {"id":"h"}',
- '├─8 text "8"',
- '│ data: {"id":"i"}',
- '├─9 text "9"',
- '│ data: {"id":"j"}',
- '└─10 text "10"',
- ' data: {"id":"k"}'
- ].join('\n'),
- 'should align and indent large numbers'
+ }
)
- assert.equal(
- strip(
- inspect({
- type: 'SymbolNode',
- value: '$',
- data: {test: true}
- })
- ),
- 'SymbolNode "$"\n data: {"test":true}',
- 'should work with data attributes'
- )
+ await t.test('should work on text nodes without value', async function () {
+ assert.equal(strip(inspect({type: 'text', value: ''})), 'text ""')
+ })
- assert.equal(
- strip(
- inspect({
- type: 'table',
- align: ['left', 'center'],
- children: [
- {
- type: 'tableRow',
- children: [
- {
- type: 'tableCell',
- children: [{type: 'text', value: 'foo'}]
- },
- {
- type: 'tableCell',
- children: [{type: 'text', value: 'bar'}]
- }
- ]
- },
- {
- type: 'tableRow',
- children: [
- {
- type: 'tableCell',
- children: [{type: 'text', value: 'baz'}]
- },
- {
- type: 'tableCell',
- children: [{type: 'text', value: 'qux'}]
- }
- ]
- }
- ]
- })
- ),
- [
- 'table[2]',
- '│ align: ["left","center"]',
- '├─0 tableRow[2]',
- '│ ├─0 tableCell[1]',
- '│ │ └─0 text "foo"',
- '│ └─1 tableCell[1]',
- '│ └─0 text "bar"',
- '└─1 tableRow[2]',
- ' ├─0 tableCell[1]',
- ' │ └─0 text "baz"',
- ' └─1 tableCell[1]',
- ' └─0 text "qux"'
- ].join('\n'),
- 'should work with other attributes'
- )
+ await t.test('should work on void nodes', async function () {
+ assert.equal(strip(inspect({type: 'thematicBreak'})), 'thematicBreak')
+ })
- assert.equal(
- strip(
- inspect({
- type: 'element',
- tagName: 'br',
- children: []
- })
- ),
- 'element
[0]',
- 'should work on parent nodes without children'
- )
+ await t.test('should see properties as data', async function (t) {
+ await t.test('should work', async function () {
+ assert.equal(
+ strip(inspect(h('button', {type: 'submit', value: 'Send'}))),
+ [
+ 'element