code-battles 1.6.4 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/cjs/index.js +2234 -2004
  2. package/dist/cjs/styles.css +2 -1
  3. package/dist/cjs/types/components/DataTable.d.ts +21 -0
  4. package/dist/cjs/types/components/ResultStaticsTable.d.ts +3 -0
  5. package/dist/cjs/types/configuration.d.ts +2 -2
  6. package/dist/cjs/types/utilities.d.ts +2 -2
  7. package/dist/code_battles/__init__.py +1 -1
  8. package/dist/code_battles/battles.py +69 -28
  9. package/dist/code_battles/utilities.py +12 -3
  10. package/dist/esm/index.js +2235 -2005
  11. package/dist/esm/styles.css +2 -1
  12. package/dist/esm/types/components/DataTable.d.ts +21 -0
  13. package/dist/esm/types/components/ResultStaticsTable.d.ts +3 -0
  14. package/dist/esm/types/configuration.d.ts +2 -2
  15. package/dist/esm/types/utilities.d.ts +2 -2
  16. package/dist/index.d.ts +2 -2
  17. package/dist/pyscript/codemirror-eKulCBrd.js +2 -0
  18. package/dist/pyscript/codemirror-eKulCBrd.js.map +1 -0
  19. package/dist/pyscript/codemirror_commands-BVu_0Pnj.js +2 -0
  20. package/dist/pyscript/codemirror_commands-BVu_0Pnj.js.map +1 -0
  21. package/dist/pyscript/codemirror_lang-python-a2LxSo5G.js +2 -0
  22. package/dist/pyscript/codemirror_lang-python-a2LxSo5G.js.map +1 -0
  23. package/dist/pyscript/codemirror_language-_2pXlKJ9.js +2 -0
  24. package/dist/pyscript/codemirror_language-_2pXlKJ9.js.map +1 -0
  25. package/dist/pyscript/codemirror_view-DMW9kQlJ.js +2 -0
  26. package/dist/pyscript/codemirror_view-DMW9kQlJ.js.map +1 -0
  27. package/dist/pyscript/core-DezwbZpG.js +4 -0
  28. package/dist/pyscript/core-DezwbZpG.js.map +1 -0
  29. package/dist/pyscript/core.js +1 -1
  30. package/dist/pyscript/deprecations-manager-B1bDno27.js +2 -0
  31. package/dist/pyscript/deprecations-manager-B1bDno27.js.map +1 -0
  32. package/dist/pyscript/donkey-DNl0ASkM.js +2 -0
  33. package/dist/pyscript/donkey-DNl0ASkM.js.map +1 -0
  34. package/dist/pyscript/error-DmRE4Y-7.js +2 -0
  35. package/dist/pyscript/error-DmRE4Y-7.js.map +1 -0
  36. package/dist/pyscript/index-DkgvWIf-.js +2 -0
  37. package/dist/pyscript/index-DkgvWIf-.js.map +1 -0
  38. package/dist/pyscript/mpy-BoY0tVRD.js +2 -0
  39. package/dist/pyscript/mpy-BoY0tVRD.js.map +1 -0
  40. package/dist/pyscript/py-DsQqgZuM.js +2 -0
  41. package/dist/pyscript/py-DsQqgZuM.js.map +1 -0
  42. package/dist/pyscript/py-editor-DZkG_or6.js +2 -0
  43. package/dist/pyscript/py-editor-DZkG_or6.js.map +1 -0
  44. package/dist/pyscript/py-game-D0Z4YnzZ.js +2 -0
  45. package/dist/pyscript/py-game-D0Z4YnzZ.js.map +1 -0
  46. package/dist/pyscript/py-terminal-DYHK7LJ0.js +2 -0
  47. package/dist/pyscript/py-terminal-DYHK7LJ0.js.map +1 -0
  48. package/dist/pyscript/service-worker.js +1 -0
  49. package/dist/pyscript/storage.js +1 -1
  50. package/dist/pyscript/storage.js.map +1 -1
  51. package/dist/pyscript/xterm-CVv2fC4I.js +2 -0
  52. package/dist/pyscript/xterm-CVv2fC4I.js.map +1 -0
  53. package/dist/pyscript/zip-D13-hp9W.js +2 -0
  54. package/dist/pyscript/zip-D13-hp9W.js.map +1 -0
  55. package/package.json +14 -14
package/dist/cjs/index.js CHANGED
@@ -374,10 +374,10 @@ const updatePointModifier = () => {
374
374
  const pointModifier = {};
375
375
  for (const round of rounds) {
376
376
  if (results[round.players.join(", ")] &&
377
- results[round.players.join(", ")][round.map]) {
378
- for (const result of results[round.players.join(", ")][round.map]) {
379
- const first = round.players[result[0]];
380
- const second = round.players[result[1]];
377
+ results[round.players.join(", ")][JSON.stringify(round.parameters)]) {
378
+ for (const result of results[round.players.join(", ")][JSON.stringify(round.parameters)]) {
379
+ const first = round.players[result.places[0]];
380
+ const second = round.players[result.places[1]];
381
381
  if (!pointModifier[first]) {
382
382
  pointModifier[first] = 0;
383
383
  }
@@ -403,11 +403,11 @@ const toPlacing = (n) => {
403
403
  }
404
404
  return n.toString() + DIGITS[n % 10];
405
405
  };
406
- const runNoUI = (map, apis, playerBots, seed, verbose) => {
406
+ const runNoUI = (parameters, apis, playerBots, seed, verbose) => {
407
407
  const players = playerBots.map((api) => (api === "None" ? "" : apis[api]));
408
408
  tryUntilSuccess(() =>
409
409
  // @ts-ignore
410
- window._startSimulation(map, players, playerBots, true, false, verbose, seed));
410
+ window._startSimulation(parameters, players, playerBots, true, false, verbose, seed));
411
411
  };
412
412
  const tryUntilSuccess = (f, timeout = 500) => {
413
413
  try {
@@ -886,9 +886,9 @@ function requireCheckPropTypes () {
886
886
  var printWarning = function() {};
887
887
 
888
888
  if (process.env.NODE_ENV !== 'production') {
889
- var ReactPropTypesSecret = requireReactPropTypesSecret();
889
+ var ReactPropTypesSecret = /*@__PURE__*/ requireReactPropTypesSecret();
890
890
  var loggedTypeFailures = {};
891
- var has = requireHas();
891
+ var has = /*@__PURE__*/ requireHas();
892
892
 
893
893
  printWarning = function(text) {
894
894
  var message = 'Warning: ' + text;
@@ -997,9 +997,9 @@ function requireFactoryWithTypeCheckers () {
997
997
  var ReactIs = requireReactIs();
998
998
  var assign = requireObjectAssign();
999
999
 
1000
- var ReactPropTypesSecret = requireReactPropTypesSecret();
1001
- var has = requireHas();
1002
- var checkPropTypes = requireCheckPropTypes();
1000
+ var ReactPropTypesSecret = /*@__PURE__*/ requireReactPropTypesSecret();
1001
+ var has = /*@__PURE__*/ requireHas();
1002
+ var checkPropTypes = /*@__PURE__*/ requireCheckPropTypes();
1003
1003
 
1004
1004
  var printWarning = function() {};
1005
1005
 
@@ -1612,7 +1612,7 @@ function requireFactoryWithThrowingShims () {
1612
1612
  if (hasRequiredFactoryWithThrowingShims) return factoryWithThrowingShims;
1613
1613
  hasRequiredFactoryWithThrowingShims = 1;
1614
1614
 
1615
- var ReactPropTypesSecret = requireReactPropTypesSecret();
1615
+ var ReactPropTypesSecret = /*@__PURE__*/ requireReactPropTypesSecret();
1616
1616
 
1617
1617
  function emptyFunction() {}
1618
1618
  function emptyFunctionWithReset() {}
@@ -1676,20 +1676,27 @@ function requireFactoryWithThrowingShims () {
1676
1676
  * LICENSE file in the root directory of this source tree.
1677
1677
  */
1678
1678
 
1679
- if (process.env.NODE_ENV !== 'production') {
1680
- var ReactIs = requireReactIs();
1681
-
1682
- // By explicitly using `prop-types` you are opting into new development behavior.
1683
- // http://fb.me/prop-types-in-prod
1684
- var throwOnDirectAccess = true;
1685
- propTypes.exports = requireFactoryWithTypeCheckers()(ReactIs.isElement, throwOnDirectAccess);
1686
- } else {
1687
- // By explicitly using `prop-types` you are opting into new production behavior.
1688
- // http://fb.me/prop-types-in-prod
1689
- propTypes.exports = requireFactoryWithThrowingShims()();
1679
+ var hasRequiredPropTypes;
1680
+
1681
+ function requirePropTypes () {
1682
+ if (hasRequiredPropTypes) return propTypes.exports;
1683
+ hasRequiredPropTypes = 1;
1684
+ if (process.env.NODE_ENV !== 'production') {
1685
+ var ReactIs = requireReactIs();
1686
+
1687
+ // By explicitly using `prop-types` you are opting into new development behavior.
1688
+ // http://fb.me/prop-types-in-prod
1689
+ var throwOnDirectAccess = true;
1690
+ propTypes.exports = /*@__PURE__*/ requireFactoryWithTypeCheckers()(ReactIs.isElement, throwOnDirectAccess);
1691
+ } else {
1692
+ // By explicitly using `prop-types` you are opting into new production behavior.
1693
+ // http://fb.me/prop-types-in-prod
1694
+ propTypes.exports = /*@__PURE__*/ requireFactoryWithThrowingShims()();
1695
+ }
1696
+ return propTypes.exports;
1690
1697
  }
1691
1698
 
1692
- var propTypesExports = propTypes.exports;
1699
+ var propTypesExports = /*@__PURE__*/ requirePropTypes();
1693
1700
 
1694
1701
  function _classCallCheck(instance, Constructor) {
1695
1702
  if (!(instance instanceof Constructor)) {
@@ -2466,7 +2473,7 @@ const PickBotBlock = () => {
2466
2473
 
2467
2474
  const BotSelector = ({ playerCount, setPlayerCount, playerBots, setPlayerBots, apis, }) => {
2468
2475
  return (React.createElement(React.Fragment, null,
2469
- React.createElement(core.NumberInput, { mt: "xs", label: "Player Count", value: playerCount, min: 1, onChange: (c) => {
2476
+ React.createElement(core.NumberInput, { label: "Player Count", value: playerCount, min: 1, onChange: (c) => {
2470
2477
  if (typeof c === "number") {
2471
2478
  setPlayerCount(c);
2472
2479
  while (playerBots.length < c) {
@@ -2489,9 +2496,9 @@ const BotSelector = ({ playerCount, setPlayerCount, playerBots, setPlayerBots, a
2489
2496
  const RunSimulationBlock = () => {
2490
2497
  const [apis, loading] = useAPIs();
2491
2498
  const configuration = useConfiguration();
2492
- const [map, setMap] = useLocalStorage({
2493
- key: "Map",
2494
- defaultValue: configuration.maps[0],
2499
+ const [parameters, setParameters] = useLocalStorage({
2500
+ key: "Parameters",
2501
+ defaultValue: {},
2495
2502
  });
2496
2503
  const [playerCount, setPlayerCount] = useLocalStorage({
2497
2504
  key: "Player Count",
@@ -2512,19 +2519,30 @@ const RunSimulationBlock = () => {
2512
2519
  if (Object.keys(runningNoUIN).length === 1) {
2513
2520
  remaining = Math.max(...Object.values(runningNoUIN));
2514
2521
  }
2522
+ const getFullParameters = () => {
2523
+ var _a;
2524
+ const result = {};
2525
+ for (const key in configuration.parameters) {
2526
+ result[key] = (_a = parameters[key]) !== null && _a !== void 0 ? _a : configuration.parameters[key][0];
2527
+ }
2528
+ return result;
2529
+ };
2515
2530
  const run = () => {
2516
2531
  // @ts-ignore
2517
2532
  window._isSimulationFromFile = false;
2518
- navigate(`/simulation/${map.replaceAll(" ", "-")}/${playerBots.map(encodeURIComponent).join(",")}?seed=${seed === "-" ? "" : seed}`);
2533
+ const params = getFullParameters();
2534
+ navigate(`/simulation/${playerBots.map(encodeURIComponent).join(",")}?seed=${seed === "-" ? "" : seed}&${Object.keys(params)
2535
+ .map((p) => `${p}=${encodeURIComponent(params[p])}`)
2536
+ .join("&")}`);
2519
2537
  };
2520
2538
  const startRunNoUI = () => {
2521
2539
  setRunningNoUI(true);
2522
- runNoUI(map, apis, playerBots, seed.toString(), false);
2540
+ runNoUI(getFullParameters(), apis, playerBots, seed.toString(), true);
2523
2541
  };
2524
2542
  const startRunNoUIN = (n) => {
2525
2543
  setLocalStorage("Results", {});
2526
2544
  setRunningNoUIN({ [n.toString()]: n });
2527
- runNoUI(map, apis, playerBots, seed.toString(), false);
2545
+ runNoUI(getFullParameters(), apis, playerBots, seed.toString(), false);
2528
2546
  };
2529
2547
  React.useEffect(() => {
2530
2548
  // @ts-ignore
@@ -2553,10 +2571,10 @@ const RunSimulationBlock = () => {
2553
2571
  for (const key in runningNoUIN) {
2554
2572
  if (runningNoUIN[key] == 0) {
2555
2573
  const results = getLocalStorage("Results");
2556
- const currentResults = results[playerBots.join(", ")][map];
2574
+ const currentResults = results[playerBots.join(", ")][JSON.stringify(getFullParameters())];
2557
2575
  const winCounts = {};
2558
2576
  for (const result of currentResults) {
2559
- const winner = playerBots[result[0]];
2577
+ const winner = playerBots[result.places[0]];
2560
2578
  if (!winCounts[winner]) {
2561
2579
  winCounts[winner] = 1;
2562
2580
  }
@@ -2578,16 +2596,18 @@ const RunSimulationBlock = () => {
2578
2596
  setLocalStorage("Results", {});
2579
2597
  }
2580
2598
  else {
2581
- runNoUI(map, apis, playerBots, seed.toString(), false);
2599
+ runNoUI(getFullParameters(), apis, playerBots, seed.toString(), false);
2582
2600
  }
2583
2601
  }
2584
2602
  }, [runningNoUIN]);
2585
2603
  return (React.createElement(Block, { title: "Run Simulation", logo: "fa-solid fa-display" },
2586
- React.createElement(core.Select, { leftSection: React.createElement("i", { className: "fa-solid fa-earth-americas" }), label: "Map", data: configuration.maps, value: map, onChange: (s) => {
2587
- if (s) {
2588
- setMap(s);
2589
- }
2590
- } }),
2604
+ Object.keys(configuration.parameters)
2605
+ .sort()
2606
+ .map((parameter, parameterIndex) => {
2607
+ var _a, _b;
2608
+ const icon = ((_a = configuration.parameterIcons) !== null && _a !== void 0 ? _a : {})[parameter];
2609
+ return (React.createElement(core.Select, { mb: "xs", key: parameterIndex, leftSection: icon ? React.createElement("i", { className: icon }) : undefined, label: parameter[0].toUpperCase() + parameter.slice(1), data: configuration.parameters[parameter], value: (_b = parameters[parameter]) !== null && _b !== void 0 ? _b : configuration.parameters[parameter][0], onChange: (s) => setParameters(Object.assign(Object.assign({}, parameters), { [parameter]: s !== null && s !== void 0 ? s : configuration.parameters[parameter][0] })) }));
2610
+ }),
2591
2611
  React.createElement(BotSelector, { playerCount: playerCount, setPlayerCount: setPlayerCount, playerBots: playerBots, setPlayerBots: setPlayerBots, apis: apis }),
2592
2612
  React.createElement(core.NumberInput, { mt: "xs", leftSection: React.createElement("i", { className: "fa-solid fa-dice" }), label: "Randomness Seed", min: 0, value: seed, onChange: setSeed }),
2593
2613
  React.createElement(core.Button.Group, { mt: "xs" },
@@ -2775,7 +2795,156 @@ const NotFoundPage = () => {
2775
2795
  React.createElement("p", null, "Make sure the URL is correct.")));
2776
2796
  };
2777
2797
 
2778
- let currentMap;
2798
+ const DataTable = ({ tableName, data, renderValue, renderHead, disableSort, hideIfEmpty, selectable, selectedRows, setSelectedRows, defaultSort, defaultReversed, stickyFirstColumn, }) => {
2799
+ var _a, _b;
2800
+ const [sortByColumn, setSortByColumn] = React.useState(defaultSort !== null && defaultSort !== void 0 ? defaultSort : 0);
2801
+ const [reversed, setReversed] = React.useState(defaultReversed !== null && defaultReversed !== void 0 ? defaultReversed : false);
2802
+ const [search, setSearch] = React.useState("");
2803
+ const theme = core.useMantineTheme();
2804
+ const colorScheme = hooks.useColorScheme();
2805
+ if (hideIfEmpty && data.body.length === 0) {
2806
+ return React.createElement(React.Fragment, null);
2807
+ }
2808
+ const reverseValue = reversed ? -1 : 1;
2809
+ const id = (_, __, value) => value;
2810
+ renderValue = renderValue !== null && renderValue !== void 0 ? renderValue : id;
2811
+ const headId = (value) => value;
2812
+ renderHead = renderHead !== null && renderHead !== void 0 ? renderHead : headId;
2813
+ const bodyIndices = [];
2814
+ for (let i = 0; i < data.body.length; i++) {
2815
+ bodyIndices.push(i);
2816
+ }
2817
+ const sortedIndices = bodyIndices
2818
+ .filter((i) => data.body[i].some((x, j) => {
2819
+ var _a;
2820
+ return (x === null || x === void 0 ? void 0 : x.includes(search)) ||
2821
+ ((_a = renderValue(i, data.head[j], x)) === null || _a === void 0 ? void 0 : _a.toString().includes(search));
2822
+ }))
2823
+ .sort((a, b) => {
2824
+ var _a, _b;
2825
+ if (disableSort) {
2826
+ return 1;
2827
+ }
2828
+ const aValue = (_a = data.body[a][sortByColumn]) !== null && _a !== void 0 ? _a : "";
2829
+ const bValue = (_b = data.body[b][sortByColumn]) !== null && _b !== void 0 ? _b : "";
2830
+ let difference = parseInt(bValue) - parseInt(aValue);
2831
+ if (isNaN(difference)) {
2832
+ return reverseValue * (aValue === null || aValue === void 0 ? void 0 : aValue.localeCompare(bValue));
2833
+ }
2834
+ return reverseValue * difference;
2835
+ });
2836
+ const displayData = {
2837
+ head: data.head.map(renderHead),
2838
+ body: sortedIndices.map((rowIndex) => data.body[rowIndex].map((value, columnIndex) => renderValue(rowIndex, data.head[columnIndex], value))),
2839
+ };
2840
+ return (React.createElement(React.Fragment, null,
2841
+ React.createElement(core.TextInput, { mb: "xs", w: 400, maw: "100%", placeholder: "Search", leftSection: React.createElement("i", { className: "fa-solid fa-magnifying-glass" }), rightSection: search !== "" ? (React.createElement(core.ActionIcon, { onClick: () => setSearch(""), variant: "transparent", color: "default", size: 15 },
2842
+ React.createElement("i", { className: "fa-solid fa-xmark" }))) : undefined, value: search, onChange: (e) => setSearch(e.currentTarget.value) }),
2843
+ React.createElement("div", { style: { maxWidth: "100%", overflow: "auto", maxHeight: 500 } },
2844
+ React.createElement(core.Table, { horizontalSpacing: 7.5, verticalSpacing: 7.5 },
2845
+ React.createElement(core.Table.Thead, { style: {
2846
+ position: "sticky",
2847
+ top: 0,
2848
+ backgroundColor: colorScheme === "dark" ? theme.colors.dark[7] : "white",
2849
+ zIndex: 101,
2850
+ } },
2851
+ React.createElement(core.Table.Tr, { h: 1 },
2852
+ selectable && React.createElement(core.Table.Th, null), (_a = displayData.head) === null || _a === void 0 ? void 0 :
2853
+ _a.map((element, columnIndex) => (React.createElement(core.Table.Th, { key: columnIndex, style: {
2854
+ padding: 0,
2855
+ verticalAlign: "top",
2856
+ height: "inherit",
2857
+ } }, element !== "" && (React.createElement(core.UnstyledButton, { h: "100%", className: "control", style: {
2858
+ display: "flex",
2859
+ flexDirection: "column",
2860
+ minWidth: 100,
2861
+ }, onClick: disableSort
2862
+ ? undefined
2863
+ : () => {
2864
+ if (sortByColumn === columnIndex) {
2865
+ setReversed((r) => !r);
2866
+ }
2867
+ else {
2868
+ setSortByColumn(columnIndex);
2869
+ }
2870
+ } },
2871
+ disableSort || (React.createElement("i", { style: { fontSize: 14, marginBottom: 5 }, className: sortByColumn === columnIndex
2872
+ ? reversed
2873
+ ? "fa-solid fa-sort-up"
2874
+ : "fa-solid fa-sort-down"
2875
+ : "fa-solid fa-sort" })),
2876
+ element))))))),
2877
+ React.createElement(core.Table.Tbody, null, (_b = displayData.body) === null || _b === void 0 ? void 0 : _b.map((row, rowIndex) => {
2878
+ const realIndex = sortedIndices[rowIndex];
2879
+ return (React.createElement(core.Table.Tr, { key: rowIndex },
2880
+ selectable && (React.createElement(core.Table.Td, null,
2881
+ React.createElement(core.Checkbox, { checked: selectedRows === null || selectedRows === void 0 ? void 0 : selectedRows.includes(realIndex), onChange: (e) => {
2882
+ if (setSelectedRows) {
2883
+ if (e.currentTarget.checked) {
2884
+ setSelectedRows((s) => [...s, realIndex]);
2885
+ }
2886
+ else {
2887
+ setSelectedRows((s) => s.filter((x) => x !== realIndex));
2888
+ }
2889
+ }
2890
+ } }))),
2891
+ row.map((value, valueIndex) => (React.createElement(core.Table.Td, { key: valueIndex, style: Object.assign({ whiteSpace: "nowrap" }, (stickyFirstColumn && valueIndex === 0
2892
+ ? {
2893
+ position: "sticky",
2894
+ right: 0,
2895
+ backgroundColor: colorScheme === "dark"
2896
+ ? theme.colors.dark[7]
2897
+ : "white",
2898
+ zIndex: 100,
2899
+ }
2900
+ : {})) }, value)))));
2901
+ }))))));
2902
+ };
2903
+
2904
+ const ResultStatisticsTable = () => {
2905
+ var _a, _b, _c, _d, _e;
2906
+ const [results] = useLocalStorage({
2907
+ key: "Results",
2908
+ defaultValue: {},
2909
+ });
2910
+ const [rounds] = useLocalStorage({
2911
+ key: "Rounds",
2912
+ defaultValue: [],
2913
+ });
2914
+ const [currentRound] = useLocalStorage({
2915
+ key: "Current Round",
2916
+ defaultValue: 0,
2917
+ });
2918
+ const navigate = reactRouterDom.useNavigate();
2919
+ const round = rounds[currentRound];
2920
+ if (!round) {
2921
+ return React.createElement(React.Fragment, null);
2922
+ }
2923
+ const statistics = Object.keys((_d = (_c = ((_b = Object.values((_a = Object.values(results !== null && results !== void 0 ? results : {})[0]) !== null && _a !== void 0 ? _a : {})[0]) !== null && _b !== void 0 ? _b : [])[0]) === null || _c === void 0 ? void 0 : _c.statistics) !== null && _d !== void 0 ? _d : {});
2924
+ const roundResults = ((_e = (results !== null && results !== void 0 ? results : {})[round.players.join(", ")]) !== null && _e !== void 0 ? _e : {})[JSON.stringify(round.parameters)];
2925
+ if (!roundResults) {
2926
+ return React.createElement(React.Fragment, null);
2927
+ }
2928
+ return (React.createElement("div", { style: {
2929
+ display: "flex",
2930
+ flexDirection: "column",
2931
+ alignItems: "center",
2932
+ marginTop: 10,
2933
+ } },
2934
+ React.createElement(DataTable, { tableName: "Results", data: {
2935
+ head: ["Seed"].concat(statistics),
2936
+ body: roundResults.map((result) => [result.seed].concat(statistics.map((statistic) => { var _a; return ((_a = result === null || result === void 0 ? void 0 : result.statistics) !== null && _a !== void 0 ? _a : {})[statistic].toString(); }))),
2937
+ }, renderValue: (rowIndex, columnName, value) => {
2938
+ if (columnName === "Seed") {
2939
+ return (React.createElement(core.Button, { leftSection: React.createElement("i", { className: "fa-solid fa-play" }), onClick: () => navigate(`/simulation/${round.players.map(encodeURIComponent).join(",")}?seed=${value}&${Object.keys(round.parameters)
2940
+ .map((p) => `${p}=${encodeURIComponent(round.parameters[p])}`)
2941
+ .join("&")}`) }, "Play"));
2942
+ }
2943
+ return React.createElement(React.Fragment, { key: rowIndex }, value);
2944
+ } })));
2945
+ };
2946
+
2947
+ let currentParameters;
2779
2948
  let currentPlayers;
2780
2949
  const Round = () => {
2781
2950
  const firestore$1 = useFirestore();
@@ -2791,9 +2960,9 @@ const Round = () => {
2791
2960
  key: "Player Bots",
2792
2961
  defaultValue: ["None", "None"],
2793
2962
  });
2794
- const [map, setMap] = useLocalStorage({
2795
- key: "Map",
2796
- defaultValue: configuration.maps[0],
2963
+ const [parameters, setParameters] = useLocalStorage({
2964
+ key: "Parameters",
2965
+ defaultValue: {},
2797
2966
  });
2798
2967
  const [rounds, setRounds] = useLocalStorage({
2799
2968
  key: "Rounds",
@@ -2833,9 +3002,17 @@ const Round = () => {
2833
3002
  }
2834
3003
  React.useEffect(() => {
2835
3004
  if (remaining > 0) {
2836
- runNoUI(currentMap, apis, currentPlayers, "", false);
3005
+ runNoUI(currentParameters, apis, currentPlayers, "", false);
2837
3006
  }
2838
3007
  }, [remaining]);
3008
+ const getFullParameters = () => {
3009
+ var _a;
3010
+ const result = {};
3011
+ for (const key in configuration.parameters) {
3012
+ result[key] = (_a = parameters[key]) !== null && _a !== void 0 ? _a : configuration.parameters[key][0];
3013
+ }
3014
+ return result;
3015
+ };
2839
3016
  React.useEffect(updatePointModifier, [results]);
2840
3017
  return (React.createElement(React.Fragment, null,
2841
3018
  React.createElement("div", { style: {
@@ -2848,7 +3025,7 @@ const Round = () => {
2848
3025
  React.createElement("table", { style: { textAlign: "center" } },
2849
3026
  React.createElement("thead", null,
2850
3027
  React.createElement("tr", null,
2851
- React.createElement("th", { style: { width: "25%" } }, "Map"),
3028
+ React.createElement("th", { style: { width: "25%" } }, "Parameters"),
2852
3029
  React.createElement("th", { style: { width: "35%" } }, "Players"),
2853
3030
  roundIterations === 1 && (React.createElement(React.Fragment, null,
2854
3031
  React.createElement("th", { style: { width: "17.5%" } }, "1st Place"),
@@ -2858,9 +3035,9 @@ const Round = () => {
2858
3035
  React.createElement("tbody", null, rounds.map((round, index) => {
2859
3036
  const winCounts = {};
2860
3037
  if (results[round.players.join(", ")] !== undefined) {
2861
- const currentResults = results[round.players.join(", ")][round.map];
3038
+ const currentResults = results[round.players.join(", ")][JSON.stringify(round.parameters)];
2862
3039
  for (const result of currentResults) {
2863
- const winner = round.players[result[0]];
3040
+ const winner = round.players[result.places[0]];
2864
3041
  if (!winCounts[winner]) {
2865
3042
  winCounts[winner] = 1;
2866
3043
  }
@@ -2871,28 +3048,34 @@ const Round = () => {
2871
3048
  }
2872
3049
  const winners = Object.keys(winCounts).sort((a, b) => winCounts[b] - winCounts[a]);
2873
3050
  return (React.createElement("tr", { key: index },
2874
- React.createElement("td", null, round.map),
3051
+ React.createElement("td", { style: { whiteSpace: "pre" } }, Object.keys(round.parameters)
3052
+ .sort()
3053
+ .map((p) => `${p[0].toUpperCase()}${p.slice(1)}: ${round.parameters[p]}`)
3054
+ .join("\n")),
2875
3055
  React.createElement("td", null, round.players.map((player, index) => (React.createElement("img", { key: index, src: `/images/teams/${player.toLowerCase()}.png`, width: 30, style: { marginInlineEnd: 10 } })))),
2876
3056
  roundIterations === 1 && (React.createElement(React.Fragment, null,
2877
3057
  React.createElement("td", null, results[round.players.join(", ")] !== undefined &&
2878
- results[round.players.join(", ")][round.map] !==
2879
- undefined && (React.createElement("img", { src: `/images/teams/${round.players[results[round.players.join(", ")][round.map][0][0]].toLowerCase()}.png`, width: 30, style: { marginInlineEnd: 10 } }))),
3058
+ results[round.players.join(", ")][JSON.stringify(round.parameters)] !== undefined && (React.createElement("img", { src: `/images/teams/${round.players[results[round.players.join(", ")][JSON.stringify(round.parameters)][0][0]].toLowerCase()}.png`, width: 30, style: { marginInlineEnd: 10 } }))),
2880
3059
  React.createElement("td", null, results[round.players.join(", ")] !== undefined &&
2881
- results[round.players.join(", ")][round.map] !==
2882
- undefined && (React.createElement("img", { src: `/images/teams/${round.players[results[round.players.join(", ")][round.map][0][1]].toLowerCase()}.png`, width: 30, style: { marginInlineEnd: 10 } }))))),
3060
+ results[round.players.join(", ")][JSON.stringify(round.parameters)] !== undefined && (React.createElement("img", { src: `/images/teams/${round.players[results[round.players.join(", ")][JSON.stringify(round.parameters)][0][1]].toLowerCase()}.png`, width: 30, style: { marginInlineEnd: 10 } }))))),
2883
3061
  roundIterations !== 1 && (React.createElement("td", null, winners.map((winner, index) => (React.createElement("p", { key: index },
2884
3062
  winner,
2885
3063
  ": ",
2886
3064
  winCounts[winner]))))),
2887
3065
  React.createElement("td", null,
2888
3066
  React.createElement(core.Button.Group, { orientation: "vertical" },
2889
- React.createElement(core.Button, { leftSection: React.createElement("i", { className: "fa-solid fa-play" }), size: "xs", onClick: () => navigate(`/simulation/${round.map.replaceAll(" ", "-")}/${round.players.map(encodeURIComponent).join(",")}?showcase=true`) }, "Simulate"),
3067
+ React.createElement(core.Button, { leftSection: React.createElement("i", { className: "fa-solid fa-hand-pointer" }), size: "xs", onClick: () => {
3068
+ setLocalStorage("Current Round", index);
3069
+ } }, "Select"),
3070
+ React.createElement(core.Button, { leftSection: React.createElement("i", { className: "fa-solid fa-play" }), size: "xs", onClick: () => navigate(`/simulation/${round.players.map(encodeURIComponent).join(",")}?showcase=true&${Object.keys(round.parameters)
3071
+ .map((p) => `${p}=${encodeURIComponent(round.parameters[p])}`)
3072
+ .join("&")}`) }, "Simulate"),
2890
3073
  React.createElement(core.Button, { leftSection: React.createElement("i", { className: "fa-solid fa-forward" }), size: "xs", onClick: () => {
2891
3074
  if (roundIterations === 1) {
2892
- runNoUI(round.map, apis, round.players, "", false);
3075
+ runNoUI(round.parameters, apis, round.players, "", false);
2893
3076
  }
2894
3077
  else {
2895
- currentMap = round.map;
3078
+ currentParameters = round.parameters;
2896
3079
  currentPlayers = round.players;
2897
3080
  startRunNoUIN(roundIterations);
2898
3081
  }
@@ -2903,12 +3086,14 @@ const Round = () => {
2903
3086
  "Remaining Simulations: ",
2904
3087
  remaining)),
2905
3088
  location.search.includes("edit") && (React.createElement(React.Fragment, null,
2906
- React.createElement(core.NumberInput, { value: roundIterations, onChange: (v) => { var _a; return setRoundIterations((_a = parseInt(v.toString(), 10)) !== null && _a !== void 0 ? _a : 1); }, label: "Round Iterations", leftSection: React.createElement("i", { className: "fa-solid fa-hashtag" }) }),
2907
- React.createElement(core.Select, { mt: "xs", leftSection: React.createElement("i", { className: "fa-solid fa-map" }), label: "Map", data: configuration.maps, value: map, onChange: (s) => {
2908
- if (s) {
2909
- setMap(s);
2910
- }
2911
- } }),
3089
+ React.createElement(core.NumberInput, { mb: "xs", value: roundIterations, onChange: (v) => { var _a; return setRoundIterations((_a = parseInt(v.toString(), 10)) !== null && _a !== void 0 ? _a : 1); }, label: "Round Iterations", leftSection: React.createElement("i", { className: "fa-solid fa-hashtag" }) }),
3090
+ Object.keys(configuration.parameters)
3091
+ .sort()
3092
+ .map((parameter, parameterIndex) => {
3093
+ var _a, _b;
3094
+ const icon = ((_a = configuration.parameterIcons) !== null && _a !== void 0 ? _a : {})[parameter];
3095
+ return (React.createElement(core.Select, { key: parameterIndex, mb: "xs", leftSection: icon ? React.createElement("i", { className: icon }) : undefined, label: parameter[0].toUpperCase() + parameter.slice(1), data: configuration.parameters[parameter], value: (_b = parameters[parameter]) !== null && _b !== void 0 ? _b : configuration.parameters[parameter][0], onChange: (s) => setParameters(Object.assign(Object.assign({}, parameters), { [parameter]: s !== null && s !== void 0 ? s : configuration.parameters[parameter][0] })) }));
3096
+ }),
2912
3097
  React.createElement(BotSelector, { playerCount: playerCount, setPlayerCount: setPlayerCount, playerBots: playerBots, setPlayerBots: setPlayerBots, apis: apis }),
2913
3098
  React.createElement(core.Button, { color: "red", leftSection: React.createElement("i", { className: "fa-solid fa-trash" }), mt: "xs", onClick: () => {
2914
3099
  setRounds([]);
@@ -2920,7 +3105,10 @@ const Round = () => {
2920
3105
  React.createElement(core.Button, { leftSection: React.createElement("i", { className: "fa-solid fa-plus" }), mt: "xs", onClick: () => {
2921
3106
  setRounds((rounds) => [
2922
3107
  ...rounds,
2923
- { players: playerBots, map },
3108
+ {
3109
+ players: playerBots,
3110
+ parameters: Object.assign({}, getFullParameters()),
3111
+ },
2924
3112
  ]);
2925
3113
  }, style: { width: "30%" } }, "Add"),
2926
3114
  React.createElement(core.Button, { leftSection: React.createElement("i", { className: "fa-solid fa-save" }), fullWidth: true, mt: "xs", onClick: () => __awaiter(void 0, void 0, void 0, function* () {
@@ -2940,7 +3128,7 @@ const Round = () => {
2940
3128
  80, 80, 80, 80,
2941
3129
  ]) {
2942
3130
  setRounds((rounds) => rounds.map((round) => ({
2943
- map: round.map,
3131
+ parameters: round.parameters,
2944
3132
  players: shuffle(round.players),
2945
3133
  })));
2946
3134
  yield new Promise((resolve) => setTimeout(resolve, timeout));
@@ -2952,7 +3140,8 @@ const Round = () => {
2952
3140
  flexDirection: clientWidth >= 700 ? "row" : "column",
2953
3141
  } },
2954
3142
  React.createElement(TournamentBlock, { title: "Before", inline: true }),
2955
- React.createElement(TournamentBlock, { title: "After", inline: true, pointModifier: pointModifier }))))));
3143
+ React.createElement(TournamentBlock, { title: "After", inline: true, pointModifier: pointModifier }))),
3144
+ React.createElement(ResultStatisticsTable, null))));
2956
3145
  };
2957
3146
 
2958
3147
  const SettingsPage = () => {
@@ -3108,7 +3297,7 @@ const Simulation = () => {
3108
3297
  var _a, _b, _c, _d;
3109
3298
  const admin = useAdmin();
3110
3299
  const [apis, loading] = useAPIs();
3111
- let { map, playerapis } = reactRouterDom.useParams();
3300
+ let { playerapis } = reactRouterDom.useParams();
3112
3301
  const location = reactRouterDom.useLocation();
3113
3302
  const [searchParams] = reactRouterDom.useSearchParams();
3114
3303
  const [winner, setWinner] = React.useState();
@@ -3147,7 +3336,10 @@ const Simulation = () => {
3147
3336
  }
3148
3337
  };
3149
3338
  }, []);
3150
- map = map === null || map === void 0 ? void 0 : map.split("&")[0].replaceAll("-", " ");
3339
+ const parameters = Object.fromEntries(searchParams);
3340
+ if (parameters.seed) {
3341
+ delete parameters.seed;
3342
+ }
3151
3343
  playerapis = playerapis === null || playerapis === void 0 ? void 0 : playerapis.split("&")[0];
3152
3344
  const playerNames = (_a = playerapis === null || playerapis === void 0 ? void 0 : playerapis.split(",").map(decodeURIComponent)) !== null && _a !== void 0 ? _a : [];
3153
3345
  const players = playerNames.map((api) => (api === "None" ? "" : apis[api]));
@@ -3161,7 +3353,7 @@ const Simulation = () => {
3161
3353
  const seed = (_a = searchParams.get("seed")) !== null && _a !== void 0 ? _a : "";
3162
3354
  tryUntilSuccess(() =>
3163
3355
  // @ts-ignore
3164
- window._startSimulation(map, players, playerNames, false, !showcaseMode, true, seed));
3356
+ window._startSimulation(parameters, players, playerNames, false, !showcaseMode, true, seed));
3165
3357
  }
3166
3358
  }, [loading]);
3167
3359
  const newRank = getRank(getLocalStorage("Cached tournament/info"), winner, getLocalStorage("Point Modifier")) + 1;
@@ -3314,7 +3506,7 @@ const App = ({ routes, blocks }) => {
3314
3506
  React.createElement(reactRouterDom.Routes, null,
3315
3507
  React.createElement(reactRouterDom.Route, { path: "/", element: React.createElement(HomePage, { blocks: blocks }) }),
3316
3508
  React.createElement(reactRouterDom.Route, { path: "/view/:apiname", element: React.createElement(ViewAPI, null) }),
3317
- React.createElement(reactRouterDom.Route, { path: "/simulation/:map/:playerapis", element: React.createElement(Simulation, null) }),
3509
+ React.createElement(reactRouterDom.Route, { path: "/simulation/:playerapis", element: React.createElement(Simulation, null) }),
3318
3510
  React.createElement(reactRouterDom.Route, { path: "/round", element: React.createElement(Round, null) }),
3319
3511
  React.createElement(reactRouterDom.Route, { path: "/settings", element: React.createElement(SettingsPage, null) }),
3320
3512
  React.createElement(reactRouterDom.Route, { path: "*", element: React.createElement(NotFoundPage, null) }),
@@ -3385,7 +3577,7 @@ const TopPane = () => {
3385
3577
  };
3386
3578
 
3387
3579
  const CodeBattles = ({ configuration, routes, blocks }) => {
3388
- var _a, _b, _c, _d, _e, _f, _g, _h;
3580
+ var _a, _b, _c, _d, _e, _f;
3389
3581
  const colorScheme = hooks.useColorScheme();
3390
3582
  const firebase = app.initializeApp(configuration.firebase);
3391
3583
  const firestore$1 = firestore.getFirestore(firebase);
@@ -3396,7 +3588,6 @@ const CodeBattles = ({ configuration, routes, blocks }) => {
3396
3588
  locale: (_b = (_a = configuration.dates) === null || _a === void 0 ? void 0 : _a.locale) !== null && _b !== void 0 ? _b : "en",
3397
3589
  firstDayOfWeek: (_d = (_c = configuration.dates) === null || _c === void 0 ? void 0 : _c.firstDayOfWeek) !== null && _d !== void 0 ? _d : 0,
3398
3590
  weekendDays: (_f = (_e = configuration.dates) === null || _e === void 0 ? void 0 : _e.weekendDays) !== null && _f !== void 0 ? _f : [],
3399
- timezone: (_h = (_g = configuration.dates) === null || _g === void 0 ? void 0 : _g.timezone) !== null && _h !== void 0 ? _h : "UTC",
3400
3591
  } },
3401
3592
  React.createElement(reactRouterDom.BrowserRouter, null,
3402
3593
  React.createElement(notifications.Notifications, null),
@@ -3433,2272 +3624,2303 @@ const CodeBattles = ({ configuration, routes, blocks }) => {
3433
3624
 
3434
3625
  var prism = {exports: {}};
3435
3626
 
3436
- (function (module) {
3437
- /* **********************************************
3438
- Begin prism-core.js
3439
- ********************************************** */
3440
-
3441
- /// <reference lib="WebWorker"/>
3627
+ var hasRequiredPrism;
3442
3628
 
3443
- var _self = (typeof window !== 'undefined')
3444
- ? window // if in browser
3445
- : (
3446
- (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope)
3447
- ? self // if in worker
3448
- : {} // if in node js
3449
- );
3629
+ function requirePrism () {
3630
+ if (hasRequiredPrism) return prism.exports;
3631
+ hasRequiredPrism = 1;
3632
+ (function (module) {
3633
+ /* **********************************************
3634
+ Begin prism-core.js
3635
+ ********************************************** */
3450
3636
 
3451
- /**
3452
- * Prism: Lightweight, robust, elegant syntax highlighting
3453
- *
3454
- * @license MIT <https://opensource.org/licenses/MIT>
3455
- * @author Lea Verou <https://lea.verou.me>
3456
- * @namespace
3457
- * @public
3458
- */
3459
- var Prism = (function (_self) {
3637
+ /// <reference lib="WebWorker"/>
3460
3638
 
3461
- // Private helper vars
3462
- var lang = /(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i;
3463
- var uniqueId = 0;
3639
+ var _self = (typeof window !== 'undefined')
3640
+ ? window // if in browser
3641
+ : (
3642
+ (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope)
3643
+ ? self // if in worker
3644
+ : {} // if in node js
3645
+ );
3464
3646
 
3465
- // The grammar object for plaintext
3466
- var plainTextGrammar = {};
3647
+ /**
3648
+ * Prism: Lightweight, robust, elegant syntax highlighting
3649
+ *
3650
+ * @license MIT <https://opensource.org/licenses/MIT>
3651
+ * @author Lea Verou <https://lea.verou.me>
3652
+ * @namespace
3653
+ * @public
3654
+ */
3655
+ var Prism = (function (_self) {
3467
3656
 
3657
+ // Private helper vars
3658
+ var lang = /(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i;
3659
+ var uniqueId = 0;
3468
3660
 
3469
- var _ = {
3470
- /**
3471
- * By default, Prism will attempt to highlight all code elements (by calling {@link Prism.highlightAll}) on the
3472
- * current page after the page finished loading. This might be a problem if e.g. you wanted to asynchronously load
3473
- * additional languages or plugins yourself.
3474
- *
3475
- * By setting this value to `true`, Prism will not automatically highlight all code elements on the page.
3476
- *
3477
- * You obviously have to change this value before the automatic highlighting started. To do this, you can add an
3478
- * empty Prism object into the global scope before loading the Prism script like this:
3479
- *
3480
- * ```js
3481
- * window.Prism = window.Prism || {};
3482
- * Prism.manual = true;
3483
- * // add a new <script> to load Prism's script
3484
- * ```
3485
- *
3486
- * @default false
3487
- * @type {boolean}
3488
- * @memberof Prism
3489
- * @public
3490
- */
3491
- manual: _self.Prism && _self.Prism.manual,
3492
- /**
3493
- * By default, if Prism is in a web worker, it assumes that it is in a worker it created itself, so it uses
3494
- * `addEventListener` to communicate with its parent instance. However, if you're using Prism manually in your
3495
- * own worker, you don't want it to do this.
3496
- *
3497
- * By setting this value to `true`, Prism will not add its own listeners to the worker.
3498
- *
3499
- * You obviously have to change this value before Prism executes. To do this, you can add an
3500
- * empty Prism object into the global scope before loading the Prism script like this:
3501
- *
3502
- * ```js
3503
- * window.Prism = window.Prism || {};
3504
- * Prism.disableWorkerMessageHandler = true;
3505
- * // Load Prism's script
3506
- * ```
3507
- *
3508
- * @default false
3509
- * @type {boolean}
3510
- * @memberof Prism
3511
- * @public
3512
- */
3513
- disableWorkerMessageHandler: _self.Prism && _self.Prism.disableWorkerMessageHandler,
3661
+ // The grammar object for plaintext
3662
+ var plainTextGrammar = {};
3514
3663
 
3515
- /**
3516
- * A namespace for utility methods.
3517
- *
3518
- * All function in this namespace that are not explicitly marked as _public_ are for __internal use only__ and may
3519
- * change or disappear at any time.
3520
- *
3521
- * @namespace
3522
- * @memberof Prism
3523
- */
3524
- util: {
3525
- encode: function encode(tokens) {
3526
- if (tokens instanceof Token) {
3527
- return new Token(tokens.type, encode(tokens.content), tokens.alias);
3528
- } else if (Array.isArray(tokens)) {
3529
- return tokens.map(encode);
3530
- } else {
3531
- return tokens.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/\u00a0/g, ' ');
3532
- }
3533
- },
3534
3664
 
3665
+ var _ = {
3535
3666
  /**
3536
- * Returns the name of the type of the given value.
3667
+ * By default, Prism will attempt to highlight all code elements (by calling {@link Prism.highlightAll}) on the
3668
+ * current page after the page finished loading. This might be a problem if e.g. you wanted to asynchronously load
3669
+ * additional languages or plugins yourself.
3537
3670
  *
3538
- * @param {any} o
3539
- * @returns {string}
3540
- * @example
3541
- * type(null) === 'Null'
3542
- * type(undefined) === 'Undefined'
3543
- * type(123) === 'Number'
3544
- * type('foo') === 'String'
3545
- * type(true) === 'Boolean'
3546
- * type([1, 2]) === 'Array'
3547
- * type({}) === 'Object'
3548
- * type(String) === 'Function'
3549
- * type(/abc+/) === 'RegExp'
3671
+ * By setting this value to `true`, Prism will not automatically highlight all code elements on the page.
3672
+ *
3673
+ * You obviously have to change this value before the automatic highlighting started. To do this, you can add an
3674
+ * empty Prism object into the global scope before loading the Prism script like this:
3675
+ *
3676
+ * ```js
3677
+ * window.Prism = window.Prism || {};
3678
+ * Prism.manual = true;
3679
+ * // add a new <script> to load Prism's script
3680
+ * ```
3681
+ *
3682
+ * @default false
3683
+ * @type {boolean}
3684
+ * @memberof Prism
3685
+ * @public
3550
3686
  */
3551
- type: function (o) {
3552
- return Object.prototype.toString.call(o).slice(8, -1);
3553
- },
3554
-
3687
+ manual: _self.Prism && _self.Prism.manual,
3555
3688
  /**
3556
- * Returns a unique number for the given object. Later calls will still return the same number.
3689
+ * By default, if Prism is in a web worker, it assumes that it is in a worker it created itself, so it uses
3690
+ * `addEventListener` to communicate with its parent instance. However, if you're using Prism manually in your
3691
+ * own worker, you don't want it to do this.
3692
+ *
3693
+ * By setting this value to `true`, Prism will not add its own listeners to the worker.
3557
3694
  *
3558
- * @param {Object} obj
3559
- * @returns {number}
3695
+ * You obviously have to change this value before Prism executes. To do this, you can add an
3696
+ * empty Prism object into the global scope before loading the Prism script like this:
3697
+ *
3698
+ * ```js
3699
+ * window.Prism = window.Prism || {};
3700
+ * Prism.disableWorkerMessageHandler = true;
3701
+ * // Load Prism's script
3702
+ * ```
3703
+ *
3704
+ * @default false
3705
+ * @type {boolean}
3706
+ * @memberof Prism
3707
+ * @public
3560
3708
  */
3561
- objId: function (obj) {
3562
- if (!obj['__id']) {
3563
- Object.defineProperty(obj, '__id', { value: ++uniqueId });
3564
- }
3565
- return obj['__id'];
3566
- },
3709
+ disableWorkerMessageHandler: _self.Prism && _self.Prism.disableWorkerMessageHandler,
3567
3710
 
3568
3711
  /**
3569
- * Creates a deep clone of the given object.
3712
+ * A namespace for utility methods.
3570
3713
  *
3571
- * The main intended use of this function is to clone language definitions.
3714
+ * All function in this namespace that are not explicitly marked as _public_ are for __internal use only__ and may
3715
+ * change or disappear at any time.
3572
3716
  *
3573
- * @param {T} o
3574
- * @param {Record<number, any>} [visited]
3575
- * @returns {T}
3576
- * @template T
3717
+ * @namespace
3718
+ * @memberof Prism
3577
3719
  */
3578
- clone: function deepClone(o, visited) {
3579
- visited = visited || {};
3580
-
3581
- var clone; var id;
3582
- switch (_.util.type(o)) {
3583
- case 'Object':
3584
- id = _.util.objId(o);
3585
- if (visited[id]) {
3586
- return visited[id];
3587
- }
3588
- clone = /** @type {Record<string, any>} */ ({});
3589
- visited[id] = clone;
3720
+ util: {
3721
+ encode: function encode(tokens) {
3722
+ if (tokens instanceof Token) {
3723
+ return new Token(tokens.type, encode(tokens.content), tokens.alias);
3724
+ } else if (Array.isArray(tokens)) {
3725
+ return tokens.map(encode);
3726
+ } else {
3727
+ return tokens.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/\u00a0/g, ' ');
3728
+ }
3729
+ },
3730
+
3731
+ /**
3732
+ * Returns the name of the type of the given value.
3733
+ *
3734
+ * @param {any} o
3735
+ * @returns {string}
3736
+ * @example
3737
+ * type(null) === 'Null'
3738
+ * type(undefined) === 'Undefined'
3739
+ * type(123) === 'Number'
3740
+ * type('foo') === 'String'
3741
+ * type(true) === 'Boolean'
3742
+ * type([1, 2]) === 'Array'
3743
+ * type({}) === 'Object'
3744
+ * type(String) === 'Function'
3745
+ * type(/abc+/) === 'RegExp'
3746
+ */
3747
+ type: function (o) {
3748
+ return Object.prototype.toString.call(o).slice(8, -1);
3749
+ },
3750
+
3751
+ /**
3752
+ * Returns a unique number for the given object. Later calls will still return the same number.
3753
+ *
3754
+ * @param {Object} obj
3755
+ * @returns {number}
3756
+ */
3757
+ objId: function (obj) {
3758
+ if (!obj['__id']) {
3759
+ Object.defineProperty(obj, '__id', { value: ++uniqueId });
3760
+ }
3761
+ return obj['__id'];
3762
+ },
3590
3763
 
3591
- for (var key in o) {
3592
- if (o.hasOwnProperty(key)) {
3593
- clone[key] = deepClone(o[key], visited);
3764
+ /**
3765
+ * Creates a deep clone of the given object.
3766
+ *
3767
+ * The main intended use of this function is to clone language definitions.
3768
+ *
3769
+ * @param {T} o
3770
+ * @param {Record<number, any>} [visited]
3771
+ * @returns {T}
3772
+ * @template T
3773
+ */
3774
+ clone: function deepClone(o, visited) {
3775
+ visited = visited || {};
3776
+
3777
+ var clone; var id;
3778
+ switch (_.util.type(o)) {
3779
+ case 'Object':
3780
+ id = _.util.objId(o);
3781
+ if (visited[id]) {
3782
+ return visited[id];
3594
3783
  }
3595
- }
3784
+ clone = /** @type {Record<string, any>} */ ({});
3785
+ visited[id] = clone;
3786
+
3787
+ for (var key in o) {
3788
+ if (o.hasOwnProperty(key)) {
3789
+ clone[key] = deepClone(o[key], visited);
3790
+ }
3791
+ }
3792
+
3793
+ return /** @type {any} */ (clone);
3794
+
3795
+ case 'Array':
3796
+ id = _.util.objId(o);
3797
+ if (visited[id]) {
3798
+ return visited[id];
3799
+ }
3800
+ clone = [];
3801
+ visited[id] = clone;
3802
+
3803
+ (/** @type {Array} */(/** @type {any} */(o))).forEach(function (v, i) {
3804
+ clone[i] = deepClone(v, visited);
3805
+ });
3596
3806
 
3597
- return /** @type {any} */ (clone);
3807
+ return /** @type {any} */ (clone);
3598
3808
 
3599
- case 'Array':
3600
- id = _.util.objId(o);
3601
- if (visited[id]) {
3602
- return visited[id];
3809
+ default:
3810
+ return o;
3811
+ }
3812
+ },
3813
+
3814
+ /**
3815
+ * Returns the Prism language of the given element set by a `language-xxxx` or `lang-xxxx` class.
3816
+ *
3817
+ * If no language is set for the element or the element is `null` or `undefined`, `none` will be returned.
3818
+ *
3819
+ * @param {Element} element
3820
+ * @returns {string}
3821
+ */
3822
+ getLanguage: function (element) {
3823
+ while (element) {
3824
+ var m = lang.exec(element.className);
3825
+ if (m) {
3826
+ return m[1].toLowerCase();
3603
3827
  }
3604
- clone = [];
3605
- visited[id] = clone;
3828
+ element = element.parentElement;
3829
+ }
3830
+ return 'none';
3831
+ },
3832
+
3833
+ /**
3834
+ * Sets the Prism `language-xxxx` class of the given element.
3835
+ *
3836
+ * @param {Element} element
3837
+ * @param {string} language
3838
+ * @returns {void}
3839
+ */
3840
+ setLanguage: function (element, language) {
3841
+ // remove all `language-xxxx` classes
3842
+ // (this might leave behind a leading space)
3843
+ element.className = element.className.replace(RegExp(lang, 'gi'), '');
3844
+
3845
+ // add the new `language-xxxx` class
3846
+ // (using `classList` will automatically clean up spaces for us)
3847
+ element.classList.add('language-' + language);
3848
+ },
3606
3849
 
3607
- (/** @type {Array} */(/** @type {any} */(o))).forEach(function (v, i) {
3608
- clone[i] = deepClone(v, visited);
3609
- });
3850
+ /**
3851
+ * Returns the script element that is currently executing.
3852
+ *
3853
+ * This does __not__ work for line script element.
3854
+ *
3855
+ * @returns {HTMLScriptElement | null}
3856
+ */
3857
+ currentScript: function () {
3858
+ if (typeof document === 'undefined') {
3859
+ return null;
3860
+ }
3861
+ if (document.currentScript && document.currentScript.tagName === 'SCRIPT' && 1 < 2 /* hack to trip TS' flow analysis */) {
3862
+ return /** @type {any} */ (document.currentScript);
3863
+ }
3610
3864
 
3611
- return /** @type {any} */ (clone);
3865
+ // IE11 workaround
3866
+ // we'll get the src of the current script by parsing IE11's error stack trace
3867
+ // this will not work for inline scripts
3868
+
3869
+ try {
3870
+ throw new Error();
3871
+ } catch (err) {
3872
+ // Get file src url from stack. Specifically works with the format of stack traces in IE.
3873
+ // A stack will look like this:
3874
+ //
3875
+ // Error
3876
+ // at _.util.currentScript (http://localhost/components/prism-core.js:119:5)
3877
+ // at Global code (http://localhost/components/prism-core.js:606:1)
3878
+
3879
+ var src = (/at [^(\r\n]*\((.*):[^:]+:[^:]+\)$/i.exec(err.stack) || [])[1];
3880
+ if (src) {
3881
+ var scripts = document.getElementsByTagName('script');
3882
+ for (var i in scripts) {
3883
+ if (scripts[i].src == src) {
3884
+ return scripts[i];
3885
+ }
3886
+ }
3887
+ }
3888
+ return null;
3889
+ }
3890
+ },
3612
3891
 
3613
- default:
3614
- return o;
3892
+ /**
3893
+ * Returns whether a given class is active for `element`.
3894
+ *
3895
+ * The class can be activated if `element` or one of its ancestors has the given class and it can be deactivated
3896
+ * if `element` or one of its ancestors has the negated version of the given class. The _negated version_ of the
3897
+ * given class is just the given class with a `no-` prefix.
3898
+ *
3899
+ * Whether the class is active is determined by the closest ancestor of `element` (where `element` itself is
3900
+ * closest ancestor) that has the given class or the negated version of it. If neither `element` nor any of its
3901
+ * ancestors have the given class or the negated version of it, then the default activation will be returned.
3902
+ *
3903
+ * In the paradoxical situation where the closest ancestor contains __both__ the given class and the negated
3904
+ * version of it, the class is considered active.
3905
+ *
3906
+ * @param {Element} element
3907
+ * @param {string} className
3908
+ * @param {boolean} [defaultActivation=false]
3909
+ * @returns {boolean}
3910
+ */
3911
+ isActive: function (element, className, defaultActivation) {
3912
+ var no = 'no-' + className;
3913
+
3914
+ while (element) {
3915
+ var classList = element.classList;
3916
+ if (classList.contains(className)) {
3917
+ return true;
3918
+ }
3919
+ if (classList.contains(no)) {
3920
+ return false;
3921
+ }
3922
+ element = element.parentElement;
3923
+ }
3924
+ return !!defaultActivation;
3615
3925
  }
3616
3926
  },
3617
3927
 
3618
3928
  /**
3619
- * Returns the Prism language of the given element set by a `language-xxxx` or `lang-xxxx` class.
3620
- *
3621
- * If no language is set for the element or the element is `null` or `undefined`, `none` will be returned.
3929
+ * This namespace contains all currently loaded languages and the some helper functions to create and modify languages.
3622
3930
  *
3623
- * @param {Element} element
3624
- * @returns {string}
3931
+ * @namespace
3932
+ * @memberof Prism
3933
+ * @public
3625
3934
  */
3626
- getLanguage: function (element) {
3627
- while (element) {
3628
- var m = lang.exec(element.className);
3629
- if (m) {
3630
- return m[1].toLowerCase();
3935
+ languages: {
3936
+ /**
3937
+ * The grammar for plain, unformatted text.
3938
+ */
3939
+ plain: plainTextGrammar,
3940
+ plaintext: plainTextGrammar,
3941
+ text: plainTextGrammar,
3942
+ txt: plainTextGrammar,
3943
+
3944
+ /**
3945
+ * Creates a deep copy of the language with the given id and appends the given tokens.
3946
+ *
3947
+ * If a token in `redef` also appears in the copied language, then the existing token in the copied language
3948
+ * will be overwritten at its original position.
3949
+ *
3950
+ * ## Best practices
3951
+ *
3952
+ * Since the position of overwriting tokens (token in `redef` that overwrite tokens in the copied language)
3953
+ * doesn't matter, they can technically be in any order. However, this can be confusing to others that trying to
3954
+ * understand the language definition because, normally, the order of tokens matters in Prism grammars.
3955
+ *
3956
+ * Therefore, it is encouraged to order overwriting tokens according to the positions of the overwritten tokens.
3957
+ * Furthermore, all non-overwriting tokens should be placed after the overwriting ones.
3958
+ *
3959
+ * @param {string} id The id of the language to extend. This has to be a key in `Prism.languages`.
3960
+ * @param {Grammar} redef The new tokens to append.
3961
+ * @returns {Grammar} The new language created.
3962
+ * @public
3963
+ * @example
3964
+ * Prism.languages['css-with-colors'] = Prism.languages.extend('css', {
3965
+ * // Prism.languages.css already has a 'comment' token, so this token will overwrite CSS' 'comment' token
3966
+ * // at its original position
3967
+ * 'comment': { ... },
3968
+ * // CSS doesn't have a 'color' token, so this token will be appended
3969
+ * 'color': /\b(?:red|green|blue)\b/
3970
+ * });
3971
+ */
3972
+ extend: function (id, redef) {
3973
+ var lang = _.util.clone(_.languages[id]);
3974
+
3975
+ for (var key in redef) {
3976
+ lang[key] = redef[key];
3977
+ }
3978
+
3979
+ return lang;
3980
+ },
3981
+
3982
+ /**
3983
+ * Inserts tokens _before_ another token in a language definition or any other grammar.
3984
+ *
3985
+ * ## Usage
3986
+ *
3987
+ * This helper method makes it easy to modify existing languages. For example, the CSS language definition
3988
+ * not only defines CSS highlighting for CSS documents, but also needs to define highlighting for CSS embedded
3989
+ * in HTML through `<style>` elements. To do this, it needs to modify `Prism.languages.markup` and add the
3990
+ * appropriate tokens. However, `Prism.languages.markup` is a regular JavaScript object literal, so if you do
3991
+ * this:
3992
+ *
3993
+ * ```js
3994
+ * Prism.languages.markup.style = {
3995
+ * // token
3996
+ * };
3997
+ * ```
3998
+ *
3999
+ * then the `style` token will be added (and processed) at the end. `insertBefore` allows you to insert tokens
4000
+ * before existing tokens. For the CSS example above, you would use it like this:
4001
+ *
4002
+ * ```js
4003
+ * Prism.languages.insertBefore('markup', 'cdata', {
4004
+ * 'style': {
4005
+ * // token
4006
+ * }
4007
+ * });
4008
+ * ```
4009
+ *
4010
+ * ## Special cases
4011
+ *
4012
+ * If the grammars of `inside` and `insert` have tokens with the same name, the tokens in `inside`'s grammar
4013
+ * will be ignored.
4014
+ *
4015
+ * This behavior can be used to insert tokens after `before`:
4016
+ *
4017
+ * ```js
4018
+ * Prism.languages.insertBefore('markup', 'comment', {
4019
+ * 'comment': Prism.languages.markup.comment,
4020
+ * // tokens after 'comment'
4021
+ * });
4022
+ * ```
4023
+ *
4024
+ * ## Limitations
4025
+ *
4026
+ * The main problem `insertBefore` has to solve is iteration order. Since ES2015, the iteration order for object
4027
+ * properties is guaranteed to be the insertion order (except for integer keys) but some browsers behave
4028
+ * differently when keys are deleted and re-inserted. So `insertBefore` can't be implemented by temporarily
4029
+ * deleting properties which is necessary to insert at arbitrary positions.
4030
+ *
4031
+ * To solve this problem, `insertBefore` doesn't actually insert the given tokens into the target object.
4032
+ * Instead, it will create a new object and replace all references to the target object with the new one. This
4033
+ * can be done without temporarily deleting properties, so the iteration order is well-defined.
4034
+ *
4035
+ * However, only references that can be reached from `Prism.languages` or `insert` will be replaced. I.e. if
4036
+ * you hold the target object in a variable, then the value of the variable will not change.
4037
+ *
4038
+ * ```js
4039
+ * var oldMarkup = Prism.languages.markup;
4040
+ * var newMarkup = Prism.languages.insertBefore('markup', 'comment', { ... });
4041
+ *
4042
+ * assert(oldMarkup !== Prism.languages.markup);
4043
+ * assert(newMarkup === Prism.languages.markup);
4044
+ * ```
4045
+ *
4046
+ * @param {string} inside The property of `root` (e.g. a language id in `Prism.languages`) that contains the
4047
+ * object to be modified.
4048
+ * @param {string} before The key to insert before.
4049
+ * @param {Grammar} insert An object containing the key-value pairs to be inserted.
4050
+ * @param {Object<string, any>} [root] The object containing `inside`, i.e. the object that contains the
4051
+ * object to be modified.
4052
+ *
4053
+ * Defaults to `Prism.languages`.
4054
+ * @returns {Grammar} The new grammar object.
4055
+ * @public
4056
+ */
4057
+ insertBefore: function (inside, before, insert, root) {
4058
+ root = root || /** @type {any} */ (_.languages);
4059
+ var grammar = root[inside];
4060
+ /** @type {Grammar} */
4061
+ var ret = {};
4062
+
4063
+ for (var token in grammar) {
4064
+ if (grammar.hasOwnProperty(token)) {
4065
+
4066
+ if (token == before) {
4067
+ for (var newToken in insert) {
4068
+ if (insert.hasOwnProperty(newToken)) {
4069
+ ret[newToken] = insert[newToken];
4070
+ }
4071
+ }
4072
+ }
4073
+
4074
+ // Do not insert token which also occur in insert. See #1525
4075
+ if (!insert.hasOwnProperty(token)) {
4076
+ ret[token] = grammar[token];
4077
+ }
4078
+ }
4079
+ }
4080
+
4081
+ var old = root[inside];
4082
+ root[inside] = ret;
4083
+
4084
+ // Update references in other language definitions
4085
+ _.languages.DFS(_.languages, function (key, value) {
4086
+ if (value === old && key != inside) {
4087
+ this[key] = ret;
4088
+ }
4089
+ });
4090
+
4091
+ return ret;
4092
+ },
4093
+
4094
+ // Traverse a language definition with Depth First Search
4095
+ DFS: function DFS(o, callback, type, visited) {
4096
+ visited = visited || {};
4097
+
4098
+ var objId = _.util.objId;
4099
+
4100
+ for (var i in o) {
4101
+ if (o.hasOwnProperty(i)) {
4102
+ callback.call(o, i, o[i], type || i);
4103
+
4104
+ var property = o[i];
4105
+ var propertyType = _.util.type(property);
4106
+
4107
+ if (propertyType === 'Object' && !visited[objId(property)]) {
4108
+ visited[objId(property)] = true;
4109
+ DFS(property, callback, null, visited);
4110
+ } else if (propertyType === 'Array' && !visited[objId(property)]) {
4111
+ visited[objId(property)] = true;
4112
+ DFS(property, callback, i, visited);
4113
+ }
4114
+ }
3631
4115
  }
3632
- element = element.parentElement;
3633
4116
  }
3634
- return 'none';
3635
4117
  },
3636
4118
 
4119
+ plugins: {},
4120
+
3637
4121
  /**
3638
- * Sets the Prism `language-xxxx` class of the given element.
4122
+ * This is the most high-level function in Prism’s API.
4123
+ * It fetches all the elements that have a `.language-xxxx` class and then calls {@link Prism.highlightElement} on
4124
+ * each one of them.
3639
4125
  *
3640
- * @param {Element} element
3641
- * @param {string} language
3642
- * @returns {void}
4126
+ * This is equivalent to `Prism.highlightAllUnder(document, async, callback)`.
4127
+ *
4128
+ * @param {boolean} [async=false] Same as in {@link Prism.highlightAllUnder}.
4129
+ * @param {HighlightCallback} [callback] Same as in {@link Prism.highlightAllUnder}.
4130
+ * @memberof Prism
4131
+ * @public
3643
4132
  */
3644
- setLanguage: function (element, language) {
3645
- // remove all `language-xxxx` classes
3646
- // (this might leave behind a leading space)
3647
- element.className = element.className.replace(RegExp(lang, 'gi'), '');
3648
-
3649
- // add the new `language-xxxx` class
3650
- // (using `classList` will automatically clean up spaces for us)
3651
- element.classList.add('language-' + language);
4133
+ highlightAll: function (async, callback) {
4134
+ _.highlightAllUnder(document, async, callback);
3652
4135
  },
3653
4136
 
3654
4137
  /**
3655
- * Returns the script element that is currently executing.
4138
+ * Fetches all the descendants of `container` that have a `.language-xxxx` class and then calls
4139
+ * {@link Prism.highlightElement} on each one of them.
3656
4140
  *
3657
- * This does __not__ work for line script element.
4141
+ * The following hooks will be run:
4142
+ * 1. `before-highlightall`
4143
+ * 2. `before-all-elements-highlight`
4144
+ * 3. All hooks of {@link Prism.highlightElement} for each element.
3658
4145
  *
3659
- * @returns {HTMLScriptElement | null}
4146
+ * @param {ParentNode} container The root element, whose descendants that have a `.language-xxxx` class will be highlighted.
4147
+ * @param {boolean} [async=false] Whether each element is to be highlighted asynchronously using Web Workers.
4148
+ * @param {HighlightCallback} [callback] An optional callback to be invoked on each element after its highlighting is done.
4149
+ * @memberof Prism
4150
+ * @public
3660
4151
  */
3661
- currentScript: function () {
3662
- if (typeof document === 'undefined') {
3663
- return null;
3664
- }
3665
- if (document.currentScript && document.currentScript.tagName === 'SCRIPT' && 1 < 2 /* hack to trip TS' flow analysis */) {
3666
- return /** @type {any} */ (document.currentScript);
3667
- }
4152
+ highlightAllUnder: function (container, async, callback) {
4153
+ var env = {
4154
+ callback: callback,
4155
+ container: container,
4156
+ selector: 'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'
4157
+ };
3668
4158
 
3669
- // IE11 workaround
3670
- // we'll get the src of the current script by parsing IE11's error stack trace
3671
- // this will not work for inline scripts
3672
-
3673
- try {
3674
- throw new Error();
3675
- } catch (err) {
3676
- // Get file src url from stack. Specifically works with the format of stack traces in IE.
3677
- // A stack will look like this:
3678
- //
3679
- // Error
3680
- // at _.util.currentScript (http://localhost/components/prism-core.js:119:5)
3681
- // at Global code (http://localhost/components/prism-core.js:606:1)
3682
-
3683
- var src = (/at [^(\r\n]*\((.*):[^:]+:[^:]+\)$/i.exec(err.stack) || [])[1];
3684
- if (src) {
3685
- var scripts = document.getElementsByTagName('script');
3686
- for (var i in scripts) {
3687
- if (scripts[i].src == src) {
3688
- return scripts[i];
3689
- }
3690
- }
3691
- }
3692
- return null;
4159
+ _.hooks.run('before-highlightall', env);
4160
+
4161
+ env.elements = Array.prototype.slice.apply(env.container.querySelectorAll(env.selector));
4162
+
4163
+ _.hooks.run('before-all-elements-highlight', env);
4164
+
4165
+ for (var i = 0, element; (element = env.elements[i++]);) {
4166
+ _.highlightElement(element, async === true, env.callback);
3693
4167
  }
3694
4168
  },
3695
4169
 
3696
4170
  /**
3697
- * Returns whether a given class is active for `element`.
4171
+ * Highlights the code inside a single element.
3698
4172
  *
3699
- * The class can be activated if `element` or one of its ancestors has the given class and it can be deactivated
3700
- * if `element` or one of its ancestors has the negated version of the given class. The _negated version_ of the
3701
- * given class is just the given class with a `no-` prefix.
4173
+ * The following hooks will be run:
4174
+ * 1. `before-sanity-check`
4175
+ * 2. `before-highlight`
4176
+ * 3. All hooks of {@link Prism.highlight}. These hooks will be run by an asynchronous worker if `async` is `true`.
4177
+ * 4. `before-insert`
4178
+ * 5. `after-highlight`
4179
+ * 6. `complete`
3702
4180
  *
3703
- * Whether the class is active is determined by the closest ancestor of `element` (where `element` itself is
3704
- * closest ancestor) that has the given class or the negated version of it. If neither `element` nor any of its
3705
- * ancestors have the given class or the negated version of it, then the default activation will be returned.
4181
+ * Some the above hooks will be skipped if the element doesn't contain any text or there is no grammar loaded for
4182
+ * the element's language.
3706
4183
  *
3707
- * In the paradoxical situation where the closest ancestor contains __both__ the given class and the negated
3708
- * version of it, the class is considered active.
4184
+ * @param {Element} element The element containing the code.
4185
+ * It must have a class of `language-xxxx` to be processed, where `xxxx` is a valid language identifier.
4186
+ * @param {boolean} [async=false] Whether the element is to be highlighted asynchronously using Web Workers
4187
+ * to improve performance and avoid blocking the UI when highlighting very large chunks of code. This option is
4188
+ * [disabled by default](https://prismjs.com/faq.html#why-is-asynchronous-highlighting-disabled-by-default).
3709
4189
  *
3710
- * @param {Element} element
3711
- * @param {string} className
3712
- * @param {boolean} [defaultActivation=false]
3713
- * @returns {boolean}
4190
+ * Note: All language definitions required to highlight the code must be included in the main `prism.js` file for
4191
+ * asynchronous highlighting to work. You can build your own bundle on the
4192
+ * [Download page](https://prismjs.com/download.html).
4193
+ * @param {HighlightCallback} [callback] An optional callback to be invoked after the highlighting is done.
4194
+ * Mostly useful when `async` is `true`, since in that case, the highlighting is done asynchronously.
4195
+ * @memberof Prism
4196
+ * @public
3714
4197
  */
3715
- isActive: function (element, className, defaultActivation) {
3716
- var no = 'no-' + className;
4198
+ highlightElement: function (element, async, callback) {
4199
+ // Find language
4200
+ var language = _.util.getLanguage(element);
4201
+ var grammar = _.languages[language];
4202
+
4203
+ // Set language on the element, if not present
4204
+ _.util.setLanguage(element, language);
4205
+
4206
+ // Set language on the parent, for styling
4207
+ var parent = element.parentElement;
4208
+ if (parent && parent.nodeName.toLowerCase() === 'pre') {
4209
+ _.util.setLanguage(parent, language);
4210
+ }
3717
4211
 
3718
- while (element) {
3719
- var classList = element.classList;
3720
- if (classList.contains(className)) {
3721
- return true;
3722
- }
3723
- if (classList.contains(no)) {
3724
- return false;
3725
- }
3726
- element = element.parentElement;
4212
+ var code = element.textContent;
4213
+
4214
+ var env = {
4215
+ element: element,
4216
+ language: language,
4217
+ grammar: grammar,
4218
+ code: code
4219
+ };
4220
+
4221
+ function insertHighlightedCode(highlightedCode) {
4222
+ env.highlightedCode = highlightedCode;
4223
+
4224
+ _.hooks.run('before-insert', env);
4225
+
4226
+ env.element.innerHTML = env.highlightedCode;
4227
+
4228
+ _.hooks.run('after-highlight', env);
4229
+ _.hooks.run('complete', env);
4230
+ callback && callback.call(env.element);
3727
4231
  }
3728
- return !!defaultActivation;
3729
- }
3730
- },
3731
4232
 
3732
- /**
3733
- * This namespace contains all currently loaded languages and the some helper functions to create and modify languages.
3734
- *
3735
- * @namespace
3736
- * @memberof Prism
3737
- * @public
3738
- */
3739
- languages: {
3740
- /**
3741
- * The grammar for plain, unformatted text.
3742
- */
3743
- plain: plainTextGrammar,
3744
- plaintext: plainTextGrammar,
3745
- text: plainTextGrammar,
3746
- txt: plainTextGrammar,
4233
+ _.hooks.run('before-sanity-check', env);
4234
+
4235
+ // plugins may change/add the parent/element
4236
+ parent = env.element.parentElement;
4237
+ if (parent && parent.nodeName.toLowerCase() === 'pre' && !parent.hasAttribute('tabindex')) {
4238
+ parent.setAttribute('tabindex', '0');
4239
+ }
4240
+
4241
+ if (!env.code) {
4242
+ _.hooks.run('complete', env);
4243
+ callback && callback.call(env.element);
4244
+ return;
4245
+ }
4246
+
4247
+ _.hooks.run('before-highlight', env);
4248
+
4249
+ if (!env.grammar) {
4250
+ insertHighlightedCode(_.util.encode(env.code));
4251
+ return;
4252
+ }
4253
+
4254
+ if (async && _self.Worker) {
4255
+ var worker = new Worker(_.filename);
4256
+
4257
+ worker.onmessage = function (evt) {
4258
+ insertHighlightedCode(evt.data);
4259
+ };
4260
+
4261
+ worker.postMessage(JSON.stringify({
4262
+ language: env.language,
4263
+ code: env.code,
4264
+ immediateClose: true
4265
+ }));
4266
+ } else {
4267
+ insertHighlightedCode(_.highlight(env.code, env.grammar, env.language));
4268
+ }
4269
+ },
3747
4270
 
3748
4271
  /**
3749
- * Creates a deep copy of the language with the given id and appends the given tokens.
3750
- *
3751
- * If a token in `redef` also appears in the copied language, then the existing token in the copied language
3752
- * will be overwritten at its original position.
4272
+ * Low-level function, only use if you know what you’re doing. It accepts a string of text as input
4273
+ * and the language definitions to use, and returns a string with the HTML produced.
3753
4274
  *
3754
- * ## Best practices
4275
+ * The following hooks will be run:
4276
+ * 1. `before-tokenize`
4277
+ * 2. `after-tokenize`
4278
+ * 3. `wrap`: On each {@link Token}.
3755
4279
  *
3756
- * Since the position of overwriting tokens (token in `redef` that overwrite tokens in the copied language)
3757
- * doesn't matter, they can technically be in any order. However, this can be confusing to others that trying to
3758
- * understand the language definition because, normally, the order of tokens matters in Prism grammars.
4280
+ * @param {string} text A string with the code to be highlighted.
4281
+ * @param {Grammar} grammar An object containing the tokens to use.
3759
4282
  *
3760
- * Therefore, it is encouraged to order overwriting tokens according to the positions of the overwritten tokens.
3761
- * Furthermore, all non-overwriting tokens should be placed after the overwriting ones.
3762
- *
3763
- * @param {string} id The id of the language to extend. This has to be a key in `Prism.languages`.
3764
- * @param {Grammar} redef The new tokens to append.
3765
- * @returns {Grammar} The new language created.
4283
+ * Usually a language definition like `Prism.languages.markup`.
4284
+ * @param {string} language The name of the language definition passed to `grammar`.
4285
+ * @returns {string} The highlighted HTML.
4286
+ * @memberof Prism
3766
4287
  * @public
3767
4288
  * @example
3768
- * Prism.languages['css-with-colors'] = Prism.languages.extend('css', {
3769
- * // Prism.languages.css already has a 'comment' token, so this token will overwrite CSS' 'comment' token
3770
- * // at its original position
3771
- * 'comment': { ... },
3772
- * // CSS doesn't have a 'color' token, so this token will be appended
3773
- * 'color': /\b(?:red|green|blue)\b/
3774
- * });
4289
+ * Prism.highlight('var foo = true;', Prism.languages.javascript, 'javascript');
3775
4290
  */
3776
- extend: function (id, redef) {
3777
- var lang = _.util.clone(_.languages[id]);
3778
-
3779
- for (var key in redef) {
3780
- lang[key] = redef[key];
4291
+ highlight: function (text, grammar, language) {
4292
+ var env = {
4293
+ code: text,
4294
+ grammar: grammar,
4295
+ language: language
4296
+ };
4297
+ _.hooks.run('before-tokenize', env);
4298
+ if (!env.grammar) {
4299
+ throw new Error('The language "' + env.language + '" has no grammar.');
3781
4300
  }
3782
-
3783
- return lang;
4301
+ env.tokens = _.tokenize(env.code, env.grammar);
4302
+ _.hooks.run('after-tokenize', env);
4303
+ return Token.stringify(_.util.encode(env.tokens), env.language);
3784
4304
  },
3785
4305
 
3786
4306
  /**
3787
- * Inserts tokens _before_ another token in a language definition or any other grammar.
3788
- *
3789
- * ## Usage
4307
+ * This is the heart of Prism, and the most low-level function you can use. It accepts a string of text as input
4308
+ * and the language definitions to use, and returns an array with the tokenized code.
3790
4309
  *
3791
- * This helper method makes it easy to modify existing languages. For example, the CSS language definition
3792
- * not only defines CSS highlighting for CSS documents, but also needs to define highlighting for CSS embedded
3793
- * in HTML through `<style>` elements. To do this, it needs to modify `Prism.languages.markup` and add the
3794
- * appropriate tokens. However, `Prism.languages.markup` is a regular JavaScript object literal, so if you do
3795
- * this:
4310
+ * When the language definition includes nested tokens, the function is called recursively on each of these tokens.
3796
4311
  *
3797
- * ```js
3798
- * Prism.languages.markup.style = {
3799
- * // token
3800
- * };
3801
- * ```
4312
+ * This method could be useful in other contexts as well, as a very crude parser.
3802
4313
  *
3803
- * then the `style` token will be added (and processed) at the end. `insertBefore` allows you to insert tokens
3804
- * before existing tokens. For the CSS example above, you would use it like this:
4314
+ * @param {string} text A string with the code to be highlighted.
4315
+ * @param {Grammar} grammar An object containing the tokens to use.
3805
4316
  *
3806
- * ```js
3807
- * Prism.languages.insertBefore('markup', 'cdata', {
3808
- * 'style': {
3809
- * // token
4317
+ * Usually a language definition like `Prism.languages.markup`.
4318
+ * @returns {TokenStream} An array of strings and tokens, a token stream.
4319
+ * @memberof Prism
4320
+ * @public
4321
+ * @example
4322
+ * let code = `var foo = 0;`;
4323
+ * let tokens = Prism.tokenize(code, Prism.languages.javascript);
4324
+ * tokens.forEach(token => {
4325
+ * if (token instanceof Prism.Token && token.type === 'number') {
4326
+ * console.log(`Found numeric literal: ${token.content}`);
3810
4327
  * }
3811
4328
  * });
3812
- * ```
3813
- *
3814
- * ## Special cases
3815
- *
3816
- * If the grammars of `inside` and `insert` have tokens with the same name, the tokens in `inside`'s grammar
3817
- * will be ignored.
3818
- *
3819
- * This behavior can be used to insert tokens after `before`:
3820
- *
3821
- * ```js
3822
- * Prism.languages.insertBefore('markup', 'comment', {
3823
- * 'comment': Prism.languages.markup.comment,
3824
- * // tokens after 'comment'
3825
- * });
3826
- * ```
3827
- *
3828
- * ## Limitations
3829
- *
3830
- * The main problem `insertBefore` has to solve is iteration order. Since ES2015, the iteration order for object
3831
- * properties is guaranteed to be the insertion order (except for integer keys) but some browsers behave
3832
- * differently when keys are deleted and re-inserted. So `insertBefore` can't be implemented by temporarily
3833
- * deleting properties which is necessary to insert at arbitrary positions.
3834
- *
3835
- * To solve this problem, `insertBefore` doesn't actually insert the given tokens into the target object.
3836
- * Instead, it will create a new object and replace all references to the target object with the new one. This
3837
- * can be done without temporarily deleting properties, so the iteration order is well-defined.
3838
- *
3839
- * However, only references that can be reached from `Prism.languages` or `insert` will be replaced. I.e. if
3840
- * you hold the target object in a variable, then the value of the variable will not change.
3841
- *
3842
- * ```js
3843
- * var oldMarkup = Prism.languages.markup;
3844
- * var newMarkup = Prism.languages.insertBefore('markup', 'comment', { ... });
3845
- *
3846
- * assert(oldMarkup !== Prism.languages.markup);
3847
- * assert(newMarkup === Prism.languages.markup);
3848
- * ```
3849
- *
3850
- * @param {string} inside The property of `root` (e.g. a language id in `Prism.languages`) that contains the
3851
- * object to be modified.
3852
- * @param {string} before The key to insert before.
3853
- * @param {Grammar} insert An object containing the key-value pairs to be inserted.
3854
- * @param {Object<string, any>} [root] The object containing `inside`, i.e. the object that contains the
3855
- * object to be modified.
3856
- *
3857
- * Defaults to `Prism.languages`.
3858
- * @returns {Grammar} The new grammar object.
3859
- * @public
3860
4329
  */
3861
- insertBefore: function (inside, before, insert, root) {
3862
- root = root || /** @type {any} */ (_.languages);
3863
- var grammar = root[inside];
3864
- /** @type {Grammar} */
3865
- var ret = {};
3866
-
3867
- for (var token in grammar) {
3868
- if (grammar.hasOwnProperty(token)) {
3869
-
3870
- if (token == before) {
3871
- for (var newToken in insert) {
3872
- if (insert.hasOwnProperty(newToken)) {
3873
- ret[newToken] = insert[newToken];
3874
- }
3875
- }
3876
- }
3877
-
3878
- // Do not insert token which also occur in insert. See #1525
3879
- if (!insert.hasOwnProperty(token)) {
3880
- ret[token] = grammar[token];
3881
- }
4330
+ tokenize: function (text, grammar) {
4331
+ var rest = grammar.rest;
4332
+ if (rest) {
4333
+ for (var token in rest) {
4334
+ grammar[token] = rest[token];
3882
4335
  }
4336
+
4337
+ delete grammar.rest;
3883
4338
  }
3884
4339
 
3885
- var old = root[inside];
3886
- root[inside] = ret;
4340
+ var tokenList = new LinkedList();
4341
+ addAfter(tokenList, tokenList.head, text);
3887
4342
 
3888
- // Update references in other language definitions
3889
- _.languages.DFS(_.languages, function (key, value) {
3890
- if (value === old && key != inside) {
3891
- this[key] = ret;
3892
- }
3893
- });
4343
+ matchGrammar(text, tokenList, grammar, tokenList.head, 0);
3894
4344
 
3895
- return ret;
4345
+ return toArray(tokenList);
3896
4346
  },
3897
4347
 
3898
- // Traverse a language definition with Depth First Search
3899
- DFS: function DFS(o, callback, type, visited) {
3900
- visited = visited || {};
3901
-
3902
- var objId = _.util.objId;
3903
-
3904
- for (var i in o) {
3905
- if (o.hasOwnProperty(i)) {
3906
- callback.call(o, i, o[i], type || i);
4348
+ /**
4349
+ * @namespace
4350
+ * @memberof Prism
4351
+ * @public
4352
+ */
4353
+ hooks: {
4354
+ all: {},
4355
+
4356
+ /**
4357
+ * Adds the given callback to the list of callbacks for the given hook.
4358
+ *
4359
+ * The callback will be invoked when the hook it is registered for is run.
4360
+ * Hooks are usually directly run by a highlight function but you can also run hooks yourself.
4361
+ *
4362
+ * One callback function can be registered to multiple hooks and the same hook multiple times.
4363
+ *
4364
+ * @param {string} name The name of the hook.
4365
+ * @param {HookCallback} callback The callback function which is given environment variables.
4366
+ * @public
4367
+ */
4368
+ add: function (name, callback) {
4369
+ var hooks = _.hooks.all;
4370
+
4371
+ hooks[name] = hooks[name] || [];
4372
+
4373
+ hooks[name].push(callback);
4374
+ },
3907
4375
 
3908
- var property = o[i];
3909
- var propertyType = _.util.type(property);
4376
+ /**
4377
+ * Runs a hook invoking all registered callbacks with the given environment variables.
4378
+ *
4379
+ * Callbacks will be invoked synchronously and in the order in which they were registered.
4380
+ *
4381
+ * @param {string} name The name of the hook.
4382
+ * @param {Object<string, any>} env The environment variables of the hook passed to all callbacks registered.
4383
+ * @public
4384
+ */
4385
+ run: function (name, env) {
4386
+ var callbacks = _.hooks.all[name];
4387
+
4388
+ if (!callbacks || !callbacks.length) {
4389
+ return;
4390
+ }
3910
4391
 
3911
- if (propertyType === 'Object' && !visited[objId(property)]) {
3912
- visited[objId(property)] = true;
3913
- DFS(property, callback, null, visited);
3914
- } else if (propertyType === 'Array' && !visited[objId(property)]) {
3915
- visited[objId(property)] = true;
3916
- DFS(property, callback, i, visited);
3917
- }
4392
+ for (var i = 0, callback; (callback = callbacks[i++]);) {
4393
+ callback(env);
3918
4394
  }
3919
4395
  }
3920
- }
3921
- },
4396
+ },
4397
+
4398
+ Token: Token
4399
+ };
4400
+ _self.Prism = _;
3922
4401
 
3923
- plugins: {},
4402
+
4403
+ // Typescript note:
4404
+ // The following can be used to import the Token type in JSDoc:
4405
+ //
4406
+ // @typedef {InstanceType<import("./prism-core")["Token"]>} Token
3924
4407
 
3925
4408
  /**
3926
- * This is the most high-level function in Prism’s API.
3927
- * It fetches all the elements that have a `.language-xxxx` class and then calls {@link Prism.highlightElement} on
3928
- * each one of them.
3929
- *
3930
- * This is equivalent to `Prism.highlightAllUnder(document, async, callback)`.
4409
+ * Creates a new token.
3931
4410
  *
3932
- * @param {boolean} [async=false] Same as in {@link Prism.highlightAllUnder}.
3933
- * @param {HighlightCallback} [callback] Same as in {@link Prism.highlightAllUnder}.
3934
- * @memberof Prism
4411
+ * @param {string} type See {@link Token#type type}
4412
+ * @param {string | TokenStream} content See {@link Token#content content}
4413
+ * @param {string|string[]} [alias] The alias(es) of the token.
4414
+ * @param {string} [matchedStr=""] A copy of the full string this token was created from.
4415
+ * @class
4416
+ * @global
3935
4417
  * @public
3936
4418
  */
3937
- highlightAll: function (async, callback) {
3938
- _.highlightAllUnder(document, async, callback);
3939
- },
4419
+ function Token(type, content, alias, matchedStr) {
4420
+ /**
4421
+ * The type of the token.
4422
+ *
4423
+ * This is usually the key of a pattern in a {@link Grammar}.
4424
+ *
4425
+ * @type {string}
4426
+ * @see GrammarToken
4427
+ * @public
4428
+ */
4429
+ this.type = type;
4430
+ /**
4431
+ * The strings or tokens contained by this token.
4432
+ *
4433
+ * This will be a token stream if the pattern matched also defined an `inside` grammar.
4434
+ *
4435
+ * @type {string | TokenStream}
4436
+ * @public
4437
+ */
4438
+ this.content = content;
4439
+ /**
4440
+ * The alias(es) of the token.
4441
+ *
4442
+ * @type {string|string[]}
4443
+ * @see GrammarToken
4444
+ * @public
4445
+ */
4446
+ this.alias = alias;
4447
+ // Copy of the full string this token was created from
4448
+ this.length = (matchedStr || '').length | 0;
4449
+ }
3940
4450
 
3941
4451
  /**
3942
- * Fetches all the descendants of `container` that have a `.language-xxxx` class and then calls
3943
- * {@link Prism.highlightElement} on each one of them.
4452
+ * A token stream is an array of strings and {@link Token Token} objects.
3944
4453
  *
3945
- * The following hooks will be run:
3946
- * 1. `before-highlightall`
3947
- * 2. `before-all-elements-highlight`
3948
- * 3. All hooks of {@link Prism.highlightElement} for each element.
4454
+ * Token streams have to fulfill a few properties that are assumed by most functions (mostly internal ones) that process
4455
+ * them.
4456
+ *
4457
+ * 1. No adjacent strings.
4458
+ * 2. No empty strings.
3949
4459
  *
3950
- * @param {ParentNode} container The root element, whose descendants that have a `.language-xxxx` class will be highlighted.
3951
- * @param {boolean} [async=false] Whether each element is to be highlighted asynchronously using Web Workers.
3952
- * @param {HighlightCallback} [callback] An optional callback to be invoked on each element after its highlighting is done.
3953
- * @memberof Prism
4460
+ * The only exception here is the token stream that only contains the empty string and nothing else.
4461
+ *
4462
+ * @typedef {Array<string | Token>} TokenStream
4463
+ * @global
3954
4464
  * @public
3955
4465
  */
3956
- highlightAllUnder: function (container, async, callback) {
3957
- var env = {
3958
- callback: callback,
3959
- container: container,
3960
- selector: 'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'
3961
- };
3962
-
3963
- _.hooks.run('before-highlightall', env);
3964
-
3965
- env.elements = Array.prototype.slice.apply(env.container.querySelectorAll(env.selector));
3966
-
3967
- _.hooks.run('before-all-elements-highlight', env);
3968
-
3969
- for (var i = 0, element; (element = env.elements[i++]);) {
3970
- _.highlightElement(element, async === true, env.callback);
3971
- }
3972
- },
3973
4466
 
3974
4467
  /**
3975
- * Highlights the code inside a single element.
4468
+ * Converts the given token or token stream to an HTML representation.
3976
4469
  *
3977
4470
  * The following hooks will be run:
3978
- * 1. `before-sanity-check`
3979
- * 2. `before-highlight`
3980
- * 3. All hooks of {@link Prism.highlight}. These hooks will be run by an asynchronous worker if `async` is `true`.
3981
- * 4. `before-insert`
3982
- * 5. `after-highlight`
3983
- * 6. `complete`
3984
- *
3985
- * Some the above hooks will be skipped if the element doesn't contain any text or there is no grammar loaded for
3986
- * the element's language.
4471
+ * 1. `wrap`: On each {@link Token}.
3987
4472
  *
3988
- * @param {Element} element The element containing the code.
3989
- * It must have a class of `language-xxxx` to be processed, where `xxxx` is a valid language identifier.
3990
- * @param {boolean} [async=false] Whether the element is to be highlighted asynchronously using Web Workers
3991
- * to improve performance and avoid blocking the UI when highlighting very large chunks of code. This option is
3992
- * [disabled by default](https://prismjs.com/faq.html#why-is-asynchronous-highlighting-disabled-by-default).
3993
- *
3994
- * Note: All language definitions required to highlight the code must be included in the main `prism.js` file for
3995
- * asynchronous highlighting to work. You can build your own bundle on the
3996
- * [Download page](https://prismjs.com/download.html).
3997
- * @param {HighlightCallback} [callback] An optional callback to be invoked after the highlighting is done.
3998
- * Mostly useful when `async` is `true`, since in that case, the highlighting is done asynchronously.
3999
- * @memberof Prism
4000
- * @public
4473
+ * @param {string | Token | TokenStream} o The token or token stream to be converted.
4474
+ * @param {string} language The name of current language.
4475
+ * @returns {string} The HTML representation of the token or token stream.
4476
+ * @memberof Token
4477
+ * @static
4001
4478
  */
4002
- highlightElement: function (element, async, callback) {
4003
- // Find language
4004
- var language = _.util.getLanguage(element);
4005
- var grammar = _.languages[language];
4006
-
4007
- // Set language on the element, if not present
4008
- _.util.setLanguage(element, language);
4009
-
4010
- // Set language on the parent, for styling
4011
- var parent = element.parentElement;
4012
- if (parent && parent.nodeName.toLowerCase() === 'pre') {
4013
- _.util.setLanguage(parent, language);
4479
+ Token.stringify = function stringify(o, language) {
4480
+ if (typeof o == 'string') {
4481
+ return o;
4482
+ }
4483
+ if (Array.isArray(o)) {
4484
+ var s = '';
4485
+ o.forEach(function (e) {
4486
+ s += stringify(e, language);
4487
+ });
4488
+ return s;
4014
4489
  }
4015
-
4016
- var code = element.textContent;
4017
4490
 
4018
4491
  var env = {
4019
- element: element,
4020
- language: language,
4021
- grammar: grammar,
4022
- code: code
4492
+ type: o.type,
4493
+ content: stringify(o.content, language),
4494
+ tag: 'span',
4495
+ classes: ['token', o.type],
4496
+ attributes: {},
4497
+ language: language
4023
4498
  };
4024
4499
 
4025
- function insertHighlightedCode(highlightedCode) {
4026
- env.highlightedCode = highlightedCode;
4027
-
4028
- _.hooks.run('before-insert', env);
4029
-
4030
- env.element.innerHTML = env.highlightedCode;
4031
-
4032
- _.hooks.run('after-highlight', env);
4033
- _.hooks.run('complete', env);
4034
- callback && callback.call(env.element);
4035
- }
4036
-
4037
- _.hooks.run('before-sanity-check', env);
4038
-
4039
- // plugins may change/add the parent/element
4040
- parent = env.element.parentElement;
4041
- if (parent && parent.nodeName.toLowerCase() === 'pre' && !parent.hasAttribute('tabindex')) {
4042
- parent.setAttribute('tabindex', '0');
4043
- }
4044
-
4045
- if (!env.code) {
4046
- _.hooks.run('complete', env);
4047
- callback && callback.call(env.element);
4048
- return;
4500
+ var aliases = o.alias;
4501
+ if (aliases) {
4502
+ if (Array.isArray(aliases)) {
4503
+ Array.prototype.push.apply(env.classes, aliases);
4504
+ } else {
4505
+ env.classes.push(aliases);
4506
+ }
4049
4507
  }
4050
4508
 
4051
- _.hooks.run('before-highlight', env);
4509
+ _.hooks.run('wrap', env);
4052
4510
 
4053
- if (!env.grammar) {
4054
- insertHighlightedCode(_.util.encode(env.code));
4055
- return;
4511
+ var attributes = '';
4512
+ for (var name in env.attributes) {
4513
+ attributes += ' ' + name + '="' + (env.attributes[name] || '').replace(/"/g, '&quot;') + '"';
4056
4514
  }
4057
4515
 
4058
- if (async && _self.Worker) {
4059
- var worker = new Worker(_.filename);
4060
-
4061
- worker.onmessage = function (evt) {
4062
- insertHighlightedCode(evt.data);
4063
- };
4064
-
4065
- worker.postMessage(JSON.stringify({
4066
- language: env.language,
4067
- code: env.code,
4068
- immediateClose: true
4069
- }));
4070
- } else {
4071
- insertHighlightedCode(_.highlight(env.code, env.grammar, env.language));
4072
- }
4073
- },
4516
+ return '<' + env.tag + ' class="' + env.classes.join(' ') + '"' + attributes + '>' + env.content + '</' + env.tag + '>';
4517
+ };
4074
4518
 
4075
4519
  /**
4076
- * Low-level function, only use if you know what you’re doing. It accepts a string of text as input
4077
- * and the language definitions to use, and returns a string with the HTML produced.
4078
- *
4079
- * The following hooks will be run:
4080
- * 1. `before-tokenize`
4081
- * 2. `after-tokenize`
4082
- * 3. `wrap`: On each {@link Token}.
4083
- *
4084
- * @param {string} text A string with the code to be highlighted.
4085
- * @param {Grammar} grammar An object containing the tokens to use.
4086
- *
4087
- * Usually a language definition like `Prism.languages.markup`.
4088
- * @param {string} language The name of the language definition passed to `grammar`.
4089
- * @returns {string} The highlighted HTML.
4090
- * @memberof Prism
4091
- * @public
4092
- * @example
4093
- * Prism.highlight('var foo = true;', Prism.languages.javascript, 'javascript');
4520
+ * @param {RegExp} pattern
4521
+ * @param {number} pos
4522
+ * @param {string} text
4523
+ * @param {boolean} lookbehind
4524
+ * @returns {RegExpExecArray | null}
4094
4525
  */
4095
- highlight: function (text, grammar, language) {
4096
- var env = {
4097
- code: text,
4098
- grammar: grammar,
4099
- language: language
4100
- };
4101
- _.hooks.run('before-tokenize', env);
4102
- if (!env.grammar) {
4103
- throw new Error('The language "' + env.language + '" has no grammar.');
4526
+ function matchPattern(pattern, pos, text, lookbehind) {
4527
+ pattern.lastIndex = pos;
4528
+ var match = pattern.exec(text);
4529
+ if (match && lookbehind && match[1]) {
4530
+ // change the match to remove the text matched by the Prism lookbehind group
4531
+ var lookbehindLength = match[1].length;
4532
+ match.index += lookbehindLength;
4533
+ match[0] = match[0].slice(lookbehindLength);
4104
4534
  }
4105
- env.tokens = _.tokenize(env.code, env.grammar);
4106
- _.hooks.run('after-tokenize', env);
4107
- return Token.stringify(_.util.encode(env.tokens), env.language);
4108
- },
4535
+ return match;
4536
+ }
4109
4537
 
4110
4538
  /**
4111
- * This is the heart of Prism, and the most low-level function you can use. It accepts a string of text as input
4112
- * and the language definitions to use, and returns an array with the tokenized code.
4113
- *
4114
- * When the language definition includes nested tokens, the function is called recursively on each of these tokens.
4539
+ * @param {string} text
4540
+ * @param {LinkedList<string | Token>} tokenList
4541
+ * @param {any} grammar
4542
+ * @param {LinkedListNode<string | Token>} startNode
4543
+ * @param {number} startPos
4544
+ * @param {RematchOptions} [rematch]
4545
+ * @returns {void}
4546
+ * @private
4115
4547
  *
4116
- * This method could be useful in other contexts as well, as a very crude parser.
4117
- *
4118
- * @param {string} text A string with the code to be highlighted.
4119
- * @param {Grammar} grammar An object containing the tokens to use.
4120
- *
4121
- * Usually a language definition like `Prism.languages.markup`.
4122
- * @returns {TokenStream} An array of strings and tokens, a token stream.
4123
- * @memberof Prism
4124
- * @public
4125
- * @example
4126
- * let code = `var foo = 0;`;
4127
- * let tokens = Prism.tokenize(code, Prism.languages.javascript);
4128
- * tokens.forEach(token => {
4129
- * if (token instanceof Prism.Token && token.type === 'number') {
4130
- * console.log(`Found numeric literal: ${token.content}`);
4131
- * }
4132
- * });
4133
- */
4134
- tokenize: function (text, grammar) {
4135
- var rest = grammar.rest;
4136
- if (rest) {
4137
- for (var token in rest) {
4138
- grammar[token] = rest[token];
4139
- }
4140
-
4141
- delete grammar.rest;
4142
- }
4143
-
4144
- var tokenList = new LinkedList();
4145
- addAfter(tokenList, tokenList.head, text);
4146
-
4147
- matchGrammar(text, tokenList, grammar, tokenList.head, 0);
4148
-
4149
- return toArray(tokenList);
4150
- },
4151
-
4152
- /**
4153
- * @namespace
4154
- * @memberof Prism
4155
- * @public
4548
+ * @typedef RematchOptions
4549
+ * @property {string} cause
4550
+ * @property {number} reach
4156
4551
  */
4157
- hooks: {
4158
- all: {},
4159
-
4160
- /**
4161
- * Adds the given callback to the list of callbacks for the given hook.
4162
- *
4163
- * The callback will be invoked when the hook it is registered for is run.
4164
- * Hooks are usually directly run by a highlight function but you can also run hooks yourself.
4165
- *
4166
- * One callback function can be registered to multiple hooks and the same hook multiple times.
4167
- *
4168
- * @param {string} name The name of the hook.
4169
- * @param {HookCallback} callback The callback function which is given environment variables.
4170
- * @public
4171
- */
4172
- add: function (name, callback) {
4173
- var hooks = _.hooks.all;
4174
-
4175
- hooks[name] = hooks[name] || [];
4176
-
4177
- hooks[name].push(callback);
4178
- },
4179
-
4180
- /**
4181
- * Runs a hook invoking all registered callbacks with the given environment variables.
4182
- *
4183
- * Callbacks will be invoked synchronously and in the order in which they were registered.
4184
- *
4185
- * @param {string} name The name of the hook.
4186
- * @param {Object<string, any>} env The environment variables of the hook passed to all callbacks registered.
4187
- * @public
4188
- */
4189
- run: function (name, env) {
4190
- var callbacks = _.hooks.all[name];
4191
-
4192
- if (!callbacks || !callbacks.length) {
4193
- return;
4552
+ function matchGrammar(text, tokenList, grammar, startNode, startPos, rematch) {
4553
+ for (var token in grammar) {
4554
+ if (!grammar.hasOwnProperty(token) || !grammar[token]) {
4555
+ continue;
4194
4556
  }
4195
4557
 
4196
- for (var i = 0, callback; (callback = callbacks[i++]);) {
4197
- callback(env);
4198
- }
4199
- }
4200
- },
4558
+ var patterns = grammar[token];
4559
+ patterns = Array.isArray(patterns) ? patterns : [patterns];
4201
4560
 
4202
- Token: Token
4203
- };
4204
- _self.Prism = _;
4561
+ for (var j = 0; j < patterns.length; ++j) {
4562
+ if (rematch && rematch.cause == token + ',' + j) {
4563
+ return;
4564
+ }
4205
4565
 
4566
+ var patternObj = patterns[j];
4567
+ var inside = patternObj.inside;
4568
+ var lookbehind = !!patternObj.lookbehind;
4569
+ var greedy = !!patternObj.greedy;
4570
+ var alias = patternObj.alias;
4206
4571
 
4207
- // Typescript note:
4208
- // The following can be used to import the Token type in JSDoc:
4209
- //
4210
- // @typedef {InstanceType<import("./prism-core")["Token"]>} Token
4572
+ if (greedy && !patternObj.pattern.global) {
4573
+ // Without the global flag, lastIndex won't work
4574
+ var flags = patternObj.pattern.toString().match(/[imsuy]*$/)[0];
4575
+ patternObj.pattern = RegExp(patternObj.pattern.source, flags + 'g');
4576
+ }
4211
4577
 
4212
- /**
4213
- * Creates a new token.
4214
- *
4215
- * @param {string} type See {@link Token#type type}
4216
- * @param {string | TokenStream} content See {@link Token#content content}
4217
- * @param {string|string[]} [alias] The alias(es) of the token.
4218
- * @param {string} [matchedStr=""] A copy of the full string this token was created from.
4219
- * @class
4220
- * @global
4221
- * @public
4222
- */
4223
- function Token(type, content, alias, matchedStr) {
4224
- /**
4225
- * The type of the token.
4226
- *
4227
- * This is usually the key of a pattern in a {@link Grammar}.
4228
- *
4229
- * @type {string}
4230
- * @see GrammarToken
4231
- * @public
4232
- */
4233
- this.type = type;
4234
- /**
4235
- * The strings or tokens contained by this token.
4236
- *
4237
- * This will be a token stream if the pattern matched also defined an `inside` grammar.
4238
- *
4239
- * @type {string | TokenStream}
4240
- * @public
4241
- */
4242
- this.content = content;
4243
- /**
4244
- * The alias(es) of the token.
4245
- *
4246
- * @type {string|string[]}
4247
- * @see GrammarToken
4248
- * @public
4249
- */
4250
- this.alias = alias;
4251
- // Copy of the full string this token was created from
4252
- this.length = (matchedStr || '').length | 0;
4253
- }
4578
+ /** @type {RegExp} */
4579
+ var pattern = patternObj.pattern || patternObj;
4254
4580
 
4255
- /**
4256
- * A token stream is an array of strings and {@link Token Token} objects.
4257
- *
4258
- * Token streams have to fulfill a few properties that are assumed by most functions (mostly internal ones) that process
4259
- * them.
4260
- *
4261
- * 1. No adjacent strings.
4262
- * 2. No empty strings.
4263
- *
4264
- * The only exception here is the token stream that only contains the empty string and nothing else.
4265
- *
4266
- * @typedef {Array<string | Token>} TokenStream
4267
- * @global
4268
- * @public
4269
- */
4581
+ for ( // iterate the token list and keep track of the current token/string position
4582
+ var currentNode = startNode.next, pos = startPos;
4583
+ currentNode !== tokenList.tail;
4584
+ pos += currentNode.value.length, currentNode = currentNode.next
4585
+ ) {
4270
4586
 
4271
- /**
4272
- * Converts the given token or token stream to an HTML representation.
4273
- *
4274
- * The following hooks will be run:
4275
- * 1. `wrap`: On each {@link Token}.
4276
- *
4277
- * @param {string | Token | TokenStream} o The token or token stream to be converted.
4278
- * @param {string} language The name of current language.
4279
- * @returns {string} The HTML representation of the token or token stream.
4280
- * @memberof Token
4281
- * @static
4282
- */
4283
- Token.stringify = function stringify(o, language) {
4284
- if (typeof o == 'string') {
4285
- return o;
4286
- }
4287
- if (Array.isArray(o)) {
4288
- var s = '';
4289
- o.forEach(function (e) {
4290
- s += stringify(e, language);
4291
- });
4292
- return s;
4293
- }
4587
+ if (rematch && pos >= rematch.reach) {
4588
+ break;
4589
+ }
4294
4590
 
4295
- var env = {
4296
- type: o.type,
4297
- content: stringify(o.content, language),
4298
- tag: 'span',
4299
- classes: ['token', o.type],
4300
- attributes: {},
4301
- language: language
4302
- };
4591
+ var str = currentNode.value;
4303
4592
 
4304
- var aliases = o.alias;
4305
- if (aliases) {
4306
- if (Array.isArray(aliases)) {
4307
- Array.prototype.push.apply(env.classes, aliases);
4308
- } else {
4309
- env.classes.push(aliases);
4310
- }
4311
- }
4593
+ if (tokenList.length > text.length) {
4594
+ // Something went terribly wrong, ABORT, ABORT!
4595
+ return;
4596
+ }
4312
4597
 
4313
- _.hooks.run('wrap', env);
4598
+ if (str instanceof Token) {
4599
+ continue;
4600
+ }
4314
4601
 
4315
- var attributes = '';
4316
- for (var name in env.attributes) {
4317
- attributes += ' ' + name + '="' + (env.attributes[name] || '').replace(/"/g, '&quot;') + '"';
4318
- }
4602
+ var removeCount = 1; // this is the to parameter of removeBetween
4603
+ var match;
4319
4604
 
4320
- return '<' + env.tag + ' class="' + env.classes.join(' ') + '"' + attributes + '>' + env.content + '</' + env.tag + '>';
4321
- };
4605
+ if (greedy) {
4606
+ match = matchPattern(pattern, pos, text, lookbehind);
4607
+ if (!match || match.index >= text.length) {
4608
+ break;
4609
+ }
4322
4610
 
4323
- /**
4324
- * @param {RegExp} pattern
4325
- * @param {number} pos
4326
- * @param {string} text
4327
- * @param {boolean} lookbehind
4328
- * @returns {RegExpExecArray | null}
4329
- */
4330
- function matchPattern(pattern, pos, text, lookbehind) {
4331
- pattern.lastIndex = pos;
4332
- var match = pattern.exec(text);
4333
- if (match && lookbehind && match[1]) {
4334
- // change the match to remove the text matched by the Prism lookbehind group
4335
- var lookbehindLength = match[1].length;
4336
- match.index += lookbehindLength;
4337
- match[0] = match[0].slice(lookbehindLength);
4338
- }
4339
- return match;
4340
- }
4611
+ var from = match.index;
4612
+ var to = match.index + match[0].length;
4613
+ var p = pos;
4341
4614
 
4342
- /**
4343
- * @param {string} text
4344
- * @param {LinkedList<string | Token>} tokenList
4345
- * @param {any} grammar
4346
- * @param {LinkedListNode<string | Token>} startNode
4347
- * @param {number} startPos
4348
- * @param {RematchOptions} [rematch]
4349
- * @returns {void}
4350
- * @private
4351
- *
4352
- * @typedef RematchOptions
4353
- * @property {string} cause
4354
- * @property {number} reach
4355
- */
4356
- function matchGrammar(text, tokenList, grammar, startNode, startPos, rematch) {
4357
- for (var token in grammar) {
4358
- if (!grammar.hasOwnProperty(token) || !grammar[token]) {
4359
- continue;
4360
- }
4615
+ // find the node that contains the match
4616
+ p += currentNode.value.length;
4617
+ while (from >= p) {
4618
+ currentNode = currentNode.next;
4619
+ p += currentNode.value.length;
4620
+ }
4621
+ // adjust pos (and p)
4622
+ p -= currentNode.value.length;
4623
+ pos = p;
4361
4624
 
4362
- var patterns = grammar[token];
4363
- patterns = Array.isArray(patterns) ? patterns : [patterns];
4625
+ // the current node is a Token, then the match starts inside another Token, which is invalid
4626
+ if (currentNode.value instanceof Token) {
4627
+ continue;
4628
+ }
4364
4629
 
4365
- for (var j = 0; j < patterns.length; ++j) {
4366
- if (rematch && rematch.cause == token + ',' + j) {
4367
- return;
4368
- }
4630
+ // find the last node which is affected by this match
4631
+ for (
4632
+ var k = currentNode;
4633
+ k !== tokenList.tail && (p < to || typeof k.value === 'string');
4634
+ k = k.next
4635
+ ) {
4636
+ removeCount++;
4637
+ p += k.value.length;
4638
+ }
4639
+ removeCount--;
4640
+
4641
+ // replace with the new match
4642
+ str = text.slice(pos, p);
4643
+ match.index -= pos;
4644
+ } else {
4645
+ match = matchPattern(pattern, 0, str, lookbehind);
4646
+ if (!match) {
4647
+ continue;
4648
+ }
4649
+ }
4369
4650
 
4370
- var patternObj = patterns[j];
4371
- var inside = patternObj.inside;
4372
- var lookbehind = !!patternObj.lookbehind;
4373
- var greedy = !!patternObj.greedy;
4374
- var alias = patternObj.alias;
4651
+ // eslint-disable-next-line no-redeclare
4652
+ var from = match.index;
4653
+ var matchStr = match[0];
4654
+ var before = str.slice(0, from);
4655
+ var after = str.slice(from + matchStr.length);
4375
4656
 
4376
- if (greedy && !patternObj.pattern.global) {
4377
- // Without the global flag, lastIndex won't work
4378
- var flags = patternObj.pattern.toString().match(/[imsuy]*$/)[0];
4379
- patternObj.pattern = RegExp(patternObj.pattern.source, flags + 'g');
4380
- }
4657
+ var reach = pos + str.length;
4658
+ if (rematch && reach > rematch.reach) {
4659
+ rematch.reach = reach;
4660
+ }
4381
4661
 
4382
- /** @type {RegExp} */
4383
- var pattern = patternObj.pattern || patternObj;
4662
+ var removeFrom = currentNode.prev;
4384
4663
 
4385
- for ( // iterate the token list and keep track of the current token/string position
4386
- var currentNode = startNode.next, pos = startPos;
4387
- currentNode !== tokenList.tail;
4388
- pos += currentNode.value.length, currentNode = currentNode.next
4389
- ) {
4664
+ if (before) {
4665
+ removeFrom = addAfter(tokenList, removeFrom, before);
4666
+ pos += before.length;
4667
+ }
4390
4668
 
4391
- if (rematch && pos >= rematch.reach) {
4392
- break;
4393
- }
4669
+ removeRange(tokenList, removeFrom, removeCount);
4394
4670
 
4395
- var str = currentNode.value;
4671
+ var wrapped = new Token(token, inside ? _.tokenize(matchStr, inside) : matchStr, alias, matchStr);
4672
+ currentNode = addAfter(tokenList, removeFrom, wrapped);
4396
4673
 
4397
- if (tokenList.length > text.length) {
4398
- // Something went terribly wrong, ABORT, ABORT!
4399
- return;
4400
- }
4674
+ if (after) {
4675
+ addAfter(tokenList, currentNode, after);
4676
+ }
4401
4677
 
4402
- if (str instanceof Token) {
4403
- continue;
4404
- }
4678
+ if (removeCount > 1) {
4679
+ // at least one Token object was removed, so we have to do some rematching
4680
+ // this can only happen if the current pattern is greedy
4405
4681
 
4406
- var removeCount = 1; // this is the to parameter of removeBetween
4407
- var match;
4682
+ /** @type {RematchOptions} */
4683
+ var nestedRematch = {
4684
+ cause: token + ',' + j,
4685
+ reach: reach
4686
+ };
4687
+ matchGrammar(text, tokenList, grammar, currentNode.prev, pos, nestedRematch);
4408
4688
 
4409
- if (greedy) {
4410
- match = matchPattern(pattern, pos, text, lookbehind);
4411
- if (!match || match.index >= text.length) {
4412
- break;
4689
+ // the reach might have been extended because of the rematching
4690
+ if (rematch && nestedRematch.reach > rematch.reach) {
4691
+ rematch.reach = nestedRematch.reach;
4692
+ }
4413
4693
  }
4694
+ }
4695
+ }
4696
+ }
4697
+ }
4414
4698
 
4415
- var from = match.index;
4416
- var to = match.index + match[0].length;
4417
- var p = pos;
4418
-
4419
- // find the node that contains the match
4420
- p += currentNode.value.length;
4421
- while (from >= p) {
4422
- currentNode = currentNode.next;
4423
- p += currentNode.value.length;
4424
- }
4425
- // adjust pos (and p)
4426
- p -= currentNode.value.length;
4427
- pos = p;
4699
+ /**
4700
+ * @typedef LinkedListNode
4701
+ * @property {T} value
4702
+ * @property {LinkedListNode<T> | null} prev The previous node.
4703
+ * @property {LinkedListNode<T> | null} next The next node.
4704
+ * @template T
4705
+ * @private
4706
+ */
4428
4707
 
4429
- // the current node is a Token, then the match starts inside another Token, which is invalid
4430
- if (currentNode.value instanceof Token) {
4431
- continue;
4432
- }
4708
+ /**
4709
+ * @template T
4710
+ * @private
4711
+ */
4712
+ function LinkedList() {
4713
+ /** @type {LinkedListNode<T>} */
4714
+ var head = { value: null, prev: null, next: null };
4715
+ /** @type {LinkedListNode<T>} */
4716
+ var tail = { value: null, prev: head, next: null };
4717
+ head.next = tail;
4718
+
4719
+ /** @type {LinkedListNode<T>} */
4720
+ this.head = head;
4721
+ /** @type {LinkedListNode<T>} */
4722
+ this.tail = tail;
4723
+ this.length = 0;
4724
+ }
4433
4725
 
4434
- // find the last node which is affected by this match
4435
- for (
4436
- var k = currentNode;
4437
- k !== tokenList.tail && (p < to || typeof k.value === 'string');
4438
- k = k.next
4439
- ) {
4440
- removeCount++;
4441
- p += k.value.length;
4442
- }
4443
- removeCount--;
4726
+ /**
4727
+ * Adds a new node with the given value to the list.
4728
+ *
4729
+ * @param {LinkedList<T>} list
4730
+ * @param {LinkedListNode<T>} node
4731
+ * @param {T} value
4732
+ * @returns {LinkedListNode<T>} The added node.
4733
+ * @template T
4734
+ */
4735
+ function addAfter(list, node, value) {
4736
+ // assumes that node != list.tail && values.length >= 0
4737
+ var next = node.next;
4444
4738
 
4445
- // replace with the new match
4446
- str = text.slice(pos, p);
4447
- match.index -= pos;
4448
- } else {
4449
- match = matchPattern(pattern, 0, str, lookbehind);
4450
- if (!match) {
4451
- continue;
4452
- }
4453
- }
4739
+ var newNode = { value: value, prev: node, next: next };
4740
+ node.next = newNode;
4741
+ next.prev = newNode;
4742
+ list.length++;
4454
4743
 
4455
- // eslint-disable-next-line no-redeclare
4456
- var from = match.index;
4457
- var matchStr = match[0];
4458
- var before = str.slice(0, from);
4459
- var after = str.slice(from + matchStr.length);
4744
+ return newNode;
4745
+ }
4746
+ /**
4747
+ * Removes `count` nodes after the given node. The given node will not be removed.
4748
+ *
4749
+ * @param {LinkedList<T>} list
4750
+ * @param {LinkedListNode<T>} node
4751
+ * @param {number} count
4752
+ * @template T
4753
+ */
4754
+ function removeRange(list, node, count) {
4755
+ var next = node.next;
4756
+ for (var i = 0; i < count && next !== list.tail; i++) {
4757
+ next = next.next;
4758
+ }
4759
+ node.next = next;
4760
+ next.prev = node;
4761
+ list.length -= i;
4762
+ }
4763
+ /**
4764
+ * @param {LinkedList<T>} list
4765
+ * @returns {T[]}
4766
+ * @template T
4767
+ */
4768
+ function toArray(list) {
4769
+ var array = [];
4770
+ var node = list.head.next;
4771
+ while (node !== list.tail) {
4772
+ array.push(node.value);
4773
+ node = node.next;
4774
+ }
4775
+ return array;
4776
+ }
4460
4777
 
4461
- var reach = pos + str.length;
4462
- if (rematch && reach > rematch.reach) {
4463
- rematch.reach = reach;
4464
- }
4465
4778
 
4466
- var removeFrom = currentNode.prev;
4779
+ if (!_self.document) {
4780
+ if (!_self.addEventListener) {
4781
+ // in Node.js
4782
+ return _;
4783
+ }
4467
4784
 
4468
- if (before) {
4469
- removeFrom = addAfter(tokenList, removeFrom, before);
4470
- pos += before.length;
4785
+ if (!_.disableWorkerMessageHandler) {
4786
+ // In worker
4787
+ _self.addEventListener('message', function (evt) {
4788
+ var message = JSON.parse(evt.data);
4789
+ var lang = message.language;
4790
+ var code = message.code;
4791
+ var immediateClose = message.immediateClose;
4792
+
4793
+ _self.postMessage(_.highlight(code, _.languages[lang], lang));
4794
+ if (immediateClose) {
4795
+ _self.close();
4471
4796
  }
4797
+ }, false);
4798
+ }
4472
4799
 
4473
- removeRange(tokenList, removeFrom, removeCount);
4800
+ return _;
4801
+ }
4474
4802
 
4475
- var wrapped = new Token(token, inside ? _.tokenize(matchStr, inside) : matchStr, alias, matchStr);
4476
- currentNode = addAfter(tokenList, removeFrom, wrapped);
4803
+ // Get current script and highlight
4804
+ var script = _.util.currentScript();
4477
4805
 
4478
- if (after) {
4479
- addAfter(tokenList, currentNode, after);
4480
- }
4806
+ if (script) {
4807
+ _.filename = script.src;
4481
4808
 
4482
- if (removeCount > 1) {
4483
- // at least one Token object was removed, so we have to do some rematching
4484
- // this can only happen if the current pattern is greedy
4809
+ if (script.hasAttribute('data-manual')) {
4810
+ _.manual = true;
4811
+ }
4812
+ }
4485
4813
 
4486
- /** @type {RematchOptions} */
4487
- var nestedRematch = {
4488
- cause: token + ',' + j,
4489
- reach: reach
4490
- };
4491
- matchGrammar(text, tokenList, grammar, currentNode.prev, pos, nestedRematch);
4814
+ function highlightAutomaticallyCallback() {
4815
+ if (!_.manual) {
4816
+ _.highlightAll();
4817
+ }
4818
+ }
4492
4819
 
4493
- // the reach might have been extended because of the rematching
4494
- if (rematch && nestedRematch.reach > rematch.reach) {
4495
- rematch.reach = nestedRematch.reach;
4496
- }
4497
- }
4820
+ if (!_.manual) {
4821
+ // If the document state is "loading", then we'll use DOMContentLoaded.
4822
+ // If the document state is "interactive" and the prism.js script is deferred, then we'll also use the
4823
+ // DOMContentLoaded event because there might be some plugins or languages which have also been deferred and they
4824
+ // might take longer one animation frame to execute which can create a race condition where only some plugins have
4825
+ // been loaded when Prism.highlightAll() is executed, depending on how fast resources are loaded.
4826
+ // See https://github.com/PrismJS/prism/issues/2102
4827
+ var readyState = document.readyState;
4828
+ if (readyState === 'loading' || readyState === 'interactive' && script && script.defer) {
4829
+ document.addEventListener('DOMContentLoaded', highlightAutomaticallyCallback);
4830
+ } else {
4831
+ if (window.requestAnimationFrame) {
4832
+ window.requestAnimationFrame(highlightAutomaticallyCallback);
4833
+ } else {
4834
+ window.setTimeout(highlightAutomaticallyCallback, 16);
4498
4835
  }
4499
4836
  }
4500
4837
  }
4501
- }
4502
4838
 
4503
- /**
4504
- * @typedef LinkedListNode
4505
- * @property {T} value
4506
- * @property {LinkedListNode<T> | null} prev The previous node.
4507
- * @property {LinkedListNode<T> | null} next The next node.
4508
- * @template T
4509
- * @private
4510
- */
4839
+ return _;
4511
4840
 
4512
- /**
4513
- * @template T
4514
- * @private
4515
- */
4516
- function LinkedList() {
4517
- /** @type {LinkedListNode<T>} */
4518
- var head = { value: null, prev: null, next: null };
4519
- /** @type {LinkedListNode<T>} */
4520
- var tail = { value: null, prev: head, next: null };
4521
- head.next = tail;
4522
-
4523
- /** @type {LinkedListNode<T>} */
4524
- this.head = head;
4525
- /** @type {LinkedListNode<T>} */
4526
- this.tail = tail;
4527
- this.length = 0;
4841
+ }(_self));
4842
+
4843
+ if (module.exports) {
4844
+ module.exports = Prism;
4528
4845
  }
4529
4846
 
4530
- /**
4531
- * Adds a new node with the given value to the list.
4532
- *
4533
- * @param {LinkedList<T>} list
4534
- * @param {LinkedListNode<T>} node
4535
- * @param {T} value
4536
- * @returns {LinkedListNode<T>} The added node.
4537
- * @template T
4538
- */
4539
- function addAfter(list, node, value) {
4540
- // assumes that node != list.tail && values.length >= 0
4541
- var next = node.next;
4847
+ // hack for components to work correctly in node.js
4848
+ if (typeof commonjsGlobal !== 'undefined') {
4849
+ commonjsGlobal.Prism = Prism;
4850
+ }
4542
4851
 
4543
- var newNode = { value: value, prev: node, next: next };
4544
- node.next = newNode;
4545
- next.prev = newNode;
4546
- list.length++;
4852
+ // some additional documentation/types
4547
4853
 
4548
- return newNode;
4549
- }
4550
4854
  /**
4551
- * Removes `count` nodes after the given node. The given node will not be removed.
4855
+ * The expansion of a simple `RegExp` literal to support additional properties.
4552
4856
  *
4553
- * @param {LinkedList<T>} list
4554
- * @param {LinkedListNode<T>} node
4555
- * @param {number} count
4556
- * @template T
4557
- */
4558
- function removeRange(list, node, count) {
4559
- var next = node.next;
4560
- for (var i = 0; i < count && next !== list.tail; i++) {
4561
- next = next.next;
4562
- }
4563
- node.next = next;
4564
- next.prev = node;
4565
- list.length -= i;
4566
- }
4567
- /**
4568
- * @param {LinkedList<T>} list
4569
- * @returns {T[]}
4570
- * @template T
4857
+ * @typedef GrammarToken
4858
+ * @property {RegExp} pattern The regular expression of the token.
4859
+ * @property {boolean} [lookbehind=false] If `true`, then the first capturing group of `pattern` will (effectively)
4860
+ * behave as a lookbehind group meaning that the captured text will not be part of the matched text of the new token.
4861
+ * @property {boolean} [greedy=false] Whether the token is greedy.
4862
+ * @property {string|string[]} [alias] An optional alias or list of aliases.
4863
+ * @property {Grammar} [inside] The nested grammar of this token.
4864
+ *
4865
+ * The `inside` grammar will be used to tokenize the text value of each token of this kind.
4866
+ *
4867
+ * This can be used to make nested and even recursive language definitions.
4868
+ *
4869
+ * Note: This can cause infinite recursion. Be careful when you embed different languages or even the same language into
4870
+ * each another.
4871
+ * @global
4872
+ * @public
4571
4873
  */
4572
- function toArray(list) {
4573
- var array = [];
4574
- var node = list.head.next;
4575
- while (node !== list.tail) {
4576
- array.push(node.value);
4577
- node = node.next;
4578
- }
4579
- return array;
4580
- }
4581
4874
 
4875
+ /**
4876
+ * @typedef Grammar
4877
+ * @type {Object<string, RegExp | GrammarToken | Array<RegExp | GrammarToken>>}
4878
+ * @property {Grammar} [rest] An optional grammar object that will be appended to this grammar.
4879
+ * @global
4880
+ * @public
4881
+ */
4582
4882
 
4583
- if (!_self.document) {
4584
- if (!_self.addEventListener) {
4585
- // in Node.js
4586
- return _;
4587
- }
4588
-
4589
- if (!_.disableWorkerMessageHandler) {
4590
- // In worker
4591
- _self.addEventListener('message', function (evt) {
4592
- var message = JSON.parse(evt.data);
4593
- var lang = message.language;
4594
- var code = message.code;
4595
- var immediateClose = message.immediateClose;
4596
-
4597
- _self.postMessage(_.highlight(code, _.languages[lang], lang));
4598
- if (immediateClose) {
4599
- _self.close();
4600
- }
4601
- }, false);
4602
- }
4603
-
4604
- return _;
4605
- }
4606
-
4607
- // Get current script and highlight
4608
- var script = _.util.currentScript();
4883
+ /**
4884
+ * A function which will invoked after an element was successfully highlighted.
4885
+ *
4886
+ * @callback HighlightCallback
4887
+ * @param {Element} element The element successfully highlighted.
4888
+ * @returns {void}
4889
+ * @global
4890
+ * @public
4891
+ */
4609
4892
 
4610
- if (script) {
4611
- _.filename = script.src;
4893
+ /**
4894
+ * @callback HookCallback
4895
+ * @param {Object<string, any>} env The environment variables of the hook.
4896
+ * @returns {void}
4897
+ * @global
4898
+ * @public
4899
+ */
4612
4900
 
4613
- if (script.hasAttribute('data-manual')) {
4614
- _.manual = true;
4615
- }
4616
- }
4617
4901
 
4618
- function highlightAutomaticallyCallback() {
4619
- if (!_.manual) {
4620
- _.highlightAll();
4621
- }
4622
- }
4902
+ /* **********************************************
4903
+ Begin prism-markup.js
4904
+ ********************************************** */
4623
4905
 
4624
- if (!_.manual) {
4625
- // If the document state is "loading", then we'll use DOMContentLoaded.
4626
- // If the document state is "interactive" and the prism.js script is deferred, then we'll also use the
4627
- // DOMContentLoaded event because there might be some plugins or languages which have also been deferred and they
4628
- // might take longer one animation frame to execute which can create a race condition where only some plugins have
4629
- // been loaded when Prism.highlightAll() is executed, depending on how fast resources are loaded.
4630
- // See https://github.com/PrismJS/prism/issues/2102
4631
- var readyState = document.readyState;
4632
- if (readyState === 'loading' || readyState === 'interactive' && script && script.defer) {
4633
- document.addEventListener('DOMContentLoaded', highlightAutomaticallyCallback);
4634
- } else {
4635
- if (window.requestAnimationFrame) {
4636
- window.requestAnimationFrame(highlightAutomaticallyCallback);
4637
- } else {
4638
- window.setTimeout(highlightAutomaticallyCallback, 16);
4906
+ Prism.languages.markup = {
4907
+ 'comment': {
4908
+ pattern: /<!--(?:(?!<!--)[\s\S])*?-->/,
4909
+ greedy: true
4910
+ },
4911
+ 'prolog': {
4912
+ pattern: /<\?[\s\S]+?\?>/,
4913
+ greedy: true
4914
+ },
4915
+ 'doctype': {
4916
+ // https://www.w3.org/TR/xml/#NT-doctypedecl
4917
+ pattern: /<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,
4918
+ greedy: true,
4919
+ inside: {
4920
+ 'internal-subset': {
4921
+ pattern: /(^[^\[]*\[)[\s\S]+(?=\]>$)/,
4922
+ lookbehind: true,
4923
+ greedy: true,
4924
+ inside: null // see below
4925
+ },
4926
+ 'string': {
4927
+ pattern: /"[^"]*"|'[^']*'/,
4928
+ greedy: true
4929
+ },
4930
+ 'punctuation': /^<!|>$|[[\]]/,
4931
+ 'doctype-tag': /^DOCTYPE/i,
4932
+ 'name': /[^\s<>'"]+/
4639
4933
  }
4640
- }
4641
- }
4642
-
4643
- return _;
4644
-
4645
- }(_self));
4646
-
4647
- if (module.exports) {
4648
- module.exports = Prism;
4649
- }
4650
-
4651
- // hack for components to work correctly in node.js
4652
- if (typeof commonjsGlobal !== 'undefined') {
4653
- commonjsGlobal.Prism = Prism;
4654
- }
4655
-
4656
- // some additional documentation/types
4934
+ },
4935
+ 'cdata': {
4936
+ pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i,
4937
+ greedy: true
4938
+ },
4939
+ 'tag': {
4940
+ pattern: /<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,
4941
+ greedy: true,
4942
+ inside: {
4943
+ 'tag': {
4944
+ pattern: /^<\/?[^\s>\/]+/,
4945
+ inside: {
4946
+ 'punctuation': /^<\/?/,
4947
+ 'namespace': /^[^\s>\/:]+:/
4948
+ }
4949
+ },
4950
+ 'special-attr': [],
4951
+ 'attr-value': {
4952
+ pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,
4953
+ inside: {
4954
+ 'punctuation': [
4955
+ {
4956
+ pattern: /^=/,
4957
+ alias: 'attr-equals'
4958
+ },
4959
+ {
4960
+ pattern: /^(\s*)["']|["']$/,
4961
+ lookbehind: true
4962
+ }
4963
+ ]
4964
+ }
4965
+ },
4966
+ 'punctuation': /\/?>/,
4967
+ 'attr-name': {
4968
+ pattern: /[^\s>\/]+/,
4969
+ inside: {
4970
+ 'namespace': /^[^\s>\/:]+:/
4971
+ }
4972
+ }
4657
4973
 
4658
- /**
4659
- * The expansion of a simple `RegExp` literal to support additional properties.
4660
- *
4661
- * @typedef GrammarToken
4662
- * @property {RegExp} pattern The regular expression of the token.
4663
- * @property {boolean} [lookbehind=false] If `true`, then the first capturing group of `pattern` will (effectively)
4664
- * behave as a lookbehind group meaning that the captured text will not be part of the matched text of the new token.
4665
- * @property {boolean} [greedy=false] Whether the token is greedy.
4666
- * @property {string|string[]} [alias] An optional alias or list of aliases.
4667
- * @property {Grammar} [inside] The nested grammar of this token.
4668
- *
4669
- * The `inside` grammar will be used to tokenize the text value of each token of this kind.
4670
- *
4671
- * This can be used to make nested and even recursive language definitions.
4672
- *
4673
- * Note: This can cause infinite recursion. Be careful when you embed different languages or even the same language into
4674
- * each another.
4675
- * @global
4676
- * @public
4677
- */
4974
+ }
4975
+ },
4976
+ 'entity': [
4977
+ {
4978
+ pattern: /&[\da-z]{1,8};/i,
4979
+ alias: 'named-entity'
4980
+ },
4981
+ /&#x?[\da-f]{1,8};/i
4982
+ ]
4983
+ };
4678
4984
 
4679
- /**
4680
- * @typedef Grammar
4681
- * @type {Object<string, RegExp | GrammarToken | Array<RegExp | GrammarToken>>}
4682
- * @property {Grammar} [rest] An optional grammar object that will be appended to this grammar.
4683
- * @global
4684
- * @public
4685
- */
4985
+ Prism.languages.markup['tag'].inside['attr-value'].inside['entity'] =
4986
+ Prism.languages.markup['entity'];
4987
+ Prism.languages.markup['doctype'].inside['internal-subset'].inside = Prism.languages.markup;
4686
4988
 
4687
- /**
4688
- * A function which will invoked after an element was successfully highlighted.
4689
- *
4690
- * @callback HighlightCallback
4691
- * @param {Element} element The element successfully highlighted.
4692
- * @returns {void}
4693
- * @global
4694
- * @public
4695
- */
4989
+ // Plugin to make entity title show the real entity, idea by Roman Komarov
4990
+ Prism.hooks.add('wrap', function (env) {
4696
4991
 
4697
- /**
4698
- * @callback HookCallback
4699
- * @param {Object<string, any>} env The environment variables of the hook.
4700
- * @returns {void}
4701
- * @global
4702
- * @public
4703
- */
4992
+ if (env.type === 'entity') {
4993
+ env.attributes['title'] = env.content.replace(/&amp;/, '&');
4994
+ }
4995
+ });
4704
4996
 
4997
+ Object.defineProperty(Prism.languages.markup.tag, 'addInlined', {
4998
+ /**
4999
+ * Adds an inlined language to markup.
5000
+ *
5001
+ * An example of an inlined language is CSS with `<style>` tags.
5002
+ *
5003
+ * @param {string} tagName The name of the tag that contains the inlined language. This name will be treated as
5004
+ * case insensitive.
5005
+ * @param {string} lang The language key.
5006
+ * @example
5007
+ * addInlined('style', 'css');
5008
+ */
5009
+ value: function addInlined(tagName, lang) {
5010
+ var includedCdataInside = {};
5011
+ includedCdataInside['language-' + lang] = {
5012
+ pattern: /(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,
5013
+ lookbehind: true,
5014
+ inside: Prism.languages[lang]
5015
+ };
5016
+ includedCdataInside['cdata'] = /^<!\[CDATA\[|\]\]>$/i;
4705
5017
 
4706
- /* **********************************************
4707
- Begin prism-markup.js
4708
- ********************************************** */
5018
+ var inside = {
5019
+ 'included-cdata': {
5020
+ pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i,
5021
+ inside: includedCdataInside
5022
+ }
5023
+ };
5024
+ inside['language-' + lang] = {
5025
+ pattern: /[\s\S]+/,
5026
+ inside: Prism.languages[lang]
5027
+ };
4709
5028
 
4710
- Prism.languages.markup = {
4711
- 'comment': {
4712
- pattern: /<!--(?:(?!<!--)[\s\S])*?-->/,
4713
- greedy: true
4714
- },
4715
- 'prolog': {
4716
- pattern: /<\?[\s\S]+?\?>/,
4717
- greedy: true
4718
- },
4719
- 'doctype': {
4720
- // https://www.w3.org/TR/xml/#NT-doctypedecl
4721
- pattern: /<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,
4722
- greedy: true,
4723
- inside: {
4724
- 'internal-subset': {
4725
- pattern: /(^[^\[]*\[)[\s\S]+(?=\]>$)/,
5029
+ var def = {};
5030
+ def[tagName] = {
5031
+ pattern: RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g, function () { return tagName; }), 'i'),
4726
5032
  lookbehind: true,
4727
5033
  greedy: true,
4728
- inside: null // see below
4729
- },
4730
- 'string': {
4731
- pattern: /"[^"]*"|'[^']*'/,
4732
- greedy: true
4733
- },
4734
- 'punctuation': /^<!|>$|[[\]]/,
4735
- 'doctype-tag': /^DOCTYPE/i,
4736
- 'name': /[^\s<>'"]+/
5034
+ inside: inside
5035
+ };
5036
+
5037
+ Prism.languages.insertBefore('markup', 'cdata', def);
4737
5038
  }
4738
- },
4739
- 'cdata': {
4740
- pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i,
4741
- greedy: true
4742
- },
4743
- 'tag': {
4744
- pattern: /<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,
4745
- greedy: true,
4746
- inside: {
4747
- 'tag': {
4748
- pattern: /^<\/?[^\s>\/]+/,
4749
- inside: {
4750
- 'punctuation': /^<\/?/,
4751
- 'namespace': /^[^\s>\/:]+:/
4752
- }
4753
- },
4754
- 'special-attr': [],
4755
- 'attr-value': {
4756
- pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,
5039
+ });
5040
+ Object.defineProperty(Prism.languages.markup.tag, 'addAttribute', {
5041
+ /**
5042
+ * Adds an pattern to highlight languages embedded in HTML attributes.
5043
+ *
5044
+ * An example of an inlined language is CSS with `style` attributes.
5045
+ *
5046
+ * @param {string} attrName The name of the tag that contains the inlined language. This name will be treated as
5047
+ * case insensitive.
5048
+ * @param {string} lang The language key.
5049
+ * @example
5050
+ * addAttribute('style', 'css');
5051
+ */
5052
+ value: function (attrName, lang) {
5053
+ Prism.languages.markup.tag.inside['special-attr'].push({
5054
+ pattern: RegExp(
5055
+ /(^|["'\s])/.source + '(?:' + attrName + ')' + /\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,
5056
+ 'i'
5057
+ ),
5058
+ lookbehind: true,
4757
5059
  inside: {
4758
- 'punctuation': [
4759
- {
4760
- pattern: /^=/,
4761
- alias: 'attr-equals'
4762
- },
4763
- {
4764
- pattern: /^(\s*)["']|["']$/,
4765
- lookbehind: true
5060
+ 'attr-name': /^[^\s=]+/,
5061
+ 'attr-value': {
5062
+ pattern: /=[\s\S]+/,
5063
+ inside: {
5064
+ 'value': {
5065
+ pattern: /(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,
5066
+ lookbehind: true,
5067
+ alias: [lang, 'language-' + lang],
5068
+ inside: Prism.languages[lang]
5069
+ },
5070
+ 'punctuation': [
5071
+ {
5072
+ pattern: /^=/,
5073
+ alias: 'attr-equals'
5074
+ },
5075
+ /"|'/
5076
+ ]
4766
5077
  }
4767
- ]
4768
- }
4769
- },
4770
- 'punctuation': /\/?>/,
4771
- 'attr-name': {
4772
- pattern: /[^\s>\/]+/,
4773
- inside: {
4774
- 'namespace': /^[^\s>\/:]+:/
5078
+ }
4775
5079
  }
4776
- }
4777
-
5080
+ });
4778
5081
  }
4779
- },
4780
- 'entity': [
4781
- {
4782
- pattern: /&[\da-z]{1,8};/i,
4783
- alias: 'named-entity'
4784
- },
4785
- /&#x?[\da-f]{1,8};/i
4786
- ]
4787
- };
5082
+ });
4788
5083
 
4789
- Prism.languages.markup['tag'].inside['attr-value'].inside['entity'] =
4790
- Prism.languages.markup['entity'];
4791
- Prism.languages.markup['doctype'].inside['internal-subset'].inside = Prism.languages.markup;
5084
+ Prism.languages.html = Prism.languages.markup;
5085
+ Prism.languages.mathml = Prism.languages.markup;
5086
+ Prism.languages.svg = Prism.languages.markup;
4792
5087
 
4793
- // Plugin to make entity title show the real entity, idea by Roman Komarov
4794
- Prism.hooks.add('wrap', function (env) {
5088
+ Prism.languages.xml = Prism.languages.extend('markup', {});
5089
+ Prism.languages.ssml = Prism.languages.xml;
5090
+ Prism.languages.atom = Prism.languages.xml;
5091
+ Prism.languages.rss = Prism.languages.xml;
4795
5092
 
4796
- if (env.type === 'entity') {
4797
- env.attributes['title'] = env.content.replace(/&amp;/, '&');
4798
- }
4799
- });
4800
5093
 
4801
- Object.defineProperty(Prism.languages.markup.tag, 'addInlined', {
4802
- /**
4803
- * Adds an inlined language to markup.
4804
- *
4805
- * An example of an inlined language is CSS with `<style>` tags.
4806
- *
4807
- * @param {string} tagName The name of the tag that contains the inlined language. This name will be treated as
4808
- * case insensitive.
4809
- * @param {string} lang The language key.
4810
- * @example
4811
- * addInlined('style', 'css');
4812
- */
4813
- value: function addInlined(tagName, lang) {
4814
- var includedCdataInside = {};
4815
- includedCdataInside['language-' + lang] = {
4816
- pattern: /(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,
4817
- lookbehind: true,
4818
- inside: Prism.languages[lang]
4819
- };
4820
- includedCdataInside['cdata'] = /^<!\[CDATA\[|\]\]>$/i;
5094
+ /* **********************************************
5095
+ Begin prism-css.js
5096
+ ********************************************** */
4821
5097
 
4822
- var inside = {
4823
- 'included-cdata': {
4824
- pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i,
4825
- inside: includedCdataInside
4826
- }
4827
- };
4828
- inside['language-' + lang] = {
4829
- pattern: /[\s\S]+/,
4830
- inside: Prism.languages[lang]
4831
- };
5098
+ (function (Prism) {
4832
5099
 
4833
- var def = {};
4834
- def[tagName] = {
4835
- pattern: RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g, function () { return tagName; }), 'i'),
4836
- lookbehind: true,
4837
- greedy: true,
4838
- inside: inside
4839
- };
5100
+ var string = /(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;
4840
5101
 
4841
- Prism.languages.insertBefore('markup', 'cdata', def);
4842
- }
4843
- });
4844
- Object.defineProperty(Prism.languages.markup.tag, 'addAttribute', {
4845
- /**
4846
- * Adds an pattern to highlight languages embedded in HTML attributes.
4847
- *
4848
- * An example of an inlined language is CSS with `style` attributes.
4849
- *
4850
- * @param {string} attrName The name of the tag that contains the inlined language. This name will be treated as
4851
- * case insensitive.
4852
- * @param {string} lang The language key.
4853
- * @example
4854
- * addAttribute('style', 'css');
4855
- */
4856
- value: function (attrName, lang) {
4857
- Prism.languages.markup.tag.inside['special-attr'].push({
4858
- pattern: RegExp(
4859
- /(^|["'\s])/.source + '(?:' + attrName + ')' + /\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,
4860
- 'i'
4861
- ),
4862
- lookbehind: true,
4863
- inside: {
4864
- 'attr-name': /^[^\s=]+/,
4865
- 'attr-value': {
4866
- pattern: /=[\s\S]+/,
4867
- inside: {
4868
- 'value': {
4869
- pattern: /(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,
4870
- lookbehind: true,
4871
- alias: [lang, 'language-' + lang],
4872
- inside: Prism.languages[lang]
4873
- },
4874
- 'punctuation': [
4875
- {
4876
- pattern: /^=/,
4877
- alias: 'attr-equals'
4878
- },
4879
- /"|'/
4880
- ]
5102
+ Prism.languages.css = {
5103
+ 'comment': /\/\*[\s\S]*?\*\//,
5104
+ 'atrule': {
5105
+ pattern: RegExp('@[\\w-](?:' + /[^;{\s"']|\s+(?!\s)/.source + '|' + string.source + ')*?' + /(?:;|(?=\s*\{))/.source),
5106
+ inside: {
5107
+ 'rule': /^@[\w-]+/,
5108
+ 'selector-function-argument': {
5109
+ pattern: /(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,
5110
+ lookbehind: true,
5111
+ alias: 'selector'
5112
+ },
5113
+ 'keyword': {
5114
+ pattern: /(^|[^\w-])(?:and|not|only|or)(?![\w-])/,
5115
+ lookbehind: true
4881
5116
  }
5117
+ // See rest below
4882
5118
  }
4883
- }
4884
- });
4885
- }
4886
- });
4887
-
4888
- Prism.languages.html = Prism.languages.markup;
4889
- Prism.languages.mathml = Prism.languages.markup;
4890
- Prism.languages.svg = Prism.languages.markup;
5119
+ },
5120
+ 'url': {
5121
+ // https://drafts.csswg.org/css-values-3/#urls
5122
+ pattern: RegExp('\\burl\\((?:' + string.source + '|' + /(?:[^\\\r\n()"']|\\[\s\S])*/.source + ')\\)', 'i'),
5123
+ greedy: true,
5124
+ inside: {
5125
+ 'function': /^url/i,
5126
+ 'punctuation': /^\(|\)$/,
5127
+ 'string': {
5128
+ pattern: RegExp('^' + string.source + '$'),
5129
+ alias: 'url'
5130
+ }
5131
+ }
5132
+ },
5133
+ 'selector': {
5134
+ pattern: RegExp('(^|[{}\\s])[^{}\\s](?:[^{};"\'\\s]|\\s+(?![\\s{])|' + string.source + ')*(?=\\s*\\{)'),
5135
+ lookbehind: true
5136
+ },
5137
+ 'string': {
5138
+ pattern: string,
5139
+ greedy: true
5140
+ },
5141
+ 'property': {
5142
+ pattern: /(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,
5143
+ lookbehind: true
5144
+ },
5145
+ 'important': /!important\b/i,
5146
+ 'function': {
5147
+ pattern: /(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,
5148
+ lookbehind: true
5149
+ },
5150
+ 'punctuation': /[(){};:,]/
5151
+ };
4891
5152
 
4892
- Prism.languages.xml = Prism.languages.extend('markup', {});
4893
- Prism.languages.ssml = Prism.languages.xml;
4894
- Prism.languages.atom = Prism.languages.xml;
4895
- Prism.languages.rss = Prism.languages.xml;
5153
+ Prism.languages.css['atrule'].inside.rest = Prism.languages.css;
4896
5154
 
5155
+ var markup = Prism.languages.markup;
5156
+ if (markup) {
5157
+ markup.tag.addInlined('style', 'css');
5158
+ markup.tag.addAttribute('style', 'css');
5159
+ }
4897
5160
 
4898
- /* **********************************************
4899
- Begin prism-css.js
4900
- ********************************************** */
5161
+ }(Prism));
4901
5162
 
4902
- (function (Prism) {
4903
5163
 
4904
- var string = /(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;
5164
+ /* **********************************************
5165
+ Begin prism-clike.js
5166
+ ********************************************** */
4905
5167
 
4906
- Prism.languages.css = {
4907
- 'comment': /\/\*[\s\S]*?\*\//,
4908
- 'atrule': {
4909
- pattern: RegExp('@[\\w-](?:' + /[^;{\s"']|\s+(?!\s)/.source + '|' + string.source + ')*?' + /(?:;|(?=\s*\{))/.source),
4910
- inside: {
4911
- 'rule': /^@[\w-]+/,
4912
- 'selector-function-argument': {
4913
- pattern: /(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,
4914
- lookbehind: true,
4915
- alias: 'selector'
4916
- },
4917
- 'keyword': {
4918
- pattern: /(^|[^\w-])(?:and|not|only|or)(?![\w-])/,
4919
- lookbehind: true
4920
- }
4921
- // See rest below
4922
- }
4923
- },
4924
- 'url': {
4925
- // https://drafts.csswg.org/css-values-3/#urls
4926
- pattern: RegExp('\\burl\\((?:' + string.source + '|' + /(?:[^\\\r\n()"']|\\[\s\S])*/.source + ')\\)', 'i'),
4927
- greedy: true,
4928
- inside: {
4929
- 'function': /^url/i,
4930
- 'punctuation': /^\(|\)$/,
4931
- 'string': {
4932
- pattern: RegExp('^' + string.source + '$'),
4933
- alias: 'url'
4934
- }
5168
+ Prism.languages.clike = {
5169
+ 'comment': [
5170
+ {
5171
+ pattern: /(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,
5172
+ lookbehind: true,
5173
+ greedy: true
5174
+ },
5175
+ {
5176
+ pattern: /(^|[^\\:])\/\/.*/,
5177
+ lookbehind: true,
5178
+ greedy: true
4935
5179
  }
4936
- },
4937
- 'selector': {
4938
- pattern: RegExp('(^|[{}\\s])[^{}\\s](?:[^{};"\'\\s]|\\s+(?![\\s{])|' + string.source + ')*(?=\\s*\\{)'),
4939
- lookbehind: true
4940
- },
5180
+ ],
4941
5181
  'string': {
4942
- pattern: string,
5182
+ pattern: /(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,
4943
5183
  greedy: true
4944
5184
  },
4945
- 'property': {
4946
- pattern: /(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,
4947
- lookbehind: true
4948
- },
4949
- 'important': /!important\b/i,
4950
- 'function': {
4951
- pattern: /(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,
4952
- lookbehind: true
5185
+ 'class-name': {
5186
+ pattern: /(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,
5187
+ lookbehind: true,
5188
+ inside: {
5189
+ 'punctuation': /[.\\]/
5190
+ }
4953
5191
  },
4954
- 'punctuation': /[(){};:,]/
5192
+ 'keyword': /\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,
5193
+ 'boolean': /\b(?:false|true)\b/,
5194
+ 'function': /\b\w+(?=\()/,
5195
+ 'number': /\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,
5196
+ 'operator': /[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,
5197
+ 'punctuation': /[{}[\];(),.:]/
4955
5198
  };
4956
5199
 
4957
- Prism.languages.css['atrule'].inside.rest = Prism.languages.css;
4958
5200
 
4959
- var markup = Prism.languages.markup;
4960
- if (markup) {
4961
- markup.tag.addInlined('style', 'css');
4962
- markup.tag.addAttribute('style', 'css');
4963
- }
5201
+ /* **********************************************
5202
+ Begin prism-javascript.js
5203
+ ********************************************** */
4964
5204
 
4965
- }(Prism));
4966
-
4967
-
4968
- /* **********************************************
4969
- Begin prism-clike.js
4970
- ********************************************** */
4971
-
4972
- Prism.languages.clike = {
4973
- 'comment': [
4974
- {
4975
- pattern: /(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,
4976
- lookbehind: true,
4977
- greedy: true
5205
+ Prism.languages.javascript = Prism.languages.extend('clike', {
5206
+ 'class-name': [
5207
+ Prism.languages.clike['class-name'],
5208
+ {
5209
+ pattern: /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,
5210
+ lookbehind: true
5211
+ }
5212
+ ],
5213
+ 'keyword': [
5214
+ {
5215
+ pattern: /((?:^|\})\s*)catch\b/,
5216
+ lookbehind: true
5217
+ },
5218
+ {
5219
+ pattern: /(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,
5220
+ lookbehind: true
5221
+ },
5222
+ ],
5223
+ // Allow for all non-ASCII characters (See http://stackoverflow.com/a/2008444)
5224
+ 'function': /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,
5225
+ 'number': {
5226
+ pattern: RegExp(
5227
+ /(^|[^\w$])/.source +
5228
+ '(?:' +
5229
+ (
5230
+ // constant
5231
+ /NaN|Infinity/.source +
5232
+ '|' +
5233
+ // binary integer
5234
+ /0[bB][01]+(?:_[01]+)*n?/.source +
5235
+ '|' +
5236
+ // octal integer
5237
+ /0[oO][0-7]+(?:_[0-7]+)*n?/.source +
5238
+ '|' +
5239
+ // hexadecimal integer
5240
+ /0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source +
5241
+ '|' +
5242
+ // decimal bigint
5243
+ /\d+(?:_\d+)*n/.source +
5244
+ '|' +
5245
+ // decimal number (integer or float) but no bigint
5246
+ /(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source
5247
+ ) +
5248
+ ')' +
5249
+ /(?![\w$])/.source
5250
+ ),
5251
+ lookbehind: true
4978
5252
  },
4979
- {
4980
- pattern: /(^|[^\\:])\/\/.*/,
4981
- lookbehind: true,
4982
- greedy: true
4983
- }
4984
- ],
4985
- 'string': {
4986
- pattern: /(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,
4987
- greedy: true
4988
- },
4989
- 'class-name': {
4990
- pattern: /(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,
4991
- lookbehind: true,
4992
- inside: {
4993
- 'punctuation': /[.\\]/
4994
- }
4995
- },
4996
- 'keyword': /\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,
4997
- 'boolean': /\b(?:false|true)\b/,
4998
- 'function': /\b\w+(?=\()/,
4999
- 'number': /\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,
5000
- 'operator': /[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,
5001
- 'punctuation': /[{}[\];(),.:]/
5002
- };
5003
-
5253
+ 'operator': /--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/
5254
+ });
5004
5255
 
5005
- /* **********************************************
5006
- Begin prism-javascript.js
5007
- ********************************************** */
5256
+ Prism.languages.javascript['class-name'][0].pattern = /(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/;
5008
5257
 
5009
- Prism.languages.javascript = Prism.languages.extend('clike', {
5010
- 'class-name': [
5011
- Prism.languages.clike['class-name'],
5012
- {
5013
- pattern: /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,
5014
- lookbehind: true
5015
- }
5016
- ],
5017
- 'keyword': [
5018
- {
5019
- pattern: /((?:^|\})\s*)catch\b/,
5020
- lookbehind: true
5021
- },
5022
- {
5023
- pattern: /(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,
5024
- lookbehind: true
5025
- },
5026
- ],
5027
- // Allow for all non-ASCII characters (See http://stackoverflow.com/a/2008444)
5028
- 'function': /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,
5029
- 'number': {
5030
- pattern: RegExp(
5031
- /(^|[^\w$])/.source +
5032
- '(?:' +
5033
- (
5034
- // constant
5035
- /NaN|Infinity/.source +
5036
- '|' +
5037
- // binary integer
5038
- /0[bB][01]+(?:_[01]+)*n?/.source +
5039
- '|' +
5040
- // octal integer
5041
- /0[oO][0-7]+(?:_[0-7]+)*n?/.source +
5042
- '|' +
5043
- // hexadecimal integer
5044
- /0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source +
5045
- '|' +
5046
- // decimal bigint
5047
- /\d+(?:_\d+)*n/.source +
5258
+ Prism.languages.insertBefore('javascript', 'keyword', {
5259
+ 'regex': {
5260
+ pattern: RegExp(
5261
+ // lookbehind
5262
+ // eslint-disable-next-line regexp/no-dupe-characters-character-class
5263
+ /((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)/.source +
5264
+ // Regex pattern:
5265
+ // There are 2 regex patterns here. The RegExp set notation proposal added support for nested character
5266
+ // classes if the `v` flag is present. Unfortunately, nested CCs are both context-free and incompatible
5267
+ // with the only syntax, so we have to define 2 different regex patterns.
5268
+ /\//.source +
5269
+ '(?:' +
5270
+ /(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}/.source +
5048
5271
  '|' +
5049
- // decimal number (integer or float) but no bigint
5050
- /(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source
5051
- ) +
5052
- ')' +
5053
- /(?![\w$])/.source
5054
- ),
5055
- lookbehind: true
5056
- },
5057
- 'operator': /--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/
5058
- });
5059
-
5060
- Prism.languages.javascript['class-name'][0].pattern = /(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/;
5061
-
5062
- Prism.languages.insertBefore('javascript', 'keyword', {
5063
- 'regex': {
5064
- pattern: RegExp(
5065
- // lookbehind
5066
- // eslint-disable-next-line regexp/no-dupe-characters-character-class
5067
- /((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)/.source +
5068
- // Regex pattern:
5069
- // There are 2 regex patterns here. The RegExp set notation proposal added support for nested character
5070
- // classes if the `v` flag is present. Unfortunately, nested CCs are both context-free and incompatible
5071
- // with the only syntax, so we have to define 2 different regex patterns.
5072
- /\//.source +
5073
- '(?:' +
5074
- /(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}/.source +
5075
- '|' +
5076
- // `v` flag syntax. This supports 3 levels of nested character classes.
5077
- /(?:\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.)*\])*\])*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}v[dgimyus]{0,7}/.source +
5078
- ')' +
5079
- // lookahead
5080
- /(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/.source
5081
- ),
5082
- lookbehind: true,
5083
- greedy: true,
5084
- inside: {
5085
- 'regex-source': {
5086
- pattern: /^(\/)[\s\S]+(?=\/[a-z]*$)/,
5087
- lookbehind: true,
5088
- alias: 'language-regex',
5089
- inside: Prism.languages.regex
5090
- },
5091
- 'regex-delimiter': /^\/|\/$/,
5092
- 'regex-flags': /^[a-z]+$/,
5093
- }
5094
- },
5095
- // This must be declared before keyword because we use "function" inside the look-forward
5096
- 'function-variable': {
5097
- pattern: /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,
5098
- alias: 'function'
5099
- },
5100
- 'parameter': [
5101
- {
5102
- pattern: /(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,
5103
- lookbehind: true,
5104
- inside: Prism.languages.javascript
5105
- },
5106
- {
5107
- pattern: /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,
5272
+ // `v` flag syntax. This supports 3 levels of nested character classes.
5273
+ /(?:\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.)*\])*\])*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}v[dgimyus]{0,7}/.source +
5274
+ ')' +
5275
+ // lookahead
5276
+ /(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/.source
5277
+ ),
5108
5278
  lookbehind: true,
5109
- inside: Prism.languages.javascript
5279
+ greedy: true,
5280
+ inside: {
5281
+ 'regex-source': {
5282
+ pattern: /^(\/)[\s\S]+(?=\/[a-z]*$)/,
5283
+ lookbehind: true,
5284
+ alias: 'language-regex',
5285
+ inside: Prism.languages.regex
5286
+ },
5287
+ 'regex-delimiter': /^\/|\/$/,
5288
+ 'regex-flags': /^[a-z]+$/,
5289
+ }
5110
5290
  },
5111
- {
5112
- pattern: /(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,
5113
- lookbehind: true,
5114
- inside: Prism.languages.javascript
5291
+ // This must be declared before keyword because we use "function" inside the look-forward
5292
+ 'function-variable': {
5293
+ pattern: /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,
5294
+ alias: 'function'
5115
5295
  },
5116
- {
5117
- pattern: /((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,
5118
- lookbehind: true,
5119
- inside: Prism.languages.javascript
5120
- }
5121
- ],
5122
- 'constant': /\b[A-Z](?:[A-Z_]|\dx?)*\b/
5123
- });
5124
-
5125
- Prism.languages.insertBefore('javascript', 'string', {
5126
- 'hashbang': {
5127
- pattern: /^#!.*/,
5128
- greedy: true,
5129
- alias: 'comment'
5130
- },
5131
- 'template-string': {
5132
- pattern: /`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,
5133
- greedy: true,
5134
- inside: {
5135
- 'template-punctuation': {
5136
- pattern: /^`|`$/,
5137
- alias: 'string'
5296
+ 'parameter': [
5297
+ {
5298
+ pattern: /(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,
5299
+ lookbehind: true,
5300
+ inside: Prism.languages.javascript
5138
5301
  },
5139
- 'interpolation': {
5140
- pattern: /((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,
5302
+ {
5303
+ pattern: /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,
5141
5304
  lookbehind: true,
5142
- inside: {
5143
- 'interpolation-punctuation': {
5144
- pattern: /^\$\{|\}$/,
5145
- alias: 'punctuation'
5146
- },
5147
- rest: Prism.languages.javascript
5148
- }
5305
+ inside: Prism.languages.javascript
5149
5306
  },
5150
- 'string': /[\s\S]+/
5307
+ {
5308
+ pattern: /(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,
5309
+ lookbehind: true,
5310
+ inside: Prism.languages.javascript
5311
+ },
5312
+ {
5313
+ pattern: /((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,
5314
+ lookbehind: true,
5315
+ inside: Prism.languages.javascript
5316
+ }
5317
+ ],
5318
+ 'constant': /\b[A-Z](?:[A-Z_]|\dx?)*\b/
5319
+ });
5320
+
5321
+ Prism.languages.insertBefore('javascript', 'string', {
5322
+ 'hashbang': {
5323
+ pattern: /^#!.*/,
5324
+ greedy: true,
5325
+ alias: 'comment'
5326
+ },
5327
+ 'template-string': {
5328
+ pattern: /`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,
5329
+ greedy: true,
5330
+ inside: {
5331
+ 'template-punctuation': {
5332
+ pattern: /^`|`$/,
5333
+ alias: 'string'
5334
+ },
5335
+ 'interpolation': {
5336
+ pattern: /((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,
5337
+ lookbehind: true,
5338
+ inside: {
5339
+ 'interpolation-punctuation': {
5340
+ pattern: /^\$\{|\}$/,
5341
+ alias: 'punctuation'
5342
+ },
5343
+ rest: Prism.languages.javascript
5344
+ }
5345
+ },
5346
+ 'string': /[\s\S]+/
5347
+ }
5348
+ },
5349
+ 'string-property': {
5350
+ pattern: /((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,
5351
+ lookbehind: true,
5352
+ greedy: true,
5353
+ alias: 'property'
5151
5354
  }
5152
- },
5153
- 'string-property': {
5154
- pattern: /((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,
5155
- lookbehind: true,
5156
- greedy: true,
5157
- alias: 'property'
5158
- }
5159
- });
5355
+ });
5160
5356
 
5161
- Prism.languages.insertBefore('javascript', 'operator', {
5162
- 'literal-property': {
5163
- pattern: /((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,
5164
- lookbehind: true,
5165
- alias: 'property'
5166
- },
5167
- });
5357
+ Prism.languages.insertBefore('javascript', 'operator', {
5358
+ 'literal-property': {
5359
+ pattern: /((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,
5360
+ lookbehind: true,
5361
+ alias: 'property'
5362
+ },
5363
+ });
5168
5364
 
5169
- if (Prism.languages.markup) {
5170
- Prism.languages.markup.tag.addInlined('script', 'javascript');
5365
+ if (Prism.languages.markup) {
5366
+ Prism.languages.markup.tag.addInlined('script', 'javascript');
5171
5367
 
5172
- // add attribute support for all DOM events.
5173
- // https://developer.mozilla.org/en-US/docs/Web/Events#Standard_events
5174
- Prism.languages.markup.tag.addAttribute(
5175
- /on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,
5176
- 'javascript'
5177
- );
5178
- }
5368
+ // add attribute support for all DOM events.
5369
+ // https://developer.mozilla.org/en-US/docs/Web/Events#Standard_events
5370
+ Prism.languages.markup.tag.addAttribute(
5371
+ /on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,
5372
+ 'javascript'
5373
+ );
5374
+ }
5179
5375
 
5180
- Prism.languages.js = Prism.languages.javascript;
5376
+ Prism.languages.js = Prism.languages.javascript;
5181
5377
 
5182
5378
 
5183
- /* **********************************************
5184
- Begin prism-file-highlight.js
5185
- ********************************************** */
5379
+ /* **********************************************
5380
+ Begin prism-file-highlight.js
5381
+ ********************************************** */
5186
5382
 
5187
- (function () {
5383
+ (function () {
5188
5384
 
5189
- if (typeof Prism === 'undefined' || typeof document === 'undefined') {
5190
- return;
5191
- }
5385
+ if (typeof Prism === 'undefined' || typeof document === 'undefined') {
5386
+ return;
5387
+ }
5192
5388
 
5193
- // https://developer.mozilla.org/en-US/docs/Web/API/Element/matches#Polyfill
5194
- if (!Element.prototype.matches) {
5195
- Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
5196
- }
5389
+ // https://developer.mozilla.org/en-US/docs/Web/API/Element/matches#Polyfill
5390
+ if (!Element.prototype.matches) {
5391
+ Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
5392
+ }
5197
5393
 
5198
- var LOADING_MESSAGE = 'Loading…';
5199
- var FAILURE_MESSAGE = function (status, message) {
5200
- return '✖ Error ' + status + ' while fetching file: ' + message;
5201
- };
5202
- var FAILURE_EMPTY_MESSAGE = '✖ Error: File does not exist or is empty';
5203
-
5204
- var EXTENSIONS = {
5205
- 'js': 'javascript',
5206
- 'py': 'python',
5207
- 'rb': 'ruby',
5208
- 'ps1': 'powershell',
5209
- 'psm1': 'powershell',
5210
- 'sh': 'bash',
5211
- 'bat': 'batch',
5212
- 'h': 'c',
5213
- 'tex': 'latex'
5214
- };
5394
+ var LOADING_MESSAGE = 'Loading…';
5395
+ var FAILURE_MESSAGE = function (status, message) {
5396
+ return '✖ Error ' + status + ' while fetching file: ' + message;
5397
+ };
5398
+ var FAILURE_EMPTY_MESSAGE = '✖ Error: File does not exist or is empty';
5399
+
5400
+ var EXTENSIONS = {
5401
+ 'js': 'javascript',
5402
+ 'py': 'python',
5403
+ 'rb': 'ruby',
5404
+ 'ps1': 'powershell',
5405
+ 'psm1': 'powershell',
5406
+ 'sh': 'bash',
5407
+ 'bat': 'batch',
5408
+ 'h': 'c',
5409
+ 'tex': 'latex'
5410
+ };
5215
5411
 
5216
- var STATUS_ATTR = 'data-src-status';
5217
- var STATUS_LOADING = 'loading';
5218
- var STATUS_LOADED = 'loaded';
5219
- var STATUS_FAILED = 'failed';
5412
+ var STATUS_ATTR = 'data-src-status';
5413
+ var STATUS_LOADING = 'loading';
5414
+ var STATUS_LOADED = 'loaded';
5415
+ var STATUS_FAILED = 'failed';
5220
5416
 
5221
- var SELECTOR = 'pre[data-src]:not([' + STATUS_ATTR + '="' + STATUS_LOADED + '"])'
5222
- + ':not([' + STATUS_ATTR + '="' + STATUS_LOADING + '"])';
5417
+ var SELECTOR = 'pre[data-src]:not([' + STATUS_ATTR + '="' + STATUS_LOADED + '"])'
5418
+ + ':not([' + STATUS_ATTR + '="' + STATUS_LOADING + '"])';
5223
5419
 
5224
- /**
5225
- * Loads the given file.
5226
- *
5227
- * @param {string} src The URL or path of the source file to load.
5228
- * @param {(result: string) => void} success
5229
- * @param {(reason: string) => void} error
5230
- */
5231
- function loadFile(src, success, error) {
5232
- var xhr = new XMLHttpRequest();
5233
- xhr.open('GET', src, true);
5234
- xhr.onreadystatechange = function () {
5235
- if (xhr.readyState == 4) {
5236
- if (xhr.status < 400 && xhr.responseText) {
5237
- success(xhr.responseText);
5238
- } else {
5239
- if (xhr.status >= 400) {
5240
- error(FAILURE_MESSAGE(xhr.status, xhr.statusText));
5420
+ /**
5421
+ * Loads the given file.
5422
+ *
5423
+ * @param {string} src The URL or path of the source file to load.
5424
+ * @param {(result: string) => void} success
5425
+ * @param {(reason: string) => void} error
5426
+ */
5427
+ function loadFile(src, success, error) {
5428
+ var xhr = new XMLHttpRequest();
5429
+ xhr.open('GET', src, true);
5430
+ xhr.onreadystatechange = function () {
5431
+ if (xhr.readyState == 4) {
5432
+ if (xhr.status < 400 && xhr.responseText) {
5433
+ success(xhr.responseText);
5241
5434
  } else {
5242
- error(FAILURE_EMPTY_MESSAGE);
5435
+ if (xhr.status >= 400) {
5436
+ error(FAILURE_MESSAGE(xhr.status, xhr.statusText));
5437
+ } else {
5438
+ error(FAILURE_EMPTY_MESSAGE);
5439
+ }
5243
5440
  }
5244
5441
  }
5245
- }
5246
- };
5247
- xhr.send(null);
5248
- }
5442
+ };
5443
+ xhr.send(null);
5444
+ }
5249
5445
 
5250
- /**
5251
- * Parses the given range.
5252
- *
5253
- * This returns a range with inclusive ends.
5254
- *
5255
- * @param {string | null | undefined} range
5256
- * @returns {[number, number | undefined] | undefined}
5257
- */
5258
- function parseRange(range) {
5259
- var m = /^\s*(\d+)\s*(?:(,)\s*(?:(\d+)\s*)?)?$/.exec(range || '');
5260
- if (m) {
5261
- var start = Number(m[1]);
5262
- var comma = m[2];
5263
- var end = m[3];
5264
-
5265
- if (!comma) {
5266
- return [start, start];
5267
- }
5268
- if (!end) {
5269
- return [start, undefined];
5446
+ /**
5447
+ * Parses the given range.
5448
+ *
5449
+ * This returns a range with inclusive ends.
5450
+ *
5451
+ * @param {string | null | undefined} range
5452
+ * @returns {[number, number | undefined] | undefined}
5453
+ */
5454
+ function parseRange(range) {
5455
+ var m = /^\s*(\d+)\s*(?:(,)\s*(?:(\d+)\s*)?)?$/.exec(range || '');
5456
+ if (m) {
5457
+ var start = Number(m[1]);
5458
+ var comma = m[2];
5459
+ var end = m[3];
5460
+
5461
+ if (!comma) {
5462
+ return [start, start];
5463
+ }
5464
+ if (!end) {
5465
+ return [start, undefined];
5466
+ }
5467
+ return [start, Number(end)];
5270
5468
  }
5271
- return [start, Number(end)];
5469
+ return undefined;
5272
5470
  }
5273
- return undefined;
5274
- }
5275
5471
 
5276
- Prism.hooks.add('before-highlightall', function (env) {
5277
- env.selector += ', ' + SELECTOR;
5278
- });
5472
+ Prism.hooks.add('before-highlightall', function (env) {
5473
+ env.selector += ', ' + SELECTOR;
5474
+ });
5279
5475
 
5280
- Prism.hooks.add('before-sanity-check', function (env) {
5281
- var pre = /** @type {HTMLPreElement} */ (env.element);
5282
- if (pre.matches(SELECTOR)) {
5283
- env.code = ''; // fast-path the whole thing and go to complete
5476
+ Prism.hooks.add('before-sanity-check', function (env) {
5477
+ var pre = /** @type {HTMLPreElement} */ (env.element);
5478
+ if (pre.matches(SELECTOR)) {
5479
+ env.code = ''; // fast-path the whole thing and go to complete
5284
5480
 
5285
- pre.setAttribute(STATUS_ATTR, STATUS_LOADING); // mark as loading
5481
+ pre.setAttribute(STATUS_ATTR, STATUS_LOADING); // mark as loading
5286
5482
 
5287
- // add code element with loading message
5288
- var code = pre.appendChild(document.createElement('CODE'));
5289
- code.textContent = LOADING_MESSAGE;
5483
+ // add code element with loading message
5484
+ var code = pre.appendChild(document.createElement('CODE'));
5485
+ code.textContent = LOADING_MESSAGE;
5290
5486
 
5291
- var src = pre.getAttribute('data-src');
5487
+ var src = pre.getAttribute('data-src');
5292
5488
 
5293
- var language = env.language;
5294
- if (language === 'none') {
5295
- // the language might be 'none' because there is no language set;
5296
- // in this case, we want to use the extension as the language
5297
- var extension = (/\.(\w+)$/.exec(src) || [, 'none'])[1];
5298
- language = EXTENSIONS[extension] || extension;
5299
- }
5489
+ var language = env.language;
5490
+ if (language === 'none') {
5491
+ // the language might be 'none' because there is no language set;
5492
+ // in this case, we want to use the extension as the language
5493
+ var extension = (/\.(\w+)$/.exec(src) || [, 'none'])[1];
5494
+ language = EXTENSIONS[extension] || extension;
5495
+ }
5300
5496
 
5301
- // set language classes
5302
- Prism.util.setLanguage(code, language);
5303
- Prism.util.setLanguage(pre, language);
5497
+ // set language classes
5498
+ Prism.util.setLanguage(code, language);
5499
+ Prism.util.setLanguage(pre, language);
5304
5500
 
5305
- // preload the language
5306
- var autoloader = Prism.plugins.autoloader;
5307
- if (autoloader) {
5308
- autoloader.loadLanguages(language);
5309
- }
5501
+ // preload the language
5502
+ var autoloader = Prism.plugins.autoloader;
5503
+ if (autoloader) {
5504
+ autoloader.loadLanguages(language);
5505
+ }
5310
5506
 
5311
- // load file
5312
- loadFile(
5313
- src,
5314
- function (text) {
5315
- // mark as loaded
5316
- pre.setAttribute(STATUS_ATTR, STATUS_LOADED);
5507
+ // load file
5508
+ loadFile(
5509
+ src,
5510
+ function (text) {
5511
+ // mark as loaded
5512
+ pre.setAttribute(STATUS_ATTR, STATUS_LOADED);
5317
5513
 
5318
- // handle data-range
5319
- var range = parseRange(pre.getAttribute('data-range'));
5320
- if (range) {
5321
- var lines = text.split(/\r\n?|\n/g);
5514
+ // handle data-range
5515
+ var range = parseRange(pre.getAttribute('data-range'));
5516
+ if (range) {
5517
+ var lines = text.split(/\r\n?|\n/g);
5322
5518
 
5323
- // the range is one-based and inclusive on both ends
5324
- var start = range[0];
5325
- var end = range[1] == null ? lines.length : range[1];
5519
+ // the range is one-based and inclusive on both ends
5520
+ var start = range[0];
5521
+ var end = range[1] == null ? lines.length : range[1];
5326
5522
 
5327
- if (start < 0) { start += lines.length; }
5328
- start = Math.max(0, Math.min(start - 1, lines.length));
5329
- if (end < 0) { end += lines.length; }
5330
- end = Math.max(0, Math.min(end, lines.length));
5523
+ if (start < 0) { start += lines.length; }
5524
+ start = Math.max(0, Math.min(start - 1, lines.length));
5525
+ if (end < 0) { end += lines.length; }
5526
+ end = Math.max(0, Math.min(end, lines.length));
5331
5527
 
5332
- text = lines.slice(start, end).join('\n');
5528
+ text = lines.slice(start, end).join('\n');
5333
5529
 
5334
- // add data-start for line numbers
5335
- if (!pre.hasAttribute('data-start')) {
5336
- pre.setAttribute('data-start', String(start + 1));
5530
+ // add data-start for line numbers
5531
+ if (!pre.hasAttribute('data-start')) {
5532
+ pre.setAttribute('data-start', String(start + 1));
5533
+ }
5337
5534
  }
5338
- }
5339
5535
 
5340
- // highlight code
5341
- code.textContent = text;
5342
- Prism.highlightElement(code);
5343
- },
5344
- function (error) {
5345
- // mark as failed
5346
- pre.setAttribute(STATUS_ATTR, STATUS_FAILED);
5536
+ // highlight code
5537
+ code.textContent = text;
5538
+ Prism.highlightElement(code);
5539
+ },
5540
+ function (error) {
5541
+ // mark as failed
5542
+ pre.setAttribute(STATUS_ATTR, STATUS_FAILED);
5347
5543
 
5348
- code.textContent = error;
5349
- }
5350
- );
5351
- }
5352
- });
5544
+ code.textContent = error;
5545
+ }
5546
+ );
5547
+ }
5548
+ });
5353
5549
 
5354
- Prism.plugins.fileHighlight = {
5355
- /**
5356
- * Executes the File Highlight plugin for all matching `pre` elements under the given container.
5357
- *
5358
- * Note: Elements which are already loaded or currently loading will not be touched by this method.
5359
- *
5360
- * @param {ParentNode} [container=document]
5361
- */
5362
- highlight: function highlight(container) {
5363
- var elements = (container || document).querySelectorAll(SELECTOR);
5550
+ Prism.plugins.fileHighlight = {
5551
+ /**
5552
+ * Executes the File Highlight plugin for all matching `pre` elements under the given container.
5553
+ *
5554
+ * Note: Elements which are already loaded or currently loading will not be touched by this method.
5555
+ *
5556
+ * @param {ParentNode} [container=document]
5557
+ */
5558
+ highlight: function highlight(container) {
5559
+ var elements = (container || document).querySelectorAll(SELECTOR);
5364
5560
 
5365
- for (var i = 0, element; (element = elements[i++]);) {
5366
- Prism.highlightElement(element);
5561
+ for (var i = 0, element; (element = elements[i++]);) {
5562
+ Prism.highlightElement(element);
5563
+ }
5367
5564
  }
5368
- }
5369
- };
5370
-
5371
- var logged = false;
5372
- /** @deprecated Use `Prism.plugins.fileHighlight.highlight` instead. */
5373
- Prism.fileHighlight = function () {
5374
- if (!logged) {
5375
- console.warn('Prism.fileHighlight is deprecated. Use `Prism.plugins.fileHighlight.highlight` instead.');
5376
- logged = true;
5377
- }
5378
- Prism.plugins.fileHighlight.highlight.apply(this, arguments);
5379
- };
5565
+ };
5380
5566
 
5381
- }());
5382
- } (prism));
5383
-
5384
- Prism.languages.python = {
5385
- 'comment': {
5386
- pattern: /(^|[^\\])#.*/,
5387
- lookbehind: true,
5388
- greedy: true
5389
- },
5390
- 'string-interpolation': {
5391
- pattern: /(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,
5392
- greedy: true,
5393
- inside: {
5394
- 'interpolation': {
5395
- // "{" <expression> <optional "!s", "!r", or "!a"> <optional ":" format specifier> "}"
5396
- pattern: /((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,
5397
- lookbehind: true,
5398
- inside: {
5399
- 'format-spec': {
5400
- pattern: /(:)[^:(){}]+(?=\}$)/,
5401
- lookbehind: true
5402
- },
5403
- 'conversion-option': {
5404
- pattern: /![sra](?=[:}]$)/,
5405
- alias: 'punctuation'
5406
- },
5407
- rest: null
5567
+ var logged = false;
5568
+ /** @deprecated Use `Prism.plugins.fileHighlight.highlight` instead. */
5569
+ Prism.fileHighlight = function () {
5570
+ if (!logged) {
5571
+ console.warn('Prism.fileHighlight is deprecated. Use `Prism.plugins.fileHighlight.highlight` instead.');
5572
+ logged = true;
5408
5573
  }
5409
- },
5410
- 'string': /[\s\S]+/
5411
- }
5412
- },
5413
- 'triple-quoted-string': {
5414
- pattern: /(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,
5415
- greedy: true,
5416
- alias: 'string'
5417
- },
5418
- 'string': {
5419
- pattern: /(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,
5420
- greedy: true
5421
- },
5422
- 'function': {
5423
- pattern: /((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,
5424
- lookbehind: true
5425
- },
5426
- 'class-name': {
5427
- pattern: /(\bclass\s+)\w+/i,
5428
- lookbehind: true
5429
- },
5430
- 'decorator': {
5431
- pattern: /(^[\t ]*)@\w+(?:\.\w+)*/m,
5432
- lookbehind: true,
5433
- alias: ['annotation', 'punctuation'],
5434
- inside: {
5435
- 'punctuation': /\./
5436
- }
5437
- },
5438
- 'keyword': /\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,
5439
- 'builtin': /\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,
5440
- 'boolean': /\b(?:False|None|True)\b/,
5441
- 'number': /\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,
5442
- 'operator': /[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,
5443
- 'punctuation': /[{}[\];(),.:]/
5444
- };
5574
+ Prism.plugins.fileHighlight.highlight.apply(this, arguments);
5575
+ };
5445
5576
 
5446
- Prism.languages.python['string-interpolation'].inside['interpolation'].inside.rest = Prism.languages.python;
5577
+ }());
5578
+ } (prism));
5579
+ return prism.exports;
5580
+ }
5447
5581
 
5448
- Prism.languages.py = Prism.languages.python;
5582
+ requirePrism();
5449
5583
 
5450
- (function () {
5584
+ var prismPython = {};
5451
5585
 
5452
- if (typeof Prism === 'undefined' || typeof document === 'undefined') {
5453
- return;
5454
- }
5586
+ var hasRequiredPrismPython;
5455
5587
 
5456
- /**
5457
- * Plugin name which is used as a class name for <pre> which is activating the plugin
5458
- *
5459
- * @type {string}
5460
- */
5461
- var PLUGIN_NAME = 'line-numbers';
5588
+ function requirePrismPython () {
5589
+ if (hasRequiredPrismPython) return prismPython;
5590
+ hasRequiredPrismPython = 1;
5591
+ Prism.languages.python = {
5592
+ 'comment': {
5593
+ pattern: /(^|[^\\])#.*/,
5594
+ lookbehind: true,
5595
+ greedy: true
5596
+ },
5597
+ 'string-interpolation': {
5598
+ pattern: /(?:f|fr|rf)(?:("""|''')[\s\S]*?\1|("|')(?:\\.|(?!\2)[^\\\r\n])*\2)/i,
5599
+ greedy: true,
5600
+ inside: {
5601
+ 'interpolation': {
5602
+ // "{" <expression> <optional "!s", "!r", or "!a"> <optional ":" format specifier> "}"
5603
+ pattern: /((?:^|[^{])(?:\{\{)*)\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}]|\{(?!\{)(?:[^{}])+\})+\})+\}/,
5604
+ lookbehind: true,
5605
+ inside: {
5606
+ 'format-spec': {
5607
+ pattern: /(:)[^:(){}]+(?=\}$)/,
5608
+ lookbehind: true
5609
+ },
5610
+ 'conversion-option': {
5611
+ pattern: /![sra](?=[:}]$)/,
5612
+ alias: 'punctuation'
5613
+ },
5614
+ rest: null
5615
+ }
5616
+ },
5617
+ 'string': /[\s\S]+/
5618
+ }
5619
+ },
5620
+ 'triple-quoted-string': {
5621
+ pattern: /(?:[rub]|br|rb)?("""|''')[\s\S]*?\1/i,
5622
+ greedy: true,
5623
+ alias: 'string'
5624
+ },
5625
+ 'string': {
5626
+ pattern: /(?:[rub]|br|rb)?("|')(?:\\.|(?!\1)[^\\\r\n])*\1/i,
5627
+ greedy: true
5628
+ },
5629
+ 'function': {
5630
+ pattern: /((?:^|\s)def[ \t]+)[a-zA-Z_]\w*(?=\s*\()/g,
5631
+ lookbehind: true
5632
+ },
5633
+ 'class-name': {
5634
+ pattern: /(\bclass\s+)\w+/i,
5635
+ lookbehind: true
5636
+ },
5637
+ 'decorator': {
5638
+ pattern: /(^[\t ]*)@\w+(?:\.\w+)*/m,
5639
+ lookbehind: true,
5640
+ alias: ['annotation', 'punctuation'],
5641
+ inside: {
5642
+ 'punctuation': /\./
5643
+ }
5644
+ },
5645
+ 'keyword': /\b(?:_(?=\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\b/,
5646
+ 'builtin': /\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\b/,
5647
+ 'boolean': /\b(?:False|None|True)\b/,
5648
+ 'number': /\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\b|(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)(?:e[+-]?\d+(?:_\d+)*)?j?(?!\w)/i,
5649
+ 'operator': /[-+%=]=?|!=|:=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]/,
5650
+ 'punctuation': /[{}[\];(),.:]/
5651
+ };
5462
5652
 
5463
- /**
5464
- * Regular expression used for determining line breaks
5465
- *
5466
- * @type {RegExp}
5467
- */
5468
- var NEW_LINE_EXP = /\n(?!$)/g;
5653
+ Prism.languages.python['string-interpolation'].inside['interpolation'].inside.rest = Prism.languages.python;
5469
5654
 
5655
+ Prism.languages.py = Prism.languages.python;
5656
+ return prismPython;
5657
+ }
5470
5658
 
5471
- /**
5472
- * Global exports
5473
- */
5474
- var config = Prism.plugins.lineNumbers = {
5475
- /**
5476
- * Get node for provided line number
5477
- *
5478
- * @param {Element} element pre element
5479
- * @param {number} number line number
5480
- * @returns {Element|undefined}
5481
- */
5482
- getLine: function (element, number) {
5483
- if (element.tagName !== 'PRE' || !element.classList.contains(PLUGIN_NAME)) {
5484
- return;
5485
- }
5659
+ requirePrismPython();
5486
5660
 
5487
- var lineNumberRows = element.querySelector('.line-numbers-rows');
5488
- if (!lineNumberRows) {
5489
- return;
5490
- }
5491
- var lineNumberStart = parseInt(element.getAttribute('data-start'), 10) || 1;
5492
- var lineNumberEnd = lineNumberStart + (lineNumberRows.children.length - 1);
5661
+ var prismLineNumbers = {};
5493
5662
 
5494
- if (number < lineNumberStart) {
5495
- number = lineNumberStart;
5496
- }
5497
- if (number > lineNumberEnd) {
5498
- number = lineNumberEnd;
5499
- }
5663
+ var hasRequiredPrismLineNumbers;
5500
5664
 
5501
- var lineIndex = number - lineNumberStart;
5665
+ function requirePrismLineNumbers () {
5666
+ if (hasRequiredPrismLineNumbers) return prismLineNumbers;
5667
+ hasRequiredPrismLineNumbers = 1;
5668
+ (function () {
5502
5669
 
5503
- return lineNumberRows.children[lineIndex];
5504
- },
5670
+ if (typeof Prism === 'undefined' || typeof document === 'undefined') {
5671
+ return;
5672
+ }
5505
5673
 
5506
5674
  /**
5507
- * Resizes the line numbers of the given element.
5675
+ * Plugin name which is used as a class name for <pre> which is activating the plugin
5508
5676
  *
5509
- * This function will not add line numbers. It will only resize existing ones.
5510
- *
5511
- * @param {HTMLElement} element A `<pre>` element with line numbers.
5512
- * @returns {void}
5677
+ * @type {string}
5513
5678
  */
5514
- resize: function (element) {
5515
- resizeElements([element]);
5516
- },
5679
+ var PLUGIN_NAME = 'line-numbers';
5517
5680
 
5518
5681
  /**
5519
- * Whether the plugin can assume that the units font sizes and margins are not depended on the size of
5520
- * the current viewport.
5521
- *
5522
- * Setting this to `true` will allow the plugin to do certain optimizations for better performance.
5682
+ * Regular expression used for determining line breaks
5523
5683
  *
5524
- * Set this to `false` if you use any of the following CSS units: `vh`, `vw`, `vmin`, `vmax`.
5525
- *
5526
- * @type {boolean}
5684
+ * @type {RegExp}
5527
5685
  */
5528
- assumeViewportIndependence: true
5529
- };
5686
+ var NEW_LINE_EXP = /\n(?!$)/g;
5530
5687
 
5531
- /**
5532
- * Resizes the given elements.
5533
- *
5534
- * @param {HTMLElement[]} elements
5535
- */
5536
- function resizeElements(elements) {
5537
- elements = elements.filter(function (e) {
5538
- var codeStyles = getStyles(e);
5539
- var whiteSpace = codeStyles['white-space'];
5540
- return whiteSpace === 'pre-wrap' || whiteSpace === 'pre-line';
5541
- });
5542
5688
 
5543
- if (elements.length == 0) {
5544
- return;
5545
- }
5689
+ /**
5690
+ * Global exports
5691
+ */
5692
+ var config = Prism.plugins.lineNumbers = {
5693
+ /**
5694
+ * Get node for provided line number
5695
+ *
5696
+ * @param {Element} element pre element
5697
+ * @param {number} number line number
5698
+ * @returns {Element|undefined}
5699
+ */
5700
+ getLine: function (element, number) {
5701
+ if (element.tagName !== 'PRE' || !element.classList.contains(PLUGIN_NAME)) {
5702
+ return;
5703
+ }
5546
5704
 
5547
- var infos = elements.map(function (element) {
5548
- var codeElement = element.querySelector('code');
5549
- var lineNumbersWrapper = element.querySelector('.line-numbers-rows');
5550
- if (!codeElement || !lineNumbersWrapper) {
5551
- return undefined;
5552
- }
5705
+ var lineNumberRows = element.querySelector('.line-numbers-rows');
5706
+ if (!lineNumberRows) {
5707
+ return;
5708
+ }
5709
+ var lineNumberStart = parseInt(element.getAttribute('data-start'), 10) || 1;
5710
+ var lineNumberEnd = lineNumberStart + (lineNumberRows.children.length - 1);
5711
+
5712
+ if (number < lineNumberStart) {
5713
+ number = lineNumberStart;
5714
+ }
5715
+ if (number > lineNumberEnd) {
5716
+ number = lineNumberEnd;
5717
+ }
5553
5718
 
5554
- /** @type {HTMLElement} */
5555
- var lineNumberSizer = element.querySelector('.line-numbers-sizer');
5556
- var codeLines = codeElement.textContent.split(NEW_LINE_EXP);
5719
+ var lineIndex = number - lineNumberStart;
5720
+
5721
+ return lineNumberRows.children[lineIndex];
5722
+ },
5723
+
5724
+ /**
5725
+ * Resizes the line numbers of the given element.
5726
+ *
5727
+ * This function will not add line numbers. It will only resize existing ones.
5728
+ *
5729
+ * @param {HTMLElement} element A `<pre>` element with line numbers.
5730
+ * @returns {void}
5731
+ */
5732
+ resize: function (element) {
5733
+ resizeElements([element]);
5734
+ },
5735
+
5736
+ /**
5737
+ * Whether the plugin can assume that the units font sizes and margins are not depended on the size of
5738
+ * the current viewport.
5739
+ *
5740
+ * Setting this to `true` will allow the plugin to do certain optimizations for better performance.
5741
+ *
5742
+ * Set this to `false` if you use any of the following CSS units: `vh`, `vw`, `vmin`, `vmax`.
5743
+ *
5744
+ * @type {boolean}
5745
+ */
5746
+ assumeViewportIndependence: true
5747
+ };
5557
5748
 
5558
- if (!lineNumberSizer) {
5559
- lineNumberSizer = document.createElement('span');
5560
- lineNumberSizer.className = 'line-numbers-sizer';
5749
+ /**
5750
+ * Resizes the given elements.
5751
+ *
5752
+ * @param {HTMLElement[]} elements
5753
+ */
5754
+ function resizeElements(elements) {
5755
+ elements = elements.filter(function (e) {
5756
+ var codeStyles = getStyles(e);
5757
+ var whiteSpace = codeStyles['white-space'];
5758
+ return whiteSpace === 'pre-wrap' || whiteSpace === 'pre-line';
5759
+ });
5561
5760
 
5562
- codeElement.appendChild(lineNumberSizer);
5761
+ if (elements.length == 0) {
5762
+ return;
5563
5763
  }
5564
5764
 
5565
- lineNumberSizer.innerHTML = '0';
5566
- lineNumberSizer.style.display = 'block';
5765
+ var infos = elements.map(function (element) {
5766
+ var codeElement = element.querySelector('code');
5767
+ var lineNumbersWrapper = element.querySelector('.line-numbers-rows');
5768
+ if (!codeElement || !lineNumbersWrapper) {
5769
+ return undefined;
5770
+ }
5567
5771
 
5568
- var oneLinerHeight = lineNumberSizer.getBoundingClientRect().height;
5569
- lineNumberSizer.innerHTML = '';
5772
+ /** @type {HTMLElement} */
5773
+ var lineNumberSizer = element.querySelector('.line-numbers-sizer');
5774
+ var codeLines = codeElement.textContent.split(NEW_LINE_EXP);
5570
5775
 
5571
- return {
5572
- element: element,
5573
- lines: codeLines,
5574
- lineHeights: [],
5575
- oneLinerHeight: oneLinerHeight,
5576
- sizer: lineNumberSizer,
5577
- };
5578
- }).filter(Boolean);
5579
-
5580
- infos.forEach(function (info) {
5581
- var lineNumberSizer = info.sizer;
5582
- var lines = info.lines;
5583
- var lineHeights = info.lineHeights;
5584
- var oneLinerHeight = info.oneLinerHeight;
5585
-
5586
- lineHeights[lines.length - 1] = undefined;
5587
- lines.forEach(function (line, index) {
5588
- if (line && line.length > 1) {
5589
- var e = lineNumberSizer.appendChild(document.createElement('span'));
5590
- e.style.display = 'block';
5591
- e.textContent = line;
5592
- } else {
5593
- lineHeights[index] = oneLinerHeight;
5776
+ if (!lineNumberSizer) {
5777
+ lineNumberSizer = document.createElement('span');
5778
+ lineNumberSizer.className = 'line-numbers-sizer';
5779
+
5780
+ codeElement.appendChild(lineNumberSizer);
5594
5781
  }
5782
+
5783
+ lineNumberSizer.innerHTML = '0';
5784
+ lineNumberSizer.style.display = 'block';
5785
+
5786
+ var oneLinerHeight = lineNumberSizer.getBoundingClientRect().height;
5787
+ lineNumberSizer.innerHTML = '';
5788
+
5789
+ return {
5790
+ element: element,
5791
+ lines: codeLines,
5792
+ lineHeights: [],
5793
+ oneLinerHeight: oneLinerHeight,
5794
+ sizer: lineNumberSizer,
5795
+ };
5796
+ }).filter(Boolean);
5797
+
5798
+ infos.forEach(function (info) {
5799
+ var lineNumberSizer = info.sizer;
5800
+ var lines = info.lines;
5801
+ var lineHeights = info.lineHeights;
5802
+ var oneLinerHeight = info.oneLinerHeight;
5803
+
5804
+ lineHeights[lines.length - 1] = undefined;
5805
+ lines.forEach(function (line, index) {
5806
+ if (line && line.length > 1) {
5807
+ var e = lineNumberSizer.appendChild(document.createElement('span'));
5808
+ e.style.display = 'block';
5809
+ e.textContent = line;
5810
+ } else {
5811
+ lineHeights[index] = oneLinerHeight;
5812
+ }
5813
+ });
5595
5814
  });
5596
- });
5597
5815
 
5598
- infos.forEach(function (info) {
5599
- var lineNumberSizer = info.sizer;
5600
- var lineHeights = info.lineHeights;
5816
+ infos.forEach(function (info) {
5817
+ var lineNumberSizer = info.sizer;
5818
+ var lineHeights = info.lineHeights;
5601
5819
 
5602
- var childIndex = 0;
5603
- for (var i = 0; i < lineHeights.length; i++) {
5604
- if (lineHeights[i] === undefined) {
5605
- lineHeights[i] = lineNumberSizer.children[childIndex++].getBoundingClientRect().height;
5820
+ var childIndex = 0;
5821
+ for (var i = 0; i < lineHeights.length; i++) {
5822
+ if (lineHeights[i] === undefined) {
5823
+ lineHeights[i] = lineNumberSizer.children[childIndex++].getBoundingClientRect().height;
5824
+ }
5606
5825
  }
5607
- }
5608
- });
5826
+ });
5609
5827
 
5610
- infos.forEach(function (info) {
5611
- var lineNumberSizer = info.sizer;
5612
- var wrapper = info.element.querySelector('.line-numbers-rows');
5828
+ infos.forEach(function (info) {
5829
+ var lineNumberSizer = info.sizer;
5830
+ var wrapper = info.element.querySelector('.line-numbers-rows');
5613
5831
 
5614
- lineNumberSizer.style.display = 'none';
5615
- lineNumberSizer.innerHTML = '';
5832
+ lineNumberSizer.style.display = 'none';
5833
+ lineNumberSizer.innerHTML = '';
5616
5834
 
5617
- info.lineHeights.forEach(function (height, lineNumber) {
5618
- wrapper.children[lineNumber].style.height = height + 'px';
5835
+ info.lineHeights.forEach(function (height, lineNumber) {
5836
+ wrapper.children[lineNumber].style.height = height + 'px';
5837
+ });
5619
5838
  });
5620
- });
5621
- }
5622
-
5623
- /**
5624
- * Returns style declarations for the element
5625
- *
5626
- * @param {Element} element
5627
- */
5628
- function getStyles(element) {
5629
- if (!element) {
5630
- return null;
5631
5839
  }
5632
5840
 
5633
- return window.getComputedStyle ? getComputedStyle(element) : (element.currentStyle || null);
5634
- }
5841
+ /**
5842
+ * Returns style declarations for the element
5843
+ *
5844
+ * @param {Element} element
5845
+ */
5846
+ function getStyles(element) {
5847
+ if (!element) {
5848
+ return null;
5849
+ }
5635
5850
 
5636
- var lastWidth = undefined;
5637
- window.addEventListener('resize', function () {
5638
- if (config.assumeViewportIndependence && lastWidth === window.innerWidth) {
5639
- return;
5851
+ return window.getComputedStyle ? getComputedStyle(element) : (element.currentStyle || null);
5640
5852
  }
5641
- lastWidth = window.innerWidth;
5642
5853
 
5643
- resizeElements(Array.prototype.slice.call(document.querySelectorAll('pre.' + PLUGIN_NAME)));
5644
- });
5854
+ var lastWidth = undefined;
5855
+ window.addEventListener('resize', function () {
5856
+ if (config.assumeViewportIndependence && lastWidth === window.innerWidth) {
5857
+ return;
5858
+ }
5859
+ lastWidth = window.innerWidth;
5645
5860
 
5646
- Prism.hooks.add('complete', function (env) {
5647
- if (!env.code) {
5648
- return;
5649
- }
5861
+ resizeElements(Array.prototype.slice.call(document.querySelectorAll('pre.' + PLUGIN_NAME)));
5862
+ });
5650
5863
 
5651
- var code = /** @type {Element} */ (env.element);
5652
- var pre = /** @type {HTMLElement} */ (code.parentNode);
5864
+ Prism.hooks.add('complete', function (env) {
5865
+ if (!env.code) {
5866
+ return;
5867
+ }
5653
5868
 
5654
- // works only for <code> wrapped inside <pre> (not inline)
5655
- if (!pre || !/pre/i.test(pre.nodeName)) {
5656
- return;
5657
- }
5869
+ var code = /** @type {Element} */ (env.element);
5870
+ var pre = /** @type {HTMLElement} */ (code.parentNode);
5658
5871
 
5659
- // Abort if line numbers already exists
5660
- if (code.querySelector('.line-numbers-rows')) {
5661
- return;
5662
- }
5872
+ // works only for <code> wrapped inside <pre> (not inline)
5873
+ if (!pre || !/pre/i.test(pre.nodeName)) {
5874
+ return;
5875
+ }
5663
5876
 
5664
- // only add line numbers if <code> or one of its ancestors has the `line-numbers` class
5665
- if (!Prism.util.isActive(code, PLUGIN_NAME)) {
5666
- return;
5667
- }
5877
+ // Abort if line numbers already exists
5878
+ if (code.querySelector('.line-numbers-rows')) {
5879
+ return;
5880
+ }
5668
5881
 
5669
- // Remove the class 'line-numbers' from the <code>
5670
- code.classList.remove(PLUGIN_NAME);
5671
- // Add the class 'line-numbers' to the <pre>
5672
- pre.classList.add(PLUGIN_NAME);
5882
+ // only add line numbers if <code> or one of its ancestors has the `line-numbers` class
5883
+ if (!Prism.util.isActive(code, PLUGIN_NAME)) {
5884
+ return;
5885
+ }
5673
5886
 
5674
- var match = env.code.match(NEW_LINE_EXP);
5675
- var linesNum = match ? match.length + 1 : 1;
5676
- var lineNumbersWrapper;
5887
+ // Remove the class 'line-numbers' from the <code>
5888
+ code.classList.remove(PLUGIN_NAME);
5889
+ // Add the class 'line-numbers' to the <pre>
5890
+ pre.classList.add(PLUGIN_NAME);
5677
5891
 
5678
- var lines = new Array(linesNum + 1).join('<span></span>');
5892
+ var match = env.code.match(NEW_LINE_EXP);
5893
+ var linesNum = match ? match.length + 1 : 1;
5894
+ var lineNumbersWrapper;
5679
5895
 
5680
- lineNumbersWrapper = document.createElement('span');
5681
- lineNumbersWrapper.setAttribute('aria-hidden', 'true');
5682
- lineNumbersWrapper.className = 'line-numbers-rows';
5683
- lineNumbersWrapper.innerHTML = lines;
5896
+ var lines = new Array(linesNum + 1).join('<span></span>');
5684
5897
 
5685
- if (pre.hasAttribute('data-start')) {
5686
- pre.style.counterReset = 'linenumber ' + (parseInt(pre.getAttribute('data-start'), 10) - 1);
5687
- }
5898
+ lineNumbersWrapper = document.createElement('span');
5899
+ lineNumbersWrapper.setAttribute('aria-hidden', 'true');
5900
+ lineNumbersWrapper.className = 'line-numbers-rows';
5901
+ lineNumbersWrapper.innerHTML = lines;
5902
+
5903
+ if (pre.hasAttribute('data-start')) {
5904
+ pre.style.counterReset = 'linenumber ' + (parseInt(pre.getAttribute('data-start'), 10) - 1);
5905
+ }
5906
+
5907
+ env.element.appendChild(lineNumbersWrapper);
5688
5908
 
5689
- env.element.appendChild(lineNumbersWrapper);
5909
+ resizeElements([pre]);
5690
5910
 
5691
- resizeElements([pre]);
5911
+ Prism.hooks.run('line-numbers', env);
5912
+ });
5692
5913
 
5693
- Prism.hooks.run('line-numbers', env);
5694
- });
5914
+ Prism.hooks.add('line-numbers', function (env) {
5915
+ env.plugins = env.plugins || {};
5916
+ env.plugins.lineNumbers = true;
5917
+ });
5695
5918
 
5696
- Prism.hooks.add('line-numbers', function (env) {
5697
- env.plugins = env.plugins || {};
5698
- env.plugins.lineNumbers = true;
5699
- });
5919
+ }());
5920
+ return prismLineNumbers;
5921
+ }
5700
5922
 
5701
- }());
5923
+ requirePrismLineNumbers();
5702
5924
 
5703
5925
  const initialize = () => {
5704
5926
  // @ts-ignore
@@ -5718,15 +5940,23 @@ const initialize = () => {
5718
5940
  }
5719
5941
  };
5720
5942
  // @ts-ignore
5721
- window.setResults = (playerNames, places, map, verbose) => {
5943
+ window.setResults = (playerNames, seed, places, statistics, parameters, verbose) => {
5944
+ // @ts-ignore
5945
+ parameters = parameters.toJs();
5946
+ // @ts-ignore
5947
+ statistics = statistics.toJs();
5722
5948
  const results = getLocalStorage("Results");
5723
5949
  if (!results[playerNames.join(", ")]) {
5724
5950
  results[playerNames.join(", ")] = {};
5725
5951
  }
5726
- if (!results[playerNames.join(", ")][map]) {
5727
- results[playerNames.join(", ")][map] = [];
5952
+ if (!results[playerNames.join(", ")][JSON.stringify(parameters)]) {
5953
+ results[playerNames.join(", ")][JSON.stringify(parameters)] = [];
5728
5954
  }
5729
- results[playerNames.join(", ")][map].push(places);
5955
+ results[playerNames.join(", ")][JSON.stringify(parameters)].push({
5956
+ seed,
5957
+ places,
5958
+ statistics,
5959
+ });
5730
5960
  setLocalStorage("Results", results);
5731
5961
  updatePointModifier();
5732
5962
  // @ts-ignore