heading.js 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. /**
  2. * @import {Info, State} from 'mdast-util-to-markdown'
  3. * @import {Heading, Parents} from 'mdast'
  4. */
  5. import {encodeCharacterReference} from '../util/encode-character-reference.js'
  6. import {formatHeadingAsSetext} from '../util/format-heading-as-setext.js'
  7. /**
  8. * @param {Heading} node
  9. * @param {Parents | undefined} _
  10. * @param {State} state
  11. * @param {Info} info
  12. * @returns {string}
  13. */
  14. export function heading(node, _, state, info) {
  15. const rank = Math.max(Math.min(6, node.depth || 1), 1)
  16. const tracker = state.createTracker(info)
  17. if (formatHeadingAsSetext(node, state)) {
  18. const exit = state.enter('headingSetext')
  19. const subexit = state.enter('phrasing')
  20. const value = state.containerPhrasing(node, {
  21. ...tracker.current(),
  22. before: '\n',
  23. after: '\n'
  24. })
  25. subexit()
  26. exit()
  27. return (
  28. value +
  29. '\n' +
  30. (rank === 1 ? '=' : '-').repeat(
  31. // The whole size…
  32. value.length -
  33. // Minus the position of the character after the last EOL (or
  34. // 0 if there is none)…
  35. (Math.max(value.lastIndexOf('\r'), value.lastIndexOf('\n')) + 1)
  36. )
  37. )
  38. }
  39. const sequence = '#'.repeat(rank)
  40. const exit = state.enter('headingAtx')
  41. const subexit = state.enter('phrasing')
  42. // Note: for proper tracking, we should reset the output positions when there
  43. // is no content returned, because then the space is not output.
  44. // Practically, in that case, there is no content, so it doesn’t matter that
  45. // we’ve tracked one too many characters.
  46. tracker.move(sequence + ' ')
  47. let value = state.containerPhrasing(node, {
  48. before: '# ',
  49. after: '\n',
  50. ...tracker.current()
  51. })
  52. if (/^[\t ]/.test(value)) {
  53. // To do: what effect has the character reference on tracking?
  54. value = encodeCharacterReference(value.charCodeAt(0)) + value.slice(1)
  55. }
  56. value = value ? sequence + ' ' + value : sequence
  57. if (state.options.closeAtx) {
  58. value += ' ' + sequence
  59. }
  60. subexit()
  61. exit()
  62. return value
  63. }