/** * @typedef {import('mdast').Delete} Delete * * @typedef {import('mdast-util-from-markdown').CompileContext} CompileContext * @typedef {import('mdast-util-from-markdown').Extension} FromMarkdownExtension * @typedef {import('mdast-util-from-markdown').Handle} FromMarkdownHandle * * @typedef {import('mdast-util-to-markdown').ConstructName} ConstructName * @typedef {import('mdast-util-to-markdown').Handle} ToMarkdownHandle * @typedef {import('mdast-util-to-markdown').Options} ToMarkdownExtension */ /** * List of constructs that occur in phrasing (paragraphs, headings), but cannot * contain strikethrough. * So they sort of cancel each other out. * Note: could use a better name. * * Note: keep in sync with: * * @type {Array} */ const constructsWithoutStrikethrough = [ 'autolink', 'destinationLiteral', 'destinationRaw', 'reference', 'titleQuote', 'titleApostrophe' ] handleDelete.peek = peekDelete /** * Create an extension for `mdast-util-from-markdown` to enable GFM * strikethrough in markdown. * * @returns {FromMarkdownExtension} * Extension for `mdast-util-from-markdown` to enable GFM strikethrough. */ export function gfmStrikethroughFromMarkdown() { return { canContainEols: ['delete'], enter: {strikethrough: enterStrikethrough}, exit: {strikethrough: exitStrikethrough} } } /** * Create an extension for `mdast-util-to-markdown` to enable GFM * strikethrough in markdown. * * @returns {ToMarkdownExtension} * Extension for `mdast-util-to-markdown` to enable GFM strikethrough. */ export function gfmStrikethroughToMarkdown() { return { unsafe: [ { character: '~', inConstruct: 'phrasing', notInConstruct: constructsWithoutStrikethrough } ], handlers: {delete: handleDelete} } } /** * @this {CompileContext} * @type {FromMarkdownHandle} */ function enterStrikethrough(token) { this.enter({type: 'delete', children: []}, token) } /** * @this {CompileContext} * @type {FromMarkdownHandle} */ function exitStrikethrough(token) { this.exit(token) } /** * @type {ToMarkdownHandle} * @param {Delete} node */ function handleDelete(node, _, state, info) { const tracker = state.createTracker(info) const exit = state.enter('strikethrough') let value = tracker.move('~~') value += state.containerPhrasing(node, { ...tracker.current(), before: value, after: '~' }) value += tracker.move('~~') exit() return value } /** @type {ToMarkdownHandle} */ function peekDelete() { return '~' }