javascript.js 9.9 KB

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