javascript.js 17 KB

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