From e3969ef4ed874458f4b66d4631f78fff7717012c Mon Sep 17 00:00:00 2001 From: David Anson Date: Sat, 13 Aug 2022 17:38:04 -0700 Subject: [PATCH] Regenerate index.js after dependency updates. --- dist/index.js | 26384 ++++++++++++++++++++++++++---------------------- 1 file changed, 14336 insertions(+), 12048 deletions(-) diff --git a/dist/index.js b/dist/index.js index dca01d5..5a5ec5c 100644 --- a/dist/index.js +++ b/dist/index.js @@ -140,6 +140,7 @@ const file_command_1 = __nccwpck_require__(717); const utils_1 = __nccwpck_require__(5278); const os = __importStar(__nccwpck_require__(2037)); const path = __importStar(__nccwpck_require__(1017)); +const uuid_1 = __nccwpck_require__(5840); const oidc_utils_1 = __nccwpck_require__(8041); /** * The code to exit an action @@ -169,7 +170,14 @@ function exportVariable(name, val) { process.env[name] = convertedVal; const filePath = process.env['GITHUB_ENV'] || ''; if (filePath) { - const delimiter = '_GitHubActionsFileCommandDelimeter_'; + const delimiter = `ghadelimiter_${uuid_1.v4()}`; + // These should realistically never happen, but just in case someone finds a way to exploit uuid generation let's not allow keys or values that contain the delimiter. + if (name.includes(delimiter)) { + throw new Error(`Unexpected input: name should not contain the delimiter "${delimiter}"`); + } + if (convertedVal.includes(delimiter)) { + throw new Error(`Unexpected input: value should not contain the delimiter "${delimiter}"`); + } const commandValue = `${name}<<${delimiter}${os.EOL}${convertedVal}${os.EOL}${delimiter}`; file_command_1.issueCommand('ENV', commandValue); } @@ -6582,8 +6590,9 @@ function compile(self) { .map(escapeRE) .join('|'); // (?!_) cause 1.5x slowdown - self.re.schema_test = RegExp('(^|(?!_)(?:[><\uff5c]|' + re.src_ZPCc + '))(' + slist + ')', 'i'); - self.re.schema_search = RegExp('(^|(?!_)(?:[><\uff5c]|' + re.src_ZPCc + '))(' + slist + ')', 'ig'); + self.re.schema_test = RegExp('(^|(?!_)(?:[><\uff5c]|' + re.src_ZPCc + '))(' + slist + ')', 'i'); + self.re.schema_search = RegExp('(^|(?!_)(?:[><\uff5c]|' + re.src_ZPCc + '))(' + slist + ')', 'ig'); + self.re.schema_at_start = RegExp('^' + self.re.schema_search.source, 'i'); self.re.pretest = RegExp( '(' + self.re.schema_test.source + ')|(' + self.re.host_fuzzy_test.source + ')|@', @@ -6898,6 +6907,33 @@ LinkifyIt.prototype.match = function match(text) { }; +/** + * LinkifyIt#matchAtStart(text) -> Match|null + * + * Returns fully-formed (not fuzzy) link if it starts at the beginning + * of the string, and null otherwise. + **/ +LinkifyIt.prototype.matchAtStart = function matchAtStart(text) { + // Reset scan cache + this.__text_cache__ = text; + this.__index__ = -1; + + if (!text.length) return null; + + var m = this.re.schema_at_start.exec(text); + if (!m) return null; + + var len = this.testSchemaAt(text, m[2], m[0].length); + if (!len) return null; + + this.__schema__ = m[2]; + this.__index__ = m.index + m[1].length; + this.__last_index__ = m.index + m[0].length + len; + + return createMatch(this, 0); +}; + + /** chainable * LinkifyIt#tlds(list [, keepOld]) -> this * - list (Array): list of tlds @@ -6975,6 +7011,7 @@ module.exports = LinkifyIt; module.exports = function (opts) { var re = {}; + opts = opts || {}; // Use direct extract instead of `regenerate` to reduse browserified size re.src_Any = (__nccwpck_require__(703).source); @@ -7014,7 +7051,8 @@ module.exports = function (opts) { re.src_host_terminator = - '(?=$|' + text_separators + '|' + re.src_ZPCc + ')(?!-|_|:\\d|\\.-|\\.(?!$|' + re.src_ZPCc + '))'; + '(?=$|' + text_separators + '|' + re.src_ZPCc + ')' + + '(?!' + (opts['---'] ? '-(?!--)|' : '-|') + '_|:\\d|\\.-|\\.(?!$|' + re.src_ZPCc + '))'; re.src_path = @@ -7027,7 +7065,7 @@ module.exports = function (opts) { '\\{(?:(?!' + re.src_ZCc + '|[}]).)*\\}|' + '\\"(?:(?!' + re.src_ZCc + '|["]).)+\\"|' + "\\'(?:(?!" + re.src_ZCc + "|[']).)+\\'|" + - "\\'(?=" + re.src_pseudo_letter + '|[-]).|' + // allow `I'm_king` if no pair found + "\\'(?=" + re.src_pseudo_letter + '|[-])|' + // allow `I'm_king` if no pair found '\\.{2,}[a-zA-Z0-9%/&]|' + // google has many dots in "google search" links (#66, #81). // github has ... in commit range links, // Restrict to @@ -7036,16 +7074,16 @@ module.exports = function (opts) { // - parts of file path // - params separator // until more examples found. - '\\.(?!' + re.src_ZCc + '|[.]).|' + - (opts && opts['---'] ? + '\\.(?!' + re.src_ZCc + '|[.]|$)|' + + (opts['---'] ? '\\-(?!--(?:[^-]|$))(?:-*)|' // `---` => long dash, terminate : '\\-+|' ) + - ',(?!' + re.src_ZCc + ').|' + // allow `,,,` in paths - ';(?!' + re.src_ZCc + ').|' + // allow `;` if not followed by space-like char - '\\!+(?!' + re.src_ZCc + '|[!]).|' + // allow `!!!` in paths, but not at the end - '\\?(?!' + re.src_ZCc + '|[?]).' + + ',(?!' + re.src_ZCc + '|$)|' + // allow `,,,` in paths + ';(?!' + re.src_ZCc + '|$)|' + // allow `;` if not followed by space-like char + '\\!+(?!' + re.src_ZCc + '|[!]|$)|' + // allow `!!!` in paths, but not at the end + '\\?(?!' + re.src_ZCc + '|[?]|$)' + ')+' + '|\\/' + ')?'; @@ -8586,7 +8624,10 @@ var _rules = [ [ 'inline', __nccwpck_require__(1951) ], [ 'linkify', __nccwpck_require__(5462) ], [ 'replacements', __nccwpck_require__(8373) ], - [ 'smartquotes', __nccwpck_require__(2178) ] + [ 'smartquotes', __nccwpck_require__(2178) ], + // `text_join` finds `text_special` tokens (for escape sequences) + // and joins them with the rest of the text + [ 'text_join', __nccwpck_require__(7502) ] ]; @@ -8650,6 +8691,7 @@ var Ruler = __nccwpck_require__(2093); var _rules = [ [ 'text', __nccwpck_require__(1117) ], + [ 'linkify', __nccwpck_require__(1783) ], [ 'newline', __nccwpck_require__(8774) ], [ 'escape', __nccwpck_require__(1836) ], [ 'backticks', __nccwpck_require__(8520) ], @@ -8662,11 +8704,18 @@ var _rules = [ [ 'entity', __nccwpck_require__(973) ] ]; +// `rule2` ruleset was created specifically for emphasis/strikethrough +// post-processing and may be changed in the future. +// +// Don't use this for anything except pairs (plugins working with `balance_pairs`). +// var _rules2 = [ [ 'balance_pairs', __nccwpck_require__(9418) ], [ 'strikethrough', (__nccwpck_require__(3015)/* .postProcess */ .g) ], [ 'emphasis', (__nccwpck_require__(1677)/* .postProcess */ .g) ], - [ 'text_collapse', __nccwpck_require__(2333) ] + // rules for pairs separate '**' into its own text tokens, which may be left unused, + // rule below merges unused segments back with the rest of the text + [ 'fragments_join', __nccwpck_require__(3807) ] ]; @@ -8859,7 +8908,8 @@ module.exports = { rules: [ 'normalize', 'block', - 'inline' + 'inline', + 'text_join' ] }, @@ -8894,7 +8944,7 @@ module.exports = { rules2: [ 'balance_pairs', 'emphasis', - 'text_collapse' + 'fragments_join' ] } } @@ -8997,7 +9047,8 @@ module.exports = { rules: [ 'normalize', 'block', - 'inline' + 'inline', + 'text_join' ] }, @@ -9013,7 +9064,7 @@ module.exports = { ], rules2: [ 'balance_pairs', - 'text_collapse' + 'fragments_join' ] } } @@ -11352,7 +11403,7 @@ function getLine(state, line) { var pos = state.bMarks[line] + state.tShift[line], max = state.eMarks[line]; - return state.src.substr(pos, max - pos); + return state.src.slice(pos, max); } function escapedSplit(str) { @@ -11686,8 +11737,17 @@ module.exports = function linkify(state) { level = currentToken.level; lastPos = 0; - for (ln = 0; ln < links.length; ln++) { + // forbid escape sequence at the start of the string, + // this avoids http\://example.com/ from being linkified as + // http://example.com/ + if (links.length > 0 && + links[0].index === 0 && + i > 0 && + tokens[i - 1].type === 'text_special') { + links = links.slice(1); + } + for (ln = 0; ln < links.length; ln++) { url = links[ln].url; fullUrl = state.md.normalizeLink(url); if (!state.md.validateLink(fullUrl)) { continue; } @@ -11800,19 +11860,18 @@ module.exports = function normalize(state) { // TODO: // - fractionals 1/2, 1/4, 3/4 -> ½, ¼, ¾ -// - miltiplication 2 x 4 -> 2 × 4 +// - multiplications 2 x 4 -> 2 × 4 var RARE_RE = /\+-|\.\.|\?\?\?\?|!!!!|,,|--/; // Workaround for phantomjs - need regex without /g flag, // or root check will fail every second time -var SCOPED_ABBR_TEST_RE = /\((c|tm|r|p)\)/i; +var SCOPED_ABBR_TEST_RE = /\((c|tm|r)\)/i; -var SCOPED_ABBR_RE = /\((c|tm|r|p)\)/ig; +var SCOPED_ABBR_RE = /\((c|tm|r)\)/ig; var SCOPED_ABBR = { c: '©', r: '®', - p: '§', tm: '™' }; @@ -11915,7 +11974,7 @@ var APOSTROPHE = '\u2019'; /* ’ */ function replaceAt(str, index, ch) { - return str.substr(0, index) + ch + str.substr(index + 1); + return str.slice(0, index) + ch + str.slice(index + 1); } function process_inlines(tokens, state) { @@ -12131,6 +12190,59 @@ StateCore.prototype.Token = Token; module.exports = StateCore; +/***/ }), + +/***/ 7502: +/***/ ((module) => { + +"use strict"; +// Join raw text tokens with the rest of the text +// +// This is set as a separate rule to provide an opportunity for plugins +// to run text replacements after text join, but before escape join. +// +// For example, `\:)` shouldn't be replaced with an emoji. +// + + + +module.exports = function text_join(state) { + var j, l, tokens, curr, max, last, + blockTokens = state.tokens; + + for (j = 0, l = blockTokens.length; j < l; j++) { + if (blockTokens[j].type !== 'inline') continue; + + tokens = blockTokens[j].children; + max = tokens.length; + + for (curr = 0; curr < max; curr++) { + if (tokens[curr].type === 'text_special') { + tokens[curr].type = 'text'; + } + } + + for (curr = last = 0; curr < max; curr++) { + if (tokens[curr].type === 'text' && + curr + 1 < max && + tokens[curr + 1].type === 'text') { + + // collapse two adjacent text nodes + tokens[curr + 1].content = tokens[curr].content + tokens[curr + 1].content; + } else { + if (curr !== last) { tokens[last] = tokens[curr]; } + + last++; + } + } + + if (curr !== last) { + tokens.length = last; + } + } +}; + + /***/ }), /***/ 3939: @@ -12583,38 +12695,45 @@ var NAMED_RE = /^&([a-z][a-z0-9]{1,31});/i; module.exports = function entity(state, silent) { - var ch, code, match, pos = state.pos, max = state.posMax; + var ch, code, match, token, pos = state.pos, max = state.posMax; - if (state.src.charCodeAt(pos) !== 0x26/* & */) { return false; } + if (state.src.charCodeAt(pos) !== 0x26/* & */) return false; - if (pos + 1 < max) { - ch = state.src.charCodeAt(pos + 1); + if (pos + 1 >= max) return false; - if (ch === 0x23 /* # */) { - match = state.src.slice(pos).match(DIGITAL_RE); - if (match) { + ch = state.src.charCodeAt(pos + 1); + + if (ch === 0x23 /* # */) { + match = state.src.slice(pos).match(DIGITAL_RE); + if (match) { + if (!silent) { + code = match[1][0].toLowerCase() === 'x' ? parseInt(match[1].slice(1), 16) : parseInt(match[1], 10); + + token = state.push('text_special', '', 0); + token.content = isValidEntityCode(code) ? fromCodePoint(code) : fromCodePoint(0xFFFD); + token.markup = match[0]; + token.info = 'entity'; + } + state.pos += match[0].length; + return true; + } + } else { + match = state.src.slice(pos).match(NAMED_RE); + if (match) { + if (has(entities, match[1])) { if (!silent) { - code = match[1][0].toLowerCase() === 'x' ? parseInt(match[1].slice(1), 16) : parseInt(match[1], 10); - state.pending += isValidEntityCode(code) ? fromCodePoint(code) : fromCodePoint(0xFFFD); + token = state.push('text_special', '', 0); + token.content = entities[match[1]]; + token.markup = match[0]; + token.info = 'entity'; } state.pos += match[0].length; return true; } - } else { - match = state.src.slice(pos).match(NAMED_RE); - if (match) { - if (has(entities, match[1])) { - if (!silent) { state.pending += entities[match[1]]; } - state.pos += match[0].length; - return true; - } - } } } - if (!silent) { state.pending += '&'; } - state.pos++; - return true; + return false; }; @@ -12639,45 +12758,113 @@ for (var i = 0; i < 256; i++) { ESCAPED.push(0); } module.exports = function escape(state, silent) { - var ch, pos = state.pos, max = state.posMax; - - if (state.src.charCodeAt(pos) !== 0x5C/* \ */) { return false; } + var ch1, ch2, origStr, escapedStr, token, pos = state.pos, max = state.posMax; + if (state.src.charCodeAt(pos) !== 0x5C/* \ */) return false; pos++; - if (pos < max) { - ch = state.src.charCodeAt(pos); + // '\' at the end of the inline block + if (pos >= max) return false; - if (ch < 256 && ESCAPED[ch] !== 0) { - if (!silent) { state.pending += state.src[pos]; } - state.pos += 2; - return true; + ch1 = state.src.charCodeAt(pos); + + if (ch1 === 0x0A) { + if (!silent) { + state.push('hardbreak', 'br', 0); } - if (ch === 0x0A) { - if (!silent) { - state.push('hardbreak', 'br', 0); - } - + pos++; + // skip leading whitespaces from next line + while (pos < max) { + ch1 = state.src.charCodeAt(pos); + if (!isSpace(ch1)) break; pos++; - // skip leading whitespaces from next line - while (pos < max) { - ch = state.src.charCodeAt(pos); - if (!isSpace(ch)) { break; } - pos++; - } + } - state.pos = pos; - return true; + state.pos = pos; + return true; + } + + escapedStr = state.src[pos]; + + if (ch1 >= 0xD800 && ch1 <= 0xDBFF && pos + 1 < max) { + ch2 = state.src.charCodeAt(pos + 1); + + if (ch2 >= 0xDC00 && ch2 <= 0xDFFF) { + escapedStr += state.src[pos + 1]; + pos++; } } - if (!silent) { state.pending += '\\'; } - state.pos++; + origStr = '\\' + escapedStr; + + if (!silent) { + token = state.push('text_special', '', 0); + + if (ch1 < 256 && ESCAPED[ch1] !== 0) { + token.content = escapedStr; + } else { + token.content = origStr; + } + + token.markup = origStr; + token.info = 'escape'; + } + + state.pos = pos + 1; return true; }; +/***/ }), + +/***/ 3807: +/***/ ((module) => { + +"use strict"; +// Clean up tokens after emphasis and strikethrough postprocessing: +// merge adjacent text nodes into one and re-calculate all token levels +// +// This is necessary because initially emphasis delimiter markers (*, _, ~) +// are treated as their own separate text tokens. Then emphasis rule either +// leaves them as text (needed to merge with adjacent text) or turns them +// into opening/closing tags (which messes up levels inside). +// + + + +module.exports = function fragments_join(state) { + var curr, last, + level = 0, + tokens = state.tokens, + max = state.tokens.length; + + for (curr = last = 0; curr < max; curr++) { + // re-calculate levels after emphasis/strikethrough turns some text nodes + // into opening/closing tags + if (tokens[curr].nesting < 0) level--; // closing tag + tokens[curr].level = level; + if (tokens[curr].nesting > 0) level++; // opening tag + + if (tokens[curr].type === 'text' && + curr + 1 < max && + tokens[curr + 1].type === 'text') { + + // collapse two adjacent text nodes + tokens[curr + 1].content = tokens[curr].content + tokens[curr + 1].content; + } else { + if (curr !== last) { tokens[last] = tokens[curr]; } + + last++; + } + } + + if (curr !== last) { + tokens.length = last; + } +}; + + /***/ }), /***/ 7753: @@ -12692,6 +12879,14 @@ module.exports = function escape(state, silent) { var HTML_TAG_RE = (__nccwpck_require__(6537)/* .HTML_TAG_RE */ .n); +function isLinkOpen(str) { + return /^\s]/i.test(str); +} +function isLinkClose(str) { + return /^<\/a\s*>/i.test(str); +} + + function isLetter(ch) { /*eslint no-bitwise:0*/ var lc = ch | 0x20; // to lower case @@ -12727,6 +12922,9 @@ module.exports = function html_inline(state, silent) { if (!silent) { token = state.push('html_inline', '', 0); token.content = state.src.slice(pos, pos + match[0].length); + + if (isLinkOpen(token.content)) state.linkLevel++; + if (isLinkClose(token.content)) state.linkLevel--; } state.pos += match[0].length; return true; @@ -13038,7 +13236,9 @@ module.exports = function link(state, silent) { attrs.push([ 'title', title ]); } + state.linkLevel++; state.md.inline.tokenize(state); + state.linkLevel--; token = state.push('link_close', 'a', -1); } @@ -13049,6 +13249,72 @@ module.exports = function link(state, silent) { }; +/***/ }), + +/***/ 1783: +/***/ ((module) => { + +"use strict"; +// Process links like https://example.org/ + + + + +// RFC3986: scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) +var SCHEME_RE = /(?:^|[^a-z0-9.+-])([a-z][a-z0-9.+-]*)$/i; + + +module.exports = function linkify(state, silent) { + var pos, max, match, proto, link, url, fullUrl, token; + + if (!state.md.options.linkify) return false; + if (state.linkLevel > 0) return false; + + pos = state.pos; + max = state.posMax; + + if (pos + 3 > max) return false; + if (state.src.charCodeAt(pos) !== 0x3A/* : */) return false; + if (state.src.charCodeAt(pos + 1) !== 0x2F/* / */) return false; + if (state.src.charCodeAt(pos + 2) !== 0x2F/* / */) return false; + + match = state.pending.match(SCHEME_RE); + if (!match) return false; + + proto = match[1]; + + link = state.md.linkify.matchAtStart(state.src.slice(pos - proto.length)); + if (!link) return false; + + url = link.url; + + // disallow '*' at the end of the link (conflicts with emphasis) + url = url.replace(/\*+$/, ''); + + fullUrl = state.md.normalizeLink(url); + if (!state.md.validateLink(fullUrl)) return false; + + if (!silent) { + state.pending = state.pending.slice(0, -proto.length); + + token = state.push('link_open', 'a', 1); + token.attrs = [ [ 'href', fullUrl ] ]; + token.markup = 'linkify'; + token.info = 'auto'; + + token = state.push('text', '', 0); + token.content = state.md.normalizeLinkText(url); + + token = state.push('link_close', 'a', -1); + token.markup = 'linkify'; + token.info = 'auto'; + } + + state.pos += url.length - proto.length; + return true; +}; + + /***/ }), /***/ 8774: @@ -13146,6 +13412,10 @@ function StateInline(src, md, env, outTokens) { // backtick length => last seen position this.backticks = {}; this.backticksScanned = false; + + // Counter used to disable inline linkify-it execution + // inside and markdown links + this.linkLevel = 0; } @@ -13500,55 +13770,6 @@ module.exports = function text(state, silent) { };*/ -/***/ }), - -/***/ 2333: -/***/ ((module) => { - -"use strict"; -// Clean up tokens after emphasis and strikethrough postprocessing: -// merge adjacent text nodes into one and re-calculate all token levels -// -// This is necessary because initially emphasis delimiter markers (*, _, ~) -// are treated as their own separate text tokens. Then emphasis rule either -// leaves them as text (needed to merge with adjacent text) or turns them -// into opening/closing tags (which messes up levels inside). -// - - - -module.exports = function text_collapse(state) { - var curr, last, - level = 0, - tokens = state.tokens, - max = state.tokens.length; - - for (curr = last = 0; curr < max; curr++) { - // re-calculate levels after emphasis/strikethrough turns some text nodes - // into opening/closing tags - if (tokens[curr].nesting < 0) level--; // closing tag - tokens[curr].level = level; - if (tokens[curr].nesting > 0) level++; // opening tag - - if (tokens[curr].type === 'text' && - curr + 1 < max && - tokens[curr + 1].type === 'text') { - - // collapse two adjacent text nodes - tokens[curr + 1].content = tokens[curr].content + tokens[curr + 1].content; - } else { - if (curr !== last) { tokens[last] = tokens[curr]; } - - last++; - } - } - - if (curr !== last) { - tokens.length = last; - } -}; - - /***/ }), /***/ 8622: @@ -13790,915 +14011,10 @@ const outputFormatter = (options) => { module.exports = outputFormatter; -/***/ }), - -/***/ 2870: -/***/ ((module) => { - -"use strict"; -// @ts-check - - - -// Regular expression for matching common newline characters -// See NEWLINES_RE in markdown-it/lib/rules_core/normalize.js -const newLineRe = /\r\n?|\n/g; -module.exports.newLineRe = newLineRe; - -// Regular expression for matching common front matter (YAML and TOML) -module.exports.frontMatterRe = - // eslint-disable-next-line max-len - /((^---\s*$[^]*?^---\s*$)|(^\+\+\+\s*$[^]*?^(\+\+\+|\.\.\.)\s*$)|(^\{\s*$[^]*?^\}\s*$))(\r\n|\r|\n|$)/m; - -// Regular expression for matching inline disable/enable comments -const inlineCommentRe = - // eslint-disable-next-line max-len - //ig; -module.exports.inlineCommentRe = inlineCommentRe; - -// Regular expressions for range matching -module.exports.bareUrlRe = /(?:http|ftp)s?:\/\/[^\s\]"']*(?:\/|[^\s\]"'\W])/ig; -module.exports.listItemMarkerRe = /^([\s>]*)(?:[*+-]|\d+[.)])\s+/; -module.exports.orderedListItemMarkerRe = /^[\s>]*0*(\d+)[.)]/; - -// Regular expression for all instances of emphasis markers -const emphasisMarkersRe = /[_*]/g; - -// Regular expression for inline links and shortcut reference links -const linkRe = /(\[(?:[^[\]]|\[[^\]]*\])*\])(\(\S*\)|\[\S*\])?/g; -module.exports.linkRe = linkRe; - -// Regular expression for link reference definition lines -module.exports.linkReferenceRe = /^ {0,3}\[[^\]]+]:\s.*$/; - -// All punctuation characters (normal and full-width) -const allPunctuation = ".,;:!?。,;:!?"; -module.exports.allPunctuation = allPunctuation; - -// All punctuation characters without question mark (normal and full-width) -module.exports.allPunctuationNoQuestion = allPunctuation.replace(/[??]/gu, ""); - -// Returns true iff the input is a number -module.exports.isNumber = function isNumber(obj) { - return typeof obj === "number"; -}; - -// Returns true iff the input is a string -module.exports.isString = function isString(obj) { - return typeof obj === "string"; -}; - -// Returns true iff the input string is empty -module.exports.isEmptyString = function isEmptyString(str) { - return str.length === 0; -}; - -// Returns true iff the input is an object -module.exports.isObject = function isObject(obj) { - return (obj !== null) && (typeof obj === "object") && !Array.isArray(obj); -}; - -// Returns true iff the input line is blank (no content) -// Example: Contains nothing, whitespace, or comment (unclosed start/end okay) -module.exports.isBlankLine = function isBlankLine(line) { - // Call to String.replace follows best practices and is not a security check - // False-positive for js/incomplete-multi-character-sanitization - return ( - !line || - !line.trim() || - !line - .replace(//g, "") - .replace(//g, "") - .replace(/>/g, "") - .trim() - ); -}; - -/** - * Compare function for Array.prototype.sort for ascending order of numbers. - * - * @param {number} a First number. - * @param {number} b Second number. - * @returns {number} Positive value if a>b, negative value if b> 1; - if (array[mid] < element) { - left = mid + 1; - } else if (array[mid] > element) { - right = mid - 1; - } else { - return true; - } - } - return false; -}; - -// Replaces the content of properly-formatted CommonMark comments with "." -// This preserves the line/column information for the rest of the document -// https://spec.commonmark.org/0.29/#html-blocks -// https://spec.commonmark.org/0.29/#html-comment -const htmlCommentBegin = ""; -module.exports.clearHtmlCommentText = function clearHtmlCommentText(text) { - let i = 0; - while ((i = text.indexOf(htmlCommentBegin, i)) !== -1) { - const j = text.indexOf(htmlCommentEnd, i + 2); - if (j === -1) { - // Un-terminated comments are treated as text - break; - } - // If the comment has content... - if (j > i + htmlCommentBegin.length) { - let k = i - 1; - while (text[k] === " ") { - k--; - } - // If comment is not within an indented code block... - if (k >= i - 4) { - const content = text.slice(i + htmlCommentBegin.length, j); - const isBlock = (k < 0) || (text[k] === "\n"); - const isValid = isBlock || - (!content.startsWith(">") && !content.startsWith("->") && - !content.endsWith("-") && !content.includes("--")); - // If a valid block/inline comment... - if (isValid) { - const inlineCommentIndex = text - .slice(i, j + htmlCommentEnd.length) - .search(inlineCommentRe); - // If not a markdownlint inline directive... - if (inlineCommentIndex === -1) { - text = - text.slice(0, i + htmlCommentBegin.length) + - content.replace(/[^\r\n]/g, ".") + - text.slice(j); - } - } - } - } - i = j + htmlCommentEnd.length; - } - return text; -}; - -// Escapes a string for use in a RegExp -module.exports.escapeForRegExp = function escapeForRegExp(str) { - return str.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&"); -}; - -// Un-escapes Markdown content (simple algorithm; not a parser) -const escapedMarkdownRe = /\\./g; -module.exports.unescapeMarkdown = - function unescapeMarkdown(markdown, replacement) { - return markdown.replace(escapedMarkdownRe, (match) => { - const char = match[1]; - if ("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~".includes(char)) { - return replacement || char; - } - return match; - }); - }; - -/** - * Return the string representation of a fence markup character. - * - * @param {string} markup Fence string. - * @returns {string} String representation. - */ -module.exports.fencedCodeBlockStyleFor = - function fencedCodeBlockStyleFor(markup) { - switch (markup[0]) { - case "~": - return "tilde"; - default: - return "backtick"; - } - }; - -/** - * Return the string representation of a emphasis or strong markup character. - * - * @param {string} markup Emphasis or strong string. - * @returns {string} String representation. - */ -module.exports.emphasisOrStrongStyleFor = - function emphasisOrStrongStyleFor(markup) { - switch (markup[0]) { - case "*": - return "asterisk"; - default: - return "underscore"; - } - }; - -/** - * Return the number of characters of indent for a token. - * - * @param {Object} token MarkdownItToken instance. - * @returns {number} Characters of indent. - */ -function indentFor(token) { - const line = token.line.replace(/^[\s>]*(> |>)/, ""); - return line.length - line.trimStart().length; -} -module.exports.indentFor = indentFor; - -// Returns the heading style for a heading token -module.exports.headingStyleFor = function headingStyleFor(token) { - if ((token.map[1] - token.map[0]) === 1) { - if (/[^\\]#\s*$/.test(token.line)) { - return "atx_closed"; - } - return "atx"; - } - return "setext"; -}; - -/** - * Return the string representation of an unordered list marker. - * - * @param {Object} token MarkdownItToken instance. - * @returns {string} String representation. - */ -module.exports.unorderedListStyleFor = function unorderedListStyleFor(token) { - switch (token.markup) { - case "-": - return "dash"; - case "+": - return "plus"; - // case "*": - default: - return "asterisk"; - } -}; - -/** - * Calls the provided function for each matching token. - * - * @param {Object} params RuleParams instance. - * @param {string} type Token type identifier. - * @param {Function} handler Callback function. - * @returns {void} - */ -function filterTokens(params, type, handler) { - params.tokens.forEach(function forToken(token) { - if (token.type === type) { - handler(token); - } - }); -} -module.exports.filterTokens = filterTokens; - -/** - * Returns whether a token is a math block (created by markdown-it-texmath). - * - * @param {Object} token MarkdownItToken instance. - * @returns {boolean} True iff token is a math block. - */ -function isMathBlock(token) { - return ( - ((token.tag === "$$") || (token.tag === "math")) && - token.type.startsWith("math_block") && - !token.type.endsWith("_end") - ); -} -module.exports.isMathBlock = isMathBlock; - -// Get line metadata array -module.exports.getLineMetadata = function getLineMetadata(params) { - const lineMetadata = params.lines.map( - (line, index) => [ line, index, false, 0, false, false, false, false ] - ); - filterTokens(params, "fence", (token) => { - lineMetadata[token.map[0]][3] = 1; - lineMetadata[token.map[1] - 1][3] = -1; - for (let i = token.map[0] + 1; i < token.map[1] - 1; i++) { - lineMetadata[i][2] = true; - } - }); - filterTokens(params, "code_block", (token) => { - for (let i = token.map[0]; i < token.map[1]; i++) { - lineMetadata[i][2] = true; - } - }); - filterTokens(params, "table_open", (token) => { - for (let i = token.map[0]; i < token.map[1]; i++) { - lineMetadata[i][4] = true; - } - }); - filterTokens(params, "list_item_open", (token) => { - let count = 1; - for (let i = token.map[0]; i < token.map[1]; i++) { - lineMetadata[i][5] = count; - count++; - } - }); - filterTokens(params, "hr", (token) => { - lineMetadata[token.map[0]][6] = true; - }); - params.tokens.filter(isMathBlock).forEach((token) => { - for (let i = token.map[0]; i < token.map[1]; i++) { - lineMetadata[i][7] = true; - } - }); - return lineMetadata; -}; - -/** - * Calls the provided function for each line. - * - * @param {Object} lineMetadata Line metadata object. - * @param {Function} handler Function taking (line, lineIndex, inCode, onFence, - * inTable, inItem, inBreak, inMath). - * @returns {void} - */ -function forEachLine(lineMetadata, handler) { - lineMetadata.forEach(function forMetadata(metadata) { - handler(...metadata); - }); -} -module.exports.forEachLine = forEachLine; - -// Returns (nested) lists as a flat array (in order) -module.exports.flattenLists = function flattenLists(tokens) { - const flattenedLists = []; - const stack = []; - let current = null; - let nesting = 0; - const nestingStack = []; - let lastWithMap = { "map": [ 0, 1 ] }; - tokens.forEach((token) => { - if ((token.type === "bullet_list_open") || - (token.type === "ordered_list_open")) { - // Save current context and start a new one - stack.push(current); - current = { - "unordered": (token.type === "bullet_list_open"), - "parentsUnordered": !current || - (current.unordered && current.parentsUnordered), - "open": token, - "indent": indentFor(token), - "parentIndent": (current && current.indent) || 0, - "items": [], - "nesting": nesting, - "lastLineIndex": -1, - "insert": flattenedLists.length - }; - nesting++; - } else if ((token.type === "bullet_list_close") || - (token.type === "ordered_list_close")) { - // Finalize current context and restore previous - current.lastLineIndex = lastWithMap.map[1]; - flattenedLists.splice(current.insert, 0, current); - delete current.insert; - current = stack.pop(); - nesting--; - } else if (token.type === "list_item_open") { - // Add list item - current.items.push(token); - } else if (token.type === "blockquote_open") { - nestingStack.push(nesting); - nesting = 0; - } else if (token.type === "blockquote_close") { - nesting = nestingStack.pop(); - } else if (token.map) { - // Track last token with map - lastWithMap = token; - } - }); - return flattenedLists; -}; - -// Calls the provided function for each specified inline child token -module.exports.forEachInlineChild = -function forEachInlineChild(params, type, handler) { - filterTokens(params, "inline", function forToken(token) { - token.children.forEach(function forChild(child) { - if (child.type === type) { - handler(child, token); - } - }); - }); -}; - -// Calls the provided function for each heading's content -module.exports.forEachHeading = function forEachHeading(params, handler) { - let heading = null; - params.tokens.forEach(function forToken(token) { - if (token.type === "heading_open") { - heading = token; - } else if (token.type === "heading_close") { - heading = null; - } else if ((token.type === "inline") && heading) { - handler(heading, token.content); - } - }); -}; - -/** - * Calls the provided function for each inline code span's content. - * - * @param {string} input Markdown content. - * @param {Function} handler Callback function taking (code, lineIndex, - * columnIndex, ticks). - * @returns {void} - */ -function forEachInlineCodeSpan(input, handler) { - let currentLine = 0; - let currentColumn = 0; - let index = 0; - while (index < input.length) { - let startIndex = -1; - let startLine = -1; - let startColumn = -1; - let tickCount = 0; - let currentTicks = 0; - let state = "normal"; - // Deliberate <= so trailing 0 completes the last span (ex: "text `code`") - // False-positive for js/index-out-of-bounds - for (; index <= input.length; index++) { - const char = input[index]; - // Ignore backticks in link destination - if ((char === "[") && (state === "normal")) { - state = "linkTextOpen"; - } else if ((char === "]") && (state === "linkTextOpen")) { - state = "linkTextClosed"; - } else if ((char === "(") && (state === "linkTextClosed")) { - state = "linkDestinationOpen"; - } else if ( - ((char === "(") && (state === "linkDestinationOpen")) || - ((char === ")") && (state === "linkDestinationOpen")) || - (state === "linkTextClosed")) { - state = "normal"; - } - // Parse backtick open/close - if ((char === "`") && (state !== "linkDestinationOpen")) { - // Count backticks at start or end of code span - currentTicks++; - if ((startIndex === -1) || (startColumn === -1)) { - startIndex = index + 1; - } - } else { - if ((startIndex >= 0) && - (startColumn >= 0) && - (tickCount === currentTicks)) { - // Found end backticks; invoke callback for code span - handler( - input.substring(startIndex, index - currentTicks), - startLine, startColumn, tickCount); - startIndex = -1; - startColumn = -1; - } else if ((startIndex >= 0) && (startColumn === -1)) { - // Found start backticks - tickCount = currentTicks; - startLine = currentLine; - startColumn = currentColumn; - } - // Not in backticks - currentTicks = 0; - } - if (char === "\n") { - // On next line - currentLine++; - currentColumn = 0; - } else if ((char === "\\") && - ((startIndex === -1) || (startColumn === -1)) && - (input[index + 1] !== "\n")) { - // Escape character outside code, skip next - index++; - currentColumn += 2; - } else { - // On next column - currentColumn++; - } - } - if (startIndex >= 0) { - // Restart loop after unmatched start backticks (ex: "`text``code``") - index = startIndex; - currentLine = startLine; - currentColumn = startColumn; - } - } -} -module.exports.forEachInlineCodeSpan = forEachInlineCodeSpan; - -/** - * Adds a generic error object via the onError callback. - * - * @param {Object} onError RuleOnError instance. - * @param {number} lineNumber Line number. - * @param {string} [detail] Error details. - * @param {string} [context] Error context. - * @param {number[]} [range] Column and length of error. - * @param {Object} [fixInfo] RuleOnErrorFixInfo instance. - * @returns {void} - */ -function addError(onError, lineNumber, detail, context, range, fixInfo) { - onError({ - lineNumber, - detail, - context, - range, - fixInfo - }); -} -module.exports.addError = addError; - -// Adds an error object with details conditionally via the onError callback -module.exports.addErrorDetailIf = function addErrorDetailIf( - onError, lineNumber, expected, actual, detail, context, range, fixInfo) { - if (expected !== actual) { - addError( - onError, - lineNumber, - "Expected: " + expected + "; Actual: " + actual + - (detail ? "; " + detail : ""), - context, - range, - fixInfo); - } -}; - -// Adds an error object with context via the onError callback -module.exports.addErrorContext = function addErrorContext( - onError, lineNumber, context, left, right, range, fixInfo) { - if (context.length <= 30) { - // Nothing to do - } else if (left && right) { - context = context.substr(0, 15) + "..." + context.substr(-15); - } else if (right) { - context = "..." + context.substr(-30); - } else { - context = context.substr(0, 30) + "..."; - } - addError(onError, lineNumber, null, context, range, fixInfo); -}; - -/** - * Returns an array of code block and span content ranges. - * - * @param {Object} params RuleParams instance. - * @param {Object} lineMetadata Line metadata object. - * @returns {number[][]} Array of ranges (lineIndex, columnIndex, length). - */ -module.exports.codeBlockAndSpanRanges = (params, lineMetadata) => { - const exclusions = []; - // Add code block ranges (excludes fences) - forEachLine(lineMetadata, (line, lineIndex, inCode, onFence) => { - if (inCode && !onFence) { - exclusions.push([ lineIndex, 0, line.length ]); - } - }); - // Add code span ranges (excludes ticks) - filterTokens(params, "inline", (token) => { - if (token.children.some((child) => child.type === "code_inline")) { - const tokenLines = params.lines.slice(token.map[0], token.map[1]); - forEachInlineCodeSpan( - tokenLines.join("\n"), - (code, lineIndex, columnIndex) => { - const codeLines = code.split(newLineRe); - for (const [ i, line ] of codeLines.entries()) { - exclusions.push([ - token.lineNumber - 1 + lineIndex + i, - i ? 0 : columnIndex, - line.length - ]); - } - } - ); - } - }); - return exclusions; -}; - -/** - * Determines whether the specified range overlaps another range. - * - * @param {number[][]} ranges Array of ranges (line, index, length). - * @param {number} lineIndex Line index to check. - * @param {number} index Index to check. - * @param {number} length Length to check. - * @returns {boolean} True iff the specified range overlaps. - */ -module.exports.overlapsAnyRange = (ranges, lineIndex, index, length) => ( - !ranges.every((span) => ( - (lineIndex !== span[0]) || - (index + length < span[1]) || - (index > span[1] + span[2]) - )) -); - -// Returns a range object for a line by applying a RegExp -module.exports.rangeFromRegExp = function rangeFromRegExp(line, regexp) { - let range = null; - const match = line.match(regexp); - if (match) { - const column = match.index + 1; - const length = match[0].length; - range = [ column, length ]; - } - return range; -}; - -// Determines if the front matter includes a title -module.exports.frontMatterHasTitle = - function frontMatterHasTitle(frontMatterLines, frontMatterTitlePattern) { - const ignoreFrontMatter = - (frontMatterTitlePattern !== undefined) && !frontMatterTitlePattern; - const frontMatterTitleRe = - new RegExp( - String(frontMatterTitlePattern || "^\\s*\"?title\"?\\s*[:=]"), - "i" - ); - return !ignoreFrontMatter && - frontMatterLines.some((line) => frontMatterTitleRe.test(line)); - }; - -/** - * Returns a list of emphasis markers in code spans and links. - * - * @param {Object} params RuleParams instance. - * @returns {number[][]} List of markers. - */ -function emphasisMarkersInContent(params) { - const { lines } = params; - const byLine = new Array(lines.length); - // Search links - lines.forEach((tokenLine, tokenLineIndex) => { - const inLine = []; - let linkMatch = null; - while ((linkMatch = linkRe.exec(tokenLine))) { - let markerMatch = null; - while ((markerMatch = emphasisMarkersRe.exec(linkMatch[0]))) { - inLine.push(linkMatch.index + markerMatch.index); - } - } - byLine[tokenLineIndex] = inLine; - }); - // Search code spans - filterTokens(params, "inline", (token) => { - const { children, lineNumber, map } = token; - if (children.some((child) => child.type === "code_inline")) { - const tokenLines = lines.slice(map[0], map[1]); - forEachInlineCodeSpan( - tokenLines.join("\n"), - (code, lineIndex, column, tickCount) => { - const codeLines = code.split(newLineRe); - codeLines.forEach((codeLine, codeLineIndex) => { - const byLineIndex = lineNumber - 1 + lineIndex + codeLineIndex; - const inLine = byLine[byLineIndex]; - const codeLineOffset = codeLineIndex ? 0 : column - 1 + tickCount; - let match = null; - while ((match = emphasisMarkersRe.exec(codeLine))) { - inLine.push(codeLineOffset + match.index); - } - byLine[byLineIndex] = inLine; - }); - } - ); - } - }); - return byLine; -} -module.exports.emphasisMarkersInContent = emphasisMarkersInContent; - -/** - * Gets the most common line ending, falling back to the platform default. - * - * @param {string} input Markdown content to analyze. - * @param {string} [platform] Platform identifier (process.platform). - * @returns {string} Preferred line ending. - */ -function getPreferredLineEnding(input, platform) { - let cr = 0; - let lf = 0; - let crlf = 0; - const endings = input.match(newLineRe) || []; - endings.forEach((ending) => { - // eslint-disable-next-line default-case - switch (ending) { - case "\r": - cr++; - break; - case "\n": - lf++; - break; - case "\r\n": - crlf++; - break; - } - }); - let preferredLineEnding = null; - if (!cr && !lf && !crlf) { - preferredLineEnding = - ((platform || process.platform) === "win32") ? "\r\n" : "\n"; - } else if ((lf >= crlf) && (lf >= cr)) { - preferredLineEnding = "\n"; - } else if (crlf >= cr) { - preferredLineEnding = "\r\n"; - } else { - preferredLineEnding = "\r"; - } - return preferredLineEnding; -} -module.exports.getPreferredLineEnding = getPreferredLineEnding; - -/** - * Normalizes the fields of a RuleOnErrorFixInfo instance. - * - * @param {Object} fixInfo RuleOnErrorFixInfo instance. - * @param {number} [lineNumber] Line number. - * @returns {Object} Normalized RuleOnErrorFixInfo instance. - */ -function normalizeFixInfo(fixInfo, lineNumber) { - return { - "lineNumber": fixInfo.lineNumber || lineNumber, - "editColumn": fixInfo.editColumn || 1, - "deleteCount": fixInfo.deleteCount || 0, - "insertText": fixInfo.insertText || "" - }; -} - -/** - * Fixes the specified error on a line of Markdown content. - * - * @param {string} line Line of Markdown content. - * @param {Object} fixInfo RuleOnErrorFixInfo instance. - * @param {string} lineEnding Line ending to use. - * @returns {string} Fixed content. - */ -function applyFix(line, fixInfo, lineEnding) { - const { editColumn, deleteCount, insertText } = normalizeFixInfo(fixInfo); - const editIndex = editColumn - 1; - return (deleteCount === -1) ? - null : - line.slice(0, editIndex) + - insertText.replace(/\n/g, lineEnding || "\n") + - line.slice(editIndex + deleteCount); -} -module.exports.applyFix = applyFix; - -// Applies as many fixes as possible to the input lines -module.exports.applyFixes = function applyFixes(input, errors) { - const lineEnding = getPreferredLineEnding(input); - const lines = input.split(newLineRe); - // Normalize fixInfo objects - let fixInfos = errors - .filter((error) => error.fixInfo) - .map((error) => normalizeFixInfo(error.fixInfo, error.lineNumber)); - // Sort bottom-to-top, line-deletes last, right-to-left, long-to-short - fixInfos.sort((a, b) => { - const aDeletingLine = (a.deleteCount === -1); - const bDeletingLine = (b.deleteCount === -1); - return ( - (b.lineNumber - a.lineNumber) || - (aDeletingLine ? 1 : (bDeletingLine ? -1 : 0)) || - (b.editColumn - a.editColumn) || - (b.insertText.length - a.insertText.length) - ); - }); - // Remove duplicate entries (needed for following collapse step) - let lastFixInfo = {}; - fixInfos = fixInfos.filter((fixInfo) => { - const unique = ( - (fixInfo.lineNumber !== lastFixInfo.lineNumber) || - (fixInfo.editColumn !== lastFixInfo.editColumn) || - (fixInfo.deleteCount !== lastFixInfo.deleteCount) || - (fixInfo.insertText !== lastFixInfo.insertText) - ); - lastFixInfo = fixInfo; - return unique; - }); - // Collapse insert/no-delete and no-insert/delete for same line/column - lastFixInfo = {}; - fixInfos.forEach((fixInfo) => { - if ( - (fixInfo.lineNumber === lastFixInfo.lineNumber) && - (fixInfo.editColumn === lastFixInfo.editColumn) && - !fixInfo.insertText && - (fixInfo.deleteCount > 0) && - lastFixInfo.insertText && - !lastFixInfo.deleteCount) { - fixInfo.insertText = lastFixInfo.insertText; - lastFixInfo.lineNumber = 0; - } - lastFixInfo = fixInfo; - }); - fixInfos = fixInfos.filter((fixInfo) => fixInfo.lineNumber); - // Apply all (remaining/updated) fixes - let lastLineIndex = -1; - let lastEditIndex = -1; - fixInfos.forEach((fixInfo) => { - const { lineNumber, editColumn, deleteCount } = fixInfo; - const lineIndex = lineNumber - 1; - const editIndex = editColumn - 1; - if ( - (lineIndex !== lastLineIndex) || - (deleteCount === -1) || - ((editIndex + deleteCount) <= - (lastEditIndex - ((deleteCount > 0) ? 0 : 1))) - ) { - lines[lineIndex] = applyFix(lines[lineIndex], fixInfo, lineEnding); - } - lastLineIndex = lineIndex; - lastEditIndex = editIndex; - }); - // Return corrected input - return lines.filter((line) => line !== null).join(lineEnding); -}; - -/** - * Gets the range and fixInfo values for reporting an error if the expected - * text is found on the specified line. - * - * @param {string[]} lines Lines of Markdown content. - * @param {number} lineIndex Line index to check. - * @param {string} search Text to search for. - * @param {string} replace Text to replace with. - * @returns {Object} Range and fixInfo wrapper. - */ -function getRangeAndFixInfoIfFound(lines, lineIndex, search, replace) { - let range = null; - let fixInfo = null; - const searchIndex = lines[lineIndex].indexOf(search); - if (searchIndex !== -1) { - const column = searchIndex + 1; - const length = search.length; - range = [ column, length ]; - fixInfo = { - "editColumn": column, - "deleteCount": length, - "insertText": replace - }; - } - return { - range, - fixInfo - }; -} -module.exports.getRangeAndFixInfoIfFound = getRangeAndFixInfoIfFound; - -/** - * Gets the next (subsequent) child token if it is of the expected type. - * - * @param {Object} parentToken Parent token. - * @param {Object} childToken Child token basis. - * @param {string} nextType Token type of next token. - * @param {string} nextNextType Token type of next-next token. - * @returns {Object} Next token. - */ -function getNextChildToken(parentToken, childToken, nextType, nextNextType) { - const { children } = parentToken; - const index = children.indexOf(childToken); - if ( - (index !== -1) && - (children.length > index + 2) && - (children[index + 1].type === nextType) && - (children[index + 2].type === nextNextType) - ) { - return children[index + 1]; - } - return null; -} -module.exports.getNextChildToken = getNextChildToken; - -/** - * Calls Object.freeze() on an object and its children. - * - * @param {Object} obj Object to deep freeze. - * @returns {Object} Object passed to the function. - */ -function deepFreeze(obj) { - const pending = [ obj ]; - let current = null; - while ((current = pending.shift())) { - Object.freeze(current); - for (const name of Object.getOwnPropertyNames(current)) { - const value = current[name]; - if (value && (typeof value === "object")) { - pending.push(value); - } - } - } - return obj; -} -module.exports.deepFreeze = deepFreeze; - - /***/ }), /***/ 2935: -/***/ ((module) => { +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { "use strict"; // @ts-check @@ -14715,11 +14031,15 @@ module.exports.frontMatterRe = // eslint-disable-next-line max-len /((^---\s*$[^]*?^---\s*$)|(^\+\+\+\s*$[^]*?^(\+\+\+|\.\.\.)\s*$)|(^\{\s*$[^]*?^\}\s*$))(\r\n|\r|\n|$)/m; -// Regular expression for matching inline disable/enable comments -const inlineCommentRe = +// Regular expression for matching the start of inline disable/enable comments +const inlineCommentStartRe = // eslint-disable-next-line max-len - //ig; -module.exports.inlineCommentRe = inlineCommentRe; + /()/ig; +module.exports.inlineCommentStartRe = inlineCommentStartRe; + +// Regular expression for matching HTML elements +const htmlElementRe = /<(([A-Za-z][A-Za-z0-9-]*)(?:\s[^`>]*)?)\/?>/g; +module.exports.htmlElementRe = htmlElementRe; // Regular expressions for range matching module.exports.bareUrlRe = /(?:http|ftp)s?:\/\/[^\s\]"']*(?:\/|[^\s\]"'\W])/ig; @@ -14729,12 +14049,17 @@ module.exports.orderedListItemMarkerRe = /^[\s>]*0*(\d+)[.)]/; // Regular expression for all instances of emphasis markers const emphasisMarkersRe = /[_*]/g; -// Regular expression for inline links and shortcut reference links -const linkRe = /(\[(?:[^[\]]|\[[^\]]*\])*\])(\(\S*\)|\[\S*\])?/g; -module.exports.linkRe = linkRe; +// Regular expression for blockquote prefixes +const blockquotePrefixRe = /^[>\s]*/; +module.exports.blockquotePrefixRe = blockquotePrefixRe; -// Regular expression for link reference definition lines -module.exports.linkReferenceRe = /^ {0,3}\[[^\]]+]:\s.*$/; +// Regular expression for reference links (full, collapsed, and shortcut) +const referenceLinkRe = + /!?\\?\[((?:\[[^\]\0]*]|[^\]\0])*)](?:(?:\[([^\]\0]*)\])|([^(])|$)/g; + +// Regular expression for link reference definitions +const linkReferenceDefinitionRe = /^ {0,3}\[([^\]]*[^\\])]:/; +module.exports.linkReferenceDefinitionRe = linkReferenceDefinitionRe; // All punctuation characters (normal and full-width) const allPunctuation = ".,;:!?。,;:!?"; @@ -14763,22 +14088,43 @@ module.exports.isObject = function isObject(obj) { return (obj !== null) && (typeof obj === "object") && !Array.isArray(obj); }; -// Returns true iff the input line is blank (no content) -// Example: Contains nothing, whitespace, or comment (unclosed start/end okay) -module.exports.isBlankLine = function isBlankLine(line) { - // Call to String.replace follows best practices and is not a security check - // False-positive for js/incomplete-multi-character-sanitization +/** + * Returns true iff the input line is blank (contains nothing, whitespace, or + * comments (unclosed start/end comments allowed)). + * + * @param {string} line Input line. + * @returns {boolean} True iff line is blank. + */ +function isBlankLine(line) { + const startComment = ""; + const removeComments = (s) => { + // eslint-disable-next-line no-constant-condition + while (true) { + const start = s.indexOf(startComment); + const end = s.indexOf(endComment); + if ((end !== -1) && ((start === -1) || (end < start))) { + // Unmatched end comment is first + s = s.slice(end + endComment.length); + } else if ((start !== -1) && (end !== -1)) { + // Start comment is before end comment + s = s.slice(0, start) + s.slice(end + endComment.length); + } else if ((start !== -1) && (end === -1)) { + // Unmatched start comment is last + s = s.slice(0, start); + } else { + // No more comments to remove + return s; + } + } + }; return ( !line || !line.trim() || - !line - .replace(//g, "") - .replace(//g, "") - .replace(/>/g, "") - .trim() + !removeComments(line).replace(/>/g, "").trim() ); -}; +} +module.exports.isBlankLine = isBlankLine; /** * Compare function for Array.prototype.sort for ascending order of numbers. @@ -14838,16 +14184,10 @@ module.exports.clearHtmlCommentText = function clearHtmlCommentText(text) { !content.endsWith("-") && !content.includes("--")); // If a valid block/inline comment... if (isValid) { - const inlineCommentIndex = text - .slice(i, j + htmlCommentEnd.length) - .search(inlineCommentRe); - // If not a markdownlint inline directive... - if (inlineCommentIndex === -1) { - text = - text.slice(0, i + htmlCommentBegin.length) + - content.replace(/[^\r\n]/g, ".") + - text.slice(j); - } + text = + text.slice(0, i + htmlCommentBegin.length) + + content.replace(/[^\r\n]/g, ".") + + text.slice(j); } } } @@ -14956,11 +14296,11 @@ module.exports.unorderedListStyleFor = function unorderedListStyleFor(token) { * @returns {void} */ function filterTokens(params, type, handler) { - params.tokens.forEach(function forToken(token) { + for (const token of params.tokens) { if (token.type === type) { handler(token); } - }); + } } module.exports.filterTokens = filterTokens; @@ -15011,11 +14351,11 @@ module.exports.getLineMetadata = function getLineMetadata(params) { filterTokens(params, "hr", (token) => { lineMetadata[token.map[0]][6] = true; }); - params.tokens.filter(isMathBlock).forEach((token) => { + for (const token of params.tokens.filter(isMathBlock)) { for (let i = token.map[0]; i < token.map[1]; i++) { lineMetadata[i][7] = true; } - }); + } return lineMetadata; }; @@ -15028,9 +14368,9 @@ module.exports.getLineMetadata = function getLineMetadata(params) { * @returns {void} */ function forEachLine(lineMetadata, handler) { - lineMetadata.forEach(function forMetadata(metadata) { + for (const metadata of lineMetadata) { handler(...metadata); - }); + } } module.exports.forEachLine = forEachLine; @@ -15042,7 +14382,7 @@ module.exports.flattenLists = function flattenLists(tokens) { let nesting = 0; const nestingStack = []; let lastWithMap = { "map": [ 0, 1 ] }; - tokens.forEach((token) => { + for (const token of tokens) { if ((token.type === "bullet_list_open") || (token.type === "ordered_list_open")) { // Save current context and start a new one @@ -15075,12 +14415,13 @@ module.exports.flattenLists = function flattenLists(tokens) { nestingStack.push(nesting); nesting = 0; } else if (token.type === "blockquote_close") { - nesting = nestingStack.pop(); - } else if (token.map) { + nesting = nestingStack.pop() || 0; + } + if (token.map) { // Track last token with map lastWithMap = token; } - }); + } return flattenedLists; }; @@ -15088,26 +14429,26 @@ module.exports.flattenLists = function flattenLists(tokens) { module.exports.forEachInlineChild = function forEachInlineChild(params, type, handler) { filterTokens(params, "inline", function forToken(token) { - token.children.forEach(function forChild(child) { + for (const child of token.children) { if (child.type === type) { handler(child, token); } - }); + } }); }; // Calls the provided function for each heading's content module.exports.forEachHeading = function forEachHeading(params, handler) { let heading = null; - params.tokens.forEach(function forToken(token) { + for (const token of params.tokens) { if (token.type === "heading_open") { heading = token; } else if (token.type === "heading_close") { heading = null; } else if ((token.type === "inline") && heading) { - handler(heading, token.content); + handler(heading, token.content, token); } - }); + } }; /** @@ -15119,84 +14460,71 @@ module.exports.forEachHeading = function forEachHeading(params, handler) { * @returns {void} */ function forEachInlineCodeSpan(input, handler) { - let currentLine = 0; - let currentColumn = 0; - let index = 0; - while (index < input.length) { - let startIndex = -1; - let startLine = -1; - let startColumn = -1; - let tickCount = 0; - let currentTicks = 0; - let state = "normal"; - // Deliberate <= so trailing 0 completes the last span (ex: "text `code`") - // False-positive for js/index-out-of-bounds - for (; index <= input.length; index++) { - const char = input[index]; - // Ignore backticks in link destination - if ((char === "[") && (state === "normal")) { - state = "linkTextOpen"; - } else if ((char === "]") && (state === "linkTextOpen")) { - state = "linkTextClosed"; - } else if ((char === "(") && (state === "linkTextClosed")) { - state = "linkDestinationOpen"; - } else if ( - ((char === "(") && (state === "linkDestinationOpen")) || - ((char === ")") && (state === "linkDestinationOpen")) || - (state === "linkTextClosed")) { - state = "normal"; - } - // Parse backtick open/close - if ((char === "`") && (state !== "linkDestinationOpen")) { - // Count backticks at start or end of code span - currentTicks++; - if ((startIndex === -1) || (startColumn === -1)) { - startIndex = index + 1; - } - } else { - if ((startIndex >= 0) && - (startColumn >= 0) && - (tickCount === currentTicks)) { - // Found end backticks; invoke callback for code span + const backtickRe = /`+/g; + let match = null; + const backticksLengthAndIndex = []; + while ((match = backtickRe.exec(input)) !== null) { + backticksLengthAndIndex.push([ match[0].length, match.index ]); + } + const newLinesIndex = []; + while ((match = newLineRe.exec(input)) !== null) { + newLinesIndex.push(match.index); + } + let lineIndex = 0; + let lineStartIndex = 0; + let k = 0; + for (let i = 0; i < backticksLengthAndIndex.length - 1; i++) { + const [ startLength, startIndex ] = backticksLengthAndIndex[i]; + if ((startIndex === 0) || (input[startIndex - 1] !== "\\")) { + for (let j = i + 1; j < backticksLengthAndIndex.length; j++) { + const [ endLength, endIndex ] = backticksLengthAndIndex[j]; + if (startLength === endLength) { + for (; k < newLinesIndex.length; k++) { + const newLineIndex = newLinesIndex[k]; + if (startIndex < newLineIndex) { + break; + } + lineIndex++; + lineStartIndex = newLineIndex + 1; + } + const columnIndex = startIndex - lineStartIndex + startLength; handler( - input.substring(startIndex, index - currentTicks), - startLine, startColumn, tickCount); - startIndex = -1; - startColumn = -1; - } else if ((startIndex >= 0) && (startColumn === -1)) { - // Found start backticks - tickCount = currentTicks; - startLine = currentLine; - startColumn = currentColumn; + input.slice(startIndex + startLength, endIndex), + lineIndex, + columnIndex, + startLength + ); + i = j; + break; } - // Not in backticks - currentTicks = 0; } - if (char === "\n") { - // On next line - currentLine++; - currentColumn = 0; - } else if ((char === "\\") && - ((startIndex === -1) || (startColumn === -1)) && - (input[index + 1] !== "\n")) { - // Escape character outside code, skip next - index++; - currentColumn += 2; - } else { - // On next column - currentColumn++; - } - } - if (startIndex >= 0) { - // Restart loop after unmatched start backticks (ex: "`text``code``") - index = startIndex; - currentLine = startLine; - currentColumn = startColumn; } } } module.exports.forEachInlineCodeSpan = forEachInlineCodeSpan; +/** + * Adds ellipsis to the left/right/middle of the specified text. + * + * @param {string} text Text to ellipsify. + * @param {boolean} [start] True iff the start of the text is important. + * @param {boolean} [end] True iff the end of the text is important. + * @returns {string} Ellipsified text. + */ +function ellipsify(text, start, end) { + if (text.length <= 30) { + // Nothing to do + } else if (start && end) { + text = text.slice(0, 15) + "..." + text.slice(-15); + } else if (end) { + text = "..." + text.slice(-30); + } else { + text = text.slice(0, 30) + "..."; + } + return text; +} +module.exports.ellipsify = ellipsify; + /** * Adds a generic error object via the onError callback. * @@ -15237,16 +14565,8 @@ module.exports.addErrorDetailIf = function addErrorDetailIf( // Adds an error object with context via the onError callback module.exports.addErrorContext = function addErrorContext( onError, lineNumber, context, left, right, range, fixInfo) { - if (context.length <= 30) { - // Nothing to do - } else if (left && right) { - context = context.substr(0, 15) + "..." + context.substr(-15); - } else if (right) { - context = "..." + context.substr(-30); - } else { - context = context.substr(0, 30) + "..."; - } - addError(onError, lineNumber, null, context, range, fixInfo); + context = ellipsify(context, left, right); + addError(onError, lineNumber, undefined, context, range, fixInfo); }; /** @@ -15287,21 +14607,41 @@ module.exports.codeBlockAndSpanRanges = (params, lineMetadata) => { }; /** - * Determines whether the specified range overlaps another range. + * Returns an array of HTML element ranges. + * + * @param {Object} params RuleParams instance. + * @param {Object} lineMetadata Line metadata object. + * @returns {number[][]} Array of ranges (lineIndex, columnIndex, length). + */ +module.exports.htmlElementRanges = (params, lineMetadata) => { + const exclusions = []; + forEachLine(lineMetadata, (line, lineIndex, inCode) => { + let match = null; + // eslint-disable-next-line no-unmodified-loop-condition + while (!inCode && ((match = htmlElementRe.exec(line)) !== null)) { + exclusions.push([ lineIndex, match.index, match[0].length ]); + } + }); + return exclusions; +}; + +/** + * Determines whether the specified range is within another range. * * @param {number[][]} ranges Array of ranges (line, index, length). * @param {number} lineIndex Line index to check. * @param {number} index Index to check. * @param {number} length Length to check. - * @returns {boolean} True iff the specified range overlaps. + * @returns {boolean} True iff the specified range is within. */ -module.exports.overlapsAnyRange = (ranges, lineIndex, index, length) => ( +const withinAnyRange = (ranges, lineIndex, index, length) => ( !ranges.every((span) => ( (lineIndex !== span[0]) || - (index + length < span[1]) || - (index > span[1] + span[2]) + (index < span[1]) || + (index + length > span[1] + span[2]) )) ); +module.exports.withinAnyRange = withinAnyRange; // Returns a range object for a line by applying a RegExp module.exports.rangeFromRegExp = function rangeFromRegExp(line, regexp) { @@ -15329,6 +14669,82 @@ module.exports.frontMatterHasTitle = frontMatterLines.some((line) => frontMatterTitleRe.test(line)); }; +/** + * Calls the provided function for each link. + * + * @param {string} line Line of Markdown input. + * @param {Function} handler Function taking (index, link, text, destination). + * @returns {void} + */ +function forEachLink(line, handler) { + // Helper to find matching close symbol for link text/destination + const findClosingSymbol = (index) => { + const begin = line[index]; + const end = (begin === "[") ? "]" : ")"; + let nesting = 0; + let escaping = false; + let pointy = false; + for (let i = index + 1; i < line.length; i++) { + const current = line[i]; + if (current === "\\") { + escaping = !escaping; + } else if (!escaping && (current === begin)) { + nesting++; + } else if (!escaping && (current === end)) { + if (nesting > 0) { + nesting--; + } else if (!pointy) { + // Return index after matching close symbol + return i + 1; + } + } else if ((i === index + 1) && (begin === "(") && (current === "<")) { + pointy = true; + } else if (!escaping && pointy && current === ">") { + pointy = false; + nesting = 0; + } else { + escaping = false; + } + } + // No match found + return -1; + }; + // Scan line for unescaped "[" character + let escaping = false; + for (let i = 0; i < line.length; i++) { + const current = line[i]; + if (current === "\\") { + escaping = !escaping; + } else if (!escaping && (current === "[")) { + // Scan for matching close "]" of link text + const textEnd = findClosingSymbol(i); + if (textEnd !== -1) { + if ((line[textEnd] === "(") || (line[textEnd] === "[")) { + // Scan for matching close ")" or "]" of link destination + const destEnd = findClosingSymbol(textEnd); + if (destEnd !== -1) { + // Call handler with link text and destination + const link = line.slice(i, destEnd); + const text = line.slice(i, textEnd); + const dest = line.slice(textEnd, destEnd); + handler(i, link, text, dest); + i = destEnd; + } + } + if (i < textEnd) { + // Call handler with link text only + const text = line.slice(i, textEnd); + handler(i, text, text); + i = textEnd; + } + } + } else { + escaping = false; + } + } +} +module.exports.forEachLink = forEachLink; + /** * Returns a list of emphasis markers in code spans and links. * @@ -15339,17 +14755,16 @@ function emphasisMarkersInContent(params) { const { lines } = params; const byLine = new Array(lines.length); // Search links - lines.forEach((tokenLine, tokenLineIndex) => { + for (const [ tokenLineIndex, tokenLine ] of lines.entries()) { const inLine = []; - let linkMatch = null; - while ((linkMatch = linkRe.exec(tokenLine))) { + forEachLink(tokenLine, (index, match) => { let markerMatch = null; - while ((markerMatch = emphasisMarkersRe.exec(linkMatch[0]))) { - inLine.push(linkMatch.index + markerMatch.index); + while ((markerMatch = emphasisMarkersRe.exec(match))) { + inLine.push(index + markerMatch.index); } - } + }); byLine[tokenLineIndex] = inLine; - }); + } // Search code spans filterTokens(params, "inline", (token) => { const { children, lineNumber, map } = token; @@ -15359,7 +14774,7 @@ function emphasisMarkersInContent(params) { tokenLines.join("\n"), (code, lineIndex, column, tickCount) => { const codeLines = code.split(newLineRe); - codeLines.forEach((codeLine, codeLineIndex) => { + for (const [ codeLineIndex, codeLine ] of codeLines.entries()) { const byLineIndex = lineNumber - 1 + lineIndex + codeLineIndex; const inLine = byLine[byLineIndex]; const codeLineOffset = codeLineIndex ? 0 : column - 1 + tickCount; @@ -15368,7 +14783,7 @@ function emphasisMarkersInContent(params) { inLine.push(codeLineOffset + match.index); } byLine[byLineIndex] = inLine; - }); + } } ); } @@ -15377,19 +14792,152 @@ function emphasisMarkersInContent(params) { } module.exports.emphasisMarkersInContent = emphasisMarkersInContent; +/** + * Returns an object with information about reference links and images. + * + * @param {Object} lineMetadata Line metadata object. + * @returns {Object} Reference link/image data. + */ +function getReferenceLinkImageData(lineMetadata) { + // Initialize return values + const references = new Map(); + const shortcuts = new Set(); + const definitions = new Map(); + const duplicateDefinitions = []; + // Define helper functions + const normalizeLabel = (s) => s.toLowerCase().trim().replace(/\s+/g, " "); + const exclusions = []; + const excluded = (match) => withinAnyRange( + exclusions, 0, match.index, match[0].length - (match[3] || "").length + ); + // Convert input to single-line so multi-line links/images are easier + const lineOffsets = []; + let currentOffset = 0; + const contentLines = []; + forEachLine(lineMetadata, (line, lineIndex, inCode) => { + lineOffsets[lineIndex] = currentOffset; + if (!inCode) { + line = line.replace(blockquotePrefixRe, ""); + if (line.trim().length === 0) { + // Allow RegExp to detect the end of a block + line = "\0"; + } + contentLines.push(line); + currentOffset += line.length + 1; + } + }); + lineOffsets.push(currentOffset); + const contentLine = contentLines.join(" "); + // Determine single-line exclusions for inline code spans + forEachInlineCodeSpan(contentLine, (code, lineIndex, columnIndex) => { + exclusions.push([ 0, columnIndex, code.length ]); + }); + // Identify all link/image reference definitions + forEachLine(lineMetadata, (line, lineIndex, inCode) => { + if (!inCode) { + const linkReferenceDefinitionMatch = linkReferenceDefinitionRe.exec(line); + if (linkReferenceDefinitionMatch) { + const label = normalizeLabel(linkReferenceDefinitionMatch[1]); + if (definitions.has(label)) { + duplicateDefinitions.push([ label, lineIndex ]); + } else { + definitions.set(label, lineIndex); + } + exclusions.push([ 0, lineOffsets[lineIndex], line.length ]); + } + } + }); + // Identify all link and image references + let lineIndex = 0; + const pendingContents = [ + { + "content": contentLine, + "contentLineIndex": 0, + "contentIndex": 0, + "topLevel": true + } + ]; + let pendingContent = null; + while ((pendingContent = pendingContents.shift())) { + const { content, contentLineIndex, contentIndex, topLevel } = + pendingContent; + let referenceLinkMatch = null; + while ((referenceLinkMatch = referenceLinkRe.exec(content)) !== null) { + const [ matchString, matchText, matchLabel ] = referenceLinkMatch; + if ( + !matchString.startsWith("\\") && + !matchString.startsWith("!\\") && + !matchText.endsWith("\\") && + !(matchLabel || "").endsWith("\\") && + !(topLevel && excluded(referenceLinkMatch)) + ) { + const shortcutLink = (matchLabel === undefined); + const collapsedLink = + (!shortcutLink && (matchLabel.length === 0)); + const label = normalizeLabel( + (shortcutLink || collapsedLink) ? matchText : matchLabel + ); + if (label.length > 0) { + const referenceindex = referenceLinkMatch.index; + if (topLevel) { + // Calculate line index + while (lineOffsets[lineIndex + 1] <= referenceindex) { + lineIndex++; + } + } else { + // Use provided line index + lineIndex = contentLineIndex; + } + const referenceIndex = referenceindex + + (topLevel ? -lineOffsets[lineIndex] : contentIndex); + if (shortcutLink) { + // Track separately due to ambiguity in "text [text] text" + shortcuts.add(label); + } else { + // Track reference and location + const referenceData = references.get(label) || []; + referenceData.push([ + lineIndex, + referenceIndex, + matchString.length + ]); + references.set(label, referenceData); + } + // Check for links embedded in brackets + if (!matchString.startsWith("!")) { + pendingContents.push({ + "content": matchText, + "contentLineIndex": lineIndex, + "contentIndex": referenceIndex + 1, + "topLevel": false + }); + } + } + } + } + } + return { + references, + shortcuts, + definitions, + duplicateDefinitions + }; +} +module.exports.getReferenceLinkImageData = getReferenceLinkImageData; + /** * Gets the most common line ending, falling back to the platform default. * * @param {string} input Markdown content to analyze. - * @param {string} [platform] Platform identifier (process.platform). + * @param {Object} [os] Node.js "os" module. * @returns {string} Preferred line ending. */ -function getPreferredLineEnding(input, platform) { +function getPreferredLineEnding(input, os) { let cr = 0; let lf = 0; let crlf = 0; const endings = input.match(newLineRe) || []; - endings.forEach((ending) => { + for (const ending of endings) { // eslint-disable-next-line default-case switch (ending) { case "\r": @@ -15402,11 +14950,10 @@ function getPreferredLineEnding(input, platform) { crlf++; break; } - }); + } let preferredLineEnding = null; if (!cr && !lf && !crlf) { - preferredLineEnding = - ((platform || process.platform) === "win32") ? "\r\n" : "\n"; + preferredLineEnding = (os && os.EOL) || "\n"; } else if ((lf >= crlf) && (lf >= cr)) { preferredLineEnding = "\n"; } else if (crlf >= cr) { @@ -15439,8 +14986,8 @@ function normalizeFixInfo(fixInfo, lineNumber) { * * @param {string} line Line of Markdown content. * @param {Object} fixInfo RuleOnErrorFixInfo instance. - * @param {string} lineEnding Line ending to use. - * @returns {string} Fixed content. + * @param {string} [lineEnding] Line ending to use. + * @returns {string | null} Fixed content. */ function applyFix(line, fixInfo, lineEnding) { const { editColumn, deleteCount, insertText } = normalizeFixInfo(fixInfo); @@ -15453,9 +15000,15 @@ function applyFix(line, fixInfo, lineEnding) { } module.exports.applyFix = applyFix; -// Applies as many fixes as possible to the input lines -module.exports.applyFixes = function applyFixes(input, errors) { - const lineEnding = getPreferredLineEnding(input); +/** + * Applies as many fixes as possible to Markdown content. + * + * @param {string} input Lines of Markdown content. + * @param {Object[]} errors RuleOnErrorInfo instances. + * @returns {string} Corrected content. + */ +function applyFixes(input, errors) { + const lineEnding = getPreferredLineEnding(input, __nccwpck_require__(2037)); const lines = input.split(newLineRe); // Normalize fixInfo objects let fixInfos = errors @@ -15485,8 +15038,10 @@ module.exports.applyFixes = function applyFixes(input, errors) { return unique; }); // Collapse insert/no-delete and no-insert/delete for same line/column - lastFixInfo = {}; - fixInfos.forEach((fixInfo) => { + lastFixInfo = { + "lineNumber": -1 + }; + for (const fixInfo of fixInfos) { if ( (fixInfo.lineNumber === lastFixInfo.lineNumber) && (fixInfo.editColumn === lastFixInfo.editColumn) && @@ -15498,12 +15053,12 @@ module.exports.applyFixes = function applyFixes(input, errors) { lastFixInfo.lineNumber = 0; } lastFixInfo = fixInfo; - }); + } fixInfos = fixInfos.filter((fixInfo) => fixInfo.lineNumber); // Apply all (remaining/updated) fixes let lastLineIndex = -1; let lastEditIndex = -1; - fixInfos.forEach((fixInfo) => { + for (const fixInfo of fixInfos) { const { lineNumber, editColumn, deleteCount } = fixInfo; const lineIndex = lineNumber - 1; const editIndex = editColumn - 1; @@ -15513,14 +15068,16 @@ module.exports.applyFixes = function applyFixes(input, errors) { ((editIndex + deleteCount) <= (lastEditIndex - ((deleteCount > 0) ? 0 : 1))) ) { + // @ts-ignore lines[lineIndex] = applyFix(lines[lineIndex], fixInfo, lineEnding); } lastLineIndex = lineIndex; lastEditIndex = editIndex; - }); + } // Return corrected input return lines.filter((line) => line !== null).join(lineEnding); -}; +} +module.exports.applyFixes = applyFixes; /** * Gets the range and fixInfo values for reporting an error if the expected @@ -15530,28 +15087,33 @@ module.exports.applyFixes = function applyFixes(input, errors) { * @param {number} lineIndex Line index to check. * @param {string} search Text to search for. * @param {string} replace Text to replace with. + * @param {number} [instance] Instance on the line (1-based). * @returns {Object} Range and fixInfo wrapper. */ -function getRangeAndFixInfoIfFound(lines, lineIndex, search, replace) { - let range = null; - let fixInfo = null; - const searchIndex = lines[lineIndex].indexOf(search); - if (searchIndex !== -1) { - const column = searchIndex + 1; - const length = search.length; - range = [ column, length ]; - fixInfo = { - "editColumn": column, - "deleteCount": length, - "insertText": replace +module.exports.getRangeAndFixInfoIfFound = + (lines, lineIndex, search, replace, instance = 1) => { + let range = null; + let fixInfo = null; + let searchIndex = -1; + while (instance > 0) { + searchIndex = lines[lineIndex].indexOf(search, searchIndex + 1); + instance--; + } + if (searchIndex !== -1) { + const column = searchIndex + 1; + const length = search.length; + range = [ column, length ]; + fixInfo = { + "editColumn": column, + "deleteCount": length, + "insertText": replace + }; + } + return { + range, + fixInfo }; - } - return { - range, - fixInfo }; -} -module.exports.getRangeAndFixInfoIfFound = getRangeAndFixInfoIfFound; /** * Gets the next (subsequent) child token if it is of the expected type. @@ -15578,4137 +15140,17 @@ function getNextChildToken(parentToken, childToken, nextType, nextNextType) { module.exports.getNextChildToken = getNextChildToken; /** - * Calls Object.freeze() on an object and its children. + * Expands a path with a tilde to an absolute path. * - * @param {Object} obj Object to deep freeze. - * @returns {Object} Object passed to the function. + * @param {string} file Path that may begin with a tilde. + * @param {Object} os Node.js "os" module. + * @returns {string} Absolute path (or original path). */ -function deepFreeze(obj) { - const pending = [ obj ]; - let current = null; - while ((current = pending.shift())) { - Object.freeze(current); - for (const name of Object.getOwnPropertyNames(current)) { - const value = current[name]; - if (value && (typeof value === "object")) { - pending.push(value); - } - } - } - return obj; +function expandTildePath(file, os) { + const homedir = os && os.homedir && os.homedir(); + return homedir ? file.replace(/^~($|\/|\\)/, `${homedir}$1`) : file; } -module.exports.deepFreeze = deepFreeze; - - -/***/ }), - -/***/ 3266: -/***/ ((module) => { - -"use strict"; -// @ts-check - - - -let codeBlockAndSpanRanges = null; -module.exports.codeBlockAndSpanRanges = (value) => { - if (value) { - codeBlockAndSpanRanges = value; - } - return codeBlockAndSpanRanges; -}; - -let flattenedLists = null; -module.exports.flattenedLists = (value) => { - if (value) { - flattenedLists = value; - } - return flattenedLists; -}; - -let lineMetadata = null; -module.exports.lineMetadata = (value) => { - if (value) { - lineMetadata = value; - } - return lineMetadata; -}; - -module.exports.clear = () => { - codeBlockAndSpanRanges = null; - flattenedLists = null; - lineMetadata = null; -}; - - -/***/ }), - -/***/ 5039: -/***/ ((module) => { - -"use strict"; -// @ts-check - - - -module.exports.deprecatedRuleNames = [ "MD002", "MD006" ]; -module.exports.homepage = "https://github.com/DavidAnson/markdownlint"; -module.exports.version = "0.25.1"; - - -/***/ }), - -/***/ 3611: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const path = __nccwpck_require__(1017); -const { promisify } = __nccwpck_require__(3837); -const markdownIt = __nccwpck_require__(8561); -const { deprecatedRuleNames } = __nccwpck_require__(5039); -const rules = __nccwpck_require__(7494); -const helpers = __nccwpck_require__(2935); -const cache = __nccwpck_require__(3266); - -// @ts-ignore -// eslint-disable-next-line camelcase, max-len, no-inline-comments, no-undef -const dynamicRequire = (typeof require === "undefined") ? require : /* c8 ignore next */ eval("require"); -// Capture native require implementation for dynamic loading of modules - -/** - * Validate the list of rules for structure and reuse. - * - * @param {Rule[]} ruleList List of rules. - * @param {boolean} synchronous Whether to execute synchronously. - * @returns {string} Error message if validation fails. - */ -function validateRuleList(ruleList, synchronous) { - let result = null; - if (ruleList.length === rules.length) { - // No need to validate if only using built-in rules - return result; - } - const allIds = {}; - ruleList.forEach(function forRule(rule, index) { - const customIndex = index - rules.length; - // eslint-disable-next-line jsdoc/require-jsdoc - function newError(property) { - return new Error( - "Property '" + property + "' of custom rule at index " + - customIndex + " is incorrect."); - } - [ "names", "tags" ].forEach(function forProperty(property) { - const value = rule[property]; - if (!result && - (!value || !Array.isArray(value) || (value.length === 0) || - !value.every(helpers.isString) || value.some(helpers.isEmptyString))) { - result = newError(property); - } - }); - [ - [ "description", "string" ], - [ "function", "function" ] - ].forEach(function forProperty(propertyInfo) { - const property = propertyInfo[0]; - const value = rule[property]; - if (!result && (!value || (typeof value !== propertyInfo[1]))) { - result = newError(property); - } - }); - if ( - !result && - rule.information && - (Object.getPrototypeOf(rule.information) !== URL.prototype) - ) { - result = newError("information"); - } - if ( - !result && - (rule.asynchronous !== undefined) && - (typeof rule.asynchronous !== "boolean") - ) { - result = newError("asynchronous"); - } - if (!result && rule.asynchronous && synchronous) { - result = new Error( - "Custom rule " + rule.names.join("/") + " at index " + customIndex + - " is asynchronous and can not be used in a synchronous context." - ); - } - if (!result) { - rule.names.forEach(function forName(name) { - const nameUpper = name.toUpperCase(); - if (!result && (allIds[nameUpper] !== undefined)) { - result = new Error("Name '" + name + "' of custom rule at index " + - customIndex + " is already used as a name or tag."); - } - allIds[nameUpper] = true; - }); - rule.tags.forEach(function forTag(tag) { - const tagUpper = tag.toUpperCase(); - if (!result && allIds[tagUpper]) { - result = new Error("Tag '" + tag + "' of custom rule at index " + - customIndex + " is already used as a name."); - } - allIds[tagUpper] = false; - }); - } - }); - return result; -} - -/** - * Creates a LintResults instance with toString for pretty display. - * - * @param {Rule[]} ruleList List of rules. - * @returns {LintResults} New LintResults instance. - */ -function newResults(ruleList) { - const lintResults = {}; - // eslint-disable-next-line jsdoc/require-jsdoc - function toString(useAlias) { - let ruleNameToRule = null; - const results = []; - const keys = Object.keys(lintResults); - keys.sort(); - keys.forEach(function forFile(file) { - const fileResults = lintResults[file]; - if (Array.isArray(fileResults)) { - fileResults.forEach(function forResult(result) { - const ruleMoniker = result.ruleNames ? - result.ruleNames.join("/") : - (result.ruleName + "/" + result.ruleAlias); - results.push( - file + ": " + - result.lineNumber + ": " + - ruleMoniker + " " + - result.ruleDescription + - (result.errorDetail ? - " [" + result.errorDetail + "]" : - "") + - (result.errorContext ? - " [Context: \"" + result.errorContext + "\"]" : - "")); - }); - } else { - if (!ruleNameToRule) { - ruleNameToRule = {}; - ruleList.forEach(function forRule(rule) { - const ruleName = rule.names[0].toUpperCase(); - ruleNameToRule[ruleName] = rule; - }); - } - Object.keys(fileResults).forEach(function forRule(ruleName) { - const rule = ruleNameToRule[ruleName.toUpperCase()]; - const ruleResults = fileResults[ruleName]; - ruleResults.forEach(function forLine(lineNumber) { - const nameIndex = Math.min(useAlias ? 1 : 0, rule.names.length - 1); - const result = - file + ": " + - lineNumber + ": " + - rule.names[nameIndex] + " " + - rule.description; - results.push(result); - }); - }); - } - }); - return results.join("\n"); - } - Object.defineProperty(lintResults, "toString", { "value": toString }); - // @ts-ignore - return lintResults; -} - -/** - * Remove front matter (if present at beginning of content). - * - * @param {string} content Markdown content. - * @param {RegExp} frontMatter Regular expression to match front matter. - * @returns {Object} Trimmed content and front matter lines. - */ -function removeFrontMatter(content, frontMatter) { - let frontMatterLines = []; - if (frontMatter) { - const frontMatterMatch = content.match(frontMatter); - if (frontMatterMatch && !frontMatterMatch.index) { - const contentMatched = frontMatterMatch[0]; - content = content.slice(contentMatched.length); - frontMatterLines = contentMatched.split(helpers.newLineRe); - if ((frontMatterLines.length > 0) && - (frontMatterLines[frontMatterLines.length - 1] === "")) { - frontMatterLines.length--; - } - } - } - return { - "content": content, - "frontMatterLines": frontMatterLines - }; -} - -/** - * Annotate tokens with line/lineNumber. - * - * @param {MarkdownItToken[]} tokens Array of markdown-it tokens. - * @param {string[]} lines Lines of Markdown content. - * @returns {void} - */ -function annotateTokens(tokens, lines) { - let trMap = null; - tokens.forEach(function forToken(token) { - // Provide missing maps for table content - if (token.type === "tr_open") { - trMap = token.map; - } else if (token.type === "tr_close") { - trMap = null; - } - if (!token.map && trMap) { - token.map = [ ...trMap ]; - } - // Adjust maps for math blocks - if (helpers.isMathBlock(token) && token.map[1]) { - // markdown-it-texmath plugin does not account for math_block_end - token.map[1]++; - } - // Update token metadata - if (token.map) { - token.line = lines[token.map[0]]; - token.lineNumber = token.map[0] + 1; - // Trim bottom of token to exclude whitespace lines - while (token.map[1] && !((lines[token.map[1] - 1] || "").trim())) { - token.map[1]--; - } - // Annotate children with lineNumber - let lineNumber = token.lineNumber; - const codeSpanExtraLines = []; - helpers.forEachInlineCodeSpan( - token.content, - function handleInlineCodeSpan(code) { - codeSpanExtraLines.push(code.split(helpers.newLineRe).length - 1); - } - ); - (token.children || []).forEach(function forChild(child) { - child.lineNumber = lineNumber; - child.line = lines[lineNumber - 1]; - if ((child.type === "softbreak") || (child.type === "hardbreak")) { - lineNumber++; - } else if (child.type === "code_inline") { - lineNumber += codeSpanExtraLines.shift(); - } - }); - } - }); -} - -/** - * Map rule names/tags to canonical rule name. - * - * @param {Rule[]} ruleList List of rules. - * @returns {Object.} Map of alias to rule name. - */ -function mapAliasToRuleNames(ruleList) { - const aliasToRuleNames = {}; - // const tagToRuleNames = {}; - ruleList.forEach(function forRule(rule) { - const ruleName = rule.names[0].toUpperCase(); - // The following is useful for updating README.md: - // console.log( - // "* **[" + ruleName + "](doc/Rules.md#" + ruleName.toLowerCase() + - // ")** *" + rule.names.slice(1).join("/") + "* - " + rule.description); - rule.names.forEach(function forName(name) { - const nameUpper = name.toUpperCase(); - aliasToRuleNames[nameUpper] = [ ruleName ]; - }); - rule.tags.forEach(function forTag(tag) { - const tagUpper = tag.toUpperCase(); - const ruleNames = aliasToRuleNames[tagUpper] || []; - ruleNames.push(ruleName); - aliasToRuleNames[tagUpper] = ruleNames; - // tagToRuleNames[tag] = ruleName; - }); - }); - // The following is useful for updating README.md: - // Object.keys(tagToRuleNames).sort().forEach(function forTag(tag) { - // console.log("* **" + tag + "** - " + - // aliasToRuleNames[tag.toUpperCase()].join(", ")); - // }); - // @ts-ignore - return aliasToRuleNames; -} - -/** - * Apply (and normalize) configuration object. - * - * @param {Rule[]} ruleList List of rules. - * @param {Configuration} config Configuration object. - * @param {Object.} aliasToRuleNames Map of alias to rule - * names. - * @returns {Configuration} Effective configuration. - */ -function getEffectiveConfig(ruleList, config, aliasToRuleNames) { - const defaultKey = Object.keys(config).filter( - (key) => key.toUpperCase() === "DEFAULT" - ); - const ruleDefault = (defaultKey.length === 0) || !!config[defaultKey[0]]; - const effectiveConfig = {}; - ruleList.forEach((rule) => { - const ruleName = rule.names[0].toUpperCase(); - effectiveConfig[ruleName] = ruleDefault; - }); - deprecatedRuleNames.forEach((ruleName) => { - effectiveConfig[ruleName] = false; - }); - Object.keys(config).forEach((key) => { - let value = config[key]; - if (value) { - if (!(value instanceof Object)) { - value = {}; - } - } else { - value = false; - } - const keyUpper = key.toUpperCase(); - (aliasToRuleNames[keyUpper] || []).forEach((ruleName) => { - effectiveConfig[ruleName] = value; - }); - }); - return effectiveConfig; -} - -/** - * Create a mapping of enabled rules per line. - * - * @param {Rule[]} ruleList List of rules. - * @param {string[]} lines List of content lines. - * @param {string[]} frontMatterLines List of front matter lines. - * @param {boolean} noInlineConfig Whether to allow inline configuration. - * @param {Configuration} config Configuration object. - * @param {Object.} aliasToRuleNames Map of alias to rule - * names. - * @returns {Object} Effective configuration and enabled rules per line number. - */ -function getEnabledRulesPerLineNumber( - ruleList, - lines, - frontMatterLines, - noInlineConfig, - config, - aliasToRuleNames) { - // Shared variables - let enabledRules = {}; - let capturedRules = {}; - const allRuleNames = []; - const enabledRulesPerLineNumber = new Array(1 + frontMatterLines.length); - // Helper functions - // eslint-disable-next-line jsdoc/require-jsdoc - function handleInlineConfig(input, forEachMatch, forEachLine) { - input.forEach((line, lineIndex) => { - if (!noInlineConfig) { - let match = null; - while ((match = helpers.inlineCommentRe.exec(line))) { - const action = (match[1] || match[3]).toUpperCase(); - const parameter = match[2] || match[4]; - forEachMatch(action, parameter, lineIndex + 1); - } - } - if (forEachLine) { - forEachLine(); - } - }); - } - // eslint-disable-next-line jsdoc/require-jsdoc - function configureFile(action, parameter) { - if (action === "CONFIGURE-FILE") { - try { - const json = JSON.parse(parameter); - config = { - ...config, - ...json - }; - } catch { - // Ignore parse errors for inline configuration - } - } - } - // eslint-disable-next-line jsdoc/require-jsdoc - function applyEnableDisable(action, parameter, state) { - state = { ...state }; - const enabled = (action.startsWith("ENABLE")); - const items = parameter ? - parameter.trim().toUpperCase().split(/\s+/) : - allRuleNames; - items.forEach((nameUpper) => { - (aliasToRuleNames[nameUpper] || []).forEach((ruleName) => { - state[ruleName] = enabled; - }); - }); - return state; - } - // eslint-disable-next-line jsdoc/require-jsdoc - function enableDisableFile(action, parameter) { - if ((action === "ENABLE-FILE") || (action === "DISABLE-FILE")) { - enabledRules = applyEnableDisable(action, parameter, enabledRules); - } - } - // eslint-disable-next-line jsdoc/require-jsdoc - function captureRestoreEnableDisable(action, parameter) { - if (action === "CAPTURE") { - capturedRules = enabledRules; - } else if (action === "RESTORE") { - enabledRules = capturedRules; - } else if ((action === "ENABLE") || (action === "DISABLE")) { - enabledRules = applyEnableDisable(action, parameter, enabledRules); - } - } - // eslint-disable-next-line jsdoc/require-jsdoc - function updateLineState() { - enabledRulesPerLineNumber.push(enabledRules); - } - // eslint-disable-next-line jsdoc/require-jsdoc - function disableNextLine(action, parameter, lineNumber) { - if (action === "DISABLE-NEXT-LINE") { - const nextLineNumber = frontMatterLines.length + lineNumber + 1; - enabledRulesPerLineNumber[nextLineNumber] = - applyEnableDisable( - action, - parameter, - enabledRulesPerLineNumber[nextLineNumber] || {} - ); - } - } - // Handle inline comments - handleInlineConfig([ lines.join("\n") ], configureFile); - const effectiveConfig = getEffectiveConfig( - ruleList, config, aliasToRuleNames); - ruleList.forEach((rule) => { - const ruleName = rule.names[0].toUpperCase(); - allRuleNames.push(ruleName); - enabledRules[ruleName] = !!effectiveConfig[ruleName]; - }); - capturedRules = enabledRules; - handleInlineConfig(lines, enableDisableFile); - handleInlineConfig(lines, captureRestoreEnableDisable, updateLineState); - handleInlineConfig(lines, disableNextLine); - // Return results - return { - effectiveConfig, - enabledRulesPerLineNumber - }; -} - -/** - * Lints a string containing Markdown content. - * - * @param {Rule[]} ruleList List of rules. - * @param {string} name Identifier for the content. - * @param {string} content Markdown content. - * @param {Object} md Instance of markdown-it. - * @param {Configuration} config Configuration object. - * @param {RegExp} frontMatter Regular expression for front matter. - * @param {boolean} handleRuleFailures Whether to handle exceptions in rules. - * @param {boolean} noInlineConfig Whether to allow inline configuration. - * @param {number} resultVersion Version of the LintResults object to return. - * @param {Function} callback Callback (err, result) function. - * @returns {void} - */ -function lintContent( - ruleList, - name, - content, - md, - config, - frontMatter, - handleRuleFailures, - noInlineConfig, - resultVersion, - callback) { - // Remove UTF-8 byte order marker (if present) - content = content.replace(/^\uFEFF/, ""); - // Remove front matter - const removeFrontMatterResult = removeFrontMatter(content, frontMatter); - const frontMatterLines = removeFrontMatterResult.frontMatterLines; - // Ignore the content of HTML comments - content = helpers.clearHtmlCommentText(removeFrontMatterResult.content); - // Parse content into tokens and lines - const tokens = md.parse(content, {}); - const lines = content.split(helpers.newLineRe); - annotateTokens(tokens, lines); - const aliasToRuleNames = mapAliasToRuleNames(ruleList); - const { effectiveConfig, enabledRulesPerLineNumber } = - getEnabledRulesPerLineNumber( - ruleList, - lines, - frontMatterLines, - noInlineConfig, - config, - aliasToRuleNames - ); - // Create parameters for rules - const params = { - "name": helpers.deepFreeze(name), - "tokens": helpers.deepFreeze(tokens), - "lines": helpers.deepFreeze(lines), - "frontMatterLines": helpers.deepFreeze(frontMatterLines) - }; - cache.lineMetadata(helpers.getLineMetadata(params)); - cache.flattenedLists(helpers.flattenLists(params.tokens)); - cache.codeBlockAndSpanRanges( - helpers.codeBlockAndSpanRanges(params, cache.lineMetadata()) - ); - // Function to run for each rule - let results = []; - // eslint-disable-next-line jsdoc/require-jsdoc - function forRule(rule) { - // Configure rule - const ruleName = rule.names[0].toUpperCase(); - params.config = effectiveConfig[ruleName]; - // eslint-disable-next-line jsdoc/require-jsdoc - function throwError(property) { - throw new Error( - "Property '" + property + "' of onError parameter is incorrect."); - } - // eslint-disable-next-line jsdoc/require-jsdoc - function onError(errorInfo) { - if (!errorInfo || - !helpers.isNumber(errorInfo.lineNumber) || - (errorInfo.lineNumber < 1) || - (errorInfo.lineNumber > lines.length)) { - throwError("lineNumber"); - } - const lineNumber = errorInfo.lineNumber + frontMatterLines.length; - if (!enabledRulesPerLineNumber[lineNumber][ruleName]) { - return; - } - if (errorInfo.detail && - !helpers.isString(errorInfo.detail)) { - throwError("detail"); - } - if (errorInfo.context && - !helpers.isString(errorInfo.context)) { - throwError("context"); - } - if (errorInfo.range && - (!Array.isArray(errorInfo.range) || - (errorInfo.range.length !== 2) || - !helpers.isNumber(errorInfo.range[0]) || - (errorInfo.range[0] < 1) || - !helpers.isNumber(errorInfo.range[1]) || - (errorInfo.range[1] < 1) || - ((errorInfo.range[0] + errorInfo.range[1] - 1) > - lines[errorInfo.lineNumber - 1].length))) { - throwError("range"); - } - const fixInfo = errorInfo.fixInfo; - const cleanFixInfo = {}; - if (fixInfo) { - if (!helpers.isObject(fixInfo)) { - throwError("fixInfo"); - } - if (fixInfo.lineNumber !== undefined) { - if ((!helpers.isNumber(fixInfo.lineNumber) || - (fixInfo.lineNumber < 1) || - (fixInfo.lineNumber > lines.length))) { - throwError("fixInfo.lineNumber"); - } - cleanFixInfo.lineNumber = - fixInfo.lineNumber + frontMatterLines.length; - } - const effectiveLineNumber = fixInfo.lineNumber || errorInfo.lineNumber; - if (fixInfo.editColumn !== undefined) { - if ((!helpers.isNumber(fixInfo.editColumn) || - (fixInfo.editColumn < 1) || - (fixInfo.editColumn > - lines[effectiveLineNumber - 1].length + 1))) { - throwError("fixInfo.editColumn"); - } - cleanFixInfo.editColumn = fixInfo.editColumn; - } - if (fixInfo.deleteCount !== undefined) { - if ((!helpers.isNumber(fixInfo.deleteCount) || - (fixInfo.deleteCount < -1) || - (fixInfo.deleteCount > - lines[effectiveLineNumber - 1].length))) { - throwError("fixInfo.deleteCount"); - } - cleanFixInfo.deleteCount = fixInfo.deleteCount; - } - if (fixInfo.insertText !== undefined) { - if (!helpers.isString(fixInfo.insertText)) { - throwError("fixInfo.insertText"); - } - cleanFixInfo.insertText = fixInfo.insertText; - } - } - results.push({ - lineNumber, - "ruleName": rule.names[0], - "ruleNames": rule.names, - "ruleDescription": rule.description, - "ruleInformation": rule.information ? rule.information.href : null, - "errorDetail": errorInfo.detail || null, - "errorContext": errorInfo.context || null, - "errorRange": errorInfo.range ? [ ...errorInfo.range ] : null, - "fixInfo": fixInfo ? cleanFixInfo : null - }); - } - // Call (possibly external) rule function to report errors - const catchCallsOnError = (error) => onError({ - "lineNumber": 1, - "detail": `This rule threw an exception: ${error.message || error}` - }); - const invokeRuleFunction = () => rule.function(params, onError); - if (rule.asynchronous) { - // Asynchronous rule, ensure it returns a Promise - const ruleFunctionPromise = - Promise.resolve().then(invokeRuleFunction); - return handleRuleFailures ? - ruleFunctionPromise.catch(catchCallsOnError) : - ruleFunctionPromise; - } - // Synchronous rule - try { - invokeRuleFunction(); - } catch (error) { - if (handleRuleFailures) { - catchCallsOnError(error); - } else { - throw error; - } - } - return null; - } - // eslint-disable-next-line jsdoc/require-jsdoc - function formatResults() { - // Sort results by rule name by line number - results.sort((a, b) => ( - a.ruleName.localeCompare(b.ruleName) || - a.lineNumber - b.lineNumber - )); - if (resultVersion < 3) { - // Remove fixInfo and multiple errors for the same rule and line number - const noPrevious = { - "ruleName": null, - "lineNumber": -1 - }; - results = results.filter((error, index, array) => { - delete error.fixInfo; - const previous = array[index - 1] || noPrevious; - return ( - (error.ruleName !== previous.ruleName) || - (error.lineNumber !== previous.lineNumber) - ); - }); - } - if (resultVersion === 0) { - // Return a dictionary of rule->[line numbers] - const dictionary = {}; - for (const error of results) { - const ruleLines = dictionary[error.ruleName] || []; - ruleLines.push(error.lineNumber); - dictionary[error.ruleName] = ruleLines; - } - // @ts-ignore - results = dictionary; - } else if (resultVersion === 1) { - // Use ruleAlias instead of ruleNames - for (const error of results) { - error.ruleAlias = error.ruleNames[1] || error.ruleName; - delete error.ruleNames; - } - } else { - // resultVersion 2 or 3: Remove unwanted ruleName - for (const error of results) { - delete error.ruleName; - } - } - return results; - } - // Run all rules - const ruleListAsync = ruleList.filter((rule) => rule.asynchronous); - const ruleListSync = ruleList.filter((rule) => !rule.asynchronous); - const ruleListAsyncFirst = [ - ...ruleListAsync, - ...ruleListSync - ]; - const callbackSuccess = () => callback(null, formatResults()); - const callbackError = - (error) => callback(error instanceof Error ? error : new Error(error)); - try { - const ruleResults = ruleListAsyncFirst.map(forRule); - if (ruleListAsync.length > 0) { - Promise.all(ruleResults.slice(0, ruleListAsync.length)) - .then(callbackSuccess) - .catch(callbackError); - } else { - callbackSuccess(); - } - } catch (error) { - callbackError(error); - } finally { - cache.clear(); - } -} - -/** - * Lints a file containing Markdown content. - * - * @param {Rule[]} ruleList List of rules. - * @param {string} file Path of file to lint. - * @param {Object} md Instance of markdown-it. - * @param {Configuration} config Configuration object. - * @param {RegExp} frontMatter Regular expression for front matter. - * @param {boolean} handleRuleFailures Whether to handle exceptions in rules. - * @param {boolean} noInlineConfig Whether to allow inline configuration. - * @param {number} resultVersion Version of the LintResults object to return. - * @param {Object} fs File system implementation. - * @param {boolean} synchronous Whether to execute synchronously. - * @param {Function} callback Callback (err, result) function. - * @returns {void} - */ -function lintFile( - ruleList, - file, - md, - config, - frontMatter, - handleRuleFailures, - noInlineConfig, - resultVersion, - fs, - synchronous, - callback) { - // eslint-disable-next-line jsdoc/require-jsdoc - function lintContentWrapper(err, content) { - if (err) { - return callback(err); - } - return lintContent(ruleList, file, content, md, config, frontMatter, - handleRuleFailures, noInlineConfig, resultVersion, callback); - } - // Make a/synchronous call to read file - if (synchronous) { - lintContentWrapper(null, fs.readFileSync(file, "utf8")); - } else { - fs.readFile(file, "utf8", lintContentWrapper); - } -} - -/** - * Lint files and strings specified in the Options object. - * - * @param {Options} options Options object. - * @param {boolean} synchronous Whether to execute synchronously. - * @param {Function} callback Callback (err, result) function. - * @returns {void} - */ -function lintInput(options, synchronous, callback) { - // Normalize inputs - options = options || {}; - callback = callback || function noop() {}; - // eslint-disable-next-line unicorn/prefer-spread - const ruleList = rules.concat(options.customRules || []); - const ruleErr = validateRuleList(ruleList, synchronous); - if (ruleErr) { - return callback(ruleErr); - } - let files = []; - if (Array.isArray(options.files)) { - files = [ ...options.files ]; - } else if (options.files) { - files = [ String(options.files) ]; - } - const strings = options.strings || {}; - const stringsKeys = Object.keys(strings); - const config = options.config || { "default": true }; - const frontMatter = (options.frontMatter === undefined) ? - helpers.frontMatterRe : options.frontMatter; - const handleRuleFailures = !!options.handleRuleFailures; - const noInlineConfig = !!options.noInlineConfig; - const resultVersion = (options.resultVersion === undefined) ? - 2 : options.resultVersion; - const md = markdownIt({ "html": true }); - const markdownItPlugins = options.markdownItPlugins || []; - markdownItPlugins.forEach(function forPlugin(plugin) { - // @ts-ignore - md.use(...plugin); - }); - const fs = options.fs || __nccwpck_require__(7147); - const results = newResults(ruleList); - let done = false; - let concurrency = 0; - // eslint-disable-next-line jsdoc/require-jsdoc - function lintWorker() { - let currentItem = null; - // eslint-disable-next-line jsdoc/require-jsdoc - function lintWorkerCallback(err, result) { - concurrency--; - if (err) { - done = true; - return callback(err); - } - results[currentItem] = result; - if (!synchronous) { - lintWorker(); - } - return null; - } - if (done) { - // Abort for error or nothing left to do - } else if (files.length > 0) { - // Lint next file - concurrency++; - currentItem = files.shift(); - lintFile( - ruleList, - currentItem, - md, - config, - frontMatter, - handleRuleFailures, - noInlineConfig, - resultVersion, - fs, - synchronous, - lintWorkerCallback - ); - } else if (stringsKeys.length > 0) { - // Lint next string - concurrency++; - currentItem = stringsKeys.shift(); - lintContent( - ruleList, - currentItem, - strings[currentItem] || "", - md, - config, - frontMatter, - handleRuleFailures, - noInlineConfig, - resultVersion, - lintWorkerCallback - ); - } else if (concurrency === 0) { - // Finish - done = true; - return callback(null, results); - } - return null; - } - if (synchronous) { - while (!done) { - lintWorker(); - } - } else { - // Testing on a Raspberry Pi 4 Model B with an artificial 5ms file access - // delay suggests that a concurrency factor of 8 can eliminate the impact - // of that delay (i.e., total time is the same as with no delay). - lintWorker(); - lintWorker(); - lintWorker(); - lintWorker(); - lintWorker(); - lintWorker(); - lintWorker(); - lintWorker(); - } - return null; -} - -/** - * Lint specified Markdown files. - * - * @param {Options} options Configuration options. - * @param {LintCallback} callback Callback (err, result) function. - * @returns {void} - */ -function markdownlint(options, callback) { - return lintInput(options, false, callback); -} - -const markdownlintPromisify = promisify && promisify(markdownlint); - -/** - * Lint specified Markdown files. - * - * @param {Options} options Configuration options. - * @returns {Promise} Results object. - */ -function markdownlintPromise(options) { - return markdownlintPromisify(options); -} - -/** - * Lint specified Markdown files synchronously. - * - * @param {Options} options Configuration options. - * @returns {LintResults} Results object. - */ -function markdownlintSync(options) { - let results = null; - lintInput(options, true, function callback(error, res) { - if (error) { - throw error; - } - results = res; - }); - return results; -} - -/** - * Parse the content of a configuration file. - * - * @param {string} name Name of the configuration file. - * @param {string} content Configuration content. - * @param {ConfigurationParser[]} parsers Parsing function(s). - * @returns {Object} Configuration object and error message. - */ -function parseConfiguration(name, content, parsers) { - let config = null; - let message = ""; - const errors = []; - let index = 0; - // Try each parser - (parsers || [ JSON.parse ]).every((parser) => { - try { - config = parser(content); - } catch (error) { - errors.push(`Parser ${index++}: ${error.message}`); - } - return !config; - }); - // Message if unable to parse - if (!config) { - errors.unshift(`Unable to parse '${name}'`); - message = errors.join("; "); - } - return { - config, - message - }; -} - -/** - * Resolve referenced "extends" path in a configuration file - * using path.resolve() with require.resolve() as a fallback. - * - * @param {string} configFile Configuration file name. - * @param {string} referenceId Referenced identifier to resolve. - * @param {Object} fs File system implementation. - * @param {ResolveConfigExtendsCallback} [callback] Callback (err, result) - * function. - * @returns {void} - */ -function resolveConfigExtends(configFile, referenceId, fs, callback) { - const configFileDirname = path.dirname(configFile); - const resolvedExtendsFile = path.resolve(configFileDirname, referenceId); - fs.access(resolvedExtendsFile, (err) => { - if (err) { - // Not a file, try require.resolve - try { - return callback(null, dynamicRequire.resolve( - referenceId, - { "paths": [ configFileDirname ] } - )); - } catch { - // Unable to resolve, use resolvedExtendsFile - } - } - return callback(null, resolvedExtendsFile); - }); -} - -/** - * Resolve referenced "extends" path in a configuration file - * using path.resolve() with require.resolve() as a fallback. - * - * @param {string} configFile Configuration file name. - * @param {string} referenceId Referenced identifier to resolve. - * @param {Object} fs File system implementation. - * @returns {string} Resolved path to file. - */ -function resolveConfigExtendsSync(configFile, referenceId, fs) { - const configFileDirname = path.dirname(configFile); - const resolvedExtendsFile = path.resolve(configFileDirname, referenceId); - try { - fs.accessSync(resolvedExtendsFile); - return resolvedExtendsFile; - } catch { - // Not a file, try require.resolve - } - try { - return dynamicRequire.resolve( - referenceId, - { "paths": [ configFileDirname ] } - ); - } catch { - // Unable to resolve, return resolvedExtendsFile - } - return resolvedExtendsFile; -} - -/** - * Read specified configuration file. - * - * @param {string} file Configuration file name. - * @param {ConfigurationParser[] | ReadConfigCallback} parsers Parsing - * function(s). - * @param {Object} [fs] File system implementation. - * @param {ReadConfigCallback} [callback] Callback (err, result) function. - * @returns {void} - */ -function readConfig(file, parsers, fs, callback) { - if (!callback) { - if (fs) { - callback = fs; - fs = null; - } else { - // @ts-ignore - callback = parsers; - parsers = null; - } - } - if (!fs) { - fs = __nccwpck_require__(7147); - } - // Read file - fs.readFile(file, "utf8", (err, content) => { - if (err) { - return callback(err); - } - // Try to parse file - // @ts-ignore - const { config, message } = parseConfiguration(file, content, parsers); - if (!config) { - return callback(new Error(message)); - } - // Extend configuration - const configExtends = config.extends; - if (configExtends) { - delete config.extends; - return resolveConfigExtends( - file, - configExtends, - fs, - (_, resolvedExtends) => readConfig( - resolvedExtends, - parsers, - fs, - (errr, extendsConfig) => { - if (errr) { - return callback(errr); - } - return callback(null, { - ...extendsConfig, - ...config - }); - } - ) - ); - } - return callback(null, config); - }); -} - -const readConfigPromisify = promisify && promisify(readConfig); - -/** - * Read specified configuration file. - * - * @param {string} file Configuration file name. - * @param {ConfigurationParser[]} [parsers] Parsing function(s). - * @param {Object} [fs] File system implementation. - * @returns {Promise} Configuration object. - */ -function readConfigPromise(file, parsers, fs) { - // @ts-ignore - return readConfigPromisify(file, parsers, fs); -} - -/** - * Read specified configuration file synchronously. - * - * @param {string} file Configuration file name. - * @param {ConfigurationParser[]} [parsers] Parsing function(s). - * @param {Object} [fs] File system implementation. - * @returns {Configuration} Configuration object. - * @throws An Error if processing fails. - */ -function readConfigSync(file, parsers, fs) { - if (!fs) { - fs = __nccwpck_require__(7147); - } - // Read file - const content = fs.readFileSync(file, "utf8"); - // Try to parse file - const { config, message } = parseConfiguration(file, content, parsers); - if (!config) { - throw new Error(message); - } - // Extend configuration - const configExtends = config.extends; - if (configExtends) { - delete config.extends; - const resolvedExtends = resolveConfigExtendsSync(file, configExtends, fs); - return { - ...readConfigSync(resolvedExtends, parsers, fs), - ...config - }; - } - return config; -} - -/** - * Gets the (semantic) version of the library. - * - * @returns {string} SemVer string. - */ -function getVersion() { - return (__nccwpck_require__(5039).version); -} - -// Export a/synchronous/Promise APIs -markdownlint.sync = markdownlintSync; -markdownlint.readConfig = readConfig; -markdownlint.readConfigSync = readConfigSync; -markdownlint.getVersion = getVersion; -markdownlint.promises = { - "markdownlint": markdownlintPromise, - "readConfig": readConfigPromise -}; -module.exports = markdownlint; - -// Type declarations - -/** - * Function to implement rule logic. - * - * @callback RuleFunction - * @param {RuleParams} params Rule parameters. - * @param {RuleOnError} onError Error-reporting callback. - * @returns {void} - */ - -/** - * Rule parameters. - * - * @typedef {Object} RuleParams - * @property {string} name File/string name. - * @property {MarkdownItToken[]} tokens Token objects from markdown-it. - * @property {string[]} lines File/string lines. - * @property {string[]} frontMatterLines Front matter lines. - * @property {RuleConfiguration} config Rule configuration. - */ - -/** - * Markdown-It token. - * - * @typedef {Object} MarkdownItToken - * @property {string[][]} attrs HTML attributes. - * @property {boolean} block Block-level token. - * @property {MarkdownItToken[]} children Child nodes. - * @property {string} content Tag contents. - * @property {boolean} hidden Ignore element. - * @property {string} info Fence info. - * @property {number} level Nesting level. - * @property {number[]} map Beginning/ending line numbers. - * @property {string} markup Markup text. - * @property {Object} meta Arbitrary data. - * @property {number} nesting Level change. - * @property {string} tag HTML tag name. - * @property {string} type Token type. - * @property {number} lineNumber Line number (1-based). - * @property {string} line Line content. - */ - -/** - * Error-reporting callback. - * - * @callback RuleOnError - * @param {RuleOnErrorInfo} onErrorInfo Error information. - * @returns {void} - */ - -/** - * Fix information for RuleOnError callback. - * - * @typedef {Object} RuleOnErrorInfo - * @property {number} lineNumber Line number (1-based). - * @property {string} [detail] Detail about the error. - * @property {string} [context] Context for the error. - * @property {number[]} [range] Column number (1-based) and length. - * @property {RuleOnErrorFixInfo} [fixInfo] Fix information. - */ - -/** - * Fix information for RuleOnErrorInfo. - * - * @typedef {Object} RuleOnErrorFixInfo - * @property {number} [lineNumber] Line number (1-based). - * @property {number} [editColumn] Column of the fix (1-based). - * @property {number} [deleteCount] Count of characters to delete. - * @property {string} [insertText] Text to insert (after deleting). - */ - -/** - * Rule definition. - * - * @typedef {Object} Rule - * @property {string[]} names Rule name(s). - * @property {string} description Rule description. - * @property {URL} [information] Link to more information. - * @property {string[]} tags Rule tag(s). - * @property {boolean} [asynchronous] True if asynchronous. - * @property {RuleFunction} function Rule implementation. - */ - -/** - * Configuration options. - * - * @typedef {Object} Options - * @property {string[] | string} [files] Files to lint. - * @property {Object.} [strings] Strings to lint. - * @property {Configuration} [config] Configuration object. - * @property {Rule[] | Rule} [customRules] Custom rules. - * @property {RegExp} [frontMatter] Front matter pattern. - * @property {boolean} [handleRuleFailures] True to catch exceptions. - * @property {boolean} [noInlineConfig] True to ignore HTML directives. - * @property {number} [resultVersion] Results object version. - * @property {Plugin[]} [markdownItPlugins] Additional plugins. - * @property {Object} [fs] File system implementation. - */ - -/** - * A markdown-it plugin. - * - * @typedef {Array} Plugin - */ - -/** - * Function to pretty-print lint results. - * - * @callback ToStringCallback - * @param {boolean} [ruleAliases] True to use rule aliases. - * @returns {string} - */ - -/** - * Lint results (for resultVersion 3). - * - * @typedef {Object.} LintResults - * @property {ToStringCallback} toString String representation. - */ - -/** - * Lint error. - * - * @typedef {Object} LintError - * @property {number} lineNumber Line number (1-based). - * @property {string[]} ruleNames Rule name(s). - * @property {string} ruleDescription Rule description. - * @property {string} ruleInformation Link to more information. - * @property {string} errorDetail Detail about the error. - * @property {string} errorContext Context for the error. - * @property {number[]} errorRange Column number (1-based) and length. - * @property {FixInfo} [fixInfo] Fix information. - */ - -/** - * Fix information. - * - * @typedef {Object} FixInfo - * @property {number} [lineNumber] Line number (1-based). - * @property {number} [editColumn] Column of the fix (1-based). - * @property {number} [deleteCount] Count of characters to delete. - * @property {string} [insertText] Text to insert (after deleting). - */ - -/** - * Called with the result of the lint function. - * - * @callback LintCallback - * @param {Error | null} err Error object or null. - * @param {LintResults} [results] Lint results. - * @returns {void} - */ - -/** - * Configuration object for linting rules. For a detailed schema, see - * {@link ../schema/markdownlint-config-schema.json}. - * - * @typedef {Object.} Configuration - */ - -/** - * Rule configuration object. - * - * @typedef {boolean | Object} RuleConfiguration Rule configuration. - */ - -/** - * Parses a configuration string and returns a configuration object. - * - * @callback ConfigurationParser - * @param {string} text Configuration string. - * @returns {Configuration} - */ - -/** - * Called with the result of the readConfig function. - * - * @callback ReadConfigCallback - * @param {Error | null} err Error object or null. - * @param {Configuration} [config] Configuration object. - * @returns {void} - */ - -/** - * Called with the result of the resolveConfigExtends function. - * - * @callback ResolveConfigExtendsCallback - * @param {Error | null} err Error object or null. - * @param {string} [path] Resolved path to file. - * @returns {void} - */ - - -/***/ }), - -/***/ 3516: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorDetailIf, filterTokens } = __nccwpck_require__(2935); - -module.exports = { - "names": [ "MD001", "heading-increment", "header-increment" ], - "description": "Heading levels should only increment by one level at a time", - "tags": [ "headings", "headers" ], - "function": function MD001(params, onError) { - let prevLevel = 0; - filterTokens(params, "heading_open", function forToken(token) { - const level = Number.parseInt(token.tag.slice(1), 10); - if (prevLevel && (level > prevLevel)) { - addErrorDetailIf(onError, token.lineNumber, - "h" + (prevLevel + 1), "h" + level); - } - prevLevel = level; - }); - } -}; - - -/***/ }), - -/***/ 7706: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorDetailIf } = __nccwpck_require__(2935); - -module.exports = { - "names": [ "MD002", "first-heading-h1", "first-header-h1" ], - "description": "First heading should be a top-level heading", - "tags": [ "headings", "headers" ], - "function": function MD002(params, onError) { - const level = Number(params.config.level || 1); - const tag = "h" + level; - params.tokens.every(function forToken(token) { - if (token.type === "heading_open") { - addErrorDetailIf(onError, token.lineNumber, tag, token.tag); - return false; - } - return true; - }); - } -}; - - -/***/ }), - -/***/ 2898: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorDetailIf, filterTokens, headingStyleFor } = - __nccwpck_require__(2935); - -module.exports = { - "names": [ "MD003", "heading-style", "header-style" ], - "description": "Heading style", - "tags": [ "headings", "headers" ], - "function": function MD003(params, onError) { - let style = String(params.config.style || "consistent"); - filterTokens(params, "heading_open", function forToken(token) { - const styleForToken = headingStyleFor(token); - if (style === "consistent") { - style = styleForToken; - } - if (styleForToken !== style) { - const h12 = /h[12]/.test(token.tag); - const setextWithAtx = - (style === "setext_with_atx") && - ((h12 && (styleForToken === "setext")) || - (!h12 && (styleForToken === "atx"))); - const setextWithAtxClosed = - (style === "setext_with_atx_closed") && - ((h12 && (styleForToken === "setext")) || - (!h12 && (styleForToken === "atx_closed"))); - if (!setextWithAtx && !setextWithAtxClosed) { - let expected = style; - if (style === "setext_with_atx") { - expected = h12 ? "setext" : "atx"; - } else if (style === "setext_with_atx_closed") { - expected = h12 ? "setext" : "atx_closed"; - } - addErrorDetailIf(onError, token.lineNumber, - expected, styleForToken); - } - } - }); - } -}; - - -/***/ }), - -/***/ 3469: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorDetailIf, listItemMarkerRe, unorderedListStyleFor } = - __nccwpck_require__(2935); -const { flattenedLists } = __nccwpck_require__(3266); - -const expectedStyleToMarker = { - "dash": "-", - "plus": "+", - "asterisk": "*" -}; -const differentItemStyle = { - "dash": "plus", - "plus": "asterisk", - "asterisk": "dash" -}; -const validStyles = Object.keys(expectedStyleToMarker); - -module.exports = { - "names": [ "MD004", "ul-style" ], - "description": "Unordered list style", - "tags": [ "bullet", "ul" ], - "function": function MD004(params, onError) { - const style = String(params.config.style || "consistent"); - let expectedStyle = style; - const nestingStyles = []; - flattenedLists().forEach((list) => { - if (list.unordered) { - if (expectedStyle === "consistent") { - expectedStyle = unorderedListStyleFor(list.items[0]); - } - list.items.forEach((item) => { - const itemStyle = unorderedListStyleFor(item); - if (style === "sublist") { - const nesting = list.nesting; - if (!nestingStyles[nesting]) { - nestingStyles[nesting] = - (itemStyle === nestingStyles[nesting - 1]) ? - differentItemStyle[itemStyle] : - itemStyle; - } - expectedStyle = nestingStyles[nesting]; - } - if (!validStyles.includes(expectedStyle)) { - expectedStyle = validStyles[0]; - } - let range = null; - let fixInfo = null; - const match = item.line.match(listItemMarkerRe); - if (match) { - const column = match.index + 1; - const length = match[0].length; - range = [ column, length ]; - fixInfo = { - "editColumn": match[1].length + 1, - "deleteCount": 1, - "insertText": expectedStyleToMarker[expectedStyle] - }; - } - addErrorDetailIf( - onError, - item.lineNumber, - expectedStyle, - itemStyle, - null, - null, - range, - fixInfo - ); - }); - } - }); - } -}; - - -/***/ }), - -/***/ 1842: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addError, addErrorDetailIf, indentFor, listItemMarkerRe, - orderedListItemMarkerRe, rangeFromRegExp } = __nccwpck_require__(2935); -const { flattenedLists } = __nccwpck_require__(3266); - -module.exports = { - "names": [ "MD005", "list-indent" ], - "description": "Inconsistent indentation for list items at the same level", - "tags": [ "bullet", "ul", "indentation" ], - "function": function MD005(params, onError) { - flattenedLists().forEach((list) => { - const expectedIndent = list.indent; - let expectedEnd = 0; - let actualEnd = -1; - let endMatching = false; - list.items.forEach((item) => { - const { line, lineNumber } = item; - const actualIndent = indentFor(item); - let match = null; - if (list.unordered) { - addErrorDetailIf( - onError, - lineNumber, - expectedIndent, - actualIndent, - null, - null, - rangeFromRegExp(line, listItemMarkerRe) - // No fixInfo; MD007 handles this scenario better - ); - } else if ((match = orderedListItemMarkerRe.exec(line))) { - actualEnd = match[0].length; - expectedEnd = expectedEnd || actualEnd; - const markerLength = match[1].length + 1; - if ((expectedIndent !== actualIndent) || endMatching) { - if (expectedEnd === actualEnd) { - endMatching = true; - } else { - const detail = endMatching ? - `Expected: (${expectedEnd}); Actual: (${actualEnd})` : - `Expected: ${expectedIndent}; Actual: ${actualIndent}`; - const expected = endMatching ? - expectedEnd - markerLength : - expectedIndent; - const actual = endMatching ? - actualEnd - markerLength : - actualIndent; - addError( - onError, - lineNumber, - detail, - null, - rangeFromRegExp(line, listItemMarkerRe), - { - "editColumn": Math.min(actual, expected) + 1, - "deleteCount": Math.max(actual - expected, 0), - "insertText": "".padEnd(Math.max(expected - actual, 0)) - } - ); - } - } - } - }); - }); - } -}; - - -/***/ }), - -/***/ 2246: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorDetailIf, listItemMarkerRe, rangeFromRegExp } = - __nccwpck_require__(2935); -const { flattenedLists } = __nccwpck_require__(3266); - -module.exports = { - "names": [ "MD006", "ul-start-left" ], - "description": - "Consider starting bulleted lists at the beginning of the line", - "tags": [ "bullet", "ul", "indentation" ], - "function": function MD006(params, onError) { - flattenedLists().forEach((list) => { - if (list.unordered && !list.nesting && (list.indent !== 0)) { - list.items.forEach((item) => { - const { lineNumber, line } = item; - addErrorDetailIf( - onError, - lineNumber, - 0, - list.indent, - null, - null, - rangeFromRegExp(line, listItemMarkerRe), - { - "deleteCount": line.length - line.trimStart().length - }); - }); - } - }); - } -}; - - -/***/ }), - -/***/ 1316: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorDetailIf, indentFor, listItemMarkerRe } = - __nccwpck_require__(2935); -const { flattenedLists } = __nccwpck_require__(3266); - -module.exports = { - "names": [ "MD007", "ul-indent" ], - "description": "Unordered list indentation", - "tags": [ "bullet", "ul", "indentation" ], - "function": function MD007(params, onError) { - const indent = Number(params.config.indent || 2); - const startIndented = !!params.config.start_indented; - const startIndent = Number(params.config.start_indent || indent); - flattenedLists().forEach((list) => { - if (list.unordered && list.parentsUnordered) { - list.items.forEach((item) => { - const { lineNumber, line } = item; - const expectedIndent = - (startIndented ? startIndent : 0) + - (list.nesting * indent); - const actualIndent = indentFor(item); - let range = null; - let editColumn = 1; - const match = line.match(listItemMarkerRe); - if (match) { - range = [ 1, match[0].length ]; - editColumn += match[1].length - actualIndent; - } - addErrorDetailIf( - onError, - lineNumber, - expectedIndent, - actualIndent, - null, - null, - range, - { - editColumn, - "deleteCount": actualIndent, - "insertText": "".padEnd(expectedIndent) - }); - }); - } - }); - } -}; - - -/***/ }), - -/***/ 9798: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addError, filterTokens, forEachInlineCodeSpan, forEachLine, - includesSorted, newLineRe, numericSortAscending } = __nccwpck_require__(2935); -const { lineMetadata } = __nccwpck_require__(3266); - -module.exports = { - "names": [ "MD009", "no-trailing-spaces" ], - "description": "Trailing spaces", - "tags": [ "whitespace" ], - "function": function MD009(params, onError) { - let brSpaces = params.config.br_spaces; - brSpaces = Number((brSpaces === undefined) ? 2 : brSpaces); - const listItemEmptyLines = !!params.config.list_item_empty_lines; - const strict = !!params.config.strict; - const listItemLineNumbers = []; - if (listItemEmptyLines) { - filterTokens(params, "list_item_open", (token) => { - for (let i = token.map[0]; i < token.map[1]; i++) { - listItemLineNumbers.push(i + 1); - } - }); - listItemLineNumbers.sort(numericSortAscending); - } - const paragraphLineNumbers = []; - const codeInlineLineNumbers = []; - if (strict) { - filterTokens(params, "paragraph_open", (token) => { - for (let i = token.map[0]; i < token.map[1] - 1; i++) { - paragraphLineNumbers.push(i + 1); - } - }); - paragraphLineNumbers.sort(numericSortAscending); - filterTokens(params, "inline", (token) => { - if (token.children.some((child) => child.type === "code_inline")) { - const tokenLines = params.lines.slice(token.map[0], token.map[1]); - forEachInlineCodeSpan(tokenLines.join("\n"), (code, lineIndex) => { - const codeLineCount = code.split(newLineRe).length; - for (let i = 0; i < codeLineCount; i++) { - codeInlineLineNumbers.push(token.lineNumber + lineIndex + i); - } - }); - } - }); - codeInlineLineNumbers.sort(numericSortAscending); - } - const expected = (brSpaces < 2) ? 0 : brSpaces; - forEachLine(lineMetadata(), (line, lineIndex, inCode) => { - const lineNumber = lineIndex + 1; - const trailingSpaces = line.length - line.trimEnd().length; - if ( - trailingSpaces && - !inCode && - !includesSorted(listItemLineNumbers, lineNumber) && - ( - (expected !== trailingSpaces) || - (strict && - (!includesSorted(paragraphLineNumbers, lineNumber) || - includesSorted(codeInlineLineNumbers, lineNumber))) - ) - ) { - const column = line.length - trailingSpaces + 1; - addError( - onError, - lineNumber, - "Expected: " + (expected === 0 ? "" : "0 or ") + - expected + "; Actual: " + trailingSpaces, - null, - [ column, trailingSpaces ], - { - "editColumn": column, - "deleteCount": trailingSpaces - }); - } - }); - } -}; - - -/***/ }), - -/***/ 9059: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addError, forEachLine, overlapsAnyRange } = __nccwpck_require__(2935); -const { codeBlockAndSpanRanges, lineMetadata } = __nccwpck_require__(3266); - -const tabRe = /\t+/g; - -module.exports = { - "names": [ "MD010", "no-hard-tabs" ], - "description": "Hard tabs", - "tags": [ "whitespace", "hard_tab" ], - "function": function MD010(params, onError) { - const codeBlocks = params.config.code_blocks; - const includeCode = (codeBlocks === undefined) ? true : !!codeBlocks; - const spacesPerTab = params.config.spaces_per_tab; - const spaceMultiplier = (spacesPerTab === undefined) ? - 1 : - Math.max(0, Number(spacesPerTab)); - const exclusions = includeCode ? [] : codeBlockAndSpanRanges(); - forEachLine(lineMetadata(), (line, lineIndex, inCode) => { - if (includeCode || !inCode) { - let match = null; - while ((match = tabRe.exec(line)) !== null) { - const { index } = match; - const column = index + 1; - const length = match[0].length; - if (!overlapsAnyRange(exclusions, lineIndex, index, length)) { - addError( - onError, - lineIndex + 1, - "Column: " + column, - null, - [ column, length ], - { - "editColumn": column, - "deleteCount": length, - "insertText": "".padEnd(length * spaceMultiplier) - } - ); - } - } - } - }); - } -}; - - -/***/ }), - -/***/ 1813: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addError, forEachLine, overlapsAnyRange } = __nccwpck_require__(2935); -const { codeBlockAndSpanRanges, lineMetadata } = __nccwpck_require__(3266); - -const reversedLinkRe = - /(^|[^\\])\(([^)]+)\)\[([^\]^][^\]]*)](?!\()/g; - -module.exports = { - "names": [ "MD011", "no-reversed-links" ], - "description": "Reversed link syntax", - "tags": [ "links" ], - "function": function MD011(params, onError) { - const exclusions = codeBlockAndSpanRanges(); - forEachLine(lineMetadata(), (line, lineIndex, inCode, onFence) => { - if (!inCode && !onFence) { - let match = null; - while ((match = reversedLinkRe.exec(line)) !== null) { - const [ reversedLink, preChar, linkText, linkDestination ] = match; - const index = match.index + preChar.length; - const length = match[0].length - preChar.length; - if ( - !linkText.endsWith("\\") && - !linkDestination.endsWith("\\") && - !overlapsAnyRange(exclusions, lineIndex, index, length) - ) { - addError( - onError, - lineIndex + 1, - reversedLink.slice(preChar.length), - null, - [ index + 1, length ], - { - "editColumn": index + 1, - "deleteCount": length, - "insertText": `[${linkText}](${linkDestination})` - } - ); - } - } - } - }); - } -}; - - -/***/ }), - -/***/ 3347: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorDetailIf, forEachLine } = __nccwpck_require__(2935); -const { lineMetadata } = __nccwpck_require__(3266); - -module.exports = { - "names": [ "MD012", "no-multiple-blanks" ], - "description": "Multiple consecutive blank lines", - "tags": [ "whitespace", "blank_lines" ], - "function": function MD012(params, onError) { - const maximum = Number(params.config.maximum || 1); - let count = 0; - forEachLine(lineMetadata(), (line, lineIndex, inCode) => { - count = (inCode || (line.trim().length > 0)) ? 0 : count + 1; - if (maximum < count) { - addErrorDetailIf( - onError, - lineIndex + 1, - maximum, - count, - null, - null, - null, - { - "deleteCount": -1 - }); - } - }); - } -}; - - -/***/ }), - -/***/ 9811: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorDetailIf, filterTokens, forEachHeading, forEachLine, - includesSorted } = __nccwpck_require__(2935); -const { lineMetadata } = __nccwpck_require__(3266); - -const longLineRePrefix = "^.{"; -const longLineRePostfixRelaxed = "}.*\\s.*$"; -const longLineRePostfixStrict = "}.+$"; -const labelRe = /^\s*\[.*[^\\]]:/; -const linkOrImageOnlyLineRe = /^[es]*(lT?L|I)[ES]*$/; -const sternModeRe = /^([#>\s]*\s)?\S*$/; -const tokenTypeMap = { - "em_open": "e", - "em_close": "E", - "image": "I", - "link_open": "l", - "link_close": "L", - "strong_open": "s", - "strong_close": "S", - "text": "T" -}; - -module.exports = { - "names": [ "MD013", "line-length" ], - "description": "Line length", - "tags": [ "line_length" ], - "function": function MD013(params, onError) { - const lineLength = Number(params.config.line_length || 80); - const headingLineLength = - Number(params.config.heading_line_length || lineLength); - const codeLineLength = - Number(params.config.code_block_line_length || lineLength); - const strict = !!params.config.strict; - const stern = !!params.config.stern; - const longLineRePostfix = - (strict || stern) ? longLineRePostfixStrict : longLineRePostfixRelaxed; - const longLineRe = - new RegExp(longLineRePrefix + lineLength + longLineRePostfix); - const longHeadingLineRe = - new RegExp(longLineRePrefix + headingLineLength + longLineRePostfix); - const longCodeLineRe = - new RegExp(longLineRePrefix + codeLineLength + longLineRePostfix); - const codeBlocks = params.config.code_blocks; - const includeCodeBlocks = (codeBlocks === undefined) ? true : !!codeBlocks; - const tables = params.config.tables; - const includeTables = (tables === undefined) ? true : !!tables; - let headings = params.config.headings; - if (headings === undefined) { - headings = params.config.headers; - } - const includeHeadings = (headings === undefined) ? true : !!headings; - const headingLineNumbers = []; - forEachHeading(params, (heading) => { - headingLineNumbers.push(heading.lineNumber); - }); - const linkOnlyLineNumbers = []; - filterTokens(params, "inline", (token) => { - let childTokenTypes = ""; - token.children.forEach((child) => { - if (child.type !== "text" || child.content !== "") { - childTokenTypes += tokenTypeMap[child.type] || "x"; - } - }); - if (linkOrImageOnlyLineRe.test(childTokenTypes)) { - linkOnlyLineNumbers.push(token.lineNumber); - } - }); - forEachLine(lineMetadata(), (line, lineIndex, inCode, onFence, inTable) => { - const lineNumber = lineIndex + 1; - const isHeading = includesSorted(headingLineNumbers, lineNumber); - const length = inCode ? - codeLineLength : - (isHeading ? headingLineLength : lineLength); - const lengthRe = inCode ? - longCodeLineRe : - (isHeading ? longHeadingLineRe : longLineRe); - if ((includeCodeBlocks || !inCode) && - (includeTables || !inTable) && - (includeHeadings || !isHeading) && - (strict || - (!(stern && sternModeRe.test(line)) && - !includesSorted(linkOnlyLineNumbers, lineNumber) && - !labelRe.test(line))) && - lengthRe.test(line)) { - addErrorDetailIf( - onError, - lineNumber, - length, - line.length, - null, - null, - [ length + 1, line.length - length ]); - } - }); - } -}; - - -/***/ }), - -/***/ 1004: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorContext, filterTokens } = __nccwpck_require__(2935); - -const dollarCommandRe = /^(\s*)(\$\s+)/; - -module.exports = { - "names": [ "MD014", "commands-show-output" ], - "description": "Dollar signs used before commands without showing output", - "tags": [ "code" ], - "function": function MD014(params, onError) { - [ "code_block", "fence" ].forEach((type) => { - filterTokens(params, type, (token) => { - const margin = (token.type === "fence") ? 1 : 0; - const dollarInstances = []; - let allDollars = true; - for (let i = token.map[0] + margin; i < token.map[1] - margin; i++) { - const line = params.lines[i]; - const lineTrim = line.trim(); - if (lineTrim) { - const match = dollarCommandRe.exec(line); - if (match) { - const column = match[1].length + 1; - const length = match[2].length; - dollarInstances.push([ i, lineTrim, column, length ]); - } else { - allDollars = false; - } - } - } - if (allDollars) { - dollarInstances.forEach((instance) => { - const [ i, lineTrim, column, length ] = instance; - addErrorContext( - onError, - i + 1, - lineTrim, - null, - null, - [ column, length ], - { - "editColumn": column, - "deleteCount": length - } - ); - }); - } - }); - }); - } -}; - - -/***/ }), - -/***/ 2450: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorContext, forEachLine } = __nccwpck_require__(2935); -const { lineMetadata } = __nccwpck_require__(3266); - -module.exports = { - "names": [ "MD018", "no-missing-space-atx" ], - "description": "No space after hash on atx style heading", - "tags": [ "headings", "headers", "atx", "spaces" ], - "function": function MD018(params, onError) { - forEachLine(lineMetadata(), (line, lineIndex, inCode) => { - if (!inCode && - /^#+[^# \t]/.test(line) && - !/#\s*$/.test(line) && - !line.startsWith("#️⃣")) { - const hashCount = /^#+/.exec(line)[0].length; - addErrorContext( - onError, - lineIndex + 1, - line.trim(), - null, - null, - [ 1, hashCount + 1 ], - { - "editColumn": hashCount + 1, - "insertText": " " - } - ); - } - }); - } -}; - - -/***/ }), - -/***/ 1803: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorContext, filterTokens, headingStyleFor } = - __nccwpck_require__(2935); - -module.exports = { - "names": [ "MD019", "no-multiple-space-atx" ], - "description": "Multiple spaces after hash on atx style heading", - "tags": [ "headings", "headers", "atx", "spaces" ], - "function": function MD019(params, onError) { - filterTokens(params, "heading_open", (token) => { - if (headingStyleFor(token) === "atx") { - const { line, lineNumber } = token; - const match = /^(#+)([ \t]{2,})(?:\S)/.exec(line); - if (match) { - const [ - , - { "length": hashLength }, - { "length": spacesLength } - ] = match; - addErrorContext( - onError, - lineNumber, - line.trim(), - null, - null, - [ 1, hashLength + spacesLength + 1 ], - { - "editColumn": hashLength + 1, - "deleteCount": spacesLength - 1 - } - ); - } - } - }); - } -}; - - -/***/ }), - -/***/ 9799: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorContext, forEachLine } = __nccwpck_require__(2935); -const { lineMetadata } = __nccwpck_require__(3266); - -module.exports = { - "names": [ "MD020", "no-missing-space-closed-atx" ], - "description": "No space inside hashes on closed atx style heading", - "tags": [ "headings", "headers", "atx_closed", "spaces" ], - "function": function MD020(params, onError) { - forEachLine(lineMetadata(), (line, lineIndex, inCode) => { - if (!inCode) { - const match = - /^(#+)([ \t]*)([^#]*?[^#\\])([ \t]*)((?:\\#)?)(#+)(\s*)$/.exec(line); - if (match) { - const [ - , - leftHash, - { "length": leftSpaceLength }, - content, - { "length": rightSpaceLength }, - rightEscape, - rightHash, - { "length": trailSpaceLength } - ] = match; - const leftHashLength = leftHash.length; - const rightHashLength = rightHash.length; - const left = !leftSpaceLength; - const right = !rightSpaceLength || rightEscape; - const rightEscapeReplacement = rightEscape ? `${rightEscape} ` : ""; - if (left || right) { - const range = left ? - [ - 1, - leftHashLength + 1 - ] : - [ - line.length - trailSpaceLength - rightHashLength, - rightHashLength + 1 - ]; - addErrorContext( - onError, - lineIndex + 1, - line.trim(), - left, - right, - range, - { - "editColumn": 1, - "deleteCount": line.length, - "insertText": - `${leftHash} ${content} ${rightEscapeReplacement}${rightHash}` - } - ); - } - } - } - }); - } -}; - - -/***/ }), - -/***/ 385: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorContext, filterTokens, headingStyleFor } = - __nccwpck_require__(2935); - -module.exports = { - "names": [ "MD021", "no-multiple-space-closed-atx" ], - "description": "Multiple spaces inside hashes on closed atx style heading", - "tags": [ "headings", "headers", "atx_closed", "spaces" ], - "function": function MD021(params, onError) { - filterTokens(params, "heading_open", (token) => { - if (headingStyleFor(token) === "atx_closed") { - const { line, lineNumber } = token; - const match = /^(#+)([ \t]+)([^#]+?)([ \t]+)(#+)(\s*)$/.exec(line); - if (match) { - const [ - , - leftHash, - { "length": leftSpaceLength }, - content, - { "length": rightSpaceLength }, - rightHash, - { "length": trailSpaceLength } - ] = match; - const left = leftSpaceLength > 1; - const right = rightSpaceLength > 1; - if (left || right) { - const length = line.length; - const leftHashLength = leftHash.length; - const rightHashLength = rightHash.length; - const range = left ? - [ - 1, - leftHashLength + leftSpaceLength + 1 - ] : - [ - length - trailSpaceLength - rightHashLength - rightSpaceLength, - rightSpaceLength + rightHashLength + 1 - ]; - addErrorContext( - onError, - lineNumber, - line.trim(), - left, - right, - range, - { - "editColumn": 1, - "deleteCount": length, - "insertText": `${leftHash} ${content} ${rightHash}` - } - ); - } - } - } - }); - } -}; - - -/***/ }), - -/***/ 6836: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorDetailIf, filterTokens, isBlankLine } = __nccwpck_require__(2935); - -module.exports = { - "names": [ "MD022", "blanks-around-headings", "blanks-around-headers" ], - "description": "Headings should be surrounded by blank lines", - "tags": [ "headings", "headers", "blank_lines" ], - "function": function MD022(params, onError) { - let linesAbove = params.config.lines_above; - linesAbove = Number((linesAbove === undefined) ? 1 : linesAbove); - let linesBelow = params.config.lines_below; - linesBelow = Number((linesBelow === undefined) ? 1 : linesBelow); - const { lines } = params; - filterTokens(params, "heading_open", (token) => { - const [ topIndex, nextIndex ] = token.map; - let actualAbove = 0; - for (let i = 0; i < linesAbove; i++) { - if (isBlankLine(lines[topIndex - i - 1])) { - actualAbove++; - } - } - addErrorDetailIf( - onError, - topIndex + 1, - linesAbove, - actualAbove, - "Above", - lines[topIndex].trim(), - null, - { - "insertText": "".padEnd(linesAbove - actualAbove, "\n") - }); - let actualBelow = 0; - for (let i = 0; i < linesBelow; i++) { - if (isBlankLine(lines[nextIndex + i])) { - actualBelow++; - } - } - addErrorDetailIf( - onError, - topIndex + 1, - linesBelow, - actualBelow, - "Below", - lines[topIndex].trim(), - null, - { - "lineNumber": nextIndex + 1, - "insertText": "".padEnd(linesBelow - actualBelow, "\n") - }); - }); - } -}; - - -/***/ }), - -/***/ 6313: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorContext, filterTokens } = __nccwpck_require__(2935); - -const spaceBeforeHeadingRe = /^((?:\s+)|(?:[>\s]+\s\s))[^>\s]/; - -module.exports = { - "names": [ "MD023", "heading-start-left", "header-start-left" ], - "description": "Headings must start at the beginning of the line", - "tags": [ "headings", "headers", "spaces" ], - "function": function MD023(params, onError) { - filterTokens(params, "heading_open", function forToken(token) { - const { lineNumber, line } = token; - const match = line.match(spaceBeforeHeadingRe); - if (match) { - const [ prefixAndFirstChar, prefix ] = match; - let deleteCount = prefix.length; - const prefixLengthNoSpace = prefix.trimEnd().length; - if (prefixLengthNoSpace) { - deleteCount -= prefixLengthNoSpace - 1; - } - addErrorContext( - onError, - lineNumber, - line, - null, - null, - [ 1, prefixAndFirstChar.length ], - { - "editColumn": prefixLengthNoSpace + 1, - "deleteCount": deleteCount - }); - } - }); - } -}; - - -/***/ }), - -/***/ 2822: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorContext, forEachHeading } = __nccwpck_require__(2935); - -module.exports = { - "names": [ "MD024", "no-duplicate-heading", "no-duplicate-header" ], - "description": "Multiple headings with the same content", - "tags": [ "headings", "headers" ], - "function": function MD024(params, onError) { - const siblingsOnly = !!params.config.siblings_only || - !!params.config.allow_different_nesting || false; - const knownContents = [ null, [] ]; - let lastLevel = 1; - let knownContent = knownContents[lastLevel]; - forEachHeading(params, (heading, content) => { - if (siblingsOnly) { - const newLevel = heading.tag.slice(1); - while (lastLevel < newLevel) { - lastLevel++; - knownContents[lastLevel] = []; - } - while (lastLevel > newLevel) { - knownContents[lastLevel] = []; - lastLevel--; - } - knownContent = knownContents[newLevel]; - } - if (knownContent.includes(content)) { - addErrorContext(onError, heading.lineNumber, - heading.line.trim()); - } else { - knownContent.push(content); - } - }); - } -}; - - -/***/ }), - -/***/ 2785: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorContext, filterTokens, frontMatterHasTitle } = - __nccwpck_require__(2935); - -module.exports = { - "names": [ "MD025", "single-title", "single-h1" ], - "description": "Multiple top-level headings in the same document", - "tags": [ "headings", "headers" ], - "function": function MD025(params, onError) { - const level = Number(params.config.level || 1); - const tag = "h" + level; - const foundFrontMatterTitle = - frontMatterHasTitle( - params.frontMatterLines, - params.config.front_matter_title - ); - let hasTopLevelHeading = false; - filterTokens(params, "heading_open", function forToken(token) { - if (token.tag === tag) { - if (hasTopLevelHeading || foundFrontMatterTitle) { - addErrorContext(onError, token.lineNumber, - token.line.trim()); - } else if (token.lineNumber === 1) { - hasTopLevelHeading = true; - } - } - }); - } -}; - - -/***/ }), - -/***/ 3782: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addError, allPunctuationNoQuestion, escapeForRegExp, forEachHeading } = - __nccwpck_require__(2935); - -const endOfLineHtmlEntityRe = /&#?[0-9a-zA-Z]+;$/; - -module.exports = { - "names": [ "MD026", "no-trailing-punctuation" ], - "description": "Trailing punctuation in heading", - "tags": [ "headings", "headers" ], - "function": function MD026(params, onError) { - let punctuation = params.config.punctuation; - punctuation = String( - (punctuation === undefined) ? allPunctuationNoQuestion : punctuation - ); - const trailingPunctuationRe = - new RegExp("\\s*[" + escapeForRegExp(punctuation) + "]+$"); - forEachHeading(params, (heading) => { - const { line, lineNumber } = heading; - const trimmedLine = line.replace(/[\s#]*$/, ""); - const match = trailingPunctuationRe.exec(trimmedLine); - if (match && !endOfLineHtmlEntityRe.test(trimmedLine)) { - const fullMatch = match[0]; - const column = match.index + 1; - const length = fullMatch.length; - addError( - onError, - lineNumber, - `Punctuation: '${fullMatch}'`, - null, - [ column, length ], - { - "editColumn": column, - "deleteCount": length - } - ); - } - }); - } -}; - - -/***/ }), - -/***/ 2923: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorContext, newLineRe } = __nccwpck_require__(2935); - -const spaceAfterBlockQuoteRe = /^((?:\s*>)+)(\s{2,})\S/; - -module.exports = { - "names": [ "MD027", "no-multiple-space-blockquote" ], - "description": "Multiple spaces after blockquote symbol", - "tags": [ "blockquote", "whitespace", "indentation" ], - "function": function MD027(params, onError) { - let blockquoteNesting = 0; - let listItemNesting = 0; - params.tokens.forEach((token) => { - const { content, lineNumber, type } = token; - if (type === "blockquote_open") { - blockquoteNesting++; - } else if (type === "blockquote_close") { - blockquoteNesting--; - } else if (type === "list_item_open") { - listItemNesting++; - } else if (type === "list_item_close") { - listItemNesting--; - } else if ((type === "inline") && blockquoteNesting) { - const lineCount = content.split(newLineRe).length; - for (let i = 0; i < lineCount; i++) { - const line = params.lines[lineNumber + i - 1]; - const match = line.match(spaceAfterBlockQuoteRe); - if (match) { - const [ - fullMatch, - { "length": blockquoteLength }, - { "length": spaceLength } - ] = match; - if (!listItemNesting || (fullMatch[fullMatch.length - 1] === ">")) { - addErrorContext( - onError, - lineNumber + i, - line, - null, - null, - [ 1, fullMatch.length ], - { - "editColumn": blockquoteLength + 1, - "deleteCount": spaceLength - 1 - } - ); - } - } - } - } - }); - } -}; - - -/***/ }), - -/***/ 333: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addError } = __nccwpck_require__(2935); - -module.exports = { - "names": [ "MD028", "no-blanks-blockquote" ], - "description": "Blank line inside blockquote", - "tags": [ "blockquote", "whitespace" ], - "function": function MD028(params, onError) { - let prevToken = {}; - let prevLineNumber = null; - params.tokens.forEach(function forToken(token) { - if ((token.type === "blockquote_open") && - (prevToken.type === "blockquote_close")) { - for ( - let lineNumber = prevLineNumber; - lineNumber < token.lineNumber; - lineNumber++) { - addError(onError, lineNumber); - } - } - prevToken = token; - if (token.type === "blockquote_open") { - prevLineNumber = token.map[1] + 1; - } - }); - } -}; - - -/***/ }), - -/***/ 8278: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorDetailIf, listItemMarkerRe, orderedListItemMarkerRe, - rangeFromRegExp } = __nccwpck_require__(2935); -const { flattenedLists } = __nccwpck_require__(3266); - -const listStyleExamples = { - "one": "1/1/1", - "ordered": "1/2/3", - "zero": "0/0/0" -}; - -module.exports = { - "names": [ "MD029", "ol-prefix" ], - "description": "Ordered list item prefix", - "tags": [ "ol" ], - "function": function MD029(params, onError) { - const style = String(params.config.style || "one_or_ordered"); - flattenedLists().filter((list) => !list.unordered).forEach((list) => { - const { items } = list; - let current = 1; - let incrementing = false; - // Check for incrementing number pattern 1/2/3 or 0/1/2 - if (items.length >= 2) { - const first = orderedListItemMarkerRe.exec(items[0].line); - const second = orderedListItemMarkerRe.exec(items[1].line); - if (first && second) { - const [ , firstNumber ] = first; - const [ , secondNumber ] = second; - if ((secondNumber !== "1") || (firstNumber === "0")) { - incrementing = true; - if (firstNumber === "0") { - current = 0; - } - } - } - } - // Determine effective style - let listStyle = style; - if (listStyle === "one_or_ordered") { - listStyle = incrementing ? "ordered" : "one"; - } - // Force expected value for 0/0/0 and 1/1/1 patterns - if (listStyle === "zero") { - current = 0; - } else if (listStyle === "one") { - current = 1; - } - // Validate each list item marker - items.forEach((item) => { - const match = orderedListItemMarkerRe.exec(item.line); - if (match) { - addErrorDetailIf(onError, item.lineNumber, - String(current), match[1], - "Style: " + listStyleExamples[listStyle], null, - rangeFromRegExp(item.line, listItemMarkerRe)); - if (listStyle === "ordered") { - current++; - } - } - }); - }); - } -}; - - -/***/ }), - -/***/ 4156: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorDetailIf } = __nccwpck_require__(2935); -const { flattenedLists } = __nccwpck_require__(3266); - -module.exports = { - "names": [ "MD030", "list-marker-space" ], - "description": "Spaces after list markers", - "tags": [ "ol", "ul", "whitespace" ], - "function": function MD030(params, onError) { - const ulSingle = Number(params.config.ul_single || 1); - const olSingle = Number(params.config.ol_single || 1); - const ulMulti = Number(params.config.ul_multi || 1); - const olMulti = Number(params.config.ol_multi || 1); - flattenedLists().forEach((list) => { - const lineCount = list.lastLineIndex - list.open.map[0]; - const allSingle = lineCount === list.items.length; - const expectedSpaces = list.unordered ? - (allSingle ? ulSingle : ulMulti) : - (allSingle ? olSingle : olMulti); - list.items.forEach((item) => { - const { line, lineNumber } = item; - const match = /^[\s>]*\S+(\s*)/.exec(line); - const [ { "length": matchLength }, { "length": actualSpaces } ] = match; - if (matchLength < line.length) { - let fixInfo = null; - if (expectedSpaces !== actualSpaces) { - fixInfo = { - "editColumn": matchLength - actualSpaces + 1, - "deleteCount": actualSpaces, - "insertText": "".padEnd(expectedSpaces) - }; - } - addErrorDetailIf( - onError, - lineNumber, - expectedSpaces, - actualSpaces, - null, - null, - [ 1, matchLength ], - fixInfo - ); - } - }); - }); - } -}; - - -/***/ }), - -/***/ 8578: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorContext, forEachLine, isBlankLine } = __nccwpck_require__(2935); -const { lineMetadata } = __nccwpck_require__(3266); - -const codeFencePrefixRe = /^(.*?)\s*[`~]/; - -module.exports = { - "names": [ "MD031", "blanks-around-fences" ], - "description": "Fenced code blocks should be surrounded by blank lines", - "tags": [ "code", "blank_lines" ], - "function": function MD031(params, onError) { - const listItems = params.config.list_items; - const includeListItems = (listItems === undefined) ? true : !!listItems; - const { lines } = params; - forEachLine(lineMetadata(), (line, i, inCode, onFence, inTable, inItem) => { - const onTopFence = (onFence > 0); - const onBottomFence = (onFence < 0); - if ((includeListItems || !inItem) && - ((onTopFence && !isBlankLine(lines[i - 1])) || - (onBottomFence && !isBlankLine(lines[i + 1])))) { - const [ , prefix ] = line.match(codeFencePrefixRe) || []; - const fixInfo = (prefix === undefined) ? null : { - "lineNumber": i + (onTopFence ? 1 : 2), - "insertText": `${prefix}\n` - }; - addErrorContext( - onError, - i + 1, - lines[i].trim(), - null, - null, - null, - fixInfo); - } - }); - } -}; - - -/***/ }), - -/***/ 995: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorContext, isBlankLine } = __nccwpck_require__(2935); -const { flattenedLists } = __nccwpck_require__(3266); - -const quotePrefixRe = /^[>\s]*/; - -module.exports = { - "names": [ "MD032", "blanks-around-lists" ], - "description": "Lists should be surrounded by blank lines", - "tags": [ "bullet", "ul", "ol", "blank_lines" ], - "function": function MD032(params, onError) { - const { lines } = params; - flattenedLists().filter((list) => !list.nesting).forEach((list) => { - const firstIndex = list.open.map[0]; - if (!isBlankLine(lines[firstIndex - 1])) { - const line = lines[firstIndex]; - const quotePrefix = line.match(quotePrefixRe)[0].trimEnd(); - addErrorContext( - onError, - firstIndex + 1, - line.trim(), - null, - null, - null, - { - "insertText": `${quotePrefix}\n` - }); - } - const lastIndex = list.lastLineIndex - 1; - if (!isBlankLine(lines[lastIndex + 1])) { - const line = lines[lastIndex]; - const quotePrefix = line.match(quotePrefixRe)[0].trimEnd(); - addErrorContext( - onError, - lastIndex + 1, - line.trim(), - null, - null, - null, - { - "lineNumber": lastIndex + 2, - "insertText": `${quotePrefix}\n` - }); - } - }); - } -}; - - -/***/ }), - -/***/ 4167: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { - addError, forEachLine, overlapsAnyRange, unescapeMarkdown -} = __nccwpck_require__(2935); -const { codeBlockAndSpanRanges, lineMetadata } = __nccwpck_require__(3266); - -const htmlElementRe = /<(([A-Za-z][A-Za-z0-9-]*)(?:\s[^>]*)?)\/?>/g; -const linkDestinationRe = /]\(\s*$/; -// See https://spec.commonmark.org/0.29/#autolinks -const emailAddressRe = - // eslint-disable-next-line max-len - /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; - -module.exports = { - "names": [ "MD033", "no-inline-html" ], - "description": "Inline HTML", - "tags": [ "html" ], - "function": function MD033(params, onError) { - let allowedElements = params.config.allowed_elements; - allowedElements = Array.isArray(allowedElements) ? allowedElements : []; - allowedElements = allowedElements.map((element) => element.toLowerCase()); - const exclusions = codeBlockAndSpanRanges(); - forEachLine(lineMetadata(), (line, lineIndex, inCode) => { - let match = null; - // eslint-disable-next-line no-unmodified-loop-condition - while (!inCode && ((match = htmlElementRe.exec(line)) !== null)) { - const [ tag, content, element ] = match; - if ( - !allowedElements.includes(element.toLowerCase()) && - !tag.endsWith("\\>") && - !emailAddressRe.test(content) && - !overlapsAnyRange(exclusions, lineIndex, match.index, match[0].length) - ) { - const prefix = line.substring(0, match.index); - if (!linkDestinationRe.test(prefix)) { - const unescaped = unescapeMarkdown(prefix + "<", "_"); - if (!unescaped.endsWith("_")) { - addError(onError, lineIndex + 1, "Element: " + element, - null, [ match.index + 1, tag.length ]); - } - } - } - } - }); - } -}; - - -/***/ }), - -/***/ 4222: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorContext, bareUrlRe, filterTokens } = __nccwpck_require__(2935); - -module.exports = { - "names": [ "MD034", "no-bare-urls" ], - "description": "Bare URL used", - "tags": [ "links", "url" ], - "function": function MD034(params, onError) { - filterTokens(params, "inline", (token) => { - let inLink = false; - token.children.forEach((child) => { - const { content, line, lineNumber, type } = child; - let match = null; - if (type === "link_open") { - inLink = true; - } else if (type === "link_close") { - inLink = false; - } else if ((type === "text") && !inLink) { - while ((match = bareUrlRe.exec(content)) !== null) { - const [ bareUrl ] = match; - const matchIndex = match.index; - const bareUrlLength = bareUrl.length; - // Allow "[https://example.com]" to avoid conflicts with - // MD011/no-reversed-links; allow quoting as another way - // of deliberately including a bare URL - const leftChar = content[matchIndex - 1]; - const rightChar = content[matchIndex + bareUrlLength]; - if ( - !((leftChar === "[") && (rightChar === "]")) && - !((leftChar === "\"") && (rightChar === "\"")) && - !((leftChar === "'") && (rightChar === "'")) - ) { - const index = line.indexOf(content); - const range = (index === -1) ? null : [ - index + matchIndex + 1, - bareUrlLength - ]; - const fixInfo = range ? { - "editColumn": range[0], - "deleteCount": range[1], - "insertText": `<${bareUrl}>` - } : null; - addErrorContext( - onError, - lineNumber, - bareUrl, - null, - null, - range, - fixInfo - ); - } - } - } - }); - }); - } -}; - - -/***/ }), - -/***/ 2936: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorDetailIf, filterTokens } = __nccwpck_require__(2935); - -module.exports = { - "names": [ "MD035", "hr-style" ], - "description": "Horizontal rule style", - "tags": [ "hr" ], - "function": function MD035(params, onError) { - let style = String(params.config.style || "consistent"); - filterTokens(params, "hr", (token) => { - const { lineNumber, markup } = token; - if (style === "consistent") { - style = markup; - } - addErrorDetailIf(onError, lineNumber, style, markup); - }); - } -}; - - -/***/ }), - -/***/ 6626: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorContext, allPunctuation } = __nccwpck_require__(2935); - -module.exports = { - "names": [ "MD036", "no-emphasis-as-heading", "no-emphasis-as-header" ], - "description": "Emphasis used instead of a heading", - "tags": [ "headings", "headers", "emphasis" ], - "function": function MD036(params, onError) { - let punctuation = params.config.punctuation; - punctuation = - String((punctuation === undefined) ? allPunctuation : punctuation); - const re = new RegExp("[" + punctuation + "]$"); - // eslint-disable-next-line jsdoc/require-jsdoc - function base(token) { - if (token.type === "paragraph_open") { - return function inParagraph(t) { - // Always paragraph_open/inline/paragraph_close, - const children = t.children.filter(function notEmptyText(child) { - return (child.type !== "text") || (child.content !== ""); - }); - if ((children.length === 3) && - ((children[0].type === "strong_open") || - (children[0].type === "em_open")) && - (children[1].type === "text") && - !re.test(children[1].content)) { - addErrorContext(onError, t.lineNumber, - children[1].content); - } - return base; - }; - } else if (token.type === "blockquote_open") { - return function inBlockquote(t) { - if (t.type !== "blockquote_close") { - return inBlockquote; - } - return base; - }; - } else if (token.type === "list_item_open") { - return function inListItem(t) { - if (t.type !== "list_item_close") { - return inListItem; - } - return base; - }; - } - return base; - } - let state = base; - params.tokens.forEach(function forToken(token) { - state = state(token); - }); - } -}; - - -/***/ }), - -/***/ 1706: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorContext, emphasisMarkersInContent, forEachLine, isBlankLine } = - __nccwpck_require__(2935); -const { lineMetadata } = __nccwpck_require__(3266); - -const emphasisRe = /(^|[^\\]|\\\\)(?:(\*\*?\*?)|(__?_?))/g; -const embeddedUnderscoreRe = /([A-Za-z0-9])_([A-Za-z0-9])/g; -const asteriskListItemMarkerRe = /^([\s>]*)\*(\s+)/; -const leftSpaceRe = /^\s+/; -const rightSpaceRe = /\s+$/; -const tablePipeRe = /\|/; - -module.exports = { - "names": [ "MD037", "no-space-in-emphasis" ], - "description": "Spaces inside emphasis markers", - "tags": [ "whitespace", "emphasis" ], - "function": function MD037(params, onError) { - // eslint-disable-next-line init-declarations - let effectiveEmphasisLength, emphasisIndex, emphasisKind, emphasisLength, - pendingError = null; - // eslint-disable-next-line jsdoc/require-jsdoc - function resetRunTracking() { - emphasisIndex = -1; - emphasisLength = 0; - emphasisKind = ""; - effectiveEmphasisLength = 0; - pendingError = null; - } - // eslint-disable-next-line jsdoc/require-jsdoc - function handleRunEnd( - line, lineIndex, contextLength, match, matchIndex, inTable - ) { - // Close current run - let content = line.substring(emphasisIndex, matchIndex); - if (!emphasisLength) { - content = content.trimStart(); - } - if (!match) { - content = content.trimEnd(); - } - const leftSpace = leftSpaceRe.test(content); - const rightSpace = rightSpaceRe.test(content); - if ( - (leftSpace || rightSpace) && - (!inTable || !tablePipeRe.test(content)) - ) { - // Report the violation - const contextStart = emphasisIndex - emphasisLength; - const contextEnd = matchIndex + contextLength; - const context = line.substring(contextStart, contextEnd); - const column = contextStart + 1; - const length = contextEnd - contextStart; - const leftMarker = line.substring(contextStart, emphasisIndex); - const rightMarker = match ? (match[2] || match[3]) : ""; - const fixedText = `${leftMarker}${content.trim()}${rightMarker}`; - return [ - onError, - lineIndex + 1, - context, - leftSpace, - rightSpace, - [ column, length ], - { - "editColumn": column, - "deleteCount": length, - "insertText": fixedText - } - ]; - } - return null; - } - // Initialize - const ignoreMarkersByLine = emphasisMarkersInContent(params); - resetRunTracking(); - forEachLine( - lineMetadata(), - (line, lineIndex, inCode, onFence, inTable, inItem, onBreak, inMath) => { - const onItemStart = (inItem === 1); - if ( - inCode || - onFence || - inTable || - onBreak || - onItemStart || - isBlankLine(line) - ) { - // Emphasis resets when leaving a block - resetRunTracking(); - } - if ( - inCode || - onFence || - onBreak || - inMath - ) { - // Emphasis has no meaning here - return; - } - let patchedLine = line.replace(embeddedUnderscoreRe, "$1 $2"); - if (onItemStart) { - // Trim overlapping '*' list item marker - patchedLine = patchedLine.replace(asteriskListItemMarkerRe, "$1 $2"); - } - let match = null; - // Match all emphasis-looking runs in the line... - while ((match = emphasisRe.exec(patchedLine))) { - const ignoreMarkersForLine = ignoreMarkersByLine[lineIndex]; - const matchIndex = match.index + match[1].length; - if (ignoreMarkersForLine.includes(matchIndex)) { - // Ignore emphasis markers inside code spans and links - continue; - } - const matchLength = match[0].length - match[1].length; - const matchKind = (match[2] || match[3])[0]; - if (emphasisIndex === -1) { - // New run - emphasisIndex = matchIndex + matchLength; - emphasisLength = matchLength; - emphasisKind = matchKind; - effectiveEmphasisLength = matchLength; - } else if (matchKind === emphasisKind) { - // Matching emphasis markers - if (matchLength === effectiveEmphasisLength) { - // Ending an existing run, report any pending error - if (pendingError) { - // @ts-ignore - addErrorContext(...pendingError); - pendingError = null; - } - const error = handleRunEnd( - line, - lineIndex, - effectiveEmphasisLength, - match, - matchIndex, - inTable - ); - if (error) { - // @ts-ignore - addErrorContext(...error); - } - // Reset - resetRunTracking(); - } else if (matchLength === 3) { - // Swap internal run length (1->2 or 2->1) - effectiveEmphasisLength = matchLength - effectiveEmphasisLength; - } else if (effectiveEmphasisLength === 3) { - // Downgrade internal run (3->1 or 3->2) - effectiveEmphasisLength -= matchLength; - } else { - // Upgrade to internal run (1->3 or 2->3) - effectiveEmphasisLength += matchLength; - } - // Back up one character so RegExp has a chance to match the - // next marker (ex: "**star**_underscore_") - if (emphasisRe.lastIndex > 1) { - emphasisRe.lastIndex--; - } - } else if (emphasisRe.lastIndex > 1) { - // Back up one character so RegExp has a chance to match the - // mis-matched marker (ex: "*text_*") - emphasisRe.lastIndex--; - } - } - if (emphasisIndex !== -1) { - pendingError = pendingError || - handleRunEnd(line, lineIndex, 0, null, line.length, inTable); - // Adjust for pending run on new line - emphasisIndex = 0; - emphasisLength = 0; - } - } - ); - } -}; - - -/***/ }), - -/***/ 94: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorContext, filterTokens, forEachInlineCodeSpan, newLineRe } = - __nccwpck_require__(2935); - -const leftSpaceRe = /^\s([^`]|$)/; -const rightSpaceRe = /[^`]\s$/; -const singleLeftRightSpaceRe = /^\s(?:\S.*\S|\S)\s$/; - -module.exports = { - "names": [ "MD038", "no-space-in-code" ], - "description": "Spaces inside code span elements", - "tags": [ "whitespace", "code" ], - "function": function MD038(params, onError) { - filterTokens(params, "inline", (token) => { - if (token.children.some((child) => child.type === "code_inline")) { - const tokenLines = params.lines.slice(token.map[0], token.map[1]); - forEachInlineCodeSpan( - tokenLines.join("\n"), - (code, lineIndex, columnIndex, tickCount) => { - let rangeIndex = columnIndex - tickCount; - let rangeLength = code.length + (2 * tickCount); - let rangeLineOffset = 0; - let fixIndex = columnIndex; - let fixLength = code.length; - const codeLines = code.split(newLineRe); - const left = leftSpaceRe.test(code); - const right = !left && rightSpaceRe.test(code); - if (right && (codeLines.length > 1)) { - rangeIndex = 0; - rangeLineOffset = codeLines.length - 1; - fixIndex = 0; - } - const allowed = singleLeftRightSpaceRe.test(code); - if ((left || right) && !allowed) { - const codeLinesRange = codeLines[rangeLineOffset]; - if (codeLines.length > 1) { - rangeLength = codeLinesRange.length + tickCount; - fixLength = codeLinesRange.length; - } - const context = tokenLines[lineIndex + rangeLineOffset] - .substring(rangeIndex, rangeIndex + rangeLength); - const codeLinesRangeTrim = codeLinesRange.trim(); - const fixText = - (codeLinesRangeTrim.startsWith("`") ? " " : "") + - codeLinesRangeTrim + - (codeLinesRangeTrim.endsWith("`") ? " " : ""); - addErrorContext( - onError, - token.lineNumber + lineIndex + rangeLineOffset, - context, - left, - right, - [ rangeIndex + 1, rangeLength ], - { - "editColumn": fixIndex + 1, - "deleteCount": fixLength, - "insertText": fixText - } - ); - } - }); - } - }); - } -}; - - -/***/ }), - -/***/ 443: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorContext, filterTokens } = __nccwpck_require__(2935); - -const spaceInLinkRe = - /\[(?:\s+(?:[^\]]*?)\s*|(?:[^\]]*?)\s+)](?=((?:\([^)]*\))|(?:\[[^\]]*\])))/; - -module.exports = { - "names": [ "MD039", "no-space-in-links" ], - "description": "Spaces inside link text", - "tags": [ "whitespace", "links" ], - "function": function MD039(params, onError) { - filterTokens(params, "inline", (token) => { - const { children } = token; - let { lineNumber } = token; - let inLink = false; - let linkText = ""; - let lineIndex = 0; - children.forEach((child) => { - const { content, type } = child; - if (type === "link_open") { - inLink = true; - linkText = ""; - } else if (type === "link_close") { - inLink = false; - const left = linkText.trimStart().length !== linkText.length; - const right = linkText.trimEnd().length !== linkText.length; - if (left || right) { - const line = params.lines[lineNumber - 1]; - let range = null; - let fixInfo = null; - const match = line.slice(lineIndex).match(spaceInLinkRe); - if (match) { - const column = match.index + lineIndex + 1; - const length = match[0].length; - range = [ column, length ]; - fixInfo = { - "editColumn": column + 1, - "deleteCount": length - 2, - "insertText": linkText.trim() - }; - lineIndex = column + length - 1; - } - addErrorContext( - onError, - lineNumber, - `[${linkText}]`, - left, - right, - range, - fixInfo - ); - } - } else if ((type === "softbreak") || (type === "hardbreak")) { - lineNumber++; - lineIndex = 0; - } else if (inLink) { - linkText += content; - } - }); - }); - } -}; - - -/***/ }), - -/***/ 1025: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorContext, filterTokens } = __nccwpck_require__(2935); - -module.exports = { - "names": [ "MD040", "fenced-code-language" ], - "description": "Fenced code blocks should have a language specified", - "tags": [ "code", "language" ], - "function": function MD040(params, onError) { - filterTokens(params, "fence", function forToken(token) { - if (!token.info.trim()) { - addErrorContext(onError, token.lineNumber, token.line); - } - }); - } -}; - - -/***/ }), - -/***/ 5864: -/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { - -"use strict"; -// @ts-check - - - -const { addErrorContext, frontMatterHasTitle } = __nccwpck_require__(2935); - -module.exports = { - "names": [ "MD041", "first-line-heading", "first-line-h1" ], - "description": "First line in a file should be a top-level heading", - "tags": [ "headings", "headers" ], - "function": function MD041(params, onError) { - const level = Number(params.config.level || 1); - const tag = "h" + level; - const foundFrontMatterTitle = - frontMatterHasTitle( - params.frontMatterLines, - params.config.front_matter_title - ); - if (!foundFrontMatterTitle) { - const htmlHeadingRe = new RegExp(`^]`, "i"); - params.tokens.every((token) => { - let isError = false; - if (token.type === "html_block") { - if (token.content.startsWith("", startIndex); + if (endIndex === -1) { + break; + } + const parameter = line.slice(startIndex, endIndex); + forEachMatch(action, parameter, lineIndex + 1); + } + } + if (forEachLine) { + forEachLine(); + } + } + } + // eslint-disable-next-line jsdoc/require-jsdoc + function configureFile(action, parameter) { + if (action === "CONFIGURE-FILE") { + const { "config": parsed } = parseConfiguration( + "CONFIGURE-FILE", parameter, configParsers + ); + if (parsed) { + config = { + ...config, + ...parsed + }; + } + } + } + // eslint-disable-next-line jsdoc/require-jsdoc + function applyEnableDisable(action, parameter, state) { + state = { ...state }; + const enabled = (action.startsWith("ENABLE")); + const trimmed = parameter && parameter.trim(); + const items = trimmed ? trimmed.toUpperCase().split(/\s+/) : allRuleNames; + for (const nameUpper of items) { + for (const ruleName of (aliasToRuleNames[nameUpper] || [])) { + state[ruleName] = enabled; + } + } + return state; + } + // eslint-disable-next-line jsdoc/require-jsdoc + function enableDisableFile(action, parameter) { + if ((action === "ENABLE-FILE") || (action === "DISABLE-FILE")) { + enabledRules = applyEnableDisable(action, parameter, enabledRules); + } + } + // eslint-disable-next-line jsdoc/require-jsdoc + function captureRestoreEnableDisable(action, parameter) { + if (action === "CAPTURE") { + capturedRules = enabledRules; + } else if (action === "RESTORE") { + enabledRules = capturedRules; + } else if ((action === "ENABLE") || (action === "DISABLE")) { + enabledRules = applyEnableDisable(action, parameter, enabledRules); + } + } + // eslint-disable-next-line jsdoc/require-jsdoc + function updateLineState() { + enabledRulesPerLineNumber.push(enabledRules); + } + // eslint-disable-next-line jsdoc/require-jsdoc + function disableLineNextLine(action, parameter, lineNumber) { + const disableLine = (action === "DISABLE-LINE"); + const disableNextLine = (action === "DISABLE-NEXT-LINE"); + if (disableLine || disableNextLine) { + const nextLineNumber = + frontMatterLines.length + lineNumber + (disableNextLine ? 1 : 0); + enabledRulesPerLineNumber[nextLineNumber] = + applyEnableDisable( + action, + parameter, + enabledRulesPerLineNumber[nextLineNumber] || {} + ); + } + } + // Handle inline comments + handleInlineConfig([ lines.join("\n") ], configureFile); + const effectiveConfig = getEffectiveConfig( + ruleList, config, aliasToRuleNames); + for (const rule of ruleList) { + const ruleName = rule.names[0].toUpperCase(); + allRuleNames.push(ruleName); + enabledRules[ruleName] = !!effectiveConfig[ruleName]; + } + capturedRules = enabledRules; + handleInlineConfig(lines, enableDisableFile); + handleInlineConfig(lines, captureRestoreEnableDisable, updateLineState); + handleInlineConfig(lines, disableLineNextLine); + // Return results + return { + effectiveConfig, + enabledRulesPerLineNumber + }; +} + +/** + * Lints a string containing Markdown content. + * + * @param {Rule[]} ruleList List of rules. + * @param {string} name Identifier for the content. + * @param {string} content Markdown content. + * @param {Object} md Instance of markdown-it. + * @param {Configuration} config Configuration object. + * @param {ConfigurationParser[] | null} configParsers Configuration parsers. + * @param {RegExp} frontMatter Regular expression for front matter. + * @param {boolean} handleRuleFailures Whether to handle exceptions in rules. + * @param {boolean} noInlineConfig Whether to allow inline configuration. + * @param {number} resultVersion Version of the LintResults object to return. + * @param {Function} callback Callback (err, result) function. + * @returns {void} + */ +function lintContent( + ruleList, + name, + content, + md, + config, + configParsers, + frontMatter, + handleRuleFailures, + noInlineConfig, + resultVersion, + callback) { + // Remove UTF-8 byte order marker (if present) + content = content.replace(/^\uFEFF/, ""); + // Remove front matter + const removeFrontMatterResult = removeFrontMatter(content, frontMatter); + const { frontMatterLines } = removeFrontMatterResult; + content = removeFrontMatterResult.content; + // Get enabled rules per line (with HTML comments present) + const { effectiveConfig, enabledRulesPerLineNumber } = + getEnabledRulesPerLineNumber( + ruleList, + content.split(helpers.newLineRe), + frontMatterLines, + noInlineConfig, + config, + configParsers, + mapAliasToRuleNames(ruleList) + ); + // Hide the content of HTML comments from rules, etc. + content = helpers.clearHtmlCommentText(content); + // Parse content into tokens and lines + const tokens = md.parse(content, {}); + const lines = content.split(helpers.newLineRe); + annotateAndFreezeTokens(tokens, lines); + // Create (frozen) parameters for rules + const paramsBase = { + name, + tokens, + "lines": Object.freeze(lines), + "frontMatterLines": Object.freeze(frontMatterLines) + }; + const lineMetadata = + helpers.getLineMetadata(paramsBase); + const codeBlockAndSpanRanges = + helpers.codeBlockAndSpanRanges(paramsBase, lineMetadata); + const flattenedLists = + helpers.flattenLists(paramsBase.tokens); + const htmlElementRanges = + helpers.htmlElementRanges(paramsBase, lineMetadata); + const referenceLinkImageData = + helpers.getReferenceLinkImageData(lineMetadata); + cache.set({ + codeBlockAndSpanRanges, + flattenedLists, + htmlElementRanges, + lineMetadata, + referenceLinkImageData + }); + // Function to run for each rule + let results = []; + // eslint-disable-next-line jsdoc/require-jsdoc + function forRule(rule) { + // Configure rule + const ruleName = rule.names[0].toUpperCase(); + const params = { + ...paramsBase, + "config": effectiveConfig[ruleName] + }; + // eslint-disable-next-line jsdoc/require-jsdoc + function throwError(property) { + throw new Error( + "Property '" + property + "' of onError parameter is incorrect."); + } + // eslint-disable-next-line jsdoc/require-jsdoc + function onError(errorInfo) { + if (!errorInfo || + !helpers.isNumber(errorInfo.lineNumber) || + (errorInfo.lineNumber < 1) || + (errorInfo.lineNumber > lines.length)) { + throwError("lineNumber"); + } + const lineNumber = errorInfo.lineNumber + frontMatterLines.length; + if (!enabledRulesPerLineNumber[lineNumber][ruleName]) { + return; + } + if (errorInfo.detail && + !helpers.isString(errorInfo.detail)) { + throwError("detail"); + } + if (errorInfo.context && + !helpers.isString(errorInfo.context)) { + throwError("context"); + } + if (errorInfo.range && + (!Array.isArray(errorInfo.range) || + (errorInfo.range.length !== 2) || + !helpers.isNumber(errorInfo.range[0]) || + (errorInfo.range[0] < 1) || + !helpers.isNumber(errorInfo.range[1]) || + (errorInfo.range[1] < 1) || + ((errorInfo.range[0] + errorInfo.range[1] - 1) > + lines[errorInfo.lineNumber - 1].length))) { + throwError("range"); + } + const fixInfo = errorInfo.fixInfo; + const cleanFixInfo = {}; + if (fixInfo) { + if (!helpers.isObject(fixInfo)) { + throwError("fixInfo"); + } + if (fixInfo.lineNumber !== undefined) { + if ((!helpers.isNumber(fixInfo.lineNumber) || + (fixInfo.lineNumber < 1) || + (fixInfo.lineNumber > lines.length))) { + throwError("fixInfo.lineNumber"); + } + cleanFixInfo.lineNumber = + fixInfo.lineNumber + frontMatterLines.length; + } + const effectiveLineNumber = fixInfo.lineNumber || errorInfo.lineNumber; + if (fixInfo.editColumn !== undefined) { + if ((!helpers.isNumber(fixInfo.editColumn) || + (fixInfo.editColumn < 1) || + (fixInfo.editColumn > + lines[effectiveLineNumber - 1].length + 1))) { + throwError("fixInfo.editColumn"); + } + cleanFixInfo.editColumn = fixInfo.editColumn; + } + if (fixInfo.deleteCount !== undefined) { + if ((!helpers.isNumber(fixInfo.deleteCount) || + (fixInfo.deleteCount < -1) || + (fixInfo.deleteCount > + lines[effectiveLineNumber - 1].length))) { + throwError("fixInfo.deleteCount"); + } + cleanFixInfo.deleteCount = fixInfo.deleteCount; + } + if (fixInfo.insertText !== undefined) { + if (!helpers.isString(fixInfo.insertText)) { + throwError("fixInfo.insertText"); + } + cleanFixInfo.insertText = fixInfo.insertText; + } + } + results.push({ + lineNumber, + "ruleName": rule.names[0], + "ruleNames": rule.names, + "ruleDescription": rule.description, + "ruleInformation": rule.information ? rule.information.href : null, + "errorDetail": errorInfo.detail || null, + "errorContext": errorInfo.context || null, + "errorRange": errorInfo.range ? [ ...errorInfo.range ] : null, + "fixInfo": fixInfo ? cleanFixInfo : null + }); + } + // Call (possibly external) rule function to report errors + const catchCallsOnError = (error) => onError({ + "lineNumber": 1, + "detail": `This rule threw an exception: ${error.message || error}` + }); + const invokeRuleFunction = () => rule.function(params, onError); + if (rule.asynchronous) { + // Asynchronous rule, ensure it returns a Promise + const ruleFunctionPromise = + Promise.resolve().then(invokeRuleFunction); + return handleRuleFailures ? + ruleFunctionPromise.catch(catchCallsOnError) : + ruleFunctionPromise; + } + // Synchronous rule + try { + invokeRuleFunction(); + } catch (error) { + if (handleRuleFailures) { + catchCallsOnError(error); + } else { + throw error; + } + } + return null; + } + // eslint-disable-next-line jsdoc/require-jsdoc + function formatResults() { + // Sort results by rule name by line number + results.sort((a, b) => ( + a.ruleName.localeCompare(b.ruleName) || + a.lineNumber - b.lineNumber + )); + if (resultVersion < 3) { + // Remove fixInfo and multiple errors for the same rule and line number + const noPrevious = { + "ruleName": null, + "lineNumber": -1 + }; + results = results.filter((error, index, array) => { + delete error.fixInfo; + const previous = array[index - 1] || noPrevious; + return ( + (error.ruleName !== previous.ruleName) || + (error.lineNumber !== previous.lineNumber) + ); + }); + } + if (resultVersion === 0) { + // Return a dictionary of rule->[line numbers] + const dictionary = {}; + for (const error of results) { + const ruleLines = dictionary[error.ruleName] || []; + ruleLines.push(error.lineNumber); + dictionary[error.ruleName] = ruleLines; + } + // @ts-ignore + results = dictionary; + } else if (resultVersion === 1) { + // Use ruleAlias instead of ruleNames + for (const error of results) { + error.ruleAlias = error.ruleNames[1] || error.ruleName; + delete error.ruleNames; + } + } else { + // resultVersion 2 or 3: Remove unwanted ruleName + for (const error of results) { + delete error.ruleName; + } + } + return results; + } + // Run all rules + const ruleListAsync = ruleList.filter((rule) => rule.asynchronous); + const ruleListSync = ruleList.filter((rule) => !rule.asynchronous); + const ruleListAsyncFirst = [ + ...ruleListAsync, + ...ruleListSync + ]; + const callbackSuccess = () => callback(null, formatResults()); + const callbackError = + (error) => callback(error instanceof Error ? error : new Error(error)); + try { + const ruleResults = ruleListAsyncFirst.map(forRule); + if (ruleListAsync.length > 0) { + Promise.all(ruleResults.slice(0, ruleListAsync.length)) + .then(callbackSuccess) + .catch(callbackError); + } else { + callbackSuccess(); + } + } catch (error) { + callbackError(error); + } finally { + cache.clear(); + } +} + +/** + * Lints a file containing Markdown content. + * + * @param {Rule[]} ruleList List of rules. + * @param {string} file Path of file to lint. + * @param {Object} md Instance of markdown-it. + * @param {Configuration} config Configuration object. + * @param {ConfigurationParser[] | null} configParsers Configuration parsers. + * @param {RegExp} frontMatter Regular expression for front matter. + * @param {boolean} handleRuleFailures Whether to handle exceptions in rules. + * @param {boolean} noInlineConfig Whether to allow inline configuration. + * @param {number} resultVersion Version of the LintResults object to return. + * @param {Object} fs File system implementation. + * @param {boolean} synchronous Whether to execute synchronously. + * @param {Function} callback Callback (err, result) function. + * @returns {void} + */ +function lintFile( + ruleList, + file, + md, + config, + configParsers, + frontMatter, + handleRuleFailures, + noInlineConfig, + resultVersion, + fs, + synchronous, + callback) { + // eslint-disable-next-line jsdoc/require-jsdoc + function lintContentWrapper(err, content) { + if (err) { + return callback(err); + } + return lintContent( + ruleList, + file, + content, + md, + config, + configParsers, + frontMatter, + handleRuleFailures, + noInlineConfig, + resultVersion, + callback + ); + } + // Make a/synchronous call to read file + if (synchronous) { + lintContentWrapper(null, fs.readFileSync(file, "utf8")); + } else { + fs.readFile(file, "utf8", lintContentWrapper); + } +} + +/** + * Lint files and strings specified in the Options object. + * + * @param {Options} options Options object. + * @param {boolean} synchronous Whether to execute synchronously. + * @param {Function} callback Callback (err, result) function. + * @returns {void} + */ +function lintInput(options, synchronous, callback) { + // Normalize inputs + options = options || {}; + callback = callback || function noop() {}; + // eslint-disable-next-line unicorn/prefer-spread + const ruleList = rules.concat(options.customRules || []); + const ruleErr = validateRuleList(ruleList, synchronous); + if (ruleErr) { + callback(ruleErr); + return; + } + let files = []; + if (Array.isArray(options.files)) { + files = [ ...options.files ]; + } else if (options.files) { + files = [ String(options.files) ]; + } + const strings = options.strings || {}; + const stringsKeys = Object.keys(strings); + const config = options.config || { "default": true }; + const configParsers = options.configParsers || null; + const frontMatter = (options.frontMatter === undefined) ? + helpers.frontMatterRe : options.frontMatter; + const handleRuleFailures = !!options.handleRuleFailures; + const noInlineConfig = !!options.noInlineConfig; + const resultVersion = (options.resultVersion === undefined) ? + 3 : options.resultVersion; + const md = markdownIt({ "html": true }); + const markdownItPlugins = options.markdownItPlugins || []; + for (const plugin of markdownItPlugins) { + // @ts-ignore + md.use(...plugin); + } + const fs = options.fs || __nccwpck_require__(7147); + const results = newResults(ruleList); + let done = false; + let concurrency = 0; + // eslint-disable-next-line jsdoc/require-jsdoc + function lintWorker() { + let currentItem = null; + // eslint-disable-next-line jsdoc/require-jsdoc + function lintWorkerCallback(err, result) { + concurrency--; + if (err) { + done = true; + return callback(err); + } + results[currentItem] = result; + if (!synchronous) { + lintWorker(); + } + return null; + } + if (done) { + // Abort for error or nothing left to do + } else if (files.length > 0) { + // Lint next file + concurrency++; + currentItem = files.shift(); + lintFile( + ruleList, + currentItem, + md, + config, + configParsers, + frontMatter, + handleRuleFailures, + noInlineConfig, + resultVersion, + fs, + synchronous, + lintWorkerCallback + ); + } else if ((currentItem = stringsKeys.shift())) { + // Lint next string + concurrency++; + lintContent( + ruleList, + currentItem, + strings[currentItem] || "", + md, + config, + configParsers, + frontMatter, + handleRuleFailures, + noInlineConfig, + resultVersion, + lintWorkerCallback + ); + } else if (concurrency === 0) { + // Finish + done = true; + return callback(null, results); + } + return null; + } + if (synchronous) { + while (!done) { + lintWorker(); + } + } else { + // Testing on a Raspberry Pi 4 Model B with an artificial 5ms file access + // delay suggests that a concurrency factor of 8 can eliminate the impact + // of that delay (i.e., total time is the same as with no delay). + lintWorker(); + lintWorker(); + lintWorker(); + lintWorker(); + lintWorker(); + lintWorker(); + lintWorker(); + lintWorker(); + } +} + +/** + * Lint specified Markdown files. + * + * @param {Options} options Configuration options. + * @param {LintCallback} callback Callback (err, result) function. + * @returns {void} + */ +function markdownlint(options, callback) { + return lintInput(options, false, callback); +} + +const markdownlintPromisify = promisify && promisify(markdownlint); + +/** + * Lint specified Markdown files. + * + * @param {Options} options Configuration options. + * @returns {Promise} Results object. + */ +function markdownlintPromise(options) { + // @ts-ignore + return markdownlintPromisify(options); +} + +/** + * Lint specified Markdown files synchronously. + * + * @param {Options} options Configuration options. + * @returns {LintResults} Results object. + */ +function markdownlintSync(options) { + let results = {}; + lintInput(options, true, function callback(error, res) { + if (error) { + throw error; + } + results = res; + }); + // @ts-ignore + return results; +} + +/** + * Resolve referenced "extends" path in a configuration file + * using path.resolve() with require.resolve() as a fallback. + * + * @param {string} configFile Configuration file name. + * @param {string} referenceId Referenced identifier to resolve. + * @param {Object} fs File system implementation. + * @param {ResolveConfigExtendsCallback} callback Callback (err, result) + * function. + * @returns {void} + */ +function resolveConfigExtends(configFile, referenceId, fs, callback) { + const configFileDirname = path.dirname(configFile); + const resolvedExtendsFile = path.resolve(configFileDirname, referenceId); + fs.access(resolvedExtendsFile, (err) => { + if (err) { + // Not a file, try require.resolve + try { + return callback(null, dynamicRequire.resolve( + referenceId, + { "paths": [ configFileDirname ] } + )); + } catch { + // Unable to resolve, use resolvedExtendsFile + } + } + return callback(null, resolvedExtendsFile); + }); +} + +/** + * Resolve referenced "extends" path in a configuration file + * using path.resolve() with require.resolve() as a fallback. + * + * @param {string} configFile Configuration file name. + * @param {string} referenceId Referenced identifier to resolve. + * @param {Object} fs File system implementation. + * @returns {string} Resolved path to file. + */ +function resolveConfigExtendsSync(configFile, referenceId, fs) { + const configFileDirname = path.dirname(configFile); + const resolvedExtendsFile = path.resolve(configFileDirname, referenceId); + try { + fs.accessSync(resolvedExtendsFile); + return resolvedExtendsFile; + } catch { + // Not a file, try require.resolve + } + try { + return dynamicRequire.resolve( + referenceId, + { "paths": [ configFileDirname ] } + ); + } catch { + // Unable to resolve, return resolvedExtendsFile + } + return resolvedExtendsFile; +} + +/** + * Read specified configuration file. + * + * @param {string} file Configuration file name. + * @param {ConfigurationParser[] | ReadConfigCallback} parsers Parsing + * function(s). + * @param {Object} [fs] File system implementation. + * @param {ReadConfigCallback} [callback] Callback (err, result) function. + * @returns {void} + */ +function readConfig(file, parsers, fs, callback) { + if (!callback) { + if (fs) { + callback = fs; + fs = null; + } else { + // @ts-ignore + callback = parsers; + // @ts-ignore + parsers = null; + } + } + if (!fs) { + fs = __nccwpck_require__(7147); + } + // Read file + const os = __nccwpck_require__(2037); + file = helpers.expandTildePath(file, os); + fs.readFile(file, "utf8", (err, content) => { + if (err) { + // @ts-ignore + return callback(err); + } + // Try to parse file + // @ts-ignore + const { config, message } = parseConfiguration(file, content, parsers); + if (!config) { + // @ts-ignore + return callback(new Error(message)); + } + // Extend configuration + const configExtends = config.extends; + if (configExtends) { + delete config.extends; + return resolveConfigExtends( + file, + helpers.expandTildePath(configExtends, os), + fs, + (_, resolvedExtends) => readConfig( + // @ts-ignore + resolvedExtends, + parsers, + fs, + (errr, extendsConfig) => { + if (errr) { + // @ts-ignore + return callback(errr); + } + // @ts-ignore + return callback(null, { + ...extendsConfig, + ...config + }); + } + ) + ); + } + // @ts-ignore + return callback(null, config); + }); +} + +const readConfigPromisify = promisify && promisify(readConfig); + +/** + * Read specified configuration file. + * + * @param {string} file Configuration file name. + * @param {ConfigurationParser[]} [parsers] Parsing function(s). + * @param {Object} [fs] File system implementation. + * @returns {Promise} Configuration object. + */ +function readConfigPromise(file, parsers, fs) { + // @ts-ignore + return readConfigPromisify(file, parsers, fs); +} + +/** + * Read specified configuration file synchronously. + * + * @param {string} file Configuration file name. + * @param {ConfigurationParser[]} [parsers] Parsing function(s). + * @param {Object} [fs] File system implementation. + * @returns {Configuration} Configuration object. + * @throws An Error if processing fails. + */ +function readConfigSync(file, parsers, fs) { + if (!fs) { + fs = __nccwpck_require__(7147); + } + // Read file + const os = __nccwpck_require__(2037); + file = helpers.expandTildePath(file, os); + const content = fs.readFileSync(file, "utf8"); + // Try to parse file + const { config, message } = parseConfiguration(file, content, parsers); + if (!config) { + throw new Error(message); + } + // Extend configuration + const configExtends = config.extends; + if (configExtends) { + delete config.extends; + const resolvedExtends = resolveConfigExtendsSync( + file, + helpers.expandTildePath(configExtends, os), + fs + ); + return { + ...readConfigSync(resolvedExtends, parsers, fs), + ...config + }; + } + return config; +} + +/** + * Gets the (semantic) version of the library. + * + * @returns {string} SemVer string. + */ +function getVersion() { + return (__nccwpck_require__(983).version); +} + +// Export a/synchronous/Promise APIs +markdownlint.sync = markdownlintSync; +markdownlint.readConfig = readConfig; +markdownlint.readConfigSync = readConfigSync; +markdownlint.getVersion = getVersion; +markdownlint.promises = { + "markdownlint": markdownlintPromise, + "readConfig": readConfigPromise +}; +module.exports = markdownlint; + +// Type declarations + +/** + * Function to implement rule logic. + * + * @callback RuleFunction + * @param {RuleParams} params Rule parameters. + * @param {RuleOnError} onError Error-reporting callback. + * @returns {void} + */ + +/** + * Rule parameters. + * + * @typedef {Object} RuleParams + * @property {string} name File/string name. + * @property {MarkdownItToken[]} tokens Token objects from markdown-it. + * @property {string[]} lines File/string lines. + * @property {string[]} frontMatterLines Front matter lines. + * @property {RuleConfiguration} config Rule configuration. + */ + +/** + * Markdown-It token. + * + * @typedef {Object} MarkdownItToken + * @property {string[][]} attrs HTML attributes. + * @property {boolean} block Block-level token. + * @property {MarkdownItToken[]} children Child nodes. + * @property {string} content Tag contents. + * @property {boolean} hidden Ignore element. + * @property {string} info Fence info. + * @property {number} level Nesting level. + * @property {number[]} map Beginning/ending line numbers. + * @property {string} markup Markup text. + * @property {Object} meta Arbitrary data. + * @property {number} nesting Level change. + * @property {string} tag HTML tag name. + * @property {string} type Token type. + * @property {number} lineNumber Line number (1-based). + * @property {string} line Line content. + */ + +/** + * Error-reporting callback. + * + * @callback RuleOnError + * @param {RuleOnErrorInfo} onErrorInfo Error information. + * @returns {void} + */ + +/** + * Fix information for RuleOnError callback. + * + * @typedef {Object} RuleOnErrorInfo + * @property {number} lineNumber Line number (1-based). + * @property {string} [detail] Detail about the error. + * @property {string} [context] Context for the error. + * @property {number[]} [range] Column number (1-based) and length. + * @property {RuleOnErrorFixInfo} [fixInfo] Fix information. + */ + +/** + * Fix information for RuleOnErrorInfo. + * + * @typedef {Object} RuleOnErrorFixInfo + * @property {number} [lineNumber] Line number (1-based). + * @property {number} [editColumn] Column of the fix (1-based). + * @property {number} [deleteCount] Count of characters to delete. + * @property {string} [insertText] Text to insert (after deleting). + */ + +/** + * Rule definition. + * + * @typedef {Object} Rule + * @property {string[]} names Rule name(s). + * @property {string} description Rule description. + * @property {URL} [information] Link to more information. + * @property {string[]} tags Rule tag(s). + * @property {boolean} [asynchronous] True if asynchronous. + * @property {RuleFunction} function Rule implementation. + */ + +/** + * Configuration options. + * + * @typedef {Object} Options + * @property {Configuration} [config] Configuration object. + * @property {ConfigurationParser[]} [configParsers] Configuration parsers. + * @property {Rule[] | Rule} [customRules] Custom rules. + * @property {string[] | string} [files] Files to lint. + * @property {RegExp} [frontMatter] Front matter pattern. + * @property {Object} [fs] File system implementation. + * @property {boolean} [handleRuleFailures] True to catch exceptions. + * @property {Plugin[]} [markdownItPlugins] Additional plugins. + * @property {boolean} [noInlineConfig] True to ignore HTML directives. + * @property {number} [resultVersion] Results object version. + * @property {Object.} [strings] Strings to lint. + */ + +/** + * A markdown-it plugin. + * + * @typedef {Array} Plugin + */ + +/** + * Function to pretty-print lint results. + * + * @callback ToStringCallback + * @param {boolean} [ruleAliases] True to use rule aliases. + * @returns {string} + */ + +/** + * Lint results (for resultVersion 3). + * + * @typedef {Object.} LintResults + * @property {ToStringCallback} toString String representation. + */ + +/** + * Lint error. + * + * @typedef {Object} LintError + * @property {number} lineNumber Line number (1-based). + * @property {string[]} ruleNames Rule name(s). + * @property {string} ruleDescription Rule description. + * @property {string} ruleInformation Link to more information. + * @property {string} errorDetail Detail about the error. + * @property {string} errorContext Context for the error. + * @property {number[]} errorRange Column number (1-based) and length. + * @property {FixInfo} [fixInfo] Fix information. + */ + +/** + * Fix information. + * + * @typedef {Object} FixInfo + * @property {number} [lineNumber] Line number (1-based). + * @property {number} [editColumn] Column of the fix (1-based). + * @property {number} [deleteCount] Count of characters to delete. + * @property {string} [insertText] Text to insert (after deleting). + */ + +/** + * Called with the result of the lint function. + * + * @callback LintCallback + * @param {Error | null} err Error object or null. + * @param {LintResults} [results] Lint results. + * @returns {void} + */ + +/** + * Configuration object for linting rules. For a detailed schema, see + * {@link ../schema/markdownlint-config-schema.json}. + * + * @typedef {Object.} Configuration + */ + +/** + * Rule configuration object. + * + * @typedef {boolean | Object} RuleConfiguration Rule configuration. + */ + +/** + * Parses a configuration string and returns a configuration object. + * + * @callback ConfigurationParser + * @param {string} text Configuration string. + * @returns {Configuration} + */ + +/** + * Called with the result of the readConfig function. + * + * @callback ReadConfigCallback + * @param {Error | null} err Error object or null. + * @param {Configuration} [config] Configuration object. + * @returns {void} + */ + +/** + * Called with the result of the resolveConfigExtends function. + * + * @callback ResolveConfigExtendsCallback + * @param {Error | null} err Error object or null. + * @param {string} [path] Resolved path to file. + * @returns {void} + */ + + +/***/ }), + +/***/ 9651: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorDetailIf, filterTokens } = __nccwpck_require__(2935); + +module.exports = { + "names": [ "MD001", "heading-increment", "header-increment" ], + "description": "Heading levels should only increment by one level at a time", + "tags": [ "headings", "headers" ], + "function": function MD001(params, onError) { + let prevLevel = 0; + filterTokens(params, "heading_open", function forToken(token) { + const level = Number.parseInt(token.tag.slice(1), 10); + if (prevLevel && (level > prevLevel)) { + addErrorDetailIf(onError, token.lineNumber, + "h" + (prevLevel + 1), "h" + level); + } + prevLevel = level; + }); + } +}; + + +/***/ }), + +/***/ 4545: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorDetailIf } = __nccwpck_require__(2935); + +module.exports = { + "names": [ "MD002", "first-heading-h1", "first-header-h1" ], + "description": "First heading should be a top-level heading", + "tags": [ "headings", "headers" ], + "function": function MD002(params, onError) { + const level = Number(params.config.level || 1); + const tag = "h" + level; + params.tokens.every(function forToken(token) { + if (token.type === "heading_open") { + addErrorDetailIf(onError, token.lineNumber, tag, token.tag); + return false; + } + return true; + }); + } +}; + + +/***/ }), + +/***/ 9277: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorDetailIf, filterTokens, headingStyleFor } = + __nccwpck_require__(2935); + +module.exports = { + "names": [ "MD003", "heading-style", "header-style" ], + "description": "Heading style", + "tags": [ "headings", "headers" ], + "function": function MD003(params, onError) { + let style = String(params.config.style || "consistent"); + filterTokens(params, "heading_open", function forToken(token) { + const styleForToken = headingStyleFor(token); + if (style === "consistent") { + style = styleForToken; + } + if (styleForToken !== style) { + const h12 = /h[12]/.test(token.tag); + const setextWithAtx = + (style === "setext_with_atx") && + ((h12 && (styleForToken === "setext")) || + (!h12 && (styleForToken === "atx"))); + const setextWithAtxClosed = + (style === "setext_with_atx_closed") && + ((h12 && (styleForToken === "setext")) || + (!h12 && (styleForToken === "atx_closed"))); + if (!setextWithAtx && !setextWithAtxClosed) { + let expected = style; + if (style === "setext_with_atx") { + expected = h12 ? "setext" : "atx"; + } else if (style === "setext_with_atx_closed") { + expected = h12 ? "setext" : "atx_closed"; + } + addErrorDetailIf(onError, token.lineNumber, + expected, styleForToken); + } + } + }); + } +}; + + +/***/ }), + +/***/ 3755: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorDetailIf, listItemMarkerRe, unorderedListStyleFor } = + __nccwpck_require__(2935); +const { flattenedLists } = __nccwpck_require__(2260); + +const expectedStyleToMarker = { + "dash": "-", + "plus": "+", + "asterisk": "*" +}; +const differentItemStyle = { + "dash": "plus", + "plus": "asterisk", + "asterisk": "dash" +}; +const validStyles = Object.keys(expectedStyleToMarker); + +module.exports = { + "names": [ "MD004", "ul-style" ], + "description": "Unordered list style", + "tags": [ "bullet", "ul" ], + "function": function MD004(params, onError) { + const style = String(params.config.style || "consistent"); + let expectedStyle = style; + const nestingStyles = []; + for (const list of flattenedLists()) { + if (list.unordered) { + if (expectedStyle === "consistent") { + expectedStyle = unorderedListStyleFor(list.items[0]); + } + for (const item of list.items) { + const itemStyle = unorderedListStyleFor(item); + if (style === "sublist") { + const nesting = list.nesting; + if (!nestingStyles[nesting]) { + nestingStyles[nesting] = + (itemStyle === nestingStyles[nesting - 1]) ? + differentItemStyle[itemStyle] : + itemStyle; + } + expectedStyle = nestingStyles[nesting]; + } + if (!validStyles.includes(expectedStyle)) { + expectedStyle = validStyles[0]; + } + let range = null; + let fixInfo = null; + const match = item.line.match(listItemMarkerRe); + if (match) { + const column = match.index + 1; + const length = match[0].length; + range = [ column, length ]; + fixInfo = { + "editColumn": match[1].length + 1, + "deleteCount": 1, + "insertText": expectedStyleToMarker[expectedStyle] + }; + } + addErrorDetailIf( + onError, + item.lineNumber, + expectedStyle, + itemStyle, + null, + null, + range, + fixInfo + ); + } + } + } + } +}; + + +/***/ }), + +/***/ 3354: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addError, addErrorDetailIf, indentFor, listItemMarkerRe, + orderedListItemMarkerRe, rangeFromRegExp } = __nccwpck_require__(2935); +const { flattenedLists } = __nccwpck_require__(2260); + +module.exports = { + "names": [ "MD005", "list-indent" ], + "description": "Inconsistent indentation for list items at the same level", + "tags": [ "bullet", "ul", "indentation" ], + "function": function MD005(params, onError) { + for (const list of flattenedLists()) { + const expectedIndent = list.indent; + let expectedEnd = 0; + let actualEnd = -1; + let endMatching = false; + for (const item of list.items) { + const { line, lineNumber } = item; + const actualIndent = indentFor(item); + let match = null; + if (list.unordered) { + addErrorDetailIf( + onError, + lineNumber, + expectedIndent, + actualIndent, + null, + null, + rangeFromRegExp(line, listItemMarkerRe) + // No fixInfo; MD007 handles this scenario better + ); + } else if ((match = orderedListItemMarkerRe.exec(line))) { + actualEnd = match[0].length; + expectedEnd = expectedEnd || actualEnd; + const markerLength = match[1].length + 1; + if ((expectedIndent !== actualIndent) || endMatching) { + if (expectedEnd === actualEnd) { + endMatching = true; + } else { + const detail = endMatching ? + `Expected: (${expectedEnd}); Actual: (${actualEnd})` : + `Expected: ${expectedIndent}; Actual: ${actualIndent}`; + const expected = endMatching ? + expectedEnd - markerLength : + expectedIndent; + const actual = endMatching ? + actualEnd - markerLength : + actualIndent; + addError( + onError, + lineNumber, + detail, + null, + rangeFromRegExp(line, listItemMarkerRe), + { + "editColumn": Math.min(actual, expected) + 1, + "deleteCount": Math.max(actual - expected, 0), + "insertText": "".padEnd(Math.max(expected - actual, 0)) + } + ); + } + } + } + } + } + } +}; + + +/***/ }), + +/***/ 725: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorDetailIf, listItemMarkerRe, rangeFromRegExp } = + __nccwpck_require__(2935); +const { flattenedLists } = __nccwpck_require__(2260); + +module.exports = { + "names": [ "MD006", "ul-start-left" ], + "description": + "Consider starting bulleted lists at the beginning of the line", + "tags": [ "bullet", "ul", "indentation" ], + "function": function MD006(params, onError) { + for (const list of flattenedLists()) { + if (list.unordered && !list.nesting && (list.indent !== 0)) { + for (const item of list.items) { + const { lineNumber, line } = item; + addErrorDetailIf( + onError, + lineNumber, + 0, + list.indent, + null, + null, + rangeFromRegExp(line, listItemMarkerRe), + { + "deleteCount": line.length - line.trimStart().length + }); + } + } + } + } +}; + + +/***/ }), + +/***/ 8121: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorDetailIf, indentFor, listItemMarkerRe } = + __nccwpck_require__(2935); +const { flattenedLists } = __nccwpck_require__(2260); + +module.exports = { + "names": [ "MD007", "ul-indent" ], + "description": "Unordered list indentation", + "tags": [ "bullet", "ul", "indentation" ], + "function": function MD007(params, onError) { + const indent = Number(params.config.indent || 2); + const startIndented = !!params.config.start_indented; + const startIndent = Number(params.config.start_indent || indent); + for (const list of flattenedLists()) { + if (list.unordered && list.parentsUnordered) { + for (const item of list.items) { + const { lineNumber, line } = item; + const expectedIndent = + (startIndented ? startIndent : 0) + + (list.nesting * indent); + const actualIndent = indentFor(item); + let range = null; + let editColumn = 1; + const match = line.match(listItemMarkerRe); + if (match) { + range = [ 1, match[0].length ]; + editColumn += match[1].length - actualIndent; + } + addErrorDetailIf( + onError, + lineNumber, + expectedIndent, + actualIndent, + null, + null, + range, + { + editColumn, + "deleteCount": actualIndent, + "insertText": "".padEnd(expectedIndent) + }); + } + } + } + } +}; + + +/***/ }), + +/***/ 7315: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addError, filterTokens, forEachLine, includesSorted, + numericSortAscending } = __nccwpck_require__(2935); +const { lineMetadata } = __nccwpck_require__(2260); + +module.exports = { + "names": [ "MD009", "no-trailing-spaces" ], + "description": "Trailing spaces", + "tags": [ "whitespace" ], + "function": function MD009(params, onError) { + let brSpaces = params.config.br_spaces; + brSpaces = Number((brSpaces === undefined) ? 2 : brSpaces); + const listItemEmptyLines = !!params.config.list_item_empty_lines; + const strict = !!params.config.strict; + const listItemLineNumbers = []; + if (listItemEmptyLines) { + filterTokens(params, "list_item_open", (token) => { + for (let i = token.map[0]; i < token.map[1]; i++) { + listItemLineNumbers.push(i + 1); + } + }); + listItemLineNumbers.sort(numericSortAscending); + } + const paragraphLineNumbers = []; + const codeInlineLineNumbers = []; + if (strict) { + filterTokens(params, "paragraph_open", (token) => { + for (let i = token.map[0]; i < token.map[1] - 1; i++) { + paragraphLineNumbers.push(i + 1); + } + }); + const addLineNumberRange = (start, end) => { + for (let i = start; i < end; i++) { + codeInlineLineNumbers.push(i); + } + }; + filterTokens(params, "inline", (token) => { + let start = 0; + for (const child of token.children) { + if (start > 0) { + addLineNumberRange(start, child.lineNumber); + start = 0; + } + if (child.type === "code_inline") { + start = child.lineNumber; + } + } + if (start > 0) { + addLineNumberRange(start, token.map[1]); + } + }); + } + const expected = (brSpaces < 2) ? 0 : brSpaces; + forEachLine(lineMetadata(), (line, lineIndex, inCode) => { + const lineNumber = lineIndex + 1; + const trailingSpaces = line.length - line.trimEnd().length; + if ( + trailingSpaces && + !inCode && + !includesSorted(listItemLineNumbers, lineNumber) && + ( + (expected !== trailingSpaces) || + (strict && + (!includesSorted(paragraphLineNumbers, lineNumber) || + includesSorted(codeInlineLineNumbers, lineNumber))) + ) + ) { + const column = line.length - trailingSpaces + 1; + addError( + onError, + lineNumber, + "Expected: " + (expected === 0 ? "" : "0 or ") + + expected + "; Actual: " + trailingSpaces, + undefined, + [ column, trailingSpaces ], + { + "editColumn": column, + "deleteCount": trailingSpaces + }); + } + }); + } +}; + + +/***/ }), + +/***/ 1016: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addError, filterTokens, forEachLine, withinAnyRange } = + __nccwpck_require__(2935); +const { codeBlockAndSpanRanges, lineMetadata } = __nccwpck_require__(2260); + +const tabRe = /\t+/g; + +module.exports = { + "names": [ "MD010", "no-hard-tabs" ], + "description": "Hard tabs", + "tags": [ "whitespace", "hard_tab" ], + "function": function MD010(params, onError) { + const codeBlocks = params.config.code_blocks; + const includeCode = (codeBlocks === undefined) ? true : !!codeBlocks; + const ignoreCodeLanguages = new Set( + (params.config.ignore_code_languages || []) + .map((language) => language.toLowerCase()) + ); + const spacesPerTab = params.config.spaces_per_tab; + const spaceMultiplier = (spacesPerTab === undefined) ? + 1 : + Math.max(0, Number(spacesPerTab)); + const exclusions = includeCode ? [] : codeBlockAndSpanRanges(); + filterTokens(params, "fence", (token) => { + const language = token.info.trim().toLowerCase(); + if (ignoreCodeLanguages.has(language)) { + for (let i = token.map[0] + 1; i < token.map[1] - 1; i++) { + exclusions.push([ i, 0, params.lines[i].length ]); + } + } + }); + forEachLine(lineMetadata(), (line, lineIndex, inCode) => { + if (includeCode || !inCode) { + let match = null; + while ((match = tabRe.exec(line)) !== null) { + const { index } = match; + const column = index + 1; + const length = match[0].length; + if (!withinAnyRange(exclusions, lineIndex, index, length)) { + addError( + onError, + lineIndex + 1, + "Column: " + column, + null, + [ column, length ], + { + "editColumn": column, + "deleteCount": length, + "insertText": "".padEnd(length * spaceMultiplier) + } + ); + } + } + } + }); + } +}; + + +/***/ }), + +/***/ 3753: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addError, forEachLine, withinAnyRange } = __nccwpck_require__(2935); +const { codeBlockAndSpanRanges, lineMetadata } = __nccwpck_require__(2260); + +const reversedLinkRe = + /(^|[^\\])\(([^)]+)\)\[([^\]^][^\]]*)](?!\()/g; + +module.exports = { + "names": [ "MD011", "no-reversed-links" ], + "description": "Reversed link syntax", + "tags": [ "links" ], + "function": function MD011(params, onError) { + const exclusions = codeBlockAndSpanRanges(); + forEachLine(lineMetadata(), (line, lineIndex, inCode, onFence) => { + if (!inCode && !onFence) { + let match = null; + while ((match = reversedLinkRe.exec(line)) !== null) { + const [ reversedLink, preChar, linkText, linkDestination ] = match; + const index = match.index + preChar.length; + const length = match[0].length - preChar.length; + if ( + !linkText.endsWith("\\") && + !linkDestination.endsWith("\\") && + !withinAnyRange(exclusions, lineIndex, index, length) + ) { + addError( + onError, + lineIndex + 1, + reversedLink.slice(preChar.length), + null, + [ index + 1, length ], + { + "editColumn": index + 1, + "deleteCount": length, + "insertText": `[${linkText}](${linkDestination})` + } + ); + } + } + } + }); + } +}; + + +/***/ }), + +/***/ 6454: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorDetailIf, forEachLine } = __nccwpck_require__(2935); +const { lineMetadata } = __nccwpck_require__(2260); + +module.exports = { + "names": [ "MD012", "no-multiple-blanks" ], + "description": "Multiple consecutive blank lines", + "tags": [ "whitespace", "blank_lines" ], + "function": function MD012(params, onError) { + const maximum = Number(params.config.maximum || 1); + let count = 0; + forEachLine(lineMetadata(), (line, lineIndex, inCode) => { + count = (inCode || (line.trim().length > 0)) ? 0 : count + 1; + if (maximum < count) { + addErrorDetailIf( + onError, + lineIndex + 1, + maximum, + count, + null, + null, + null, + { + "deleteCount": -1 + }); + } + }); + } +}; + + +/***/ }), + +/***/ 1518: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorDetailIf, filterTokens, forEachHeading, forEachLine, + includesSorted, linkReferenceDefinitionRe } = __nccwpck_require__(2935); +const { lineMetadata } = __nccwpck_require__(2260); + +const longLineRePrefix = "^.{"; +const longLineRePostfixRelaxed = "}.*\\s.*$"; +const longLineRePostfixStrict = "}.+$"; +const linkOrImageOnlyLineRe = /^[es]*(lT?L|I)[ES]*$/; +const sternModeRe = /^([#>\s]*\s)?\S*$/; +const tokenTypeMap = { + "em_open": "e", + "em_close": "E", + "image": "I", + "link_open": "l", + "link_close": "L", + "strong_open": "s", + "strong_close": "S", + "text": "T" +}; + +module.exports = { + "names": [ "MD013", "line-length" ], + "description": "Line length", + "tags": [ "line_length" ], + "function": function MD013(params, onError) { + const lineLength = Number(params.config.line_length || 80); + const headingLineLength = + Number(params.config.heading_line_length || lineLength); + const codeLineLength = + Number(params.config.code_block_line_length || lineLength); + const strict = !!params.config.strict; + const stern = !!params.config.stern; + const longLineRePostfix = + (strict || stern) ? longLineRePostfixStrict : longLineRePostfixRelaxed; + const longLineRe = + new RegExp(longLineRePrefix + lineLength + longLineRePostfix); + const longHeadingLineRe = + new RegExp(longLineRePrefix + headingLineLength + longLineRePostfix); + const longCodeLineRe = + new RegExp(longLineRePrefix + codeLineLength + longLineRePostfix); + const codeBlocks = params.config.code_blocks; + const includeCodeBlocks = (codeBlocks === undefined) ? true : !!codeBlocks; + const tables = params.config.tables; + const includeTables = (tables === undefined) ? true : !!tables; + let headings = params.config.headings; + if (headings === undefined) { + headings = params.config.headers; + } + const includeHeadings = (headings === undefined) ? true : !!headings; + const headingLineNumbers = []; + forEachHeading(params, (heading) => { + headingLineNumbers.push(heading.lineNumber); + }); + const linkOnlyLineNumbers = []; + filterTokens(params, "inline", (token) => { + let childTokenTypes = ""; + for (const child of token.children) { + if (child.type !== "text" || child.content !== "") { + childTokenTypes += tokenTypeMap[child.type] || "x"; + } + } + if (linkOrImageOnlyLineRe.test(childTokenTypes)) { + linkOnlyLineNumbers.push(token.lineNumber); + } + }); + forEachLine(lineMetadata(), (line, lineIndex, inCode, onFence, inTable) => { + const lineNumber = lineIndex + 1; + const isHeading = includesSorted(headingLineNumbers, lineNumber); + const length = inCode ? + codeLineLength : + (isHeading ? headingLineLength : lineLength); + const lengthRe = inCode ? + longCodeLineRe : + (isHeading ? longHeadingLineRe : longLineRe); + if ((includeCodeBlocks || !inCode) && + (includeTables || !inTable) && + (includeHeadings || !isHeading) && + (strict || + (!(stern && sternModeRe.test(line)) && + !includesSorted(linkOnlyLineNumbers, lineNumber) && + !linkReferenceDefinitionRe.test(line))) && + lengthRe.test(line)) { + addErrorDetailIf( + onError, + lineNumber, + length, + line.length, + null, + null, + [ length + 1, line.length - length ]); + } + }); + } +}; + + +/***/ }), + +/***/ 3463: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorContext, filterTokens } = __nccwpck_require__(2935); + +const dollarCommandRe = /^(\s*)(\$\s+)/; + +module.exports = { + "names": [ "MD014", "commands-show-output" ], + "description": "Dollar signs used before commands without showing output", + "tags": [ "code" ], + "function": function MD014(params, onError) { + for (const type of [ "code_block", "fence" ]) { + filterTokens(params, type, (token) => { + const margin = (token.type === "fence") ? 1 : 0; + const dollarInstances = []; + let allDollars = true; + for (let i = token.map[0] + margin; i < token.map[1] - margin; i++) { + const line = params.lines[i]; + const lineTrim = line.trim(); + if (lineTrim) { + const match = dollarCommandRe.exec(line); + if (match) { + const column = match[1].length + 1; + const length = match[2].length; + dollarInstances.push([ i, lineTrim, column, length ]); + } else { + allDollars = false; + } + } + } + if (allDollars) { + for (const instance of dollarInstances) { + const [ i, lineTrim, column, length ] = instance; + addErrorContext( + onError, + i + 1, + lineTrim, + null, + null, + [ column, length ], + { + "editColumn": column, + "deleteCount": length + } + ); + } + } + }); + } + } +}; + + +/***/ }), + +/***/ 5496: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorContext, forEachLine } = __nccwpck_require__(2935); +const { lineMetadata } = __nccwpck_require__(2260); + +module.exports = { + "names": [ "MD018", "no-missing-space-atx" ], + "description": "No space after hash on atx style heading", + "tags": [ "headings", "headers", "atx", "spaces" ], + "function": function MD018(params, onError) { + forEachLine(lineMetadata(), (line, lineIndex, inCode) => { + if (!inCode && + /^#+[^# \t]/.test(line) && + !/#\s*$/.test(line) && + !line.startsWith("#️⃣")) { + const hashCount = /^#+/.exec(line)[0].length; + addErrorContext( + onError, + lineIndex + 1, + line.trim(), + null, + null, + [ 1, hashCount + 1 ], + { + "editColumn": hashCount + 1, + "insertText": " " + } + ); + } + }); + } +}; + + +/***/ }), + +/***/ 6478: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorContext, filterTokens, headingStyleFor } = + __nccwpck_require__(2935); + +module.exports = { + "names": [ "MD019", "no-multiple-space-atx" ], + "description": "Multiple spaces after hash on atx style heading", + "tags": [ "headings", "headers", "atx", "spaces" ], + "function": function MD019(params, onError) { + filterTokens(params, "heading_open", (token) => { + if (headingStyleFor(token) === "atx") { + const { line, lineNumber } = token; + const match = /^(#+)([ \t]{2,})(?:\S)/.exec(line); + if (match) { + const [ + , + { "length": hashLength }, + { "length": spacesLength } + ] = match; + addErrorContext( + onError, + lineNumber, + line.trim(), + null, + null, + [ 1, hashLength + spacesLength + 1 ], + { + "editColumn": hashLength + 1, + "deleteCount": spacesLength - 1 + } + ); + } + } + }); + } +}; + + +/***/ }), + +/***/ 9915: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorContext, forEachLine } = __nccwpck_require__(2935); +const { lineMetadata } = __nccwpck_require__(2260); + +module.exports = { + "names": [ "MD020", "no-missing-space-closed-atx" ], + "description": "No space inside hashes on closed atx style heading", + "tags": [ "headings", "headers", "atx_closed", "spaces" ], + "function": function MD020(params, onError) { + forEachLine(lineMetadata(), (line, lineIndex, inCode) => { + if (!inCode) { + const match = + /^(#+)([ \t]*)([^#]*?[^#\\])([ \t]*)((?:\\#)?)(#+)(\s*)$/.exec(line); + if (match) { + const [ + , + leftHash, + { "length": leftSpaceLength }, + content, + { "length": rightSpaceLength }, + rightEscape, + rightHash, + { "length": trailSpaceLength } + ] = match; + const leftHashLength = leftHash.length; + const rightHashLength = rightHash.length; + const left = !leftSpaceLength; + const right = !rightSpaceLength || rightEscape; + const rightEscapeReplacement = rightEscape ? `${rightEscape} ` : ""; + if (left || right) { + const range = left ? + [ + 1, + leftHashLength + 1 + ] : + [ + line.length - trailSpaceLength - rightHashLength, + rightHashLength + 1 + ]; + addErrorContext( + onError, + lineIndex + 1, + line.trim(), + left, + right, + range, + { + "editColumn": 1, + "deleteCount": line.length, + "insertText": + `${leftHash} ${content} ${rightEscapeReplacement}${rightHash}` + } + ); + } + } + } + }); + } +}; + + +/***/ }), + +/***/ 4898: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorContext, filterTokens, headingStyleFor } = + __nccwpck_require__(2935); + +const closedAtxRe = /^(#+)([ \t]+)([^ \t]|[^ \t].*[^ \t])([ \t]+)(#+)(\s*)$/; + +module.exports = { + "names": [ "MD021", "no-multiple-space-closed-atx" ], + "description": "Multiple spaces inside hashes on closed atx style heading", + "tags": [ "headings", "headers", "atx_closed", "spaces" ], + "function": function MD021(params, onError) { + filterTokens(params, "heading_open", (token) => { + if (headingStyleFor(token) === "atx_closed") { + const { line, lineNumber } = token; + const match = closedAtxRe.exec(line); + if (match) { + const [ + , + leftHash, + { "length": leftSpaceLength }, + content, + { "length": rightSpaceLength }, + rightHash, + { "length": trailSpaceLength } + ] = match; + const left = leftSpaceLength > 1; + const right = rightSpaceLength > 1; + if (left || right) { + const length = line.length; + const leftHashLength = leftHash.length; + const rightHashLength = rightHash.length; + const range = left ? + [ + 1, + leftHashLength + leftSpaceLength + 1 + ] : + [ + length - trailSpaceLength - rightHashLength - rightSpaceLength, + rightSpaceLength + rightHashLength + 1 + ]; + addErrorContext( + onError, + lineNumber, + line.trim(), + left, + right, + range, + { + "editColumn": 1, + "deleteCount": length, + "insertText": `${leftHash} ${content} ${rightHash}` + } + ); + } + } + } + }); + } +}; + + +/***/ }), + +/***/ 5164: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorDetailIf, filterTokens, isBlankLine } = __nccwpck_require__(2935); + +module.exports = { + "names": [ "MD022", "blanks-around-headings", "blanks-around-headers" ], + "description": "Headings should be surrounded by blank lines", + "tags": [ "headings", "headers", "blank_lines" ], + "function": function MD022(params, onError) { + let linesAbove = params.config.lines_above; + linesAbove = Number((linesAbove === undefined) ? 1 : linesAbove); + let linesBelow = params.config.lines_below; + linesBelow = Number((linesBelow === undefined) ? 1 : linesBelow); + const { lines } = params; + filterTokens(params, "heading_open", (token) => { + const [ topIndex, nextIndex ] = token.map; + let actualAbove = 0; + for (let i = 0; i < linesAbove; i++) { + if (isBlankLine(lines[topIndex - i - 1])) { + actualAbove++; + } + } + addErrorDetailIf( + onError, + topIndex + 1, + linesAbove, + actualAbove, + "Above", + lines[topIndex].trim(), + null, + { + "insertText": "".padEnd(linesAbove - actualAbove, "\n") + }); + let actualBelow = 0; + for (let i = 0; i < linesBelow; i++) { + if (isBlankLine(lines[nextIndex + i])) { + actualBelow++; + } + } + addErrorDetailIf( + onError, + topIndex + 1, + linesBelow, + actualBelow, + "Below", + lines[topIndex].trim(), + null, + { + "lineNumber": nextIndex + 1, + "insertText": "".padEnd(linesBelow - actualBelow, "\n") + }); + }); + } +}; + + +/***/ }), + +/***/ 1829: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorContext, filterTokens } = __nccwpck_require__(2935); + +const spaceBeforeHeadingRe = /^((?:\s+)|(?:[>\s]+\s\s))[^>\s]/; + +module.exports = { + "names": [ "MD023", "heading-start-left", "header-start-left" ], + "description": "Headings must start at the beginning of the line", + "tags": [ "headings", "headers", "spaces" ], + "function": function MD023(params, onError) { + filterTokens(params, "heading_open", function forToken(token) { + const { lineNumber, line } = token; + const match = line.match(spaceBeforeHeadingRe); + if (match) { + const [ prefixAndFirstChar, prefix ] = match; + let deleteCount = prefix.length; + const prefixLengthNoSpace = prefix.trimEnd().length; + if (prefixLengthNoSpace) { + deleteCount -= prefixLengthNoSpace - 1; + } + addErrorContext( + onError, + lineNumber, + line, + null, + null, + [ 1, prefixAndFirstChar.length ], + { + "editColumn": prefixLengthNoSpace + 1, + "deleteCount": deleteCount + }); + } + }); + } +}; + + +/***/ }), + +/***/ 7177: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorContext, forEachHeading } = __nccwpck_require__(2935); + +module.exports = { + "names": [ "MD024", "no-duplicate-heading", "no-duplicate-header" ], + "description": "Multiple headings with the same content", + "tags": [ "headings", "headers" ], + "function": function MD024(params, onError) { + const siblingsOnly = !!params.config.siblings_only || + !!params.config.allow_different_nesting || false; + const knownContents = [ null, [] ]; + let lastLevel = 1; + let knownContent = knownContents[lastLevel]; + forEachHeading(params, (heading, content) => { + if (siblingsOnly) { + const newLevel = heading.tag.slice(1); + while (lastLevel < newLevel) { + lastLevel++; + knownContents[lastLevel] = []; + } + while (lastLevel > newLevel) { + knownContents[lastLevel] = []; + lastLevel--; + } + knownContent = knownContents[newLevel]; + } + if (knownContent.includes(content)) { + addErrorContext(onError, heading.lineNumber, + heading.line.trim()); + } else { + knownContent.push(content); + } + }); + } +}; + + +/***/ }), + +/***/ 692: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorContext, filterTokens, frontMatterHasTitle } = + __nccwpck_require__(2935); + +module.exports = { + "names": [ "MD025", "single-title", "single-h1" ], + "description": "Multiple top-level headings in the same document", + "tags": [ "headings", "headers" ], + "function": function MD025(params, onError) { + const level = Number(params.config.level || 1); + const tag = "h" + level; + const foundFrontMatterTitle = + frontMatterHasTitle( + params.frontMatterLines, + params.config.front_matter_title + ); + let hasTopLevelHeading = false; + filterTokens(params, "heading_open", function forToken(token) { + if (token.tag === tag) { + if (hasTopLevelHeading || foundFrontMatterTitle) { + addErrorContext(onError, token.lineNumber, + token.line.trim()); + } else if (token.lineNumber === 1) { + hasTopLevelHeading = true; + } + } + }); + } +}; + + +/***/ }), + +/***/ 1629: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addError, allPunctuationNoQuestion, escapeForRegExp, forEachHeading } = + __nccwpck_require__(2935); + +const endOfLineHtmlEntityRe = /&#?[0-9a-zA-Z]+;$/; + +module.exports = { + "names": [ "MD026", "no-trailing-punctuation" ], + "description": "Trailing punctuation in heading", + "tags": [ "headings", "headers" ], + "function": function MD026(params, onError) { + let punctuation = params.config.punctuation; + punctuation = String( + (punctuation === undefined) ? allPunctuationNoQuestion : punctuation + ); + const trailingPunctuationRe = + new RegExp("\\s*[" + escapeForRegExp(punctuation) + "]+$"); + forEachHeading(params, (heading) => { + const { line, lineNumber } = heading; + const trimmedLine = line.replace(/([^\s#])[\s#]+$/, "$1"); + const match = trailingPunctuationRe.exec(trimmedLine); + if (match && !endOfLineHtmlEntityRe.test(trimmedLine)) { + const fullMatch = match[0]; + const column = match.index + 1; + const length = fullMatch.length; + addError( + onError, + lineNumber, + `Punctuation: '${fullMatch}'`, + null, + [ column, length ], + { + "editColumn": column, + "deleteCount": length + } + ); + } + }); + } +}; + + +/***/ }), + +/***/ 6325: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorContext, newLineRe } = __nccwpck_require__(2935); + +const spaceAfterBlockQuoteRe = /^((?:\s*>)+)(\s{2,})\S/; + +module.exports = { + "names": [ "MD027", "no-multiple-space-blockquote" ], + "description": "Multiple spaces after blockquote symbol", + "tags": [ "blockquote", "whitespace", "indentation" ], + "function": function MD027(params, onError) { + let blockquoteNesting = 0; + let listItemNesting = 0; + for (const token of params.tokens) { + const { content, lineNumber, type } = token; + if (type === "blockquote_open") { + blockquoteNesting++; + } else if (type === "blockquote_close") { + blockquoteNesting--; + } else if (type === "list_item_open") { + listItemNesting++; + } else if (type === "list_item_close") { + listItemNesting--; + } else if ((type === "inline") && blockquoteNesting) { + const lineCount = content.split(newLineRe).length; + for (let i = 0; i < lineCount; i++) { + const line = params.lines[lineNumber + i - 1]; + const match = line.match(spaceAfterBlockQuoteRe); + if (match) { + const [ + fullMatch, + { "length": blockquoteLength }, + { "length": spaceLength } + ] = match; + if (!listItemNesting || (fullMatch[fullMatch.length - 1] === ">")) { + addErrorContext( + onError, + lineNumber + i, + line, + null, + null, + [ 1, fullMatch.length ], + { + "editColumn": blockquoteLength + 1, + "deleteCount": spaceLength - 1 + } + ); + } + } + } + } + } + } +}; + + +/***/ }), + +/***/ 7542: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addError } = __nccwpck_require__(2935); + +module.exports = { + "names": [ "MD028", "no-blanks-blockquote" ], + "description": "Blank line inside blockquote", + "tags": [ "blockquote", "whitespace" ], + "function": function MD028(params, onError) { + let prevToken = {}; + let prevLineNumber = null; + for (const token of params.tokens) { + if ((token.type === "blockquote_open") && + (prevToken.type === "blockquote_close")) { + for ( + let lineNumber = prevLineNumber; + lineNumber < token.lineNumber; + lineNumber++) { + addError(onError, lineNumber); + } + } + prevToken = token; + if (token.type === "blockquote_open") { + prevLineNumber = token.map[1] + 1; + } + } + } +}; + + +/***/ }), + +/***/ 3404: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorDetailIf, listItemMarkerRe, orderedListItemMarkerRe, + rangeFromRegExp } = __nccwpck_require__(2935); +const { flattenedLists } = __nccwpck_require__(2260); + +const listStyleExamples = { + "one": "1/1/1", + "ordered": "1/2/3", + "zero": "0/0/0" +}; + +module.exports = { + "names": [ "MD029", "ol-prefix" ], + "description": "Ordered list item prefix", + "tags": [ "ol" ], + "function": function MD029(params, onError) { + const style = String(params.config.style || "one_or_ordered"); + const filteredLists = flattenedLists().filter((list) => !list.unordered); + for (const list of filteredLists) { + const { items } = list; + let current = 1; + let incrementing = false; + // Check for incrementing number pattern 1/2/3 or 0/1/2 + if (items.length >= 2) { + const first = orderedListItemMarkerRe.exec(items[0].line); + const second = orderedListItemMarkerRe.exec(items[1].line); + if (first && second) { + const [ , firstNumber ] = first; + const [ , secondNumber ] = second; + if ((secondNumber !== "1") || (firstNumber === "0")) { + incrementing = true; + if (firstNumber === "0") { + current = 0; + } + } + } + } + // Determine effective style + let listStyle = style; + if (listStyle === "one_or_ordered") { + listStyle = incrementing ? "ordered" : "one"; + } + // Force expected value for 0/0/0 and 1/1/1 patterns + if (listStyle === "zero") { + current = 0; + } else if (listStyle === "one") { + current = 1; + } + // Validate each list item marker + for (const item of items) { + const match = orderedListItemMarkerRe.exec(item.line); + if (match) { + addErrorDetailIf(onError, item.lineNumber, + String(current), match[1], + "Style: " + listStyleExamples[listStyle], null, + rangeFromRegExp(item.line, listItemMarkerRe)); + if (listStyle === "ordered") { + current++; + } + } + } + } + } +}; + + +/***/ }), + +/***/ 2549: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorDetailIf } = __nccwpck_require__(2935); +const { flattenedLists } = __nccwpck_require__(2260); + +module.exports = { + "names": [ "MD030", "list-marker-space" ], + "description": "Spaces after list markers", + "tags": [ "ol", "ul", "whitespace" ], + "function": function MD030(params, onError) { + const ulSingle = Number(params.config.ul_single || 1); + const olSingle = Number(params.config.ol_single || 1); + const ulMulti = Number(params.config.ul_multi || 1); + const olMulti = Number(params.config.ol_multi || 1); + for (const list of flattenedLists()) { + const lineCount = list.lastLineIndex - list.open.map[0]; + const allSingle = lineCount === list.items.length; + const expectedSpaces = list.unordered ? + (allSingle ? ulSingle : ulMulti) : + (allSingle ? olSingle : olMulti); + for (const item of list.items) { + const { line, lineNumber } = item; + const match = /^[\s>]*\S+(\s*)/.exec(line); + const [ { "length": matchLength }, { "length": actualSpaces } ] = match; + if (matchLength < line.length) { + let fixInfo = null; + if (expectedSpaces !== actualSpaces) { + fixInfo = { + "editColumn": matchLength - actualSpaces + 1, + "deleteCount": actualSpaces, + "insertText": "".padEnd(expectedSpaces) + }; + } + addErrorDetailIf( + onError, + lineNumber, + expectedSpaces, + actualSpaces, + null, + null, + [ 1, matchLength ], + fixInfo + ); + } + } + } + } +}; + + +/***/ }), + +/***/ 2202: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorContext, forEachLine, isBlankLine } = __nccwpck_require__(2935); +const { lineMetadata } = __nccwpck_require__(2260); + +const codeFencePrefixRe = /^(.*?)[`~]/; + +module.exports = { + "names": [ "MD031", "blanks-around-fences" ], + "description": "Fenced code blocks should be surrounded by blank lines", + "tags": [ "code", "blank_lines" ], + "function": function MD031(params, onError) { + const listItems = params.config.list_items; + const includeListItems = (listItems === undefined) ? true : !!listItems; + const { lines } = params; + forEachLine(lineMetadata(), (line, i, inCode, onFence, inTable, inItem) => { + const onTopFence = (onFence > 0); + const onBottomFence = (onFence < 0); + if ((includeListItems || !inItem) && + ((onTopFence && !isBlankLine(lines[i - 1])) || + (onBottomFence && !isBlankLine(lines[i + 1])))) { + const [ , prefix ] = line.match(codeFencePrefixRe) || []; + const fixInfo = (prefix === undefined) ? null : { + "lineNumber": i + (onTopFence ? 1 : 2), + "insertText": `${prefix.replace(/[^>]/g, " ").trim()}\n` + }; + addErrorContext( + onError, + i + 1, + lines[i].trim(), + null, + null, + null, + fixInfo); + } + }); + } +}; + + +/***/ }), + +/***/ 3474: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorContext, blockquotePrefixRe, isBlankLine } = + __nccwpck_require__(2935); +const { flattenedLists } = __nccwpck_require__(2260); + +module.exports = { + "names": [ "MD032", "blanks-around-lists" ], + "description": "Lists should be surrounded by blank lines", + "tags": [ "bullet", "ul", "ol", "blank_lines" ], + "function": function MD032(params, onError) { + const { lines } = params; + const filteredLists = flattenedLists().filter((list) => !list.nesting); + for (const list of filteredLists) { + const firstIndex = list.open.map[0]; + if (!isBlankLine(lines[firstIndex - 1])) { + const line = lines[firstIndex]; + const quotePrefix = line.match(blockquotePrefixRe)[0].trimEnd(); + addErrorContext( + onError, + firstIndex + 1, + line.trim(), + null, + null, + null, + { + "insertText": `${quotePrefix}\n` + }); + } + const lastIndex = list.lastLineIndex - 1; + if (!isBlankLine(lines[lastIndex + 1])) { + const line = lines[lastIndex]; + const quotePrefix = line.match(blockquotePrefixRe)[0].trimEnd(); + addErrorContext( + onError, + lastIndex + 1, + line.trim(), + null, + null, + null, + { + "lineNumber": lastIndex + 2, + "insertText": `${quotePrefix}\n` + }); + } + } + } +}; + + +/***/ }), + +/***/ 77: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { + addError, forEachLine, htmlElementRe, withinAnyRange, unescapeMarkdown +} = __nccwpck_require__(2935); +const { codeBlockAndSpanRanges, lineMetadata } = __nccwpck_require__(2260); + +const linkDestinationRe = /]\(\s*$/; +// See https://spec.commonmark.org/0.29/#autolinks +const emailAddressRe = + // eslint-disable-next-line max-len + /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; + +module.exports = { + "names": [ "MD033", "no-inline-html" ], + "description": "Inline HTML", + "tags": [ "html" ], + "function": function MD033(params, onError) { + let allowedElements = params.config.allowed_elements; + allowedElements = Array.isArray(allowedElements) ? allowedElements : []; + allowedElements = allowedElements.map((element) => element.toLowerCase()); + const exclusions = codeBlockAndSpanRanges(); + forEachLine(lineMetadata(), (line, lineIndex, inCode) => { + let match = null; + // eslint-disable-next-line no-unmodified-loop-condition + while (!inCode && ((match = htmlElementRe.exec(line)) !== null)) { + const [ tag, content, element ] = match; + if ( + !allowedElements.includes(element.toLowerCase()) && + !tag.endsWith("\\>") && + !emailAddressRe.test(content) && + !withinAnyRange(exclusions, lineIndex, match.index, match[0].length) + ) { + const prefix = line.substring(0, match.index); + if (!linkDestinationRe.test(prefix)) { + const unescaped = unescapeMarkdown(prefix + "<", "_"); + if (!unescaped.endsWith("_")) { + addError(onError, lineIndex + 1, "Element: " + element, + undefined, [ match.index + 1, tag.length ]); + } + } + } + } + }); + } +}; + + +/***/ }), + +/***/ 4721: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorContext, bareUrlRe, filterTokens } = __nccwpck_require__(2935); + +module.exports = { + "names": [ "MD034", "no-bare-urls" ], + "description": "Bare URL used", + "tags": [ "links", "url" ], + "function": function MD034(params, onError) { + filterTokens(params, "inline", (token) => { + let inLink = false; + for (const child of token.children) { + const { content, line, lineNumber, type } = child; + let match = null; + if (type === "link_open") { + inLink = true; + } else if (type === "link_close") { + inLink = false; + } else if ((type === "text") && !inLink) { + while ((match = bareUrlRe.exec(content)) !== null) { + const [ bareUrl ] = match; + const matchIndex = match.index; + const bareUrlLength = bareUrl.length; + // Allow "[https://example.com]" to avoid conflicts with + // MD011/no-reversed-links; allow quoting as another way + // of deliberately including a bare URL + const leftChar = content[matchIndex - 1]; + const rightChar = content[matchIndex + bareUrlLength]; + if ( + !((leftChar === "[") && (rightChar === "]")) && + !((leftChar === "\"") && (rightChar === "\"")) && + !((leftChar === "'") && (rightChar === "'")) + ) { + const index = line.indexOf(content); + const range = (index === -1) ? null : [ + index + matchIndex + 1, + bareUrlLength + ]; + const fixInfo = range ? { + "editColumn": range[0], + "deleteCount": range[1], + "insertText": `<${bareUrl}>` + } : null; + addErrorContext( + onError, + lineNumber, + bareUrl, + null, + null, + range, + fixInfo + ); + } + } + } + } + }); + } +}; + + +/***/ }), + +/***/ 2997: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorDetailIf, filterTokens } = __nccwpck_require__(2935); + +module.exports = { + "names": [ "MD035", "hr-style" ], + "description": "Horizontal rule style", + "tags": [ "hr" ], + "function": function MD035(params, onError) { + let style = String(params.config.style || "consistent").trim(); + filterTokens(params, "hr", (token) => { + const { line, lineNumber } = token; + let { markup } = token; + const match = line.match(/[_*\-\s\t]+$/); + if (match) { + markup = match[0].trim(); + } + if (style === "consistent") { + style = markup; + } + addErrorDetailIf(onError, lineNumber, style, markup); + }); + } +}; + + +/***/ }), + +/***/ 338: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorContext, allPunctuation } = __nccwpck_require__(2935); + +module.exports = { + "names": [ "MD036", "no-emphasis-as-heading", "no-emphasis-as-header" ], + "description": "Emphasis used instead of a heading", + "tags": [ "headings", "headers", "emphasis" ], + "function": function MD036(params, onError) { + let punctuation = params.config.punctuation; + punctuation = + String((punctuation === undefined) ? allPunctuation : punctuation); + const re = new RegExp("[" + punctuation + "]$"); + // eslint-disable-next-line jsdoc/require-jsdoc + function base(token) { + if (token.type === "paragraph_open") { + return function inParagraph(t) { + // Always paragraph_open/inline/paragraph_close, + const children = t.children.filter(function notEmptyText(child) { + return (child.type !== "text") || (child.content !== ""); + }); + if ((children.length === 3) && + ((children[0].type === "strong_open") || + (children[0].type === "em_open")) && + (children[1].type === "text") && + !re.test(children[1].content)) { + addErrorContext(onError, t.lineNumber, + children[1].content); + } + return base; + }; + } else if (token.type === "blockquote_open") { + return function inBlockquote(t) { + if (t.type !== "blockquote_close") { + return inBlockquote; + } + return base; + }; + } else if (token.type === "list_item_open") { + return function inListItem(t) { + if (t.type !== "list_item_close") { + return inListItem; + } + return base; + }; + } + return base; + } + let state = base; + for (const token of params.tokens) { + state = state(token); + } + } +}; + + +/***/ }), + +/***/ 2905: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorContext, emphasisMarkersInContent, forEachLine, isBlankLine, + withinAnyRange } = __nccwpck_require__(2935); +const { htmlElementRanges, lineMetadata } = __nccwpck_require__(2260); + +const emphasisRe = /(^|[^\\]|\\\\)(?:(\*\*?\*?)|(__?_?))/g; +const embeddedUnderscoreRe = /([A-Za-z0-9])_([A-Za-z0-9])/g; +const asteriskListItemMarkerRe = /^([\s>]*)\*(\s+)/; +const leftSpaceRe = /^\s+/; +const rightSpaceRe = /\s+$/; +const tablePipeRe = /\|/; + +module.exports = { + "names": [ "MD037", "no-space-in-emphasis" ], + "description": "Spaces inside emphasis markers", + "tags": [ "whitespace", "emphasis" ], + "function": function MD037(params, onError) { + const exclusions = htmlElementRanges(); + // eslint-disable-next-line init-declarations + let effectiveEmphasisLength, emphasisIndex, emphasisKind, emphasisLength, + pendingError = null; + // eslint-disable-next-line jsdoc/require-jsdoc + function resetRunTracking() { + emphasisIndex = -1; + emphasisLength = 0; + emphasisKind = ""; + effectiveEmphasisLength = 0; + pendingError = null; + } + // eslint-disable-next-line jsdoc/require-jsdoc + function handleRunEnd( + line, lineIndex, contextLength, match, matchIndex, inTable + ) { + // Close current run + let content = line.substring(emphasisIndex, matchIndex); + if (!emphasisLength) { + content = content.trimStart(); + } + if (!match) { + content = content.trimEnd(); + } + const leftSpace = leftSpaceRe.test(content); + const rightSpace = rightSpaceRe.test(content); + if ( + (leftSpace || rightSpace) && + (!inTable || !tablePipeRe.test(content)) + ) { + // Report the violation + const contextStart = emphasisIndex - emphasisLength; + const contextEnd = matchIndex + contextLength; + const column = contextStart + 1; + const length = contextEnd - contextStart; + if (!withinAnyRange(exclusions, lineIndex, column, length)) { + const context = line.substring(contextStart, contextEnd); + const leftMarker = line.substring(contextStart, emphasisIndex); + const rightMarker = match ? (match[2] || match[3]) : ""; + const fixedText = `${leftMarker}${content.trim()}${rightMarker}`; + return [ + onError, + lineIndex + 1, + context, + leftSpace, + rightSpace, + [ column, length ], + { + "editColumn": column, + "deleteCount": length, + "insertText": fixedText + } + ]; + } + } + return null; + } + // Initialize + const ignoreMarkersByLine = emphasisMarkersInContent(params); + resetRunTracking(); + forEachLine( + lineMetadata(), + (line, lineIndex, inCode, onFence, inTable, inItem, onBreak, inMath) => { + const onItemStart = (inItem === 1); + if ( + inCode || + onFence || + inTable || + onBreak || + onItemStart || + isBlankLine(line) + ) { + // Emphasis resets when leaving a block + resetRunTracking(); + } + if ( + inCode || + onFence || + onBreak || + inMath + ) { + // Emphasis has no meaning here + return; + } + let patchedLine = line.replace(embeddedUnderscoreRe, "$1 $2"); + if (onItemStart) { + // Trim overlapping '*' list item marker + patchedLine = patchedLine.replace(asteriskListItemMarkerRe, "$1 $2"); + } + let match = null; + // Match all emphasis-looking runs in the line... + while ((match = emphasisRe.exec(patchedLine))) { + const ignoreMarkersForLine = ignoreMarkersByLine[lineIndex]; + const matchIndex = match.index + match[1].length; + if (ignoreMarkersForLine.includes(matchIndex)) { + // Ignore emphasis markers inside code spans and links + continue; + } + const matchLength = match[0].length - match[1].length; + const matchKind = (match[2] || match[3])[0]; + if (emphasisIndex === -1) { + // New run + emphasisIndex = matchIndex + matchLength; + emphasisLength = matchLength; + emphasisKind = matchKind; + effectiveEmphasisLength = matchLength; + } else if (matchKind === emphasisKind) { + // Matching emphasis markers + if (matchLength === effectiveEmphasisLength) { + // Ending an existing run, report any pending error + if (pendingError) { + // @ts-ignore + addErrorContext(...pendingError); + pendingError = null; + } + const error = handleRunEnd( + line, + lineIndex, + effectiveEmphasisLength, + match, + matchIndex, + inTable + ); + if (error) { + // @ts-ignore + addErrorContext(...error); + } + // Reset + resetRunTracking(); + } else if (matchLength === 3) { + // Swap internal run length (1->2 or 2->1) + effectiveEmphasisLength = matchLength - effectiveEmphasisLength; + } else if (effectiveEmphasisLength === 3) { + // Downgrade internal run (3->1 or 3->2) + effectiveEmphasisLength -= matchLength; + } else { + // Upgrade to internal run (1->3 or 2->3) + effectiveEmphasisLength += matchLength; + } + // Back up one character so RegExp has a chance to match the + // next marker (ex: "**star**_underscore_") + if (emphasisRe.lastIndex > 1) { + emphasisRe.lastIndex--; + } + } else if (emphasisRe.lastIndex > 1) { + // Back up one character so RegExp has a chance to match the + // mis-matched marker (ex: "*text_*") + emphasisRe.lastIndex--; + } + } + if (emphasisIndex !== -1) { + pendingError = pendingError || + handleRunEnd(line, lineIndex, 0, null, line.length, inTable); + // Adjust for pending run on new line + emphasisIndex = 0; + emphasisLength = 0; + } + } + ); + } +}; + + +/***/ }), + +/***/ 6054: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorContext, filterTokens, forEachInlineCodeSpan, newLineRe } = + __nccwpck_require__(2935); + +const leftSpaceRe = /^\s([^`]|$)/; +const rightSpaceRe = /[^`]\s$/; + +const spaceInsideCodeInline = (token) => ( + (token.type === "code_inline") && + (leftSpaceRe.test(token.content) || rightSpaceRe.test(token.content)) +); + +module.exports = { + "names": [ "MD038", "no-space-in-code" ], + "description": "Spaces inside code span elements", + "tags": [ "whitespace", "code" ], + "function": function MD038(params, onError) { + filterTokens(params, "inline", (token) => { + if (token.children.some(spaceInsideCodeInline)) { + const tokenLines = params.lines.slice(token.map[0], token.map[1]); + forEachInlineCodeSpan( + tokenLines.join("\n"), + (code, lineIndex, columnIndex, tickCount) => { + let rangeIndex = columnIndex - tickCount; + let rangeLength = code.length + (2 * tickCount); + let rangeLineOffset = 0; + let fixIndex = columnIndex; + let fixLength = code.length; + const codeLines = code.split(newLineRe); + const left = leftSpaceRe.test(code); + const right = !left && rightSpaceRe.test(code); + if (right && (codeLines.length > 1)) { + rangeIndex = 0; + rangeLineOffset = codeLines.length - 1; + fixIndex = 0; + } + if (left || right) { + const codeLinesRange = codeLines[rangeLineOffset]; + if (codeLines.length > 1) { + rangeLength = codeLinesRange.length + tickCount; + fixLength = codeLinesRange.length; + } + const context = tokenLines[lineIndex + rangeLineOffset] + .substring(rangeIndex, rangeIndex + rangeLength); + const codeLinesRangeTrim = codeLinesRange.trim(); + const fixText = + (codeLinesRangeTrim.startsWith("`") ? " " : "") + + codeLinesRangeTrim + + (codeLinesRangeTrim.endsWith("`") ? " " : ""); + addErrorContext( + onError, + token.lineNumber + lineIndex + rangeLineOffset, + context, + left, + right, + [ rangeIndex + 1, rangeLength ], + { + "editColumn": fixIndex + 1, + "deleteCount": fixLength, + "insertText": fixText + } + ); + } + }); + } + }); + } +}; + + +/***/ }), + +/***/ 8596: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorContext, filterTokens } = __nccwpck_require__(2935); + +const spaceInLinkRe = + /\[(?:\s+(?:[^\]]*?)\s*|(?:[^\]]*?)\s+)](?=((?:\([^)]*\))|(?:\[[^\]]*\])))/; + +module.exports = { + "names": [ "MD039", "no-space-in-links" ], + "description": "Spaces inside link text", + "tags": [ "whitespace", "links" ], + "function": function MD039(params, onError) { + filterTokens(params, "inline", (token) => { + const { children } = token; + let { lineNumber } = token; + let inLink = false; + let linkText = ""; + let lineIndex = 0; + for (const child of children) { + const { content, markup, type } = child; + if (type === "link_open") { + inLink = true; + linkText = ""; + } else if (type === "link_close") { + inLink = false; + const left = linkText.trimStart().length !== linkText.length; + const right = linkText.trimEnd().length !== linkText.length; + if (left || right) { + const line = params.lines[lineNumber - 1]; + let range = null; + let fixInfo = null; + const match = line.slice(lineIndex).match(spaceInLinkRe); + if (match) { + const column = match.index + lineIndex + 1; + const length = match[0].length; + range = [ column, length ]; + fixInfo = { + "editColumn": column + 1, + "deleteCount": length - 2, + "insertText": linkText.trim() + }; + lineIndex = column + length - 1; + } + addErrorContext( + onError, + lineNumber, + `[${linkText}]`, + left, + right, + range, + fixInfo + ); + } + } else if ((type === "softbreak") || (type === "hardbreak")) { + lineNumber++; + lineIndex = 0; + } else if (inLink) { + linkText += type.endsWith("_inline") ? + `${markup}${content}${markup}` : + (content || markup); + } + } + }); + } +}; + + +/***/ }), + +/***/ 320: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorContext, filterTokens } = __nccwpck_require__(2935); + +module.exports = { + "names": [ "MD040", "fenced-code-language" ], + "description": "Fenced code blocks should have a language specified", + "tags": [ "code", "language" ], + "function": function MD040(params, onError) { + filterTokens(params, "fence", function forToken(token) { + if (!token.info.trim()) { + addErrorContext(onError, token.lineNumber, token.line); + } + }); + } +}; + + +/***/ }), + +/***/ 8679: +/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => { + +"use strict"; +// @ts-check + + + +const { addErrorContext, frontMatterHasTitle } = __nccwpck_require__(2935); + +module.exports = { + "names": [ "MD041", "first-line-heading", "first-line-h1" ], + "description": "First line in a file should be a top-level heading", + "tags": [ "headings", "headers" ], + "function": function MD041(params, onError) { + const level = Number(params.config.level || 1); + const tag = "h" + level; + const foundFrontMatterTitle = + frontMatterHasTitle( + params.frontMatterLines, + params.config.front_matter_title + ); + if (!foundFrontMatterTitle) { + const htmlHeadingRe = new RegExp(`^]`, "i"); + params.tokens.every((token) => { + let isError = false; + if (token.type === "html_block") { + if (token.content.startsWith("