/ src / theme / languages / markdown.js
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    })();