source: node_modules/highlight.js/lib/languages/javascript.js@ d24f17c

main
Last change on this file since d24f17c was d24f17c, checked in by Aleksandar Panovski <apano77@…>, 15 months ago

Initial commit

  • Property mode set to 100644
File size: 14.1 KB
RevLine 
[d24f17c]1const IDENT_RE = '[A-Za-z$_][0-9A-Za-z$_]*';
2const KEYWORDS = [
3 "as", // for exports
4 "in",
5 "of",
6 "if",
7 "for",
8 "while",
9 "finally",
10 "var",
11 "new",
12 "function",
13 "do",
14 "return",
15 "void",
16 "else",
17 "break",
18 "catch",
19 "instanceof",
20 "with",
21 "throw",
22 "case",
23 "default",
24 "try",
25 "switch",
26 "continue",
27 "typeof",
28 "delete",
29 "let",
30 "yield",
31 "const",
32 "class",
33 // JS handles these with a special rule
34 // "get",
35 // "set",
36 "debugger",
37 "async",
38 "await",
39 "static",
40 "import",
41 "from",
42 "export",
43 "extends"
44];
45const LITERALS = [
46 "true",
47 "false",
48 "null",
49 "undefined",
50 "NaN",
51 "Infinity"
52];
53
54const TYPES = [
55 "Intl",
56 "DataView",
57 "Number",
58 "Math",
59 "Date",
60 "String",
61 "RegExp",
62 "Object",
63 "Function",
64 "Boolean",
65 "Error",
66 "Symbol",
67 "Set",
68 "Map",
69 "WeakSet",
70 "WeakMap",
71 "Proxy",
72 "Reflect",
73 "JSON",
74 "Promise",
75 "Float64Array",
76 "Int16Array",
77 "Int32Array",
78 "Int8Array",
79 "Uint16Array",
80 "Uint32Array",
81 "Float32Array",
82 "Array",
83 "Uint8Array",
84 "Uint8ClampedArray",
85 "ArrayBuffer",
86 "BigInt64Array",
87 "BigUint64Array",
88 "BigInt"
89];
90
91const ERROR_TYPES = [
92 "EvalError",
93 "InternalError",
94 "RangeError",
95 "ReferenceError",
96 "SyntaxError",
97 "TypeError",
98 "URIError"
99];
100
101const BUILT_IN_GLOBALS = [
102 "setInterval",
103 "setTimeout",
104 "clearInterval",
105 "clearTimeout",
106
107 "require",
108 "exports",
109
110 "eval",
111 "isFinite",
112 "isNaN",
113 "parseFloat",
114 "parseInt",
115 "decodeURI",
116 "decodeURIComponent",
117 "encodeURI",
118 "encodeURIComponent",
119 "escape",
120 "unescape"
121];
122
123const BUILT_IN_VARIABLES = [
124 "arguments",
125 "this",
126 "super",
127 "console",
128 "window",
129 "document",
130 "localStorage",
131 "module",
132 "global" // Node.js
133];
134
135const BUILT_INS = [].concat(
136 BUILT_IN_GLOBALS,
137 BUILT_IN_VARIABLES,
138 TYPES,
139 ERROR_TYPES
140);
141
142/**
143 * @param {string} value
144 * @returns {RegExp}
145 * */
146
147/**
148 * @param {RegExp | string } re
149 * @returns {string}
150 */
151function source(re) {
152 if (!re) return null;
153 if (typeof re === "string") return re;
154
155 return re.source;
156}
157
158/**
159 * @param {RegExp | string } re
160 * @returns {string}
161 */
162function lookahead(re) {
163 return concat('(?=', re, ')');
164}
165
166/**
167 * @param {...(RegExp | string) } args
168 * @returns {string}
169 */
170function concat(...args) {
171 const joined = args.map((x) => source(x)).join("");
172 return joined;
173}
174
175/*
176Language: JavaScript
177Description: JavaScript (JS) is a lightweight, interpreted, or just-in-time compiled programming language with first-class functions.
178Category: common, scripting
179Website: https://developer.mozilla.org/en-US/docs/Web/JavaScript
180*/
181
182/** @type LanguageFn */
183function javascript(hljs) {
184 /**
185 * Takes a string like "<Booger" and checks to see
186 * if we can find a matching "</Booger" later in the
187 * content.
188 * @param {RegExpMatchArray} match
189 * @param {{after:number}} param1
190 */
191 const hasClosingTag = (match, { after }) => {
192 const tag = "</" + match[0].slice(1);
193 const pos = match.input.indexOf(tag, after);
194 return pos !== -1;
195 };
196
197 const IDENT_RE$1 = IDENT_RE;
198 const FRAGMENT = {
199 begin: '<>',
200 end: '</>'
201 };
202 const XML_TAG = {
203 begin: /<[A-Za-z0-9\\._:-]+/,
204 end: /\/[A-Za-z0-9\\._:-]+>|\/>/,
205 /**
206 * @param {RegExpMatchArray} match
207 * @param {CallbackResponse} response
208 */
209 isTrulyOpeningTag: (match, response) => {
210 const afterMatchIndex = match[0].length + match.index;
211 const nextChar = match.input[afterMatchIndex];
212 // nested type?
213 // HTML should not include another raw `<` inside a tag
214 // But a type might: `<Array<Array<number>>`, etc.
215 if (nextChar === "<") {
216 response.ignoreMatch();
217 return;
218 }
219 // <something>
220 // This is now either a tag or a type.
221 if (nextChar === ">") {
222 // if we cannot find a matching closing tag, then we
223 // will ignore it
224 if (!hasClosingTag(match, { after: afterMatchIndex })) {
225 response.ignoreMatch();
226 }
227 }
228 }
229 };
230 const KEYWORDS$1 = {
231 $pattern: IDENT_RE,
232 keyword: KEYWORDS,
233 literal: LITERALS,
234 built_in: BUILT_INS
235 };
236
237 // https://tc39.es/ecma262/#sec-literals-numeric-literals
238 const decimalDigits = '[0-9](_?[0-9])*';
239 const frac = `\\.(${decimalDigits})`;
240 // DecimalIntegerLiteral, including Annex B NonOctalDecimalIntegerLiteral
241 // https://tc39.es/ecma262/#sec-additional-syntax-numeric-literals
242 const decimalInteger = `0|[1-9](_?[0-9])*|0[0-7]*[89][0-9]*`;
243 const NUMBER = {
244 className: 'number',
245 variants: [
246 // DecimalLiteral
247 { begin: `(\\b(${decimalInteger})((${frac})|\\.)?|(${frac}))` +
248 `[eE][+-]?(${decimalDigits})\\b` },
249 { begin: `\\b(${decimalInteger})\\b((${frac})\\b|\\.)?|(${frac})\\b` },
250
251 // DecimalBigIntegerLiteral
252 { begin: `\\b(0|[1-9](_?[0-9])*)n\\b` },
253
254 // NonDecimalIntegerLiteral
255 { begin: "\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*n?\\b" },
256 { begin: "\\b0[bB][0-1](_?[0-1])*n?\\b" },
257 { begin: "\\b0[oO][0-7](_?[0-7])*n?\\b" },
258
259 // LegacyOctalIntegerLiteral (does not include underscore separators)
260 // https://tc39.es/ecma262/#sec-additional-syntax-numeric-literals
261 { begin: "\\b0[0-7]+n?\\b" },
262 ],
263 relevance: 0
264 };
265
266 const SUBST = {
267 className: 'subst',
268 begin: '\\$\\{',
269 end: '\\}',
270 keywords: KEYWORDS$1,
271 contains: [] // defined later
272 };
273 const HTML_TEMPLATE = {
274 begin: 'html`',
275 end: '',
276 starts: {
277 end: '`',
278 returnEnd: false,
279 contains: [
280 hljs.BACKSLASH_ESCAPE,
281 SUBST
282 ],
283 subLanguage: 'xml'
284 }
285 };
286 const CSS_TEMPLATE = {
287 begin: 'css`',
288 end: '',
289 starts: {
290 end: '`',
291 returnEnd: false,
292 contains: [
293 hljs.BACKSLASH_ESCAPE,
294 SUBST
295 ],
296 subLanguage: 'css'
297 }
298 };
299 const TEMPLATE_STRING = {
300 className: 'string',
301 begin: '`',
302 end: '`',
303 contains: [
304 hljs.BACKSLASH_ESCAPE,
305 SUBST
306 ]
307 };
308 const JSDOC_COMMENT = hljs.COMMENT(
309 /\/\*\*(?!\/)/,
310 '\\*/',
311 {
312 relevance: 0,
313 contains: [
314 {
315 className: 'doctag',
316 begin: '@[A-Za-z]+',
317 contains: [
318 {
319 className: 'type',
320 begin: '\\{',
321 end: '\\}',
322 relevance: 0
323 },
324 {
325 className: 'variable',
326 begin: IDENT_RE$1 + '(?=\\s*(-)|$)',
327 endsParent: true,
328 relevance: 0
329 },
330 // eat spaces (not newlines) so we can find
331 // types or variables
332 {
333 begin: /(?=[^\n])\s/,
334 relevance: 0
335 }
336 ]
337 }
338 ]
339 }
340 );
341 const COMMENT = {
342 className: "comment",
343 variants: [
344 JSDOC_COMMENT,
345 hljs.C_BLOCK_COMMENT_MODE,
346 hljs.C_LINE_COMMENT_MODE
347 ]
348 };
349 const SUBST_INTERNALS = [
350 hljs.APOS_STRING_MODE,
351 hljs.QUOTE_STRING_MODE,
352 HTML_TEMPLATE,
353 CSS_TEMPLATE,
354 TEMPLATE_STRING,
355 NUMBER,
356 hljs.REGEXP_MODE
357 ];
358 SUBST.contains = SUBST_INTERNALS
359 .concat({
360 // we need to pair up {} inside our subst to prevent
361 // it from ending too early by matching another }
362 begin: /\{/,
363 end: /\}/,
364 keywords: KEYWORDS$1,
365 contains: [
366 "self"
367 ].concat(SUBST_INTERNALS)
368 });
369 const SUBST_AND_COMMENTS = [].concat(COMMENT, SUBST.contains);
370 const PARAMS_CONTAINS = SUBST_AND_COMMENTS.concat([
371 // eat recursive parens in sub expressions
372 {
373 begin: /\(/,
374 end: /\)/,
375 keywords: KEYWORDS$1,
376 contains: ["self"].concat(SUBST_AND_COMMENTS)
377 }
378 ]);
379 const PARAMS = {
380 className: 'params',
381 begin: /\(/,
382 end: /\)/,
383 excludeBegin: true,
384 excludeEnd: true,
385 keywords: KEYWORDS$1,
386 contains: PARAMS_CONTAINS
387 };
388
389 return {
390 name: 'Javascript',
391 aliases: ['js', 'jsx', 'mjs', 'cjs'],
392 keywords: KEYWORDS$1,
393 // this will be extended by TypeScript
394 exports: { PARAMS_CONTAINS },
395 illegal: /#(?![$_A-z])/,
396 contains: [
397 hljs.SHEBANG({
398 label: "shebang",
399 binary: "node",
400 relevance: 5
401 }),
402 {
403 label: "use_strict",
404 className: 'meta',
405 relevance: 10,
406 begin: /^\s*['"]use (strict|asm)['"]/
407 },
408 hljs.APOS_STRING_MODE,
409 hljs.QUOTE_STRING_MODE,
410 HTML_TEMPLATE,
411 CSS_TEMPLATE,
412 TEMPLATE_STRING,
413 COMMENT,
414 NUMBER,
415 { // object attr container
416 begin: concat(/[{,\n]\s*/,
417 // we need to look ahead to make sure that we actually have an
418 // attribute coming up so we don't steal a comma from a potential
419 // "value" container
420 //
421 // NOTE: this might not work how you think. We don't actually always
422 // enter this mode and stay. Instead it might merely match `,
423 // <comments up next>` and then immediately end after the , because it
424 // fails to find any actual attrs. But this still does the job because
425 // it prevents the value contain rule from grabbing this instead and
426 // prevening this rule from firing when we actually DO have keys.
427 lookahead(concat(
428 // we also need to allow for multiple possible comments inbetween
429 // the first key:value pairing
430 /(((\/\/.*$)|(\/\*(\*[^/]|[^*])*\*\/))\s*)*/,
431 IDENT_RE$1 + '\\s*:'))),
432 relevance: 0,
433 contains: [
434 {
435 className: 'attr',
436 begin: IDENT_RE$1 + lookahead('\\s*:'),
437 relevance: 0
438 }
439 ]
440 },
441 { // "value" container
442 begin: '(' + hljs.RE_STARTERS_RE + '|\\b(case|return|throw)\\b)\\s*',
443 keywords: 'return throw case',
444 contains: [
445 COMMENT,
446 hljs.REGEXP_MODE,
447 {
448 className: 'function',
449 // we have to count the parens to make sure we actually have the
450 // correct bounding ( ) before the =>. There could be any number of
451 // sub-expressions inside also surrounded by parens.
452 begin: '(\\(' +
453 '[^()]*(\\(' +
454 '[^()]*(\\(' +
455 '[^()]*' +
456 '\\)[^()]*)*' +
457 '\\)[^()]*)*' +
458 '\\)|' + hljs.UNDERSCORE_IDENT_RE + ')\\s*=>',
459 returnBegin: true,
460 end: '\\s*=>',
461 contains: [
462 {
463 className: 'params',
464 variants: [
465 {
466 begin: hljs.UNDERSCORE_IDENT_RE,
467 relevance: 0
468 },
469 {
470 className: null,
471 begin: /\(\s*\)/,
472 skip: true
473 },
474 {
475 begin: /\(/,
476 end: /\)/,
477 excludeBegin: true,
478 excludeEnd: true,
479 keywords: KEYWORDS$1,
480 contains: PARAMS_CONTAINS
481 }
482 ]
483 }
484 ]
485 },
486 { // could be a comma delimited list of params to a function call
487 begin: /,/, relevance: 0
488 },
489 {
490 className: '',
491 begin: /\s/,
492 end: /\s*/,
493 skip: true
494 },
495 { // JSX
496 variants: [
497 { begin: FRAGMENT.begin, end: FRAGMENT.end },
498 {
499 begin: XML_TAG.begin,
500 // we carefully check the opening tag to see if it truly
501 // is a tag and not a false positive
502 'on:begin': XML_TAG.isTrulyOpeningTag,
503 end: XML_TAG.end
504 }
505 ],
506 subLanguage: 'xml',
507 contains: [
508 {
509 begin: XML_TAG.begin,
510 end: XML_TAG.end,
511 skip: true,
512 contains: ['self']
513 }
514 ]
515 }
516 ],
517 relevance: 0
518 },
519 {
520 className: 'function',
521 beginKeywords: 'function',
522 end: /[{;]/,
523 excludeEnd: true,
524 keywords: KEYWORDS$1,
525 contains: [
526 'self',
527 hljs.inherit(hljs.TITLE_MODE, { begin: IDENT_RE$1 }),
528 PARAMS
529 ],
530 illegal: /%/
531 },
532 {
533 // prevent this from getting swallowed up by function
534 // since they appear "function like"
535 beginKeywords: "while if switch catch for"
536 },
537 {
538 className: 'function',
539 // we have to count the parens to make sure we actually have the correct
540 // bounding ( ). There could be any number of sub-expressions inside
541 // also surrounded by parens.
542 begin: hljs.UNDERSCORE_IDENT_RE +
543 '\\(' + // first parens
544 '[^()]*(\\(' +
545 '[^()]*(\\(' +
546 '[^()]*' +
547 '\\)[^()]*)*' +
548 '\\)[^()]*)*' +
549 '\\)\\s*\\{', // end parens
550 returnBegin:true,
551 contains: [
552 PARAMS,
553 hljs.inherit(hljs.TITLE_MODE, { begin: IDENT_RE$1 }),
554 ]
555 },
556 // hack: prevents detection of keywords in some circumstances
557 // .keyword()
558 // $keyword = x
559 {
560 variants: [
561 { begin: '\\.' + IDENT_RE$1 },
562 { begin: '\\$' + IDENT_RE$1 }
563 ],
564 relevance: 0
565 },
566 { // ES6 class
567 className: 'class',
568 beginKeywords: 'class',
569 end: /[{;=]/,
570 excludeEnd: true,
571 illegal: /[:"[\]]/,
572 contains: [
573 { beginKeywords: 'extends' },
574 hljs.UNDERSCORE_TITLE_MODE
575 ]
576 },
577 {
578 begin: /\b(?=constructor)/,
579 end: /[{;]/,
580 excludeEnd: true,
581 contains: [
582 hljs.inherit(hljs.TITLE_MODE, { begin: IDENT_RE$1 }),
583 'self',
584 PARAMS
585 ]
586 },
587 {
588 begin: '(get|set)\\s+(?=' + IDENT_RE$1 + '\\()',
589 end: /\{/,
590 keywords: "get set",
591 contains: [
592 hljs.inherit(hljs.TITLE_MODE, { begin: IDENT_RE$1 }),
593 { begin: /\(\)/ }, // eat to avoid empty params
594 PARAMS
595 ]
596 },
597 {
598 begin: /\$[(.]/ // relevance booster for a pattern common to JS libs: `$(something)` and `$.something`
599 }
600 ]
601 };
602}
603
604module.exports = javascript;
Note: See TracBrowser for help on using the repository browser.