index.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. /**
  2. * @typedef {import('mdast').Nodes} Nodes
  3. *
  4. * @typedef Options
  5. * Configuration (optional).
  6. * @property {boolean | null | undefined} [includeImageAlt=true]
  7. * Whether to use `alt` for `image`s (default: `true`).
  8. * @property {boolean | null | undefined} [includeHtml=true]
  9. * Whether to use `value` of HTML (default: `true`).
  10. */
  11. /** @type {Options} */
  12. const emptyOptions = {}
  13. /**
  14. * Get the text content of a node or list of nodes.
  15. *
  16. * Prefers the node’s plain-text fields, otherwise serializes its children,
  17. * and if the given value is an array, serialize the nodes in it.
  18. *
  19. * @param {unknown} [value]
  20. * Thing to serialize, typically `Node`.
  21. * @param {Options | null | undefined} [options]
  22. * Configuration (optional).
  23. * @returns {string}
  24. * Serialized `value`.
  25. */
  26. export function toString(value, options) {
  27. const settings = options || emptyOptions
  28. const includeImageAlt =
  29. typeof settings.includeImageAlt === 'boolean'
  30. ? settings.includeImageAlt
  31. : true
  32. const includeHtml =
  33. typeof settings.includeHtml === 'boolean' ? settings.includeHtml : true
  34. return one(value, includeImageAlt, includeHtml)
  35. }
  36. /**
  37. * One node or several nodes.
  38. *
  39. * @param {unknown} value
  40. * Thing to serialize.
  41. * @param {boolean} includeImageAlt
  42. * Include image `alt`s.
  43. * @param {boolean} includeHtml
  44. * Include HTML.
  45. * @returns {string}
  46. * Serialized node.
  47. */
  48. function one(value, includeImageAlt, includeHtml) {
  49. if (node(value)) {
  50. if ('value' in value) {
  51. return value.type === 'html' && !includeHtml ? '' : value.value
  52. }
  53. if (includeImageAlt && 'alt' in value && value.alt) {
  54. return value.alt
  55. }
  56. if ('children' in value) {
  57. return all(value.children, includeImageAlt, includeHtml)
  58. }
  59. }
  60. if (Array.isArray(value)) {
  61. return all(value, includeImageAlt, includeHtml)
  62. }
  63. return ''
  64. }
  65. /**
  66. * Serialize a list of nodes.
  67. *
  68. * @param {Array<unknown>} values
  69. * Thing to serialize.
  70. * @param {boolean} includeImageAlt
  71. * Include image `alt`s.
  72. * @param {boolean} includeHtml
  73. * Include HTML.
  74. * @returns {string}
  75. * Serialized nodes.
  76. */
  77. function all(values, includeImageAlt, includeHtml) {
  78. /** @type {Array<string>} */
  79. const result = []
  80. let index = -1
  81. while (++index < values.length) {
  82. result[index] = one(values[index], includeImageAlt, includeHtml)
  83. }
  84. return result.join('')
  85. }
  86. /**
  87. * Check if `value` looks like a node.
  88. *
  89. * @param {unknown} value
  90. * Thing.
  91. * @returns {value is Nodes}
  92. * Whether `value` is a node.
  93. */
  94. function node(value) {
  95. return Boolean(value && typeof value === 'object')
  96. }