rehype-autolink-headings
Advanced tools
Comparing version
145
index.js
@@ -1,13 +0,39 @@ | ||
'use strict' | ||
/** | ||
* @typedef {import('hast').Root} Root | ||
* @typedef {import('hast').Parent} Parent | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {Element['children'][number]} ElementChild | ||
* @typedef {import('hast').Properties} Properties | ||
* | ||
* @typedef {'prepend'|'append'|'wrap'|'before'|'after'} Behavior | ||
* | ||
* @callback Build | ||
* @param {Element} node | ||
* @returns {ElementChild|ElementChild[]} | ||
* | ||
* @typedef Options | ||
* Configuration. | ||
* @property {Behavior} [behavior='prepend'] | ||
* How to create links. | ||
* @property {Behavior} [behaviour] | ||
* Please use `behavior` instead | ||
* @property {Properties} [properties] | ||
* Extra properties to set on the link when injecting. | ||
* Defaults to `{ariaHidden: true, tabIndex: -1}` when `'prepend'` or | ||
* `'append'`. | ||
* @property {ElementChild|ElementChild[]|Build} [content={type: 'element', tagName: 'span', properties: {className: ['icon', 'icon-link']}, children: []}] | ||
* hast nodes to insert in the link. | ||
* @property {ElementChild|ElementChild[]|Build} [group] | ||
* hast node to wrap the heading and link with, if `behavior` is `'before'` or | ||
* `'after'`. | ||
* There is no default. | ||
*/ | ||
var extend = require('extend') | ||
var has = require('hast-util-has-property') | ||
var rank = require('hast-util-heading-rank') | ||
var visit = require('unist-util-visit') | ||
import extend from 'extend' | ||
import {hasProperty} from 'hast-util-has-property' | ||
import {headingRank} from 'hast-util-heading-rank' | ||
import {visit, SKIP} from 'unist-util-visit' | ||
module.exports = autolink | ||
var splice = [].splice | ||
var contentDefaults = { | ||
/** @type {Element} */ | ||
const contentDefaults = { | ||
type: 'element', | ||
@@ -19,10 +45,16 @@ tagName: 'span', | ||
function autolink(options) { | ||
var settings = options || {} | ||
var props = settings.properties | ||
var behavior = settings.behaviour || settings.behavior || 'prepend' | ||
var content = settings.content || contentDefaults | ||
var group = settings.group | ||
var method | ||
/** | ||
* Plugin to automatically add links to headings (h1-h6). | ||
* | ||
* @type {import('unified').Plugin<[Options?]|void[], Root>} | ||
*/ | ||
export default function rehypeAutolinkHeadings(options = {}) { | ||
let props = options.properties | ||
const behavior = options.behaviour || options.behavior || 'prepend' | ||
const content = options.content || contentDefaults | ||
const group = options.group | ||
/** @type {import('unist-util-visit').Visitor<Element>} */ | ||
let method | ||
if (behavior === 'wrap') { | ||
@@ -33,21 +65,18 @@ method = wrap | ||
} else { | ||
method = inject | ||
if (!props) { | ||
props = {ariaHidden: 'true', tabIndex: -1} | ||
} | ||
} | ||
return transformer | ||
function transformer(tree) { | ||
visit(tree, 'element', visitor) | ||
method = inject | ||
} | ||
function visitor(node, index, parent) { | ||
if (rank(node) && has(node, 'id')) { | ||
return method(node, index, parent) | ||
} | ||
return (tree) => { | ||
visit(tree, 'element', (node, index, parent) => { | ||
if (headingRank(node) && hasProperty(node, 'id')) { | ||
return method(node, index, parent) | ||
} | ||
}) | ||
} | ||
/** @type {import('unist-util-visit').Visitor<Element>} */ | ||
function inject(node) { | ||
@@ -58,31 +87,53 @@ node.children[behavior === 'prepend' ? 'unshift' : 'push']( | ||
return [visit.SKIP] | ||
return [SKIP] | ||
} | ||
/** @type {import('unist-util-visit').Visitor<Element>} */ | ||
function around(node, index, parent) { | ||
var link = create(node, extend(true, {}, props), toChildren(content, node)) | ||
var nodes = behavior === 'before' ? [link, node] : [node, link] | ||
var grouping = group && toNode(group, node) | ||
// Uncommon. | ||
/* c8 ignore next */ | ||
if (typeof index !== 'number' || !parent) return | ||
if (grouping) { | ||
grouping.children = nodes | ||
nodes = grouping | ||
const link = create( | ||
node, | ||
extend(true, {}, props), | ||
toChildren(content, node) | ||
) | ||
let nodes = behavior === 'before' ? [link, node] : [node, link] | ||
if (group) { | ||
const grouping = toNode(group, node) | ||
if (grouping && !Array.isArray(grouping) && grouping.type === 'element') { | ||
grouping.children = nodes | ||
nodes = [grouping] | ||
} | ||
} | ||
splice.apply(parent.children, [index, 1].concat(nodes)) | ||
parent.children.splice(index, 1, ...nodes) | ||
return [visit.SKIP, index + nodes.length] | ||
return [SKIP, index + nodes.length] | ||
} | ||
/** @type {import('unist-util-visit').Visitor<Element>} */ | ||
function wrap(node) { | ||
node.children = [create(node, extend(true, {}, props), node.children)] | ||
return [visit.SKIP] | ||
return [SKIP] | ||
} | ||
/** | ||
* @param {ElementChild|ElementChild[]|Build} value | ||
* @param {Element} node | ||
* @returns {ElementChild[]} | ||
*/ | ||
function toChildren(value, node) { | ||
var result = toNode(value, node) | ||
const result = toNode(value, node) | ||
return Array.isArray(result) ? result : [result] | ||
} | ||
/** | ||
* @param {ElementChild|ElementChild[]|Build} value | ||
* @param {Element} node | ||
* @returns {ElementChild|ElementChild[]} | ||
*/ | ||
function toNode(value, node) { | ||
@@ -93,2 +144,8 @@ if (typeof value === 'function') return value(node) | ||
/** | ||
* @param {Element} node | ||
* @param {Properties} props | ||
* @param {ElementChild[]} children | ||
* @returns {Element} | ||
*/ | ||
function create(node, props, children) { | ||
@@ -98,6 +155,10 @@ return { | ||
tagName: 'a', | ||
properties: Object.assign({}, props, {href: '#' + node.properties.id}), | ||
children: children | ||
properties: Object.assign({}, props, { | ||
// Fix hast types and make them required. | ||
/* c8 ignore next */ | ||
href: '#' + (node.properties || {}).id | ||
}), | ||
children | ||
} | ||
} | ||
} |
{ | ||
"name": "rehype-autolink-headings", | ||
"version": "5.1.0", | ||
"version": "6.0.0", | ||
"description": "rehype plugin to add links to headings", | ||
@@ -25,47 +25,42 @@ "license": "MIT", | ||
], | ||
"sideEffects": false, | ||
"type": "module", | ||
"main": "index.js", | ||
"types": "index.d.ts", | ||
"files": [ | ||
"index.js", | ||
"types/index.d.ts" | ||
"index.d.ts", | ||
"index.js" | ||
], | ||
"types": "types/index.d.ts", | ||
"dependencies": { | ||
"@types/hast": "^2.0.0", | ||
"extend": "^3.0.0", | ||
"hast-util-has-property": "^1.0.0", | ||
"hast-util-heading-rank": "^1.0.0", | ||
"unist-util-visit": "^2.0.0" | ||
"hast-util-has-property": "^2.0.0", | ||
"hast-util-heading-rank": "^2.0.0", | ||
"unified": "^10.0.0", | ||
"unist-util-visit": "^4.0.0" | ||
}, | ||
"devDependencies": { | ||
"@types/hast": "^2.0.0", | ||
"bail": "^1.0.0", | ||
"browserify": "^17.0.0", | ||
"dtslint": "^4.0.0", | ||
"is-hidden": "^1.0.0", | ||
"negate": "^1.0.0", | ||
"nyc": "^15.0.0", | ||
"@types/extend": "^3.0.1", | ||
"@types/tape": "^4.0.0", | ||
"bail": "^2.0.0", | ||
"c8": "^7.0.0", | ||
"is-hidden": "^2.0.0", | ||
"prettier": "^2.0.0", | ||
"rehype": "^11.0.0", | ||
"rehype": "^12.0.0", | ||
"remark-cli": "^9.0.0", | ||
"remark-preset-wooorm": "^8.0.0", | ||
"rimraf": "^3.0.0", | ||
"tape": "^5.0.0", | ||
"tinyify": "^3.0.0", | ||
"to-vfile": "^6.0.0", | ||
"unified": "^9.0.0", | ||
"xo": "^0.38.0" | ||
"to-vfile": "^7.0.0", | ||
"type-coverage": "^2.0.0", | ||
"typescript": "^4.0.0", | ||
"xo": "^0.42.0" | ||
}, | ||
"scripts": { | ||
"build": "rimraf \"*.d.ts\" \"test/**/*.d.ts\" && tsc && type-coverage", | ||
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix", | ||
"build-bundle": "browserify . -s rehypeAutolinkHeadings -o rehype-autolink-headings.js", | ||
"build-mangle": "browserify . -s rehypeAutolinkHeadings -o rehype-autolink-headings.min.js -p tinyify", | ||
"build": "npm run build-bundle && npm run build-mangle", | ||
"test-api": "node test", | ||
"test-coverage": "nyc --reporter lcov tape test/index.js", | ||
"test-types": "dtslint types", | ||
"test": "npm run format && npm run build && npm run test-coverage && npm run test-types" | ||
"test-api": "node --conditions development test/index.js", | ||
"test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov npm run test-api", | ||
"test": "npm run build && npm run format && npm run test-coverage" | ||
}, | ||
"nyc": { | ||
"check-coverage": true, | ||
"lines": 100, | ||
"functions": 100, | ||
"branches": 100 | ||
}, | ||
"prettier": { | ||
@@ -81,9 +76,4 @@ "tabWidth": 2, | ||
"prettier": true, | ||
"esnext": false, | ||
"rules": { | ||
"unicorn/no-fn-reference-in-iterator": "off", | ||
"unicorn/prefer-optional-catch-binding": "off" | ||
}, | ||
"ignores": [ | ||
"rehype-autolink-headings.js" | ||
"types/" | ||
] | ||
@@ -95,3 +85,9 @@ }, | ||
] | ||
}, | ||
"typeCoverage": { | ||
"atLeast": 100, | ||
"detail": true, | ||
"strict": true, | ||
"ignoreCatch": true | ||
} | ||
} |
@@ -15,2 +15,5 @@ # rehype-autolink-headings | ||
This package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c): | ||
Node 12+ is needed to use it and it must be `import`ed instead of `require`d. | ||
[npm][]: | ||
@@ -37,15 +40,15 @@ | ||
```js | ||
var fs = require('fs') | ||
var rehype = require('rehype') | ||
var slug = require('rehype-slug') | ||
var link = require('rehype-autolink-headings') | ||
import fs from 'node:fs' | ||
import rehype from 'rehype' | ||
import rehypeSlug from 'rehype-slug' | ||
import rehypeAutolinkHeadings from 'rehype-autolink-headings' | ||
var doc = fs.readFileSync('fragment.html') | ||
const buf = fs.readFileSync('fragment.html') | ||
rehype() | ||
.data('settings', {fragment: true}) | ||
.use(slug) | ||
.use(link) | ||
.process(doc, function(err, file) { | ||
if (err) throw err | ||
.use(rehypeSlug) | ||
.use(rehypeAutolinkHeadings) | ||
.process(buf) | ||
.then((file) => { | ||
console.log(String(file)) | ||
@@ -67,4 +70,7 @@ }) | ||
### `rehype().use(link[, options])` | ||
This package exports no identifiers. | ||
The default export is `rehypeAutolinkHeadings`. | ||
### `unified().use(rehypeAutolinkHeadings[, options])` | ||
Add links to headings (h1-h6) with an `id`. | ||
@@ -71,0 +77,0 @@ |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
16113
21.66%15
-6.25%198
76.79%235
2.62%Yes
NaN6
50%1
Infinity%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
Updated