/** * @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').Options} ToMarkdownExtension * @typedef {import('mdast-util-to-markdown').Handle} ToMarkdownHandle */ import {containerPhrasing} from 'mdast-util-to-markdown/lib/util/container-phrasing.js' import {track} from 'mdast-util-to-markdown/lib/util/track.js' // To do: next major: expose functions. // To do: next major: use `state`, state utilities. /** * 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 /** * Extension for `mdast-util-from-markdown` to enable GFM strikethrough. * * @type {FromMarkdownExtension} */ export const gfmStrikethroughFromMarkdown = { canContainEols: ['delete'], enter: {strikethrough: enterStrikethrough}, exit: {strikethrough: exitStrikethrough} } /** * Extension for `mdast-util-to-markdown` to enable GFM strikethrough. * * @type {ToMarkdownExtension} */ export const gfmStrikethroughToMarkdown = { 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, _, context, safeOptions) { const tracker = track(safeOptions) const exit = context.enter('strikethrough') let value = tracker.move('~~') value += containerPhrasing(node, context, { ...tracker.current(), before: value, after: '~' }) value += tracker.move('~~') exit() return value } /** @type {ToMarkdownHandle} */ function peekDelete() { return '~' }