/** * @typedef {import('mdast').Heading} Heading * @typedef {import('mdast').Parents} Parents * @typedef {import('../types.js').Info} Info * @typedef {import('../types.js').State} State */ import {formatHeadingAsSetext} from '../util/format-heading-as-setext.js' /** * @param {Heading} node * @param {Parents | undefined} _ * @param {State} state * @param {Info} info * @returns {string} */ export function heading(node, _, state, info) { const rank = Math.max(Math.min(6, node.depth || 1), 1) const tracker = state.createTracker(info) if (formatHeadingAsSetext(node, state)) { const exit = state.enter('headingSetext') const subexit = state.enter('phrasing') const value = state.containerPhrasing(node, { ...tracker.current(), before: '\n', after: '\n' }) subexit() exit() return ( value + '\n' + (rank === 1 ? '=' : '-').repeat( // The whole size… value.length - // Minus the position of the character after the last EOL (or // 0 if there is none)… (Math.max(value.lastIndexOf('\r'), value.lastIndexOf('\n')) + 1) ) ) } const sequence = '#'.repeat(rank) const exit = state.enter('headingAtx') const subexit = state.enter('phrasing') // Note: for proper tracking, we should reset the output positions when there // is no content returned, because then the space is not output. // Practically, in that case, there is no content, so it doesn’t matter that // we’ve tracked one too many characters. tracker.move(sequence + ' ') let value = state.containerPhrasing(node, { before: '# ', after: '\n', ...tracker.current() }) if (/^[\t ]/.test(value)) { // To do: what effect has the character reference on tracking? value = '&#x' + value.charCodeAt(0).toString(16).toUpperCase() + ';' + value.slice(1) } value = value ? sequence + ' ' + value : sequence if (state.options.closeAtx) { value += ' ' + sequence } subexit() exit() return value }