/** * @import { * Code, * Construct, * State, * TokenizeContext, * Tokenizer * } from 'micromark-util-types' */ import { factorySpace } from 'micromark-factory-space'; import { markdownLineEnding, markdownSpace } from 'micromark-util-character'; /** @type {Construct} */ export const thematicBreak = { name: 'thematicBreak', tokenize: tokenizeThematicBreak }; /** * @this {TokenizeContext} * Context. * @type {Tokenizer} */ function tokenizeThematicBreak(effects, ok, nok) { let size = 0; /** @type {NonNullable} */ let marker; return start; /** * Start of thematic break. * * ```markdown * > | *** * ^ * ``` * * @type {State} */ function start(code) { effects.enter("thematicBreak"); // To do: parse indent like `markdown-rs`. return before(code); } /** * After optional whitespace, at marker. * * ```markdown * > | *** * ^ * ``` * * @type {State} */ function before(code) { marker = code; return atBreak(code); } /** * After something, before something else. * * ```markdown * > | *** * ^ * ``` * * @type {State} */ function atBreak(code) { if (code === marker) { effects.enter("thematicBreakSequence"); return sequence(code); } if (size >= 3 && (code === null || markdownLineEnding(code))) { effects.exit("thematicBreak"); return ok(code); } return nok(code); } /** * In sequence. * * ```markdown * > | *** * ^ * ``` * * @type {State} */ function sequence(code) { if (code === marker) { effects.consume(code); size++; return sequence; } effects.exit("thematicBreakSequence"); return markdownSpace(code) ? factorySpace(effects, atBreak, "whitespace")(code) : atBreak(code); } }