statum-markdown.js 98 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186
  1. /*!
  2. * Statum - client-side state library (markdown module).
  3. *
  4. * The CommonMark 0.31.2 engine (escape-first: raw source HTML is always
  5. * neutralised — see the security note above the engine) plus the
  6. * `stm-markdown` and `stm-h-demotion` bindings and the programmatic
  7. * `statum.markdown` API. The engine itself has no DOM references; only the
  8. * bindings touch elements.
  9. *
  10. * Load order: THIRD - requires statum-core.js (`window.statum._bridge`);
  11. * the `stm-markdown` handler orders itself after statum-document.js's
  12. * `stm-html`. (The attribute registry lives in statum-document.js; if that
  13. * module is absent, core queues the registration until it loads.) Like core:
  14. * an IIFE, no dependencies, no build step, plain script tag.
  15. */
  16. (function () {
  17. 'use strict';
  18. if (!window.statum || !window.statum._bridge) {
  19. console.error('[statum] statum-markdown.js requires statum-core.js');
  20. return;
  21. }
  22. var bridge = window.statum._bridge;
  23. var evalExpr = bridge.evalExpr;
  24. // ---------------------------------------------------------------------------
  25. // Markdown rendering (CommonMark 0.31.2)
  26. // ---------------------------------------------------------------------------
  27. //
  28. // A two-pass CommonMark engine: block structure first (paragraphs, ATX and
  29. // setext headings, thematic breaks, indented and fenced code blocks, block
  30. // quotes with lazy continuation, lists with tight/loose rendering and link
  31. // reference definitions), then inline parsing inside the leaf blocks
  32. // (delimiter-run emphasis, links and images, code spans, autolinks,
  33. // backslash escapes, entity references, hard/soft line breaks).
  34. //
  35. // SECURITY: the markdown source is untrusted text. Raw HTML is never passed
  36. // through — inline HTML and HTML-block-looking constructs render as escaped
  37. // text, which intentionally diverges from the CommonMark HTML output for
  38. // those examples. Link and image destinations are scheme-filtered by
  39. // safeMarkdownUrl() and everything is escaped before it reaches the output.
  40. function safeMarkdownUrl(url) {
  41. var u = url.trim();
  42. var m = u.match(/^([a-zA-Z][a-zA-Z0-9+.-]*):/);
  43. if (!m) return u;
  44. var scheme = m[1].toLowerCase();
  45. if (scheme === 'http' || scheme === 'https' || scheme === 'mailto' || scheme === 'ftp') return u;
  46. return '#';
  47. }
  48. /**
  49. * Packed HTML5 named-entity table (WHATWG `entities.json`, 2125 entries).
  50. * Each record is "name cp[,cp...]" on one line; multi-codepoint entities
  51. * carry comma-separated codepoints. Line breaks are escaped so the whole
  52. * table stays one string literal. Parsed lazily into a name -> text map the
  53. * first time an entity reference is looked up.
  54. */
  55. var MD_ENTITIES_PACKED = ''
  56. + "AElig 198\nAMP 38\nAacute 193\nAbreve 258\nAcirc 194\nAcy 1040\nAfr 120068\nAgrave 192\n"
  57. + "Alpha 913\nAmacr 256\nAnd 10835\nAogon 260\nAopf 120120\nApplyFunction 8289\nAring 197\n"
  58. + "Ascr 119964\nAssign 8788\nAtilde 195\nAuml 196\nBackslash 8726\nBarv 10983\nBarwed 8966\n"
  59. + "Bcy 1041\nBecause 8757\nBernoullis 8492\nBeta 914\nBfr 120069\nBopf 120121\nBreve 728\n"
  60. + "Bscr 8492\nBumpeq 8782\nCHcy 1063\nCOPY 169\nCacute 262\nCap 8914\n"
  61. + "CapitalDifferentialD 8517\nCayleys 8493\nCcaron 268\nCcedil 199\nCcirc 264\nCconint 8752\n"
  62. + "Cdot 266\nCedilla 184\nCenterDot 183\nCfr 8493\nChi 935\nCircleDot 8857\n"
  63. + "CircleMinus 8854\nCirclePlus 8853\nCircleTimes 8855\nClockwiseContourIntegral 8754\n"
  64. + "CloseCurlyDoubleQuote 8221\nCloseCurlyQuote 8217\nColon 8759\nColone 10868\n"
  65. + "Congruent 8801\nConint 8751\nContourIntegral 8750\nCopf 8450\nCoproduct 8720\n"
  66. + "CounterClockwiseContourIntegral 8755\nCross 10799\nCscr 119966\nCup 8915\nCupCap 8781\n"
  67. + "DD 8517\nDDotrahd 10513\nDJcy 1026\nDScy 1029\nDZcy 1039\nDagger 8225\nDarr 8609\n"
  68. + "Dashv 10980\nDcaron 270\nDcy 1044\nDel 8711\nDelta 916\nDfr 120071\nDiacriticalAcute 180\n"
  69. + "DiacriticalDot 729\nDiacriticalDoubleAcute 733\nDiacriticalGrave 96\n"
  70. + "DiacriticalTilde 732\nDiamond 8900\nDifferentialD 8518\nDopf 120123\nDot 168\n"
  71. + "DotDot 8412\nDotEqual 8784\nDoubleContourIntegral 8751\nDoubleDot 168\n"
  72. + "DoubleDownArrow 8659\nDoubleLeftArrow 8656\nDoubleLeftRightArrow 8660\n"
  73. + "DoubleLeftTee 10980\nDoubleLongLeftArrow 10232\nDoubleLongLeftRightArrow 10234\n"
  74. + "DoubleLongRightArrow 10233\nDoubleRightArrow 8658\nDoubleRightTee 8872\n"
  75. + "DoubleUpArrow 8657\nDoubleUpDownArrow 8661\nDoubleVerticalBar 8741\nDownArrow 8595\n"
  76. + "DownArrowBar 10515\nDownArrowUpArrow 8693\nDownBreve 785\nDownLeftRightVector 10576\n"
  77. + "DownLeftTeeVector 10590\nDownLeftVector 8637\nDownLeftVectorBar 10582\n"
  78. + "DownRightTeeVector 10591\nDownRightVector 8641\nDownRightVectorBar 10583\nDownTee 8868\n"
  79. + "DownTeeArrow 8615\nDownarrow 8659\nDscr 119967\nDstrok 272\nENG 330\nETH 208\nEacute 201\n"
  80. + "Ecaron 282\nEcirc 202\nEcy 1069\nEdot 278\nEfr 120072\nEgrave 200\nElement 8712\n"
  81. + "Emacr 274\nEmptySmallSquare 9723\nEmptyVerySmallSquare 9643\nEogon 280\nEopf 120124\n"
  82. + "Epsilon 917\nEqual 10869\nEqualTilde 8770\nEquilibrium 8652\nEscr 8496\nEsim 10867\n"
  83. + "Eta 919\nEuml 203\nExists 8707\nExponentialE 8519\nFcy 1060\nFfr 120073\n"
  84. + "FilledSmallSquare 9724\nFilledVerySmallSquare 9642\nFopf 120125\nForAll 8704\n"
  85. + "Fouriertrf 8497\nFscr 8497\nGJcy 1027\nGT 62\nGamma 915\nGammad 988\nGbreve 286\n"
  86. + "Gcedil 290\nGcirc 284\nGcy 1043\nGdot 288\nGfr 120074\nGg 8921\nGopf 120126\n"
  87. + "GreaterEqual 8805\nGreaterEqualLess 8923\nGreaterFullEqual 8807\nGreaterGreater 10914\n"
  88. + "GreaterLess 8823\nGreaterSlantEqual 10878\nGreaterTilde 8819\nGscr 119970\nGt 8811\n"
  89. + "HARDcy 1066\nHacek 711\nHat 94\nHcirc 292\nHfr 8460\nHilbertSpace 8459\nHopf 8461\n"
  90. + "HorizontalLine 9472\nHscr 8459\nHstrok 294\nHumpDownHump 8782\nHumpEqual 8783\nIEcy 1045\n"
  91. + "IJlig 306\nIOcy 1025\nIacute 205\nIcirc 206\nIcy 1048\nIdot 304\nIfr 8465\nIgrave 204\n"
  92. + "Im 8465\nImacr 298\nImaginaryI 8520\nImplies 8658\nInt 8748\nIntegral 8747\n"
  93. + "Intersection 8898\nInvisibleComma 8291\nInvisibleTimes 8290\nIogon 302\nIopf 120128\n"
  94. + "Iota 921\nIscr 8464\nItilde 296\nIukcy 1030\nIuml 207\nJcirc 308\nJcy 1049\nJfr 120077\n"
  95. + "Jopf 120129\nJscr 119973\nJsercy 1032\nJukcy 1028\nKHcy 1061\nKJcy 1036\nKappa 922\n"
  96. + "Kcedil 310\nKcy 1050\nKfr 120078\nKopf 120130\nKscr 119974\nLJcy 1033\nLT 60\nLacute 313\n"
  97. + "Lambda 923\nLang 10218\nLaplacetrf 8466\nLarr 8606\nLcaron 317\nLcedil 315\nLcy 1051\n"
  98. + "LeftAngleBracket 10216\nLeftArrow 8592\nLeftArrowBar 8676\nLeftArrowRightArrow 8646\n"
  99. + "LeftCeiling 8968\nLeftDoubleBracket 10214\nLeftDownTeeVector 10593\nLeftDownVector 8643\n"
  100. + "LeftDownVectorBar 10585\nLeftFloor 8970\nLeftRightArrow 8596\nLeftRightVector 10574\n"
  101. + "LeftTee 8867\nLeftTeeArrow 8612\nLeftTeeVector 10586\nLeftTriangle 8882\n"
  102. + "LeftTriangleBar 10703\nLeftTriangleEqual 8884\nLeftUpDownVector 10577\n"
  103. + "LeftUpTeeVector 10592\nLeftUpVector 8639\nLeftUpVectorBar 10584\nLeftVector 8636\n"
  104. + "LeftVectorBar 10578\nLeftarrow 8656\nLeftrightarrow 8660\nLessEqualGreater 8922\n"
  105. + "LessFullEqual 8806\nLessGreater 8822\nLessLess 10913\nLessSlantEqual 10877\n"
  106. + "LessTilde 8818\nLfr 120079\nLl 8920\nLleftarrow 8666\nLmidot 319\nLongLeftArrow 10229\n"
  107. + "LongLeftRightArrow 10231\nLongRightArrow 10230\nLongleftarrow 10232\n"
  108. + "Longleftrightarrow 10234\nLongrightarrow 10233\nLopf 120131\nLowerLeftArrow 8601\n"
  109. + "LowerRightArrow 8600\nLscr 8466\nLsh 8624\nLstrok 321\nLt 8810\nMap 10501\nMcy 1052\n"
  110. + "MediumSpace 8287\nMellintrf 8499\nMfr 120080\nMinusPlus 8723\nMopf 120132\nMscr 8499\n"
  111. + "Mu 924\nNJcy 1034\nNacute 323\nNcaron 327\nNcedil 325\nNcy 1053\n"
  112. + "NegativeMediumSpace 8203\nNegativeThickSpace 8203\nNegativeThinSpace 8203\n"
  113. + "NegativeVeryThinSpace 8203\nNestedGreaterGreater 8811\nNestedLessLess 8810\nNewLine 10\n"
  114. + "Nfr 120081\nNoBreak 8288\nNonBreakingSpace 160\nNopf 8469\nNot 10988\nNotCongruent 8802\n"
  115. + "NotCupCap 8813\nNotDoubleVerticalBar 8742\nNotElement 8713\nNotEqual 8800\n"
  116. + "NotEqualTilde 8770,824\nNotExists 8708\nNotGreater 8815\nNotGreaterEqual 8817\n"
  117. + "NotGreaterFullEqual 8807,824\nNotGreaterGreater 8811,824\nNotGreaterLess 8825\n"
  118. + "NotGreaterSlantEqual 10878,824\nNotGreaterTilde 8821\nNotHumpDownHump 8782,824\n"
  119. + "NotHumpEqual 8783,824\nNotLeftTriangle 8938\nNotLeftTriangleBar 10703,824\n"
  120. + "NotLeftTriangleEqual 8940\nNotLess 8814\nNotLessEqual 8816\nNotLessGreater 8824\n"
  121. + "NotLessLess 8810,824\nNotLessSlantEqual 10877,824\nNotLessTilde 8820\n"
  122. + "NotNestedGreaterGreater 10914,824\nNotNestedLessLess 10913,824\nNotPrecedes 8832\n"
  123. + "NotPrecedesEqual 10927,824\nNotPrecedesSlantEqual 8928\nNotReverseElement 8716\n"
  124. + "NotRightTriangle 8939\nNotRightTriangleBar 10704,824\nNotRightTriangleEqual 8941\n"
  125. + "NotSquareSubset 8847,824\nNotSquareSubsetEqual 8930\nNotSquareSuperset 8848,824\n"
  126. + "NotSquareSupersetEqual 8931\nNotSubset 8834,8402\nNotSubsetEqual 8840\nNotSucceeds 8833\n"
  127. + "NotSucceedsEqual 10928,824\nNotSucceedsSlantEqual 8929\nNotSucceedsTilde 8831,824\n"
  128. + "NotSuperset 8835,8402\nNotSupersetEqual 8841\nNotTilde 8769\nNotTildeEqual 8772\n"
  129. + "NotTildeFullEqual 8775\nNotTildeTilde 8777\nNotVerticalBar 8740\nNscr 119977\nNtilde 209\n"
  130. + "Nu 925\nOElig 338\nOacute 211\nOcirc 212\nOcy 1054\nOdblac 336\nOfr 120082\nOgrave 210\n"
  131. + "Omacr 332\nOmega 937\nOmicron 927\nOopf 120134\nOpenCurlyDoubleQuote 8220\n"
  132. + "OpenCurlyQuote 8216\nOr 10836\nOscr 119978\nOslash 216\nOtilde 213\nOtimes 10807\n"
  133. + "Ouml 214\nOverBar 8254\nOverBrace 9182\nOverBracket 9140\nOverParenthesis 9180\n"
  134. + "PartialD 8706\nPcy 1055\nPfr 120083\nPhi 934\nPi 928\nPlusMinus 177\nPoincareplane 8460\n"
  135. + "Popf 8473\nPr 10939\nPrecedes 8826\nPrecedesEqual 10927\nPrecedesSlantEqual 8828\n"
  136. + "PrecedesTilde 8830\nPrime 8243\nProduct 8719\nProportion 8759\nProportional 8733\n"
  137. + "Pscr 119979\nPsi 936\nQUOT 34\nQfr 120084\nQopf 8474\nQscr 119980\nRBarr 10512\nREG 174\n"
  138. + "Racute 340\nRang 10219\nRarr 8608\nRarrtl 10518\nRcaron 344\nRcedil 342\nRcy 1056\n"
  139. + "Re 8476\nReverseElement 8715\nReverseEquilibrium 8651\nReverseUpEquilibrium 10607\n"
  140. + "Rfr 8476\nRho 929\nRightAngleBracket 10217\nRightArrow 8594\nRightArrowBar 8677\n"
  141. + "RightArrowLeftArrow 8644\nRightCeiling 8969\nRightDoubleBracket 10215\n"
  142. + "RightDownTeeVector 10589\nRightDownVector 8642\nRightDownVectorBar 10581\n"
  143. + "RightFloor 8971\nRightTee 8866\nRightTeeArrow 8614\nRightTeeVector 10587\n"
  144. + "RightTriangle 8883\nRightTriangleBar 10704\nRightTriangleEqual 8885\n"
  145. + "RightUpDownVector 10575\nRightUpTeeVector 10588\nRightUpVector 8638\n"
  146. + "RightUpVectorBar 10580\nRightVector 8640\nRightVectorBar 10579\nRightarrow 8658\n"
  147. + "Ropf 8477\nRoundImplies 10608\nRrightarrow 8667\nRscr 8475\nRsh 8625\nRuleDelayed 10740\n"
  148. + "SHCHcy 1065\nSHcy 1064\nSOFTcy 1068\nSacute 346\nSc 10940\nScaron 352\nScedil 350\n"
  149. + "Scirc 348\nScy 1057\nSfr 120086\nShortDownArrow 8595\nShortLeftArrow 8592\n"
  150. + "ShortRightArrow 8594\nShortUpArrow 8593\nSigma 931\nSmallCircle 8728\nSopf 120138\n"
  151. + "Sqrt 8730\nSquare 9633\nSquareIntersection 8851\nSquareSubset 8847\n"
  152. + "SquareSubsetEqual 8849\nSquareSuperset 8848\nSquareSupersetEqual 8850\nSquareUnion 8852\n"
  153. + "Sscr 119982\nStar 8902\nSub 8912\nSubset 8912\nSubsetEqual 8838\nSucceeds 8827\n"
  154. + "SucceedsEqual 10928\nSucceedsSlantEqual 8829\nSucceedsTilde 8831\nSuchThat 8715\n"
  155. + "Sum 8721\nSup 8913\nSuperset 8835\nSupersetEqual 8839\nSupset 8913\nTHORN 222\n"
  156. + "TRADE 8482\nTSHcy 1035\nTScy 1062\nTab 9\nTau 932\nTcaron 356\nTcedil 354\nTcy 1058\n"
  157. + "Tfr 120087\nTherefore 8756\nTheta 920\nThickSpace 8287,8202\nThinSpace 8201\nTilde 8764\n"
  158. + "TildeEqual 8771\nTildeFullEqual 8773\nTildeTilde 8776\nTopf 120139\nTripleDot 8411\n"
  159. + "Tscr 119983\nTstrok 358\nUacute 218\nUarr 8607\nUarrocir 10569\nUbrcy 1038\nUbreve 364\n"
  160. + "Ucirc 219\nUcy 1059\nUdblac 368\nUfr 120088\nUgrave 217\nUmacr 362\nUnderBar 95\n"
  161. + "UnderBrace 9183\nUnderBracket 9141\nUnderParenthesis 9181\nUnion 8899\nUnionPlus 8846\n"
  162. + "Uogon 370\nUopf 120140\nUpArrow 8593\nUpArrowBar 10514\nUpArrowDownArrow 8645\n"
  163. + "UpDownArrow 8597\nUpEquilibrium 10606\nUpTee 8869\nUpTeeArrow 8613\nUparrow 8657\n"
  164. + "Updownarrow 8661\nUpperLeftArrow 8598\nUpperRightArrow 8599\nUpsi 978\nUpsilon 933\n"
  165. + "Uring 366\nUscr 119984\nUtilde 360\nUuml 220\nVDash 8875\nVbar 10987\nVcy 1042\n"
  166. + "Vdash 8873\nVdashl 10982\nVee 8897\nVerbar 8214\nVert 8214\nVerticalBar 8739\n"
  167. + "VerticalLine 124\nVerticalSeparator 10072\nVerticalTilde 8768\nVeryThinSpace 8202\n"
  168. + "Vfr 120089\nVopf 120141\nVscr 119985\nVvdash 8874\nWcirc 372\nWedge 8896\nWfr 120090\n"
  169. + "Wopf 120142\nWscr 119986\nXfr 120091\nXi 926\nXopf 120143\nXscr 119987\nYAcy 1071\n"
  170. + "YIcy 1031\nYUcy 1070\nYacute 221\nYcirc 374\nYcy 1067\nYfr 120092\nYopf 120144\n"
  171. + "Yscr 119988\nYuml 376\nZHcy 1046\nZacute 377\nZcaron 381\nZcy 1047\nZdot 379\n"
  172. + "ZeroWidthSpace 8203\nZeta 918\nZfr 8488\nZopf 8484\nZscr 119989\naacute 225\nabreve 259\n"
  173. + "ac 8766\nacE 8766,819\nacd 8767\nacirc 226\nacute 180\nacy 1072\naelig 230\naf 8289\n"
  174. + "afr 120094\nagrave 224\nalefsym 8501\naleph 8501\nalpha 945\namacr 257\namalg 10815\n"
  175. + "amp 38\nand 8743\nandand 10837\nandd 10844\nandslope 10840\nandv 10842\nang 8736\n"
  176. + "ange 10660\nangle 8736\nangmsd 8737\nangmsdaa 10664\nangmsdab 10665\nangmsdac 10666\n"
  177. + "angmsdad 10667\nangmsdae 10668\nangmsdaf 10669\nangmsdag 10670\nangmsdah 10671\n"
  178. + "angrt 8735\nangrtvb 8894\nangrtvbd 10653\nangsph 8738\nangst 197\nangzarr 9084\n"
  179. + "aogon 261\naopf 120146\nap 8776\napE 10864\napacir 10863\nape 8778\napid 8779\napos 39\n"
  180. + "approx 8776\napproxeq 8778\naring 229\nascr 119990\nast 42\nasymp 8776\nasympeq 8781\n"
  181. + "atilde 227\nauml 228\nawconint 8755\nawint 10769\nbNot 10989\nbackcong 8780\n"
  182. + "backepsilon 1014\nbackprime 8245\nbacksim 8765\nbacksimeq 8909\nbarvee 8893\nbarwed 8965\n"
  183. + "barwedge 8965\nbbrk 9141\nbbrktbrk 9142\nbcong 8780\nbcy 1073\nbdquo 8222\nbecaus 8757\n"
  184. + "because 8757\nbemptyv 10672\nbepsi 1014\nbernou 8492\nbeta 946\nbeth 8502\nbetween 8812\n"
  185. + "bfr 120095\nbigcap 8898\nbigcirc 9711\nbigcup 8899\nbigodot 10752\nbigoplus 10753\n"
  186. + "bigotimes 10754\nbigsqcup 10758\nbigstar 9733\nbigtriangledown 9661\nbigtriangleup 9651\n"
  187. + "biguplus 10756\nbigvee 8897\nbigwedge 8896\nbkarow 10509\nblacklozenge 10731\n"
  188. + "blacksquare 9642\nblacktriangle 9652\nblacktriangledown 9662\nblacktriangleleft 9666\n"
  189. + "blacktriangleright 9656\nblank 9251\nblk12 9618\nblk14 9617\nblk34 9619\nblock 9608\n"
  190. + "bne 61,8421\nbnequiv 8801,8421\nbnot 8976\nbopf 120147\nbot 8869\nbottom 8869\n"
  191. + "bowtie 8904\nboxDL 9559\nboxDR 9556\nboxDl 9558\nboxDr 9555\nboxH 9552\nboxHD 9574\n"
  192. + "boxHU 9577\nboxHd 9572\nboxHu 9575\nboxUL 9565\nboxUR 9562\nboxUl 9564\nboxUr 9561\n"
  193. + "boxV 9553\nboxVH 9580\nboxVL 9571\nboxVR 9568\nboxVh 9579\nboxVl 9570\nboxVr 9567\n"
  194. + "boxbox 10697\nboxdL 9557\nboxdR 9554\nboxdl 9488\nboxdr 9484\nboxh 9472\nboxhD 9573\n"
  195. + "boxhU 9576\nboxhd 9516\nboxhu 9524\nboxminus 8863\nboxplus 8862\nboxtimes 8864\n"
  196. + "boxuL 9563\nboxuR 9560\nboxul 9496\nboxur 9492\nboxv 9474\nboxvH 9578\nboxvL 9569\n"
  197. + "boxvR 9566\nboxvh 9532\nboxvl 9508\nboxvr 9500\nbprime 8245\nbreve 728\nbrvbar 166\n"
  198. + "bscr 119991\nbsemi 8271\nbsim 8765\nbsime 8909\nbsol 92\nbsolb 10693\nbsolhsub 10184\n"
  199. + "bull 8226\nbullet 8226\nbump 8782\nbumpE 10926\nbumpe 8783\nbumpeq 8783\ncacute 263\n"
  200. + "cap 8745\ncapand 10820\ncapbrcup 10825\ncapcap 10827\ncapcup 10823\ncapdot 10816\n"
  201. + "caps 8745,65024\ncaret 8257\ncaron 711\nccaps 10829\nccaron 269\nccedil 231\nccirc 265\n"
  202. + "ccups 10828\nccupssm 10832\ncdot 267\ncedil 184\ncemptyv 10674\ncent 162\ncenterdot 183\n"
  203. + "cfr 120096\nchcy 1095\ncheck 10003\ncheckmark 10003\nchi 967\ncir 9675\ncirE 10691\n"
  204. + "circ 710\ncirceq 8791\ncirclearrowleft 8634\ncirclearrowright 8635\ncircledR 174\n"
  205. + "circledS 9416\ncircledast 8859\ncircledcirc 8858\ncircleddash 8861\ncire 8791\n"
  206. + "cirfnint 10768\ncirmid 10991\ncirscir 10690\nclubs 9827\nclubsuit 9827\ncolon 58\n"
  207. + "colone 8788\ncoloneq 8788\ncomma 44\ncommat 64\ncomp 8705\ncompfn 8728\ncomplement 8705\n"
  208. + "complexes 8450\ncong 8773\ncongdot 10861\nconint 8750\ncopf 120148\ncoprod 8720\n"
  209. + "copy 169\ncopysr 8471\ncrarr 8629\ncross 10007\ncscr 119992\ncsub 10959\ncsube 10961\n"
  210. + "csup 10960\ncsupe 10962\nctdot 8943\ncudarrl 10552\ncudarrr 10549\ncuepr 8926\n"
  211. + "cuesc 8927\ncularr 8630\ncularrp 10557\ncup 8746\ncupbrcap 10824\ncupcap 10822\n"
  212. + "cupcup 10826\ncupdot 8845\ncupor 10821\ncups 8746,65024\ncurarr 8631\ncurarrm 10556\n"
  213. + "curlyeqprec 8926\ncurlyeqsucc 8927\ncurlyvee 8910\ncurlywedge 8911\ncurren 164\n"
  214. + "curvearrowleft 8630\ncurvearrowright 8631\ncuvee 8910\ncuwed 8911\ncwconint 8754\n"
  215. + "cwint 8753\ncylcty 9005\ndArr 8659\ndHar 10597\ndagger 8224\ndaleth 8504\ndarr 8595\n"
  216. + "dash 8208\ndashv 8867\ndbkarow 10511\ndblac 733\ndcaron 271\ndcy 1076\ndd 8518\n"
  217. + "ddagger 8225\nddarr 8650\nddotseq 10871\ndeg 176\ndelta 948\ndemptyv 10673\ndfisht 10623\n"
  218. + "dfr 120097\ndharl 8643\ndharr 8642\ndiam 8900\ndiamond 8900\ndiamondsuit 9830\n"
  219. + "diams 9830\ndie 168\ndigamma 989\ndisin 8946\ndiv 247\ndivide 247\ndivideontimes 8903\n"
  220. + "divonx 8903\ndjcy 1106\ndlcorn 8990\ndlcrop 8973\ndollar 36\ndopf 120149\ndot 729\n"
  221. + "doteq 8784\ndoteqdot 8785\ndotminus 8760\ndotplus 8724\ndotsquare 8865\n"
  222. + "doublebarwedge 8966\ndownarrow 8595\ndowndownarrows 8650\ndownharpoonleft 8643\n"
  223. + "downharpoonright 8642\ndrbkarow 10512\ndrcorn 8991\ndrcrop 8972\ndscr 119993\ndscy 1109\n"
  224. + "dsol 10742\ndstrok 273\ndtdot 8945\ndtri 9663\ndtrif 9662\nduarr 8693\nduhar 10607\n"
  225. + "dwangle 10662\ndzcy 1119\ndzigrarr 10239\neDDot 10871\neDot 8785\neacute 233\n"
  226. + "easter 10862\necaron 283\necir 8790\necirc 234\necolon 8789\necy 1101\nedot 279\nee 8519\n"
  227. + "efDot 8786\nefr 120098\neg 10906\negrave 232\negs 10902\negsdot 10904\nel 10905\n"
  228. + "elinters 9191\nell 8467\nels 10901\nelsdot 10903\nemacr 275\nempty 8709\nemptyset 8709\n"
  229. + "emptyv 8709\nemsp 8195\nemsp13 8196\nemsp14 8197\neng 331\nensp 8194\neogon 281\n"
  230. + "eopf 120150\nepar 8917\neparsl 10723\neplus 10865\nepsi 949\nepsilon 949\nepsiv 1013\n"
  231. + "eqcirc 8790\neqcolon 8789\neqsim 8770\neqslantgtr 10902\neqslantless 10901\nequals 61\n"
  232. + "equest 8799\nequiv 8801\nequivDD 10872\neqvparsl 10725\nerDot 8787\nerarr 10609\n"
  233. + "escr 8495\nesdot 8784\nesim 8770\neta 951\neth 240\neuml 235\neuro 8364\nexcl 33\n"
  234. + "exist 8707\nexpectation 8496\nexponentiale 8519\nfallingdotseq 8786\nfcy 1092\n"
  235. + "female 9792\nffilig 64259\nfflig 64256\nffllig 64260\nffr 120099\nfilig 64257\n"
  236. + "fjlig 102,106\nflat 9837\nfllig 64258\nfltns 9649\nfnof 402\nfopf 120151\nforall 8704\n"
  237. + "fork 8916\nforkv 10969\nfpartint 10765\nfrac12 189\nfrac13 8531\nfrac14 188\nfrac15 8533\n"
  238. + "frac16 8537\nfrac18 8539\nfrac23 8532\nfrac25 8534\nfrac34 190\nfrac35 8535\nfrac38 8540\n"
  239. + "frac45 8536\nfrac56 8538\nfrac58 8541\nfrac78 8542\nfrasl 8260\nfrown 8994\nfscr 119995\n"
  240. + "gE 8807\ngEl 10892\ngacute 501\ngamma 947\ngammad 989\ngap 10886\ngbreve 287\ngcirc 285\n"
  241. + "gcy 1075\ngdot 289\nge 8805\ngel 8923\ngeq 8805\ngeqq 8807\ngeqslant 10878\nges 10878\n"
  242. + "gescc 10921\ngesdot 10880\ngesdoto 10882\ngesdotol 10884\ngesl 8923,65024\ngesles 10900\n"
  243. + "gfr 120100\ngg 8811\nggg 8921\ngimel 8503\ngjcy 1107\ngl 8823\nglE 10898\ngla 10917\n"
  244. + "glj 10916\ngnE 8809\ngnap 10890\ngnapprox 10890\ngne 10888\ngneq 10888\ngneqq 8809\n"
  245. + "gnsim 8935\ngopf 120152\ngrave 96\ngscr 8458\ngsim 8819\ngsime 10894\ngsiml 10896\ngt 62\n"
  246. + "gtcc 10919\ngtcir 10874\ngtdot 8919\ngtlPar 10645\ngtquest 10876\ngtrapprox 10886\n"
  247. + "gtrarr 10616\ngtrdot 8919\ngtreqless 8923\ngtreqqless 10892\ngtrless 8823\ngtrsim 8819\n"
  248. + "gvertneqq 8809,65024\ngvnE 8809,65024\nhArr 8660\nhairsp 8202\nhalf 189\nhamilt 8459\n"
  249. + "hardcy 1098\nharr 8596\nharrcir 10568\nharrw 8621\nhbar 8463\nhcirc 293\nhearts 9829\n"
  250. + "heartsuit 9829\nhellip 8230\nhercon 8889\nhfr 120101\nhksearow 10533\nhkswarow 10534\n"
  251. + "hoarr 8703\nhomtht 8763\nhookleftarrow 8617\nhookrightarrow 8618\nhopf 120153\n"
  252. + "horbar 8213\nhscr 119997\nhslash 8463\nhstrok 295\nhybull 8259\nhyphen 8208\niacute 237\n"
  253. + "ic 8291\nicirc 238\nicy 1080\niecy 1077\niexcl 161\niff 8660\nifr 120102\nigrave 236\n"
  254. + "ii 8520\niiiint 10764\niiint 8749\niinfin 10716\niiota 8489\nijlig 307\nimacr 299\n"
  255. + "image 8465\nimagline 8464\nimagpart 8465\nimath 305\nimof 8887\nimped 437\nin 8712\n"
  256. + "incare 8453\ninfin 8734\ninfintie 10717\ninodot 305\nint 8747\nintcal 8890\n"
  257. + "integers 8484\nintercal 8890\nintlarhk 10775\nintprod 10812\niocy 1105\niogon 303\n"
  258. + "iopf 120154\niota 953\niprod 10812\niquest 191\niscr 119998\nisin 8712\nisinE 8953\n"
  259. + "isindot 8949\nisins 8948\nisinsv 8947\nisinv 8712\nit 8290\nitilde 297\niukcy 1110\n"
  260. + "iuml 239\njcirc 309\njcy 1081\njfr 120103\njmath 567\njopf 120155\njscr 119999\n"
  261. + "jsercy 1112\njukcy 1108\nkappa 954\nkappav 1008\nkcedil 311\nkcy 1082\nkfr 120104\n"
  262. + "kgreen 312\nkhcy 1093\nkjcy 1116\nkopf 120156\nkscr 120000\nlAarr 8666\nlArr 8656\n"
  263. + "lAtail 10523\nlBarr 10510\nlE 8806\nlEg 10891\nlHar 10594\nlacute 314\nlaemptyv 10676\n"
  264. + "lagran 8466\nlambda 955\nlang 10216\nlangd 10641\nlangle 10216\nlap 10885\nlaquo 171\n"
  265. + "larr 8592\nlarrb 8676\nlarrbfs 10527\nlarrfs 10525\nlarrhk 8617\nlarrlp 8619\n"
  266. + "larrpl 10553\nlarrsim 10611\nlarrtl 8610\nlat 10923\nlatail 10521\nlate 10925\n"
  267. + "lates 10925,65024\nlbarr 10508\nlbbrk 10098\nlbrace 123\nlbrack 91\nlbrke 10635\n"
  268. + "lbrksld 10639\nlbrkslu 10637\nlcaron 318\nlcedil 316\nlceil 8968\nlcub 123\nlcy 1083\n"
  269. + "ldca 10550\nldquo 8220\nldquor 8222\nldrdhar 10599\nldrushar 10571\nldsh 8626\nle 8804\n"
  270. + "leftarrow 8592\nleftarrowtail 8610\nleftharpoondown 8637\nleftharpoonup 8636\n"
  271. + "leftleftarrows 8647\nleftrightarrow 8596\nleftrightarrows 8646\nleftrightharpoons 8651\n"
  272. + "leftrightsquigarrow 8621\nleftthreetimes 8907\nleg 8922\nleq 8804\nleqq 8806\n"
  273. + "leqslant 10877\nles 10877\nlescc 10920\nlesdot 10879\nlesdoto 10881\nlesdotor 10883\n"
  274. + "lesg 8922,65024\nlesges 10899\nlessapprox 10885\nlessdot 8918\nlesseqgtr 8922\n"
  275. + "lesseqqgtr 10891\nlessgtr 8822\nlesssim 8818\nlfisht 10620\nlfloor 8970\nlfr 120105\n"
  276. + "lg 8822\nlgE 10897\nlhard 8637\nlharu 8636\nlharul 10602\nlhblk 9604\nljcy 1113\nll 8810\n"
  277. + "llarr 8647\nllcorner 8990\nllhard 10603\nlltri 9722\nlmidot 320\nlmoust 9136\n"
  278. + "lmoustache 9136\nlnE 8808\nlnap 10889\nlnapprox 10889\nlne 10887\nlneq 10887\nlneqq 8808\n"
  279. + "lnsim 8934\nloang 10220\nloarr 8701\nlobrk 10214\nlongleftarrow 10229\n"
  280. + "longleftrightarrow 10231\nlongmapsto 10236\nlongrightarrow 10230\nlooparrowleft 8619\n"
  281. + "looparrowright 8620\nlopar 10629\nlopf 120157\nloplus 10797\nlotimes 10804\nlowast 8727\n"
  282. + "lowbar 95\nloz 9674\nlozenge 9674\nlozf 10731\nlpar 40\nlparlt 10643\nlrarr 8646\n"
  283. + "lrcorner 8991\nlrhar 8651\nlrhard 10605\nlrm 8206\nlrtri 8895\nlsaquo 8249\nlscr 120001\n"
  284. + "lsh 8624\nlsim 8818\nlsime 10893\nlsimg 10895\nlsqb 91\nlsquo 8216\nlsquor 8218\n"
  285. + "lstrok 322\nlt 60\nltcc 10918\nltcir 10873\nltdot 8918\nlthree 8907\nltimes 8905\n"
  286. + "ltlarr 10614\nltquest 10875\nltrPar 10646\nltri 9667\nltrie 8884\nltrif 9666\n"
  287. + "lurdshar 10570\nluruhar 10598\nlvertneqq 8808,65024\nlvnE 8808,65024\nmDDot 8762\n"
  288. + "macr 175\nmale 9794\nmalt 10016\nmaltese 10016\nmap 8614\nmapsto 8614\nmapstodown 8615\n"
  289. + "mapstoleft 8612\nmapstoup 8613\nmarker 9646\nmcomma 10793\nmcy 1084\nmdash 8212\n"
  290. + "measuredangle 8737\nmfr 120106\nmho 8487\nmicro 181\nmid 8739\nmidast 42\nmidcir 10992\n"
  291. + "middot 183\nminus 8722\nminusb 8863\nminusd 8760\nminusdu 10794\nmlcp 10971\nmldr 8230\n"
  292. + "mnplus 8723\nmodels 8871\nmopf 120158\nmp 8723\nmscr 120002\nmstpos 8766\nmu 956\n"
  293. + "multimap 8888\nmumap 8888\nnGg 8921,824\nnGt 8811,8402\nnGtv 8811,824\nnLeftarrow 8653\n"
  294. + "nLeftrightarrow 8654\nnLl 8920,824\nnLt 8810,8402\nnLtv 8810,824\nnRightarrow 8655\n"
  295. + "nVDash 8879\nnVdash 8878\nnabla 8711\nnacute 324\nnang 8736,8402\nnap 8777\n"
  296. + "napE 10864,824\nnapid 8779,824\nnapos 329\nnapprox 8777\nnatur 9838\nnatural 9838\n"
  297. + "naturals 8469\nnbsp 160\nnbump 8782,824\nnbumpe 8783,824\nncap 10819\nncaron 328\n"
  298. + "ncedil 326\nncong 8775\nncongdot 10861,824\nncup 10818\nncy 1085\nndash 8211\nne 8800\n"
  299. + "neArr 8663\nnearhk 10532\nnearr 8599\nnearrow 8599\nnedot 8784,824\nnequiv 8802\n"
  300. + "nesear 10536\nnesim 8770,824\nnexist 8708\nnexists 8708\nnfr 120107\nngE 8807,824\n"
  301. + "nge 8817\nngeq 8817\nngeqq 8807,824\nngeqslant 10878,824\nnges 10878,824\nngsim 8821\n"
  302. + "ngt 8815\nngtr 8815\nnhArr 8654\nnharr 8622\nnhpar 10994\nni 8715\nnis 8956\nnisd 8954\n"
  303. + "niv 8715\nnjcy 1114\nnlArr 8653\nnlE 8806,824\nnlarr 8602\nnldr 8229\nnle 8816\n"
  304. + "nleftarrow 8602\nnleftrightarrow 8622\nnleq 8816\nnleqq 8806,824\nnleqslant 10877,824\n"
  305. + "nles 10877,824\nnless 8814\nnlsim 8820\nnlt 8814\nnltri 8938\nnltrie 8940\nnmid 8740\n"
  306. + "nopf 120159\nnot 172\nnotin 8713\nnotinE 8953,824\nnotindot 8949,824\nnotinva 8713\n"
  307. + "notinvb 8951\nnotinvc 8950\nnotni 8716\nnotniva 8716\nnotnivb 8958\nnotnivc 8957\n"
  308. + "npar 8742\nnparallel 8742\nnparsl 11005,8421\nnpart 8706,824\nnpolint 10772\nnpr 8832\n"
  309. + "nprcue 8928\nnpre 10927,824\nnprec 8832\nnpreceq 10927,824\nnrArr 8655\nnrarr 8603\n"
  310. + "nrarrc 10547,824\nnrarrw 8605,824\nnrightarrow 8603\nnrtri 8939\nnrtrie 8941\nnsc 8833\n"
  311. + "nsccue 8929\nnsce 10928,824\nnscr 120003\nnshortmid 8740\nnshortparallel 8742\nnsim 8769\n"
  312. + "nsime 8772\nnsimeq 8772\nnsmid 8740\nnspar 8742\nnsqsube 8930\nnsqsupe 8931\nnsub 8836\n"
  313. + "nsubE 10949,824\nnsube 8840\nnsubset 8834,8402\nnsubseteq 8840\nnsubseteqq 10949,824\n"
  314. + "nsucc 8833\nnsucceq 10928,824\nnsup 8837\nnsupE 10950,824\nnsupe 8841\nnsupset 8835,8402\n"
  315. + "nsupseteq 8841\nnsupseteqq 10950,824\nntgl 8825\nntilde 241\nntlg 8824\n"
  316. + "ntriangleleft 8938\nntrianglelefteq 8940\nntriangleright 8939\nntrianglerighteq 8941\n"
  317. + "nu 957\nnum 35\nnumero 8470\nnumsp 8199\nnvDash 8877\nnvHarr 10500\nnvap 8781,8402\n"
  318. + "nvdash 8876\nnvge 8805,8402\nnvgt 62,8402\nnvinfin 10718\nnvlArr 10498\nnvle 8804,8402\n"
  319. + "nvlt 60,8402\nnvltrie 8884,8402\nnvrArr 10499\nnvrtrie 8885,8402\nnvsim 8764,8402\n"
  320. + "nwArr 8662\nnwarhk 10531\nnwarr 8598\nnwarrow 8598\nnwnear 10535\noS 9416\noacute 243\n"
  321. + "oast 8859\nocir 8858\nocirc 244\nocy 1086\nodash 8861\nodblac 337\nodiv 10808\nodot 8857\n"
  322. + "odsold 10684\noelig 339\nofcir 10687\nofr 120108\nogon 731\nograve 242\nogt 10689\n"
  323. + "ohbar 10677\nohm 937\noint 8750\nolarr 8634\nolcir 10686\nolcross 10683\noline 8254\n"
  324. + "olt 10688\nomacr 333\nomega 969\nomicron 959\nomid 10678\nominus 8854\noopf 120160\n"
  325. + "opar 10679\noperp 10681\noplus 8853\nor 8744\norarr 8635\nord 10845\norder 8500\n"
  326. + "orderof 8500\nordf 170\nordm 186\norigof 8886\noror 10838\norslope 10839\norv 10843\n"
  327. + "oscr 8500\noslash 248\nosol 8856\notilde 245\notimes 8855\notimesas 10806\nouml 246\n"
  328. + "ovbar 9021\npar 8741\npara 182\nparallel 8741\nparsim 10995\nparsl 11005\npart 8706\n"
  329. + "pcy 1087\npercnt 37\nperiod 46\npermil 8240\nperp 8869\npertenk 8241\npfr 120109\n"
  330. + "phi 966\nphiv 981\nphmmat 8499\nphone 9742\npi 960\npitchfork 8916\npiv 982\nplanck 8463\n"
  331. + "planckh 8462\nplankv 8463\nplus 43\nplusacir 10787\nplusb 8862\npluscir 10786\n"
  332. + "plusdo 8724\nplusdu 10789\npluse 10866\nplusmn 177\nplussim 10790\nplustwo 10791\npm 177\n"
  333. + "pointint 10773\npopf 120161\npound 163\npr 8826\nprE 10931\nprap 10935\nprcue 8828\n"
  334. + "pre 10927\nprec 8826\nprecapprox 10935\npreccurlyeq 8828\npreceq 10927\n"
  335. + "precnapprox 10937\nprecneqq 10933\nprecnsim 8936\nprecsim 8830\nprime 8242\nprimes 8473\n"
  336. + "prnE 10933\nprnap 10937\nprnsim 8936\nprod 8719\nprofalar 9006\nprofline 8978\n"
  337. + "profsurf 8979\nprop 8733\npropto 8733\nprsim 8830\nprurel 8880\npscr 120005\npsi 968\n"
  338. + "puncsp 8200\nqfr 120110\nqint 10764\nqopf 120162\nqprime 8279\nqscr 120006\n"
  339. + "quaternions 8461\nquatint 10774\nquest 63\nquesteq 8799\nquot 34\nrAarr 8667\nrArr 8658\n"
  340. + "rAtail 10524\nrBarr 10511\nrHar 10596\nrace 8765,817\nracute 341\nradic 8730\n"
  341. + "raemptyv 10675\nrang 10217\nrangd 10642\nrange 10661\nrangle 10217\nraquo 187\nrarr 8594\n"
  342. + "rarrap 10613\nrarrb 8677\nrarrbfs 10528\nrarrc 10547\nrarrfs 10526\nrarrhk 8618\n"
  343. + "rarrlp 8620\nrarrpl 10565\nrarrsim 10612\nrarrtl 8611\nrarrw 8605\nratail 10522\n"
  344. + "ratio 8758\nrationals 8474\nrbarr 10509\nrbbrk 10099\nrbrace 125\nrbrack 93\nrbrke 10636\n"
  345. + "rbrksld 10638\nrbrkslu 10640\nrcaron 345\nrcedil 343\nrceil 8969\nrcub 125\nrcy 1088\n"
  346. + "rdca 10551\nrdldhar 10601\nrdquo 8221\nrdquor 8221\nrdsh 8627\nreal 8476\nrealine 8475\n"
  347. + "realpart 8476\nreals 8477\nrect 9645\nreg 174\nrfisht 10621\nrfloor 8971\nrfr 120111\n"
  348. + "rhard 8641\nrharu 8640\nrharul 10604\nrho 961\nrhov 1009\nrightarrow 8594\n"
  349. + "rightarrowtail 8611\nrightharpoondown 8641\nrightharpoonup 8640\nrightleftarrows 8644\n"
  350. + "rightleftharpoons 8652\nrightrightarrows 8649\nrightsquigarrow 8605\n"
  351. + "rightthreetimes 8908\nring 730\nrisingdotseq 8787\nrlarr 8644\nrlhar 8652\nrlm 8207\n"
  352. + "rmoust 9137\nrmoustache 9137\nrnmid 10990\nroang 10221\nroarr 8702\nrobrk 10215\n"
  353. + "ropar 10630\nropf 120163\nroplus 10798\nrotimes 10805\nrpar 41\nrpargt 10644\n"
  354. + "rppolint 10770\nrrarr 8649\nrsaquo 8250\nrscr 120007\nrsh 8625\nrsqb 93\nrsquo 8217\n"
  355. + "rsquor 8217\nrthree 8908\nrtimes 8906\nrtri 9657\nrtrie 8885\nrtrif 9656\nrtriltri 10702\n"
  356. + "ruluhar 10600\nrx 8478\nsacute 347\nsbquo 8218\nsc 8827\nscE 10932\nscap 10936\n"
  357. + "scaron 353\nsccue 8829\nsce 10928\nscedil 351\nscirc 349\nscnE 10934\nscnap 10938\n"
  358. + "scnsim 8937\nscpolint 10771\nscsim 8831\nscy 1089\nsdot 8901\nsdotb 8865\nsdote 10854\n"
  359. + "seArr 8664\nsearhk 10533\nsearr 8600\nsearrow 8600\nsect 167\nsemi 59\nseswar 10537\n"
  360. + "setminus 8726\nsetmn 8726\nsext 10038\nsfr 120112\nsfrown 8994\nsharp 9839\nshchcy 1097\n"
  361. + "shcy 1096\nshortmid 8739\nshortparallel 8741\nshy 173\nsigma 963\nsigmaf 962\nsigmav 962\n"
  362. + "sim 8764\nsimdot 10858\nsime 8771\nsimeq 8771\nsimg 10910\nsimgE 10912\nsiml 10909\n"
  363. + "simlE 10911\nsimne 8774\nsimplus 10788\nsimrarr 10610\nslarr 8592\nsmallsetminus 8726\n"
  364. + "smashp 10803\nsmeparsl 10724\nsmid 8739\nsmile 8995\nsmt 10922\nsmte 10924\n"
  365. + "smtes 10924,65024\nsoftcy 1100\nsol 47\nsolb 10692\nsolbar 9023\nsopf 120164\n"
  366. + "spades 9824\nspadesuit 9824\nspar 8741\nsqcap 8851\nsqcaps 8851,65024\nsqcup 8852\n"
  367. + "sqcups 8852,65024\nsqsub 8847\nsqsube 8849\nsqsubset 8847\nsqsubseteq 8849\nsqsup 8848\n"
  368. + "sqsupe 8850\nsqsupset 8848\nsqsupseteq 8850\nsqu 9633\nsquare 9633\nsquarf 9642\n"
  369. + "squf 9642\nsrarr 8594\nsscr 120008\nssetmn 8726\nssmile 8995\nsstarf 8902\nstar 9734\n"
  370. + "starf 9733\nstraightepsilon 1013\nstraightphi 981\nstrns 175\nsub 8834\nsubE 10949\n"
  371. + "subdot 10941\nsube 8838\nsubedot 10947\nsubmult 10945\nsubnE 10955\nsubne 8842\n"
  372. + "subplus 10943\nsubrarr 10617\nsubset 8834\nsubseteq 8838\nsubseteqq 10949\n"
  373. + "subsetneq 8842\nsubsetneqq 10955\nsubsim 10951\nsubsub 10965\nsubsup 10963\nsucc 8827\n"
  374. + "succapprox 10936\nsucccurlyeq 8829\nsucceq 10928\nsuccnapprox 10938\nsuccneqq 10934\n"
  375. + "succnsim 8937\nsuccsim 8831\nsum 8721\nsung 9834\nsup 8835\nsup1 185\nsup2 178\nsup3 179\n"
  376. + "supE 10950\nsupdot 10942\nsupdsub 10968\nsupe 8839\nsupedot 10948\nsuphsol 10185\n"
  377. + "suphsub 10967\nsuplarr 10619\nsupmult 10946\nsupnE 10956\nsupne 8843\nsupplus 10944\n"
  378. + "supset 8835\nsupseteq 8839\nsupseteqq 10950\nsupsetneq 8843\nsupsetneqq 10956\n"
  379. + "supsim 10952\nsupsub 10964\nsupsup 10966\nswArr 8665\nswarhk 10534\nswarr 8601\n"
  380. + "swarrow 8601\nswnwar 10538\nszlig 223\ntarget 8982\ntau 964\ntbrk 9140\ntcaron 357\n"
  381. + "tcedil 355\ntcy 1090\ntdot 8411\ntelrec 8981\ntfr 120113\nthere4 8756\ntherefore 8756\n"
  382. + "theta 952\nthetasym 977\nthetav 977\nthickapprox 8776\nthicksim 8764\nthinsp 8201\n"
  383. + "thkap 8776\nthksim 8764\nthorn 254\ntilde 732\ntimes 215\ntimesb 8864\ntimesbar 10801\n"
  384. + "timesd 10800\ntint 8749\ntoea 10536\ntop 8868\ntopbot 9014\ntopcir 10993\ntopf 120165\n"
  385. + "topfork 10970\ntosa 10537\ntprime 8244\ntrade 8482\ntriangle 9653\ntriangledown 9663\n"
  386. + "triangleleft 9667\ntrianglelefteq 8884\ntriangleq 8796\ntriangleright 9657\n"
  387. + "trianglerighteq 8885\ntridot 9708\ntrie 8796\ntriminus 10810\ntriplus 10809\ntrisb 10701\n"
  388. + "tritime 10811\ntrpezium 9186\ntscr 120009\ntscy 1094\ntshcy 1115\ntstrok 359\ntwixt 8812\n"
  389. + "twoheadleftarrow 8606\ntwoheadrightarrow 8608\nuArr 8657\nuHar 10595\nuacute 250\n"
  390. + "uarr 8593\nubrcy 1118\nubreve 365\nucirc 251\nucy 1091\nudarr 8645\nudblac 369\n"
  391. + "udhar 10606\nufisht 10622\nufr 120114\nugrave 249\nuharl 8639\nuharr 8638\nuhblk 9600\n"
  392. + "ulcorn 8988\nulcorner 8988\nulcrop 8975\nultri 9720\numacr 363\numl 168\nuogon 371\n"
  393. + "uopf 120166\nuparrow 8593\nupdownarrow 8597\nupharpoonleft 8639\nupharpoonright 8638\n"
  394. + "uplus 8846\nupsi 965\nupsih 978\nupsilon 965\nupuparrows 8648\nurcorn 8989\n"
  395. + "urcorner 8989\nurcrop 8974\nuring 367\nurtri 9721\nuscr 120010\nutdot 8944\nutilde 361\n"
  396. + "utri 9653\nutrif 9652\nuuarr 8648\nuuml 252\nuwangle 10663\nvArr 8661\nvBar 10984\n"
  397. + "vBarv 10985\nvDash 8872\nvangrt 10652\nvarepsilon 1013\nvarkappa 1008\nvarnothing 8709\n"
  398. + "varphi 981\nvarpi 982\nvarpropto 8733\nvarr 8597\nvarrho 1009\nvarsigma 962\n"
  399. + "varsubsetneq 8842,65024\nvarsubsetneqq 10955,65024\nvarsupsetneq 8843,65024\n"
  400. + "varsupsetneqq 10956,65024\nvartheta 977\nvartriangleleft 8882\nvartriangleright 8883\n"
  401. + "vcy 1074\nvdash 8866\nvee 8744\nveebar 8891\nveeeq 8794\nvellip 8942\nverbar 124\n"
  402. + "vert 124\nvfr 120115\nvltri 8882\nvnsub 8834,8402\nvnsup 8835,8402\nvopf 120167\n"
  403. + "vprop 8733\nvrtri 8883\nvscr 120011\nvsubnE 10955,65024\nvsubne 8842,65024\n"
  404. + "vsupnE 10956,65024\nvsupne 8843,65024\nvzigzag 10650\nwcirc 373\nwedbar 10847\n"
  405. + "wedge 8743\nwedgeq 8793\nweierp 8472\nwfr 120116\nwopf 120168\nwp 8472\nwr 8768\n"
  406. + "wreath 8768\nwscr 120012\nxcap 8898\nxcirc 9711\nxcup 8899\nxdtri 9661\nxfr 120117\n"
  407. + "xhArr 10234\nxharr 10231\nxi 958\nxlArr 10232\nxlarr 10229\nxmap 10236\nxnis 8955\n"
  408. + "xodot 10752\nxopf 120169\nxoplus 10753\nxotime 10754\nxrArr 10233\nxrarr 10230\n"
  409. + "xscr 120013\nxsqcup 10758\nxuplus 10756\nxutri 9651\nxvee 8897\nxwedge 8896\nyacute 253\n"
  410. + "yacy 1103\nycirc 375\nycy 1099\nyen 165\nyfr 120118\nyicy 1111\nyopf 120170\nyscr 120014\n"
  411. + "yucy 1102\nyuml 255\nzacute 378\nzcaron 382\nzcy 1079\nzdot 380\nzeetrf 8488\nzeta 950\n"
  412. + "zfr 120119\nzhcy 1078\nzigrarr 8669\nzopf 120171\nzscr 120015\nzwj 8205\nzwnj 8204\n"
  413. ;
  414. // ---------------------------------------------------------------------------
  415. // Markdown block structure (CommonMark 0.31.2, section 3)
  416. // ---------------------------------------------------------------------------
  417. //
  418. // A cmark-style line scanner: each line is matched against the stack of
  419. // open "container" blocks (document > blockquote > list > item > ...),
  420. // consuming their prefixes, then new blocks are attempted in order
  421. // (blockquote, ATX heading, fenced code, setext underline, thematic break,
  422. // list item, indented code). Whatever remains is appended to the deepest
  423. // open leaf, or becomes a lazy paragraph continuation.
  424. //
  425. // We do not implement HTML blocks as containers: raw HTML is a security
  426. // hazard for `innerHTML`, so HTML-block-looking paragraphs stay paragraphs
  427. // and get escaped by the inline pass like any other text. That also means
  428. // `<script>` cannot interrupt a paragraph the way the spec allows.
  429. /** Number of columns that count as an indented code block. */
  430. var MD_CODE_INDENT = 4;
  431. /** Characters that can begin a non-paragraph block (fast bail-out). */
  432. var MD_MAYBE_SPECIAL_RE = /^[#`~*+_=<>0-9\-]/;
  433. var MD_THEMATIC_RE = /^(?:\*[ \t]*){3,}$|^(?:_[ \t]*){3,}$|^(?:-[ \t]*){3,}$/;
  434. var MD_BULLET_RE = /^[*+\-]/;
  435. var MD_ORDERED_RE = /^(\d{1,9})([.)])/;
  436. var MD_ATX_RE = /^#{1,6}(?:[ \t]+|$)/;
  437. var MD_FENCE_RE = /^`{3,}(?!.*`)|^~{3,}/;
  438. var MD_CLOSE_FENCE_RE = /^(?:`{3,}|~{3,})(?=[ \t]*$)/;
  439. var MD_SETEXT_RE = /^(?:=+|-+)[ \t]*$/;
  440. var MD_NON_SPACE_RE = /[^ \t\f\v\r\n]/;
  441. /**
  442. * Create a block node of the given type.
  443. * @param {string} type document|blockquote|list|item|paragraph|heading|code|thematic
  444. */
  445. function mdNode(type) {
  446. return {
  447. type: type, parent: null, children: [], strings: [],
  448. open: true, info: '', literal: '',
  449. fenced: false, fenceChar: '', fenceLength: 0, fenceOffset: 0,
  450. level: 1, listData: null, tight: true, headingSetext: false,
  451. sourceLine: 0
  452. };
  453. }
  454. function mdParser() {
  455. var doc = mdNode('document');
  456. return {
  457. doc: doc, tip: doc, oldtip: doc,
  458. offset: 0, column: 0, nextNonspace: 0, nextNonspaceColumn: 0,
  459. indent: 0, indented: false, blank: false, partiallyConsumedTab: false,
  460. allClosed: true, lastMatchedContainer: doc,
  461. currentLine: '', lineNumber: 0, lastLineLength: 0,
  462. refmap: {}, lineOffsets: []
  463. };
  464. }
  465. /** Normalise endings and split into lines (trailing blank from final \n dropped). */
  466. function mdSplitInput(raw) {
  467. var text = String(raw).replace(/\r\n|\r(?!\n)/g, '\n').replace(/\r/g, '\n');
  468. var out = text.split('\n');
  469. if (out.length && out[out.length - 1] === '') out.pop();
  470. return out;
  471. }
  472. // --- parser cursor helpers ------------------------------------------------
  473. /** Find the next non-space/tab char; sets blank/indent/indented on p. */
  474. function mdFindNextNonspace(p) {
  475. var ln = p.currentLine, i = p.offset, cols = p.column, c;
  476. while ((c = ln.charAt(i)) !== '') {
  477. if (c === ' ') { i++; cols++; }
  478. else if (c === '\t') { i++; cols += 4 - (cols % 4); }
  479. else break;
  480. }
  481. p.blank = c === '' ;
  482. p.nextNonspace = i;
  483. p.nextNonspaceColumn = cols;
  484. p.indent = p.nextNonspaceColumn - p.column;
  485. p.indented = p.indent >= MD_CODE_INDENT;
  486. }
  487. /**
  488. * Advance the cursor by `count` columns (or characters when `columns` is
  489. * false). Handles partially consumed tabs, which stay in the line as the
  490. * equivalent spaces.
  491. */
  492. function mdAdvanceOffset(p, count, columns) {
  493. var ln = p.currentLine, charsToTab, advance, c;
  494. while (count > 0 && (c = ln.charAt(p.offset)) !== '') {
  495. if (c === '\t') {
  496. charsToTab = 4 - (p.column % 4);
  497. if (columns) {
  498. p.partiallyConsumedTab = charsToTab > count;
  499. advance = charsToTab > count ? count : charsToTab;
  500. p.column += advance;
  501. if (!p.partiallyConsumedTab) p.offset += 1;
  502. count -= advance;
  503. } else {
  504. p.partiallyConsumedTab = false;
  505. p.column += charsToTab;
  506. p.offset += 1;
  507. count -= 1;
  508. }
  509. } else {
  510. p.partiallyConsumedTab = false;
  511. p.offset += 1;
  512. p.column += 1;
  513. count -= 1;
  514. }
  515. }
  516. }
  517. function mdAdvanceNextNonspace(p) {
  518. p.offset = p.nextNonspace;
  519. p.column = p.nextNonspaceColumn;
  520. p.partiallyConsumedTab = false;
  521. }
  522. /**
  523. * Append the rest of the current line (from p.offset) to the tip. When a
  524. * tab was only partially consumed, the surviving columns are re-emitted as
  525. * spaces, exactly like cmark.
  526. */
  527. function mdAddLine(p) {
  528. var s = '';
  529. if (p.partiallyConsumedTab) {
  530. p.offset += 1; // skip the tab character itself
  531. var charsToTab = 4 - (p.column % 4);
  532. while (s.length < charsToTab) s += ' ';
  533. }
  534. p.tip.strings.push(s + p.currentLine.slice(p.offset));
  535. }
  536. function mdCanContain(type, child) {
  537. if (type === 'item' || type === 'blockquote' ||
  538. type === 'document' || type === 'list') {
  539. if (type === 'list') return child === 'item';
  540. return child !== 'item';
  541. }
  542. return false;
  543. }
  544. function mdAcceptsLines(type) {
  545. return type === 'paragraph' || type === 'code';
  546. }
  547. /** Close every block from tip down to (excluding) `lastMatched`. */
  548. function mdCloseUnmatched(p) {
  549. if (p.allClosed) return;
  550. while (p.oldtip !== p.lastMatchedContainer) {
  551. mdFinalize(p, p.oldtip, p.lineNumber - 1);
  552. p.oldtip = p.oldtip.parent;
  553. }
  554. p.allClosed = true;
  555. }
  556. /**
  557. * Add a child block of `tag` under the tip, finalising any tip that cannot
  558. * contain it first.
  559. */
  560. function mdAddChild(p, tag) {
  561. while (!mdCanContain(p.tip.type, tag)) mdFinalize(p, p.tip, p.lineNumber - 1);
  562. var node = mdNode(tag);
  563. node.parent = p.tip;
  564. node.sourceLine = p.lineNumber;
  565. p.tip.children.push(node);
  566. p.tip = node;
  567. return node;
  568. }
  569. // --- container continue checks -------------------------------------------
  570. // 0 = matched, 1 = not matched, 2 = line fully handled (fence close)
  571. function mdContinueBlock(p, container) {
  572. var ln = p.currentLine, t = container.type;
  573. if (t === 'document' || t === 'list') return 0;
  574. if (t === 'blockquote') {
  575. if (!p.indented && ln.charAt(p.nextNonspace) === '>') {
  576. mdAdvanceNextNonspace(p);
  577. mdAdvanceOffset(p, 1, false);
  578. if (ln.charAt(p.offset) === ' ' || ln.charAt(p.offset) === '\t') {
  579. mdAdvanceOffset(p, 1, true);
  580. }
  581. return 0;
  582. }
  583. return 1;
  584. }
  585. if (t === 'item') {
  586. if (p.blank) {
  587. if (!container.children.length) return 1; // blank after empty item
  588. mdAdvanceNextNonspace(p);
  589. return 0;
  590. }
  591. var need = container.listData.markerOffset + container.listData.padding;
  592. if (p.indent >= need) {
  593. mdAdvanceOffset(p, need, true);
  594. return 0;
  595. }
  596. return 1;
  597. }
  598. if (t === 'code') {
  599. if (container.fenced) {
  600. var rest = ln.slice(p.nextNonspace);
  601. if (p.indent <= 3 && ln.charAt(p.nextNonspace) === container.fenceChar &&
  602. MD_CLOSE_FENCE_RE.test(rest) && rest.match(MD_CLOSE_FENCE_RE)[0].length >= container.fenceLength) {
  603. mdFinalize(p, container, p.lineNumber);
  604. return 2;
  605. }
  606. // skip up to fenceOffset leading spaces
  607. var i = container.fenceOffset;
  608. while (i > 0 && (ln.charAt(p.offset) === ' ' || ln.charAt(p.offset) === '\t')) {
  609. mdAdvanceOffset(p, 1, true);
  610. i--;
  611. }
  612. return 0;
  613. }
  614. if (p.indent >= MD_CODE_INDENT) { mdAdvanceOffset(p, MD_CODE_INDENT, true); return 0; }
  615. if (p.blank) { mdAdvanceNextNonspace(p); return 0; }
  616. return 1;
  617. }
  618. if (t === 'heading' || t === 'thematic') return 1;
  619. if (t === 'paragraph') return p.blank ? 1 : 0;
  620. return 1;
  621. }
  622. /**
  623. * True when a blank line separates `node` from its following sibling (used
  624. * for the tight/loose list decision).
  625. */
  626. function mdEndsWithBlank(node) {
  627. if (!node.parent) return false;
  628. var idx = node.parent.children.indexOf(node);
  629. var next = node.parent.children[idx + 1];
  630. if (!next) return false;
  631. return mdNodeEndLine(node) !== next.sourceLine - 1;
  632. }
  633. /** Last source line number consumed by a node (tracked during the scan). */
  634. function mdNodeEndLine(node) {
  635. return node.endLine == null ? node.sourceLine : node.endLine;
  636. }
  637. // --- block starts ----------------------------------------------------------
  638. /**
  639. * Parse a list marker at the cursor. Returns the marker data or null.
  640. * Mirrors cmark: the marker itself, then 1-4 spaces (5+ or a blank rest
  641. * means "content starts one space after the marker").
  642. */
  643. function mdParseListMarker(p, container) {
  644. var rest = p.currentLine.slice(p.nextNonspace);
  645. var data = { type: null, tight: true, bulletChar: null, start: null,
  646. delimiter: null, padding: null, markerOffset: p.indent };
  647. var m, nextc;
  648. if (p.indent >= 4) return null;
  649. if ((m = rest.match(MD_BULLET_RE))) {
  650. data.type = 'bullet';
  651. data.bulletChar = m[0].charAt(0);
  652. } else if ((m = rest.match(MD_ORDERED_RE)) &&
  653. (container.type !== 'paragraph' || Number(m[1]) === 1)) {
  654. data.type = 'ordered';
  655. data.start = parseInt(m[1], 10);
  656. data.delimiter = m[2];
  657. } else {
  658. return null;
  659. }
  660. nextc = p.currentLine.charAt(p.nextNonspace + m[0].length);
  661. if (!(nextc === '' || nextc === ' ' || nextc === '\t')) return null;
  662. if (container.type === 'paragraph' &&
  663. !MD_NON_SPACE_RE.test(p.currentLine.slice(p.nextNonspace + m[0].length))) {
  664. return null;
  665. }
  666. mdAdvanceNextNonspace(p);
  667. mdAdvanceOffset(p, m[0].length, true);
  668. var spacesStartCol = p.column, spacesStartOffset = p.offset;
  669. do {
  670. mdAdvanceOffset(p, 1, true);
  671. nextc = p.currentLine.charAt(p.offset);
  672. } while (p.column - spacesStartCol < 5 && (nextc === ' ' || nextc === '\t'));
  673. var blankItem = p.currentLine.charAt(p.offset) === '' && p.offset >= p.currentLine.length;
  674. var spacesAfterMarker = p.column - spacesStartCol;
  675. if (spacesAfterMarker >= 5 || spacesAfterMarker < 1 || blankItem) {
  676. data.padding = m[0].length + 1;
  677. p.column = spacesStartCol;
  678. p.offset = spacesStartOffset;
  679. var c2 = p.currentLine.charAt(p.offset);
  680. if (c2 === ' ' || c2 === '\t') mdAdvanceOffset(p, 1, true);
  681. } else {
  682. data.padding = m[0].length + spacesAfterMarker;
  683. }
  684. return data;
  685. }
  686. function mdListsMatch(a, b) {
  687. return a.type === b.type && a.delimiter === b.delimiter &&
  688. a.bulletChar === b.bulletChar;
  689. }
  690. /**
  691. * Try to start a new block at the cursor. Returns 0 (no match), 1 (opened a
  692. * container, keep trying), or 2 (opened a leaf; the line is spent).
  693. */
  694. function mdTryBlockStart(p, container) {
  695. var ln = p.currentLine, m, node;
  696. // block quote
  697. if (!p.indented && ln.charAt(p.nextNonspace) === '>') {
  698. mdAdvanceNextNonspace(p);
  699. mdAdvanceOffset(p, 1, false);
  700. if (ln.charAt(p.offset) === ' ' || ln.charAt(p.offset) === '\t') {
  701. mdAdvanceOffset(p, 1, true);
  702. }
  703. mdCloseUnmatched(p);
  704. mdAddChild(p, 'blockquote');
  705. return 1;
  706. }
  707. // ATX heading
  708. if (!p.indented && (m = ln.slice(p.nextNonspace).match(MD_ATX_RE))) {
  709. mdAdvanceNextNonspace(p);
  710. mdAdvanceOffset(p, m[0].length, false);
  711. mdCloseUnmatched(p);
  712. node = mdAddChild(p, 'heading');
  713. node.level = m[0].replace(/[ \t]/g, '').length;
  714. node.strings.push(
  715. ln.slice(p.offset)
  716. .replace(/^[ \t]*#+[ \t]*$/, '')
  717. .replace(/[ \t]+#+[ \t]*$/, ''));
  718. mdAdvanceOffset(p, ln.length - p.offset, false);
  719. return 2;
  720. }
  721. // fenced code block
  722. if (!p.indented && (m = ln.slice(p.nextNonspace).match(MD_FENCE_RE))) {
  723. mdCloseUnmatched(p);
  724. node = mdAddChild(p, 'code');
  725. node.fenced = true;
  726. node.fenceLength = m[0].length;
  727. node.fenceChar = m[0].charAt(0);
  728. node.fenceOffset = p.indent;
  729. mdAdvanceNextNonspace(p);
  730. mdAdvanceOffset(p, m[0].length, false);
  731. return 2;
  732. }
  733. // setext heading underline
  734. if (!p.indented && container.type === 'paragraph' &&
  735. (m = ln.slice(p.nextNonspace).match(MD_SETEXT_RE))) {
  736. mdCloseUnmatched(p);
  737. var pos;
  738. var joined = container.strings.join('\n');
  739. while (joined.charAt(0) === '[' && (pos = mdParseReference(joined, p.refmap)) > 0) {
  740. joined = joined.slice(pos);
  741. }
  742. container.strings = joined.length ? [joined] : [];
  743. var content = container.strings.join('\n');
  744. if (content.length > 0) {
  745. node = mdNode('heading');
  746. node.level = m[0].charAt(0) === '=' ? 1 : 2;
  747. node.headingSetext = true;
  748. node.strings = container.strings.slice();
  749. node.sourceLine = container.sourceLine;
  750. node.endLine = p.lineNumber;
  751. node.parent = container.parent;
  752. var ci = container.parent.children.indexOf(container);
  753. container.parent.children[ci] = node;
  754. p.tip = node;
  755. mdAdvanceOffset(p, ln.length - p.offset, false);
  756. return 2;
  757. }
  758. return 0;
  759. }
  760. // thematic break
  761. if (!p.indented && MD_THEMATIC_RE.test(ln.slice(p.nextNonspace))) {
  762. mdCloseUnmatched(p);
  763. mdAddChild(p, 'thematic');
  764. mdAdvanceOffset(p, ln.length - p.offset, false);
  765. return 2;
  766. }
  767. // list item
  768. var data;
  769. if ((!p.indented || container.type === 'list') && (data = mdParseListMarker(p, container))) {
  770. mdCloseUnmatched(p);
  771. if (p.tip.type !== 'list' || !mdListsMatch(container.listData, data)) {
  772. var list = mdAddChild(p, 'list');
  773. list.listData = data;
  774. container = list;
  775. }
  776. var item = mdAddChild(p, 'item');
  777. item.listData = data;
  778. return 1;
  779. }
  780. // indented code block
  781. if (p.indented && p.tip.type !== 'paragraph' && !p.blank) {
  782. mdAdvanceOffset(p, MD_CODE_INDENT, true);
  783. mdCloseUnmatched(p);
  784. mdAddChild(p, 'code');
  785. return 2;
  786. }
  787. return 0;
  788. }
  789. // --- line incorporation and finalisation -----------------------------------
  790. /**
  791. * Process one source line into the open block tree: match container
  792. * prefixes, try to open new blocks, then hand the remainder to a leaf.
  793. */
  794. function mdIncorporateLine(p, ln) {
  795. var container = p.doc, lastChild, allMatched = true, res;
  796. p.oldtip = p.tip;
  797. p.offset = 0;
  798. p.column = 0;
  799. p.blank = false;
  800. p.partiallyConsumedTab = false;
  801. p.lineNumber += 1;
  802. p.currentLine = ln.indexOf('\u0000') >= 0 ? ln.replace(/\u0000/g, '\uFFFD') : ln;
  803. // 1. Match the open containers' prefixes, deepest first.
  804. while (container.children.length) {
  805. lastChild = container.children[container.children.length - 1];
  806. if (!lastChild.open) break;
  807. container = lastChild;
  808. mdFindNextNonspace(p);
  809. res = mdContinueBlock(p, container);
  810. if (res === 2) { p.lastLineLength = ln.length; return; }
  811. if (res === 1) { allMatched = false; container = container.parent; break; }
  812. }
  813. p.allClosed = container === p.oldtip;
  814. p.lastMatchedContainer = container;
  815. // 2. Unless we already sit in a leaf that accepts lines, try block starts.
  816. var matchedLeaf = container.type !== 'paragraph' && mdAcceptsLines(container.type);
  817. while (!matchedLeaf) {
  818. mdFindNextNonspace(p);
  819. if (!p.indented && !MD_MAYBE_SPECIAL_RE.test(p.currentLine.slice(p.nextNonspace))) {
  820. mdAdvanceNextNonspace(p);
  821. break;
  822. }
  823. res = mdTryBlockStart(p, container);
  824. if (res === 1) { container = p.tip; continue; }
  825. if (res === 2) { container = p.tip; matchedLeaf = true; break; }
  826. mdAdvanceNextNonspace(p);
  827. break;
  828. }
  829. // 3. The remainder is line content for the tip.
  830. if (!p.allClosed && !p.blank && p.tip.type === 'paragraph') {
  831. mdAddLine(p); // lazy paragraph continuation
  832. } else {
  833. mdCloseUnmatched(p);
  834. if (mdAcceptsLines(container.type)) {
  835. mdAddLine(p);
  836. } else if (p.offset < p.currentLine.length && !p.blank) {
  837. mdAddChild(p, 'paragraph');
  838. mdAdvanceNextNonspace(p);
  839. mdAddLine(p);
  840. }
  841. }
  842. p.lastLineLength = ln.length;
  843. }
  844. /**
  845. * Close a block: extract fenced info strings / indented-code literals, work
  846. * out list tightness, peel link reference definitions off paragraphs and
  847. * record which source line the block ended on.
  848. */
  849. function mdFinalize(p, block, endLine) {
  850. var above = block.parent;
  851. block.open = false;
  852. block.endLine = endLine == null ? p.lineNumber : endLine;
  853. if (block.type === 'code') {
  854. if (block.fenced) {
  855. var content = block.strings.join('\n');
  856. var nl = content.indexOf('\n');
  857. var firstLine = nl >= 0 ? content.slice(0, nl) : content;
  858. var rest = nl >= 0 ? content.slice(nl + 1) : '';
  859. block.info = mdUnescapeString(firstLine.replace(/^[ \t]+/, '').replace(/[ \t]+$/, ''));
  860. // cmark keeps the final newline of the block's content
  861. block.literal = rest.length ? rest + '\n' : (block.strings.length > 1 ? '\n' : '');
  862. } else {
  863. var lines = block.strings.slice();
  864. while (lines.length && !MD_NON_SPACE_RE.test(lines[lines.length - 1])) lines.pop();
  865. block.literal = lines.join('\n') + '\n';
  866. }
  867. block.strings = [];
  868. }
  869. if (block.type === 'paragraph') {
  870. // Reference definitions live at the start of paragraphs only; each
  871. // consumed definition must advance or we stop.
  872. var txt = block.strings.join('\n');
  873. var pos;
  874. while (txt.charAt(0) === '[' && (pos = mdParseReference(txt, p.refmap)) > 0) {
  875. txt = txt.slice(pos);
  876. }
  877. block.strings = txt.length ? [txt] : [];
  878. if (!txt.length) mdRemoveFromParent(block);
  879. }
  880. if ((block.type === 'item' || block.type === 'list') && block.children.length) {
  881. // items and lists end where their last child ends (a trailing blank
  882. // line is not part of them) — this drives the tight/loose rule.
  883. // Blockquotes deliberately keep the line their `>` marker last
  884. // appeared on: ` >` is not a blank line for these purposes.
  885. block.endLine = block.children[block.children.length - 1].endLine;
  886. }
  887. if (block.type === 'list') {
  888. block.tight = true;
  889. for (var i = 0; i < block.children.length; i++) {
  890. var item = block.children[i];
  891. if (i < block.children.length - 1 && mdEndsWithBlank(item)) { block.tight = false; break; }
  892. for (var j = 0; j < item.children.length; j++) {
  893. if (j < item.children.length - 1 && mdEndsWithBlank(item.children[j])) { block.tight = false; break; }
  894. }
  895. if (!block.tight) break;
  896. }
  897. }
  898. p.tip = above;
  899. }
  900. /** Detach a node (used when a paragraph turns out to be all references). */
  901. function mdRemoveFromParent(node) {
  902. if (!node.parent) return;
  903. var i = node.parent.children.indexOf(node);
  904. if (i >= 0) node.parent.children.splice(i, 1);
  905. }
  906. /** Parse the whole input into a block tree. */
  907. function mdParseDocument(raw) {
  908. var p = mdParser();
  909. var lines = mdSplitInput(raw);
  910. for (var i = 0; i < lines.length; i++) mdIncorporateLine(p, lines[i]);
  911. while (p.tip && p.tip.type !== 'document') mdFinalize(p, p.tip, lines.length);
  912. return p;
  913. }
  914. // --- shared inline regexes / URI handling -----------------------------------
  915. var MD_LINK_TITLE_RE = /(?:")([^"]*)(?:")|(?:')([^']*)(?:')/;
  916. /**
  917. * Scan a link title at `subject[pos]` without regex backtracking: a quoted
  918. * run (with `\"`-style escapes) or a parenthesised run. Returns
  919. * `{ text, len }` or null.
  920. * @param {string} subject
  921. * @param {number} pos
  922. * @returns {?{text: string, len: number}}
  923. */
  924. function mdScanLinkTitle(subject, pos) {
  925. var start = pos, q = subject.charAt(pos);
  926. if (q !== '"' && q !== "'" && q !== '(') return null;
  927. var close = q === '(' ? ')' : q;
  928. var i = pos + 1;
  929. while (i < subject.length) {
  930. var ch = subject.charAt(i);
  931. if (ch === '\\' && subject.charAt(i + 1) !== '' &&
  932. MD_ESCAPABLE.indexOf(subject.charAt(i + 1)) >= 0) { i += 2; continue; }
  933. if (ch === close) {
  934. return { text: subject.slice(start + 1, i), len: i + 1 - start };
  935. }
  936. if (ch === '\n' && subject.charAt(i + 1) === '\n') return null; // blank line ends it
  937. i++;
  938. }
  939. return null;
  940. }
  941. var MD_LINK_DEST_BRACES_RE = /^<(?:[^<>\n\\\x00]|\\.)*>/;
  942. /**
  943. * End bound for scanning a construct that cannot contain whitespace, '<' or
  944. * '>' from `pos` (autolinks; raw HTML tags scan themselves linearly).
  945. * Slicing to this index instead of the end of the subject keeps the inline
  946. * parser linear on pathological input (many unmatched '<' or '&'): the
  947. * anchored construct regexes cannot match past the bound anyway.
  948. * @param {string} subject
  949. * @param {number} pos
  950. * @returns {number}
  951. */
  952. function mdBoundScan(subject, pos) {
  953. var i = pos + 1, c;
  954. while (i < subject.length) {
  955. c = subject.charCodeAt(i);
  956. if (c <= 0x20 || c === 0x3C || c === 0x3E) break;
  957. i++;
  958. }
  959. return i < subject.length ? i + 1 : subject.length;
  960. }
  961. /**
  962. * Match a raw HTML open/close tag at subject[pos] using a linear scan
  963. * (the equivalent regex backtracks catastrophically on malformed input).
  964. * Returns the matched text or null. SECURITY: callers render this escaped.
  965. * @param {string} subject
  966. * @param {number} pos
  967. * @returns {?string}
  968. */
  969. function mdScanHtmlTag(subject, pos) {
  970. var i = pos;
  971. if (subject.charAt(i) !== '<') return null;
  972. i++;
  973. var closing = subject.charAt(i) === '/';
  974. if (closing) i++;
  975. if (!/[A-Za-z]/.test(subject.charAt(i))) return null;
  976. var start = i;
  977. while (i < subject.length && /[A-Za-z0-9-]/.test(subject.charAt(i))) i++;
  978. if (i === start) return null;
  979. if (closing) {
  980. while (i < subject.length && /[ \t\n]/.test(subject.charAt(i))) i++;
  981. if (subject.charAt(i) === '>') return subject.slice(pos, i + 1);
  982. return null;
  983. }
  984. // attributes
  985. while (i < subject.length) {
  986. var wsStart = i;
  987. while (i < subject.length && /[ \t\n]/.test(subject.charAt(i))) i++;
  988. if (subject.charAt(i) === '>') return subject.slice(pos, i + 1);
  989. if (subject.charAt(i) === '/' && subject.charAt(i + 1) === '>') return subject.slice(pos, i + 2);
  990. if (i === wsStart) return null; // attribute must be preceded by space
  991. var an = i;
  992. while (i < subject.length && !/[\s/=><]/.test(subject.charAt(i))) i++;
  993. if (i === an) return null;
  994. var eq = i;
  995. while (i < subject.length && /[ \t\n]/.test(subject.charAt(i))) i++;
  996. if (subject.charAt(i) !== '=') { i = eq; continue; }
  997. i++;
  998. while (i < subject.length && /[ \t\n]/.test(subject.charAt(i))) i++;
  999. var q = subject.charAt(i);
  1000. if (q === '"' || q === "'") {
  1001. i++;
  1002. var endq = subject.indexOf(q, i);
  1003. if (endq < 0) return null;
  1004. i = endq + 1;
  1005. } else {
  1006. var v = i;
  1007. while (i < subject.length && !/[\s>]/.test(subject.charAt(i))) i++;
  1008. if (i === v) return null;
  1009. }
  1010. }
  1011. return null;
  1012. }
  1013. /**
  1014. * CommonMark's URL normalisation: percent-encode every character that is
  1015. * not in the RFC 3986 "unreserved + reserved + '#' escape" set. Non-ASCII
  1016. * characters become UTF-8 percent-escapes (like encodeURIComponent).
  1017. * @param {string} uri
  1018. * @returns {string}
  1019. */
  1020. function mdNormalizeUri(uri) {
  1021. if (!uri) return '';
  1022. var out = '', ch, i;
  1023. for (i = 0; i < uri.length; i++) {
  1024. ch = uri.charAt(i);
  1025. if (MD_URI_SAFE_RE.test(ch)) { out += ch; continue; }
  1026. // encode one code point (surrogate pairs together)
  1027. var cp = uri.charCodeAt(i);
  1028. var str = ch;
  1029. if (cp >= 0xD800 && cp <= 0xDBFF && i + 1 < uri.length) {
  1030. str += uri.charAt(i + 1);
  1031. i++;
  1032. }
  1033. out += encodeURIComponent(str);
  1034. }
  1035. return out;
  1036. }
  1037. /** URI characters kept literally (unreserved, reserved and '%'). */
  1038. var MD_URI_SAFE_RE = /^[A-Za-z0-9;,\/?:@&=+\$\-_\.!~\*'\(\)%#]$/;
  1039. /**
  1040. * Normalise a link label for reference lookup: strip brackets, trim,
  1041. * collapse internal whitespace, case-fold.
  1042. * @param {string} label raw `[...]` including brackets
  1043. * @returns {string}
  1044. */
  1045. function mdNormalizeReference(label) {
  1046. return label.slice(1, label.length - 1).trim()
  1047. .replace(/[ \t\r\n]+/g, ' ')
  1048. .toLowerCase().toUpperCase();
  1049. }
  1050. /**
  1051. * Parse one link reference definition from the start of `s`. Returns the
  1052. * number of characters consumed, or 0.
  1053. * @param {string} s
  1054. * @param {Object} refmap
  1055. * @returns {number}
  1056. */
  1057. function mdParseReference(s, refmap) {
  1058. var subject = s, pos = 0, rawlabel, dest, title = null, startpos = 0;
  1059. function peek2() { return pos < subject.length ? subject.charAt(pos) : ''; }
  1060. function match2(re) {
  1061. var m = re.exec(subject.slice(pos));
  1062. if (m) pos += m[0].length;
  1063. return m;
  1064. }
  1065. function spnl2() { match2(/^ *(?:\n *)?/); }
  1066. // label: one bracketed run, no nested brackets, no blank line
  1067. var depth = 0, i = 0, ch;
  1068. while (i < subject.length) {
  1069. ch = subject.charAt(i);
  1070. if (ch === '\\') { i += 2; continue; }
  1071. if (ch === '[') { depth++; if (depth > 1) return 0; }
  1072. else if (ch === ']') break;
  1073. i++;
  1074. }
  1075. if (depth !== 1 || subject.charAt(i) !== ']') return 0;
  1076. rawlabel = subject.slice(0, i + 1);
  1077. if (rawlabel.length > 1001) return 0;
  1078. pos = i + 1;
  1079. if (peek2() !== ':') return 0;
  1080. pos++;
  1081. spnl2();
  1082. // destination
  1083. var m2 = match2(MD_LINK_DEST_BRACES_RE);
  1084. if (m2) {
  1085. dest = mdNormalizeUri(mdUnescapeString(m2[0].slice(1, -1)));
  1086. } else {
  1087. var save = pos, openparens = 0, c;
  1088. while ((c = peek2()) !== '') {
  1089. if (c === '\\' && subject.charAt(pos + 1) !== '' &&
  1090. MD_ESCAPABLE.indexOf(subject.charAt(pos + 1)) >= 0) {
  1091. pos += 1;
  1092. if (peek2() !== '') pos += 1;
  1093. } else if (c === '(') { pos++; openparens++; }
  1094. else if (c === ')') { if (openparens < 1) break; pos++; openparens--; }
  1095. else if (MD_WS_CHAR_RE.test(c)) break;
  1096. else pos++;
  1097. }
  1098. if (pos === save && c !== ')') return 0;
  1099. if (openparens !== 0) return 0;
  1100. dest = mdNormalizeUri(mdUnescapeString(subject.slice(save, pos)));
  1101. }
  1102. var beforetitle = pos;
  1103. spnl2();
  1104. if (pos !== beforetitle) {
  1105. var t = mdScanLinkTitle(subject, pos);
  1106. if (t) { title = mdUnescapeString(t.text); pos += t.len; }
  1107. }
  1108. if (title === null) pos = beforetitle;
  1109. // must be at end of line
  1110. var atLineEnd = match2(/^ *(?:\n|$)/) !== null;
  1111. if (!atLineEnd) {
  1112. if (title !== null) {
  1113. title = null;
  1114. pos = beforetitle;
  1115. atLineEnd = match2(/^ *(?:\n|$)/) !== null;
  1116. }
  1117. if (!atLineEnd) return 0;
  1118. }
  1119. var normlabel = mdNormalizeReference(rawlabel);
  1120. if (normlabel === '') return 0;
  1121. if (!refmap[normlabel]) {
  1122. refmap[normlabel] = { destination: dest, title: title == null ? '' : title };
  1123. }
  1124. return pos;
  1125. }
  1126. // ---------------------------------------------------------------------------
  1127. // Markdown inline parsing (CommonMark 0.31.2, section 6)
  1128. // ---------------------------------------------------------------------------
  1129. //
  1130. // A hand-rolled scanner over paragraph/heading content: plain text runs are
  1131. // copied until a special character (\n ` [ ] \ ! < & * _), then that
  1132. // character's handler runs. Emphasis is resolved afterwards with the
  1133. // delimiter-run algorithm from the spec: openers are searched bottom-up
  1134. // with the "rule of 3" and openers_bottom optimisation; leftover delimiter
  1135. // text stays literal. Links and images share a bracket stack; links may
  1136. // not contain links.
  1137. //
  1138. // Inline nodes form a doubly-linked list (firstChild/lastChild/next/prev on
  1139. // the parent) exactly like the block tree: process_emphasis has to splice
  1140. // nodes out of the middle, which is painful with arrays.
  1141. var MD_ESCAPABLE = '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~';
  1142. var MD_ASCII_PUNCT_TEST_RE = /^[!-/:-@[-`{-~]$/;
  1143. var MD_ENTITY_HERE_RE = /^&(?:#x[a-f0-9]{1,6}|#[0-9]{1,7}|[a-z][a-z0-9]{1,31});/i;
  1144. var MD_TICKS_HERE_RE = /^`+/;
  1145. var MD_WS_CHAR_RE = /[ \t\n\x0b\x0c\x0d]/;
  1146. var MD_FINAL_SPACE_RE = / *$/;
  1147. /**
  1148. * Unicode punctuation/symbol code points (categories P* and S*) above the
  1149. * ASCII range, as "lo-hi" hex ranges (binary-searched). Needed for the
  1150. * left/right-flanking rules on non-ASCII text; ES5 has no \p{P}.
  1151. */
  1152. var MD_UNICODE_PUNCT_RANGES = [
  1153. 'A1-A9','AB-AC','AE-B1','B4','B6-B8','BB','BF','D7','F7','2C2-2C5','2D2-2DF','2E5-2EB',
  1154. '2ED','2EF-2FF','375','37E','384-385','387','3F6','482','55A-55F','589-58A','58D-58F','5BE',
  1155. '5C0','5C3','5C6','5F3-5F4','606-60F','61B','61D-61F','66A-66D','6D4','6DE','6E9','6FD-6FE',
  1156. '700-70D','7F6-7F9','7FE-7FF','830-83E','85E','888','964-965','970','9F2-9F3','9FA-9FB',
  1157. '9FD','A76','AF0-AF1','B70','BF3-BFA','C77','C7F','C84','D4F','D79','DF4','E3F','E4F',
  1158. 'E5A-E5B','F01-F17','F1A-F1F','F34','F36','F38','F3A-F3D','F85','FBE-FC5','FC7-FCC',
  1159. 'FCE-FDA','104A-104F','109E-109F','10FB','1360-1368','1390-1399','1400','166D-166E',
  1160. '169B-169C','16EB-16ED','1735-1736','17D4-17D6','17D8-17DB','1800-180A','1940','1944-1945',
  1161. '19DE-19FF','1A1E-1A1F','1AA0-1AA6','1AA8-1AAD','1B4E-1B4F','1B5A-1B6A','1B74-1B7F',
  1162. '1BFC-1BFF','1C3B-1C3F','1C7E-1C7F','1CC0-1CC7','1CD3','1FBD','1FBF-1FC1','1FCD-1FCF',
  1163. '1FDD-1FDF','1FED-1FEF','1FFD-1FFE','2010-2027','2030-205E','207A-207E','208A-208E',
  1164. '20A0-20C0','2100-2101','2103-2106','2108-2109','2114','2116-2118','211E-2123','2125',
  1165. '2127','2129','212E','213A-213B','2140-2144','214A-214D','214F','218A-218B','2190-2429',
  1166. '2440-244A','249C-24E9','2500-2775','2794-2B73','2B76-2B95','2B97-2BFF','2CE5-2CEA',
  1167. '2CF9-2CFC','2CFE-2CFF','2D70','2E00-2E2E','2E30-2E5D','2E80-2E99','2E9B-2EF3','2F00-2FD5',
  1168. '2FF0-2FFF','3001-3004','3008-3020','3030','3036-3037','303D-303F','309B-309C','30A0',
  1169. '30FB','3190-3191','3196-319F','31C0-31E5','31EF','3200-321E','322A-3247','3250',
  1170. '3260-327F','328A-32B0','32C0-33FF','4DC0-4DFF','A490-A4C6','A4FE-A4FF','A60D-A60F','A673',
  1171. 'A67E','A6F2-A6F7','A700-A716','A720-A721','A789-A78A','A828-A82B','A836-A839','A874-A877',
  1172. 'A8CE-A8CF','A8F8-A8FA','A8FC','A92E-A92F','A95F','A9C1-A9CD','A9DE-A9DF','AA5C-AA5F',
  1173. 'AA77-AA79','AADE-AADF','AAF0-AAF1','AB5B','AB6A-AB6B','ABEB','FB29','FBB2-FBC2',
  1174. 'FD3E-FD4F','FDCF','FDFC-FDFF','FE10-FE19','FE30-FE52','FE54-FE66','FE68-FE6B','FF01-FF0F',
  1175. 'FF1A-FF20','FF3B-FF40','FF5B-FF65','FFE0-FFE6','FFE8-FFEE','FFFC-FFFD','10100-10102',
  1176. '10137-1013F','10179-10189','1018C-1018E','10190-1019C','101A0','101D0-101FC','1039F',
  1177. '103D0','1056F','10857','10877-10878','1091F','1093F','10A50-10A58','10A7F','10AC8',
  1178. '10AF0-10AF6','10B39-10B3F','10B99-10B9C','10D6E','10D8E-10D8F','10EAD','10F55-10F59',
  1179. '10F86-10F89','11047-1104D','110BB-110BC','110BE-110C1','11140-11143','11174-11175',
  1180. '111C5-111C8','111CD','111DB','111DD-111DF','11238-1123D','112A9','113D4-113D5',
  1181. '113D7-113D8','1144B-1144F','1145A-1145B','1145D','114C6','115C1-115D7','11641-11643',
  1182. '11660-1166C','116B9','1173C-1173F','1183B','11944-11946','119E2','11A3F-11A46',
  1183. '11A9A-11A9C','11A9E-11AA2','11B00-11B09','11BE1','11C41-11C45','11C70-11C71','11EF7-11EF8',
  1184. '11F43-11F4F','11FD5-11FF1','11FFF','12470-12474','12FF1-12FF2','16A6E-16A6F','16AF5',
  1185. '16B37-16B3F','16B44-16B45','16D6D-16D6F','16E97-16E9A','16FE2','1BC9C','1BC9F',
  1186. '1CC00-1CCEF','1CD00-1CEB3','1CF50-1CFC3','1D000-1D0F5','1D100-1D126','1D129-1D164',
  1187. '1D16A-1D16C','1D183-1D184','1D18C-1D1A9','1D1AE-1D1EA','1D200-1D241','1D245','1D300-1D356',
  1188. '1D6C1','1D6DB','1D6FB','1D715','1D735','1D74F','1D76F','1D789','1D7A9','1D7C3',
  1189. '1D800-1D9FF','1DA37-1DA3A','1DA6D-1DA74','1DA76-1DA83','1DA85-1DA8B','1E14F','1E2FF',
  1190. '1E5FF','1E95E-1E95F','1ECAC','1ECB0','1ED2E','1EEF0-1EEF1','1F000-1F02B','1F030-1F093',
  1191. '1F0A0-1F0AE','1F0B1-1F0BF','1F0C1-1F0CF','1F0D1-1F0F5','1F10D-1F1AD','1F1E6-1F202',
  1192. '1F210-1F23B','1F240-1F248','1F250-1F251','1F260-1F265','1F300-1F6D7','1F6DC-1F6EC',
  1193. '1F6F0-1F6FC','1F700-1F776','1F77B-1F7D9','1F7E0-1F7EB','1F7F0','1F800-1F80B','1F810-1F847',
  1194. '1F850-1F859','1F860-1F887','1F890-1F8AD','1F8B0-1F8BB','1F8C0-1F8C1','1F900-1FA53',
  1195. '1FA60-1FA6D','1FA70-1FA7C','1FA80-1FA89','1FA8F-1FAC6','1FACE-1FADC','1FADF-1FAE9',
  1196. '1FAF0-1FAF8','1FB00-1FB92','1FB94-1FBEF',
  1197. ];
  1198. function mdIsUnicodePunct(cp) {
  1199. var lo = 0, hi = MD_UNICODE_PUNCT_RANGES.length - 1;
  1200. while (lo <= hi) {
  1201. var mid = (lo + hi) >> 1;
  1202. var dash = MD_UNICODE_PUNCT_RANGES[mid].indexOf('-');
  1203. var a, b;
  1204. if (dash < 0) { a = b = parseInt(MD_UNICODE_PUNCT_RANGES[mid], 16); }
  1205. else {
  1206. a = parseInt(MD_UNICODE_PUNCT_RANGES[mid].slice(0, dash), 16);
  1207. b = parseInt(MD_UNICODE_PUNCT_RANGES[mid].slice(dash + 1), 16);
  1208. }
  1209. if (cp < a) hi = mid - 1;
  1210. else if (cp > b) lo = mid + 1;
  1211. else return true;
  1212. }
  1213. return false;
  1214. }
  1215. function mdIsPunct(ch) {
  1216. if (ch === '' || ch == null) return false;
  1217. if (MD_ASCII_PUNCT_TEST_RE.test(ch)) return true;
  1218. var cp = ch.charCodeAt(0);
  1219. if (cp < 0xA1) return false;
  1220. // combine a surrogate pair into one code point
  1221. if (cp >= 0xD800 && cp <= 0xDBFF && ch.length > 1) {
  1222. var lo = ch.charCodeAt(1);
  1223. if (lo >= 0xDC00 && lo <= 0xDFFF) cp = 0x10000 + ((cp - 0xD800) << 10) + (lo - 0xDC00);
  1224. }
  1225. return mdIsUnicodePunct(cp);
  1226. }
  1227. /**
  1228. * String.fromCharCode with surrogate-pair support.
  1229. * @param {number} cp
  1230. * @returns {string}
  1231. */
  1232. function mdFromCodePoint(cp) {
  1233. if (cp == null || cp < 0 || cp > 0x10FFFF || (cp >= 0xD800 && cp <= 0xDFFF)) return '\uFFFD';
  1234. if (cp <= 0xFFFF) return String.fromCharCode(cp);
  1235. var c = cp - 0x10000;
  1236. return String.fromCharCode(0xD800 + (c >> 10), 0xDC00 + (c & 0x3FF));
  1237. }
  1238. var mdEntityMap = null;
  1239. /** Parse MD_ENTITIES_PACKED into a name -> string map (once). */
  1240. function mdGetEntityMap() {
  1241. if (mdEntityMap) return mdEntityMap;
  1242. var map = {}, recs = MD_ENTITIES_PACKED.split('\n');
  1243. for (var i = 0; i < recs.length; i++) {
  1244. var sp = recs[i].indexOf(' ');
  1245. if (sp < 0) continue;
  1246. var cps = recs[i].slice(sp + 1).split(',');
  1247. var s = '';
  1248. for (var j = 0; j < cps.length; j++) s += mdFromCodePoint(parseInt(cps[j], 10));
  1249. map[recs[i].slice(0, sp)] = s;
  1250. }
  1251. mdEntityMap = map;
  1252. return map;
  1253. }
  1254. /**
  1255. * Resolve an entity reference at the start of `s`; null when invalid.
  1256. * @param {string} s
  1257. * @returns {?string}
  1258. */
  1259. function mdReplaceEntity(s) {
  1260. var m = s.match(MD_ENTITY_HERE_RE);
  1261. if (!m) return null;
  1262. var body = m[0].slice(1, -1);
  1263. if (body.charAt(0) === '#') {
  1264. var num = body.charAt(1) === 'x' || body.charAt(1) === 'X'
  1265. ? parseInt(body.slice(2), 16)
  1266. : parseInt(body.slice(1), 10);
  1267. if (isNaN(num) || num === 0 || num > 0x10FFFF) return '\uFFFD';
  1268. return mdFromCodePoint(num);
  1269. }
  1270. var map = mdGetEntityMap();
  1271. return Object.prototype.hasOwnProperty.call(map, body) ? map[body] : null;
  1272. }
  1273. /**
  1274. * Replace backslash escapes and entity references (spec 2.2/2.3). Used on
  1275. * link destinations, titles, labels and code info strings.
  1276. * @param {string} s
  1277. * @returns {string}
  1278. */
  1279. function mdUnescapeString(s) {
  1280. if (s.indexOf('\\') < 0 && s.indexOf('&') < 0) return s;
  1281. var out = '', i = 0, ch, rep, m;
  1282. while (i < s.length) {
  1283. ch = s.charAt(i);
  1284. if (ch === '\\' && MD_ESCAPABLE.indexOf(s.charAt(i + 1)) >= 0) {
  1285. out += s.charAt(i + 1);
  1286. i += 2;
  1287. continue;
  1288. }
  1289. if (ch === '&') {
  1290. // entity references are at most 34 characters long (spec 2.3), so a
  1291. // bounded window is enough and keeps this loop linear in s.length
  1292. rep = mdReplaceEntity(s.slice(i, i + 34));
  1293. if (rep !== null) {
  1294. m = s.slice(i, i + 34).match(MD_ENTITY_HERE_RE);
  1295. out += rep;
  1296. i += m[0].length;
  1297. continue;
  1298. }
  1299. }
  1300. out += ch;
  1301. i++;
  1302. }
  1303. return out;
  1304. }
  1305. // --- inline nodes -----------------------------------------------------------
  1306. /**
  1307. * Create an inline node. Types: text, softbreak, code, emph, strong,
  1308. * link, image, html (escaped text).
  1309. */
  1310. function mdInlineNode(type, literal) {
  1311. return { type: type, literal: literal == null ? '' : literal,
  1312. parent: null, next: null, prev: null,
  1313. firstChild: null, lastChild: null,
  1314. destination: null, title: null, hardBreak: false };
  1315. }
  1316. function mdAppendChild(parent, node) {
  1317. node.parent = parent;
  1318. node.prev = parent.lastChild;
  1319. if (parent.lastChild) parent.lastChild.next = node;
  1320. else parent.firstChild = node;
  1321. parent.lastChild = node;
  1322. return node;
  1323. }
  1324. function mdUnlink(node) {
  1325. if (node.prev) node.prev.next = node.next;
  1326. else if (node.parent) node.parent.firstChild = node.next;
  1327. if (node.next) node.next.prev = node.prev;
  1328. else if (node.parent) node.parent.lastChild = node.prev;
  1329. node.parent = null;
  1330. node.next = null;
  1331. node.prev = null;
  1332. }
  1333. function mdInsertAfter(node, sibling) {
  1334. sibling.parent = node.parent;
  1335. sibling.next = node.next;
  1336. sibling.prev = node;
  1337. if (node.next) node.next.prev = sibling;
  1338. else if (node.parent) node.parent.lastChild = sibling;
  1339. node.next = sibling;
  1340. }
  1341. /** Collect a node's children into an array (for rendering). */
  1342. function mdChildren(node) {
  1343. var out = [], c = node.firstChild;
  1344. while (c) { out.push(c); c = c.next; }
  1345. return out;
  1346. }
  1347. // --- the subject scanner ----------------------------------------------------
  1348. /**
  1349. * Parse the inline content of one leaf block.
  1350. * @param {string} subject already-trimmed paragraph/heading text
  1351. * @param {Object} refmap normalised-label -> { destination, title }
  1352. * @returns {Object} a synthetic parent whose children are the inlines
  1353. */
  1354. function mdParseInlines(subject, refmap) {
  1355. var block = { parent: null, next: null, prev: null,
  1356. firstChild: null, lastChild: null, type: 'root' };
  1357. var pos = 0;
  1358. var delimiters = null; // linked list, newest first
  1359. var brackets = null; // linked list, newest first
  1360. function text(s) { return mdAppendChild(block, mdInlineNode('text', s)); }
  1361. function peek() { return pos < subject.length ? subject.charAt(pos) : ''; }
  1362. function match(re) {
  1363. var m = re.exec(subject.slice(pos));
  1364. if (m) pos += m[0].length;
  1365. return m;
  1366. }
  1367. function spnl() {
  1368. match(/^ *(?:\n *)?/);
  1369. return true;
  1370. }
  1371. // -- emphasis delimiter bookkeeping --
  1372. function scanDelims(cc) {
  1373. var numdelims = 0, startpos = pos;
  1374. while (peek() === cc) { numdelims++; pos++; }
  1375. // adjacent characters, taking surrogate pairs as one character
  1376. var charBefore = startpos === 0 ? '\n'
  1377. : (mdIsHighSurrogate(subject.charAt(startpos - 1))
  1378. ? subject.slice(startpos - 2, startpos)
  1379. : subject.charAt(startpos - 1));
  1380. var nextCh = peek();
  1381. var charAfter = nextCh === '' ? '\n'
  1382. : (mdIsHighSurrogate(nextCh) ? subject.substr(pos, 2) : nextCh);
  1383. var afterWs = /^\s/.test(charAfter);
  1384. var beforeWs = /^\s/.test(charBefore);
  1385. var afterPunct = mdIsPunct(charAfter);
  1386. var beforePunct = mdIsPunct(charBefore);
  1387. var leftFlanking = !afterWs && (!afterPunct || beforeWs || beforePunct);
  1388. var rightFlanking = !beforeWs && (!beforePunct || afterWs || afterPunct);
  1389. var canOpen, canClose;
  1390. if (cc === '_') {
  1391. canOpen = leftFlanking && (!rightFlanking || beforePunct);
  1392. canClose = rightFlanking && (!leftFlanking || afterPunct);
  1393. } else {
  1394. canOpen = leftFlanking;
  1395. canClose = rightFlanking;
  1396. }
  1397. pos = startpos;
  1398. return { numdelims: numdelims, canOpen: canOpen, canClose: canClose };
  1399. }
  1400. function handleDelim(cc) {
  1401. var res = scanDelims(cc);
  1402. if (!res || res.numdelims === 0) return false;
  1403. var node = text(subject.slice(pos, pos + res.numdelims));
  1404. pos += res.numdelims;
  1405. if (res.canOpen || res.canClose) {
  1406. var d = { cc: cc, numdelims: res.numdelims, origdelims: res.numdelims,
  1407. node: node, previous: delimiters, next: null,
  1408. canOpen: res.canOpen, canClose: res.canClose };
  1409. if (delimiters) delimiters.next = d;
  1410. delimiters = d;
  1411. }
  1412. return true;
  1413. }
  1414. function removeDelimiter(d) {
  1415. if (d.previous) d.previous.next = d.next;
  1416. if (d.next === null) delimiters = d.previous;
  1417. else d.next.previous = d.previous;
  1418. }
  1419. function removeDelimitersBetween(bottom, top) {
  1420. if (bottom.next !== top) { bottom.next = top; top.previous = bottom; }
  1421. }
  1422. /** True for the high half of a UTF-16 surrogate pair. */
  1423. function mdIsHighSurrogate(ch) {
  1424. var c = ch.charCodeAt(0);
  1425. return c >= 0xD800 && c <= 0xDBFF;
  1426. }
  1427. /** Emphasis resolution over the delimiter stack (spec 6.2). */
  1428. function processEmphasis(stackBottom) {
  1429. var openersBottom = new Array(8);
  1430. for (var i = 0; i < 8; i++) openersBottom[i] = stackBottom;
  1431. var closer = delimiters;
  1432. while (closer !== null && closer.previous !== stackBottom) closer = closer.previous;
  1433. var opener, openerInl, closerInl, useDelims, tmp, next, openerFound, oddMatch;
  1434. while (closer !== null) {
  1435. if (!closer.canClose) { closer = closer.next; continue; }
  1436. opener = closer.previous;
  1437. openerFound = false;
  1438. // openers_bottom index: 0..3 for '_', 4..7 for '*' — see rule of 3
  1439. var idx = (closer.cc === '_' ? 0 : 4) + (closer.canOpen ? 2 : 0) + (closer.origdelims % 3 === 0 ? 0 : 1);
  1440. while (opener !== null && opener !== stackBottom && opener !== openersBottom[idx]) {
  1441. oddMatch = (closer.canOpen || opener.canClose) &&
  1442. closer.origdelims % 3 !== 0 &&
  1443. (opener.origdelims + closer.origdelims) % 3 === 0;
  1444. if (opener.cc === closer.cc && opener.canOpen && !oddMatch) { openerFound = true; break; }
  1445. opener = opener.previous;
  1446. }
  1447. var oldCloser = closer;
  1448. if (!openerFound) {
  1449. openersBottom[idx] = oldCloser.previous;
  1450. if (!oldCloser.canOpen) removeDelimiter(oldCloser);
  1451. closer = closer.next;
  1452. continue;
  1453. }
  1454. useDelims = closer.numdelims >= 2 && opener.numdelims >= 2 ? 2 : 1;
  1455. openerInl = opener.node;
  1456. closerInl = closer.node;
  1457. opener.numdelims -= useDelims;
  1458. closer.numdelims -= useDelims;
  1459. openerInl.literal = openerInl.literal.slice(0, openerInl.literal.length - useDelims);
  1460. closerInl.literal = closerInl.literal.slice(0, closerInl.literal.length - useDelims);
  1461. var emph = mdInlineNode(useDelims === 1 ? 'emph' : 'strong');
  1462. tmp = openerInl.next;
  1463. while (tmp && tmp !== closerInl) {
  1464. next = tmp.next;
  1465. mdUnlink(tmp);
  1466. mdAppendChild(emph, tmp);
  1467. tmp = next;
  1468. }
  1469. mdInsertAfter(openerInl, emph);
  1470. removeDelimitersBetween(opener, closer);
  1471. if (opener.numdelims === 0) { mdUnlink(openerInl); removeDelimiter(opener); }
  1472. if (closer.numdelims === 0) {
  1473. mdUnlink(closerInl);
  1474. var after = closer.next;
  1475. removeDelimiter(closer);
  1476. closer = after;
  1477. }
  1478. // when the closer still has delimiters left, stay on it: the next
  1479. // iteration searches for another opener further left
  1480. }
  1481. while (delimiters !== null && delimiters !== stackBottom) removeDelimiter(delimiters);
  1482. }
  1483. // -- link / image machinery --
  1484. /**
  1485. * Parse a link title at pos; returns the unescaped title or null.
  1486. * Uses the linear scanner (no regex backtracking).
  1487. */
  1488. function parseLinkTitle() {
  1489. var res = mdScanLinkTitle(subject, pos);
  1490. if (!res) return null;
  1491. pos += res.len;
  1492. return mdUnescapeString(res.text);
  1493. }
  1494. /** Parse `<dest>` or a bare destination; returns normalised URI or null. */
  1495. function parseLinkDestination() {
  1496. var m = match(MD_LINK_DEST_BRACES_RE);
  1497. if (m) return mdNormalizeUri(mdUnescapeString(m[0].slice(1, -1)));
  1498. if (peek() === '<') return null;
  1499. var savepos = pos, openparens = 0, c;
  1500. while ((c = peek()) !== '') {
  1501. if (c === '\\' && subject.charAt(pos + 1) !== '' &&
  1502. MD_ESCAPABLE.indexOf(subject.charAt(pos + 1)) >= 0) {
  1503. pos += 1;
  1504. if (peek() !== '') pos += 1;
  1505. } else if (c === '(') { pos++; openparens++; }
  1506. else if (c === ')') { if (openparens < 1) break; pos++; openparens--; }
  1507. else if (MD_WS_CHAR_RE.test(c)) break;
  1508. else pos++;
  1509. }
  1510. if (pos === savepos && c !== ')') return null;
  1511. if (openparens !== 0) { pos = savepos; return null; }
  1512. return mdNormalizeUri(mdUnescapeString(subject.slice(savepos, pos)));
  1513. }
  1514. /**
  1515. * Parse `[...]` at pos; returns the consumed length (including both
  1516. * brackets), or 0 when there is no well-formed label. A label may not
  1517. * contain a blank line and is capped at 1000 characters.
  1518. */
  1519. function parseLinkLabel() {
  1520. if (subject.charAt(pos) !== '[') return 0;
  1521. var i = pos + 1, ch;
  1522. while (i < subject.length) {
  1523. ch = subject.charAt(i);
  1524. if (ch === '\\') { i += 2; continue; }
  1525. if (ch === '[') return 0; // nested brackets are not labels
  1526. if (ch === ']') break;
  1527. i++;
  1528. }
  1529. if (subject.charAt(i) !== ']') return 0;
  1530. var len = i + 1 - pos;
  1531. var label = subject.slice(pos, i + 1);
  1532. if (len > 1001) return 0;
  1533. if (/\n[ \t]*\n/.test(label)) return 0; // no blank lines inside
  1534. return len;
  1535. }
  1536. function addBracket(node, index, image) {
  1537. if (brackets) brackets.bracketAfter = true;
  1538. brackets = { node: node, previous: brackets, previousDelimiter: delimiters,
  1539. index: index, image: image, active: true, bracketAfter: false };
  1540. }
  1541. function removeBracket() { brackets = brackets.previous; }
  1542. function parseCloseBracket() {
  1543. var startpos = pos, isImage, dest, title, matched = false, reflabel;
  1544. pos += 1;
  1545. var opener = brackets;
  1546. if (opener === null) { text(']'); return true; }
  1547. if (!opener.active) { text(']'); removeBracket(); return true; }
  1548. isImage = opener.image;
  1549. var savepos = pos;
  1550. if (peek() === '(') {
  1551. pos++;
  1552. if (spnl() && (dest = parseLinkDestination()) !== null) {
  1553. var beforeTitle = pos;
  1554. spnl();
  1555. // A title is only allowed when whitespace separated it from the
  1556. // destination (spec: "optional... preceded by a space").
  1557. if (pos !== beforeTitle) {
  1558. var tryTitle = parseLinkTitle();
  1559. if (tryTitle !== null) {
  1560. title = tryTitle;
  1561. spnl();
  1562. } else {
  1563. pos = beforeTitle;
  1564. }
  1565. }
  1566. if (peek() === ')') {
  1567. pos += 1;
  1568. matched = true;
  1569. } else {
  1570. pos = savepos;
  1571. }
  1572. } else {
  1573. pos = savepos;
  1574. }
  1575. }
  1576. if (!matched) {
  1577. var beforelabel = pos;
  1578. var n = parseLinkLabel();
  1579. if (n > 2) {
  1580. // full reference: [text][label]
  1581. reflabel = subject.slice(beforelabel, beforelabel + n);
  1582. pos = beforelabel + n;
  1583. } else if (n === 2 && !opener.bracketAfter) {
  1584. // collapsed reference: [text][] — consume the empty label
  1585. reflabel = '[' + subject.slice(opener.index, startpos) + ']';
  1586. pos = beforelabel + n;
  1587. } else if (!opener.bracketAfter) {
  1588. // shortcut reference: [text]
  1589. reflabel = '[' + subject.slice(opener.index, startpos) + ']';
  1590. }
  1591. if (n === 0) pos = savepos;
  1592. if (reflabel) {
  1593. var link = refmap[mdNormalizeReference(reflabel)];
  1594. if (link) { dest = link.destination; title = link.title; matched = true; }
  1595. }
  1596. }
  1597. if (matched) {
  1598. var node = mdInlineNode(isImage ? 'image' : 'link');
  1599. node.destination = dest == null ? '' : dest;
  1600. node.title = title == null ? '' : title;
  1601. var tmp = opener.node.next, next;
  1602. while (tmp) {
  1603. next = tmp.next;
  1604. mdUnlink(tmp);
  1605. mdAppendChild(node, tmp);
  1606. tmp = next;
  1607. }
  1608. // the link takes the opener's position in the parent's child list
  1609. mdInsertAfter(opener.node, node);
  1610. processEmphasis(opener.previousDelimiter);
  1611. removeBracket();
  1612. mdUnlink(opener.node);
  1613. if (!isImage) {
  1614. var b = brackets;
  1615. while (b !== null) { if (!b.image) b.active = false; b = b.previous; }
  1616. }
  1617. return true;
  1618. }
  1619. removeBracket();
  1620. // NB: `startpos` was captured before consuming ']', so pos now sits
  1621. // just after it — do not rewind onto the bracket again.
  1622. pos = startpos + 1;
  1623. text(']');
  1624. return true;
  1625. }
  1626. // -- autolinks and raw HTML (neutralised) --
  1627. var MD_EMAIL_AUTOLINK_RE = /^<([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)>/;
  1628. var MD_AUTOLINK_RE = /^<[A-Za-z][A-Za-z0-9.+-]{1,31}:[^<>\x00-\x20]*>/i;
  1629. /**
  1630. * Try an autolink at pos. Returns the node or null.
  1631. */
  1632. function parseAutolink() {
  1633. // Autolinks cannot contain whitespace or '<'/'>' (MD_AUTOLINK_RE), so
  1634. // slicing to the next such character bounds the scan without changing
  1635. // what can match. Without this bound the slice+match was quadratic in
  1636. // pathological input (thousands of unmatched '<').
  1637. var rest = subject.slice(pos, mdBoundScan(subject, pos));
  1638. var m = rest.match(MD_AUTOLINK_RE);
  1639. var node;
  1640. if (m) {
  1641. node = mdInlineNode('link');
  1642. node.destination = mdNormalizeUri(m[0].slice(1, -1));
  1643. node.autolinkText = m[0].slice(1, -1);
  1644. mdAppendChild(block, node);
  1645. mdAppendChild(node, mdInlineNode('text', m[0].slice(1, -1)));
  1646. pos += m[0].length;
  1647. return node;
  1648. }
  1649. m = rest.match(MD_EMAIL_AUTOLINK_RE);
  1650. if (m) {
  1651. node = mdInlineNode('link');
  1652. node.destination = 'mailto:' + m[1];
  1653. node.autolinkText = m[1];
  1654. mdAppendChild(block, node);
  1655. mdAppendChild(node, mdInlineNode('text', m[1]));
  1656. pos += m[0].length;
  1657. return node;
  1658. }
  1659. return null;
  1660. }
  1661. /**
  1662. * Match a raw HTML tag at pos. SECURITY: the matched text is returned so
  1663. * the caller can render it escaped — it is never emitted as markup.
  1664. */
  1665. function parseHtmlTag() {
  1666. var raw = mdScanHtmlTag(subject, pos);
  1667. if (!raw) return null;
  1668. var node = mdAppendChild(block, mdInlineNode('html'));
  1669. node.literal = raw;
  1670. pos += raw.length;
  1671. return node;
  1672. }
  1673. // -- the main dispatch loop --
  1674. while (pos < subject.length) {
  1675. var c = peek();
  1676. var res = false;
  1677. switch (c) {
  1678. case '\n':
  1679. pos++;
  1680. {
  1681. var lastc = block.lastChild;
  1682. if (lastc && lastc.type === 'text' && / $/.test(lastc.literal)) {
  1683. var hard = / {2}$/.test(lastc.literal);
  1684. lastc.literal = lastc.literal.replace(MD_FINAL_SPACE_RE, '');
  1685. var sb = mdAppendChild(block, mdInlineNode('softbreak'));
  1686. sb.hardBreak = hard;
  1687. } else {
  1688. mdAppendChild(block, mdInlineNode('softbreak'));
  1689. }
  1690. match(/^ */);
  1691. }
  1692. break;
  1693. case '\\':
  1694. if (subject.charAt(pos + 1) === '\n') {
  1695. pos += 2;
  1696. var hb = mdAppendChild(block, mdInlineNode('softbreak'));
  1697. hb.hardBreak = true;
  1698. match(/^ */);
  1699. } else if (subject.charAt(pos + 1) !== '' &&
  1700. MD_ESCAPABLE.indexOf(subject.charAt(pos + 1)) >= 0) {
  1701. text(subject.charAt(pos + 1));
  1702. pos += 2;
  1703. } else {
  1704. text('\\');
  1705. pos++;
  1706. }
  1707. break;
  1708. case '`':
  1709. {
  1710. // opening run, then the next run of backticks of the SAME length
  1711. var ticks = subject.slice(pos).match(MD_TICKS_HERE_RE)[0];
  1712. var afterOpen = pos + ticks.length;
  1713. var searchPos = afterOpen, run;
  1714. var codeNode = null;
  1715. while ((run = subject.slice(searchPos).match(/^[\s\S]*?(`+)/)) && run[1]) {
  1716. var runStart = searchPos + run[0].length - run[1].length;
  1717. if (run[1].length === ticks.length) {
  1718. // newline -> space; spaces *before* a newline are dropped
  1719. // (spec: "line endings are replaced by spaces... preceded
  1720. // by a space are removed")
  1721. var content = subject.slice(afterOpen, runStart)
  1722. .replace(/ *\n/g, '\n').replace(/\n/g, ' ');
  1723. if (/^ /.test(content) && / $/.test(content) && content.replace(/ /g, '') !== '') {
  1724. content = content.slice(1, content.length - 1);
  1725. }
  1726. codeNode = mdAppendChild(block, mdInlineNode('code', content));
  1727. pos = runStart + run[1].length;
  1728. break;
  1729. }
  1730. searchPos = runStart + run[1].length;
  1731. }
  1732. if (!codeNode) {
  1733. text(ticks);
  1734. pos = afterOpen;
  1735. }
  1736. }
  1737. break;
  1738. case '*':
  1739. case '_':
  1740. handleDelim(c);
  1741. break;
  1742. case '[':
  1743. {
  1744. var node = text('[');
  1745. addBracket(node, pos + 1, false);
  1746. pos++;
  1747. }
  1748. break;
  1749. case '!':
  1750. if (subject.charAt(pos + 1) === '[') {
  1751. var n2 = text('![');
  1752. addBracket(n2, pos + 2, true);
  1753. pos += 2;
  1754. } else {
  1755. text('!');
  1756. pos++;
  1757. }
  1758. break;
  1759. case ']':
  1760. parseCloseBracket();
  1761. break;
  1762. case '<':
  1763. if (parseAutolink()) break;
  1764. if (parseHtmlTag()) break;
  1765. text('<');
  1766. pos++;
  1767. break;
  1768. case '&':
  1769. {
  1770. var rep = mdReplaceEntity(subject.slice(pos, pos + 34));
  1771. if (rep !== null) {
  1772. text(rep);
  1773. pos += subject.slice(pos, pos + 34).match(MD_ENTITY_HERE_RE)[0].length;
  1774. } else {
  1775. text('&');
  1776. pos++;
  1777. }
  1778. }
  1779. break;
  1780. default:
  1781. {
  1782. var m = subject.slice(pos).match(/^[^\n`\\[\]!<&*_]+/);
  1783. if (!m) { text(c); pos++; }
  1784. else { text(m[0]); pos += m[0].length; }
  1785. }
  1786. }
  1787. }
  1788. processEmphasis(null);
  1789. return block;
  1790. }
  1791. // ---------------------------------------------------------------------------
  1792. // Markdown HTML rendering
  1793. // ---------------------------------------------------------------------------
  1794. /**
  1795. * Escape the five HTML-significant characters. `"` becomes `&quot;` (also
  1796. * safe inside double-quoted attributes), matching cmark.
  1797. * @param {string} s
  1798. * @returns {string}
  1799. */
  1800. function mdEscape(s) {
  1801. return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
  1802. .replace(/"/g, '&quot;');
  1803. }
  1804. /**
  1805. * Parse (once) and render a leaf block's inline content. The parsed inline
  1806. * tree is cached on the block so image alt text can reuse it.
  1807. */
  1808. function mdLeafInlines(node, refmap) {
  1809. if (!node._inlines) {
  1810. node._inlines = mdParseInlines(node.strings.join('\n').trim(), refmap);
  1811. }
  1812. return node._inlines;
  1813. }
  1814. /** Render inline nodes to HTML (children of a paragraph/heading). */
  1815. function mdRenderInlines(node) {
  1816. var out = '', c = node.firstChild;
  1817. while (c) {
  1818. switch (c.type) {
  1819. case 'text':
  1820. out += mdEscape(c.literal);
  1821. break;
  1822. case 'softbreak':
  1823. out += c.hardBreak ? '<br />\n' : '\n';
  1824. break;
  1825. case 'code':
  1826. out += '<code>' + mdEscape(c.literal) + '</code>';
  1827. break;
  1828. case 'emph':
  1829. out += '<em>' + mdRenderInlines(c) + '</em>';
  1830. break;
  1831. case 'strong':
  1832. out += '<strong>' + mdRenderInlines(c) + '</strong>';
  1833. break;
  1834. case 'link':
  1835. out += '<a href="' + safeMarkdownUrl(mdEscapeAttr(c.destination)) + '"' +
  1836. (c.title ? ' title="' + mdEscapeAttr(c.title) + '"' : '') + '>' +
  1837. mdRenderInlines(c) + '</a>';
  1838. break;
  1839. case 'image':
  1840. out += '<img src="' + safeMarkdownUrl(mdEscapeAttr(c.destination)) + '"' +
  1841. ' alt="' + mdImageAlt(c) + '"' +
  1842. (c.title ? ' title="' + mdEscapeAttr(c.title) + '"' : '') + ' />';
  1843. break;
  1844. case 'html':
  1845. out += mdEscape(c.literal);
  1846. break;
  1847. default:
  1848. out += mdEscape(c.literal || '');
  1849. }
  1850. c = c.next;
  1851. }
  1852. return out;
  1853. }
  1854. /** Plain-text rendering of image alt text (markdown stripped). */
  1855. function mdImageAlt(node) {
  1856. var out = '', c = node.firstChild;
  1857. while (c) {
  1858. if (c.type === 'text' || c.type === 'code' || c.type === 'html') out += c.literal;
  1859. else if (c.type === 'softbreak') out += c.hardBreak ? '\n' : '\n';
  1860. else if (c.firstChild) out += mdImageAlt(c);
  1861. c = c.next;
  1862. }
  1863. return mdEscapeAttr(out);
  1864. }
  1865. /** Escape for a double-quoted attribute value. */
  1866. function mdEscapeAttr(s) {
  1867. return String(s).replace(/&/g, '&amp;').replace(/"/g, '&quot;')
  1868. .replace(/</g, '&lt;').replace(/>/g, '&gt;');
  1869. }
  1870. /**
  1871. * Output buffer that suppresses repeated newlines (cmark's `cr`).
  1872. */
  1873. function mdOut() {
  1874. // `last` starts as a newline so the very first cr() is a no-op
  1875. return { s: '', last: '\n' };
  1876. }
  1877. /** Append a literal string. */
  1878. function mdLit(out, s) {
  1879. if (!s) return;
  1880. out.s += s;
  1881. out.last = s.charAt(s.length - 1);
  1882. }
  1883. /** Append a newline unless the output already ends with one. */
  1884. function mdCr(out) {
  1885. if (out.last !== '\n') mdLit(out, '\n');
  1886. }
  1887. /**
  1888. * Render one block node (and its children) to HTML. `tight` is the
  1889. * enclosing list's tightness: tight lists suppress `<p>` wrappers.
  1890. */
  1891. function mdRenderBlocks(node, tight, out, refmap) {
  1892. var i, child;
  1893. switch (node.type) {
  1894. case 'document':
  1895. for (i = 0; i < node.children.length; i++) mdRenderBlocks(node.children[i], tight, out, refmap);
  1896. break;
  1897. case 'paragraph':
  1898. // in a tight list the paragraph renders bare
  1899. if (tight) { mdLit(out, mdRenderInlines(mdLeafInlines(node, refmap))); }
  1900. else {
  1901. mdCr(out);
  1902. mdLit(out, '<p>');
  1903. mdLit(out, mdRenderInlines(mdLeafInlines(node, refmap)));
  1904. mdLit(out, '</p>');
  1905. mdCr(out);
  1906. }
  1907. break;
  1908. case 'heading':
  1909. mdCr(out);
  1910. mdLit(out, '<h' + node.level + '>');
  1911. mdLit(out, mdRenderInlines(mdLeafInlines(node, refmap)));
  1912. mdLit(out, '</h' + node.level + '>');
  1913. mdCr(out);
  1914. break;
  1915. case 'thematic':
  1916. mdCr(out);
  1917. mdLit(out, '<hr />');
  1918. mdCr(out);
  1919. break;
  1920. case 'code':
  1921. mdCr(out);
  1922. var info = node.info ? node.info.split(/\s+/)[0] : '';
  1923. var attrs = '';
  1924. if (info) attrs = ' class="language-' + mdEscapeAttr(info) + '"';
  1925. mdLit(out, '<pre><code' + attrs + '>' + mdEscape(node.literal) + '</code></pre>');
  1926. mdCr(out);
  1927. break;
  1928. case 'blockquote':
  1929. mdCr(out);
  1930. mdLit(out, '<blockquote>');
  1931. mdCr(out);
  1932. // cmark unwraps paragraphs only when their grandparent is a tight
  1933. // list; inside a blockquote they always keep their <p>.
  1934. for (i = 0; i < node.children.length; i++) mdRenderBlocks(node.children[i], false, out, refmap);
  1935. mdCr(out);
  1936. mdLit(out, '</blockquote>');
  1937. mdCr(out);
  1938. break;
  1939. case 'list':
  1940. mdCr(out);
  1941. var tag = node.listData.type === 'ordered' ? 'ol' : 'ul';
  1942. var start = '';
  1943. if (tag === 'ol' && node.listData.start != null && node.listData.start !== 1) {
  1944. start = ' start="' + node.listData.start + '"';
  1945. }
  1946. mdLit(out, '<' + tag + start + '>');
  1947. mdCr(out);
  1948. for (i = 0; i < node.children.length; i++) mdRenderBlocks(node.children[i], node.tight, out, refmap);
  1949. mdCr(out);
  1950. mdLit(out, '</' + tag + '>');
  1951. mdCr(out);
  1952. break;
  1953. case 'item':
  1954. mdLit(out, '<li>');
  1955. for (i = 0; i < node.children.length; i++) {
  1956. // tightness applies to the item's own paragraphs and lists;
  1957. // blockquote contents are always loose.
  1958. mdRenderBlocks(node.children[i], node.children[i].type === 'blockquote' ? false : tight, out, refmap);
  1959. }
  1960. mdLit(out, '</li>');
  1961. mdCr(out);
  1962. break;
  1963. default:
  1964. break;
  1965. }
  1966. }
  1967. /**
  1968. * Render markdown to safe HTML.
  1969. *
  1970. * CommonMark 0.31.2 minus raw HTML (escaped instead, see the note at the
  1971. * top of the markdown section) and minus HTML-block constructs that only
  1972. * exist to feed raw HTML through.
  1973. * @param {string} raw markdown source
  1974. * @returns {string} HTML safe for `innerHTML`
  1975. */
  1976. function renderMarkdown(raw) {
  1977. var parser = mdParseDocument(raw);
  1978. var out = mdOut();
  1979. mdRenderBlocks(parser.doc, false, out, parser.refmap);
  1980. return out.s;
  1981. }
  1982. /**
  1983. * Demote child header tags by N levels (h1 → h2, etc.), capping at h6.
  1984. */
  1985. function handleHDemotion(el) {
  1986. var attr = el.getAttribute('stm-h-demotion');
  1987. if (!attr) return;
  1988. var n = parseInt(attr, 10);
  1989. if (isNaN(n) || n <= 0) return;
  1990. el.querySelectorAll('h1,h2,h3,h4,h5,h6').forEach(function (h) {
  1991. var level = parseInt(h.tagName.charAt(1), 10);
  1992. var newLevel = Math.min(level + n, 6);
  1993. if (newLevel === level) return;
  1994. var replacement = document.createElement('h' + newLevel);
  1995. for (var i = 0; i < h.attributes.length; i++)
  1996. replacement.setAttribute(h.attributes[i].name, h.attributes[i].value);
  1997. while (h.firstChild) replacement.appendChild(h.firstChild);
  1998. h.replaceWith(replacement);
  1999. });
  2000. }
  2001. // ---------------------------------------------------------------------------
  2002. // Bindings (module seam) + programmatic API
  2003. // ---------------------------------------------------------------------------
  2004. /** Normalise a binding value to markdown source (`null`/`undefined` -> ''). */
  2005. function mdSource(value) {
  2006. return value === null || value === undefined ? '' : String(value);
  2007. }
  2008. /**
  2009. * Apply a markdown value to an element: the single code path shared by the
  2010. * `stm-markdown` handler and `statum.markdown.renderTo`. Per the "leave
  2011. * original DOM content" policy, an unresolved value (`undefined`) leaves
  2012. * the element untouched.
  2013. */
  2014. function applyMarkdown(el, value) {
  2015. if (value === undefined) return;
  2016. el.innerHTML = renderMarkdown(mdSource(value));
  2017. }
  2018. /** Bind `stm-markdown`: render the expression's value as markdown. */
  2019. function handleMarkdown(el, scope) {
  2020. if (el.hasAttribute('stm-markdown')) {
  2021. var md = evalExpr(el.getAttribute('stm-markdown'), scope);
  2022. applyMarkdown(el, md);
  2023. }
  2024. }
  2025. /**
  2026. * Bind `stm-h-demotion`: demote the element's headers. Registered after
  2027. * `stm-markdown` (and therefore also after `stm-html`) so the rendered
  2028. * headers are present in the DOM when it runs.
  2029. */
  2030. function handleDemotion(el) {
  2031. if (el.hasAttribute('stm-h-demotion')) handleHDemotion(el);
  2032. }
  2033. /**
  2034. * Programmatic markdown API, sharing the binding's code path.
  2035. */
  2036. window.statum.markdown = {
  2037. /** Render markdown source to safe HTML. @param {string} src */
  2038. render: function (src) { return renderMarkdown(mdSource(src)); },
  2039. /** Render markdown source into an element (replaces its content). */
  2040. renderTo: function (el, src) { applyMarkdown(el, src); }
  2041. };
  2042. // Ordering constraints: markdown renders before demotion so the headers it
  2043. // produces exist when demotion runs.
  2044. bridge.registerAttribute('stm-markdown', handleMarkdown, { after: 'stm-html' });
  2045. bridge.registerAttribute('stm-h-demotion', handleDemotion, { after: 'stm-markdown' });
  2046. // Test-only escape hatch: tests/markdown and tests/split load these module
  2047. // files under QuickJS with `window.__STATUM_TEST__` set beforehand and
  2048. // reach the engine through statum._testMarkdown. Shipped pages never set
  2049. // the flag, so this adds no surface to the public API.
  2050. if (window.__STATUM_TEST__) window.statum._testMarkdown = renderMarkdown;
  2051. })();