heading-atx.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. 'use strict'
  2. var assert = require('assert')
  3. var codes = require('../character/codes.js')
  4. var markdownLineEnding = require('../character/markdown-line-ending.js')
  5. var markdownLineEndingOrSpace = require('../character/markdown-line-ending-or-space.js')
  6. var markdownSpace = require('../character/markdown-space.js')
  7. var constants = require('../constant/constants.js')
  8. var types = require('../constant/types.js')
  9. var chunkedSplice = require('../util/chunked-splice.js')
  10. var factorySpace = require('./factory-space.js')
  11. function _interopDefaultLegacy(e) {
  12. return e && typeof e === 'object' && 'default' in e ? e : {default: e}
  13. }
  14. var assert__default = /*#__PURE__*/ _interopDefaultLegacy(assert)
  15. var headingAtx = {
  16. name: 'headingAtx',
  17. tokenize: tokenizeHeadingAtx,
  18. resolve: resolveHeadingAtx
  19. }
  20. function resolveHeadingAtx(events, context) {
  21. var contentEnd = events.length - 2
  22. var contentStart = 3
  23. var content
  24. var text
  25. // Prefix whitespace, part of the opening.
  26. if (events[contentStart][1].type === types.whitespace) {
  27. contentStart += 2
  28. }
  29. // Suffix whitespace, part of the closing.
  30. if (
  31. contentEnd - 2 > contentStart &&
  32. events[contentEnd][1].type === types.whitespace
  33. ) {
  34. contentEnd -= 2
  35. }
  36. if (
  37. events[contentEnd][1].type === types.atxHeadingSequence &&
  38. (contentStart === contentEnd - 1 ||
  39. (contentEnd - 4 > contentStart &&
  40. events[contentEnd - 2][1].type === types.whitespace))
  41. ) {
  42. contentEnd -= contentStart + 1 === contentEnd ? 2 : 4
  43. }
  44. if (contentEnd > contentStart) {
  45. content = {
  46. type: types.atxHeadingText,
  47. start: events[contentStart][1].start,
  48. end: events[contentEnd][1].end
  49. }
  50. text = {
  51. type: types.chunkText,
  52. start: events[contentStart][1].start,
  53. end: events[contentEnd][1].end,
  54. contentType: constants.contentTypeText
  55. }
  56. chunkedSplice(events, contentStart, contentEnd - contentStart + 1, [
  57. ['enter', content, context],
  58. ['enter', text, context],
  59. ['exit', text, context],
  60. ['exit', content, context]
  61. ])
  62. }
  63. return events
  64. }
  65. function tokenizeHeadingAtx(effects, ok, nok) {
  66. var self = this
  67. var size = 0
  68. return start
  69. function start(code) {
  70. assert__default['default'](code === codes.numberSign, 'expected `#`')
  71. effects.enter(types.atxHeading)
  72. effects.enter(types.atxHeadingSequence)
  73. return fenceOpenInside(code)
  74. }
  75. function fenceOpenInside(code) {
  76. if (
  77. code === codes.numberSign &&
  78. size++ < constants.atxHeadingOpeningFenceSizeMax
  79. ) {
  80. effects.consume(code)
  81. return fenceOpenInside
  82. }
  83. if (code === codes.eof || markdownLineEndingOrSpace(code)) {
  84. effects.exit(types.atxHeadingSequence)
  85. return self.interrupt ? ok(code) : headingBreak(code)
  86. }
  87. return nok(code)
  88. }
  89. function headingBreak(code) {
  90. if (code === codes.numberSign) {
  91. effects.enter(types.atxHeadingSequence)
  92. return sequence(code)
  93. }
  94. if (code === codes.eof || markdownLineEnding(code)) {
  95. effects.exit(types.atxHeading)
  96. return ok(code)
  97. }
  98. if (markdownSpace(code)) {
  99. return factorySpace(effects, headingBreak, types.whitespace)(code)
  100. }
  101. effects.enter(types.atxHeadingText)
  102. return data(code)
  103. }
  104. function sequence(code) {
  105. if (code === codes.numberSign) {
  106. effects.consume(code)
  107. return sequence
  108. }
  109. effects.exit(types.atxHeadingSequence)
  110. return headingBreak(code)
  111. }
  112. function data(code) {
  113. if (
  114. code === codes.eof ||
  115. code === codes.numberSign ||
  116. markdownLineEndingOrSpace(code)
  117. ) {
  118. effects.exit(types.atxHeadingText)
  119. return headingBreak(code)
  120. }
  121. effects.consume(code)
  122. return data
  123. }
  124. }
  125. module.exports = headingAtx