Socket
Socket
Sign inDemoInstall

rehype-minify-whitespace

Package Overview
Dependencies
Maintainers
2
Versions
19
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

rehype-minify-whitespace - npm Package Compare versions

Comparing version 5.0.1 to 6.0.0

lib/block.d.ts

43

index.d.ts

@@ -1,41 +0,2 @@

/**
* Minify whitespace.
*
* @type {import('unified').Plugin<[Options?]|Array<void>, Root>}
*/
export default function rehypeMinifyWhitespace(
options?: void | Options | undefined
):
| void
| import('unified').Transformer<import('hast').Root, import('hast').Root>
export type Root = import('hast').Root
export type Element = import('hast').Element
export type Text = import('hast').Text
export type Node = Root | Root['children'][number]
export type Options = {
/**
* If `newlines: true`, collapses whitespace containing newlines to `'\n'`
* instead of `' '`.
* The default is to collapse to a single space.
*/
newlines?: boolean | undefined
}
export type Whitespace = 'pre' | 'nowrap' | 'pre-wrap' | 'normal'
export type Context = {
collapse: ReturnType<typeof collapseFactory>
whitespace: Whitespace
before?: boolean | undefined
after?: boolean | undefined
}
export type Result = {
remove: boolean
ignore: boolean
stripAtStart: boolean
}
/**
* @param {(value: string) => string} replace
*/
declare function collapseFactory(
replace: (value: string) => string
): (value: string) => string
export {}
export { default } from "./lib/index.js";
export type Options = import('./lib/index.js').Options;

@@ -18,337 +18,31 @@ /**

*
* ##### `options`
* ###### Parameters
*
* Configuration (optional).
* * `options` (`Options`, optional)
* — configuration
*
* ##### `options.newlines`
* ###### Returns
*
* Whether to collapse runs of whitespace that include line endings to one
* line ending (`boolean`, default: `false`).
* The default is to collapse everything to one space.
* Transform ([`Transformer`](https://github.com/unifiedjs/unified#transformer)).
*
* @example
* <h1>Heading</h1>
* <p><strong>This</strong> and <em>that</em></p>
*/
/**
* @typedef {import('hast').Root} Root
* @typedef {import('hast').Element} Element
* @typedef {import('hast').Text} Text
* @typedef {Root|Root['children'][number]} Node
* ### `Options`
*
* @typedef Options
* @property {boolean} [newlines=false]
* If `newlines: true`, collapses whitespace containing newlines to `'\n'`
* instead of `' '`.
* The default is to collapse to a single space.
* Configuration (TypeScript).
*
* @typedef {'pre'|'nowrap'|'pre-wrap'|'normal'} Whitespace
* ###### Fields
*
* @typedef Context
* @property {ReturnType<collapseFactory>} collapse
* @property {Whitespace} whitespace
* @property {boolean} [before]
* @property {boolean} [after]
* * `newlines` (`boolean`, default: `false`)
* — collapse whitespace containing newlines to `'\n'` instead of `' '`;
* the default is to collapse to a single space
*
* @typedef Result
* @property {boolean} remove
* @property {boolean} ignore
* @property {boolean} stripAtStart
* @example
* {}
* <h1>Heading</h1>
* <p><strong>This</strong> and <em>that</em></p>
*/
import {isElement} from 'hast-util-is-element'
import {embedded} from 'hast-util-embedded'
import {convert} from 'unist-util-is'
import {whitespace} from 'hast-util-whitespace'
import {blocks} from './block.js'
import {content as contents} from './content.js'
import {skippable as skippables} from './skippable.js'
const ignorableNode = convert(['doctype', 'comment'])
/**
* Minify whitespace.
*
* @type {import('unified').Plugin<[Options?]|Array<void>, Root>}
* @typedef {import('./lib/index.js').Options} Options
*/
export default function rehypeMinifyWhitespace(options = {}) {
const collapse = collapseFactory(
options.newlines ? replaceNewlines : replaceWhitespace
)
return (tree) => {
minify(tree, {collapse, whitespace: 'normal'})
}
}
/**
* @param {Node} node
* @param {Context} context
* @returns {Result}
*/
function minify(node, context) {
if ('children' in node) {
const settings = Object.assign({}, context)
if (node.type === 'root' || blocklike(node)) {
settings.before = true
settings.after = true
}
settings.whitespace = inferWhiteSpace(node, context)
return all(node, settings)
}
if (node.type === 'text') {
if (context.whitespace === 'normal') {
return minifyText(node, context)
}
// Naïve collapse, but no trimming:
if (context.whitespace === 'nowrap') {
node.value = context.collapse(node.value)
}
// The `pre-wrap` or `pre` whitespace settings are neither collapsed nor
// trimmed.
}
return {remove: false, ignore: ignorableNode(node), stripAtStart: false}
}
/**
* @param {Text} node
* @param {Context} context
* @returns {Result}
*/
function minifyText(node, context) {
const value = context.collapse(node.value)
const result = {remove: false, ignore: false, stripAtStart: false}
let start = 0
let end = value.length
if (context.before && removable(value.charAt(0))) {
start++
}
if (start !== end && removable(value.charAt(end - 1))) {
if (context.after) {
end--
} else {
result.stripAtStart = true
}
}
if (start === end) {
result.remove = true
} else {
node.value = value.slice(start, end)
}
return result
}
/**
* @param {Root|Element} parent
* @param {Context} context
* @returns {Result}
*/
function all(parent, context) {
let before = context.before
const after = context.after
const children = parent.children
let length = children.length
let index = -1
while (++index < length) {
const result = minify(
children[index],
Object.assign({}, context, {
before,
after: collapsableAfter(children, index, after)
})
)
if (result.remove) {
children.splice(index, 1)
index--
length--
} else if (!result.ignore) {
before = result.stripAtStart
}
// If this element, such as a `<select>` or `<img>`, contributes content
// somehow, allow whitespace again.
if (content(children[index])) {
before = false
}
}
return {remove: false, ignore: false, stripAtStart: Boolean(before || after)}
}
/**
* @param {Array<Node>} nodes
* @param {number} index
* @param {boolean|undefined} [after]
* @returns {boolean|undefined}
*/
function collapsableAfter(nodes, index, after) {
while (++index < nodes.length) {
const node = nodes[index]
let result = inferBoundary(node)
if (result === undefined && 'children' in node && !skippable(node)) {
result = collapsableAfter(node.children, -1)
}
if (typeof result === 'boolean') {
return result
}
}
return after
}
/**
* Infer two types of boundaries:
*
* 1. `true` — boundary for which whitespace around it does not contribute
* anything
* 2. `false` — boundary for which whitespace around it *does* contribute
*
* No result (`undefined`) is returned if it is unknown.
*
* @param {Node} node
* @returns {boolean|undefined}
*/
function inferBoundary(node) {
if (node.type === 'element') {
if (content(node)) {
return false
}
if (blocklike(node)) {
return true
}
// Unknown: either depends on siblings if embedded or metadata, or on
// children.
} else if (node.type === 'text') {
if (!whitespace(node)) {
return false
}
} else if (!ignorableNode(node)) {
return false
}
}
/**
* Infer whether a node is skippable.
*
* @param {Node} node
* @returns {boolean}
*/
function content(node) {
return embedded(node) || isElement(node, contents)
}
/**
* See: <https://html.spec.whatwg.org/#the-css-user-agent-style-sheet-and-presentational-hints>
*
* @param {Element} node
* @returns {boolean}
*/
function blocklike(node) {
return isElement(node, blocks)
}
/**
* @param {Element|Root} node
* @returns {boolean}
*/
function skippable(node) {
return (
Boolean(
'properties' in node && node.properties && node.properties.hidden
) ||
ignorableNode(node) ||
isElement(node, skippables)
)
}
/**
* @param {string} character
* @returns {boolean}
*/
function removable(character) {
return character === ' ' || character === '\n'
}
/**
* @param {string} value
* @returns {string}
*/
function replaceNewlines(value) {
const match = /\r?\n|\r/.exec(value)
return match ? match[0] : ' '
}
/**
* @returns {string}
*/
function replaceWhitespace() {
return ' '
}
/**
* @param {(value: string) => string} replace
*/
function collapseFactory(replace) {
return collapse
/**
* @param {string} value
* @returns {string}
*/
function collapse(value) {
return String(value).replace(/[\t\n\v\f\r ]+/g, replace)
}
}
/**
* We don’t need to support void elements here (so `nobr wbr` -> `normal` is
* ignored).
*
* @param {Root|Element} node
* @param {Context} context
* @returns {Whitespace}
*/
function inferWhiteSpace(node, context) {
if ('tagName' in node && node.properties) {
switch (node.tagName) {
// Whitespace in script/style, while not displayed by CSS as significant,
// could have some meaning in JS/CSS, so we can’t touch them.
case 'listing':
case 'plaintext':
case 'script':
case 'style':
case 'xmp':
return 'pre'
case 'nobr':
return 'nowrap'
case 'pre':
return node.properties.wrap ? 'pre-wrap' : 'pre'
case 'td':
case 'th':
return node.properties.noWrap ? 'nowrap' : context.whitespace
case 'textarea':
return 'pre-wrap'
default:
}
}
return context.whitespace
}
export {default} from './lib/index.js'
{
"name": "rehype-minify-whitespace",
"version": "5.0.1",
"version": "6.0.0",
"description": "rehype plugin to collapse whitespace",
"license": "MIT",
"keywords": [
"unified",
"collapse",
"html",
"mangle",
"minify",
"plugin",
"rehype",
"rehype-plugin",
"plugin",
"html",
"minify",
"mangle",
"collapse",
"whitespace",
"space",
"unified",
"white",
"space"
"whitespace"
],

@@ -31,33 +31,23 @@ "repository": "https://github.com/rehypejs/rehype-minify/tree/main/packages/rehype-minify-whitespace",

"type": "module",
"main": "index.js",
"types": "index.d.ts",
"exports": "./index.js",
"files": [
"block.d.ts",
"block.js",
"content.d.ts",
"content.js",
"index.d.ts",
"index.js",
"skippable.d.ts",
"skippable.js"
"lib/"
],
"dependencies": {
"@types/hast": "^2.0.0",
"hast-util-embedded": "^2.0.0",
"hast-util-is-element": "^2.0.0",
"hast-util-whitespace": "^2.0.0",
"unified": "^10.0.0",
"unist-util-is": "^5.0.0"
"@types/hast": "^3.0.0",
"hast-util-embedded": "^3.0.0",
"hast-util-is-element": "^3.0.0",
"hast-util-whitespace": "^3.0.0",
"unist-util-is": "^6.0.0"
},
"scripts": {
"build": "rimraf \"*.d.ts\" && tsc && type-coverage",
"test": "node --conditions development test.js"
},
"xo": false,
"scripts": {},
"typeCoverage": {
"atLeast": 100,
"detail": true,
"strict": true,
"ignoreCatch": true
}
"ignoreCatch": true,
"strict": true
},
"xo": false
}

@@ -9,4 +9,4 @@ <!--This file is generated-->

[![Size][size-badge]][size]
[![Sponsors][sponsors-badge]][collective]
[![Backers][backers-badge]][collective]
[![Sponsors][funding-sponsors-badge]][funding]
[![Backers][funding-backers-badge]][funding]
[![Chat][chat-badge]][chat]

@@ -24,2 +24,3 @@

* [`unified().use(rehypeMinifyWhitespace[, options])`](#unifieduserehypeminifywhitespace-options)
* [`Options`](#options)
* [Example](#example)

@@ -45,3 +46,3 @@ * [Syntax](#syntax)

This package is [ESM only][esm].
In Node.js (version 12.20+, 14.14+, or 16.0+), install with [npm][]:
In Node.js (version 16+), install with [npm][]:

@@ -52,13 +53,13 @@ ```sh

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

@@ -72,19 +73,15 @@ ```

```js
import rehypeMinifyWhitespace from 'rehype-minify-whitespace'
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 rehypeStringify from 'rehype-stringify'
import rehypeMinifyWhitespace from 'rehype-minify-whitespace'
main()
const file = await unified()
.use(rehypeParse)
.use(rehypeMinifyWhitespace)
.use(rehypeStringify)
.process(await read('index.html'))
async function main() {
const file = await unified()
.use(rehypeParse)
.use(rehypeMinifyWhitespace)
.use(rehypeStringify)
.process(await read('index.html'))
console.log(String(file))
}
console.log(String(file))
```

@@ -121,12 +118,21 @@

##### `options`
###### Parameters
Configuration (optional).
* `options` (`Options`, optional)
— configuration
##### `options.newlines`
###### Returns
Whether to collapse runs of whitespace that include line endings to one
line ending (`boolean`, default: `false`).
The default is to collapse everything to one space.
Transform ([`Transformer`](https://github.com/unifiedjs/unified#transformer)).
### `Options`
Configuration (TypeScript).
###### Fields
* `newlines` (`boolean`, default: `false`)
— collapse whitespace containing newlines to `'\n'` instead of `' '`;
the default is to collapse to a single space
## Example

@@ -149,8 +155,8 @@

HTML is handled according to WHATWG HTML (the living standard), which is also
followed by browsers such as Chrome and Firefox.
HTML is parsed according to WHATWG HTML (the living standard), which is also
followed by all browsers.
## Syntax tree
The syntax tree format used is [`hast`][hast].
The syntax tree used is [hast][].

@@ -163,10 +169,14 @@ ## Types

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-minify-whitespace@^6`,
compatible with Node.js 16.
## Security
As **rehype** works on HTML, and improper use of HTML can open you up to a
As **rehype** works on HTML and improper use of HTML can open you up to a
[cross-site scripting (XSS)][xss] attack, use of rehype can also be unsafe.

@@ -189,54 +199,54 @@ Use [`rehype-sanitize`][rehype-sanitize] to make the tree safe.

[build-badge]: https://github.com/rehypejs/rehype-minify/workflows/main/badge.svg
[author]: https://wooorm.com
[build]: https://github.com/rehypejs/rehype-minify/actions
[coverage-badge]: https://img.shields.io/codecov/c/github/rehypejs/rehype-minify.svg
[build-badge]: https://github.com/rehypejs/rehype-minify/workflows/main/badge.svg
[chat]: https://github.com/rehypejs/rehype/discussions
[chat-badge]: https://img.shields.io/badge/chat-discussions-success.svg
[coc]: https://github.com/rehypejs/.github/blob/main/code-of-conduct.md
[contributing]: https://github.com/rehypejs/.github/blob/main/contributing.md
[coverage]: https://codecov.io/github/rehypejs/rehype-minify
[downloads-badge]: https://img.shields.io/npm/dm/rehype-minify-whitespace.svg
[coverage-badge]: https://img.shields.io/codecov/c/github/rehypejs/rehype-minify.svg
[downloads]: https://www.npmjs.com/package/rehype-minify-whitespace
[size-badge]: https://img.shields.io/bundlephobia/minzip/rehype-minify-whitespace.svg
[downloads-badge]: https://img.shields.io/npm/dm/rehype-minify-whitespace.svg
[size]: https://bundlephobia.com/result?p=rehype-minify-whitespace
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
[sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg
[esm-sh]: https://esm.sh
[backers-badge]: https://opencollective.com/unified/backers/badge.svg
[funding]: https://opencollective.com/unified
[collective]: https://opencollective.com/unified
[funding-backers-badge]: https://opencollective.com/unified/backers/badge.svg
[chat-badge]: https://img.shields.io/badge/chat-discussions-success.svg
[funding-sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg
[chat]: https://github.com/rehypejs/rehype/discussions
[hast]: https://github.com/syntax-tree/hast
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
[health]: https://github.com/rehypejs/.github
[license]: https://github.com/rehypejs/rehype-minify/blob/main/license
[npm]: https://docs.npmjs.com/cli/install
[skypack]: https://www.skypack.dev
[rehype]: https://github.com/rehypejs/rehype
[typescript]: https://www.typescriptlang.org
[rehype-sanitize]: https://github.com/rehypejs/rehype-sanitize
[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting
[size]: https://bundlejs.com/?q=rehype-minify-whitespace
[health]: https://github.com/rehypejs/.github
[size-badge]: https://img.shields.io/bundlejs/size/rehype-minify-whitespace
[contributing]: https://github.com/rehypejs/.github/blob/main/contributing.md
[support]: https://github.com/rehypejs/.github/blob/main/support.md
[coc]: https://github.com/rehypejs/.github/blob/main/code-of-conduct.md
[typescript]: https://www.typescriptlang.org
[license]: https://github.com/rehypejs/rehype-minify/blob/main/license
[author]: https://wooorm.com
[hast]: https://github.com/syntax-tree/hast
[rehype]: https://github.com/rehypejs/rehype
[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting
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