/ src / theme / languages / javascript.js
javascript.js
  1  /*! `javascript` grammar compiled for Highlight.js 11.10.0 */
  2    (function(){
  3      var hljsGrammar = (function () {
  4    'use strict';
  5  
  6    const IDENT_RE = '[A-Za-z$_][0-9A-Za-z$_]*';
  7    const KEYWORDS = [
  8      "as", // for exports
  9      "in",
 10      "of",
 11      "if",
 12      "for",
 13      "while",
 14      "finally",
 15      "var",
 16      "new",
 17      "function",
 18      "do",
 19      "return",
 20      "void",
 21      "else",
 22      "break",
 23      "catch",
 24      "instanceof",
 25      "with",
 26      "throw",
 27      "case",
 28      "default",
 29      "try",
 30      "switch",
 31      "continue",
 32      "typeof",
 33      "delete",
 34      "let",
 35      "yield",
 36      "const",
 37      "class",
 38      // JS handles these with a special rule
 39      // "get",
 40      // "set",
 41      "debugger",
 42      "async",
 43      "await",
 44      "static",
 45      "import",
 46      "from",
 47      "export",
 48      "extends"
 49    ];
 50    const LITERALS = [
 51      "true",
 52      "false",
 53      "null",
 54      "undefined",
 55      "NaN",
 56      "Infinity"
 57    ];
 58  
 59    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects
 60    const TYPES = [
 61      // Fundamental objects
 62      "Object",
 63      "Function",
 64      "Boolean",
 65      "Symbol",
 66      // numbers and dates
 67      "Math",
 68      "Date",
 69      "Number",
 70      "BigInt",
 71      // text
 72      "String",
 73      "RegExp",
 74      // Indexed collections
 75      "Array",
 76      "Float32Array",
 77      "Float64Array",
 78      "Int8Array",
 79      "Uint8Array",
 80      "Uint8ClampedArray",
 81      "Int16Array",
 82      "Int32Array",
 83      "Uint16Array",
 84      "Uint32Array",
 85      "BigInt64Array",
 86      "BigUint64Array",
 87      // Keyed collections
 88      "Set",
 89      "Map",
 90      "WeakSet",
 91      "WeakMap",
 92      // Structured data
 93      "ArrayBuffer",
 94      "SharedArrayBuffer",
 95      "Atomics",
 96      "DataView",
 97      "JSON",
 98      // Control abstraction objects
 99      "Promise",
100      "Generator",
101      "GeneratorFunction",
102      "AsyncFunction",
103      // Reflection
104      "Reflect",
105      "Proxy",
106      // Internationalization
107      "Intl",
108      // WebAssembly
109      "WebAssembly"
110    ];
111  
112    const ERROR_TYPES = [
113      "Error",
114      "EvalError",
115      "InternalError",
116      "RangeError",
117      "ReferenceError",
118      "SyntaxError",
119      "TypeError",
120      "URIError"
121    ];
122  
123    const BUILT_IN_GLOBALS = [
124      "setInterval",
125      "setTimeout",
126      "clearInterval",
127      "clearTimeout",
128  
129      "require",
130      "exports",
131  
132      "eval",
133      "isFinite",
134      "isNaN",
135      "parseFloat",
136      "parseInt",
137      "decodeURI",
138      "decodeURIComponent",
139      "encodeURI",
140      "encodeURIComponent",
141      "escape",
142      "unescape"
143    ];
144  
145    const BUILT_IN_VARIABLES = [
146      "arguments",
147      "this",
148      "super",
149      "console",
150      "window",
151      "document",
152      "localStorage",
153      "sessionStorage",
154      "module",
155      "global" // Node.js
156    ];
157  
158    const BUILT_INS = [].concat(
159      BUILT_IN_GLOBALS,
160      TYPES,
161      ERROR_TYPES
162    );
163  
164    /*
165    Language: JavaScript
166    Description: JavaScript (JS) is a lightweight, interpreted, or just-in-time compiled programming language with first-class functions.
167    Category: common, scripting, web
168    Website: https://developer.mozilla.org/en-US/docs/Web/JavaScript
169    */
170  
171  
172    /** @type LanguageFn */
173    function javascript(hljs) {
174      const regex = hljs.regex;
175      /**
176       * Takes a string like "<Booger" and checks to see
177       * if we can find a matching "</Booger" later in the
178       * content.
179       * @param {RegExpMatchArray} match
180       * @param {{after:number}} param1
181       */
182      const hasClosingTag = (match, { after }) => {
183        const tag = "</" + match[0].slice(1);
184        const pos = match.input.indexOf(tag, after);
185        return pos !== -1;
186      };
187  
188      const IDENT_RE$1 = IDENT_RE;
189      const FRAGMENT = {
190        begin: '<>',
191        end: '</>'
192      };
193      // to avoid some special cases inside isTrulyOpeningTag
194      const XML_SELF_CLOSING = /<[A-Za-z0-9\\._:-]+\s*\/>/;
195      const XML_TAG = {
196        begin: /<[A-Za-z0-9\\._:-]+/,
197        end: /\/[A-Za-z0-9\\._:-]+>|\/>/,
198        /**
199         * @param {RegExpMatchArray} match
200         * @param {CallbackResponse} response
201         */
202        isTrulyOpeningTag: (match, response) => {
203          const afterMatchIndex = match[0].length + match.index;
204          const nextChar = match.input[afterMatchIndex];
205          if (
206            // HTML should not include another raw `<` inside a tag
207            // nested type?
208            // `<Array<Array<number>>`, etc.
209            nextChar === "<" ||
210            // the , gives away that this is not HTML
211            // `<T, A extends keyof T, V>`
212            nextChar === ","
213            ) {
214            response.ignoreMatch();
215            return;
216          }
217  
218          // `<something>`
219          // Quite possibly a tag, lets look for a matching closing tag...
220          if (nextChar === ">") {
221            // if we cannot find a matching closing tag, then we
222            // will ignore it
223            if (!hasClosingTag(match, { after: afterMatchIndex })) {
224              response.ignoreMatch();
225            }
226          }
227  
228          // `<blah />` (self-closing)
229          // handled by simpleSelfClosing rule
230  
231          let m;
232          const afterMatch = match.input.substring(afterMatchIndex);
233  
234          // some more template typing stuff
235          //  <T = any>(key?: string) => Modify<
236          if ((m = afterMatch.match(/^\s*=/))) {
237            response.ignoreMatch();
238            return;
239          }
240  
241          // `<From extends string>`
242          // technically this could be HTML, but it smells like a type
243          // NOTE: This is ugh, but added specifically for https://github.com/highlightjs/highlight.js/issues/3276
244          if ((m = afterMatch.match(/^\s+extends\s+/))) {
245            if (m.index === 0) {
246              response.ignoreMatch();
247              // eslint-disable-next-line no-useless-return
248              return;
249            }
250          }
251        }
252      };
253      const KEYWORDS$1 = {
254        $pattern: IDENT_RE,
255        keyword: KEYWORDS,
256        literal: LITERALS,
257        built_in: BUILT_INS,
258        "variable.language": BUILT_IN_VARIABLES
259      };
260  
261      // https://tc39.es/ecma262/#sec-literals-numeric-literals
262      const decimalDigits = '[0-9](_?[0-9])*';
263      const frac = `\\.(${decimalDigits})`;
264      // DecimalIntegerLiteral, including Annex B NonOctalDecimalIntegerLiteral
265      // https://tc39.es/ecma262/#sec-additional-syntax-numeric-literals
266      const decimalInteger = `0|[1-9](_?[0-9])*|0[0-7]*[89][0-9]*`;
267      const NUMBER = {
268        className: 'number',
269        variants: [
270          // DecimalLiteral
271          { begin: `(\\b(${decimalInteger})((${frac})|\\.)?|(${frac}))` +
272            `[eE][+-]?(${decimalDigits})\\b` },
273          { begin: `\\b(${decimalInteger})\\b((${frac})\\b|\\.)?|(${frac})\\b` },
274  
275          // DecimalBigIntegerLiteral
276          { begin: `\\b(0|[1-9](_?[0-9])*)n\\b` },
277  
278          // NonDecimalIntegerLiteral
279          { begin: "\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*n?\\b" },
280          { begin: "\\b0[bB][0-1](_?[0-1])*n?\\b" },
281          { begin: "\\b0[oO][0-7](_?[0-7])*n?\\b" },
282  
283          // LegacyOctalIntegerLiteral (does not include underscore separators)
284          // https://tc39.es/ecma262/#sec-additional-syntax-numeric-literals
285          { begin: "\\b0[0-7]+n?\\b" },
286        ],
287        relevance: 0
288      };
289  
290      const SUBST = {
291        className: 'subst',
292        begin: '\\$\\{',
293        end: '\\}',
294        keywords: KEYWORDS$1,
295        contains: [] // defined later
296      };
297      const HTML_TEMPLATE = {
298        begin: '\.?html`',
299        end: '',
300        starts: {
301          end: '`',
302          returnEnd: false,
303          contains: [
304            hljs.BACKSLASH_ESCAPE,
305            SUBST
306          ],
307          subLanguage: 'xml'
308        }
309      };
310      const CSS_TEMPLATE = {
311        begin: '\.?css`',
312        end: '',
313        starts: {
314          end: '`',
315          returnEnd: false,
316          contains: [
317            hljs.BACKSLASH_ESCAPE,
318            SUBST
319          ],
320          subLanguage: 'css'
321        }
322      };
323      const GRAPHQL_TEMPLATE = {
324        begin: '\.?gql`',
325        end: '',
326        starts: {
327          end: '`',
328          returnEnd: false,
329          contains: [
330            hljs.BACKSLASH_ESCAPE,
331            SUBST
332          ],
333          subLanguage: 'graphql'
334        }
335      };
336      const TEMPLATE_STRING = {
337        className: 'string',
338        begin: '`',
339        end: '`',
340        contains: [
341          hljs.BACKSLASH_ESCAPE,
342          SUBST
343        ]
344      };
345      const JSDOC_COMMENT = hljs.COMMENT(
346        /\/\*\*(?!\/)/,
347        '\\*/',
348        {
349          relevance: 0,
350          contains: [
351            {
352              begin: '(?=@[A-Za-z]+)',
353              relevance: 0,
354              contains: [
355                {
356                  className: 'doctag',
357                  begin: '@[A-Za-z]+'
358                },
359                {
360                  className: 'type',
361                  begin: '\\{',
362                  end: '\\}',
363                  excludeEnd: true,
364                  excludeBegin: true,
365                  relevance: 0
366                },
367                {
368                  className: 'variable',
369                  begin: IDENT_RE$1 + '(?=\\s*(-)|$)',
370                  endsParent: true,
371                  relevance: 0
372                },
373                // eat spaces (not newlines) so we can find
374                // types or variables
375                {
376                  begin: /(?=[^\n])\s/,
377                  relevance: 0
378                }
379              ]
380            }
381          ]
382        }
383      );
384      const COMMENT = {
385        className: "comment",
386        variants: [
387          JSDOC_COMMENT,
388          hljs.C_BLOCK_COMMENT_MODE,
389          hljs.C_LINE_COMMENT_MODE
390        ]
391      };
392      const SUBST_INTERNALS = [
393        hljs.APOS_STRING_MODE,
394        hljs.QUOTE_STRING_MODE,
395        HTML_TEMPLATE,
396        CSS_TEMPLATE,
397        GRAPHQL_TEMPLATE,
398        TEMPLATE_STRING,
399        // Skip numbers when they are part of a variable name
400        { match: /\$\d+/ },
401        NUMBER,
402        // This is intentional:
403        // See https://github.com/highlightjs/highlight.js/issues/3288
404        // hljs.REGEXP_MODE
405      ];
406      SUBST.contains = SUBST_INTERNALS
407        .concat({
408          // we need to pair up {} inside our subst to prevent
409          // it from ending too early by matching another }
410          begin: /\{/,
411          end: /\}/,
412          keywords: KEYWORDS$1,
413          contains: [
414            "self"
415          ].concat(SUBST_INTERNALS)
416        });
417      const SUBST_AND_COMMENTS = [].concat(COMMENT, SUBST.contains);
418      const PARAMS_CONTAINS = SUBST_AND_COMMENTS.concat([
419        // eat recursive parens in sub expressions
420        {
421          begin: /(\s*)\(/,
422          end: /\)/,
423          keywords: KEYWORDS$1,
424          contains: ["self"].concat(SUBST_AND_COMMENTS)
425        }
426      ]);
427      const PARAMS = {
428        className: 'params',
429        // convert this to negative lookbehind in v12
430        begin: /(\s*)\(/, // to match the parms with 
431        end: /\)/,
432        excludeBegin: true,
433        excludeEnd: true,
434        keywords: KEYWORDS$1,
435        contains: PARAMS_CONTAINS
436      };
437  
438      // ES6 classes
439      const CLASS_OR_EXTENDS = {
440        variants: [
441          // class Car extends vehicle
442          {
443            match: [
444              /class/,
445              /\s+/,
446              IDENT_RE$1,
447              /\s+/,
448              /extends/,
449              /\s+/,
450              regex.concat(IDENT_RE$1, "(", regex.concat(/\./, IDENT_RE$1), ")*")
451            ],
452            scope: {
453              1: "keyword",
454              3: "title.class",
455              5: "keyword",
456              7: "title.class.inherited"
457            }
458          },
459          // class Car
460          {
461            match: [
462              /class/,
463              /\s+/,
464              IDENT_RE$1
465            ],
466            scope: {
467              1: "keyword",
468              3: "title.class"
469            }
470          },
471  
472        ]
473      };
474  
475      const CLASS_REFERENCE = {
476        relevance: 0,
477        match:
478        regex.either(
479          // Hard coded exceptions
480          /\bJSON/,
481          // Float32Array, OutT
482          /\b[A-Z][a-z]+([A-Z][a-z]*|\d)*/,
483          // CSSFactory, CSSFactoryT
484          /\b[A-Z]{2,}([A-Z][a-z]+|\d)+([A-Z][a-z]*)*/,
485          // FPs, FPsT
486          /\b[A-Z]{2,}[a-z]+([A-Z][a-z]+|\d)*([A-Z][a-z]*)*/,
487          // P
488          // single letters are not highlighted
489          // BLAH
490          // this will be flagged as a UPPER_CASE_CONSTANT instead
491        ),
492        className: "title.class",
493        keywords: {
494          _: [
495            // se we still get relevance credit for JS library classes
496            ...TYPES,
497            ...ERROR_TYPES
498          ]
499        }
500      };
501  
502      const USE_STRICT = {
503        label: "use_strict",
504        className: 'meta',
505        relevance: 10,
506        begin: /^\s*['"]use (strict|asm)['"]/
507      };
508  
509      const FUNCTION_DEFINITION = {
510        variants: [
511          {
512            match: [
513              /function/,
514              /\s+/,
515              IDENT_RE$1,
516              /(?=\s*\()/
517            ]
518          },
519          // anonymous function
520          {
521            match: [
522              /function/,
523              /\s*(?=\()/
524            ]
525          }
526        ],
527        className: {
528          1: "keyword",
529          3: "title.function"
530        },
531        label: "func.def",
532        contains: [ PARAMS ],
533        illegal: /%/
534      };
535  
536      const UPPER_CASE_CONSTANT = {
537        relevance: 0,
538        match: /\b[A-Z][A-Z_0-9]+\b/,
539        className: "variable.constant"
540      };
541  
542      function noneOf(list) {
543        return regex.concat("(?!", list.join("|"), ")");
544      }
545  
546      const FUNCTION_CALL = {
547        match: regex.concat(
548          /\b/,
549          noneOf([
550            ...BUILT_IN_GLOBALS,
551            "super",
552            "import"
553          ].map(x => `${x}\\s*\\(`)),
554          IDENT_RE$1, regex.lookahead(/\s*\(/)),
555        className: "title.function",
556        relevance: 0
557      };
558  
559      const PROPERTY_ACCESS = {
560        begin: regex.concat(/\./, regex.lookahead(
561          regex.concat(IDENT_RE$1, /(?![0-9A-Za-z$_(])/)
562        )),
563        end: IDENT_RE$1,
564        excludeBegin: true,
565        keywords: "prototype",
566        className: "property",
567        relevance: 0
568      };
569  
570      const GETTER_OR_SETTER = {
571        match: [
572          /get|set/,
573          /\s+/,
574          IDENT_RE$1,
575          /(?=\()/
576        ],
577        className: {
578          1: "keyword",
579          3: "title.function"
580        },
581        contains: [
582          { // eat to avoid empty params
583            begin: /\(\)/
584          },
585          PARAMS
586        ]
587      };
588  
589      const FUNC_LEAD_IN_RE = '(\\(' +
590        '[^()]*(\\(' +
591        '[^()]*(\\(' +
592        '[^()]*' +
593        '\\)[^()]*)*' +
594        '\\)[^()]*)*' +
595        '\\)|' + hljs.UNDERSCORE_IDENT_RE + ')\\s*=>';
596  
597      const FUNCTION_VARIABLE = {
598        match: [
599          /const|var|let/, /\s+/,
600          IDENT_RE$1, /\s*/,
601          /=\s*/,
602          /(async\s*)?/, // async is optional
603          regex.lookahead(FUNC_LEAD_IN_RE)
604        ],
605        keywords: "async",
606        className: {
607          1: "keyword",
608          3: "title.function"
609        },
610        contains: [
611          PARAMS
612        ]
613      };
614  
615      return {
616        name: 'JavaScript',
617        aliases: ['js', 'jsx', 'mjs', 'cjs'],
618        keywords: KEYWORDS$1,
619        // this will be extended by TypeScript
620        exports: { PARAMS_CONTAINS, CLASS_REFERENCE },
621        illegal: /#(?![$_A-z])/,
622        contains: [
623          hljs.SHEBANG({
624            label: "shebang",
625            binary: "node",
626            relevance: 5
627          }),
628          USE_STRICT,
629          hljs.APOS_STRING_MODE,
630          hljs.QUOTE_STRING_MODE,
631          HTML_TEMPLATE,
632          CSS_TEMPLATE,
633          GRAPHQL_TEMPLATE,
634          TEMPLATE_STRING,
635          COMMENT,
636          // Skip numbers when they are part of a variable name
637          { match: /\$\d+/ },
638          NUMBER,
639          CLASS_REFERENCE,
640          {
641            className: 'attr',
642            begin: IDENT_RE$1 + regex.lookahead(':'),
643            relevance: 0
644          },
645          FUNCTION_VARIABLE,
646          { // "value" container
647            begin: '(' + hljs.RE_STARTERS_RE + '|\\b(case|return|throw)\\b)\\s*',
648            keywords: 'return throw case',
649            relevance: 0,
650            contains: [
651              COMMENT,
652              hljs.REGEXP_MODE,
653              {
654                className: 'function',
655                // we have to count the parens to make sure we actually have the
656                // correct bounding ( ) before the =>.  There could be any number of
657                // sub-expressions inside also surrounded by parens.
658                begin: FUNC_LEAD_IN_RE,
659                returnBegin: true,
660                end: '\\s*=>',
661                contains: [
662                  {
663                    className: 'params',
664                    variants: [
665                      {
666                        begin: hljs.UNDERSCORE_IDENT_RE,
667                        relevance: 0
668                      },
669                      {
670                        className: null,
671                        begin: /\(\s*\)/,
672                        skip: true
673                      },
674                      {
675                        begin: /(\s*)\(/,
676                        end: /\)/,
677                        excludeBegin: true,
678                        excludeEnd: true,
679                        keywords: KEYWORDS$1,
680                        contains: PARAMS_CONTAINS
681                      }
682                    ]
683                  }
684                ]
685              },
686              { // could be a comma delimited list of params to a function call
687                begin: /,/,
688                relevance: 0
689              },
690              {
691                match: /\s+/,
692                relevance: 0
693              },
694              { // JSX
695                variants: [
696                  { begin: FRAGMENT.begin, end: FRAGMENT.end },
697                  { match: XML_SELF_CLOSING },
698                  {
699                    begin: XML_TAG.begin,
700                    // we carefully check the opening tag to see if it truly
701                    // is a tag and not a false positive
702                    'on:begin': XML_TAG.isTrulyOpeningTag,
703                    end: XML_TAG.end
704                  }
705                ],
706                subLanguage: 'xml',
707                contains: [
708                  {
709                    begin: XML_TAG.begin,
710                    end: XML_TAG.end,
711                    skip: true,
712                    contains: ['self']
713                  }
714                ]
715              }
716            ],
717          },
718          FUNCTION_DEFINITION,
719          {
720            // prevent this from getting swallowed up by function
721            // since they appear "function like"
722            beginKeywords: "while if switch catch for"
723          },
724          {
725            // we have to count the parens to make sure we actually have the correct
726            // bounding ( ).  There could be any number of sub-expressions inside
727            // also surrounded by parens.
728            begin: '\\b(?!function)' + hljs.UNDERSCORE_IDENT_RE +
729              '\\(' + // first parens
730              '[^()]*(\\(' +
731                '[^()]*(\\(' +
732                  '[^()]*' +
733                '\\)[^()]*)*' +
734              '\\)[^()]*)*' +
735              '\\)\\s*\\{', // end parens
736            returnBegin:true,
737            label: "func.def",
738            contains: [
739              PARAMS,
740              hljs.inherit(hljs.TITLE_MODE, { begin: IDENT_RE$1, className: "title.function" })
741            ]
742          },
743          // catch ... so it won't trigger the property rule below
744          {
745            match: /\.\.\./,
746            relevance: 0
747          },
748          PROPERTY_ACCESS,
749          // hack: prevents detection of keywords in some circumstances
750          // .keyword()
751          // $keyword = x
752          {
753            match: '\\$' + IDENT_RE$1,
754            relevance: 0
755          },
756          {
757            match: [ /\bconstructor(?=\s*\()/ ],
758            className: { 1: "title.function" },
759            contains: [ PARAMS ]
760          },
761          FUNCTION_CALL,
762          UPPER_CASE_CONSTANT,
763          CLASS_OR_EXTENDS,
764          GETTER_OR_SETTER,
765          {
766            match: /\$[(.]/ // relevance booster for a pattern common to JS libs: `$(something)` and `$.something`
767          }
768        ]
769      };
770    }
771  
772    return javascript;
773  
774  })();
775  
776      hljs.registerLanguage('javascript', hljsGrammar);
777    })();