import {visit} from 'unist-util-visit' /** * @typedef {import('unist').Node} Node * @typedef {import('hast').Root} Root * @typedef {import('hast').Element} Element * * @callback AllowElement * @param {Element} element * @param {number} index * @param {Element|Root} parent * @returns {boolean|undefined} * * @typedef Options * @property {Array} [allowedElements] * @property {Array} [disallowedElements=[]] * @property {AllowElement} [allowElement] * @property {boolean} [unwrapDisallowed=false] */ /** * @type {import('unified').Plugin<[Options], Root>} */ export default function rehypeFilter(options) { if (options.allowedElements && options.disallowedElements) { throw new TypeError( 'Only one of `allowedElements` and `disallowedElements` should be defined' ) } if ( options.allowedElements || options.disallowedElements || options.allowElement ) { return (tree) => { visit(tree, 'element', (node, index, parent_) => { const parent = /** @type {Element|Root} */ (parent_) /** @type {boolean|undefined} */ let remove if (options.allowedElements) { remove = !options.allowedElements.includes(node.tagName) } else if (options.disallowedElements) { remove = options.disallowedElements.includes(node.tagName) } if (!remove && options.allowElement && typeof index === 'number') { remove = !options.allowElement(node, index, parent) } if (remove && typeof index === 'number') { if (options.unwrapDisallowed && node.children) { parent.children.splice(index, 1, ...node.children) } else { parent.children.splice(index, 1) } return index } return undefined }) } } }