javascript.js 17 KB

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