Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

rehype-minify-whitespace

Package Overview
Dependencies
Maintainers
3
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 6.0.0 to 6.0.1

index.d.ts.map

3

index.d.ts
export { default } from "./lib/index.js";
export type Options = import('./lib/index.js').Options;
export type Options = import("hast-util-minify-whitespace").Options;
//# sourceMappingURL=index.d.ts.map

@@ -44,5 +44,5 @@ /**

/**
* @typedef {import('./lib/index.js').Options} Options
* @typedef {import('hast-util-minify-whitespace').Options} Options
*/
export {default} from './lib/index.js'

@@ -10,61 +10,4 @@ /**

export default function rehypeMinifyWhitespace(options?: Options | null | undefined): (tree: Root) => undefined;
export type Nodes = import('hast').Nodes;
export type Parents = import('hast').Parents;
export type Root = import('hast').Root;
export type Text = import('hast').Text;
/**
* Collapse a string.
*/
export type Collapse = (value: string) => string;
/**
* Configuration.
*/
export type Options = {
/**
* Collapse whitespace containing newlines to `'\n'` instead of `' '`
* (default: `false`); the default is to collapse to a single space.
*/
newlines?: boolean | null | undefined;
};
/**
* Result.
*/
export type Result = {
/**
* Whether to remove.
*/
remove: boolean;
/**
* Whether to ignore.
*/
ignore: boolean;
/**
* Whether to strip at the start.
*/
stripAtStart: boolean;
};
/**
* Info passed around.
*/
export type State = {
/**
* Collapse.
*/
collapse: Collapse;
/**
* Current whitespace.
*/
whitespace: Whitespace;
/**
* Whether there is a break before (default: `false`).
*/
before?: boolean | undefined;
/**
* Whether there is a break after (default: `false`).
*/
after?: boolean | undefined;
};
/**
* Whitespace setting.
*/
export type Whitespace = 'normal' | 'nowrap' | 'pre' | 'pre-wrap';
import type { Options } from 'hast-util-minify-whitespace';
import type { Root } from 'hast';
//# sourceMappingURL=index.d.ts.map
/**
* @typedef {import('hast').Nodes} Nodes
* @typedef {import('hast').Parents} Parents
* @typedef {import('hast').Root} Root
* @typedef {import('hast').Text} Text
* @import {Options} from 'hast-util-minify-whitespace'
* @import {Root} from 'hast'
*/
/**
* @callback Collapse
* Collapse a string.
* @param {string} value
* Value to collapse.
* @returns {string}
* Collapsed value.
*
* @typedef Options
* Configuration.
* @property {boolean | null | undefined} [newlines=false]
* Collapse whitespace containing newlines to `'\n'` instead of `' '`
* (default: `false`); the default is to collapse to a single space.
*
* @typedef Result
* Result.
* @property {boolean} remove
* Whether to remove.
* @property {boolean} ignore
* Whether to ignore.
* @property {boolean} stripAtStart
* Whether to strip at the start.
*
* @typedef State
* Info passed around.
* @property {Collapse} collapse
* Collapse.
* @property {Whitespace} whitespace
* Current whitespace.
* @property {boolean | undefined} [before]
* Whether there is a break before (default: `false`).
* @property {boolean | undefined} [after]
* Whether there is a break after (default: `false`).
*
* @typedef {'normal' | 'nowrap' | 'pre' | 'pre-wrap'} Whitespace
* Whitespace setting.
*/
import {minifyWhitespace} from 'hast-util-minify-whitespace'
import {embedded} from 'hast-util-embedded'
import {isElement} from 'hast-util-is-element'
import {whitespace} from 'hast-util-whitespace'
import {convert} from 'unist-util-is'
import {blocks} from './block.js'
import {content as contents} from './content.js'
import {skippable as skippables} from './skippable.js'
/** @type {Options} */
const emptyOptions = {}
const ignorableNode = convert(['doctype', 'comment'])
/**

@@ -67,7 +17,2 @@ * Minify whitespace.

export default function rehypeMinifyWhitespace(options) {
const settings = options || emptyOptions
const collapse = collapseFactory(
settings.newlines ? replaceNewlines : replaceWhitespace
)
/**

@@ -80,307 +25,4 @@ * @param {Root} tree

return function (tree) {
minify(tree, {collapse, whitespace: 'normal'})
minifyWhitespace(tree, options)
}
}
/**
* @param {Nodes} node
* Node.
* @param {State} state
* Info passed around.
* @returns {Result}
* Result.
*/
function minify(node, state) {
if ('children' in node) {
const settings = {...state}
if (node.type === 'root' || blocklike(node)) {
settings.before = true
settings.after = true
}
settings.whitespace = inferWhiteSpace(node, state)
return all(node, settings)
}
if (node.type === 'text') {
if (state.whitespace === 'normal') {
return minifyText(node, state)
}
// Naïve collapse, but no trimming:
if (state.whitespace === 'nowrap') {
node.value = state.collapse(node.value)
}
// The `pre-wrap` or `pre` whitespace settings are neither collapsed nor
// trimmed.
}
return {ignore: ignorableNode(node), stripAtStart: false, remove: false}
}
/**
* @param {Text} node
* Node.
* @param {State} state
* Info passed around.
* @returns {Result}
* Result.
*/
function minifyText(node, state) {
const value = state.collapse(node.value)
const result = {ignore: false, stripAtStart: false, remove: false}
let start = 0
let end = value.length
if (state.before && removable(value.charAt(0))) {
start++
}
if (start !== end && removable(value.charAt(end - 1))) {
if (state.after) {
end--
} else {
result.stripAtStart = true
}
}
if (start === end) {
result.remove = true
} else {
node.value = value.slice(start, end)
}
return result
}
/**
* @param {Parents} parent
* Node.
* @param {State} state
* Info passed around.
* @returns {Result}
* Result.
*/
function all(parent, state) {
let before = state.before
const after = state.after
const children = parent.children
let length = children.length
let index = -1
while (++index < length) {
const result = minify(children[index], {
...state,
after: collapsableAfter(children, index, after),
before
})
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 {ignore: false, stripAtStart: Boolean(before || after), remove: false}
}
/**
* @param {Array<Nodes>} nodes
* Nodes.
* @param {number} index
* Index.
* @param {boolean | undefined} [after]
* Whether there is a break after `nodes` (default: `false`).
* @returns {boolean | undefined}
* Whether there is a break after the node at `index`.
*/
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 {Nodes} node
* Node.
* @returns {boolean | undefined}
* Boundary.
*/
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 {Nodes} node
* Node.
* @returns {boolean}
* Whether `node` is skippable.
*/
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 {Nodes} node
* Node.
* @returns {boolean}
* Whether `node` is block-like.
*/
function blocklike(node) {
return isElement(node, blocks)
}
/**
* @param {Parents} node
* Node.
* @returns {boolean}
* Whether `node` is skippable.
*/
function skippable(node) {
return (
Boolean(node.type === 'element' && node.properties.hidden) ||
ignorableNode(node) ||
isElement(node, skippables)
)
}
/**
* @param {string} character
* Character.
* @returns {boolean}
* Whether `character` is removable.
*/
function removable(character) {
return character === ' ' || character === '\n'
}
/**
* @type {Collapse}
*/
function replaceNewlines(value) {
const match = /\r?\n|\r/.exec(value)
return match ? match[0] : ' '
}
/**
* @type {Collapse}
*/
function replaceWhitespace() {
return ' '
}
/**
* @param {Collapse} replace
* @returns {Collapse}
* Collapse.
*/
function collapseFactory(replace) {
return collapse
/**
* @type {Collapse}
*/
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 {Parents} node
* Node.
* @param {State} state
* Info passed around.
* @returns {Whitespace}
* Whitespace.
*/
function inferWhiteSpace(node, state) {
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' : state.whitespace
}
case 'textarea': {
return 'pre-wrap'
}
default:
}
}
return state.whitespace
}
{
"name": "rehype-minify-whitespace",
"version": "6.0.0",
"version": "6.0.1",
"description": "rehype plugin to collapse whitespace",

@@ -34,2 +34,3 @@ "license": "MIT",

"index.d.ts",
"index.d.ts.map",
"index.js",

@@ -40,6 +41,3 @@ "lib/"

"@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"
"hast-util-minify-whitespace": "^1.0.0"
},

@@ -53,3 +51,9 @@ "scripts": {},

},
"xo": false
"xo": {
"prettier": true,
"rules": {
"capitalized-comments": "off",
"unicorn/prefer-string-replace-all": "off"
}
}
}

@@ -17,17 +17,17 @@ <!--This file is generated-->

* [What is this?](#what-is-this)
* [When should I use this?](#when-should-i-use-this)
* [Install](#install)
* [Use](#use)
* [API](#api)
* [`unified().use(rehypeMinifyWhitespace[, options])`](#unifieduserehypeminifywhitespace-options)
* [`Options`](#options)
* [Example](#example)
* [Syntax](#syntax)
* [Syntax tree](#syntax-tree)
* [Types](#types)
* [Compatibility](#compatibility)
* [Security](#security)
* [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)
* [`unified().use(rehypeMinifyWhitespace[, options])`](#unifieduserehypeminifywhitespace-options)
* [`Options`](#options)
* [Example](#example)
* [Syntax](#syntax)
* [Syntax tree](#syntax-tree)
* [Types](#types)
* [Compatibility](#compatibility)
* [Security](#security)
* [Contribute](#contribute)
* [License](#license)

@@ -116,4 +116,4 @@ ## What is this?

* `options` (`Options`, optional)
— configuration
* `options` (`Options`, optional)
— configuration

@@ -130,5 +130,5 @@ ###### Returns

* `newlines` (`boolean`, default: `false`)
— collapse whitespace containing newlines to `'\n'` instead of `' '`;
the default is to collapse to a single space
* `newlines` (`boolean`, default: `false`)
— collapse whitespace containing newlines to `'\n'` instead of `' '`;
the default is to collapse to a single space

@@ -135,0 +135,0 @@ ## Example

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