thematic-break.js 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. /**
  2. * @import {
  3. * Code,
  4. * Construct,
  5. * State,
  6. * TokenizeContext,
  7. * Tokenizer
  8. * } from 'micromark-util-types'
  9. */
  10. import { factorySpace } from 'micromark-factory-space';
  11. import { markdownLineEnding, markdownSpace } from 'micromark-util-character';
  12. /** @type {Construct} */
  13. export const thematicBreak = {
  14. name: 'thematicBreak',
  15. tokenize: tokenizeThematicBreak
  16. };
  17. /**
  18. * @this {TokenizeContext}
  19. * Context.
  20. * @type {Tokenizer}
  21. */
  22. function tokenizeThematicBreak(effects, ok, nok) {
  23. let size = 0;
  24. /** @type {NonNullable<Code>} */
  25. let marker;
  26. return start;
  27. /**
  28. * Start of thematic break.
  29. *
  30. * ```markdown
  31. * > | ***
  32. * ^
  33. * ```
  34. *
  35. * @type {State}
  36. */
  37. function start(code) {
  38. effects.enter("thematicBreak");
  39. // To do: parse indent like `markdown-rs`.
  40. return before(code);
  41. }
  42. /**
  43. * After optional whitespace, at marker.
  44. *
  45. * ```markdown
  46. * > | ***
  47. * ^
  48. * ```
  49. *
  50. * @type {State}
  51. */
  52. function before(code) {
  53. marker = code;
  54. return atBreak(code);
  55. }
  56. /**
  57. * After something, before something else.
  58. *
  59. * ```markdown
  60. * > | ***
  61. * ^
  62. * ```
  63. *
  64. * @type {State}
  65. */
  66. function atBreak(code) {
  67. if (code === marker) {
  68. effects.enter("thematicBreakSequence");
  69. return sequence(code);
  70. }
  71. if (size >= 3 && (code === null || markdownLineEnding(code))) {
  72. effects.exit("thematicBreak");
  73. return ok(code);
  74. }
  75. return nok(code);
  76. }
  77. /**
  78. * In sequence.
  79. *
  80. * ```markdown
  81. * > | ***
  82. * ^
  83. * ```
  84. *
  85. * @type {State}
  86. */
  87. function sequence(code) {
  88. if (code === marker) {
  89. effects.consume(code);
  90. size++;
  91. return sequence;
  92. }
  93. effects.exit("thematicBreakSequence");
  94. return markdownSpace(code) ? factorySpace(effects, atBreak, "whitespace")(code) : atBreak(code);
  95. }
  96. }