content.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /**
  2. * @import {
  3. * Construct,
  4. * Resolver,
  5. * State,
  6. * TokenizeContext,
  7. * Tokenizer,
  8. * Token
  9. * } from 'micromark-util-types'
  10. */
  11. import { factorySpace } from 'micromark-factory-space';
  12. import { markdownLineEnding } from 'micromark-util-character';
  13. import { subtokenize } from 'micromark-util-subtokenize';
  14. /**
  15. * No name because it must not be turned off.
  16. * @type {Construct}
  17. */
  18. export const content = {
  19. resolve: resolveContent,
  20. tokenize: tokenizeContent
  21. };
  22. /** @type {Construct} */
  23. const continuationConstruct = {
  24. partial: true,
  25. tokenize: tokenizeContinuation
  26. };
  27. /**
  28. * Content is transparent: it’s parsed right now. That way, definitions are also
  29. * parsed right now: before text in paragraphs (specifically, media) are parsed.
  30. *
  31. * @type {Resolver}
  32. */
  33. function resolveContent(events) {
  34. subtokenize(events);
  35. return events;
  36. }
  37. /**
  38. * @this {TokenizeContext}
  39. * Context.
  40. * @type {Tokenizer}
  41. */
  42. function tokenizeContent(effects, ok) {
  43. /** @type {Token | undefined} */
  44. let previous;
  45. return chunkStart;
  46. /**
  47. * Before a content chunk.
  48. *
  49. * ```markdown
  50. * > | abc
  51. * ^
  52. * ```
  53. *
  54. * @type {State}
  55. */
  56. function chunkStart(code) {
  57. effects.enter("content");
  58. previous = effects.enter("chunkContent", {
  59. contentType: "content"
  60. });
  61. return chunkInside(code);
  62. }
  63. /**
  64. * In a content chunk.
  65. *
  66. * ```markdown
  67. * > | abc
  68. * ^^^
  69. * ```
  70. *
  71. * @type {State}
  72. */
  73. function chunkInside(code) {
  74. if (code === null) {
  75. return contentEnd(code);
  76. }
  77. // To do: in `markdown-rs`, each line is parsed on its own, and everything
  78. // is stitched together resolving.
  79. if (markdownLineEnding(code)) {
  80. return effects.check(continuationConstruct, contentContinue, contentEnd)(code);
  81. }
  82. // Data.
  83. effects.consume(code);
  84. return chunkInside;
  85. }
  86. /**
  87. *
  88. *
  89. * @type {State}
  90. */
  91. function contentEnd(code) {
  92. effects.exit("chunkContent");
  93. effects.exit("content");
  94. return ok(code);
  95. }
  96. /**
  97. *
  98. *
  99. * @type {State}
  100. */
  101. function contentContinue(code) {
  102. effects.consume(code);
  103. effects.exit("chunkContent");
  104. previous.next = effects.enter("chunkContent", {
  105. contentType: "content",
  106. previous
  107. });
  108. previous = previous.next;
  109. return chunkInside;
  110. }
  111. }
  112. /**
  113. * @this {TokenizeContext}
  114. * Context.
  115. * @type {Tokenizer}
  116. */
  117. function tokenizeContinuation(effects, ok, nok) {
  118. const self = this;
  119. return startLookahead;
  120. /**
  121. *
  122. *
  123. * @type {State}
  124. */
  125. function startLookahead(code) {
  126. effects.exit("chunkContent");
  127. effects.enter("lineEnding");
  128. effects.consume(code);
  129. effects.exit("lineEnding");
  130. return factorySpace(effects, prefixed, "linePrefix");
  131. }
  132. /**
  133. *
  134. *
  135. * @type {State}
  136. */
  137. function prefixed(code) {
  138. if (code === null || markdownLineEnding(code)) {
  139. return nok(code);
  140. }
  141. // Always populated by defaults.
  142. const tail = self.events[self.events.length - 1];
  143. if (!self.parser.constructs.disable.null.includes('codeIndented') && tail && tail[1].type === "linePrefix" && tail[2].sliceSerialize(tail[1], true).length >= 4) {
  144. return ok(code);
  145. }
  146. return effects.interrupt(self.parser.constructs.flow, nok, ok)(code);
  147. }
  148. }