diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/index.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/index.js new file mode 100644 index 0000000..f9528b7 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/index.js @@ -0,0 +1,7 @@ +'use strict'; + +var md = require('./src')('commonmark'); + +exports.run = function(data) { + return md.render(data); +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/index.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/index.js new file mode 100644 index 0000000..f71477e --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/index.js @@ -0,0 +1,4 @@ +'use strict'; + + +module.exports = require('./lib/'); diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/common/entities.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/common/entities.js new file mode 100644 index 0000000..5061e3a --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/common/entities.js @@ -0,0 +1,2134 @@ +// List of valid entities +// +// Generate with ./support/entities.js script +// +'use strict'; + +/*eslint quotes:0*/ +module.exports = { + "Aacute":"\u00C1", + "aacute":"\u00E1", + "Abreve":"\u0102", + "abreve":"\u0103", + "ac":"\u223E", + "acd":"\u223F", + "acE":"\u223E\u0333", + "Acirc":"\u00C2", + "acirc":"\u00E2", + "acute":"\u00B4", + "Acy":"\u0410", + "acy":"\u0430", + "AElig":"\u00C6", + "aelig":"\u00E6", + "af":"\u2061", + "Afr":"\uD835\uDD04", + "afr":"\uD835\uDD1E", + "Agrave":"\u00C0", + "agrave":"\u00E0", + "alefsym":"\u2135", + "aleph":"\u2135", + "Alpha":"\u0391", + "alpha":"\u03B1", + "Amacr":"\u0100", + "amacr":"\u0101", + "amalg":"\u2A3F", + "AMP":"\u0026", + "amp":"\u0026", + "And":"\u2A53", + "and":"\u2227", + "andand":"\u2A55", + "andd":"\u2A5C", + "andslope":"\u2A58", + "andv":"\u2A5A", + "ang":"\u2220", + "ange":"\u29A4", + "angle":"\u2220", + "angmsd":"\u2221", + "angmsdaa":"\u29A8", + "angmsdab":"\u29A9", + "angmsdac":"\u29AA", + "angmsdad":"\u29AB", + "angmsdae":"\u29AC", + "angmsdaf":"\u29AD", + "angmsdag":"\u29AE", + "angmsdah":"\u29AF", + "angrt":"\u221F", + "angrtvb":"\u22BE", + "angrtvbd":"\u299D", + "angsph":"\u2222", + "angst":"\u00C5", + "angzarr":"\u237C", + "Aogon":"\u0104", + "aogon":"\u0105", + "Aopf":"\uD835\uDD38", + "aopf":"\uD835\uDD52", + "ap":"\u2248", + "apacir":"\u2A6F", + "apE":"\u2A70", + "ape":"\u224A", + "apid":"\u224B", + "apos":"\u0027", + "ApplyFunction":"\u2061", + "approx":"\u2248", + "approxeq":"\u224A", + "Aring":"\u00C5", + "aring":"\u00E5", + "Ascr":"\uD835\uDC9C", + "ascr":"\uD835\uDCB6", + "Assign":"\u2254", + "ast":"\u002A", + "asymp":"\u2248", + "asympeq":"\u224D", + "Atilde":"\u00C3", + "atilde":"\u00E3", + "Auml":"\u00C4", + "auml":"\u00E4", + "awconint":"\u2233", + "awint":"\u2A11", + "backcong":"\u224C", + "backepsilon":"\u03F6", + "backprime":"\u2035", + "backsim":"\u223D", + "backsimeq":"\u22CD", + "Backslash":"\u2216", + "Barv":"\u2AE7", + "barvee":"\u22BD", + "Barwed":"\u2306", + "barwed":"\u2305", + "barwedge":"\u2305", + "bbrk":"\u23B5", + "bbrktbrk":"\u23B6", + "bcong":"\u224C", + "Bcy":"\u0411", + "bcy":"\u0431", + "bdquo":"\u201E", + "becaus":"\u2235", + "Because":"\u2235", + "because":"\u2235", + "bemptyv":"\u29B0", + "bepsi":"\u03F6", + "bernou":"\u212C", + "Bernoullis":"\u212C", + "Beta":"\u0392", + "beta":"\u03B2", + "beth":"\u2136", + "between":"\u226C", + "Bfr":"\uD835\uDD05", + "bfr":"\uD835\uDD1F", + "bigcap":"\u22C2", + "bigcirc":"\u25EF", + "bigcup":"\u22C3", + "bigodot":"\u2A00", + "bigoplus":"\u2A01", + "bigotimes":"\u2A02", + "bigsqcup":"\u2A06", + "bigstar":"\u2605", + "bigtriangledown":"\u25BD", + "bigtriangleup":"\u25B3", + "biguplus":"\u2A04", + "bigvee":"\u22C1", + "bigwedge":"\u22C0", + "bkarow":"\u290D", + "blacklozenge":"\u29EB", + "blacksquare":"\u25AA", + "blacktriangle":"\u25B4", + "blacktriangledown":"\u25BE", + "blacktriangleleft":"\u25C2", + "blacktriangleright":"\u25B8", + "blank":"\u2423", + "blk12":"\u2592", + "blk14":"\u2591", + "blk34":"\u2593", + "block":"\u2588", + "bne":"\u003D\u20E5", + "bnequiv":"\u2261\u20E5", + "bNot":"\u2AED", + "bnot":"\u2310", + "Bopf":"\uD835\uDD39", + "bopf":"\uD835\uDD53", + "bot":"\u22A5", + "bottom":"\u22A5", + "bowtie":"\u22C8", + "boxbox":"\u29C9", + "boxDL":"\u2557", + "boxDl":"\u2556", + "boxdL":"\u2555", + "boxdl":"\u2510", + "boxDR":"\u2554", + "boxDr":"\u2553", + "boxdR":"\u2552", + "boxdr":"\u250C", + "boxH":"\u2550", + "boxh":"\u2500", + "boxHD":"\u2566", + "boxHd":"\u2564", + "boxhD":"\u2565", + "boxhd":"\u252C", + "boxHU":"\u2569", + "boxHu":"\u2567", + "boxhU":"\u2568", + "boxhu":"\u2534", + "boxminus":"\u229F", + "boxplus":"\u229E", + "boxtimes":"\u22A0", + "boxUL":"\u255D", + "boxUl":"\u255C", + "boxuL":"\u255B", + "boxul":"\u2518", + "boxUR":"\u255A", + "boxUr":"\u2559", + "boxuR":"\u2558", + "boxur":"\u2514", + "boxV":"\u2551", + "boxv":"\u2502", + "boxVH":"\u256C", + "boxVh":"\u256B", + "boxvH":"\u256A", + "boxvh":"\u253C", + "boxVL":"\u2563", + "boxVl":"\u2562", + "boxvL":"\u2561", + "boxvl":"\u2524", + "boxVR":"\u2560", + "boxVr":"\u255F", + "boxvR":"\u255E", + "boxvr":"\u251C", + "bprime":"\u2035", + "Breve":"\u02D8", + "breve":"\u02D8", + "brvbar":"\u00A6", + "Bscr":"\u212C", + "bscr":"\uD835\uDCB7", + "bsemi":"\u204F", + "bsim":"\u223D", + "bsime":"\u22CD", + "bsol":"\u005C", + "bsolb":"\u29C5", + "bsolhsub":"\u27C8", + "bull":"\u2022", + "bullet":"\u2022", + "bump":"\u224E", + "bumpE":"\u2AAE", + "bumpe":"\u224F", + "Bumpeq":"\u224E", + "bumpeq":"\u224F", + "Cacute":"\u0106", + "cacute":"\u0107", + "Cap":"\u22D2", + "cap":"\u2229", + "capand":"\u2A44", + "capbrcup":"\u2A49", + "capcap":"\u2A4B", + "capcup":"\u2A47", + "capdot":"\u2A40", + "CapitalDifferentialD":"\u2145", + "caps":"\u2229\uFE00", + "caret":"\u2041", + "caron":"\u02C7", + "Cayleys":"\u212D", + "ccaps":"\u2A4D", + "Ccaron":"\u010C", + "ccaron":"\u010D", + "Ccedil":"\u00C7", + "ccedil":"\u00E7", + "Ccirc":"\u0108", + "ccirc":"\u0109", + "Cconint":"\u2230", + "ccups":"\u2A4C", + "ccupssm":"\u2A50", + "Cdot":"\u010A", + "cdot":"\u010B", + "cedil":"\u00B8", + "Cedilla":"\u00B8", + "cemptyv":"\u29B2", + "cent":"\u00A2", + "CenterDot":"\u00B7", + "centerdot":"\u00B7", + "Cfr":"\u212D", + "cfr":"\uD835\uDD20", + "CHcy":"\u0427", + "chcy":"\u0447", + "check":"\u2713", + "checkmark":"\u2713", + "Chi":"\u03A7", + "chi":"\u03C7", + "cir":"\u25CB", + "circ":"\u02C6", + "circeq":"\u2257", + "circlearrowleft":"\u21BA", + "circlearrowright":"\u21BB", + "circledast":"\u229B", + "circledcirc":"\u229A", + "circleddash":"\u229D", + "CircleDot":"\u2299", + "circledR":"\u00AE", + "circledS":"\u24C8", + "CircleMinus":"\u2296", + "CirclePlus":"\u2295", + "CircleTimes":"\u2297", + "cirE":"\u29C3", + "cire":"\u2257", + "cirfnint":"\u2A10", + "cirmid":"\u2AEF", + "cirscir":"\u29C2", + "ClockwiseContourIntegral":"\u2232", + "CloseCurlyDoubleQuote":"\u201D", + "CloseCurlyQuote":"\u2019", + "clubs":"\u2663", + "clubsuit":"\u2663", + "Colon":"\u2237", + "colon":"\u003A", + "Colone":"\u2A74", + "colone":"\u2254", + "coloneq":"\u2254", + "comma":"\u002C", + "commat":"\u0040", + "comp":"\u2201", + "compfn":"\u2218", + "complement":"\u2201", + "complexes":"\u2102", + "cong":"\u2245", + "congdot":"\u2A6D", + "Congruent":"\u2261", + "Conint":"\u222F", + "conint":"\u222E", + "ContourIntegral":"\u222E", + "Copf":"\u2102", + "copf":"\uD835\uDD54", + "coprod":"\u2210", + "Coproduct":"\u2210", + "COPY":"\u00A9", + "copy":"\u00A9", + "copysr":"\u2117", + "CounterClockwiseContourIntegral":"\u2233", + "crarr":"\u21B5", + "Cross":"\u2A2F", + "cross":"\u2717", + "Cscr":"\uD835\uDC9E", + "cscr":"\uD835\uDCB8", + "csub":"\u2ACF", + "csube":"\u2AD1", + "csup":"\u2AD0", + "csupe":"\u2AD2", + "ctdot":"\u22EF", + "cudarrl":"\u2938", + "cudarrr":"\u2935", + "cuepr":"\u22DE", + "cuesc":"\u22DF", + "cularr":"\u21B6", + "cularrp":"\u293D", + "Cup":"\u22D3", + "cup":"\u222A", + "cupbrcap":"\u2A48", + "CupCap":"\u224D", + "cupcap":"\u2A46", + "cupcup":"\u2A4A", + "cupdot":"\u228D", + "cupor":"\u2A45", + "cups":"\u222A\uFE00", + "curarr":"\u21B7", + "curarrm":"\u293C", + "curlyeqprec":"\u22DE", + "curlyeqsucc":"\u22DF", + "curlyvee":"\u22CE", + "curlywedge":"\u22CF", + "curren":"\u00A4", + "curvearrowleft":"\u21B6", + "curvearrowright":"\u21B7", + "cuvee":"\u22CE", + "cuwed":"\u22CF", + "cwconint":"\u2232", + "cwint":"\u2231", + "cylcty":"\u232D", + "Dagger":"\u2021", + "dagger":"\u2020", + "daleth":"\u2138", + "Darr":"\u21A1", + "dArr":"\u21D3", + "darr":"\u2193", + "dash":"\u2010", + "Dashv":"\u2AE4", + "dashv":"\u22A3", + "dbkarow":"\u290F", + "dblac":"\u02DD", + "Dcaron":"\u010E", + "dcaron":"\u010F", + "Dcy":"\u0414", + "dcy":"\u0434", + "DD":"\u2145", + "dd":"\u2146", + "ddagger":"\u2021", + "ddarr":"\u21CA", + "DDotrahd":"\u2911", + "ddotseq":"\u2A77", + "deg":"\u00B0", + "Del":"\u2207", + "Delta":"\u0394", + "delta":"\u03B4", + "demptyv":"\u29B1", + "dfisht":"\u297F", + "Dfr":"\uD835\uDD07", + "dfr":"\uD835\uDD21", + "dHar":"\u2965", + "dharl":"\u21C3", + "dharr":"\u21C2", + "DiacriticalAcute":"\u00B4", + "DiacriticalDot":"\u02D9", + "DiacriticalDoubleAcute":"\u02DD", + "DiacriticalGrave":"\u0060", + "DiacriticalTilde":"\u02DC", + "diam":"\u22C4", + "Diamond":"\u22C4", + "diamond":"\u22C4", + "diamondsuit":"\u2666", + "diams":"\u2666", + "die":"\u00A8", + "DifferentialD":"\u2146", + "digamma":"\u03DD", + "disin":"\u22F2", + "div":"\u00F7", + "divide":"\u00F7", + "divideontimes":"\u22C7", + "divonx":"\u22C7", + "DJcy":"\u0402", + "djcy":"\u0452", + "dlcorn":"\u231E", + "dlcrop":"\u230D", + "dollar":"\u0024", + "Dopf":"\uD835\uDD3B", + "dopf":"\uD835\uDD55", + "Dot":"\u00A8", + "dot":"\u02D9", + "DotDot":"\u20DC", + "doteq":"\u2250", + "doteqdot":"\u2251", + "DotEqual":"\u2250", + "dotminus":"\u2238", + "dotplus":"\u2214", + "dotsquare":"\u22A1", + "doublebarwedge":"\u2306", + "DoubleContourIntegral":"\u222F", + "DoubleDot":"\u00A8", + "DoubleDownArrow":"\u21D3", + "DoubleLeftArrow":"\u21D0", + "DoubleLeftRightArrow":"\u21D4", + "DoubleLeftTee":"\u2AE4", + "DoubleLongLeftArrow":"\u27F8", + "DoubleLongLeftRightArrow":"\u27FA", + "DoubleLongRightArrow":"\u27F9", + "DoubleRightArrow":"\u21D2", + "DoubleRightTee":"\u22A8", + "DoubleUpArrow":"\u21D1", + "DoubleUpDownArrow":"\u21D5", + "DoubleVerticalBar":"\u2225", + "DownArrow":"\u2193", + "Downarrow":"\u21D3", + "downarrow":"\u2193", + "DownArrowBar":"\u2913", + "DownArrowUpArrow":"\u21F5", + "DownBreve":"\u0311", + "downdownarrows":"\u21CA", + "downharpoonleft":"\u21C3", + "downharpoonright":"\u21C2", + "DownLeftRightVector":"\u2950", + "DownLeftTeeVector":"\u295E", + "DownLeftVector":"\u21BD", + "DownLeftVectorBar":"\u2956", + "DownRightTeeVector":"\u295F", + "DownRightVector":"\u21C1", + "DownRightVectorBar":"\u2957", + "DownTee":"\u22A4", + "DownTeeArrow":"\u21A7", + "drbkarow":"\u2910", + "drcorn":"\u231F", + "drcrop":"\u230C", + "Dscr":"\uD835\uDC9F", + "dscr":"\uD835\uDCB9", + "DScy":"\u0405", + "dscy":"\u0455", + "dsol":"\u29F6", + "Dstrok":"\u0110", + "dstrok":"\u0111", + "dtdot":"\u22F1", + "dtri":"\u25BF", + "dtrif":"\u25BE", + "duarr":"\u21F5", + "duhar":"\u296F", + "dwangle":"\u29A6", + "DZcy":"\u040F", + "dzcy":"\u045F", + "dzigrarr":"\u27FF", + "Eacute":"\u00C9", + "eacute":"\u00E9", + "easter":"\u2A6E", + "Ecaron":"\u011A", + "ecaron":"\u011B", + "ecir":"\u2256", + "Ecirc":"\u00CA", + "ecirc":"\u00EA", + "ecolon":"\u2255", + "Ecy":"\u042D", + "ecy":"\u044D", + "eDDot":"\u2A77", + "Edot":"\u0116", + "eDot":"\u2251", + "edot":"\u0117", + "ee":"\u2147", + "efDot":"\u2252", + "Efr":"\uD835\uDD08", + "efr":"\uD835\uDD22", + "eg":"\u2A9A", + "Egrave":"\u00C8", + "egrave":"\u00E8", + "egs":"\u2A96", + "egsdot":"\u2A98", + "el":"\u2A99", + "Element":"\u2208", + "elinters":"\u23E7", + "ell":"\u2113", + "els":"\u2A95", + "elsdot":"\u2A97", + "Emacr":"\u0112", + "emacr":"\u0113", + "empty":"\u2205", + "emptyset":"\u2205", + "EmptySmallSquare":"\u25FB", + "emptyv":"\u2205", + "EmptyVerySmallSquare":"\u25AB", + "emsp":"\u2003", + "emsp13":"\u2004", + "emsp14":"\u2005", + "ENG":"\u014A", + "eng":"\u014B", + "ensp":"\u2002", + "Eogon":"\u0118", + "eogon":"\u0119", + "Eopf":"\uD835\uDD3C", + "eopf":"\uD835\uDD56", + "epar":"\u22D5", + "eparsl":"\u29E3", + "eplus":"\u2A71", + "epsi":"\u03B5", + "Epsilon":"\u0395", + "epsilon":"\u03B5", + "epsiv":"\u03F5", + "eqcirc":"\u2256", + "eqcolon":"\u2255", + "eqsim":"\u2242", + "eqslantgtr":"\u2A96", + "eqslantless":"\u2A95", + "Equal":"\u2A75", + "equals":"\u003D", + "EqualTilde":"\u2242", + "equest":"\u225F", + "Equilibrium":"\u21CC", + "equiv":"\u2261", + "equivDD":"\u2A78", + "eqvparsl":"\u29E5", + "erarr":"\u2971", + "erDot":"\u2253", + "Escr":"\u2130", + "escr":"\u212F", + "esdot":"\u2250", + "Esim":"\u2A73", + "esim":"\u2242", + "Eta":"\u0397", + "eta":"\u03B7", + "ETH":"\u00D0", + "eth":"\u00F0", + "Euml":"\u00CB", + "euml":"\u00EB", + "euro":"\u20AC", + "excl":"\u0021", + "exist":"\u2203", + "Exists":"\u2203", + "expectation":"\u2130", + "ExponentialE":"\u2147", + "exponentiale":"\u2147", + "fallingdotseq":"\u2252", + "Fcy":"\u0424", + "fcy":"\u0444", + "female":"\u2640", + "ffilig":"\uFB03", + "fflig":"\uFB00", + "ffllig":"\uFB04", + "Ffr":"\uD835\uDD09", + "ffr":"\uD835\uDD23", + "filig":"\uFB01", + "FilledSmallSquare":"\u25FC", + "FilledVerySmallSquare":"\u25AA", + "fjlig":"\u0066\u006A", + "flat":"\u266D", + "fllig":"\uFB02", + "fltns":"\u25B1", + "fnof":"\u0192", + "Fopf":"\uD835\uDD3D", + "fopf":"\uD835\uDD57", + "ForAll":"\u2200", + "forall":"\u2200", + "fork":"\u22D4", + "forkv":"\u2AD9", + "Fouriertrf":"\u2131", + "fpartint":"\u2A0D", + "frac12":"\u00BD", + "frac13":"\u2153", + "frac14":"\u00BC", + "frac15":"\u2155", + "frac16":"\u2159", + "frac18":"\u215B", + "frac23":"\u2154", + "frac25":"\u2156", + "frac34":"\u00BE", + "frac35":"\u2157", + "frac38":"\u215C", + "frac45":"\u2158", + "frac56":"\u215A", + "frac58":"\u215D", + "frac78":"\u215E", + "frasl":"\u2044", + "frown":"\u2322", + "Fscr":"\u2131", + "fscr":"\uD835\uDCBB", + "gacute":"\u01F5", + "Gamma":"\u0393", + "gamma":"\u03B3", + "Gammad":"\u03DC", + "gammad":"\u03DD", + "gap":"\u2A86", + "Gbreve":"\u011E", + "gbreve":"\u011F", + "Gcedil":"\u0122", + "Gcirc":"\u011C", + "gcirc":"\u011D", + "Gcy":"\u0413", + "gcy":"\u0433", + "Gdot":"\u0120", + "gdot":"\u0121", + "gE":"\u2267", + "ge":"\u2265", + "gEl":"\u2A8C", + "gel":"\u22DB", + "geq":"\u2265", + "geqq":"\u2267", + "geqslant":"\u2A7E", + "ges":"\u2A7E", + "gescc":"\u2AA9", + "gesdot":"\u2A80", + "gesdoto":"\u2A82", + "gesdotol":"\u2A84", + "gesl":"\u22DB\uFE00", + "gesles":"\u2A94", + "Gfr":"\uD835\uDD0A", + "gfr":"\uD835\uDD24", + "Gg":"\u22D9", + "gg":"\u226B", + "ggg":"\u22D9", + "gimel":"\u2137", + "GJcy":"\u0403", + "gjcy":"\u0453", + "gl":"\u2277", + "gla":"\u2AA5", + "glE":"\u2A92", + "glj":"\u2AA4", + "gnap":"\u2A8A", + "gnapprox":"\u2A8A", + "gnE":"\u2269", + "gne":"\u2A88", + "gneq":"\u2A88", + "gneqq":"\u2269", + "gnsim":"\u22E7", + "Gopf":"\uD835\uDD3E", + "gopf":"\uD835\uDD58", + "grave":"\u0060", + "GreaterEqual":"\u2265", + "GreaterEqualLess":"\u22DB", + "GreaterFullEqual":"\u2267", + "GreaterGreater":"\u2AA2", + "GreaterLess":"\u2277", + "GreaterSlantEqual":"\u2A7E", + "GreaterTilde":"\u2273", + "Gscr":"\uD835\uDCA2", + "gscr":"\u210A", + "gsim":"\u2273", + "gsime":"\u2A8E", + "gsiml":"\u2A90", + "GT":"\u003E", + "Gt":"\u226B", + "gt":"\u003E", + "gtcc":"\u2AA7", + "gtcir":"\u2A7A", + "gtdot":"\u22D7", + "gtlPar":"\u2995", + "gtquest":"\u2A7C", + "gtrapprox":"\u2A86", + "gtrarr":"\u2978", + "gtrdot":"\u22D7", + "gtreqless":"\u22DB", + "gtreqqless":"\u2A8C", + "gtrless":"\u2277", + "gtrsim":"\u2273", + "gvertneqq":"\u2269\uFE00", + "gvnE":"\u2269\uFE00", + "Hacek":"\u02C7", + "hairsp":"\u200A", + "half":"\u00BD", + "hamilt":"\u210B", + "HARDcy":"\u042A", + "hardcy":"\u044A", + "hArr":"\u21D4", + "harr":"\u2194", + "harrcir":"\u2948", + "harrw":"\u21AD", + "Hat":"\u005E", + "hbar":"\u210F", + "Hcirc":"\u0124", + "hcirc":"\u0125", + "hearts":"\u2665", + "heartsuit":"\u2665", + "hellip":"\u2026", + "hercon":"\u22B9", + "Hfr":"\u210C", + "hfr":"\uD835\uDD25", + "HilbertSpace":"\u210B", + "hksearow":"\u2925", + "hkswarow":"\u2926", + "hoarr":"\u21FF", + "homtht":"\u223B", + "hookleftarrow":"\u21A9", + "hookrightarrow":"\u21AA", + "Hopf":"\u210D", + "hopf":"\uD835\uDD59", + "horbar":"\u2015", + "HorizontalLine":"\u2500", + "Hscr":"\u210B", + "hscr":"\uD835\uDCBD", + "hslash":"\u210F", + "Hstrok":"\u0126", + "hstrok":"\u0127", + "HumpDownHump":"\u224E", + "HumpEqual":"\u224F", + "hybull":"\u2043", + "hyphen":"\u2010", + "Iacute":"\u00CD", + "iacute":"\u00ED", + "ic":"\u2063", + "Icirc":"\u00CE", + "icirc":"\u00EE", + "Icy":"\u0418", + "icy":"\u0438", + "Idot":"\u0130", + "IEcy":"\u0415", + "iecy":"\u0435", + "iexcl":"\u00A1", + "iff":"\u21D4", + "Ifr":"\u2111", + "ifr":"\uD835\uDD26", + "Igrave":"\u00CC", + "igrave":"\u00EC", + "ii":"\u2148", + "iiiint":"\u2A0C", + "iiint":"\u222D", + "iinfin":"\u29DC", + "iiota":"\u2129", + "IJlig":"\u0132", + "ijlig":"\u0133", + "Im":"\u2111", + "Imacr":"\u012A", + "imacr":"\u012B", + "image":"\u2111", + "ImaginaryI":"\u2148", + "imagline":"\u2110", + "imagpart":"\u2111", + "imath":"\u0131", + "imof":"\u22B7", + "imped":"\u01B5", + "Implies":"\u21D2", + "in":"\u2208", + "incare":"\u2105", + "infin":"\u221E", + "infintie":"\u29DD", + "inodot":"\u0131", + "Int":"\u222C", + "int":"\u222B", + "intcal":"\u22BA", + "integers":"\u2124", + "Integral":"\u222B", + "intercal":"\u22BA", + "Intersection":"\u22C2", + "intlarhk":"\u2A17", + "intprod":"\u2A3C", + "InvisibleComma":"\u2063", + "InvisibleTimes":"\u2062", + "IOcy":"\u0401", + "iocy":"\u0451", + "Iogon":"\u012E", + "iogon":"\u012F", + "Iopf":"\uD835\uDD40", + "iopf":"\uD835\uDD5A", + "Iota":"\u0399", + "iota":"\u03B9", + "iprod":"\u2A3C", + "iquest":"\u00BF", + "Iscr":"\u2110", + "iscr":"\uD835\uDCBE", + "isin":"\u2208", + "isindot":"\u22F5", + "isinE":"\u22F9", + "isins":"\u22F4", + "isinsv":"\u22F3", + "isinv":"\u2208", + "it":"\u2062", + "Itilde":"\u0128", + "itilde":"\u0129", + "Iukcy":"\u0406", + "iukcy":"\u0456", + "Iuml":"\u00CF", + "iuml":"\u00EF", + "Jcirc":"\u0134", + "jcirc":"\u0135", + "Jcy":"\u0419", + "jcy":"\u0439", + "Jfr":"\uD835\uDD0D", + "jfr":"\uD835\uDD27", + "jmath":"\u0237", + "Jopf":"\uD835\uDD41", + "jopf":"\uD835\uDD5B", + "Jscr":"\uD835\uDCA5", + "jscr":"\uD835\uDCBF", + "Jsercy":"\u0408", + "jsercy":"\u0458", + "Jukcy":"\u0404", + "jukcy":"\u0454", + "Kappa":"\u039A", + "kappa":"\u03BA", + "kappav":"\u03F0", + "Kcedil":"\u0136", + "kcedil":"\u0137", + "Kcy":"\u041A", + "kcy":"\u043A", + "Kfr":"\uD835\uDD0E", + "kfr":"\uD835\uDD28", + "kgreen":"\u0138", + "KHcy":"\u0425", + "khcy":"\u0445", + "KJcy":"\u040C", + "kjcy":"\u045C", + "Kopf":"\uD835\uDD42", + "kopf":"\uD835\uDD5C", + "Kscr":"\uD835\uDCA6", + "kscr":"\uD835\uDCC0", + "lAarr":"\u21DA", + "Lacute":"\u0139", + "lacute":"\u013A", + "laemptyv":"\u29B4", + "lagran":"\u2112", + "Lambda":"\u039B", + "lambda":"\u03BB", + "Lang":"\u27EA", + "lang":"\u27E8", + "langd":"\u2991", + "langle":"\u27E8", + "lap":"\u2A85", + "Laplacetrf":"\u2112", + "laquo":"\u00AB", + "Larr":"\u219E", + "lArr":"\u21D0", + "larr":"\u2190", + "larrb":"\u21E4", + "larrbfs":"\u291F", + "larrfs":"\u291D", + "larrhk":"\u21A9", + "larrlp":"\u21AB", + "larrpl":"\u2939", + "larrsim":"\u2973", + "larrtl":"\u21A2", + "lat":"\u2AAB", + "lAtail":"\u291B", + "latail":"\u2919", + "late":"\u2AAD", + "lates":"\u2AAD\uFE00", + "lBarr":"\u290E", + "lbarr":"\u290C", + "lbbrk":"\u2772", + "lbrace":"\u007B", + "lbrack":"\u005B", + "lbrke":"\u298B", + "lbrksld":"\u298F", + "lbrkslu":"\u298D", + "Lcaron":"\u013D", + "lcaron":"\u013E", + "Lcedil":"\u013B", + "lcedil":"\u013C", + "lceil":"\u2308", + "lcub":"\u007B", + "Lcy":"\u041B", + "lcy":"\u043B", + "ldca":"\u2936", + "ldquo":"\u201C", + "ldquor":"\u201E", + "ldrdhar":"\u2967", + "ldrushar":"\u294B", + "ldsh":"\u21B2", + "lE":"\u2266", + "le":"\u2264", + "LeftAngleBracket":"\u27E8", + "LeftArrow":"\u2190", + "Leftarrow":"\u21D0", + "leftarrow":"\u2190", + "LeftArrowBar":"\u21E4", + "LeftArrowRightArrow":"\u21C6", + "leftarrowtail":"\u21A2", + "LeftCeiling":"\u2308", + "LeftDoubleBracket":"\u27E6", + "LeftDownTeeVector":"\u2961", + "LeftDownVector":"\u21C3", + "LeftDownVectorBar":"\u2959", + "LeftFloor":"\u230A", + "leftharpoondown":"\u21BD", + "leftharpoonup":"\u21BC", + "leftleftarrows":"\u21C7", + "LeftRightArrow":"\u2194", + "Leftrightarrow":"\u21D4", + "leftrightarrow":"\u2194", + "leftrightarrows":"\u21C6", + "leftrightharpoons":"\u21CB", + "leftrightsquigarrow":"\u21AD", + "LeftRightVector":"\u294E", + "LeftTee":"\u22A3", + "LeftTeeArrow":"\u21A4", + "LeftTeeVector":"\u295A", + "leftthreetimes":"\u22CB", + "LeftTriangle":"\u22B2", + "LeftTriangleBar":"\u29CF", + "LeftTriangleEqual":"\u22B4", + "LeftUpDownVector":"\u2951", + "LeftUpTeeVector":"\u2960", + "LeftUpVector":"\u21BF", + "LeftUpVectorBar":"\u2958", + "LeftVector":"\u21BC", + "LeftVectorBar":"\u2952", + "lEg":"\u2A8B", + "leg":"\u22DA", + "leq":"\u2264", + "leqq":"\u2266", + "leqslant":"\u2A7D", + "les":"\u2A7D", + "lescc":"\u2AA8", + "lesdot":"\u2A7F", + "lesdoto":"\u2A81", + "lesdotor":"\u2A83", + "lesg":"\u22DA\uFE00", + "lesges":"\u2A93", + "lessapprox":"\u2A85", + "lessdot":"\u22D6", + "lesseqgtr":"\u22DA", + "lesseqqgtr":"\u2A8B", + "LessEqualGreater":"\u22DA", + "LessFullEqual":"\u2266", + "LessGreater":"\u2276", + "lessgtr":"\u2276", + "LessLess":"\u2AA1", + "lesssim":"\u2272", + "LessSlantEqual":"\u2A7D", + "LessTilde":"\u2272", + "lfisht":"\u297C", + "lfloor":"\u230A", + "Lfr":"\uD835\uDD0F", + "lfr":"\uD835\uDD29", + "lg":"\u2276", + "lgE":"\u2A91", + "lHar":"\u2962", + "lhard":"\u21BD", + "lharu":"\u21BC", + "lharul":"\u296A", + "lhblk":"\u2584", + "LJcy":"\u0409", + "ljcy":"\u0459", + "Ll":"\u22D8", + "ll":"\u226A", + "llarr":"\u21C7", + "llcorner":"\u231E", + "Lleftarrow":"\u21DA", + "llhard":"\u296B", + "lltri":"\u25FA", + "Lmidot":"\u013F", + "lmidot":"\u0140", + "lmoust":"\u23B0", + "lmoustache":"\u23B0", + "lnap":"\u2A89", + "lnapprox":"\u2A89", + "lnE":"\u2268", + "lne":"\u2A87", + "lneq":"\u2A87", + "lneqq":"\u2268", + "lnsim":"\u22E6", + "loang":"\u27EC", + "loarr":"\u21FD", + "lobrk":"\u27E6", + "LongLeftArrow":"\u27F5", + "Longleftarrow":"\u27F8", + "longleftarrow":"\u27F5", + "LongLeftRightArrow":"\u27F7", + "Longleftrightarrow":"\u27FA", + "longleftrightarrow":"\u27F7", + "longmapsto":"\u27FC", + "LongRightArrow":"\u27F6", + "Longrightarrow":"\u27F9", + "longrightarrow":"\u27F6", + "looparrowleft":"\u21AB", + "looparrowright":"\u21AC", + "lopar":"\u2985", + "Lopf":"\uD835\uDD43", + "lopf":"\uD835\uDD5D", + "loplus":"\u2A2D", + "lotimes":"\u2A34", + "lowast":"\u2217", + "lowbar":"\u005F", + "LowerLeftArrow":"\u2199", + "LowerRightArrow":"\u2198", + "loz":"\u25CA", + "lozenge":"\u25CA", + "lozf":"\u29EB", + "lpar":"\u0028", + "lparlt":"\u2993", + "lrarr":"\u21C6", + "lrcorner":"\u231F", + "lrhar":"\u21CB", + "lrhard":"\u296D", + "lrm":"\u200E", + "lrtri":"\u22BF", + "lsaquo":"\u2039", + "Lscr":"\u2112", + "lscr":"\uD835\uDCC1", + "Lsh":"\u21B0", + "lsh":"\u21B0", + "lsim":"\u2272", + "lsime":"\u2A8D", + "lsimg":"\u2A8F", + "lsqb":"\u005B", + "lsquo":"\u2018", + "lsquor":"\u201A", + "Lstrok":"\u0141", + "lstrok":"\u0142", + "LT":"\u003C", + "Lt":"\u226A", + "lt":"\u003C", + "ltcc":"\u2AA6", + "ltcir":"\u2A79", + "ltdot":"\u22D6", + "lthree":"\u22CB", + "ltimes":"\u22C9", + "ltlarr":"\u2976", + "ltquest":"\u2A7B", + "ltri":"\u25C3", + "ltrie":"\u22B4", + "ltrif":"\u25C2", + "ltrPar":"\u2996", + "lurdshar":"\u294A", + "luruhar":"\u2966", + "lvertneqq":"\u2268\uFE00", + "lvnE":"\u2268\uFE00", + "macr":"\u00AF", + "male":"\u2642", + "malt":"\u2720", + "maltese":"\u2720", + "Map":"\u2905", + "map":"\u21A6", + "mapsto":"\u21A6", + "mapstodown":"\u21A7", + "mapstoleft":"\u21A4", + "mapstoup":"\u21A5", + "marker":"\u25AE", + "mcomma":"\u2A29", + "Mcy":"\u041C", + "mcy":"\u043C", + "mdash":"\u2014", + "mDDot":"\u223A", + "measuredangle":"\u2221", + "MediumSpace":"\u205F", + "Mellintrf":"\u2133", + "Mfr":"\uD835\uDD10", + "mfr":"\uD835\uDD2A", + "mho":"\u2127", + "micro":"\u00B5", + "mid":"\u2223", + "midast":"\u002A", + "midcir":"\u2AF0", + "middot":"\u00B7", + "minus":"\u2212", + "minusb":"\u229F", + "minusd":"\u2238", + "minusdu":"\u2A2A", + "MinusPlus":"\u2213", + "mlcp":"\u2ADB", + "mldr":"\u2026", + "mnplus":"\u2213", + "models":"\u22A7", + "Mopf":"\uD835\uDD44", + "mopf":"\uD835\uDD5E", + "mp":"\u2213", + "Mscr":"\u2133", + "mscr":"\uD835\uDCC2", + "mstpos":"\u223E", + "Mu":"\u039C", + "mu":"\u03BC", + "multimap":"\u22B8", + "mumap":"\u22B8", + "nabla":"\u2207", + "Nacute":"\u0143", + "nacute":"\u0144", + "nang":"\u2220\u20D2", + "nap":"\u2249", + "napE":"\u2A70\u0338", + "napid":"\u224B\u0338", + "napos":"\u0149", + "napprox":"\u2249", + "natur":"\u266E", + "natural":"\u266E", + "naturals":"\u2115", + "nbsp":"\u00A0", + "nbump":"\u224E\u0338", + "nbumpe":"\u224F\u0338", + "ncap":"\u2A43", + "Ncaron":"\u0147", + "ncaron":"\u0148", + "Ncedil":"\u0145", + "ncedil":"\u0146", + "ncong":"\u2247", + "ncongdot":"\u2A6D\u0338", + "ncup":"\u2A42", + "Ncy":"\u041D", + "ncy":"\u043D", + "ndash":"\u2013", + "ne":"\u2260", + "nearhk":"\u2924", + "neArr":"\u21D7", + "nearr":"\u2197", + "nearrow":"\u2197", + "nedot":"\u2250\u0338", + "NegativeMediumSpace":"\u200B", + "NegativeThickSpace":"\u200B", + "NegativeThinSpace":"\u200B", + "NegativeVeryThinSpace":"\u200B", + "nequiv":"\u2262", + "nesear":"\u2928", + "nesim":"\u2242\u0338", + "NestedGreaterGreater":"\u226B", + "NestedLessLess":"\u226A", + "NewLine":"\u000A", + "nexist":"\u2204", + "nexists":"\u2204", + "Nfr":"\uD835\uDD11", + "nfr":"\uD835\uDD2B", + "ngE":"\u2267\u0338", + "nge":"\u2271", + "ngeq":"\u2271", + "ngeqq":"\u2267\u0338", + "ngeqslant":"\u2A7E\u0338", + "nges":"\u2A7E\u0338", + "nGg":"\u22D9\u0338", + "ngsim":"\u2275", + "nGt":"\u226B\u20D2", + "ngt":"\u226F", + "ngtr":"\u226F", + "nGtv":"\u226B\u0338", + "nhArr":"\u21CE", + "nharr":"\u21AE", + "nhpar":"\u2AF2", + "ni":"\u220B", + "nis":"\u22FC", + "nisd":"\u22FA", + "niv":"\u220B", + "NJcy":"\u040A", + "njcy":"\u045A", + "nlArr":"\u21CD", + "nlarr":"\u219A", + "nldr":"\u2025", + "nlE":"\u2266\u0338", + "nle":"\u2270", + "nLeftarrow":"\u21CD", + "nleftarrow":"\u219A", + "nLeftrightarrow":"\u21CE", + "nleftrightarrow":"\u21AE", + "nleq":"\u2270", + "nleqq":"\u2266\u0338", + "nleqslant":"\u2A7D\u0338", + "nles":"\u2A7D\u0338", + "nless":"\u226E", + "nLl":"\u22D8\u0338", + "nlsim":"\u2274", + "nLt":"\u226A\u20D2", + "nlt":"\u226E", + "nltri":"\u22EA", + "nltrie":"\u22EC", + "nLtv":"\u226A\u0338", + "nmid":"\u2224", + "NoBreak":"\u2060", + "NonBreakingSpace":"\u00A0", + "Nopf":"\u2115", + "nopf":"\uD835\uDD5F", + "Not":"\u2AEC", + "not":"\u00AC", + "NotCongruent":"\u2262", + "NotCupCap":"\u226D", + "NotDoubleVerticalBar":"\u2226", + "NotElement":"\u2209", + "NotEqual":"\u2260", + "NotEqualTilde":"\u2242\u0338", + "NotExists":"\u2204", + "NotGreater":"\u226F", + "NotGreaterEqual":"\u2271", + "NotGreaterFullEqual":"\u2267\u0338", + "NotGreaterGreater":"\u226B\u0338", + "NotGreaterLess":"\u2279", + "NotGreaterSlantEqual":"\u2A7E\u0338", + "NotGreaterTilde":"\u2275", + "NotHumpDownHump":"\u224E\u0338", + "NotHumpEqual":"\u224F\u0338", + "notin":"\u2209", + "notindot":"\u22F5\u0338", + "notinE":"\u22F9\u0338", + "notinva":"\u2209", + "notinvb":"\u22F7", + "notinvc":"\u22F6", + "NotLeftTriangle":"\u22EA", + "NotLeftTriangleBar":"\u29CF\u0338", + "NotLeftTriangleEqual":"\u22EC", + "NotLess":"\u226E", + "NotLessEqual":"\u2270", + "NotLessGreater":"\u2278", + "NotLessLess":"\u226A\u0338", + "NotLessSlantEqual":"\u2A7D\u0338", + "NotLessTilde":"\u2274", + "NotNestedGreaterGreater":"\u2AA2\u0338", + "NotNestedLessLess":"\u2AA1\u0338", + "notni":"\u220C", + "notniva":"\u220C", + "notnivb":"\u22FE", + "notnivc":"\u22FD", + "NotPrecedes":"\u2280", + "NotPrecedesEqual":"\u2AAF\u0338", + "NotPrecedesSlantEqual":"\u22E0", + "NotReverseElement":"\u220C", + "NotRightTriangle":"\u22EB", + "NotRightTriangleBar":"\u29D0\u0338", + "NotRightTriangleEqual":"\u22ED", + "NotSquareSubset":"\u228F\u0338", + "NotSquareSubsetEqual":"\u22E2", + "NotSquareSuperset":"\u2290\u0338", + "NotSquareSupersetEqual":"\u22E3", + "NotSubset":"\u2282\u20D2", + "NotSubsetEqual":"\u2288", + "NotSucceeds":"\u2281", + "NotSucceedsEqual":"\u2AB0\u0338", + "NotSucceedsSlantEqual":"\u22E1", + "NotSucceedsTilde":"\u227F\u0338", + "NotSuperset":"\u2283\u20D2", + "NotSupersetEqual":"\u2289", + "NotTilde":"\u2241", + "NotTildeEqual":"\u2244", + "NotTildeFullEqual":"\u2247", + "NotTildeTilde":"\u2249", + "NotVerticalBar":"\u2224", + "npar":"\u2226", + "nparallel":"\u2226", + "nparsl":"\u2AFD\u20E5", + "npart":"\u2202\u0338", + "npolint":"\u2A14", + "npr":"\u2280", + "nprcue":"\u22E0", + "npre":"\u2AAF\u0338", + "nprec":"\u2280", + "npreceq":"\u2AAF\u0338", + "nrArr":"\u21CF", + "nrarr":"\u219B", + "nrarrc":"\u2933\u0338", + "nrarrw":"\u219D\u0338", + "nRightarrow":"\u21CF", + "nrightarrow":"\u219B", + "nrtri":"\u22EB", + "nrtrie":"\u22ED", + "nsc":"\u2281", + "nsccue":"\u22E1", + "nsce":"\u2AB0\u0338", + "Nscr":"\uD835\uDCA9", + "nscr":"\uD835\uDCC3", + "nshortmid":"\u2224", + "nshortparallel":"\u2226", + "nsim":"\u2241", + "nsime":"\u2244", + "nsimeq":"\u2244", + "nsmid":"\u2224", + "nspar":"\u2226", + "nsqsube":"\u22E2", + "nsqsupe":"\u22E3", + "nsub":"\u2284", + "nsubE":"\u2AC5\u0338", + "nsube":"\u2288", + "nsubset":"\u2282\u20D2", + "nsubseteq":"\u2288", + "nsubseteqq":"\u2AC5\u0338", + "nsucc":"\u2281", + "nsucceq":"\u2AB0\u0338", + "nsup":"\u2285", + "nsupE":"\u2AC6\u0338", + "nsupe":"\u2289", + "nsupset":"\u2283\u20D2", + "nsupseteq":"\u2289", + "nsupseteqq":"\u2AC6\u0338", + "ntgl":"\u2279", + "Ntilde":"\u00D1", + "ntilde":"\u00F1", + "ntlg":"\u2278", + "ntriangleleft":"\u22EA", + "ntrianglelefteq":"\u22EC", + "ntriangleright":"\u22EB", + "ntrianglerighteq":"\u22ED", + "Nu":"\u039D", + "nu":"\u03BD", + "num":"\u0023", + "numero":"\u2116", + "numsp":"\u2007", + "nvap":"\u224D\u20D2", + "nVDash":"\u22AF", + "nVdash":"\u22AE", + "nvDash":"\u22AD", + "nvdash":"\u22AC", + "nvge":"\u2265\u20D2", + "nvgt":"\u003E\u20D2", + "nvHarr":"\u2904", + "nvinfin":"\u29DE", + "nvlArr":"\u2902", + "nvle":"\u2264\u20D2", + "nvlt":"\u003C\u20D2", + "nvltrie":"\u22B4\u20D2", + "nvrArr":"\u2903", + "nvrtrie":"\u22B5\u20D2", + "nvsim":"\u223C\u20D2", + "nwarhk":"\u2923", + "nwArr":"\u21D6", + "nwarr":"\u2196", + "nwarrow":"\u2196", + "nwnear":"\u2927", + "Oacute":"\u00D3", + "oacute":"\u00F3", + "oast":"\u229B", + "ocir":"\u229A", + "Ocirc":"\u00D4", + "ocirc":"\u00F4", + "Ocy":"\u041E", + "ocy":"\u043E", + "odash":"\u229D", + "Odblac":"\u0150", + "odblac":"\u0151", + "odiv":"\u2A38", + "odot":"\u2299", + "odsold":"\u29BC", + "OElig":"\u0152", + "oelig":"\u0153", + "ofcir":"\u29BF", + "Ofr":"\uD835\uDD12", + "ofr":"\uD835\uDD2C", + "ogon":"\u02DB", + "Ograve":"\u00D2", + "ograve":"\u00F2", + "ogt":"\u29C1", + "ohbar":"\u29B5", + "ohm":"\u03A9", + "oint":"\u222E", + "olarr":"\u21BA", + "olcir":"\u29BE", + "olcross":"\u29BB", + "oline":"\u203E", + "olt":"\u29C0", + "Omacr":"\u014C", + "omacr":"\u014D", + "Omega":"\u03A9", + "omega":"\u03C9", + "Omicron":"\u039F", + "omicron":"\u03BF", + "omid":"\u29B6", + "ominus":"\u2296", + "Oopf":"\uD835\uDD46", + "oopf":"\uD835\uDD60", + "opar":"\u29B7", + "OpenCurlyDoubleQuote":"\u201C", + "OpenCurlyQuote":"\u2018", + "operp":"\u29B9", + "oplus":"\u2295", + "Or":"\u2A54", + "or":"\u2228", + "orarr":"\u21BB", + "ord":"\u2A5D", + "order":"\u2134", + "orderof":"\u2134", + "ordf":"\u00AA", + "ordm":"\u00BA", + "origof":"\u22B6", + "oror":"\u2A56", + "orslope":"\u2A57", + "orv":"\u2A5B", + "oS":"\u24C8", + "Oscr":"\uD835\uDCAA", + "oscr":"\u2134", + "Oslash":"\u00D8", + "oslash":"\u00F8", + "osol":"\u2298", + "Otilde":"\u00D5", + "otilde":"\u00F5", + "Otimes":"\u2A37", + "otimes":"\u2297", + "otimesas":"\u2A36", + "Ouml":"\u00D6", + "ouml":"\u00F6", + "ovbar":"\u233D", + "OverBar":"\u203E", + "OverBrace":"\u23DE", + "OverBracket":"\u23B4", + "OverParenthesis":"\u23DC", + "par":"\u2225", + "para":"\u00B6", + "parallel":"\u2225", + "parsim":"\u2AF3", + "parsl":"\u2AFD", + "part":"\u2202", + "PartialD":"\u2202", + "Pcy":"\u041F", + "pcy":"\u043F", + "percnt":"\u0025", + "period":"\u002E", + "permil":"\u2030", + "perp":"\u22A5", + "pertenk":"\u2031", + "Pfr":"\uD835\uDD13", + "pfr":"\uD835\uDD2D", + "Phi":"\u03A6", + "phi":"\u03C6", + "phiv":"\u03D5", + "phmmat":"\u2133", + "phone":"\u260E", + "Pi":"\u03A0", + "pi":"\u03C0", + "pitchfork":"\u22D4", + "piv":"\u03D6", + "planck":"\u210F", + "planckh":"\u210E", + "plankv":"\u210F", + "plus":"\u002B", + "plusacir":"\u2A23", + "plusb":"\u229E", + "pluscir":"\u2A22", + "plusdo":"\u2214", + "plusdu":"\u2A25", + "pluse":"\u2A72", + "PlusMinus":"\u00B1", + "plusmn":"\u00B1", + "plussim":"\u2A26", + "plustwo":"\u2A27", + "pm":"\u00B1", + "Poincareplane":"\u210C", + "pointint":"\u2A15", + "Popf":"\u2119", + "popf":"\uD835\uDD61", + "pound":"\u00A3", + "Pr":"\u2ABB", + "pr":"\u227A", + "prap":"\u2AB7", + "prcue":"\u227C", + "prE":"\u2AB3", + "pre":"\u2AAF", + "prec":"\u227A", + "precapprox":"\u2AB7", + "preccurlyeq":"\u227C", + "Precedes":"\u227A", + "PrecedesEqual":"\u2AAF", + "PrecedesSlantEqual":"\u227C", + "PrecedesTilde":"\u227E", + "preceq":"\u2AAF", + "precnapprox":"\u2AB9", + "precneqq":"\u2AB5", + "precnsim":"\u22E8", + "precsim":"\u227E", + "Prime":"\u2033", + "prime":"\u2032", + "primes":"\u2119", + "prnap":"\u2AB9", + "prnE":"\u2AB5", + "prnsim":"\u22E8", + "prod":"\u220F", + "Product":"\u220F", + "profalar":"\u232E", + "profline":"\u2312", + "profsurf":"\u2313", + "prop":"\u221D", + "Proportion":"\u2237", + "Proportional":"\u221D", + "propto":"\u221D", + "prsim":"\u227E", + "prurel":"\u22B0", + "Pscr":"\uD835\uDCAB", + "pscr":"\uD835\uDCC5", + "Psi":"\u03A8", + "psi":"\u03C8", + "puncsp":"\u2008", + "Qfr":"\uD835\uDD14", + "qfr":"\uD835\uDD2E", + "qint":"\u2A0C", + "Qopf":"\u211A", + "qopf":"\uD835\uDD62", + "qprime":"\u2057", + "Qscr":"\uD835\uDCAC", + "qscr":"\uD835\uDCC6", + "quaternions":"\u210D", + "quatint":"\u2A16", + "quest":"\u003F", + "questeq":"\u225F", + "QUOT":"\u0022", + "quot":"\u0022", + "rAarr":"\u21DB", + "race":"\u223D\u0331", + "Racute":"\u0154", + "racute":"\u0155", + "radic":"\u221A", + "raemptyv":"\u29B3", + "Rang":"\u27EB", + "rang":"\u27E9", + "rangd":"\u2992", + "range":"\u29A5", + "rangle":"\u27E9", + "raquo":"\u00BB", + "Rarr":"\u21A0", + "rArr":"\u21D2", + "rarr":"\u2192", + "rarrap":"\u2975", + "rarrb":"\u21E5", + "rarrbfs":"\u2920", + "rarrc":"\u2933", + "rarrfs":"\u291E", + "rarrhk":"\u21AA", + "rarrlp":"\u21AC", + "rarrpl":"\u2945", + "rarrsim":"\u2974", + "Rarrtl":"\u2916", + "rarrtl":"\u21A3", + "rarrw":"\u219D", + "rAtail":"\u291C", + "ratail":"\u291A", + "ratio":"\u2236", + "rationals":"\u211A", + "RBarr":"\u2910", + "rBarr":"\u290F", + "rbarr":"\u290D", + "rbbrk":"\u2773", + "rbrace":"\u007D", + "rbrack":"\u005D", + "rbrke":"\u298C", + "rbrksld":"\u298E", + "rbrkslu":"\u2990", + "Rcaron":"\u0158", + "rcaron":"\u0159", + "Rcedil":"\u0156", + "rcedil":"\u0157", + "rceil":"\u2309", + "rcub":"\u007D", + "Rcy":"\u0420", + "rcy":"\u0440", + "rdca":"\u2937", + "rdldhar":"\u2969", + "rdquo":"\u201D", + "rdquor":"\u201D", + "rdsh":"\u21B3", + "Re":"\u211C", + "real":"\u211C", + "realine":"\u211B", + "realpart":"\u211C", + "reals":"\u211D", + "rect":"\u25AD", + "REG":"\u00AE", + "reg":"\u00AE", + "ReverseElement":"\u220B", + "ReverseEquilibrium":"\u21CB", + "ReverseUpEquilibrium":"\u296F", + "rfisht":"\u297D", + "rfloor":"\u230B", + "Rfr":"\u211C", + "rfr":"\uD835\uDD2F", + "rHar":"\u2964", + "rhard":"\u21C1", + "rharu":"\u21C0", + "rharul":"\u296C", + "Rho":"\u03A1", + "rho":"\u03C1", + "rhov":"\u03F1", + "RightAngleBracket":"\u27E9", + "RightArrow":"\u2192", + "Rightarrow":"\u21D2", + "rightarrow":"\u2192", + "RightArrowBar":"\u21E5", + "RightArrowLeftArrow":"\u21C4", + "rightarrowtail":"\u21A3", + "RightCeiling":"\u2309", + "RightDoubleBracket":"\u27E7", + "RightDownTeeVector":"\u295D", + "RightDownVector":"\u21C2", + "RightDownVectorBar":"\u2955", + "RightFloor":"\u230B", + "rightharpoondown":"\u21C1", + "rightharpoonup":"\u21C0", + "rightleftarrows":"\u21C4", + "rightleftharpoons":"\u21CC", + "rightrightarrows":"\u21C9", + "rightsquigarrow":"\u219D", + "RightTee":"\u22A2", + "RightTeeArrow":"\u21A6", + "RightTeeVector":"\u295B", + "rightthreetimes":"\u22CC", + "RightTriangle":"\u22B3", + "RightTriangleBar":"\u29D0", + "RightTriangleEqual":"\u22B5", + "RightUpDownVector":"\u294F", + "RightUpTeeVector":"\u295C", + "RightUpVector":"\u21BE", + "RightUpVectorBar":"\u2954", + "RightVector":"\u21C0", + "RightVectorBar":"\u2953", + "ring":"\u02DA", + "risingdotseq":"\u2253", + "rlarr":"\u21C4", + "rlhar":"\u21CC", + "rlm":"\u200F", + "rmoust":"\u23B1", + "rmoustache":"\u23B1", + "rnmid":"\u2AEE", + "roang":"\u27ED", + "roarr":"\u21FE", + "robrk":"\u27E7", + "ropar":"\u2986", + "Ropf":"\u211D", + "ropf":"\uD835\uDD63", + "roplus":"\u2A2E", + "rotimes":"\u2A35", + "RoundImplies":"\u2970", + "rpar":"\u0029", + "rpargt":"\u2994", + "rppolint":"\u2A12", + "rrarr":"\u21C9", + "Rrightarrow":"\u21DB", + "rsaquo":"\u203A", + "Rscr":"\u211B", + "rscr":"\uD835\uDCC7", + "Rsh":"\u21B1", + "rsh":"\u21B1", + "rsqb":"\u005D", + "rsquo":"\u2019", + "rsquor":"\u2019", + "rthree":"\u22CC", + "rtimes":"\u22CA", + "rtri":"\u25B9", + "rtrie":"\u22B5", + "rtrif":"\u25B8", + "rtriltri":"\u29CE", + "RuleDelayed":"\u29F4", + "ruluhar":"\u2968", + "rx":"\u211E", + "Sacute":"\u015A", + "sacute":"\u015B", + "sbquo":"\u201A", + "Sc":"\u2ABC", + "sc":"\u227B", + "scap":"\u2AB8", + "Scaron":"\u0160", + "scaron":"\u0161", + "sccue":"\u227D", + "scE":"\u2AB4", + "sce":"\u2AB0", + "Scedil":"\u015E", + "scedil":"\u015F", + "Scirc":"\u015C", + "scirc":"\u015D", + "scnap":"\u2ABA", + "scnE":"\u2AB6", + "scnsim":"\u22E9", + "scpolint":"\u2A13", + "scsim":"\u227F", + "Scy":"\u0421", + "scy":"\u0441", + "sdot":"\u22C5", + "sdotb":"\u22A1", + "sdote":"\u2A66", + "searhk":"\u2925", + "seArr":"\u21D8", + "searr":"\u2198", + "searrow":"\u2198", + "sect":"\u00A7", + "semi":"\u003B", + "seswar":"\u2929", + "setminus":"\u2216", + "setmn":"\u2216", + "sext":"\u2736", + "Sfr":"\uD835\uDD16", + "sfr":"\uD835\uDD30", + "sfrown":"\u2322", + "sharp":"\u266F", + "SHCHcy":"\u0429", + "shchcy":"\u0449", + "SHcy":"\u0428", + "shcy":"\u0448", + "ShortDownArrow":"\u2193", + "ShortLeftArrow":"\u2190", + "shortmid":"\u2223", + "shortparallel":"\u2225", + "ShortRightArrow":"\u2192", + "ShortUpArrow":"\u2191", + "shy":"\u00AD", + "Sigma":"\u03A3", + "sigma":"\u03C3", + "sigmaf":"\u03C2", + "sigmav":"\u03C2", + "sim":"\u223C", + "simdot":"\u2A6A", + "sime":"\u2243", + "simeq":"\u2243", + "simg":"\u2A9E", + "simgE":"\u2AA0", + "siml":"\u2A9D", + "simlE":"\u2A9F", + "simne":"\u2246", + "simplus":"\u2A24", + "simrarr":"\u2972", + "slarr":"\u2190", + "SmallCircle":"\u2218", + "smallsetminus":"\u2216", + "smashp":"\u2A33", + "smeparsl":"\u29E4", + "smid":"\u2223", + "smile":"\u2323", + "smt":"\u2AAA", + "smte":"\u2AAC", + "smtes":"\u2AAC\uFE00", + "SOFTcy":"\u042C", + "softcy":"\u044C", + "sol":"\u002F", + "solb":"\u29C4", + "solbar":"\u233F", + "Sopf":"\uD835\uDD4A", + "sopf":"\uD835\uDD64", + "spades":"\u2660", + "spadesuit":"\u2660", + "spar":"\u2225", + "sqcap":"\u2293", + "sqcaps":"\u2293\uFE00", + "sqcup":"\u2294", + "sqcups":"\u2294\uFE00", + "Sqrt":"\u221A", + "sqsub":"\u228F", + "sqsube":"\u2291", + "sqsubset":"\u228F", + "sqsubseteq":"\u2291", + "sqsup":"\u2290", + "sqsupe":"\u2292", + "sqsupset":"\u2290", + "sqsupseteq":"\u2292", + "squ":"\u25A1", + "Square":"\u25A1", + "square":"\u25A1", + "SquareIntersection":"\u2293", + "SquareSubset":"\u228F", + "SquareSubsetEqual":"\u2291", + "SquareSuperset":"\u2290", + "SquareSupersetEqual":"\u2292", + "SquareUnion":"\u2294", + "squarf":"\u25AA", + "squf":"\u25AA", + "srarr":"\u2192", + "Sscr":"\uD835\uDCAE", + "sscr":"\uD835\uDCC8", + "ssetmn":"\u2216", + "ssmile":"\u2323", + "sstarf":"\u22C6", + "Star":"\u22C6", + "star":"\u2606", + "starf":"\u2605", + "straightepsilon":"\u03F5", + "straightphi":"\u03D5", + "strns":"\u00AF", + "Sub":"\u22D0", + "sub":"\u2282", + "subdot":"\u2ABD", + "subE":"\u2AC5", + "sube":"\u2286", + "subedot":"\u2AC3", + "submult":"\u2AC1", + "subnE":"\u2ACB", + "subne":"\u228A", + "subplus":"\u2ABF", + "subrarr":"\u2979", + "Subset":"\u22D0", + "subset":"\u2282", + "subseteq":"\u2286", + "subseteqq":"\u2AC5", + "SubsetEqual":"\u2286", + "subsetneq":"\u228A", + "subsetneqq":"\u2ACB", + "subsim":"\u2AC7", + "subsub":"\u2AD5", + "subsup":"\u2AD3", + "succ":"\u227B", + "succapprox":"\u2AB8", + "succcurlyeq":"\u227D", + "Succeeds":"\u227B", + "SucceedsEqual":"\u2AB0", + "SucceedsSlantEqual":"\u227D", + "SucceedsTilde":"\u227F", + "succeq":"\u2AB0", + "succnapprox":"\u2ABA", + "succneqq":"\u2AB6", + "succnsim":"\u22E9", + "succsim":"\u227F", + "SuchThat":"\u220B", + "Sum":"\u2211", + "sum":"\u2211", + "sung":"\u266A", + "Sup":"\u22D1", + "sup":"\u2283", + "sup1":"\u00B9", + "sup2":"\u00B2", + "sup3":"\u00B3", + "supdot":"\u2ABE", + "supdsub":"\u2AD8", + "supE":"\u2AC6", + "supe":"\u2287", + "supedot":"\u2AC4", + "Superset":"\u2283", + "SupersetEqual":"\u2287", + "suphsol":"\u27C9", + "suphsub":"\u2AD7", + "suplarr":"\u297B", + "supmult":"\u2AC2", + "supnE":"\u2ACC", + "supne":"\u228B", + "supplus":"\u2AC0", + "Supset":"\u22D1", + "supset":"\u2283", + "supseteq":"\u2287", + "supseteqq":"\u2AC6", + "supsetneq":"\u228B", + "supsetneqq":"\u2ACC", + "supsim":"\u2AC8", + "supsub":"\u2AD4", + "supsup":"\u2AD6", + "swarhk":"\u2926", + "swArr":"\u21D9", + "swarr":"\u2199", + "swarrow":"\u2199", + "swnwar":"\u292A", + "szlig":"\u00DF", + "Tab":"\u0009", + "target":"\u2316", + "Tau":"\u03A4", + "tau":"\u03C4", + "tbrk":"\u23B4", + "Tcaron":"\u0164", + "tcaron":"\u0165", + "Tcedil":"\u0162", + "tcedil":"\u0163", + "Tcy":"\u0422", + "tcy":"\u0442", + "tdot":"\u20DB", + "telrec":"\u2315", + "Tfr":"\uD835\uDD17", + "tfr":"\uD835\uDD31", + "there4":"\u2234", + "Therefore":"\u2234", + "therefore":"\u2234", + "Theta":"\u0398", + "theta":"\u03B8", + "thetasym":"\u03D1", + "thetav":"\u03D1", + "thickapprox":"\u2248", + "thicksim":"\u223C", + "ThickSpace":"\u205F\u200A", + "thinsp":"\u2009", + "ThinSpace":"\u2009", + "thkap":"\u2248", + "thksim":"\u223C", + "THORN":"\u00DE", + "thorn":"\u00FE", + "Tilde":"\u223C", + "tilde":"\u02DC", + "TildeEqual":"\u2243", + "TildeFullEqual":"\u2245", + "TildeTilde":"\u2248", + "times":"\u00D7", + "timesb":"\u22A0", + "timesbar":"\u2A31", + "timesd":"\u2A30", + "tint":"\u222D", + "toea":"\u2928", + "top":"\u22A4", + "topbot":"\u2336", + "topcir":"\u2AF1", + "Topf":"\uD835\uDD4B", + "topf":"\uD835\uDD65", + "topfork":"\u2ADA", + "tosa":"\u2929", + "tprime":"\u2034", + "TRADE":"\u2122", + "trade":"\u2122", + "triangle":"\u25B5", + "triangledown":"\u25BF", + "triangleleft":"\u25C3", + "trianglelefteq":"\u22B4", + "triangleq":"\u225C", + "triangleright":"\u25B9", + "trianglerighteq":"\u22B5", + "tridot":"\u25EC", + "trie":"\u225C", + "triminus":"\u2A3A", + "TripleDot":"\u20DB", + "triplus":"\u2A39", + "trisb":"\u29CD", + "tritime":"\u2A3B", + "trpezium":"\u23E2", + "Tscr":"\uD835\uDCAF", + "tscr":"\uD835\uDCC9", + "TScy":"\u0426", + "tscy":"\u0446", + "TSHcy":"\u040B", + "tshcy":"\u045B", + "Tstrok":"\u0166", + "tstrok":"\u0167", + "twixt":"\u226C", + "twoheadleftarrow":"\u219E", + "twoheadrightarrow":"\u21A0", + "Uacute":"\u00DA", + "uacute":"\u00FA", + "Uarr":"\u219F", + "uArr":"\u21D1", + "uarr":"\u2191", + "Uarrocir":"\u2949", + "Ubrcy":"\u040E", + "ubrcy":"\u045E", + "Ubreve":"\u016C", + "ubreve":"\u016D", + "Ucirc":"\u00DB", + "ucirc":"\u00FB", + "Ucy":"\u0423", + "ucy":"\u0443", + "udarr":"\u21C5", + "Udblac":"\u0170", + "udblac":"\u0171", + "udhar":"\u296E", + "ufisht":"\u297E", + "Ufr":"\uD835\uDD18", + "ufr":"\uD835\uDD32", + "Ugrave":"\u00D9", + "ugrave":"\u00F9", + "uHar":"\u2963", + "uharl":"\u21BF", + "uharr":"\u21BE", + "uhblk":"\u2580", + "ulcorn":"\u231C", + "ulcorner":"\u231C", + "ulcrop":"\u230F", + "ultri":"\u25F8", + "Umacr":"\u016A", + "umacr":"\u016B", + "uml":"\u00A8", + "UnderBar":"\u005F", + "UnderBrace":"\u23DF", + "UnderBracket":"\u23B5", + "UnderParenthesis":"\u23DD", + "Union":"\u22C3", + "UnionPlus":"\u228E", + "Uogon":"\u0172", + "uogon":"\u0173", + "Uopf":"\uD835\uDD4C", + "uopf":"\uD835\uDD66", + "UpArrow":"\u2191", + "Uparrow":"\u21D1", + "uparrow":"\u2191", + "UpArrowBar":"\u2912", + "UpArrowDownArrow":"\u21C5", + "UpDownArrow":"\u2195", + "Updownarrow":"\u21D5", + "updownarrow":"\u2195", + "UpEquilibrium":"\u296E", + "upharpoonleft":"\u21BF", + "upharpoonright":"\u21BE", + "uplus":"\u228E", + "UpperLeftArrow":"\u2196", + "UpperRightArrow":"\u2197", + "Upsi":"\u03D2", + "upsi":"\u03C5", + "upsih":"\u03D2", + "Upsilon":"\u03A5", + "upsilon":"\u03C5", + "UpTee":"\u22A5", + "UpTeeArrow":"\u21A5", + "upuparrows":"\u21C8", + "urcorn":"\u231D", + "urcorner":"\u231D", + "urcrop":"\u230E", + "Uring":"\u016E", + "uring":"\u016F", + "urtri":"\u25F9", + "Uscr":"\uD835\uDCB0", + "uscr":"\uD835\uDCCA", + "utdot":"\u22F0", + "Utilde":"\u0168", + "utilde":"\u0169", + "utri":"\u25B5", + "utrif":"\u25B4", + "uuarr":"\u21C8", + "Uuml":"\u00DC", + "uuml":"\u00FC", + "uwangle":"\u29A7", + "vangrt":"\u299C", + "varepsilon":"\u03F5", + "varkappa":"\u03F0", + "varnothing":"\u2205", + "varphi":"\u03D5", + "varpi":"\u03D6", + "varpropto":"\u221D", + "vArr":"\u21D5", + "varr":"\u2195", + "varrho":"\u03F1", + "varsigma":"\u03C2", + "varsubsetneq":"\u228A\uFE00", + "varsubsetneqq":"\u2ACB\uFE00", + "varsupsetneq":"\u228B\uFE00", + "varsupsetneqq":"\u2ACC\uFE00", + "vartheta":"\u03D1", + "vartriangleleft":"\u22B2", + "vartriangleright":"\u22B3", + "Vbar":"\u2AEB", + "vBar":"\u2AE8", + "vBarv":"\u2AE9", + "Vcy":"\u0412", + "vcy":"\u0432", + "VDash":"\u22AB", + "Vdash":"\u22A9", + "vDash":"\u22A8", + "vdash":"\u22A2", + "Vdashl":"\u2AE6", + "Vee":"\u22C1", + "vee":"\u2228", + "veebar":"\u22BB", + "veeeq":"\u225A", + "vellip":"\u22EE", + "Verbar":"\u2016", + "verbar":"\u007C", + "Vert":"\u2016", + "vert":"\u007C", + "VerticalBar":"\u2223", + "VerticalLine":"\u007C", + "VerticalSeparator":"\u2758", + "VerticalTilde":"\u2240", + "VeryThinSpace":"\u200A", + "Vfr":"\uD835\uDD19", + "vfr":"\uD835\uDD33", + "vltri":"\u22B2", + "vnsub":"\u2282\u20D2", + "vnsup":"\u2283\u20D2", + "Vopf":"\uD835\uDD4D", + "vopf":"\uD835\uDD67", + "vprop":"\u221D", + "vrtri":"\u22B3", + "Vscr":"\uD835\uDCB1", + "vscr":"\uD835\uDCCB", + "vsubnE":"\u2ACB\uFE00", + "vsubne":"\u228A\uFE00", + "vsupnE":"\u2ACC\uFE00", + "vsupne":"\u228B\uFE00", + "Vvdash":"\u22AA", + "vzigzag":"\u299A", + "Wcirc":"\u0174", + "wcirc":"\u0175", + "wedbar":"\u2A5F", + "Wedge":"\u22C0", + "wedge":"\u2227", + "wedgeq":"\u2259", + "weierp":"\u2118", + "Wfr":"\uD835\uDD1A", + "wfr":"\uD835\uDD34", + "Wopf":"\uD835\uDD4E", + "wopf":"\uD835\uDD68", + "wp":"\u2118", + "wr":"\u2240", + "wreath":"\u2240", + "Wscr":"\uD835\uDCB2", + "wscr":"\uD835\uDCCC", + "xcap":"\u22C2", + "xcirc":"\u25EF", + "xcup":"\u22C3", + "xdtri":"\u25BD", + "Xfr":"\uD835\uDD1B", + "xfr":"\uD835\uDD35", + "xhArr":"\u27FA", + "xharr":"\u27F7", + "Xi":"\u039E", + "xi":"\u03BE", + "xlArr":"\u27F8", + "xlarr":"\u27F5", + "xmap":"\u27FC", + "xnis":"\u22FB", + "xodot":"\u2A00", + "Xopf":"\uD835\uDD4F", + "xopf":"\uD835\uDD69", + "xoplus":"\u2A01", + "xotime":"\u2A02", + "xrArr":"\u27F9", + "xrarr":"\u27F6", + "Xscr":"\uD835\uDCB3", + "xscr":"\uD835\uDCCD", + "xsqcup":"\u2A06", + "xuplus":"\u2A04", + "xutri":"\u25B3", + "xvee":"\u22C1", + "xwedge":"\u22C0", + "Yacute":"\u00DD", + "yacute":"\u00FD", + "YAcy":"\u042F", + "yacy":"\u044F", + "Ycirc":"\u0176", + "ycirc":"\u0177", + "Ycy":"\u042B", + "ycy":"\u044B", + "yen":"\u00A5", + "Yfr":"\uD835\uDD1C", + "yfr":"\uD835\uDD36", + "YIcy":"\u0407", + "yicy":"\u0457", + "Yopf":"\uD835\uDD50", + "yopf":"\uD835\uDD6A", + "Yscr":"\uD835\uDCB4", + "yscr":"\uD835\uDCCE", + "YUcy":"\u042E", + "yucy":"\u044E", + "Yuml":"\u0178", + "yuml":"\u00FF", + "Zacute":"\u0179", + "zacute":"\u017A", + "Zcaron":"\u017D", + "zcaron":"\u017E", + "Zcy":"\u0417", + "zcy":"\u0437", + "Zdot":"\u017B", + "zdot":"\u017C", + "zeetrf":"\u2128", + "ZeroWidthSpace":"\u200B", + "Zeta":"\u0396", + "zeta":"\u03B6", + "Zfr":"\u2128", + "zfr":"\uD835\uDD37", + "ZHcy":"\u0416", + "zhcy":"\u0436", + "zigrarr":"\u21DD", + "Zopf":"\u2124", + "zopf":"\uD835\uDD6B", + "Zscr":"\uD835\uDCB5", + "zscr":"\uD835\uDCCF", + "zwj":"\u200D", + "zwnj":"\u200C" +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/common/html_blocks.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/common/html_blocks.js new file mode 100644 index 0000000..96848e0 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/common/html_blocks.js @@ -0,0 +1,62 @@ +// List of valid html blocks names, accorting to commonmark spec +// http://jgm.github.io/CommonMark/spec.html#html-blocks + +'use strict'; + +var html_blocks = {}; + +[ + 'article', + 'aside', + 'button', + 'blockquote', + 'body', + 'canvas', + 'caption', + 'col', + 'colgroup', + 'dd', + 'div', + 'dl', + 'dt', + 'embed', + 'fieldset', + 'figcaption', + 'figure', + 'footer', + 'form', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'header', + 'hgroup', + 'hr', + 'iframe', + 'li', + 'map', + 'object', + 'ol', + 'output', + 'p', + 'pre', + 'progress', + 'script', + 'section', + 'style', + 'table', + 'tbody', + 'td', + 'textarea', + 'tfoot', + 'th', + 'tr', + 'thead', + 'ul', + 'video' +].forEach(function (name) { html_blocks[name] = true; }); + + +module.exports = html_blocks; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/common/html_re.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/common/html_re.js new file mode 100644 index 0000000..f4264dc --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/common/html_re.js @@ -0,0 +1,59 @@ +// Regexps to match html elements + +'use strict'; + + +function replace(regex, options) { + regex = regex.source; + options = options || ''; + + return function self(name, val) { + if (!name) { + return new RegExp(regex, options); + } + val = val.source || val; + regex = regex.replace(name, val); + return self; + }; +} + + +var attr_name = /[a-zA-Z_:][a-zA-Z0-9:._-]*/; + +var unquoted = /[^"'=<>`\x00-\x20]+/; +var single_quoted = /'[^']*'/; +var double_quoted = /"[^"]*"/; + +/*eslint no-spaced-func:0*/ +var attr_value = replace(/(?:unquoted|single_quoted|double_quoted)/) + ('unquoted', unquoted) + ('single_quoted', single_quoted) + ('double_quoted', double_quoted) + (); + +var attribute = replace(/(?:\s+attr_name(?:\s*=\s*attr_value)?)/) + ('attr_name', attr_name) + ('attr_value', attr_value) + (); + +var open_tag = replace(/<[A-Za-z][A-Za-z0-9]*attribute*\s*\/?>/) + ('attribute', attribute) + (); + +var close_tag = /<\/[A-Za-z][A-Za-z0-9]*\s*>/; +var comment = //; +var processing = /<[?].*?[?]>/; +var declaration = /]*>/; +var cdata = /])*\]\]>/; + +var HTML_TAG_RE = replace(/^(?:open_tag|close_tag|comment|processing|declaration|cdata)/) + ('open_tag', open_tag) + ('close_tag', close_tag) + ('comment', comment) + ('processing', processing) + ('declaration', declaration) + ('cdata', cdata) + (); + + +module.exports.HTML_TAG_RE = HTML_TAG_RE; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/common/url_schemas.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/common/url_schemas.js new file mode 100644 index 0000000..bd71c25 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/common/url_schemas.js @@ -0,0 +1,172 @@ +// List of valid url schemas, accorting to commonmark spec +// http://jgm.github.io/CommonMark/spec.html#autolinks + +'use strict'; + + +module.exports = [ + 'coap', + 'doi', + 'javascript', + 'aaa', + 'aaas', + 'about', + 'acap', + 'cap', + 'cid', + 'crid', + 'data', + 'dav', + 'dict', + 'dns', + 'file', + 'ftp', + 'geo', + 'go', + 'gopher', + 'h323', + 'http', + 'https', + 'iax', + 'icap', + 'im', + 'imap', + 'info', + 'ipp', + 'iris', + 'iris.beep', + 'iris.xpc', + 'iris.xpcs', + 'iris.lwz', + 'ldap', + 'mailto', + 'mid', + 'msrp', + 'msrps', + 'mtqp', + 'mupdate', + 'news', + 'nfs', + 'ni', + 'nih', + 'nntp', + 'opaquelocktoken', + 'pop', + 'pres', + 'rtsp', + 'service', + 'session', + 'shttp', + 'sieve', + 'sip', + 'sips', + 'sms', + 'snmp', + 'soap.beep', + 'soap.beeps', + 'tag', + 'tel', + 'telnet', + 'tftp', + 'thismessage', + 'tn3270', + 'tip', + 'tv', + 'urn', + 'vemmi', + 'ws', + 'wss', + 'xcon', + 'xcon-userid', + 'xmlrpc.beep', + 'xmlrpc.beeps', + 'xmpp', + 'z39.50r', + 'z39.50s', + 'adiumxtra', + 'afp', + 'afs', + 'aim', + 'apt', + 'attachment', + 'aw', + 'beshare', + 'bitcoin', + 'bolo', + 'callto', + 'chrome', + 'chrome-extension', + 'com-eventbrite-attendee', + 'content', + 'cvs', + 'dlna-playsingle', + 'dlna-playcontainer', + 'dtn', + 'dvb', + 'ed2k', + 'facetime', + 'feed', + 'finger', + 'fish', + 'gg', + 'git', + 'gizmoproject', + 'gtalk', + 'hcp', + 'icon', + 'ipn', + 'irc', + 'irc6', + 'ircs', + 'itms', + 'jar', + 'jms', + 'keyparc', + 'lastfm', + 'ldaps', + 'magnet', + 'maps', + 'market', + 'message', + 'mms', + 'ms-help', + 'msnim', + 'mumble', + 'mvn', + 'notes', + 'oid', + 'palm', + 'paparazzi', + 'platform', + 'proxy', + 'psyc', + 'query', + 'res', + 'resource', + 'rmi', + 'rsync', + 'rtmp', + 'secondlife', + 'sftp', + 'sgn', + 'skype', + 'smb', + 'soldat', + 'spotify', + 'ssh', + 'steam', + 'svn', + 'teamspeak', + 'things', + 'udp', + 'unreal', + 'ut2004', + 'ventrilo', + 'view-source', + 'webcal', + 'wtai', + 'wyciwyg', + 'xfire', + 'xri', + 'ymsgr' +]; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/common/utils.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/common/utils.js new file mode 100644 index 0000000..6b9756e --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/common/utils.js @@ -0,0 +1,157 @@ +// Utilities +// +'use strict'; + + +function _class(obj) { return Object.prototype.toString.call(obj); } + +function isString(obj) { return _class(obj) === '[object String]'; } + +var _hasOwnProperty = Object.prototype.hasOwnProperty; + +function has(object, key) { + return object ? _hasOwnProperty.call(object, key) : false; +} + +// Merge objects +// +function assign(obj /*from1, from2, from3, ...*/) { + var sources = Array.prototype.slice.call(arguments, 1); + + sources.forEach(function (source) { + if (!source) { return; } + + if (typeof source !== 'object') { + throw new TypeError(source + 'must be object'); + } + + Object.keys(source).forEach(function (key) { + obj[key] = source[key]; + }); + }); + + return obj; +} + +// Remove element from array and put another array at those position. +// Useful for some operations with tokens +function arrayReplaceAt(src, pos, newElements) { + return [].concat(src.slice(0, pos), newElements, src.slice(pos + 1)); +} + +//////////////////////////////////////////////////////////////////////////////// + +var UNESCAPE_MD_RE = /\\([\\!"#$%&'()*+,.\/:;<=>?@[\]^_`{|}~-])/g; + +function unescapeMd(str) { + if (str.indexOf('\\') < 0) { return str; } + return str.replace(UNESCAPE_MD_RE, '$1'); +} + +//////////////////////////////////////////////////////////////////////////////// + +function isValidEntityCode(c) { + /*eslint no-bitwise:0*/ + // broken sequence + if (c >= 0xD800 && c <= 0xDFFF) { return false; } + // never used + if (c >= 0xFDD0 && c <= 0xFDEF) { return false; } + if ((c & 0xFFFF) === 0xFFFF || (c & 0xFFFF) === 0xFFFE) { return false; } + // control codes + if (c >= 0x00 && c <= 0x08) { return false; } + if (c === 0x0B) { return false; } + if (c >= 0x0E && c <= 0x1F) { return false; } + if (c >= 0x7F && c <= 0x9F) { return false; } + // out of range + if (c > 0x10FFFF) { return false; } + return true; +} + +function fromCodePoint(c) { + /*eslint no-bitwise:0*/ + if (c > 0xffff) { + c -= 0x10000; + var surrogate1 = 0xd800 + (c >> 10), + surrogate2 = 0xdc00 + (c & 0x3ff); + + return String.fromCharCode(surrogate1, surrogate2); + } + return String.fromCharCode(c); +} + +var NAMED_ENTITY_RE = /&([a-z#][a-z0-9]{1,31});/gi; +var DIGITAL_ENTITY_TEST_RE = /^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i; +var entities = require('./entities'); + +function replaceEntityPattern(match, name) { + var code = 0; + + if (has(entities, name)) { + return entities[name]; + } else if (name.charCodeAt(0) === 0x23/* # */ && DIGITAL_ENTITY_TEST_RE.test(name)) { + code = name[1].toLowerCase() === 'x' ? + parseInt(name.slice(2), 16) + : + parseInt(name.slice(1), 10); + if (isValidEntityCode(code)) { + return fromCodePoint(code); + } + } + return match; +} + +function replaceEntities(str) { + if (str.indexOf('&') < 0) { return str; } + + return str.replace(NAMED_ENTITY_RE, replaceEntityPattern); +} + +//////////////////////////////////////////////////////////////////////////////// + +var HTML_ESCAPE_TEST_RE = /[&<>"]/; +var HTML_ESCAPE_REPLACE_RE = /[&<>"]/g; +var HTML_REPLACEMENTS = { + '&': '&', + '<': '<', + '>': '>', + '"': '"' +}; + +function replaceUnsafeChar(ch) { + return HTML_REPLACEMENTS[ch]; +} + +function escapeHtml(str) { + if (HTML_ESCAPE_TEST_RE.test(str)) { + return str.replace(HTML_ESCAPE_REPLACE_RE, replaceUnsafeChar); + } + return str; +} + +//////////////////////////////////////////////////////////////////////////////// + +// Incoming link can be partially encoded. Convert possible combinations to +// unified form. +function normalizeLink(url) { + var normalized = replaceEntities(url); + + // We don't care much about result of mailformed URIs, + // but shoud not throw exception. + try { + normalized = decodeURI(normalized); + } catch (__) {} + + return encodeURI(normalized); +} + + +exports.assign = assign; +exports.isString = isString; +exports.has = has; +exports.unescapeMd = unescapeMd; +exports.isValidEntityCode = isValidEntityCode; +exports.fromCodePoint = fromCodePoint; +exports.replaceEntities = replaceEntities; +exports.escapeHtml = escapeHtml; +exports.arrayReplaceAt = arrayReplaceAt; +exports.normalizeLink = normalizeLink; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/helpers/index.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/helpers/index.js new file mode 100644 index 0000000..bfdbfa2 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/helpers/index.js @@ -0,0 +1,7 @@ +// Just a shortcut for bulk export +'use strict'; + + +exports.parseLinkLabel = require('./parse_link_label'); +exports.parseLinkDestination = require('./parse_link_destination'); +exports.parseLinkTitle = require('./parse_link_title'); diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/helpers/normalize_reference.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/helpers/normalize_reference.js new file mode 100644 index 0000000..26b9215 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/helpers/normalize_reference.js @@ -0,0 +1,11 @@ +'use strict'; + + +// Hepler to [reference labels]. No better place for this code :) +// It's only for refs/links and should not be exported anywhere. +module.exports = function normalizeReference(str) { + // use .toUpperCase() instead of .toLowerCase() + // here to avoid a conflict with Object.prototype + // members (most notably, `__proto__`) + return str.trim().replace(/\s+/g, ' ').toUpperCase(); +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/helpers/parse_link_destination.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/helpers/parse_link_destination.js new file mode 100644 index 0000000..3f35da4 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/helpers/parse_link_destination.js @@ -0,0 +1,79 @@ +// Parse link destination +// +// on success it returns a string and updates state.pos; +// on failure it returns null +// +'use strict'; + + +var normalizeLink = require('../common/utils').normalizeLink; +var unescapeMd = require('../common/utils').unescapeMd; + + +module.exports = function parseLinkDestination(state, pos) { + var code, level, link, + start = pos, + max = state.posMax; + + if (state.src.charCodeAt(pos) === 0x3C /* < */) { + pos++; + while (pos < max) { + code = state.src.charCodeAt(pos); + if (code === 0x0A /* \n */) { return false; } + if (code === 0x3E /* > */) { + link = normalizeLink(unescapeMd(state.src.slice(start + 1, pos))); + if (!state.parser.validateLink(link)) { return false; } + state.pos = pos + 1; + state.linkContent = link; + return true; + } + if (code === 0x5C /* \ */ && pos + 1 < max) { + pos += 2; + continue; + } + + pos++; + } + + // no closing '>' + return false; + } + + // this should be ... } else { ... branch + + level = 0; + while (pos < max) { + code = state.src.charCodeAt(pos); + + if (code === 0x20) { break; } + + // ascii control characters + if (code < 0x20 || code === 0x7F) { break; } + + if (code === 0x5C /* \ */ && pos + 1 < max) { + pos += 2; + continue; + } + + if (code === 0x28 /* ( */) { + level++; + if (level > 1) { break; } + } + + if (code === 0x29 /* ) */) { + level--; + if (level < 0) { break; } + } + + pos++; + } + + if (start === pos) { return false; } + + link = normalizeLink(unescapeMd(state.src.slice(start, pos))); + if (!state.parser.validateLink(link)) { return false; } + + state.linkContent = link; + state.pos = pos; + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/helpers/parse_link_label.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/helpers/parse_link_label.js new file mode 100644 index 0000000..9ac8364 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/helpers/parse_link_label.js @@ -0,0 +1,56 @@ +// Parse link label +// +// this function assumes that first character ("[") already matches; +// returns the end of the label +// +'use strict'; + +module.exports = function parseLinkLabel(state, start, disableNested) { + var level, found, marker, prevPos, + labelEnd = -1, + max = state.posMax, + oldPos = state.pos; + + if (state.labelUnmatchedScopes) { + state.labelUnmatchedScopes--; + return -1; + } + + state.pos = start + 1; + level = 1; + + while (state.pos < max) { + marker = state.src.charCodeAt(state.pos); + if (marker === 0x5D /* ] */) { + level--; + if (level === 0) { + found = true; + break; + } + } + + prevPos = state.pos; + state.parser.skipToken(state); + if (marker === 0x5B /* [ */) { + if (prevPos === state.pos - 1) { + // increase level if we find text `[`, which is not a part of any token + level++; + } else if (disableNested) { + state.pos = oldPos; + return -1; + } + } + } + + if (found) { + labelEnd = state.pos; + state.labelUnmatchedScopes = 0; + } else { + state.labelUnmatchedScopes = level - 1; + } + + // restore old state + state.pos = oldPos; + + return labelEnd; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/helpers/parse_link_title.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/helpers/parse_link_title.js new file mode 100644 index 0000000..956ecd9 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/helpers/parse_link_title.js @@ -0,0 +1,41 @@ +// Parse link title +// +// on success it returns a string and updates state.pos; +// on failure it returns null +// +'use strict'; + + +var unescapeMd = require('../common/utils').unescapeMd; + + +module.exports = function parseLinkTitle(state, pos) { + var code, + start = pos, + max = state.posMax, + marker = state.src.charCodeAt(pos); + + if (marker !== 0x22 /* " */ && marker !== 0x27 /* ' */ && marker !== 0x28 /* ( */) { return false; } + + pos++; + + // if opening marker is "(", switch it to closing marker ")" + if (marker === 0x28) { marker = 0x29; } + + while (pos < max) { + code = state.src.charCodeAt(pos); + if (code === marker) { + state.pos = pos + 1; + state.linkContent = unescapeMd(state.src.slice(start + 1, pos)); + return true; + } + if (code === 0x5C /* \ */ && pos + 1 < max) { + pos += 2; + continue; + } + + pos++; + } + + return false; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/index.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/index.js new file mode 100644 index 0000000..582d724 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/index.js @@ -0,0 +1,415 @@ +// Main perser class + +'use strict'; + + +var utils = require('./common/utils'); +var helpers = require('./helpers'); +var Renderer = require('./renderer'); +var ParserCore = require('./parser_core'); +var ParserBlock = require('./parser_block'); +var ParserInline = require('./parser_inline'); + +var config = { + 'default': require('./presets/default'), + zero: require('./presets/zero'), + full: require('./presets/full'), + commonmark: require('./presets/commonmark') +}; + + +function StateCore(self, src, env) { + this.src = src; + this.env = env; + this.options = self.options; + this.tokens = []; + this.inlineMode = false; + + this.inline = self.inline; + this.block = self.block; + this.renderer = self.renderer; + this.typographer = self.typographer; +} + +/** + * class MarkdownIt + * + * Main parser/renderer class. + * + * ##### Usage + * + * ```javascript + * // node.js, "classic" way: + * var MarkdownIt = require('markdown-it'), + * md = new MarkdownIt(); + * var result = md.render('# markdown-it rulezz!'); + * + * // node.js, the same, but with sugar: + * var md = require('markdown-it')(); + * var result = md.render('# markdown-it rulezz!'); + * + * // browser without AMD, added to "window" on script load + * // Note, there are no dash. + * var md = window.markdownit(); + * var result = md.render('# markdown-it rulezz!'); + * ``` + * + * Single line rendering, without paragraph wrap: + * + * ```javascript + * var md = require('markdown-it')(); + * var result = md.renderInline('__markdown-it__ rulezz!'); + * ``` + **/ + +/** + * new MarkdownIt([presetName, options]) + * - presetName (String): optional, `commonmark` / `full` / `zero` + * - options (Object) + * + * Creates parser instanse with given config. Can be called without `new`. + * + * ##### presetName + * + * MarkdownIt provides named presets as a convenience to quickly + * enable/disable active syntax rules and options for common use cases. + * + * - ["commonmark"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/commonmark.js) - + * configures parser to strict [CommonMark](http://commonmark.org/) mode. + * - ["full"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/full.js) - + * enables all available rules, but still without html, typographer & autolinker. + * - [default](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/default.js) - + * similar to GFM, used when no preset name given. + * - ["zero"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/zero.js) - + * all rules disabled. Useful to quickly setup your config via `.enable()`. + * For example, when you need only `bold` and `italic` markup and nothing else. + * + * ##### options: + * + * - __html__ - `false`. Set `true` to enable HTML tags in source. Be careful! + * That's not safe! You may need external sanitizer to protect output from XSS. + * It's better to extend features via plugins, instead of enabling HTML. + * - __xhtmlOut__ - `false`. Set `true` to add '/' when closing single tags + * (`
`). This is needed only for full CommonMark compatibility. In real + * world you will need HTML output. + * - __breaks__ - `false`. Set `true` to convert `\n` in paragraphs into `
`. + * - __langPrefix__ - `language-`. CSS language class prefix for fenced blocks. + * Can be useful for external highlighters. + * - __linkify__ - `false`. Set `true` to autoconvert URL-like text to links. + * - __typographer__ - `false`. Set `true` to enable [some language-neutral + * replacement](https://github.com/markdown-it/markdown-it/blob/master/lib/rules_core/replacements.js) + + * quotes beautification (smartquotes). + * - __quotes__ - `“”‘’`, string. Double + single quotes replacement pairs, when + * typographer enabled and smartquotes on. Set doubles to '«»' for Russian, + * '„“' for German. + * - __highlight__ - `null`. Highlighter function for fenced code blocks. + * Highlighter `function (str, lang)` should return escaped HTML. It can also + * return empty string if the source was not changed and should be escaped externaly. + * + * ##### Example + * + * ```javascript + * // commonmark mode + * var md = require('markdown-it')('commonmark'); + * + * // default mode + * var md = require('markdown-it')(); + * + * // enable everything + * var md = require('markdown-it')('full', { + * html: true, + * linkify: true, + * typographer: true + * }); + * ``` + * + * ##### Syntax highlighting + * + * ```js + * var hljs = require('highlight.js') // https://highlightjs.org/ + * + * var md = require('markdown-it')({ + * highlight: function (str, lang) { + * if (lang && hljs.getLanguage(lang)) { + * try { + * return hljs.highlight(lang, str).value; + * } catch (__) {} + * } + * + * try { + * return hljs.highlightAuto(str).value; + * } catch (__) {} + * + * return ''; // use external default escaping + * } + * }); + * ``` + **/ +function MarkdownIt(presetName, options) { + if (!(this instanceof MarkdownIt)) { + return new MarkdownIt(presetName, options); + } + + if (!options) { + if (!utils.isString(presetName)) { + options = presetName || {}; + presetName = 'default'; + } + } + + /** + * MarkdownIt#inline -> ParserInline + * + * Instance of [[ParserInline]]. You may need it to add new rules when + * writing plugins. For simple rules control use [[MarkdownIt.disable]] and + * [[MarkdownIt.enable]]. + **/ + this.inline = new ParserInline(); + + /** + * MarkdownIt#block -> ParserBlock + * + * Instance of [[ParserBlock]]. You may need it to add new rules when + * writing plugins. For simple rules control use [[MarkdownIt.disable]] and + * [[MarkdownIt.enable]]. + **/ + this.block = new ParserBlock(); + + /** + * MarkdownIt#core -> Core + * + * Instance of [[Core]] chain executor. You may need it to add new rules when + * writing plugins. For simple rules control use [[MarkdownIt.disable]] and + * [[MarkdownIt.enable]]. + **/ + this.core = new ParserCore(); + + /** + * MarkdownIt#renderer -> Renderer + * + * Instance of [[Renderer]]. Use it to modify output look. Or to add rendering + * rules for new token types, generated by plugins. + * + * ##### Example + * + * ```javascript + * var md = require('markdown-it')(); + * + * function myToken(tokens, idx, options, env, self) { + * //... + * return result; + * }; + * + * md.renderer.rules['my_token'] = myToken + * ``` + * + * See [[Renderer]] docs and [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.js). + **/ + this.renderer = new Renderer(); + + // Expose utils & helpers for easy acces from plugins + + /** + * MarkdownIt#utils -> utils + * + * Assorted utility functions, useful to write plugins. See details + * [here](https://github.com/markdown-it/markdown-it/blob/master/lib/common/utils.js). + **/ + this.utils = utils; + + /** + * MarkdownIt#helpers -> helpers + * + * Link components parser functions, useful to write plugins. See details + * [here](https://github.com/markdown-it/markdown-it/blob/master/lib/helpers). + **/ + this.helpers = helpers; + + + this.options = {}; + this.configure(config[presetName]); + + if (options) { this.set(options); } +} + + +/** chainable + * MarkdownIt.set(options) + * + * Set parser options (in the same format as in constructor). Probably, you + * will never need it, but you can change options after constructor call. + * + * ##### Example + * + * ```javascript + * var md = require('markdown-it')() + * .set({ html: true, breaks: true }) + * .set({ typographer, true }); + * ``` + * + * __Note:__ To achieve the best possible performance, don't modify a + * `markdown-it` instance options on the fly. If you need multiple configurations + * it's best to create multiple instances and initialize each with separate + * config. + **/ +MarkdownIt.prototype.set = function (options) { + utils.assign(this.options, options); + return this; +}; + + +/** chainable, internal + * MarkdownIt.configure(presets) + * + * Batch load of all options and compenent settings. This is internal method, + * and you probably will not need it. But if you with - see available presets + * and data structure [here](https://github.com/markdown-it/markdown-it/tree/master/lib/presets) + **/ +MarkdownIt.prototype.configure = function (presets) { + var self = this; + + if (!presets) { throw new Error('Wrong `markdown-it` preset, check name/content'); } + + if (presets.options) { self.set(presets.options); } + + if (presets.components) { + Object.keys(presets.components).forEach(function (name) { + if (presets.components[name].rules) { + self[name].ruler.enableOnly(presets.components[name].rules); + } + }); + } + return this; +}; + + +/** chainable + * MarkdownIt.enable(list) + * - list (String|Array): rule name or list of rule names to enable + * + * Enable list or rules. It will automatically find appropriate components, + * containing rules with given names. + * + * ##### Example + * + * ```javascript + * var md = require('markdown-it')() + * .enable(['sub', 'sup']) + * .disable('smartquotes'); + * ``` + **/ +MarkdownIt.prototype.enable = function (list) { + [ 'core', 'block', 'inline' ].forEach(function (chain) { + this[chain].ruler.enable(list, true); + }, this); + return this; +}; + + +/** chainable + * MarkdownIt.disable(list) + * - list (String|Array): rule name or list of rule names to disable. + * + * The same as [[MarkdownIt.enable]], but turn specified rules off. + **/ +MarkdownIt.prototype.disable = function (list) { + [ 'core', 'block', 'inline' ].forEach(function (chain) { + this[chain].ruler.disable(list, true); + }, this); + return this; +}; + + +/** chainable + * MarkdownIt.use(plugin, options) + * + * Load specified plugin with given options into current parser instance. + * + * ##### Example + * + * ```javascript + * var md = require('markdown-it')() + * .use(require('makkdown-it-emoji')); + * ``` + **/ +MarkdownIt.prototype.use = function (plugin /*, options, ... */) { + var args = [ this ].concat(Array.prototype.slice.call(arguments, 1)); + plugin.apply(plugin, args); + return this; +}; + + +/** internal + * MarkdownIt.parse(src, env) -> Array + * - src (String): source string + * - env (Object): enviroment variables + * + * Parse input string and returns list of block tokens (special token type + * "inline" will contain list of inline tokens). You should not call this + * method directly, until you write custom renderer (for example, to produce + * AST). + * + * `env` is modified with additional info. For example, with references data. + * Also `env` can be used to pass external info to plugins. + **/ +MarkdownIt.prototype.parse = function (src, env) { + var state = new StateCore(this, src, env); + + this.core.process(state); + + return state.tokens; +}; + + +/** + * MarkdownIt.render(src [, env]) -> String + * - src (String): source string + * - env (Object): optional, enviroment variables + * + * Render markdown string into html. It does all magic for you :). + * + * `env` is `{}` by default. It's not used now directly, but you can pass + * with it any additional data to plugins. + **/ +MarkdownIt.prototype.render = function (src, env) { + env = env || {}; + + return this.renderer.render(this.parse(src, env), this.options, env); +}; + + +/** internal + * MarkdownIt.parseInline(src, env) -> Array + * - src (String): source string + * - env (Object): enviroment variables + * + * The same as [[MarkdownIt.parse]] but skip all block rules. It returns the + * block tokens list with th single `inline` element, containing parsed inline + * tokens in `children` property. + **/ +MarkdownIt.prototype.parseInline = function (src, env) { + var state = new StateCore(this, src, env); + + state.inlineMode = true; + this.core.process(state); + + return state.tokens; +}; + + +/** + * MarkdownIt.renderInline(src [, env]) -> String + * - src (String): source string + * - env (Object): optional, enviroment variables + * + * Similar to [[MarkdownIt.render]] but for single paragraph content. Result + * will NOT be wrapped into `

` tags. + **/ +MarkdownIt.prototype.renderInline = function (src, env) { + env = env || {}; + + return this.renderer.render(this.parseInline(src, env), this.options, env); +}; + + +module.exports = MarkdownIt; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/parser_block.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/parser_block.js new file mode 100644 index 0000000..b140993 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/parser_block.js @@ -0,0 +1,148 @@ +/** internal + * class ParserBlock + * + * Block-level tokenizer. + **/ +'use strict'; + + +var Ruler = require('./ruler'); +var StateBlock = require('./rules_block/state_block'); + + +var _rules = [ + [ 'code', require('./rules_block/code') ], + [ 'fences', require('./rules_block/fences'), [ 'paragraph', 'blockquote', 'list' ] ], + [ 'blockquote', require('./rules_block/blockquote'), [ 'paragraph', 'blockquote', 'list' ] ], + [ 'hr', require('./rules_block/hr'), [ 'paragraph', 'blockquote', 'list' ] ], + [ 'list', require('./rules_block/list'), [ 'paragraph', 'blockquote' ] ], + [ 'footnote', require('./rules_block/footnote'), [ 'paragraph' ] ], + [ 'heading', require('./rules_block/heading'), [ 'paragraph', 'blockquote' ] ], + [ 'lheading', require('./rules_block/lheading') ], + [ 'htmlblock', require('./rules_block/htmlblock'), [ 'paragraph', 'blockquote' ] ], + [ 'table', require('./rules_block/table'), [ 'paragraph' ] ], + [ 'deflist', require('./rules_block/deflist'), [ 'paragraph' ] ], + [ 'paragraph', require('./rules_block/paragraph') ] +]; + + +/** + * new ParserBlock() + **/ +function ParserBlock() { + /** + * ParserBlock#ruler -> Ruler + * + * [[Ruler]] instance. Keep configuration of block rules. + **/ + this.ruler = new Ruler(); + + for (var i = 0; i < _rules.length; i++) { + this.ruler.push(_rules[i][0], _rules[i][1], { alt: (_rules[i][2] || []).slice() }); + } +} + + +// Generate tokens for input range +// +ParserBlock.prototype.tokenize = function (state, startLine, endLine) { + var ok, i, + rules = this.ruler.getRules(''), + len = rules.length, + line = startLine, + hasEmptyLines = false; + + while (line < endLine) { + state.line = line = state.skipEmptyLines(line); + if (line >= endLine) { break; } + + // Termination condition for nested calls. + // Nested calls currently used for blockquotes & lists + if (state.tShift[line] < state.blkIndent) { break; } + + // Try all possible rules. + // On success, rule should: + // + // - update `state.line` + // - update `state.tokens` + // - return true + + for (i = 0; i < len; i++) { + ok = rules[i](state, line, endLine, false); + if (ok) { break; } + } + + // set state.tight iff we had an empty line before current tag + // i.e. latest empty line should not count + state.tight = !hasEmptyLines; + + // paragraph might "eat" one newline after it in nested lists + if (state.isEmpty(state.line - 1)) { + hasEmptyLines = true; + } + + line = state.line; + + if (line < endLine && state.isEmpty(line)) { + hasEmptyLines = true; + line++; + + // two empty lines should stop the parser in list mode + if (line < endLine && state.parentType === 'list' && state.isEmpty(line)) { break; } + state.line = line; + } + } +}; + +var TABS_SCAN_RE = /[\n\t]/g; +var NEWLINES_RE = /\r[\n\u0085]|[\u2424\u2028\u0085]/g; +var SPACES_RE = /\u00a0/g; +var NULL_RE = /\u0000/g; + +/** + * ParserBlock.parse(str, options, env, outTokens) + * + * Process input string and push block tokens into `outTokens` + **/ +ParserBlock.prototype.parse = function (src, options, env, outTokens) { + var state, lineStart = 0, lastTabPos = 0; + + if (!src) { return []; } + + // Normalize spaces + src = src.replace(SPACES_RE, ' '); + + // Normalize newlines + src = src.replace(NEWLINES_RE, '\n'); + + // Strin NULL characters + src = src.replace(NULL_RE, ''); + + // Replace tabs with proper number of spaces (1..4) + if (src.indexOf('\t') >= 0) { + src = src.replace(TABS_SCAN_RE, function (match, offset) { + var result; + if (src.charCodeAt(offset) === 0x0A) { + lineStart = offset + 1; + lastTabPos = 0; + return match; + } + result = ' '.slice((offset - lineStart - lastTabPos) % 4); + lastTabPos = offset - lineStart + 1; + return result; + }); + } + + state = new StateBlock( + src, + this, + options, + env, + outTokens + ); + + this.tokenize(state, state.line, state.lineMax); +}; + + +module.exports = ParserBlock; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/parser_core.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/parser_core.js new file mode 100644 index 0000000..6d45f00 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/parser_core.js @@ -0,0 +1,59 @@ +/** internal + * class Core + * + * Top-level rules executor. Glues block/inline parsers and does intermediate + * transformations. + **/ +'use strict'; + + +var Ruler = require('./ruler'); + + +var _rules = [ + [ 'block', require('./rules_core/block') ], + [ 'abbr', require('./rules_core/abbr') ], + [ 'references', require('./rules_core/references') ], + [ 'inline', require('./rules_core/inline') ], + [ 'footnote_tail', require('./rules_core/footnote_tail') ], + [ 'abbr2', require('./rules_core/abbr2') ], + [ 'replacements', require('./rules_core/replacements') ], + [ 'smartquotes', require('./rules_core/smartquotes') ], + [ 'linkify', require('./rules_core/linkify') ] +]; + + +/** + * new Core() + **/ +function Core() { + /** + * Core#ruler -> Ruler + * + * [[Ruler]] instance. Keep configuration of core rules. + **/ + this.ruler = new Ruler(); + + for (var i = 0; i < _rules.length; i++) { + this.ruler.push(_rules[i][0], _rules[i][1]); + } +} + + +/** + * Core.process(state) + * + * Executes core chain rules. + **/ +Core.prototype.process = function (state) { + var i, l, rules; + + rules = this.ruler.getRules(''); + + for (i = 0, l = rules.length; i < l; i++) { + rules[i](state); + } +}; + + +module.exports = Core; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/parser_inline.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/parser_inline.js new file mode 100644 index 0000000..8f555a0 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/parser_inline.js @@ -0,0 +1,156 @@ +/** internal + * class ParserInline + * + * Tokenizes paragraph content. + **/ +'use strict'; + + +var Ruler = require('./ruler'); +var StateInline = require('./rules_inline/state_inline'); +var replaceEntities = require('./common/utils').replaceEntities; + +//////////////////////////////////////////////////////////////////////////////// +// Parser rules + +var _rules = [ + [ 'text', require('./rules_inline/text') ], + [ 'newline', require('./rules_inline/newline') ], + [ 'escape', require('./rules_inline/escape') ], + [ 'backticks', require('./rules_inline/backticks') ], + [ 'del', require('./rules_inline/del') ], + [ 'ins', require('./rules_inline/ins') ], + [ 'mark', require('./rules_inline/mark') ], + [ 'emphasis', require('./rules_inline/emphasis') ], + [ 'sub', require('./rules_inline/sub') ], + [ 'sup', require('./rules_inline/sup') ], + [ 'links', require('./rules_inline/links') ], + [ 'footnote_inline', require('./rules_inline/footnote_inline') ], + [ 'footnote_ref', require('./rules_inline/footnote_ref') ], + [ 'autolink', require('./rules_inline/autolink') ], + [ 'htmltag', require('./rules_inline/htmltag') ], + [ 'entity', require('./rules_inline/entity') ] +]; + + +var BAD_PROTOCOLS = [ 'vbscript', 'javascript', 'file' ]; + +function validateLink(url) { + var str = url.trim().toLowerCase(); + + // Care about digital entities "javascript:alert(1)" + str = replaceEntities(str); + + if (str.indexOf(':') >= 0 && BAD_PROTOCOLS.indexOf(str.split(':')[0]) >= 0) { + return false; + } + return true; +} + + +/** + * new ParserInline() + **/ +function ParserInline() { + /** + * ParserInline#validateLink(url) -> Boolean + * + * Link validation function. CommonMark allows too much in links. By default + * we disable `javascript:` and `vbscript:` schemas. You can change this + * behaviour. + * + * ```javascript + * var md = require('markdown-it')(); + * // enable everything + * md.inline.validateLink = function () { return true; } + * ``` + **/ + this.validateLink = validateLink; + + /** + * ParserInline#ruler -> Ruler + * + * [[Ruler]] instance. Keep configuration of inline rules. + **/ + this.ruler = new Ruler(); + + for (var i = 0; i < _rules.length; i++) { + this.ruler.push(_rules[i][0], _rules[i][1]); + } +} + + +// Skip single token by running all rules in validation mode; +// returns `true` if any rule reported success +// +ParserInline.prototype.skipToken = function (state) { + var i, cached_pos, pos = state.pos, + rules = this.ruler.getRules(''), + len = rules.length; + + if ((cached_pos = state.cacheGet(pos)) > 0) { + state.pos = cached_pos; + return; + } + + for (i = 0; i < len; i++) { + if (rules[i](state, true)) { + state.cacheSet(pos, state.pos); + return; + } + } + + state.pos++; + state.cacheSet(pos, state.pos); +}; + + +// Generate tokens for input range +// +ParserInline.prototype.tokenize = function (state) { + var ok, i, + rules = this.ruler.getRules(''), + len = rules.length, + end = state.posMax; + + while (state.pos < end) { + + // Try all possible rules. + // On success, rule should: + // + // - update `state.pos` + // - update `state.tokens` + // - return true + + for (i = 0; i < len; i++) { + ok = rules[i](state, false); + if (ok) { break; } + } + + if (ok) { + if (state.pos >= end) { break; } + continue; + } + + state.pending += state.src[state.pos++]; + } + + if (state.pending) { + state.pushPending(); + } +}; + + +/** + * ParserInline.parse(str, options, env, outTokens) + * + * Process input string and push inline tokens into `outTokens` + **/ +ParserInline.prototype.parse = function (str, options, env, outTokens) { + var state = new StateInline(str, this, options, env, outTokens); + + this.tokenize(state); +}; + + +module.exports = ParserInline; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/presets/commonmark.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/presets/commonmark.js new file mode 100644 index 0000000..2c4b1e3 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/presets/commonmark.js @@ -0,0 +1,70 @@ +// Commonmark default options + +'use strict'; + + +module.exports = { + options: { + html: true, // Enable HTML tags in source + xhtmlOut: true, // Use '/' to close single tags (
) + breaks: false, // Convert '\n' in paragraphs into
+ langPrefix: 'language-', // CSS language prefix for fenced blocks + linkify: false, // autoconvert URL-like texts to links + + // Enable some language-neutral replacements + quotes beautification + typographer: false, + + // Double + single quotes replacement pairs, when typographer enabled, + // and smartquotes on. Set doubles to '«»' for Russian, '„“' for German. + quotes: '\u201c\u201d\u2018\u2019' /* “”‘’ */, + + // Highlighter function. Should return escaped HTML, + // or '' if input not changed + // + // function (/*str, lang*/) { return ''; } + // + highlight: null, + + maxNesting: 20 // Internal protection, recursion limit + }, + + components: { + + core: { + rules: [ + 'block', + 'inline', + 'references', + 'abbr2' + ] + }, + + block: { + rules: [ + 'blockquote', + 'code', + 'fences', + 'heading', + 'hr', + 'htmlblock', + 'lheading', + 'list', + 'paragraph' + ] + }, + + inline: { + rules: [ + 'autolink', + 'backticks', + 'emphasis', + 'entity', + 'escape', + 'htmltag', + 'links', + 'newline', + 'text' + ] + } + } +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/presets/default.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/presets/default.js new file mode 100644 index 0000000..bb979b8 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/presets/default.js @@ -0,0 +1,78 @@ +// markdown-it default options + +'use strict'; + + +module.exports = { + options: { + html: false, // Enable HTML tags in source + xhtmlOut: false, // Use '/' to close single tags (
) + breaks: false, // Convert '\n' in paragraphs into
+ langPrefix: 'language-', // CSS language prefix for fenced blocks + linkify: false, // autoconvert URL-like texts to links + + // Enable some language-neutral replacements + quotes beautification + typographer: false, + + // Double + single quotes replacement pairs, when typographer enabled, + // and smartquotes on. Set doubles to '«»' for Russian, '„“' for German. + quotes: '\u201c\u201d\u2018\u2019' /* “”‘’ */, + + // Highlighter function. Should return escaped HTML, + // or '' if input not changed + // + // function (/*str, lang*/) { return ''; } + // + highlight: null, + + maxNesting: 20 // Internal protection, recursion limit + }, + + components: { + + core: { + rules: [ + 'block', + 'inline', + 'references', + 'replacements', + 'linkify', + 'smartquotes', + 'references', + 'abbr2', + 'footnote_tail' + ] + }, + + block: { + rules: [ + 'blockquote', + 'code', + 'fences', + 'heading', + 'hr', + 'htmlblock', + 'lheading', + 'list', + 'paragraph', + 'table' + ] + }, + + inline: { + rules: [ + 'autolink', + 'backticks', + 'del', + 'emphasis', + 'entity', + 'escape', + 'footnote_ref', + 'htmltag', + 'links', + 'newline', + 'text' + ] + } + } +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/presets/full.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/presets/full.js new file mode 100644 index 0000000..a0c231c --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/presets/full.js @@ -0,0 +1,38 @@ +// markdown-it `full` options + +'use strict'; + + +module.exports = { + options: { + html: false, // Enable HTML tags in source + xhtmlOut: false, // Use '/' to close single tags (
) + breaks: false, // Convert '\n' in paragraphs into
+ langPrefix: 'language-', // CSS language prefix for fenced blocks + linkify: false, // autoconvert URL-like texts to links + + // Enable some language-neutral replacements + quotes beautification + typographer: false, + + // Double + single quotes replacement pairs, when typographer enabled, + // and smartquotes on. Set doubles to '«»' for Russian, '„“' for German. + quotes: '\u201c\u201d\u2018\u2019' /* “”‘’ */, + + // Highlighter function. Should return escaped HTML, + // or '' if input not changed + // + // function (/*str, lang*/) { return ''; } + // + highlight: null, + + maxNesting: 20 // Internal protection, recursion limit + }, + + components: { + + // Don't restrict core/block/inline rules + core: {}, + block: {}, + inline: {} + } +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/presets/zero.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/presets/zero.js new file mode 100644 index 0000000..07bfe54 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/presets/zero.js @@ -0,0 +1,53 @@ +// "Zero" preset, with nothing enabled. Useful for manual configuring of simple +// modes. For example, to parse bold/italic only. + +'use strict'; + + +module.exports = { + options: { + html: false, // Enable HTML tags in source + xhtmlOut: false, // Use '/' to close single tags (
) + breaks: false, // Convert '\n' in paragraphs into
+ langPrefix: 'language-', // CSS language prefix for fenced blocks + linkify: false, // autoconvert URL-like texts to links + + // Enable some language-neutral replacements + quotes beautification + typographer: false, + + // Double + single quotes replacement pairs, when typographer enabled, + // and smartquotes on. Set doubles to '«»' for Russian, '„“' for German. + quotes: '\u201c\u201d\u2018\u2019' /* “”‘’ */, + + // Highlighter function. Should return escaped HTML, + // or '' if input not changed + // + // function (/*str, lang*/) { return ''; } + // + highlight: null, + + maxNesting: 20 // Internal protection, recursion limit + }, + + components: { + + core: { + rules: [ + 'block', + 'inline' + ] + }, + + block: { + rules: [ + 'paragraph' + ] + }, + + inline: { + rules: [ + 'text' + ] + } + } +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/renderer.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/renderer.js new file mode 100644 index 0000000..019cf3f --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/renderer.js @@ -0,0 +1,445 @@ +/** + * class Renderer + * + * Generates HTML from parsed token stream. Each instance has independent + * copy of rules. Those can be rewritten with ease. Also, you can add new + * rules if you create plugin and adds new token types. + **/ +'use strict'; + + +var assign = require('./common/utils').assign; +var has = require('./common/utils').has; +var unescapeMd = require('./common/utils').unescapeMd; +var replaceEntities = require('./common/utils').replaceEntities; +var escapeHtml = require('./common/utils').escapeHtml; + + +//////////////////////////////////////////////////////////////////////////////// + +var rules = {}; + + + +rules.blockquote_open = function (/* tokens, idx, options, env */) { + return '

\n'; +}; +rules.blockquote_close = function (/* tokens, idx, options, env */) { + return '
\n'; +}; + + +rules.code = function (tokens, idx /*, options, env */) { + if (tokens[idx].block) { + return '
' + escapeHtml(tokens[idx].content) + '
\n'; + } + + return '' + escapeHtml(tokens[idx].content) + ''; +}; + + +rules.fence = function (tokens, idx, options, env, self) { + var token = tokens[idx]; + var langClass = ''; + var langPrefix = options.langPrefix; + var langName = '', fenceName; + var highlighted; + + if (token.params) { + + // + // ```foo bar + // + // Try custom renderer "foo" first. That will simplify overwrite + // for diagrams, latex, and any other fenced block with custom look + // + + fenceName = token.params.split(/\s+/g)[0]; + + if (has(self.rules.fence_custom, fenceName)) { + return self.rules.fence_custom[fenceName](tokens, idx, options, env, self); + } + + langName = escapeHtml(replaceEntities(unescapeMd(fenceName))); + langClass = ' class="' + langPrefix + langName + '"'; + } + + if (options.highlight) { + highlighted = options.highlight(token.content, langName) || escapeHtml(token.content); + } else { + highlighted = escapeHtml(token.content); + } + + + return '
'
+        + highlighted
+        + '
\n'; +}; + +rules.fence_custom = {}; + +rules.heading_open = function (tokens, idx /*, options, env */) { + return ''; +}; +rules.heading_close = function (tokens, idx /*, options, env */) { + return '\n'; +}; + + +rules.hr = function (tokens, idx, options /*, env */) { + return (options.xhtmlOut ? '
\n' : '
\n'); +}; + + +rules.bullet_list_open = function (/* tokens, idx, options, env */) { + return '\n'; +}; +rules.list_item_open = function (tokens, idx /*, options, env */) { + var next = tokens[idx + 1]; + if ((next.type === 'list_item_close') || + (next.type === 'paragraph_open' && next.tight)) { + return '
  • '; + } + return '
  • \n'; +}; +rules.list_item_close = function (/* tokens, idx, options, env */) { + return '
  • \n'; +}; +rules.ordered_list_open = function (tokens, idx /*, options, env */) { + if (tokens[idx].order > 1) { + return '
      \n'; + } + return '
        \n'; +}; +rules.ordered_list_close = function (/* tokens, idx, options, env */) { + return '
      \n'; +}; + + +rules.paragraph_open = function (tokens, idx /*, options, env */) { + return tokens[idx].tight ? '' : '

      '; +}; +rules.paragraph_close = function (tokens, idx /*, options, env */) { + // We have 2 cases of "hidden" paragraphs + // + // 1. In tight lists + // 2. When content was stripped (reference definition, for example) + // + if (tokens[idx].tight === true) { + if (!tokens[idx - 1].content) { + return ''; + } + if (tokens[idx + 1].type.slice(-5) === 'close') { + return ''; + } + return '\n'; + } + return '

      \n'; +}; + + +rules.link_open = function (tokens, idx /*, options, env */) { + var title = tokens[idx].title ? (' title="' + escapeHtml(replaceEntities(tokens[idx].title)) + '"') : ''; + var target = tokens[idx].target ? (' target="' + escapeHtml(tokens[idx].target) + '"') : ''; + return ''; +}; +rules.link_close = function (/* tokens, idx, options, env */) { + return ''; +}; + + +rules.image = function (tokens, idx, options, env, self) { + var src = ' src="' + escapeHtml(tokens[idx].src) + '"'; + var title = tokens[idx].title ? (' title="' + escapeHtml(replaceEntities(tokens[idx].title)) + '"') : ''; + var alt = ' alt="' + self.renderInlineAsText(tokens[idx].tokens, options, env) + '"'; + var suffix = options.xhtmlOut ? ' /' : ''; + return ''; +}; + + +rules.table_open = function (/* tokens, idx, options, env */) { + return '\n'; +}; +rules.table_close = function (/* tokens, idx, options, env */) { + return '
      \n'; +}; +rules.thead_open = function (/* tokens, idx, options, env */) { + return '\n'; +}; +rules.thead_close = function (/* tokens, idx, options, env */) { + return '\n'; +}; +rules.tbody_open = function (/* tokens, idx, options, env */) { + return '\n'; +}; +rules.tbody_close = function (/* tokens, idx, options, env */) { + return '\n'; +}; +rules.tr_open = function (/* tokens, idx, options, env */) { + return ''; +}; +rules.tr_close = function (/* tokens, idx, options, env */) { + return '\n'; +}; +rules.th_open = function (tokens, idx /*, options, env */) { + if (tokens[idx].align) { + return ''; + } + return ''; +}; +rules.th_close = function (/* tokens, idx, options, env */) { + return ''; +}; +rules.td_open = function (tokens, idx /*, options, env */) { + if (tokens[idx].align) { + return ''; + } + return ''; +}; +rules.td_close = function (/* tokens, idx, options, env */) { + return ''; +}; + + +rules.strong_open = function (/* tokens, idx, options, env */) { + return ''; +}; +rules.strong_close = function (/* tokens, idx, options, env */) { + return ''; +}; +rules.em_open = function (/* tokens, idx, options, env */) { + return ''; +}; +rules.em_close = function (/* tokens, idx, options, env */) { + return ''; +}; + + +rules.del_open = function (/* tokens, idx, options, env */) { + return ''; +}; +rules.del_close = function (/* tokens, idx, options, env */) { + return ''; +}; + + +rules.ins_open = function (/* tokens, idx, options, env */) { + return ''; +}; +rules.ins_close = function (/* tokens, idx, options, env */) { + return ''; +}; + + +rules.mark_open = function (/* tokens, idx, options, env */) { + return ''; +}; +rules.mark_close = function (/* tokens, idx, options, env */) { + return ''; +}; + + +rules.sub = function (tokens, idx /*, options, env */) { + return '' + escapeHtml(tokens[idx].content) + ''; +}; +rules.sup = function (tokens, idx /*, options, env */) { + return '' + escapeHtml(tokens[idx].content) + ''; +}; + + +rules.hardbreak = function (tokens, idx, options /*, env */) { + return options.xhtmlOut ? '
      \n' : '
      \n'; +}; +rules.softbreak = function (tokens, idx, options /*, env */) { + return options.breaks ? (options.xhtmlOut ? '
      \n' : '
      \n') : '\n'; +}; + + +rules.text = function (tokens, idx /*, options, env */) { + return escapeHtml(tokens[idx].content); +}; + + +rules.htmlblock = function (tokens, idx /*, options, env */) { + return tokens[idx].content; +}; +rules.htmltag = function (tokens, idx /*, options, env */) { + return tokens[idx].content; +}; + + +rules.abbr_open = function (tokens, idx /*, options, env */) { + return ''; +}; +rules.abbr_close = function (/* tokens, idx, options, env */) { + return ''; +}; + + +rules.footnote_ref = function (tokens, idx) { + var n = Number(tokens[idx].id + 1).toString(); + var id = 'fnref' + n; + if (tokens[idx].subId > 0) { + id += ':' + tokens[idx].subId; + } + return '[' + n + ']'; +}; +rules.footnote_block_open = function (tokens, idx, options) { + return (options.xhtmlOut ? '
      \n' : '
      \n') + + '
      \n' + + '
        \n'; +}; +rules.footnote_block_close = function () { + return '
      \n
      \n'; +}; +rules.footnote_open = function (tokens, idx) { + var id = Number(tokens[idx].id + 1).toString(); + return '
    1. '; +}; +rules.footnote_close = function () { + return '
    2. \n'; +}; +rules.footnote_anchor = function (tokens, idx) { + var n = Number(tokens[idx].id + 1).toString(); + var id = 'fnref' + n; + if (tokens[idx].subId > 0) { + id += ':' + tokens[idx].subId; + } + return ' \u21a9'; /* ↩ */ +}; + + +rules.dl_open = function() { + return '
      \n'; +}; +rules.dt_open = function() { + return '
      '; +}; +rules.dd_open = function() { + return '
      '; +}; +rules.dl_close = function() { + return '
      \n'; +}; +rules.dt_close = function() { + return '\n'; +}; +rules.dd_close = function() { + return '\n'; +}; + + +/** + * new Renderer() + * + * Creates new [[Renderer]] instance and fill [[Renderer#rules]] with defaults. + **/ +function Renderer() { + + /** + * Renderer#rules -> Object + * + * Contains render rules for tokens. Can be updated and extended. + * + * ##### Example + * + * ```javascript + * var md = require('markdown-it')(); + * + * md.renderer.rules.strong_open = function () { return ''; }; + * md.renderer.rules.strong_close = function () { return ''; }; + * + * var result = md.renderInline(...); + * ``` + * + * Each rule is called as independed static function with fixed signature: + * + * ```javascript + * function my_token_render(tokens, idx, options, env, self) { + * // ... + * return renderedHTML; + * } + * ``` + * + * See [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.js) + * for more details and examples. + **/ + this.rules = assign({}, rules); +} + + +/** + * Renderer.renderInline(tokens, options, env) -> String + * - tokens (Array): list on block tokens to renter + * - options (Object): params of parser instance + * - env (Object): additional data from parsed input (references, for example) + * + * The same as [[Renderer.render]], but for single token of `inline` type. + **/ +Renderer.prototype.renderInline = function (tokens, options, env) { + var result = '', + _rules = this.rules; + + for (var i = 0, len = tokens.length; i < len; i++) { + result += _rules[tokens[i].type](tokens, i, options, env, this); + } + + return result; +}; + + +/** internal + * Renderer.renderInlineAsText(tokens, options, env) -> String + * - tokens (Array): list on block tokens to renter + * - options (Object): params of parser instance + * - env (Object): additional data from parsed input (references, for example) + * + * Special kludge for image `alt` attributes to conform CommonMark spec. + * Don't try to use it! Spec requires to show `alt` content with stripped markup, + * instead of simple escaping. + **/ +Renderer.prototype.renderInlineAsText = function (tokens, options, env) { + var result = '', + _rules = this.rules; + + for (var i = 0, len = tokens.length; i < len; i++) { + if (tokens[i].type === 'text') { + result += _rules.text(tokens, i, options, env, this); + } else if (tokens[i].type === 'image') { + result += this.renderInlineAsText(tokens[i].tokens, options, env); + } + } + + return result; +}; + + +/** + * Renderer.render(tokens, options, env) -> String + * - tokens (Array): list on block tokens to renter + * - options (Object): params of parser instance + * - env (Object): additional data from parsed input (references, for example) + * + * Takes token stream and generates HTML. Probably, you will never need to call + * this method directly. + **/ +Renderer.prototype.render = function (tokens, options, env) { + var i, len, + result = '', + _rules = this.rules; + + for (i = 0, len = tokens.length; i < len; i++) { + if (tokens[i].type === 'inline') { + result += this.renderInline(tokens[i].children, options, env); + } else { + result += _rules[tokens[i].type](tokens, i, options, env, this); + } + } + + return result; +}; + +module.exports = Renderer; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/ruler.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/ruler.js new file mode 100644 index 0000000..b57e9fc --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/ruler.js @@ -0,0 +1,342 @@ +/** + * class Ruler + * + * Helper class, used by [[MarkdownIt#core]], [[MarkdownIt#block]] and + * [[MarkdownIt#inline]] to manage sequences of functions (rules): + * + * - keep rules in defined order + * - assign the name to each rule + * - enable/disable rules + * - add/replace rules + * - allow assign rules to additional named chains (in the same) + * - cacheing lists of active rules + * + * You will not need use this class directly until write plugins. For simple + * rules control use [[MarkdownIt.disable]], [[MarkdownIt.enable]] and + * [[MarkdownIt.use]]. + **/ +'use strict'; + + +/** + * new Ruler() + **/ +function Ruler() { + // List of added rules. Each element is: + // + // { + // name: XXX, + // enabled: Boolean, + // fn: Function(), + // alt: [ name2, name3 ] + // } + // + this.__rules__ = []; + + // Cached rule chains. + // + // First level - chain name, '' for default. + // Second level - diginal anchor for fast filtering by charcodes. + // + this.__cache__ = null; +} + +//////////////////////////////////////////////////////////////////////////////// +// Helper methods, should not be used directly + + +// Find rule index by name +// +Ruler.prototype.__find__ = function (name) { + for (var i = 0; i < this.__rules__.length; i++) { + if (this.__rules__[i].name === name) { + return i; + } + } + return -1; +}; + + +// Build rules lookup cache +// +Ruler.prototype.__compile__ = function () { + var self = this; + var chains = [ '' ]; + + // collect unique names + self.__rules__.forEach(function (rule) { + if (!rule.enabled) { return; } + + rule.alt.forEach(function (altName) { + if (chains.indexOf(altName) < 0) { + chains.push(altName); + } + }); + }); + + self.__cache__ = {}; + + chains.forEach(function (chain) { + self.__cache__[chain] = []; + self.__rules__.forEach(function (rule) { + if (!rule.enabled) { return; } + + if (chain && rule.alt.indexOf(chain) < 0) { return; } + + self.__cache__[chain].push(rule.fn); + }); + }); +}; + + +/** + * Ruler.at(name, fn [, options]) + * - name (String): rule name to replace. + * - fn (Function): new rule function. + * - options (Object): new rule options (not mandatory). + * + * Replace rule by name with new function & options. Throws error if name not + * found. + * + * ##### Options: + * + * - __alt__ - array with names of "alternate" chains. + * + * ##### Example + * + * Replace existing typorgapher replacement rule with new one: + * + * ```javascript + * var md = require('markdown-it')(); + * + * md.core.ruler.at('replacements', function replace(state) { + * //... + * }); + * ``` + **/ +Ruler.prototype.at = function (name, fn, options) { + var index = this.__find__(name); + var opt = options || {}; + + if (index === -1) { throw new Error('Parser rule not found: ' + name); } + + this.__rules__[index].fn = fn; + this.__rules__[index].alt = opt.alt || []; + this.__cache__ = null; +}; + + +/** + * Ruler.before(beforeName, ruleName, fn [, options]) + * - beforeName (String): new rule will be added before this one. + * - ruleName (String): name of added rule. + * - fn (Function): rule function. + * - options (Object): rule options (not mandatory). + * + * Add new rule to chain before one with given name. See also + * [[Ruler.after]], [[Ruler.push]]. + * + * ##### Options: + * + * - __alt__ - array with names of "alternate" chains. + * + * ##### Example + * + * ```javascript + * var md = require('markdown-it')(); + * + * md.block.ruler.before('paragraph', 'my_rule', function replace(state) { + * //... + * }); + * ``` + **/ +Ruler.prototype.before = function (beforeName, ruleName, fn, options) { + var index = this.__find__(beforeName); + var opt = options || {}; + + if (index === -1) { throw new Error('Parser rule not found: ' + beforeName); } + + this.__rules__.splice(index, 0, { + name: ruleName, + enabled: true, + fn: fn, + alt: opt.alt || [] + }); + + this.__cache__ = null; +}; + + +/** + * Ruler.after(afterName, ruleName, fn [, options]) + * - afterName (String): new rule will be added after this one. + * - ruleName (String): name of added rule. + * - fn (Function): rule function. + * - options (Object): rule options (not mandatory). + * + * Add new rule to chain after one with given name. See also + * [[Ruler.before]], [[Ruler.push]]. + * + * ##### Options: + * + * - __alt__ - array with names of "alternate" chains. + * + * ##### Example + * + * ```javascript + * var md = require('markdown-it')(); + * + * md.inline.ruler.after('text', 'my_rule', function replace(state) { + * //... + * }); + * ``` + **/ +Ruler.prototype.after = function (afterName, ruleName, fn, options) { + var index = this.__find__(afterName); + var opt = options || {}; + + if (index === -1) { throw new Error('Parser rule not found: ' + afterName); } + + this.__rules__.splice(index + 1, 0, { + name: ruleName, + enabled: true, + fn: fn, + alt: opt.alt || [] + }); + + this.__cache__ = null; +}; + +/** + * Ruler.push(ruleName, fn [, options]) + * - ruleName (String): name of added rule. + * - fn (Function): rule function. + * - options (Object): rule options (not mandatory). + * + * Push new rule to the end of chain. See also + * [[Ruler.before]], [[Ruler.after]]. + * + * ##### Options: + * + * - __alt__ - array with names of "alternate" chains. + * + * ##### Example + * + * ```javascript + * var md = require('markdown-it')(); + * + * md.core.ruler.push('emphasis', 'my_rule', function replace(state) { + * //... + * }); + * ``` + **/ +Ruler.prototype.push = function (ruleName, fn, options) { + var opt = options || {}; + + this.__rules__.push({ + name: ruleName, + enabled: true, + fn: fn, + alt: opt.alt || [] + }); + + this.__cache__ = null; +}; + + +/** + * Ruler.enable(list [, ignoreInvalid]) + * - list (String|Array): list of rule names to enable. + * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found. + * + * Enable rules with given names. If any rule name not found - throw Error. + * Errors can be disabled by second param. + * + * See also [[Ruler.disable]], [[Ruler.enableOnly]]. + **/ +Ruler.prototype.enable = function (list, ignoreInvalid) { + if (!Array.isArray(list)) { list = [ list ]; } + + // Search by name and enable + list.forEach(function (name) { + var idx = this.__find__(name); + + if (idx < 0) { + if (ignoreInvalid) { return; } + throw new Error('Rules manager: invalid rule name ' + name); + } + this.__rules__[idx].enabled = true; + }, this); + + this.__cache__ = null; +}; + + +/** + * Ruler.enableOnly(list [, ignoreInvalid]) + * - list (String|Array): list of rule names to enable (whitelist). + * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found. + * + * Enable rules with given names, and disable everything else. If any rule name + * not found - throw Error. Errors can be disabled by second param. + * + * See also [[Ruler.disable]], [[Ruler.enable]]. + **/ +Ruler.prototype.enableOnly = function (list, ignoreInvalid) { + if (!Array.isArray(list)) { list = [ list ]; } + + this.__rules__.forEach(function (rule) { rule.enabled = false; }); + + this.enable(list, ignoreInvalid); +}; + + +/** + * Ruler.disable(list [, ignoreInvalid]) + * - list (String|Array): list of rule names to disable. + * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found. + * + * Disable rules with given names. If any rule name not found - throw Error. + * Errors can be disabled by second param. + * + * See also [[Ruler.enable]], [[Ruler.enableOnly]]. + **/ +Ruler.prototype.disable = function (list, ignoreInvalid) { + if (!Array.isArray(list)) { + list = [ list ]; + } + + // Search by name and disable + list.forEach(function (name) { + var idx = this.__find__(name); + + if (idx < 0) { + if (ignoreInvalid) { return; } + throw new Error('Rules manager: invalid rule name ' + name); + } + this.__rules__[idx].enabled = false; + }, this); + + this.__cache__ = null; +}; + + +/** + * Ruler.getRules(chainName) -> Array + * + * Return array of active functions (rules) for given chain name. It analyzes + * rules configuration, compiles caches if not exists and returns result. + * + * Default chain name is `''` (empty string). It can't be skipped. That's + * done intentionally, to keep signature monomorphic for high speed. + **/ +Ruler.prototype.getRules = function (chainName) { + if (this.__cache__ === null) { + this.__compile__(); + } + + // Chain can be empty, if rules disabled. But we still have to return Array. + return this.__cache__[chainName] || []; +}; + +module.exports = Ruler; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/blockquote.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/blockquote.js new file mode 100644 index 0000000..ca7b026 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/blockquote.js @@ -0,0 +1,133 @@ +// Block quotes + +'use strict'; + + +module.exports = function blockquote(state, startLine, endLine, silent) { + var nextLine, lastLineEmpty, oldTShift, oldBMarks, oldIndent, oldParentType, lines, + terminatorRules, + i, l, terminate, + pos = state.bMarks[startLine] + state.tShift[startLine], + max = state.eMarks[startLine]; + + if (pos > max) { return false; } + + // check the block quote marker + if (state.src.charCodeAt(pos++) !== 0x3E/* > */) { return false; } + + if (state.level >= state.options.maxNesting) { return false; } + + // we know that it's going to be a valid blockquote, + // so no point trying to find the end of it in silent mode + if (silent) { return true; } + + // skip one optional space after '>' + if (state.src.charCodeAt(pos) === 0x20) { pos++; } + + oldIndent = state.blkIndent; + state.blkIndent = 0; + + oldBMarks = [ state.bMarks[startLine] ]; + state.bMarks[startLine] = pos; + + // check if we have an empty blockquote + pos = pos < max ? state.skipSpaces(pos) : pos; + lastLineEmpty = pos >= max; + + oldTShift = [ state.tShift[startLine] ]; + state.tShift[startLine] = pos - state.bMarks[startLine]; + + terminatorRules = state.parser.ruler.getRules('blockquote'); + + // Search the end of the block + // + // Block ends with either: + // 1. an empty line outside: + // ``` + // > test + // + // ``` + // 2. an empty line inside: + // ``` + // > + // test + // ``` + // 3. another tag + // ``` + // > test + // - - - + // ``` + for (nextLine = startLine + 1; nextLine < endLine; nextLine++) { + pos = state.bMarks[nextLine] + state.tShift[nextLine]; + max = state.eMarks[nextLine]; + + if (pos >= max) { + // Case 1: line is not inside the blockquote, and this line is empty. + break; + } + + if (state.src.charCodeAt(pos++) === 0x3E/* > */) { + // This line is inside the blockquote. + + // skip one optional space after '>' + if (state.src.charCodeAt(pos) === 0x20) { pos++; } + + oldBMarks.push(state.bMarks[nextLine]); + state.bMarks[nextLine] = pos; + + pos = pos < max ? state.skipSpaces(pos) : pos; + lastLineEmpty = pos >= max; + + oldTShift.push(state.tShift[nextLine]); + state.tShift[nextLine] = pos - state.bMarks[nextLine]; + continue; + } + + // Case 2: line is not inside the blockquote, and the last line was empty. + if (lastLineEmpty) { break; } + + // Case 3: another tag found. + terminate = false; + for (i = 0, l = terminatorRules.length; i < l; i++) { + if (terminatorRules[i](state, nextLine, endLine, true)) { + terminate = true; + break; + } + } + if (terminate) { break; } + + oldBMarks.push(state.bMarks[nextLine]); + oldTShift.push(state.tShift[nextLine]); + + // A negative number means that this is a paragraph continuation; + // + // Any negative number will do the job here, but it's better for it + // to be large enough to make any bugs obvious. + state.tShift[nextLine] = -1337; + } + + oldParentType = state.parentType; + state.parentType = 'blockquote'; + state.tokens.push({ + type: 'blockquote_open', + lines: lines = [ startLine, 0 ], + level: state.level++ + }); + state.parser.tokenize(state, startLine, nextLine); + state.tokens.push({ + type: 'blockquote_close', + level: --state.level + }); + state.parentType = oldParentType; + lines[1] = state.line; + + // Restore original tShift; this might not be necessary since the parser + // has already been here, but just to make sure we can do that. + for (i = 0; i < oldTShift.length; i++) { + state.bMarks[i + startLine] = oldBMarks[i]; + state.tShift[i + startLine] = oldTShift[i]; + } + state.blkIndent = oldIndent; + + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/code.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/code.js new file mode 100644 index 0000000..77d6f90 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/code.js @@ -0,0 +1,36 @@ +// Code block (4 spaces padded) + +'use strict'; + + +module.exports = function code(state, startLine, endLine/*, silent*/) { + var nextLine, last; + + if (state.tShift[startLine] - state.blkIndent < 4) { return false; } + + last = nextLine = startLine + 1; + + while (nextLine < endLine) { + if (state.isEmpty(nextLine)) { + nextLine++; + continue; + } + if (state.tShift[nextLine] - state.blkIndent >= 4) { + nextLine++; + last = nextLine; + continue; + } + break; + } + + state.line = nextLine; + state.tokens.push({ + type: 'code', + content: state.getLines(startLine, last, 4 + state.blkIndent, true), + block: true, + lines: [ startLine, state.line ], + level: state.level + }); + + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/deflist.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/deflist.js new file mode 100644 index 0000000..7fde6cc --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/deflist.js @@ -0,0 +1,207 @@ +// Definition lists + +'use strict'; + + +// Search `[:~][\n ]`, returns next pos after marker on success +// or -1 on fail. +function skipMarker(state, line) { + var pos, marker, + start = state.bMarks[line] + state.tShift[line], + max = state.eMarks[line]; + + if (start >= max) { return -1; } + + // Check bullet + marker = state.src.charCodeAt(start++); + if (marker !== 0x7E/* ~ */ && marker !== 0x3A/* : */) { return -1; } + + pos = state.skipSpaces(start); + + // require space after ":" + if (start === pos) { return -1; } + + // no empty definitions, e.g. " : " + if (pos >= max) { return -1; } + + return pos; +} + +function markTightParagraphs(state, idx) { + var i, l, + level = state.level + 2; + + for (i = idx + 2, l = state.tokens.length - 2; i < l; i++) { + if (state.tokens[i].level === level && state.tokens[i].type === 'paragraph_open') { + state.tokens[i + 2].tight = true; + state.tokens[i].tight = true; + i += 2; + } + } +} + +module.exports = function deflist(state, startLine, endLine, silent) { + var contentStart, + ddLine, + dtLine, + itemLines, + listLines, + listTokIdx, + nextLine, + oldIndent, + oldDDIndent, + oldParentType, + oldTShift, + oldTight, + prevEmptyEnd, + tight; + + if (silent) { + // quirk: validation mode validates a dd block only, not a whole deflist + if (state.ddIndent < 0) { return false; } + return skipMarker(state, startLine) >= 0; + } + + nextLine = startLine + 1; + if (state.isEmpty(nextLine)) { + if (++nextLine > endLine) { return false; } + } + + if (state.tShift[nextLine] < state.blkIndent) { return false; } + contentStart = skipMarker(state, nextLine); + if (contentStart < 0) { return false; } + + if (state.level >= state.options.maxNesting) { return false; } + + // Start list + listTokIdx = state.tokens.length; + + state.tokens.push({ + type: 'dl_open', + lines: listLines = [ startLine, 0 ], + level: state.level++ + }); + + // + // Iterate list items + // + + dtLine = startLine; + ddLine = nextLine; + + // One definition list can contain multiple DTs, + // and one DT can be followed by multiple DDs. + // + // Thus, there is two loops here, and label is + // needed to break out of the second one + // + /*eslint no-labels:0,block-scoped-var:0*/ + OUTER: + for (;;) { + tight = true; + prevEmptyEnd = false; + + state.tokens.push({ + type: 'dt_open', + lines: [ dtLine, dtLine ], + level: state.level++ + }); + state.tokens.push({ + type: 'inline', + content: state.getLines(dtLine, dtLine + 1, state.blkIndent, false).trim(), + level: state.level + 1, + lines: [ dtLine, dtLine ], + children: [] + }); + state.tokens.push({ + type: 'dt_close', + level: --state.level + }); + + for (;;) { + state.tokens.push({ + type: 'dd_open', + lines: itemLines = [ nextLine, 0 ], + level: state.level++ + }); + + oldTight = state.tight; + oldDDIndent = state.ddIndent; + oldIndent = state.blkIndent; + oldTShift = state.tShift[ddLine]; + oldParentType = state.parentType; + state.blkIndent = state.ddIndent = state.tShift[ddLine] + 2; + state.tShift[ddLine] = contentStart - state.bMarks[ddLine]; + state.tight = true; + state.parentType = 'deflist'; + + state.parser.tokenize(state, ddLine, endLine, true); + + // If any of list item is tight, mark list as tight + if (!state.tight || prevEmptyEnd) { + tight = false; + } + // Item become loose if finish with empty line, + // but we should filter last element, because it means list finish + prevEmptyEnd = (state.line - ddLine) > 1 && state.isEmpty(state.line - 1); + + state.tShift[ddLine] = oldTShift; + state.tight = oldTight; + state.parentType = oldParentType; + state.blkIndent = oldIndent; + state.ddIndent = oldDDIndent; + + state.tokens.push({ + type: 'dd_close', + level: --state.level + }); + + itemLines[1] = nextLine = state.line; + + if (nextLine >= endLine) { break OUTER; } + + if (state.tShift[nextLine] < state.blkIndent) { break OUTER; } + contentStart = skipMarker(state, nextLine); + if (contentStart < 0) { break; } + + ddLine = nextLine; + + // go to the next loop iteration: + // insert DD tag and repeat checking + } + + if (nextLine >= endLine) { break; } + dtLine = nextLine; + + if (state.isEmpty(dtLine)) { break; } + if (state.tShift[dtLine] < state.blkIndent) { break; } + + ddLine = dtLine + 1; + if (ddLine >= endLine) { break; } + if (state.isEmpty(ddLine)) { ddLine++; } + if (ddLine >= endLine) { break; } + + if (state.tShift[ddLine] < state.blkIndent) { break; } + contentStart = skipMarker(state, ddLine); + if (contentStart < 0) { break; } + + // go to the next loop iteration: + // insert DT and DD tags and repeat checking + } + + // Finilize list + state.tokens.push({ + type: 'dl_close', + level: --state.level + }); + listLines[1] = nextLine; + + state.line = nextLine; + + // mark paragraphs tight if needed + if (tight) { + markTightParagraphs(state, listTokIdx); + } + + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/fences.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/fences.js new file mode 100644 index 0000000..186cdbb --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/fences.js @@ -0,0 +1,91 @@ +// fences (``` lang, ~~~ lang) + +'use strict'; + + +module.exports = function fences(state, startLine, endLine, silent) { + var marker, len, params, nextLine, mem, + haveEndMarker = false, + pos = state.bMarks[startLine] + state.tShift[startLine], + max = state.eMarks[startLine]; + + if (pos + 3 > max) { return false; } + + marker = state.src.charCodeAt(pos); + + if (marker !== 0x7E/* ~ */ && marker !== 0x60 /* ` */) { + return false; + } + + // scan marker length + mem = pos; + pos = state.skipChars(pos, marker); + + len = pos - mem; + + if (len < 3) { return false; } + + params = state.src.slice(pos, max).trim(); + + if (params.indexOf('`') >= 0) { return false; } + + // Since start is found, we can report success here in validation mode + if (silent) { return true; } + + // search end of block + nextLine = startLine; + + for (;;) { + nextLine++; + if (nextLine >= endLine) { + // unclosed block should be autoclosed by end of document. + // also block seems to be autoclosed by end of parent + break; + } + + pos = mem = state.bMarks[nextLine] + state.tShift[nextLine]; + max = state.eMarks[nextLine]; + + if (pos < max && state.tShift[nextLine] < state.blkIndent) { + // non-empty line with negative indent should stop the list: + // - ``` + // test + break; + } + + if (state.src.charCodeAt(pos) !== marker) { continue; } + + if (state.tShift[nextLine] - state.blkIndent >= 4) { + // closing fence should be indented less than 4 spaces + continue; + } + + pos = state.skipChars(pos, marker); + + // closing code fence must be at least as long as the opening one + if (pos - mem < len) { continue; } + + // make sure tail has spaces only + pos = state.skipSpaces(pos); + + if (pos < max) { continue; } + + haveEndMarker = true; + // found! + break; + } + + // If a fence has heading spaces, they should be removed from its inner block + len = state.tShift[startLine]; + + state.line = nextLine + (haveEndMarker ? 1 : 0); + state.tokens.push({ + type: 'fence', + params: params, + content: state.getLines(startLine + 1, nextLine, len, true), + lines: [ startLine, state.line ], + level: state.level + }); + + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/footnote.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/footnote.js new file mode 100644 index 0000000..7c8c5e4 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/footnote.js @@ -0,0 +1,67 @@ +// Process footnote reference list + +'use strict'; + + +module.exports = function footnote(state, startLine, endLine, silent) { + var oldBMark, oldTShift, oldParentType, pos, label, + start = state.bMarks[startLine] + state.tShift[startLine], + max = state.eMarks[startLine]; + + // line should be at least 5 chars - "[^x]:" + if (start + 4 > max) { return false; } + + if (state.src.charCodeAt(start) !== 0x5B/* [ */) { return false; } + if (state.src.charCodeAt(start + 1) !== 0x5E/* ^ */) { return false; } + if (state.level >= state.options.maxNesting) { return false; } + + for (pos = start + 2; pos < max; pos++) { + if (state.src.charCodeAt(pos) === 0x20) { return false; } + if (state.src.charCodeAt(pos) === 0x5D /* ] */) { + break; + } + } + + if (pos === start + 2) { return false; } // no empty footnote labels + if (pos + 1 >= max || state.src.charCodeAt(++pos) !== 0x3A /* : */) { return false; } + if (silent) { return true; } + pos++; + + if (!state.env.footnotes) { state.env.footnotes = {}; } + if (!state.env.footnotes.refs) { state.env.footnotes.refs = {}; } + label = state.src.slice(start + 2, pos - 2); + state.env.footnotes.refs[':' + label] = -1; + + state.tokens.push({ + type: 'footnote_reference_open', + label: label, + level: state.level++ + }); + + oldBMark = state.bMarks[startLine]; + oldTShift = state.tShift[startLine]; + oldParentType = state.parentType; + state.tShift[startLine] = state.skipSpaces(pos) - pos; + state.bMarks[startLine] = pos; + state.blkIndent += 4; + state.parentType = 'footnote'; + + if (state.tShift[startLine] < state.blkIndent) { + state.tShift[startLine] += state.blkIndent; + state.bMarks[startLine] -= state.blkIndent; + } + + state.parser.tokenize(state, startLine, endLine, true); + + state.parentType = oldParentType; + state.blkIndent -= 4; + state.tShift[startLine] = oldTShift; + state.bMarks[startLine] = oldBMark; + + state.tokens.push({ + type: 'footnote_reference_close', + level: --state.level + }); + + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/heading.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/heading.js new file mode 100644 index 0000000..f5ef6a2 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/heading.js @@ -0,0 +1,58 @@ +// heading (#, ##, ...) + +'use strict'; + + +module.exports = function heading(state, startLine, endLine, silent) { + var ch, level, tmp, + pos = state.bMarks[startLine] + state.tShift[startLine], + max = state.eMarks[startLine]; + + if (pos >= max) { return false; } + + ch = state.src.charCodeAt(pos); + + if (ch !== 0x23/* # */ || pos >= max) { return false; } + + // count heading level + level = 1; + ch = state.src.charCodeAt(++pos); + while (ch === 0x23/* # */ && pos < max && level <= 6) { + level++; + ch = state.src.charCodeAt(++pos); + } + + if (level > 6 || (pos < max && ch !== 0x20/* space */)) { return false; } + + if (silent) { return true; } + + // Let's cut tails like ' ### ' from the end of string + + max = state.skipCharsBack(max, 0x20, pos); // space + tmp = state.skipCharsBack(max, 0x23, pos); // # + if (tmp > pos && state.src.charCodeAt(tmp - 1) === 0x20/* space */) { + max = tmp; + } + + state.line = startLine + 1; + + state.tokens.push({ type: 'heading_open', + hLevel: level, + lines: [ startLine, state.line ], + level: state.level + }); + + // only if header is not empty + if (pos < max) { + state.tokens.push({ + type: 'inline', + content: state.src.slice(pos, max).trim(), + level: state.level + 1, + lines: [ startLine, state.line ], + children: [] + }); + } + state.tokens.push({ type: 'heading_close', hLevel: level, level: state.level }); + + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/hr.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/hr.js new file mode 100644 index 0000000..2fbbc07 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/hr.js @@ -0,0 +1,45 @@ +// Horizontal rule + +'use strict'; + + +module.exports = function hr(state, startLine, endLine, silent) { + var marker, cnt, ch, + pos = state.bMarks[startLine], + max = state.eMarks[startLine]; + + pos += state.tShift[startLine]; + + if (pos > max) { return false; } + + marker = state.src.charCodeAt(pos++); + + // Check hr marker + if (marker !== 0x2A/* * */ && + marker !== 0x2D/* - */ && + marker !== 0x5F/* _ */) { + return false; + } + + // markers can be mixed with spaces, but there should be at least 3 one + + cnt = 1; + while (pos < max) { + ch = state.src.charCodeAt(pos++); + if (ch !== marker && ch !== 0x20/* space */) { return false; } + if (ch === marker) { cnt++; } + } + + if (cnt < 3) { return false; } + + if (silent) { return true; } + + state.line = startLine + 1; + state.tokens.push({ + type: 'hr', + lines: [ startLine, state.line ], + level: state.level + }); + + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/htmlblock.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/htmlblock.js new file mode 100644 index 0000000..c585193 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/htmlblock.js @@ -0,0 +1,74 @@ +// HTML block + +'use strict'; + + +var block_names = require('../common/html_blocks'); + + +var HTML_TAG_OPEN_RE = /^<([a-zA-Z]{1,15})[\s\/>]/; +var HTML_TAG_CLOSE_RE = /^<\/([a-zA-Z]{1,15})[\s>]/; + +function isLetter(ch) { + /*eslint no-bitwise:0*/ + var lc = ch | 0x20; // to lower case + return (lc >= 0x61/* a */) && (lc <= 0x7a/* z */); +} + +module.exports = function htmlblock(state, startLine, endLine, silent) { + var ch, match, nextLine, + pos = state.bMarks[startLine], + max = state.eMarks[startLine], + shift = state.tShift[startLine]; + + pos += shift; + + if (!state.options.html) { return false; } + + if (shift > 3 || pos + 2 >= max) { return false; } + + if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false; } + + ch = state.src.charCodeAt(pos + 1); + + if (ch === 0x21/* ! */ || ch === 0x3F/* ? */) { + // Directive start / comment start / processing instruction start + if (silent) { return true; } + + } else if (ch === 0x2F/* / */ || isLetter(ch)) { + + // Probably start or end of tag + if (ch === 0x2F/* \ */) { + // closing tag + match = state.src.slice(pos, max).match(HTML_TAG_CLOSE_RE); + if (!match) { return false; } + } else { + // opening tag + match = state.src.slice(pos, max).match(HTML_TAG_OPEN_RE); + if (!match) { return false; } + } + // Make sure tag name is valid + if (block_names[match[1].toLowerCase()] !== true) { return false; } + if (silent) { return true; } + + } else { + return false; + } + + // If we are here - we detected HTML block. + // Let's roll down till empty line (block end). + nextLine = startLine + 1; + while (nextLine < state.lineMax && !state.isEmpty(nextLine)) { + nextLine++; + } + + state.line = nextLine; + state.tokens.push({ + type: 'htmlblock', + level: state.level, + lines: [ startLine, state.line ], + content: state.getLines(startLine, nextLine, 0, true) + }); + + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/lheading.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/lheading.js new file mode 100644 index 0000000..43da43b --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/lheading.js @@ -0,0 +1,55 @@ +// lheading (---, ===) + +'use strict'; + + +module.exports = function lheading(state, startLine, endLine/*, silent*/) { + var marker, pos, max, + next = startLine + 1; + + if (next >= endLine) { return false; } + if (state.tShift[next] < state.blkIndent) { return false; } + + // Scan next line + + if (state.tShift[next] - state.blkIndent > 3) { return false; } + + pos = state.bMarks[next] + state.tShift[next]; + max = state.eMarks[next]; + + if (pos >= max) { return false; } + + marker = state.src.charCodeAt(pos); + + if (marker !== 0x2D/* - */ && marker !== 0x3D/* = */) { return false; } + + pos = state.skipChars(pos, marker); + + pos = state.skipSpaces(pos); + + if (pos < max) { return false; } + + pos = state.bMarks[startLine] + state.tShift[startLine]; + + state.line = next + 1; + state.tokens.push({ + type: 'heading_open', + hLevel: marker === 0x3D/* = */ ? 1 : 2, + lines: [ startLine, state.line ], + level: state.level + }); + state.tokens.push({ + type: 'inline', + content: state.src.slice(pos, state.eMarks[startLine]).trim(), + level: state.level + 1, + lines: [ startLine, state.line - 1 ], + children: [] + }); + state.tokens.push({ + type: 'heading_close', + hLevel: marker === 0x3D/* = */ ? 1 : 2, + level: state.level + }); + + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/list.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/list.js new file mode 100644 index 0000000..65b653b --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/list.js @@ -0,0 +1,266 @@ +// Lists + +'use strict'; + + +// Search `[-+*][\n ]`, returns next pos arter marker on success +// or -1 on fail. +function skipBulletListMarker(state, startLine) { + var marker, pos, max; + + pos = state.bMarks[startLine] + state.tShift[startLine]; + max = state.eMarks[startLine]; + + if (pos >= max) { return -1; } + + marker = state.src.charCodeAt(pos++); + // Check bullet + if (marker !== 0x2A/* * */ && + marker !== 0x2D/* - */ && + marker !== 0x2B/* + */) { + return -1; + } + + if (pos < max && state.src.charCodeAt(pos) !== 0x20) { + // " 1.test " - is not a list item + return -1; + } + + return pos; +} + +// Search `\d+[.)][\n ]`, returns next pos arter marker on success +// or -1 on fail. +function skipOrderedListMarker(state, startLine) { + var ch, + pos = state.bMarks[startLine] + state.tShift[startLine], + max = state.eMarks[startLine]; + + if (pos + 1 >= max) { return -1; } + + ch = state.src.charCodeAt(pos++); + + if (ch < 0x30/* 0 */ || ch > 0x39/* 9 */) { return -1; } + + for (;;) { + // EOL -> fail + if (pos >= max) { return -1; } + + ch = state.src.charCodeAt(pos++); + + if (ch >= 0x30/* 0 */ && ch <= 0x39/* 9 */) { + continue; + } + + // found valid marker + if (ch === 0x29/* ) */ || ch === 0x2e/* . */) { + break; + } + + return -1; + } + + + if (pos < max && state.src.charCodeAt(pos) !== 0x20/* space */) { + // " 1.test " - is not a list item + return -1; + } + return pos; +} + +function markTightParagraphs(state, idx) { + var i, l, + level = state.level + 2; + + for (i = idx + 2, l = state.tokens.length - 2; i < l; i++) { + if (state.tokens[i].level === level && state.tokens[i].type === 'paragraph_open') { + state.tokens[i + 2].tight = true; + state.tokens[i].tight = true; + i += 2; + } + } +} + + +module.exports = function list(state, startLine, endLine, silent) { + var nextLine, + indent, + oldTShift, + oldIndent, + oldTight, + oldParentType, + start, + posAfterMarker, + max, + indentAfterMarker, + markerValue, + markerCharCode, + isOrdered, + contentStart, + listTokIdx, + prevEmptyEnd, + listLines, + itemLines, + tight = true, + terminatorRules, + i, l, terminate; + + // Detect list type and position after marker + if ((posAfterMarker = skipOrderedListMarker(state, startLine)) >= 0) { + isOrdered = true; + } else if ((posAfterMarker = skipBulletListMarker(state, startLine)) >= 0) { + isOrdered = false; + } else { + return false; + } + + if (state.level >= state.options.maxNesting) { return false; } + + // We should terminate list on style change. Remember first one to compare. + markerCharCode = state.src.charCodeAt(posAfterMarker - 1); + + // For validation mode we can terminate immediately + if (silent) { return true; } + + // Start list + listTokIdx = state.tokens.length; + + if (isOrdered) { + start = state.bMarks[startLine] + state.tShift[startLine]; + markerValue = Number(state.src.substr(start, posAfterMarker - start - 1)); + + state.tokens.push({ + type: 'ordered_list_open', + order: markerValue, + lines: listLines = [ startLine, 0 ], + level: state.level++ + }); + + } else { + state.tokens.push({ + type: 'bullet_list_open', + lines: listLines = [ startLine, 0 ], + level: state.level++ + }); + } + + // + // Iterate list items + // + + nextLine = startLine; + prevEmptyEnd = false; + terminatorRules = state.parser.ruler.getRules('list'); + + while (nextLine < endLine) { + contentStart = state.skipSpaces(posAfterMarker); + max = state.eMarks[nextLine]; + + if (contentStart >= max) { + // trimming space in "- \n 3" case, indent is 1 here + indentAfterMarker = 1; + } else { + indentAfterMarker = contentStart - posAfterMarker; + } + + // If we have more than 4 spaces, the indent is 1 + // (the rest is just indented code block) + if (indentAfterMarker > 4) { indentAfterMarker = 1; } + + // If indent is less than 1, assume that it's one, example: + // "-\n test" + if (indentAfterMarker < 1) { indentAfterMarker = 1; } + + // " - test" + // ^^^^^ - calculating total length of this thing + indent = (posAfterMarker - state.bMarks[nextLine]) + indentAfterMarker; + + // Run subparser & write tokens + state.tokens.push({ + type: 'list_item_open', + lines: itemLines = [ startLine, 0 ], + level: state.level++ + }); + + oldIndent = state.blkIndent; + oldTight = state.tight; + oldTShift = state.tShift[startLine]; + oldParentType = state.parentType; + state.tShift[startLine] = contentStart - state.bMarks[startLine]; + state.blkIndent = indent; + state.tight = true; + state.parentType = 'list'; + + state.parser.tokenize(state, startLine, endLine, true); + + // If any of list item is tight, mark list as tight + if (!state.tight || prevEmptyEnd) { + tight = false; + } + // Item become loose if finish with empty line, + // but we should filter last element, because it means list finish + prevEmptyEnd = (state.line - startLine) > 1 && state.isEmpty(state.line - 1); + + state.blkIndent = oldIndent; + state.tShift[startLine] = oldTShift; + state.tight = oldTight; + state.parentType = oldParentType; + + state.tokens.push({ + type: 'list_item_close', + level: --state.level + }); + + nextLine = startLine = state.line; + itemLines[1] = nextLine; + contentStart = state.bMarks[startLine]; + + if (nextLine >= endLine) { break; } + + if (state.isEmpty(nextLine)) { + break; + } + + // + // Try to check if list is terminated or continued. + // + if (state.tShift[nextLine] < state.blkIndent) { break; } + + // fail if terminating block found + terminate = false; + for (i = 0, l = terminatorRules.length; i < l; i++) { + if (terminatorRules[i](state, nextLine, endLine, true)) { + terminate = true; + break; + } + } + if (terminate) { break; } + + // fail if list has another type + if (isOrdered) { + posAfterMarker = skipOrderedListMarker(state, nextLine); + if (posAfterMarker < 0) { break; } + } else { + posAfterMarker = skipBulletListMarker(state, nextLine); + if (posAfterMarker < 0) { break; } + } + + if (markerCharCode !== state.src.charCodeAt(posAfterMarker - 1)) { break; } + } + + // Finilize list + state.tokens.push({ + type: isOrdered ? 'ordered_list_close' : 'bullet_list_close', + level: --state.level + }); + listLines[1] = nextLine; + + state.line = nextLine; + + // mark paragraphs tight if needed + if (tight) { + markTightParagraphs(state, listTokIdx); + } + + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/paragraph.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/paragraph.js new file mode 100644 index 0000000..d25e5da --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/paragraph.js @@ -0,0 +1,59 @@ +// Paragraph + +'use strict'; + + +module.exports = function paragraph(state, startLine/*, endLine*/) { + var endLine, content, terminate, i, l, + nextLine = startLine + 1, + terminatorRules; + + endLine = state.lineMax; + + // jump line-by-line until empty one or EOF + if (nextLine < endLine && !state.isEmpty(nextLine)) { + terminatorRules = state.parser.ruler.getRules('paragraph'); + + for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) { + // this would be a code block normally, but after paragraph + // it's considered a lazy continuation regardless of what's there + if (state.tShift[nextLine] - state.blkIndent > 3) { continue; } + + // Some tags can terminate paragraph without empty line. + terminate = false; + for (i = 0, l = terminatorRules.length; i < l; i++) { + if (terminatorRules[i](state, nextLine, endLine, true)) { + terminate = true; + break; + } + } + if (terminate) { break; } + } + } + + content = state.getLines(startLine, nextLine, state.blkIndent, false).trim(); + + state.line = nextLine; + if (content.length) { + state.tokens.push({ + type: 'paragraph_open', + tight: false, + lines: [ startLine, state.line ], + level: state.level + }); + state.tokens.push({ + type: 'inline', + content: content, + level: state.level + 1, + lines: [ startLine, state.line ], + children: [] + }); + state.tokens.push({ + type: 'paragraph_close', + tight: false, + level: state.level + }); + } + + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/state_block.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/state_block.js new file mode 100644 index 0000000..c59355f --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/state_block.js @@ -0,0 +1,158 @@ +// Parser state class + +'use strict'; + + +function StateBlock(src, parser, options, env, tokens) { + var ch, s, start, pos, len, indent, indent_found; + + this.src = src; + + // Shortcuts to simplify nested calls + this.parser = parser; + + this.options = options; + + this.env = env; + + // + // Internal state vartiables + // + + this.tokens = tokens; + + this.bMarks = []; // line begin offsets for fast jumps + this.eMarks = []; // line end offsets for fast jumps + this.tShift = []; // indent for each line + + // block parser variables + this.blkIndent = 0; // required block content indent + // (for example, if we are in list) + this.line = 0; // line index in src + this.lineMax = 0; // lines count + this.tight = false; // loose/tight mode for lists + this.parentType = 'root'; // if `list`, block parser stops on two newlines + this.ddIndent = -1; // indent of the current dd block (-1 if there isn't any) + + this.level = 0; + + // renderer + this.result = ''; + + // Create caches + // Generate markers. + s = this.src; + indent = 0; + indent_found = false; + + for (start = pos = indent = 0, len = s.length; pos < len; pos++) { + ch = s.charCodeAt(pos); + + if (!indent_found) { + if (ch === 0x20/* space */) { + indent++; + continue; + } else { + indent_found = true; + } + } + + if (ch === 0x0A || pos === len - 1) { + if (ch !== 0x0A) { pos++; } + this.bMarks.push(start); + this.eMarks.push(pos); + this.tShift.push(indent); + + indent_found = false; + indent = 0; + start = pos + 1; + } + } + + // Push fake entry to simplify cache bounds checks + this.bMarks.push(s.length); + this.eMarks.push(s.length); + this.tShift.push(0); + + this.lineMax = this.bMarks.length - 1; // don't count last fake line +} + +StateBlock.prototype.isEmpty = function isEmpty(line) { + return this.bMarks[line] + this.tShift[line] >= this.eMarks[line]; +}; + +StateBlock.prototype.skipEmptyLines = function skipEmptyLines(from) { + for (var max = this.lineMax; from < max; from++) { + if (this.bMarks[from] + this.tShift[from] < this.eMarks[from]) { + break; + } + } + return from; +}; + +// Skip spaces from given position. +StateBlock.prototype.skipSpaces = function skipSpaces(pos) { + for (var max = this.src.length; pos < max; pos++) { + if (this.src.charCodeAt(pos) !== 0x20/* space */) { break; } + } + return pos; +}; + +// Skip char codes from given position +StateBlock.prototype.skipChars = function skipChars(pos, code) { + for (var max = this.src.length; pos < max; pos++) { + if (this.src.charCodeAt(pos) !== code) { break; } + } + return pos; +}; + +// Skip char codes reverse from given position - 1 +StateBlock.prototype.skipCharsBack = function skipCharsBack(pos, code, min) { + if (pos <= min) { return pos; } + + while (pos > min) { + if (code !== this.src.charCodeAt(--pos)) { return pos + 1; } + } + return pos; +}; + +// cut lines range from source. +StateBlock.prototype.getLines = function getLines(begin, end, indent, keepLastLF) { + var i, first, last, queue, shift, + line = begin; + + if (begin >= end) { + return ''; + } + + // Opt: don't use push queue for single line; + if (line + 1 === end) { + first = this.bMarks[line] + Math.min(this.tShift[line], indent); + last = keepLastLF ? this.bMarks[end] : this.eMarks[end - 1]; + return this.src.slice(first, last); + } + + queue = new Array(end - begin); + + for (i = 0; line < end; line++, i++) { + shift = this.tShift[line]; + if (shift > indent) { shift = indent; } + if (shift < 0) { shift = 0; } + + first = this.bMarks[line] + shift; + + if (line + 1 < end || keepLastLF) { + // No need for bounds check because we have fake entry on tail. + last = this.eMarks[line] + 1; + } else { + last = this.eMarks[line]; + } + + queue[i] = this.src.slice(first, last); + } + + return queue.join(''); +}; + + +module.exports = StateBlock; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/table.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/table.js new file mode 100644 index 0000000..064a70b --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_block/table.js @@ -0,0 +1,134 @@ +// GFM table, non-standard + +'use strict'; + + +function getLine(state, line) { + var pos = state.bMarks[line] + state.blkIndent, + max = state.eMarks[line]; + + return state.src.substr(pos, max - pos); +} + + +module.exports = function table(state, startLine, endLine, silent) { + var ch, lineText, pos, i, nextLine, rows, + aligns, t, tableLines, tbodyLines; + + // should have at least three lines + if (startLine + 2 > endLine) { return false; } + + nextLine = startLine + 1; + + if (state.tShift[nextLine] < state.blkIndent) { return false; } + + // first character of the second line should be '|' or '-' + + pos = state.bMarks[nextLine] + state.tShift[nextLine]; + if (pos >= state.eMarks[nextLine]) { return false; } + + ch = state.src.charCodeAt(pos); + if (ch !== 0x7C/* | */ && ch !== 0x2D/* - */ && ch !== 0x3A/* : */) { return false; } + + lineText = getLine(state, startLine + 1); + if (!/^[-:| ]+$/.test(lineText)) { return false; } + + rows = lineText.split('|'); + if (rows <= 2) { return false; } + aligns = []; + for (i = 0; i < rows.length; i++) { + t = rows[i].trim(); + if (!t) { + // allow empty columns before and after table, but not in between columns; + // e.g. allow ` |---| `, disallow ` ---||--- ` + if (i === 0 || i === rows.length - 1) { + continue; + } else { + return false; + } + } + + if (!/^:?-+:?$/.test(t)) { return false; } + if (t.charCodeAt(t.length - 1) === 0x3A/* : */) { + aligns.push(t.charCodeAt(0) === 0x3A/* : */ ? 'center' : 'right'); + } else if (t.charCodeAt(0) === 0x3A/* : */) { + aligns.push('left'); + } else { + aligns.push(''); + } + } + + lineText = getLine(state, startLine).trim(); + if (lineText.indexOf('|') === -1) { return false; } + rows = lineText.replace(/^\||\|$/g, '').split('|'); + if (aligns.length !== rows.length) { return false; } + if (silent) { return true; } + + state.tokens.push({ + type: 'table_open', + lines: tableLines = [ startLine, 0 ], + level: state.level++ + }); + state.tokens.push({ + type: 'thead_open', + lines: [ startLine, startLine + 1 ], + level: state.level++ + }); + + state.tokens.push({ + type: 'tr_open', + lines: [ startLine, startLine + 1 ], + level: state.level++ + }); + for (i = 0; i < rows.length; i++) { + state.tokens.push({ + type: 'th_open', + align: aligns[i], + lines: [ startLine, startLine + 1 ], + level: state.level++ + }); + state.tokens.push({ + type: 'inline', + content: rows[i].trim(), + lines: [ startLine, startLine + 1 ], + level: state.level, + children: [] + }); + state.tokens.push({ type: 'th_close', level: --state.level }); + } + state.tokens.push({ type: 'tr_close', level: --state.level }); + state.tokens.push({ type: 'thead_close', level: --state.level }); + + state.tokens.push({ + type: 'tbody_open', + lines: tbodyLines = [ startLine + 2, 0 ], + level: state.level++ + }); + + for (nextLine = startLine + 2; nextLine < endLine; nextLine++) { + if (state.tShift[nextLine] < state.blkIndent) { break; } + + lineText = getLine(state, nextLine).trim(); + if (lineText.indexOf('|') === -1) { break; } + rows = lineText.replace(/^\||\|$/g, '').split('|'); + + state.tokens.push({ type: 'tr_open', level: state.level++ }); + for (i = 0; i < rows.length; i++) { + state.tokens.push({ type: 'td_open', align: aligns[i], level: state.level++ }); + state.tokens.push({ + type: 'inline', + content: rows[i].replace(/^\|? *| *\|?$/g, ''), + level: state.level, + children: [] + }); + state.tokens.push({ type: 'td_close', level: --state.level }); + } + state.tokens.push({ type: 'tr_close', level: --state.level }); + } + state.tokens.push({ type: 'tbody_close', level: --state.level }); + state.tokens.push({ type: 'table_close', level: --state.level }); + + tableLines[1] = tbodyLines[1] = nextLine; + state.line = nextLine; + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/abbr.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/abbr.js new file mode 100644 index 0000000..6173c43 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/abbr.js @@ -0,0 +1,75 @@ +// Parse abbreviation definitions, i.e. `*[abbr]: description` +// + +'use strict'; + + +function parseAbbr(str, parserInline, options, env) { + var pos, label, title, ch, + max = str.length, + labelEnd = -1; + + if (str.charCodeAt(0) !== 0x2A/* * */) { return -1; } + if (str.charCodeAt(1) !== 0x5B/* [ */) { return -1; } + + if (str.indexOf(']:') === -1) { return -1; } + + for (pos = 2; pos < max; pos++) { + ch = str.charCodeAt(pos); + if (ch === 0x5B /* [ */) { + return -1; + } else if (ch === 0x5D /* ] */) { + labelEnd = pos; + break; + } else if (ch === 0x5C /* \ */) { + pos++; + } + } + + if (labelEnd < 0 || str.charCodeAt(labelEnd + 1) !== 0x3A/* : */) { return -1; } + + // abbr title is always one line, so looking for ending "\n" here + for (pos = labelEnd + 2; pos < max; pos++) { + if (str.charCodeAt(pos) === 0x0A) { break; } + } + + label = str.slice(2, labelEnd).replace(/\\(.)/g, '$1'); + title = str.slice(labelEnd + 2, pos).trim(); + if (title.length === 0) { return -1; } + if (!env.abbreviations) { env.abbreviations = {}; } + // prepend ':' to avoid conflict with Object.prototype members + if (typeof env.abbreviations[':' + label] === 'undefined') { + env.abbreviations[':' + label] = title; + } + + return pos; +} + +module.exports = function abbr(state) { + var tokens = state.tokens, i, l, content, pos; + + if (state.inlineMode) { + return; + } + + // Parse inlines + for (i = 1, l = tokens.length - 1; i < l; i++) { + if (tokens[i - 1].type === 'paragraph_open' && + tokens[i].type === 'inline' && + tokens[i + 1].type === 'paragraph_close') { + + content = tokens[i].content; + while (content.length) { + pos = parseAbbr(content, state.inline, state.options, state.env); + if (pos < 0) { break; } + content = content.slice(pos).trim(); + } + + tokens[i].content = content; + if (!content.length) { + tokens[i - 1].tight = true; + tokens[i + 1].tight = true; + } + } + } +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/abbr2.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/abbr2.js new file mode 100644 index 0000000..0a3315c --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/abbr2.js @@ -0,0 +1,91 @@ +// Enclose abbreviations in tags +// +'use strict'; + + +var arrayReplaceAt = require('../common/utils').arrayReplaceAt; + + +var PUNCT_CHARS = ' \n()[]\'".,!?-'; + + +// from Google closure library +// http://closure-library.googlecode.com/git-history/docs/local_closure_goog_string_string.js.source.html#line1021 +function regEscape(s) { + return s.replace(/([-()\[\]{}+?*.$\^|,:#= 0; i--) { + token = tokens[i]; + if (token.type !== 'text') { continue; } + + pos = 0; + text = token.content; + reg.lastIndex = 0; + level = token.level; + nodes = []; + + while ((m = reg.exec(text))) { + if (reg.lastIndex > pos) { + nodes.push({ + type: 'text', + content: text.slice(pos, m.index + m[1].length), + level: level + }); + } + + nodes.push({ + type: 'abbr_open', + title: state.env.abbreviations[':' + m[2]], + level: level++ + }); + nodes.push({ + type: 'text', + content: m[2], + level: level + }); + nodes.push({ + type: 'abbr_close', + level: --level + }); + pos = reg.lastIndex - m[3].length; + } + + if (!nodes.length) { continue; } + + if (pos < text.length) { + nodes.push({ + type: 'text', + content: text.slice(pos), + level: level + }); + } + + // replace current node + blockTokens[j].children = tokens = arrayReplaceAt(tokens, i, nodes); + } + } +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/block.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/block.js new file mode 100644 index 0000000..f3bbb6d --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/block.js @@ -0,0 +1,17 @@ +'use strict'; + +module.exports = function block(state) { + + if (state.inlineMode) { + state.tokens.push({ + type: 'inline', + content: state.src.replace(/\n/g, ' ').trim(), + level: 0, + lines: [ 0, 1 ], + children: [] + }); + + } else { + state.block.parse(state.src, state.options, state.env, state.tokens); + } +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/footnote_tail.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/footnote_tail.js new file mode 100644 index 0000000..faee3ec --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/footnote_tail.js @@ -0,0 +1,95 @@ +'use strict'; + + +module.exports = function footnote_block(state) { + var i, l, j, t, lastParagraph, list, tokens, current, currentLabel, + level = 0, + insideRef = false, + refTokens = {}; + + if (!state.env.footnotes) { return; } + + state.tokens = state.tokens.filter(function(tok) { + if (tok.type === 'footnote_reference_open') { + insideRef = true; + current = []; + currentLabel = tok.label; + return false; + } + if (tok.type === 'footnote_reference_close') { + insideRef = false; + // prepend ':' to avoid conflict with Object.prototype members + refTokens[':' + currentLabel] = current; + return false; + } + if (insideRef) { current.push(tok); } + return !insideRef; + }); + + if (!state.env.footnotes.list) { return; } + list = state.env.footnotes.list; + + state.tokens.push({ + type: 'footnote_block_open', + level: level++ + }); + for (i = 0, l = list.length; i < l; i++) { + state.tokens.push({ + type: 'footnote_open', + id: i, + level: level++ + }); + + if (list[i].tokens) { + tokens = []; + tokens.push({ + type: 'paragraph_open', + tight: false, + level: level++ + }); + tokens.push({ + type: 'inline', + content: '', + level: level, + children: list[i].tokens + }); + tokens.push({ + type: 'paragraph_close', + tight: false, + level: --level + }); + } else if (list[i].label) { + tokens = refTokens[':' + list[i].label]; + } + + state.tokens = state.tokens.concat(tokens); + if (state.tokens[state.tokens.length - 1].type === 'paragraph_close') { + lastParagraph = state.tokens.pop(); + } else { + lastParagraph = null; + } + + t = list[i].count > 0 ? list[i].count : 1; + for (j = 0; j < t; j++) { + state.tokens.push({ + type: 'footnote_anchor', + id: i, + subId: j, + level: level + }); + } + + if (lastParagraph) { + state.tokens.push(lastParagraph); + } + + state.tokens.push({ + type: 'footnote_close', + level: --level + }); + } + state.tokens.push({ + type: 'footnote_block_close', + level: --level + }); +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/inline.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/inline.js new file mode 100644 index 0000000..8b2280b --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/inline.js @@ -0,0 +1,13 @@ +'use strict'; + +module.exports = function inline(state) { + var tokens = state.tokens, tok, i, l; + + // Parse inlines + for (i = 0, l = tokens.length; i < l; i++) { + tok = tokens[i]; + if (tok.type === 'inline') { + state.inline.parse(tok.content, state.options, state.env, tok.children); + } + } +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/linkify.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/linkify.js new file mode 100644 index 0000000..6d805a5 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/linkify.js @@ -0,0 +1,163 @@ +// Replace link-like texts with link nodes. +// +// Currently restricted by `inline.validateLink()` to http/https/ftp +// +'use strict'; + + +var Autolinker = require('autolinker'); +var arrayReplaceAt = require('../common/utils').arrayReplaceAt; + + +var LINK_SCAN_RE = /www|@|\:\/\//; + + +function isLinkOpen(str) { + return /^\s]/i.test(str); +} +function isLinkClose(str) { + return /^<\/a\s*>/i.test(str); +} + +// Stupid fabric to avoid singletons, for thread safety. +// Required for engines like Nashorn. +// +function createLinkifier() { + var links = []; + var autolinker = new Autolinker({ + stripPrefix: false, + url: true, + email: true, + twitter: false, + replaceFn: function (autolinker, match) { + // Only collect matched strings but don't change anything. + switch (match.getType()) { + /*eslint default-case:0*/ + case 'url': + links.push({ + text: match.matchedText, + url: match.getUrl() + }); + break; + case 'email': + links.push({ + text: match.matchedText, + // normalize email protocol + url: 'mailto:' + match.getEmail().replace(/^mailto:/i, '') + }); + break; + } + return false; + } + }); + + return { + links: links, + autolinker: autolinker + }; +} + + +module.exports = function linkify(state) { + var i, j, l, tokens, token, text, nodes, ln, pos, level, htmlLinkLevel, + blockTokens = state.tokens, + linkifier = null, links, autolinker; + + if (!state.options.linkify) { return; } + + for (j = 0, l = blockTokens.length; j < l; j++) { + if (blockTokens[j].type !== 'inline') { continue; } + tokens = blockTokens[j].children; + + htmlLinkLevel = 0; + + // We scan from the end, to keep position when new tags added. + // Use reversed logic in links start/end match + for (i = tokens.length - 1; i >= 0; i--) { + token = tokens[i]; + + // Skip content of markdown links + if (token.type === 'link_close') { + i--; + while (tokens[i].level !== token.level && tokens[i].type !== 'link_open') { + i--; + } + continue; + } + + // Skip content of html tag links + if (token.type === 'htmltag') { + if (isLinkOpen(token.content) && htmlLinkLevel > 0) { + htmlLinkLevel--; + } + if (isLinkClose(token.content)) { + htmlLinkLevel++; + } + } + if (htmlLinkLevel > 0) { continue; } + + if (token.type === 'text' && LINK_SCAN_RE.test(token.content)) { + + // Init linkifier in lazy manner, only if required. + if (!linkifier) { + linkifier = createLinkifier(); + links = linkifier.links; + autolinker = linkifier.autolinker; + } + + text = token.content; + links.length = 0; + autolinker.link(text); + + if (!links.length) { continue; } + + // Now split string to nodes + nodes = []; + level = token.level; + + for (ln = 0; ln < links.length; ln++) { + + if (!state.inline.validateLink(links[ln].url)) { continue; } + + pos = text.indexOf(links[ln].text); + + if (pos) { + level = level; + nodes.push({ + type: 'text', + content: text.slice(0, pos), + level: level + }); + } + nodes.push({ + type: 'link_open', + href: links[ln].url, + target: '', + title: '', + level: level++ + }); + nodes.push({ + type: 'text', + content: links[ln].text, + level: level + }); + nodes.push({ + type: 'link_close', + level: --level + }); + text = text.slice(pos + links[ln].text.length); + } + if (text.length) { + nodes.push({ + type: 'text', + content: text, + level: level + }); + } + + // replace current node + blockTokens[j].children = tokens = arrayReplaceAt(tokens, i, nodes); + } + } + } +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/references.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/references.js new file mode 100644 index 0000000..d64c46d --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/references.js @@ -0,0 +1,108 @@ +'use strict'; + + +var StateInline = require('../rules_inline/state_inline'); +var parseLinkDestination = require('../helpers/parse_link_destination'); +var parseLinkTitle = require('../helpers/parse_link_title'); +var normalizeReference = require('../helpers/normalize_reference'); + + +function parseReference(str, parser, options, env) { + var state, pos, code, start, href, title, label, ch, max, + labelEnd = -1; + + if (str.charCodeAt(0) !== 0x5B/* [ */) { return -1; } + + if (str.indexOf(']:') === -1) { return -1; } + + state = new StateInline(str, parser, options, env, []); + max = state.posMax; + + for (pos = 1; pos < max; pos++) { + ch = str.charCodeAt(pos); + if (ch === 0x5B /* [ */) { + return -1; + } else if (ch === 0x5D /* ] */) { + labelEnd = pos; + break; + } else if (ch === 0x5C /* \ */) { + pos++; + } + } + + if (labelEnd < 0 || str.charCodeAt(labelEnd + 1) !== 0x3A/* : */) { return -1; } + + // [label]: destination 'title' + // ^^^ skip optional whitespace here + for (pos = labelEnd + 2; pos < max; pos++) { + code = state.src.charCodeAt(pos); + if (code !== 0x20 && code !== 0x0A) { break; } + } + + // [label]: destination 'title' + // ^^^^^^^^^^^ parse this + if (!parseLinkDestination(state, pos)) { return -1; } + href = state.linkContent; + pos = state.pos; + + // [label]: destination 'title' + // ^^^ skipping those spaces + start = pos; + for (pos = pos + 1; pos < max; pos++) { + code = state.src.charCodeAt(pos); + if (code !== 0x20 && code !== 0x0A) { break; } + } + + // [label]: destination 'title' + // ^^^^^^^ parse this + if (pos < max && start !== pos && parseLinkTitle(state, pos)) { + title = state.linkContent; + pos = state.pos; + } else { + title = ''; + pos = start; + } + + // ensure that the end of the line is empty + while (pos < max && state.src.charCodeAt(pos) === 0x20/* space */) { pos++; } + if (pos < max && state.src.charCodeAt(pos) !== 0x0A) { return -1; } + + label = normalizeReference(str.slice(1, labelEnd)); + if (typeof env.references[label] === 'undefined') { + env.references[label] = { title: title, href: href }; + } + + return pos; +} + + +module.exports = function references(state) { + var tokens = state.tokens, i, l, content, pos; + + state.env.references = state.env.references || {}; + + if (state.inlineMode) { + return; + } + + // Scan definitions in paragraph inlines + for (i = 1, l = tokens.length - 1; i < l; i++) { + if (tokens[i].type === 'inline' && + tokens[i - 1].type === 'paragraph_open' && + tokens[i + 1].type === 'paragraph_close') { + + content = tokens[i].content; + while (content.length) { + pos = parseReference(content, state.inline, state.options, state.env); + if (pos < 0) { break; } + content = content.slice(pos).trim(); + } + + tokens[i].content = content; + if (!content.length) { + tokens[i - 1].tight = true; + tokens[i + 1].tight = true; + } + } + } +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/replacements.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/replacements.js new file mode 100644 index 0000000..1359058 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/replacements.js @@ -0,0 +1,74 @@ +// Simple typographyc replacements +// +// '' → ‘’ +// "" → “”. Set '«»' for Russian, '„“' for German, empty to disable +// (c) (C) → © +// (tm) (TM) → ™ +// (r) (R) → ® +// +- → ± +// (p) (P) -> § +// ... → … (also ?.... → ?.., !.... → !..) +// ???????? → ???, !!!!! → !!!, `,,` → `,` +// -- → –, --- → — +// +'use strict'; + +// TODO: +// - fractionals 1/2, 1/4, 3/4 -> ½, ¼, ¾ +// - miltiplication 2 x 4 -> 2 × 4 + +var RARE_RE = /\+-|\.\.|\?\?\?\?|!!!!|,,|--/; + +var SCOPED_ABBR_RE = /\((c|tm|r|p)\)/ig; +var SCOPED_ABBR = { + 'c': '©', + 'r': '®', + 'p': '§', + 'tm': '™' +}; + +function replaceScopedAbbr(str) { + if (str.indexOf('(') < 0) { return str; } + + return str.replace(SCOPED_ABBR_RE, function(match, name) { + return SCOPED_ABBR[name.toLowerCase()]; + }); +} + + +module.exports = function replace(state) { + var i, token, text, inlineTokens, blkIdx; + + if (!state.options.typographer) { return; } + + for (blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) { + + if (state.tokens[blkIdx].type !== 'inline') { continue; } + + inlineTokens = state.tokens[blkIdx].children; + + for (i = inlineTokens.length - 1; i >= 0; i--) { + token = inlineTokens[i]; + if (token.type === 'text') { + text = token.content; + + text = replaceScopedAbbr(text); + + if (RARE_RE.test(text)) { + text = text.replace(/\+-/g, '±') + // .., ..., ....... -> … + // but ?..... & !..... -> ?.. & !.. + .replace(/\.{2,}/g, '…').replace(/([?!])…/g, '$1..') + .replace(/([?!]){4,}/g, '$1$1$1').replace(/,{2,}/g, ',') + // em-dash + .replace(/(^|[^-])---([^-]|$)/mg, '$1\u2014$2') + // en-dash + .replace(/(^|\s)--(\s|$)/mg, '$1\u2013$2') + .replace(/(^|[^-\s])--([^-\s]|$)/mg, '$1\u2013$2'); + } + + token.content = text; + } + } + } +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/smartquotes.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/smartquotes.js new file mode 100644 index 0000000..05a954d --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_core/smartquotes.js @@ -0,0 +1,113 @@ +// Convert straight quotation marks to typographic ones +// +'use strict'; + + +var QUOTE_TEST_RE = /['"]/; +var QUOTE_RE = /['"]/g; +var PUNCT_RE = /[-\s()\[\]]/; +var APOSTROPHE = '\u2019'; /* ’ */ + +// This function returns true if the character at `pos` +// could be inside a word. +function isLetter(str, pos) { + if (pos < 0 || pos >= str.length) { return false; } + return !PUNCT_RE.test(str[pos]); +} + + +function replaceAt(str, index, ch) { + return str.substr(0, index) + ch + str.substr(index + 1); +} + + +module.exports = function smartquotes(state) { + /*eslint max-depth:0*/ + var i, token, text, t, pos, max, thisLevel, lastSpace, nextSpace, item, + canOpen, canClose, j, isSingle, blkIdx, tokens, + stack; + + if (!state.options.typographer) { return; } + + stack = []; + + for (blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) { + + if (state.tokens[blkIdx].type !== 'inline') { continue; } + + tokens = state.tokens[blkIdx].children; + stack.length = 0; + + for (i = 0; i < tokens.length; i++) { + token = tokens[i]; + + if (token.type !== 'text' || QUOTE_TEST_RE.test(token.text)) { continue; } + + thisLevel = tokens[i].level; + + for (j = stack.length - 1; j >= 0; j--) { + if (stack[j].level <= thisLevel) { break; } + } + stack.length = j + 1; + + text = token.content; + pos = 0; + max = text.length; + + /*eslint no-labels:0,block-scoped-var:0*/ + OUTER: + while (pos < max) { + QUOTE_RE.lastIndex = pos; + t = QUOTE_RE.exec(text); + if (!t) { break; } + + lastSpace = !isLetter(text, t.index - 1); + pos = t.index + 1; + isSingle = (t[0] === "'"); + nextSpace = !isLetter(text, pos); + + if (!nextSpace && !lastSpace) { + // middle of word + if (isSingle) { + token.content = replaceAt(token.content, t.index, APOSTROPHE); + } + continue; + } + + canOpen = !nextSpace; + canClose = !lastSpace; + + if (canClose) { + // this could be a closing quote, rewind the stack to get a match + for (j = stack.length - 1; j >= 0; j--) { + item = stack[j]; + if (stack[j].level < thisLevel) { break; } + if (item.single === isSingle && stack[j].level === thisLevel) { + item = stack[j]; + if (isSingle) { + tokens[item.token].content = replaceAt(tokens[item.token].content, item.pos, state.options.quotes[2]); + token.content = replaceAt(token.content, t.index, state.options.quotes[3]); + } else { + tokens[item.token].content = replaceAt(tokens[item.token].content, item.pos, state.options.quotes[0]); + token.content = replaceAt(token.content, t.index, state.options.quotes[1]); + } + stack.length = j; + continue OUTER; + } + } + } + + if (canOpen) { + stack.push({ + token: i, + pos: t.index, + single: isSingle, + level: thisLevel + }); + } else if (canClose && isSingle) { + token.content = replaceAt(token.content, t.index, APOSTROPHE); + } + } + } + } +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/autolink.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/autolink.js new file mode 100644 index 0000000..809ea18 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/autolink.js @@ -0,0 +1,80 @@ +// Process autolinks '' + +'use strict'; + +var url_schemas = require('../common/url_schemas'); +var normalizeLink = require('../common/utils').normalizeLink; + + +/*eslint max-len:0*/ +var EMAIL_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])?)*)>/; +var AUTOLINK_RE = /^<([a-zA-Z.\-]{1,25}):([^<>\x00-\x20]*)>/; + + +module.exports = function autolink(state, silent) { + var tail, linkMatch, emailMatch, url, fullUrl, pos = state.pos; + + if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false; } + + tail = state.src.slice(pos); + + if (tail.indexOf('>') < 0) { return false; } + + linkMatch = tail.match(AUTOLINK_RE); + + if (linkMatch) { + if (url_schemas.indexOf(linkMatch[1].toLowerCase()) < 0) { return false; } + + url = linkMatch[0].slice(1, -1); + fullUrl = normalizeLink(url); + if (!state.parser.validateLink(url)) { return false; } + + if (!silent) { + state.push({ + type: 'link_open', + href: fullUrl, + target: '', + level: state.level + }); + state.push({ + type: 'text', + content: url, + level: state.level + 1 + }); + state.push({ type: 'link_close', level: state.level }); + } + + state.pos += linkMatch[0].length; + return true; + } + + emailMatch = tail.match(EMAIL_RE); + + if (emailMatch) { + + url = emailMatch[0].slice(1, -1); + + fullUrl = normalizeLink('mailto:' + url); + if (!state.parser.validateLink(fullUrl)) { return false; } + + if (!silent) { + state.push({ + type: 'link_open', + href: fullUrl, + target: '', + level: state.level + }); + state.push({ + type: 'text', + content: url, + level: state.level + 1 + }); + state.push({ type: 'link_close', level: state.level }); + } + + state.pos += emailMatch[0].length; + return true; + } + + return false; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/backticks.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/backticks.js new file mode 100644 index 0000000..fff04f5 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/backticks.js @@ -0,0 +1,46 @@ +// Parse backticks + +'use strict'; + +module.exports = function backticks(state, silent) { + var start, max, marker, matchStart, matchEnd, + pos = state.pos, + ch = state.src.charCodeAt(pos); + + if (ch !== 0x60/* ` */) { return false; } + + start = pos; + pos++; + max = state.posMax; + + while (pos < max && state.src.charCodeAt(pos) === 0x60/* ` */) { pos++; } + + marker = state.src.slice(start, pos); + + matchStart = matchEnd = pos; + + while ((matchStart = state.src.indexOf('`', matchEnd)) !== -1) { + matchEnd = matchStart + 1; + + while (matchEnd < max && state.src.charCodeAt(matchEnd) === 0x60/* ` */) { matchEnd++; } + + if (matchEnd - matchStart === marker.length) { + if (!silent) { + state.push({ + type: 'code', + content: state.src.slice(pos, matchStart) + .replace(/[ \n]+/g, ' ') + .trim(), + block: false, + level: state.level + }); + } + state.pos = matchEnd; + return true; + } + } + + if (!silent) { state.pending += marker; } + state.pos += marker.length; + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/del.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/del.js new file mode 100644 index 0000000..b91b34c --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/del.js @@ -0,0 +1,102 @@ +'use strict'; + + +// parse sequence of markers, +// "start" should point at a valid marker +function scanDelims(state, start) { + var pos = start, lastChar, nextChar, count, + can_open = true, + can_close = true, + max = state.posMax, + marker = state.src.charCodeAt(start); + + lastChar = start > 0 ? state.src.charCodeAt(start - 1) : -1; + + while (pos < max && state.src.charCodeAt(pos) === marker) { pos++; } + if (pos >= max) { can_open = false; } + count = pos - start; + + nextChar = pos < max ? state.src.charCodeAt(pos) : -1; + + // check whitespace conditions + if (nextChar === 0x20 || nextChar === 0x0A) { can_open = false; } + if (lastChar === 0x20 || lastChar === 0x0A) { can_close = false; } + + return { + can_open: can_open, + can_close: can_close, + delims: count + }; +} + +module.exports = function(state, silent) { + var startCount, + count, + tagCount, + found, + stack, + res, + max = state.posMax, + start = state.pos, + marker = state.src.charCodeAt(start); + + if (marker !== 0x7E/* ~ */) { return false; } + if (silent) { return false; } // don't run any pairs in validation mode + + res = scanDelims(state, start); + startCount = res.delims; + if (!res.can_open) { + state.pos += startCount; + if (!silent) { state.pending += state.src.slice(start, state.pos); } + return true; + } + + if (state.level >= state.options.maxNesting) { return false; } + stack = Math.floor(startCount / 2); + if (stack <= 0) { return false; } + state.pos = start + startCount; + + while (state.pos < max) { + if (state.src.charCodeAt(state.pos) === marker) { + res = scanDelims(state, state.pos); + count = res.delims; + tagCount = Math.floor(count / 2); + if (res.can_close) { + if (tagCount >= stack) { + state.pos += count - 2; + found = true; + break; + } + stack -= tagCount; + state.pos += count; + continue; + } + + if (res.can_open) { stack += tagCount; } + state.pos += count; + continue; + } + + state.parser.skipToken(state); + } + + if (!found) { + // parser failed to find ending tag, so it's not valid emphasis + state.pos = start; + return false; + } + + // found! + state.posMax = state.pos; + state.pos = start + 2; + + if (!silent) { + state.push({ type: 'del_open', level: state.level++ }); + state.parser.tokenize(state); + state.push({ type: 'del_close', level: --state.level }); + } + + state.pos = state.posMax + 2; + state.posMax = max; + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/emphasis.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/emphasis.js new file mode 100644 index 0000000..ad6e53d --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/emphasis.js @@ -0,0 +1,142 @@ +// Process *this* and _that_ + +'use strict'; + + +function isAlphaNum(code) { + return (code >= 0x30 /* 0 */ && code <= 0x39 /* 9 */) || + (code >= 0x41 /* A */ && code <= 0x5A /* Z */) || + (code >= 0x61 /* a */ && code <= 0x7A /* z */); +} + +// parse sequence of emphasis markers, +// "start" should point at a valid marker +function scanDelims(state, start) { + var pos = start, lastChar, nextChar, count, + can_open = true, + can_close = true, + max = state.posMax, + marker = state.src.charCodeAt(start); + + lastChar = start > 0 ? state.src.charCodeAt(start - 1) : -1; + + while (pos < max && state.src.charCodeAt(pos) === marker) { pos++; } + if (pos >= max) { can_open = false; } + count = pos - start; + + nextChar = pos < max ? state.src.charCodeAt(pos) : -1; + + // check whitespace conditions + if (nextChar === 0x20 || nextChar === 0x0A) { can_open = false; } + if (lastChar === 0x20 || lastChar === 0x0A) { can_close = false; } + + if (marker === 0x5F /* _ */) { + // check if we aren't inside the word + if (isAlphaNum(lastChar)) { can_open = false; } + if (isAlphaNum(nextChar)) { can_close = false; } + } + + return { + can_open: can_open, + can_close: can_close, + delims: count + }; +} + +module.exports = function emphasis(state, silent) { + var startCount, + count, + found, + oldCount, + newCount, + stack, + res, + max = state.posMax, + start = state.pos, + marker = state.src.charCodeAt(start); + + if (marker !== 0x5F/* _ */ && marker !== 0x2A /* * */) { return false; } + if (silent) { return false; } // don't run any pairs in validation mode + + res = scanDelims(state, start); + startCount = res.delims; + if (!res.can_open) { + state.pos += startCount; + if (!silent) { state.pending += state.src.slice(start, state.pos); } + return true; + } + + if (state.level >= state.options.maxNesting) { return false; } + + state.pos = start + startCount; + stack = [ startCount ]; + + while (state.pos < max) { + if (state.src.charCodeAt(state.pos) === marker) { + res = scanDelims(state, state.pos); + count = res.delims; + if (res.can_close) { + oldCount = stack.pop(); + newCount = count; + + while (oldCount !== newCount) { + if (newCount < oldCount) { + stack.push(oldCount - newCount); + break; + } + + // assert(newCount > oldCount) + newCount -= oldCount; + + if (stack.length === 0) { break; } + state.pos += oldCount; + oldCount = stack.pop(); + } + + if (stack.length === 0) { + startCount = oldCount; + found = true; + break; + } + state.pos += count; + continue; + } + + if (res.can_open) { stack.push(count); } + state.pos += count; + continue; + } + + state.parser.skipToken(state); + } + + if (!found) { + // parser failed to find ending tag, so it's not valid emphasis + state.pos = start; + return false; + } + + // found! + state.posMax = state.pos; + state.pos = start + startCount; + + if (!silent) { + // we have `startCount` starting and ending markers, + // now trying to serialize them into tokens + for (count = startCount; count > 1; count -= 2) { + state.push({ type: 'strong_open', level: state.level++ }); + } + if (count % 2) { state.push({ type: 'em_open', level: state.level++ }); } + + state.parser.tokenize(state); + + if (count % 2) { state.push({ type: 'em_close', level: --state.level }); } + for (count = startCount; count > 1; count -= 2) { + state.push({ type: 'strong_close', level: --state.level }); + } + } + + state.pos = state.posMax + startCount; + state.posMax = max; + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/entity.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/entity.js new file mode 100644 index 0000000..52e7cba --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/entity.js @@ -0,0 +1,48 @@ +// Process html entity - {, ¯, ", ... + +'use strict'; + +var entities = require('../common/entities'); +var has = require('../common/utils').has; +var isValidEntityCode = require('../common/utils').isValidEntityCode; +var fromCodePoint = require('../common/utils').fromCodePoint; + + +var DIGITAL_RE = /^&#((?:x[a-f0-9]{1,8}|[0-9]{1,8}));/i; +var NAMED_RE = /^&([a-z][a-z0-9]{1,31});/i; + + +module.exports = function entity(state, silent) { + var ch, code, match, pos = state.pos, max = state.posMax; + + if (state.src.charCodeAt(pos) !== 0x26/* & */) { return false; } + + if (pos + 1 < max) { + ch = state.src.charCodeAt(pos + 1); + + if (ch === 0x23 /* # */) { + match = state.src.slice(pos).match(DIGITAL_RE); + if (match) { + if (!silent) { + code = match[1][0].toLowerCase() === 'x' ? parseInt(match[1].slice(1), 16) : parseInt(match[1], 10); + state.pending += isValidEntityCode(code) ? fromCodePoint(code) : fromCodePoint(0xFFFD); + } + state.pos += match[0].length; + return true; + } + } else { + match = state.src.slice(pos).match(NAMED_RE); + if (match) { + if (has(entities, match[1])) { + if (!silent) { state.pending += entities[match[1]]; } + state.pos += match[0].length; + return true; + } + } + } + } + + if (!silent) { state.pending += '&'; } + state.pos++; + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/escape.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/escape.js new file mode 100644 index 0000000..09dee0b --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/escape.js @@ -0,0 +1,49 @@ +// Proceess escaped chars and hardbreaks + +'use strict'; + +var ESCAPED = []; + +for (var i = 0; i < 256; i++) { ESCAPED.push(0); } + +'\\!"#$%&\'()*+,./:;<=>?@[]^_`{|}~-' + .split('').forEach(function(ch) { ESCAPED[ch.charCodeAt(0)] = 1; }); + + +module.exports = function escape(state, silent) { + var ch, pos = state.pos, max = state.posMax; + + if (state.src.charCodeAt(pos) !== 0x5C/* \ */) { return false; } + + pos++; + + if (pos < max) { + ch = state.src.charCodeAt(pos); + + if (ch < 256 && ESCAPED[ch] !== 0) { + if (!silent) { state.pending += state.src[pos]; } + state.pos += 2; + return true; + } + + if (ch === 0x0A) { + if (!silent) { + state.push({ + type: 'hardbreak', + level: state.level + }); + } + + pos++; + // skip leading whitespaces from next line + while (pos < max && state.src.charCodeAt(pos) === 0x20) { pos++; } + + state.pos = pos; + return true; + } + } + + if (!silent) { state.pending += '\\'; } + state.pos++; + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/footnote_inline.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/footnote_inline.js new file mode 100644 index 0000000..b8e9c4a --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/footnote_inline.js @@ -0,0 +1,51 @@ +// Process inline footnotes (^[...]) + +'use strict'; + +var parseLinkLabel = require('../helpers/parse_link_label'); + + +module.exports = function footnote_inline(state, silent) { + var labelStart, + labelEnd, + footnoteId, + oldLength, + max = state.posMax, + start = state.pos; + + if (start + 2 >= max) { return false; } + if (state.src.charCodeAt(start) !== 0x5E/* ^ */) { return false; } + if (state.src.charCodeAt(start + 1) !== 0x5B/* [ */) { return false; } + if (state.level >= state.options.maxNesting) { return false; } + + labelStart = start + 2; + labelEnd = parseLinkLabel(state, start + 1); + + // parser failed to find ']', so it's not a valid note + if (labelEnd < 0) { return false; } + + // We found the end of the link, and know for a fact it's a valid link; + // so all that's left to do is to call tokenizer. + // + if (!silent) { + if (!state.env.footnotes) { state.env.footnotes = {}; } + if (!state.env.footnotes.list) { state.env.footnotes.list = []; } + footnoteId = state.env.footnotes.list.length; + + state.pos = labelStart; + state.posMax = labelEnd; + + state.push({ + type: 'footnote_ref', + id: footnoteId, + level: state.level + }); + oldLength = state.tokens.length; + state.parser.tokenize(state); + state.env.footnotes.list[footnoteId] = { tokens: state.tokens.splice(oldLength) }; + } + + state.pos = labelEnd + 1; + state.posMax = max; + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/footnote_ref.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/footnote_ref.js new file mode 100644 index 0000000..f0ab553 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/footnote_ref.js @@ -0,0 +1,62 @@ +// Process footnote references ([^...]) + +'use strict'; + + +module.exports = function footnote_ref(state, silent) { + var label, + pos, + footnoteId, + footnoteSubId, + max = state.posMax, + start = state.pos; + + // should be at least 4 chars - "[^x]" + if (start + 3 > max) { return false; } + + if (!state.env.footnotes || !state.env.footnotes.refs) { return false; } + if (state.src.charCodeAt(start) !== 0x5B/* [ */) { return false; } + if (state.src.charCodeAt(start + 1) !== 0x5E/* ^ */) { return false; } + if (state.level >= state.options.maxNesting) { return false; } + + for (pos = start + 2; pos < max; pos++) { + if (state.src.charCodeAt(pos) === 0x20) { return false; } + if (state.src.charCodeAt(pos) === 0x0A) { return false; } + if (state.src.charCodeAt(pos) === 0x5D /* ] */) { + break; + } + } + + if (pos === start + 2) { return false; } // no empty footnote labels + if (pos >= max) { return false; } + pos++; + + label = state.src.slice(start + 2, pos - 1); + if (typeof state.env.footnotes.refs[':' + label] === 'undefined') { return false; } + + if (!silent) { + if (!state.env.footnotes.list) { state.env.footnotes.list = []; } + + if (state.env.footnotes.refs[':' + label] < 0) { + footnoteId = state.env.footnotes.list.length; + state.env.footnotes.list[footnoteId] = { label: label, count: 0 }; + state.env.footnotes.refs[':' + label] = footnoteId; + } else { + footnoteId = state.env.footnotes.refs[':' + label]; + } + + footnoteSubId = state.env.footnotes.list[footnoteId].count; + state.env.footnotes.list[footnoteId].count++; + + state.push({ + type: 'footnote_ref', + id: footnoteId, + subId: footnoteSubId, + level: state.level + }); + } + + state.pos = pos; + state.posMax = max; + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/htmltag.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/htmltag.js new file mode 100644 index 0000000..db3dd76 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/htmltag.js @@ -0,0 +1,49 @@ +// Process html tags + +'use strict'; + + +var HTML_TAG_RE = require('../common/html_re').HTML_TAG_RE; + + +function isLetter(ch) { + /*eslint no-bitwise:0*/ + var lc = ch | 0x20; // to lower case + return (lc >= 0x61/* a */) && (lc <= 0x7a/* z */); +} + + +module.exports = function htmltag(state, silent) { + var ch, match, max, pos = state.pos; + + if (!state.options.html) { return false; } + + // Check start + max = state.posMax; + if (state.src.charCodeAt(pos) !== 0x3C/* < */ || + pos + 2 >= max) { + return false; + } + + // Quick fail on second char + ch = state.src.charCodeAt(pos + 1); + if (ch !== 0x21/* ! */ && + ch !== 0x3F/* ? */ && + ch !== 0x2F/* / */ && + !isLetter(ch)) { + return false; + } + + match = state.src.slice(pos).match(HTML_TAG_RE); + if (!match) { return false; } + + if (!silent) { + state.push({ + type: 'htmltag', + content: state.src.slice(pos, pos + match[0].length), + level: state.level + }); + } + state.pos += match[0].length; + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/ins.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/ins.js new file mode 100644 index 0000000..2924ea7 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/ins.js @@ -0,0 +1,102 @@ +'use strict'; + + +// parse sequence of markers, +// "start" should point at a valid marker +function scanDelims(state, start) { + var pos = start, lastChar, nextChar, count, + can_open = true, + can_close = true, + max = state.posMax, + marker = state.src.charCodeAt(start); + + lastChar = start > 0 ? state.src.charCodeAt(start - 1) : -1; + + while (pos < max && state.src.charCodeAt(pos) === marker) { pos++; } + if (pos >= max) { can_open = false; } + count = pos - start; + + nextChar = pos < max ? state.src.charCodeAt(pos) : -1; + + // check whitespace conditions + if (nextChar === 0x20 || nextChar === 0x0A) { can_open = false; } + if (lastChar === 0x20 || lastChar === 0x0A) { can_close = false; } + + return { + can_open: can_open, + can_close: can_close, + delims: count + }; +} + +module.exports = function(state, silent) { + var startCount, + count, + tagCount, + found, + stack, + res, + max = state.posMax, + start = state.pos, + marker = state.src.charCodeAt(start); + + if (marker !== 0x2B/* + */) { return false; } + if (silent) { return false; } // don't run any pairs in validation mode + + res = scanDelims(state, start); + startCount = res.delims; + if (!res.can_open) { + state.pos += startCount; + if (!silent) { state.pending += state.src.slice(start, state.pos); } + return true; + } + + if (state.level >= state.options.maxNesting) { return false; } + stack = Math.floor(startCount / 2); + if (stack <= 0) { return false; } + state.pos = start + startCount; + + while (state.pos < max) { + if (state.src.charCodeAt(state.pos) === marker) { + res = scanDelims(state, state.pos); + count = res.delims; + tagCount = Math.floor(count / 2); + if (res.can_close) { + if (tagCount >= stack) { + state.pos += count - 2; + found = true; + break; + } + stack -= tagCount; + state.pos += count; + continue; + } + + if (res.can_open) { stack += tagCount; } + state.pos += count; + continue; + } + + state.parser.skipToken(state); + } + + if (!found) { + // parser failed to find ending tag, so it's not valid emphasis + state.pos = start; + return false; + } + + // found! + state.posMax = state.pos; + state.pos = start + 2; + + if (!silent) { + state.push({ type: 'ins_open', level: state.level++ }); + state.parser.tokenize(state); + state.push({ type: 'ins_close', level: --state.level }); + } + + state.pos = state.posMax + 2; + state.posMax = max; + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/links.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/links.js new file mode 100644 index 0000000..92622fa --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/links.js @@ -0,0 +1,175 @@ +// Process [links]( "stuff") + +'use strict'; + +var parseLinkLabel = require('../helpers/parse_link_label'); +var parseLinkDestination = require('../helpers/parse_link_destination'); +var parseLinkTitle = require('../helpers/parse_link_title'); +var normalizeReference = require('../helpers/normalize_reference'); +var StateInline = require('../rules_inline/state_inline'); + + +module.exports = function links(state, silent) { + var code, + href, + label, + labelEnd, + labelStart, + pos, + ref, + title, + tokens, + isImage = false, + oldPos = state.pos, + max = state.posMax, + start = state.pos, + marker = state.src.charCodeAt(start); + + if (marker === 0x21/* ! */) { + isImage = true; + marker = state.src.charCodeAt(++start); + } + + if (marker !== 0x5B/* [ */) { return false; } + if (state.level >= state.options.maxNesting) { return false; } + + labelStart = start + 1; + labelEnd = parseLinkLabel(state, start, !isImage); + + // parser failed to find ']', so it's not a valid link + if (labelEnd < 0) { return false; } + + pos = labelEnd + 1; + if (pos < max && state.src.charCodeAt(pos) === 0x28/* ( */) { + // + // Inline link + // + + // [link]( "title" ) + // ^^ skipping these spaces + pos++; + for (; pos < max; pos++) { + code = state.src.charCodeAt(pos); + if (code !== 0x20 && code !== 0x0A) { break; } + } + if (pos >= max) { return false; } + + // [link]( "title" ) + // ^^^^^^ parsing link destination + start = pos; + if (parseLinkDestination(state, pos)) { + href = state.linkContent; + pos = state.pos; + } else { + href = ''; + } + + // [link]( "title" ) + // ^^ skipping these spaces + start = pos; + for (; pos < max; pos++) { + code = state.src.charCodeAt(pos); + if (code !== 0x20 && code !== 0x0A) { break; } + } + + // [link]( "title" ) + // ^^^^^^^ parsing link title + if (pos < max && start !== pos && parseLinkTitle(state, pos)) { + title = state.linkContent; + pos = state.pos; + + // [link]( "title" ) + // ^^ skipping these spaces + for (; pos < max; pos++) { + code = state.src.charCodeAt(pos); + if (code !== 0x20 && code !== 0x0A) { break; } + } + } else { + title = ''; + } + + if (pos >= max || state.src.charCodeAt(pos) !== 0x29/* ) */) { + state.pos = oldPos; + return false; + } + pos++; + } else { + // + // Link reference + // + if (typeof state.env.references === 'undefined') { return false; } + + // [foo] [bar] + // ^^ optional whitespace (can include newlines) + for (; pos < max; pos++) { + code = state.src.charCodeAt(pos); + if (code !== 0x20 && code !== 0x0A) { break; } + } + + if (pos < max && state.src.charCodeAt(pos) === 0x5B/* [ */) { + start = pos + 1; + pos = parseLinkLabel(state, pos); + if (pos >= 0) { + label = state.src.slice(start, pos++); + } else { + pos = labelEnd + 1; + } + } else { + pos = labelEnd + 1; + } + + // covers label === '' and label === undefined + // (collapsed reference link and shortcut reference link respectively) + if (!label) { label = state.src.slice(labelStart, labelEnd); } + + ref = state.env.references[normalizeReference(label)]; + if (!ref) { + state.pos = oldPos; + return false; + } + href = ref.href; + title = ref.title; + } + + // + // We found the end of the link, and know for a fact it's a valid link; + // so all that's left to do is to call tokenizer. + // + if (!silent) { + state.pos = labelStart; + state.posMax = labelEnd; + + if (isImage) { + var newState = new StateInline( + state.src.slice(labelStart, labelEnd), + state.parser, + state.options, + state.env, + tokens = [] + ); + newState.parser.tokenize(newState); + + state.push({ + type: 'image', + src: href, + title: title, + tokens: tokens, + level: state.level + }); + } else { + state.push({ + type: 'link_open', + href: href, + target: '', + title: title, + level: state.level++ + }); + state.parser.tokenize(state); + state.push({ type: 'link_close', level: --state.level }); + } + } + + state.pos = pos; + state.posMax = max; + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/mark.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/mark.js new file mode 100644 index 0000000..e2c88dd --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/mark.js @@ -0,0 +1,102 @@ +'use strict'; + + +// parse sequence of markers, +// "start" should point at a valid marker +function scanDelims(state, start) { + var pos = start, lastChar, nextChar, count, + can_open = true, + can_close = true, + max = state.posMax, + marker = state.src.charCodeAt(start); + + lastChar = start > 0 ? state.src.charCodeAt(start - 1) : -1; + + while (pos < max && state.src.charCodeAt(pos) === marker) { pos++; } + if (pos >= max) { can_open = false; } + count = pos - start; + + nextChar = pos < max ? state.src.charCodeAt(pos) : -1; + + // check whitespace conditions + if (nextChar === 0x20 || nextChar === 0x0A) { can_open = false; } + if (lastChar === 0x20 || lastChar === 0x0A) { can_close = false; } + + return { + can_open: can_open, + can_close: can_close, + delims: count + }; +} + +module.exports = function(state, silent) { + var startCount, + count, + tagCount, + found, + stack, + res, + max = state.posMax, + start = state.pos, + marker = state.src.charCodeAt(start); + + if (marker !== 0x3D/* = */) { return false; } + if (silent) { return false; } // don't run any pairs in validation mode + + res = scanDelims(state, start); + startCount = res.delims; + if (!res.can_open) { + state.pos += startCount; + if (!silent) { state.pending += state.src.slice(start, state.pos); } + return true; + } + + if (state.level >= state.options.maxNesting) { return false; } + stack = Math.floor(startCount / 2); + if (stack <= 0) { return false; } + state.pos = start + startCount; + + while (state.pos < max) { + if (state.src.charCodeAt(state.pos) === marker) { + res = scanDelims(state, state.pos); + count = res.delims; + tagCount = Math.floor(count / 2); + if (res.can_close) { + if (tagCount >= stack) { + state.pos += count - 2; + found = true; + break; + } + stack -= tagCount; + state.pos += count; + continue; + } + + if (res.can_open) { stack += tagCount; } + state.pos += count; + continue; + } + + state.parser.skipToken(state); + } + + if (!found) { + // parser failed to find ending tag, so it's not valid emphasis + state.pos = start; + return false; + } + + // found! + state.posMax = state.pos; + state.pos = start + 2; + + if (!silent) { + state.push({ type: 'mark_open', level: state.level++ }); + state.parser.tokenize(state); + state.push({ type: 'mark_close', level: --state.level }); + } + + state.pos = state.posMax + 2; + state.posMax = max; + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/newline.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/newline.js new file mode 100644 index 0000000..926049b --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/newline.js @@ -0,0 +1,48 @@ +// Proceess '\n' + +'use strict'; + +module.exports = function newline(state, silent) { + var pmax, max, pos = state.pos; + + if (state.src.charCodeAt(pos) !== 0x0A/* \n */) { return false; } + + pmax = state.pending.length - 1; + max = state.posMax; + + // ' \n' -> hardbreak + // Lookup in pending chars is bad practice! Don't copy to other rules! + // Pending string is stored in concat mode, indexed lookups will cause + // convertion to flat mode. + if (!silent) { + if (pmax >= 0 && state.pending.charCodeAt(pmax) === 0x20) { + if (pmax >= 1 && state.pending.charCodeAt(pmax - 1) === 0x20) { + state.pending = state.pending.replace(/ +$/, ''); + state.push({ + type: 'hardbreak', + level: state.level + }); + } else { + state.pending = state.pending.slice(0, -1); + state.push({ + type: 'softbreak', + level: state.level + }); + } + + } else { + state.push({ + type: 'softbreak', + level: state.level + }); + } + } + + pos++; + + // skip heading spaces for next line + while (pos < max && state.src.charCodeAt(pos) === 0x20) { pos++; } + + state.pos = pos; + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/state_inline.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/state_inline.js new file mode 100644 index 0000000..954c562 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/state_inline.js @@ -0,0 +1,75 @@ +// Inline parser state + +'use strict'; + + +function StateInline(src, parserInline, options, env, outTokens) { + this.src = src; + this.env = env; + this.options = options; + this.parser = parserInline; + this.tokens = outTokens; + this.pos = 0; + this.posMax = this.src.length; + this.level = 0; + this.pending = ''; + this.pendingLevel = 0; + + this.cache = []; // Stores { start: end } pairs. Useful for backtrack + // optimization of pairs parse (emphasis, strikes). + + // Link parser state vars + + this.linkContent = ''; // Temporary storage for link url + + this.labelUnmatchedScopes = 0; // Track unpaired `[` for link labels + // (backtrack optimization) +} + + +// Flush pending text +// +StateInline.prototype.pushPending = function () { + this.tokens.push({ + type: 'text', + content: this.pending, + level: this.pendingLevel + }); + this.pending = ''; +}; + + +// Push new token to "stream". +// If pending text exists - flush it as text token +// +StateInline.prototype.push = function (token) { + if (this.pending) { + this.pushPending(); + } + + this.tokens.push(token); + this.pendingLevel = this.level; +}; + + +// Store value to cache. +// !!! Implementation has parser-specific optimizations +// !!! keys MUST be integer, >= 0; values MUST be integer, > 0 +// +StateInline.prototype.cacheSet = function (key, val) { + for (var i = this.cache.length; i <= key; i++) { + this.cache.push(0); + } + + this.cache[key] = val; +}; + + +// Get cache value +// +StateInline.prototype.cacheGet = function (key) { + return key < this.cache.length ? this.cache[key] : 0; +}; + + +module.exports = StateInline; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/sub.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/sub.js new file mode 100644 index 0000000..a126e9a --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/sub.js @@ -0,0 +1,58 @@ +// Process ~subscript~ + +'use strict'; + +// same as UNESCAPE_MD_RE plus a space +var UNESCAPE_RE = /\\([ \\!"#$%&'()*+,.\/:;<=>?@[\]^_`{|}~-])/g; + +module.exports = function sub(state, silent) { + var found, + content, + max = state.posMax, + start = state.pos; + + if (state.src.charCodeAt(start) !== 0x7E/* ~ */) { return false; } + if (silent) { return false; } // don't run any pairs in validation mode + if (start + 2 >= max) { return false; } + if (state.level >= state.options.maxNesting) { return false; } + + state.pos = start + 1; + + while (state.pos < max) { + if (state.src.charCodeAt(state.pos) === 0x7E/* ~ */) { + found = true; + break; + } + + state.parser.skipToken(state); + } + + if (!found || start + 1 === state.pos) { + state.pos = start; + return false; + } + + content = state.src.slice(start + 1, state.pos); + + // don't allow unescaped spaces/newlines inside + if (content.match(/(^|[^\\])(\\\\)*\s/)) { + state.pos = start; + return false; + } + + // found! + state.posMax = state.pos; + state.pos = start + 1; + + if (!silent) { + state.push({ + type: 'sub', + level: state.level, + content: content.replace(UNESCAPE_RE, '$1') + }); + } + + state.pos = state.posMax + 1; + state.posMax = max; + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/sup.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/sup.js new file mode 100644 index 0000000..07bf357 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/sup.js @@ -0,0 +1,58 @@ +// Process ^superscript^ + +'use strict'; + +// same as UNESCAPE_MD_RE plus a space +var UNESCAPE_RE = /\\([ \\!"#$%&'()*+,.\/:;<=>?@[\]^_`{|}~-])/g; + +module.exports = function sup(state, silent) { + var found, + content, + max = state.posMax, + start = state.pos; + + if (state.src.charCodeAt(start) !== 0x5E/* ^ */) { return false; } + if (silent) { return false; } // don't run any pairs in validation mode + if (start + 2 >= max) { return false; } + if (state.level >= state.options.maxNesting) { return false; } + + state.pos = start + 1; + + while (state.pos < max) { + if (state.src.charCodeAt(state.pos) === 0x5E/* ^ */) { + found = true; + break; + } + + state.parser.skipToken(state); + } + + if (!found || start + 1 === state.pos) { + state.pos = start; + return false; + } + + content = state.src.slice(start + 1, state.pos); + + // don't allow unescaped spaces/newlines inside + if (content.match(/(^|[^\\])(\\\\)*\s/)) { + state.pos = start; + return false; + } + + // found! + state.posMax = state.pos; + state.pos = start + 1; + + if (!silent) { + state.push({ + type: 'sup', + level: state.level, + content: content.replace(UNESCAPE_RE, '$1') + }); + } + + state.pos = state.posMax + 1; + state.posMax = max; + return true; +}; diff --git a/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/text.js b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/text.js new file mode 100644 index 0000000..d02bb26 --- /dev/null +++ b/benchmark/implementations/markdown-it-2.2.1-commonmark/src/lib/rules_inline/text.js @@ -0,0 +1,53 @@ +// Skip text characters for text token, place those to pending buffer +// and increment current pos + +'use strict'; + + +// Rule to skip pure text +// '{}$%@~+=:' reserved for extentions + +function isTerminatorChar(ch) { + switch (ch) { + case 0x0A/* \n */: + case 0x5C/* \ */: + case 0x60/* ` */: + case 0x2A/* * */: + case 0x5F/* _ */: + case 0x5E/* ^ */: + case 0x5B/* [ */: + case 0x5D/* ] */: + case 0x21/* ! */: + case 0x26/* & */: + case 0x3C/* < */: + case 0x3E/* > */: + case 0x7B/* { */: + case 0x7D/* } */: + case 0x24/* $ */: + case 0x25/* % */: + case 0x40/* @ */: + case 0x7E/* ~ */: + case 0x2B/* + */: + case 0x3D/* = */: + case 0x3A/* : */: + return true; + default: + return false; + } +} + +module.exports = function text(state, silent) { + var pos = state.pos; + + while (pos < state.posMax && !isTerminatorChar(state.src.charCodeAt(pos))) { + pos++; + } + + if (pos === state.pos) { return false; } + + if (!silent) { state.pending += state.src.slice(state.pos, pos); } + + state.pos = pos; + + return true; +};