/** | |
* @typedef {import('micromark-util-types').Code} Code | |
* @typedef {import('micromark-util-types').Construct} Construct | |
* @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 {markdownLineEnding, markdownSpace} from 'micromark-util-character' | |
/** @type {Construct} */ | |
export const thematicBreak = { | |
name: 'thematicBreak', | |
tokenize: tokenizeThematicBreak | |
} | |
/** | |
* @this {TokenizeContext} | |
* @type {Tokenizer} | |
*/ | |
function tokenizeThematicBreak(effects, ok, nok) { | |
let size = 0 | |
/** @type {NonNullable<Code>} */ | |
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) | |
} | |
} | |