inline-code.js 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. /**
  2. * @import {State} from 'mdast-util-to-markdown'
  3. * @import {InlineCode, Parents} from 'mdast'
  4. */
  5. inlineCode.peek = inlineCodePeek
  6. /**
  7. * @param {InlineCode} node
  8. * @param {Parents | undefined} _
  9. * @param {State} state
  10. * @returns {string}
  11. */
  12. export function inlineCode(node, _, state) {
  13. let value = node.value || ''
  14. let sequence = '`'
  15. let index = -1
  16. // If there is a single grave accent on its own in the code, use a fence of
  17. // two.
  18. // If there are two in a row, use one.
  19. while (new RegExp('(^|[^`])' + sequence + '([^`]|$)').test(value)) {
  20. sequence += '`'
  21. }
  22. // If this is not just spaces or eols (tabs don’t count), and either the
  23. // first or last character are a space, eol, or tick, then pad with spaces.
  24. if (
  25. /[^ \r\n]/.test(value) &&
  26. ((/^[ \r\n]/.test(value) && /[ \r\n]$/.test(value)) || /^`|`$/.test(value))
  27. ) {
  28. value = ' ' + value + ' '
  29. }
  30. // We have a potential problem: certain characters after eols could result in
  31. // blocks being seen.
  32. // For example, if someone injected the string `'\n# b'`, then that would
  33. // result in an ATX heading.
  34. // We can’t escape characters in `inlineCode`, but because eols are
  35. // transformed to spaces when going from markdown to HTML anyway, we can swap
  36. // them out.
  37. while (++index < state.unsafe.length) {
  38. const pattern = state.unsafe[index]
  39. const expression = state.compilePattern(pattern)
  40. /** @type {RegExpExecArray | null} */
  41. let match
  42. // Only look for `atBreak`s.
  43. // Btw: note that `atBreak` patterns will always start the regex at LF or
  44. // CR.
  45. if (!pattern.atBreak) continue
  46. while ((match = expression.exec(value))) {
  47. let position = match.index
  48. // Support CRLF (patterns only look for one of the characters).
  49. if (
  50. value.charCodeAt(position) === 10 /* `\n` */ &&
  51. value.charCodeAt(position - 1) === 13 /* `\r` */
  52. ) {
  53. position--
  54. }
  55. value = value.slice(0, position) + ' ' + value.slice(match.index + 1)
  56. }
  57. }
  58. return sequence + value + sequence
  59. }
  60. /**
  61. * @returns {string}
  62. */
  63. function inlineCodePeek() {
  64. return '`'
  65. }