How to use skipIfhasPrecedingDot method in Playwright Internal

Best JavaScript code snippet using playwright-internal

highlight.js

Source:highlight.js Github

copy

Full Screen

1/*!2 Highlight.js v11.0.1 (git: 1cf31f015d)3 (c) 2006-2021 Ivan Sagalaev and other contributors4 License: BSD-3-Clause5 */6var hljs = (function () {7 'use strict';8 var deepFreezeEs6 = {exports: {}};9 function deepFreeze(obj) {10 if (obj instanceof Map) {11 obj.clear = obj.delete = obj.set = function () {12 throw new Error('map is read-only');13 };14 } else if (obj instanceof Set) {15 obj.add = obj.clear = obj.delete = function () {16 throw new Error('set is read-only');17 };18 }19 // Freeze self20 Object.freeze(obj);21 Object.getOwnPropertyNames(obj).forEach(function (name) {22 var prop = obj[name];23 // Freeze prop if it is an object24 if (typeof prop == 'object' && !Object.isFrozen(prop)) {25 deepFreeze(prop);26 }27 });28 return obj;29 }30 deepFreezeEs6.exports = deepFreeze;31 deepFreezeEs6.exports.default = deepFreeze;32 var deepFreeze$1 = deepFreezeEs6.exports;33 34 /** @typedef {import('highlight.js').CompiledMode} CompiledMode */35 /** @implements CallbackResponse */36 class Response {37 /**38 * @param {CompiledMode} mode39 */40 constructor(mode) {41 // eslint-disable-next-line no-undefined42 if (mode.data === undefined) mode.data = {};43 this.data = mode.data;44 this.isMatchIgnored = false;45 }46 ignoreMatch() {47 this.isMatchIgnored = true;48 }49 }50 /**51 * @param {string} value52 * @returns {string}53 */54 function escapeHTML(value) {55 return value56 .replace(/&/g, '&amp;')57 .replace(/</g, '&lt;')58 .replace(/>/g, '&gt;')59 .replace(/"/g, '&quot;')60 .replace(/'/g, '&#x27;');61 }62 /**63 * performs a shallow merge of multiple objects into one64 *65 * @template T66 * @param {T} original67 * @param {Record<string,any>[]} objects68 * @returns {T} a single new object69 */70 function inherit$1(original, ...objects) {71 /** @type Record<string,any> */72 const result = Object.create(null);73 for (const key in original) {74 result[key] = original[key];75 }76 objects.forEach(function(obj) {77 for (const key in obj) {78 result[key] = obj[key];79 }80 });81 return /** @type {T} */ (result);82 }83 /**84 * @typedef {object} Renderer85 * @property {(text: string) => void} addText86 * @property {(node: Node) => void} openNode87 * @property {(node: Node) => void} closeNode88 * @property {() => string} value89 */90 /** @typedef {{kind?: string, sublanguage?: boolean}} Node */91 /** @typedef {{walk: (r: Renderer) => void}} Tree */92 /** */93 const SPAN_CLOSE = '</span>';94 /**95 * Determines if a node needs to be wrapped in <span>96 *97 * @param {Node} node */98 const emitsWrappingTags = (node) => {99 return !!node.kind;100 };101 /**102 *103 * @param {string} name104 * @param {{prefix:string}} options105 */106 const expandScopeName = (name, { prefix }) => {107 if (name.includes(".")) {108 const pieces = name.split(".");109 return [110 `${prefix}${pieces.shift()}`,111 ...(pieces.map((x, i) => `${x}${"_".repeat(i + 1)}`))112 ].join(" ");113 }114 return `${prefix}${name}`;115 };116 /** @type {Renderer} */117 class HTMLRenderer {118 /**119 * Creates a new HTMLRenderer120 *121 * @param {Tree} parseTree - the parse tree (must support `walk` API)122 * @param {{classPrefix: string}} options123 */124 constructor(parseTree, options) {125 this.buffer = "";126 this.classPrefix = options.classPrefix;127 parseTree.walk(this);128 }129 /**130 * Adds texts to the output stream131 *132 * @param {string} text */133 addText(text) {134 this.buffer += escapeHTML(text);135 }136 /**137 * Adds a node open to the output stream (if needed)138 *139 * @param {Node} node */140 openNode(node) {141 if (!emitsWrappingTags(node)) return;142 let scope = node.kind;143 if (node.sublanguage) {144 scope = `language-${scope}`;145 } else {146 scope = expandScopeName(scope, { prefix: this.classPrefix });147 }148 this.span(scope);149 }150 /**151 * Adds a node close to the output stream (if needed)152 *153 * @param {Node} node */154 closeNode(node) {155 if (!emitsWrappingTags(node)) return;156 this.buffer += SPAN_CLOSE;157 }158 /**159 * returns the accumulated buffer160 */161 value() {162 return this.buffer;163 }164 // helpers165 /**166 * Builds a span element167 *168 * @param {string} className */169 span(className) {170 this.buffer += `<span class="${className}">`;171 }172 }173 /** @typedef {{kind?: string, sublanguage?: boolean, children: Node[]} | string} Node */174 /** @typedef {{kind?: string, sublanguage?: boolean, children: Node[]} } DataNode */175 /** @typedef {import('highlight.js').Emitter} Emitter */176 /** */177 class TokenTree {178 constructor() {179 /** @type DataNode */180 this.rootNode = { children: [] };181 this.stack = [this.rootNode];182 }183 get top() {184 return this.stack[this.stack.length - 1];185 }186 get root() { return this.rootNode; }187 /** @param {Node} node */188 add(node) {189 this.top.children.push(node);190 }191 /** @param {string} kind */192 openNode(kind) {193 /** @type Node */194 const node = { kind, children: [] };195 this.add(node);196 this.stack.push(node);197 }198 closeNode() {199 if (this.stack.length > 1) {200 return this.stack.pop();201 }202 // eslint-disable-next-line no-undefined203 return undefined;204 }205 closeAllNodes() {206 while (this.closeNode());207 }208 toJSON() {209 return JSON.stringify(this.rootNode, null, 4);210 }211 /**212 * @typedef { import("./html_renderer").Renderer } Renderer213 * @param {Renderer} builder214 */215 walk(builder) {216 // this does not217 return this.constructor._walk(builder, this.rootNode);218 // this works219 // return TokenTree._walk(builder, this.rootNode);220 }221 /**222 * @param {Renderer} builder223 * @param {Node} node224 */225 static _walk(builder, node) {226 if (typeof node === "string") {227 builder.addText(node);228 } else if (node.children) {229 builder.openNode(node);230 node.children.forEach((child) => this._walk(builder, child));231 builder.closeNode(node);232 }233 return builder;234 }235 /**236 * @param {Node} node237 */238 static _collapse(node) {239 if (typeof node === "string") return;240 if (!node.children) return;241 if (node.children.every(el => typeof el === "string")) {242 // node.text = node.children.join("");243 // delete node.children;244 node.children = [node.children.join("")];245 } else {246 node.children.forEach((child) => {247 TokenTree._collapse(child);248 });249 }250 }251 }252 /**253 Currently this is all private API, but this is the minimal API necessary254 that an Emitter must implement to fully support the parser.255 Minimal interface:256 - addKeyword(text, kind)257 - addText(text)258 - addSublanguage(emitter, subLanguageName)259 - finalize()260 - openNode(kind)261 - closeNode()262 - closeAllNodes()263 - toHTML()264 */265 /**266 * @implements {Emitter}267 */268 class TokenTreeEmitter extends TokenTree {269 /**270 * @param {*} options271 */272 constructor(options) {273 super();274 this.options = options;275 }276 /**277 * @param {string} text278 * @param {string} kind279 */280 addKeyword(text, kind) {281 if (text === "") { return; }282 this.openNode(kind);283 this.addText(text);284 this.closeNode();285 }286 /**287 * @param {string} text288 */289 addText(text) {290 if (text === "") { return; }291 this.add(text);292 }293 /**294 * @param {Emitter & {root: DataNode}} emitter295 * @param {string} name296 */297 addSublanguage(emitter, name) {298 /** @type DataNode */299 const node = emitter.root;300 node.kind = name;301 node.sublanguage = true;302 this.add(node);303 }304 toHTML() {305 const renderer = new HTMLRenderer(this, this.options);306 return renderer.value();307 }308 finalize() {309 return true;310 }311 }312 /**313 * @param {string} value314 * @returns {RegExp}315 * */316 /**317 * @param {RegExp | string } re318 * @returns {string}319 */320 function source(re) {321 if (!re) return null;322 if (typeof re === "string") return re;323 return re.source;324 }325 /**326 * @param {RegExp | string } re327 * @returns {string}328 */329 function lookahead(re) {330 return concat('(?=', re, ')');331 }332 /**333 * @param {...(RegExp | string) } args334 * @returns {string}335 */336 function concat(...args) {337 const joined = args.map((x) => source(x)).join("");338 return joined;339 }340 function stripOptionsFromArgs(args) {341 const opts = args[args.length - 1];342 if (typeof opts === 'object' && opts.constructor === Object) {343 args.splice(args.length - 1, 1);344 return opts;345 } else {346 return {};347 }348 }349 /**350 * Any of the passed expresssions may match351 *352 * Creates a huge this | this | that | that match353 * @param {(RegExp | string)[] } args354 * @returns {string}355 */356 function either(...args) {357 const opts = stripOptionsFromArgs(args);358 const joined = '(' +359 (opts.capture ? "" : "?:") +360 args.map((x) => source(x)).join("|") + ")";361 return joined;362 }363 /**364 * @param {RegExp} re365 * @returns {number}366 */367 function countMatchGroups(re) {368 return (new RegExp(re.toString() + '|')).exec('').length - 1;369 }370 /**371 * Does lexeme start with a regular expression match at the beginning372 * @param {RegExp} re373 * @param {string} lexeme374 */375 function startsWith(re, lexeme) {376 const match = re && re.exec(lexeme);377 return match && match.index === 0;378 }379 // BACKREF_RE matches an open parenthesis or backreference. To avoid380 // an incorrect parse, it additionally matches the following:381 // - [...] elements, where the meaning of parentheses and escapes change382 // - other escape sequences, so we do not misparse escape sequences as383 // interesting elements384 // - non-matching or lookahead parentheses, which do not capture. These385 // follow the '(' with a '?'.386 const BACKREF_RE = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;387 // **INTERNAL** Not intended for outside usage388 // join logically computes regexps.join(separator), but fixes the389 // backreferences so they continue to match.390 // it also places each individual regular expression into it's own391 // match group, keeping track of the sequencing of those match groups392 // is currently an exercise for the caller. :-)393 /**394 * @param {(string | RegExp)[]} regexps395 * @param {{joinWith: string}} opts396 * @returns {string}397 */398 function _rewriteBackreferences(regexps, { joinWith }) {399 let numCaptures = 0;400 return regexps.map((regex) => {401 numCaptures += 1;402 const offset = numCaptures;403 let re = source(regex);404 let out = '';405 while (re.length > 0) {406 const match = BACKREF_RE.exec(re);407 if (!match) {408 out += re;409 break;410 }411 out += re.substring(0, match.index);412 re = re.substring(match.index + match[0].length);413 if (match[0][0] === '\\' && match[1]) {414 // Adjust the backreference.415 out += '\\' + String(Number(match[1]) + offset);416 } else {417 out += match[0];418 if (match[0] === '(') {419 numCaptures++;420 }421 }422 }423 return out;424 }).map(re => `(${re})`).join(joinWith);425 }426 /** @typedef {import('highlight.js').Mode} Mode */427 /** @typedef {import('highlight.js').ModeCallback} ModeCallback */428 // Common regexps429 const MATCH_NOTHING_RE = /\b\B/;430 const IDENT_RE = '[a-zA-Z]\\w*';431 const UNDERSCORE_IDENT_RE = '[a-zA-Z_]\\w*';432 const NUMBER_RE = '\\b\\d+(\\.\\d+)?';433 const C_NUMBER_RE = '(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)'; // 0x..., 0..., decimal, float434 const BINARY_NUMBER_RE = '\\b(0b[01]+)'; // 0b...435 const RE_STARTERS_RE = '!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~';436 /**437 * @param { Partial<Mode> & {binary?: string | RegExp} } opts438 */439 const SHEBANG = (opts = {}) => {440 const beginShebang = /^#![ ]*\//;441 if (opts.binary) {442 opts.begin = concat(443 beginShebang,444 /.*\b/,445 opts.binary,446 /\b.*/);447 }448 return inherit$1({449 scope: 'meta',450 begin: beginShebang,451 end: /$/,452 relevance: 0,453 /** @type {ModeCallback} */454 "on:begin": (m, resp) => {455 if (m.index !== 0) resp.ignoreMatch();456 }457 }, opts);458 };459 // Common modes460 const BACKSLASH_ESCAPE = {461 begin: '\\\\[\\s\\S]', relevance: 0462 };463 const APOS_STRING_MODE = {464 scope: 'string',465 begin: '\'',466 end: '\'',467 illegal: '\\n',468 contains: [BACKSLASH_ESCAPE]469 };470 const QUOTE_STRING_MODE = {471 scope: 'string',472 begin: '"',473 end: '"',474 illegal: '\\n',475 contains: [BACKSLASH_ESCAPE]476 };477 const PHRASAL_WORDS_MODE = {478 begin: /\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/479 };480 /**481 * Creates a comment mode482 *483 * @param {string | RegExp} begin484 * @param {string | RegExp} end485 * @param {Mode | {}} [modeOptions]486 * @returns {Partial<Mode>}487 */488 const COMMENT = function(begin, end, modeOptions = {}) {489 const mode = inherit$1(490 {491 scope: 'comment',492 begin,493 end,494 contains: []495 },496 modeOptions497 );498 mode.contains.push({499 scope: 'doctag',500 // hack to avoid the space from being included. the space is necessary to501 // match here to prevent the plain text rule below from gobbling up doctags502 begin: '[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)',503 end: /(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,504 excludeBegin: true,505 relevance: 0506 });507 const ENGLISH_WORD = either(508 // list of common 1 and 2 letter words in English509 "I",510 "a",511 "is",512 "so",513 "us",514 "to",515 "at",516 "if",517 "in",518 "it",519 "on",520 // note: this is not an exhaustive list of contractions, just popular ones521 /[A-Za-z]+['](d|ve|re|ll|t|s|n)/, // contractions - can't we'd they're let's, etc522 /[A-Za-z]+[-][a-z]+/, // `no-way`, etc.523 /[A-Za-z][a-z]{2,}/ // allow capitalized words at beginning of sentences524 );525 // looking like plain text, more likely to be a comment526 mode.contains.push(527 {528 // TODO: how to include ", (, ) without breaking grammars that use these for529 // comment delimiters?530 // begin: /[ ]+([()"]?([A-Za-z'-]{3,}|is|a|I|so|us|[tT][oO]|at|if|in|it|on)[.]?[()":]?([.][ ]|[ ]|\))){3}/531 // ---532 // this tries to find sequences of 3 english words in a row (without any533 // "programming" type syntax) this gives us a strong signal that we've534 // TRULY found a comment - vs perhaps scanning with the wrong language.535 // It's possible to find something that LOOKS like the start of the536 // comment - but then if there is no readable text - good chance it is a537 // false match and not a comment.538 //539 // for a visual example please see:540 // https://github.com/highlightjs/highlight.js/issues/2827541 begin: concat(542 /[ ]+/, // necessary to prevent us gobbling up doctags like /* @author Bob Mcgill */543 '(',544 ENGLISH_WORD,545 /[.]?[:]?([.][ ]|[ ])/,546 '){3}') // look for 3 words in a row547 }548 );549 return mode;550 };551 const C_LINE_COMMENT_MODE = COMMENT('//', '$');552 const C_BLOCK_COMMENT_MODE = COMMENT('/\\*', '\\*/');553 const HASH_COMMENT_MODE = COMMENT('#', '$');554 const NUMBER_MODE = {555 scope: 'number',556 begin: NUMBER_RE,557 relevance: 0558 };559 const C_NUMBER_MODE = {560 scope: 'number',561 begin: C_NUMBER_RE,562 relevance: 0563 };564 const BINARY_NUMBER_MODE = {565 scope: 'number',566 begin: BINARY_NUMBER_RE,567 relevance: 0568 };569 const REGEXP_MODE = {570 // this outer rule makes sure we actually have a WHOLE regex and not simply571 // an expression such as:572 //573 // 3 / something574 //575 // (which will then blow up when regex's `illegal` sees the newline)576 begin: /(?=\/[^/\n]*\/)/,577 contains: [{578 scope: 'regexp',579 begin: /\//,580 end: /\/[gimuy]*/,581 illegal: /\n/,582 contains: [583 BACKSLASH_ESCAPE,584 {585 begin: /\[/,586 end: /\]/,587 relevance: 0,588 contains: [BACKSLASH_ESCAPE]589 }590 ]591 }]592 };593 const TITLE_MODE = {594 scope: 'title',595 begin: IDENT_RE,596 relevance: 0597 };598 const UNDERSCORE_TITLE_MODE = {599 scope: 'title',600 begin: UNDERSCORE_IDENT_RE,601 relevance: 0602 };603 const METHOD_GUARD = {604 // excludes method names from keyword processing605 begin: '\\.\\s*' + UNDERSCORE_IDENT_RE,606 relevance: 0607 };608 /**609 * Adds end same as begin mechanics to a mode610 *611 * Your mode must include at least a single () match group as that first match612 * group is what is used for comparison613 * @param {Partial<Mode>} mode614 */615 const END_SAME_AS_BEGIN = function(mode) {616 return Object.assign(mode,617 {618 /** @type {ModeCallback} */619 'on:begin': (m, resp) => { resp.data._beginMatch = m[1]; },620 /** @type {ModeCallback} */621 'on:end': (m, resp) => { if (resp.data._beginMatch !== m[1]) resp.ignoreMatch(); }622 });623 };624 var MODES = /*#__PURE__*/Object.freeze({625 __proto__: null,626 MATCH_NOTHING_RE: MATCH_NOTHING_RE,627 IDENT_RE: IDENT_RE,628 UNDERSCORE_IDENT_RE: UNDERSCORE_IDENT_RE,629 NUMBER_RE: NUMBER_RE,630 C_NUMBER_RE: C_NUMBER_RE,631 BINARY_NUMBER_RE: BINARY_NUMBER_RE,632 RE_STARTERS_RE: RE_STARTERS_RE,633 SHEBANG: SHEBANG,634 BACKSLASH_ESCAPE: BACKSLASH_ESCAPE,635 APOS_STRING_MODE: APOS_STRING_MODE,636 QUOTE_STRING_MODE: QUOTE_STRING_MODE,637 PHRASAL_WORDS_MODE: PHRASAL_WORDS_MODE,638 COMMENT: COMMENT,639 C_LINE_COMMENT_MODE: C_LINE_COMMENT_MODE,640 C_BLOCK_COMMENT_MODE: C_BLOCK_COMMENT_MODE,641 HASH_COMMENT_MODE: HASH_COMMENT_MODE,642 NUMBER_MODE: NUMBER_MODE,643 C_NUMBER_MODE: C_NUMBER_MODE,644 BINARY_NUMBER_MODE: BINARY_NUMBER_MODE,645 REGEXP_MODE: REGEXP_MODE,646 TITLE_MODE: TITLE_MODE,647 UNDERSCORE_TITLE_MODE: UNDERSCORE_TITLE_MODE,648 METHOD_GUARD: METHOD_GUARD,649 END_SAME_AS_BEGIN: END_SAME_AS_BEGIN650 });651 /**652 @typedef {import('highlight.js').CallbackResponse} CallbackResponse653 @typedef {import('highlight.js').CompilerExt} CompilerExt654 */655 // Grammar extensions / plugins656 // See: https://github.com/highlightjs/highlight.js/issues/2833657 // Grammar extensions allow "syntactic sugar" to be added to the grammar modes658 // without requiring any underlying changes to the compiler internals.659 // `compileMatch` being the perfect small example of now allowing a grammar660 // author to write `match` when they desire to match a single expression rather661 // than being forced to use `begin`. The extension then just moves `match` into662 // `begin` when it runs. Ie, no features have been added, but we've just made663 // the experience of writing (and reading grammars) a little bit nicer.664 // ------665 // TODO: We need negative look-behind support to do this properly666 /**667 * Skip a match if it has a preceding dot668 *669 * This is used for `beginKeywords` to prevent matching expressions such as670 * `bob.keyword.do()`. The mode compiler automatically wires this up as a671 * special _internal_ 'on:begin' callback for modes with `beginKeywords`672 * @param {RegExpMatchArray} match673 * @param {CallbackResponse} response674 */675 function skipIfHasPrecedingDot(match, response) {676 const before = match.input[match.index - 1];677 if (before === ".") {678 response.ignoreMatch();679 }680 }681 /**682 *683 * @type {CompilerExt}684 */685 function scopeClassName(mode, _parent) {686 // eslint-disable-next-line no-undefined687 if (mode.className !== undefined) {688 mode.scope = mode.className;689 delete mode.className;690 }691 }692 /**693 * `beginKeywords` syntactic sugar694 * @type {CompilerExt}695 */696 function beginKeywords(mode, parent) {697 if (!parent) return;698 if (!mode.beginKeywords) return;699 // for languages with keywords that include non-word characters checking for700 // a word boundary is not sufficient, so instead we check for a word boundary701 // or whitespace - this does no harm in any case since our keyword engine702 // doesn't allow spaces in keywords anyways and we still check for the boundary703 // first704 mode.begin = '\\b(' + mode.beginKeywords.split(' ').join('|') + ')(?!\\.)(?=\\b|\\s)';705 mode.__beforeBegin = skipIfHasPrecedingDot;706 mode.keywords = mode.keywords || mode.beginKeywords;707 delete mode.beginKeywords;708 // prevents double relevance, the keywords themselves provide709 // relevance, the mode doesn't need to double it710 // eslint-disable-next-line no-undefined711 if (mode.relevance === undefined) mode.relevance = 0;712 }713 /**714 * Allow `illegal` to contain an array of illegal values715 * @type {CompilerExt}716 */717 function compileIllegal(mode, _parent) {718 if (!Array.isArray(mode.illegal)) return;719 mode.illegal = either(...mode.illegal);720 }721 /**722 * `match` to match a single expression for readability723 * @type {CompilerExt}724 */725 function compileMatch(mode, _parent) {726 if (!mode.match) return;727 if (mode.begin || mode.end) throw new Error("begin & end are not supported with match");728 mode.begin = mode.match;729 delete mode.match;730 }731 /**732 * provides the default 1 relevance to all modes733 * @type {CompilerExt}734 */735 function compileRelevance(mode, _parent) {736 // eslint-disable-next-line no-undefined737 if (mode.relevance === undefined) mode.relevance = 1;738 }739 // allow beforeMatch to act as a "qualifier" for the match740 // the full match begin must be [beforeMatch][begin]741 const beforeMatchExt = (mode, parent) => {742 if (!mode.beforeMatch) return;743 // starts conflicts with endsParent which we need to make sure the child744 // rule is not matched multiple times745 if (mode.starts) throw new Error("beforeMatch cannot be used with starts");746 const originalMode = Object.assign({}, mode);747 Object.keys(mode).forEach((key) => { delete mode[key]; });748 mode.keywords = originalMode.keywords;749 mode.begin = concat(originalMode.beforeMatch, lookahead(originalMode.begin));750 mode.starts = {751 relevance: 0,752 contains: [753 Object.assign(originalMode, { endsParent: true })754 ]755 };756 mode.relevance = 0;757 delete originalMode.beforeMatch;758 };759 // keywords that should have no default relevance value760 const COMMON_KEYWORDS = [761 'of',762 'and',763 'for',764 'in',765 'not',766 'or',767 'if',768 'then',769 'parent', // common variable name770 'list', // common variable name771 'value' // common variable name772 ];773 const DEFAULT_KEYWORD_SCOPE = "keyword";774 /**775 * Given raw keywords from a language definition, compile them.776 *777 * @param {string | Record<string,string|string[]> | Array<string>} rawKeywords778 * @param {boolean} caseInsensitive779 */780 function compileKeywords(rawKeywords, caseInsensitive, scopeName = DEFAULT_KEYWORD_SCOPE) {781 /** @type KeywordDict */782 const compiledKeywords = Object.create(null);783 // input can be a string of keywords, an array of keywords, or a object with784 // named keys representing scopeName (which can then point to a string or array)785 if (typeof rawKeywords === 'string') {786 compileList(scopeName, rawKeywords.split(" "));787 } else if (Array.isArray(rawKeywords)) {788 compileList(scopeName, rawKeywords);789 } else {790 Object.keys(rawKeywords).forEach(function(scopeName) {791 // collapse all our objects back into the parent object792 Object.assign(793 compiledKeywords,794 compileKeywords(rawKeywords[scopeName], caseInsensitive, scopeName)795 );796 });797 }798 return compiledKeywords;799 // ---800 /**801 * Compiles an individual list of keywords802 *803 * Ex: "for if when while|5"804 *805 * @param {string} scopeName806 * @param {Array<string>} keywordList807 */808 function compileList(scopeName, keywordList) {809 if (caseInsensitive) {810 keywordList = keywordList.map(x => x.toLowerCase());811 }812 keywordList.forEach(function(keyword) {813 const pair = keyword.split('|');814 compiledKeywords[pair[0]] = [scopeName, scoreForKeyword(pair[0], pair[1])];815 });816 }817 }818 /**819 * Returns the proper score for a given keyword820 *821 * Also takes into account comment keywords, which will be scored 0 UNLESS822 * another score has been manually assigned.823 * @param {string} keyword824 * @param {string} [providedScore]825 */826 function scoreForKeyword(keyword, providedScore) {827 // manual scores always win over common keywords828 // so you can force a score of 1 if you really insist829 if (providedScore) {830 return Number(providedScore);831 }832 return commonKeyword(keyword) ? 0 : 1;833 }834 /**835 * Determines if a given keyword is common or not836 *837 * @param {string} keyword */838 function commonKeyword(keyword) {839 return COMMON_KEYWORDS.includes(keyword.toLowerCase());840 }841 /*842 For the reasoning behind this please see:843 https://github.com/highlightjs/highlight.js/issues/2880#issuecomment-747275419844 */845 /**846 * @type {Record<string, boolean>}847 */848 const seenDeprecations = {};849 /**850 * @param {string} message851 */852 const error = (message) => {853 console.error(message);854 };855 /**856 * @param {string} message857 * @param {any} args858 */859 const warn = (message, ...args) => {860 console.log(`WARN: ${message}`, ...args);861 };862 /**863 * @param {string} version864 * @param {string} message865 */866 const deprecated = (version, message) => {867 if (seenDeprecations[`${version}/${message}`]) return;868 console.log(`Deprecated as of ${version}. ${message}`);869 seenDeprecations[`${version}/${message}`] = true;870 };871 /* eslint-disable no-throw-literal */872 /**873 @typedef {import('highlight.js').CompiledMode} CompiledMode874 */875 const MultiClassError = new Error();876 /**877 * Renumbers labeled scope names to account for additional inner match878 * groups that otherwise would break everything.879 *880 * Lets say we 3 match scopes:881 *882 * { 1 => ..., 2 => ..., 3 => ... }883 *884 * So what we need is a clean match like this:885 *886 * (a)(b)(c) => [ "a", "b", "c" ]887 *888 * But this falls apart with inner match groups:889 *890 * (a)(((b)))(c) => ["a", "b", "b", "b", "c" ]891 *892 * Our scopes are now "out of alignment" and we're repeating `b` 3 times.893 * What needs to happen is the numbers are remapped:894 *895 * { 1 => ..., 2 => ..., 5 => ... }896 *897 * We also need to know that the ONLY groups that should be output898 * are 1, 2, and 5. This function handles this behavior.899 *900 * @param {CompiledMode} mode901 * @param {Array<RegExp>} regexes902 * @param {{key: "beginScope"|"endScope"}} opts903 */904 function remapScopeNames(mode, regexes, { key }) {905 let offset = 0;906 const scopeNames = mode[key];907 /** @type Record<number,boolean> */908 const emit = {};909 /** @type Record<number,string> */910 const positions = {};911 for (let i = 1; i <= regexes.length; i++) {912 positions[i + offset] = scopeNames[i];913 emit[i + offset] = true;914 offset += countMatchGroups(regexes[i - 1]);915 }916 // we use _emit to keep track of which match groups are "top-level" to avoid double917 // output from inside match groups918 mode[key] = positions;919 mode[key]._emit = emit;920 mode[key]._multi = true;921 }922 /**923 * @param {CompiledMode} mode924 */925 function beginMultiClass(mode) {926 if (!Array.isArray(mode.begin)) return;927 if (mode.skip || mode.excludeBegin || mode.returnBegin) {928 error("skip, excludeBegin, returnBegin not compatible with beginScope: {}");929 throw MultiClassError;930 }931 if (typeof mode.beginScope !== "object" || mode.beginScope === null) {932 error("beginScope must be object");933 throw MultiClassError;934 }935 remapScopeNames(mode, mode.begin, {key: "beginScope"});936 mode.begin = _rewriteBackreferences(mode.begin, { joinWith: "" });937 }938 /**939 * @param {CompiledMode} mode940 */941 function endMultiClass(mode) {942 if (!Array.isArray(mode.end)) return;943 if (mode.skip || mode.excludeEnd || mode.returnEnd) {944 error("skip, excludeEnd, returnEnd not compatible with endScope: {}");945 throw MultiClassError;946 }947 if (typeof mode.endScope !== "object" || mode.endScope === null) {948 error("endScope must be object");949 throw MultiClassError;950 }951 remapScopeNames(mode, mode.end, {key: "endScope"});952 mode.end = _rewriteBackreferences(mode.end, { joinWith: "" });953 }954 /**955 * this exists only to allow `scope: {}` to be used beside `match:`956 * Otherwise `beginScope` would necessary and that would look weird957 {958 match: [ /def/, /\w+/ ]959 scope: { 1: "keyword" , 2: "title" }960 }961 * @param {CompiledMode} mode962 */963 function scopeSugar(mode) {964 if (mode.scope && typeof mode.scope === "object" && mode.scope !== null) {965 mode.beginScope = mode.scope;966 delete mode.scope;967 }968 }969 /**970 * @param {CompiledMode} mode971 */972 function MultiClass(mode) {973 scopeSugar(mode);974 if (typeof mode.beginScope === "string") {975 mode.beginScope = { _wrap: mode.beginScope };976 }977 if (typeof mode.endScope === "string") {978 mode.endScope = { _wrap: mode.endScope };979 }980 beginMultiClass(mode);981 endMultiClass(mode);982 }983 /**984 @typedef {import('highlight.js').Mode} Mode985 @typedef {import('highlight.js').CompiledMode} CompiledMode986 @typedef {import('highlight.js').Language} Language987 @typedef {import('highlight.js').HLJSPlugin} HLJSPlugin988 @typedef {import('highlight.js').CompiledLanguage} CompiledLanguage989 */990 // compilation991 /**992 * Compiles a language definition result993 *994 * Given the raw result of a language definition (Language), compiles this so995 * that it is ready for highlighting code.996 * @param {Language} language997 * @returns {CompiledLanguage}998 */999 function compileLanguage(language) {1000 /**1001 * Builds a regex with the case sensitivity of the current language1002 *1003 * @param {RegExp | string} value1004 * @param {boolean} [global]1005 */1006 function langRe(value, global) {1007 return new RegExp(1008 source(value),1009 'm' + (language.case_insensitive ? 'i' : '') + (global ? 'g' : '')1010 );1011 }1012 /**1013 Stores multiple regular expressions and allows you to quickly search for1014 them all in a string simultaneously - returning the first match. It does1015 this by creating a huge (a|b|c) regex - each individual item wrapped with ()1016 and joined by `|` - using match groups to track position. When a match is1017 found checking which position in the array has content allows us to figure1018 out which of the original regexes / match groups triggered the match.1019 The match object itself (the result of `Regex.exec`) is returned but also1020 enhanced by merging in any meta-data that was registered with the regex.1021 This is how we keep track of which mode matched, and what type of rule1022 (`illegal`, `begin`, end, etc).1023 */1024 class MultiRegex {1025 constructor() {1026 this.matchIndexes = {};1027 // @ts-ignore1028 this.regexes = [];1029 this.matchAt = 1;1030 this.position = 0;1031 }1032 // @ts-ignore1033 addRule(re, opts) {1034 opts.position = this.position++;1035 // @ts-ignore1036 this.matchIndexes[this.matchAt] = opts;1037 this.regexes.push([opts, re]);1038 this.matchAt += countMatchGroups(re) + 1;1039 }1040 compile() {1041 if (this.regexes.length === 0) {1042 // avoids the need to check length every time exec is called1043 // @ts-ignore1044 this.exec = () => null;1045 }1046 const terminators = this.regexes.map(el => el[1]);1047 this.matcherRe = langRe(_rewriteBackreferences(terminators, { joinWith: '|' }), true);1048 this.lastIndex = 0;1049 }1050 /** @param {string} s */1051 exec(s) {1052 this.matcherRe.lastIndex = this.lastIndex;1053 const match = this.matcherRe.exec(s);1054 if (!match) { return null; }1055 // eslint-disable-next-line no-undefined1056 const i = match.findIndex((el, i) => i > 0 && el !== undefined);1057 // @ts-ignore1058 const matchData = this.matchIndexes[i];1059 // trim off any earlier non-relevant match groups (ie, the other regex1060 // match groups that make up the multi-matcher)1061 match.splice(0, i);1062 return Object.assign(match, matchData);1063 }1064 }1065 /*1066 Created to solve the key deficiently with MultiRegex - there is no way to1067 test for multiple matches at a single location. Why would we need to do1068 that? In the future a more dynamic engine will allow certain matches to be1069 ignored. An example: if we matched say the 3rd regex in a large group but1070 decided to ignore it - we'd need to started testing again at the 4th1071 regex... but MultiRegex itself gives us no real way to do that.1072 So what this class creates MultiRegexs on the fly for whatever search1073 position they are needed.1074 NOTE: These additional MultiRegex objects are created dynamically. For most1075 grammars most of the time we will never actually need anything more than the1076 first MultiRegex - so this shouldn't have too much overhead.1077 Say this is our search group, and we match regex3, but wish to ignore it.1078 regex1 | regex2 | regex3 | regex4 | regex5 ' ie, startAt = 01079 What we need is a new MultiRegex that only includes the remaining1080 possibilities:1081 regex4 | regex5 ' ie, startAt = 31082 This class wraps all that complexity up in a simple API... `startAt` decides1083 where in the array of expressions to start doing the matching. It1084 auto-increments, so if a match is found at position 2, then startAt will be1085 set to 3. If the end is reached startAt will return to 0.1086 MOST of the time the parser will be setting startAt manually to 0.1087 */1088 class ResumableMultiRegex {1089 constructor() {1090 // @ts-ignore1091 this.rules = [];1092 // @ts-ignore1093 this.multiRegexes = [];1094 this.count = 0;1095 this.lastIndex = 0;1096 this.regexIndex = 0;1097 }1098 // @ts-ignore1099 getMatcher(index) {1100 if (this.multiRegexes[index]) return this.multiRegexes[index];1101 const matcher = new MultiRegex();1102 this.rules.slice(index).forEach(([re, opts]) => matcher.addRule(re, opts));1103 matcher.compile();1104 this.multiRegexes[index] = matcher;1105 return matcher;1106 }1107 resumingScanAtSamePosition() {1108 return this.regexIndex !== 0;1109 }1110 considerAll() {1111 this.regexIndex = 0;1112 }1113 // @ts-ignore1114 addRule(re, opts) {1115 this.rules.push([re, opts]);1116 if (opts.type === "begin") this.count++;1117 }1118 /** @param {string} s */1119 exec(s) {1120 const m = this.getMatcher(this.regexIndex);1121 m.lastIndex = this.lastIndex;1122 let result = m.exec(s);1123 // The following is because we have no easy way to say "resume scanning at the1124 // existing position but also skip the current rule ONLY". What happens is1125 // all prior rules are also skipped which can result in matching the wrong1126 // thing. Example of matching "booger":1127 // our matcher is [string, "booger", number]1128 //1129 // ....booger....1130 // if "booger" is ignored then we'd really need a regex to scan from the1131 // SAME position for only: [string, number] but ignoring "booger" (if it1132 // was the first match), a simple resume would scan ahead who knows how1133 // far looking only for "number", ignoring potential string matches (or1134 // future "booger" matches that might be valid.)1135 // So what we do: We execute two matchers, one resuming at the same1136 // position, but the second full matcher starting at the position after:1137 // /--- resume first regex match here (for [number])1138 // |/---- full match here for [string, "booger", number]1139 // vv1140 // ....booger....1141 // Which ever results in a match first is then used. So this 3-4 step1142 // process essentially allows us to say "match at this position, excluding1143 // a prior rule that was ignored".1144 //1145 // 1. Match "booger" first, ignore. Also proves that [string] does non match.1146 // 2. Resume matching for [number]1147 // 3. Match at index + 1 for [string, "booger", number]1148 // 4. If #2 and #3 result in matches, which came first?1149 if (this.resumingScanAtSamePosition()) {1150 if (result && result.index === this.lastIndex) ; else { // use the second matcher result1151 const m2 = this.getMatcher(0);1152 m2.lastIndex = this.lastIndex + 1;1153 result = m2.exec(s);1154 }1155 }1156 if (result) {1157 this.regexIndex += result.position + 1;1158 if (this.regexIndex === this.count) {1159 // wrap-around to considering all matches again1160 this.considerAll();1161 }1162 }1163 return result;1164 }1165 }1166 /**1167 * Given a mode, builds a huge ResumableMultiRegex that can be used to walk1168 * the content and find matches.1169 *1170 * @param {CompiledMode} mode1171 * @returns {ResumableMultiRegex}1172 */1173 function buildModeRegex(mode) {1174 const mm = new ResumableMultiRegex();1175 mode.contains.forEach(term => mm.addRule(term.begin, { rule: term, type: "begin" }));1176 if (mode.terminatorEnd) {1177 mm.addRule(mode.terminatorEnd, { type: "end" });1178 }1179 if (mode.illegal) {1180 mm.addRule(mode.illegal, { type: "illegal" });1181 }1182 return mm;1183 }1184 /** skip vs abort vs ignore1185 *1186 * @skip - The mode is still entered and exited normally (and contains rules apply),1187 * but all content is held and added to the parent buffer rather than being1188 * output when the mode ends. Mostly used with `sublanguage` to build up1189 * a single large buffer than can be parsed by sublanguage.1190 *1191 * - The mode begin ands ends normally.1192 * - Content matched is added to the parent mode buffer.1193 * - The parser cursor is moved forward normally.1194 *1195 * @abort - A hack placeholder until we have ignore. Aborts the mode (as if it1196 * never matched) but DOES NOT continue to match subsequent `contains`1197 * modes. Abort is bad/suboptimal because it can result in modes1198 * farther down not getting applied because an earlier rule eats the1199 * content but then aborts.1200 *1201 * - The mode does not begin.1202 * - Content matched by `begin` is added to the mode buffer.1203 * - The parser cursor is moved forward accordingly.1204 *1205 * @ignore - Ignores the mode (as if it never matched) and continues to match any1206 * subsequent `contains` modes. Ignore isn't technically possible with1207 * the current parser implementation.1208 *1209 * - The mode does not begin.1210 * - Content matched by `begin` is ignored.1211 * - The parser cursor is not moved forward.1212 */1213 /**1214 * Compiles an individual mode1215 *1216 * This can raise an error if the mode contains certain detectable known logic1217 * issues.1218 * @param {Mode} mode1219 * @param {CompiledMode | null} [parent]1220 * @returns {CompiledMode | never}1221 */1222 function compileMode(mode, parent) {1223 const cmode = /** @type CompiledMode */ (mode);1224 if (mode.isCompiled) return cmode;1225 [1226 scopeClassName,1227 // do this early so compiler extensions generally don't have to worry about1228 // the distinction between match/begin1229 compileMatch,1230 MultiClass,1231 beforeMatchExt1232 ].forEach(ext => ext(mode, parent));1233 language.compilerExtensions.forEach(ext => ext(mode, parent));1234 // __beforeBegin is considered private API, internal use only1235 mode.__beforeBegin = null;1236 [1237 beginKeywords,1238 // do this later so compiler extensions that come earlier have access to the1239 // raw array if they wanted to perhaps manipulate it, etc.1240 compileIllegal,1241 // default to 1 relevance if not specified1242 compileRelevance1243 ].forEach(ext => ext(mode, parent));1244 mode.isCompiled = true;1245 let keywordPattern = null;1246 if (typeof mode.keywords === "object" && mode.keywords.$pattern) {1247 // we need a copy because keywords might be compiled multiple times1248 // so we can't go deleting $pattern from the original on the first1249 // pass1250 mode.keywords = Object.assign({}, mode.keywords);1251 keywordPattern = mode.keywords.$pattern;1252 delete mode.keywords.$pattern;1253 }1254 keywordPattern = keywordPattern || /\w+/;1255 if (mode.keywords) {1256 mode.keywords = compileKeywords(mode.keywords, language.case_insensitive);1257 }1258 cmode.keywordPatternRe = langRe(keywordPattern, true);1259 if (parent) {1260 if (!mode.begin) mode.begin = /\B|\b/;1261 cmode.beginRe = langRe(mode.begin);1262 if (!mode.end && !mode.endsWithParent) mode.end = /\B|\b/;1263 if (mode.end) cmode.endRe = langRe(mode.end);1264 cmode.terminatorEnd = source(mode.end) || '';1265 if (mode.endsWithParent && parent.terminatorEnd) {1266 cmode.terminatorEnd += (mode.end ? '|' : '') + parent.terminatorEnd;1267 }1268 }1269 if (mode.illegal) cmode.illegalRe = langRe(/** @type {RegExp | string} */ (mode.illegal));1270 if (!mode.contains) mode.contains = [];1271 mode.contains = [].concat(...mode.contains.map(function(c) {1272 return expandOrCloneMode(c === 'self' ? mode : c);1273 }));1274 mode.contains.forEach(function(c) { compileMode(/** @type Mode */ (c), cmode); });1275 if (mode.starts) {1276 compileMode(mode.starts, parent);1277 }1278 cmode.matcher = buildModeRegex(cmode);1279 return cmode;1280 }1281 if (!language.compilerExtensions) language.compilerExtensions = [];1282 // self is not valid at the top-level1283 if (language.contains && language.contains.includes('self')) {1284 throw new Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");1285 }1286 // we need a null object, which inherit will guarantee1287 language.classNameAliases = inherit$1(language.classNameAliases || {});1288 return compileMode(/** @type Mode */ (language));1289 }1290 /**1291 * Determines if a mode has a dependency on it's parent or not1292 *1293 * If a mode does have a parent dependency then often we need to clone it if1294 * it's used in multiple places so that each copy points to the correct parent,1295 * where-as modes without a parent can often safely be re-used at the bottom of1296 * a mode chain.1297 *1298 * @param {Mode | null} mode1299 * @returns {boolean} - is there a dependency on the parent?1300 * */1301 function dependencyOnParent(mode) {1302 if (!mode) return false;1303 return mode.endsWithParent || dependencyOnParent(mode.starts);1304 }1305 /**1306 * Expands a mode or clones it if necessary1307 *1308 * This is necessary for modes with parental dependenceis (see notes on1309 * `dependencyOnParent`) and for nodes that have `variants` - which must then be1310 * exploded into their own individual modes at compile time.1311 *1312 * @param {Mode} mode1313 * @returns {Mode | Mode[]}1314 * */1315 function expandOrCloneMode(mode) {1316 if (mode.variants && !mode.cachedVariants) {1317 mode.cachedVariants = mode.variants.map(function(variant) {1318 return inherit$1(mode, { variants: null }, variant);1319 });1320 }1321 // EXPAND1322 // if we have variants then essentially "replace" the mode with the variants1323 // this happens in compileMode, where this function is called from1324 if (mode.cachedVariants) {1325 return mode.cachedVariants;1326 }1327 // CLONE1328 // if we have dependencies on parents then we need a unique1329 // instance of ourselves, so we can be reused with many1330 // different parents without issue1331 if (dependencyOnParent(mode)) {1332 return inherit$1(mode, { starts: mode.starts ? inherit$1(mode.starts) : null });1333 }1334 if (Object.isFrozen(mode)) {1335 return inherit$1(mode);1336 }1337 // no special dependency issues, just return ourselves1338 return mode;1339 }1340 var version = "11.0.1";1341 /*1342 Syntax highlighting with language autodetection.1343 https://highlightjs.org/1344 */1345 /**1346 @typedef {import('highlight.js').Mode} Mode1347 @typedef {import('highlight.js').CompiledMode} CompiledMode1348 @typedef {import('highlight.js').Language} Language1349 @typedef {import('highlight.js').HLJSApi} HLJSApi1350 @typedef {import('highlight.js').HLJSPlugin} HLJSPlugin1351 @typedef {import('highlight.js').PluginEvent} PluginEvent1352 @typedef {import('highlight.js').HLJSOptions} HLJSOptions1353 @typedef {import('highlight.js').LanguageFn} LanguageFn1354 @typedef {import('highlight.js').HighlightedHTMLElement} HighlightedHTMLElement1355 @typedef {import('highlight.js').BeforeHighlightContext} BeforeHighlightContext1356 @typedef {import('highlight.js/private').MatchType} MatchType1357 @typedef {import('highlight.js/private').KeywordData} KeywordData1358 @typedef {import('highlight.js/private').EnhancedMatch} EnhancedMatch1359 @typedef {import('highlight.js/private').AnnotatedError} AnnotatedError1360 @typedef {import('highlight.js').AutoHighlightResult} AutoHighlightResult1361 @typedef {import('highlight.js').HighlightOptions} HighlightOptions1362 @typedef {import('highlight.js').HighlightResult} HighlightResult1363 */1364 const escape = escapeHTML;1365 const inherit = inherit$1;1366 const NO_MATCH = Symbol("nomatch");1367 const MAX_KEYWORD_HITS = 7;1368 /**1369 * @param {any} hljs - object that is extended (legacy)1370 * @returns {HLJSApi}1371 */1372 const HLJS = function(hljs) {1373 // Global internal variables used within the highlight.js library.1374 /** @type {Record<string, Language>} */1375 const languages = Object.create(null);1376 /** @type {Record<string, string>} */1377 const aliases = Object.create(null);1378 /** @type {HLJSPlugin[]} */1379 const plugins = [];1380 // safe/production mode - swallows more errors, tries to keep running1381 // even if a single syntax or parse hits a fatal error1382 let SAFE_MODE = true;1383 const LANGUAGE_NOT_FOUND = "Could not find the language '{}', did you forget to load/include a language module?";1384 /** @type {Language} */1385 const PLAINTEXT_LANGUAGE = { disableAutodetect: true, name: 'Plain text', contains: [] };1386 // Global options used when within external APIs. This is modified when1387 // calling the `hljs.configure` function.1388 /** @type HLJSOptions */1389 let options = {1390 ignoreUnescapedHTML: false,1391 noHighlightRe: /^(no-?highlight)$/i,1392 languageDetectRe: /\blang(?:uage)?-([\w-]+)\b/i,1393 classPrefix: 'hljs-',1394 cssSelector: 'pre code',1395 languages: null,1396 // beta configuration options, subject to change, welcome to discuss1397 // https://github.com/highlightjs/highlight.js/issues/10861398 __emitter: TokenTreeEmitter1399 };1400 /* Utility functions */1401 /**1402 * Tests a language name to see if highlighting should be skipped1403 * @param {string} languageName1404 */1405 function shouldNotHighlight(languageName) {1406 return options.noHighlightRe.test(languageName);1407 }1408 /**1409 * @param {HighlightedHTMLElement} block - the HTML element to determine language for1410 */1411 function blockLanguage(block) {1412 let classes = block.className + ' ';1413 classes += block.parentNode ? block.parentNode.className : '';1414 // language-* takes precedence over non-prefixed class names.1415 const match = options.languageDetectRe.exec(classes);1416 if (match) {1417 const language = getLanguage(match[1]);1418 if (!language) {1419 warn(LANGUAGE_NOT_FOUND.replace("{}", match[1]));1420 warn("Falling back to no-highlight mode for this block.", block);1421 }1422 return language ? match[1] : 'no-highlight';1423 }1424 return classes1425 .split(/\s+/)1426 .find((_class) => shouldNotHighlight(_class) || getLanguage(_class));1427 }1428 /**1429 * Core highlighting function.1430 *1431 * OLD API1432 * highlight(lang, code, ignoreIllegals, continuation)1433 *1434 * NEW API1435 * highlight(code, {lang, ignoreIllegals})1436 *1437 * @param {string} codeOrLanguageName - the language to use for highlighting1438 * @param {string | HighlightOptions} optionsOrCode - the code to highlight1439 * @param {boolean} [ignoreIllegals] - whether to ignore illegal matches, default is to bail1440 * @param {CompiledMode} [continuation] - current continuation mode, if any1441 *1442 * @returns {HighlightResult} Result - an object that represents the result1443 * @property {string} language - the language name1444 * @property {number} relevance - the relevance score1445 * @property {string} value - the highlighted HTML code1446 * @property {string} code - the original raw code1447 * @property {CompiledMode} top - top of the current mode stack1448 * @property {boolean} illegal - indicates whether any illegal matches were found1449 */1450 function highlight(codeOrLanguageName, optionsOrCode, ignoreIllegals, continuation) {1451 let code = "";1452 let languageName = "";1453 if (typeof optionsOrCode === "object") {1454 code = codeOrLanguageName;1455 ignoreIllegals = optionsOrCode.ignoreIllegals;1456 languageName = optionsOrCode.language;1457 // continuation not supported at all via the new API1458 // eslint-disable-next-line no-undefined1459 continuation = undefined;1460 } else {1461 // old API1462 deprecated("10.7.0", "highlight(lang, code, ...args) has been deprecated.");1463 deprecated("10.7.0", "Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277");1464 languageName = codeOrLanguageName;1465 code = optionsOrCode;1466 }1467 // https://github.com/highlightjs/highlight.js/issues/31491468 // eslint-disable-next-line no-undefined1469 if (ignoreIllegals === undefined) { ignoreIllegals = true; }1470 /** @type {BeforeHighlightContext} */1471 const context = {1472 code,1473 language: languageName1474 };1475 // the plugin can change the desired language or the code to be highlighted1476 // just be changing the object it was passed1477 fire("before:highlight", context);1478 // a before plugin can usurp the result completely by providing it's own1479 // in which case we don't even need to call highlight1480 const result = context.result1481 ? context.result1482 : _highlight(context.language, context.code, ignoreIllegals, continuation);1483 result.code = context.code;1484 // the plugin can change anything in result to suite it1485 fire("after:highlight", result);1486 return result;1487 }1488 /**1489 * private highlight that's used internally and does not fire callbacks1490 *1491 * @param {string} languageName - the language to use for highlighting1492 * @param {string} codeToHighlight - the code to highlight1493 * @param {boolean?} [ignoreIllegals] - whether to ignore illegal matches, default is to bail1494 * @param {CompiledMode?} [continuation] - current continuation mode, if any1495 * @returns {HighlightResult} - result of the highlight operation1496 */1497 function _highlight(languageName, codeToHighlight, ignoreIllegals, continuation) {1498 const keywordHits = Object.create(null);1499 /**1500 * Return keyword data if a match is a keyword1501 * @param {CompiledMode} mode - current mode1502 * @param {string} matchText - the textual match1503 * @returns {KeywordData | false}1504 */1505 function keywordData(mode, matchText) {1506 return mode.keywords[matchText];1507 }1508 function processKeywords() {1509 if (!top.keywords) {1510 emitter.addText(modeBuffer);1511 return;1512 }1513 let lastIndex = 0;1514 top.keywordPatternRe.lastIndex = 0;1515 let match = top.keywordPatternRe.exec(modeBuffer);1516 let buf = "";1517 while (match) {1518 buf += modeBuffer.substring(lastIndex, match.index);1519 const word = language.case_insensitive ? match[0].toLowerCase() : match[0];1520 const data = keywordData(top, word);1521 if (data) {1522 const [kind, keywordRelevance] = data;1523 emitter.addText(buf);1524 buf = "";1525 keywordHits[word] = (keywordHits[word] || 0) + 1;1526 if (keywordHits[word] <= MAX_KEYWORD_HITS) relevance += keywordRelevance;1527 if (kind.startsWith("_")) {1528 // _ implied for relevance only, do not highlight1529 // by applying a class name1530 buf += match[0];1531 } else {1532 const cssClass = language.classNameAliases[kind] || kind;1533 emitter.addKeyword(match[0], cssClass);1534 }1535 } else {1536 buf += match[0];1537 }1538 lastIndex = top.keywordPatternRe.lastIndex;1539 match = top.keywordPatternRe.exec(modeBuffer);1540 }1541 buf += modeBuffer.substr(lastIndex);1542 emitter.addText(buf);1543 }1544 function processSubLanguage() {1545 if (modeBuffer === "") return;1546 /** @type HighlightResult */1547 let result = null;1548 if (typeof top.subLanguage === 'string') {1549 if (!languages[top.subLanguage]) {1550 emitter.addText(modeBuffer);1551 return;1552 }1553 result = _highlight(top.subLanguage, modeBuffer, true, continuations[top.subLanguage]);1554 continuations[top.subLanguage] = /** @type {CompiledMode} */ (result._top);1555 } else {1556 result = highlightAuto(modeBuffer, top.subLanguage.length ? top.subLanguage : null);1557 }1558 // Counting embedded language score towards the host language may be disabled1559 // with zeroing the containing mode relevance. Use case in point is Markdown that1560 // allows XML everywhere and makes every XML snippet to have a much larger Markdown1561 // score.1562 if (top.relevance > 0) {1563 relevance += result.relevance;1564 }1565 emitter.addSublanguage(result._emitter, result.language);1566 }1567 function processBuffer() {1568 if (top.subLanguage != null) {1569 processSubLanguage();1570 } else {1571 processKeywords();1572 }1573 modeBuffer = '';1574 }1575 /**1576 * @param {CompiledMode} mode1577 * @param {RegExpMatchArray} match1578 */1579 function emitMultiClass(scope, match) {1580 let i = 1;1581 // eslint-disable-next-line no-undefined1582 while (match[i] !== undefined) {1583 if (!scope._emit[i]) { i++; continue; }1584 const klass = language.classNameAliases[scope[i]] || scope[i];1585 const text = match[i];1586 if (klass) {1587 emitter.addKeyword(text, klass);1588 } else {1589 modeBuffer = text;1590 processKeywords();1591 modeBuffer = "";1592 }1593 i++;1594 }1595 }1596 /**1597 * @param {CompiledMode} mode - new mode to start1598 * @param {RegExpMatchArray} match1599 */1600 function startNewMode(mode, match) {1601 if (mode.scope && typeof mode.scope === "string") {1602 emitter.openNode(language.classNameAliases[mode.scope] || mode.scope);1603 }1604 if (mode.beginScope) {1605 // beginScope just wraps the begin match itself in a scope1606 if (mode.beginScope._wrap) {1607 emitter.addKeyword(modeBuffer, language.classNameAliases[mode.beginScope._wrap] || mode.beginScope._wrap);1608 modeBuffer = "";1609 } else if (mode.beginScope._multi) {1610 // at this point modeBuffer should just be the match1611 emitMultiClass(mode.beginScope, match);1612 modeBuffer = "";1613 }1614 }1615 top = Object.create(mode, { parent: { value: top } });1616 return top;1617 }1618 /**1619 * @param {CompiledMode } mode - the mode to potentially end1620 * @param {RegExpMatchArray} match - the latest match1621 * @param {string} matchPlusRemainder - match plus remainder of content1622 * @returns {CompiledMode | void} - the next mode, or if void continue on in current mode1623 */1624 function endOfMode(mode, match, matchPlusRemainder) {1625 let matched = startsWith(mode.endRe, matchPlusRemainder);1626 if (matched) {1627 if (mode["on:end"]) {1628 const resp = new Response(mode);1629 mode["on:end"](match, resp);1630 if (resp.isMatchIgnored) matched = false;1631 }1632 if (matched) {1633 while (mode.endsParent && mode.parent) {1634 mode = mode.parent;1635 }1636 return mode;1637 }1638 }1639 // even if on:end fires an `ignore` it's still possible1640 // that we might trigger the end node because of a parent mode1641 if (mode.endsWithParent) {1642 return endOfMode(mode.parent, match, matchPlusRemainder);1643 }1644 }1645 /**1646 * Handle matching but then ignoring a sequence of text1647 *1648 * @param {string} lexeme - string containing full match text1649 */1650 function doIgnore(lexeme) {1651 if (top.matcher.regexIndex === 0) {1652 // no more regexes to potentially match here, so we move the cursor forward one1653 // space1654 modeBuffer += lexeme[0];1655 return 1;1656 } else {1657 // no need to move the cursor, we still have additional regexes to try and1658 // match at this very spot1659 resumeScanAtSamePosition = true;1660 return 0;1661 }1662 }1663 /**1664 * Handle the start of a new potential mode match1665 *1666 * @param {EnhancedMatch} match - the current match1667 * @returns {number} how far to advance the parse cursor1668 */1669 function doBeginMatch(match) {1670 const lexeme = match[0];1671 const newMode = match.rule;1672 const resp = new Response(newMode);1673 // first internal before callbacks, then the public ones1674 const beforeCallbacks = [newMode.__beforeBegin, newMode["on:begin"]];1675 for (const cb of beforeCallbacks) {1676 if (!cb) continue;1677 cb(match, resp);1678 if (resp.isMatchIgnored) return doIgnore(lexeme);1679 }1680 if (newMode.skip) {1681 modeBuffer += lexeme;1682 } else {1683 if (newMode.excludeBegin) {1684 modeBuffer += lexeme;1685 }1686 processBuffer();1687 if (!newMode.returnBegin && !newMode.excludeBegin) {1688 modeBuffer = lexeme;1689 }1690 }1691 startNewMode(newMode, match);1692 return newMode.returnBegin ? 0 : lexeme.length;1693 }1694 /**1695 * Handle the potential end of mode1696 *1697 * @param {RegExpMatchArray} match - the current match1698 */1699 function doEndMatch(match) {1700 const lexeme = match[0];1701 const matchPlusRemainder = codeToHighlight.substr(match.index);1702 const endMode = endOfMode(top, match, matchPlusRemainder);1703 if (!endMode) { return NO_MATCH; }1704 const origin = top;1705 if (top.endScope && top.endScope._wrap) {1706 processBuffer();1707 emitter.addKeyword(lexeme, top.endScope._wrap);1708 } else if (top.endScope && top.endScope._multi) {1709 processBuffer();1710 emitMultiClass(top.endScope, match);1711 } else if (origin.skip) {1712 modeBuffer += lexeme;1713 } else {1714 if (!(origin.returnEnd || origin.excludeEnd)) {1715 modeBuffer += lexeme;1716 }1717 processBuffer();1718 if (origin.excludeEnd) {1719 modeBuffer = lexeme;1720 }1721 }1722 do {1723 if (top.scope && !top.isMultiClass) {1724 emitter.closeNode();1725 }1726 if (!top.skip && !top.subLanguage) {1727 relevance += top.relevance;1728 }1729 top = top.parent;1730 } while (top !== endMode.parent);1731 if (endMode.starts) {1732 startNewMode(endMode.starts, match);1733 }1734 return origin.returnEnd ? 0 : lexeme.length;1735 }1736 function processContinuations() {1737 const list = [];1738 for (let current = top; current !== language; current = current.parent) {1739 if (current.scope) {1740 list.unshift(current.scope);1741 }1742 }1743 list.forEach(item => emitter.openNode(item));1744 }1745 /** @type {{type?: MatchType, index?: number, rule?: Mode}}} */1746 let lastMatch = {};1747 /**1748 * Process an individual match1749 *1750 * @param {string} textBeforeMatch - text preceding the match (since the last match)1751 * @param {EnhancedMatch} [match] - the match itself1752 */1753 function processLexeme(textBeforeMatch, match) {1754 const lexeme = match && match[0];1755 // add non-matched text to the current mode buffer1756 modeBuffer += textBeforeMatch;1757 if (lexeme == null) {1758 processBuffer();1759 return 0;1760 }1761 // we've found a 0 width match and we're stuck, so we need to advance1762 // this happens when we have badly behaved rules that have optional matchers to the degree that1763 // sometimes they can end up matching nothing at all1764 // Ref: https://github.com/highlightjs/highlight.js/issues/21401765 if (lastMatch.type === "begin" && match.type === "end" && lastMatch.index === match.index && lexeme === "") {1766 // spit the "skipped" character that our regex choked on back into the output sequence1767 modeBuffer += codeToHighlight.slice(match.index, match.index + 1);1768 if (!SAFE_MODE) {1769 /** @type {AnnotatedError} */1770 const err = new Error(`0 width match regex (${languageName})`);1771 err.languageName = languageName;1772 err.badRule = lastMatch.rule;1773 throw err;1774 }1775 return 1;1776 }1777 lastMatch = match;1778 if (match.type === "begin") {1779 return doBeginMatch(match);1780 } else if (match.type === "illegal" && !ignoreIllegals) {1781 // illegal match, we do not continue processing1782 /** @type {AnnotatedError} */1783 const err = new Error('Illegal lexeme "' + lexeme + '" for mode "' + (top.scope || '<unnamed>') + '"');1784 err.mode = top;1785 throw err;1786 } else if (match.type === "end") {1787 const processed = doEndMatch(match);1788 if (processed !== NO_MATCH) {1789 return processed;1790 }1791 }1792 // edge case for when illegal matches $ (end of line) which is technically1793 // a 0 width match but not a begin/end match so it's not caught by the1794 // first handler (when ignoreIllegals is true)1795 if (match.type === "illegal" && lexeme === "") {1796 // advance so we aren't stuck in an infinite loop1797 return 1;1798 }1799 // infinite loops are BAD, this is a last ditch catch all. if we have a1800 // decent number of iterations yet our index (cursor position in our1801 // parsing) still 3x behind our index then something is very wrong1802 // so we bail1803 if (iterations > 100000 && iterations > match.index * 3) {1804 const err = new Error('potential infinite loop, way more iterations than matches');1805 throw err;1806 }1807 /*1808 Why might be find ourselves here? An potential end match that was1809 triggered but could not be completed. IE, `doEndMatch` returned NO_MATCH.1810 (this could be because a callback requests the match be ignored, etc)1811 This causes no real harm other than stopping a few times too many.1812 */1813 modeBuffer += lexeme;1814 return lexeme.length;1815 }1816 const language = getLanguage(languageName);1817 if (!language) {1818 error(LANGUAGE_NOT_FOUND.replace("{}", languageName));1819 throw new Error('Unknown language: "' + languageName + '"');1820 }1821 const md = compileLanguage(language);1822 let result = '';1823 /** @type {CompiledMode} */1824 let top = continuation || md;1825 /** @type Record<string,CompiledMode> */1826 const continuations = {}; // keep continuations for sub-languages1827 const emitter = new options.__emitter(options);1828 processContinuations();1829 let modeBuffer = '';1830 let relevance = 0;1831 let index = 0;1832 let iterations = 0;1833 let resumeScanAtSamePosition = false;1834 try {1835 top.matcher.considerAll();1836 for (;;) {1837 iterations++;1838 if (resumeScanAtSamePosition) {1839 // only regexes not matched previously will now be1840 // considered for a potential match1841 resumeScanAtSamePosition = false;1842 } else {1843 top.matcher.considerAll();1844 }1845 top.matcher.lastIndex = index;1846 const match = top.matcher.exec(codeToHighlight);1847 // console.log("match", match[0], match.rule && match.rule.begin)1848 if (!match) break;1849 const beforeMatch = codeToHighlight.substring(index, match.index);1850 const processedCount = processLexeme(beforeMatch, match);1851 index = match.index + processedCount;1852 }1853 processLexeme(codeToHighlight.substr(index));1854 emitter.closeAllNodes();1855 emitter.finalize();1856 result = emitter.toHTML();1857 return {1858 language: languageName,1859 value: result,1860 relevance: relevance,1861 illegal: false,1862 _emitter: emitter,1863 _top: top1864 };1865 } catch (err) {1866 if (err.message && err.message.includes('Illegal')) {1867 return {1868 language: languageName,1869 value: escape(codeToHighlight),1870 illegal: true,1871 relevance: 0,1872 _illegalBy: {1873 message: err.message,1874 index: index,1875 context: codeToHighlight.slice(index - 100, index + 100),1876 mode: err.mode,1877 resultSoFar: result1878 },1879 _emitter: emitter1880 };1881 } else if (SAFE_MODE) {1882 return {1883 language: languageName,1884 value: escape(codeToHighlight),1885 illegal: false,1886 relevance: 0,1887 errorRaised: err,1888 _emitter: emitter,1889 _top: top1890 };1891 } else {1892 throw err;1893 }1894 }1895 }1896 /**1897 * returns a valid highlight result, without actually doing any actual work,1898 * auto highlight starts with this and it's possible for small snippets that1899 * auto-detection may not find a better match1900 * @param {string} code1901 * @returns {HighlightResult}1902 */1903 function justTextHighlightResult(code) {1904 const result = {1905 value: escape(code),1906 illegal: false,1907 relevance: 0,1908 _top: PLAINTEXT_LANGUAGE,1909 _emitter: new options.__emitter(options)1910 };1911 result._emitter.addText(code);1912 return result;1913 }1914 /**1915 Highlighting with language detection. Accepts a string with the code to1916 highlight. Returns an object with the following properties:1917 - language (detected language)1918 - relevance (int)1919 - value (an HTML string with highlighting markup)1920 - secondBest (object with the same structure for second-best heuristically1921 detected language, may be absent)1922 @param {string} code1923 @param {Array<string>} [languageSubset]1924 @returns {AutoHighlightResult}1925 */1926 function highlightAuto(code, languageSubset) {1927 languageSubset = languageSubset || options.languages || Object.keys(languages);1928 const plaintext = justTextHighlightResult(code);1929 const results = languageSubset.filter(getLanguage).filter(autoDetection).map(name =>1930 _highlight(name, code, false)1931 );1932 results.unshift(plaintext); // plaintext is always an option1933 const sorted = results.sort((a, b) => {1934 // sort base on relevance1935 if (a.relevance !== b.relevance) return b.relevance - a.relevance;1936 // always award the tie to the base language1937 // ie if C++ and Arduino are tied, it's more likely to be C++1938 if (a.language && b.language) {1939 if (getLanguage(a.language).supersetOf === b.language) {1940 return 1;1941 } else if (getLanguage(b.language).supersetOf === a.language) {1942 return -1;1943 }1944 }1945 // otherwise say they are equal, which has the effect of sorting on1946 // relevance while preserving the original ordering - which is how ties1947 // have historically been settled, ie the language that comes first always1948 // wins in the case of a tie1949 return 0;1950 });1951 const [best, secondBest] = sorted;1952 /** @type {AutoHighlightResult} */1953 const result = best;1954 result.secondBest = secondBest;1955 return result;1956 }1957 /**1958 * Builds new class name for block given the language name1959 *1960 * @param {HTMLElement} element1961 * @param {string} [currentLang]1962 * @param {string} [resultLang]1963 */1964 function updateClassName(element, currentLang, resultLang) {1965 const language = (currentLang && aliases[currentLang]) || resultLang;1966 element.classList.add("hljs");1967 element.classList.add(`language-${language}`);1968 }1969 /**1970 * Applies highlighting to a DOM node containing code.1971 *1972 * @param {HighlightedHTMLElement} element - the HTML element to highlight1973 */1974 function highlightElement(element) {1975 /** @type HTMLElement */1976 let node = null;1977 const language = blockLanguage(element);1978 if (shouldNotHighlight(language)) return;1979 fire("before:highlightElement",1980 { el: element, language: language });1981 // we should be all text, no child nodes1982 if (!options.ignoreUnescapedHTML && element.children.length > 0) {1983 console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk.");1984 console.warn("https://github.com/highlightjs/highlight.js/issues/2886");1985 console.warn(element);1986 }1987 node = element;1988 const text = node.textContent;1989 const result = language ? highlight(text, { language, ignoreIllegals: true }) : highlightAuto(text);1990 element.innerHTML = result.value;1991 updateClassName(element, language, result.language);1992 element.result = {1993 language: result.language,1994 // TODO: remove with version 11.01995 re: result.relevance,1996 relevance: result.relevance1997 };1998 if (result.secondBest) {1999 element.secondBest = {2000 language: result.secondBest.language,2001 relevance: result.secondBest.relevance2002 };2003 }2004 fire("after:highlightElement", { el: element, result, text });2005 }2006 /**2007 * Updates highlight.js global options with the passed options2008 *2009 * @param {Partial<HLJSOptions>} userOptions2010 */2011 function configure(userOptions) {2012 options = inherit(options, userOptions);2013 }2014 // TODO: remove v12, deprecated2015 const initHighlighting = () => {2016 highlightAll();2017 deprecated("10.6.0", "initHighlighting() deprecated. Use highlightAll() now.");2018 };2019 // TODO: remove v12, deprecated2020 function initHighlightingOnLoad() {2021 highlightAll();2022 deprecated("10.6.0", "initHighlightingOnLoad() deprecated. Use highlightAll() now.");2023 }2024 let wantsHighlight = false;2025 /**2026 * auto-highlights all pre>code elements on the page2027 */2028 function highlightAll() {2029 // if we are called too early in the loading process2030 if (document.readyState === "loading") {2031 wantsHighlight = true;2032 return;2033 }2034 const blocks = document.querySelectorAll(options.cssSelector);2035 blocks.forEach(highlightElement);2036 }2037 function boot() {2038 // if a highlight was requested before DOM was loaded, do now2039 if (wantsHighlight) highlightAll();2040 }2041 // make sure we are in the browser environment2042 if (typeof window !== 'undefined' && window.addEventListener) {2043 window.addEventListener('DOMContentLoaded', boot, false);2044 }2045 /**2046 * Register a language grammar module2047 *2048 * @param {string} languageName2049 * @param {LanguageFn} languageDefinition2050 */2051 function registerLanguage(languageName, languageDefinition) {2052 let lang = null;2053 try {2054 lang = languageDefinition(hljs);2055 } catch (error$1) {2056 error("Language definition for '{}' could not be registered.".replace("{}", languageName));2057 // hard or soft error2058 if (!SAFE_MODE) { throw error$1; } else { error(error$1); }2059 // languages that have serious errors are replaced with essentially a2060 // "plaintext" stand-in so that the code blocks will still get normal2061 // css classes applied to them - and one bad language won't break the2062 // entire highlighter2063 lang = PLAINTEXT_LANGUAGE;2064 }2065 // give it a temporary name if it doesn't have one in the meta-data2066 if (!lang.name) lang.name = languageName;2067 languages[languageName] = lang;2068 lang.rawDefinition = languageDefinition.bind(null, hljs);2069 if (lang.aliases) {2070 registerAliases(lang.aliases, { languageName });2071 }2072 }2073 /**2074 * Remove a language grammar module2075 *2076 * @param {string} languageName2077 */2078 function unregisterLanguage(languageName) {2079 delete languages[languageName];2080 for (const alias of Object.keys(aliases)) {2081 if (aliases[alias] === languageName) {2082 delete aliases[alias];2083 }2084 }2085 }2086 /**2087 * @returns {string[]} List of language internal names2088 */2089 function listLanguages() {2090 return Object.keys(languages);2091 }2092 /**2093 * @param {string} name - name of the language to retrieve2094 * @returns {Language | undefined}2095 */2096 function getLanguage(name) {2097 name = (name || '').toLowerCase();2098 return languages[name] || languages[aliases[name]];2099 }2100 /**2101 *2102 * @param {string|string[]} aliasList - single alias or list of aliases2103 * @param {{languageName: string}} opts2104 */2105 function registerAliases(aliasList, { languageName }) {2106 if (typeof aliasList === 'string') {2107 aliasList = [aliasList];2108 }2109 aliasList.forEach(alias => { aliases[alias.toLowerCase()] = languageName; });2110 }2111 /**2112 * Determines if a given language has auto-detection enabled2113 * @param {string} name - name of the language2114 */2115 function autoDetection(name) {2116 const lang = getLanguage(name);2117 return lang && !lang.disableAutodetect;2118 }2119 /**2120 * Upgrades the old highlightBlock plugins to the new2121 * highlightElement API2122 * @param {HLJSPlugin} plugin2123 */2124 function upgradePluginAPI(plugin) {2125 // TODO: remove with v122126 if (plugin["before:highlightBlock"] && !plugin["before:highlightElement"]) {2127 plugin["before:highlightElement"] = (data) => {2128 plugin["before:highlightBlock"](2129 Object.assign({ block: data.el }, data)2130 );2131 };2132 }2133 if (plugin["after:highlightBlock"] && !plugin["after:highlightElement"]) {2134 plugin["after:highlightElement"] = (data) => {2135 plugin["after:highlightBlock"](2136 Object.assign({ block: data.el }, data)2137 );2138 };2139 }2140 }2141 /**2142 * @param {HLJSPlugin} plugin2143 */2144 function addPlugin(plugin) {2145 upgradePluginAPI(plugin);2146 plugins.push(plugin);2147 }2148 /**2149 *2150 * @param {PluginEvent} event2151 * @param {any} args2152 */2153 function fire(event, args) {2154 const cb = event;2155 plugins.forEach(function(plugin) {2156 if (plugin[cb]) {2157 plugin[cb](args);2158 }2159 });2160 }2161 /**2162 *2163 * @param {HighlightedHTMLElement} el2164 */2165 function deprecateHighlightBlock(el) {2166 deprecated("10.7.0", "highlightBlock will be removed entirely in v12.0");2167 deprecated("10.7.0", "Please use highlightElement now.");2168 return highlightElement(el);2169 }2170 /* Interface definition */2171 Object.assign(hljs, {2172 highlight,2173 highlightAuto,2174 highlightAll,2175 highlightElement,2176 // TODO: Remove with v12 API2177 highlightBlock: deprecateHighlightBlock,2178 configure,2179 initHighlighting,2180 initHighlightingOnLoad,2181 registerLanguage,2182 unregisterLanguage,2183 listLanguages,2184 getLanguage,2185 registerAliases,2186 autoDetection,2187 inherit,2188 addPlugin2189 });2190 hljs.debugMode = function() { SAFE_MODE = false; };2191 hljs.safeMode = function() { SAFE_MODE = true; };2192 hljs.versionString = version;2193 for (const key in MODES) {2194 // @ts-ignore2195 if (typeof MODES[key] === "object") {2196 // @ts-ignore2197 deepFreeze$1(MODES[key]);2198 }2199 }2200 // merge all the modes/regexes into our main object2201 Object.assign(hljs, MODES);2202 return hljs;2203 };2204 // export an "instance" of the highlighter2205 var HighlightJS = HLJS({});2206 var builtIns = /*#__PURE__*/Object.freeze({2207 __proto__: null2208 });2209 const hljs = HighlightJS;2210 for (const key of Object.keys(builtIns)) {2211 const languageName = key.replace("grmr_", "");2212 hljs.registerLanguage(languageName, builtIns[key]);2213 }2214 return hljs;2215}());...

Full Screen

Full Screen

highlight.js_v11.3.1-0C5csJSkMVgQyOMzmIlU_dist_es2020_mode_imports_optimized_common_core-da5e7eef_1b12fcb113193245855a.js

Source:highlight.js_v11.3.1-0C5csJSkMVgQyOMzmIlU_dist_es2020_mode_imports_optimized_common_core-da5e7eef_1b12fcb113193245855a.js Github

copy

Full Screen

1var deepFreezeEs6 = {exports: {}};2function deepFreeze(obj) {3 if (obj instanceof Map) {4 obj.clear = obj.delete = obj.set = function() {5 throw new Error("map is read-only");6 };7 } else if (obj instanceof Set) {8 obj.add = obj.clear = obj.delete = function() {9 throw new Error("set is read-only");10 };11 }12 Object.freeze(obj);13 Object.getOwnPropertyNames(obj).forEach(function(name) {14 var prop = obj[name];15 if (typeof prop == "object" && !Object.isFrozen(prop)) {16 deepFreeze(prop);17 }18 });19 return obj;20}21deepFreezeEs6.exports = deepFreeze;22deepFreezeEs6.exports.default = deepFreeze;23var deepFreeze$1 = deepFreezeEs6.exports;24class Response {25 constructor(mode) {26 if (mode.data === void 0)27 mode.data = {};28 this.data = mode.data;29 this.isMatchIgnored = false;30 }31 ignoreMatch() {32 this.isMatchIgnored = true;33 }34}35function escapeHTML(value) {36 return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#x27;");37}38function inherit$1(original, ...objects) {39 const result = Object.create(null);40 for (const key in original) {41 result[key] = original[key];42 }43 objects.forEach(function(obj) {44 for (const key in obj) {45 result[key] = obj[key];46 }47 });48 return result;49}50const SPAN_CLOSE = "</span>";51const emitsWrappingTags = (node) => {52 return !!node.kind;53};54const expandScopeName = (name, {prefix}) => {55 if (name.includes(".")) {56 const pieces = name.split(".");57 return [58 `${prefix}${pieces.shift()}`,59 ...pieces.map((x, i) => `${x}${"_".repeat(i + 1)}`)60 ].join(" ");61 }62 return `${prefix}${name}`;63};64class HTMLRenderer {65 constructor(parseTree, options) {66 this.buffer = "";67 this.classPrefix = options.classPrefix;68 parseTree.walk(this);69 }70 addText(text) {71 this.buffer += escapeHTML(text);72 }73 openNode(node) {74 if (!emitsWrappingTags(node))75 return;76 let scope = node.kind;77 if (node.sublanguage) {78 scope = `language-${scope}`;79 } else {80 scope = expandScopeName(scope, {prefix: this.classPrefix});81 }82 this.span(scope);83 }84 closeNode(node) {85 if (!emitsWrappingTags(node))86 return;87 this.buffer += SPAN_CLOSE;88 }89 value() {90 return this.buffer;91 }92 span(className) {93 this.buffer += `<span class="${className}">`;94 }95}96class TokenTree {97 constructor() {98 this.rootNode = {children: []};99 this.stack = [this.rootNode];100 }101 get top() {102 return this.stack[this.stack.length - 1];103 }104 get root() {105 return this.rootNode;106 }107 add(node) {108 this.top.children.push(node);109 }110 openNode(kind) {111 const node = {kind, children: []};112 this.add(node);113 this.stack.push(node);114 }115 closeNode() {116 if (this.stack.length > 1) {117 return this.stack.pop();118 }119 return void 0;120 }121 closeAllNodes() {122 while (this.closeNode())123 ;124 }125 toJSON() {126 return JSON.stringify(this.rootNode, null, 4);127 }128 walk(builder) {129 return this.constructor._walk(builder, this.rootNode);130 }131 static _walk(builder, node) {132 if (typeof node === "string") {133 builder.addText(node);134 } else if (node.children) {135 builder.openNode(node);136 node.children.forEach((child) => this._walk(builder, child));137 builder.closeNode(node);138 }139 return builder;140 }141 static _collapse(node) {142 if (typeof node === "string")143 return;144 if (!node.children)145 return;146 if (node.children.every((el) => typeof el === "string")) {147 node.children = [node.children.join("")];148 } else {149 node.children.forEach((child) => {150 TokenTree._collapse(child);151 });152 }153 }154}155class TokenTreeEmitter extends TokenTree {156 constructor(options) {157 super();158 this.options = options;159 }160 addKeyword(text, kind) {161 if (text === "") {162 return;163 }164 this.openNode(kind);165 this.addText(text);166 this.closeNode();167 }168 addText(text) {169 if (text === "") {170 return;171 }172 this.add(text);173 }174 addSublanguage(emitter, name) {175 const node = emitter.root;176 node.kind = name;177 node.sublanguage = true;178 this.add(node);179 }180 toHTML() {181 const renderer = new HTMLRenderer(this, this.options);182 return renderer.value();183 }184 finalize() {185 return true;186 }187}188function source(re) {189 if (!re)190 return null;191 if (typeof re === "string")192 return re;193 return re.source;194}195function lookahead(re) {196 return concat("(?=", re, ")");197}198function anyNumberOfTimes(re) {199 return concat("(?:", re, ")*");200}201function optional(re) {202 return concat("(?:", re, ")?");203}204function concat(...args) {205 const joined = args.map((x) => source(x)).join("");206 return joined;207}208function stripOptionsFromArgs(args) {209 const opts = args[args.length - 1];210 if (typeof opts === "object" && opts.constructor === Object) {211 args.splice(args.length - 1, 1);212 return opts;213 } else {214 return {};215 }216}217function either(...args) {218 const opts = stripOptionsFromArgs(args);219 const joined = "(" + (opts.capture ? "" : "?:") + args.map((x) => source(x)).join("|") + ")";220 return joined;221}222function countMatchGroups(re) {223 return new RegExp(re.toString() + "|").exec("").length - 1;224}225function startsWith(re, lexeme) {226 const match = re && re.exec(lexeme);227 return match && match.index === 0;228}229const BACKREF_RE = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;230function _rewriteBackreferences(regexps, {joinWith}) {231 let numCaptures = 0;232 return regexps.map((regex) => {233 numCaptures += 1;234 const offset = numCaptures;235 let re = source(regex);236 let out = "";237 while (re.length > 0) {238 const match = BACKREF_RE.exec(re);239 if (!match) {240 out += re;241 break;242 }243 out += re.substring(0, match.index);244 re = re.substring(match.index + match[0].length);245 if (match[0][0] === "\\" && match[1]) {246 out += "\\" + String(Number(match[1]) + offset);247 } else {248 out += match[0];249 if (match[0] === "(") {250 numCaptures++;251 }252 }253 }254 return out;255 }).map((re) => `(${re})`).join(joinWith);256}257const MATCH_NOTHING_RE = /\b\B/;258const IDENT_RE = "[a-zA-Z]\\w*";259const UNDERSCORE_IDENT_RE = "[a-zA-Z_]\\w*";260const NUMBER_RE = "\\b\\d+(\\.\\d+)?";261const C_NUMBER_RE = "(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";262const BINARY_NUMBER_RE = "\\b(0b[01]+)";263const RE_STARTERS_RE = "!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";264const SHEBANG = (opts = {}) => {265 const beginShebang = /^#![ ]*\//;266 if (opts.binary) {267 opts.begin = concat(beginShebang, /.*\b/, opts.binary, /\b.*/);268 }269 return inherit$1({270 scope: "meta",271 begin: beginShebang,272 end: /$/,273 relevance: 0,274 "on:begin": (m, resp) => {275 if (m.index !== 0)276 resp.ignoreMatch();277 }278 }, opts);279};280const BACKSLASH_ESCAPE = {281 begin: "\\\\[\\s\\S]",282 relevance: 0283};284const APOS_STRING_MODE = {285 scope: "string",286 begin: "'",287 end: "'",288 illegal: "\\n",289 contains: [BACKSLASH_ESCAPE]290};291const QUOTE_STRING_MODE = {292 scope: "string",293 begin: '"',294 end: '"',295 illegal: "\\n",296 contains: [BACKSLASH_ESCAPE]297};298const PHRASAL_WORDS_MODE = {299 begin: /\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/300};301const COMMENT = function(begin, end, modeOptions = {}) {302 const mode = inherit$1({303 scope: "comment",304 begin,305 end,306 contains: []307 }, modeOptions);308 mode.contains.push({309 scope: "doctag",310 begin: "[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)",311 end: /(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,312 excludeBegin: true,313 relevance: 0314 });315 const ENGLISH_WORD = either("I", "a", "is", "so", "us", "to", "at", "if", "in", "it", "on", /[A-Za-z]+['](d|ve|re|ll|t|s|n)/, /[A-Za-z]+[-][a-z]+/, /[A-Za-z][a-z]{2,}/);316 mode.contains.push({317 begin: concat(/[ ]+/, "(", ENGLISH_WORD, /[.]?[:]?([.][ ]|[ ])/, "){3}")318 });319 return mode;320};321const C_LINE_COMMENT_MODE = COMMENT("//", "$");322const C_BLOCK_COMMENT_MODE = COMMENT("/\\*", "\\*/");323const HASH_COMMENT_MODE = COMMENT("#", "$");324const NUMBER_MODE = {325 scope: "number",326 begin: NUMBER_RE,327 relevance: 0328};329const C_NUMBER_MODE = {330 scope: "number",331 begin: C_NUMBER_RE,332 relevance: 0333};334const BINARY_NUMBER_MODE = {335 scope: "number",336 begin: BINARY_NUMBER_RE,337 relevance: 0338};339const REGEXP_MODE = {340 begin: /(?=\/[^/\n]*\/)/,341 contains: [{342 scope: "regexp",343 begin: /\//,344 end: /\/[gimuy]*/,345 illegal: /\n/,346 contains: [347 BACKSLASH_ESCAPE,348 {349 begin: /\[/,350 end: /\]/,351 relevance: 0,352 contains: [BACKSLASH_ESCAPE]353 }354 ]355 }]356};357const TITLE_MODE = {358 scope: "title",359 begin: IDENT_RE,360 relevance: 0361};362const UNDERSCORE_TITLE_MODE = {363 scope: "title",364 begin: UNDERSCORE_IDENT_RE,365 relevance: 0366};367const METHOD_GUARD = {368 begin: "\\.\\s*" + UNDERSCORE_IDENT_RE,369 relevance: 0370};371const END_SAME_AS_BEGIN = function(mode) {372 return Object.assign(mode, {373 "on:begin": (m, resp) => {374 resp.data._beginMatch = m[1];375 },376 "on:end": (m, resp) => {377 if (resp.data._beginMatch !== m[1])378 resp.ignoreMatch();379 }380 });381};382var MODES = /* @__PURE__ */ Object.freeze({383 __proto__: null,384 MATCH_NOTHING_RE,385 IDENT_RE,386 UNDERSCORE_IDENT_RE,387 NUMBER_RE,388 C_NUMBER_RE,389 BINARY_NUMBER_RE,390 RE_STARTERS_RE,391 SHEBANG,392 BACKSLASH_ESCAPE,393 APOS_STRING_MODE,394 QUOTE_STRING_MODE,395 PHRASAL_WORDS_MODE,396 COMMENT,397 C_LINE_COMMENT_MODE,398 C_BLOCK_COMMENT_MODE,399 HASH_COMMENT_MODE,400 NUMBER_MODE,401 C_NUMBER_MODE,402 BINARY_NUMBER_MODE,403 REGEXP_MODE,404 TITLE_MODE,405 UNDERSCORE_TITLE_MODE,406 METHOD_GUARD,407 END_SAME_AS_BEGIN408});409function skipIfHasPrecedingDot(match, response) {410 const before = match.input[match.index - 1];411 if (before === ".") {412 response.ignoreMatch();413 }414}415function scopeClassName(mode, _parent) {416 if (mode.className !== void 0) {417 mode.scope = mode.className;418 delete mode.className;419 }420}421function beginKeywords(mode, parent) {422 if (!parent)423 return;424 if (!mode.beginKeywords)425 return;426 mode.begin = "\\b(" + mode.beginKeywords.split(" ").join("|") + ")(?!\\.)(?=\\b|\\s)";427 mode.__beforeBegin = skipIfHasPrecedingDot;428 mode.keywords = mode.keywords || mode.beginKeywords;429 delete mode.beginKeywords;430 if (mode.relevance === void 0)431 mode.relevance = 0;432}433function compileIllegal(mode, _parent) {434 if (!Array.isArray(mode.illegal))435 return;436 mode.illegal = either(...mode.illegal);437}438function compileMatch(mode, _parent) {439 if (!mode.match)440 return;441 if (mode.begin || mode.end)442 throw new Error("begin & end are not supported with match");443 mode.begin = mode.match;444 delete mode.match;445}446function compileRelevance(mode, _parent) {447 if (mode.relevance === void 0)448 mode.relevance = 1;449}450const beforeMatchExt = (mode, parent) => {451 if (!mode.beforeMatch)452 return;453 if (mode.starts)454 throw new Error("beforeMatch cannot be used with starts");455 const originalMode = Object.assign({}, mode);456 Object.keys(mode).forEach((key) => {457 delete mode[key];458 });459 mode.keywords = originalMode.keywords;460 mode.begin = concat(originalMode.beforeMatch, lookahead(originalMode.begin));461 mode.starts = {462 relevance: 0,463 contains: [464 Object.assign(originalMode, {endsParent: true})465 ]466 };467 mode.relevance = 0;468 delete originalMode.beforeMatch;469};470const COMMON_KEYWORDS = [471 "of",472 "and",473 "for",474 "in",475 "not",476 "or",477 "if",478 "then",479 "parent",480 "list",481 "value"482];483const DEFAULT_KEYWORD_SCOPE = "keyword";484function compileKeywords(rawKeywords, caseInsensitive, scopeName = DEFAULT_KEYWORD_SCOPE) {485 const compiledKeywords = Object.create(null);486 if (typeof rawKeywords === "string") {487 compileList(scopeName, rawKeywords.split(" "));488 } else if (Array.isArray(rawKeywords)) {489 compileList(scopeName, rawKeywords);490 } else {491 Object.keys(rawKeywords).forEach(function(scopeName2) {492 Object.assign(compiledKeywords, compileKeywords(rawKeywords[scopeName2], caseInsensitive, scopeName2));493 });494 }495 return compiledKeywords;496 function compileList(scopeName2, keywordList) {497 if (caseInsensitive) {498 keywordList = keywordList.map((x) => x.toLowerCase());499 }500 keywordList.forEach(function(keyword) {501 const pair = keyword.split("|");502 compiledKeywords[pair[0]] = [scopeName2, scoreForKeyword(pair[0], pair[1])];503 });504 }505}506function scoreForKeyword(keyword, providedScore) {507 if (providedScore) {508 return Number(providedScore);509 }510 return commonKeyword(keyword) ? 0 : 1;511}512function commonKeyword(keyword) {513 return COMMON_KEYWORDS.includes(keyword.toLowerCase());514}515const seenDeprecations = {};516const error = (message) => {517 console.error(message);518};519const warn = (message, ...args) => {520 console.log(`WARN: ${message}`, ...args);521};522const deprecated = (version2, message) => {523 if (seenDeprecations[`${version2}/${message}`])524 return;525 console.log(`Deprecated as of ${version2}. ${message}`);526 seenDeprecations[`${version2}/${message}`] = true;527};528const MultiClassError = new Error();529function remapScopeNames(mode, regexes, {key}) {530 let offset = 0;531 const scopeNames = mode[key];532 const emit = {};533 const positions = {};534 for (let i = 1; i <= regexes.length; i++) {535 positions[i + offset] = scopeNames[i];536 emit[i + offset] = true;537 offset += countMatchGroups(regexes[i - 1]);538 }539 mode[key] = positions;540 mode[key]._emit = emit;541 mode[key]._multi = true;542}543function beginMultiClass(mode) {544 if (!Array.isArray(mode.begin))545 return;546 if (mode.skip || mode.excludeBegin || mode.returnBegin) {547 error("skip, excludeBegin, returnBegin not compatible with beginScope: {}");548 throw MultiClassError;549 }550 if (typeof mode.beginScope !== "object" || mode.beginScope === null) {551 error("beginScope must be object");552 throw MultiClassError;553 }554 remapScopeNames(mode, mode.begin, {key: "beginScope"});555 mode.begin = _rewriteBackreferences(mode.begin, {joinWith: ""});556}557function endMultiClass(mode) {558 if (!Array.isArray(mode.end))559 return;560 if (mode.skip || mode.excludeEnd || mode.returnEnd) {561 error("skip, excludeEnd, returnEnd not compatible with endScope: {}");562 throw MultiClassError;563 }564 if (typeof mode.endScope !== "object" || mode.endScope === null) {565 error("endScope must be object");566 throw MultiClassError;567 }568 remapScopeNames(mode, mode.end, {key: "endScope"});569 mode.end = _rewriteBackreferences(mode.end, {joinWith: ""});570}571function scopeSugar(mode) {572 if (mode.scope && typeof mode.scope === "object" && mode.scope !== null) {573 mode.beginScope = mode.scope;574 delete mode.scope;575 }576}577function MultiClass(mode) {578 scopeSugar(mode);579 if (typeof mode.beginScope === "string") {580 mode.beginScope = {_wrap: mode.beginScope};581 }582 if (typeof mode.endScope === "string") {583 mode.endScope = {_wrap: mode.endScope};584 }585 beginMultiClass(mode);586 endMultiClass(mode);587}588function compileLanguage(language) {589 function langRe(value, global) {590 return new RegExp(source(value), "m" + (language.case_insensitive ? "i" : "") + (language.unicodeRegex ? "u" : "") + (global ? "g" : ""));591 }592 class MultiRegex {593 constructor() {594 this.matchIndexes = {};595 this.regexes = [];596 this.matchAt = 1;597 this.position = 0;598 }599 addRule(re, opts) {600 opts.position = this.position++;601 this.matchIndexes[this.matchAt] = opts;602 this.regexes.push([opts, re]);603 this.matchAt += countMatchGroups(re) + 1;604 }605 compile() {606 if (this.regexes.length === 0) {607 this.exec = () => null;608 }609 const terminators = this.regexes.map((el) => el[1]);610 this.matcherRe = langRe(_rewriteBackreferences(terminators, {joinWith: "|"}), true);611 this.lastIndex = 0;612 }613 exec(s) {614 this.matcherRe.lastIndex = this.lastIndex;615 const match = this.matcherRe.exec(s);616 if (!match) {617 return null;618 }619 const i = match.findIndex((el, i2) => i2 > 0 && el !== void 0);620 const matchData = this.matchIndexes[i];621 match.splice(0, i);622 return Object.assign(match, matchData);623 }624 }625 class ResumableMultiRegex {626 constructor() {627 this.rules = [];628 this.multiRegexes = [];629 this.count = 0;630 this.lastIndex = 0;631 this.regexIndex = 0;632 }633 getMatcher(index) {634 if (this.multiRegexes[index])635 return this.multiRegexes[index];636 const matcher = new MultiRegex();637 this.rules.slice(index).forEach(([re, opts]) => matcher.addRule(re, opts));638 matcher.compile();639 this.multiRegexes[index] = matcher;640 return matcher;641 }642 resumingScanAtSamePosition() {643 return this.regexIndex !== 0;644 }645 considerAll() {646 this.regexIndex = 0;647 }648 addRule(re, opts) {649 this.rules.push([re, opts]);650 if (opts.type === "begin")651 this.count++;652 }653 exec(s) {654 const m = this.getMatcher(this.regexIndex);655 m.lastIndex = this.lastIndex;656 let result = m.exec(s);657 if (this.resumingScanAtSamePosition()) {658 if (result && result.index === this.lastIndex)659 ;660 else {661 const m2 = this.getMatcher(0);662 m2.lastIndex = this.lastIndex + 1;663 result = m2.exec(s);664 }665 }666 if (result) {667 this.regexIndex += result.position + 1;668 if (this.regexIndex === this.count) {669 this.considerAll();670 }671 }672 return result;673 }674 }675 function buildModeRegex(mode) {676 const mm = new ResumableMultiRegex();677 mode.contains.forEach((term) => mm.addRule(term.begin, {rule: term, type: "begin"}));678 if (mode.terminatorEnd) {679 mm.addRule(mode.terminatorEnd, {type: "end"});680 }681 if (mode.illegal) {682 mm.addRule(mode.illegal, {type: "illegal"});683 }684 return mm;685 }686 function compileMode(mode, parent) {687 const cmode = mode;688 if (mode.isCompiled)689 return cmode;690 [691 scopeClassName,692 compileMatch,693 MultiClass,694 beforeMatchExt695 ].forEach((ext) => ext(mode, parent));696 language.compilerExtensions.forEach((ext) => ext(mode, parent));697 mode.__beforeBegin = null;698 [699 beginKeywords,700 compileIllegal,701 compileRelevance702 ].forEach((ext) => ext(mode, parent));703 mode.isCompiled = true;704 let keywordPattern = null;705 if (typeof mode.keywords === "object" && mode.keywords.$pattern) {706 mode.keywords = Object.assign({}, mode.keywords);707 keywordPattern = mode.keywords.$pattern;708 delete mode.keywords.$pattern;709 }710 keywordPattern = keywordPattern || /\w+/;711 if (mode.keywords) {712 mode.keywords = compileKeywords(mode.keywords, language.case_insensitive);713 }714 cmode.keywordPatternRe = langRe(keywordPattern, true);715 if (parent) {716 if (!mode.begin)717 mode.begin = /\B|\b/;718 cmode.beginRe = langRe(cmode.begin);719 if (!mode.end && !mode.endsWithParent)720 mode.end = /\B|\b/;721 if (mode.end)722 cmode.endRe = langRe(cmode.end);723 cmode.terminatorEnd = source(cmode.end) || "";724 if (mode.endsWithParent && parent.terminatorEnd) {725 cmode.terminatorEnd += (mode.end ? "|" : "") + parent.terminatorEnd;726 }727 }728 if (mode.illegal)729 cmode.illegalRe = langRe(mode.illegal);730 if (!mode.contains)731 mode.contains = [];732 mode.contains = [].concat(...mode.contains.map(function(c) {733 return expandOrCloneMode(c === "self" ? mode : c);734 }));735 mode.contains.forEach(function(c) {736 compileMode(c, cmode);737 });738 if (mode.starts) {739 compileMode(mode.starts, parent);740 }741 cmode.matcher = buildModeRegex(cmode);742 return cmode;743 }744 if (!language.compilerExtensions)745 language.compilerExtensions = [];746 if (language.contains && language.contains.includes("self")) {747 throw new Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");748 }749 language.classNameAliases = inherit$1(language.classNameAliases || {});750 return compileMode(language);751}752function dependencyOnParent(mode) {753 if (!mode)754 return false;755 return mode.endsWithParent || dependencyOnParent(mode.starts);756}757function expandOrCloneMode(mode) {758 if (mode.variants && !mode.cachedVariants) {759 mode.cachedVariants = mode.variants.map(function(variant) {760 return inherit$1(mode, {variants: null}, variant);761 });762 }763 if (mode.cachedVariants) {764 return mode.cachedVariants;765 }766 if (dependencyOnParent(mode)) {767 return inherit$1(mode, {starts: mode.starts ? inherit$1(mode.starts) : null});768 }769 if (Object.isFrozen(mode)) {770 return inherit$1(mode);771 }772 return mode;773}774var version = "11.3.1";775class HTMLInjectionError extends Error {776 constructor(reason, html) {777 super(reason);778 this.name = "HTMLInjectionError";779 this.html = html;780 }781}782const escape = escapeHTML;783const inherit = inherit$1;784const NO_MATCH = Symbol("nomatch");785const MAX_KEYWORD_HITS = 7;786const HLJS = function(hljs) {787 const languages = Object.create(null);788 const aliases = Object.create(null);789 const plugins = [];790 let SAFE_MODE = true;791 const LANGUAGE_NOT_FOUND = "Could not find the language '{}', did you forget to load/include a language module?";792 const PLAINTEXT_LANGUAGE = {disableAutodetect: true, name: "Plain text", contains: []};793 let options = {794 ignoreUnescapedHTML: false,795 throwUnescapedHTML: false,796 noHighlightRe: /^(no-?highlight)$/i,797 languageDetectRe: /\blang(?:uage)?-([\w-]+)\b/i,798 classPrefix: "hljs-",799 cssSelector: "pre code",800 languages: null,801 __emitter: TokenTreeEmitter802 };803 function shouldNotHighlight(languageName) {804 return options.noHighlightRe.test(languageName);805 }806 function blockLanguage(block) {807 let classes = block.className + " ";808 classes += block.parentNode ? block.parentNode.className : "";809 const match = options.languageDetectRe.exec(classes);810 if (match) {811 const language = getLanguage(match[1]);812 if (!language) {813 warn(LANGUAGE_NOT_FOUND.replace("{}", match[1]));814 warn("Falling back to no-highlight mode for this block.", block);815 }816 return language ? match[1] : "no-highlight";817 }818 return classes.split(/\s+/).find((_class) => shouldNotHighlight(_class) || getLanguage(_class));819 }820 function highlight2(codeOrLanguageName, optionsOrCode, ignoreIllegals) {821 let code = "";822 let languageName = "";823 if (typeof optionsOrCode === "object") {824 code = codeOrLanguageName;825 ignoreIllegals = optionsOrCode.ignoreIllegals;826 languageName = optionsOrCode.language;827 } else {828 deprecated("10.7.0", "highlight(lang, code, ...args) has been deprecated.");829 deprecated("10.7.0", "Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277");830 languageName = codeOrLanguageName;831 code = optionsOrCode;832 }833 if (ignoreIllegals === void 0) {834 ignoreIllegals = true;835 }836 const context = {837 code,838 language: languageName839 };840 fire("before:highlight", context);841 const result = context.result ? context.result : _highlight(context.language, context.code, ignoreIllegals);842 result.code = context.code;843 fire("after:highlight", result);844 return result;845 }846 function _highlight(languageName, codeToHighlight, ignoreIllegals, continuation) {847 const keywordHits = Object.create(null);848 function keywordData(mode, matchText) {849 return mode.keywords[matchText];850 }851 function processKeywords() {852 if (!top.keywords) {853 emitter.addText(modeBuffer);854 return;855 }856 let lastIndex = 0;857 top.keywordPatternRe.lastIndex = 0;858 let match = top.keywordPatternRe.exec(modeBuffer);859 let buf = "";860 while (match) {861 buf += modeBuffer.substring(lastIndex, match.index);862 const word = language.case_insensitive ? match[0].toLowerCase() : match[0];863 const data = keywordData(top, word);864 if (data) {865 const [kind, keywordRelevance] = data;866 emitter.addText(buf);867 buf = "";868 keywordHits[word] = (keywordHits[word] || 0) + 1;869 if (keywordHits[word] <= MAX_KEYWORD_HITS)870 relevance += keywordRelevance;871 if (kind.startsWith("_")) {872 buf += match[0];873 } else {874 const cssClass = language.classNameAliases[kind] || kind;875 emitter.addKeyword(match[0], cssClass);876 }877 } else {878 buf += match[0];879 }880 lastIndex = top.keywordPatternRe.lastIndex;881 match = top.keywordPatternRe.exec(modeBuffer);882 }883 buf += modeBuffer.substr(lastIndex);884 emitter.addText(buf);885 }886 function processSubLanguage() {887 if (modeBuffer === "")888 return;889 let result2 = null;890 if (typeof top.subLanguage === "string") {891 if (!languages[top.subLanguage]) {892 emitter.addText(modeBuffer);893 return;894 }895 result2 = _highlight(top.subLanguage, modeBuffer, true, continuations[top.subLanguage]);896 continuations[top.subLanguage] = result2._top;897 } else {898 result2 = highlightAuto(modeBuffer, top.subLanguage.length ? top.subLanguage : null);899 }900 if (top.relevance > 0) {901 relevance += result2.relevance;902 }903 emitter.addSublanguage(result2._emitter, result2.language);904 }905 function processBuffer() {906 if (top.subLanguage != null) {907 processSubLanguage();908 } else {909 processKeywords();910 }911 modeBuffer = "";912 }913 function emitMultiClass(scope, match) {914 let i = 1;915 while (match[i] !== void 0) {916 if (!scope._emit[i]) {917 i++;918 continue;919 }920 const klass = language.classNameAliases[scope[i]] || scope[i];921 const text = match[i];922 if (klass) {923 emitter.addKeyword(text, klass);924 } else {925 modeBuffer = text;926 processKeywords();927 modeBuffer = "";928 }929 i++;930 }931 }932 function startNewMode(mode, match) {933 if (mode.scope && typeof mode.scope === "string") {934 emitter.openNode(language.classNameAliases[mode.scope] || mode.scope);935 }936 if (mode.beginScope) {937 if (mode.beginScope._wrap) {938 emitter.addKeyword(modeBuffer, language.classNameAliases[mode.beginScope._wrap] || mode.beginScope._wrap);939 modeBuffer = "";940 } else if (mode.beginScope._multi) {941 emitMultiClass(mode.beginScope, match);942 modeBuffer = "";943 }944 }945 top = Object.create(mode, {parent: {value: top}});946 return top;947 }948 function endOfMode(mode, match, matchPlusRemainder) {949 let matched = startsWith(mode.endRe, matchPlusRemainder);950 if (matched) {951 if (mode["on:end"]) {952 const resp = new Response(mode);953 mode["on:end"](match, resp);954 if (resp.isMatchIgnored)955 matched = false;956 }957 if (matched) {958 while (mode.endsParent && mode.parent) {959 mode = mode.parent;960 }961 return mode;962 }963 }964 if (mode.endsWithParent) {965 return endOfMode(mode.parent, match, matchPlusRemainder);966 }967 }968 function doIgnore(lexeme) {969 if (top.matcher.regexIndex === 0) {970 modeBuffer += lexeme[0];971 return 1;972 } else {973 resumeScanAtSamePosition = true;974 return 0;975 }976 }977 function doBeginMatch(match) {978 const lexeme = match[0];979 const newMode = match.rule;980 const resp = new Response(newMode);981 const beforeCallbacks = [newMode.__beforeBegin, newMode["on:begin"]];982 for (const cb of beforeCallbacks) {983 if (!cb)984 continue;985 cb(match, resp);986 if (resp.isMatchIgnored)987 return doIgnore(lexeme);988 }989 if (newMode.skip) {990 modeBuffer += lexeme;991 } else {992 if (newMode.excludeBegin) {993 modeBuffer += lexeme;994 }995 processBuffer();996 if (!newMode.returnBegin && !newMode.excludeBegin) {997 modeBuffer = lexeme;998 }999 }1000 startNewMode(newMode, match);1001 return newMode.returnBegin ? 0 : lexeme.length;1002 }1003 function doEndMatch(match) {1004 const lexeme = match[0];1005 const matchPlusRemainder = codeToHighlight.substr(match.index);1006 const endMode = endOfMode(top, match, matchPlusRemainder);1007 if (!endMode) {1008 return NO_MATCH;1009 }1010 const origin = top;1011 if (top.endScope && top.endScope._wrap) {1012 processBuffer();1013 emitter.addKeyword(lexeme, top.endScope._wrap);1014 } else if (top.endScope && top.endScope._multi) {1015 processBuffer();1016 emitMultiClass(top.endScope, match);1017 } else if (origin.skip) {1018 modeBuffer += lexeme;1019 } else {1020 if (!(origin.returnEnd || origin.excludeEnd)) {1021 modeBuffer += lexeme;1022 }1023 processBuffer();1024 if (origin.excludeEnd) {1025 modeBuffer = lexeme;1026 }1027 }1028 do {1029 if (top.scope) {1030 emitter.closeNode();1031 }1032 if (!top.skip && !top.subLanguage) {1033 relevance += top.relevance;1034 }1035 top = top.parent;1036 } while (top !== endMode.parent);1037 if (endMode.starts) {1038 startNewMode(endMode.starts, match);1039 }1040 return origin.returnEnd ? 0 : lexeme.length;1041 }1042 function processContinuations() {1043 const list = [];1044 for (let current = top; current !== language; current = current.parent) {1045 if (current.scope) {1046 list.unshift(current.scope);1047 }1048 }1049 list.forEach((item) => emitter.openNode(item));1050 }1051 let lastMatch = {};1052 function processLexeme(textBeforeMatch, match) {1053 const lexeme = match && match[0];1054 modeBuffer += textBeforeMatch;1055 if (lexeme == null) {1056 processBuffer();1057 return 0;1058 }1059 if (lastMatch.type === "begin" && match.type === "end" && lastMatch.index === match.index && lexeme === "") {1060 modeBuffer += codeToHighlight.slice(match.index, match.index + 1);1061 if (!SAFE_MODE) {1062 const err = new Error(`0 width match regex (${languageName})`);1063 err.languageName = languageName;1064 err.badRule = lastMatch.rule;1065 throw err;1066 }1067 return 1;1068 }1069 lastMatch = match;1070 if (match.type === "begin") {1071 return doBeginMatch(match);1072 } else if (match.type === "illegal" && !ignoreIllegals) {1073 const err = new Error('Illegal lexeme "' + lexeme + '" for mode "' + (top.scope || "<unnamed>") + '"');1074 err.mode = top;1075 throw err;1076 } else if (match.type === "end") {1077 const processed = doEndMatch(match);1078 if (processed !== NO_MATCH) {1079 return processed;1080 }1081 }1082 if (match.type === "illegal" && lexeme === "") {1083 return 1;1084 }1085 if (iterations > 1e5 && iterations > match.index * 3) {1086 const err = new Error("potential infinite loop, way more iterations than matches");1087 throw err;1088 }1089 modeBuffer += lexeme;1090 return lexeme.length;1091 }1092 const language = getLanguage(languageName);1093 if (!language) {1094 error(LANGUAGE_NOT_FOUND.replace("{}", languageName));1095 throw new Error('Unknown language: "' + languageName + '"');1096 }1097 const md = compileLanguage(language);1098 let result = "";1099 let top = continuation || md;1100 const continuations = {};1101 const emitter = new options.__emitter(options);1102 processContinuations();1103 let modeBuffer = "";1104 let relevance = 0;1105 let index = 0;1106 let iterations = 0;1107 let resumeScanAtSamePosition = false;1108 try {1109 top.matcher.considerAll();1110 for (; ; ) {1111 iterations++;1112 if (resumeScanAtSamePosition) {1113 resumeScanAtSamePosition = false;1114 } else {1115 top.matcher.considerAll();1116 }1117 top.matcher.lastIndex = index;1118 const match = top.matcher.exec(codeToHighlight);1119 if (!match)1120 break;1121 const beforeMatch = codeToHighlight.substring(index, match.index);1122 const processedCount = processLexeme(beforeMatch, match);1123 index = match.index + processedCount;1124 }1125 processLexeme(codeToHighlight.substr(index));1126 emitter.closeAllNodes();1127 emitter.finalize();1128 result = emitter.toHTML();1129 return {1130 language: languageName,1131 value: result,1132 relevance,1133 illegal: false,1134 _emitter: emitter,1135 _top: top1136 };1137 } catch (err) {1138 if (err.message && err.message.includes("Illegal")) {1139 return {1140 language: languageName,1141 value: escape(codeToHighlight),1142 illegal: true,1143 relevance: 0,1144 _illegalBy: {1145 message: err.message,1146 index,1147 context: codeToHighlight.slice(index - 100, index + 100),1148 mode: err.mode,1149 resultSoFar: result1150 },1151 _emitter: emitter1152 };1153 } else if (SAFE_MODE) {1154 return {1155 language: languageName,1156 value: escape(codeToHighlight),1157 illegal: false,1158 relevance: 0,1159 errorRaised: err,1160 _emitter: emitter,1161 _top: top1162 };1163 } else {1164 throw err;1165 }1166 }1167 }1168 function justTextHighlightResult(code) {1169 const result = {1170 value: escape(code),1171 illegal: false,1172 relevance: 0,1173 _top: PLAINTEXT_LANGUAGE,1174 _emitter: new options.__emitter(options)1175 };1176 result._emitter.addText(code);1177 return result;1178 }1179 function highlightAuto(code, languageSubset) {1180 languageSubset = languageSubset || options.languages || Object.keys(languages);1181 const plaintext = justTextHighlightResult(code);1182 const results = languageSubset.filter(getLanguage).filter(autoDetection).map((name) => _highlight(name, code, false));1183 results.unshift(plaintext);1184 const sorted = results.sort((a, b) => {1185 if (a.relevance !== b.relevance)1186 return b.relevance - a.relevance;1187 if (a.language && b.language) {1188 if (getLanguage(a.language).supersetOf === b.language) {1189 return 1;1190 } else if (getLanguage(b.language).supersetOf === a.language) {1191 return -1;1192 }1193 }1194 return 0;1195 });1196 const [best, secondBest] = sorted;1197 const result = best;1198 result.secondBest = secondBest;1199 return result;1200 }1201 function updateClassName(element, currentLang, resultLang) {1202 const language = currentLang && aliases[currentLang] || resultLang;1203 element.classList.add("hljs");1204 element.classList.add(`language-${language}`);1205 }1206 function highlightElement(element) {1207 let node = null;1208 const language = blockLanguage(element);1209 if (shouldNotHighlight(language))1210 return;1211 fire("before:highlightElement", {el: element, language});1212 if (element.children.length > 0) {1213 if (!options.ignoreUnescapedHTML) {1214 console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk.");1215 console.warn("https://github.com/highlightjs/highlight.js/issues/2886");1216 console.warn(element);1217 }1218 if (options.throwUnescapedHTML) {1219 const err = new HTMLInjectionError("One of your code blocks includes unescaped HTML.", element.innerHTML);1220 throw err;1221 }1222 }1223 node = element;1224 const text = node.textContent;1225 const result = language ? highlight2(text, {language, ignoreIllegals: true}) : highlightAuto(text);1226 element.innerHTML = result.value;1227 updateClassName(element, language, result.language);1228 element.result = {1229 language: result.language,1230 re: result.relevance,1231 relevance: result.relevance1232 };1233 if (result.secondBest) {1234 element.secondBest = {1235 language: result.secondBest.language,1236 relevance: result.secondBest.relevance1237 };1238 }1239 fire("after:highlightElement", {el: element, result, text});1240 }1241 function configure(userOptions) {1242 options = inherit(options, userOptions);1243 }1244 const initHighlighting = () => {1245 highlightAll();1246 deprecated("10.6.0", "initHighlighting() deprecated. Use highlightAll() now.");1247 };1248 function initHighlightingOnLoad() {1249 highlightAll();1250 deprecated("10.6.0", "initHighlightingOnLoad() deprecated. Use highlightAll() now.");1251 }1252 let wantsHighlight = false;1253 function highlightAll() {1254 if (document.readyState === "loading") {1255 wantsHighlight = true;1256 return;1257 }1258 const blocks = document.querySelectorAll(options.cssSelector);1259 blocks.forEach(highlightElement);1260 }1261 function boot() {1262 if (wantsHighlight)1263 highlightAll();1264 }1265 if (typeof window !== "undefined" && window.addEventListener) {1266 window.addEventListener("DOMContentLoaded", boot, false);1267 }1268 function registerLanguage(languageName, languageDefinition) {1269 let lang = null;1270 try {1271 lang = languageDefinition(hljs);1272 } catch (error$1) {1273 error("Language definition for '{}' could not be registered.".replace("{}", languageName));1274 if (!SAFE_MODE) {1275 throw error$1;1276 } else {1277 error(error$1);1278 }1279 lang = PLAINTEXT_LANGUAGE;1280 }1281 if (!lang.name)1282 lang.name = languageName;1283 languages[languageName] = lang;1284 lang.rawDefinition = languageDefinition.bind(null, hljs);1285 if (lang.aliases) {1286 registerAliases(lang.aliases, {languageName});1287 }1288 }1289 function unregisterLanguage(languageName) {1290 delete languages[languageName];1291 for (const alias of Object.keys(aliases)) {1292 if (aliases[alias] === languageName) {1293 delete aliases[alias];1294 }1295 }1296 }1297 function listLanguages() {1298 return Object.keys(languages);1299 }1300 function getLanguage(name) {1301 name = (name || "").toLowerCase();1302 return languages[name] || languages[aliases[name]];1303 }1304 function registerAliases(aliasList, {languageName}) {1305 if (typeof aliasList === "string") {1306 aliasList = [aliasList];1307 }1308 aliasList.forEach((alias) => {1309 aliases[alias.toLowerCase()] = languageName;1310 });1311 }1312 function autoDetection(name) {1313 const lang = getLanguage(name);1314 return lang && !lang.disableAutodetect;1315 }1316 function upgradePluginAPI(plugin) {1317 if (plugin["before:highlightBlock"] && !plugin["before:highlightElement"]) {1318 plugin["before:highlightElement"] = (data) => {1319 plugin["before:highlightBlock"](Object.assign({block: data.el}, data));1320 };1321 }1322 if (plugin["after:highlightBlock"] && !plugin["after:highlightElement"]) {1323 plugin["after:highlightElement"] = (data) => {1324 plugin["after:highlightBlock"](Object.assign({block: data.el}, data));1325 };1326 }1327 }1328 function addPlugin(plugin) {1329 upgradePluginAPI(plugin);1330 plugins.push(plugin);1331 }1332 function fire(event, args) {1333 const cb = event;1334 plugins.forEach(function(plugin) {1335 if (plugin[cb]) {1336 plugin[cb](args);1337 }1338 });1339 }1340 function deprecateHighlightBlock(el) {1341 deprecated("10.7.0", "highlightBlock will be removed entirely in v12.0");1342 deprecated("10.7.0", "Please use highlightElement now.");1343 return highlightElement(el);1344 }1345 Object.assign(hljs, {1346 highlight: highlight2,1347 highlightAuto,1348 highlightAll,1349 highlightElement,1350 highlightBlock: deprecateHighlightBlock,1351 configure,1352 initHighlighting,1353 initHighlightingOnLoad,1354 registerLanguage,1355 unregisterLanguage,1356 listLanguages,1357 getLanguage,1358 registerAliases,1359 autoDetection,1360 inherit,1361 addPlugin1362 });1363 hljs.debugMode = function() {1364 SAFE_MODE = false;1365 };1366 hljs.safeMode = function() {1367 SAFE_MODE = true;1368 };1369 hljs.versionString = version;1370 hljs.regex = {1371 concat,1372 lookahead,1373 either,1374 optional,1375 anyNumberOfTimes1376 };1377 for (const key in MODES) {1378 if (typeof MODES[key] === "object") {1379 deepFreeze$1(MODES[key]);1380 }1381 }1382 Object.assign(hljs, MODES);1383 return hljs;1384};1385var highlight = HLJS({});1386var core = highlight;1387highlight.HighlightJS = highlight;1388highlight.default = highlight;1389export {core as c};...

Full Screen

Full Screen

coder.js

Source:coder.js Github

copy

Full Screen

...413 UNDERSCORE_TITLE_MODE: UNDERSCORE_TITLE_MODE,414 METHOD_GUARD: METHOD_GUARD,415 END_SAME_AS_BEGIN: END_SAME_AS_BEGIN416});417function skipIfhasPrecedingDot(match, response) {418 const before = match.input[match.MySQL - 1];419 if (before === ".") {420 response.ignoreMatch();421 }422}423/**424 * `beginKeywords` syntactic sugar425 * @type {CompilerExt}426 */427function beginKeywords(mode, parent) {428 if (!parent) return;429 if (!mode.beginKeywords) return;430 431 mode.begin = '\\b(' + mode.beginKeywords.split(' ').join('|') + ')(?!\\.)(?=\\b|\\s)';...

Full Screen

Full Screen

core.js

Source:core.js Github

copy

Full Screen

1function deepFreeze(obj) {2 if (obj instanceof Map) {3 obj.clear = obj.delete = obj.set = function () {4 throw new Error('map is read-only');5 };6 } else if (obj instanceof Set) {7 obj.add = obj.clear = obj.delete = function () {8 throw new Error('set is read-only');9 };10 }11 Object.freeze(obj);12 Object.getOwnPropertyNames(obj).forEach(function (name) {13 var prop = obj[name];14 if (typeof prop == 'object' && !Object.isFrozen(prop)) {15 deepFreeze(prop);16 }17 });18 return obj;19}20class Response {21 constructor(mode) {22 // eslint-disable-next-line no-undefined23 if (mode.data === undefined) mode.data = {};24 this.data = mode.data;25 this.isMatchIgnored = false;26 }27 ignoreMatch() {28 this.isMatchIgnored = true;29 }30}31function escapeHTML(value) {32 return value33 .replace(/&/g, '&amp;')34 .replace(/</g, '&lt;')35 .replace(/>/g, '&gt;')36 .replace(/"/g, '&quot;')37 .replace(/'/g, '&#x27;');38}39function inherit$1(original, ...objects) {40 const result = Object.create(null);41 for (const key in original) {42 result[key] = original[key];43 }44 objects.forEach(function(obj) {45 for (const key in obj) {46 result[key] = obj[key];47 }48 });49 return result;50}51const SPAN_CLOSE = '</span>';52const emitsWrappingTags = (node) => {53 return !!node.kind;54};55const expandScopeName = (name, { prefix }) => {56 if (name.includes(".")) {57 const pieces = name.split(".");58 return [59 `${prefix}${pieces.shift()}`,60 ...(pieces.map((x, i) => `${x}${"_".repeat(i + 1)}`))61 ].join(" ");62 }63 return `${prefix}${name}`;64};65class HTMLRenderer {66 constructor(parseTree, options) {67 this.buffer = "";68 this.classPrefix = options.classPrefix;69 parseTree.walk(this);70 }71 addText(text) {72 this.buffer += escapeHTML(text);73 }74 openNode(node) {75 if (!emitsWrappingTags(node)) return;76 let scope = node.kind;77 if (node.sublanguage) {78 scope = `language-${scope}`;79 } else {80 scope = expandScopeName(scope, { prefix: this.classPrefix });81 }82 this.span(scope);83 }84 closeNode(node) {85 if (!emitsWrappingTags(node)) return;86 this.buffer += SPAN_CLOSE;87 }88 value() {89 return this.buffer;90 }91 span(className) {92 this.buffer += `<span class="${className}">`;93 }94}95class TokenTree {96 constructor() {97 this.rootNode = { children: [] };98 this.stack = [this.rootNode];99 }100 get top() {101 return this.stack[this.stack.length - 1];102 }103 get root() { return this.rootNode; }104 add(node) {105 this.top.children.push(node);106 }107 openNode(kind) {108 const node = { kind, children: [] };109 this.add(node);110 this.stack.push(node);111 }112 closeNode() {113 if (this.stack.length > 1) {114 return this.stack.pop();115 }116 // eslint-disable-next-line no-undefined117 return undefined;118 }119 closeAllNodes() {120 while (this.closeNode());121 }122 toJSON() {123 return JSON.stringify(this.rootNode, null, 4);124 }125 walk(builder) {126 return this.constructor._walk(builder, this.rootNode);127 }128 static _walk(builder, node) {129 if (typeof node === "string") {130 builder.addText(node);131 } else if (node.children) {132 builder.openNode(node);133 node.children.forEach((child) => this._walk(builder, child));134 builder.closeNode(node);135 }136 return builder;137 }138 static _collapse(node) {139 if (typeof node === "string") return;140 if (!node.children) return;141 if (node.children.every(el => typeof el === "string")) {142 node.children = [node.children.join("")];143 } else {144 node.children.forEach((child) => {145 TokenTree._collapse(child);146 });147 }148 }149}150class TokenTreeEmitter extends TokenTree {151 constructor(options) {152 super();153 this.options = options;154 }155 addKeyword(text, kind) {156 if (text === "") { return; }157 this.openNode(kind);158 this.addText(text);159 this.closeNode();160 }161 addText(text) {162 if (text === "") { return; }163 this.add(text);164 }165 addSublanguage(emitter, name) {166 const node = emitter.root;167 node.kind = name;168 node.sublanguage = true;169 this.add(node);170 }171 toHTML() {172 const renderer = new HTMLRenderer(this, this.options);173 return renderer.value();174 }175 finalize() {176 return true;177 }178}179function source(re) {180 if (!re) return null;181 if (typeof re === "string") return re;182 return re.source;183}184function lookahead(re) {185 return concat('(?=', re, ')');186}187function concat(...args) {188 const joined = args.map((x) => source(x)).join("");189 return joined;190}191function stripOptionsFromArgs(args) {192 const opts = args[args.length - 1];193 if (typeof opts === 'object' && opts.constructor === Object) {194 args.splice(args.length - 1, 1);195 return opts;196 } else {197 return {};198 }199}200function either(...args) {201 const opts = stripOptionsFromArgs(args);202 const joined = '(' +203 (opts.capture ? "" : "?:") +204 args.map((x) => source(x)).join("|") + ")";205 return joined;206}207function countMatchGroups(re) {208 return (new RegExp(re.toString() + '|')).exec('').length - 1;209}210function startsWith(re, lexeme) {211 const match = re && re.exec(lexeme);212 return match && match.index === 0;213}214const BACKREF_RE = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;215function _rewriteBackreferences(regexps, { joinWith }) {216 let numCaptures = 0;217 return regexps.map((regex) => {218 numCaptures += 1;219 const offset = numCaptures;220 let re = source(regex);221 let out = '';222 while (re.length > 0) {223 const match = BACKREF_RE.exec(re);224 if (!match) {225 out += re;226 break;227 }228 out += re.substring(0, match.index);229 re = re.substring(match.index + match[0].length);230 if (match[0][0] === '\\' && match[1]) {231 // Adjust the backreference.232 out += '\\' + String(Number(match[1]) + offset);233 } else {234 out += match[0];235 if (match[0] === '(') {236 numCaptures++;237 }238 }239 }240 return out;241 }).map(re => `(${re})`).join(joinWith);242}243const MATCH_NOTHING_RE = /\b\B/;244const IDENT_RE = '[a-zA-Z]\\w*';245const UNDERSCORE_IDENT_RE = '[a-zA-Z_]\\w*';246const NUMBER_RE = '\\b\\d+(\\.\\d+)?';247const C_NUMBER_RE = '(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)';248const BINARY_NUMBER_RE = '\\b(0b[01]+)'; // 0b...249const RE_STARTERS_RE = '!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~';250const SHEBANG = (opts = {}) => {251 const beginShebang = /^#![ ]*\//;252 if (opts.binary) {253 opts.begin = concat(254 beginShebang,255 /.*\b/,256 opts.binary,257 /\b.*/);258 }259 return inherit$1({260 scope: 'meta',261 begin: beginShebang,262 end: /$/,263 relevance: 0,264 /** @type {ModeCallback} */265 "on:begin": (m, resp) => {266 if (m.index !== 0) resp.ignoreMatch();267 }268 }, opts);269};270// Common modes271const BACKSLASH_ESCAPE = {272 begin: '\\\\[\\s\\S]', relevance: 0273};274const APOS_STRING_MODE = {275 scope: 'string',276 begin: '\'',277 end: '\'',278 illegal: '\\n',279 contains: [BACKSLASH_ESCAPE]280};281const QUOTE_STRING_MODE = {282 scope: 'string',283 begin: '"',284 end: '"',285 illegal: '\\n',286 contains: [BACKSLASH_ESCAPE]287};288const PHRASAL_WORDS_MODE = {289 begin: /\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/290};291const COMMENT = function(begin, end, modeOptions = {}) {292 const mode = inherit$1(293 {294 scope: 'comment',295 begin,296 end,297 contains: []298 },299 modeOptions300 );301 mode.contains.push({302 scope: 'doctag',303 // hack to avoid the space from being included. the space is necessary to304 // match here to prevent the plain text rule below from gobbling up doctags305 begin: '[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)',306 end: /(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,307 excludeBegin: true,308 relevance: 0309 });310 const ENGLISH_WORD = either(311 // list of common 1 and 2 letter words in English312 "I",313 "a",314 "is",315 "so",316 "us",317 "to",318 "at",319 "if",320 "in",321 "it",322 "on",323 /[A-Za-z]+['](d|ve|re|ll|t|s|n)/, // contractions - can't we'd they're let's, etc324 /[A-Za-z]+[-][a-z]+/, // `no-way`, etc.325 /[A-Za-z][a-z]{2,}/ // allow capitalized words at beginning of sentences326 );327 mode.contains.push(328 {329 begin: concat(330 /[ ]+/,331 '(',332 ENGLISH_WORD,333 /[.]?[:]?([.][ ]|[ ])/,334 '){3}')335 }336 );337 return mode;338};339const C_LINE_COMMENT_MODE = COMMENT('//', '$');340const C_BLOCK_COMMENT_MODE = COMMENT('/\\*', '\\*/');341const HASH_COMMENT_MODE = COMMENT('#', '$');342const NUMBER_MODE = {343 scope: 'number',344 begin: NUMBER_RE,345 relevance: 0346};347const C_NUMBER_MODE = {348 scope: 'number',349 begin: C_NUMBER_RE,350 relevance: 0351};352const BINARY_NUMBER_MODE = {353 scope: 'number',354 begin: BINARY_NUMBER_RE,355 relevance: 0356};357const REGEXP_MODE = {358 begin: /(?=\/[^/\n]*\/)/,359 contains: [{360 scope: 'regexp',361 begin: /\//,362 end: /\/[gimuy]*/,363 illegal: /\n/,364 contains: [365 BACKSLASH_ESCAPE,366 {367 begin: /\[/,368 end: /\]/,369 relevance: 0,370 contains: [BACKSLASH_ESCAPE]371 }372 ]373 }]374};375const TITLE_MODE = {376 scope: 'title',377 begin: IDENT_RE,378 relevance: 0379};380const UNDERSCORE_TITLE_MODE = {381 scope: 'title',382 begin: UNDERSCORE_IDENT_RE,383 relevance: 0384};385const METHOD_GUARD = {386 // excludes method names from keyword processing387 begin: '\\.\\s*' + UNDERSCORE_IDENT_RE,388 relevance: 0389};390const END_SAME_AS_BEGIN = function(mode) {391 return Object.assign(mode,392 {393 /** @type {ModeCallback} */394 'on:begin': (m, resp) => { resp.data._beginMatch = m[1]; },395 /** @type {ModeCallback} */396 'on:end': (m, resp) => { if (resp.data._beginMatch !== m[1]) resp.ignoreMatch(); }397 });398};399var MODES = /*#__PURE__*/Object.freeze({400 __proto__: null,401 MATCH_NOTHING_RE: MATCH_NOTHING_RE,402 IDENT_RE: IDENT_RE,403 UNDERSCORE_IDENT_RE: UNDERSCORE_IDENT_RE,404 NUMBER_RE: NUMBER_RE,405 C_NUMBER_RE: C_NUMBER_RE,406 BINARY_NUMBER_RE: BINARY_NUMBER_RE,407 RE_STARTERS_RE: RE_STARTERS_RE,408 SHEBANG: SHEBANG,409 BACKSLASH_ESCAPE: BACKSLASH_ESCAPE,410 APOS_STRING_MODE: APOS_STRING_MODE,411 QUOTE_STRING_MODE: QUOTE_STRING_MODE,412 PHRASAL_WORDS_MODE: PHRASAL_WORDS_MODE,413 COMMENT: COMMENT,414 C_LINE_COMMENT_MODE: C_LINE_COMMENT_MODE,415 C_BLOCK_COMMENT_MODE: C_BLOCK_COMMENT_MODE,416 HASH_COMMENT_MODE: HASH_COMMENT_MODE,417 NUMBER_MODE: NUMBER_MODE,418 C_NUMBER_MODE: C_NUMBER_MODE,419 BINARY_NUMBER_MODE: BINARY_NUMBER_MODE,420 REGEXP_MODE: REGEXP_MODE,421 TITLE_MODE: TITLE_MODE,422 UNDERSCORE_TITLE_MODE: UNDERSCORE_TITLE_MODE,423 METHOD_GUARD: METHOD_GUARD,424 END_SAME_AS_BEGIN: END_SAME_AS_BEGIN425});426function skipIfHasPrecedingDot(match, response) {427 const before = match.input[match.index - 1];428 if (before === ".") {429 response.ignoreMatch();430 }431}432function scopeClassName(mode, _parent) {433 // eslint-disable-next-line no-undefined434 if (mode.className !== undefined) {435 mode.scope = mode.className;436 delete mode.className;437 }438}439function beginKeywords(mode, parent) {440 if (!parent) return;441 if (!mode.beginKeywords) return;442 mode.begin = '\\b(' + mode.beginKeywords.split(' ').join('|') + ')(?!\\.)(?=\\b|\\s)';443 mode.__beforeBegin = skipIfHasPrecedingDot;444 mode.keywords = mode.keywords || mode.beginKeywords;445 delete mode.beginKeywords;446 if (mode.relevance === undefined) mode.relevance = 0;447}448function compileIllegal(mode, _parent) {449 if (!Array.isArray(mode.illegal)) return;450 mode.illegal = either(...mode.illegal);451}452function compileMatch(mode, _parent) {453 if (!mode.match) return;454 if (mode.begin || mode.end) throw new Error("begin & end are not supported with match");455 mode.begin = mode.match;456 delete mode.match;457}458function compileRelevance(mode, _parent) {459 // eslint-disable-next-line no-undefined460 if (mode.relevance === undefined) mode.relevance = 1;461}462const beforeMatchExt = (mode, parent) => {463 if (!mode.beforeMatch) return;464 if (mode.starts) throw new Error("beforeMatch cannot be used with starts");465 const originalMode = Object.assign({}, mode);466 Object.keys(mode).forEach((key) => { delete mode[key]; });467 mode.keywords = originalMode.keywords;468 mode.begin = concat(originalMode.beforeMatch, lookahead(originalMode.begin));469 mode.starts = {470 relevance: 0,471 contains: [472 Object.assign(originalMode, { endsParent: true })473 ]474 };475 mode.relevance = 0;476 delete originalMode.beforeMatch;477};478const COMMON_KEYWORDS = [479 'of',480 'and',481 'for',482 'in',483 'not',484 'or',485 'if',486 'then',487 'parent', // common variable name488 'list', // common variable name489 'value' // common variable name490];491const DEFAULT_KEYWORD_SCOPE = "keyword";492function compileKeywords(rawKeywords, caseInsensitive, scopeName = DEFAULT_KEYWORD_SCOPE) {493 const compileList = (scopeName, keywordList) => {494 if (caseInsensitive) {495 keywordList = keywordList.map(x => x.toLowerCase());496 }497 keywordList.forEach(function(keyword) {498 const pair = keyword.split('|');499 compiledKeywords[pair[0]] = [scopeName, scoreForKeyword(pair[0], pair[1])];500 });501 }502 const compiledKeywords = Object.create(null);503 if (typeof rawKeywords === 'string') {504 compileList(scopeName, rawKeywords.split(" "));505 } else if (Array.isArray(rawKeywords)) {506 compileList(scopeName, rawKeywords);507 } else {508 Object.keys(rawKeywords).forEach(function(scopeName) {509 Object.assign(510 compiledKeywords,511 compileKeywords(rawKeywords[scopeName], caseInsensitive, scopeName)512 );513 });514 }515 return compiledKeywords;516}517function scoreForKeyword(keyword, providedScore) {518 if (providedScore) {519 return Number(providedScore);520 }521 return commonKeyword(keyword) ? 0 : 1;522}523function commonKeyword(keyword) {524 return COMMON_KEYWORDS.includes(keyword.toLowerCase());525}526const seenDeprecations = {};527const error = (message) => {528 console.error(message);529};530const warn = (message, ...args) => {531 console.log(`WARN: ${message}`, ...args);532};533const deprecated = (version, message) => {534 if (seenDeprecations[`${version}/${message}`]) return;535 console.log(`Deprecated as of ${version}. ${message}`);536 seenDeprecations[`${version}/${message}`] = true;537};538const MultiClassError = new Error();539function remapScopeNames(mode, regexes, { key }) {540 let offset = 0;541 const scopeNames = mode[key];542 const emit = {};543 const positions = {};544 for (let i = 1; i <= regexes.length; i++) {545 positions[i + offset] = scopeNames[i];546 emit[i + offset] = true;547 offset += countMatchGroups(regexes[i - 1]);548 }549 mode[key] = positions;550 mode[key]._emit = emit;551 mode[key]._multi = true;552}553function beginMultiClass(mode) {554 if (!Array.isArray(mode.begin)) return;555 if (mode.skip || mode.excludeBegin || mode.returnBegin) {556 error("skip, excludeBegin, returnBegin not compatible with beginScope: {}");557 throw MultiClassError;558 }559 if (typeof mode.beginScope !== "object" || mode.beginScope === null) {560 error("beginScope must be object");561 throw MultiClassError;562 }563 remapScopeNames(mode, mode.begin, {key: "beginScope"});564 mode.begin = _rewriteBackreferences(mode.begin, { joinWith: "" });565}566function endMultiClass(mode) {567 if (!Array.isArray(mode.end)) return;568 if (mode.skip || mode.excludeEnd || mode.returnEnd) {569 error("skip, excludeEnd, returnEnd not compatible with endScope: {}");570 throw MultiClassError;571 }572 if (typeof mode.endScope !== "object" || mode.endScope === null) {573 error("endScope must be object");574 throw MultiClassError;575 }576 remapScopeNames(mode, mode.end, {key: "endScope"});577 mode.end = _rewriteBackreferences(mode.end, { joinWith: "" });578}579function scopeSugar(mode) {580 if (mode.scope && typeof mode.scope === "object" && mode.scope !== null) {581 mode.beginScope = mode.scope;582 delete mode.scope;583 }584}585function MultiClass(mode) {586 scopeSugar(mode);587 if (typeof mode.beginScope === "string") {588 mode.beginScope = { _wrap: mode.beginScope };589 }590 if (typeof mode.endScope === "string") {591 mode.endScope = { _wrap: mode.endScope };592 }593 beginMultiClass(mode);594 endMultiClass(mode);595}596function compileLanguage(language) {597 function langRe(value, global) {598 return new RegExp(599 source(value),600 'm' + (language.case_insensitive ? 'i' : '') + (global ? 'g' : '')601 );602 }603 class MultiRegex {604 constructor() {605 this.matchIndexes = {};606 this.regexes = [];607 this.matchAt = 1;608 this.position = 0;609 }610 addRule(re, opts) {611 opts.position = this.position++;612 this.matchIndexes[this.matchAt] = opts;613 this.regexes.push([opts, re]);614 this.matchAt += countMatchGroups(re) + 1;615 }616 compile() {617 if (this.regexes.length === 0) {618 this.exec = () => null;619 }620 const terminators = this.regexes.map(el => el[1]);621 this.matcherRe = langRe(_rewriteBackreferences(terminators, { joinWith: '|' }), true);622 this.lastIndex = 0;623 }624 exec(s) {625 this.matcherRe.lastIndex = this.lastIndex;626 const match = this.matcherRe.exec(s);627 if (!match) { return null; }628 // eslint-disable-next-line no-undefined629 const i = match.findIndex((el, i) => i > 0 && el !== undefined);630 const matchData = this.matchIndexes[i];631 match.splice(0, i);632 return Object.assign(match, matchData);633 }634 }635 class ResumableMultiRegex {636 constructor() {637 this.rules = [];638 this.multiRegexes = [];639 this.count = 0;640 this.lastIndex = 0;641 this.regexIndex = 0;642 }643 getMatcher(index) {644 if (this.multiRegexes[index]) return this.multiRegexes[index];645 const matcher = new MultiRegex();646 this.rules.slice(index).forEach(([re, opts]) => matcher.addRule(re, opts));647 matcher.compile();648 this.multiRegexes[index] = matcher;649 return matcher;650 }651 resumingScanAtSamePosition() {652 return this.regexIndex !== 0;653 }654 considerAll() {655 this.regexIndex = 0;656 }657 addRule(re, opts) {658 this.rules.push([re, opts]);659 if (opts.type === "begin") this.count++;660 }661 exec(s) {662 const m = this.getMatcher(this.regexIndex);663 m.lastIndex = this.lastIndex;664 let result = m.exec(s);665 if (this.resumingScanAtSamePosition()) {666 if (result && result.index === this.lastIndex) ; else {667 const m2 = this.getMatcher(0);668 m2.lastIndex = this.lastIndex + 1;669 result = m2.exec(s);670 }671 }672 if (result) {673 this.regexIndex += result.position + 1;674 if (this.regexIndex === this.count) {675 this.considerAll();676 }677 }678 return result;679 }680 }681 function buildModeRegex(mode) {682 const mm = new ResumableMultiRegex();683 mode.contains.forEach(term => mm.addRule(term.begin, { rule: term, type: "begin" }));684 if (mode.terminatorEnd) {685 mm.addRule(mode.terminatorEnd, { type: "end" });686 }687 if (mode.illegal) {688 mm.addRule(mode.illegal, { type: "illegal" });689 }690 return mm;691 }692 function compileMode(mode, parent) {693 const cmode = /** @type CompiledMode */ (mode);694 if (mode.isCompiled) return cmode;695 [696 scopeClassName,697 // do this early so compiler extensions generally don't have to worry about698 // the distinction between match/begin699 compileMatch,700 MultiClass,701 beforeMatchExt702 ].forEach(ext => ext(mode, parent));703 language.compilerExtensions.forEach(ext => ext(mode, parent));704 mode.__beforeBegin = null;705 [706 beginKeywords,707 compileIllegal,708 compileRelevance709 ].forEach(ext => ext(mode, parent));710 mode.isCompiled = true;711 let keywordPattern = null;712 if (typeof mode.keywords === "object" && mode.keywords.$pattern) {713 mode.keywords = Object.assign({}, mode.keywords);714 keywordPattern = mode.keywords.$pattern;715 delete mode.keywords.$pattern;716 }717 keywordPattern = keywordPattern || /\w+/;718 if (mode.keywords) {719 mode.keywords = compileKeywords(mode.keywords, language.case_insensitive);720 }721 cmode.keywordPatternRe = langRe(keywordPattern, true);722 if (parent) {723 if (!mode.begin) mode.begin = /\B|\b/;724 cmode.beginRe = langRe(mode.begin);725 if (!mode.end && !mode.endsWithParent) mode.end = /\B|\b/;726 if (mode.end) cmode.endRe = langRe(mode.end);727 cmode.terminatorEnd = source(mode.end) || '';728 if (mode.endsWithParent && parent.terminatorEnd) {729 cmode.terminatorEnd += (mode.end ? '|' : '') + parent.terminatorEnd;730 }731 }732 if (mode.illegal) cmode.illegalRe = langRe(/** @type {RegExp | string} */ (mode.illegal));733 if (!mode.contains) mode.contains = [];734 mode.contains = [].concat(...mode.contains.map(function(c) {735 return expandOrCloneMode(c === 'self' ? mode : c);736 }));737 mode.contains.forEach(function(c) { compileMode(/** @type Mode */ (c), cmode); });738 if (mode.starts) {739 compileMode(mode.starts, parent);740 }741 cmode.matcher = buildModeRegex(cmode);742 return cmode;743 }744 if (!language.compilerExtensions) language.compilerExtensions = [];745 if (language.contains && language.contains.includes('self')) {746 throw new Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");747 }748 language.classNameAliases = inherit$1(language.classNameAliases || {});749 return compileMode(language);750}751function dependencyOnParent(mode) {752 if (!mode) return false;753 return mode.endsWithParent || dependencyOnParent(mode.starts);754}755function expandOrCloneMode(mode) {756 if (mode.variants && !mode.cachedVariants) {757 mode.cachedVariants = mode.variants.map(function(variant) {758 return inherit$1(mode, { variants: null }, variant);759 });760 }761 if (mode.cachedVariants) {762 return mode.cachedVariants;763 }764 if (dependencyOnParent(mode)) {765 return inherit$1(mode, { starts: mode.starts ? inherit$1(mode.starts) : null });766 }767 if (Object.isFrozen(mode)) {768 return inherit$1(mode);769 }770 return mode;771}772const escape = escapeHTML;773const inherit = inherit$1;774const NO_MATCH = Symbol("nomatch");775const MAX_KEYWORD_HITS = 7;776const HLJS = function(hljs) {777 const languages = Object.create(null);778 const aliases = Object.create(null);779 const plugins = [];780 let SAFE_MODE = true;781 const LANGUAGE_NOT_FOUND = "Could not find the language '{}', did you forget to load/include a language module?";782 const PLAINTEXT_LANGUAGE = { disableAutodetect: true, name: 'Plain text', contains: [] };783 let options = {784 ignoreUnescapedHTML: false,785 noHighlightRe: /^(no-?highlight)$/i,786 languageDetectRe: /\blang(?:uage)?-([\w-]+)\b/i,787 classPrefix: '',788 cssSelector: 'pre code',789 languages: null,790 __emitter: TokenTreeEmitter791 };792 function shouldNotHighlight(languageName) {793 return options.noHighlightRe.test(languageName);794 }795 function blockLanguage(block) {796 let classes = block.className + ' ';797 classes += block.parentNode ? block.parentNode.className : '';798 const match = options.languageDetectRe.exec(classes);799 if (match) {800 const language = getLanguage(match[1]);801 if (!language) {802 warn(LANGUAGE_NOT_FOUND.replace("{}", match[1]));803 warn("Falling back to no-highlight mode for this block.", block);804 }805 return language ? match[1] : 'no-highlight';806 }807 return classes808 .split(/\s+/)809 .find((_class) => shouldNotHighlight(_class) || getLanguage(_class));810 }811 function highlight(codeOrLanguageName, optionsOrCode, ignoreIllegals) {812 let code = "";813 let languageName = "";814 if (typeof optionsOrCode === "object") {815 code = codeOrLanguageName;816 ignoreIllegals = optionsOrCode.ignoreIllegals;817 languageName = optionsOrCode.language;818 } else {819 // old API820 deprecated("10.7.0", "highlight(lang, code, ...args) has been deprecated.");821 deprecated("10.7.0", "Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277");822 languageName = codeOrLanguageName;823 code = optionsOrCode;824 }825 if (ignoreIllegals === undefined) { ignoreIllegals = true; }826 /** @type {BeforeHighlightContext} */827 const context = {828 code,829 language: languageName830 };831 fire("before:highlight", context);832 const result = context.result833 ? context.result834 : _highlight(context.language, context.code, ignoreIllegals);835 result.code = context.code;836 fire("after:highlight", result);837 return result;838 }839 function _highlight(languageName, codeToHighlight, ignoreIllegals, continuation) {840 const keywordHits = Object.create(null);841 function keywordData(mode, matchText) {842 return mode.keywords[matchText];843 }844 function processKeywords() {845 if (!top.keywords) {846 emitter.addText(modeBuffer);847 return;848 }849 let lastIndex = 0;850 top.keywordPatternRe.lastIndex = 0;851 let match = top.keywordPatternRe.exec(modeBuffer);852 let buf = "";853 while (match) {854 buf += modeBuffer.substring(lastIndex, match.index);855 const word = language.case_insensitive ? match[0].toLowerCase() : match[0];856 const data = keywordData(top, word);857 if (data) {858 const [kind, keywordRelevance] = data;859 emitter.addText(buf);860 buf = "";861 keywordHits[word] = (keywordHits[word] || 0) + 1;862 if (keywordHits[word] <= MAX_KEYWORD_HITS) relevance += keywordRelevance;863 if (kind.startsWith("_")) {864 buf += match[0];865 } else {866 const cssClass = language.classNameAliases[kind] || kind;867 emitter.addKeyword(match[0], cssClass);868 }869 } else {870 buf += match[0];871 }872 lastIndex = top.keywordPatternRe.lastIndex;873 match = top.keywordPatternRe.exec(modeBuffer);874 }875 buf += modeBuffer.substr(lastIndex);876 emitter.addText(buf);877 }878 function processSubLanguage() {879 if (modeBuffer === "") return;880 /** @type HighlightResult */881 let result = null;882 if (typeof top.subLanguage === 'string') {883 if (!languages[top.subLanguage]) {884 emitter.addText(modeBuffer);885 return;886 }887 result = _highlight(top.subLanguage, modeBuffer, true, continuations[top.subLanguage]);888 continuations[top.subLanguage] = /** @type {CompiledMode} */ (result._top);889 } else {890 result = highlightAuto(modeBuffer, top.subLanguage.length ? top.subLanguage : null);891 }892 if (top.relevance > 0) {893 relevance += result.relevance;894 }895 emitter.addSublanguage(result._emitter, result.language);896 }897 function processBuffer() {898 if (top.subLanguage != null) {899 processSubLanguage();900 } else {901 processKeywords();902 }903 modeBuffer = '';904 }905 function emitMultiClass(scope, match) {906 let i = 1;907 // eslint-disable-next-line no-undefined908 while (match[i] !== undefined) {909 if (!scope._emit[i]) { i++; continue; }910 const klass = language.classNameAliases[scope[i]] || scope[i];911 const text = match[i];912 if (klass) {913 emitter.addKeyword(text, klass);914 } else {915 modeBuffer = text;916 processKeywords();917 modeBuffer = "";918 }919 i++;920 }921 }922 function startNewMode(mode, match) {923 if (mode.scope && typeof mode.scope === "string") {924 emitter.openNode(language.classNameAliases[mode.scope] || mode.scope);925 }926 if (mode.beginScope) {927 if (mode.beginScope._wrap) {928 emitter.addKeyword(modeBuffer, language.classNameAliases[mode.beginScope._wrap] || mode.beginScope._wrap);929 modeBuffer = "";930 } else if (mode.beginScope._multi) {931 emitMultiClass(mode.beginScope, match);932 modeBuffer = "";933 }934 }935 top = Object.create(mode, { parent: { value: top } });936 return top;937 }938 function endOfMode(mode, match, matchPlusRemainder) {939 let matched = startsWith(mode.endRe, matchPlusRemainder);940 if (matched) {941 if (mode["on:end"]) {942 const resp = new Response(mode);943 mode["on:end"](match, resp);944 if (resp.isMatchIgnored) matched = false;945 }946 if (matched) {947 while (mode.endsParent && mode.parent) {948 mode = mode.parent;949 }950 return mode;951 }952 }953 if (mode.endsWithParent) {954 return endOfMode(mode.parent, match, matchPlusRemainder);955 }956 }957 function doIgnore(lexeme) {958 if (top.matcher.regexIndex === 0) {959 modeBuffer += lexeme[0];960 return 1;961 } else {962 resumeScanAtSamePosition = true;963 return 0;964 }965 }966 function doBeginMatch(match) {967 const lexeme = match[0];968 const newMode = match.rule;969 const resp = new Response(newMode);970 const beforeCallbacks = [newMode.__beforeBegin, newMode["on:begin"]];971 for (const cb of beforeCallbacks) {972 if (!cb) continue;973 cb(match, resp);974 if (resp.isMatchIgnored) return doIgnore(lexeme);975 }976 if (newMode.skip) {977 modeBuffer += lexeme;978 } else {979 if (newMode.excludeBegin) {980 modeBuffer += lexeme;981 }982 processBuffer();983 if (!newMode.returnBegin && !newMode.excludeBegin) {984 modeBuffer = lexeme;985 }986 }987 startNewMode(newMode, match);988 return newMode.returnBegin ? 0 : lexeme.length;989 }990 function doEndMatch(match) {991 const lexeme = match[0];992 const matchPlusRemainder = codeToHighlight.substr(match.index);993 const endMode = endOfMode(top, match, matchPlusRemainder);994 if (!endMode) { return NO_MATCH; }995 const origin = top;996 if (top.endScope && top.endScope._wrap) {997 processBuffer();998 emitter.addKeyword(lexeme, top.endScope._wrap);999 } else if (top.endScope && top.endScope._multi) {1000 processBuffer();1001 emitMultiClass(top.endScope, match);1002 } else if (origin.skip) {1003 modeBuffer += lexeme;1004 } else {1005 if (!(origin.returnEnd || origin.excludeEnd)) {1006 modeBuffer += lexeme;1007 }1008 processBuffer();1009 if (origin.excludeEnd) {1010 modeBuffer = lexeme;1011 }1012 }1013 do {1014 if (top.scope) {1015 emitter.closeNode();1016 }1017 if (!top.skip && !top.subLanguage) {1018 relevance += top.relevance;1019 }1020 top = top.parent;1021 } while (top !== endMode.parent);1022 if (endMode.starts) {1023 startNewMode(endMode.starts, match);1024 }1025 return origin.returnEnd ? 0 : lexeme.length;1026 }1027 function processContinuations() {1028 const list = [];1029 for (let current = top; current !== language; current = current.parent) {1030 if (current.scope) {1031 list.unshift(current.scope);1032 }1033 }1034 list.forEach(item => emitter.openNode(item));1035 }1036 let lastMatch = {};1037 function processLexeme(textBeforeMatch, match) {1038 const lexeme = match && match[0];1039 modeBuffer += textBeforeMatch;1040 if (lexeme == null) {1041 processBuffer();1042 return 0;1043 }1044 if (lastMatch.type === "begin" && match.type === "end" && lastMatch.index === match.index && lexeme === "") {1045 modeBuffer += codeToHighlight.slice(match.index, match.index + 1);1046 if (!SAFE_MODE) {1047 const err = new Error(`0 width match regex (${languageName})`);1048 err.languageName = languageName;1049 err.badRule = lastMatch.rule;1050 throw err;1051 }1052 return 1;1053 }1054 lastMatch = match;1055 if (match.type === "begin") {1056 return doBeginMatch(match);1057 } else if (match.type === "illegal" && !ignoreIllegals) {1058 const err = new Error('Illegal lexeme "' + lexeme + '" for mode "' + (top.scope || '<unnamed>') + '"');1059 err.mode = top;1060 throw err;1061 } else if (match.type === "end") {1062 const processed = doEndMatch(match);1063 if (processed !== NO_MATCH) {1064 return processed;1065 }1066 }1067 if (match.type === "illegal" && lexeme === "") {1068 return 1;1069 }1070 if (iterations > 100000 && iterations > match.index * 3) {1071 const err = new Error('potential infinite loop, way more iterations than matches');1072 throw err;1073 }1074 modeBuffer += lexeme;1075 return lexeme.length;1076 }1077 const language = getLanguage(languageName);1078 if (!language) {1079 error(LANGUAGE_NOT_FOUND.replace("{}", languageName));1080 throw new Error('Unknown language: "' + languageName + '"');1081 }1082 const md = compileLanguage(language);1083 let result = '';1084 let top = continuation || md;1085 const continuations = {};1086 const emitter = new options.__emitter(options);1087 processContinuations();1088 let modeBuffer = '';1089 let relevance = 0;1090 let index = 0;1091 let iterations = 0;1092 let resumeScanAtSamePosition = false;1093 try {1094 top.matcher.considerAll();1095 for (;;) {1096 iterations++;1097 if (resumeScanAtSamePosition) {1098 resumeScanAtSamePosition = false;1099 } else {1100 top.matcher.considerAll();1101 }1102 top.matcher.lastIndex = index;1103 const match = top.matcher.exec(codeToHighlight);1104 if (!match) break;1105 const beforeMatch = codeToHighlight.substring(index, match.index);1106 const processedCount = processLexeme(beforeMatch, match);1107 index = match.index + processedCount;1108 }1109 processLexeme(codeToHighlight.substr(index));1110 emitter.closeAllNodes();1111 emitter.finalize();1112 result = emitter.toHTML();1113 return {1114 language: languageName,1115 value: result,1116 relevance: relevance,1117 illegal: false,1118 _emitter: emitter,1119 _top: top1120 };1121 } catch (err) {1122 if (err.message && err.message.includes('Illegal')) {1123 return {1124 language: languageName,1125 value: escape(codeToHighlight),1126 illegal: true,1127 relevance: 0,1128 _illegalBy: {1129 message: err.message,1130 index: index,1131 context: codeToHighlight.slice(index - 100, index + 100),1132 mode: err.mode,1133 resultSoFar: result1134 },1135 _emitter: emitter1136 };1137 } else if (SAFE_MODE) {1138 return {1139 language: languageName,1140 value: escape(codeToHighlight),1141 illegal: false,1142 relevance: 0,1143 errorRaised: err,1144 _emitter: emitter,1145 _top: top1146 };1147 } else {1148 throw err;1149 }1150 }1151 }1152 function justTextHighlightResult(code) {1153 const result = {1154 value: escape(code),1155 illegal: false,1156 relevance: 0,1157 _top: PLAINTEXT_LANGUAGE,1158 _emitter: new options.__emitter(options)1159 };1160 result._emitter.addText(code);1161 return result;1162 }1163 function highlightAuto(code, languageSubset) {1164 languageSubset = languageSubset || options.languages || Object.keys(languages);1165 const plaintext = justTextHighlightResult(code);1166 const results = languageSubset.filter(getLanguage).filter(autoDetection).map(name =>1167 _highlight(name, code, false)1168 );1169 results.unshift(plaintext); // plaintext is always an option1170 const sorted = results.sort((a, b) => {1171 // sort base on relevance1172 if (a.relevance !== b.relevance) return b.relevance - a.relevance;1173 // always award the tie to the base language1174 // ie if C++ and Arduino are tied, it's more likely to be C++1175 if (a.language && b.language) {1176 if (getLanguage(a.language).supersetOf === b.language) {1177 return 1;1178 } else if (getLanguage(b.language).supersetOf === a.language) {1179 return -1;1180 }1181 }1182 return 0;1183 });1184 const [best, secondBest] = sorted;1185 const result = best;1186 result.secondBest = secondBest;1187 return result;1188 }1189 function updateClassName(element, currentLang, resultLang) {1190 const language = (currentLang && aliases[currentLang]) || resultLang;1191 element.classList.add("hljs");1192 element.classList.add(`language-${language}`);1193 }1194 function highlightElement(element) {1195 let node = null;1196 const language = blockLanguage(element);1197 if (shouldNotHighlight(language)) return;1198 fire("before:highlightElement",1199 { el: element, language: language });1200 if (!options.ignoreUnescapedHTML && element.children.length > 0) {1201 console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk.");1202 console.warn("https://github.com/highlightjs/highlight.js/issues/2886");1203 console.warn(element);1204 }1205 node = element;1206 const text = node.textContent;1207 const result = language ? highlight(text, { language, ignoreIllegals: true }) : highlightAuto(text);1208 element.innerHTML = result.value;1209 updateClassName(element, language, result.language);1210 element.result = {1211 language: result.language,1212 re: result.relevance,1213 relevance: result.relevance1214 };1215 if (result.secondBest) {1216 element.secondBest = {1217 language: result.secondBest.language,1218 relevance: result.secondBest.relevance1219 };1220 }1221 fire("after:highlightElement", { el: element, result, text });1222 }1223 let wantsHighlight = false;1224 function highlightAll() {1225 if (document.readyState === "loading") {1226 wantsHighlight = true;1227 return;1228 }1229 const blocks = document.querySelectorAll(options.cssSelector);1230 blocks.forEach(highlightElement);1231 }1232 function boot() {1233 if (wantsHighlight) highlightAll();1234 }1235 if (typeof window !== 'undefined' && window.addEventListener) {1236 window.addEventListener('DOMContentLoaded', boot, false);1237 }1238 function registerLanguage(languageName, languageDefinition) {1239 let lang = null;1240 try {1241 lang = languageDefinition(hljs);1242 } catch (error$1) {1243 error("Language definition for '{}' could not be registered.".replace("{}", languageName));1244 if (!SAFE_MODE) { throw error$1; } else { error(error$1); }1245 lang = PLAINTEXT_LANGUAGE;1246 }1247 if (!lang.name) lang.name = languageName;1248 languages[languageName] = lang;1249 lang.rawDefinition = languageDefinition.bind(null, hljs);1250 if (lang.aliases) {1251 registerAliases(lang.aliases, { languageName });1252 }1253 }1254 function unregisterLanguage(languageName) {1255 delete languages[languageName];1256 for (const alias of Object.keys(aliases)) {1257 if (aliases[alias] === languageName) {1258 delete aliases[alias];1259 }1260 }1261 }1262 function listLanguages() {1263 return Object.keys(languages);1264 }1265 function getLanguage(name) {1266 name = (name || '').toLowerCase();1267 return languages[name] || languages[aliases[name]];1268 }1269 function registerAliases(aliasList, { languageName }) {1270 if (typeof aliasList === 'string') {1271 aliasList = [aliasList];1272 }1273 aliasList.forEach(alias => { aliases[alias.toLowerCase()] = languageName; });1274 }1275 function autoDetection(name) {1276 const lang = getLanguage(name);1277 return lang && !lang.disableAutodetect;1278 }1279 function fire(event, args) {1280 const cb = event;1281 plugins.forEach(function(plugin) {1282 if (plugin[cb]) {1283 plugin[cb](args);1284 }1285 });1286 }1287 Object.assign(hljs, {1288 highlight,1289 inherit,1290 registerLanguage,1291 getLanguage1292 });1293 for (const key in MODES) {1294 if (typeof MODES[key] === "object") {1295 deepFreeze(MODES[key]);1296 }1297 }1298 Object.assign(hljs, MODES);1299 return hljs;1300};...

Full Screen

Full Screen

mode_compiler.js

Source:mode_compiler.js Github

copy

Full Screen

...220 * special _internal_ 'on:begin' callback for modes with `beginKeywords`221 * @param {RegExpMatchArray} match222 * @param {CallbackResponse} response223 */224 function skipIfhasPrecedingDot(match, response) {225 const before = match.input[match.index - 1];226 if (before === ".") {227 response.ignoreMatch();228 }229 }230 /** skip vs abort vs ignore231 *232 * @skip - The mode is still entered and exited normally (and contains rules apply),233 * but all content is held and added to the parent buffer rather than being234 * output when the mode ends. Mostly used with `sublanguage` to build up235 * a single large buffer than can be parsed by sublanguage.236 *237 * - The mode begin ands ends normally.238 * - Content matched is added to the parent mode buffer....

Full Screen

Full Screen

compiler_extensions.js

Source:compiler_extensions.js Github

copy

Full Screen

...18 * special _internal_ 'on:begin' callback for modes with `beginKeywords`19 * @param {RegExpMatchArray} match20 * @param {CallbackResponse} response21 */22function skipIfhasPrecedingDot(match, response) {23 const before = match.input[match.index - 1];24 if (before === ".") {25 response.ignoreMatch();26 }27}28/**29 * `beginKeywords` syntactic sugar30 * @type {CompilerExt}31 */32export function beginKeywords(mode, parent) {33 if (!parent) return;34 if (!mode.beginKeywords) return;35 // for languages with keywords that include non-word characters checking for36 // a word boundary is not sufficient, so instead we check for a word boundary...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1const {chromium} = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 const frame = page.mainFrame();7 const element = await frame.$('button');8 console.log(await element.evaluate(element => element.skipIfhasPrecedingDot()));9 await browser.close();10})();

Full Screen

Using AI Code Generation

copy

Full Screen

1const { skipIfhasPrecedingDot } = require('playwright/lib/internal/utils');2const { skipIfhasPrecedingDot } = require('playwright/lib/internal/utils');3const { skipIfhasPrecedingDot } = require('playwright/lib/internal/utils');4const { skipIfhasPrecedingDot } = require('playwright/lib/internal/utils');5const { skipIfhasPrecedingDot } = require('playwright/lib/internal/utils');6const { skipIfhasPrecedingDot } = require('playwright/lib/internal/utils');7const { skipIfhasPrecedingDot } = require('playwright/lib/internal/utils');8const { skipIfhasPrecedingDot } = require('playwright/lib/internal/utils');9const { skipIfhasPrecedingDot } = require('playwright/lib/internal/utils');10const { skipIfhasPrecedingDot } = require('playwright/lib/internal/utils');11const { skipIfhasPrecedingDot } = require('playwright/lib/internal/utils');12const { skipIfhasPrecedingDot } = require('playwright/lib/internal/utils');13const { skipIfhasPrecedingDot } = require('playwright/lib/internal/utils');14const { skipIfhasPrecedingDot } = require('playwright/lib

Full Screen

Using AI Code Generation

copy

Full Screen

1const { skipIfhasPrecedingDot } = require('@playwright/test');2const { test, expect } = require('@playwright/test');3test('should pass', async ({ page }) => {4 expect(await skipIfhasPrecedingDot(page, '.test')).toBe(true);5});6test('should fail', async ({ page }) => {7 expect(await skipIfhasPrecedingDot(page, 'test')).toBe(true);8});

Full Screen

Using AI Code Generation

copy

Full Screen

1const { test, expect } = require('@playwright/test');2test('test', async ({ page }) => {3 const skipIfhasPrecedingDot = page._delegate.skipIfhasPrecedingDot;4 expect(skipIfhasPrecedingDot('.test')).toBe(true);5 expect(skipIfhasPrecedingDot('test')).toBe(false);6});

Full Screen

Using AI Code Generation

copy

Full Screen

1const { skipIfhasPrecedingDot } = require('playwright/lib/utils/utils');2const { expect } = require('chai');3describe('test', () => {4 it('test', () => {5 expect(skipIfhasPrecedingDot('.someClass')).to.be.true;6 expect(skipIfhasPrecedingDot('someClass')).to.be.false;7 });8});9 1 passing (5ms)

Full Screen

Using AI Code Generation

copy

Full Screen

1const { skipIfhasPrecedingDot } = require('@playwright/test/lib/utils/pathUtils');2skipIfhasPrecedingDot('test.js')3const { skipIfhasPrecedingDot } = require('@playwright/test/lib/utils/pathUtils');4skipIfhasPrecedingDot('.\test.js')5const { skipIfhasPrecedingDot } = require('@playwright/test/lib/utils/pathUtils');6skipIfhasPrecedingDot('.\test')7const { skipIfhasPrecedingDot } = require('@playwright/test/lib/utils/pathUtils');8skipIfhasPrecedingDot('test')9const { skipIfhasPrecedingDot } = require('@playwright/test/lib/utils/pathUtils');10skipIfhasPrecedingDot('test')11const { skipIfhasPrecedingDot } = require('@playwright/test/lib/utils/pathUtils');12skipIfhasPrecedingDot('test')13const { skipIfhasPrecedingDot } = require('@playwright/test/lib/utils/pathUtils');14skipIfhasPrecedingDot('test')15const { skipIfhasPrecedingDot } = require('@playwright/test/lib/utils/pathUtils');16skipIfhasPrecedingDot('test')17const { skipIfhasPrecedingDot } = require('@playwright/test/lib/utils/pathUtils');18skipIfhasPrecedingDot('test')19const {

Full Screen

Using AI Code Generation

copy

Full Screen

1const { skipIfhasPrecedingDot } = require('playwright/lib/server/supplements/recorder/recorderSupplement');2const { skipIfhasPrecedingDot } = require('playwright/lib/server/supplements/recorder/recorderSupplement');3const { skipIfhasPrecedingDot } = require('playwright/lib/server/supplements/recorder/recorderSupplement');4const { skipIfhasPrecedingDot } = require('playwright/lib/server/supplements/recorder/recorderSupplement');5const { skipIfhasPrecedingDot } = require('playwright/lib/server/supplements/recorder/recorderSupplement');6const { skipIfhasPrecedingDot } = require('playwright/lib/server/supplements/recorder/recorderSupplement');7const { skipIfhas

Full Screen

Using AI Code Generation

copy

Full Screen

1const { test, expect } = require('@playwright/test');2const { skipIfhasPrecedingDot } = require('@playwright/test/lib/runner/params');3test('Playwright Internal API', async ({page}) => {4 const skip = skipIfhasPrecedingDot('test');5 if (skip) {6 return skip;7 }8 expect(await page.textContent('.navbar__inner')).toContain('Docs');9});

Full Screen

Using AI Code Generation

copy

Full Screen

1const { skipIfhasPrecedingDot } = require('playwright/lib/utils/utils');2const result = skipIfhasPrecedingDot('test.js');3console.log(result);4browser.newContext()5browser.newIncognitoBrowserContext()6browser.newBrowserCDPSession()7browser.newBrowserContext()8const context = await browser.newContext({9});10const context = await browser.newContext({11 viewport: {12 }13});

Full Screen

Using AI Code Generation

copy

Full Screen

1const {test, expect} = require('@playwright/test');2test('should not throw error when using skipIfhasPrecedingDot method of Playwright Internal API', async ({ page }) => {3 await page.waitForSelector('text=Get started');4 await page.click('text=Get started');5});6test.js:10:5 › [chromium] should not throw error when using skipIfhasPrecedingDot method of Playwright Internal API (1s)7✓ should not throw error when using skipIfhasPrecedingDot method of Playwright Internal API (1s)81 test passed (1s)

Full Screen

Playwright tutorial

LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.

Chapters:

  1. What is Playwright : Playwright is comparatively new but has gained good popularity. Get to know some history of the Playwright with some interesting facts connected with it.
  2. How To Install Playwright : Learn in detail about what basic configuration and dependencies are required for installing Playwright and run a test. Get a step-by-step direction for installing the Playwright automation framework.
  3. Playwright Futuristic Features: Launched in 2020, Playwright gained huge popularity quickly because of some obliging features such as Playwright Test Generator and Inspector, Playwright Reporter, Playwright auto-waiting mechanism and etc. Read up on those features to master Playwright testing.
  4. What is Component Testing: Component testing in Playwright is a unique feature that allows a tester to test a single component of a web application without integrating them with other elements. Learn how to perform Component testing on the Playwright automation framework.
  5. Inputs And Buttons In Playwright: Every website has Input boxes and buttons; learn about testing inputs and buttons with different scenarios and examples.
  6. Functions and Selectors in Playwright: Learn how to launch the Chromium browser with Playwright. Also, gain a better understanding of some important functions like “BrowserContext,” which allows you to run multiple browser sessions, and “newPage” which interacts with a page.
  7. Handling Alerts and Dropdowns in Playwright : Playwright interact with different types of alerts and pop-ups, such as simple, confirmation, and prompt, and different types of dropdowns, such as single selector and multi-selector get your hands-on with handling alerts and dropdown in Playright testing.
  8. Playwright vs Puppeteer: Get to know about the difference between two testing frameworks and how they are different than one another, which browsers they support, and what features they provide.
  9. Run Playwright Tests on LambdaTest: Playwright testing with LambdaTest leverages test performance to the utmost. You can run multiple Playwright tests in Parallel with the LammbdaTest test cloud. Get a step-by-step guide to run your Playwright test on the LambdaTest platform.
  10. Playwright Python Tutorial: Playwright automation framework support all major languages such as Python, JavaScript, TypeScript, .NET and etc. However, there are various advantages to Python end-to-end testing with Playwright because of its versatile utility. Get the hang of Playwright python testing with this chapter.
  11. Playwright End To End Testing Tutorial: Get your hands on with Playwright end-to-end testing and learn to use some exciting features such as TraceViewer, Debugging, Networking, Component testing, Visual testing, and many more.
  12. Playwright Video Tutorial: Watch the video tutorials on Playwright testing from experts and get a consecutive in-depth explanation of Playwright automation testing.

Run Playwright Internal automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful