/** * @typedef {import('micromark-util-types').NormalizedExtension} NormalizedExtension * @typedef {import('micromark-util-types').Extension} Extension * @typedef {import('micromark-util-types').Construct} Construct * @typedef {import('micromark-util-types').HtmlExtension} HtmlExtension */ import {splice} from 'micromark-util-chunked' const hasOwnProperty = {}.hasOwnProperty /** * Combine several syntax extensions into one. * * @param {Extension[]} extensions List of syntax extensions. * @returns {NormalizedExtension} A single combined extension. */ export function combineExtensions(extensions) { /** @type {NormalizedExtension} */ const all = {} let index = -1 while (++index < extensions.length) { syntaxExtension(all, extensions[index]) } return all } /** * Merge `extension` into `all`. * * @param {NormalizedExtension} all Extension to merge into. * @param {Extension} extension Extension to merge. * @returns {void} */ function syntaxExtension(all, extension) { /** @type {string} */ let hook for (hook in extension) { const maybe = hasOwnProperty.call(all, hook) ? all[hook] : undefined const left = maybe || (all[hook] = {}) const right = extension[hook] /** @type {string} */ let code for (code in right) { if (!hasOwnProperty.call(left, code)) left[code] = [] const value = right[code] constructs( // @ts-expect-error Looks like a list. left[code], Array.isArray(value) ? value : value ? [value] : [] ) } } } /** * Merge `list` into `existing` (both lists of constructs). * Mutates `existing`. * * @param {unknown[]} existing * @param {unknown[]} list * @returns {void} */ function constructs(existing, list) { let index = -1 /** @type {unknown[]} */ const before = [] while (++index < list.length) { // @ts-expect-error Looks like an object. ;(list[index].add === 'after' ? existing : before).push(list[index]) } splice(existing, 0, 0, before) } /** * Combine several HTML extensions into one. * * @param {HtmlExtension[]} htmlExtensions List of HTML extensions. * @returns {HtmlExtension} A single combined extension. */ export function combineHtmlExtensions(htmlExtensions) { /** @type {HtmlExtension} */ const handlers = {} let index = -1 while (++index < htmlExtensions.length) { htmlExtension(handlers, htmlExtensions[index]) } return handlers } /** * Merge `extension` into `all`. * * @param {HtmlExtension} all Extension to merge into. * @param {HtmlExtension} extension Extension to merge. * @returns {void} */ function htmlExtension(all, extension) { /** @type {string} */ let hook for (hook in extension) { const maybe = hasOwnProperty.call(all, hook) ? all[hook] : undefined const left = maybe || (all[hook] = {}) const right = extension[hook] /** @type {string} */ let type if (right) { for (type in right) { left[type] = right[type] } } } }