@splunk/react-ui 4.1.0 → 4.4.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 (163) hide show
  1. package/Accordion.js +4 -4
  2. package/Anchor.js +2 -2
  3. package/Animation.js +26 -35
  4. package/AnimationToggle.js +2 -2
  5. package/Box.js +2 -2
  6. package/Button.js +22 -22
  7. package/ButtonGroup.js +2 -2
  8. package/ButtonSimple.js +12 -6
  9. package/CHANGELOG.md +69 -2
  10. package/Calendar.js +23 -23
  11. package/Card.js +15 -15
  12. package/CardLayout.js +2 -2
  13. package/Chip.js +13 -13
  14. package/Clickable.js +4 -4
  15. package/CloseButton.js +8 -8
  16. package/Code.js +1279 -1120
  17. package/CollapsiblePanel.js +11 -11
  18. package/Color.js +111 -172
  19. package/ColumnLayout.js +6 -6
  20. package/ComboBox.js +63 -30
  21. package/Concertina.js +2 -2
  22. package/ControlGroup.js +61 -20
  23. package/Date.js +66 -29
  24. package/DefinitionList.js +2 -2
  25. package/Dropdown.js +6 -6
  26. package/FetchOptions.js +8 -8
  27. package/File.js +87 -72
  28. package/FormRows.js +219 -331
  29. package/Heading.js +2 -2
  30. package/Image.js +15 -15
  31. package/JSONTree.js +63 -20
  32. package/Layer.js +8 -8
  33. package/Link.js +13 -13
  34. package/List.js +2 -2
  35. package/Markdown.js +19 -19
  36. package/Menu.js +315 -230
  37. package/Message.js +19 -19
  38. package/Modal.js +22 -11
  39. package/ModalLayer.js +25 -11
  40. package/Monogram.js +7 -7
  41. package/Multiselect.js +1931 -1057
  42. package/Number.js +40 -27
  43. package/Paginator.js +67 -49
  44. package/Paragraph.js +2 -2
  45. package/Popover.js +62 -35
  46. package/Progress.js +9 -21
  47. package/RadioBar.js +6 -6
  48. package/RadioList.js +2 -2
  49. package/ResultsMenu.js +18 -10
  50. package/ScreenReaderContent.js +2 -2
  51. package/Scroll.js +37 -19
  52. package/ScrollContainerContext.js +2 -2
  53. package/Select.js +1309 -562
  54. package/SidePanel.js +22 -17
  55. package/Slider.js +8 -8
  56. package/SlidingPanels.js +63 -47
  57. package/StaticContent.js +2 -2
  58. package/StepBar.js +8 -8
  59. package/Switch.js +20 -11
  60. package/TabBar.js +54 -40
  61. package/TabLayout.js +4 -4
  62. package/Table.js +148 -85
  63. package/Text.js +474 -356
  64. package/Tooltip.js +6 -6
  65. package/TransitionOpen.js +26 -24
  66. package/WaitSpinner.js +4 -4
  67. package/package.json +8 -7
  68. package/stubs-splunkui.d.ts +1 -0
  69. package/types/src/Accordion/Accordion.d.ts +2 -2
  70. package/types/src/Animation/Animation.d.ts +6 -5
  71. package/types/src/Button/Button.d.ts +2 -2
  72. package/types/src/ButtonSimple/ButtonSimple.d.ts +5 -5
  73. package/types/src/Calendar/DateTable.d.ts +1 -0
  74. package/types/src/Calendar/MonthHeader.d.ts +2 -2
  75. package/types/src/CollapsiblePanel/CollapsiblePanel.d.ts +1 -2
  76. package/types/src/Color/Color.d.ts +5 -4
  77. package/types/src/Color/Swatch.d.ts +4 -15
  78. package/types/src/ComboBox/ComboBox.d.ts +2 -2
  79. package/types/src/ControlGroup/ControlGroup.d.ts +7 -2
  80. package/types/src/ControlGroup/ControlGroupContext.d.ts +15 -0
  81. package/types/src/Date/Date.d.ts +7 -5
  82. package/types/src/Date/Icon.d.ts +1 -0
  83. package/types/src/Dropdown/Dropdown.d.ts +1 -1
  84. package/types/src/File/File.d.ts +2 -2
  85. package/types/src/File/FileContext.d.ts +9 -0
  86. package/types/src/File/Icon.d.ts +1 -0
  87. package/types/src/File/IconCloud.d.ts +1 -0
  88. package/types/src/File/Item.d.ts +5 -10
  89. package/types/src/File/PaperClip.d.ts +1 -0
  90. package/types/src/File/Retry.d.ts +1 -0
  91. package/types/src/File/Trash.d.ts +1 -0
  92. package/types/src/FormRows/FormRows.d.ts +11 -69
  93. package/types/src/FormRows/FormRowsContext.d.ts +9 -0
  94. package/types/src/FormRows/Row.d.ts +7 -20
  95. package/types/src/JSONTree/JSONTree.d.ts +14 -2
  96. package/types/src/JSONTree/TreeNode.d.ts +4 -1
  97. package/types/src/Menu/Divider.d.ts +1 -0
  98. package/types/src/Menu/Heading.d.ts +3 -1
  99. package/types/src/Menu/Item.d.ts +22 -6
  100. package/types/src/Menu/Menu.d.ts +17 -18
  101. package/types/src/Menu/MenuContext.d.ts +6 -0
  102. package/types/src/Menu/index.d.ts +1 -0
  103. package/types/src/Multiselect/Compact.d.ts +7 -26
  104. package/types/src/Multiselect/Multiselect.d.ts +7 -2
  105. package/types/src/Multiselect/Normal.d.ts +8 -2
  106. package/types/src/Multiselect/Option.d.ts +4 -1
  107. package/types/src/Number/IncrementIcon.d.ts +1 -0
  108. package/types/src/Number/Number.d.ts +4 -4
  109. package/types/src/Paginator/PageSeparator.d.ts +3 -0
  110. package/types/src/Popover/Popover.d.ts +5 -5
  111. package/types/src/Popover/PopoverContext.d.ts +6 -0
  112. package/types/src/Popover/index.d.ts +1 -0
  113. package/types/src/RadioBar/RadioBar.d.ts +5 -5
  114. package/types/src/RadioList/RadioListContext.d.ts +1 -0
  115. package/types/src/ResultsMenu/ResultsMenu.d.ts +4 -0
  116. package/types/src/Scroll/Inner.d.ts +4 -3
  117. package/types/src/Scroll/Scroll.d.ts +1 -1
  118. package/types/src/Select/Option.d.ts +2 -5
  119. package/types/src/Select/OptionBase.d.ts +94 -0
  120. package/types/src/Select/Select.d.ts +12 -37
  121. package/types/src/Select/SelectBase.d.ts +221 -0
  122. package/types/src/SidePanel/SidePanel.d.ts +4 -0
  123. package/types/src/Slider/Slider.d.ts +4 -4
  124. package/types/src/SlidingPanels/SlidingPanels.d.ts +0 -1
  125. package/types/src/Switch/CheckIcon.d.ts +1 -0
  126. package/types/src/Switch/Switch.d.ts +3 -7
  127. package/types/src/TabBar/Tab.d.ts +4 -1
  128. package/types/src/TabLayout/TabLayout.d.ts +2 -2
  129. package/types/src/Table/DragHandle.d.ts +1 -0
  130. package/types/src/Table/Head.d.ts +2 -0
  131. package/types/src/Table/HeadCell.d.ts +2 -2
  132. package/types/src/Table/HeadDropdownCell.d.ts +1 -1
  133. package/types/src/Table/HeadExpandRowsIcon.d.ts +1 -0
  134. package/types/src/Table/HeadInner.d.ts +3 -3
  135. package/types/src/Table/Table.d.ts +7 -3
  136. package/types/src/Table/Toggle.d.ts +1 -0
  137. package/types/src/Text/IconOutlinedHide.d.ts +1 -0
  138. package/types/src/Text/IconOutlinedView.d.ts +1 -0
  139. package/types/src/Text/Text.d.ts +28 -12
  140. package/types/src/Tooltip/InfoIcon.d.ts +1 -0
  141. package/types/src/Tooltip/Tooltip.d.ts +3 -3
  142. package/types/src/icons/Alert.d.ts +1 -0
  143. package/types/src/icons/AlertFilled.d.ts +1 -0
  144. package/types/src/icons/CaretDown.d.ts +1 -0
  145. package/types/src/icons/CaretRight.d.ts +1 -0
  146. package/types/src/icons/Check.d.ts +1 -0
  147. package/types/src/icons/ChevronDown.d.ts +1 -0
  148. package/types/src/icons/ChevronLeft.d.ts +1 -0
  149. package/types/src/icons/ChevronRight.d.ts +1 -0
  150. package/types/src/icons/CrossMark.d.ts +1 -0
  151. package/types/src/icons/External.d.ts +1 -0
  152. package/types/src/icons/InfoFilled.d.ts +1 -0
  153. package/types/src/icons/More.d.ts +1 -0
  154. package/types/src/icons/MoreVertical.d.ts +1 -0
  155. package/types/src/icons/Plus.d.ts +1 -0
  156. package/types/src/icons/SVG.d.ts +1 -0
  157. package/types/src/icons/Search.d.ts +1 -0
  158. package/types/src/icons/SortedDown.d.ts +1 -0
  159. package/types/src/icons/SortedUp.d.ts +1 -0
  160. package/types/src/icons/Success.d.ts +1 -0
  161. package/types/src/icons/SuccessFilled.d.ts +1 -0
  162. package/types/src/icons/WarningFilled.d.ts +1 -0
  163. package/types/src/utils/types.d.ts +1 -0
package/Code.js CHANGED
@@ -82,7 +82,7 @@ module.exports =
82
82
  /******/
83
83
  /******/
84
84
  /******/ // Load entry module and return exports
85
- /******/ return __webpack_require__(__webpack_require__.s = 143);
85
+ /******/ return __webpack_require__(__webpack_require__.s = 141);
86
86
  /******/ })
87
87
  /************************************************************************/
88
88
  /******/ ({
@@ -101,7 +101,7 @@ module.exports = require("prop-types");
101
101
 
102
102
  /***/ }),
103
103
 
104
- /***/ 143:
104
+ /***/ 141:
105
105
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
106
106
 
107
107
  "use strict";
@@ -123,7 +123,7 @@ var external_prop_types_default = /*#__PURE__*/__webpack_require__.n(external_pr
123
123
  var external_lodash_ = __webpack_require__(4);
124
124
 
125
125
  // EXTERNAL MODULE: ./src/Code/prism/prism.empty
126
- var prism_empty = __webpack_require__(67);
126
+ var prism_empty = __webpack_require__(69);
127
127
  var prism_empty_default = /*#__PURE__*/__webpack_require__.n(prism_empty);
128
128
 
129
129
  // EXTERNAL MODULE: external "styled-components"
@@ -377,7 +377,7 @@ module.exports = require("lodash");
377
377
 
378
378
  /***/ }),
379
379
 
380
- /***/ 67:
380
+ /***/ 69:
381
381
  /***/ (function(module, exports, __webpack_require__) {
382
382
 
383
383
 
@@ -390,8 +390,8 @@ var _self = (typeof window !== 'undefined')
390
390
  ? window // if in browser
391
391
  : (
392
392
  (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope)
393
- ? self // if in worker
394
- : {} // if in node js
393
+ ? self // if in worker
394
+ : {} // if in node js
395
395
  );
396
396
 
397
397
  /**
@@ -402,1115 +402,1151 @@ var _self = (typeof window !== 'undefined')
402
402
  * @namespace
403
403
  * @public
404
404
  */
405
- var Prism = (function (_self){
405
+ var Prism = (function (_self) {
406
406
 
407
- // Private helper vars
408
- var lang = /\blang(?:uage)?-([\w-]+)\b/i;
409
- var uniqueId = 0;
407
+ // Private helper vars
408
+ var lang = /\blang(?:uage)?-([\w-]+)\b/i;
409
+ var uniqueId = 0;
410
410
 
411
+ // The grammar object for plaintext
412
+ var plainTextGrammar = {};
411
413
 
412
- var _ = {
413
- /**
414
- * By default, Prism will attempt to highlight all code elements (by calling {@link Prism.highlightAll}) on the
415
- * current page after the page finished loading. This might be a problem if e.g. you wanted to asynchronously load
416
- * additional languages or plugins yourself.
417
- *
418
- * By setting this value to `true`, Prism will not automatically highlight all code elements on the page.
419
- *
420
- * You obviously have to change this value before the automatic highlighting started. To do this, you can add an
421
- * empty Prism object into the global scope before loading the Prism script like this:
422
- *
423
- * ```js
424
- * window.Prism = window.Prism || {};
425
- * Prism.manual = true;
426
- * // add a new <script> to load Prism's script
427
- * ```
428
- *
429
- * @default false
430
- * @type {boolean}
431
- * @memberof Prism
432
- * @public
433
- */
434
- manual: _self.Prism && _self.Prism.manual,
435
- disableWorkerMessageHandler: _self.Prism && _self.Prism.disableWorkerMessageHandler,
436
-
437
- /**
438
- * A namespace for utility methods.
439
- *
440
- * All function in this namespace that are not explicitly marked as _public_ are for __internal use only__ and may
441
- * change or disappear at any time.
442
- *
443
- * @namespace
444
- * @memberof Prism
445
- */
446
- util: {
447
- encode: function encode(tokens) {
448
- if (tokens instanceof Token) {
449
- return new Token(tokens.type, encode(tokens.content), tokens.alias);
450
- } else if (Array.isArray(tokens)) {
451
- return tokens.map(encode);
452
- } else {
453
- return tokens.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/\u00a0/g, ' ');
454
- }
455
- },
456
414
 
415
+ var _ = {
457
416
  /**
458
- * Returns the name of the type of the given value.
417
+ * By default, Prism will attempt to highlight all code elements (by calling {@link Prism.highlightAll}) on the
418
+ * current page after the page finished loading. This might be a problem if e.g. you wanted to asynchronously load
419
+ * additional languages or plugins yourself.
459
420
  *
460
- * @param {any} o
461
- * @returns {string}
462
- * @example
463
- * type(null) === 'Null'
464
- * type(undefined) === 'Undefined'
465
- * type(123) === 'Number'
466
- * type('foo') === 'String'
467
- * type(true) === 'Boolean'
468
- * type([1, 2]) === 'Array'
469
- * type({}) === 'Object'
470
- * type(String) === 'Function'
471
- * type(/abc+/) === 'RegExp'
421
+ * By setting this value to `true`, Prism will not automatically highlight all code elements on the page.
422
+ *
423
+ * You obviously have to change this value before the automatic highlighting started. To do this, you can add an
424
+ * empty Prism object into the global scope before loading the Prism script like this:
425
+ *
426
+ * ```js
427
+ * window.Prism = window.Prism || {};
428
+ * Prism.manual = true;
429
+ * // add a new <script> to load Prism's script
430
+ * ```
431
+ *
432
+ * @default false
433
+ * @type {boolean}
434
+ * @memberof Prism
435
+ * @public
472
436
  */
473
- type: function (o) {
474
- return Object.prototype.toString.call(o).slice(8, -1);
475
- },
437
+ manual: _self.Prism && _self.Prism.manual,
438
+ disableWorkerMessageHandler: _self.Prism && _self.Prism.disableWorkerMessageHandler,
476
439
 
477
440
  /**
478
- * Returns a unique number for the given object. Later calls will still return the same number.
441
+ * A namespace for utility methods.
479
442
  *
480
- * @param {Object} obj
481
- * @returns {number}
443
+ * All function in this namespace that are not explicitly marked as _public_ are for __internal use only__ and may
444
+ * change or disappear at any time.
445
+ *
446
+ * @namespace
447
+ * @memberof Prism
482
448
  */
483
- objId: function (obj) {
484
- if (!obj['__id']) {
485
- Object.defineProperty(obj, '__id', { value: ++uniqueId });
449
+ util: {
450
+ encode: function encode(tokens) {
451
+ if (tokens instanceof Token) {
452
+ return new Token(tokens.type, encode(tokens.content), tokens.alias);
453
+ } else if (Array.isArray(tokens)) {
454
+ return tokens.map(encode);
455
+ } else {
456
+ return tokens.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/\u00a0/g, ' ');
457
+ }
458
+ },
459
+
460
+ /**
461
+ * Returns the name of the type of the given value.
462
+ *
463
+ * @param {any} o
464
+ * @returns {string}
465
+ * @example
466
+ * type(null) === 'Null'
467
+ * type(undefined) === 'Undefined'
468
+ * type(123) === 'Number'
469
+ * type('foo') === 'String'
470
+ * type(true) === 'Boolean'
471
+ * type([1, 2]) === 'Array'
472
+ * type({}) === 'Object'
473
+ * type(String) === 'Function'
474
+ * type(/abc+/) === 'RegExp'
475
+ */
476
+ type: function (o) {
477
+ return Object.prototype.toString.call(o).slice(8, -1);
478
+ },
479
+
480
+ /**
481
+ * Returns a unique number for the given object. Later calls will still return the same number.
482
+ *
483
+ * @param {Object} obj
484
+ * @returns {number}
485
+ */
486
+ objId: function (obj) {
487
+ if (!obj['__id']) {
488
+ Object.defineProperty(obj, '__id', { value: ++uniqueId });
489
+ }
490
+ return obj['__id'];
491
+ },
492
+
493
+ /**
494
+ * Creates a deep clone of the given object.
495
+ *
496
+ * The main intended use of this function is to clone language definitions.
497
+ *
498
+ * @param {T} o
499
+ * @param {Record<number, any>} [visited]
500
+ * @returns {T}
501
+ * @template T
502
+ */
503
+ clone: function deepClone(o, visited) {
504
+ visited = visited || {};
505
+
506
+ var clone; var id;
507
+ switch (_.util.type(o)) {
508
+ case 'Object':
509
+ id = _.util.objId(o);
510
+ if (visited[id]) {
511
+ return visited[id];
512
+ }
513
+ clone = /** @type {Record<string, any>} */ ({});
514
+ visited[id] = clone;
515
+
516
+ for (var key in o) {
517
+ if (o.hasOwnProperty(key)) {
518
+ clone[key] = deepClone(o[key], visited);
519
+ }
520
+ }
521
+
522
+ return /** @type {any} */ (clone);
523
+
524
+ case 'Array':
525
+ id = _.util.objId(o);
526
+ if (visited[id]) {
527
+ return visited[id];
528
+ }
529
+ clone = [];
530
+ visited[id] = clone;
531
+
532
+ (/** @type {Array} */(/** @type {any} */(o))).forEach(function (v, i) {
533
+ clone[i] = deepClone(v, visited);
534
+ });
535
+
536
+ return /** @type {any} */ (clone);
537
+
538
+ default:
539
+ return o;
540
+ }
541
+ },
542
+
543
+ /**
544
+ * Returns the Prism language of the given element set by a `language-xxxx` or `lang-xxxx` class.
545
+ *
546
+ * If no language is set for the element or the element is `null` or `undefined`, `none` will be returned.
547
+ *
548
+ * @param {Element} element
549
+ * @returns {string}
550
+ */
551
+ getLanguage: function (element) {
552
+ while (element && !lang.test(element.className)) {
553
+ element = element.parentElement;
554
+ }
555
+ if (element) {
556
+ return (element.className.match(lang) || [, 'none'])[1].toLowerCase();
557
+ }
558
+ return 'none';
559
+ },
560
+
561
+ /**
562
+ * Returns the script element that is currently executing.
563
+ *
564
+ * This does __not__ work for line script element.
565
+ *
566
+ * @returns {HTMLScriptElement | null}
567
+ */
568
+ currentScript: function () {
569
+ if (typeof document === 'undefined') {
570
+ return null;
571
+ }
572
+ if ('currentScript' in document && 1 < 2 /* hack to trip TS' flow analysis */) {
573
+ return /** @type {any} */ (document.currentScript);
574
+ }
575
+
576
+ // IE11 workaround
577
+ // we'll get the src of the current script by parsing IE11's error stack trace
578
+ // this will not work for inline scripts
579
+
580
+ try {
581
+ throw new Error();
582
+ } catch (err) {
583
+ // Get file src url from stack. Specifically works with the format of stack traces in IE.
584
+ // A stack will look like this:
585
+ //
586
+ // Error
587
+ // at _.util.currentScript (http://localhost/components/prism-core.js:119:5)
588
+ // at Global code (http://localhost/components/prism-core.js:606:1)
589
+
590
+ var src = (/at [^(\r\n]*\((.*):[^:]+:[^:]+\)$/i.exec(err.stack) || [])[1];
591
+ if (src) {
592
+ var scripts = document.getElementsByTagName('script');
593
+ for (var i in scripts) {
594
+ if (scripts[i].src == src) {
595
+ return scripts[i];
596
+ }
597
+ }
598
+ }
599
+ return null;
600
+ }
601
+ },
602
+
603
+ /**
604
+ * Returns whether a given class is active for `element`.
605
+ *
606
+ * The class can be activated if `element` or one of its ancestors has the given class and it can be deactivated
607
+ * if `element` or one of its ancestors has the negated version of the given class. The _negated version_ of the
608
+ * given class is just the given class with a `no-` prefix.
609
+ *
610
+ * Whether the class is active is determined by the closest ancestor of `element` (where `element` itself is
611
+ * closest ancestor) that has the given class or the negated version of it. If neither `element` nor any of its
612
+ * ancestors have the given class or the negated version of it, then the default activation will be returned.
613
+ *
614
+ * In the paradoxical situation where the closest ancestor contains __both__ the given class and the negated
615
+ * version of it, the class is considered active.
616
+ *
617
+ * @param {Element} element
618
+ * @param {string} className
619
+ * @param {boolean} [defaultActivation=false]
620
+ * @returns {boolean}
621
+ */
622
+ isActive: function (element, className, defaultActivation) {
623
+ var no = 'no-' + className;
624
+
625
+ while (element) {
626
+ var classList = element.classList;
627
+ if (classList.contains(className)) {
628
+ return true;
629
+ }
630
+ if (classList.contains(no)) {
631
+ return false;
632
+ }
633
+ element = element.parentElement;
634
+ }
635
+ return !!defaultActivation;
486
636
  }
487
- return obj['__id'];
488
637
  },
489
638
 
490
639
  /**
491
- * Creates a deep clone of the given object.
640
+ * This namespace contains all currently loaded languages and the some helper functions to create and modify languages.
492
641
  *
493
- * The main intended use of this function is to clone language definitions.
494
- *
495
- * @param {T} o
496
- * @param {Record<number, any>} [visited]
497
- * @returns {T}
498
- * @template T
642
+ * @namespace
643
+ * @memberof Prism
644
+ * @public
499
645
  */
500
- clone: function deepClone(o, visited) {
501
- visited = visited || {};
502
-
503
- var clone, id;
504
- switch (_.util.type(o)) {
505
- case 'Object':
506
- id = _.util.objId(o);
507
- if (visited[id]) {
508
- return visited[id];
509
- }
510
- clone = /** @type {Record<string, any>} */ ({});
511
- visited[id] = clone;
646
+ languages: {
647
+ /**
648
+ * The grammar for plain, unformatted text.
649
+ */
650
+ plain: plainTextGrammar,
651
+ plaintext: plainTextGrammar,
652
+ text: plainTextGrammar,
653
+ txt: plainTextGrammar,
654
+
655
+ /**
656
+ * Creates a deep copy of the language with the given id and appends the given tokens.
657
+ *
658
+ * If a token in `redef` also appears in the copied language, then the existing token in the copied language
659
+ * will be overwritten at its original position.
660
+ *
661
+ * ## Best practices
662
+ *
663
+ * Since the position of overwriting tokens (token in `redef` that overwrite tokens in the copied language)
664
+ * doesn't matter, they can technically be in any order. However, this can be confusing to others that trying to
665
+ * understand the language definition because, normally, the order of tokens matters in Prism grammars.
666
+ *
667
+ * Therefore, it is encouraged to order overwriting tokens according to the positions of the overwritten tokens.
668
+ * Furthermore, all non-overwriting tokens should be placed after the overwriting ones.
669
+ *
670
+ * @param {string} id The id of the language to extend. This has to be a key in `Prism.languages`.
671
+ * @param {Grammar} redef The new tokens to append.
672
+ * @returns {Grammar} The new language created.
673
+ * @public
674
+ * @example
675
+ * Prism.languages['css-with-colors'] = Prism.languages.extend('css', {
676
+ * // Prism.languages.css already has a 'comment' token, so this token will overwrite CSS' 'comment' token
677
+ * // at its original position
678
+ * 'comment': { ... },
679
+ * // CSS doesn't have a 'color' token, so this token will be appended
680
+ * 'color': /\b(?:red|green|blue)\b/
681
+ * });
682
+ */
683
+ extend: function (id, redef) {
684
+ var lang = _.util.clone(_.languages[id]);
685
+
686
+ for (var key in redef) {
687
+ lang[key] = redef[key];
688
+ }
689
+
690
+ return lang;
691
+ },
692
+
693
+ /**
694
+ * Inserts tokens _before_ another token in a language definition or any other grammar.
695
+ *
696
+ * ## Usage
697
+ *
698
+ * This helper method makes it easy to modify existing languages. For example, the CSS language definition
699
+ * not only defines CSS highlighting for CSS documents, but also needs to define highlighting for CSS embedded
700
+ * in HTML through `<style>` elements. To do this, it needs to modify `Prism.languages.markup` and add the
701
+ * appropriate tokens. However, `Prism.languages.markup` is a regular JavaScript object literal, so if you do
702
+ * this:
703
+ *
704
+ * ```js
705
+ * Prism.languages.markup.style = {
706
+ * // token
707
+ * };
708
+ * ```
709
+ *
710
+ * then the `style` token will be added (and processed) at the end. `insertBefore` allows you to insert tokens
711
+ * before existing tokens. For the CSS example above, you would use it like this:
712
+ *
713
+ * ```js
714
+ * Prism.languages.insertBefore('markup', 'cdata', {
715
+ * 'style': {
716
+ * // token
717
+ * }
718
+ * });
719
+ * ```
720
+ *
721
+ * ## Special cases
722
+ *
723
+ * If the grammars of `inside` and `insert` have tokens with the same name, the tokens in `inside`'s grammar
724
+ * will be ignored.
725
+ *
726
+ * This behavior can be used to insert tokens after `before`:
727
+ *
728
+ * ```js
729
+ * Prism.languages.insertBefore('markup', 'comment', {
730
+ * 'comment': Prism.languages.markup.comment,
731
+ * // tokens after 'comment'
732
+ * });
733
+ * ```
734
+ *
735
+ * ## Limitations
736
+ *
737
+ * The main problem `insertBefore` has to solve is iteration order. Since ES2015, the iteration order for object
738
+ * properties is guaranteed to be the insertion order (except for integer keys) but some browsers behave
739
+ * differently when keys are deleted and re-inserted. So `insertBefore` can't be implemented by temporarily
740
+ * deleting properties which is necessary to insert at arbitrary positions.
741
+ *
742
+ * To solve this problem, `insertBefore` doesn't actually insert the given tokens into the target object.
743
+ * Instead, it will create a new object and replace all references to the target object with the new one. This
744
+ * can be done without temporarily deleting properties, so the iteration order is well-defined.
745
+ *
746
+ * However, only references that can be reached from `Prism.languages` or `insert` will be replaced. I.e. if
747
+ * you hold the target object in a variable, then the value of the variable will not change.
748
+ *
749
+ * ```js
750
+ * var oldMarkup = Prism.languages.markup;
751
+ * var newMarkup = Prism.languages.insertBefore('markup', 'comment', { ... });
752
+ *
753
+ * assert(oldMarkup !== Prism.languages.markup);
754
+ * assert(newMarkup === Prism.languages.markup);
755
+ * ```
756
+ *
757
+ * @param {string} inside The property of `root` (e.g. a language id in `Prism.languages`) that contains the
758
+ * object to be modified.
759
+ * @param {string} before The key to insert before.
760
+ * @param {Grammar} insert An object containing the key-value pairs to be inserted.
761
+ * @param {Object<string, any>} [root] The object containing `inside`, i.e. the object that contains the
762
+ * object to be modified.
763
+ *
764
+ * Defaults to `Prism.languages`.
765
+ * @returns {Grammar} The new grammar object.
766
+ * @public
767
+ */
768
+ insertBefore: function (inside, before, insert, root) {
769
+ root = root || /** @type {any} */ (_.languages);
770
+ var grammar = root[inside];
771
+ /** @type {Grammar} */
772
+ var ret = {};
773
+
774
+ for (var token in grammar) {
775
+ if (grammar.hasOwnProperty(token)) {
776
+
777
+ if (token == before) {
778
+ for (var newToken in insert) {
779
+ if (insert.hasOwnProperty(newToken)) {
780
+ ret[newToken] = insert[newToken];
781
+ }
782
+ }
783
+ }
512
784
 
513
- for (var key in o) {
514
- if (o.hasOwnProperty(key)) {
515
- clone[key] = deepClone(o[key], visited);
785
+ // Do not insert token which also occur in insert. See #1525
786
+ if (!insert.hasOwnProperty(token)) {
787
+ ret[token] = grammar[token];
516
788
  }
517
789
  }
790
+ }
518
791
 
519
- return /** @type {any} */ (clone);
792
+ var old = root[inside];
793
+ root[inside] = ret;
520
794
 
521
- case 'Array':
522
- id = _.util.objId(o);
523
- if (visited[id]) {
524
- return visited[id];
795
+ // Update references in other language definitions
796
+ _.languages.DFS(_.languages, function (key, value) {
797
+ if (value === old && key != inside) {
798
+ this[key] = ret;
525
799
  }
526
- clone = [];
527
- visited[id] = clone;
800
+ });
528
801
 
529
- (/** @type {Array} */(/** @type {any} */(o))).forEach(function (v, i) {
530
- clone[i] = deepClone(v, visited);
531
- });
802
+ return ret;
803
+ },
532
804
 
533
- return /** @type {any} */ (clone);
805
+ // Traverse a language definition with Depth First Search
806
+ DFS: function DFS(o, callback, type, visited) {
807
+ visited = visited || {};
534
808
 
535
- default:
536
- return o;
537
- }
538
- },
809
+ var objId = _.util.objId;
539
810
 
540
- /**
541
- * Returns the Prism language of the given element set by a `language-xxxx` or `lang-xxxx` class.
542
- *
543
- * If no language is set for the element or the element is `null` or `undefined`, `none` will be returned.
544
- *
545
- * @param {Element} element
546
- * @returns {string}
547
- */
548
- getLanguage: function (element) {
549
- while (element && !lang.test(element.className)) {
550
- element = element.parentElement;
551
- }
552
- if (element) {
553
- return (element.className.match(lang) || [, 'none'])[1].toLowerCase();
554
- }
555
- return 'none';
556
- },
811
+ for (var i in o) {
812
+ if (o.hasOwnProperty(i)) {
813
+ callback.call(o, i, o[i], type || i);
557
814
 
558
- /**
559
- * Returns the script element that is currently executing.
560
- *
561
- * This does __not__ work for line script element.
562
- *
563
- * @returns {HTMLScriptElement | null}
564
- */
565
- currentScript: function () {
566
- if (typeof document === 'undefined') {
567
- return null;
568
- }
569
- if ('currentScript' in document && 1 < 2 /* hack to trip TS' flow analysis */) {
570
- return /** @type {any} */ (document.currentScript);
571
- }
815
+ var property = o[i];
816
+ var propertyType = _.util.type(property);
572
817
 
573
- // IE11 workaround
574
- // we'll get the src of the current script by parsing IE11's error stack trace
575
- // this will not work for inline scripts
576
-
577
- try {
578
- throw new Error();
579
- } catch (err) {
580
- // Get file src url from stack. Specifically works with the format of stack traces in IE.
581
- // A stack will look like this:
582
- //
583
- // Error
584
- // at _.util.currentScript (http://localhost/components/prism-core.js:119:5)
585
- // at Global code (http://localhost/components/prism-core.js:606:1)
586
-
587
- var src = (/at [^(\r\n]*\((.*):.+:.+\)$/i.exec(err.stack) || [])[1];
588
- if (src) {
589
- var scripts = document.getElementsByTagName('script');
590
- for (var i in scripts) {
591
- if (scripts[i].src == src) {
592
- return scripts[i];
818
+ if (propertyType === 'Object' && !visited[objId(property)]) {
819
+ visited[objId(property)] = true;
820
+ DFS(property, callback, null, visited);
821
+ } else if (propertyType === 'Array' && !visited[objId(property)]) {
822
+ visited[objId(property)] = true;
823
+ DFS(property, callback, i, visited);
593
824
  }
594
825
  }
595
826
  }
596
- return null;
597
827
  }
598
828
  },
599
829
 
830
+ plugins: {},
831
+
600
832
  /**
601
- * Returns whether a given class is active for `element`.
833
+ * This is the most high-level function in Prism’s API.
834
+ * It fetches all the elements that have a `.language-xxxx` class and then calls {@link Prism.highlightElement} on
835
+ * each one of them.
602
836
  *
603
- * The class can be activated if `element` or one of its ancestors has the given class and it can be deactivated
604
- * if `element` or one of its ancestors has the negated version of the given class. The _negated version_ of the
605
- * given class is just the given class with a `no-` prefix.
837
+ * This is equivalent to `Prism.highlightAllUnder(document, async, callback)`.
606
838
  *
607
- * Whether the class is active is determined by the closest ancestor of `element` (where `element` itself is
608
- * closest ancestor) that has the given class or the negated version of it. If neither `element` nor any of its
609
- * ancestors have the given class or the negated version of it, then the default activation will be returned.
610
- *
611
- * In the paradoxical situation where the closest ancestor contains __both__ the given class and the negated
612
- * version of it, the class is considered active.
613
- *
614
- * @param {Element} element
615
- * @param {string} className
616
- * @param {boolean} [defaultActivation=false]
617
- * @returns {boolean}
839
+ * @param {boolean} [async=false] Same as in {@link Prism.highlightAllUnder}.
840
+ * @param {HighlightCallback} [callback] Same as in {@link Prism.highlightAllUnder}.
841
+ * @memberof Prism
842
+ * @public
618
843
  */
619
- isActive: function (element, className, defaultActivation) {
620
- var no = 'no-' + className;
621
-
622
- while (element) {
623
- var classList = element.classList;
624
- if (classList.contains(className)) {
625
- return true;
626
- }
627
- if (classList.contains(no)) {
628
- return false;
629
- }
630
- element = element.parentElement;
631
- }
632
- return !!defaultActivation;
633
- }
634
- },
844
+ highlightAll: function (async, callback) {
845
+ _.highlightAllUnder(document, async, callback);
846
+ },
635
847
 
636
- /**
637
- * This namespace contains all currently loaded languages and the some helper functions to create and modify languages.
638
- *
639
- * @namespace
640
- * @memberof Prism
641
- * @public
642
- */
643
- languages: {
644
848
  /**
645
- * Creates a deep copy of the language with the given id and appends the given tokens.
849
+ * Fetches all the descendants of `container` that have a `.language-xxxx` class and then calls
850
+ * {@link Prism.highlightElement} on each one of them.
646
851
  *
647
- * If a token in `redef` also appears in the copied language, then the existing token in the copied language
648
- * will be overwritten at its original position.
852
+ * The following hooks will be run:
853
+ * 1. `before-highlightall`
854
+ * 2. `before-all-elements-highlight`
855
+ * 3. All hooks of {@link Prism.highlightElement} for each element.
649
856
  *
650
- * ## Best practices
651
- *
652
- * Since the position of overwriting tokens (token in `redef` that overwrite tokens in the copied language)
653
- * doesn't matter, they can technically be in any order. However, this can be confusing to others that trying to
654
- * understand the language definition because, normally, the order of tokens matters in Prism grammars.
655
- *
656
- * Therefore, it is encouraged to order overwriting tokens according to the positions of the overwritten tokens.
657
- * Furthermore, all non-overwriting tokens should be placed after the overwriting ones.
658
- *
659
- * @param {string} id The id of the language to extend. This has to be a key in `Prism.languages`.
660
- * @param {Grammar} redef The new tokens to append.
661
- * @returns {Grammar} The new language created.
857
+ * @param {ParentNode} container The root element, whose descendants that have a `.language-xxxx` class will be highlighted.
858
+ * @param {boolean} [async=false] Whether each element is to be highlighted asynchronously using Web Workers.
859
+ * @param {HighlightCallback} [callback] An optional callback to be invoked on each element after its highlighting is done.
860
+ * @memberof Prism
662
861
  * @public
663
- * @example
664
- * Prism.languages['css-with-colors'] = Prism.languages.extend('css', {
665
- * // Prism.languages.css already has a 'comment' token, so this token will overwrite CSS' 'comment' token
666
- * // at its original position
667
- * 'comment': { ... },
668
- * // CSS doesn't have a 'color' token, so this token will be appended
669
- * 'color': /\b(?:red|green|blue)\b/
670
- * });
671
862
  */
672
- extend: function (id, redef) {
673
- var lang = _.util.clone(_.languages[id]);
863
+ highlightAllUnder: function (container, async, callback) {
864
+ var env = {
865
+ callback: callback,
866
+ container: container,
867
+ selector: 'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'
868
+ };
674
869
 
675
- for (var key in redef) {
676
- lang[key] = redef[key];
677
- }
870
+ _.hooks.run('before-highlightall', env);
871
+
872
+ env.elements = Array.prototype.slice.apply(env.container.querySelectorAll(env.selector));
873
+
874
+ _.hooks.run('before-all-elements-highlight', env);
678
875
 
679
- return lang;
876
+ for (var i = 0, element; (element = env.elements[i++]);) {
877
+ _.highlightElement(element, async === true, env.callback);
878
+ }
680
879
  },
681
880
 
682
881
  /**
683
- * Inserts tokens _before_ another token in a language definition or any other grammar.
684
- *
685
- * ## Usage
686
- *
687
- * This helper method makes it easy to modify existing languages. For example, the CSS language definition
688
- * not only defines CSS highlighting for CSS documents, but also needs to define highlighting for CSS embedded
689
- * in HTML through `<style>` elements. To do this, it needs to modify `Prism.languages.markup` and add the
690
- * appropriate tokens. However, `Prism.languages.markup` is a regular JavaScript object literal, so if you do
691
- * this:
692
- *
693
- * ```js
694
- * Prism.languages.markup.style = {
695
- * // token
696
- * };
697
- * ```
698
- *
699
- * then the `style` token will be added (and processed) at the end. `insertBefore` allows you to insert tokens
700
- * before existing tokens. For the CSS example above, you would use it like this:
701
- *
702
- * ```js
703
- * Prism.languages.insertBefore('markup', 'cdata', {
704
- * 'style': {
705
- * // token
706
- * }
707
- * });
708
- * ```
709
- *
710
- * ## Special cases
882
+ * Highlights the code inside a single element.
711
883
  *
712
- * If the grammars of `inside` and `insert` have tokens with the same name, the tokens in `inside`'s grammar
713
- * will be ignored.
884
+ * The following hooks will be run:
885
+ * 1. `before-sanity-check`
886
+ * 2. `before-highlight`
887
+ * 3. All hooks of {@link Prism.highlight}. These hooks will be run by an asynchronous worker if `async` is `true`.
888
+ * 4. `before-insert`
889
+ * 5. `after-highlight`
890
+ * 6. `complete`
714
891
  *
715
- * This behavior can be used to insert tokens after `before`:
892
+ * Some the above hooks will be skipped if the element doesn't contain any text or there is no grammar loaded for
893
+ * the element's language.
716
894
  *
717
- * ```js
718
- * Prism.languages.insertBefore('markup', 'comment', {
719
- * 'comment': Prism.languages.markup.comment,
720
- * // tokens after 'comment'
721
- * });
722
- * ```
723
- *
724
- * ## Limitations
725
- *
726
- * The main problem `insertBefore` has to solve is iteration order. Since ES2015, the iteration order for object
727
- * properties is guaranteed to be the insertion order (except for integer keys) but some browsers behave
728
- * differently when keys are deleted and re-inserted. So `insertBefore` can't be implemented by temporarily
729
- * deleting properties which is necessary to insert at arbitrary positions.
730
- *
731
- * To solve this problem, `insertBefore` doesn't actually insert the given tokens into the target object.
732
- * Instead, it will create a new object and replace all references to the target object with the new one. This
733
- * can be done without temporarily deleting properties, so the iteration order is well-defined.
734
- *
735
- * However, only references that can be reached from `Prism.languages` or `insert` will be replaced. I.e. if
736
- * you hold the target object in a variable, then the value of the variable will not change.
737
- *
738
- * ```js
739
- * var oldMarkup = Prism.languages.markup;
740
- * var newMarkup = Prism.languages.insertBefore('markup', 'comment', { ... });
895
+ * @param {Element} element The element containing the code.
896
+ * It must have a class of `language-xxxx` to be processed, where `xxxx` is a valid language identifier.
897
+ * @param {boolean} [async=false] Whether the element is to be highlighted asynchronously using Web Workers
898
+ * to improve performance and avoid blocking the UI when highlighting very large chunks of code. This option is
899
+ * [disabled by default](https://prismjs.com/faq.html#why-is-asynchronous-highlighting-disabled-by-default).
741
900
  *
742
- * assert(oldMarkup !== Prism.languages.markup);
743
- * assert(newMarkup === Prism.languages.markup);
744
- * ```
745
- *
746
- * @param {string} inside The property of `root` (e.g. a language id in `Prism.languages`) that contains the
747
- * object to be modified.
748
- * @param {string} before The key to insert before.
749
- * @param {Grammar} insert An object containing the key-value pairs to be inserted.
750
- * @param {Object<string, any>} [root] The object containing `inside`, i.e. the object that contains the
751
- * object to be modified.
752
- *
753
- * Defaults to `Prism.languages`.
754
- * @returns {Grammar} The new grammar object.
901
+ * Note: All language definitions required to highlight the code must be included in the main `prism.js` file for
902
+ * asynchronous highlighting to work. You can build your own bundle on the
903
+ * [Download page](https://prismjs.com/download.html).
904
+ * @param {HighlightCallback} [callback] An optional callback to be invoked after the highlighting is done.
905
+ * Mostly useful when `async` is `true`, since in that case, the highlighting is done asynchronously.
906
+ * @memberof Prism
755
907
  * @public
756
908
  */
757
- insertBefore: function (inside, before, insert, root) {
758
- root = root || /** @type {any} */ (_.languages);
759
- var grammar = root[inside];
760
- /** @type {Grammar} */
761
- var ret = {};
762
-
763
- for (var token in grammar) {
764
- if (grammar.hasOwnProperty(token)) {
765
-
766
- if (token == before) {
767
- for (var newToken in insert) {
768
- if (insert.hasOwnProperty(newToken)) {
769
- ret[newToken] = insert[newToken];
770
- }
771
- }
772
- }
773
-
774
- // Do not insert token which also occur in insert. See #1525
775
- if (!insert.hasOwnProperty(token)) {
776
- ret[token] = grammar[token];
777
- }
778
- }
909
+ highlightElement: function (element, async, callback) {
910
+ // Find language
911
+ var language = _.util.getLanguage(element);
912
+ var grammar = _.languages[language];
913
+
914
+ // Set language on the element, if not present
915
+ element.className = element.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language;
916
+
917
+ // Set language on the parent, for styling
918
+ var parent = element.parentElement;
919
+ if (parent && parent.nodeName.toLowerCase() === 'pre') {
920
+ parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language;
779
921
  }
780
922
 
781
- var old = root[inside];
782
- root[inside] = ret;
923
+ var code = element.textContent;
783
924
 
784
- // Update references in other language definitions
785
- _.languages.DFS(_.languages, function(key, value) {
786
- if (value === old && key != inside) {
787
- this[key] = ret;
788
- }
789
- });
790
-
791
- return ret;
792
- },
793
-
794
- // Traverse a language definition with Depth First Search
795
- DFS: function DFS(o, callback, type, visited) {
796
- visited = visited || {};
925
+ var env = {
926
+ element: element,
927
+ language: language,
928
+ grammar: grammar,
929
+ code: code
930
+ };
797
931
 
798
- var objId = _.util.objId;
932
+ function insertHighlightedCode(highlightedCode) {
933
+ env.highlightedCode = highlightedCode;
799
934
 
800
- for (var i in o) {
801
- if (o.hasOwnProperty(i)) {
802
- callback.call(o, i, o[i], type || i);
935
+ _.hooks.run('before-insert', env);
803
936
 
804
- var property = o[i],
805
- propertyType = _.util.type(property);
937
+ env.element.innerHTML = env.highlightedCode;
806
938
 
807
- if (propertyType === 'Object' && !visited[objId(property)]) {
808
- visited[objId(property)] = true;
809
- DFS(property, callback, null, visited);
810
- }
811
- else if (propertyType === 'Array' && !visited[objId(property)]) {
812
- visited[objId(property)] = true;
813
- DFS(property, callback, i, visited);
814
- }
815
- }
939
+ _.hooks.run('after-highlight', env);
940
+ _.hooks.run('complete', env);
941
+ callback && callback.call(env.element);
816
942
  }
817
- }
818
- },
819
-
820
- plugins: {},
821
-
822
- /**
823
- * This is the most high-level function in Prism’s API.
824
- * It fetches all the elements that have a `.language-xxxx` class and then calls {@link Prism.highlightElement} on
825
- * each one of them.
826
- *
827
- * This is equivalent to `Prism.highlightAllUnder(document, async, callback)`.
828
- *
829
- * @param {boolean} [async=false] Same as in {@link Prism.highlightAllUnder}.
830
- * @param {HighlightCallback} [callback] Same as in {@link Prism.highlightAllUnder}.
831
- * @memberof Prism
832
- * @public
833
- */
834
- highlightAll: function(async, callback) {
835
- _.highlightAllUnder(document, async, callback);
836
- },
837
-
838
- /**
839
- * Fetches all the descendants of `container` that have a `.language-xxxx` class and then calls
840
- * {@link Prism.highlightElement} on each one of them.
841
- *
842
- * The following hooks will be run:
843
- * 1. `before-highlightall`
844
- * 2. `before-all-elements-highlight`
845
- * 3. All hooks of {@link Prism.highlightElement} for each element.
846
- *
847
- * @param {ParentNode} container The root element, whose descendants that have a `.language-xxxx` class will be highlighted.
848
- * @param {boolean} [async=false] Whether each element is to be highlighted asynchronously using Web Workers.
849
- * @param {HighlightCallback} [callback] An optional callback to be invoked on each element after its highlighting is done.
850
- * @memberof Prism
851
- * @public
852
- */
853
- highlightAllUnder: function(container, async, callback) {
854
- var env = {
855
- callback: callback,
856
- container: container,
857
- selector: 'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'
858
- };
859
-
860
- _.hooks.run('before-highlightall', env);
861
-
862
- env.elements = Array.prototype.slice.apply(env.container.querySelectorAll(env.selector));
863
943
 
864
- _.hooks.run('before-all-elements-highlight', env);
944
+ _.hooks.run('before-sanity-check', env);
865
945
 
866
- for (var i = 0, element; element = env.elements[i++];) {
867
- _.highlightElement(element, async === true, env.callback);
868
- }
869
- },
870
-
871
- /**
872
- * Highlights the code inside a single element.
873
- *
874
- * The following hooks will be run:
875
- * 1. `before-sanity-check`
876
- * 2. `before-highlight`
877
- * 3. All hooks of {@link Prism.highlight}. These hooks will be run by an asynchronous worker if `async` is `true`.
878
- * 4. `before-insert`
879
- * 5. `after-highlight`
880
- * 6. `complete`
881
- *
882
- * Some the above hooks will be skipped if the element doesn't contain any text or there is no grammar loaded for
883
- * the element's language.
884
- *
885
- * @param {Element} element The element containing the code.
886
- * It must have a class of `language-xxxx` to be processed, where `xxxx` is a valid language identifier.
887
- * @param {boolean} [async=false] Whether the element is to be highlighted asynchronously using Web Workers
888
- * to improve performance and avoid blocking the UI when highlighting very large chunks of code. This option is
889
- * [disabled by default](https://prismjs.com/faq.html#why-is-asynchronous-highlighting-disabled-by-default).
890
- *
891
- * Note: All language definitions required to highlight the code must be included in the main `prism.js` file for
892
- * asynchronous highlighting to work. You can build your own bundle on the
893
- * [Download page](https://prismjs.com/download.html).
894
- * @param {HighlightCallback} [callback] An optional callback to be invoked after the highlighting is done.
895
- * Mostly useful when `async` is `true`, since in that case, the highlighting is done asynchronously.
896
- * @memberof Prism
897
- * @public
898
- */
899
- highlightElement: function(element, async, callback) {
900
- // Find language
901
- var language = _.util.getLanguage(element);
902
- var grammar = _.languages[language];
903
-
904
- // Set language on the element, if not present
905
- element.className = element.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language;
906
-
907
- // Set language on the parent, for styling
908
- var parent = element.parentElement;
909
- if (parent && parent.nodeName.toLowerCase() === 'pre') {
910
- parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language;
911
- }
946
+ // plugins may change/add the parent/element
947
+ parent = env.element.parentElement;
948
+ if (parent && parent.nodeName.toLowerCase() === 'pre' && !parent.hasAttribute('tabindex')) {
949
+ parent.setAttribute('tabindex', '0');
950
+ }
912
951
 
913
- var code = element.textContent;
952
+ if (!env.code) {
953
+ _.hooks.run('complete', env);
954
+ callback && callback.call(env.element);
955
+ return;
956
+ }
914
957
 
915
- var env = {
916
- element: element,
917
- language: language,
918
- grammar: grammar,
919
- code: code
920
- };
958
+ _.hooks.run('before-highlight', env);
921
959
 
922
- function insertHighlightedCode(highlightedCode) {
923
- env.highlightedCode = highlightedCode;
960
+ if (!env.grammar) {
961
+ insertHighlightedCode(_.util.encode(env.code));
962
+ return;
963
+ }
924
964
 
925
- _.hooks.run('before-insert', env);
965
+ if (async && _self.Worker) {
966
+ var worker = new Worker(_.filename);
926
967
 
927
- env.element.innerHTML = env.highlightedCode;
968
+ worker.onmessage = function (evt) {
969
+ insertHighlightedCode(evt.data);
970
+ };
928
971
 
929
- _.hooks.run('after-highlight', env);
930
- _.hooks.run('complete', env);
931
- callback && callback.call(env.element);
932
- }
972
+ worker.postMessage(JSON.stringify({
973
+ language: env.language,
974
+ code: env.code,
975
+ immediateClose: true
976
+ }));
977
+ } else {
978
+ insertHighlightedCode(_.highlight(env.code, env.grammar, env.language));
979
+ }
980
+ },
933
981
 
934
- _.hooks.run('before-sanity-check', env);
982
+ /**
983
+ * Low-level function, only use if you know what you’re doing. It accepts a string of text as input
984
+ * and the language definitions to use, and returns a string with the HTML produced.
985
+ *
986
+ * The following hooks will be run:
987
+ * 1. `before-tokenize`
988
+ * 2. `after-tokenize`
989
+ * 3. `wrap`: On each {@link Token}.
990
+ *
991
+ * @param {string} text A string with the code to be highlighted.
992
+ * @param {Grammar} grammar An object containing the tokens to use.
993
+ *
994
+ * Usually a language definition like `Prism.languages.markup`.
995
+ * @param {string} language The name of the language definition passed to `grammar`.
996
+ * @returns {string} The highlighted HTML.
997
+ * @memberof Prism
998
+ * @public
999
+ * @example
1000
+ * Prism.highlight('var foo = true;', Prism.languages.javascript, 'javascript');
1001
+ */
1002
+ highlight: function (text, grammar, language) {
1003
+ var env = {
1004
+ code: text,
1005
+ grammar: grammar,
1006
+ language: language
1007
+ };
1008
+ _.hooks.run('before-tokenize', env);
1009
+ env.tokens = _.tokenize(env.code, env.grammar);
1010
+ _.hooks.run('after-tokenize', env);
1011
+ return Token.stringify(_.util.encode(env.tokens), env.language);
1012
+ },
935
1013
 
936
- if (!env.code) {
937
- _.hooks.run('complete', env);
938
- callback && callback.call(env.element);
939
- return;
940
- }
1014
+ /**
1015
+ * This is the heart of Prism, and the most low-level function you can use. It accepts a string of text as input
1016
+ * and the language definitions to use, and returns an array with the tokenized code.
1017
+ *
1018
+ * When the language definition includes nested tokens, the function is called recursively on each of these tokens.
1019
+ *
1020
+ * This method could be useful in other contexts as well, as a very crude parser.
1021
+ *
1022
+ * @param {string} text A string with the code to be highlighted.
1023
+ * @param {Grammar} grammar An object containing the tokens to use.
1024
+ *
1025
+ * Usually a language definition like `Prism.languages.markup`.
1026
+ * @returns {TokenStream} An array of strings and tokens, a token stream.
1027
+ * @memberof Prism
1028
+ * @public
1029
+ * @example
1030
+ * let code = `var foo = 0;`;
1031
+ * let tokens = Prism.tokenize(code, Prism.languages.javascript);
1032
+ * tokens.forEach(token => {
1033
+ * if (token instanceof Prism.Token && token.type === 'number') {
1034
+ * console.log(`Found numeric literal: ${token.content}`);
1035
+ * }
1036
+ * });
1037
+ */
1038
+ tokenize: function (text, grammar) {
1039
+ var rest = grammar.rest;
1040
+ if (rest) {
1041
+ for (var token in rest) {
1042
+ grammar[token] = rest[token];
1043
+ }
941
1044
 
942
- _.hooks.run('before-highlight', env);
1045
+ delete grammar.rest;
1046
+ }
943
1047
 
944
- if (!env.grammar) {
945
- insertHighlightedCode(_.util.encode(env.code));
946
- return;
947
- }
1048
+ var tokenList = new LinkedList();
1049
+ addAfter(tokenList, tokenList.head, text);
948
1050
 
949
- if (async && _self.Worker) {
950
- var worker = new Worker(_.filename);
1051
+ matchGrammar(text, tokenList, grammar, tokenList.head, 0);
951
1052
 
952
- worker.onmessage = function(evt) {
953
- insertHighlightedCode(evt.data);
954
- };
1053
+ return toArray(tokenList);
1054
+ },
955
1055
 
956
- worker.postMessage(JSON.stringify({
957
- language: env.language,
958
- code: env.code,
959
- immediateClose: true
960
- }));
961
- }
962
- else {
963
- insertHighlightedCode(_.highlight(env.code, env.grammar, env.language));
964
- }
965
- },
1056
+ /**
1057
+ * @namespace
1058
+ * @memberof Prism
1059
+ * @public
1060
+ */
1061
+ hooks: {
1062
+ all: {},
1063
+
1064
+ /**
1065
+ * Adds the given callback to the list of callbacks for the given hook.
1066
+ *
1067
+ * The callback will be invoked when the hook it is registered for is run.
1068
+ * Hooks are usually directly run by a highlight function but you can also run hooks yourself.
1069
+ *
1070
+ * One callback function can be registered to multiple hooks and the same hook multiple times.
1071
+ *
1072
+ * @param {string} name The name of the hook.
1073
+ * @param {HookCallback} callback The callback function which is given environment variables.
1074
+ * @public
1075
+ */
1076
+ add: function (name, callback) {
1077
+ var hooks = _.hooks.all;
1078
+
1079
+ hooks[name] = hooks[name] || [];
1080
+
1081
+ hooks[name].push(callback);
1082
+ },
966
1083
 
967
- /**
968
- * Low-level function, only use if you know what you’re doing. It accepts a string of text as input
969
- * and the language definitions to use, and returns a string with the HTML produced.
970
- *
971
- * The following hooks will be run:
972
- * 1. `before-tokenize`
973
- * 2. `after-tokenize`
974
- * 3. `wrap`: On each {@link Token}.
975
- *
976
- * @param {string} text A string with the code to be highlighted.
977
- * @param {Grammar} grammar An object containing the tokens to use.
978
- *
979
- * Usually a language definition like `Prism.languages.markup`.
980
- * @param {string} language The name of the language definition passed to `grammar`.
981
- * @returns {string} The highlighted HTML.
982
- * @memberof Prism
983
- * @public
984
- * @example
985
- * Prism.highlight('var foo = true;', Prism.languages.javascript, 'javascript');
986
- */
987
- highlight: function (text, grammar, language) {
988
- var env = {
989
- code: text,
990
- grammar: grammar,
991
- language: language
992
- };
993
- _.hooks.run('before-tokenize', env);
994
- env.tokens = _.tokenize(env.code, env.grammar);
995
- _.hooks.run('after-tokenize', env);
996
- return Token.stringify(_.util.encode(env.tokens), env.language);
997
- },
1084
+ /**
1085
+ * Runs a hook invoking all registered callbacks with the given environment variables.
1086
+ *
1087
+ * Callbacks will be invoked synchronously and in the order in which they were registered.
1088
+ *
1089
+ * @param {string} name The name of the hook.
1090
+ * @param {Object<string, any>} env The environment variables of the hook passed to all callbacks registered.
1091
+ * @public
1092
+ */
1093
+ run: function (name, env) {
1094
+ var callbacks = _.hooks.all[name];
1095
+
1096
+ if (!callbacks || !callbacks.length) {
1097
+ return;
1098
+ }
998
1099
 
999
- /**
1000
- * This is the heart of Prism, and the most low-level function you can use. It accepts a string of text as input
1001
- * and the language definitions to use, and returns an array with the tokenized code.
1002
- *
1003
- * When the language definition includes nested tokens, the function is called recursively on each of these tokens.
1004
- *
1005
- * This method could be useful in other contexts as well, as a very crude parser.
1006
- *
1007
- * @param {string} text A string with the code to be highlighted.
1008
- * @param {Grammar} grammar An object containing the tokens to use.
1009
- *
1010
- * Usually a language definition like `Prism.languages.markup`.
1011
- * @returns {TokenStream} An array of strings and tokens, a token stream.
1012
- * @memberof Prism
1013
- * @public
1014
- * @example
1015
- * let code = `var foo = 0;`;
1016
- * let tokens = Prism.tokenize(code, Prism.languages.javascript);
1017
- * tokens.forEach(token => {
1018
- * if (token instanceof Prism.Token && token.type === 'number') {
1019
- * console.log(`Found numeric literal: ${token.content}`);
1020
- * }
1021
- * });
1022
- */
1023
- tokenize: function(text, grammar) {
1024
- var rest = grammar.rest;
1025
- if (rest) {
1026
- for (var token in rest) {
1027
- grammar[token] = rest[token];
1100
+ for (var i = 0, callback; (callback = callbacks[i++]);) {
1101
+ callback(env);
1102
+ }
1028
1103
  }
1104
+ },
1029
1105
 
1030
- delete grammar.rest;
1031
- }
1032
-
1033
- var tokenList = new LinkedList();
1034
- addAfter(tokenList, tokenList.head, text);
1106
+ Token: Token
1107
+ };
1108
+ _self.Prism = _;
1035
1109
 
1036
- matchGrammar(text, tokenList, grammar, tokenList.head, 0);
1037
1110
 
1038
- return toArray(tokenList);
1039
- },
1111
+ // Typescript note:
1112
+ // The following can be used to import the Token type in JSDoc:
1113
+ //
1114
+ // @typedef {InstanceType<import("./prism-core")["Token"]>} Token
1040
1115
 
1041
1116
  /**
1042
- * @namespace
1043
- * @memberof Prism
1117
+ * Creates a new token.
1118
+ *
1119
+ * @param {string} type See {@link Token#type type}
1120
+ * @param {string | TokenStream} content See {@link Token#content content}
1121
+ * @param {string|string[]} [alias] The alias(es) of the token.
1122
+ * @param {string} [matchedStr=""] A copy of the full string this token was created from.
1123
+ * @class
1124
+ * @global
1044
1125
  * @public
1045
1126
  */
1046
- hooks: {
1047
- all: {},
1048
-
1127
+ function Token(type, content, alias, matchedStr) {
1049
1128
  /**
1050
- * Adds the given callback to the list of callbacks for the given hook.
1129
+ * The type of the token.
1051
1130
  *
1052
- * The callback will be invoked when the hook it is registered for is run.
1053
- * Hooks are usually directly run by a highlight function but you can also run hooks yourself.
1131
+ * This is usually the key of a pattern in a {@link Grammar}.
1054
1132
  *
1055
- * One callback function can be registered to multiple hooks and the same hook multiple times.
1056
- *
1057
- * @param {string} name The name of the hook.
1058
- * @param {HookCallback} callback The callback function which is given environment variables.
1133
+ * @type {string}
1134
+ * @see GrammarToken
1059
1135
  * @public
1060
1136
  */
1061
- add: function (name, callback) {
1062
- var hooks = _.hooks.all;
1063
-
1064
- hooks[name] = hooks[name] || [];
1065
-
1066
- hooks[name].push(callback);
1067
- },
1068
-
1137
+ this.type = type;
1069
1138
  /**
1070
- * Runs a hook invoking all registered callbacks with the given environment variables.
1139
+ * The strings or tokens contained by this token.
1071
1140
  *
1072
- * Callbacks will be invoked synchronously and in the order in which they were registered.
1141
+ * This will be a token stream if the pattern matched also defined an `inside` grammar.
1073
1142
  *
1074
- * @param {string} name The name of the hook.
1075
- * @param {Object<string, any>} env The environment variables of the hook passed to all callbacks registered.
1143
+ * @type {string | TokenStream}
1076
1144
  * @public
1077
1145
  */
1078
- run: function (name, env) {
1079
- var callbacks = _.hooks.all[name];
1080
-
1081
- if (!callbacks || !callbacks.length) {
1082
- return;
1083
- }
1084
-
1085
- for (var i=0, callback; callback = callbacks[i++];) {
1086
- callback(env);
1087
- }
1088
- }
1089
- },
1090
-
1091
- Token: Token
1092
- };
1093
- _self.Prism = _;
1094
-
1095
-
1096
- // Typescript note:
1097
- // The following can be used to import the Token type in JSDoc:
1098
- //
1099
- // @typedef {InstanceType<import("./prism-core")["Token"]>} Token
1100
-
1101
- /**
1102
- * Creates a new token.
1103
- *
1104
- * @param {string} type See {@link Token#type type}
1105
- * @param {string | TokenStream} content See {@link Token#content content}
1106
- * @param {string|string[]} [alias] The alias(es) of the token.
1107
- * @param {string} [matchedStr=""] A copy of the full string this token was created from.
1108
- * @class
1109
- * @global
1110
- * @public
1111
- */
1112
- function Token(type, content, alias, matchedStr) {
1146
+ this.content = content;
1147
+ /**
1148
+ * The alias(es) of the token.
1149
+ *
1150
+ * @type {string|string[]}
1151
+ * @see GrammarToken
1152
+ * @public
1153
+ */
1154
+ this.alias = alias;
1155
+ // Copy of the full string this token was created from
1156
+ this.length = (matchedStr || '').length | 0;
1157
+ }
1158
+
1113
1159
  /**
1114
- * The type of the token.
1160
+ * A token stream is an array of strings and {@link Token Token} objects.
1115
1161
  *
1116
- * This is usually the key of a pattern in a {@link Grammar}.
1162
+ * Token streams have to fulfill a few properties that are assumed by most functions (mostly internal ones) that process
1163
+ * them.
1117
1164
  *
1118
- * @type {string}
1119
- * @see GrammarToken
1120
- * @public
1121
- */
1122
- this.type = type;
1123
- /**
1124
- * The strings or tokens contained by this token.
1165
+ * 1. No adjacent strings.
1166
+ * 2. No empty strings.
1125
1167
  *
1126
- * This will be a token stream if the pattern matched also defined an `inside` grammar.
1168
+ * The only exception here is the token stream that only contains the empty string and nothing else.
1127
1169
  *
1128
- * @type {string | TokenStream}
1170
+ * @typedef {Array<string | Token>} TokenStream
1171
+ * @global
1129
1172
  * @public
1130
1173
  */
1131
- this.content = content;
1174
+
1132
1175
  /**
1133
- * The alias(es) of the token.
1176
+ * Converts the given token or token stream to an HTML representation.
1134
1177
  *
1135
- * @type {string|string[]}
1136
- * @see GrammarToken
1137
- * @public
1178
+ * The following hooks will be run:
1179
+ * 1. `wrap`: On each {@link Token}.
1180
+ *
1181
+ * @param {string | Token | TokenStream} o The token or token stream to be converted.
1182
+ * @param {string} language The name of current language.
1183
+ * @returns {string} The HTML representation of the token or token stream.
1184
+ * @memberof Token
1185
+ * @static
1138
1186
  */
1139
- this.alias = alias;
1140
- // Copy of the full string this token was created from
1141
- this.length = (matchedStr || '').length | 0;
1142
- }
1143
-
1144
- /**
1145
- * A token stream is an array of strings and {@link Token Token} objects.
1146
- *
1147
- * Token streams have to fulfill a few properties that are assumed by most functions (mostly internal ones) that process
1148
- * them.
1149
- *
1150
- * 1. No adjacent strings.
1151
- * 2. No empty strings.
1152
- *
1153
- * The only exception here is the token stream that only contains the empty string and nothing else.
1154
- *
1155
- * @typedef {Array<string | Token>} TokenStream
1156
- * @global
1157
- * @public
1158
- */
1159
-
1160
- /**
1161
- * Converts the given token or token stream to an HTML representation.
1162
- *
1163
- * The following hooks will be run:
1164
- * 1. `wrap`: On each {@link Token}.
1165
- *
1166
- * @param {string | Token | TokenStream} o The token or token stream to be converted.
1167
- * @param {string} language The name of current language.
1168
- * @returns {string} The HTML representation of the token or token stream.
1169
- * @memberof Token
1170
- * @static
1171
- */
1172
- Token.stringify = function stringify(o, language) {
1173
- if (typeof o == 'string') {
1174
- return o;
1175
- }
1176
- if (Array.isArray(o)) {
1177
- var s = '';
1178
- o.forEach(function (e) {
1179
- s += stringify(e, language);
1180
- });
1181
- return s;
1182
- }
1183
-
1184
- var env = {
1185
- type: o.type,
1186
- content: stringify(o.content, language),
1187
- tag: 'span',
1188
- classes: ['token', o.type],
1189
- attributes: {},
1190
- language: language
1191
- };
1192
-
1193
- var aliases = o.alias;
1194
- if (aliases) {
1195
- if (Array.isArray(aliases)) {
1196
- Array.prototype.push.apply(env.classes, aliases);
1197
- } else {
1198
- env.classes.push(aliases);
1187
+ Token.stringify = function stringify(o, language) {
1188
+ if (typeof o == 'string') {
1189
+ return o;
1190
+ }
1191
+ if (Array.isArray(o)) {
1192
+ var s = '';
1193
+ o.forEach(function (e) {
1194
+ s += stringify(e, language);
1195
+ });
1196
+ return s;
1199
1197
  }
1200
- }
1201
1198
 
1202
- _.hooks.run('wrap', env);
1199
+ var env = {
1200
+ type: o.type,
1201
+ content: stringify(o.content, language),
1202
+ tag: 'span',
1203
+ classes: ['token', o.type],
1204
+ attributes: {},
1205
+ language: language
1206
+ };
1203
1207
 
1204
- var attributes = '';
1205
- for (var name in env.attributes) {
1206
- attributes += ' ' + name + '="' + (env.attributes[name] || '').replace(/"/g, '&quot;') + '"';
1207
- }
1208
+ var aliases = o.alias;
1209
+ if (aliases) {
1210
+ if (Array.isArray(aliases)) {
1211
+ Array.prototype.push.apply(env.classes, aliases);
1212
+ } else {
1213
+ env.classes.push(aliases);
1214
+ }
1215
+ }
1208
1216
 
1209
- return '<' + env.tag + ' class="' + env.classes.join(' ') + '"' + attributes + '>' + env.content + '</' + env.tag + '>';
1210
- };
1217
+ _.hooks.run('wrap', env);
1211
1218
 
1212
- /**
1213
- * @param {string} text
1214
- * @param {LinkedList<string | Token>} tokenList
1215
- * @param {any} grammar
1216
- * @param {LinkedListNode<string | Token>} startNode
1217
- * @param {number} startPos
1218
- * @param {RematchOptions} [rematch]
1219
- * @returns {void}
1220
- * @private
1221
- *
1222
- * @typedef RematchOptions
1223
- * @property {string} cause
1224
- * @property {number} reach
1225
- */
1226
- function matchGrammar(text, tokenList, grammar, startNode, startPos, rematch) {
1227
- for (var token in grammar) {
1228
- if (!grammar.hasOwnProperty(token) || !grammar[token]) {
1229
- continue;
1219
+ var attributes = '';
1220
+ for (var name in env.attributes) {
1221
+ attributes += ' ' + name + '="' + (env.attributes[name] || '').replace(/"/g, '&quot;') + '"';
1230
1222
  }
1231
1223
 
1232
- var patterns = grammar[token];
1233
- patterns = Array.isArray(patterns) ? patterns : [patterns];
1224
+ return '<' + env.tag + ' class="' + env.classes.join(' ') + '"' + attributes + '>' + env.content + '</' + env.tag + '>';
1225
+ };
1234
1226
 
1235
- for (var j = 0; j < patterns.length; ++j) {
1236
- if (rematch && rematch.cause == token + ',' + j) {
1237
- return;
1238
- }
1227
+ /**
1228
+ * @param {RegExp} pattern
1229
+ * @param {number} pos
1230
+ * @param {string} text
1231
+ * @param {boolean} lookbehind
1232
+ * @returns {RegExpExecArray | null}
1233
+ */
1234
+ function matchPattern(pattern, pos, text, lookbehind) {
1235
+ pattern.lastIndex = pos;
1236
+ var match = pattern.exec(text);
1237
+ if (match && lookbehind && match[1]) {
1238
+ // change the match to remove the text matched by the Prism lookbehind group
1239
+ var lookbehindLength = match[1].length;
1240
+ match.index += lookbehindLength;
1241
+ match[0] = match[0].slice(lookbehindLength);
1242
+ }
1243
+ return match;
1244
+ }
1239
1245
 
1240
- var patternObj = patterns[j],
1241
- inside = patternObj.inside,
1242
- lookbehind = !!patternObj.lookbehind,
1243
- greedy = !!patternObj.greedy,
1244
- lookbehindLength = 0,
1245
- alias = patternObj.alias;
1246
-
1247
- if (greedy && !patternObj.pattern.global) {
1248
- // Without the global flag, lastIndex won't work
1249
- var flags = patternObj.pattern.toString().match(/[imsuy]*$/)[0];
1250
- patternObj.pattern = RegExp(patternObj.pattern.source, flags + 'g');
1246
+ /**
1247
+ * @param {string} text
1248
+ * @param {LinkedList<string | Token>} tokenList
1249
+ * @param {any} grammar
1250
+ * @param {LinkedListNode<string | Token>} startNode
1251
+ * @param {number} startPos
1252
+ * @param {RematchOptions} [rematch]
1253
+ * @returns {void}
1254
+ * @private
1255
+ *
1256
+ * @typedef RematchOptions
1257
+ * @property {string} cause
1258
+ * @property {number} reach
1259
+ */
1260
+ function matchGrammar(text, tokenList, grammar, startNode, startPos, rematch) {
1261
+ for (var token in grammar) {
1262
+ if (!grammar.hasOwnProperty(token) || !grammar[token]) {
1263
+ continue;
1251
1264
  }
1252
1265
 
1253
- /** @type {RegExp} */
1254
- var pattern = patternObj.pattern || patternObj;
1255
-
1256
- for ( // iterate the token list and keep track of the current token/string position
1257
- var currentNode = startNode.next, pos = startPos;
1258
- currentNode !== tokenList.tail;
1259
- pos += currentNode.value.length, currentNode = currentNode.next
1260
- ) {
1266
+ var patterns = grammar[token];
1267
+ patterns = Array.isArray(patterns) ? patterns : [patterns];
1261
1268
 
1262
- if (rematch && pos >= rematch.reach) {
1263
- break;
1269
+ for (var j = 0; j < patterns.length; ++j) {
1270
+ if (rematch && rematch.cause == token + ',' + j) {
1271
+ return;
1264
1272
  }
1265
1273
 
1266
- var str = currentNode.value;
1274
+ var patternObj = patterns[j];
1275
+ var inside = patternObj.inside;
1276
+ var lookbehind = !!patternObj.lookbehind;
1277
+ var greedy = !!patternObj.greedy;
1278
+ var alias = patternObj.alias;
1267
1279
 
1268
- if (tokenList.length > text.length) {
1269
- // Something went terribly wrong, ABORT, ABORT!
1270
- return;
1280
+ if (greedy && !patternObj.pattern.global) {
1281
+ // Without the global flag, lastIndex won't work
1282
+ var flags = patternObj.pattern.toString().match(/[imsuy]*$/)[0];
1283
+ patternObj.pattern = RegExp(patternObj.pattern.source, flags + 'g');
1271
1284
  }
1272
1285
 
1273
- if (str instanceof Token) {
1274
- continue;
1275
- }
1286
+ /** @type {RegExp} */
1287
+ var pattern = patternObj.pattern || patternObj;
1276
1288
 
1277
- var removeCount = 1; // this is the to parameter of removeBetween
1289
+ for ( // iterate the token list and keep track of the current token/string position
1290
+ var currentNode = startNode.next, pos = startPos;
1291
+ currentNode !== tokenList.tail;
1292
+ pos += currentNode.value.length, currentNode = currentNode.next
1293
+ ) {
1278
1294
 
1279
- if (greedy && currentNode != tokenList.tail.prev) {
1280
- pattern.lastIndex = pos;
1281
- var match = pattern.exec(text);
1282
- if (!match) {
1295
+ if (rematch && pos >= rematch.reach) {
1283
1296
  break;
1284
1297
  }
1285
1298
 
1286
- var from = match.index + (lookbehind && match[1] ? match[1].length : 0);
1287
- var to = match.index + match[0].length;
1288
- var p = pos;
1299
+ var str = currentNode.value;
1289
1300
 
1290
- // find the node that contains the match
1291
- p += currentNode.value.length;
1292
- while (from >= p) {
1293
- currentNode = currentNode.next;
1294
- p += currentNode.value.length;
1301
+ if (tokenList.length > text.length) {
1302
+ // Something went terribly wrong, ABORT, ABORT!
1303
+ return;
1295
1304
  }
1296
- // adjust pos (and p)
1297
- p -= currentNode.value.length;
1298
- pos = p;
1299
1305
 
1300
- // the current node is a Token, then the match starts inside another Token, which is invalid
1301
- if (currentNode.value instanceof Token) {
1306
+ if (str instanceof Token) {
1302
1307
  continue;
1303
1308
  }
1304
1309
 
1305
- // find the last node which is affected by this match
1306
- for (
1307
- var k = currentNode;
1308
- k !== tokenList.tail && (p < to || typeof k.value === 'string');
1309
- k = k.next
1310
- ) {
1311
- removeCount++;
1312
- p += k.value.length;
1313
- }
1314
- removeCount--;
1310
+ var removeCount = 1; // this is the to parameter of removeBetween
1311
+ var match;
1315
1312
 
1316
- // replace with the new match
1317
- str = text.slice(pos, p);
1318
- match.index -= pos;
1319
- } else {
1320
- pattern.lastIndex = 0;
1313
+ if (greedy) {
1314
+ match = matchPattern(pattern, pos, text, lookbehind);
1315
+ if (!match) {
1316
+ break;
1317
+ }
1321
1318
 
1322
- var match = pattern.exec(str);
1323
- }
1319
+ var from = match.index;
1320
+ var to = match.index + match[0].length;
1321
+ var p = pos;
1324
1322
 
1325
- if (!match) {
1326
- continue;
1327
- }
1323
+ // find the node that contains the match
1324
+ p += currentNode.value.length;
1325
+ while (from >= p) {
1326
+ currentNode = currentNode.next;
1327
+ p += currentNode.value.length;
1328
+ }
1329
+ // adjust pos (and p)
1330
+ p -= currentNode.value.length;
1331
+ pos = p;
1328
1332
 
1329
- if (lookbehind) {
1330
- lookbehindLength = match[1] ? match[1].length : 0;
1331
- }
1333
+ // the current node is a Token, then the match starts inside another Token, which is invalid
1334
+ if (currentNode.value instanceof Token) {
1335
+ continue;
1336
+ }
1332
1337
 
1333
- var from = match.index + lookbehindLength,
1334
- matchStr = match[0].slice(lookbehindLength),
1335
- to = from + matchStr.length,
1336
- before = str.slice(0, from),
1337
- after = str.slice(to);
1338
+ // find the last node which is affected by this match
1339
+ for (
1340
+ var k = currentNode;
1341
+ k !== tokenList.tail && (p < to || typeof k.value === 'string');
1342
+ k = k.next
1343
+ ) {
1344
+ removeCount++;
1345
+ p += k.value.length;
1346
+ }
1347
+ removeCount--;
1338
1348
 
1339
- var reach = pos + str.length;
1340
- if (rematch && reach > rematch.reach) {
1341
- rematch.reach = reach;
1342
- }
1349
+ // replace with the new match
1350
+ str = text.slice(pos, p);
1351
+ match.index -= pos;
1352
+ } else {
1353
+ match = matchPattern(pattern, 0, str, lookbehind);
1354
+ if (!match) {
1355
+ continue;
1356
+ }
1357
+ }
1343
1358
 
1344
- var removeFrom = currentNode.prev;
1359
+ // eslint-disable-next-line no-redeclare
1360
+ var from = match.index;
1361
+ var matchStr = match[0];
1362
+ var before = str.slice(0, from);
1363
+ var after = str.slice(from + matchStr.length);
1345
1364
 
1346
- if (before) {
1347
- removeFrom = addAfter(tokenList, removeFrom, before);
1348
- pos += before.length;
1349
- }
1365
+ var reach = pos + str.length;
1366
+ if (rematch && reach > rematch.reach) {
1367
+ rematch.reach = reach;
1368
+ }
1350
1369
 
1351
- removeRange(tokenList, removeFrom, removeCount);
1370
+ var removeFrom = currentNode.prev;
1352
1371
 
1353
- var wrapped = new Token(token, inside ? _.tokenize(matchStr, inside) : matchStr, alias, matchStr);
1354
- currentNode = addAfter(tokenList, removeFrom, wrapped);
1372
+ if (before) {
1373
+ removeFrom = addAfter(tokenList, removeFrom, before);
1374
+ pos += before.length;
1375
+ }
1355
1376
 
1356
- if (after) {
1357
- addAfter(tokenList, currentNode, after);
1358
- }
1377
+ removeRange(tokenList, removeFrom, removeCount);
1378
+
1379
+ var wrapped = new Token(token, inside ? _.tokenize(matchStr, inside) : matchStr, alias, matchStr);
1380
+ currentNode = addAfter(tokenList, removeFrom, wrapped);
1381
+
1382
+ if (after) {
1383
+ addAfter(tokenList, currentNode, after);
1384
+ }
1385
+
1386
+ if (removeCount > 1) {
1387
+ // at least one Token object was removed, so we have to do some rematching
1388
+ // this can only happen if the current pattern is greedy
1359
1389
 
1360
- if (removeCount > 1) {
1361
- // at least one Token object was removed, so we have to do some rematching
1362
- // this can only happen if the current pattern is greedy
1363
- matchGrammar(text, tokenList, grammar, currentNode.prev, pos, {
1364
- cause: token + ',' + j,
1365
- reach: reach
1366
- });
1390
+ /** @type {RematchOptions} */
1391
+ var nestedRematch = {
1392
+ cause: token + ',' + j,
1393
+ reach: reach
1394
+ };
1395
+ matchGrammar(text, tokenList, grammar, currentNode.prev, pos, nestedRematch);
1396
+
1397
+ // the reach might have been extended because of the rematching
1398
+ if (rematch && nestedRematch.reach > rematch.reach) {
1399
+ rematch.reach = nestedRematch.reach;
1400
+ }
1401
+ }
1367
1402
  }
1368
1403
  }
1369
1404
  }
1370
1405
  }
1371
- }
1372
1406
 
1373
- /**
1374
- * @typedef LinkedListNode
1375
- * @property {T} value
1376
- * @property {LinkedListNode<T> | null} prev The previous node.
1377
- * @property {LinkedListNode<T> | null} next The next node.
1378
- * @template T
1379
- * @private
1380
- */
1407
+ /**
1408
+ * @typedef LinkedListNode
1409
+ * @property {T} value
1410
+ * @property {LinkedListNode<T> | null} prev The previous node.
1411
+ * @property {LinkedListNode<T> | null} next The next node.
1412
+ * @template T
1413
+ * @private
1414
+ */
1381
1415
 
1382
- /**
1383
- * @template T
1384
- * @private
1385
- */
1386
- function LinkedList() {
1387
- /** @type {LinkedListNode<T>} */
1388
- var head = { value: null, prev: null, next: null };
1389
- /** @type {LinkedListNode<T>} */
1390
- var tail = { value: null, prev: head, next: null };
1391
- head.next = tail;
1392
-
1393
- /** @type {LinkedListNode<T>} */
1394
- this.head = head;
1395
- /** @type {LinkedListNode<T>} */
1396
- this.tail = tail;
1397
- this.length = 0;
1398
- }
1416
+ /**
1417
+ * @template T
1418
+ * @private
1419
+ */
1420
+ function LinkedList() {
1421
+ /** @type {LinkedListNode<T>} */
1422
+ var head = { value: null, prev: null, next: null };
1423
+ /** @type {LinkedListNode<T>} */
1424
+ var tail = { value: null, prev: head, next: null };
1425
+ head.next = tail;
1426
+
1427
+ /** @type {LinkedListNode<T>} */
1428
+ this.head = head;
1429
+ /** @type {LinkedListNode<T>} */
1430
+ this.tail = tail;
1431
+ this.length = 0;
1432
+ }
1399
1433
 
1400
- /**
1401
- * Adds a new node with the given value to the list.
1402
- * @param {LinkedList<T>} list
1403
- * @param {LinkedListNode<T>} node
1404
- * @param {T} value
1405
- * @returns {LinkedListNode<T>} The added node.
1406
- * @template T
1407
- */
1408
- function addAfter(list, node, value) {
1409
- // assumes that node != list.tail && values.length >= 0
1410
- var next = node.next;
1434
+ /**
1435
+ * Adds a new node with the given value to the list.
1436
+ *
1437
+ * @param {LinkedList<T>} list
1438
+ * @param {LinkedListNode<T>} node
1439
+ * @param {T} value
1440
+ * @returns {LinkedListNode<T>} The added node.
1441
+ * @template T
1442
+ */
1443
+ function addAfter(list, node, value) {
1444
+ // assumes that node != list.tail && values.length >= 0
1445
+ var next = node.next;
1411
1446
 
1412
- var newNode = { value: value, prev: node, next: next };
1413
- node.next = newNode;
1414
- next.prev = newNode;
1415
- list.length++;
1447
+ var newNode = { value: value, prev: node, next: next };
1448
+ node.next = newNode;
1449
+ next.prev = newNode;
1450
+ list.length++;
1416
1451
 
1417
- return newNode;
1418
- }
1419
- /**
1420
- * Removes `count` nodes after the given node. The given node will not be removed.
1421
- * @param {LinkedList<T>} list
1422
- * @param {LinkedListNode<T>} node
1423
- * @param {number} count
1424
- * @template T
1425
- */
1426
- function removeRange(list, node, count) {
1427
- var next = node.next;
1428
- for (var i = 0; i < count && next !== list.tail; i++) {
1429
- next = next.next;
1452
+ return newNode;
1430
1453
  }
1431
- node.next = next;
1432
- next.prev = node;
1433
- list.length -= i;
1434
- }
1435
- /**
1436
- * @param {LinkedList<T>} list
1437
- * @returns {T[]}
1438
- * @template T
1439
- */
1440
- function toArray(list) {
1441
- var array = [];
1442
- var node = list.head.next;
1443
- while (node !== list.tail) {
1444
- array.push(node.value);
1445
- node = node.next;
1454
+ /**
1455
+ * Removes `count` nodes after the given node. The given node will not be removed.
1456
+ *
1457
+ * @param {LinkedList<T>} list
1458
+ * @param {LinkedListNode<T>} node
1459
+ * @param {number} count
1460
+ * @template T
1461
+ */
1462
+ function removeRange(list, node, count) {
1463
+ var next = node.next;
1464
+ for (var i = 0; i < count && next !== list.tail; i++) {
1465
+ next = next.next;
1466
+ }
1467
+ node.next = next;
1468
+ next.prev = node;
1469
+ list.length -= i;
1470
+ }
1471
+ /**
1472
+ * @param {LinkedList<T>} list
1473
+ * @returns {T[]}
1474
+ * @template T
1475
+ */
1476
+ function toArray(list) {
1477
+ var array = [];
1478
+ var node = list.head.next;
1479
+ while (node !== list.tail) {
1480
+ array.push(node.value);
1481
+ node = node.next;
1482
+ }
1483
+ return array;
1446
1484
  }
1447
- return array;
1448
- }
1449
1485
 
1450
1486
 
1451
- if (!_self.document) {
1452
- if (!_self.addEventListener) {
1453
- // in Node.js
1454
- return _;
1455
- }
1487
+ if (!_self.document) {
1488
+ if (!_self.addEventListener) {
1489
+ // in Node.js
1490
+ return _;
1491
+ }
1456
1492
 
1457
- if (!_.disableWorkerMessageHandler) {
1458
- // In worker
1459
- _self.addEventListener('message', function (evt) {
1460
- var message = JSON.parse(evt.data),
1461
- lang = message.language,
1462
- code = message.code,
1463
- immediateClose = message.immediateClose;
1464
-
1465
- _self.postMessage(_.highlight(code, _.languages[lang], lang));
1466
- if (immediateClose) {
1467
- _self.close();
1468
- }
1469
- }, false);
1470
- }
1493
+ if (!_.disableWorkerMessageHandler) {
1494
+ // In worker
1495
+ _self.addEventListener('message', function (evt) {
1496
+ var message = JSON.parse(evt.data);
1497
+ var lang = message.language;
1498
+ var code = message.code;
1499
+ var immediateClose = message.immediateClose;
1500
+
1501
+ _self.postMessage(_.highlight(code, _.languages[lang], lang));
1502
+ if (immediateClose) {
1503
+ _self.close();
1504
+ }
1505
+ }, false);
1506
+ }
1471
1507
 
1472
- return _;
1473
- }
1508
+ return _;
1509
+ }
1474
1510
 
1475
- // Get current script and highlight
1476
- var script = _.util.currentScript();
1511
+ // Get current script and highlight
1512
+ var script = _.util.currentScript();
1477
1513
 
1478
- if (script) {
1479
- _.filename = script.src;
1514
+ if (script) {
1515
+ _.filename = script.src;
1480
1516
 
1481
- if (script.hasAttribute('data-manual')) {
1482
- _.manual = true;
1517
+ if (script.hasAttribute('data-manual')) {
1518
+ _.manual = true;
1519
+ }
1483
1520
  }
1484
- }
1485
1521
 
1486
- function highlightAutomaticallyCallback() {
1487
- if (!_.manual) {
1488
- _.highlightAll();
1522
+ function highlightAutomaticallyCallback() {
1523
+ if (!_.manual) {
1524
+ _.highlightAll();
1525
+ }
1489
1526
  }
1490
- }
1491
1527
 
1492
- if (!_.manual) {
1493
- // If the document state is "loading", then we'll use DOMContentLoaded.
1494
- // If the document state is "interactive" and the prism.js script is deferred, then we'll also use the
1495
- // DOMContentLoaded event because there might be some plugins or languages which have also been deferred and they
1496
- // might take longer one animation frame to execute which can create a race condition where only some plugins have
1497
- // been loaded when Prism.highlightAll() is executed, depending on how fast resources are loaded.
1498
- // See https://github.com/PrismJS/prism/issues/2102
1499
- var readyState = document.readyState;
1500
- if (readyState === 'loading' || readyState === 'interactive' && script && script.defer) {
1501
- document.addEventListener('DOMContentLoaded', highlightAutomaticallyCallback);
1502
- } else {
1503
- if (window.requestAnimationFrame) {
1504
- window.requestAnimationFrame(highlightAutomaticallyCallback);
1528
+ if (!_.manual) {
1529
+ // If the document state is "loading", then we'll use DOMContentLoaded.
1530
+ // If the document state is "interactive" and the prism.js script is deferred, then we'll also use the
1531
+ // DOMContentLoaded event because there might be some plugins or languages which have also been deferred and they
1532
+ // might take longer one animation frame to execute which can create a race condition where only some plugins have
1533
+ // been loaded when Prism.highlightAll() is executed, depending on how fast resources are loaded.
1534
+ // See https://github.com/PrismJS/prism/issues/2102
1535
+ var readyState = document.readyState;
1536
+ if (readyState === 'loading' || readyState === 'interactive' && script && script.defer) {
1537
+ document.addEventListener('DOMContentLoaded', highlightAutomaticallyCallback);
1505
1538
  } else {
1506
- window.setTimeout(highlightAutomaticallyCallback, 16);
1539
+ if (window.requestAnimationFrame) {
1540
+ window.requestAnimationFrame(highlightAutomaticallyCallback);
1541
+ } else {
1542
+ window.setTimeout(highlightAutomaticallyCallback, 16);
1543
+ }
1507
1544
  }
1508
1545
  }
1509
- }
1510
1546
 
1511
- return _;
1547
+ return _;
1512
1548
 
1513
- })(_self);
1549
+ }(_self));
1514
1550
 
1515
1551
  if ( true && module.exports) {
1516
1552
  module.exports = Prism;
@@ -1542,7 +1578,7 @@ if (typeof global !== 'undefined') {
1542
1578
  * each another.
1543
1579
  * @global
1544
1580
  * @public
1545
- */
1581
+ */
1546
1582
 
1547
1583
  /**
1548
1584
  * @typedef Grammar
@@ -1560,7 +1596,7 @@ if (typeof global !== 'undefined') {
1560
1596
  * @returns {void}
1561
1597
  * @global
1562
1598
  * @public
1563
- */
1599
+ */
1564
1600
 
1565
1601
  /**
1566
1602
  * @callback HookCallback
@@ -1573,11 +1609,13 @@ if (typeof global !== 'undefined') {
1573
1609
  // https://www.json.org/json-en.html
1574
1610
  Prism.languages.json = {
1575
1611
  'property': {
1576
- pattern: /"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,
1612
+ pattern: /(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,
1613
+ lookbehind: true,
1577
1614
  greedy: true
1578
1615
  },
1579
1616
  'string': {
1580
- pattern: /"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,
1617
+ pattern: /(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,
1618
+ lookbehind: true,
1581
1619
  greedy: true
1582
1620
  },
1583
1621
  'comment': {
@@ -1597,15 +1635,21 @@ Prism.languages.json = {
1597
1635
  Prism.languages.webmanifest = Prism.languages.json;
1598
1636
 
1599
1637
  Prism.languages.markup = {
1600
- 'comment': /<!--[\s\S]*?-->/,
1601
- 'prolog': /<\?[\s\S]+?\?>/,
1638
+ 'comment': {
1639
+ pattern: /<!--(?:(?!<!--)[\s\S])*?-->/,
1640
+ greedy: true
1641
+ },
1642
+ 'prolog': {
1643
+ pattern: /<\?[\s\S]+?\?>/,
1644
+ greedy: true
1645
+ },
1602
1646
  'doctype': {
1603
1647
  // https://www.w3.org/TR/xml/#NT-doctypedecl
1604
1648
  pattern: /<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,
1605
1649
  greedy: true,
1606
1650
  inside: {
1607
1651
  'internal-subset': {
1608
- pattern: /(\[)[\s\S]+(?=\]>$)/,
1652
+ pattern: /(^[^\[]*\[)[\s\S]+(?=\]>$)/,
1609
1653
  lookbehind: true,
1610
1654
  greedy: true,
1611
1655
  inside: null // see below
@@ -1615,11 +1659,14 @@ Prism.languages.markup = {
1615
1659
  greedy: true
1616
1660
  },
1617
1661
  'punctuation': /^<!|>$|[[\]]/,
1618
- 'doctype-tag': /^DOCTYPE/,
1662
+ 'doctype-tag': /^DOCTYPE/i,
1619
1663
  'name': /[^\s<>'"]+/
1620
1664
  }
1621
1665
  },
1622
- 'cdata': /<!\[CDATA\[[\s\S]*?]]>/i,
1666
+ 'cdata': {
1667
+ pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i,
1668
+ greedy: true
1669
+ },
1623
1670
  'tag': {
1624
1671
  pattern: /<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,
1625
1672
  greedy: true,
@@ -1631,6 +1678,7 @@ Prism.languages.markup = {
1631
1678
  'namespace': /^[^\s>\/:]+:/
1632
1679
  }
1633
1680
  },
1681
+ 'special-attr': [],
1634
1682
  'attr-value': {
1635
1683
  pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,
1636
1684
  inside: {
@@ -1708,7 +1756,7 @@ Object.defineProperty(Prism.languages.markup.tag, 'addInlined', {
1708
1756
 
1709
1757
  var def = {};
1710
1758
  def[tagName] = {
1711
- pattern: RegExp(/(<__[\s\S]*?>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g, function () { return tagName; }), 'i'),
1759
+ pattern: RegExp(/(<__[^>]*>)(?:<!\[CDATA\[(?:[^\]]|\](?!\]>))*\]\]>|(?!<!\[CDATA\[)[\s\S])*?(?=<\/__>)/.source.replace(/__/g, function () { return tagName; }), 'i'),
1712
1760
  lookbehind: true,
1713
1761
  greedy: true,
1714
1762
  inside: inside
@@ -1717,6 +1765,49 @@ Object.defineProperty(Prism.languages.markup.tag, 'addInlined', {
1717
1765
  Prism.languages.insertBefore('markup', 'cdata', def);
1718
1766
  }
1719
1767
  });
1768
+ Object.defineProperty(Prism.languages.markup.tag, 'addAttribute', {
1769
+ /**
1770
+ * Adds an pattern to highlight languages embedded in HTML attributes.
1771
+ *
1772
+ * An example of an inlined language is CSS with `style` attributes.
1773
+ *
1774
+ * @param {string} attrName The name of the tag that contains the inlined language. This name will be treated as
1775
+ * case insensitive.
1776
+ * @param {string} lang The language key.
1777
+ * @example
1778
+ * addAttribute('style', 'css');
1779
+ */
1780
+ value: function (attrName, lang) {
1781
+ Prism.languages.markup.tag.inside['special-attr'].push({
1782
+ pattern: RegExp(
1783
+ /(^|["'\s])/.source + '(?:' + attrName + ')' + /\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,
1784
+ 'i'
1785
+ ),
1786
+ lookbehind: true,
1787
+ inside: {
1788
+ 'attr-name': /^[^\s=]+/,
1789
+ 'attr-value': {
1790
+ pattern: /=[\s\S]+/,
1791
+ inside: {
1792
+ 'value': {
1793
+ pattern: /(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,
1794
+ lookbehind: true,
1795
+ alias: [lang, 'language-' + lang],
1796
+ inside: Prism.languages[lang]
1797
+ },
1798
+ 'punctuation': [
1799
+ {
1800
+ pattern: /^=/,
1801
+ alias: 'attr-equals'
1802
+ },
1803
+ /"|'/
1804
+ ]
1805
+ }
1806
+ }
1807
+ }
1808
+ });
1809
+ }
1810
+ });
1720
1811
 
1721
1812
  Prism.languages.html = Prism.languages.markup;
1722
1813
  Prism.languages.mathml = Prism.languages.markup;
@@ -1731,7 +1822,8 @@ Prism.languages.clike = {
1731
1822
  'comment': [
1732
1823
  {
1733
1824
  pattern: /(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,
1734
- lookbehind: true
1825
+ lookbehind: true,
1826
+ greedy: true
1735
1827
  },
1736
1828
  {
1737
1829
  pattern: /(^|[^\\:])\/\/.*/,
@@ -1752,8 +1844,8 @@ Prism.languages.clike = {
1752
1844
  },
1753
1845
  'keyword': /\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,
1754
1846
  'boolean': /\b(?:true|false)\b/,
1755
- 'function': /\w+(?=\()/,
1756
- 'number': /\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i,
1847
+ 'function': /\b\w+(?=\()/,
1848
+ 'number': /\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,
1757
1849
  'operator': /[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,
1758
1850
  'punctuation': /[{}[\];(),.:]/
1759
1851
  };
@@ -1762,23 +1854,23 @@ Prism.languages.javascript = Prism.languages.extend('clike', {
1762
1854
  'class-name': [
1763
1855
  Prism.languages.clike['class-name'],
1764
1856
  {
1765
- pattern: /(^|[^$\w\xA0-\uFFFF])[_$A-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\.(?:prototype|constructor))/,
1857
+ pattern: /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:prototype|constructor))/,
1766
1858
  lookbehind: true
1767
1859
  }
1768
1860
  ],
1769
1861
  'keyword': [
1770
1862
  {
1771
- pattern: /((?:^|})\s*)(?:catch|finally)\b/,
1863
+ pattern: /((?:^|\})\s*)catch\b/,
1772
1864
  lookbehind: true
1773
1865
  },
1774
1866
  {
1775
- pattern: /(^|[^.]|\.\.\.\s*)\b(?:as|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|for|from|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/,
1867
+ 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/,
1776
1868
  lookbehind: true
1777
1869
  },
1778
1870
  ],
1779
- 'number': /\b(?:(?:0[xX](?:[\dA-Fa-f](?:_[\dA-Fa-f])?)+|0[bB](?:[01](?:_[01])?)+|0[oO](?:[0-7](?:_[0-7])?)+)n?|(?:\d(?:_\d)?)+n|NaN|Infinity)\b|(?:\b(?:\d(?:_\d)?)+\.?(?:\d(?:_\d)?)*|\B\.(?:\d(?:_\d)?)+)(?:[Ee][+-]?(?:\d(?:_\d)?)+)?/,
1780
1871
  // Allow for all non-ASCII characters (See http://stackoverflow.com/a/2008444)
1781
- 'function': /#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,
1872
+ 'function': /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,
1873
+ 'number': /\b(?:(?:0[xX](?:[\dA-Fa-f](?:_[\dA-Fa-f])?)+|0[bB](?:[01](?:_[01])?)+|0[oO](?:[0-7](?:_[0-7])?)+)n?|(?:\d(?:_\d)?)+n|NaN|Infinity)\b|(?:\b(?:\d(?:_\d)?)+\.?(?:\d(?:_\d)?)*|\B\.(?:\d(?:_\d)?)+)(?:[Ee][+-]?(?:\d(?:_\d)?)+)?/,
1782
1874
  'operator': /--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/
1783
1875
  });
1784
1876
 
@@ -1786,7 +1878,8 @@ Prism.languages.javascript['class-name'][0].pattern = /(\b(?:class|interface|ext
1786
1878
 
1787
1879
  Prism.languages.insertBefore('javascript', 'keyword', {
1788
1880
  'regex': {
1789
- pattern: /((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*]|\\.|[^/\\\[\r\n])+\/[gimyus]{0,6}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,
1881
+ // eslint-disable-next-line regexp/no-dupe-characters-character-class
1882
+ pattern: /((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,
1790
1883
  lookbehind: true,
1791
1884
  greedy: true,
1792
1885
  inside: {
@@ -1796,32 +1889,33 @@ Prism.languages.insertBefore('javascript', 'keyword', {
1796
1889
  alias: 'language-regex',
1797
1890
  inside: Prism.languages.regex
1798
1891
  },
1799
- 'regex-flags': /[a-z]+$/,
1800
- 'regex-delimiter': /^\/|\/$/
1892
+ 'regex-delimiter': /^\/|\/$/,
1893
+ 'regex-flags': /^[a-z]+$/,
1801
1894
  }
1802
1895
  },
1803
1896
  // This must be declared before keyword because we use "function" inside the look-forward
1804
1897
  'function-variable': {
1805
- pattern: /#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/,
1898
+ 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*=>))/,
1806
1899
  alias: 'function'
1807
1900
  },
1808
1901
  'parameter': [
1809
1902
  {
1810
- pattern: /(function(?:\s+[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)?\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\))/,
1903
+ pattern: /(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,
1811
1904
  lookbehind: true,
1812
1905
  inside: Prism.languages.javascript
1813
1906
  },
1814
1907
  {
1815
- pattern: /[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=>)/i,
1908
+ pattern: /(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,
1909
+ lookbehind: true,
1816
1910
  inside: Prism.languages.javascript
1817
1911
  },
1818
1912
  {
1819
- pattern: /(\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*=>)/,
1913
+ pattern: /(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,
1820
1914
  lookbehind: true,
1821
1915
  inside: Prism.languages.javascript
1822
1916
  },
1823
1917
  {
1824
- 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]))(?:[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*\{)/,
1918
+ 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*\{)/,
1825
1919
  lookbehind: true,
1826
1920
  inside: Prism.languages.javascript
1827
1921
  }
@@ -1830,8 +1924,13 @@ Prism.languages.insertBefore('javascript', 'keyword', {
1830
1924
  });
1831
1925
 
1832
1926
  Prism.languages.insertBefore('javascript', 'string', {
1927
+ 'hashbang': {
1928
+ pattern: /^#!.*/,
1929
+ greedy: true,
1930
+ alias: 'comment'
1931
+ },
1833
1932
  'template-string': {
1834
- pattern: /`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}|(?!\${)[^\\`])*`/,
1933
+ pattern: /`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,
1835
1934
  greedy: true,
1836
1935
  inside: {
1837
1936
  'template-punctuation': {
@@ -1839,11 +1938,11 @@ Prism.languages.insertBefore('javascript', 'string', {
1839
1938
  alias: 'string'
1840
1939
  },
1841
1940
  'interpolation': {
1842
- pattern: /((?:^|[^\\])(?:\\{2})*)\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}/,
1941
+ pattern: /((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,
1843
1942
  lookbehind: true,
1844
1943
  inside: {
1845
1944
  'interpolation-punctuation': {
1846
- pattern: /^\${|}$/,
1945
+ pattern: /^\$\{|\}$/,
1847
1946
  alias: 'punctuation'
1848
1947
  },
1849
1948
  rest: Prism.languages.javascript
@@ -1856,134 +1955,160 @@ Prism.languages.insertBefore('javascript', 'string', {
1856
1955
 
1857
1956
  if (Prism.languages.markup) {
1858
1957
  Prism.languages.markup.tag.addInlined('script', 'javascript');
1958
+
1959
+ // add attribute support for all DOM events.
1960
+ // https://developer.mozilla.org/en-US/docs/Web/Events#Standard_events
1961
+ Prism.languages.markup.tag.addAttribute(
1962
+ /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,
1963
+ 'javascript'
1964
+ );
1859
1965
  }
1860
1966
 
1861
1967
  Prism.languages.js = Prism.languages.javascript;
1862
1968
 
1863
- (function(Prism) {
1969
+ (function (Prism) {
1970
+
1971
+ var javascript = Prism.util.clone(Prism.languages.javascript);
1864
1972
 
1865
- var javascript = Prism.util.clone(Prism.languages.javascript);
1973
+ var space = /(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source;
1974
+ var braces = /(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source;
1975
+ var spread = /(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source;
1866
1976
 
1867
- Prism.languages.jsx = Prism.languages.extend('markup', javascript);
1868
- Prism.languages.jsx.tag.pattern= /<\/?(?:[\w.:-]+\s*(?:\s+(?:[\w.:$-]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s{'">=]+|\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])+\}))?|\{\s*\.{3}\s*[a-z_$][\w$]*(?:\.[a-z_$][\w$]*)*\s*\}))*\s*\/?)?>/i;
1977
+ /**
1978
+ * @param {string} source
1979
+ * @param {string} [flags]
1980
+ */
1981
+ function re(source, flags) {
1982
+ source = source
1983
+ .replace(/<S>/g, function () { return space; })
1984
+ .replace(/<BRACES>/g, function () { return braces; })
1985
+ .replace(/<SPREAD>/g, function () { return spread; });
1986
+ return RegExp(source, flags);
1987
+ }
1869
1988
 
1870
- Prism.languages.jsx.tag.inside['tag'].pattern = /^<\/?[^\s>\/]*/i;
1871
- Prism.languages.jsx.tag.inside['attr-value'].pattern = /=(?!\{)(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">]+)/i;
1872
- Prism.languages.jsx.tag.inside['tag'].inside['class-name'] = /^[A-Z]\w*(?:\.[A-Z]\w*)*$/;
1989
+ spread = re(spread).source;
1873
1990
 
1874
- Prism.languages.insertBefore('inside', 'attr-name', {
1875
- 'spread': {
1876
- pattern: /\{\s*\.{3}\s*[a-z_$][\w$]*(?:\.[a-z_$][\w$]*)*\s*\}/,
1877
- inside: {
1878
- 'punctuation': /\.{3}|[{}.]/,
1879
- 'attr-value': /\w+/
1991
+
1992
+ Prism.languages.jsx = Prism.languages.extend('markup', javascript);
1993
+ Prism.languages.jsx.tag.pattern = re(
1994
+ /<\/?(?:[\w.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/.source
1995
+ );
1996
+
1997
+ Prism.languages.jsx.tag.inside['tag'].pattern = /^<\/?[^\s>\/]*/i;
1998
+ Prism.languages.jsx.tag.inside['attr-value'].pattern = /=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/i;
1999
+ Prism.languages.jsx.tag.inside['tag'].inside['class-name'] = /^[A-Z]\w*(?:\.[A-Z]\w*)*$/;
2000
+ Prism.languages.jsx.tag.inside['comment'] = javascript['comment'];
2001
+
2002
+ Prism.languages.insertBefore('inside', 'attr-name', {
2003
+ 'spread': {
2004
+ pattern: re(/<SPREAD>/.source),
2005
+ inside: Prism.languages.jsx
1880
2006
  }
1881
- }
1882
- }, Prism.languages.jsx.tag);
2007
+ }, Prism.languages.jsx.tag);
1883
2008
 
1884
- Prism.languages.insertBefore('inside', 'attr-value',{
1885
- 'script': {
1886
- // Allow for two levels of nesting
1887
- pattern: /=(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])+\})/i,
1888
- inside: {
1889
- 'script-punctuation': {
1890
- pattern: /^=(?={)/,
1891
- alias: 'punctuation'
2009
+ Prism.languages.insertBefore('inside', 'special-attr', {
2010
+ 'script': {
2011
+ // Allow for two levels of nesting
2012
+ pattern: re(/=<BRACES>/.source),
2013
+ inside: {
2014
+ 'script-punctuation': {
2015
+ pattern: /^=(?=\{)/,
2016
+ alias: 'punctuation'
2017
+ },
2018
+ rest: Prism.languages.jsx
1892
2019
  },
1893
- rest: Prism.languages.jsx
1894
- },
1895
- 'alias': 'language-javascript'
1896
- }
1897
- }, Prism.languages.jsx.tag);
2020
+ 'alias': 'language-javascript'
2021
+ }
2022
+ }, Prism.languages.jsx.tag);
1898
2023
 
1899
- // The following will handle plain text inside tags
1900
- var stringifyToken = function (token) {
1901
- if (!token) {
1902
- return '';
1903
- }
1904
- if (typeof token === 'string') {
1905
- return token;
1906
- }
1907
- if (typeof token.content === 'string') {
1908
- return token.content;
1909
- }
1910
- return token.content.map(stringifyToken).join('');
1911
- };
2024
+ // The following will handle plain text inside tags
2025
+ var stringifyToken = function (token) {
2026
+ if (!token) {
2027
+ return '';
2028
+ }
2029
+ if (typeof token === 'string') {
2030
+ return token;
2031
+ }
2032
+ if (typeof token.content === 'string') {
2033
+ return token.content;
2034
+ }
2035
+ return token.content.map(stringifyToken).join('');
2036
+ };
1912
2037
 
1913
- var walkTokens = function (tokens) {
1914
- var openedTags = [];
1915
- for (var i = 0; i < tokens.length; i++) {
1916
- var token = tokens[i];
1917
- var notTagNorBrace = false;
1918
-
1919
- if (typeof token !== 'string') {
1920
- if (token.type === 'tag' && token.content[0] && token.content[0].type === 'tag') {
1921
- // We found a tag, now find its kind
1922
-
1923
- if (token.content[0].content[0].content === '</') {
1924
- // Closing tag
1925
- if (openedTags.length > 0 && openedTags[openedTags.length - 1].tagName === stringifyToken(token.content[0].content[1])) {
1926
- // Pop matching opening tag
1927
- openedTags.pop();
1928
- }
1929
- } else {
1930
- if (token.content[token.content.length - 1].content === '/>') {
1931
- // Autoclosed tag, ignore
2038
+ var walkTokens = function (tokens) {
2039
+ var openedTags = [];
2040
+ for (var i = 0; i < tokens.length; i++) {
2041
+ var token = tokens[i];
2042
+ var notTagNorBrace = false;
2043
+
2044
+ if (typeof token !== 'string') {
2045
+ if (token.type === 'tag' && token.content[0] && token.content[0].type === 'tag') {
2046
+ // We found a tag, now find its kind
2047
+
2048
+ if (token.content[0].content[0].content === '</') {
2049
+ // Closing tag
2050
+ if (openedTags.length > 0 && openedTags[openedTags.length - 1].tagName === stringifyToken(token.content[0].content[1])) {
2051
+ // Pop matching opening tag
2052
+ openedTags.pop();
2053
+ }
1932
2054
  } else {
1933
- // Opening tag
1934
- openedTags.push({
1935
- tagName: stringifyToken(token.content[0].content[1]),
1936
- openedBraces: 0
1937
- });
2055
+ if (token.content[token.content.length - 1].content === '/>') {
2056
+ // Autoclosed tag, ignore
2057
+ } else {
2058
+ // Opening tag
2059
+ openedTags.push({
2060
+ tagName: stringifyToken(token.content[0].content[1]),
2061
+ openedBraces: 0
2062
+ });
2063
+ }
1938
2064
  }
1939
- }
1940
- } else if (openedTags.length > 0 && token.type === 'punctuation' && token.content === '{') {
2065
+ } else if (openedTags.length > 0 && token.type === 'punctuation' && token.content === '{') {
1941
2066
 
1942
- // Here we might have entered a JSX context inside a tag
1943
- openedTags[openedTags.length - 1].openedBraces++;
2067
+ // Here we might have entered a JSX context inside a tag
2068
+ openedTags[openedTags.length - 1].openedBraces++;
1944
2069
 
1945
- } else if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces > 0 && token.type === 'punctuation' && token.content === '}') {
2070
+ } else if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces > 0 && token.type === 'punctuation' && token.content === '}') {
1946
2071
 
1947
- // Here we might have left a JSX context inside a tag
1948
- openedTags[openedTags.length - 1].openedBraces--;
2072
+ // Here we might have left a JSX context inside a tag
2073
+ openedTags[openedTags.length - 1].openedBraces--;
1949
2074
 
1950
- } else {
1951
- notTagNorBrace = true
1952
- }
1953
- }
1954
- if (notTagNorBrace || typeof token === 'string') {
1955
- if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces === 0) {
1956
- // Here we are inside a tag, and not inside a JSX context.
1957
- // That's plain text: drop any tokens matched.
1958
- var plainText = stringifyToken(token);
1959
-
1960
- // And merge text with adjacent text
1961
- if (i < tokens.length - 1 && (typeof tokens[i + 1] === 'string' || tokens[i + 1].type === 'plain-text')) {
1962
- plainText += stringifyToken(tokens[i + 1]);
1963
- tokens.splice(i + 1, 1);
2075
+ } else {
2076
+ notTagNorBrace = true;
1964
2077
  }
1965
- if (i > 0 && (typeof tokens[i - 1] === 'string' || tokens[i - 1].type === 'plain-text')) {
1966
- plainText = stringifyToken(tokens[i - 1]) + plainText;
1967
- tokens.splice(i - 1, 1);
1968
- i--;
2078
+ }
2079
+ if (notTagNorBrace || typeof token === 'string') {
2080
+ if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces === 0) {
2081
+ // Here we are inside a tag, and not inside a JSX context.
2082
+ // That's plain text: drop any tokens matched.
2083
+ var plainText = stringifyToken(token);
2084
+
2085
+ // And merge text with adjacent text
2086
+ if (i < tokens.length - 1 && (typeof tokens[i + 1] === 'string' || tokens[i + 1].type === 'plain-text')) {
2087
+ plainText += stringifyToken(tokens[i + 1]);
2088
+ tokens.splice(i + 1, 1);
2089
+ }
2090
+ if (i > 0 && (typeof tokens[i - 1] === 'string' || tokens[i - 1].type === 'plain-text')) {
2091
+ plainText = stringifyToken(tokens[i - 1]) + plainText;
2092
+ tokens.splice(i - 1, 1);
2093
+ i--;
2094
+ }
2095
+
2096
+ tokens[i] = new Prism.Token('plain-text', plainText, null, plainText);
1969
2097
  }
2098
+ }
1970
2099
 
1971
- tokens[i] = new Prism.Token('plain-text', plainText, null, plainText);
2100
+ if (token.content && typeof token.content !== 'string') {
2101
+ walkTokens(token.content);
1972
2102
  }
1973
2103
  }
2104
+ };
1974
2105
 
1975
- if (token.content && typeof token.content !== 'string') {
1976
- walkTokens(token.content);
2106
+ Prism.hooks.add('after-tokenize', function (env) {
2107
+ if (env.language !== 'jsx' && env.language !== 'tsx') {
2108
+ return;
1977
2109
  }
1978
- }
1979
- };
1980
-
1981
- Prism.hooks.add('after-tokenize', function (env) {
1982
- if (env.language !== 'jsx' && env.language !== 'tsx') {
1983
- return;
1984
- }
1985
- walkTokens(env.tokens);
1986
- });
2110
+ walkTokens(env.tokens);
2111
+ });
1987
2112
 
1988
2113
  }(Prism));
1989
2114
 
@@ -1991,16 +2116,23 @@ Prism.hooks.add('after-tokenize', function (env) {
1991
2116
 
1992
2117
  Prism.languages.typescript = Prism.languages.extend('javascript', {
1993
2118
  'class-name': {
1994
- pattern: /(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,
2119
+ pattern: /(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,
1995
2120
  lookbehind: true,
1996
2121
  greedy: true,
1997
2122
  inside: null // see below
1998
2123
  },
1999
- // From JavaScript Prism keyword list and TypeScript language spec: https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#221-reserved-words
2000
- 'keyword': /\b(?:abstract|as|asserts|async|await|break|case|catch|class|const|constructor|continue|debugger|declare|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|is|keyof|let|module|namespace|new|null|of|package|private|protected|public|readonly|return|require|set|static|super|switch|this|throw|try|type|typeof|undefined|var|void|while|with|yield)\b/,
2001
2124
  'builtin': /\b(?:string|Function|any|number|boolean|Array|symbol|console|Promise|unknown|never)\b/,
2002
2125
  });
2003
2126
 
2127
+ // The keywords TypeScript adds to JavaScript
2128
+ Prism.languages.typescript.keyword.push(
2129
+ /\b(?:abstract|as|declare|implements|is|keyof|readonly|require)\b/,
2130
+ // keywords that have to be followed by an identifier
2131
+ /\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,
2132
+ // This is for `import type *, {}`
2133
+ /\btype\b(?=\s*(?:[\{*]|$))/
2134
+ );
2135
+
2004
2136
  // doesn't work with TS because TS is too complex
2005
2137
  delete Prism.languages.typescript['parameter'];
2006
2138
 
@@ -2011,12 +2143,22 @@ Prism.hooks.add('after-tokenize', function (env) {
2011
2143
  Prism.languages.typescript['class-name'].inside = typeInside;
2012
2144
 
2013
2145
  Prism.languages.insertBefore('typescript', 'function', {
2146
+ 'decorator': {
2147
+ pattern: /@[$\w\xA0-\uFFFF]+/,
2148
+ inside: {
2149
+ 'at': {
2150
+ pattern: /^@/,
2151
+ alias: 'operator'
2152
+ },
2153
+ 'function': /^[\s\S]+/
2154
+ }
2155
+ },
2014
2156
  'generic-function': {
2015
2157
  // e.g. foo<T extends "bar" | "baz">( ...
2016
- pattern: /#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,
2158
+ pattern: /#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,
2017
2159
  greedy: true,
2018
2160
  inside: {
2019
- 'function': /^#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*/,
2161
+ 'function': /^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,
2020
2162
  'generic': {
2021
2163
  pattern: /<[\s\S]+/, // everything after the first <
2022
2164
  alias: 'class-name',
@@ -2030,20 +2172,30 @@ Prism.hooks.add('after-tokenize', function (env) {
2030
2172
 
2031
2173
  }(Prism));
2032
2174
 
2033
- var typescript = Prism.util.clone(Prism.languages.typescript);
2034
- Prism.languages.tsx = Prism.languages.extend('jsx', typescript);
2175
+ (function (Prism) {
2176
+ var typescript = Prism.util.clone(Prism.languages.typescript);
2177
+ Prism.languages.tsx = Prism.languages.extend('jsx', typescript);
2178
+
2179
+ // This will prevent collisions between TSX tags and TS generic types.
2180
+ // Idea by https://github.com/karlhorky
2181
+ // Discussion: https://github.com/PrismJS/prism/issues/2594#issuecomment-710666928
2182
+ var tag = Prism.languages.tsx.tag;
2183
+ tag.pattern = RegExp(/(^|[^\w$]|(?=<\/))/.source + '(?:' + tag.pattern.source + ')', tag.pattern.flags);
2184
+ tag.lookbehind = true;
2185
+ }(Prism));
2186
+
2035
2187
  (function (Prism) {
2036
2188
 
2037
- var string = /("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/;
2189
+ var string = /(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;
2038
2190
 
2039
2191
  Prism.languages.css = {
2040
2192
  'comment': /\/\*[\s\S]*?\*\//,
2041
2193
  'atrule': {
2042
- pattern: /@[\w-]+[\s\S]*?(?:;|(?=\s*\{))/,
2194
+ pattern: /@[\w-](?:[^;{\s]|\s+(?![\s{]))*(?:;|(?=\s*\{))/,
2043
2195
  inside: {
2044
2196
  'rule': /^@[\w-]+/,
2045
2197
  'selector-function-argument': {
2046
- pattern: /(\bselector\s*\((?!\s*\))\s*)(?:[^()]|\((?:[^()]|\([^()]*\))*\))+?(?=\s*\))/,
2198
+ pattern: /(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,
2047
2199
  lookbehind: true,
2048
2200
  alias: 'selector'
2049
2201
  },
@@ -2067,14 +2219,23 @@ Prism.languages.tsx = Prism.languages.extend('jsx', typescript);
2067
2219
  }
2068
2220
  }
2069
2221
  },
2070
- 'selector': RegExp('[^{}\\s](?:[^{};"\']|' + string.source + ')*?(?=\\s*\\{)'),
2222
+ 'selector': {
2223
+ pattern: RegExp('(^|[{}\\s])[^{}\\s](?:[^{};"\'\\s]|\\s+(?![\\s{])|' + string.source + ')*(?=\\s*\\{)'),
2224
+ lookbehind: true
2225
+ },
2071
2226
  'string': {
2072
2227
  pattern: string,
2073
2228
  greedy: true
2074
2229
  },
2075
- 'property': /[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*(?=\s*:)/i,
2230
+ 'property': {
2231
+ pattern: /(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,
2232
+ lookbehind: true
2233
+ },
2076
2234
  'important': /!important\b/i,
2077
- 'function': /[-a-z0-9]+(?=\()/i,
2235
+ 'function': {
2236
+ pattern: /(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,
2237
+ lookbehind: true
2238
+ },
2078
2239
  'punctuation': /[(){};:,]/
2079
2240
  };
2080
2241
 
@@ -2083,29 +2244,12 @@ Prism.languages.tsx = Prism.languages.extend('jsx', typescript);
2083
2244
  var markup = Prism.languages.markup;
2084
2245
  if (markup) {
2085
2246
  markup.tag.addInlined('style', 'css');
2086
-
2087
- Prism.languages.insertBefore('inside', 'attr-value', {
2088
- 'style-attr': {
2089
- pattern: /\s*style=("|')(?:\\[\s\S]|(?!\1)[^\\])*\1/i,
2090
- inside: {
2091
- 'attr-name': {
2092
- pattern: /^\s*style/i,
2093
- inside: markup.tag.inside
2094
- },
2095
- 'punctuation': /^\s*=\s*['"]|['"]\s*$/,
2096
- 'attr-value': {
2097
- pattern: /.+/i,
2098
- inside: Prism.languages.css
2099
- }
2100
- },
2101
- alias: 'language-css'
2102
- }
2103
- }, markup.tag);
2247
+ markup.tag.addAttribute('style', 'css');
2104
2248
  }
2105
2249
 
2106
2250
  }(Prism));
2107
2251
 
2108
- (function(Prism) {
2252
+ (function (Prism) {
2109
2253
  // $ set | grep '^[A-Z][^[:space:]]*=' | cut -d= -f1 | tr '\n' '|'
2110
2254
  // + LC_ALL, RANDOM, REPLY, SECONDS.
2111
2255
  // + make sure PS1..4 are here as they are not always set,
@@ -2122,7 +2266,7 @@ Prism.languages.tsx = Prism.languages.extend('jsx', typescript);
2122
2266
  var insideString = {
2123
2267
  'bash': commandAfterHeredoc,
2124
2268
  'environment': {
2125
- pattern: RegExp("\\$" + envVars),
2269
+ pattern: RegExp('\\$' + envVars),
2126
2270
  alias: 'constant'
2127
2271
  },
2128
2272
  'variable': [
@@ -2139,9 +2283,9 @@ Prism.languages.tsx = Prism.languages.extend('jsx', typescript);
2139
2283
  },
2140
2284
  /^\$\(\(/
2141
2285
  ],
2142
- 'number': /\b0x[\dA-Fa-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee]-?\d+)?/,
2286
+ 'number': /\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,
2143
2287
  // Operators according to https://www.gnu.org/software/bash/manual/bashref.html#Shell-Arithmetic
2144
- 'operator': /--?|-=|\+\+?|\+=|!=?|~|\*\*?|\*=|\/=?|%=?|<<=?|>>=?|<=?|>=?|==?|&&?|&=|\^=?|\|\|?|\|=|\?|:/,
2288
+ 'operator': /--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,
2145
2289
  // If there is no $ sign at the beginning highlight (( and )) as punctuation
2146
2290
  'punctuation': /\(\(?|\)\)?|,|;/
2147
2291
  }
@@ -2162,7 +2306,7 @@ Prism.languages.tsx = Prism.languages.extend('jsx', typescript);
2162
2306
  'operator': /:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,
2163
2307
  'punctuation': /[\[\]]/,
2164
2308
  'environment': {
2165
- pattern: RegExp("(\\{)" + envVars),
2309
+ pattern: RegExp('(\\{)' + envVars),
2166
2310
  lookbehind: true,
2167
2311
  alias: 'constant'
2168
2312
  }
@@ -2190,13 +2334,13 @@ Prism.languages.tsx = Prism.languages.extend('jsx', typescript);
2190
2334
  // but not “foo {”
2191
2335
  {
2192
2336
  // a) and c)
2193
- pattern: /(\bfunction\s+)\w+(?=(?:\s*\(?:\s*\))?\s*\{)/,
2337
+ pattern: /(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,
2194
2338
  lookbehind: true,
2195
2339
  alias: 'function'
2196
2340
  },
2197
2341
  {
2198
2342
  // b)
2199
- pattern: /\b\w+(?=\s*\(\s*\)\s*\{)/,
2343
+ pattern: /\b[\w-]+(?=\s*\(\s*\)\s*\{)/,
2200
2344
  alias: 'function'
2201
2345
  }
2202
2346
  ],
@@ -2212,7 +2356,7 @@ Prism.languages.tsx = Prism.languages.extend('jsx', typescript);
2212
2356
  pattern: /(^|[\s;|&]|[<>]\()\w+(?=\+?=)/,
2213
2357
  inside: {
2214
2358
  'environment': {
2215
- pattern: RegExp("(^|[\\s;|&]|[<>]\\()" + envVars),
2359
+ pattern: RegExp('(^|[\\s;|&]|[<>]\\()' + envVars),
2216
2360
  lookbehind: true,
2217
2361
  alias: 'constant'
2218
2362
  }
@@ -2223,7 +2367,7 @@ Prism.languages.tsx = Prism.languages.extend('jsx', typescript);
2223
2367
  'string': [
2224
2368
  // Support for Here-documents https://en.wikipedia.org/wiki/Here_document
2225
2369
  {
2226
- pattern: /((?:^|[^<])<<-?\s*)(\w+?)\s[\s\S]*?(?:\r?\n|\r)\2/,
2370
+ pattern: /((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,
2227
2371
  lookbehind: true,
2228
2372
  greedy: true,
2229
2373
  inside: insideString
@@ -2240,14 +2384,29 @@ Prism.languages.tsx = Prism.languages.extend('jsx', typescript);
2240
2384
  },
2241
2385
  // “Normal” string
2242
2386
  {
2243
- pattern: /(^|[^\\](?:\\\\)*)(["'])(?:\\[\s\S]|\$\([^)]+\)|`[^`]+`|(?!\2)[^\\])*\2/,
2387
+ // https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html
2388
+ pattern: /(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,
2244
2389
  lookbehind: true,
2245
2390
  greedy: true,
2246
2391
  inside: insideString
2392
+ },
2393
+ {
2394
+ // https://www.gnu.org/software/bash/manual/html_node/Single-Quotes.html
2395
+ pattern: /(^|[^$\\])'[^']*'/,
2396
+ lookbehind: true,
2397
+ greedy: true
2398
+ },
2399
+ {
2400
+ // https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html
2401
+ pattern: /\$'(?:[^'\\]|\\[\s\S])*'/,
2402
+ greedy: true,
2403
+ inside: {
2404
+ 'entity': insideString.entity
2405
+ }
2247
2406
  }
2248
2407
  ],
2249
2408
  'environment': {
2250
- pattern: RegExp("\\$?" + envVars),
2409
+ pattern: RegExp('\\$?' + envVars),
2251
2410
  alias: 'constant'
2252
2411
  },
2253
2412
  'variable': insideString.variable,
@@ -2276,7 +2435,7 @@ Prism.languages.tsx = Prism.languages.extend('jsx', typescript);
2276
2435
  },
2277
2436
  'operator': {
2278
2437
  // Lots of redirections here, but not just that.
2279
- pattern: /\d?<>|>\||\+=|==?|!=?|=~|<<[<-]?|[&\d]?>>|\d?[<>]&?|&[>&]?|\|[&|]?|<=?|>=?/,
2438
+ pattern: /\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,
2280
2439
  inside: {
2281
2440
  'file-descriptor': {
2282
2441
  pattern: /^\d/,
@@ -2311,12 +2470,12 @@ Prism.languages.tsx = Prism.languages.extend('jsx', typescript);
2311
2470
  'number'
2312
2471
  ];
2313
2472
  var inside = insideString.variable[1].inside;
2314
- for(var i = 0; i < toBeCopied.length; i++) {
2473
+ for (var i = 0; i < toBeCopied.length; i++) {
2315
2474
  inside[toBeCopied[i]] = Prism.languages.bash[toBeCopied[i]];
2316
2475
  }
2317
2476
 
2318
2477
  Prism.languages.shell = Prism.languages.bash;
2319
- })(Prism);
2478
+ }(Prism));
2320
2479
 
2321
2480
  (function (Prism) {
2322
2481
 
@@ -2343,14 +2502,14 @@ Prism.languages.tsx = Prism.languages.extend('jsx', typescript);
2343
2502
  */
2344
2503
  function createValuePattern(value, flags) {
2345
2504
  flags = (flags || '').replace(/m/g, '') + 'm'; // add m flag
2346
- var pattern = /([:\-,[{]\s*(?:\s<<prop>>[ \t]+)?)(?:<<value>>)(?=[ \t]*(?:$|,|]|}|\s*#))/.source
2505
+ var pattern = /([:\-,[{]\s*(?:\s<<prop>>[ \t]+)?)(?:<<value>>)(?=[ \t]*(?:$|,|\]|\}|(?:[\r\n]\s*)?#))/.source
2347
2506
  .replace(/<<prop>>/g, function () { return properties; }).replace(/<<value>>/g, function () { return value; });
2348
- return RegExp(pattern, flags)
2507
+ return RegExp(pattern, flags);
2349
2508
  }
2350
2509
 
2351
2510
  Prism.languages.yaml = {
2352
2511
  'scalar': {
2353
- pattern: RegExp(/([\-:]\s*(?:\s<<prop>>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)[^\r\n]+(?:\2[^\r\n]+)*)/.source
2512
+ pattern: RegExp(/([\-:]\s*(?:\s<<prop>>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\S[^\r\n]*(?:\2[^\r\n]+)*)/.source
2354
2513
  .replace(/<<prop>>/g, function () { return properties; })),
2355
2514
  lookbehind: true,
2356
2515
  alias: 'string'
@@ -2370,7 +2529,7 @@ Prism.languages.tsx = Prism.languages.extend('jsx', typescript);
2370
2529
  alias: 'important'
2371
2530
  },
2372
2531
  'datetime': {
2373
- pattern: createValuePattern(/\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?)?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/.source),
2532
+ pattern: createValuePattern(/\d{4}-\d\d?-\d\d?(?:[tT]|[ \t]+)\d\d?:\d{2}:\d{2}(?:\.\d*)?(?:[ \t]*(?:Z|[-+]\d\d?(?::\d{2})?))?|\d{4}-\d{2}-\d{2}|\d\d?:\d{2}(?::\d{2}(?:\.\d*)?)?/.source),
2374
2533
  lookbehind: true,
2375
2534
  alias: 'number'
2376
2535
  },
@@ -2390,7 +2549,7 @@ Prism.languages.tsx = Prism.languages.extend('jsx', typescript);
2390
2549
  greedy: true
2391
2550
  },
2392
2551
  'number': {
2393
- pattern: createValuePattern(/[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+\.?\d*|\.?\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/.source, 'i'),
2552
+ pattern: createValuePattern(/[+-]?(?:0x[\da-f]+|0o[0-7]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?|\.inf|\.nan)/.source, 'i'),
2394
2553
  lookbehind: true
2395
2554
  },
2396
2555
  'tag': tag,