trst.nim 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832
  1. discard """
  2. output: '''
  3. [Suite] RST parsing
  4. [Suite] RST tables
  5. [Suite] RST indentation
  6. [Suite] Markdown indentation
  7. [Suite] Warnings
  8. [Suite] RST include directive
  9. [Suite] RST escaping
  10. [Suite] RST inline markup
  11. '''
  12. """
  13. # tests for rst module
  14. import ../../lib/packages/docutils/[rstgen, rst, rstast]
  15. import unittest, strutils
  16. import std/private/miscdollars
  17. import os
  18. import std/[assertions, syncio]
  19. const preferMarkdown = {roPreferMarkdown, roSupportMarkdown, roNimFile, roSandboxDisabled}
  20. const preferRst = {roSupportMarkdown, roNimFile, roSandboxDisabled}
  21. proc toAst(input: string,
  22. rstOptions: RstParseOptions = preferMarkdown,
  23. error: ref string = nil,
  24. warnings: ref seq[string] = nil): string =
  25. ## If `error` is nil then no errors should be generated.
  26. ## The same goes for `warnings`.
  27. proc testMsgHandler(filename: string, line, col: int, msgkind: MsgKind,
  28. arg: string) =
  29. let mc = msgkind.whichMsgClass
  30. let a = $msgkind % arg
  31. var message: string
  32. toLocation(message, filename, line, col + ColRstOffset)
  33. message.add " $1: $2" % [$mc, a]
  34. if mc == mcError:
  35. if error == nil:
  36. raise newException(EParseError, "[unexpected error] " & message)
  37. error[] = message
  38. # we check only first error because subsequent ones may be meaningless
  39. raise newException(EParseError, "")
  40. else:
  41. doAssert warnings != nil, "unexpected RST warning '" & message & "'"
  42. warnings[].add message
  43. try:
  44. const filen = "input"
  45. proc myFindFile(filename: string): string =
  46. # we don't find any files in online mode:
  47. result = ""
  48. var (rst, _, _) = rstParse(input, filen, line=LineRstInit, column=ColRstInit,
  49. rstOptions, myFindFile, testMsgHandler)
  50. result = treeRepr(rst)
  51. except EParseError as e:
  52. if e.msg != "":
  53. result = e.msg
  54. suite "RST parsing":
  55. test "References are whitespace-neutral and case-insensitive":
  56. # refname is 'lexical-analysis', the same for all the 3 variants:
  57. check(dedent"""
  58. Lexical Analysis
  59. ================
  60. Ref. `Lexical Analysis`_ or `Lexical analysis`_ or `lexical analysis`_.
  61. """.toAst ==
  62. dedent"""
  63. rnInner
  64. rnHeadline level=1 anchor='lexical-analysis'
  65. rnLeaf 'Lexical'
  66. rnLeaf ' '
  67. rnLeaf 'Analysis'
  68. rnParagraph
  69. rnLeaf 'Ref'
  70. rnLeaf '.'
  71. rnLeaf ' '
  72. rnInternalRef
  73. rnInner
  74. rnLeaf 'Lexical'
  75. rnLeaf ' '
  76. rnLeaf 'Analysis'
  77. rnLeaf 'lexical-analysis'
  78. rnLeaf ' '
  79. rnLeaf 'or'
  80. rnLeaf ' '
  81. rnInternalRef
  82. rnInner
  83. rnLeaf 'Lexical'
  84. rnLeaf ' '
  85. rnLeaf 'analysis'
  86. rnLeaf 'lexical-analysis'
  87. rnLeaf ' '
  88. rnLeaf 'or'
  89. rnLeaf ' '
  90. rnInternalRef
  91. rnInner
  92. rnLeaf 'lexical'
  93. rnLeaf ' '
  94. rnLeaf 'analysis'
  95. rnLeaf 'lexical-analysis'
  96. rnLeaf '.'
  97. rnLeaf ' '
  98. """)
  99. test "RST quoted literal blocks":
  100. let expected =
  101. dedent"""
  102. rnInner
  103. rnLeaf 'Paragraph'
  104. rnLeaf ':'
  105. rnLiteralBlock
  106. rnLeaf '>x'
  107. """
  108. check(dedent"""
  109. Paragraph::
  110. >x""".toAst(rstOptions = preferRst) == expected)
  111. check(dedent"""
  112. Paragraph::
  113. >x""".toAst(rstOptions = preferRst) == expected)
  114. test "RST quoted literal blocks, :: at a separate line":
  115. let expected =
  116. dedent"""
  117. rnInner
  118. rnInner
  119. rnLeaf 'Paragraph'
  120. rnLiteralBlock
  121. rnLeaf '>x
  122. >>y'
  123. """
  124. check(dedent"""
  125. Paragraph
  126. ::
  127. >x
  128. >>y""".toAst(rstOptions = preferRst) == expected)
  129. check(dedent"""
  130. Paragraph
  131. ::
  132. >x
  133. >>y""".toAst(rstOptions = preferRst) == expected)
  134. test "Markdown quoted blocks":
  135. check(dedent"""
  136. Paragraph.
  137. >x""".toAst ==
  138. dedent"""
  139. rnInner
  140. rnLeaf 'Paragraph'
  141. rnLeaf '.'
  142. rnMarkdownBlockQuote
  143. rnMarkdownBlockQuoteItem quotationDepth=1
  144. rnLeaf 'x'
  145. """)
  146. # bug #17987
  147. check(dedent"""
  148. foo https://github.com/nim-lang/Nim/issues/8258
  149. > bar""".toAst ==
  150. dedent"""
  151. rnInner
  152. rnInner
  153. rnLeaf 'foo'
  154. rnLeaf ' '
  155. rnStandaloneHyperlink
  156. rnLeaf 'https://github.com/nim-lang/Nim/issues/8258'
  157. rnMarkdownBlockQuote
  158. rnMarkdownBlockQuoteItem quotationDepth=1
  159. rnLeaf 'bar'
  160. """)
  161. let expected = dedent"""
  162. rnInner
  163. rnLeaf 'Paragraph'
  164. rnLeaf '.'
  165. rnMarkdownBlockQuote
  166. rnMarkdownBlockQuoteItem quotationDepth=1
  167. rnInner
  168. rnLeaf 'x1'
  169. rnLeaf ' '
  170. rnLeaf 'x2'
  171. rnMarkdownBlockQuoteItem quotationDepth=2
  172. rnInner
  173. rnLeaf 'y1'
  174. rnLeaf ' '
  175. rnLeaf 'y2'
  176. rnMarkdownBlockQuoteItem quotationDepth=1
  177. rnLeaf 'z'
  178. """
  179. check(dedent"""
  180. Paragraph.
  181. >x1 x2
  182. >>y1 y2
  183. >z""".toAst == expected)
  184. check(dedent"""
  185. Paragraph.
  186. > x1 x2
  187. >> y1 y2
  188. > z""".toAst == expected)
  189. check(dedent"""
  190. >x
  191. >y
  192. >z""".toAst ==
  193. dedent"""
  194. rnMarkdownBlockQuote
  195. rnMarkdownBlockQuoteItem quotationDepth=1
  196. rnInner
  197. rnLeaf 'x'
  198. rnLeaf ' '
  199. rnLeaf 'y'
  200. rnLeaf ' '
  201. rnLeaf 'z'
  202. """)
  203. check(dedent"""
  204. > z
  205. > > >y
  206. """.toAst ==
  207. dedent"""
  208. rnMarkdownBlockQuote
  209. rnMarkdownBlockQuoteItem quotationDepth=1
  210. rnLeaf 'z'
  211. rnMarkdownBlockQuoteItem quotationDepth=3
  212. rnLeaf 'y'
  213. """)
  214. test "Markdown quoted blocks: lazy":
  215. let expected = dedent"""
  216. rnInner
  217. rnMarkdownBlockQuote
  218. rnMarkdownBlockQuoteItem quotationDepth=2
  219. rnInner
  220. rnLeaf 'x'
  221. rnLeaf ' '
  222. rnLeaf 'continuation1'
  223. rnLeaf ' '
  224. rnLeaf 'continuation2'
  225. rnParagraph
  226. rnLeaf 'newParagraph'
  227. """
  228. check(dedent"""
  229. >>x
  230. continuation1
  231. continuation2
  232. newParagraph""".toAst == expected)
  233. check(dedent"""
  234. >> x
  235. continuation1
  236. continuation2
  237. newParagraph""".toAst == expected)
  238. # however mixing more than 1 non-lazy line and lazy one(s) splits quote
  239. # in our parser, which appeared the easiest way to handle such cases:
  240. var warnings = new seq[string]
  241. check(dedent"""
  242. >> x
  243. >> continuation1
  244. continuation2
  245. newParagraph""".toAst(warnings=warnings) ==
  246. dedent"""
  247. rnInner
  248. rnMarkdownBlockQuote
  249. rnMarkdownBlockQuoteItem quotationDepth=2
  250. rnLeaf 'x'
  251. rnMarkdownBlockQuoteItem quotationDepth=2
  252. rnInner
  253. rnLeaf 'continuation1'
  254. rnLeaf ' '
  255. rnLeaf 'continuation2'
  256. rnParagraph
  257. rnLeaf 'newParagraph'
  258. """)
  259. check(warnings[] == @[
  260. "input(2, 1) Warning: RST style: two or more quoted lines " &
  261. "are followed by unquoted line 3"])
  262. test "Markdown quoted blocks: not lazy":
  263. # here is where we deviate from CommonMark specification: 'bar' below is
  264. # not considered as continuation of 2-level '>> foo' quote.
  265. check(dedent"""
  266. >>> foo
  267. > bar
  268. >> baz
  269. """.toAst() ==
  270. dedent"""
  271. rnMarkdownBlockQuote
  272. rnMarkdownBlockQuoteItem quotationDepth=3
  273. rnLeaf 'foo'
  274. rnMarkdownBlockQuoteItem quotationDepth=1
  275. rnLeaf 'bar'
  276. rnMarkdownBlockQuoteItem quotationDepth=2
  277. rnLeaf 'baz'
  278. """)
  279. test "Markdown quoted blocks: inline markup works":
  280. check(dedent"""
  281. > hi **bold** text
  282. """.toAst == dedent"""
  283. rnMarkdownBlockQuote
  284. rnMarkdownBlockQuoteItem quotationDepth=1
  285. rnInner
  286. rnLeaf 'hi'
  287. rnLeaf ' '
  288. rnStrongEmphasis
  289. rnLeaf 'bold'
  290. rnLeaf ' '
  291. rnLeaf 'text'
  292. """)
  293. test "Markdown quoted blocks: blank line separator":
  294. let expected = dedent"""
  295. rnInner
  296. rnMarkdownBlockQuote
  297. rnMarkdownBlockQuoteItem quotationDepth=1
  298. rnInner
  299. rnLeaf 'x'
  300. rnLeaf ' '
  301. rnLeaf 'y'
  302. rnMarkdownBlockQuote
  303. rnMarkdownBlockQuoteItem quotationDepth=1
  304. rnInner
  305. rnLeaf 'z'
  306. rnLeaf ' '
  307. rnLeaf 't'
  308. """
  309. check(dedent"""
  310. >x
  311. >y
  312. > z
  313. > t""".toAst == expected)
  314. check(dedent"""
  315. >x
  316. y
  317. > z
  318. t""".toAst == expected)
  319. test "Markdown quoted blocks: nested body blocks/elements work #1":
  320. let expected = dedent"""
  321. rnMarkdownBlockQuote
  322. rnMarkdownBlockQuoteItem quotationDepth=1
  323. rnBulletList
  324. rnBulletItem
  325. rnInner
  326. rnLeaf 'x'
  327. rnBulletItem
  328. rnInner
  329. rnLeaf 'y'
  330. """
  331. check(dedent"""
  332. > - x
  333. - y
  334. """.toAst == expected)
  335. # TODO: if bug #17340 point 28 is resolved then this may work:
  336. # check(dedent"""
  337. # > - x
  338. # - y
  339. # """.toAst == expected)
  340. check(dedent"""
  341. > - x
  342. > - y
  343. """.toAst == expected)
  344. check(dedent"""
  345. >
  346. > - x
  347. >
  348. > - y
  349. >
  350. """.toAst == expected)
  351. test "Markdown quoted blocks: nested body blocks/elements work #2":
  352. let expected = dedent"""
  353. rnAdmonition adType=note
  354. [nil]
  355. [nil]
  356. rnDefList
  357. rnDefItem
  358. rnDefName
  359. rnLeaf 'deflist'
  360. rnLeaf ':'
  361. rnDefBody
  362. rnMarkdownBlockQuote
  363. rnMarkdownBlockQuoteItem quotationDepth=2
  364. rnInner
  365. rnLeaf 'quote'
  366. rnLeaf ' '
  367. rnLeaf 'continuation'
  368. """
  369. check(dedent"""
  370. .. Note:: deflist:
  371. >> quote
  372. continuation
  373. """.toAst(rstOptions = preferRst) == expected)
  374. check(dedent"""
  375. .. Note::
  376. deflist:
  377. >> quote
  378. continuation
  379. """.toAst(rstOptions = preferRst) == expected)
  380. check(dedent"""
  381. .. Note::
  382. deflist:
  383. >> quote
  384. >> continuation
  385. """.toAst(rstOptions = preferRst) == expected)
  386. # spaces are not significant between `>`:
  387. check(dedent"""
  388. .. Note::
  389. deflist:
  390. > > quote
  391. > > continuation
  392. """.toAst(rstOptions = preferRst) == expected)
  393. test "Markdown quoted blocks: de-indent handled well":
  394. check(dedent"""
  395. >
  396. > - x
  397. > - y
  398. >
  399. > Paragraph.
  400. """.toAst(rstOptions = preferRst) == dedent"""
  401. rnMarkdownBlockQuote
  402. rnMarkdownBlockQuoteItem quotationDepth=1
  403. rnInner
  404. rnBlockQuote
  405. rnBulletList
  406. rnBulletItem
  407. rnInner
  408. rnLeaf 'x'
  409. rnBulletItem
  410. rnInner
  411. rnLeaf 'y'
  412. rnParagraph
  413. rnLeaf 'Paragraph'
  414. rnLeaf '.'
  415. """)
  416. let expectCodeBlock = dedent"""
  417. rnCodeBlock
  418. [nil]
  419. rnFieldList
  420. rnField
  421. rnFieldName
  422. rnLeaf 'default-language'
  423. rnFieldBody
  424. rnLeaf 'Nim'
  425. rnLiteralBlock
  426. rnLeaf '
  427. let a = 1
  428. ```'
  429. """
  430. test "Markdown code blocks with more > 3 backticks":
  431. check(dedent"""
  432. ````
  433. let a = 1
  434. ```
  435. ````""".toAst == expectCodeBlock)
  436. test "Markdown code blocks with ~~~":
  437. check(dedent"""
  438. ~~~
  439. let a = 1
  440. ```
  441. ~~~""".toAst == expectCodeBlock)
  442. check(dedent"""
  443. ~~~~~
  444. let a = 1
  445. ```
  446. ~~~~~""".toAst == expectCodeBlock)
  447. test "Markdown code blocks with Nim-specific arguments":
  448. check(dedent"""
  449. ```nim number-lines=1 test
  450. let a = 1
  451. ```""".toAst ==
  452. dedent"""
  453. rnCodeBlock
  454. rnDirArg
  455. rnLeaf 'nim'
  456. rnFieldList
  457. rnField
  458. rnFieldName
  459. rnLeaf 'number-lines'
  460. rnFieldBody
  461. rnLeaf '1'
  462. rnField
  463. rnFieldName
  464. rnLeaf 'test'
  465. rnFieldBody
  466. rnLiteralBlock
  467. rnLeaf '
  468. let a = 1'
  469. """)
  470. check(dedent"""
  471. ```nim test = "nim c $1" number-lines = 1
  472. let a = 1
  473. ```""".toAst ==
  474. dedent"""
  475. rnCodeBlock
  476. rnDirArg
  477. rnLeaf 'nim'
  478. rnFieldList
  479. rnField
  480. rnFieldName
  481. rnLeaf 'test'
  482. rnFieldBody
  483. rnLeaf '"nim c $1"'
  484. rnField
  485. rnFieldName
  486. rnLeaf 'number-lines'
  487. rnFieldBody
  488. rnLeaf '1'
  489. rnLiteralBlock
  490. rnLeaf '
  491. let a = 1'
  492. """)
  493. test "additional indentation < 4 spaces is handled fine":
  494. check(dedent"""
  495. Indentation
  496. ```nim
  497. let a = 1
  498. ```""".toAst ==
  499. dedent"""
  500. rnInner
  501. rnParagraph
  502. rnLeaf 'Indentation'
  503. rnParagraph
  504. rnCodeBlock
  505. rnDirArg
  506. rnLeaf 'nim'
  507. [nil]
  508. rnLiteralBlock
  509. rnLeaf '
  510. let a = 1'
  511. """)
  512. # | |
  513. # | \ indentation of exactly two spaces before 'let a = 1'
  514. test "no blank line is required before or after Markdown code block":
  515. let inputBacktick = dedent"""
  516. Some text
  517. ```
  518. CodeBlock()
  519. ```
  520. Other text"""
  521. let inputTilde = dedent"""
  522. Some text
  523. ~~~~~~~~~
  524. CodeBlock()
  525. ~~~~~~~~~
  526. Other text"""
  527. let expected = dedent"""
  528. rnInner
  529. rnParagraph
  530. rnLeaf 'Some'
  531. rnLeaf ' '
  532. rnLeaf 'text'
  533. rnParagraph
  534. rnCodeBlock
  535. [nil]
  536. rnFieldList
  537. rnField
  538. rnFieldName
  539. rnLeaf 'default-language'
  540. rnFieldBody
  541. rnLeaf 'Nim'
  542. rnLiteralBlock
  543. rnLeaf '
  544. CodeBlock()'
  545. rnLeaf ' '
  546. rnLeaf 'Other'
  547. rnLeaf ' '
  548. rnLeaf 'text'
  549. """
  550. check inputBacktick.toAst == expected
  551. check inputTilde.toAst == expected
  552. test "option list has priority over definition list":
  553. for opt in [preferMarkdown, preferRst]:
  554. check(dedent"""
  555. --defusages
  556. file
  557. -o set
  558. """.toAst(rstOptions = opt) ==
  559. dedent"""
  560. rnOptionList
  561. rnOptionListItem order=1
  562. rnOptionGroup
  563. rnLeaf '--'
  564. rnLeaf 'defusages'
  565. rnDescription
  566. rnInner
  567. rnLeaf 'file'
  568. rnOptionListItem order=2
  569. rnOptionGroup
  570. rnLeaf '-'
  571. rnLeaf 'o'
  572. rnDescription
  573. rnLeaf 'set'
  574. """)
  575. test "items of 1 option list can be separated by blank lines":
  576. check(dedent"""
  577. -a desc1
  578. -b desc2
  579. """.toAst ==
  580. dedent"""
  581. rnOptionList
  582. rnOptionListItem order=1
  583. rnOptionGroup
  584. rnLeaf '-'
  585. rnLeaf 'a'
  586. rnDescription
  587. rnLeaf 'desc1'
  588. rnOptionListItem order=2
  589. rnOptionGroup
  590. rnLeaf '-'
  591. rnLeaf 'b'
  592. rnDescription
  593. rnLeaf 'desc2'
  594. """)
  595. test "definition list does not gobble up the following blocks":
  596. check(dedent"""
  597. defName
  598. defBody
  599. -b desc2
  600. """.toAst(rstOptions = preferRst) ==
  601. dedent"""
  602. rnInner
  603. rnDefList
  604. rnDefItem
  605. rnDefName
  606. rnLeaf 'defName'
  607. rnDefBody
  608. rnInner
  609. rnLeaf 'defBody'
  610. rnOptionList
  611. rnOptionListItem order=1
  612. rnOptionGroup
  613. rnLeaf '-'
  614. rnLeaf 'b'
  615. rnDescription
  616. rnLeaf 'desc2'
  617. """)
  618. test "RST comment":
  619. check(dedent"""
  620. .. comment1
  621. comment2
  622. someParagraph""".toAst ==
  623. dedent"""
  624. rnLeaf 'someParagraph'
  625. """)
  626. check(dedent"""
  627. ..
  628. comment1
  629. comment2
  630. someParagraph""".toAst ==
  631. dedent"""
  632. rnLeaf 'someParagraph'
  633. """)
  634. test "check that additional line right after .. ends comment":
  635. check(dedent"""
  636. ..
  637. notAcomment1
  638. notAcomment2
  639. someParagraph""".toAst(rstOptions = preferRst) ==
  640. dedent"""
  641. rnInner
  642. rnBlockQuote
  643. rnInner
  644. rnLeaf 'notAcomment1'
  645. rnLeaf ' '
  646. rnLeaf 'notAcomment2'
  647. rnParagraph
  648. rnLeaf 'someParagraph'
  649. """)
  650. test "check that additional line right after .. ends comment (Markdown mode)":
  651. # in Markdown small indentation does not matter so this should
  652. # just be split to 2 paragraphs.
  653. check(dedent"""
  654. ..
  655. notAcomment1
  656. notAcomment2
  657. someParagraph""".toAst ==
  658. dedent"""
  659. rnInner
  660. rnInner
  661. rnLeaf 'notAcomment1'
  662. rnLeaf ' '
  663. rnLeaf 'notAcomment2'
  664. rnParagraph
  665. rnLeaf 'someParagraph'
  666. """)
  667. test "but blank lines after 2nd non-empty line don't end the comment":
  668. check(dedent"""
  669. ..
  670. comment1
  671. comment2
  672. someParagraph""".toAst ==
  673. dedent"""
  674. rnLeaf 'someParagraph'
  675. """)
  676. test "using .. as separator b/w directives and block quotes":
  677. check(dedent"""
  678. .. note:: someNote
  679. ..
  680. someBlockQuote""".toAst(rstOptions = preferRst) ==
  681. dedent"""
  682. rnInner
  683. rnAdmonition adType=note
  684. [nil]
  685. [nil]
  686. rnLeaf 'someNote'
  687. rnBlockQuote
  688. rnInner
  689. rnLeaf 'someBlockQuote'
  690. """)
  691. test "no redundant blank lines in literal blocks":
  692. check(dedent"""
  693. Check::
  694. code
  695. """.toAst(rstOptions = preferRst) ==
  696. dedent"""
  697. rnInner
  698. rnLeaf 'Check'
  699. rnLeaf ':'
  700. rnLiteralBlock
  701. rnLeaf 'code'
  702. """)
  703. test "Markdown indented code blocks":
  704. check(dedent"""
  705. See
  706. some code""".toAst ==
  707. dedent"""
  708. rnInner
  709. rnInner
  710. rnLeaf 'See'
  711. rnLiteralBlock
  712. rnLeaf 'some code'
  713. """)
  714. # not a code block -- no blank line before:
  715. check(dedent"""
  716. See
  717. some code""".toAst ==
  718. dedent"""
  719. rnInner
  720. rnLeaf 'See'
  721. rnLeaf ' '
  722. rnLeaf 'some'
  723. rnLeaf ' '
  724. rnLeaf 'code'
  725. """)
  726. suite "RST tables":
  727. test "formatting in tables works":
  728. check(
  729. dedent"""
  730. ========= ===
  731. `build` `a`
  732. ========= ===
  733. """.toAst ==
  734. dedent"""
  735. rnTable colCount=2
  736. rnTableRow
  737. rnTableDataCell
  738. rnInlineCode
  739. rnDirArg
  740. rnLeaf 'nim'
  741. [nil]
  742. rnLiteralBlock
  743. rnLeaf 'build'
  744. rnTableDataCell
  745. rnInlineCode
  746. rnDirArg
  747. rnLeaf 'nim'
  748. [nil]
  749. rnLiteralBlock
  750. rnLeaf 'a'
  751. """)
  752. test "tables with slightly overflowed cells cause an error (1)":
  753. var error = new string
  754. check(
  755. dedent"""
  756. ====== ======
  757. Inputs Output
  758. ====== ======
  759. """.toAst(error=error) == "")
  760. check(error[] == "input(2, 2) Error: Illformed table: " &
  761. "this word crosses table column from the right")
  762. test "tables with slightly overflowed cells cause an error (2)":
  763. var error = new string
  764. check("" == dedent"""
  765. ===== ===== ======
  766. Input Output
  767. ===== ===== ======
  768. False False False
  769. ===== ===== ======
  770. """.toAst(error=error))
  771. check(error[] == "input(2, 8) Error: Illformed table: " &
  772. "this word crosses table column from the right")
  773. test "tables with slightly underflowed cells cause an error":
  774. var error = new string
  775. check("" == dedent"""
  776. ===== ===== ======
  777. Input Output
  778. ===== ===== ======
  779. False False False
  780. ===== ===== ======
  781. """.toAst(error=error))
  782. check(error[] == "input(2, 7) Error: Illformed table: " &
  783. "this word crosses table column from the left")
  784. test "tables with unequal underlines should be reported (1)":
  785. var error = new string
  786. error[] = "none"
  787. check("" == dedent"""
  788. ===== ======
  789. Input Output
  790. ===== ======
  791. False False
  792. ===== =======
  793. """.toAst(error=error))
  794. check(error[] == "input(5, 14) Error: Illformed table: " &
  795. "end of table column #2 should end at position 13")
  796. test "tables with unequal underlines should be reported (2)":
  797. var error = new string
  798. check("" == dedent"""
  799. ===== ======
  800. Input Output
  801. ===== =======
  802. False False
  803. ===== ======
  804. """.toAst(error=error))
  805. check(error[] == "input(3, 14) Error: Illformed table: " &
  806. "end of table column #2 should end at position 13")
  807. test "tables with empty first cells":
  808. check(
  809. dedent"""
  810. = = =
  811. x y z
  812. t
  813. = = =
  814. """.toAst ==
  815. dedent"""
  816. rnTable colCount=3
  817. rnTableRow
  818. rnTableDataCell
  819. rnLeaf 'x'
  820. rnTableDataCell
  821. rnInner
  822. rnLeaf 'y'
  823. rnLeaf ' '
  824. rnTableDataCell
  825. rnInner
  826. rnLeaf 'z'
  827. rnLeaf ' '
  828. rnLeaf 't'
  829. """)
  830. test "tables with spanning cells & separators":
  831. check(
  832. dedent"""
  833. ===== ===== ======
  834. Inputs Output
  835. ------------ ------
  836. A B A or B
  837. ===== ===== ======
  838. False False False
  839. True False True
  840. ----- ----- ------
  841. False True True
  842. True True True
  843. ===== ===== ======
  844. """.toAst ==
  845. dedent"""
  846. rnTable colCount=3
  847. rnTableRow
  848. rnTableHeaderCell span=2
  849. rnLeaf 'Inputs'
  850. rnTableHeaderCell span=1
  851. rnLeaf 'Output'
  852. rnTableRow endsHeader
  853. rnTableHeaderCell
  854. rnLeaf 'A'
  855. rnTableHeaderCell
  856. rnLeaf 'B'
  857. rnTableHeaderCell
  858. rnInner
  859. rnLeaf 'A'
  860. rnLeaf ' '
  861. rnLeaf 'or'
  862. rnLeaf ' '
  863. rnLeaf 'B'
  864. rnTableRow
  865. rnTableDataCell
  866. rnLeaf 'False'
  867. rnTableDataCell
  868. rnLeaf 'False'
  869. rnTableDataCell
  870. rnLeaf 'False'
  871. rnTableRow
  872. rnTableDataCell span=1
  873. rnLeaf 'True'
  874. rnTableDataCell span=1
  875. rnLeaf 'False'
  876. rnTableDataCell span=1
  877. rnLeaf 'True'
  878. rnTableRow
  879. rnTableDataCell
  880. rnLeaf 'False'
  881. rnTableDataCell
  882. rnLeaf 'True'
  883. rnTableDataCell
  884. rnLeaf 'True'
  885. rnTableRow
  886. rnTableDataCell
  887. rnLeaf 'True'
  888. rnTableDataCell
  889. rnLeaf 'True'
  890. rnTableDataCell
  891. rnLeaf 'True'
  892. """)
  893. test "tables with spanning cells with uneqal underlines cause an error":
  894. var error = new string
  895. check(
  896. dedent"""
  897. ===== ===== ======
  898. Inputs Output
  899. ------------- ------
  900. A B A or B
  901. ===== ===== ======
  902. """.toAst(error=error) == "")
  903. check(error[] == "input(3, 1) Error: Illformed table: " &
  904. "spanning underline does not match main table columns")
  905. let expTable = dedent"""
  906. rnTable colCount=2
  907. rnTableRow
  908. rnTableDataCell
  909. rnLeaf 'Inputs'
  910. rnTableDataCell
  911. rnLeaf 'Output'
  912. """
  913. test "only tables with `=` columns specs are allowed (1)":
  914. var warnings = new seq[string]
  915. check(
  916. dedent"""
  917. ------ ------
  918. Inputs Output
  919. ------ ------
  920. """.toAst(warnings=warnings) ==
  921. expTable)
  922. check(warnings[] ==
  923. @["input(1, 1) Warning: RST style: " &
  924. "only tables with `=` columns specification are allowed",
  925. "input(3, 1) Warning: RST style: " &
  926. "only tables with `=` columns specification are allowed"])
  927. test "only tables with `=` columns specs are allowed (2)":
  928. var warnings = new seq[string]
  929. check(
  930. dedent"""
  931. ====== ======
  932. Inputs Output
  933. ~~~~~~ ~~~~~~
  934. """.toAst(warnings=warnings) ==
  935. expTable)
  936. check(warnings[] ==
  937. @["input(3, 1) Warning: RST style: "&
  938. "only tables with `=` columns specification are allowed"])
  939. suite "RST indentation":
  940. test "nested bullet lists":
  941. let input = dedent """
  942. * - bullet1
  943. - bullet2
  944. * - bullet3
  945. - bullet4
  946. """
  947. let output = input.toAst
  948. check(output == dedent"""
  949. rnBulletList
  950. rnBulletItem
  951. rnBulletList
  952. rnBulletItem
  953. rnInner
  954. rnLeaf 'bullet1'
  955. rnBulletItem
  956. rnInner
  957. rnLeaf 'bullet2'
  958. rnBulletItem
  959. rnBulletList
  960. rnBulletItem
  961. rnInner
  962. rnLeaf 'bullet3'
  963. rnBulletItem
  964. rnInner
  965. rnLeaf 'bullet4'
  966. """)
  967. test "nested markup blocks":
  968. let input = dedent"""
  969. #) .. Hint:: .. Error:: none
  970. #) .. Warning:: term0
  971. Definition0
  972. #) some
  973. paragraph1
  974. #) term1
  975. Definition1
  976. term2
  977. Definition2
  978. """
  979. check(input.toAst(rstOptions = preferRst) == dedent"""
  980. rnEnumList labelFmt=1)
  981. rnEnumItem
  982. rnAdmonition adType=hint
  983. [nil]
  984. [nil]
  985. rnAdmonition adType=error
  986. [nil]
  987. [nil]
  988. rnLeaf 'none'
  989. rnEnumItem
  990. rnAdmonition adType=warning
  991. [nil]
  992. [nil]
  993. rnDefList
  994. rnDefItem
  995. rnDefName
  996. rnLeaf 'term0'
  997. rnDefBody
  998. rnInner
  999. rnLeaf 'Definition0'
  1000. rnEnumItem
  1001. rnInner
  1002. rnLeaf 'some'
  1003. rnLeaf ' '
  1004. rnLeaf 'paragraph1'
  1005. rnEnumItem
  1006. rnDefList
  1007. rnDefItem
  1008. rnDefName
  1009. rnLeaf 'term1'
  1010. rnDefBody
  1011. rnInner
  1012. rnLeaf 'Definition1'
  1013. rnDefItem
  1014. rnDefName
  1015. rnLeaf 'term2'
  1016. rnDefBody
  1017. rnInner
  1018. rnLeaf 'Definition2'
  1019. """)
  1020. test "code-block parsing":
  1021. let input1 = dedent"""
  1022. .. code-block:: nim
  1023. :test: "nim c $1"
  1024. template additive(typ: typedesc) =
  1025. discard
  1026. """
  1027. let input2 = dedent"""
  1028. .. code-block:: nim
  1029. :test: "nim c $1"
  1030. template additive(typ: typedesc) =
  1031. discard
  1032. """
  1033. let input3 = dedent"""
  1034. .. code-block:: nim
  1035. :test: "nim c $1"
  1036. template additive(typ: typedesc) =
  1037. discard
  1038. """
  1039. let inputWrong = dedent"""
  1040. .. code-block:: nim
  1041. :test: "nim c $1"
  1042. template additive(typ: typedesc) =
  1043. discard
  1044. """
  1045. let ast = dedent"""
  1046. rnCodeBlock
  1047. rnDirArg
  1048. rnLeaf 'nim'
  1049. rnFieldList
  1050. rnField
  1051. rnFieldName
  1052. rnLeaf 'test'
  1053. rnFieldBody
  1054. rnInner
  1055. rnLeaf '"'
  1056. rnLeaf 'nim'
  1057. rnLeaf ' '
  1058. rnLeaf 'c'
  1059. rnLeaf ' '
  1060. rnLeaf '$'
  1061. rnLeaf '1'
  1062. rnLeaf '"'
  1063. rnField
  1064. rnFieldName
  1065. rnLeaf 'default-language'
  1066. rnFieldBody
  1067. rnLeaf 'Nim'
  1068. rnLiteralBlock
  1069. rnLeaf 'template additive(typ: typedesc) =
  1070. discard'
  1071. """
  1072. check input1.toAst == ast
  1073. check input2.toAst == ast
  1074. check input3.toAst == ast
  1075. # "template..." should be parsed as a definition list attached to ":test:":
  1076. check inputWrong.toAst != ast
  1077. test "Markdown definition lists work in conjunction with bullet lists":
  1078. check(dedent"""
  1079. * some term
  1080. : the definition
  1081. Paragraph.""".toAst ==
  1082. dedent"""
  1083. rnInner
  1084. rnBulletList
  1085. rnBulletItem
  1086. rnMdDefList
  1087. rnDefItem
  1088. rnDefName
  1089. rnLeaf 'some'
  1090. rnLeaf ' '
  1091. rnLeaf 'term'
  1092. rnDefBody
  1093. rnInner
  1094. rnLeaf 'the'
  1095. rnLeaf ' '
  1096. rnLeaf 'definition'
  1097. rnParagraph
  1098. rnLeaf 'Paragraph'
  1099. rnLeaf '.'
  1100. """)
  1101. test "Markdown definition lists work with blank lines and extra paragraphs":
  1102. check(dedent"""
  1103. Term1
  1104. : Definition1
  1105. Term2 *inline markup*
  1106. : Definition2
  1107. Paragraph2
  1108. Term3
  1109. : * point1
  1110. * point2
  1111. : term3definition2
  1112. """.toAst == dedent"""
  1113. rnMdDefList
  1114. rnDefItem
  1115. rnDefName
  1116. rnLeaf 'Term1'
  1117. rnDefBody
  1118. rnInner
  1119. rnLeaf 'Definition1'
  1120. rnDefItem
  1121. rnDefName
  1122. rnLeaf 'Term2'
  1123. rnLeaf ' '
  1124. rnEmphasis
  1125. rnLeaf 'inline'
  1126. rnLeaf ' '
  1127. rnLeaf 'markup'
  1128. rnDefBody
  1129. rnParagraph
  1130. rnLeaf 'Definition2'
  1131. rnParagraph
  1132. rnLeaf 'Paragraph2'
  1133. rnDefItem
  1134. rnDefName
  1135. rnLeaf 'Term3'
  1136. rnDefBody
  1137. rnBulletList
  1138. rnBulletItem
  1139. rnInner
  1140. rnLeaf 'point1'
  1141. rnBulletItem
  1142. rnInner
  1143. rnLeaf 'point2'
  1144. rnDefBody
  1145. rnInner
  1146. rnLeaf 'term3definition2'
  1147. """)
  1148. suite "Markdown indentation":
  1149. test "Markdown paragraph indentation":
  1150. # Additional spaces (<=3) of indentation does not break the paragraph.
  1151. # TODO: in 2nd case de-indentation causes paragraph to break, this is
  1152. # reasonable but does not seem to conform the Markdown spec.
  1153. check(dedent"""
  1154. Start1
  1155. stop1
  1156. Start2
  1157. stop2
  1158. """.toAst ==
  1159. dedent"""
  1160. rnInner
  1161. rnParagraph
  1162. rnLeaf 'Start1'
  1163. rnLeaf ' '
  1164. rnLeaf 'stop1'
  1165. rnParagraph
  1166. rnLeaf 'Start2'
  1167. rnParagraph
  1168. rnLeaf 'stop2'
  1169. rnLeaf ' '
  1170. """)
  1171. suite "Warnings":
  1172. test "warnings for broken footnotes/links/substitutions":
  1173. let input = dedent"""
  1174. firstParagraph
  1175. footnoteRef [som]_
  1176. link `a broken Link`_
  1177. substitution |undefined subst|
  1178. link short.link_
  1179. lastParagraph
  1180. """
  1181. var warnings = new seq[string]
  1182. let output = input.toAst(rstOptions=preferRst, warnings=warnings)
  1183. check(warnings[] == @[
  1184. "input(3, 14) Warning: broken link 'citation-som'",
  1185. "input(5, 7) Warning: broken link 'a broken Link'",
  1186. "input(7, 15) Warning: unknown substitution 'undefined subst'",
  1187. "input(9, 6) Warning: broken link 'short.link'"
  1188. ])
  1189. test "Pandoc Markdown concise link warning points to target":
  1190. var warnings = new seq[string]
  1191. check(
  1192. "ref [here][target]".toAst(warnings=warnings) ==
  1193. dedent"""
  1194. rnInner
  1195. rnLeaf 'ref'
  1196. rnLeaf ' '
  1197. rnPandocRef
  1198. rnInner
  1199. rnLeaf 'here'
  1200. rnInner
  1201. rnLeaf 'target'
  1202. """)
  1203. check warnings[] == @["input(1, 12) Warning: broken link 'target'"]
  1204. test "With include directive and blank lines at the beginning":
  1205. "other.rst".writeFile(dedent"""
  1206. firstParagraph
  1207. here brokenLink_""")
  1208. let input = ".. include:: other.rst"
  1209. var warnings = new seq[string]
  1210. let output = input.toAst(warnings=warnings)
  1211. check warnings[] == @["other.rst(5, 6) Warning: broken link 'brokenLink'"]
  1212. check(output == dedent"""
  1213. rnInner
  1214. rnParagraph
  1215. rnLeaf 'firstParagraph'
  1216. rnParagraph
  1217. rnLeaf 'here'
  1218. rnLeaf ' '
  1219. rnRstRef
  1220. rnLeaf 'brokenLink'
  1221. """)
  1222. removeFile("other.rst")
  1223. test "warnings for ambiguous links (references + anchors)":
  1224. # Reference like `x`_ generates a link alias x that may clash with others
  1225. let input = dedent"""
  1226. Manual reference: `foo <#foo,string,string>`_
  1227. .. _foo:
  1228. Paragraph.
  1229. Ref foo_
  1230. """
  1231. var warnings = new seq[string]
  1232. let output = input.toAst(warnings=warnings)
  1233. check(warnings[] == @[
  1234. dedent """
  1235. input(7, 5) Warning: ambiguous doc link `foo`
  1236. clash:
  1237. (3, 8): (manual directive anchor)
  1238. (1, 45): (implicitly-generated hyperlink alias)"""
  1239. ])
  1240. # reference should be resolved to the manually set anchor:
  1241. check(output ==
  1242. dedent"""
  1243. rnInner
  1244. rnParagraph
  1245. rnLeaf 'Manual'
  1246. rnLeaf ' '
  1247. rnLeaf 'reference'
  1248. rnLeaf ':'
  1249. rnLeaf ' '
  1250. rnHyperlink
  1251. rnInner
  1252. rnLeaf 'foo'
  1253. rnInner
  1254. rnLeaf '#foo,string,string'
  1255. rnParagraph anchor='foo'
  1256. rnLeaf 'Paragraph'
  1257. rnLeaf '.'
  1258. rnParagraph
  1259. rnLeaf 'Ref'
  1260. rnLeaf ' '
  1261. rnInternalRef
  1262. rnInner
  1263. rnLeaf 'foo'
  1264. rnLeaf 'foo'
  1265. rnLeaf ' '
  1266. """)
  1267. suite "RST include directive":
  1268. test "Include whole":
  1269. "other.rst".writeFile("**test1**")
  1270. let input = ".. include:: other.rst"
  1271. doAssert "<strong>test1</strong>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
  1272. removeFile("other.rst")
  1273. test "Include starting from":
  1274. "other.rst".writeFile("""
  1275. And this should **NOT** be visible in `docs.html`
  1276. OtherStart
  1277. *Visible*
  1278. """)
  1279. let input = """
  1280. .. include:: other.rst
  1281. :start-after: OtherStart
  1282. """
  1283. check "<em>Visible</em>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
  1284. removeFile("other.rst")
  1285. test "Include everything before":
  1286. "other.rst".writeFile("""
  1287. *Visible*
  1288. OtherEnd
  1289. And this should **NOT** be visible in `docs.html`
  1290. """)
  1291. let input = """
  1292. .. include:: other.rst
  1293. :end-before: OtherEnd
  1294. """
  1295. doAssert "<em>Visible</em>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
  1296. removeFile("other.rst")
  1297. test "Include everything between":
  1298. "other.rst".writeFile("""
  1299. And this should **NOT** be visible in `docs.html`
  1300. OtherStart
  1301. *Visible*
  1302. OtherEnd
  1303. And this should **NOT** be visible in `docs.html`
  1304. """)
  1305. let input = """
  1306. .. include:: other.rst
  1307. :start-after: OtherStart
  1308. :end-before: OtherEnd
  1309. """
  1310. check "<em>Visible</em>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
  1311. removeFile("other.rst")
  1312. test "Ignore premature ending string":
  1313. "other.rst".writeFile("""
  1314. OtherEnd
  1315. And this should **NOT** be visible in `docs.html`
  1316. OtherStart
  1317. *Visible*
  1318. OtherEnd
  1319. And this should **NOT** be visible in `docs.html`
  1320. """)
  1321. let input = """
  1322. .. include:: other.rst
  1323. :start-after: OtherStart
  1324. :end-before: OtherEnd
  1325. """
  1326. doAssert "<em>Visible</em>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
  1327. removeFile("other.rst")
  1328. suite "RST escaping":
  1329. test "backspaces":
  1330. check("""\ this""".toAst == dedent"""
  1331. rnLeaf 'this'
  1332. """)
  1333. check("""\\ this""".toAst == dedent"""
  1334. rnInner
  1335. rnLeaf '\'
  1336. rnLeaf ' '
  1337. rnLeaf 'this'
  1338. """)
  1339. check("""\\\ this""".toAst == dedent"""
  1340. rnInner
  1341. rnLeaf '\'
  1342. rnLeaf 'this'
  1343. """)
  1344. check("""\\\\ this""".toAst == dedent"""
  1345. rnInner
  1346. rnLeaf '\'
  1347. rnLeaf '\'
  1348. rnLeaf ' '
  1349. rnLeaf 'this'
  1350. """)
  1351. suite "RST inline markup":
  1352. test "* and ** surrounded by spaces are not inline markup":
  1353. check("a * b * c ** d ** e".toAst == dedent"""
  1354. rnInner
  1355. rnLeaf 'a'
  1356. rnLeaf ' '
  1357. rnLeaf '*'
  1358. rnLeaf ' '
  1359. rnLeaf 'b'
  1360. rnLeaf ' '
  1361. rnLeaf '*'
  1362. rnLeaf ' '
  1363. rnLeaf 'c'
  1364. rnLeaf ' '
  1365. rnLeaf '**'
  1366. rnLeaf ' '
  1367. rnLeaf 'd'
  1368. rnLeaf ' '
  1369. rnLeaf '**'
  1370. rnLeaf ' '
  1371. rnLeaf 'e'
  1372. """)
  1373. test "end-string has repeating symbols":
  1374. check("*emphasis content****".toAst == dedent"""
  1375. rnEmphasis
  1376. rnLeaf 'emphasis'
  1377. rnLeaf ' '
  1378. rnLeaf 'content'
  1379. rnLeaf '***'
  1380. """)
  1381. check("""*emphasis content\****""".toAst == dedent"""
  1382. rnEmphasis
  1383. rnLeaf 'emphasis'
  1384. rnLeaf ' '
  1385. rnLeaf 'content'
  1386. rnLeaf '*'
  1387. rnLeaf '**'
  1388. """) # exact configuration of leafs with * is not really essential,
  1389. # only total number of * is essential
  1390. check("**strong content****".toAst == dedent"""
  1391. rnStrongEmphasis
  1392. rnLeaf 'strong'
  1393. rnLeaf ' '
  1394. rnLeaf 'content'
  1395. rnLeaf '**'
  1396. """)
  1397. check("""**strong content*\****""".toAst == dedent"""
  1398. rnStrongEmphasis
  1399. rnLeaf 'strong'
  1400. rnLeaf ' '
  1401. rnLeaf 'content'
  1402. rnLeaf '*'
  1403. rnLeaf '*'
  1404. rnLeaf '*'
  1405. """)
  1406. check("``lit content`````".toAst == dedent"""
  1407. rnInlineLiteral
  1408. rnLeaf 'lit'
  1409. rnLeaf ' '
  1410. rnLeaf 'content'
  1411. rnLeaf '```'
  1412. """)
  1413. test "interpreted text parsing: code fragments":
  1414. check(dedent"""
  1415. .. default-role:: option
  1416. `--gc:refc`""".toAst ==
  1417. dedent"""
  1418. rnInner
  1419. rnDefaultRole
  1420. rnDirArg
  1421. rnLeaf 'option'
  1422. [nil]
  1423. [nil]
  1424. rnParagraph
  1425. rnCodeFragment
  1426. rnInner
  1427. rnLeaf '--'
  1428. rnLeaf 'gc'
  1429. rnLeaf ':'
  1430. rnLeaf 'refc'
  1431. rnLeaf 'option'
  1432. """)
  1433. test """interpreted text can be ended with \` """:
  1434. let output = (".. default-role:: literal\n" & """`\``""").toAst
  1435. check(output.endsWith """
  1436. rnParagraph
  1437. rnInlineLiteral
  1438. rnLeaf '`'""" & "\n")
  1439. let output2 = """`\``""".toAst
  1440. check(output2 == dedent"""
  1441. rnInlineCode
  1442. rnDirArg
  1443. rnLeaf 'nim'
  1444. [nil]
  1445. rnLiteralBlock
  1446. rnLeaf '`'
  1447. """)
  1448. let output3 = """`proc \`+\``""".toAst
  1449. check(output3 == dedent"""
  1450. rnInlineCode
  1451. rnDirArg
  1452. rnLeaf 'nim'
  1453. [nil]
  1454. rnLiteralBlock
  1455. rnLeaf 'proc `+`'
  1456. """)
  1457. check("""`\\`""".toAst ==
  1458. dedent"""
  1459. rnInlineCode
  1460. rnDirArg
  1461. rnLeaf 'nim'
  1462. [nil]
  1463. rnLiteralBlock
  1464. rnLeaf '\\'
  1465. """)
  1466. test "Markdown-style code/backtick":
  1467. # no whitespace is required before `
  1468. check("`try`...`except`".toAst ==
  1469. dedent"""
  1470. rnInner
  1471. rnInlineCode
  1472. rnDirArg
  1473. rnLeaf 'nim'
  1474. [nil]
  1475. rnLiteralBlock
  1476. rnLeaf 'try'
  1477. rnLeaf '...'
  1478. rnInlineCode
  1479. rnDirArg
  1480. rnLeaf 'nim'
  1481. [nil]
  1482. rnLiteralBlock
  1483. rnLeaf 'except'
  1484. """)
  1485. test """inline literals can contain \ anywhere""":
  1486. check("""``\``""".toAst == dedent"""
  1487. rnInlineLiteral
  1488. rnLeaf '\'
  1489. """)
  1490. check("""``\\``""".toAst == dedent"""
  1491. rnInlineLiteral
  1492. rnLeaf '\'
  1493. rnLeaf '\'
  1494. """)
  1495. check("""``\```""".toAst == dedent"""
  1496. rnInlineLiteral
  1497. rnLeaf '\'
  1498. rnLeaf '`'
  1499. """)
  1500. check("""``\\```""".toAst == dedent"""
  1501. rnInlineLiteral
  1502. rnLeaf '\'
  1503. rnLeaf '\'
  1504. rnLeaf '`'
  1505. """)
  1506. check("""``\````""".toAst == dedent"""
  1507. rnInlineLiteral
  1508. rnLeaf '\'
  1509. rnLeaf '`'
  1510. rnLeaf '`'
  1511. """)
  1512. test "references with _ at the end":
  1513. check(dedent"""
  1514. .. _lnk: https
  1515. lnk_""".toAst ==
  1516. dedent"""
  1517. rnHyperlink
  1518. rnInner
  1519. rnLeaf 'lnk'
  1520. rnInner
  1521. rnLeaf 'https'
  1522. """)
  1523. test "not a hyper link":
  1524. check(dedent"""
  1525. .. _lnk: https
  1526. lnk___""".toAst ==
  1527. dedent"""
  1528. rnInner
  1529. rnLeaf 'lnk'
  1530. rnLeaf '___'
  1531. """)
  1532. test "no punctuation in the end of a standalone URI is allowed":
  1533. check(dedent"""
  1534. [see (http://no.org)], end""".toAst(rstOptions = preferRst) ==
  1535. dedent"""
  1536. rnInner
  1537. rnLeaf '['
  1538. rnLeaf 'see'
  1539. rnLeaf ' '
  1540. rnLeaf '('
  1541. rnStandaloneHyperlink
  1542. rnLeaf 'http://no.org'
  1543. rnLeaf ')'
  1544. rnLeaf ']'
  1545. rnLeaf ','
  1546. rnLeaf ' '
  1547. rnLeaf 'end'
  1548. """)
  1549. # but `/` at the end is OK
  1550. check(
  1551. dedent"""
  1552. See http://no.org/ end""".toAst ==
  1553. dedent"""
  1554. rnInner
  1555. rnLeaf 'See'
  1556. rnLeaf ' '
  1557. rnStandaloneHyperlink
  1558. rnLeaf 'http://no.org/'
  1559. rnLeaf ' '
  1560. rnLeaf 'end'
  1561. """)
  1562. # a more complex URL with some made-up ending '&='.
  1563. # Github Markdown would include final &= and
  1564. # so would rst2html.py in contradiction with RST spec.
  1565. check(
  1566. dedent"""
  1567. See https://www.google.com/url?sa=t&source=web&cd=&cad=rja&url=https%3A%2F%2Fnim-lang.github.io%2FNim%2Frst.html%23features&usg=AO&= end""".toAst ==
  1568. dedent"""
  1569. rnInner
  1570. rnLeaf 'See'
  1571. rnLeaf ' '
  1572. rnStandaloneHyperlink
  1573. rnLeaf 'https://www.google.com/url?sa=t&source=web&cd=&cad=rja&url=https%3A%2F%2Fnim-lang.github.io%2FNim%2Frst.html%23features&usg=AO'
  1574. rnLeaf '&'
  1575. rnLeaf '='
  1576. rnLeaf ' '
  1577. rnLeaf 'end'
  1578. """)
  1579. test "Markdown-style link can be split to a few lines":
  1580. check(dedent"""
  1581. is [term-rewriting
  1582. macros](manual.html#term-rewriting-macros)""".toAst ==
  1583. dedent"""
  1584. rnInner
  1585. rnLeaf 'is'
  1586. rnLeaf ' '
  1587. rnHyperlink
  1588. rnLeaf 'term-rewriting macros'
  1589. rnLeaf 'manual.html#term-rewriting-macros'
  1590. """)
  1591. test "URL with balanced parentheses (Markdown rule)":
  1592. # 2 balanced parens, 1 unbalanced:
  1593. check(dedent"""
  1594. https://en.wikipedia.org/wiki/APL_((programming_language)))""".toAst ==
  1595. dedent"""
  1596. rnInner
  1597. rnStandaloneHyperlink
  1598. rnLeaf 'https://en.wikipedia.org/wiki/APL_((programming_language))'
  1599. rnLeaf ')'
  1600. """)
  1601. # the same for Markdown-style link:
  1602. check(dedent"""
  1603. [foo [bar]](https://en.wikipedia.org/wiki/APL_((programming_language))))""".toAst ==
  1604. dedent"""
  1605. rnInner
  1606. rnHyperlink
  1607. rnLeaf 'foo [bar]'
  1608. rnLeaf 'https://en.wikipedia.org/wiki/APL_((programming_language))'
  1609. rnLeaf ')'
  1610. """)
  1611. # unbalanced (here behavior is more RST-like actually):
  1612. check(dedent"""
  1613. https://en.wikipedia.org/wiki/APL_(programming_language(""".toAst ==
  1614. dedent"""
  1615. rnInner
  1616. rnStandaloneHyperlink
  1617. rnLeaf 'https://en.wikipedia.org/wiki/APL_(programming_language'
  1618. rnLeaf '('
  1619. """)
  1620. # unbalanced [, but still acceptable:
  1621. check(dedent"""
  1622. [my {link example](http://example.com/bracket_(symbol_[))""".toAst ==
  1623. dedent"""
  1624. rnHyperlink
  1625. rnLeaf 'my {link example'
  1626. rnLeaf 'http://example.com/bracket_(symbol_[)'
  1627. """)
  1628. test "not a Markdown link":
  1629. # bug #17340 (27) `f` will be considered as a protocol and blocked as unsafe
  1630. var warnings = new seq[string]
  1631. check("[T](f: var Foo)".toAst(warnings = warnings) ==
  1632. dedent"""
  1633. rnInner
  1634. rnLeaf '['
  1635. rnLeaf 'T'
  1636. rnLeaf ']'
  1637. rnLeaf '('
  1638. rnLeaf 'f'
  1639. rnLeaf ':'
  1640. rnLeaf ' '
  1641. rnLeaf 'var'
  1642. rnLeaf ' '
  1643. rnLeaf 'Foo'
  1644. rnLeaf ')'
  1645. """)
  1646. check(warnings[] == @["input(1, 5) Warning: broken link 'f'"])