mdast-util-to-hast
Advanced tools
Comparing version 12.3.0 to 13.0.0
@@ -1,35 +0,41 @@ | ||
import type {Literal} from 'hast' | ||
import type {State} from './lib/state.js' | ||
import type {Data, ElementContent, Literal, Properties} from 'hast' | ||
// Expose types. | ||
export type {State, Handler, Handlers, Options} from './lib/state.js' | ||
export type { | ||
FootnoteBackContentTemplate, | ||
FootnoteBackLabelTemplate | ||
} from './lib/footer.js' | ||
export type {Handler, Handlers, Options, State} from './lib/state.js' | ||
// To do: next major: remove. | ||
/** | ||
* Deprecated: use `State`. | ||
*/ | ||
export type H = State | ||
// Expose JS API. | ||
export {handlers as defaultHandlers} from './lib/handlers/index.js' | ||
// To do: next major: remove. | ||
export {one, all} from './lib/state.js' | ||
export { | ||
defaultFootnoteBackContent, | ||
defaultFootnoteBackLabel | ||
} from './lib/footer.js' | ||
export {toHast} from './lib/index.js' | ||
// Expose node type. | ||
/** | ||
* Raw string of HTML embedded into HTML AST. | ||
*/ | ||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions | ||
export interface Raw extends Literal { | ||
/** | ||
* Node type. | ||
* Node type of raw. | ||
*/ | ||
type: 'raw' | ||
/** | ||
* Data associated with the hast raw. | ||
*/ | ||
data?: RawData | undefined | ||
} | ||
/** | ||
* Info associated with hast raw nodes by the ecosystem. | ||
*/ | ||
export interface RawData extends Data {} | ||
// Register nodes in content. | ||
declare module 'hast' { | ||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions | ||
interface RootContentMap { | ||
interface ElementContentMap { | ||
/** | ||
@@ -41,4 +47,3 @@ * Raw string of HTML embedded into HTML AST. | ||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions | ||
interface ElementContentMap { | ||
interface RootContentMap { | ||
/** | ||
@@ -50,1 +55,33 @@ * Raw string of HTML embedded into HTML AST. | ||
} | ||
// Register data on mdast. | ||
declare module 'mdast' { | ||
interface Data { | ||
/** | ||
* Field supported by `mdast-util-to-hast` to signal that a node should | ||
* result in something with these children. | ||
* | ||
* When this is defined, when a parent is created, these children will | ||
* be used. | ||
*/ | ||
hChildren?: ElementContent[] | undefined | ||
/** | ||
* Field supported by `mdast-util-to-hast` to signal that a node should | ||
* result in a particular element, instead of its default behavior. | ||
* | ||
* When this is defined, an element with the given tag name is created. | ||
* For example, when setting `hName` to `'b'`, a `<b>` element is created. | ||
*/ | ||
hName?: string | undefined | ||
/** | ||
* Field supported by `mdast-util-to-hast` to signal that a node should | ||
* result in an element with these properties. | ||
* | ||
* When this is defined, when an element is created, these properties will | ||
* be used. | ||
*/ | ||
hProperties?: Properties | undefined | ||
} | ||
} |
// Note: types exposed from `index.d.ts`. | ||
export {handlers as defaultHandlers} from './lib/handlers/index.js' | ||
// To do: next major: remove. | ||
export {one, all} from './lib/state.js' | ||
export {toHast} from './lib/index.js' | ||
export { | ||
defaultFootnoteBackContent, | ||
defaultFootnoteBackLabel | ||
} from './lib/footer.js' |
/** | ||
* Generate the default content that GitHub uses on backreferences. | ||
* | ||
* @param {number} _ | ||
* Index of the definition in the order that they are first referenced, | ||
* 0-indexed. | ||
* @param {number} rereferenceIndex | ||
* Index of calls to the same definition, 0-indexed. | ||
* @returns {Array<ElementContent>} | ||
* Content. | ||
*/ | ||
export function defaultFootnoteBackContent(_: number, rereferenceIndex: number): Array<ElementContent>; | ||
/** | ||
* Generate the default label that GitHub uses on backreferences. | ||
* | ||
* @param {number} referenceIndex | ||
* Index of the definition in the order that they are first referenced, | ||
* 0-indexed. | ||
* @param {number} rereferenceIndex | ||
* Index of calls to the same definition, 0-indexed. | ||
* @returns {string} | ||
* Label. | ||
*/ | ||
export function defaultFootnoteBackLabel(referenceIndex: number, rereferenceIndex: number): string; | ||
/** | ||
* Generate a hast footer for called footnote definitions. | ||
@@ -9,5 +33,49 @@ * | ||
*/ | ||
export function footer(state: State): Element | undefined | ||
export type Element = import('hast').Element | ||
export type ElementContent = import('hast').ElementContent | ||
export type State = import('./state.js').State | ||
export function footer(state: State): Element | undefined; | ||
export type Element = import('hast').Element; | ||
export type ElementContent = import('hast').ElementContent; | ||
export type State = import('./state.js').State; | ||
/** | ||
* Generate content for the backreference dynamically. | ||
* | ||
* For the following markdown: | ||
* | ||
* ```markdown | ||
* Alpha[^micromark], bravo[^micromark], and charlie[^remark]. | ||
* | ||
* [^remark]: things about remark | ||
* [^micromark]: things about micromark | ||
* ``` | ||
* | ||
* This function will be called with: | ||
* | ||
* * `0` and `0` for the backreference from `things about micromark` to | ||
* `alpha`, as it is the first used definition, and the first call to it | ||
* * `0` and `1` for the backreference from `things about micromark` to | ||
* `bravo`, as it is the first used definition, and the second call to it | ||
* * `1` and `0` for the backreference from `things about remark` to | ||
* `charlie`, as it is the second used definition | ||
*/ | ||
export type FootnoteBackContentTemplate = (referenceIndex: number, rereferenceIndex: number) => Array<ElementContent> | ElementContent | string; | ||
/** | ||
* Generate a back label dynamically. | ||
* | ||
* For the following markdown: | ||
* | ||
* ```markdown | ||
* Alpha[^micromark], bravo[^micromark], and charlie[^remark]. | ||
* | ||
* [^remark]: things about remark | ||
* [^micromark]: things about micromark | ||
* ``` | ||
* | ||
* This function will be called with: | ||
* | ||
* * `0` and `0` for the backreference from `things about micromark` to | ||
* `alpha`, as it is the first used definition, and the first call to it | ||
* * `0` and `1` for the backreference from `things about micromark` to | ||
* `bravo`, as it is the first used definition, and the second call to it | ||
* * `1` and `0` for the backreference from `things about remark` to | ||
* `charlie`, as it is the second used definition | ||
*/ | ||
export type FootnoteBackLabelTemplate = (referenceIndex: number, rereferenceIndex: number) => string; |
@@ -8,5 +8,111 @@ /** | ||
/** | ||
* @callback FootnoteBackContentTemplate | ||
* Generate content for the backreference dynamically. | ||
* | ||
* For the following markdown: | ||
* | ||
* ```markdown | ||
* Alpha[^micromark], bravo[^micromark], and charlie[^remark]. | ||
* | ||
* [^remark]: things about remark | ||
* [^micromark]: things about micromark | ||
* ``` | ||
* | ||
* This function will be called with: | ||
* | ||
* * `0` and `0` for the backreference from `things about micromark` to | ||
* `alpha`, as it is the first used definition, and the first call to it | ||
* * `0` and `1` for the backreference from `things about micromark` to | ||
* `bravo`, as it is the first used definition, and the second call to it | ||
* * `1` and `0` for the backreference from `things about remark` to | ||
* `charlie`, as it is the second used definition | ||
* @param {number} referenceIndex | ||
* Index of the definition in the order that they are first referenced, | ||
* 0-indexed. | ||
* @param {number} rereferenceIndex | ||
* Index of calls to the same definition, 0-indexed. | ||
* @returns {Array<ElementContent> | ElementContent | string} | ||
* Content for the backreference when linking back from definitions to their | ||
* reference. | ||
* | ||
* @callback FootnoteBackLabelTemplate | ||
* Generate a back label dynamically. | ||
* | ||
* For the following markdown: | ||
* | ||
* ```markdown | ||
* Alpha[^micromark], bravo[^micromark], and charlie[^remark]. | ||
* | ||
* [^remark]: things about remark | ||
* [^micromark]: things about micromark | ||
* ``` | ||
* | ||
* This function will be called with: | ||
* | ||
* * `0` and `0` for the backreference from `things about micromark` to | ||
* `alpha`, as it is the first used definition, and the first call to it | ||
* * `0` and `1` for the backreference from `things about micromark` to | ||
* `bravo`, as it is the first used definition, and the second call to it | ||
* * `1` and `0` for the backreference from `things about remark` to | ||
* `charlie`, as it is the second used definition | ||
* @param {number} referenceIndex | ||
* Index of the definition in the order that they are first referenced, | ||
* 0-indexed. | ||
* @param {number} rereferenceIndex | ||
* Index of calls to the same definition, 0-indexed. | ||
* @returns {string} | ||
* Back label to use when linking back from definitions to their reference. | ||
*/ | ||
import structuredClone from '@ungap/structured-clone' | ||
import {normalizeUri} from 'micromark-util-sanitize-uri' | ||
/** | ||
* Generate the default content that GitHub uses on backreferences. | ||
* | ||
* @param {number} _ | ||
* Index of the definition in the order that they are first referenced, | ||
* 0-indexed. | ||
* @param {number} rereferenceIndex | ||
* Index of calls to the same definition, 0-indexed. | ||
* @returns {Array<ElementContent>} | ||
* Content. | ||
*/ | ||
export function defaultFootnoteBackContent(_, rereferenceIndex) { | ||
/** @type {Array<ElementContent>} */ | ||
const result = [{type: 'text', value: '↩'}] | ||
if (rereferenceIndex > 1) { | ||
result.push({ | ||
type: 'element', | ||
tagName: 'sup', | ||
properties: {}, | ||
children: [{type: 'text', value: String(rereferenceIndex)}] | ||
}) | ||
} | ||
return result | ||
} | ||
/** | ||
* Generate the default label that GitHub uses on backreferences. | ||
* | ||
* @param {number} referenceIndex | ||
* Index of the definition in the order that they are first referenced, | ||
* 0-indexed. | ||
* @param {number} rereferenceIndex | ||
* Index of calls to the same definition, 0-indexed. | ||
* @returns {string} | ||
* Label. | ||
*/ | ||
export function defaultFootnoteBackLabel(referenceIndex, rereferenceIndex) { | ||
return ( | ||
'Back to reference ' + | ||
(referenceIndex + 1) + | ||
(rereferenceIndex > 1 ? '-' + rereferenceIndex : '') | ||
) | ||
} | ||
/** | ||
* Generate a hast footer for called footnote definitions. | ||
@@ -19,9 +125,23 @@ * | ||
*/ | ||
// eslint-disable-next-line complexity | ||
export function footer(state) { | ||
const clobberPrefix = | ||
typeof state.options.clobberPrefix === 'string' | ||
? state.options.clobberPrefix | ||
: 'user-content-' | ||
const footnoteBackContent = | ||
state.options.footnoteBackContent || defaultFootnoteBackContent | ||
const footnoteBackLabel = | ||
state.options.footnoteBackLabel || defaultFootnoteBackLabel | ||
const footnoteLabel = state.options.footnoteLabel || 'Footnotes' | ||
const footnoteLabelTagName = state.options.footnoteLabelTagName || 'h2' | ||
const footnoteLabelProperties = state.options.footnoteLabelProperties || { | ||
className: ['sr-only'] | ||
} | ||
/** @type {Array<ElementContent>} */ | ||
const listItems = [] | ||
let index = -1 | ||
let referenceIndex = -1 | ||
while (++index < state.footnoteOrder.length) { | ||
const def = state.footnoteById[state.footnoteOrder[index]] | ||
while (++referenceIndex < state.footnoteOrder.length) { | ||
const def = state.footnoteById.get(state.footnoteOrder[referenceIndex]) | ||
@@ -35,9 +155,23 @@ if (!def) { | ||
const safeId = normalizeUri(id.toLowerCase()) | ||
let referenceIndex = 0 | ||
let rereferenceIndex = 0 | ||
/** @type {Array<ElementContent>} */ | ||
const backReferences = [] | ||
const counts = state.footnoteCounts.get(id) | ||
while (++referenceIndex <= state.footnoteCounts[id]) { | ||
/** @type {Element} */ | ||
const backReference = { | ||
// eslint-disable-next-line no-unmodified-loop-condition | ||
while (counts !== undefined && ++rereferenceIndex <= counts) { | ||
if (backReferences.length > 0) { | ||
backReferences.push({type: 'text', value: ' '}) | ||
} | ||
let children = | ||
typeof footnoteBackContent === 'string' | ||
? footnoteBackContent | ||
: footnoteBackContent(referenceIndex, rereferenceIndex) | ||
if (typeof children === 'string') { | ||
children = {type: 'text', value: children} | ||
} | ||
backReferences.push({ | ||
type: 'element', | ||
@@ -48,26 +182,15 @@ tagName: 'a', | ||
'#' + | ||
state.clobberPrefix + | ||
clobberPrefix + | ||
'fnref-' + | ||
safeId + | ||
(referenceIndex > 1 ? '-' + referenceIndex : ''), | ||
dataFootnoteBackref: true, | ||
className: ['data-footnote-backref'], | ||
ariaLabel: state.footnoteBackLabel | ||
(rereferenceIndex > 1 ? '-' + rereferenceIndex : ''), | ||
dataFootnoteBackref: '', | ||
ariaLabel: | ||
typeof footnoteBackLabel === 'string' | ||
? footnoteBackLabel | ||
: footnoteBackLabel(referenceIndex, rereferenceIndex), | ||
className: ['data-footnote-backref'] | ||
}, | ||
children: [{type: 'text', value: '↩'}] | ||
} | ||
if (referenceIndex > 1) { | ||
backReference.children.push({ | ||
type: 'element', | ||
tagName: 'sup', | ||
children: [{type: 'text', value: String(referenceIndex)}] | ||
}) | ||
} | ||
if (backReferences.length > 0) { | ||
backReferences.push({type: 'text', value: ' '}) | ||
} | ||
backReferences.push(backReference) | ||
children: Array.isArray(children) ? children : [children] | ||
}) | ||
} | ||
@@ -94,3 +217,3 @@ | ||
tagName: 'li', | ||
properties: {id: state.clobberPrefix + 'fn-' + safeId}, | ||
properties: {id: clobberPrefix + 'fn-' + safeId}, | ||
children: state.wrap(content, true) | ||
@@ -115,9 +238,8 @@ } | ||
type: 'element', | ||
tagName: state.footnoteLabelTagName, | ||
tagName: footnoteLabelTagName, | ||
properties: { | ||
// To do: use structured clone. | ||
...JSON.parse(JSON.stringify(state.footnoteLabelProperties)), | ||
...structuredClone(footnoteLabelProperties), | ||
id: 'footnote-label' | ||
}, | ||
children: [{type: 'text', value: state.footnoteLabel}] | ||
children: [{type: 'text', value: footnoteLabel}] | ||
}, | ||
@@ -124,0 +246,0 @@ {type: 'text', value: '\n'}, |
/** | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {import('mdast').Blockquote} Blockquote | ||
* @typedef {import('../state.js').State} State | ||
*/ | ||
/** | ||
* Turn an mdast `blockquote` node into hast. | ||
@@ -16,5 +11,5 @@ * | ||
*/ | ||
export function blockquote(state: State, node: Blockquote): Element | ||
export type Element = import('hast').Element | ||
export type Blockquote = import('mdast').Blockquote | ||
export type State = import('../state.js').State | ||
export function blockquote(state: State, node: Blockquote): Element; | ||
export type Element = import('hast').Element; | ||
export type Blockquote = import('mdast').Blockquote; | ||
export type State = import('../state.js').State; |
@@ -7,2 +7,5 @@ /** | ||
// Make VS Code show references to the above types. | ||
'' | ||
/** | ||
@@ -9,0 +12,0 @@ * Turn an mdast `blockquote` node into hast. |
/** | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {import('hast').Text} Text | ||
* @typedef {import('mdast').Break} Break | ||
* @typedef {import('../state.js').State} State | ||
*/ | ||
/** | ||
* Turn an mdast `break` node into hast. | ||
@@ -17,6 +11,6 @@ * | ||
*/ | ||
export function hardBreak(state: State, node: Break): Array<Element | Text> | ||
export type Element = import('hast').Element | ||
export type Text = import('hast').Text | ||
export type Break = import('mdast').Break | ||
export type State = import('../state.js').State | ||
export function hardBreak(state: State, node: Break): Array<Element | Text>; | ||
export type Element = import('hast').Element; | ||
export type Text = import('hast').Text; | ||
export type Break = import('mdast').Break; | ||
export type State = import('../state.js').State; |
@@ -8,2 +8,5 @@ /** | ||
// Make VS Code show references to the above types. | ||
'' | ||
/** | ||
@@ -10,0 +13,0 @@ * Turn an mdast `break` node into hast. |
/** | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {import('hast').Properties} Properties | ||
* @typedef {import('mdast').Code} Code | ||
* @typedef {import('../state.js').State} State | ||
*/ | ||
/** | ||
* Turn an mdast `code` node into hast. | ||
@@ -18,6 +11,6 @@ * | ||
*/ | ||
export function code(state: State, node: Code): Element | ||
export type Element = import('hast').Element | ||
export type Properties = import('hast').Properties | ||
export type Code = import('mdast').Code | ||
export type State = import('../state.js').State | ||
export function code(state: State, node: Code): Element; | ||
export type Element = import('hast').Element; | ||
export type Properties = import('hast').Properties; | ||
export type Code = import('mdast').Code; | ||
export type State = import('../state.js').State; |
@@ -6,5 +6,7 @@ /** | ||
* @typedef {import('../state.js').State} State | ||
*/ | ||
// Make VS Code show references to the above types. | ||
'' | ||
/** | ||
@@ -22,10 +24,7 @@ * Turn an mdast `code` node into hast. | ||
const value = node.value ? node.value + '\n' : '' | ||
// To do: next major, use `node.lang` w/o regex, the splitting’s been going | ||
// on for years in remark now. | ||
const lang = node.lang ? node.lang.match(/^[^ \t]+(?=[ \t]|$)/) : null | ||
/** @type {Properties} */ | ||
const properties = {} | ||
if (lang) { | ||
properties.className = ['language-' + lang] | ||
if (node.lang) { | ||
properties.className = ['language-' + node.lang] | ||
} | ||
@@ -32,0 +31,0 @@ |
/** | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {import('mdast').Delete} Delete | ||
* @typedef {import('../state.js').State} State | ||
*/ | ||
/** | ||
* Turn an mdast `delete` node into hast. | ||
@@ -17,5 +11,5 @@ * | ||
*/ | ||
export function strikethrough(state: State, node: Delete): Element | ||
export type Element = import('hast').Element | ||
export type Delete = import('mdast').Delete | ||
export type State = import('../state.js').State | ||
export function strikethrough(state: State, node: Delete): Element; | ||
export type Element = import('hast').Element; | ||
export type Delete = import('mdast').Delete; | ||
export type State = import('../state.js').State; |
@@ -5,5 +5,7 @@ /** | ||
* @typedef {import('../state.js').State} State | ||
*/ | ||
// Make VS Code show references to the above types. | ||
'' | ||
/** | ||
@@ -10,0 +12,0 @@ * Turn an mdast `delete` node into hast. |
/** | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {import('mdast').Emphasis} Emphasis | ||
* @typedef {import('../state.js').State} State | ||
*/ | ||
/** | ||
* Turn an mdast `emphasis` node into hast. | ||
@@ -16,5 +11,5 @@ * | ||
*/ | ||
export function emphasis(state: State, node: Emphasis): Element | ||
export type Element = import('hast').Element | ||
export type Emphasis = import('mdast').Emphasis | ||
export type State = import('../state.js').State | ||
export function emphasis(state: State, node: Emphasis): Element; | ||
export type Element = import('hast').Element; | ||
export type Emphasis = import('mdast').Emphasis; | ||
export type State = import('../state.js').State; |
@@ -7,2 +7,5 @@ /** | ||
// Make VS Code show references to the above types. | ||
'' | ||
/** | ||
@@ -9,0 +12,0 @@ * Turn an mdast `emphasis` node into hast. |
@@ -11,8 +11,5 @@ /** | ||
*/ | ||
export function footnoteReference( | ||
state: State, | ||
node: FootnoteReference | ||
): Element | ||
export type FootnoteReference = import('mdast').FootnoteReference | ||
export type Element = import('hast').Element | ||
export type State = import('../state.js').State | ||
export function footnoteReference(state: State, node: FootnoteReference): Element; | ||
export type Element = import('hast').Element; | ||
export type FootnoteReference = import('mdast').FootnoteReference; | ||
export type State = import('../state.js').State; |
/** | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {import('mdast').FootnoteReference} FootnoteReference | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {import('../state.js').State} State | ||
@@ -20,2 +20,6 @@ */ | ||
export function footnoteReference(state, node) { | ||
const clobberPrefix = | ||
typeof state.options.clobberPrefix === 'string' | ||
? state.options.clobberPrefix | ||
: 'user-content-' | ||
const id = String(node.identifier).toUpperCase() | ||
@@ -27,12 +31,14 @@ const safeId = normalizeUri(id.toLowerCase()) | ||
if (index === -1) { | ||
let reuseCounter = state.footnoteCounts.get(id) | ||
if (reuseCounter === undefined) { | ||
reuseCounter = 0 | ||
state.footnoteOrder.push(id) | ||
state.footnoteCounts[id] = 1 | ||
counter = state.footnoteOrder.length | ||
} else { | ||
state.footnoteCounts[id]++ | ||
counter = index + 1 | ||
} | ||
const reuseCounter = state.footnoteCounts[id] | ||
reuseCounter += 1 | ||
state.footnoteCounts.set(id, reuseCounter) | ||
@@ -44,5 +50,5 @@ /** @type {Element} */ | ||
properties: { | ||
href: '#' + state.clobberPrefix + 'fn-' + safeId, | ||
href: '#' + clobberPrefix + 'fn-' + safeId, | ||
id: | ||
state.clobberPrefix + | ||
clobberPrefix + | ||
'fnref-' + | ||
@@ -49,0 +55,0 @@ safeId + |
@@ -6,3 +6,3 @@ /** | ||
* Info passed around. | ||
* @param {Footnote} node | ||
* @param {Node} node | ||
* mdast node. | ||
@@ -12,5 +12,6 @@ * @returns {Element} | ||
*/ | ||
export function footnote(state: State, node: Footnote): Element | ||
export type Element = import('hast').Element | ||
export type Footnote = import('mdast').Footnote | ||
export type State = import('../state.js').State | ||
export function footnote(state: State, node: Node): Element; | ||
export type Element = import('hast').Element; | ||
export type FootnoteDefinition = import('mdast').FootnoteDefinition; | ||
export type Node = import('mdast').Node; | ||
export type State = import('../state.js').State; |
/** | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {import('mdast').Heading} Heading | ||
* @typedef {import('../state.js').State} State | ||
*/ | ||
/** | ||
* Turn an mdast `heading` node into hast. | ||
@@ -16,5 +11,5 @@ * | ||
*/ | ||
export function heading(state: State, node: Heading): Element | ||
export type Element = import('hast').Element | ||
export type Heading = import('mdast').Heading | ||
export type State = import('../state.js').State | ||
export function heading(state: State, node: Heading): Element; | ||
export type Element = import('hast').Element; | ||
export type Heading = import('mdast').Heading; | ||
export type State = import('../state.js').State; |
@@ -7,2 +7,5 @@ /** | ||
// Make VS Code show references to the above types. | ||
'' | ||
/** | ||
@@ -9,0 +12,0 @@ * Turn an mdast `heading` node into hast. |
/** | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {import('mdast').HTML} Html | ||
* @typedef {import('../state.js').State} State | ||
* @typedef {import('../../index.js').Raw} Raw | ||
*/ | ||
/** | ||
* Turn an mdast `html` node into hast (`raw` node in dangerous mode, otherwise | ||
@@ -15,9 +9,9 @@ * nothing). | ||
* mdast node. | ||
* @returns {Raw | Element | null} | ||
* @returns {Element | Raw | undefined} | ||
* hast node. | ||
*/ | ||
export function html(state: State, node: Html): Raw | Element | null | ||
export type Element = import('hast').Element | ||
export type Html = import('mdast').HTML | ||
export type State = import('../state.js').State | ||
export type Raw = import('../../index.js').Raw | ||
export function html(state: State, node: Html): Element | Raw | undefined; | ||
export type Element = import('hast').Element; | ||
export type Html = import('mdast').Html; | ||
export type State = import('../state.js').State; | ||
export type Raw = import('../../index.js').Raw; |
/** | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {import('mdast').HTML} Html | ||
* @typedef {import('mdast').Html} Html | ||
* @typedef {import('../state.js').State} State | ||
@@ -8,2 +8,5 @@ * @typedef {import('../../index.js').Raw} Raw | ||
// Make VS Code show references to the above types. | ||
'' | ||
/** | ||
@@ -17,7 +20,7 @@ * Turn an mdast `html` node into hast (`raw` node in dangerous mode, otherwise | ||
* mdast node. | ||
* @returns {Raw | Element | null} | ||
* @returns {Element | Raw | undefined} | ||
* hast node. | ||
*/ | ||
export function html(state, node) { | ||
if (state.dangerous) { | ||
if (state.options.allowDangerousHtml) { | ||
/** @type {Raw} */ | ||
@@ -29,4 +32,3 @@ const result = {type: 'raw', value: node.value} | ||
// To do: next major: return `undefined`. | ||
return null | ||
return undefined | ||
} |
@@ -8,13 +8,10 @@ /** | ||
* mdast node. | ||
* @returns {ElementContent | Array<ElementContent>} | ||
* @returns {Array<ElementContent> | ElementContent} | ||
* hast node. | ||
*/ | ||
export function imageReference( | ||
state: State, | ||
node: ImageReference | ||
): ElementContent | Array<ElementContent> | ||
export type ElementContent = import('hast').ElementContent | ||
export type Element = import('hast').Element | ||
export type Properties = import('hast').Properties | ||
export type ImageReference = import('mdast').ImageReference | ||
export type State = import('../state.js').State | ||
export function imageReference(state: State, node: ImageReference): Array<ElementContent> | ElementContent; | ||
export type Element = import('hast').Element; | ||
export type ElementContent = import('hast').ElementContent; | ||
export type Properties = import('hast').Properties; | ||
export type ImageReference = import('mdast').ImageReference; | ||
export type State = import('../state.js').State; |
/** | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {import('hast').ElementContent} ElementContent | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {import('hast').Properties} Properties | ||
@@ -19,7 +19,8 @@ * @typedef {import('mdast').ImageReference} ImageReference | ||
* mdast node. | ||
* @returns {ElementContent | Array<ElementContent>} | ||
* @returns {Array<ElementContent> | ElementContent} | ||
* hast node. | ||
*/ | ||
export function imageReference(state, node) { | ||
const def = state.definition(node.identifier) | ||
const id = String(node.identifier).toUpperCase() | ||
const def = state.definitionById.get(id) | ||
@@ -26,0 +27,0 @@ if (!def) { |
@@ -11,6 +11,6 @@ /** | ||
*/ | ||
export function image(state: State, node: Image): Element | ||
export type Element = import('hast').Element | ||
export type Properties = import('hast').Properties | ||
export type Image = import('mdast').Image | ||
export type State = import('../state.js').State | ||
export function image(state: State, node: Image): Element; | ||
export type Element = import('hast').Element; | ||
export type Properties = import('hast').Properties; | ||
export type Image = import('mdast').Image; | ||
export type State = import('../state.js').State; |
export namespace handlers { | ||
export {blockquote} | ||
export {hardBreak as break} | ||
export {code} | ||
export {strikethrough as delete} | ||
export {emphasis} | ||
export {footnoteReference} | ||
export {footnote} | ||
export {heading} | ||
export {html} | ||
export {imageReference} | ||
export {image} | ||
export {inlineCode} | ||
export {linkReference} | ||
export {link} | ||
export {listItem} | ||
export {list} | ||
export {paragraph} | ||
export {root} | ||
export {strong} | ||
export {table} | ||
export {tableCell} | ||
export {tableRow} | ||
export {text} | ||
export {thematicBreak} | ||
export {ignore as toml} | ||
export {ignore as yaml} | ||
export {ignore as definition} | ||
export {ignore as footnoteDefinition} | ||
export { blockquote }; | ||
export { hardBreak as break }; | ||
export { code }; | ||
export { strikethrough as delete }; | ||
export { emphasis }; | ||
export { footnoteReference }; | ||
export { heading }; | ||
export { html }; | ||
export { imageReference }; | ||
export { image }; | ||
export { inlineCode }; | ||
export { linkReference }; | ||
export { link }; | ||
export { listItem }; | ||
export { list }; | ||
export { paragraph }; | ||
export { root }; | ||
export { strong }; | ||
export { table }; | ||
export { tableCell }; | ||
export { tableRow }; | ||
export { text }; | ||
export { thematicBreak }; | ||
export { ignore as toml }; | ||
export { ignore as yaml }; | ||
export { ignore as definition }; | ||
export { ignore as footnoteDefinition }; | ||
} | ||
import {blockquote} from './blockquote.js' | ||
import {hardBreak} from './break.js' | ||
import {code} from './code.js' | ||
import {strikethrough} from './delete.js' | ||
import {emphasis} from './emphasis.js' | ||
import {footnoteReference} from './footnote-reference.js' | ||
import {footnote} from './footnote.js' | ||
import {heading} from './heading.js' | ||
import {html} from './html.js' | ||
import {imageReference} from './image-reference.js' | ||
import {image} from './image.js' | ||
import {inlineCode} from './inline-code.js' | ||
import {linkReference} from './link-reference.js' | ||
import {link} from './link.js' | ||
import {listItem} from './list-item.js' | ||
import {list} from './list.js' | ||
import {paragraph} from './paragraph.js' | ||
import {root} from './root.js' | ||
import {strong} from './strong.js' | ||
import {table} from './table.js' | ||
import {tableCell} from './table-cell.js' | ||
import {tableRow} from './table-row.js' | ||
import {text} from './text.js' | ||
import {thematicBreak} from './thematic-break.js' | ||
declare function ignore(): null | ||
export {} | ||
import { blockquote } from './blockquote.js'; | ||
import { hardBreak } from './break.js'; | ||
import { code } from './code.js'; | ||
import { strikethrough } from './delete.js'; | ||
import { emphasis } from './emphasis.js'; | ||
import { footnoteReference } from './footnote-reference.js'; | ||
import { heading } from './heading.js'; | ||
import { html } from './html.js'; | ||
import { imageReference } from './image-reference.js'; | ||
import { image } from './image.js'; | ||
import { inlineCode } from './inline-code.js'; | ||
import { linkReference } from './link-reference.js'; | ||
import { link } from './link.js'; | ||
import { listItem } from './list-item.js'; | ||
import { list } from './list.js'; | ||
import { paragraph } from './paragraph.js'; | ||
import { root } from './root.js'; | ||
import { strong } from './strong.js'; | ||
import { table } from './table.js'; | ||
import { tableCell } from './table-cell.js'; | ||
import { tableRow } from './table-row.js'; | ||
import { text } from './text.js'; | ||
import { thematicBreak } from './thematic-break.js'; | ||
declare function ignore(): undefined; | ||
export {}; |
@@ -7,3 +7,2 @@ import {blockquote} from './blockquote.js' | ||
import {footnoteReference} from './footnote-reference.js' | ||
import {footnote} from './footnote.js' | ||
import {heading} from './heading.js' | ||
@@ -29,2 +28,4 @@ import {html} from './html.js' | ||
* Default handlers for nodes. | ||
* | ||
* @satisfies {import('../state.js').Handlers} | ||
*/ | ||
@@ -38,3 +39,2 @@ export const handlers = { | ||
footnoteReference, | ||
footnote, | ||
heading, | ||
@@ -50,2 +50,3 @@ html, | ||
paragraph, | ||
// @ts-expect-error: root is different, but hard to type. | ||
root, | ||
@@ -66,4 +67,3 @@ strong, | ||
function ignore() { | ||
// To do: next major: return `undefined`. | ||
return null | ||
return undefined | ||
} |
/** | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {import('hast').Text} Text | ||
* @typedef {import('mdast').InlineCode} InlineCode | ||
* @typedef {import('../state.js').State} State | ||
*/ | ||
/** | ||
* Turn an mdast `inlineCode` node into hast. | ||
@@ -17,6 +11,6 @@ * | ||
*/ | ||
export function inlineCode(state: State, node: InlineCode): Element | ||
export type Element = import('hast').Element | ||
export type Text = import('hast').Text | ||
export type InlineCode = import('mdast').InlineCode | ||
export type State = import('../state.js').State | ||
export function inlineCode(state: State, node: InlineCode): Element; | ||
export type Element = import('hast').Element; | ||
export type Text = import('hast').Text; | ||
export type InlineCode = import('mdast').InlineCode; | ||
export type State = import('../state.js').State; |
@@ -8,2 +8,5 @@ /** | ||
// Make VS Code show references to the above types. | ||
'' | ||
/** | ||
@@ -10,0 +13,0 @@ * Turn an mdast `inlineCode` node into hast. |
@@ -8,13 +8,10 @@ /** | ||
* mdast node. | ||
* @returns {ElementContent | Array<ElementContent>} | ||
* @returns {Array<ElementContent> | ElementContent} | ||
* hast node. | ||
*/ | ||
export function linkReference( | ||
state: State, | ||
node: LinkReference | ||
): ElementContent | Array<ElementContent> | ||
export type Element = import('hast').Element | ||
export type ElementContent = import('hast').ElementContent | ||
export type Properties = import('hast').Properties | ||
export type LinkReference = import('mdast').LinkReference | ||
export type State = import('../state.js').State | ||
export function linkReference(state: State, node: LinkReference): Array<ElementContent> | ElementContent; | ||
export type Element = import('hast').Element; | ||
export type ElementContent = import('hast').ElementContent; | ||
export type Properties = import('hast').Properties; | ||
export type LinkReference = import('mdast').LinkReference; | ||
export type State = import('../state.js').State; |
@@ -19,7 +19,8 @@ /** | ||
* mdast node. | ||
* @returns {ElementContent | Array<ElementContent>} | ||
* @returns {Array<ElementContent> | ElementContent} | ||
* hast node. | ||
*/ | ||
export function linkReference(state, node) { | ||
const def = state.definition(node.identifier) | ||
const id = String(node.identifier).toUpperCase() | ||
const def = state.definitionById.get(id) | ||
@@ -26,0 +27,0 @@ if (!def) { |
@@ -11,6 +11,6 @@ /** | ||
*/ | ||
export function link(state: State, node: Link): Element | ||
export type Element = import('hast').Element | ||
export type Properties = import('hast').Properties | ||
export type Link = import('mdast').Link | ||
export type State = import('../state.js').State | ||
export function link(state: State, node: Link): Element; | ||
export type Element = import('hast').Element; | ||
export type Properties = import('hast').Properties; | ||
export type Link = import('mdast').Link; | ||
export type State = import('../state.js').State; |
/** | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {import('hast').ElementContent} ElementContent | ||
* @typedef {import('hast').Properties} Properties | ||
* @typedef {import('mdast').Content} Content | ||
* @typedef {import('mdast').ListItem} ListItem | ||
* @typedef {import('mdast').Parent} Parent | ||
* @typedef {import('mdast').Root} Root | ||
* @typedef {import('../state.js').State} State | ||
*/ | ||
/** | ||
* @typedef {Root | Content} Nodes | ||
* @typedef {Extract<Nodes, Parent>} Parents | ||
*/ | ||
/** | ||
* Turn an mdast `listItem` node into hast. | ||
@@ -22,3 +8,3 @@ * | ||
* mdast node. | ||
* @param {Parents | null | undefined} parent | ||
* @param {Parents | undefined} parent | ||
* Parent of `node`. | ||
@@ -28,16 +14,8 @@ * @returns {Element} | ||
*/ | ||
export function listItem( | ||
state: State, | ||
node: ListItem, | ||
parent: Parents | null | undefined | ||
): Element | ||
export type Element = import('hast').Element | ||
export type ElementContent = import('hast').ElementContent | ||
export type Properties = import('hast').Properties | ||
export type Content = import('mdast').Content | ||
export type ListItem = import('mdast').ListItem | ||
export type Parent = import('mdast').Parent | ||
export type Root = import('mdast').Root | ||
export type State = import('../state.js').State | ||
export type Nodes = Root | Content | ||
export type Parents = Extract<Nodes, Parent> | ||
export function listItem(state: State, node: ListItem, parent: Parents | undefined): Element; | ||
export type Element = import('hast').Element; | ||
export type ElementContent = import('hast').ElementContent; | ||
export type Properties = import('hast').Properties; | ||
export type ListItem = import('mdast').ListItem; | ||
export type Parents = import('mdast').Parents; | ||
export type State = import('../state.js').State; |
@@ -5,13 +5,9 @@ /** | ||
* @typedef {import('hast').Properties} Properties | ||
* @typedef {import('mdast').Content} Content | ||
* @typedef {import('mdast').ListItem} ListItem | ||
* @typedef {import('mdast').Parent} Parent | ||
* @typedef {import('mdast').Root} Root | ||
* @typedef {import('mdast').Parents} Parents | ||
* @typedef {import('../state.js').State} State | ||
*/ | ||
/** | ||
* @typedef {Root | Content} Nodes | ||
* @typedef {Extract<Nodes, Parent>} Parents | ||
*/ | ||
// Make VS Code show references to the above types. | ||
'' | ||
@@ -25,3 +21,3 @@ /** | ||
* mdast node. | ||
* @param {Parents | null | undefined} parent | ||
* @param {Parents | undefined} parent | ||
* Parent of `node`. | ||
@@ -128,5 +124,5 @@ * @returns {Element} | ||
return spread === undefined || spread === null | ||
return spread === null || spread === undefined | ||
? node.children.length > 1 | ||
: spread | ||
} |
/** | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {import('hast').Properties} Properties | ||
* @typedef {import('mdast').List} List | ||
* @typedef {import('../state.js').State} State | ||
*/ | ||
/** | ||
* Turn an mdast `list` node into hast. | ||
@@ -17,6 +11,6 @@ * | ||
*/ | ||
export function list(state: State, node: List): Element | ||
export type Element = import('hast').Element | ||
export type Properties = import('hast').Properties | ||
export type List = import('mdast').List | ||
export type State = import('../state.js').State | ||
export function list(state: State, node: List): Element; | ||
export type Element = import('hast').Element; | ||
export type Properties = import('hast').Properties; | ||
export type List = import('mdast').List; | ||
export type State = import('../state.js').State; |
@@ -8,2 +8,5 @@ /** | ||
// Make VS Code show references to the above types. | ||
'' | ||
/** | ||
@@ -10,0 +13,0 @@ * Turn an mdast `list` node into hast. |
/** | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {import('mdast').Paragraph} Paragraph | ||
* @typedef {import('../state.js').State} State | ||
*/ | ||
/** | ||
* Turn an mdast `paragraph` node into hast. | ||
@@ -16,5 +11,5 @@ * | ||
*/ | ||
export function paragraph(state: State, node: Paragraph): Element | ||
export type Element = import('hast').Element | ||
export type Paragraph = import('mdast').Paragraph | ||
export type State = import('../state.js').State | ||
export function paragraph(state: State, node: Paragraph): Element; | ||
export type Element = import('hast').Element; | ||
export type Paragraph = import('mdast').Paragraph; | ||
export type State = import('../state.js').State; |
@@ -7,2 +7,5 @@ /** | ||
// Make VS Code show references to the above types. | ||
'' | ||
/** | ||
@@ -9,0 +12,0 @@ * Turn an mdast `paragraph` node into hast. |
/** | ||
* @typedef {import('hast').Root} HastRoot | ||
* @typedef {import('hast').Element} HastElement | ||
* @typedef {import('mdast').Root} MdastRoot | ||
* @typedef {import('../state.js').State} State | ||
*/ | ||
/** | ||
* Turn an mdast `root` node into hast. | ||
@@ -14,9 +8,9 @@ * | ||
* mdast node. | ||
* @returns {HastRoot | HastElement} | ||
* @returns {HastParents} | ||
* hast node. | ||
*/ | ||
export function root(state: State, node: MdastRoot): HastRoot | HastElement | ||
export type HastRoot = import('hast').Root | ||
export type HastElement = import('hast').Element | ||
export type MdastRoot = import('mdast').Root | ||
export type State = import('../state.js').State | ||
export function root(state: State, node: MdastRoot): HastParents; | ||
export type HastParents = import('hast').Parents; | ||
export type HastRoot = import('hast').Root; | ||
export type MdastRoot = import('mdast').Root; | ||
export type State = import('../state.js').State; |
/** | ||
* @typedef {import('hast').Parents} HastParents | ||
* @typedef {import('hast').Root} HastRoot | ||
* @typedef {import('hast').Element} HastElement | ||
* @typedef {import('mdast').Root} MdastRoot | ||
@@ -8,2 +8,5 @@ * @typedef {import('../state.js').State} State | ||
// Make VS Code show references to the above types. | ||
'' | ||
/** | ||
@@ -16,3 +19,3 @@ * Turn an mdast `root` node into hast. | ||
* mdast node. | ||
* @returns {HastRoot | HastElement} | ||
* @returns {HastParents} | ||
* hast node. | ||
@@ -19,0 +22,0 @@ */ |
/** | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {import('mdast').Strong} Strong | ||
* @typedef {import('../state.js').State} State | ||
*/ | ||
/** | ||
* Turn an mdast `strong` node into hast. | ||
@@ -16,5 +11,5 @@ * | ||
*/ | ||
export function strong(state: State, node: Strong): Element | ||
export type Element = import('hast').Element | ||
export type Strong = import('mdast').Strong | ||
export type State = import('../state.js').State | ||
export function strong(state: State, node: Strong): Element; | ||
export type Element = import('hast').Element; | ||
export type Strong = import('mdast').Strong; | ||
export type State = import('../state.js').State; |
@@ -7,2 +7,5 @@ /** | ||
// Make VS Code show references to the above types. | ||
'' | ||
/** | ||
@@ -9,0 +12,0 @@ * Turn an mdast `strong` node into hast. |
/** | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {import('mdast').TableCell} TableCell | ||
* @typedef {import('../state.js').State} State | ||
*/ | ||
/** | ||
* Turn an mdast `tableCell` node into hast. | ||
@@ -16,5 +11,5 @@ * | ||
*/ | ||
export function tableCell(state: State, node: TableCell): Element | ||
export type Element = import('hast').Element | ||
export type TableCell = import('mdast').TableCell | ||
export type State = import('../state.js').State | ||
export function tableCell(state: State, node: TableCell): Element; | ||
export type Element = import('hast').Element; | ||
export type TableCell = import('mdast').TableCell; | ||
export type State = import('../state.js').State; |
@@ -7,2 +7,5 @@ /** | ||
// Make VS Code show references to the above types. | ||
'' | ||
/** | ||
@@ -9,0 +12,0 @@ * Turn an mdast `tableCell` node into hast. |
/** | ||
* @typedef {import('hast').Properties} Properties | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {import('hast').ElementContent} ElementContent | ||
* @typedef {import('mdast').Content} Content | ||
* @typedef {import('mdast').Parent} Parent | ||
* @typedef {import('mdast').Root} Root | ||
* @typedef {import('mdast').TableRow} TableRow | ||
* @typedef {import('../state.js').State} State | ||
*/ | ||
/** | ||
* @typedef {Root | Content} Nodes | ||
* @typedef {Extract<Nodes, Parent>} Parents | ||
*/ | ||
/** | ||
* Turn an mdast `tableRow` node into hast. | ||
@@ -22,3 +8,3 @@ * | ||
* mdast node. | ||
* @param {Parents | null | undefined} parent | ||
* @param {Parents | undefined} parent | ||
* Parent of `node`. | ||
@@ -28,16 +14,8 @@ * @returns {Element} | ||
*/ | ||
export function tableRow( | ||
state: State, | ||
node: TableRow, | ||
parent: Parents | null | undefined | ||
): Element | ||
export type Properties = import('hast').Properties | ||
export type Element = import('hast').Element | ||
export type ElementContent = import('hast').ElementContent | ||
export type Content = import('mdast').Content | ||
export type Parent = import('mdast').Parent | ||
export type Root = import('mdast').Root | ||
export type TableRow = import('mdast').TableRow | ||
export type State = import('../state.js').State | ||
export type Nodes = Root | Content | ||
export type Parents = Extract<Nodes, Parent> | ||
export function tableRow(state: State, node: TableRow, parent: Parents | undefined): Element; | ||
export type Element = import('hast').Element; | ||
export type ElementContent = import('hast').ElementContent; | ||
export type Properties = import('hast').Properties; | ||
export type Parents = import('mdast').Parents; | ||
export type TableRow = import('mdast').TableRow; | ||
export type State = import('../state.js').State; |
/** | ||
* @typedef {import('hast').Properties} Properties | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {import('hast').ElementContent} ElementContent | ||
* @typedef {import('mdast').Content} Content | ||
* @typedef {import('mdast').Parent} Parent | ||
* @typedef {import('mdast').Root} Root | ||
* @typedef {import('hast').Properties} Properties | ||
* @typedef {import('mdast').Parents} Parents | ||
* @typedef {import('mdast').TableRow} TableRow | ||
@@ -12,6 +10,4 @@ * @typedef {import('../state.js').State} State | ||
/** | ||
* @typedef {Root | Content} Nodes | ||
* @typedef {Extract<Nodes, Parent>} Parents | ||
*/ | ||
// Make VS Code show references to the above types. | ||
'' | ||
@@ -25,3 +21,3 @@ /** | ||
* mdast node. | ||
* @param {Parents | null | undefined} parent | ||
* @param {Parents | undefined} parent | ||
* Parent of `node`. | ||
@@ -36,2 +32,3 @@ * @returns {Element} | ||
const tagName = rowIndex === 0 ? 'th' : 'td' | ||
// To do: option to use `style`? | ||
const align = parent && parent.type === 'table' ? parent.align : undefined | ||
@@ -38,0 +35,0 @@ const length = align ? align.length : node.children.length |
@@ -11,5 +11,5 @@ /** | ||
*/ | ||
export function table(state: State, node: Table): Element | ||
export type Element = import('hast').Element | ||
export type Table = import('mdast').Table | ||
export type State = import('../state.js').State | ||
export function table(state: State, node: Table): Element; | ||
export type Element = import('hast').Element; | ||
export type Table = import('mdast').Table; | ||
export type State = import('../state.js').State; |
@@ -7,3 +7,3 @@ /** | ||
import {pointStart, pointEnd} from 'unist-util-position' | ||
import {pointEnd, pointStart} from 'unist-util-position' | ||
@@ -49,3 +49,3 @@ /** | ||
const end = pointEnd(node.children[node.children.length - 1]) | ||
if (start.line && end.line) body.position = {start, end} | ||
if (start && end) body.position = {start, end} | ||
tableContent.push(body) | ||
@@ -52,0 +52,0 @@ } |
@@ -8,9 +8,9 @@ /** | ||
* mdast node. | ||
* @returns {HastText | HastElement} | ||
* @returns {HastElement | HastText} | ||
* hast node. | ||
*/ | ||
export function text(state: State, node: MdastText): HastText | HastElement | ||
export type HastElement = import('hast').Element | ||
export type HastText = import('hast').Text | ||
export type MdastText = import('mdast').Text | ||
export type State = import('../state.js').State | ||
export function text(state: State, node: MdastText): HastElement | HastText; | ||
export type HastElement = import('hast').Element; | ||
export type HastText = import('hast').Text; | ||
export type MdastText = import('mdast').Text; | ||
export type State = import('../state.js').State; |
@@ -17,3 +17,3 @@ /** | ||
* mdast node. | ||
* @returns {HastText | HastElement} | ||
* @returns {HastElement | HastText} | ||
* hast node. | ||
@@ -20,0 +20,0 @@ */ |
/** | ||
* @typedef {import('hast').Element} Element | ||
* @typedef {import('mdast').ThematicBreak} ThematicBreak | ||
* @typedef {import('../state.js').State} State | ||
*/ | ||
/** | ||
* Turn an mdast `thematicBreak` node into hast. | ||
@@ -16,5 +11,5 @@ * | ||
*/ | ||
export function thematicBreak(state: State, node: ThematicBreak): Element | ||
export type Element = import('hast').Element | ||
export type ThematicBreak = import('mdast').ThematicBreak | ||
export type State = import('../state.js').State | ||
export function thematicBreak(state: State, node: ThematicBreak): Element; | ||
export type Element = import('hast').Element; | ||
export type ThematicBreak = import('mdast').ThematicBreak; | ||
export type State = import('../state.js').State; |
@@ -7,2 +7,5 @@ /** | ||
// Make VS Code show references to the above types. | ||
'' | ||
/** | ||
@@ -9,0 +12,0 @@ * Turn an mdast `thematicBreak` node into hast. |
@@ -74,16 +74,9 @@ /** | ||
* @param {Options | null | undefined} [options] | ||
* Configuration. | ||
* @returns {HastNodes | null | undefined} | ||
* Configuration (optional). | ||
* @returns {HastNodes} | ||
* hast tree. | ||
*/ | ||
export function toHast( | ||
tree: MdastNodes, | ||
options?: Options | null | undefined | ||
): HastNodes | null | undefined | ||
export type HastContent = import('hast').Content | ||
export type HastRoot = import('hast').Root | ||
export type MdastContent = import('mdast').Content | ||
export type MdastRoot = import('mdast').Root | ||
export type Options = import('./state.js').Options | ||
export type HastNodes = HastRoot | HastContent | ||
export type MdastNodes = MdastRoot | MdastContent | ||
export function toHast(tree: MdastNodes, options?: Options | null | undefined): HastNodes; | ||
export type HastNodes = import('hast').Nodes; | ||
export type MdastNodes = import('mdast').Nodes; | ||
export type Options = import('./state.js').Options; |
/** | ||
* @typedef {import('hast').Content} HastContent | ||
* @typedef {import('hast').Root} HastRoot | ||
* | ||
* @typedef {import('mdast').Content} MdastContent | ||
* @typedef {import('mdast').Root} MdastRoot | ||
* | ||
* @typedef {import('hast').Nodes} HastNodes | ||
* @typedef {import('mdast').Nodes} MdastNodes | ||
* @typedef {import('./state.js').Options} Options | ||
*/ | ||
/** | ||
* @typedef {HastRoot | HastContent} HastNodes | ||
* @typedef {MdastRoot | MdastContent} MdastNodes | ||
*/ | ||
import {ok as assert} from 'devlop' | ||
import {footer} from './footer.js' | ||
@@ -92,21 +84,24 @@ import {createState} from './state.js' | ||
* @param {Options | null | undefined} [options] | ||
* Configuration. | ||
* @returns {HastNodes | null | undefined} | ||
* Configuration (optional). | ||
* @returns {HastNodes} | ||
* hast tree. | ||
*/ | ||
// To do: next major: always return a single `root`. | ||
export function toHast(tree, options) { | ||
const state = createState(tree, options) | ||
const node = state.one(tree, null) | ||
const node = state.one(tree, undefined) | ||
const foot = footer(state) | ||
/** @type {HastNodes} */ | ||
const result = Array.isArray(node) | ||
? {type: 'root', children: node} | ||
: node || {type: 'root', children: []} | ||
if (foot) { | ||
// @ts-expect-error If there’s a footer, there were definitions, meaning block | ||
// If there’s a footer, there were definitions, meaning block | ||
// content. | ||
// So assume `node` is a parent node. | ||
node.children.push({type: 'text', value: '\n'}, foot) | ||
// So `result` is a parent node. | ||
assert('children' in result) | ||
result.children.push({type: 'text', value: '\n'}, foot) | ||
} | ||
// To do: next major: always return root? | ||
return Array.isArray(node) ? {type: 'root', children: node} : node | ||
return result | ||
} |
/** | ||
* @typedef {import('hast').ElementContent} ElementContent | ||
* | ||
* @typedef {import('mdast').Content} Content | ||
* @typedef {import('mdast').Reference} Reference | ||
* @typedef {import('mdast').Root} Root | ||
* | ||
* @typedef {import('./state.js').State} State | ||
*/ | ||
/** | ||
* @typedef {Root | Content} Nodes | ||
* @typedef {Extract<Nodes, Reference>} References | ||
*/ | ||
/** | ||
* Return the content of a reference without definition as plain text. | ||
@@ -19,17 +6,11 @@ * | ||
* Info passed around. | ||
* @param {References} node | ||
* @param {Extract<Nodes, Reference>} node | ||
* Reference node (image, link). | ||
* @returns {ElementContent | Array<ElementContent>} | ||
* @returns {Array<ElementContent>} | ||
* hast content. | ||
*/ | ||
export function revert( | ||
state: State, | ||
node: References | ||
): ElementContent | Array<ElementContent> | ||
export type ElementContent = import('hast').ElementContent | ||
export type Content = import('mdast').Content | ||
export type Reference = import('mdast').Reference | ||
export type Root = import('mdast').Root | ||
export type State = import('./state.js').State | ||
export type Nodes = Root | Content | ||
export type References = Extract<Nodes, Reference> | ||
export function revert(state: State, node: Extract<Nodes, Reference>): Array<ElementContent>; | ||
export type ElementContent = import('hast').ElementContent; | ||
export type Nodes = import('mdast').Nodes; | ||
export type Reference = import('mdast').Reference; | ||
export type State = import('./state.js').State; |
/** | ||
* @typedef {import('hast').ElementContent} ElementContent | ||
* | ||
* @typedef {import('mdast').Content} Content | ||
* @typedef {import('mdast').Nodes} Nodes | ||
* @typedef {import('mdast').Reference} Reference | ||
* @typedef {import('mdast').Root} Root | ||
* | ||
@@ -11,9 +10,5 @@ * @typedef {import('./state.js').State} State | ||
/** | ||
* @typedef {Root | Content} Nodes | ||
* @typedef {Extract<Nodes, Reference>} References | ||
*/ | ||
// Make VS Code show references to the above types. | ||
'' | ||
// To do: next major: always return array. | ||
/** | ||
@@ -24,5 +19,5 @@ * Return the content of a reference without definition as plain text. | ||
* Info passed around. | ||
* @param {References} node | ||
* @param {Extract<Nodes, Reference>} node | ||
* Reference node (image, link). | ||
* @returns {ElementContent | Array<ElementContent>} | ||
* @returns {Array<ElementContent>} | ||
* hast content. | ||
@@ -41,3 +36,3 @@ */ | ||
if (node.type === 'imageReference') { | ||
return {type: 'text', value: '![' + node.alt + suffix} | ||
return [{type: 'text', value: '![' + node.alt + suffix}] | ||
} | ||
@@ -44,0 +39,0 @@ |
@@ -7,297 +7,222 @@ /** | ||
* @param {Options | null | undefined} [options] | ||
* Configuration. | ||
* Configuration (optional). | ||
* @returns {State} | ||
* `state` function. | ||
*/ | ||
export function createState( | ||
tree: MdastNodes, | ||
options?: Options | null | undefined | ||
): State | ||
export function createState(tree: MdastNodes, options?: Options | null | undefined): State; | ||
/** | ||
* Transform an mdast node into a hast node. | ||
* | ||
* @param {State} state | ||
* Info passed around. | ||
* @param {MdastNodes} node | ||
* mdast node. | ||
* @param {MdastParents | null | undefined} [parent] | ||
* Parent of `node`. | ||
* @returns {HastElementContent | Array<HastElementContent> | null | undefined} | ||
* Resulting hast node. | ||
*/ | ||
export function one( | ||
state: State, | ||
node: MdastNodes, | ||
parent?: MdastParents | null | undefined | ||
): HastElementContent | Array<HastElementContent> | null | undefined | ||
/** | ||
* Transform the children of an mdast node into hast nodes. | ||
* | ||
* @param {State} state | ||
* Info passed around. | ||
* @param {MdastNodes} parent | ||
* mdast node to compile | ||
* @returns {Array<HastElementContent>} | ||
* Resulting hast nodes. | ||
*/ | ||
export function all(state: State, parent: MdastNodes): Array<HastElementContent> | ||
/** | ||
* Wrap `nodes` with line endings between each node. | ||
* | ||
* @template {HastContent} Type | ||
* @template {HastRootContent} Type | ||
* Node type. | ||
* @param {Array<Type>} nodes | ||
* List of nodes to wrap. | ||
* @param {boolean | null | undefined} [loose=false] | ||
* Whether to add line endings at start and end. | ||
* @returns {Array<Type | HastText>} | ||
* @param {boolean | undefined} [loose=false] | ||
* Whether to add line endings at start and end (default: `false`). | ||
* @returns {Array<HastText | Type>} | ||
* Wrapped nodes. | ||
*/ | ||
export function wrap<Type extends import('hast').Content>( | ||
nodes: Type[], | ||
loose?: boolean | null | undefined | ||
): (import('hast').Text | Type)[] | ||
export type HastContent = import('hast').Content | ||
export type HastElement = import('hast').Element | ||
export type HastElementContent = import('hast').ElementContent | ||
export type HastProperties = import('hast').Properties | ||
export type HastRoot = import('hast').Root | ||
export type HastText = import('hast').Text | ||
export type MdastContent = import('mdast').Content | ||
export type MdastDefinition = import('mdast').Definition | ||
export type MdastFootnoteDefinition = import('mdast').FootnoteDefinition | ||
export type MdastParent = import('mdast').Parent | ||
export type MdastRoot = import('mdast').Root | ||
export type HastNodes = HastRoot | HastContent | ||
export type MdastNodes = MdastRoot | MdastContent | ||
export type MdastParents = Extract<MdastNodes, MdastParent> | ||
export function wrap<Type extends import("hast").RootContent>(nodes: Type[], loose?: boolean | undefined): (import("hast").Text | Type)[]; | ||
export type HastElement = import('hast').Element; | ||
export type HastElementContent = import('hast').ElementContent; | ||
export type HastNodes = import('hast').Nodes; | ||
export type HastProperties = import('hast').Properties; | ||
export type HastRootContent = import('hast').RootContent; | ||
export type HastText = import('hast').Text; | ||
export type MdastDefinition = import('mdast').Definition; | ||
export type MdastFootnoteDefinition = import('mdast').FootnoteDefinition; | ||
export type MdastNodes = import('mdast').Nodes; | ||
export type MdastParents = import('mdast').Parents; | ||
export type FootnoteBackContentTemplate = import('./footer.js').FootnoteBackContentTemplate; | ||
export type FootnoteBackLabelTemplate = import('./footer.js').FootnoteBackLabelTemplate; | ||
/** | ||
* hast fields. | ||
*/ | ||
export type EmbeddedHastFields = { | ||
/** | ||
* Generate a specific element with this tag name instead. | ||
*/ | ||
hName?: string | null | undefined | ||
/** | ||
* Generate an element with these properties instead. | ||
*/ | ||
hProperties?: HastProperties | null | undefined | ||
/** | ||
* Generate an element with this content instead. | ||
*/ | ||
hChildren?: Array<HastElementContent> | null | undefined | ||
} | ||
/** | ||
* mdast data with embedded hast fields. | ||
*/ | ||
export type MdastData = Record<string, unknown> & EmbeddedHastFields | ||
/** | ||
* mdast node with embedded hast data. | ||
*/ | ||
export type MdastNodeWithData = MdastNodes & { | ||
data?: MdastData | null | undefined | ||
} | ||
/** | ||
* Point-like value. | ||
*/ | ||
export type PointLike = { | ||
/** | ||
* Line. | ||
*/ | ||
line?: number | null | undefined | ||
/** | ||
* Column. | ||
*/ | ||
column?: number | null | undefined | ||
/** | ||
* Offset. | ||
*/ | ||
offset?: number | null | undefined | ||
} | ||
/** | ||
* Position-like value. | ||
*/ | ||
export type PositionLike = { | ||
/** | ||
* Point-like value. | ||
*/ | ||
start?: PointLike | null | undefined | ||
/** | ||
* Point-like value. | ||
*/ | ||
end?: PointLike | null | undefined | ||
} | ||
/** | ||
* Handle a node. | ||
*/ | ||
export type Handler = ( | ||
state: State, | ||
node: any, | ||
parent: MdastParents | null | undefined | ||
) => HastElementContent | Array<HastElementContent> | null | undefined | ||
export type Handler = (state: State, node: any, parent: MdastParents | undefined) => Array<HastElementContent> | HastElementContent | undefined; | ||
/** | ||
* Signature of `state` for when props are passed. | ||
* Handle nodes. | ||
*/ | ||
export type HFunctionProps = ( | ||
node: MdastNodes | PositionLike | null | undefined, | ||
tagName: string, | ||
props: HastProperties, | ||
children?: Array<HastElementContent> | null | undefined | ||
) => HastElement | ||
export type Handlers = Partial<Record<MdastNodes['type'], Handler>>; | ||
/** | ||
* Signature of `state` for when no props are passed. | ||
*/ | ||
export type HFunctionNoProps = ( | ||
node: MdastNodes | PositionLike | null | undefined, | ||
tagName: string, | ||
children?: Array<HastElementContent> | null | undefined | ||
) => HastElement | ||
/** | ||
* Info on `state`. | ||
*/ | ||
export type HFields = { | ||
/** | ||
* Whether HTML is allowed. | ||
*/ | ||
dangerous: boolean | ||
/** | ||
* Prefix to use to prevent DOM clobbering. | ||
*/ | ||
clobberPrefix: string | ||
/** | ||
* Label to use to introduce the footnote section. | ||
*/ | ||
footnoteLabel: string | ||
/** | ||
* HTML used for the footnote label. | ||
*/ | ||
footnoteLabelTagName: string | ||
/** | ||
* Properties on the HTML tag used for the footnote label. | ||
*/ | ||
footnoteLabelProperties: HastProperties | ||
/** | ||
* Label to use from backreferences back to their footnote call. | ||
*/ | ||
footnoteBackLabel: string | ||
/** | ||
* Definition cache. | ||
*/ | ||
definition: (identifier: string) => MdastDefinition | null | ||
/** | ||
* Footnote definitions by their identifier. | ||
*/ | ||
footnoteById: Record<string, MdastFootnoteDefinition> | ||
/** | ||
* Identifiers of order when footnote calls first appear in tree order. | ||
*/ | ||
footnoteOrder: Array<string> | ||
/** | ||
* Counts for how often the same footnote was called. | ||
*/ | ||
footnoteCounts: Record<string, number> | ||
/** | ||
* Applied handlers. | ||
*/ | ||
handlers: Handlers | ||
/** | ||
* Handler for any none not in `passThrough` or otherwise handled. | ||
*/ | ||
unknownHandler: Handler | ||
/** | ||
* Copy a node’s positional info. | ||
*/ | ||
patch: (from: MdastNodes, node: HastNodes) => void | ||
/** | ||
* Honor the `data` of `from`, and generate an element instead of `node`. | ||
*/ | ||
applyData: <Type extends HastNodes>( | ||
from: MdastNodes, | ||
to: Type | ||
) => import('hast').Element | Type | ||
/** | ||
* Transform an mdast node to hast. | ||
*/ | ||
one: ( | ||
node: MdastNodes, | ||
parent: MdastParents | null | undefined | ||
) => HastElementContent | Array<HastElementContent> | null | undefined | ||
/** | ||
* Transform the children of an mdast parent to hast. | ||
*/ | ||
all: (node: MdastNodes) => Array<HastElementContent> | ||
/** | ||
* Wrap `nodes` with line endings between each node, adds initial/final line endings when `loose`. | ||
*/ | ||
wrap: <Type_1 extends import('hast').Content>( | ||
nodes: Type_1[], | ||
loose?: boolean | null | undefined | ||
) => (Type_1 | import('hast').Text)[] | ||
/** | ||
* Like `state` but lower-level and usable on non-elements. | ||
* Deprecated: use `patch` and `applyData`. | ||
*/ | ||
augment: ( | ||
left: MdastNodeWithData | PositionLike | null | undefined, | ||
right: HastElementContent | ||
) => HastElementContent | ||
/** | ||
* List of node types to pass through untouched (except for their children). | ||
*/ | ||
passThrough: Array<string> | ||
} | ||
/** | ||
* Configuration (optional). | ||
*/ | ||
export type Options = { | ||
/** | ||
* Whether to persist raw HTML in markdown in the hast tree. | ||
*/ | ||
allowDangerousHtml?: boolean | null | undefined | ||
/** | ||
* Prefix to use before the `id` attribute on footnotes to prevent it from | ||
* *clobbering*. | ||
*/ | ||
clobberPrefix?: string | null | undefined | ||
/** | ||
* Label to use from backreferences back to their footnote call (affects | ||
* screen readers). | ||
*/ | ||
footnoteBackLabel?: string | null | undefined | ||
/** | ||
* Label to use for the footnotes section (affects screen readers). | ||
*/ | ||
footnoteLabel?: string | null | undefined | ||
/** | ||
* Properties to use on the footnote label (note that `id: 'footnote-label'` | ||
* is always added as footnote calls use it with `aria-describedby` to | ||
* provide an accessible label). | ||
*/ | ||
footnoteLabelProperties?: HastProperties | null | undefined | ||
/** | ||
* Tag name to use for the footnote label. | ||
*/ | ||
footnoteLabelTagName?: string | null | undefined | ||
/** | ||
* Extra handlers for nodes. | ||
*/ | ||
handlers?: Handlers | null | undefined | ||
/** | ||
* List of custom mdast node types to pass through (keep) in hast (note that | ||
* the node itself is passed, but eventual children are transformed). | ||
*/ | ||
passThrough?: Array<string> | null | undefined | ||
/** | ||
* Handler for all unknown nodes. | ||
*/ | ||
unknownHandler?: Handler | null | undefined | ||
} | ||
/** | ||
* Whether to persist raw HTML in markdown in the hast tree (default: | ||
* `false`). | ||
*/ | ||
allowDangerousHtml?: boolean | null | undefined; | ||
/** | ||
* Prefix to use before the `id` property on footnotes to prevent them from | ||
* *clobbering* (default: `'user-content-'`). | ||
* | ||
* Pass `''` for trusted markdown and when you are careful with | ||
* polyfilling. | ||
* You could pass a different prefix. | ||
* | ||
* DOM clobbering is this: | ||
* | ||
* ```html | ||
* <p id="x"></p> | ||
* <script>alert(x) // `x` now refers to the `p#x` DOM element</script> | ||
* ``` | ||
* | ||
* The above example shows that elements are made available by browsers, by | ||
* their ID, on the `window` object. | ||
* This is a security risk because you might be expecting some other variable | ||
* at that place. | ||
* It can also break polyfills. | ||
* Using a prefix solves these problems. | ||
*/ | ||
clobberPrefix?: string | null | undefined; | ||
/** | ||
* Content of the backreference back to references (default: `defaultFootnoteBackContent`). | ||
* | ||
* The default value is: | ||
* | ||
* ```js | ||
* function defaultFootnoteBackContent(_, rereferenceIndex) { | ||
* const result = [{type: 'text', value: '↩'}] | ||
* | ||
* if (rereferenceIndex > 1) { | ||
* result.push({ | ||
* type: 'element', | ||
* tagName: 'sup', | ||
* properties: {}, | ||
* children: [{type: 'text', value: String(rereferenceIndex)}] | ||
* }) | ||
* } | ||
* | ||
* return result | ||
* } | ||
* ``` | ||
* | ||
* This content is used in the `a` element of each backreference (the `↩` | ||
* links). | ||
*/ | ||
footnoteBackContent?: FootnoteBackContentTemplate | string | null | undefined; | ||
/** | ||
* Label to describe the backreference back to references (default: | ||
* `defaultFootnoteBackLabel`). | ||
* | ||
* The default value is: | ||
* | ||
* ```js | ||
* function defaultFootnoteBackLabel(referenceIndex, rereferenceIndex) { | ||
* return ( | ||
* 'Back to reference ' + | ||
* (referenceIndex + 1) + | ||
* (rereferenceIndex > 1 ? '-' + rereferenceIndex : '') | ||
* ) | ||
* } | ||
* ``` | ||
* | ||
* Change it when the markdown is not in English. | ||
* | ||
* This label is used in the `ariaLabel` property on each backreference | ||
* (the `↩` links). | ||
* It affects users of assistive technology. | ||
*/ | ||
footnoteBackLabel?: FootnoteBackLabelTemplate | string | null | undefined; | ||
/** | ||
* Textual label to use for the footnotes section (default: `'Footnotes'`). | ||
* | ||
* Change it when the markdown is not in English. | ||
* | ||
* This label is typically hidden visually (assuming a `sr-only` CSS class | ||
* is defined that does that) and so affects screen readers only. | ||
* If you do have such a class, but want to show this section to everyone, | ||
* pass different properties with the `footnoteLabelProperties` option. | ||
*/ | ||
footnoteLabel?: string | null | undefined; | ||
/** | ||
* Properties to use on the footnote label (default: `{className: | ||
* ['sr-only']}`). | ||
* | ||
* Change it to show the label and add other properties. | ||
* | ||
* This label is typically hidden visually (assuming an `sr-only` CSS class | ||
* is defined that does that) and so affects screen readers only. | ||
* If you do have such a class, but want to show this section to everyone, | ||
* pass an empty string. | ||
* You can also add different properties. | ||
* | ||
* > 👉 **Note**: `id: 'footnote-label'` is always added, because footnote | ||
* > calls use it with `aria-describedby` to provide an accessible label. | ||
*/ | ||
footnoteLabelProperties?: HastProperties | null | undefined; | ||
/** | ||
* HTML tag name to use for the footnote label element (default: `'h2'`). | ||
* | ||
* Change it to match your document structure. | ||
* | ||
* This label is typically hidden visually (assuming a `sr-only` CSS class | ||
* is defined that does that) and so affects screen readers only. | ||
* If you do have such a class, but want to show this section to everyone, | ||
* pass different properties with the `footnoteLabelProperties` option. | ||
*/ | ||
footnoteLabelTagName?: string | null | undefined; | ||
/** | ||
* Extra handlers for nodes (optional). | ||
*/ | ||
handlers?: Handlers | null | undefined; | ||
/** | ||
* List of custom mdast node types to pass through (keep) in hast (note that | ||
* the node itself is passed, but eventual children are transformed) | ||
* (optional). | ||
*/ | ||
passThrough?: Array<MdastNodes['type']> | null | undefined; | ||
/** | ||
* Handler for all unknown nodes (optional). | ||
*/ | ||
unknownHandler?: Handler | null | undefined; | ||
}; | ||
/** | ||
* Handle nodes. | ||
*/ | ||
export type Handlers = Record<string, Handler> | ||
/** | ||
* Info passed around. | ||
*/ | ||
export type State = HFunctionProps & HFunctionNoProps & HFields | ||
export type State = { | ||
/** | ||
* Transform the children of an mdast parent to hast. | ||
*/ | ||
all: (node: MdastNodes) => Array<HastElementContent>; | ||
/** | ||
* Honor the `data` of `from`, and generate an element instead of `node`. | ||
*/ | ||
applyData: <Type extends import("hast").Nodes>(from: MdastNodes, to: Type) => import("hast").Element | Type; | ||
/** | ||
* Definitions by their identifier. | ||
*/ | ||
definitionById: Map<string, MdastDefinition>; | ||
/** | ||
* Footnote definitions by their identifier. | ||
*/ | ||
footnoteById: Map<string, MdastFootnoteDefinition>; | ||
/** | ||
* Counts for how often the same footnote was called. | ||
*/ | ||
footnoteCounts: Map<string, number>; | ||
/** | ||
* Identifiers of order when footnote calls first appear in tree order. | ||
*/ | ||
footnoteOrder: Array<string>; | ||
/** | ||
* Applied handlers. | ||
*/ | ||
handlers: Handlers; | ||
/** | ||
* Transform an mdast node to hast. | ||
*/ | ||
one: (node: MdastNodes, parent: MdastParents | undefined) => Array<HastElementContent> | HastElementContent | undefined; | ||
/** | ||
* Configuration. | ||
*/ | ||
options: Options; | ||
/** | ||
* Copy a node’s positional info. | ||
*/ | ||
patch: (from: MdastNodes, node: HastNodes) => undefined; | ||
/** | ||
* Wrap `nodes` with line endings between each node, adds initial/final line endings when `loose`. | ||
*/ | ||
wrap: <Type_1 extends import("hast").RootContent>(nodes: Type_1[], loose?: boolean | undefined) => (import("hast").Text | Type_1)[]; | ||
}; |
636
lib/state.js
/** | ||
* @typedef {import('hast').Content} HastContent | ||
* @typedef {import('hast').Element} HastElement | ||
* @typedef {import('hast').ElementContent} HastElementContent | ||
* @typedef {import('hast').Nodes} HastNodes | ||
* @typedef {import('hast').Properties} HastProperties | ||
* @typedef {import('hast').Root} HastRoot | ||
* @typedef {import('hast').RootContent} HastRootContent | ||
* @typedef {import('hast').Text} HastText | ||
* | ||
* @typedef {import('mdast').Content} MdastContent | ||
* @typedef {import('mdast').Definition} MdastDefinition | ||
* @typedef {import('mdast').FootnoteDefinition} MdastFootnoteDefinition | ||
* @typedef {import('mdast').Parent} MdastParent | ||
* @typedef {import('mdast').Root} MdastRoot | ||
* @typedef {import('mdast').Nodes} MdastNodes | ||
* @typedef {import('mdast').Parents} MdastParents | ||
* | ||
* @typedef {import('./footer.js').FootnoteBackContentTemplate} FootnoteBackContentTemplate | ||
* @typedef {import('./footer.js').FootnoteBackLabelTemplate} FootnoteBackLabelTemplate | ||
*/ | ||
/** | ||
* @typedef {HastRoot | HastContent} HastNodes | ||
* @typedef {MdastRoot | MdastContent} MdastNodes | ||
* @typedef {Extract<MdastNodes, MdastParent>} MdastParents | ||
* | ||
* @typedef EmbeddedHastFields | ||
* hast fields. | ||
* @property {string | null | undefined} [hName] | ||
* Generate a specific element with this tag name instead. | ||
* @property {HastProperties | null | undefined} [hProperties] | ||
* Generate an element with these properties instead. | ||
* @property {Array<HastElementContent> | null | undefined} [hChildren] | ||
* Generate an element with this content instead. | ||
* | ||
* @typedef {Record<string, unknown> & EmbeddedHastFields} MdastData | ||
* mdast data with embedded hast fields. | ||
* | ||
* @typedef {MdastNodes & {data?: MdastData | null | undefined}} MdastNodeWithData | ||
* mdast node with embedded hast data. | ||
* | ||
* @typedef PointLike | ||
* Point-like value. | ||
* @property {number | null | undefined} [line] | ||
* Line. | ||
* @property {number | null | undefined} [column] | ||
* Column. | ||
* @property {number | null | undefined} [offset] | ||
* Offset. | ||
* | ||
* @typedef PositionLike | ||
* Position-like value. | ||
* @property {PointLike | null | undefined} [start] | ||
* Point-like value. | ||
* @property {PointLike | null | undefined} [end] | ||
* Point-like value. | ||
* | ||
* @callback Handler | ||
@@ -58,114 +25,158 @@ * Handle a node. | ||
* mdast node to handle. | ||
* @param {MdastParents | null | undefined} parent | ||
* @param {MdastParents | undefined} parent | ||
* Parent of `node`. | ||
* @returns {HastElementContent | Array<HastElementContent> | null | undefined} | ||
* @returns {Array<HastElementContent> | HastElementContent | undefined} | ||
* hast node. | ||
* | ||
* @callback HFunctionProps | ||
* Signature of `state` for when props are passed. | ||
* @param {MdastNodes | PositionLike | null | undefined} node | ||
* mdast node or unist position. | ||
* @param {string} tagName | ||
* HTML tag name. | ||
* @param {HastProperties} props | ||
* Properties. | ||
* @param {Array<HastElementContent> | null | undefined} [children] | ||
* hast content. | ||
* @returns {HastElement} | ||
* Compiled element. | ||
* @typedef {Partial<Record<MdastNodes['type'], Handler>>} Handlers | ||
* Handle nodes. | ||
* | ||
* @callback HFunctionNoProps | ||
* Signature of `state` for when no props are passed. | ||
* @param {MdastNodes | PositionLike | null | undefined} node | ||
* mdast node or unist position. | ||
* @param {string} tagName | ||
* HTML tag name. | ||
* @param {Array<HastElementContent> | null | undefined} [children] | ||
* hast content. | ||
* @returns {HastElement} | ||
* Compiled element. | ||
* | ||
* @typedef HFields | ||
* Info on `state`. | ||
* @property {boolean} dangerous | ||
* Whether HTML is allowed. | ||
* @property {string} clobberPrefix | ||
* Prefix to use to prevent DOM clobbering. | ||
* @property {string} footnoteLabel | ||
* Label to use to introduce the footnote section. | ||
* @property {string} footnoteLabelTagName | ||
* HTML used for the footnote label. | ||
* @property {HastProperties} footnoteLabelProperties | ||
* Properties on the HTML tag used for the footnote label. | ||
* @property {string} footnoteBackLabel | ||
* Label to use from backreferences back to their footnote call. | ||
* @property {(identifier: string) => MdastDefinition | null} definition | ||
* Definition cache. | ||
* @property {Record<string, MdastFootnoteDefinition>} footnoteById | ||
* Footnote definitions by their identifier. | ||
* @property {Array<string>} footnoteOrder | ||
* Identifiers of order when footnote calls first appear in tree order. | ||
* @property {Record<string, number>} footnoteCounts | ||
* Counts for how often the same footnote was called. | ||
* @property {Handlers} handlers | ||
* Applied handlers. | ||
* @property {Handler} unknownHandler | ||
* Handler for any none not in `passThrough` or otherwise handled. | ||
* @property {(from: MdastNodes, node: HastNodes) => void} patch | ||
* Copy a node’s positional info. | ||
* @property {<Type extends HastNodes>(from: MdastNodes, to: Type) => Type | HastElement} applyData | ||
* Honor the `data` of `from`, and generate an element instead of `node`. | ||
* @property {(node: MdastNodes, parent: MdastParents | null | undefined) => HastElementContent | Array<HastElementContent> | null | undefined} one | ||
* Transform an mdast node to hast. | ||
* @property {(node: MdastNodes) => Array<HastElementContent>} all | ||
* Transform the children of an mdast parent to hast. | ||
* @property {<Type extends HastContent>(nodes: Array<Type>, loose?: boolean | null | undefined) => Array<Type | HastText>} wrap | ||
* Wrap `nodes` with line endings between each node, adds initial/final line endings when `loose`. | ||
* @property {(left: MdastNodeWithData | PositionLike | null | undefined, right: HastElementContent) => HastElementContent} augment | ||
* Like `state` but lower-level and usable on non-elements. | ||
* Deprecated: use `patch` and `applyData`. | ||
* @property {Array<string>} passThrough | ||
* List of node types to pass through untouched (except for their children). | ||
* | ||
* @typedef Options | ||
* Configuration (optional). | ||
* @property {boolean | null | undefined} [allowDangerousHtml=false] | ||
* Whether to persist raw HTML in markdown in the hast tree. | ||
* Whether to persist raw HTML in markdown in the hast tree (default: | ||
* `false`). | ||
* @property {string | null | undefined} [clobberPrefix='user-content-'] | ||
* Prefix to use before the `id` attribute on footnotes to prevent it from | ||
* *clobbering*. | ||
* @property {string | null | undefined} [footnoteBackLabel='Back to content'] | ||
* Label to use from backreferences back to their footnote call (affects | ||
* screen readers). | ||
* Prefix to use before the `id` property on footnotes to prevent them from | ||
* *clobbering* (default: `'user-content-'`). | ||
* | ||
* Pass `''` for trusted markdown and when you are careful with | ||
* polyfilling. | ||
* You could pass a different prefix. | ||
* | ||
* DOM clobbering is this: | ||
* | ||
* ```html | ||
* <p id="x"></p> | ||
* <script>alert(x) // `x` now refers to the `p#x` DOM element</script> | ||
* ``` | ||
* | ||
* The above example shows that elements are made available by browsers, by | ||
* their ID, on the `window` object. | ||
* This is a security risk because you might be expecting some other variable | ||
* at that place. | ||
* It can also break polyfills. | ||
* Using a prefix solves these problems. | ||
* @property {FootnoteBackContentTemplate | string | null | undefined} [footnoteBackContent] | ||
* Content of the backreference back to references (default: `defaultFootnoteBackContent`). | ||
* | ||
* The default value is: | ||
* | ||
* ```js | ||
* function defaultFootnoteBackContent(_, rereferenceIndex) { | ||
* const result = [{type: 'text', value: '↩'}] | ||
* | ||
* if (rereferenceIndex > 1) { | ||
* result.push({ | ||
* type: 'element', | ||
* tagName: 'sup', | ||
* properties: {}, | ||
* children: [{type: 'text', value: String(rereferenceIndex)}] | ||
* }) | ||
* } | ||
* | ||
* return result | ||
* } | ||
* ``` | ||
* | ||
* This content is used in the `a` element of each backreference (the `↩` | ||
* links). | ||
* @property {FootnoteBackLabelTemplate | string | null | undefined} [footnoteBackLabel] | ||
* Label to describe the backreference back to references (default: | ||
* `defaultFootnoteBackLabel`). | ||
* | ||
* The default value is: | ||
* | ||
* ```js | ||
* function defaultFootnoteBackLabel(referenceIndex, rereferenceIndex) { | ||
* return ( | ||
* 'Back to reference ' + | ||
* (referenceIndex + 1) + | ||
* (rereferenceIndex > 1 ? '-' + rereferenceIndex : '') | ||
* ) | ||
* } | ||
* ``` | ||
* | ||
* Change it when the markdown is not in English. | ||
* | ||
* This label is used in the `ariaLabel` property on each backreference | ||
* (the `↩` links). | ||
* It affects users of assistive technology. | ||
* @property {string | null | undefined} [footnoteLabel='Footnotes'] | ||
* Label to use for the footnotes section (affects screen readers). | ||
* Textual label to use for the footnotes section (default: `'Footnotes'`). | ||
* | ||
* Change it when the markdown is not in English. | ||
* | ||
* This label is typically hidden visually (assuming a `sr-only` CSS class | ||
* is defined that does that) and so affects screen readers only. | ||
* If you do have such a class, but want to show this section to everyone, | ||
* pass different properties with the `footnoteLabelProperties` option. | ||
* @property {HastProperties | null | undefined} [footnoteLabelProperties={className: ['sr-only']}] | ||
* Properties to use on the footnote label (note that `id: 'footnote-label'` | ||
* is always added as footnote calls use it with `aria-describedby` to | ||
* provide an accessible label). | ||
* Properties to use on the footnote label (default: `{className: | ||
* ['sr-only']}`). | ||
* | ||
* Change it to show the label and add other properties. | ||
* | ||
* This label is typically hidden visually (assuming an `sr-only` CSS class | ||
* is defined that does that) and so affects screen readers only. | ||
* If you do have such a class, but want to show this section to everyone, | ||
* pass an empty string. | ||
* You can also add different properties. | ||
* | ||
* > 👉 **Note**: `id: 'footnote-label'` is always added, because footnote | ||
* > calls use it with `aria-describedby` to provide an accessible label. | ||
* @property {string | null | undefined} [footnoteLabelTagName='h2'] | ||
* Tag name to use for the footnote label. | ||
* HTML tag name to use for the footnote label element (default: `'h2'`). | ||
* | ||
* Change it to match your document structure. | ||
* | ||
* This label is typically hidden visually (assuming a `sr-only` CSS class | ||
* is defined that does that) and so affects screen readers only. | ||
* If you do have such a class, but want to show this section to everyone, | ||
* pass different properties with the `footnoteLabelProperties` option. | ||
* @property {Handlers | null | undefined} [handlers] | ||
* Extra handlers for nodes. | ||
* @property {Array<string> | null | undefined} [passThrough] | ||
* Extra handlers for nodes (optional). | ||
* @property {Array<MdastNodes['type']> | null | undefined} [passThrough] | ||
* List of custom mdast node types to pass through (keep) in hast (note that | ||
* the node itself is passed, but eventual children are transformed). | ||
* the node itself is passed, but eventual children are transformed) | ||
* (optional). | ||
* @property {Handler | null | undefined} [unknownHandler] | ||
* Handler for all unknown nodes. | ||
* Handler for all unknown nodes (optional). | ||
* | ||
* @typedef {Record<string, Handler>} Handlers | ||
* Handle nodes. | ||
* | ||
* @typedef {HFunctionProps & HFunctionNoProps & HFields} State | ||
* @typedef State | ||
* Info passed around. | ||
* @property {(node: MdastNodes) => Array<HastElementContent>} all | ||
* Transform the children of an mdast parent to hast. | ||
* @property {<Type extends HastNodes>(from: MdastNodes, to: Type) => HastElement | Type} applyData | ||
* Honor the `data` of `from`, and generate an element instead of `node`. | ||
* @property {Map<string, MdastDefinition>} definitionById | ||
* Definitions by their identifier. | ||
* @property {Map<string, MdastFootnoteDefinition>} footnoteById | ||
* Footnote definitions by their identifier. | ||
* @property {Map<string, number>} footnoteCounts | ||
* Counts for how often the same footnote was called. | ||
* @property {Array<string>} footnoteOrder | ||
* Identifiers of order when footnote calls first appear in tree order. | ||
* @property {Handlers} handlers | ||
* Applied handlers. | ||
* @property {(node: MdastNodes, parent: MdastParents | undefined) => Array<HastElementContent> | HastElementContent | undefined} one | ||
* Transform an mdast node to hast. | ||
* @property {Options} options | ||
* Configuration. | ||
* @property {(from: MdastNodes, node: HastNodes) => undefined} patch | ||
* Copy a node’s positional info. | ||
* @property {<Type extends HastRootContent>(nodes: Array<Type>, loose?: boolean | undefined) => Array<HastText | Type>} wrap | ||
* Wrap `nodes` with line endings between each node, adds initial/final line endings when `loose`. | ||
*/ | ||
import structuredClone from '@ungap/structured-clone' | ||
import {visit} from 'unist-util-visit' | ||
import {position, pointStart, pointEnd} from 'unist-util-position' | ||
import {generated} from 'unist-util-generated' | ||
import {definitions} from 'mdast-util-definitions' | ||
import {handlers} from './handlers/index.js' | ||
import {position} from 'unist-util-position' | ||
import {handlers as defaultHandlers} from './handlers/index.js' | ||
const own = {}.hasOwnProperty | ||
/** @type {Options} */ | ||
const emptyOptions = {} | ||
/** | ||
@@ -177,3 +188,3 @@ * Create `state` from an mdast tree. | ||
* @param {Options | null | undefined} [options] | ||
* Configuration. | ||
* Configuration (optional). | ||
* @returns {State} | ||
@@ -183,152 +194,80 @@ * `state` function. | ||
export function createState(tree, options) { | ||
const settings = options || {} | ||
const dangerous = settings.allowDangerousHtml || false | ||
/** @type {Record<string, MdastFootnoteDefinition>} */ | ||
const footnoteById = {} | ||
const settings = options || emptyOptions | ||
/** @type {Map<string, MdastDefinition>} */ | ||
const definitionById = new Map() | ||
/** @type {Map<string, MdastFootnoteDefinition>} */ | ||
const footnoteById = new Map() | ||
/** @type {Map<string, number>} */ | ||
const footnoteCounts = new Map() | ||
/** @type {Handlers} */ | ||
// @ts-expect-error: the root handler returns a root. | ||
// Hard to type. | ||
const handlers = {...defaultHandlers, ...settings.handlers} | ||
// To do: next major: add `options` to state, remove: | ||
// `dangerous`, `clobberPrefix`, `footnoteLabel`, `footnoteLabelTagName`, | ||
// `footnoteLabelProperties`, `footnoteBackLabel`, `passThrough`, | ||
// `unknownHandler`. | ||
// To do: next major: move to `state.options.allowDangerousHtml`. | ||
state.dangerous = dangerous | ||
// To do: next major: move to `state.options`. | ||
state.clobberPrefix = | ||
settings.clobberPrefix === undefined || settings.clobberPrefix === null | ||
? 'user-content-' | ||
: settings.clobberPrefix | ||
// To do: next major: move to `state.options`. | ||
state.footnoteLabel = settings.footnoteLabel || 'Footnotes' | ||
// To do: next major: move to `state.options`. | ||
state.footnoteLabelTagName = settings.footnoteLabelTagName || 'h2' | ||
// To do: next major: move to `state.options`. | ||
state.footnoteLabelProperties = settings.footnoteLabelProperties || { | ||
className: ['sr-only'] | ||
/** @type {State} */ | ||
const state = { | ||
all, | ||
applyData, | ||
definitionById, | ||
footnoteById, | ||
footnoteCounts, | ||
footnoteOrder: [], | ||
handlers, | ||
one, | ||
options: settings, | ||
patch, | ||
wrap | ||
} | ||
// To do: next major: move to `state.options`. | ||
state.footnoteBackLabel = settings.footnoteBackLabel || 'Back to content' | ||
// To do: next major: move to `state.options`. | ||
state.unknownHandler = settings.unknownHandler | ||
// To do: next major: move to `state.options`. | ||
state.passThrough = settings.passThrough | ||
state.handlers = {...handlers, ...settings.handlers} | ||
visit(tree, function (node) { | ||
if (node.type === 'definition' || node.type === 'footnoteDefinition') { | ||
const map = node.type === 'definition' ? definitionById : footnoteById | ||
const id = String(node.identifier).toUpperCase() | ||
// To do: next major: replace utility with `definitionById` object, so we | ||
// only walk once (as we need footnotes too). | ||
state.definition = definitions(tree) | ||
state.footnoteById = footnoteById | ||
/** @type {Array<string>} */ | ||
state.footnoteOrder = [] | ||
/** @type {Record<string, number>} */ | ||
state.footnoteCounts = {} | ||
state.patch = patch | ||
state.applyData = applyData | ||
state.one = oneBound | ||
state.all = allBound | ||
state.wrap = wrap | ||
// To do: next major: remove `augment`. | ||
state.augment = augment | ||
visit(tree, 'footnoteDefinition', (definition) => { | ||
const id = String(definition.identifier).toUpperCase() | ||
// Mimick CM behavior of link definitions. | ||
// See: <https://github.com/syntax-tree/mdast-util-definitions/blob/8290999/index.js#L26>. | ||
if (!own.call(footnoteById, id)) { | ||
footnoteById[id] = definition | ||
// Mimick CM behavior of link definitions. | ||
// See: <https://github.com/syntax-tree/mdast-util-definitions/blob/9032189/lib/index.js#L20-L21>. | ||
if (!map.has(id)) { | ||
// @ts-expect-error: node type matches map. | ||
map.set(id, node) | ||
} | ||
} | ||
}) | ||
// @ts-expect-error Hush, it’s fine! | ||
return state | ||
/** | ||
* Finalise the created `right`, a hast node, from `left`, an mdast node. | ||
* Transform an mdast node into a hast node. | ||
* | ||
* @param {MdastNodeWithData | PositionLike | null | undefined} left | ||
* @param {HastElementContent} right | ||
* @returns {HastElementContent} | ||
* @param {MdastNodes} node | ||
* mdast node. | ||
* @param {MdastParents | undefined} [parent] | ||
* Parent of `node`. | ||
* @returns {Array<HastElementContent> | HastElementContent | undefined} | ||
* Resulting hast node. | ||
*/ | ||
/* c8 ignore start */ | ||
// To do: next major: remove. | ||
function augment(left, right) { | ||
// Handle `data.hName`, `data.hProperties, `data.hChildren`. | ||
if (left && 'data' in left && left.data) { | ||
/** @type {MdastData} */ | ||
const data = left.data | ||
function one(node, parent) { | ||
const type = node.type | ||
const handle = state.handlers[type] | ||
if (data.hName) { | ||
if (right.type !== 'element') { | ||
right = { | ||
type: 'element', | ||
tagName: '', | ||
properties: {}, | ||
children: [] | ||
} | ||
} | ||
right.tagName = data.hName | ||
} | ||
if (right.type === 'element' && data.hProperties) { | ||
right.properties = {...right.properties, ...data.hProperties} | ||
} | ||
if ('children' in right && right.children && data.hChildren) { | ||
right.children = data.hChildren | ||
} | ||
if (own.call(state.handlers, type) && handle) { | ||
return handle(state, node, parent) | ||
} | ||
if (left) { | ||
const ctx = 'type' in left ? left : {position: left} | ||
if (!generated(ctx)) { | ||
// @ts-expect-error: fine. | ||
right.position = {start: pointStart(ctx), end: pointEnd(ctx)} | ||
if (state.options.passThrough && state.options.passThrough.includes(type)) { | ||
if ('children' in node) { | ||
const {children, ...shallow} = node | ||
const result = structuredClone(shallow) | ||
// @ts-expect-error: TS doesn’t understand… | ||
result.children = state.all(node) | ||
// @ts-expect-error: TS doesn’t understand… | ||
return result | ||
} | ||
} | ||
return right | ||
} | ||
/* c8 ignore stop */ | ||
/** | ||
* Create an element for `node`. | ||
* | ||
* @type {HFunctionProps} | ||
*/ | ||
/* c8 ignore start */ | ||
// To do: next major: remove. | ||
function state(node, tagName, props, children) { | ||
if (Array.isArray(props)) { | ||
children = props | ||
props = {} | ||
// @ts-expect-error: it’s custom. | ||
return structuredClone(node) | ||
} | ||
// @ts-expect-error augmenting an element yields an element. | ||
return augment(node, { | ||
type: 'element', | ||
tagName, | ||
properties: props || {}, | ||
children: children || [] | ||
}) | ||
} | ||
/* c8 ignore stop */ | ||
const unknown = state.options.unknownHandler || defaultUnknownHandler | ||
/** | ||
* Transform an mdast node into a hast node. | ||
* | ||
* @param {MdastNodes} node | ||
* mdast node. | ||
* @param {MdastParents | null | undefined} [parent] | ||
* Parent of `node`. | ||
* @returns {HastElementContent | Array<HastElementContent> | null | undefined} | ||
* Resulting hast node. | ||
*/ | ||
function oneBound(node, parent) { | ||
// @ts-expect-error: that’s a state :) | ||
return one(state, node, parent) | ||
return unknown(state, node, parent) | ||
} | ||
@@ -344,5 +283,38 @@ | ||
*/ | ||
function allBound(parent) { | ||
// @ts-expect-error: that’s a state :) | ||
return all(state, parent) | ||
function all(parent) { | ||
/** @type {Array<HastElementContent>} */ | ||
const values = [] | ||
if ('children' in parent) { | ||
const nodes = parent.children | ||
let index = -1 | ||
while (++index < nodes.length) { | ||
const result = state.one(nodes[index], parent) | ||
// To do: see if we van clean this? Can we merge texts? | ||
if (result) { | ||
if (index && nodes[index - 1].type === 'break') { | ||
if (!Array.isArray(result) && result.type === 'text') { | ||
result.value = result.value.replace(/^\s+/, '') | ||
} | ||
if (!Array.isArray(result) && result.type === 'element') { | ||
const head = result.children[0] | ||
if (head && head.type === 'text') { | ||
head.value = head.value.replace(/^\s+/, '') | ||
} | ||
} | ||
} | ||
if (Array.isArray(result)) { | ||
values.push(...result) | ||
} else { | ||
values.push(result) | ||
} | ||
} | ||
} | ||
} | ||
return values | ||
} | ||
@@ -358,3 +330,3 @@ } | ||
* hast node to copy into. | ||
* @returns {void} | ||
* @returns {undefined} | ||
* Nothing. | ||
@@ -375,7 +347,7 @@ */ | ||
* hast node to change. | ||
* @returns {Type | HastElement} | ||
* @returns {HastElement | Type} | ||
* Nothing. | ||
*/ | ||
function applyData(from, to) { | ||
/** @type {Type | HastElement} */ | ||
/** @type {HastElement | Type} */ | ||
let result = to | ||
@@ -397,21 +369,9 @@ | ||
// raw, text, and root nodes (unless custom handlers are passed). | ||
// The intent is likely to keep the content around (otherwise: pass | ||
// `hChildren`). | ||
// The intent of `hName` is to create an element, but likely also to keep | ||
// the content around (otherwise: pass `hChildren`). | ||
else { | ||
result = { | ||
type: 'element', | ||
tagName: hName, | ||
properties: {}, | ||
children: [] | ||
} | ||
// To do: next major: take the children from the `root`, or inject the | ||
// raw/text/comment or so into the element? | ||
// if ('children' in node) { | ||
// // @ts-expect-error: assume `children` are allowed in elements. | ||
// result.children = node.children | ||
// } else { | ||
// // @ts-expect-error: assume `node` is allowed in elements. | ||
// result.children.push(node) | ||
// } | ||
/** @type {Array<HastElementContent>} */ | ||
// @ts-expect-error: assume no doctypes in `root`. | ||
const children = 'children' in result ? result.children : [result] | ||
result = {type: 'element', tagName: hName, properties: {}, children} | ||
} | ||
@@ -421,3 +381,3 @@ } | ||
if (result.type === 'element' && hProperties) { | ||
result.properties = {...result.properties, ...hProperties} | ||
Object.assign(result.properties, structuredClone(hProperties)) | ||
} | ||
@@ -431,3 +391,2 @@ | ||
) { | ||
// @ts-expect-error: assume valid children are defined. | ||
result.children = hChildren | ||
@@ -441,89 +400,2 @@ } | ||
/** | ||
* Transform an mdast node into a hast node. | ||
* | ||
* @param {State} state | ||
* Info passed around. | ||
* @param {MdastNodes} node | ||
* mdast node. | ||
* @param {MdastParents | null | undefined} [parent] | ||
* Parent of `node`. | ||
* @returns {HastElementContent | Array<HastElementContent> | null | undefined} | ||
* Resulting hast node. | ||
*/ | ||
// To do: next major: do not expose, keep bound. | ||
export function one(state, node, parent) { | ||
const type = node && node.type | ||
// Fail on non-nodes. | ||
if (!type) { | ||
throw new Error('Expected node, got `' + node + '`') | ||
} | ||
if (own.call(state.handlers, type)) { | ||
return state.handlers[type](state, node, parent) | ||
} | ||
if (state.passThrough && state.passThrough.includes(type)) { | ||
// To do: next major: deep clone. | ||
// @ts-expect-error: types of passed through nodes are expected to be added manually. | ||
return 'children' in node ? {...node, children: all(state, node)} : node | ||
} | ||
if (state.unknownHandler) { | ||
return state.unknownHandler(state, node, parent) | ||
} | ||
return defaultUnknownHandler(state, node) | ||
} | ||
/** | ||
* Transform the children of an mdast node into hast nodes. | ||
* | ||
* @param {State} state | ||
* Info passed around. | ||
* @param {MdastNodes} parent | ||
* mdast node to compile | ||
* @returns {Array<HastElementContent>} | ||
* Resulting hast nodes. | ||
*/ | ||
// To do: next major: do not expose, keep bound. | ||
export function all(state, parent) { | ||
/** @type {Array<HastElementContent>} */ | ||
const values = [] | ||
if ('children' in parent) { | ||
const nodes = parent.children | ||
let index = -1 | ||
while (++index < nodes.length) { | ||
const result = one(state, nodes[index], parent) | ||
// To do: see if we van clean this? Can we merge texts? | ||
if (result) { | ||
if (index && nodes[index - 1].type === 'break') { | ||
if (!Array.isArray(result) && result.type === 'text') { | ||
result.value = result.value.replace(/^\s+/, '') | ||
} | ||
if (!Array.isArray(result) && result.type === 'element') { | ||
const head = result.children[0] | ||
if (head && head.type === 'text') { | ||
head.value = head.value.replace(/^\s+/, '') | ||
} | ||
} | ||
} | ||
if (Array.isArray(result)) { | ||
values.push(...result) | ||
} else { | ||
values.push(result) | ||
} | ||
} | ||
} | ||
} | ||
return values | ||
} | ||
/** | ||
* Transform an unknown node. | ||
@@ -535,3 +407,3 @@ * | ||
* Unknown mdast node. | ||
* @returns {HastText | HastElement} | ||
* @returns {HastElement | HastText} | ||
* Resulting hast node. | ||
@@ -541,3 +413,3 @@ */ | ||
const data = node.data || {} | ||
/** @type {HastText | HastElement} */ | ||
/** @type {HastElement | HastText} */ | ||
const result = | ||
@@ -551,3 +423,3 @@ 'value' in node && | ||
properties: {}, | ||
children: all(state, node) | ||
children: state.all(node) | ||
} | ||
@@ -562,13 +434,13 @@ | ||
* | ||
* @template {HastContent} Type | ||
* @template {HastRootContent} Type | ||
* Node type. | ||
* @param {Array<Type>} nodes | ||
* List of nodes to wrap. | ||
* @param {boolean | null | undefined} [loose=false] | ||
* Whether to add line endings at start and end. | ||
* @returns {Array<Type | HastText>} | ||
* @param {boolean | undefined} [loose=false] | ||
* Whether to add line endings at start and end (default: `false`). | ||
* @returns {Array<HastText | Type>} | ||
* Wrapped nodes. | ||
*/ | ||
export function wrap(nodes, loose) { | ||
/** @type {Array<Type | HastText>} */ | ||
/** @type {Array<HastText | Type>} */ | ||
const result = [] | ||
@@ -575,0 +447,0 @@ let index = -1 |
{ | ||
"name": "mdast-util-to-hast", | ||
"version": "12.3.0", | ||
"version": "13.0.0", | ||
"description": "mdast utility to transform to hast", | ||
@@ -29,7 +29,5 @@ "license": "MIT", | ||
"type": "module", | ||
"main": "index.js", | ||
"types": "index.d.ts", | ||
"exports": "./index.js", | ||
"files": [ | ||
"lib/", | ||
"complex-types.d.ts", | ||
"index.d.ts", | ||
@@ -39,25 +37,26 @@ "index.js" | ||
"dependencies": { | ||
"@types/hast": "^2.0.0", | ||
"@types/mdast": "^3.0.0", | ||
"mdast-util-definitions": "^5.0.0", | ||
"micromark-util-sanitize-uri": "^1.1.0", | ||
"@types/hast": "^3.0.0", | ||
"@types/mdast": "^4.0.0", | ||
"@ungap/structured-clone": "^1.0.0", | ||
"devlop": "^1.0.0", | ||
"micromark-util-sanitize-uri": "^2.0.0", | ||
"trim-lines": "^3.0.0", | ||
"unist-util-generated": "^2.0.0", | ||
"unist-util-position": "^4.0.0", | ||
"unist-util-visit": "^4.0.0" | ||
"unist-util-position": "^5.0.0", | ||
"unist-util-visit": "^5.0.0" | ||
}, | ||
"devDependencies": { | ||
"@types/node": "^18.0.0", | ||
"c8": "^7.0.0", | ||
"@types/node": "^20.0.0", | ||
"@types/ungap__structured-clone": "^0.3.0", | ||
"c8": "^8.0.0", | ||
"hast-util-to-html": "^8.0.4", | ||
"hastscript": "^7.0.0", | ||
"mdast-util-from-markdown": "^1.0.0", | ||
"mdast-util-gfm": "^2.0.0", | ||
"micromark-extension-gfm": "^2.0.0", | ||
"prettier": "^2.0.0", | ||
"mdast-util-from-markdown": "^2.0.0", | ||
"mdast-util-gfm": "^3.0.0", | ||
"micromark-extension-gfm": "^3.0.0", | ||
"prettier": "^3.0.0", | ||
"remark-cli": "^11.0.0", | ||
"remark-preset-wooorm": "^9.0.0", | ||
"type-coverage": "^2.0.0", | ||
"typescript": "^4.0.0", | ||
"xo": "^0.53.0" | ||
"typescript": "^5.0.0", | ||
"xo": "^0.55.0" | ||
}, | ||
@@ -67,27 +66,20 @@ "scripts": { | ||
"build": "tsc --build --clean && tsc --build && type-coverage", | ||
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix", | ||
"format": "remark . -qfo && prettier . -w --log-level warn && xo --fix", | ||
"test-api": "node --conditions development test/index.js", | ||
"test-coverage": "c8 --check-coverage --100 --reporter lcov npm run test-api", | ||
"test-coverage": "c8 --100 --reporter lcov npm run test-api", | ||
"test": "npm run build && npm run format && npm run test-coverage" | ||
}, | ||
"prettier": { | ||
"tabWidth": 2, | ||
"useTabs": false, | ||
"singleQuote": true, | ||
"bracketSpacing": false, | ||
"semi": false, | ||
"trailingComma": "none" | ||
"singleQuote": true, | ||
"tabWidth": 2, | ||
"trailingComma": "none", | ||
"useTabs": false | ||
}, | ||
"xo": { | ||
"prettier": true, | ||
"rules": { | ||
"max-depth": "off", | ||
"import/no-cycle": "error" | ||
} | ||
}, | ||
"remarkConfig": { | ||
"plugins": [ | ||
"preset-wooorm", | ||
"remark-preset-wooorm", | ||
[ | ||
"lint-no-html", | ||
"remark-lint-no-html", | ||
false | ||
@@ -100,8 +92,28 @@ ] | ||
"detail": true, | ||
"strict": true, | ||
"ignoreCatch": true, | ||
"#": "needed `any`s", | ||
"ignoreFiles": [ | ||
"lib/state.d.ts" | ||
] | ||
], | ||
"strict": true | ||
}, | ||
"xo": { | ||
"overrides": [ | ||
{ | ||
"files": [ | ||
"**/*.ts" | ||
], | ||
"rules": { | ||
"@typescript-eslint/consistent-type-definitions": "off" | ||
} | ||
} | ||
], | ||
"prettier": true, | ||
"rules": { | ||
"import/no-cycle": "error", | ||
"max-depth": "off", | ||
"unicorn/prefer-at": "off", | ||
"unicorn/prefer-string-replace-all": "off" | ||
} | ||
} | ||
} |
269
readme.md
@@ -20,4 +20,8 @@ # mdast-util-to-hast | ||
* [API](#api) | ||
* [`defaultFootnoteBackContent(referenceIndex, rereferenceIndex)`](#defaultfootnotebackcontentreferenceindex-rereferenceindex) | ||
* [`defaultFootnoteBackLabel(referenceIndex, rereferenceIndex)`](#defaultfootnotebacklabelreferenceindex-rereferenceindex) | ||
* [`defaultHandlers`](#defaulthandlers) | ||
* [`toHast(tree[, options])`](#tohasttree-options) | ||
* [`defaultHandlers`](#defaulthandlers) | ||
* [`FootnoteBackContentTemplate`](#footnotebackcontenttemplate) | ||
* [`FootnoteBackLabelTemplate`](#footnotebacklabeltemplate) | ||
* [`Handler`](#handler) | ||
@@ -66,3 +70,3 @@ * [`Handlers`](#handlers) | ||
This package is [ESM only][esm]. | ||
In Node.js (version 14.14+ and 16.0+), install with [npm][]: | ||
In Node.js (version 16+), install with [npm][]: | ||
@@ -76,3 +80,3 @@ ```sh | ||
```js | ||
import {toHast} from 'https://esm.sh/mdast-util-to-hast@12' | ||
import {toHast} from 'https://esm.sh/mdast-util-to-hast@13' | ||
``` | ||
@@ -84,3 +88,3 @@ | ||
<script type="module"> | ||
import {toHast} from 'https://esm.sh/mdast-util-to-hast@12?bundle' | ||
import {toHast} from 'https://esm.sh/mdast-util-to-hast@13?bundle' | ||
</script> | ||
@@ -101,5 +105,5 @@ ``` | ||
import {fs} from 'node:fs/promises' | ||
import {toHtml} from 'hast-util-to-html' | ||
import {fromMarkdown} from 'mdast-util-from-markdown' | ||
import {toHast} from 'mdast-util-to-hast' | ||
import {toHtml} from 'hast-util-to-html' | ||
@@ -122,6 +126,45 @@ const markdown = String(await fs.readFile('example.md')) | ||
This package exports the identifiers [`defaultHandlers`][api-default-handlers] | ||
and [`toHast`][api-to-hast]. | ||
This package exports the identifiers | ||
[`defaultFootnoteBackContent`][api-default-footnote-back-content], | ||
[`defaultFootnoteBackLabel`][api-default-footnote-back-label], | ||
[`defaultHandlers`][api-default-handlers], and | ||
[`toHast`][api-to-hast]. | ||
There is no default export. | ||
### `defaultFootnoteBackContent(referenceIndex, rereferenceIndex)` | ||
Generate the default content that GitHub uses on backreferences. | ||
###### Parameters | ||
* `referenceIndex` (`number`) | ||
— index of the definition in the order that they are first referenced, | ||
0-indexed | ||
* `rereferenceIndex` (`number`) | ||
— index of calls to the same definition, 0-indexed | ||
###### Returns | ||
Content (`Array<ElementContent>`). | ||
### `defaultFootnoteBackLabel(referenceIndex, rereferenceIndex)` | ||
Generate the default label that GitHub uses on backreferences. | ||
###### Parameters | ||
* `referenceIndex` (`number`) | ||
— index of the definition in the order that they are first referenced, | ||
0-indexed | ||
* `rereferenceIndex` (`number`) | ||
— index of calls to the same definition, 0-indexed | ||
###### Returns | ||
Label (`string`). | ||
### `defaultHandlers` | ||
Default handlers for nodes ([`Handlers`][api-handlers]). | ||
### `toHast(tree[, options])` | ||
@@ -140,3 +183,3 @@ | ||
hast tree ([`HastNode | null | undefined`][hast-node]). | ||
hast tree ([`HastNode`][hast-node]). | ||
@@ -210,6 +253,72 @@ ##### Notes | ||
### `defaultHandlers` | ||
### `FootnoteBackContentTemplate` | ||
Default handlers for nodes ([`Handlers`][api-handlers]). | ||
Generate content for the backreference dynamically. | ||
For the following markdown: | ||
```markdown | ||
Alpha[^micromark], bravo[^micromark], and charlie[^remark]. | ||
[^remark]: things about remark | ||
[^micromark]: things about micromark | ||
``` | ||
This function will be called with: | ||
* `0` and `0` for the backreference from `things about micromark` to | ||
`alpha`, as it is the first used definition, and the first call to it | ||
* `0` and `1` for the backreference from `things about micromark` to | ||
`bravo`, as it is the first used definition, and the second call to it | ||
* `1` and `0` for the backreference from `things about remark` to | ||
`charlie`, as it is the second used definition | ||
###### Parameters | ||
* `referenceIndex` (`number`) | ||
— index of the definition in the order that they are first referenced, | ||
0-indexed | ||
* `rereferenceIndex` (`number`) | ||
— index of calls to the same definition, 0-indexed | ||
###### Returns | ||
Content for the backreference when linking back from definitions to their | ||
reference (`Array<ElementContent>`, `ElementContent`, or `string`). | ||
### `FootnoteBackLabelTemplate` | ||
Generate a back label dynamically. | ||
For the following markdown: | ||
```markdown | ||
Alpha[^micromark], bravo[^micromark], and charlie[^remark]. | ||
[^remark]: things about remark | ||
[^micromark]: things about micromark | ||
``` | ||
This function will be called with: | ||
* `0` and `0` for the backreference from `things about micromark` to | ||
`alpha`, as it is the first used definition, and the first call to it | ||
* `0` and `1` for the backreference from `things about micromark` to | ||
`bravo`, as it is the first used definition, and the second call to it | ||
* `1` and `0` for the backreference from `things about remark` to | ||
`charlie`, as it is the second used definition | ||
###### Parameters | ||
* `referenceIndex` (`number`) | ||
— index of the definition in the order that they are first referenced, | ||
0-indexed | ||
* `rereferenceIndex` (`number`) | ||
— index of calls to the same definition, 0-indexed | ||
###### Returns | ||
Back label to use when linking back from definitions to their reference | ||
(`string`). | ||
### `Handler` | ||
@@ -225,3 +334,3 @@ | ||
— node to handle | ||
* `parent` ([`MdastNode | null | undefined`][mdast-node]) | ||
* `parent` ([`MdastNode | undefined`][mdast-node]) | ||
— parent of `node` | ||
@@ -231,3 +340,3 @@ | ||
Result ([`HastNode | Array<HastNode> | null | undefined`][mdast-node]). | ||
Result ([`Array<HastNode> | HastNode | undefined`][hast-node]). | ||
@@ -241,3 +350,3 @@ ### `Handlers` | ||
```ts | ||
type Handlers = Record<string, Handler> | ||
type Handlers = Partial<Record<Nodes['type'], Handler>> | ||
``` | ||
@@ -254,7 +363,14 @@ | ||
* `clobberPrefix` (`string`, default: `'user-content-'`) | ||
— prefix to use before the `id` attribute on footnotes to prevent it from | ||
— prefix to use before the `id` property on footnotes to prevent them from | ||
*clobbering* | ||
* `footnoteBackLabel` (`string`, default: `'Back to content'`) | ||
— label to use from backreferences back to their footnote call (affects | ||
screen readers) | ||
* `footnoteBackContent` | ||
([`FootnoteBackContentTemplate`][api-footnote-back-content-template] | ||
or `string`, default: | ||
[`defaultFootnoteBackContent`][api-default-footnote-back-content]) | ||
— content of the backreference back to references | ||
* `footnoteBackLabel` | ||
([`FootnoteBackLabelTemplate`][api-footnote-back-label-template] | ||
or `string`, default: | ||
[`defaultFootnoteBackLabel`][api-default-footnote-back-label]) | ||
— label to describe the backreference back to references | ||
* `footnoteLabel` (`string`, default: `'Footnotes'`) | ||
@@ -271,3 +387,3 @@ — label to use for the footnotes section (affects screen readers) | ||
— extra handlers for nodes | ||
* `passThrough` (`Array<string>`, optional) | ||
* `passThrough` (`Array<Nodes['type']>`, optional) | ||
— list of custom mdast node types to pass through (keep) in hast (note that | ||
@@ -285,7 +401,10 @@ the node itself is passed, but eventual children are transformed) | ||
```ts | ||
import type {Literal} from 'hast' | ||
import type {Data, Literal} from 'hast' | ||
interface Raw extends Literal { | ||
type: 'raw' | ||
data?: RawData | undefined | ||
} | ||
interface RawData extends Data {} | ||
``` | ||
@@ -299,23 +418,24 @@ | ||
<!-- To do: add `options`, alternative to `definition`. --> | ||
* `patch` (`(from: MdastNode, to: HastNode) => void`) | ||
— copy a node’s positional info | ||
* `all` (`(node: MdastNode) => Array<HastNode>`) | ||
— transform the children of an mdast parent to hast | ||
* `applyData` (`<Type extends HastNode>(from: MdastNode, to: Type) => Type | HastElement`) | ||
— honor the `data` of `from` and maybe generate an element instead of `to` | ||
* `definitionById` (`Map<string, Definition>`) | ||
— definitions by their uppercased identifier | ||
* `footnoteById` (`Map<string, FootnoteDefinition>`) | ||
— footnote definitions by their uppercased identifier | ||
* `footnoteCounts` (`Map<string, number>`) | ||
— counts for how often the same footnote was called | ||
* `footnoteOrder` (`Array<string>`) | ||
— identifiers of order when footnote calls first appear in tree order | ||
* `handlers` ([`Handlers`][api-handlers]) | ||
— applied node handlers | ||
* `one` (`(node: MdastNode, parent: MdastNode | undefined) => HastNode | Array<HastNode> | undefined`) | ||
— transform an mdast node to hast | ||
* `all` (`(node: MdastNode) => Array<HastNode>`) | ||
— transform the children of an mdast parent to hast | ||
* `options` ([`Options`][api-options]) | ||
— configuration | ||
* `patch` (`(from: MdastNode, to: HastNode) => undefined`) | ||
* `wrap` (`<Type extends HastNode>(nodes: Array<Type>, loose?: boolean) => Array<Type | HastText>`) | ||
— wrap `nodes` with line endings between each node, adds initial/final line | ||
endings when `loose` | ||
* `handlers` ([`Handlers`][api-handlers]) | ||
— applied node handlers | ||
* `footnoteById` (`Record<string, MdastFootnoteDefinition>`) | ||
— footnote definitions by their uppercased identifier | ||
* `footnoteOrder` (`Array<string>`) | ||
— identifiers of order when footnote calls first appear in tree order | ||
* `footnoteCounts` (`Record<string, number>`) | ||
— counts for how often the same footnote was called | ||
@@ -364,7 +484,7 @@ ## Examples | ||
```js | ||
import {fromMarkdown} from 'mdast-util-from-markdown' | ||
import {toHast} from 'mdast-util-to-hast' | ||
import {raw} from 'hast-util-raw' | ||
import {sanitize} from 'hast-util-sanitize' | ||
import {toHtml} from 'hast-util-to-html' | ||
import {fromMarkdown} from 'mdast-util-from-markdown' | ||
import {toHast} from 'mdast-util-to-hast' | ||
@@ -399,7 +519,7 @@ const markdown = 'It <i>works</i>! <img onerror="alert(1)">' | ||
```js | ||
import {toHtml} from 'hast-util-to-html' | ||
import {gfm} from 'micromark-extension-gfm' | ||
import {fromMarkdown} from 'mdast-util-from-markdown' | ||
import {gfm} from 'micromark-extension-gfm' | ||
import {gfmFromMarkdown} from 'mdast-util-gfm' | ||
import {toHast} from 'mdast-util-to-hast' | ||
import {toHtml} from 'hast-util-to-html' | ||
@@ -424,3 +544,3 @@ const markdown = 'Bonjour[^1]\n\n[^1]: Monde!' | ||
<li id="user-content-fn-1"> | ||
<p>Monde! <a href="#user-content-fnref-1" data-footnote-backref class="data-footnote-backref" aria-label="Back to content">↩</a></p> | ||
<p>Monde! <a href="#user-content-fnref-1" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p> | ||
</li> | ||
@@ -437,3 +557,3 @@ </ol> | ||
```diff | ||
@@ -9,7 +9,10 @@ const mdast = fromMarkdown(markdown, { | ||
@@ -9,7 +9,16 @@ const mdast = fromMarkdown(markdown, { | ||
extensions: [gfm()], | ||
@@ -445,3 +565,9 @@ mdastExtensions: [gfmFromMarkdown()] | ||
+ footnoteLabel: 'Notes de bas de page', | ||
+ footnoteBackLabel: 'Arrière' | ||
+ footnoteBackLabel(referenceIndex, rereferenceIndex) { | ||
+ return ( | ||
+ 'Retour à la référence ' + | ||
+ (referenceIndex + 1) + | ||
+ (rereferenceIndex > 1 ? '-' + rereferenceIndex : '') | ||
+ ) | ||
+ } | ||
+}) | ||
@@ -462,4 +588,4 @@ const html = toHtml(hast) | ||
<li id="user-content-fn-1"> | ||
-<p>Monde! <a href="#user-content-fnref-1" data-footnote-backref class="data-footnote-backref" aria-label="Back to content">↩</a></p> | ||
+<p>Monde! <a href="#user-content-fnref-1" data-footnote-backref class="data-footnote-backref" aria-label="Arrière">↩</a></p> | ||
-<p>Monde! <a href="#user-content-fnref-1" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p> | ||
+<p>Monde! <a href="#user-content-fnref-1" data-footnote-backref="" aria-label="Retour à la référence 1" class="data-footnote-backref">↩</a></p> | ||
</li> | ||
@@ -481,4 +607,4 @@ </ol> | ||
```js | ||
import {toHtml} from 'hast-util-to-html' | ||
import {toHast} from 'mdast-util-to-hast' | ||
import {toHtml} from 'hast-util-to-html' | ||
@@ -509,4 +635,4 @@ const mdast = { | ||
```js | ||
import {toHtml} from 'hast-util-to-html' | ||
import {toHast} from 'mdast-util-to-hast' | ||
import {toHtml} from 'hast-util-to-html' | ||
@@ -1366,6 +1492,12 @@ const mdast = { | ||
This package is fully typed with [TypeScript][]. | ||
It also exports [`Handler`][api-handler], [`Handlers`][api-handlers], | ||
[`Options`][api-options], [`Raw`][api-raw], and [`State`][api-state] types. | ||
It exports the | ||
[`FootnoteBackContentTemplate`][api-footnote-back-content-template], | ||
[`FootnoteBackLabelTemplate`][api-footnote-back-label-template], | ||
[`Handler`][api-handler], | ||
[`Handlers`][api-handlers], | ||
[`Options`][api-options], | ||
[`Raw`][api-raw], and | ||
[`State`][api-state] types. | ||
It also registers the `Raw` node type with `@types/mdast`. | ||
It also registers the `Raw` node type with `@types/hast`. | ||
If you’re working with the syntax tree (and you pass | ||
@@ -1385,3 +1517,3 @@ `allowDangerousHtml: true`), make sure to import this utility somewhere in your | ||
visit(tree, (node) => { | ||
visit(tree, function (node) { | ||
// `node` can now be `raw`. | ||
@@ -1391,9 +1523,30 @@ }) | ||
Finally, it also registers the `hChildren`, `hName`, and `hProperties` fields | ||
on `Data` of `@types/mdast`. | ||
If you’re working with the syntax tree, make sure to import this utility | ||
somewhere in your types, as that registers the data fields in the tree. | ||
```js | ||
/** | ||
* @typedef {import('mdast-util-to-hast')} | ||
*/ | ||
import {visit} from 'unist-util-visit' | ||
/** @type {import('hast').Root} */ | ||
const tree = { /* … */ } | ||
console.log(tree.data?.hName) // Types as `string | undefined`. | ||
``` | ||
## Compatibility | ||
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 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, `mdast-util-to-hast@^13`, | ||
compatible with Node.js 16. | ||
## Security | ||
@@ -1505,5 +1658,5 @@ | ||
[size-badge]: https://img.shields.io/bundlephobia/minzip/mdast-util-to-hast.svg | ||
[size-badge]: https://img.shields.io/badge/dynamic/json?label=minzipped%20size&query=$.size.compressedSize&url=https://deno.bundlejs.com/?q=mdast-util-to-hast | ||
[size]: https://bundlephobia.com/result?p=mdast-util-to-hast | ||
[size]: https://bundlejs.com/?q=mdast-util-to-hast | ||
@@ -1572,6 +1725,12 @@ [sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg | ||
[api-default-footnote-back-content]: #defaultfootnotebackcontentreferenceindex-rereferenceindex | ||
[api-default-footnote-back-label]: #defaultfootnotebacklabelreferenceindex-rereferenceindex | ||
[api-default-handlers]: #defaulthandlers | ||
[api-to-hast]: #tohasttree-options | ||
[api-footnote-back-content-template]: #footnotebackcontenttemplate | ||
[api-footnote-back-label-template]: #footnotebacklabeltemplate | ||
[api-handler]: #handler | ||
@@ -1586,1 +1745,3 @@ | ||
[api-state]: #state | ||
[api-to-hast]: #tohasttree-options |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
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
124232
1719
0
14
62
2625
+ Addeddevlop@^1.0.0
+ Added@types/hast@3.0.4(transitive)
+ Added@types/mdast@4.0.4(transitive)
+ Added@types/unist@3.0.3(transitive)
+ Added@ungap/structured-clone@1.2.0(transitive)
+ Addeddequal@2.0.3(transitive)
+ Addeddevlop@1.1.0(transitive)
+ Addedmicromark-util-character@2.1.0(transitive)
+ Addedmicromark-util-encode@2.0.0(transitive)
+ Addedmicromark-util-sanitize-uri@2.0.0(transitive)
+ Addedmicromark-util-symbol@2.0.0(transitive)
+ Addedmicromark-util-types@2.0.0(transitive)
+ Addedunist-util-is@6.0.0(transitive)
+ Addedunist-util-position@5.0.0(transitive)
+ Addedunist-util-visit@5.0.0(transitive)
+ Addedunist-util-visit-parents@6.0.1(transitive)
- Removedmdast-util-definitions@^5.0.0
- Removedunist-util-generated@^2.0.0
- Removed@types/hast@2.3.10(transitive)
- Removed@types/mdast@3.0.15(transitive)
- Removed@types/unist@2.0.11(transitive)
- Removedmdast-util-definitions@5.1.2(transitive)
- Removedmicromark-util-character@1.2.0(transitive)
- Removedmicromark-util-encode@1.1.0(transitive)
- Removedmicromark-util-sanitize-uri@1.2.0(transitive)
- Removedmicromark-util-symbol@1.1.0(transitive)
- Removedmicromark-util-types@1.1.0(transitive)
- Removedunist-util-generated@2.0.1(transitive)
- Removedunist-util-is@5.2.1(transitive)
- Removedunist-util-position@4.0.4(transitive)
- Removedunist-util-visit@4.1.2(transitive)
- Removedunist-util-visit-parents@5.1.3(transitive)
Updated@types/hast@^3.0.0
Updated@types/mdast@^4.0.0
Updatedunist-util-position@^5.0.0
Updatedunist-util-visit@^5.0.0