markdown.js
1 /*! `markdown` grammar compiled for Highlight.js 11.10.0 */ 2 (function(){ 3 var hljsGrammar = (function () { 4 'use strict'; 5 6 /* 7 Language: Markdown 8 Requires: xml.js 9 Author: John Crepezzi <john.crepezzi@gmail.com> 10 Website: https://daringfireball.net/projects/markdown/ 11 Category: common, markup 12 */ 13 14 function markdown(hljs) { 15 const regex = hljs.regex; 16 const INLINE_HTML = { 17 begin: /<\/?[A-Za-z_]/, 18 end: '>', 19 subLanguage: 'xml', 20 relevance: 0 21 }; 22 const HORIZONTAL_RULE = { 23 begin: '^[-\\*]{3,}', 24 end: '$' 25 }; 26 const CODE = { 27 className: 'code', 28 variants: [ 29 // TODO: fix to allow these to work with sublanguage also 30 { begin: '(`{3,})[^`](.|\\n)*?\\1`*[ ]*' }, 31 { begin: '(~{3,})[^~](.|\\n)*?\\1~*[ ]*' }, 32 // needed to allow markdown as a sublanguage to work 33 { 34 begin: '```', 35 end: '```+[ ]*$' 36 }, 37 { 38 begin: '~~~', 39 end: '~~~+[ ]*$' 40 }, 41 { begin: '`.+?`' }, 42 { 43 begin: '(?=^( {4}|\\t))', 44 // use contains to gobble up multiple lines to allow the block to be whatever size 45 // but only have a single open/close tag vs one per line 46 contains: [ 47 { 48 begin: '^( {4}|\\t)', 49 end: '(\\n)$' 50 } 51 ], 52 relevance: 0 53 } 54 ] 55 }; 56 const LIST = { 57 className: 'bullet', 58 begin: '^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)', 59 end: '\\s+', 60 excludeEnd: true 61 }; 62 const LINK_REFERENCE = { 63 begin: /^\[[^\n]+\]:/, 64 returnBegin: true, 65 contains: [ 66 { 67 className: 'symbol', 68 begin: /\[/, 69 end: /\]/, 70 excludeBegin: true, 71 excludeEnd: true 72 }, 73 { 74 className: 'link', 75 begin: /:\s*/, 76 end: /$/, 77 excludeBegin: true 78 } 79 ] 80 }; 81 const URL_SCHEME = /[A-Za-z][A-Za-z0-9+.-]*/; 82 const LINK = { 83 variants: [ 84 // too much like nested array access in so many languages 85 // to have any real relevance 86 { 87 begin: /\[.+?\]\[.*?\]/, 88 relevance: 0 89 }, 90 // popular internet URLs 91 { 92 begin: /\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/, 93 relevance: 2 94 }, 95 { 96 begin: regex.concat(/\[.+?\]\(/, URL_SCHEME, /:\/\/.*?\)/), 97 relevance: 2 98 }, 99 // relative urls 100 { 101 begin: /\[.+?\]\([./?&#].*?\)/, 102 relevance: 1 103 }, 104 // whatever else, lower relevance (might not be a link at all) 105 { 106 begin: /\[.*?\]\(.*?\)/, 107 relevance: 0 108 } 109 ], 110 returnBegin: true, 111 contains: [ 112 { 113 // empty strings for alt or link text 114 match: /\[(?=\])/ }, 115 { 116 className: 'string', 117 relevance: 0, 118 begin: '\\[', 119 end: '\\]', 120 excludeBegin: true, 121 returnEnd: true 122 }, 123 { 124 className: 'link', 125 relevance: 0, 126 begin: '\\]\\(', 127 end: '\\)', 128 excludeBegin: true, 129 excludeEnd: true 130 }, 131 { 132 className: 'symbol', 133 relevance: 0, 134 begin: '\\]\\[', 135 end: '\\]', 136 excludeBegin: true, 137 excludeEnd: true 138 } 139 ] 140 }; 141 const BOLD = { 142 className: 'strong', 143 contains: [], // defined later 144 variants: [ 145 { 146 begin: /_{2}(?!\s)/, 147 end: /_{2}/ 148 }, 149 { 150 begin: /\*{2}(?!\s)/, 151 end: /\*{2}/ 152 } 153 ] 154 }; 155 const ITALIC = { 156 className: 'emphasis', 157 contains: [], // defined later 158 variants: [ 159 { 160 begin: /\*(?![*\s])/, 161 end: /\*/ 162 }, 163 { 164 begin: /_(?![_\s])/, 165 end: /_/, 166 relevance: 0 167 } 168 ] 169 }; 170 171 // 3 level deep nesting is not allowed because it would create confusion 172 // in cases like `***testing***` because where we don't know if the last 173 // `***` is starting a new bold/italic or finishing the last one 174 const BOLD_WITHOUT_ITALIC = hljs.inherit(BOLD, { contains: [] }); 175 const ITALIC_WITHOUT_BOLD = hljs.inherit(ITALIC, { contains: [] }); 176 BOLD.contains.push(ITALIC_WITHOUT_BOLD); 177 ITALIC.contains.push(BOLD_WITHOUT_ITALIC); 178 179 let CONTAINABLE = [ 180 INLINE_HTML, 181 LINK 182 ]; 183 184 [ 185 BOLD, 186 ITALIC, 187 BOLD_WITHOUT_ITALIC, 188 ITALIC_WITHOUT_BOLD 189 ].forEach(m => { 190 m.contains = m.contains.concat(CONTAINABLE); 191 }); 192 193 CONTAINABLE = CONTAINABLE.concat(BOLD, ITALIC); 194 195 const HEADER = { 196 className: 'section', 197 variants: [ 198 { 199 begin: '^#{1,6}', 200 end: '$', 201 contains: CONTAINABLE 202 }, 203 { 204 begin: '(?=^.+?\\n[=-]{2,}$)', 205 contains: [ 206 { begin: '^[=-]*$' }, 207 { 208 begin: '^', 209 end: "\\n", 210 contains: CONTAINABLE 211 } 212 ] 213 } 214 ] 215 }; 216 217 const BLOCKQUOTE = { 218 className: 'quote', 219 begin: '^>\\s+', 220 contains: CONTAINABLE, 221 end: '$' 222 }; 223 224 const ENTITY = { 225 //https://spec.commonmark.org/0.31.2/#entity-references 226 scope: 'literal', 227 match: /&([a-zA-Z0-9]+|#[0-9]{1,7}|#[Xx][0-9a-fA-F]{1,6});/ 228 }; 229 230 return { 231 name: 'Markdown', 232 aliases: [ 233 'md', 234 'mkdown', 235 'mkd' 236 ], 237 contains: [ 238 HEADER, 239 INLINE_HTML, 240 LIST, 241 BOLD, 242 ITALIC, 243 BLOCKQUOTE, 244 CODE, 245 HORIZONTAL_RULE, 246 LINK, 247 LINK_REFERENCE, 248 ENTITY 249 ] 250 }; 251 } 252 253 return markdown; 254 255 })(); 256 257 hljs.registerLanguage('markdown', hljsGrammar); 258 })();