Socket
Socket
Sign inDemoInstall

rehype-format

Package Overview
Dependencies
Maintainers
2
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

rehype-format - npm Package Compare versions

Comparing version 4.0.1 to 5.0.0

lib/index.d.ts

40

index.d.ts

@@ -1,38 +0,2 @@

/**
* Format whitespace in HTML.
*
* @type {import('unified').Plugin<[Options?] | Array<void>, Root>}
*/
export default function rehypeFormat(
options?: void | Options | undefined
):
| void
| import('unified').Transformer<import('hast').Root, import('hast').Root>
export type Root = import('hast').Root
export type Child = Root['children'][number]
export type Element = import('hast').Element
export type Node = Root | Child
/**
* Configuration.
*/
export type Options = {
/**
* Indentation per level (`number`, `string`, default: `2`).
* When number, uses that amount of spaces.
* When `string`, uses that per indentation level.
*/
indent?: string | number | undefined
/**
* Whether to indent the first level (`boolean`, default: `true`).
* This is usually the `<html>`, thus not indenting `head` and `body`.
*/
indentInitial?: boolean | undefined
/**
* List of tag names to join with a blank line (`Array<string>`, default:
* `[]`).
* These tags, when next to each other, are joined by a blank line (`\n\n`).
* For example, when `['head', 'body']` is given, a blank line is added
* between these two.
*/
blanks?: string[] | undefined
}
export { default } from "./lib/index.js";
export type Options = import('./lib/index.js').Options;
/**
* @typedef {import('hast').Root} Root
* @typedef {Root['children'][number]} Child
* @typedef {import('hast').Element} Element
* @typedef {Root|Child} Node
*
* @typedef Options
* Configuration.
* @property {number|string} [indent=2]
* Indentation per level (`number`, `string`, default: `2`).
* When number, uses that amount of spaces.
* When `string`, uses that per indentation level.
* @property {boolean} [indentInitial=true]
* Whether to indent the first level (`boolean`, default: `true`).
* This is usually the `<html>`, thus not indenting `head` and `body`.
* @property {Array<string>} [blanks=[]]
* List of tag names to join with a blank line (`Array<string>`, default:
* `[]`).
* These tags, when next to each other, are joined by a blank line (`\n\n`).
* For example, when `['head', 'body']` is given, a blank line is added
* between these two.
* @typedef {import('./lib/index.js').Options} Options
*/
import rehypeMinifyWhitespace from 'rehype-minify-whitespace'
import {visitParents, SKIP} from 'unist-util-visit-parents'
import {embedded} from 'hast-util-embedded'
import {phrasing} from 'hast-util-phrasing'
import {whitespace} from 'hast-util-whitespace'
import {isElement} from 'hast-util-is-element'
import {whitespaceSensitiveTagNames} from 'html-whitespace-sensitive-tag-names'
const minify = rehypeMinifyWhitespace({newlines: true})
/**
* Format whitespace in HTML.
*
* @type {import('unified').Plugin<[Options?] | Array<void>, Root>}
*/
export default function rehypeFormat(options = {}) {
let indent = options.indent || 2
let indentInitial = options.indentInitial
if (typeof indent === 'number') {
indent = ' '.repeat(indent)
}
// Default to indenting the initial level.
if (indentInitial === null || indentInitial === undefined) {
indentInitial = true
}
return (tree) => {
/** @type {boolean|undefined} */
let head
// @ts-expect-error: fine, it’s a sync transformer.
minify(tree)
// eslint-disable-next-line complexity
visitParents(tree, (node, parents) => {
let index = -1
if (!('children' in node)) {
return
}
if (isElement(node, 'head')) {
head = true
}
if (head && isElement(node, 'body')) {
head = undefined
}
if (isElement(node, whitespaceSensitiveTagNames)) {
return SKIP
}
const children = node.children
let level = parents.length
// Don’t indent content of whitespace-sensitive nodes / inlines.
if (children.length === 0 || !padding(node, head)) {
return
}
if (!indentInitial) {
level--
}
/** @type {boolean|undefined} */
let eol
// Indent newlines in `text`.
while (++index < children.length) {
const child = children[index]
if (child.type === 'text' || child.type === 'comment') {
if (child.value.includes('\n')) {
eol = true
}
child.value = child.value.replace(
/ *\n/g,
'$&' + String(indent).repeat(level)
)
}
}
/** @type {Array<Child>} */
const result = []
/** @type {Child|undefined} */
let previous
index = -1
while (++index < children.length) {
const child = children[index]
if (padding(child, head) || (eol && !index)) {
addBreak(result, level, child)
eol = true
}
previous = child
result.push(child)
}
if (previous && (eol || padding(previous, head))) {
// Ignore trailing whitespace (if that already existed), as we’ll add
// properly indented whitespace.
if (whitespace(previous)) {
result.pop()
previous = result[result.length - 1]
}
addBreak(result, level - 1)
}
node.children = result
})
}
/**
* @param {Array<Child>} list
* @param {number} level
* @param {Child} [next]
* @returns {void}
*/
function addBreak(list, level, next) {
const tail = list[list.length - 1]
const previous = whitespace(tail) ? list[list.length - 2] : tail
const replace =
(blank(previous) && blank(next) ? '\n\n' : '\n') +
String(indent).repeat(Math.max(level, 0))
if (tail && tail.type === 'text') {
tail.value = whitespace(tail) ? replace : tail.value + replace
} else {
list.push({type: 'text', value: replace})
}
}
/**
* @param {Node|undefined} node
* @returns {boolean}
*/
function blank(node) {
return Boolean(
node &&
node.type === 'element' &&
options.blanks &&
options.blanks.length > 0 &&
options.blanks.includes(node.tagName)
)
}
}
/**
* @param {Node} node
* @param {boolean|undefined} head
* @returns {boolean}
*/
function padding(node, head) {
return (
node.type === 'root' ||
(node.type === 'element'
? head || isElement(node, 'script') || embedded(node) || !phrasing(node)
: false)
)
}
export {default} from './lib/index.js'
{
"name": "rehype-format",
"version": "4.0.1",
"version": "5.0.0",
"description": "rehype plugin to format HTML",

@@ -29,5 +29,5 @@ "license": "MIT",

"type": "module",
"main": "index.js",
"types": "index.d.ts",
"exports": "./index.js",
"files": [
"lib/",
"index.d.ts",

@@ -37,48 +37,43 @@ "index.js"

"dependencies": {
"@types/hast": "^2.0.0",
"hast-util-embedded": "^2.0.0",
"hast-util-is-element": "^2.0.0",
"hast-util-phrasing": "^2.0.0",
"hast-util-whitespace": "^2.0.0",
"html-whitespace-sensitive-tag-names": "^2.0.0",
"rehype-minify-whitespace": "^5.0.0",
"unified": "^10.0.0",
"unist-util-visit-parents": "^5.0.0"
"@types/hast": "^3.0.0",
"hast-util-embedded": "^3.0.0",
"hast-util-is-element": "^3.0.0",
"hast-util-phrasing": "^3.0.0",
"hast-util-whitespace": "^3.0.0",
"html-whitespace-sensitive-tag-names": "^3.0.0",
"rehype-minify-whitespace": "^6.0.0",
"unist-util-visit-parents": "^6.0.0"
},
"devDependencies": {
"@types/tape": "^4.0.0",
"c8": "^7.0.0",
"@types/node": "^20.0.0",
"c8": "^8.0.0",
"is-hidden": "^2.0.0",
"prettier": "^2.0.0",
"rehype": "^12.0.0",
"remark-cli": "^10.0.0",
"prettier": "^3.0.0",
"rehype": "^13.0.0",
"remark-cli": "^11.0.0",
"remark-preset-wooorm": "^9.0.0",
"rimraf": "^3.0.0",
"tape": "^5.0.0",
"to-vfile": "^7.0.0",
"to-vfile": "^8.0.0",
"type-coverage": "^2.0.0",
"typescript": "^4.0.0",
"xo": "^0.47.0"
"typescript": "^5.0.0",
"xo": "^0.56.0"
},
"scripts": {
"build": "rimraf \"*.d.ts\" \"test/**/*.d.ts\" && tsc && type-coverage",
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix",
"build": "tsc --build --clean && tsc --build && type-coverage",
"format": "remark . --frail --output --quiet && prettier . --log-level warn --write && xo --fix",
"prepack": "npm run build && npm run format",
"test": "npm run build && npm run format && npm run test-coverage",
"test-api": "node --conditions development test/index.js",
"test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov node --conditions development test/index.js",
"test": "npm run build && npm run format && npm run test-coverage"
"test-coverage": "c8 --100 --check-coverage --reporter lcov npm run test-api"
},
"prettier": {
"tabWidth": 2,
"useTabs": false,
"bracketSpacing": false,
"singleQuote": true,
"bracketSpacing": false,
"semi": false,
"trailingComma": "none"
"tabWidth": 2,
"trailingComma": "none",
"useTabs": false
},
"xo": {
"prettier": true
},
"remarkConfig": {
"plugins": [
"preset-wooorm"
"remark-preset-wooorm"
]

@@ -89,5 +84,12 @@ },

"detail": true,
"strict": true,
"ignoreCatch": true
"ignoreCatch": true,
"strict": true
},
"xo": {
"prettier": true,
"rules": {
"unicorn/prefer-at": "off",
"unicorn/prefer-string-replace-all": "off"
}
}
}

@@ -21,2 +21,3 @@ # rehype-format

* [`unified().use(rehypeFormat[, options])`](#unifieduserehypeformat-options)
* [`Options`](#options)
* [Examples](#examples)

@@ -61,4 +62,4 @@ * [Example: markdown input (remark)](#example-markdown-input-remark)

This package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c).
In Node.js (version 12.20+, 14.14+, or 16.0+), install with [npm][]:
This package is [ESM only][esm].
In Node.js (version 16+), install with [npm][]:

@@ -69,13 +70,13 @@ ```sh

In Deno with [Skypack][]:
In Deno with [`esm.sh`][esmsh]:
```js
import rehypeFormat from 'https://cdn.skypack.dev/rehype-format@4?dts'
import rehypeFormat from 'https://esm.sh/rehype-format@5'
```
In browsers with [Skypack][]:
In browsers with [`esm.sh`][esmsh]:
```html
<script type="module">
import rehypeFormat from 'https://cdn.skypack.dev/rehype-format@4?min'
import rehypeFormat from 'https://esm.sh/rehype-format@5?bundle'
</script>

@@ -100,25 +101,21 @@ ```

And our module `example.js` looks as follows:
…and our module `example.js` looks as follows:
```js
import rehypeFormat from 'rehype-format'
import rehypeParse from 'rehype-parse'
import rehypeStringify from 'rehype-stringify'
import {read} from 'to-vfile'
import {unified} from 'unified'
import rehypeParse from 'rehype-parse'
import rehypeFormat from 'rehype-format'
import rehypeStringify from 'rehype-stringify'
main()
const file = await unified()
.use(rehypeParse)
.use(rehypeFormat)
.use(rehypeStringify)
.process(await read('index.html'))
async function main() {
const file = await unified()
.use(rehypeParse)
.use(rehypeFormat)
.use(rehypeStringify)
.process(await read('index.html'))
console.log(String(file))
}
console.log(String(file))
```
Now running `node example.js` yields:
…then running `node example.js` yields:

@@ -143,3 +140,3 @@ ```html

This package exports no identifiers.
The default export is `rehypeFormat`.
The default export is [`rehypeFormat`][api-rehype-format].

@@ -150,24 +147,27 @@ ### `unified().use(rehypeFormat[, options])`

##### `options`
###### Parameters
Configuration (optional).
* `options` ([`Options`][api-options], optional)
— configuration
###### `options.indent`
###### Returns
Indentation per level (`number`, `string`, default: `2`).
When `number`, uses that amount of spaces.
When `string`, uses that per indentation level.
Transform ([`Transformer`][transformer]).
###### `options.indentInitial`
### `Options`
Whether to indent the first level (`boolean`, default: `true`).
The initial element is usually the `<html>` element, so when this is set to
`false`, its children `<head>` and `<body>` would not be indented.
Configuration (TypeScript type).
###### `options.blanks`
###### Fields
List of tag names to join with a blank line (`Array<string>`, default: `[]`).
These tags, when next to each other, are joined by a blank line (`\n\n`).
For example, when `['head', 'body']` is given, a blank line is added between
these two.
* `blanks` (`Array<string>`, default: `[]`)
— list of tag names to join with a blank line (default: `[]`); these tags,
when next to each other, are joined by a blank line (`\n\n`); for example,
when `['head', 'body']` is given, a blank line is added between these two
* `indent` (`number`, `string`, default: `2`)
— indentation per level (default: `2`); when number, uses that amount of
spaces; when `string`, uses that per indentation level
* `indentInitial` (`boolean`, default: `true`)
— whether to indent the first level (default: `true`); this is usually the
`<html>`, thus not indenting `head` and `body`

@@ -182,22 +182,18 @@ ## Examples

```js
import {unified} from 'unified'
import remarkParse from 'remark-parse'
import remarkRehype from 'remark-rehype'
import rehypeDocument from 'rehype-document'
import rehypeFormat from 'rehype-format'
import rehypeStringify from 'rehype-stringify'
import remarkParse from 'remark-parse'
import remarkRehype from 'remark-rehype'
import {unified} from 'unified'
main()
const file = await unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeDocument, {title: 'Neptune'})
.use(rehypeFormat)
.use(rehypeStringify)
.process('# Hello, Neptune!')
async function main() {
const file = await unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeDocument, {title: 'Neptune'})
.use(rehypeFormat)
.use(rehypeStringify)
.process('# Hello, Neptune!')
console.log(String(file))
}
console.log(String(file))
```

@@ -228,18 +224,14 @@

```js
import {unified} from 'unified'
import rehypeFormat from 'rehype-format'
import rehypeParse from 'rehype-parse'
import rehypeFormat from 'rehype-format'
import rehypeStringify from 'rehype-stringify'
import {unified} from 'unified'
main()
const file = await unified()
.use(rehypeParse)
.use(rehypeFormat, {blanks: ['head', 'body'], indent: '\t'})
.use(rehypeStringify)
.process('<h1>Hi!</h1><p>Hello, Venus!</p>')
async function main() {
const file = await unified()
.use(rehypeParse)
.use(rehypeFormat, {indent: '\t', blanks: ['head', 'body']})
.use(rehypeStringify)
.process('<h1>Hi!</h1><p>Hello, Venus!</p>')
console.log(String(file))
}
console.log(String(file))
```

@@ -270,12 +262,14 @@

This package is fully typed with [TypeScript][].
It exports an `Options` type, which specifies the interface of the accepted
options.
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 12.20+, 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, `rehype-format@^5`,
compatible with Node.js 16.
This plugin works with `rehype-parse` version 3+, `rehype-stringify` version 3+,

@@ -333,5 +327,5 @@ `rehype` version 5+, and `unified` version 6+.

[size-badge]: https://img.shields.io/bundlephobia/minzip/rehype-format.svg
[size-badge]: https://img.shields.io/bundlejs/size/rehype-format
[size]: https://bundlephobia.com/result?p=rehype-format
[size]: https://bundlejs.com/?q=rehype-format

@@ -348,4 +342,6 @@ [sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg

[skypack]: https://www.skypack.dev
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
[esmsh]: https://esm.sh
[npm]: https://docs.npmjs.com/cli/install

@@ -355,7 +351,7 @@

[contributing]: https://github.com/rehypejs/.github/blob/HEAD/contributing.md
[contributing]: https://github.com/rehypejs/.github/blob/main/contributing.md
[support]: https://github.com/rehypejs/.github/blob/HEAD/support.md
[support]: https://github.com/rehypejs/.github/blob/main/support.md
[coc]: https://github.com/rehypejs/.github/blob/HEAD/code-of-conduct.md
[coc]: https://github.com/rehypejs/.github/blob/main/code-of-conduct.md

@@ -372,2 +368,4 @@ [license]: license

[transformer]: https://github.com/unifiedjs/unified#transformer
[rehype]: https://github.com/rehypejs/rehype

@@ -380,1 +378,5 @@

[rehype-minify]: https://github.com/rehypejs/rehype-minify
[api-options]: #options
[api-rehype-format]: #unifieduserehypeformat-options
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc