import type { Token } from '../types.js'; import { type ContextStash, type TokenHandler, writeIndented, } from '../MarkdownSerializer.js'; import { getHtmlInlineFormatTokensHandlers, getInlineTokensHandlers, } from './inline_token_handlers.js'; import { TokenSource } from '../TokenSource.js'; import { numberString } from '../utils.js'; import { getTableTokensHandlers } from './table_token_handlers.js'; import { getBasicTokensHandlers } from './basic_token_handlers.js'; import { getFootnoteTokensHandlers } from './footnote_token_handlers.js'; function getLongDefinitionTokensHandlers(): Record< string, Array > { return { ...getInlineTokensHandlers(), 'hardbreak': [ (token: Token, ctx: ContextStash) => { ctx.current.log('\n'); if (ctx.current.meta['para_hidden']) { ctx.current.itemSymbol = ''; } ctx.current.itemRow++; }, ], 'code_block': [ (token: Token, ctx: ContextStash) => { if (ctx.current.itemRow === 0) { ctx.current.itemRow++; } if (ctx.output.colPos > 0) { ctx.current.log('\n'); } if (!ctx.output.endsWith('\n\n')) { ctx.current.log('\n'); } ctx.stash('getLongDefinitionTokensHandlers.code_block'); ctx.current.log = (txt: string) => { writeIndented(ctx.output, txt, ctx.current, token); }; ctx.current.log( token.content .split('\n') .map((t) => t.trim() ? (' ' + t) : '') .join('\n') + '\n', ); ctx.unstash('getLongDefinitionTokensHandlers.code_block'); ctx.current.itemRow++; }, ], 'paragraph_open': [ (token: Token, ctx: ContextStash) => { ctx.stash('getLongDefinitionTokensHandlers.paragraph_open'); ctx.current.meta['para_hidden'] = token.hidden; }, ], 'paragraph_close': [ (token: Token, ctx: ContextStash) => { ctx.unstash('getLongDefinitionTokensHandlers.paragraph_close'); if (ctx.output.colPos !== 0) { // ctx.current.log('\n'); } ctx.current.itemRow++; }, ], 'dt_open': [ (token: Token, ctx: ContextStash) => { ctx.current.itemSymbol = ''; ctx.current.itemRow = 0; }, ], 'dt_close': [ (token: Token, ctx: ContextStash) => { if (ctx.output.colPos !== 0) { ctx.current.log('\n'); } }, ], 'dd_open': [ (token: Token, ctx: ContextStash) => { if (!ctx.output.endsWith('\n\n')) { ctx.current.log('\n'); } ctx.current.itemSymbol = ': '; ctx.current.itemRow = 0; }, ], 'dd_close': [ (token: Token, ctx: ContextStash) => { if (ctx.output.colPos !== 0) { ctx.current.log('\n'); } }, ], 'dl_open': [ (token: Token, ctx: ContextStash) => { ctx.stash('getLongDefinitionTokensHandlers.dl_open'); ctx.current.listPath.push('dl'); ctx.current.listType = 'dl'; }, ], 'dl_close': [ (token: Token, ctx: ContextStash) => { ctx.unstash('getLongDefinitionTokensHandlers.dl_close'); }, ], }; } function getShortDefinitionTokensHandlers(): Record< string, Array > { const rollbackList = ( token: Token, ctx: ContextStash, tokenSource: TokenSource, ) => { const rollbackPos = ctx.current.meta['def_rollback']; if (!ctx.current.meta['def_token_start']) { throw new Error('No def_token_start'); } const outputPos = ctx.current.meta['def_output_pos']; if (!ctx.current.meta['def_output_pos']) { throw new Error('No def_output_pos'); } tokenSource.rewind(ctx.current.meta['def_token_start']); ctx.rollback(rollbackPos, 'rollbackList, ' + token.type); ctx.output.rollback(outputPos); ctx.stash('getShortDefinitionTokensHandlers.rollbackList'); ctx.current.listPath.push('dl'); ctx.current.listType = 'dl'; ctx.current.handlers = getLongDefinitionTokensHandlers(); }; return { 'dl_open': [ (token: Token, ctx: ContextStash, tokenSource: TokenSource) => { const rollbackPos = ctx.stash( 'getShortDefinitionTokensHandlers.dl_open', ); ctx.current.meta['def_rollback'] = rollbackPos; ctx.current.meta['def_token_start'] = tokenSource.pos; ctx.current.meta['def_output_pos'] = ctx.output.chunkPos; ctx.current.listPath.push('dl'); ctx.current.listType = 'dl'; ctx.current.handlers = getShortDefinitionTokensHandlers(); }, ], 'dl_close': [ (token: Token, ctx: ContextStash) => { ctx.unstash('getShortDefinitionTokensHandlers.dl_close'); }, ], ...getInlineTokensHandlers(), 'hardbreak': [ rollbackList, ], 'code_block': [ rollbackList, ], 'paragraph_open': [ (token: Token, ctx: ContextStash) => { // Skip, as paragraphs are implied by newlines }, ], 'paragraph_close': [ (token: Token, ctx: ContextStash) => { if (ctx.output.colPos !== 0) { // ctx.current.log('\n'); } }, ], 'dt_open': [ (token: Token, ctx: ContextStash) => { ctx.current.itemSymbol = ''; ctx.current.itemRow = 0; }, ], 'dt_close': [ (token: Token, ctx: ContextStash) => { if (ctx.output.colPos !== 0) { ctx.current.log('\n'); } }, ], 'dd_open': [ (token: Token, ctx: ContextStash) => { ctx.current.itemSymbol = ' ~ '; ctx.current.itemRow = 0; }, ], 'dd_close': [ (token: Token, ctx: ContextStash) => { if (ctx.output.colPos !== 0) { ctx.current.log('\n'); } }, ], }; } function getHtmlListItemTokensHandlers(): Record> { return { ...getInlineTokensHandlers(), ...getHtmlInlineFormatTokensHandlers(), ...getTableTokensHandlers(), ...getBasicTokensHandlers(), ...getFootnoteTokensHandlers(), ...getListsTokensHandlers(), }; } export function getListsTokensHandlers(): Record> { return { 'dl_open': getShortDefinitionTokensHandlers()['dl_open'], 'paragraph_close': [ (token: Token, ctx: ContextStash) => { if (ctx.output.colPos !== 0) { ctx.current.log('\n', token); } ctx.current.itemRow++; }, ], 'task_list_open': [ (token: Token, ctx: ContextStash) => { ctx.stash('getListsTokensHandlers.task_list_open'); ctx.current.listPath.push('tl'); ctx.current.listType = 'tl'; ctx.current.itemSymbol = ''; ctx.current.itemNumber = 0; }, ], 'task_list_close': [ (token: Token, ctx: ContextStash) => { ctx.unstash('getListsTokensHandlers.task_list_close'); if (ctx.output.colPos !== 0) { ctx.current.log('\n'); } }, ], 'task_item_open': [ (token: Token, ctx: ContextStash) => { ctx.current.itemRow = 0; ctx.current.itemNumber++; ctx.current.itemSymbol = token.attrGet('checked') ? 'x' : ''; if (ctx.output.colPos !== 0) { ctx.current.log('\n'); } }, ], 'task_item_close': [ (token: Token, ctx: ContextStash) => { if (ctx.output.colPos !== 0) { ctx.current.log('\n'); } }, ], 'bullet_list_open': [ (token: Token, ctx: ContextStash) => { ctx.stash('getListsTokensHandlers.bullet_list_open'); ctx.current.listPath.push('ul'); ctx.current.listType = 'ul'; ctx.current.itemSymbol = ''; ctx.current.itemNumber = 0; }, ], 'bullet_list_close': [ (token: Token, ctx: ContextStash) => { ctx.unstash('getListsTokensHandlers.bullet_list_close'); if (ctx.output.colPos !== 0) { ctx.current.log('\n'); } }, ], 'ordered_list_open': [ (token: Token, ctx: ContextStash) => { { ctx.stash('getListsTokensHandlers.ordered_list_open'); ctx.current.listPath.push('ol'); ctx.current.listType = 'ol'; ctx.current.itemSymbol = ''; const symbol = token.attrGet('symbol'); if (symbol) { ctx.current.meta['list_symbol'] = symbol; } else { ctx.current.meta['list_symbol'] = '1'; } const start = token.attrGet('start'); if (start) { ctx.current.itemNumber = (+start || 1) - 1; } else { ctx.current.itemNumber = 0; } } }, ], 'ordered_list_close': [ (token: Token, ctx: ContextStash) => { ctx.unstash('getListsTokensHandlers.ordered_list_close'); if (ctx.output.colPos !== 0) { ctx.current.log('\n'); } }, ], 'list_item_open': [ (token: Token, ctx: ContextStash) => { ctx.current.itemRow = 0; if (token.attrGet('type') !== 'none') { ctx.current.itemNumber++; } ctx.current.itemSymbol = token.info || token.markup; if (!ctx.current.itemSymbol) { ctx.current.itemSymbol = numberString( ctx.current.itemNumber, ctx.current.meta['list_symbol'] || '1', ); } if (ctx.output.colPos !== 0) { ctx.current.log('\n'); } if (ctx.current.meta['use_html_list_items']) { ctx.stash('list_item_open'); ctx.current.handlers = { ...ctx.current.handlers, ...getHtmlInlineFormatTokensHandlers(), }; } }, ], 'list_item_close': [ (token: Token, ctx: ContextStash) => { if (ctx.output.colPos !== 0) { ctx.current.log('\n'); } if (ctx.current.meta['use_html_list_items']) { ctx.unstash('/list_item_open'); } }, ], 'blockquote_open': [ (token: Token, ctx: ContextStash) => { ctx.stash('getListsTokensHandlers.blockquote_open'); ctx.current.blockquoteCnt++; if (ctx.output.colPos !== 0) { ctx.current.log('\n'); } }, ], 'blockquote_close': [ (token: Token, ctx: ContextStash) => { ctx.unstash('getListsTokensHandlers.blockquote_close'); }, ], }; } export function getHtmlListsTokensHandlers(): Record< string, Array > { // 'dl_open': getShortDefinitionTokensHandlers()['dl_open'], return { 'bullet_list_open': [ (token: Token, ctx: ContextStash) => { if (token.attrGet('not_first_para')) { ctx.current.log('
\n', token); } ctx.current.log('
    ', token); }, ], 'bullet_list_close': [ (token: Token, ctx: ContextStash) => { ctx.current.log('
', token); }, ], 'ordered_list_open': [ (token: Token, ctx: ContextStash) => { { if (token.attrGet('not_first_para')) { ctx.current.log('
\n', token); } ctx.current.listPath.push('ol'); ctx.current.listType = 'ol'; ctx.current.itemSymbol = ''; const symbol = token.attrGet('symbol'); if (symbol) { ctx.current.meta['list_symbol'] = symbol; } else { ctx.current.meta['list_symbol'] = '1'; } const start = token.attrGet('start'); if (start) { ctx.current.itemNumber = (+start || 1) - 1; ctx.current.log(`
    `, token); } else { ctx.current.itemNumber = 0; ctx.current.log('
      ', token); } } }, ], 'ordered_list_close': [ (token: Token, ctx: ContextStash) => { ctx.current.log('
    ', token); }, ], 'list_item_open': [ (token: Token, ctx: ContextStash) => { ctx.current.itemSymbol = token.info || token.markup; if (!ctx.current.itemSymbol) { // TODO ctx.current.itemSymbol = numberString( ctx.current.itemNumber, ctx.current.meta['list_symbol'] || '1', ); } ctx.current.log('
  1. ', token); if (token.attrGet('type') !== 'none') { ctx.current.itemNumber++; } }, ], 'list_item_close': [ (token: Token, ctx: ContextStash) => { ctx.current.log('
  2. ', token); }, ], }; }