contents.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. 'use strict'
  2. module.exports = contents
  3. var LIST = 'list'
  4. var LIST_ITEM = 'listItem'
  5. var PARAGRAPH = 'paragraph'
  6. var LINK = 'link'
  7. var TEXT = 'text'
  8. // Transform a list of heading objects to a markdown list.
  9. function contents(map, tight) {
  10. var minDepth = Infinity
  11. var index = -1
  12. var length = map.length
  13. var table
  14. // Find minimum depth.
  15. while (++index < length) {
  16. if (map[index].depth < minDepth) {
  17. minDepth = map[index].depth
  18. }
  19. }
  20. // Normalize depth.
  21. index = -1
  22. while (++index < length) {
  23. map[index].depth -= minDepth - 1
  24. }
  25. // Construct the main list.
  26. table = list()
  27. // Add TOC to list.
  28. index = -1
  29. while (++index < length) {
  30. insert(map[index], table, tight)
  31. }
  32. return table
  33. }
  34. // Insert a `node` into a `parent`.
  35. function insert(node, parent, tight) {
  36. var children = parent.children
  37. var length = children.length
  38. var last = children[length - 1]
  39. var isLoose = false
  40. var index
  41. var item
  42. if (node.depth === 1) {
  43. item = listItem()
  44. item.children.push({
  45. type: PARAGRAPH,
  46. children: [
  47. {
  48. type: LINK,
  49. title: null,
  50. url: '#' + node.id,
  51. children: [{type: TEXT, value: node.value}]
  52. }
  53. ]
  54. })
  55. children.push(item)
  56. } else if (last && last.type === LIST_ITEM) {
  57. insert(node, last, tight)
  58. } else if (last && last.type === LIST) {
  59. node.depth--
  60. insert(node, last, tight)
  61. } else if (parent.type === LIST) {
  62. item = listItem()
  63. insert(node, item, tight)
  64. children.push(item)
  65. } else {
  66. item = list()
  67. node.depth--
  68. insert(node, item, tight)
  69. children.push(item)
  70. }
  71. // Properly style list-items with new lines.
  72. parent.spread = !tight
  73. if (parent.type === LIST && parent.spread) {
  74. parent.spread = false
  75. index = -1
  76. while (++index < length) {
  77. if (children[index].children.length > 1) {
  78. parent.spread = true
  79. break
  80. }
  81. }
  82. }
  83. // To do: remove `loose` in next major release.
  84. if (parent.type === LIST_ITEM) {
  85. parent.loose = tight ? false : children.length > 1
  86. } else {
  87. if (tight) {
  88. isLoose = false
  89. } else {
  90. index = -1
  91. while (++index < length) {
  92. if (children[index].loose) {
  93. isLoose = true
  94. break
  95. }
  96. }
  97. }
  98. index = -1
  99. while (++index < length) {
  100. children[index].loose = isLoose
  101. }
  102. }
  103. }
  104. // Create a list.
  105. function list() {
  106. return {type: LIST, ordered: false, spread: false, children: []}
  107. }
  108. // Create a list item.
  109. function listItem() {
  110. // To do: remove `loose` in next major.
  111. return {type: LIST_ITEM, loose: false, spread: false, children: []}
  112. }