@tiptap/extension-code-block-lowlight 2.0.0-beta.2 → 2.0.0-beta.200

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.
@@ -1,13 +1,15 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@tiptap/extension-code-block'), require('prosemirror-state'), require('prosemirror-view'), require('@tiptap/core')) :
3
- typeof define === 'function' && define.amd ? define(['exports', '@tiptap/extension-code-block', 'prosemirror-state', 'prosemirror-view', '@tiptap/core'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global['@tiptap/extension-code-block-lowlight'] = {}, global.CodeBlock, global.prosemirrorState, global.prosemirrorView, global.core$2));
5
- }(this, (function (exports, CodeBlock, prosemirrorState, prosemirrorView, core$2) { 'use strict';
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@tiptap/extension-code-block'), require('@tiptap/core'), require('prosemirror-state'), require('prosemirror-view')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', '@tiptap/extension-code-block', '@tiptap/core', 'prosemirror-state', 'prosemirror-view'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["@tiptap/extension-code-block-lowlight"] = {}, global.CodeBlock, global.core$1, global.prosemirrorState, global.prosemirrorView));
5
+ })(this, (function (exports, CodeBlock, core$1, prosemirrorState, prosemirrorView) { 'use strict';
6
6
 
7
7
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
8
8
 
9
9
  var CodeBlock__default = /*#__PURE__*/_interopDefaultLegacy(CodeBlock);
10
10
 
11
+ var deepFreezeEs6 = {exports: {}};
12
+
11
13
  function deepFreeze(obj) {
12
14
  if (obj instanceof Map) {
13
15
  obj.clear = obj.delete = obj.set = function () {
@@ -34,11 +36,13 @@
34
36
  return obj;
35
37
  }
36
38
 
37
- var deepFreezeEs6 = deepFreeze;
38
- var _default = deepFreeze;
39
- deepFreezeEs6.default = _default;
39
+ deepFreezeEs6.exports = deepFreeze;
40
+ deepFreezeEs6.exports.default = deepFreeze;
40
41
 
42
+ /** @typedef {import('highlight.js').CallbackResponse} CallbackResponse */
43
+ /** @typedef {import('highlight.js').CompiledMode} CompiledMode */
41
44
  /** @implements CallbackResponse */
45
+
42
46
  class Response {
43
47
  /**
44
48
  * @param {CompiledMode} mode
@@ -77,7 +81,7 @@
77
81
  * @param {Record<string,any>[]} objects
78
82
  * @returns {T} a single new object
79
83
  */
80
- function inherit(original, ...objects) {
84
+ function inherit$1(original, ...objects) {
81
85
  /** @type Record<string,any> */
82
86
  const result = Object.create(null);
83
87
 
@@ -100,7 +104,7 @@
100
104
  * @property {() => string} value
101
105
  */
102
106
 
103
- /** @typedef {{kind?: string, sublanguage?: boolean}} Node */
107
+ /** @typedef {{scope?: string, language?: string, sublanguage?: boolean}} Node */
104
108
  /** @typedef {{walk: (r: Renderer) => void}} Tree */
105
109
  /** */
106
110
 
@@ -111,7 +115,25 @@
111
115
  *
112
116
  * @param {Node} node */
113
117
  const emitsWrappingTags = (node) => {
114
- return !!node.kind;
118
+ // rarely we can have a sublanguage where language is undefined
119
+ // TODO: track down why
120
+ return !!node.scope || (node.sublanguage && node.language);
121
+ };
122
+
123
+ /**
124
+ *
125
+ * @param {string} name
126
+ * @param {{prefix:string}} options
127
+ */
128
+ const scopeToCSSClass = (name, { prefix }) => {
129
+ if (name.includes(".")) {
130
+ const pieces = name.split(".");
131
+ return [
132
+ `${prefix}${pieces.shift()}`,
133
+ ...(pieces.map((x, i) => `${x}${"_".repeat(i + 1)}`))
134
+ ].join(" ");
135
+ }
136
+ return `${prefix}${name}`;
115
137
  };
116
138
 
117
139
  /** @type {Renderer} */
@@ -143,9 +165,11 @@
143
165
  openNode(node) {
144
166
  if (!emitsWrappingTags(node)) return;
145
167
 
146
- let className = node.kind;
147
- if (!node.sublanguage) {
148
- className = `${this.classPrefix}${className}`;
168
+ let className = "";
169
+ if (node.sublanguage) {
170
+ className = `language-${node.language}`;
171
+ } else {
172
+ className = scopeToCSSClass(node.scope, { prefix: this.classPrefix });
149
173
  }
150
174
  this.span(className);
151
175
  }
@@ -178,14 +202,23 @@
178
202
  }
179
203
  }
180
204
 
181
- /** @typedef {{kind?: string, sublanguage?: boolean, children: Node[]} | string} Node */
182
- /** @typedef {{kind?: string, sublanguage?: boolean, children: Node[]} } DataNode */
205
+ /** @typedef {{scope?: string, language?: string, sublanguage?: boolean, children: Node[]} | string} Node */
206
+ /** @typedef {{scope?: string, language?: string, sublanguage?: boolean, children: Node[]} } DataNode */
207
+ /** @typedef {import('highlight.js').Emitter} Emitter */
183
208
  /** */
184
209
 
210
+ /** @returns {DataNode} */
211
+ const newNode = (opts = {}) => {
212
+ /** @type DataNode */
213
+ const result = { children: [] };
214
+ Object.assign(result, opts);
215
+ return result;
216
+ };
217
+
185
218
  class TokenTree {
186
219
  constructor() {
187
220
  /** @type DataNode */
188
- this.rootNode = { children: [] };
221
+ this.rootNode = newNode();
189
222
  this.stack = [this.rootNode];
190
223
  }
191
224
 
@@ -200,10 +233,10 @@
200
233
  this.top.children.push(node);
201
234
  }
202
235
 
203
- /** @param {string} kind */
204
- openNode(kind) {
236
+ /** @param {string} scope */
237
+ openNode(scope) {
205
238
  /** @type Node */
206
- const node = { kind, children: [] };
239
+ const node = newNode({ scope });
207
240
  this.add(node);
208
241
  this.stack.push(node);
209
242
  }
@@ -275,11 +308,11 @@
275
308
 
276
309
  Minimal interface:
277
310
 
278
- - addKeyword(text, kind)
311
+ - addKeyword(text, scope)
279
312
  - addText(text)
280
313
  - addSublanguage(emitter, subLanguageName)
281
314
  - finalize()
282
- - openNode(kind)
315
+ - openNode(scope)
283
316
  - closeNode()
284
317
  - closeAllNodes()
285
318
  - toHTML()
@@ -300,12 +333,12 @@
300
333
 
301
334
  /**
302
335
  * @param {string} text
303
- * @param {string} kind
336
+ * @param {string} scope
304
337
  */
305
- addKeyword(text, kind) {
338
+ addKeyword(text, scope) {
306
339
  if (text === "") { return; }
307
340
 
308
- this.openNode(kind);
341
+ this.openNode(scope);
309
342
  this.addText(text);
310
343
  this.closeNode();
311
344
  }
@@ -326,8 +359,8 @@
326
359
  addSublanguage(emitter, name) {
327
360
  /** @type DataNode */
328
361
  const node = emitter.root;
329
- node.kind = name;
330
362
  node.sublanguage = true;
363
+ node.language = name;
331
364
  this.add(node);
332
365
  }
333
366
 
@@ -345,9 +378,6 @@
345
378
  * @param {string} value
346
379
  * @returns {RegExp}
347
380
  * */
348
- function escape(value) {
349
- return new RegExp(value.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'), 'm');
350
- }
351
381
 
352
382
  /**
353
383
  * @param {RegExp | string } re
@@ -360,6 +390,30 @@
360
390
  return re.source;
361
391
  }
362
392
 
393
+ /**
394
+ * @param {RegExp | string } re
395
+ * @returns {string}
396
+ */
397
+ function lookahead(re) {
398
+ return concat('(?=', re, ')');
399
+ }
400
+
401
+ /**
402
+ * @param {RegExp | string } re
403
+ * @returns {string}
404
+ */
405
+ function anyNumberOfTimes(re) {
406
+ return concat('(?:', re, ')*');
407
+ }
408
+
409
+ /**
410
+ * @param {RegExp | string } re
411
+ * @returns {string}
412
+ */
413
+ function optional(re) {
414
+ return concat('(?:', re, ')?');
415
+ }
416
+
363
417
  /**
364
418
  * @param {...(RegExp | string) } args
365
419
  * @returns {string}
@@ -369,20 +423,41 @@
369
423
  return joined;
370
424
  }
371
425
 
426
+ /**
427
+ * @param { Array<string | RegExp | Object> } args
428
+ * @returns {object}
429
+ */
430
+ function stripOptionsFromArgs(args) {
431
+ const opts = args[args.length - 1];
432
+
433
+ if (typeof opts === 'object' && opts.constructor === Object) {
434
+ args.splice(args.length - 1, 1);
435
+ return opts;
436
+ } else {
437
+ return {};
438
+ }
439
+ }
440
+
441
+ /** @typedef { {capture?: boolean} } RegexEitherOptions */
442
+
372
443
  /**
373
444
  * Any of the passed expresssions may match
374
445
  *
375
446
  * Creates a huge this | this | that | that match
376
- * @param {(RegExp | string)[] } args
447
+ * @param {(RegExp | string)[] | [...(RegExp | string)[], RegexEitherOptions]} args
377
448
  * @returns {string}
378
449
  */
379
450
  function either(...args) {
380
- const joined = '(' + args.map((x) => source(x)).join("|") + ")";
451
+ /** @type { object & {capture?: boolean} } */
452
+ const opts = stripOptionsFromArgs(args);
453
+ const joined = '('
454
+ + (opts.capture ? "" : "?:")
455
+ + args.map((x) => source(x)).join("|") + ")";
381
456
  return joined;
382
457
  }
383
458
 
384
459
  /**
385
- * @param {RegExp} re
460
+ * @param {RegExp | string} re
386
461
  * @returns {number}
387
462
  */
388
463
  function countMatchGroups(re) {
@@ -408,6 +483,7 @@
408
483
  // follow the '(' with a '?'.
409
484
  const BACKREF_RE = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;
410
485
 
486
+ // **INTERNAL** Not intended for outside usage
411
487
  // join logically computes regexps.join(separator), but fixes the
412
488
  // backreferences so they continue to match.
413
489
  // it also places each individual regular expression into it's own
@@ -415,10 +491,10 @@
415
491
  // is currently an exercise for the caller. :-)
416
492
  /**
417
493
  * @param {(string | RegExp)[]} regexps
418
- * @param {string} separator
494
+ * @param {{joinWith: string}} opts
419
495
  * @returns {string}
420
496
  */
421
- function join(regexps, separator = "|") {
497
+ function _rewriteBackreferences(regexps, { joinWith }) {
422
498
  let numCaptures = 0;
423
499
 
424
500
  return regexps.map((regex) => {
@@ -446,9 +522,12 @@
446
522
  }
447
523
  }
448
524
  return out;
449
- }).map(re => `(${re})`).join(separator);
525
+ }).map(re => `(${re})`).join(joinWith);
450
526
  }
451
527
 
528
+ /** @typedef {import('highlight.js').Mode} Mode */
529
+ /** @typedef {import('highlight.js').ModeCallback} ModeCallback */
530
+
452
531
  // Common regexps
453
532
  const MATCH_NOTHING_RE = /\b\B/;
454
533
  const IDENT_RE = '[a-zA-Z]\\w*';
@@ -470,8 +549,8 @@
470
549
  opts.binary,
471
550
  /\b.*/);
472
551
  }
473
- return inherit({
474
- className: 'meta',
552
+ return inherit$1({
553
+ scope: 'meta',
475
554
  begin: beginShebang,
476
555
  end: /$/,
477
556
  relevance: 0,
@@ -487,14 +566,14 @@
487
566
  begin: '\\\\[\\s\\S]', relevance: 0
488
567
  };
489
568
  const APOS_STRING_MODE = {
490
- className: 'string',
569
+ scope: 'string',
491
570
  begin: '\'',
492
571
  end: '\'',
493
572
  illegal: '\\n',
494
573
  contains: [BACKSLASH_ESCAPE]
495
574
  };
496
575
  const QUOTE_STRING_MODE = {
497
- className: 'string',
576
+ scope: 'string',
498
577
  begin: '"',
499
578
  end: '"',
500
579
  illegal: '\\n',
@@ -512,54 +591,88 @@
512
591
  * @returns {Partial<Mode>}
513
592
  */
514
593
  const COMMENT = function(begin, end, modeOptions = {}) {
515
- const mode = inherit(
594
+ const mode = inherit$1(
516
595
  {
517
- className: 'comment',
596
+ scope: 'comment',
518
597
  begin,
519
598
  end,
520
599
  contains: []
521
600
  },
522
601
  modeOptions
523
602
  );
524
- mode.contains.push(PHRASAL_WORDS_MODE);
525
603
  mode.contains.push({
526
- className: 'doctag',
527
- begin: '(?:TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):',
604
+ scope: 'doctag',
605
+ // hack to avoid the space from being included. the space is necessary to
606
+ // match here to prevent the plain text rule below from gobbling up doctags
607
+ begin: '[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)',
608
+ end: /(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,
609
+ excludeBegin: true,
528
610
  relevance: 0
529
611
  });
612
+ const ENGLISH_WORD = either(
613
+ // list of common 1 and 2 letter words in English
614
+ "I",
615
+ "a",
616
+ "is",
617
+ "so",
618
+ "us",
619
+ "to",
620
+ "at",
621
+ "if",
622
+ "in",
623
+ "it",
624
+ "on",
625
+ // note: this is not an exhaustive list of contractions, just popular ones
626
+ /[A-Za-z]+['](d|ve|re|ll|t|s|n)/, // contractions - can't we'd they're let's, etc
627
+ /[A-Za-z]+[-][a-z]+/, // `no-way`, etc.
628
+ /[A-Za-z][a-z]{2,}/ // allow capitalized words at beginning of sentences
629
+ );
630
+ // looking like plain text, more likely to be a comment
631
+ mode.contains.push(
632
+ {
633
+ // TODO: how to include ", (, ) without breaking grammars that use these for
634
+ // comment delimiters?
635
+ // begin: /[ ]+([()"]?([A-Za-z'-]{3,}|is|a|I|so|us|[tT][oO]|at|if|in|it|on)[.]?[()":]?([.][ ]|[ ]|\))){3}/
636
+ // ---
637
+
638
+ // this tries to find sequences of 3 english words in a row (without any
639
+ // "programming" type syntax) this gives us a strong signal that we've
640
+ // TRULY found a comment - vs perhaps scanning with the wrong language.
641
+ // It's possible to find something that LOOKS like the start of the
642
+ // comment - but then if there is no readable text - good chance it is a
643
+ // false match and not a comment.
644
+ //
645
+ // for a visual example please see:
646
+ // https://github.com/highlightjs/highlight.js/issues/2827
647
+
648
+ begin: concat(
649
+ /[ ]+/, // necessary to prevent us gobbling up doctags like /* @author Bob Mcgill */
650
+ '(',
651
+ ENGLISH_WORD,
652
+ /[.]?[:]?([.][ ]|[ ])/,
653
+ '){3}') // look for 3 words in a row
654
+ }
655
+ );
530
656
  return mode;
531
657
  };
532
658
  const C_LINE_COMMENT_MODE = COMMENT('//', '$');
533
659
  const C_BLOCK_COMMENT_MODE = COMMENT('/\\*', '\\*/');
534
660
  const HASH_COMMENT_MODE = COMMENT('#', '$');
535
661
  const NUMBER_MODE = {
536
- className: 'number',
662
+ scope: 'number',
537
663
  begin: NUMBER_RE,
538
664
  relevance: 0
539
665
  };
540
666
  const C_NUMBER_MODE = {
541
- className: 'number',
667
+ scope: 'number',
542
668
  begin: C_NUMBER_RE,
543
669
  relevance: 0
544
670
  };
545
671
  const BINARY_NUMBER_MODE = {
546
- className: 'number',
672
+ scope: 'number',
547
673
  begin: BINARY_NUMBER_RE,
548
674
  relevance: 0
549
675
  };
550
- const CSS_NUMBER_MODE = {
551
- className: 'number',
552
- begin: NUMBER_RE + '(' +
553
- '%|em|ex|ch|rem' +
554
- '|vw|vh|vmin|vmax' +
555
- '|cm|mm|in|pt|pc|px' +
556
- '|deg|grad|rad|turn' +
557
- '|s|ms' +
558
- '|Hz|kHz' +
559
- '|dpi|dpcm|dppx' +
560
- ')?',
561
- relevance: 0
562
- };
563
676
  const REGEXP_MODE = {
564
677
  // this outer rule makes sure we actually have a WHOLE regex and not simply
565
678
  // an expression such as:
@@ -569,7 +682,7 @@
569
682
  // (which will then blow up when regex's `illegal` sees the newline)
570
683
  begin: /(?=\/[^/\n]*\/)/,
571
684
  contains: [{
572
- className: 'regexp',
685
+ scope: 'regexp',
573
686
  begin: /\//,
574
687
  end: /\/[gimuy]*/,
575
688
  illegal: /\n/,
@@ -585,12 +698,12 @@
585
698
  }]
586
699
  };
587
700
  const TITLE_MODE = {
588
- className: 'title',
701
+ scope: 'title',
589
702
  begin: IDENT_RE,
590
703
  relevance: 0
591
704
  };
592
705
  const UNDERSCORE_TITLE_MODE = {
593
- className: 'title',
706
+ scope: 'title',
594
707
  begin: UNDERSCORE_IDENT_RE,
595
708
  relevance: 0
596
709
  };
@@ -638,7 +751,6 @@
638
751
  NUMBER_MODE: NUMBER_MODE,
639
752
  C_NUMBER_MODE: C_NUMBER_MODE,
640
753
  BINARY_NUMBER_MODE: BINARY_NUMBER_MODE,
641
- CSS_NUMBER_MODE: CSS_NUMBER_MODE,
642
754
  REGEXP_MODE: REGEXP_MODE,
643
755
  TITLE_MODE: TITLE_MODE,
644
756
  UNDERSCORE_TITLE_MODE: UNDERSCORE_TITLE_MODE,
@@ -646,6 +758,11 @@
646
758
  END_SAME_AS_BEGIN: END_SAME_AS_BEGIN
647
759
  });
648
760
 
761
+ /**
762
+ @typedef {import('highlight.js').CallbackResponse} CallbackResponse
763
+ @typedef {import('highlight.js').CompilerExt} CompilerExt
764
+ */
765
+
649
766
  // Grammar extensions / plugins
650
767
  // See: https://github.com/highlightjs/highlight.js/issues/2833
651
768
 
@@ -670,13 +787,24 @@
670
787
  * @param {RegExpMatchArray} match
671
788
  * @param {CallbackResponse} response
672
789
  */
673
- function skipIfhasPrecedingDot(match, response) {
790
+ function skipIfHasPrecedingDot(match, response) {
674
791
  const before = match.input[match.index - 1];
675
792
  if (before === ".") {
676
793
  response.ignoreMatch();
677
794
  }
678
795
  }
679
796
 
797
+ /**
798
+ *
799
+ * @type {CompilerExt}
800
+ */
801
+ function scopeClassName(mode, _parent) {
802
+ // eslint-disable-next-line no-undefined
803
+ if (mode.className !== undefined) {
804
+ mode.scope = mode.className;
805
+ delete mode.className;
806
+ }
807
+ }
680
808
 
681
809
  /**
682
810
  * `beginKeywords` syntactic sugar
@@ -692,7 +820,7 @@
692
820
  // doesn't allow spaces in keywords anyways and we still check for the boundary
693
821
  // first
694
822
  mode.begin = '\\b(' + mode.beginKeywords.split(' ').join('|') + ')(?!\\.)(?=\\b|\\s)';
695
- mode.__beforeBegin = skipIfhasPrecedingDot;
823
+ mode.__beforeBegin = skipIfHasPrecedingDot;
696
824
  mode.keywords = mode.keywords || mode.beginKeywords;
697
825
  delete mode.beginKeywords;
698
826
 
@@ -733,6 +861,30 @@
733
861
  if (mode.relevance === undefined) mode.relevance = 1;
734
862
  }
735
863
 
864
+ // allow beforeMatch to act as a "qualifier" for the match
865
+ // the full match begin must be [beforeMatch][begin]
866
+ const beforeMatchExt = (mode, parent) => {
867
+ if (!mode.beforeMatch) return;
868
+ // starts conflicts with endsParent which we need to make sure the child
869
+ // rule is not matched multiple times
870
+ if (mode.starts) throw new Error("beforeMatch cannot be used with starts");
871
+
872
+ const originalMode = Object.assign({}, mode);
873
+ Object.keys(mode).forEach((key) => { delete mode[key]; });
874
+
875
+ mode.keywords = originalMode.keywords;
876
+ mode.begin = concat(originalMode.beforeMatch, lookahead(originalMode.begin));
877
+ mode.starts = {
878
+ relevance: 0,
879
+ contains: [
880
+ Object.assign(originalMode, { endsParent: true })
881
+ ]
882
+ };
883
+ mode.relevance = 0;
884
+
885
+ delete originalMode.beforeMatch;
886
+ };
887
+
736
888
  // keywords that should have no default relevance value
737
889
  const COMMON_KEYWORDS = [
738
890
  'of',
@@ -748,7 +900,7 @@
748
900
  'value' // common variable name
749
901
  ];
750
902
 
751
- const DEFAULT_KEYWORD_CLASSNAME = "keyword";
903
+ const DEFAULT_KEYWORD_SCOPE = "keyword";
752
904
 
753
905
  /**
754
906
  * Given raw keywords from a language definition, compile them.
@@ -756,22 +908,22 @@
756
908
  * @param {string | Record<string,string|string[]> | Array<string>} rawKeywords
757
909
  * @param {boolean} caseInsensitive
758
910
  */
759
- function compileKeywords(rawKeywords, caseInsensitive, className = DEFAULT_KEYWORD_CLASSNAME) {
911
+ function compileKeywords(rawKeywords, caseInsensitive, scopeName = DEFAULT_KEYWORD_SCOPE) {
760
912
  /** @type KeywordDict */
761
- const compiledKeywords = {};
913
+ const compiledKeywords = Object.create(null);
762
914
 
763
915
  // input can be a string of keywords, an array of keywords, or a object with
764
- // named keys representing className (which can then point to a string or array)
916
+ // named keys representing scopeName (which can then point to a string or array)
765
917
  if (typeof rawKeywords === 'string') {
766
- compileList(className, rawKeywords.split(" "));
918
+ compileList(scopeName, rawKeywords.split(" "));
767
919
  } else if (Array.isArray(rawKeywords)) {
768
- compileList(className, rawKeywords);
920
+ compileList(scopeName, rawKeywords);
769
921
  } else {
770
- Object.keys(rawKeywords).forEach(function(className) {
922
+ Object.keys(rawKeywords).forEach(function(scopeName) {
771
923
  // collapse all our objects back into the parent object
772
924
  Object.assign(
773
925
  compiledKeywords,
774
- compileKeywords(rawKeywords[className], caseInsensitive, className)
926
+ compileKeywords(rawKeywords[scopeName], caseInsensitive, scopeName)
775
927
  );
776
928
  });
777
929
  }
@@ -784,16 +936,16 @@
784
936
  *
785
937
  * Ex: "for if when while|5"
786
938
  *
787
- * @param {string} className
939
+ * @param {string} scopeName
788
940
  * @param {Array<string>} keywordList
789
941
  */
790
- function compileList(className, keywordList) {
942
+ function compileList(scopeName, keywordList) {
791
943
  if (caseInsensitive) {
792
944
  keywordList = keywordList.map(x => x.toLowerCase());
793
945
  }
794
946
  keywordList.forEach(function(keyword) {
795
947
  const pair = keyword.split('|');
796
- compiledKeywords[pair[0]] = [className, scoreForKeyword(pair[0], pair[1])];
948
+ compiledKeywords[pair[0]] = [scopeName, scoreForKeyword(pair[0], pair[1])];
797
949
  });
798
950
  }
799
951
  }
@@ -824,6 +976,183 @@
824
976
  return COMMON_KEYWORDS.includes(keyword.toLowerCase());
825
977
  }
826
978
 
979
+ /*
980
+
981
+ For the reasoning behind this please see:
982
+ https://github.com/highlightjs/highlight.js/issues/2880#issuecomment-747275419
983
+
984
+ */
985
+
986
+ /**
987
+ * @type {Record<string, boolean>}
988
+ */
989
+ const seenDeprecations = {};
990
+
991
+ /**
992
+ * @param {string} message
993
+ */
994
+ const error = (message) => {
995
+ console.error(message);
996
+ };
997
+
998
+ /**
999
+ * @param {string} message
1000
+ * @param {any} args
1001
+ */
1002
+ const warn = (message, ...args) => {
1003
+ console.log(`WARN: ${message}`, ...args);
1004
+ };
1005
+
1006
+ /**
1007
+ * @param {string} version
1008
+ * @param {string} message
1009
+ */
1010
+ const deprecated = (version, message) => {
1011
+ if (seenDeprecations[`${version}/${message}`]) return;
1012
+
1013
+ console.log(`Deprecated as of ${version}. ${message}`);
1014
+ seenDeprecations[`${version}/${message}`] = true;
1015
+ };
1016
+
1017
+ /* eslint-disable no-throw-literal */
1018
+
1019
+ /**
1020
+ @typedef {import('highlight.js').CompiledMode} CompiledMode
1021
+ */
1022
+
1023
+ const MultiClassError = new Error();
1024
+
1025
+ /**
1026
+ * Renumbers labeled scope names to account for additional inner match
1027
+ * groups that otherwise would break everything.
1028
+ *
1029
+ * Lets say we 3 match scopes:
1030
+ *
1031
+ * { 1 => ..., 2 => ..., 3 => ... }
1032
+ *
1033
+ * So what we need is a clean match like this:
1034
+ *
1035
+ * (a)(b)(c) => [ "a", "b", "c" ]
1036
+ *
1037
+ * But this falls apart with inner match groups:
1038
+ *
1039
+ * (a)(((b)))(c) => ["a", "b", "b", "b", "c" ]
1040
+ *
1041
+ * Our scopes are now "out of alignment" and we're repeating `b` 3 times.
1042
+ * What needs to happen is the numbers are remapped:
1043
+ *
1044
+ * { 1 => ..., 2 => ..., 5 => ... }
1045
+ *
1046
+ * We also need to know that the ONLY groups that should be output
1047
+ * are 1, 2, and 5. This function handles this behavior.
1048
+ *
1049
+ * @param {CompiledMode} mode
1050
+ * @param {Array<RegExp | string>} regexes
1051
+ * @param {{key: "beginScope"|"endScope"}} opts
1052
+ */
1053
+ function remapScopeNames(mode, regexes, { key }) {
1054
+ let offset = 0;
1055
+ const scopeNames = mode[key];
1056
+ /** @type Record<number,boolean> */
1057
+ const emit = {};
1058
+ /** @type Record<number,string> */
1059
+ const positions = {};
1060
+
1061
+ for (let i = 1; i <= regexes.length; i++) {
1062
+ positions[i + offset] = scopeNames[i];
1063
+ emit[i + offset] = true;
1064
+ offset += countMatchGroups(regexes[i - 1]);
1065
+ }
1066
+ // we use _emit to keep track of which match groups are "top-level" to avoid double
1067
+ // output from inside match groups
1068
+ mode[key] = positions;
1069
+ mode[key]._emit = emit;
1070
+ mode[key]._multi = true;
1071
+ }
1072
+
1073
+ /**
1074
+ * @param {CompiledMode} mode
1075
+ */
1076
+ function beginMultiClass(mode) {
1077
+ if (!Array.isArray(mode.begin)) return;
1078
+
1079
+ if (mode.skip || mode.excludeBegin || mode.returnBegin) {
1080
+ error("skip, excludeBegin, returnBegin not compatible with beginScope: {}");
1081
+ throw MultiClassError;
1082
+ }
1083
+
1084
+ if (typeof mode.beginScope !== "object" || mode.beginScope === null) {
1085
+ error("beginScope must be object");
1086
+ throw MultiClassError;
1087
+ }
1088
+
1089
+ remapScopeNames(mode, mode.begin, { key: "beginScope" });
1090
+ mode.begin = _rewriteBackreferences(mode.begin, { joinWith: "" });
1091
+ }
1092
+
1093
+ /**
1094
+ * @param {CompiledMode} mode
1095
+ */
1096
+ function endMultiClass(mode) {
1097
+ if (!Array.isArray(mode.end)) return;
1098
+
1099
+ if (mode.skip || mode.excludeEnd || mode.returnEnd) {
1100
+ error("skip, excludeEnd, returnEnd not compatible with endScope: {}");
1101
+ throw MultiClassError;
1102
+ }
1103
+
1104
+ if (typeof mode.endScope !== "object" || mode.endScope === null) {
1105
+ error("endScope must be object");
1106
+ throw MultiClassError;
1107
+ }
1108
+
1109
+ remapScopeNames(mode, mode.end, { key: "endScope" });
1110
+ mode.end = _rewriteBackreferences(mode.end, { joinWith: "" });
1111
+ }
1112
+
1113
+ /**
1114
+ * this exists only to allow `scope: {}` to be used beside `match:`
1115
+ * Otherwise `beginScope` would necessary and that would look weird
1116
+
1117
+ {
1118
+ match: [ /def/, /\w+/ ]
1119
+ scope: { 1: "keyword" , 2: "title" }
1120
+ }
1121
+
1122
+ * @param {CompiledMode} mode
1123
+ */
1124
+ function scopeSugar(mode) {
1125
+ if (mode.scope && typeof mode.scope === "object" && mode.scope !== null) {
1126
+ mode.beginScope = mode.scope;
1127
+ delete mode.scope;
1128
+ }
1129
+ }
1130
+
1131
+ /**
1132
+ * @param {CompiledMode} mode
1133
+ */
1134
+ function MultiClass(mode) {
1135
+ scopeSugar(mode);
1136
+
1137
+ if (typeof mode.beginScope === "string") {
1138
+ mode.beginScope = { _wrap: mode.beginScope };
1139
+ }
1140
+ if (typeof mode.endScope === "string") {
1141
+ mode.endScope = { _wrap: mode.endScope };
1142
+ }
1143
+
1144
+ beginMultiClass(mode);
1145
+ endMultiClass(mode);
1146
+ }
1147
+
1148
+ /**
1149
+ @typedef {import('highlight.js').Mode} Mode
1150
+ @typedef {import('highlight.js').CompiledMode} CompiledMode
1151
+ @typedef {import('highlight.js').Language} Language
1152
+ @typedef {import('highlight.js').HLJSPlugin} HLJSPlugin
1153
+ @typedef {import('highlight.js').CompiledLanguage} CompiledLanguage
1154
+ */
1155
+
827
1156
  // compilation
828
1157
 
829
1158
  /**
@@ -832,12 +1161,11 @@
832
1161
  * Given the raw result of a language definition (Language), compiles this so
833
1162
  * that it is ready for highlighting code.
834
1163
  * @param {Language} language
835
- * @param {{plugins: HLJSPlugin[]}} opts
836
1164
  * @returns {CompiledLanguage}
837
1165
  */
838
- function compileLanguage(language, { plugins }) {
1166
+ function compileLanguage(language) {
839
1167
  /**
840
- * Builds a regex with the case sensativility of the current language
1168
+ * Builds a regex with the case sensitivity of the current language
841
1169
  *
842
1170
  * @param {RegExp | string} value
843
1171
  * @param {boolean} [global]
@@ -845,7 +1173,10 @@
845
1173
  function langRe(value, global) {
846
1174
  return new RegExp(
847
1175
  source(value),
848
- 'm' + (language.case_insensitive ? 'i' : '') + (global ? 'g' : '')
1176
+ 'm'
1177
+ + (language.case_insensitive ? 'i' : '')
1178
+ + (language.unicodeRegex ? 'u' : '')
1179
+ + (global ? 'g' : '')
849
1180
  );
850
1181
  }
851
1182
 
@@ -887,7 +1218,7 @@
887
1218
  this.exec = () => null;
888
1219
  }
889
1220
  const terminators = this.regexes.map(el => el[1]);
890
- this.matcherRe = langRe(join(terminators), true);
1221
+ this.matcherRe = langRe(_rewriteBackreferences(terminators, { joinWith: '|' }), true);
891
1222
  this.lastIndex = 0;
892
1223
  }
893
1224
 
@@ -1100,9 +1431,12 @@
1100
1431
  if (mode.isCompiled) return cmode;
1101
1432
 
1102
1433
  [
1434
+ scopeClassName,
1103
1435
  // do this early so compiler extensions generally don't have to worry about
1104
1436
  // the distinction between match/begin
1105
- compileMatch
1437
+ compileMatch,
1438
+ MultiClass,
1439
+ beforeMatchExt
1106
1440
  ].forEach(ext => ext(mode, parent));
1107
1441
 
1108
1442
  language.compilerExtensions.forEach(ext => ext(mode, parent));
@@ -1122,32 +1456,28 @@
1122
1456
  mode.isCompiled = true;
1123
1457
 
1124
1458
  let keywordPattern = null;
1125
- if (typeof mode.keywords === "object") {
1459
+ if (typeof mode.keywords === "object" && mode.keywords.$pattern) {
1460
+ // we need a copy because keywords might be compiled multiple times
1461
+ // so we can't go deleting $pattern from the original on the first
1462
+ // pass
1463
+ mode.keywords = Object.assign({}, mode.keywords);
1126
1464
  keywordPattern = mode.keywords.$pattern;
1127
1465
  delete mode.keywords.$pattern;
1128
1466
  }
1467
+ keywordPattern = keywordPattern || /\w+/;
1129
1468
 
1130
1469
  if (mode.keywords) {
1131
1470
  mode.keywords = compileKeywords(mode.keywords, language.case_insensitive);
1132
1471
  }
1133
1472
 
1134
- // both are not allowed
1135
- if (mode.lexemes && keywordPattern) {
1136
- throw new Error("ERR: Prefer `keywords.$pattern` to `mode.lexemes`, BOTH are not allowed. (see mode reference) ");
1137
- }
1138
-
1139
- // `mode.lexemes` was the old standard before we added and now recommend
1140
- // using `keywords.$pattern` to pass the keyword pattern
1141
- keywordPattern = keywordPattern || mode.lexemes || /\w+/;
1142
1473
  cmode.keywordPatternRe = langRe(keywordPattern, true);
1143
1474
 
1144
1475
  if (parent) {
1145
1476
  if (!mode.begin) mode.begin = /\B|\b/;
1146
- cmode.beginRe = langRe(mode.begin);
1147
- if (mode.endSameAsBegin) mode.end = mode.begin;
1477
+ cmode.beginRe = langRe(cmode.begin);
1148
1478
  if (!mode.end && !mode.endsWithParent) mode.end = /\B|\b/;
1149
- if (mode.end) cmode.endRe = langRe(mode.end);
1150
- cmode.terminatorEnd = source(mode.end) || '';
1479
+ if (mode.end) cmode.endRe = langRe(cmode.end);
1480
+ cmode.terminatorEnd = source(cmode.end) || '';
1151
1481
  if (mode.endsWithParent && parent.terminatorEnd) {
1152
1482
  cmode.terminatorEnd += (mode.end ? '|' : '') + parent.terminatorEnd;
1153
1483
  }
@@ -1176,7 +1506,7 @@
1176
1506
  }
1177
1507
 
1178
1508
  // we need a null object, which inherit will guarantee
1179
- language.classNameAliases = inherit(language.classNameAliases || {});
1509
+ language.classNameAliases = inherit$1(language.classNameAliases || {});
1180
1510
 
1181
1511
  return compileMode(/** @type Mode */ (language));
1182
1512
  }
@@ -1211,7 +1541,7 @@
1211
1541
  function expandOrCloneMode(mode) {
1212
1542
  if (mode.variants && !mode.cachedVariants) {
1213
1543
  mode.cachedVariants = mode.variants.map(function(variant) {
1214
- return inherit(mode, { variants: null }, variant);
1544
+ return inherit$1(mode, { variants: null }, variant);
1215
1545
  });
1216
1546
  }
1217
1547
 
@@ -1227,280 +1557,58 @@
1227
1557
  // instance of ourselves, so we can be reused with many
1228
1558
  // different parents without issue
1229
1559
  if (dependencyOnParent(mode)) {
1230
- return inherit(mode, { starts: mode.starts ? inherit(mode.starts) : null });
1560
+ return inherit$1(mode, { starts: mode.starts ? inherit$1(mode.starts) : null });
1231
1561
  }
1232
1562
 
1233
1563
  if (Object.isFrozen(mode)) {
1234
- return inherit(mode);
1564
+ return inherit$1(mode);
1235
1565
  }
1236
1566
 
1237
1567
  // no special dependency issues, just return ourselves
1238
1568
  return mode;
1239
1569
  }
1240
1570
 
1241
- var version = "10.7.1";
1242
-
1243
- // @ts-nocheck
1571
+ var version = "11.6.0";
1244
1572
 
1245
- function hasValueOrEmptyAttribute(value) {
1246
- return Boolean(value || value === "");
1247
- }
1248
-
1249
- function BuildVuePlugin(hljs) {
1250
- const Component = {
1251
- props: ["language", "code", "autodetect"],
1252
- data: function() {
1253
- return {
1254
- detectedLanguage: "",
1255
- unknownLanguage: false
1256
- };
1257
- },
1258
- computed: {
1259
- className() {
1260
- if (this.unknownLanguage) return "";
1261
-
1262
- return "hljs " + this.detectedLanguage;
1263
- },
1264
- highlighted() {
1265
- // no idea what language to use, return raw code
1266
- if (!this.autoDetect && !hljs.getLanguage(this.language)) {
1267
- console.warn(`The language "${this.language}" you specified could not be found.`);
1268
- this.unknownLanguage = true;
1269
- return escapeHTML(this.code);
1270
- }
1271
-
1272
- let result = {};
1273
- if (this.autoDetect) {
1274
- result = hljs.highlightAuto(this.code);
1275
- this.detectedLanguage = result.language;
1276
- } else {
1277
- result = hljs.highlight(this.language, this.code, this.ignoreIllegals);
1278
- this.detectedLanguage = this.language;
1279
- }
1280
- return result.value;
1281
- },
1282
- autoDetect() {
1283
- return !this.language || hasValueOrEmptyAttribute(this.autodetect);
1284
- },
1285
- ignoreIllegals() {
1286
- return true;
1287
- }
1288
- },
1289
- // this avoids needing to use a whole Vue compilation pipeline just
1290
- // to build Highlight.js
1291
- render(createElement) {
1292
- return createElement("pre", {}, [
1293
- createElement("code", {
1294
- class: this.className,
1295
- domProps: { innerHTML: this.highlighted }
1296
- })
1297
- ]);
1298
- }
1299
- // template: `<pre><code :class="className" v-html="highlighted"></code></pre>`
1300
- };
1301
-
1302
- const VuePlugin = {
1303
- install(Vue) {
1304
- Vue.component('highlightjs', Component);
1305
- }
1306
- };
1307
-
1308
- return { Component, VuePlugin };
1309
- }
1310
-
1311
- /* plugin itself */
1312
-
1313
- /** @type {HLJSPlugin} */
1314
- const mergeHTMLPlugin = {
1315
- "after:highlightElement": ({ el, result, text }) => {
1316
- const originalStream = nodeStream(el);
1317
- if (!originalStream.length) return;
1318
-
1319
- const resultNode = document.createElement('div');
1320
- resultNode.innerHTML = result.value;
1321
- result.value = mergeStreams(originalStream, nodeStream(resultNode), text);
1322
- }
1323
- };
1324
-
1325
- /* Stream merging support functions */
1326
-
1327
- /**
1328
- * @typedef Event
1329
- * @property {'start'|'stop'} event
1330
- * @property {number} offset
1331
- * @property {Node} node
1332
- */
1333
-
1334
- /**
1335
- * @param {Node} node
1336
- */
1337
- function tag(node) {
1338
- return node.nodeName.toLowerCase();
1339
- }
1340
-
1341
- /**
1342
- * @param {Node} node
1343
- */
1344
- function nodeStream(node) {
1345
- /** @type Event[] */
1346
- const result = [];
1347
- (function _nodeStream(node, offset) {
1348
- for (let child = node.firstChild; child; child = child.nextSibling) {
1349
- if (child.nodeType === 3) {
1350
- offset += child.nodeValue.length;
1351
- } else if (child.nodeType === 1) {
1352
- result.push({
1353
- event: 'start',
1354
- offset: offset,
1355
- node: child
1356
- });
1357
- offset = _nodeStream(child, offset);
1358
- // Prevent void elements from having an end tag that would actually
1359
- // double them in the output. There are more void elements in HTML
1360
- // but we list only those realistically expected in code display.
1361
- if (!tag(child).match(/br|hr|img|input/)) {
1362
- result.push({
1363
- event: 'stop',
1364
- offset: offset,
1365
- node: child
1366
- });
1367
- }
1368
- }
1369
- }
1370
- return offset;
1371
- })(node, 0);
1372
- return result;
1373
- }
1374
-
1375
- /**
1376
- * @param {any} original - the original stream
1377
- * @param {any} highlighted - stream of the highlighted source
1378
- * @param {string} value - the original source itself
1379
- */
1380
- function mergeStreams(original, highlighted, value) {
1381
- let processed = 0;
1382
- let result = '';
1383
- const nodeStack = [];
1384
-
1385
- function selectStream() {
1386
- if (!original.length || !highlighted.length) {
1387
- return original.length ? original : highlighted;
1388
- }
1389
- if (original[0].offset !== highlighted[0].offset) {
1390
- return (original[0].offset < highlighted[0].offset) ? original : highlighted;
1391
- }
1392
-
1393
- /*
1394
- To avoid starting the stream just before it should stop the order is
1395
- ensured that original always starts first and closes last:
1396
-
1397
- if (event1 == 'start' && event2 == 'start')
1398
- return original;
1399
- if (event1 == 'start' && event2 == 'stop')
1400
- return highlighted;
1401
- if (event1 == 'stop' && event2 == 'start')
1402
- return original;
1403
- if (event1 == 'stop' && event2 == 'stop')
1404
- return highlighted;
1405
-
1406
- ... which is collapsed to:
1407
- */
1408
- return highlighted[0].event === 'start' ? original : highlighted;
1409
- }
1410
-
1411
- /**
1412
- * @param {Node} node
1413
- */
1414
- function open(node) {
1415
- /** @param {Attr} attr */
1416
- function attributeString(attr) {
1417
- return ' ' + attr.nodeName + '="' + escapeHTML(attr.value) + '"';
1418
- }
1419
- // @ts-ignore
1420
- result += '<' + tag(node) + [].map.call(node.attributes, attributeString).join('') + '>';
1421
- }
1422
-
1423
- /**
1424
- * @param {Node} node
1425
- */
1426
- function close(node) {
1427
- result += '</' + tag(node) + '>';
1573
+ class HTMLInjectionError extends Error {
1574
+ constructor(reason, html) {
1575
+ super(reason);
1576
+ this.name = "HTMLInjectionError";
1577
+ this.html = html;
1428
1578
  }
1429
-
1430
- /**
1431
- * @param {Event} event
1432
- */
1433
- function render(event) {
1434
- (event.event === 'start' ? open : close)(event.node);
1435
- }
1436
-
1437
- while (original.length || highlighted.length) {
1438
- let stream = selectStream();
1439
- result += escapeHTML(value.substring(processed, stream[0].offset));
1440
- processed = stream[0].offset;
1441
- if (stream === original) {
1442
- /*
1443
- On any opening or closing tag of the original markup we first close
1444
- the entire highlighted node stack, then render the original tag along
1445
- with all the following original tags at the same offset and then
1446
- reopen all the tags on the highlighted stack.
1447
- */
1448
- nodeStack.reverse().forEach(close);
1449
- do {
1450
- render(stream.splice(0, 1)[0]);
1451
- stream = selectStream();
1452
- } while (stream === original && stream.length && stream[0].offset === processed);
1453
- nodeStack.reverse().forEach(open);
1454
- } else {
1455
- if (stream[0].event === 'start') {
1456
- nodeStack.push(stream[0].node);
1457
- } else {
1458
- nodeStack.pop();
1459
- }
1460
- render(stream.splice(0, 1)[0]);
1461
- }
1462
- }
1463
- return result + escapeHTML(value.substr(processed));
1464
1579
  }
1465
1580
 
1466
1581
  /*
1467
-
1468
- For the reasoning behind this please see:
1469
- https://github.com/highlightjs/highlight.js/issues/2880#issuecomment-747275419
1470
-
1582
+ Syntax highlighting with language autodetection.
1583
+ https://highlightjs.org/
1471
1584
  */
1472
1585
 
1473
1586
  /**
1474
- * @param {string} message
1475
- */
1476
- const error = (message) => {
1477
- console.error(message);
1478
- };
1479
-
1480
- /**
1481
- * @param {string} message
1482
- * @param {any} args
1483
- */
1484
- const warn = (message, ...args) => {
1485
- console.log(`WARN: ${message}`, ...args);
1486
- };
1487
-
1488
- /**
1489
- * @param {string} version
1490
- * @param {string} message
1491
- */
1492
- const deprecated = (version, message) => {
1493
- console.log(`Deprecated as of ${version}. ${message}`);
1494
- };
1495
-
1496
- /*
1497
- Syntax highlighting with language autodetection.
1498
- https://highlightjs.org/
1587
+ @typedef {import('highlight.js').Mode} Mode
1588
+ @typedef {import('highlight.js').CompiledMode} CompiledMode
1589
+ @typedef {import('highlight.js').CompiledScope} CompiledScope
1590
+ @typedef {import('highlight.js').Language} Language
1591
+ @typedef {import('highlight.js').HLJSApi} HLJSApi
1592
+ @typedef {import('highlight.js').HLJSPlugin} HLJSPlugin
1593
+ @typedef {import('highlight.js').PluginEvent} PluginEvent
1594
+ @typedef {import('highlight.js').HLJSOptions} HLJSOptions
1595
+ @typedef {import('highlight.js').LanguageFn} LanguageFn
1596
+ @typedef {import('highlight.js').HighlightedHTMLElement} HighlightedHTMLElement
1597
+ @typedef {import('highlight.js').BeforeHighlightContext} BeforeHighlightContext
1598
+ @typedef {import('highlight.js/private').MatchType} MatchType
1599
+ @typedef {import('highlight.js/private').KeywordData} KeywordData
1600
+ @typedef {import('highlight.js/private').EnhancedMatch} EnhancedMatch
1601
+ @typedef {import('highlight.js/private').AnnotatedError} AnnotatedError
1602
+ @typedef {import('highlight.js').AutoHighlightResult} AutoHighlightResult
1603
+ @typedef {import('highlight.js').HighlightOptions} HighlightOptions
1604
+ @typedef {import('highlight.js').HighlightResult} HighlightResult
1499
1605
  */
1500
1606
 
1501
- const escape$1 = escapeHTML;
1502
- const inherit$1 = inherit;
1607
+
1608
+ const escape = escapeHTML;
1609
+ const inherit = inherit$1;
1503
1610
  const NO_MATCH = Symbol("nomatch");
1611
+ const MAX_KEYWORD_HITS = 7;
1504
1612
 
1505
1613
  /**
1506
1614
  * @param {any} hljs - object that is extended (legacy)
@@ -1518,7 +1626,6 @@
1518
1626
  // safe/production mode - swallows more errors, tries to keep running
1519
1627
  // even if a single syntax or parse hits a fatal error
1520
1628
  let SAFE_MODE = true;
1521
- const fixMarkupRe = /(^(<[^>]+>|\t|)+|\n)/gm;
1522
1629
  const LANGUAGE_NOT_FOUND = "Could not find the language '{}', did you forget to load/include a language module?";
1523
1630
  /** @type {Language} */
1524
1631
  const PLAINTEXT_LANGUAGE = { disableAutodetect: true, name: 'Plain text', contains: [] };
@@ -1527,11 +1634,12 @@
1527
1634
  // calling the `hljs.configure` function.
1528
1635
  /** @type HLJSOptions */
1529
1636
  let options = {
1637
+ ignoreUnescapedHTML: false,
1638
+ throwUnescapedHTML: false,
1530
1639
  noHighlightRe: /^(no-?highlight)$/i,
1531
1640
  languageDetectRe: /\blang(?:uage)?-([\w-]+)\b/i,
1532
1641
  classPrefix: 'hljs-',
1533
- tabReplace: null,
1534
- useBR: false,
1642
+ cssSelector: 'pre code',
1535
1643
  languages: null,
1536
1644
  // beta configuration options, subject to change, welcome to discuss
1537
1645
  // https://github.com/highlightjs/highlight.js/issues/1086
@@ -1581,10 +1689,9 @@
1581
1689
  * NEW API
1582
1690
  * highlight(code, {lang, ignoreIllegals})
1583
1691
  *
1584
- * @param {string} codeOrlanguageName - the language to use for highlighting
1692
+ * @param {string} codeOrLanguageName - the language to use for highlighting
1585
1693
  * @param {string | HighlightOptions} optionsOrCode - the code to highlight
1586
1694
  * @param {boolean} [ignoreIllegals] - whether to ignore illegal matches, default is to bail
1587
- * @param {CompiledMode} [continuation] - current continuation mode, if any
1588
1695
  *
1589
1696
  * @returns {HighlightResult} Result - an object that represents the result
1590
1697
  * @property {string} language - the language name
@@ -1594,24 +1701,25 @@
1594
1701
  * @property {CompiledMode} top - top of the current mode stack
1595
1702
  * @property {boolean} illegal - indicates whether any illegal matches were found
1596
1703
  */
1597
- function highlight(codeOrlanguageName, optionsOrCode, ignoreIllegals, continuation) {
1704
+ function highlight(codeOrLanguageName, optionsOrCode, ignoreIllegals) {
1598
1705
  let code = "";
1599
1706
  let languageName = "";
1600
1707
  if (typeof optionsOrCode === "object") {
1601
- code = codeOrlanguageName;
1708
+ code = codeOrLanguageName;
1602
1709
  ignoreIllegals = optionsOrCode.ignoreIllegals;
1603
1710
  languageName = optionsOrCode.language;
1604
- // continuation not supported at all via the new API
1605
- // eslint-disable-next-line no-undefined
1606
- continuation = undefined;
1607
1711
  } else {
1608
1712
  // old API
1609
1713
  deprecated("10.7.0", "highlight(lang, code, ...args) has been deprecated.");
1610
1714
  deprecated("10.7.0", "Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277");
1611
- languageName = codeOrlanguageName;
1715
+ languageName = codeOrLanguageName;
1612
1716
  code = optionsOrCode;
1613
1717
  }
1614
1718
 
1719
+ // https://github.com/highlightjs/highlight.js/issues/3149
1720
+ // eslint-disable-next-line no-undefined
1721
+ if (ignoreIllegals === undefined) { ignoreIllegals = true; }
1722
+
1615
1723
  /** @type {BeforeHighlightContext} */
1616
1724
  const context = {
1617
1725
  code,
@@ -1625,7 +1733,7 @@
1625
1733
  // in which case we don't even need to call highlight
1626
1734
  const result = context.result
1627
1735
  ? context.result
1628
- : _highlight(context.language, context.code, ignoreIllegals, continuation);
1736
+ : _highlight(context.language, context.code, ignoreIllegals);
1629
1737
 
1630
1738
  result.code = context.code;
1631
1739
  // the plugin can change anything in result to suite it
@@ -1644,15 +1752,16 @@
1644
1752
  * @returns {HighlightResult} - result of the highlight operation
1645
1753
  */
1646
1754
  function _highlight(languageName, codeToHighlight, ignoreIllegals, continuation) {
1755
+ const keywordHits = Object.create(null);
1756
+
1647
1757
  /**
1648
1758
  * Return keyword data if a match is a keyword
1649
1759
  * @param {CompiledMode} mode - current mode
1650
- * @param {RegExpMatchArray} match - regexp match data
1760
+ * @param {string} matchText - the textual match
1651
1761
  * @returns {KeywordData | false}
1652
1762
  */
1653
- function keywordData(mode, match) {
1654
- const matchText = language.case_insensitive ? match[0].toLowerCase() : match[0];
1655
- return Object.prototype.hasOwnProperty.call(mode.keywords, matchText) && mode.keywords[matchText];
1763
+ function keywordData(mode, matchText) {
1764
+ return mode.keywords[matchText];
1656
1765
  }
1657
1766
 
1658
1767
  function processKeywords() {
@@ -1668,13 +1777,15 @@
1668
1777
 
1669
1778
  while (match) {
1670
1779
  buf += modeBuffer.substring(lastIndex, match.index);
1671
- const data = keywordData(top, match);
1780
+ const word = language.case_insensitive ? match[0].toLowerCase() : match[0];
1781
+ const data = keywordData(top, word);
1672
1782
  if (data) {
1673
1783
  const [kind, keywordRelevance] = data;
1674
1784
  emitter.addText(buf);
1675
1785
  buf = "";
1676
1786
 
1677
- relevance += keywordRelevance;
1787
+ keywordHits[word] = (keywordHits[word] || 0) + 1;
1788
+ if (keywordHits[word] <= MAX_KEYWORD_HITS) relevance += keywordRelevance;
1678
1789
  if (kind.startsWith("_")) {
1679
1790
  // _ implied for relevance only, do not highlight
1680
1791
  // by applying a class name
@@ -1689,7 +1800,7 @@
1689
1800
  lastIndex = top.keywordPatternRe.lastIndex;
1690
1801
  match = top.keywordPatternRe.exec(modeBuffer);
1691
1802
  }
1692
- buf += modeBuffer.substr(lastIndex);
1803
+ buf += modeBuffer.substring(lastIndex);
1693
1804
  emitter.addText(buf);
1694
1805
  }
1695
1806
 
@@ -1704,7 +1815,7 @@
1704
1815
  return;
1705
1816
  }
1706
1817
  result = _highlight(top.subLanguage, modeBuffer, true, continuations[top.subLanguage]);
1707
- continuations[top.subLanguage] = /** @type {CompiledMode} */ (result.top);
1818
+ continuations[top.subLanguage] = /** @type {CompiledMode} */ (result._top);
1708
1819
  } else {
1709
1820
  result = highlightAuto(modeBuffer, top.subLanguage.length ? top.subLanguage : null);
1710
1821
  }
@@ -1716,7 +1827,7 @@
1716
1827
  if (top.relevance > 0) {
1717
1828
  relevance += result.relevance;
1718
1829
  }
1719
- emitter.addSublanguage(result.emitter, result.language);
1830
+ emitter.addSublanguage(result._emitter, result.language);
1720
1831
  }
1721
1832
 
1722
1833
  function processBuffer() {
@@ -1729,12 +1840,47 @@
1729
1840
  }
1730
1841
 
1731
1842
  /**
1732
- * @param {Mode} mode - new mode to start
1843
+ * @param {CompiledScope} scope
1844
+ * @param {RegExpMatchArray} match
1733
1845
  */
1734
- function startNewMode(mode) {
1735
- if (mode.className) {
1736
- emitter.openNode(language.classNameAliases[mode.className] || mode.className);
1846
+ function emitMultiClass(scope, match) {
1847
+ let i = 1;
1848
+ const max = match.length - 1;
1849
+ while (i <= max) {
1850
+ if (!scope._emit[i]) { i++; continue; }
1851
+ const klass = language.classNameAliases[scope[i]] || scope[i];
1852
+ const text = match[i];
1853
+ if (klass) {
1854
+ emitter.addKeyword(text, klass);
1855
+ } else {
1856
+ modeBuffer = text;
1857
+ processKeywords();
1858
+ modeBuffer = "";
1859
+ }
1860
+ i++;
1737
1861
  }
1862
+ }
1863
+
1864
+ /**
1865
+ * @param {CompiledMode} mode - new mode to start
1866
+ * @param {RegExpMatchArray} match
1867
+ */
1868
+ function startNewMode(mode, match) {
1869
+ if (mode.scope && typeof mode.scope === "string") {
1870
+ emitter.openNode(language.classNameAliases[mode.scope] || mode.scope);
1871
+ }
1872
+ if (mode.beginScope) {
1873
+ // beginScope just wraps the begin match itself in a scope
1874
+ if (mode.beginScope._wrap) {
1875
+ emitter.addKeyword(modeBuffer, language.classNameAliases[mode.beginScope._wrap] || mode.beginScope._wrap);
1876
+ modeBuffer = "";
1877
+ } else if (mode.beginScope._multi) {
1878
+ // at this point modeBuffer should just be the match
1879
+ emitMultiClass(mode.beginScope, match);
1880
+ modeBuffer = "";
1881
+ }
1882
+ }
1883
+
1738
1884
  top = Object.create(mode, { parent: { value: top } });
1739
1885
  return top;
1740
1886
  }
@@ -1776,7 +1922,7 @@
1776
1922
  */
1777
1923
  function doIgnore(lexeme) {
1778
1924
  if (top.matcher.regexIndex === 0) {
1779
- // no more regexs to potentially match here, so we move the cursor forward one
1925
+ // no more regexes to potentially match here, so we move the cursor forward one
1780
1926
  // space
1781
1927
  modeBuffer += lexeme[0];
1782
1928
  return 1;
@@ -1807,10 +1953,6 @@
1807
1953
  if (resp.isMatchIgnored) return doIgnore(lexeme);
1808
1954
  }
1809
1955
 
1810
- if (newMode && newMode.endSameAsBegin) {
1811
- newMode.endRe = escape(lexeme);
1812
- }
1813
-
1814
1956
  if (newMode.skip) {
1815
1957
  modeBuffer += lexeme;
1816
1958
  } else {
@@ -1822,11 +1964,7 @@
1822
1964
  modeBuffer = lexeme;
1823
1965
  }
1824
1966
  }
1825
- startNewMode(newMode);
1826
- // if (mode["after:begin"]) {
1827
- // let resp = new Response(mode);
1828
- // mode["after:begin"](match, resp);
1829
- // }
1967
+ startNewMode(newMode, match);
1830
1968
  return newMode.returnBegin ? 0 : lexeme.length;
1831
1969
  }
1832
1970
 
@@ -1837,13 +1975,19 @@
1837
1975
  */
1838
1976
  function doEndMatch(match) {
1839
1977
  const lexeme = match[0];
1840
- const matchPlusRemainder = codeToHighlight.substr(match.index);
1978
+ const matchPlusRemainder = codeToHighlight.substring(match.index);
1841
1979
 
1842
1980
  const endMode = endOfMode(top, match, matchPlusRemainder);
1843
1981
  if (!endMode) { return NO_MATCH; }
1844
1982
 
1845
1983
  const origin = top;
1846
- if (origin.skip) {
1984
+ if (top.endScope && top.endScope._wrap) {
1985
+ processBuffer();
1986
+ emitter.addKeyword(lexeme, top.endScope._wrap);
1987
+ } else if (top.endScope && top.endScope._multi) {
1988
+ processBuffer();
1989
+ emitMultiClass(top.endScope, match);
1990
+ } else if (origin.skip) {
1847
1991
  modeBuffer += lexeme;
1848
1992
  } else {
1849
1993
  if (!(origin.returnEnd || origin.excludeEnd)) {
@@ -1855,7 +1999,7 @@
1855
1999
  }
1856
2000
  }
1857
2001
  do {
1858
- if (top.className) {
2002
+ if (top.scope) {
1859
2003
  emitter.closeNode();
1860
2004
  }
1861
2005
  if (!top.skip && !top.subLanguage) {
@@ -1864,10 +2008,7 @@
1864
2008
  top = top.parent;
1865
2009
  } while (top !== endMode.parent);
1866
2010
  if (endMode.starts) {
1867
- if (endMode.endSameAsBegin) {
1868
- endMode.starts.endRe = endMode.endRe;
1869
- }
1870
- startNewMode(endMode.starts);
2011
+ startNewMode(endMode.starts, match);
1871
2012
  }
1872
2013
  return origin.returnEnd ? 0 : lexeme.length;
1873
2014
  }
@@ -1875,8 +2016,8 @@
1875
2016
  function processContinuations() {
1876
2017
  const list = [];
1877
2018
  for (let current = top; current !== language; current = current.parent) {
1878
- if (current.className) {
1879
- list.unshift(current.className);
2019
+ if (current.scope) {
2020
+ list.unshift(current.scope);
1880
2021
  }
1881
2022
  }
1882
2023
  list.forEach(item => emitter.openNode(item));
@@ -1888,7 +2029,7 @@
1888
2029
  /**
1889
2030
  * Process an individual match
1890
2031
  *
1891
- * @param {string} textBeforeMatch - text preceeding the match (since the last match)
2032
+ * @param {string} textBeforeMatch - text preceding the match (since the last match)
1892
2033
  * @param {EnhancedMatch} [match] - the match itself
1893
2034
  */
1894
2035
  function processLexeme(textBeforeMatch, match) {
@@ -1911,7 +2052,7 @@
1911
2052
  modeBuffer += codeToHighlight.slice(match.index, match.index + 1);
1912
2053
  if (!SAFE_MODE) {
1913
2054
  /** @type {AnnotatedError} */
1914
- const err = new Error('0 width match regex');
2055
+ const err = new Error(`0 width match regex (${languageName})`);
1915
2056
  err.languageName = languageName;
1916
2057
  err.badRule = lastMatch.rule;
1917
2058
  throw err;
@@ -1925,7 +2066,7 @@
1925
2066
  } else if (match.type === "illegal" && !ignoreIllegals) {
1926
2067
  // illegal match, we do not continue processing
1927
2068
  /** @type {AnnotatedError} */
1928
- const err = new Error('Illegal lexeme "' + lexeme + '" for mode "' + (top.className || '<unnamed>') + '"');
2069
+ const err = new Error('Illegal lexeme "' + lexeme + '" for mode "' + (top.scope || '<unnamed>') + '"');
1929
2070
  err.mode = top;
1930
2071
  throw err;
1931
2072
  } else if (match.type === "end") {
@@ -1953,13 +2094,9 @@
1953
2094
  }
1954
2095
 
1955
2096
  /*
1956
- Why might be find ourselves here? Only one occasion now. An end match that was
1957
- triggered but could not be completed. When might this happen? When an `endSameasBegin`
1958
- rule sets the end rule to a specific match. Since the overall mode termination rule that's
1959
- being used to scan the text isn't recompiled that means that any match that LOOKS like
1960
- the end (but is not, because it is not an exact match to the beginning) will
1961
- end up here. A definite end match, but when `doEndMatch` tries to "reapply"
1962
- the end rule and fails to match, we wind up here, and just silently ignore the end.
2097
+ Why might be find ourselves here? An potential end match that was
2098
+ triggered but could not be completed. IE, `doEndMatch` returned NO_MATCH.
2099
+ (this could be because a callback requests the match be ignored, etc)
1963
2100
 
1964
2101
  This causes no real harm other than stopping a few times too many.
1965
2102
  */
@@ -1974,7 +2111,7 @@
1974
2111
  throw new Error('Unknown language: "' + languageName + '"');
1975
2112
  }
1976
2113
 
1977
- const md = compileLanguage(language, { plugins });
2114
+ const md = compileLanguage(language);
1978
2115
  let result = '';
1979
2116
  /** @type {CompiledMode} */
1980
2117
  let top = continuation || md;
@@ -2011,44 +2148,44 @@
2011
2148
  const processedCount = processLexeme(beforeMatch, match);
2012
2149
  index = match.index + processedCount;
2013
2150
  }
2014
- processLexeme(codeToHighlight.substr(index));
2151
+ processLexeme(codeToHighlight.substring(index));
2015
2152
  emitter.closeAllNodes();
2016
2153
  emitter.finalize();
2017
2154
  result = emitter.toHTML();
2018
2155
 
2019
2156
  return {
2020
- // avoid possible breakage with v10 clients expecting
2021
- // this to always be an integer
2022
- relevance: Math.floor(relevance),
2023
- value: result,
2024
2157
  language: languageName,
2158
+ value: result,
2159
+ relevance: relevance,
2025
2160
  illegal: false,
2026
- emitter: emitter,
2027
- top: top
2161
+ _emitter: emitter,
2162
+ _top: top
2028
2163
  };
2029
2164
  } catch (err) {
2030
2165
  if (err.message && err.message.includes('Illegal')) {
2031
2166
  return {
2167
+ language: languageName,
2168
+ value: escape(codeToHighlight),
2032
2169
  illegal: true,
2033
- illegalBy: {
2034
- msg: err.message,
2170
+ relevance: 0,
2171
+ _illegalBy: {
2172
+ message: err.message,
2173
+ index: index,
2035
2174
  context: codeToHighlight.slice(index - 100, index + 100),
2036
- mode: err.mode
2175
+ mode: err.mode,
2176
+ resultSoFar: result
2037
2177
  },
2038
- sofar: result,
2039
- relevance: 0,
2040
- value: escape$1(codeToHighlight),
2041
- emitter: emitter
2178
+ _emitter: emitter
2042
2179
  };
2043
2180
  } else if (SAFE_MODE) {
2044
2181
  return {
2182
+ language: languageName,
2183
+ value: escape(codeToHighlight),
2045
2184
  illegal: false,
2046
2185
  relevance: 0,
2047
- value: escape$1(codeToHighlight),
2048
- emitter: emitter,
2049
- language: languageName,
2050
- top: top,
2051
- errorRaised: err
2186
+ errorRaised: err,
2187
+ _emitter: emitter,
2188
+ _top: top
2052
2189
  };
2053
2190
  } else {
2054
2191
  throw err;
@@ -2065,13 +2202,13 @@
2065
2202
  */
2066
2203
  function justTextHighlightResult(code) {
2067
2204
  const result = {
2068
- relevance: 0,
2069
- emitter: new options.__emitter(options),
2070
- value: escape$1(code),
2205
+ value: escape(code),
2071
2206
  illegal: false,
2072
- top: PLAINTEXT_LANGUAGE
2207
+ relevance: 0,
2208
+ _top: PLAINTEXT_LANGUAGE,
2209
+ _emitter: new options.__emitter(options)
2073
2210
  };
2074
- result.emitter.addText(code);
2211
+ result._emitter.addText(code);
2075
2212
  return result;
2076
2213
  }
2077
2214
 
@@ -2082,7 +2219,7 @@
2082
2219
  - language (detected language)
2083
2220
  - relevance (int)
2084
2221
  - value (an HTML string with highlighting markup)
2085
- - second_best (object with the same structure for second-best heuristically
2222
+ - secondBest (object with the same structure for second-best heuristically
2086
2223
  detected language, may be absent)
2087
2224
 
2088
2225
  @param {string} code
@@ -2123,35 +2260,11 @@
2123
2260
 
2124
2261
  /** @type {AutoHighlightResult} */
2125
2262
  const result = best;
2126
- result.second_best = secondBest;
2263
+ result.secondBest = secondBest;
2127
2264
 
2128
2265
  return result;
2129
2266
  }
2130
2267
 
2131
- /**
2132
- Post-processing of the highlighted markup:
2133
-
2134
- - replace TABs with something more useful
2135
- - replace real line-breaks with '<br>' for non-pre containers
2136
-
2137
- @param {string} html
2138
- @returns {string}
2139
- */
2140
- function fixMarkup(html) {
2141
- if (!(options.tabReplace || options.useBR)) {
2142
- return html;
2143
- }
2144
-
2145
- return html.replace(fixMarkupRe, match => {
2146
- if (match === '\n') {
2147
- return options.useBR ? '<br>' : match;
2148
- } else if (options.tabReplace) {
2149
- return match.replace(/\t/g, options.tabReplace);
2150
- }
2151
- return match;
2152
- });
2153
- }
2154
-
2155
2268
  /**
2156
2269
  * Builds new class name for block given the language name
2157
2270
  *
@@ -2160,41 +2273,14 @@
2160
2273
  * @param {string} [resultLang]
2161
2274
  */
2162
2275
  function updateClassName(element, currentLang, resultLang) {
2163
- const language = currentLang ? aliases[currentLang] : resultLang;
2276
+ const language = (currentLang && aliases[currentLang]) || resultLang;
2164
2277
 
2165
2278
  element.classList.add("hljs");
2166
- if (language) element.classList.add(language);
2279
+ element.classList.add(`language-${language}`);
2167
2280
  }
2168
2281
 
2169
- /** @type {HLJSPlugin} */
2170
- const brPlugin = {
2171
- "before:highlightElement": ({ el }) => {
2172
- if (options.useBR) {
2173
- el.innerHTML = el.innerHTML.replace(/\n/g, '').replace(/<br[ /]*>/g, '\n');
2174
- }
2175
- },
2176
- "after:highlightElement": ({ result }) => {
2177
- if (options.useBR) {
2178
- result.value = result.value.replace(/\n/g, "<br>");
2179
- }
2180
- }
2181
- };
2182
-
2183
- const TAB_REPLACE_RE = /^(<[^>]+>|\t)+/gm;
2184
- /** @type {HLJSPlugin} */
2185
- const tabReplacePlugin = {
2186
- "after:highlightElement": ({ result }) => {
2187
- if (options.tabReplace) {
2188
- result.value = result.value.replace(TAB_REPLACE_RE, (m) =>
2189
- m.replace(/\t/g, options.tabReplace)
2190
- );
2191
- }
2192
- }
2193
- };
2194
-
2195
2282
  /**
2196
- * Applies highlighting to a DOM node containing code. Accepts a DOM node and
2197
- * two optional parameters for fixMarkup.
2283
+ * Applies highlighting to a DOM node containing code.
2198
2284
  *
2199
2285
  * @param {HighlightedHTMLElement} element - the HTML element to highlight
2200
2286
  */
@@ -2205,33 +2291,50 @@
2205
2291
 
2206
2292
  if (shouldNotHighlight(language)) return;
2207
2293
 
2208
- // support for v10 API
2209
2294
  fire("before:highlightElement",
2210
2295
  { el: element, language: language });
2211
2296
 
2297
+ // we should be all text, no child nodes (unescaped HTML) - this is possibly
2298
+ // an HTML injection attack - it's likely too late if this is already in
2299
+ // production (the code has likely already done its damage by the time
2300
+ // we're seeing it)... but we yell loudly about this so that hopefully it's
2301
+ // more likely to be caught in development before making it to production
2302
+ if (element.children.length > 0) {
2303
+ if (!options.ignoreUnescapedHTML) {
2304
+ console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk.");
2305
+ console.warn("https://github.com/highlightjs/highlight.js/wiki/security");
2306
+ console.warn("The element with unescaped HTML:");
2307
+ console.warn(element);
2308
+ }
2309
+ if (options.throwUnescapedHTML) {
2310
+ const err = new HTMLInjectionError(
2311
+ "One of your code blocks includes unescaped HTML.",
2312
+ element.innerHTML
2313
+ );
2314
+ throw err;
2315
+ }
2316
+ }
2317
+
2212
2318
  node = element;
2213
2319
  const text = node.textContent;
2214
2320
  const result = language ? highlight(text, { language, ignoreIllegals: true }) : highlightAuto(text);
2215
2321
 
2216
- // support for v10 API
2217
- fire("after:highlightElement", { el: element, result, text });
2218
-
2219
2322
  element.innerHTML = result.value;
2220
2323
  updateClassName(element, language, result.language);
2221
2324
  element.result = {
2222
2325
  language: result.language,
2223
2326
  // TODO: remove with version 11.0
2224
2327
  re: result.relevance,
2225
- relavance: result.relevance
2328
+ relevance: result.relevance
2226
2329
  };
2227
- if (result.second_best) {
2228
- element.second_best = {
2229
- language: result.second_best.language,
2230
- // TODO: remove with version 11.0
2231
- re: result.second_best.relevance,
2232
- relavance: result.second_best.relevance
2330
+ if (result.secondBest) {
2331
+ element.secondBest = {
2332
+ language: result.secondBest.language,
2333
+ relevance: result.secondBest.relevance
2233
2334
  };
2234
2335
  }
2336
+
2337
+ fire("after:highlightElement", { el: element, result, text });
2235
2338
  }
2236
2339
 
2237
2340
  /**
@@ -2240,34 +2343,19 @@
2240
2343
  * @param {Partial<HLJSOptions>} userOptions
2241
2344
  */
2242
2345
  function configure(userOptions) {
2243
- if (userOptions.useBR) {
2244
- deprecated("10.3.0", "'useBR' will be removed entirely in v11.0");
2245
- deprecated("10.3.0", "Please see https://github.com/highlightjs/highlight.js/issues/2559");
2246
- }
2247
- options = inherit$1(options, userOptions);
2346
+ options = inherit(options, userOptions);
2248
2347
  }
2249
2348
 
2250
- /**
2251
- * Highlights to all <pre><code> blocks on a page
2252
- *
2253
- * @type {Function & {called?: boolean}}
2254
- */
2255
2349
  // TODO: remove v12, deprecated
2256
2350
  const initHighlighting = () => {
2257
- if (initHighlighting.called) return;
2258
- initHighlighting.called = true;
2259
-
2260
- deprecated("10.6.0", "initHighlighting() is deprecated. Use highlightAll() instead.");
2261
-
2262
- const blocks = document.querySelectorAll('pre code');
2263
- blocks.forEach(highlightElement);
2351
+ highlightAll();
2352
+ deprecated("10.6.0", "initHighlighting() deprecated. Use highlightAll() now.");
2264
2353
  };
2265
2354
 
2266
- // Higlights all when DOMContentLoaded fires
2267
2355
  // TODO: remove v12, deprecated
2268
2356
  function initHighlightingOnLoad() {
2269
- deprecated("10.6.0", "initHighlightingOnLoad() is deprecated. Use highlightAll() instead.");
2270
- wantsHighlight = true;
2357
+ highlightAll();
2358
+ deprecated("10.6.0", "initHighlightingOnLoad() deprecated. Use highlightAll() now.");
2271
2359
  }
2272
2360
 
2273
2361
  let wantsHighlight = false;
@@ -2282,7 +2370,7 @@
2282
2370
  return;
2283
2371
  }
2284
2372
 
2285
- const blocks = document.querySelectorAll('pre code');
2373
+ const blocks = document.querySelectorAll(options.cssSelector);
2286
2374
  blocks.forEach(highlightElement);
2287
2375
  }
2288
2376
 
@@ -2347,26 +2435,6 @@
2347
2435
  return Object.keys(languages);
2348
2436
  }
2349
2437
 
2350
- /**
2351
- intended usage: When one language truly requires another
2352
-
2353
- Unlike `getLanguage`, this will throw when the requested language
2354
- is not available.
2355
-
2356
- @param {string} name - name of the language to fetch/require
2357
- @returns {Language | never}
2358
- */
2359
- function requireLanguage(name) {
2360
- deprecated("10.4.0", "requireLanguage will be removed entirely in v11.");
2361
- deprecated("10.4.0", "Please see https://github.com/highlightjs/highlight.js/pull/2844");
2362
-
2363
- const lang = getLanguage(name);
2364
- if (lang) { return lang; }
2365
-
2366
- const err = new Error('The \'{}\' language is required, but not loaded.'.replace('{}', name));
2367
- throw err;
2368
- }
2369
-
2370
2438
  /**
2371
2439
  * @param {string} name - name of the language to retrieve
2372
2440
  * @returns {Language | undefined}
@@ -2443,20 +2511,7 @@
2443
2511
  }
2444
2512
 
2445
2513
  /**
2446
- Note: fixMarkup is deprecated and will be removed entirely in v11
2447
-
2448
- @param {string} arg
2449
- @returns {string}
2450
- */
2451
- function deprecateFixMarkup(arg) {
2452
- deprecated("10.2.0", "fixMarkup will be removed entirely in v11.0");
2453
- deprecated("10.2.0", "Please see https://github.com/highlightjs/highlight.js/issues/2534");
2454
-
2455
- return fixMarkup(arg);
2456
- }
2457
-
2458
- /**
2459
- *
2514
+ * DEPRECATED
2460
2515
  * @param {HighlightedHTMLElement} el
2461
2516
  */
2462
2517
  function deprecateHighlightBlock(el) {
@@ -2471,7 +2526,6 @@
2471
2526
  highlight,
2472
2527
  highlightAuto,
2473
2528
  highlightAll,
2474
- fixMarkup: deprecateFixMarkup,
2475
2529
  highlightElement,
2476
2530
  // TODO: Remove with v12 API
2477
2531
  highlightBlock: deprecateHighlightBlock,
@@ -2483,394 +2537,45 @@
2483
2537
  listLanguages,
2484
2538
  getLanguage,
2485
2539
  registerAliases,
2486
- requireLanguage,
2487
2540
  autoDetection,
2488
- inherit: inherit$1,
2489
- addPlugin,
2490
- // plugins for frameworks
2491
- vuePlugin: BuildVuePlugin(hljs).VuePlugin
2541
+ inherit,
2542
+ addPlugin
2492
2543
  });
2493
2544
 
2494
2545
  hljs.debugMode = function() { SAFE_MODE = false; };
2495
2546
  hljs.safeMode = function() { SAFE_MODE = true; };
2496
2547
  hljs.versionString = version;
2497
2548
 
2549
+ hljs.regex = {
2550
+ concat: concat,
2551
+ lookahead: lookahead,
2552
+ either: either,
2553
+ optional: optional,
2554
+ anyNumberOfTimes: anyNumberOfTimes
2555
+ };
2556
+
2498
2557
  for (const key in MODES) {
2499
2558
  // @ts-ignore
2500
2559
  if (typeof MODES[key] === "object") {
2501
2560
  // @ts-ignore
2502
- deepFreezeEs6(MODES[key]);
2561
+ deepFreezeEs6.exports(MODES[key]);
2503
2562
  }
2504
2563
  }
2505
2564
 
2506
- // merge all the modes/regexs into our main object
2565
+ // merge all the modes/regexes into our main object
2507
2566
  Object.assign(hljs, MODES);
2508
2567
 
2509
- // built-in plugins, likely to be moved out of core in the future
2510
- hljs.addPlugin(brPlugin); // slated to be removed in v11
2511
- hljs.addPlugin(mergeHTMLPlugin);
2512
- hljs.addPlugin(tabReplacePlugin);
2513
2568
  return hljs;
2514
2569
  };
2515
2570
 
2516
2571
  // export an "instance" of the highlighter
2517
- var highlight$1 = HLJS({});
2518
-
2519
- var core$1 = highlight$1;
2572
+ var highlight = HLJS({});
2520
2573
 
2521
- function createCommonjsModule(fn) {
2522
- var module = { exports: {} };
2523
- return fn(module, module.exports), module.exports;
2524
- }
2525
-
2526
- var format = createCommonjsModule(function (module) {
2527
- (function() {
2528
-
2529
- //// Export the API
2530
- var namespace;
2531
-
2532
- // CommonJS / Node module
2533
- {
2534
- namespace = module.exports = format;
2535
- }
2536
-
2537
- namespace.format = format;
2538
- namespace.vsprintf = vsprintf;
2539
-
2540
- if (typeof console !== 'undefined' && typeof console.log === 'function') {
2541
- namespace.printf = printf;
2542
- }
2543
-
2544
- function printf(/* ... */) {
2545
- console.log(format.apply(null, arguments));
2546
- }
2547
-
2548
- function vsprintf(fmt, replacements) {
2549
- return format.apply(null, [fmt].concat(replacements));
2550
- }
2551
-
2552
- function format(fmt) {
2553
- var argIndex = 1 // skip initial format argument
2554
- , args = [].slice.call(arguments)
2555
- , i = 0
2556
- , n = fmt.length
2557
- , result = ''
2558
- , c
2559
- , escaped = false
2560
- , arg
2561
- , tmp
2562
- , leadingZero = false
2563
- , precision
2564
- , nextArg = function() { return args[argIndex++]; }
2565
- , slurpNumber = function() {
2566
- var digits = '';
2567
- while (/\d/.test(fmt[i])) {
2568
- digits += fmt[i++];
2569
- c = fmt[i];
2570
- }
2571
- return digits.length > 0 ? parseInt(digits) : null;
2572
- }
2573
- ;
2574
- for (; i < n; ++i) {
2575
- c = fmt[i];
2576
- if (escaped) {
2577
- escaped = false;
2578
- if (c == '.') {
2579
- leadingZero = false;
2580
- c = fmt[++i];
2581
- }
2582
- else if (c == '0' && fmt[i + 1] == '.') {
2583
- leadingZero = true;
2584
- i += 2;
2585
- c = fmt[i];
2586
- }
2587
- else {
2588
- leadingZero = true;
2589
- }
2590
- precision = slurpNumber();
2591
- switch (c) {
2592
- case 'b': // number in binary
2593
- result += parseInt(nextArg(), 10).toString(2);
2594
- break;
2595
- case 'c': // character
2596
- arg = nextArg();
2597
- if (typeof arg === 'string' || arg instanceof String)
2598
- result += arg;
2599
- else
2600
- result += String.fromCharCode(parseInt(arg, 10));
2601
- break;
2602
- case 'd': // number in decimal
2603
- result += parseInt(nextArg(), 10);
2604
- break;
2605
- case 'f': // floating point number
2606
- tmp = String(parseFloat(nextArg()).toFixed(precision || 6));
2607
- result += leadingZero ? tmp : tmp.replace(/^0/, '');
2608
- break;
2609
- case 'j': // JSON
2610
- result += JSON.stringify(nextArg());
2611
- break;
2612
- case 'o': // number in octal
2613
- result += '0' + parseInt(nextArg(), 10).toString(8);
2614
- break;
2615
- case 's': // string
2616
- result += nextArg();
2617
- break;
2618
- case 'x': // lowercase hexadecimal
2619
- result += '0x' + parseInt(nextArg(), 10).toString(16);
2620
- break;
2621
- case 'X': // uppercase hexadecimal
2622
- result += '0x' + parseInt(nextArg(), 10).toString(16).toUpperCase();
2623
- break;
2624
- default:
2625
- result += c;
2626
- break;
2627
- }
2628
- } else if (c === '%') {
2629
- escaped = true;
2630
- } else {
2631
- result += c;
2632
- }
2633
- }
2634
- return result;
2635
- }
2636
-
2637
- }());
2638
- });
2639
-
2640
- var fault = create(Error);
2641
-
2642
- var fault_1 = fault;
2643
-
2644
- fault.eval = create(EvalError);
2645
- fault.range = create(RangeError);
2646
- fault.reference = create(ReferenceError);
2647
- fault.syntax = create(SyntaxError);
2648
- fault.type = create(TypeError);
2649
- fault.uri = create(URIError);
2574
+ var core = highlight;
2575
+ highlight.HighlightJS = highlight;
2576
+ highlight.default = highlight;
2650
2577
 
2651
- fault.create = create;
2652
-
2653
- // Create a new `EConstructor`, with the formatted `format` as a first argument.
2654
- function create(EConstructor) {
2655
- FormattedError.displayName = EConstructor.displayName || EConstructor.name;
2656
-
2657
- return FormattedError
2658
-
2659
- function FormattedError(format$1) {
2660
- if (format$1) {
2661
- format$1 = format.apply(null, arguments);
2662
- }
2663
-
2664
- return new EConstructor(format$1)
2665
- }
2666
- }
2667
-
2668
- var highlight_1 = highlight;
2669
- var highlightAuto_1 = highlightAuto;
2670
- var registerLanguage_1 = registerLanguage;
2671
- var listLanguages_1 = listLanguages;
2672
- var registerAlias_1 = registerAlias;
2673
-
2674
- Emitter.prototype.addText = text;
2675
- Emitter.prototype.addKeyword = addKeyword;
2676
- Emitter.prototype.addSublanguage = addSublanguage;
2677
- Emitter.prototype.openNode = open;
2678
- Emitter.prototype.closeNode = close;
2679
- Emitter.prototype.closeAllNodes = noop;
2680
- Emitter.prototype.finalize = noop;
2681
- Emitter.prototype.toHTML = toHtmlNoop;
2682
-
2683
- var defaultPrefix = 'hljs-';
2684
-
2685
- // Highlighting `value` in the language `name`.
2686
- function highlight(name, value, options) {
2687
- var before = core$1.configure({});
2688
- var settings = options || {};
2689
- var prefix = settings.prefix;
2690
- var result;
2691
-
2692
- if (typeof name !== 'string') {
2693
- throw fault_1('Expected `string` for name, got `%s`', name)
2694
- }
2695
-
2696
- if (!core$1.getLanguage(name)) {
2697
- throw fault_1('Unknown language: `%s` is not registered', name)
2698
- }
2699
-
2700
- if (typeof value !== 'string') {
2701
- throw fault_1('Expected `string` for value, got `%s`', value)
2702
- }
2703
-
2704
- if (prefix === null || prefix === undefined) {
2705
- prefix = defaultPrefix;
2706
- }
2707
-
2708
- core$1.configure({__emitter: Emitter, classPrefix: prefix});
2709
-
2710
- result = core$1.highlight(value, {language: name, ignoreIllegals: true});
2711
-
2712
- core$1.configure(before || {});
2713
-
2714
- /* istanbul ignore if - Highlight.js seems to use this (currently) for broken
2715
- * grammars, so let’s keep it in there just to be sure. */
2716
- if (result.errorRaised) {
2717
- throw result.errorRaised
2718
- }
2719
-
2720
- return {
2721
- relevance: result.relevance,
2722
- language: result.language,
2723
- value: result.emitter.rootNode.children
2724
- }
2725
- }
2726
-
2727
- function highlightAuto(value, options) {
2728
- var settings = options || {};
2729
- var subset = settings.subset || core$1.listLanguages();
2730
- settings.prefix;
2731
- var length = subset.length;
2732
- var index = -1;
2733
- var result;
2734
- var secondBest;
2735
- var current;
2736
- var name;
2737
-
2738
- if (typeof value !== 'string') {
2739
- throw fault_1('Expected `string` for value, got `%s`', value)
2740
- }
2741
-
2742
- secondBest = {relevance: 0, language: null, value: []};
2743
- result = {relevance: 0, language: null, value: []};
2744
-
2745
- while (++index < length) {
2746
- name = subset[index];
2747
-
2748
- if (!core$1.getLanguage(name)) {
2749
- continue
2750
- }
2751
-
2752
- current = highlight(name, value, options);
2753
- current.language = name;
2754
-
2755
- if (current.relevance > secondBest.relevance) {
2756
- secondBest = current;
2757
- }
2758
-
2759
- if (current.relevance > result.relevance) {
2760
- secondBest = result;
2761
- result = current;
2762
- }
2763
- }
2764
-
2765
- if (secondBest.language) {
2766
- result.secondBest = secondBest;
2767
- }
2768
-
2769
- return result
2770
- }
2771
-
2772
- // Register a language.
2773
- function registerLanguage(name, syntax) {
2774
- core$1.registerLanguage(name, syntax);
2775
- }
2776
-
2777
- // Get a list of all registered languages.
2778
- function listLanguages() {
2779
- return core$1.listLanguages()
2780
- }
2781
-
2782
- // Register more aliases for an already registered language.
2783
- function registerAlias(name, alias) {
2784
- var map = name;
2785
- var key;
2786
-
2787
- if (alias) {
2788
- map = {};
2789
- map[name] = alias;
2790
- }
2791
-
2792
- for (key in map) {
2793
- core$1.registerAliases(map[key], {languageName: key});
2794
- }
2795
- }
2796
-
2797
- function Emitter(options) {
2798
- this.options = options;
2799
- this.rootNode = {children: []};
2800
- this.stack = [this.rootNode];
2801
- }
2802
-
2803
- function addKeyword(value, name) {
2804
- this.openNode(name);
2805
- this.addText(value);
2806
- this.closeNode();
2807
- }
2808
-
2809
- function addSublanguage(other, name) {
2810
- var stack = this.stack;
2811
- var current = stack[stack.length - 1];
2812
- var results = other.rootNode.children;
2813
- var node = name
2814
- ? {
2815
- type: 'element',
2816
- tagName: 'span',
2817
- properties: {className: [name]},
2818
- children: results
2819
- }
2820
- : results;
2821
-
2822
- current.children = current.children.concat(node);
2823
- }
2824
-
2825
- function text(value) {
2826
- var stack = this.stack;
2827
- var current;
2828
- var tail;
2829
-
2830
- if (value === '') return
2831
-
2832
- current = stack[stack.length - 1];
2833
- tail = current.children[current.children.length - 1];
2834
-
2835
- if (tail && tail.type === 'text') {
2836
- tail.value += value;
2837
- } else {
2838
- current.children.push({type: 'text', value: value});
2839
- }
2840
- }
2841
-
2842
- function open(name) {
2843
- var stack = this.stack;
2844
- var className = this.options.classPrefix + name;
2845
- var current = stack[stack.length - 1];
2846
- var child = {
2847
- type: 'element',
2848
- tagName: 'span',
2849
- properties: {className: [className]},
2850
- children: []
2851
- };
2852
-
2853
- current.children.push(child);
2854
- stack.push(child);
2855
- }
2856
-
2857
- function close() {
2858
- this.stack.pop();
2859
- }
2860
-
2861
- function toHtmlNoop() {
2862
- return ''
2863
- }
2864
-
2865
- function noop() {}
2866
-
2867
- var core = {
2868
- highlight: highlight_1,
2869
- highlightAuto: highlightAuto_1,
2870
- registerLanguage: registerLanguage_1,
2871
- listLanguages: listLanguages_1,
2872
- registerAlias: registerAlias_1
2873
- };
2578
+ var HighlightJS = core;
2874
2579
 
2875
2580
  function parseNodes(nodes, className = []) {
2876
2581
  return nodes
@@ -2891,18 +2596,23 @@
2891
2596
  })
2892
2597
  .flat();
2893
2598
  }
2894
- function getDecorations({ doc, name }) {
2599
+ function getHighlightNodes(result) {
2600
+ // `.value` for lowlight v1, `.children` for lowlight v2
2601
+ return result.value || result.children || [];
2602
+ }
2603
+ function registered(aliasOrLanguage) {
2604
+ return Boolean(HighlightJS.getLanguage(aliasOrLanguage));
2605
+ }
2606
+ function getDecorations({ doc, name, lowlight, defaultLanguage, }) {
2895
2607
  const decorations = [];
2896
- core$2.findChildren(doc, node => node.type.name === name)
2608
+ core$1.findChildren(doc, node => node.type.name === name)
2897
2609
  .forEach(block => {
2898
2610
  let from = block.pos + 1;
2899
- const { language } = block.node.attrs;
2900
- // TODO: add missing type for `listLanguages`
2901
- // @ts-ignore
2902
- const languages = core.listLanguages();
2903
- const nodes = language && languages.includes(language)
2904
- ? core.highlight(language, block.node.textContent).value
2905
- : core.highlightAuto(block.node.textContent).value;
2611
+ const language = block.node.attrs.language || defaultLanguage;
2612
+ const languages = lowlight.listLanguages();
2613
+ const nodes = language && (languages.includes(language) || registered(language))
2614
+ ? getHighlightNodes(lowlight.highlight(language, block.node.textContent))
2615
+ : getHighlightNodes(lowlight.highlightAuto(block.node.textContent));
2906
2616
  parseNodes(nodes).forEach(node => {
2907
2617
  const to = from + node.text.length;
2908
2618
  if (node.classes.length) {
@@ -2916,16 +2626,27 @@
2916
2626
  });
2917
2627
  return prosemirrorView.DecorationSet.create(doc, decorations);
2918
2628
  }
2919
- function LowlightPlugin({ name }) {
2920
- return new prosemirrorState.Plugin({
2629
+ function isFunction(param) {
2630
+ return typeof param === 'function';
2631
+ }
2632
+ function LowlightPlugin({ name, lowlight, defaultLanguage }) {
2633
+ if (!['highlight', 'highlightAuto', 'listLanguages'].every(api => isFunction(lowlight[api]))) {
2634
+ throw Error('You should provide an instance of lowlight to use the code-block-lowlight extension');
2635
+ }
2636
+ const lowlightPlugin = new prosemirrorState.Plugin({
2921
2637
  key: new prosemirrorState.PluginKey('lowlight'),
2922
2638
  state: {
2923
- init: (_, { doc }) => getDecorations({ doc, name }),
2639
+ init: (_, { doc }) => getDecorations({
2640
+ doc,
2641
+ name,
2642
+ lowlight,
2643
+ defaultLanguage,
2644
+ }),
2924
2645
  apply: (transaction, decorationSet, oldState, newState) => {
2925
2646
  const oldNodeName = oldState.selection.$head.parent.type.name;
2926
2647
  const newNodeName = newState.selection.$head.parent.type.name;
2927
- const oldNodes = core$2.findChildren(oldState.doc, node => node.type.name === name);
2928
- const newNodes = core$2.findChildren(newState.doc, node => node.type.name === name);
2648
+ const oldNodes = core$1.findChildren(oldState.doc, node => node.type.name === name);
2649
+ const newNodes = core$1.findChildren(newState.doc, node => node.type.name === name);
2929
2650
  if (transaction.docChanged
2930
2651
  // Apply decorations if:
2931
2652
  && (
@@ -2948,31 +2669,51 @@
2948
2669
  && node.pos + node.node.nodeSize <= step.to;
2949
2670
  });
2950
2671
  }))) {
2951
- return getDecorations({ doc: transaction.doc, name });
2672
+ return getDecorations({
2673
+ doc: transaction.doc,
2674
+ name,
2675
+ lowlight,
2676
+ defaultLanguage,
2677
+ });
2952
2678
  }
2953
2679
  return decorationSet.map(transaction.mapping, transaction.doc);
2954
2680
  },
2955
2681
  },
2956
2682
  props: {
2957
2683
  decorations(state) {
2958
- return this.getState(state);
2684
+ return lowlightPlugin.getState(state);
2959
2685
  },
2960
2686
  },
2961
2687
  });
2688
+ return lowlightPlugin;
2962
2689
  }
2963
2690
 
2964
- const CodeBlockLowlight = CodeBlock__default['default'].extend({
2691
+ const CodeBlockLowlight = CodeBlock__default["default"].extend({
2692
+ addOptions() {
2693
+ var _a;
2694
+ return {
2695
+ ...(_a = this.parent) === null || _a === void 0 ? void 0 : _a.call(this),
2696
+ lowlight: {},
2697
+ defaultLanguage: null,
2698
+ };
2699
+ },
2965
2700
  addProseMirrorPlugins() {
2701
+ var _a;
2966
2702
  return [
2967
- LowlightPlugin({ name: 'codeBlock' }),
2703
+ ...((_a = this.parent) === null || _a === void 0 ? void 0 : _a.call(this)) || [],
2704
+ LowlightPlugin({
2705
+ name: this.name,
2706
+ lowlight: this.options.lowlight,
2707
+ defaultLanguage: this.options.defaultLanguage,
2708
+ }),
2968
2709
  ];
2969
2710
  },
2970
2711
  });
2971
2712
 
2972
2713
  exports.CodeBlockLowlight = CodeBlockLowlight;
2973
- exports.default = CodeBlockLowlight;
2714
+ exports["default"] = CodeBlockLowlight;
2974
2715
 
2975
2716
  Object.defineProperty(exports, '__esModule', { value: true });
2976
2717
 
2977
- })));
2718
+ }));
2978
2719
  //# sourceMappingURL=tiptap-extension-code-block-lowlight.umd.js.map