index.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /**
  2. * @import {
  3. * Code,
  4. * Effects,
  5. * State,
  6. * TokenType
  7. * } from 'micromark-util-types'
  8. */
  9. import {factorySpace} from 'micromark-factory-space'
  10. import {markdownLineEnding} from 'micromark-util-character'
  11. import {codes, constants, types} from 'micromark-util-symbol'
  12. /**
  13. * Parse titles.
  14. *
  15. * ###### Examples
  16. *
  17. * ```markdown
  18. * "a"
  19. * 'b'
  20. * (c)
  21. * "a
  22. * b"
  23. * 'a
  24. * b'
  25. * (a\)b)
  26. * ```
  27. *
  28. * @param {Effects} effects
  29. * Context.
  30. * @param {State} ok
  31. * State switched to when successful.
  32. * @param {State} nok
  33. * State switched to when unsuccessful.
  34. * @param {TokenType} type
  35. * Type of the whole title (`"a"`, `'b'`, `(c)`).
  36. * @param {TokenType} markerType
  37. * Type for the markers (`"`, `'`, `(`, and `)`).
  38. * @param {TokenType} stringType
  39. * Type for the value (`a`).
  40. * @returns {State}
  41. * Start state.
  42. */
  43. export function factoryTitle(effects, ok, nok, type, markerType, stringType) {
  44. /** @type {NonNullable<Code>} */
  45. let marker
  46. return start
  47. /**
  48. * Start of title.
  49. *
  50. * ```markdown
  51. * > | "a"
  52. * ^
  53. * ```
  54. *
  55. * @type {State}
  56. */
  57. function start(code) {
  58. if (
  59. code === codes.quotationMark ||
  60. code === codes.apostrophe ||
  61. code === codes.leftParenthesis
  62. ) {
  63. effects.enter(type)
  64. effects.enter(markerType)
  65. effects.consume(code)
  66. effects.exit(markerType)
  67. marker = code === codes.leftParenthesis ? codes.rightParenthesis : code
  68. return begin
  69. }
  70. return nok(code)
  71. }
  72. /**
  73. * After opening marker.
  74. *
  75. * This is also used at the closing marker.
  76. *
  77. * ```markdown
  78. * > | "a"
  79. * ^
  80. * ```
  81. *
  82. * @type {State}
  83. */
  84. function begin(code) {
  85. if (code === marker) {
  86. effects.enter(markerType)
  87. effects.consume(code)
  88. effects.exit(markerType)
  89. effects.exit(type)
  90. return ok
  91. }
  92. effects.enter(stringType)
  93. return atBreak(code)
  94. }
  95. /**
  96. * At something, before something else.
  97. *
  98. * ```markdown
  99. * > | "a"
  100. * ^
  101. * ```
  102. *
  103. * @type {State}
  104. */
  105. function atBreak(code) {
  106. if (code === marker) {
  107. effects.exit(stringType)
  108. return begin(marker)
  109. }
  110. if (code === codes.eof) {
  111. return nok(code)
  112. }
  113. // Note: blank lines can’t exist in content.
  114. if (markdownLineEnding(code)) {
  115. // To do: use `space_or_tab_eol_with_options`, connect.
  116. effects.enter(types.lineEnding)
  117. effects.consume(code)
  118. effects.exit(types.lineEnding)
  119. return factorySpace(effects, atBreak, types.linePrefix)
  120. }
  121. effects.enter(types.chunkString, {contentType: constants.contentTypeString})
  122. return inside(code)
  123. }
  124. /**
  125. *
  126. *
  127. * @type {State}
  128. */
  129. function inside(code) {
  130. if (code === marker || code === codes.eof || markdownLineEnding(code)) {
  131. effects.exit(types.chunkString)
  132. return atBreak(code)
  133. }
  134. effects.consume(code)
  135. return code === codes.backslash ? escape : inside
  136. }
  137. /**
  138. * After `\`, at a special character.
  139. *
  140. * ```markdown
  141. * > | "a\*b"
  142. * ^
  143. * ```
  144. *
  145. * @type {State}
  146. */
  147. function escape(code) {
  148. if (code === marker || code === codes.backslash) {
  149. effects.consume(code)
  150. return inside
  151. }
  152. return inside(code)
  153. }
  154. }