javascript.js (10180B)
1 const IDENT_RE = '[A-Za-z$_][0-9A-Za-z$_]*'; 2 const 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 ]; 45 const LITERALS = [ 46 "true", 47 "false", 48 "null", 49 "undefined", 50 "NaN", 51 "Infinity" 52 ]; 53 54 const 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 ]; 87 88 const ERROR_TYPES = [ 89 "EvalError", 90 "InternalError", 91 "RangeError", 92 "ReferenceError", 93 "SyntaxError", 94 "TypeError", 95 "URIError" 96 ]; 97 98 const BUILT_IN_GLOBALS = [ 99 "setInterval", 100 "setTimeout", 101 "clearInterval", 102 "clearTimeout", 103 104 "require", 105 "exports", 106 107 "eval", 108 "isFinite", 109 "isNaN", 110 "parseFloat", 111 "parseInt", 112 "decodeURI", 113 "decodeURIComponent", 114 "encodeURI", 115 "encodeURIComponent", 116 "escape", 117 "unescape" 118 ]; 119 120 const BUILT_IN_VARIABLES = [ 121 "arguments", 122 "this", 123 "super", 124 "console", 125 "window", 126 "document", 127 "localStorage", 128 "module", 129 "global" // Node.js 130 ]; 131 132 const BUILT_INS = [].concat( 133 BUILT_IN_GLOBALS, 134 BUILT_IN_VARIABLES, 135 TYPES, 136 ERROR_TYPES 137 ); 138 139 /** 140 * @param {string} value 141 * @returns {RegExp} 142 * */ 143 144 /** 145 * @param {RegExp | string } re 146 * @returns {string} 147 */ 148 function source(re) { 149 if (!re) return null; 150 if (typeof re === "string") return re; 151 152 return re.source; 153 } 154 155 /** 156 * @param {RegExp | string } re 157 * @returns {string} 158 */ 159 function lookahead(re) { 160 return concat('(?=', re, ')'); 161 } 162 163 /** 164 * @param {...(RegExp | string) } args 165 * @returns {string} 166 */ 167 function concat(...args) { 168 const joined = args.map((x) => source(x)).join(""); 169 return joined; 170 } 171 172 /* 173 Language: JavaScript 174 Description: JavaScript (JS) is a lightweight, interpreted, or just-in-time compiled programming language with first-class functions. 175 Category: common, scripting 176 Website: https://developer.mozilla.org/en-US/docs/Web/JavaScript 177 */ 178 179 function javascript(hljs) { 180 var IDENT_RE$1 = IDENT_RE; 181 var FRAGMENT = { 182 begin: '<>', 183 end: '</>' 184 }; 185 var XML_TAG = { 186 begin: /<[A-Za-z0-9\\._:-]+/, 187 end: /\/[A-Za-z0-9\\._:-]+>|\/>/ 188 }; 189 var KEYWORDS$1 = { 190 $pattern: IDENT_RE, 191 keyword: KEYWORDS.join(" "), 192 literal: LITERALS.join(" "), 193 built_in: BUILT_INS.join(" ") 194 }; 195 var NUMBER = { 196 className: 'number', 197 variants: [ 198 { begin: '\\b(0[bB][01]+)n?' }, 199 { begin: '\\b(0[oO][0-7]+)n?' }, 200 { begin: hljs.C_NUMBER_RE + 'n?' } 201 ], 202 relevance: 0 203 }; 204 var SUBST = { 205 className: 'subst', 206 begin: '\\$\\{', end: '\\}', 207 keywords: KEYWORDS$1, 208 contains: [] // defined later 209 }; 210 var HTML_TEMPLATE = { 211 begin: 'html`', end: '', 212 starts: { 213 end: '`', returnEnd: false, 214 contains: [ 215 hljs.BACKSLASH_ESCAPE, 216 SUBST 217 ], 218 subLanguage: 'xml', 219 } 220 }; 221 var CSS_TEMPLATE = { 222 begin: 'css`', end: '', 223 starts: { 224 end: '`', returnEnd: false, 225 contains: [ 226 hljs.BACKSLASH_ESCAPE, 227 SUBST 228 ], 229 subLanguage: 'css', 230 } 231 }; 232 var TEMPLATE_STRING = { 233 className: 'string', 234 begin: '`', end: '`', 235 contains: [ 236 hljs.BACKSLASH_ESCAPE, 237 SUBST 238 ] 239 }; 240 SUBST.contains = [ 241 hljs.APOS_STRING_MODE, 242 hljs.QUOTE_STRING_MODE, 243 HTML_TEMPLATE, 244 CSS_TEMPLATE, 245 TEMPLATE_STRING, 246 NUMBER, 247 hljs.REGEXP_MODE 248 ]; 249 var PARAMS_CONTAINS = SUBST.contains.concat([ 250 // eat recursive parens in sub expressions 251 { begin: /\(/, end: /\)/, 252 contains: ["self"].concat(SUBST.contains, [hljs.C_BLOCK_COMMENT_MODE, hljs.C_LINE_COMMENT_MODE]) 253 }, 254 hljs.C_BLOCK_COMMENT_MODE, 255 hljs.C_LINE_COMMENT_MODE 256 ]); 257 var PARAMS = { 258 className: 'params', 259 begin: /\(/, end: /\)/, 260 excludeBegin: true, 261 excludeEnd: true, 262 contains: PARAMS_CONTAINS 263 }; 264 265 return { 266 name: 'JavaScript', 267 aliases: ['js', 'jsx', 'mjs', 'cjs'], 268 keywords: KEYWORDS$1, 269 contains: [ 270 hljs.SHEBANG({ 271 binary: "node", 272 relevance: 5 273 }), 274 { 275 className: 'meta', 276 relevance: 10, 277 begin: /^\s*['"]use (strict|asm)['"]/ 278 }, 279 hljs.APOS_STRING_MODE, 280 hljs.QUOTE_STRING_MODE, 281 HTML_TEMPLATE, 282 CSS_TEMPLATE, 283 TEMPLATE_STRING, 284 hljs.C_LINE_COMMENT_MODE, 285 hljs.COMMENT( 286 '/\\*\\*', 287 '\\*/', 288 { 289 relevance : 0, 290 contains : [ 291 { 292 className : 'doctag', 293 begin : '@[A-Za-z]+', 294 contains : [ 295 { 296 className: 'type', 297 begin: '\\{', 298 end: '\\}', 299 relevance: 0 300 }, 301 { 302 className: 'variable', 303 begin: IDENT_RE$1 + '(?=\\s*(-)|$)', 304 endsParent: true, 305 relevance: 0 306 }, 307 // eat spaces (not newlines) so we can find 308 // types or variables 309 { 310 begin: /(?=[^\n])\s/, 311 relevance: 0 312 }, 313 ] 314 } 315 ] 316 } 317 ), 318 hljs.C_BLOCK_COMMENT_MODE, 319 NUMBER, 320 { // object attr container 321 begin: concat(/[{,\n]\s*/, 322 // we need to look ahead to make sure that we actually have an 323 // attribute coming up so we don't steal a comma from a potential 324 // "value" container 325 // 326 // NOTE: this might not work how you think. We don't actually always 327 // enter this mode and stay. Instead it might merely match `, 328 // <comments up next>` and then immediately end after the , because it 329 // fails to find any actual attrs. But this still does the job because 330 // it prevents the value contain rule from grabbing this instead and 331 // prevening this rule from firing when we actually DO have keys. 332 lookahead(concat( 333 // we also need to allow for multiple possible comments inbetween 334 // the first key:value pairing 335 /(((\/\/.*$)|(\/\*(.|\n)*\*\/))\s*)*/, 336 IDENT_RE$1 + '\\s*:'))), 337 relevance: 0, 338 contains: [ 339 { 340 className: 'attr', 341 begin: IDENT_RE$1 + lookahead('\\s*:'), 342 relevance: 0, 343 }, 344 ] 345 }, 346 { // "value" container 347 begin: '(' + hljs.RE_STARTERS_RE + '|\\b(case|return|throw)\\b)\\s*', 348 keywords: 'return throw case', 349 contains: [ 350 hljs.C_LINE_COMMENT_MODE, 351 hljs.C_BLOCK_COMMENT_MODE, 352 hljs.REGEXP_MODE, 353 { 354 className: 'function', 355 // we have to count the parens to make sure we actually have the 356 // correct bounding ( ) before the =>. There could be any number of 357 // sub-expressions inside also surrounded by parens. 358 begin: '(\\([^(]*' + 359 '(\\([^(]*' + 360 '(\\([^(]*' + 361 '\\))?' + 362 '\\))?' + 363 '\\)|' + hljs.UNDERSCORE_IDENT_RE + ')\\s*=>', returnBegin: true, 364 end: '\\s*=>', 365 contains: [ 366 { 367 className: 'params', 368 variants: [ 369 { 370 begin: hljs.UNDERSCORE_IDENT_RE 371 }, 372 { 373 className: null, 374 begin: /\(\s*\)/, 375 skip: true 376 }, 377 { 378 begin: /\(/, end: /\)/, 379 excludeBegin: true, excludeEnd: true, 380 keywords: KEYWORDS$1, 381 contains: PARAMS_CONTAINS 382 } 383 ] 384 } 385 ] 386 }, 387 { // could be a comma delimited list of params to a function call 388 begin: /,/, relevance: 0, 389 }, 390 { 391 className: '', 392 begin: /\s/, 393 end: /\s*/, 394 skip: true, 395 }, 396 { // JSX 397 variants: [ 398 { begin: FRAGMENT.begin, end: FRAGMENT.end }, 399 { begin: XML_TAG.begin, end: XML_TAG.end } 400 ], 401 subLanguage: 'xml', 402 contains: [ 403 { 404 begin: XML_TAG.begin, end: XML_TAG.end, skip: true, 405 contains: ['self'] 406 } 407 ] 408 }, 409 ], 410 relevance: 0 411 }, 412 { 413 className: 'function', 414 beginKeywords: 'function', end: /\{/, excludeEnd: true, 415 contains: [ 416 hljs.inherit(hljs.TITLE_MODE, {begin: IDENT_RE$1}), 417 PARAMS 418 ], 419 illegal: /\[|%/ 420 }, 421 { 422 begin: /\$[(.]/ // relevance booster for a pattern common to JS libs: `$(something)` and `$.something` 423 }, 424 425 hljs.METHOD_GUARD, 426 { // ES6 class 427 className: 'class', 428 beginKeywords: 'class', end: /[{;=]/, excludeEnd: true, 429 illegal: /[:"\[\]]/, 430 contains: [ 431 {beginKeywords: 'extends'}, 432 hljs.UNDERSCORE_TITLE_MODE 433 ] 434 }, 435 { 436 beginKeywords: 'constructor', end: /\{/, excludeEnd: true 437 }, 438 { 439 begin: '(get|set)\\s+(?=' + IDENT_RE$1 + '\\()', 440 end: /{/, 441 keywords: "get set", 442 contains: [ 443 hljs.inherit(hljs.TITLE_MODE, {begin: IDENT_RE$1}), 444 { begin: /\(\)/ }, // eat to avoid empty params 445 PARAMS 446 ] 447 448 } 449 ], 450 illegal: /#(?!!)/ 451 }; 452 } 453 454 module.exports = javascript;