outline-parser.test.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. import { expect } from 'chai'
  2. import {
  3. matchOutline,
  4. nestOutline
  5. } from '../../../../frontend/js/features/outline/outline-parser'
  6. describe('OutlineParser', function() {
  7. describe('matchOutline', function() {
  8. it('matches all levels', function() {
  9. const content = `
  10. \\book{Book}
  11. \\part{Part}
  12. \\addpart{Part 2}
  13. \\chapter{Chapter}
  14. \\addchap{Chapter 2}
  15. \\section{Section 1}
  16. \\addsect{Section 1b}
  17. \\subsection{Subsection}
  18. \\subsubsection{Subsubsection}
  19. \\section{Section 2}
  20. \\subsubsection{Subsubsection without subsection}
  21. \\paragraph{a paragraph} Here is some text.
  22. \\subparagraph{a subparagraph} Here is some more text.
  23. `
  24. const outline = matchOutline(content)
  25. expect(outline).to.deep.equal([
  26. { line: 2, title: 'Book', level: 10 },
  27. { line: 3, title: 'Part', level: 20 },
  28. { line: 4, title: 'Part 2', level: 20 },
  29. { line: 5, title: 'Chapter', level: 30 },
  30. { line: 6, title: 'Chapter 2', level: 30 },
  31. { line: 7, title: 'Section 1', level: 40 },
  32. { line: 8, title: 'Section 1b', level: 40 },
  33. { line: 9, title: 'Subsection', level: 50 },
  34. { line: 10, title: 'Subsubsection', level: 60 },
  35. { line: 11, title: 'Section 2', level: 40 },
  36. { line: 12, title: 'Subsubsection without subsection', level: 60 },
  37. { line: 13, title: 'a paragraph', level: 70 },
  38. { line: 14, title: 'a subparagraph', level: 80 }
  39. ])
  40. })
  41. it('matches display titles', function() {
  42. const content = `
  43. \\section{\\label{foo} Label before}
  44. \\section{Label after \\label{foo}}
  45. \\section{Label \\label{foo} between}
  46. \\section{TT \\texttt{Bar}}
  47. `
  48. const outline = matchOutline(content)
  49. expect(outline).to.deep.equal([
  50. { line: 2, title: ' Label before', level: 40 },
  51. { line: 3, title: 'Label after ', level: 40 },
  52. { line: 4, title: 'Label between', level: 40 },
  53. { line: 5, title: 'TT Bar', level: 40 }
  54. ])
  55. })
  56. it('matches empty sections', function() {
  57. const outline = matchOutline('\\section{}')
  58. expect(outline).to.deep.equal([{ line: 1, title: '', level: 40 }])
  59. })
  60. it('matches indented sections', function() {
  61. const outline = matchOutline('\t\\section{Indented}')
  62. expect(outline).to.deep.equal([{ line: 1, title: 'Indented', level: 40 }])
  63. })
  64. it('matches unnumbered sections', function() {
  65. const outline = matchOutline('\\section*{Unnumbered}')
  66. expect(outline).to.deep.equal([
  67. { line: 1, title: 'Unnumbered', level: 40 }
  68. ])
  69. })
  70. it('matches short titles', function() {
  71. const outline = matchOutline(
  72. '\\chapter[Short Title For TOC]{Very Long Title for Text}'
  73. )
  74. expect(outline).to.deep.equal([
  75. { line: 1, title: 'Short Title For TOC', level: 30 }
  76. ])
  77. })
  78. it('handles spacing', function() {
  79. const content = `
  80. \\section {Weird Spacing}
  81. \\section * {Weird Spacing Unnumbered}
  82. \\section [Weird Spacing for TOC] {Weird Spacing}
  83. `
  84. const outline = matchOutline(content)
  85. expect(outline).to.deep.equal([
  86. { line: 2, title: 'Weird Spacing', level: 40 },
  87. { line: 3, title: 'Weird Spacing Unnumbered', level: 40 },
  88. { line: 4, title: 'Weird Spacing for TOC', level: 40 }
  89. ])
  90. })
  91. it("doesn't match commented lines", function() {
  92. const content = `
  93. % \\section{I should not appear in the outline}
  94. `
  95. const outline = matchOutline(content)
  96. expect(outline).to.deep.equal([])
  97. })
  98. it("doesn't match inline sections", function() {
  99. const content = `
  100. I like to write \\section{inline} on one line.
  101. `
  102. const outline = matchOutline(content)
  103. expect(outline).to.deep.equal([])
  104. })
  105. })
  106. describe('nestOutline', function() {
  107. it('matches all levels', function() {
  108. const flatOutline = [
  109. { line: 10, title: 'Book', level: 10 },
  110. { line: 20, title: 'Part A', level: 20 },
  111. { line: 30, title: 'Section A 1', level: 40 },
  112. { line: 40, title: 'Subsection A 1 1', level: 50 },
  113. { line: 50, title: 'Subsection A 1 2', level: 50 },
  114. { line: 60, title: 'Section A 2', level: 40 },
  115. { line: 70, title: 'Section A 3', level: 40 },
  116. { line: 80, title: 'Subsection A 3 1', level: 50 },
  117. { line: 90, title: 'Chapter', level: 30 },
  118. { line: 100, title: 'Part B', level: 20 },
  119. { line: 110, title: 'Section 2', level: 40 },
  120. { line: 120, title: 'Subsubsection without subsection', level: 60 }
  121. ]
  122. const nestedOutline = nestOutline(flatOutline)
  123. expect(nestedOutline).to.deep.equal([
  124. {
  125. line: 10,
  126. title: 'Book',
  127. level: 10,
  128. children: [
  129. {
  130. line: 20,
  131. title: 'Part A',
  132. level: 20,
  133. children: [
  134. {
  135. line: 30,
  136. title: 'Section A 1',
  137. level: 40,
  138. children: [
  139. { line: 40, title: 'Subsection A 1 1', level: 50 },
  140. { line: 50, title: 'Subsection A 1 2', level: 50 }
  141. ]
  142. },
  143. { line: 60, title: 'Section A 2', level: 40 },
  144. {
  145. line: 70,
  146. title: 'Section A 3',
  147. level: 40,
  148. children: [{ line: 80, title: 'Subsection A 3 1', level: 50 }]
  149. },
  150. { line: 90, title: 'Chapter', level: 30 }
  151. ]
  152. },
  153. {
  154. line: 100,
  155. title: 'Part B',
  156. level: 20,
  157. children: [
  158. {
  159. line: 110,
  160. title: 'Section 2',
  161. level: 40,
  162. children: [
  163. {
  164. line: 120,
  165. title: 'Subsubsection without subsection',
  166. level: 60
  167. }
  168. ]
  169. }
  170. ]
  171. }
  172. ]
  173. }
  174. ])
  175. })
  176. })
  177. })