/** * @typedef {import('micromark-util-types').Construct} Construct * @typedef {import('micromark-util-types').Exiter} Exiter * @typedef {import('micromark-util-types').State} State * @typedef {import('micromark-util-types').TokenizeContext} TokenizeContext * @typedef {import('micromark-util-types').Tokenizer} Tokenizer */ import {factorySpace} from 'micromark-factory-space' import {markdownSpace} from 'micromark-util-character' /** @type {Construct} */ export const blockQuote = { name: 'blockQuote', tokenize: tokenizeBlockQuoteStart, continuation: { tokenize: tokenizeBlockQuoteContinuation }, exit } /** * @this {TokenizeContext} * @type {Tokenizer} */ function tokenizeBlockQuoteStart(effects, ok, nok) { const self = this return start /** * Start of block quote. * * ```markdown * > | > a * ^ * ``` * * @type {State} */ function start(code) { if (code === 62) { const state = self.containerState if (!state.open) { effects.enter('blockQuote', { _container: true }) state.open = true } effects.enter('blockQuotePrefix') effects.enter('blockQuoteMarker') effects.consume(code) effects.exit('blockQuoteMarker') return after } return nok(code) } /** * After `>`, before optional whitespace. * * ```markdown * > | > a * ^ * ``` * * @type {State} */ function after(code) { if (markdownSpace(code)) { effects.enter('blockQuotePrefixWhitespace') effects.consume(code) effects.exit('blockQuotePrefixWhitespace') effects.exit('blockQuotePrefix') return ok } effects.exit('blockQuotePrefix') return ok(code) } } /** * Start of block quote continuation. * * ```markdown * | > a * > | > b * ^ * ``` * * @this {TokenizeContext} * @type {Tokenizer} */ function tokenizeBlockQuoteContinuation(effects, ok, nok) { const self = this return contStart /** * Start of block quote continuation. * * Also used to parse the first block quote opening. * * ```markdown * | > a * > | > b * ^ * ``` * * @type {State} */ function contStart(code) { if (markdownSpace(code)) { // Always populated by defaults. return factorySpace( effects, contBefore, 'linePrefix', self.parser.constructs.disable.null.includes('codeIndented') ? undefined : 4 )(code) } return contBefore(code) } /** * At `>`, after optional whitespace. * * Also used to parse the first block quote opening. * * ```markdown * | > a * > | > b * ^ * ``` * * @type {State} */ function contBefore(code) { return effects.attempt(blockQuote, ok, nok)(code) } } /** @type {Exiter} */ function exit(effects) { effects.exit('blockQuote') }