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