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