encode-info.js 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. /**
  2. * @import {EncodeSides} from '../types.js'
  3. */
  4. import {classifyCharacter} from 'micromark-util-classify-character'
  5. /**
  6. * Check whether to encode (as a character reference) the characters
  7. * surrounding an attention run.
  8. *
  9. * Which characters are around an attention run influence whether it works or
  10. * not.
  11. *
  12. * See <https://github.com/orgs/syntax-tree/discussions/60> for more info.
  13. * See this markdown in a particular renderer to see what works:
  14. *
  15. * ```markdown
  16. * | | A (letter inside) | B (punctuation inside) | C (whitespace inside) | D (nothing inside) |
  17. * | ----------------------- | ----------------- | ---------------------- | --------------------- | ------------------ |
  18. * | 1 (letter outside) | x*y*z | x*.*z | x* *z | x**z |
  19. * | 2 (punctuation outside) | .*y*. | .*.*. | .* *. | .**. |
  20. * | 3 (whitespace outside) | x *y* z | x *.* z | x * * z | x ** z |
  21. * | 4 (nothing outside) | *x* | *.* | * * | ** |
  22. * ```
  23. *
  24. * @param {number} outside
  25. * Code point on the outer side of the run.
  26. * @param {number} inside
  27. * Code point on the inner side of the run.
  28. * @param {'*' | '_'} marker
  29. * Marker of the run.
  30. * Underscores are handled more strictly (they form less often) than
  31. * asterisks.
  32. * @returns {EncodeSides}
  33. * Whether to encode characters.
  34. */
  35. // Important: punctuation must never be encoded.
  36. // Punctuation is solely used by markdown constructs.
  37. // And by encoding itself.
  38. // Encoding them will break constructs or double encode things.
  39. export function encodeInfo(outside, inside, marker) {
  40. const outsideKind = classifyCharacter(outside)
  41. const insideKind = classifyCharacter(inside)
  42. // Letter outside:
  43. if (outsideKind === undefined) {
  44. return insideKind === undefined
  45. ? // Letter inside:
  46. // we have to encode *both* letters for `_` as it is looser.
  47. // it already forms for `*` (and GFMs `~`).
  48. marker === '_'
  49. ? {inside: true, outside: true}
  50. : {inside: false, outside: false}
  51. : insideKind === 1
  52. ? // Whitespace inside: encode both (letter, whitespace).
  53. {inside: true, outside: true}
  54. : // Punctuation inside: encode outer (letter)
  55. {inside: false, outside: true}
  56. }
  57. // Whitespace outside:
  58. if (outsideKind === 1) {
  59. return insideKind === undefined
  60. ? // Letter inside: already forms.
  61. {inside: false, outside: false}
  62. : insideKind === 1
  63. ? // Whitespace inside: encode both (whitespace).
  64. {inside: true, outside: true}
  65. : // Punctuation inside: already forms.
  66. {inside: false, outside: false}
  67. }
  68. // Punctuation outside:
  69. return insideKind === undefined
  70. ? // Letter inside: already forms.
  71. {inside: false, outside: false}
  72. : insideKind === 1
  73. ? // Whitespace inside: encode inner (whitespace).
  74. {inside: true, outside: false}
  75. : // Punctuation inside: already forms.
  76. {inside: false, outside: false}
  77. }