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("