mirror of
https://github.com/DavidAnson/markdownlint.git
synced 2025-09-22 05:40:48 +02:00
Enable ESLint rule unicorn/no-array-for-each, auto-fix all violations, manually address new issues for ~4% time reduction measured via profile-fixture.mjs on Apple Silicon M1.
This commit is contained in:
parent
15efcb4282
commit
b6471fba31
34 changed files with 414 additions and 389 deletions
|
@ -196,7 +196,6 @@
|
||||||
"unicorn/consistent-function-scoping": "off",
|
"unicorn/consistent-function-scoping": "off",
|
||||||
"unicorn/filename-case": "off",
|
"unicorn/filename-case": "off",
|
||||||
"unicorn/no-array-callback-reference": "off",
|
"unicorn/no-array-callback-reference": "off",
|
||||||
"unicorn/no-array-for-each": "off",
|
|
||||||
"unicorn/no-keyword-prefix": "off",
|
"unicorn/no-keyword-prefix": "off",
|
||||||
"unicorn/no-new-array": "off",
|
"unicorn/no-new-array": "off",
|
||||||
"unicorn/no-null": "off",
|
"unicorn/no-null": "off",
|
||||||
|
|
|
@ -327,11 +327,11 @@ module.exports.getLineMetadata = function getLineMetadata(params) {
|
||||||
filterTokens(params, "hr", (token) => {
|
filterTokens(params, "hr", (token) => {
|
||||||
lineMetadata[token.map[0]][6] = true;
|
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++) {
|
for (let i = token.map[0]; i < token.map[1]; i++) {
|
||||||
lineMetadata[i][7] = true;
|
lineMetadata[i][7] = true;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
return lineMetadata;
|
return lineMetadata;
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
|
@ -343,9 +343,9 @@ module.exports.getLineMetadata = function getLineMetadata(params) {
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function forEachLine(lineMetadata, handler) {
|
function forEachLine(lineMetadata, handler) {
|
||||||
lineMetadata.forEach(function forMetadata(metadata) {
|
for (const metadata of lineMetadata) {
|
||||||
handler(...metadata);
|
handler(...metadata);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
module.exports.forEachLine = forEachLine;
|
module.exports.forEachLine = forEachLine;
|
||||||
// Returns (nested) lists as a flat array (in order)
|
// Returns (nested) lists as a flat array (in order)
|
||||||
|
@ -356,7 +356,7 @@ module.exports.flattenLists = function flattenLists(tokens) {
|
||||||
let nesting = 0;
|
let nesting = 0;
|
||||||
const nestingStack = [];
|
const nestingStack = [];
|
||||||
let lastWithMap = { "map": [0, 1] };
|
let lastWithMap = { "map": [0, 1] };
|
||||||
tokens.forEach((token) => {
|
for (const token of tokens) {
|
||||||
if ((token.type === "bullet_list_open") ||
|
if ((token.type === "bullet_list_open") ||
|
||||||
(token.type === "ordered_list_open")) {
|
(token.type === "ordered_list_open")) {
|
||||||
// Save current context and start a new one
|
// Save current context and start a new one
|
||||||
|
@ -399,24 +399,24 @@ module.exports.flattenLists = function flattenLists(tokens) {
|
||||||
// Track last token with map
|
// Track last token with map
|
||||||
lastWithMap = token;
|
lastWithMap = token;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
return flattenedLists;
|
return flattenedLists;
|
||||||
};
|
};
|
||||||
// Calls the provided function for each specified inline child token
|
// Calls the provided function for each specified inline child token
|
||||||
module.exports.forEachInlineChild =
|
module.exports.forEachInlineChild =
|
||||||
function forEachInlineChild(params, type, handler) {
|
function forEachInlineChild(params, type, handler) {
|
||||||
filterTokens(params, "inline", function forToken(token) {
|
filterTokens(params, "inline", function forToken(token) {
|
||||||
token.children.forEach(function forChild(child) {
|
for (const child of token.children) {
|
||||||
if (child.type === type) {
|
if (child.type === type) {
|
||||||
handler(child, token);
|
handler(child, token);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// Calls the provided function for each heading's content
|
// Calls the provided function for each heading's content
|
||||||
module.exports.forEachHeading = function forEachHeading(params, handler) {
|
module.exports.forEachHeading = function forEachHeading(params, handler) {
|
||||||
let heading = null;
|
let heading = null;
|
||||||
params.tokens.forEach(function forToken(token) {
|
for (const token of params.tokens) {
|
||||||
if (token.type === "heading_open") {
|
if (token.type === "heading_open") {
|
||||||
heading = token;
|
heading = token;
|
||||||
}
|
}
|
||||||
|
@ -426,7 +426,7 @@ module.exports.forEachHeading = function forEachHeading(params, handler) {
|
||||||
else if ((token.type === "inline") && heading) {
|
else if ((token.type === "inline") && heading) {
|
||||||
handler(heading, token.content, token);
|
handler(heading, token.content, token);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Calls the provided function for each inline code span's content.
|
* Calls the provided function for each inline code span's content.
|
||||||
|
@ -751,7 +751,7 @@ function emphasisMarkersInContent(params) {
|
||||||
const { lines } = params;
|
const { lines } = params;
|
||||||
const byLine = new Array(lines.length);
|
const byLine = new Array(lines.length);
|
||||||
// Search links
|
// Search links
|
||||||
lines.forEach((tokenLine, tokenLineIndex) => {
|
for (const [tokenLineIndex, tokenLine] of lines.entries()) {
|
||||||
const inLine = [];
|
const inLine = [];
|
||||||
forEachLink(tokenLine, (index, match) => {
|
forEachLink(tokenLine, (index, match) => {
|
||||||
let markerMatch = null;
|
let markerMatch = null;
|
||||||
|
@ -760,7 +760,7 @@ function emphasisMarkersInContent(params) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
byLine[tokenLineIndex] = inLine;
|
byLine[tokenLineIndex] = inLine;
|
||||||
});
|
}
|
||||||
// Search code spans
|
// Search code spans
|
||||||
filterTokens(params, "inline", (token) => {
|
filterTokens(params, "inline", (token) => {
|
||||||
const { children, lineNumber, map } = token;
|
const { children, lineNumber, map } = token;
|
||||||
|
@ -768,7 +768,7 @@ function emphasisMarkersInContent(params) {
|
||||||
const tokenLines = lines.slice(map[0], map[1]);
|
const tokenLines = lines.slice(map[0], map[1]);
|
||||||
forEachInlineCodeSpan(tokenLines.join("\n"), (code, lineIndex, column, tickCount) => {
|
forEachInlineCodeSpan(tokenLines.join("\n"), (code, lineIndex, column, tickCount) => {
|
||||||
const codeLines = code.split(newLineRe);
|
const codeLines = code.split(newLineRe);
|
||||||
codeLines.forEach((codeLine, codeLineIndex) => {
|
for (const [codeLineIndex, codeLine] of codeLines.entries()) {
|
||||||
const byLineIndex = lineNumber - 1 + lineIndex + codeLineIndex;
|
const byLineIndex = lineNumber - 1 + lineIndex + codeLineIndex;
|
||||||
const inLine = byLine[byLineIndex];
|
const inLine = byLine[byLineIndex];
|
||||||
const codeLineOffset = codeLineIndex ? 0 : column - 1 + tickCount;
|
const codeLineOffset = codeLineIndex ? 0 : column - 1 + tickCount;
|
||||||
|
@ -777,7 +777,7 @@ function emphasisMarkersInContent(params) {
|
||||||
inLine.push(codeLineOffset + match.index);
|
inLine.push(codeLineOffset + match.index);
|
||||||
}
|
}
|
||||||
byLine[byLineIndex] = inLine;
|
byLine[byLineIndex] = inLine;
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -924,7 +924,7 @@ function getPreferredLineEnding(input, os) {
|
||||||
let lf = 0;
|
let lf = 0;
|
||||||
let crlf = 0;
|
let crlf = 0;
|
||||||
const endings = input.match(newLineRe) || [];
|
const endings = input.match(newLineRe) || [];
|
||||||
endings.forEach((ending) => {
|
for (const ending of endings) {
|
||||||
// eslint-disable-next-line default-case
|
// eslint-disable-next-line default-case
|
||||||
switch (ending) {
|
switch (ending) {
|
||||||
case "\r":
|
case "\r":
|
||||||
|
@ -937,7 +937,7 @@ function getPreferredLineEnding(input, os) {
|
||||||
crlf++;
|
crlf++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
let preferredLineEnding = null;
|
let preferredLineEnding = null;
|
||||||
if (!cr && !lf && !crlf) {
|
if (!cr && !lf && !crlf) {
|
||||||
preferredLineEnding = (os && os.EOL) || "\n";
|
preferredLineEnding = (os && os.EOL) || "\n";
|
||||||
|
@ -1021,8 +1021,10 @@ function applyFixes(input, errors) {
|
||||||
return unique;
|
return unique;
|
||||||
});
|
});
|
||||||
// Collapse insert/no-delete and no-insert/delete for same line/column
|
// Collapse insert/no-delete and no-insert/delete for same line/column
|
||||||
lastFixInfo = {};
|
lastFixInfo = {
|
||||||
fixInfos.forEach((fixInfo) => {
|
"lineNumber": -1
|
||||||
|
};
|
||||||
|
for (const fixInfo of fixInfos) {
|
||||||
if ((fixInfo.lineNumber === lastFixInfo.lineNumber) &&
|
if ((fixInfo.lineNumber === lastFixInfo.lineNumber) &&
|
||||||
(fixInfo.editColumn === lastFixInfo.editColumn) &&
|
(fixInfo.editColumn === lastFixInfo.editColumn) &&
|
||||||
!fixInfo.insertText &&
|
!fixInfo.insertText &&
|
||||||
|
@ -1033,12 +1035,12 @@ function applyFixes(input, errors) {
|
||||||
lastFixInfo.lineNumber = 0;
|
lastFixInfo.lineNumber = 0;
|
||||||
}
|
}
|
||||||
lastFixInfo = fixInfo;
|
lastFixInfo = fixInfo;
|
||||||
});
|
}
|
||||||
fixInfos = fixInfos.filter((fixInfo) => fixInfo.lineNumber);
|
fixInfos = fixInfos.filter((fixInfo) => fixInfo.lineNumber);
|
||||||
// Apply all (remaining/updated) fixes
|
// Apply all (remaining/updated) fixes
|
||||||
let lastLineIndex = -1;
|
let lastLineIndex = -1;
|
||||||
let lastEditIndex = -1;
|
let lastEditIndex = -1;
|
||||||
fixInfos.forEach((fixInfo) => {
|
for (const fixInfo of fixInfos) {
|
||||||
const { lineNumber, editColumn, deleteCount } = fixInfo;
|
const { lineNumber, editColumn, deleteCount } = fixInfo;
|
||||||
const lineIndex = lineNumber - 1;
|
const lineIndex = lineNumber - 1;
|
||||||
const editIndex = editColumn - 1;
|
const editIndex = editColumn - 1;
|
||||||
|
@ -1050,7 +1052,7 @@ function applyFixes(input, errors) {
|
||||||
}
|
}
|
||||||
lastLineIndex = lineIndex;
|
lastLineIndex = lineIndex;
|
||||||
lastEditIndex = editIndex;
|
lastEditIndex = editIndex;
|
||||||
});
|
}
|
||||||
// Return corrected input
|
// Return corrected input
|
||||||
return lines.filter((line) => line !== null).join(lineEnding);
|
return lines.filter((line) => line !== null).join(lineEnding);
|
||||||
}
|
}
|
||||||
|
@ -1289,31 +1291,31 @@ function validateRuleList(ruleList, synchronous) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
const allIds = {};
|
const allIds = {};
|
||||||
ruleList.forEach(function forRule(rule, index) {
|
for (const [index, rule] of ruleList.entries()) {
|
||||||
const customIndex = index - rules.length;
|
const customIndex = index - rules.length;
|
||||||
// eslint-disable-next-line jsdoc/require-jsdoc
|
// eslint-disable-next-line no-inner-declarations, jsdoc/require-jsdoc
|
||||||
function newError(property) {
|
function newError(property) {
|
||||||
return new Error("Property '" + property + "' of custom rule at index " +
|
return new Error("Property '" + property + "' of custom rule at index " +
|
||||||
customIndex + " is incorrect.");
|
customIndex + " is incorrect.");
|
||||||
}
|
}
|
||||||
["names", "tags"].forEach(function forProperty(property) {
|
for (const property of ["names", "tags"]) {
|
||||||
const value = rule[property];
|
const value = rule[property];
|
||||||
if (!result &&
|
if (!result &&
|
||||||
(!value || !Array.isArray(value) || (value.length === 0) ||
|
(!value || !Array.isArray(value) || (value.length === 0) ||
|
||||||
!value.every(helpers.isString) || value.some(helpers.isEmptyString))) {
|
!value.every(helpers.isString) || value.some(helpers.isEmptyString))) {
|
||||||
result = newError(property);
|
result = newError(property);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
[
|
for (const propertyInfo of [
|
||||||
["description", "string"],
|
["description", "string"],
|
||||||
["function", "function"]
|
["function", "function"]
|
||||||
].forEach(function forProperty(propertyInfo) {
|
]) {
|
||||||
const property = propertyInfo[0];
|
const property = propertyInfo[0];
|
||||||
const value = rule[property];
|
const value = rule[property];
|
||||||
if (!result && (!value || (typeof value !== propertyInfo[1]))) {
|
if (!result && (!value || (typeof value !== propertyInfo[1]))) {
|
||||||
result = newError(property);
|
result = newError(property);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
if (!result &&
|
if (!result &&
|
||||||
rule.information &&
|
rule.information &&
|
||||||
(Object.getPrototypeOf(rule.information) !== URL.prototype)) {
|
(Object.getPrototypeOf(rule.information) !== URL.prototype)) {
|
||||||
|
@ -1329,24 +1331,25 @@ function validateRuleList(ruleList, synchronous) {
|
||||||
" is asynchronous and can not be used in a synchronous context.");
|
" is asynchronous and can not be used in a synchronous context.");
|
||||||
}
|
}
|
||||||
if (!result) {
|
if (!result) {
|
||||||
rule.names.forEach(function forName(name) {
|
for (const name of rule.names) {
|
||||||
const nameUpper = name.toUpperCase();
|
const nameUpper = name.toUpperCase();
|
||||||
if (!result && (allIds[nameUpper] !== undefined)) {
|
if (!result && (allIds[nameUpper] !== undefined)) {
|
||||||
result = new Error("Name '" + name + "' of custom rule at index " +
|
result = new Error("Name '" + name + "' of custom rule at index " +
|
||||||
customIndex + " is already used as a name or tag.");
|
customIndex + " is already used as a name or tag.");
|
||||||
}
|
}
|
||||||
allIds[nameUpper] = true;
|
allIds[nameUpper] = true;
|
||||||
});
|
}
|
||||||
rule.tags.forEach(function forTag(tag) {
|
for (const tag of rule.tags) {
|
||||||
const tagUpper = tag.toUpperCase();
|
const tagUpper = tag.toUpperCase();
|
||||||
if (!result && allIds[tagUpper]) {
|
if (!result && allIds[tagUpper]) {
|
||||||
result = new Error("Tag '" + tag + "' of custom rule at index " +
|
result = new Error("Tag '" + tag + "' of custom rule at index " +
|
||||||
customIndex + " is already used as a name.");
|
customIndex + " is already used as a name.");
|
||||||
}
|
}
|
||||||
allIds[tagUpper] = false;
|
allIds[tagUpper] = false;
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
// @ts-ignore
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -1363,10 +1366,10 @@ function newResults(ruleList) {
|
||||||
const results = [];
|
const results = [];
|
||||||
const keys = Object.keys(lintResults);
|
const keys = Object.keys(lintResults);
|
||||||
keys.sort();
|
keys.sort();
|
||||||
keys.forEach(function forFile(file) {
|
for (const file of keys) {
|
||||||
const fileResults = lintResults[file];
|
const fileResults = lintResults[file];
|
||||||
if (Array.isArray(fileResults)) {
|
if (Array.isArray(fileResults)) {
|
||||||
fileResults.forEach(function forResult(result) {
|
for (const result of fileResults) {
|
||||||
const ruleMoniker = result.ruleNames ?
|
const ruleMoniker = result.ruleNames ?
|
||||||
result.ruleNames.join("/") :
|
result.ruleNames.join("/") :
|
||||||
(result.ruleName + "/" + result.ruleAlias);
|
(result.ruleName + "/" + result.ruleAlias);
|
||||||
|
@ -1380,30 +1383,32 @@ function newResults(ruleList) {
|
||||||
(result.errorContext ?
|
(result.errorContext ?
|
||||||
" [Context: \"" + result.errorContext + "\"]" :
|
" [Context: \"" + result.errorContext + "\"]" :
|
||||||
""));
|
""));
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!ruleNameToRule) {
|
if (!ruleNameToRule) {
|
||||||
ruleNameToRule = {};
|
ruleNameToRule = {};
|
||||||
ruleList.forEach(function forRule(rule) {
|
for (const rule of ruleList) {
|
||||||
const ruleName = rule.names[0].toUpperCase();
|
const ruleName = rule.names[0].toUpperCase();
|
||||||
ruleNameToRule[ruleName] = rule;
|
ruleNameToRule[ruleName] = rule;
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
Object.keys(fileResults).forEach(function forRule(ruleName) {
|
for (const [ruleName, ruleResults] of Object.entries(fileResults)) {
|
||||||
const rule = ruleNameToRule[ruleName.toUpperCase()];
|
const rule = ruleNameToRule[ruleName.toUpperCase()];
|
||||||
const ruleResults = fileResults[ruleName];
|
for (const lineNumber of ruleResults) {
|
||||||
ruleResults.forEach(function forLine(lineNumber) {
|
// @ts-ignore
|
||||||
const nameIndex = Math.min(useAlias ? 1 : 0, rule.names.length - 1);
|
const nameIndex = Math.min(useAlias ? 1 : 0, rule.names.length - 1);
|
||||||
const result = file + ": " +
|
const result = file + ": " +
|
||||||
lineNumber + ": " +
|
lineNumber + ": " +
|
||||||
|
// @ts-ignore
|
||||||
rule.names[nameIndex] + " " +
|
rule.names[nameIndex] + " " +
|
||||||
|
// @ts-ignore
|
||||||
rule.description;
|
rule.description;
|
||||||
results.push(result);
|
results.push(result);
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
return results.join("\n");
|
return results.join("\n");
|
||||||
}
|
}
|
||||||
Object.defineProperty(lintResults, "toString", { "value": toString });
|
Object.defineProperty(lintResults, "toString", { "value": toString });
|
||||||
|
@ -1445,7 +1450,7 @@ function removeFrontMatter(content, frontMatter) {
|
||||||
*/
|
*/
|
||||||
function annotateTokens(tokens, lines) {
|
function annotateTokens(tokens, lines) {
|
||||||
let trMap = null;
|
let trMap = null;
|
||||||
tokens.forEach(function forToken(token) {
|
for (const token of tokens) {
|
||||||
// Provide missing maps for table content
|
// Provide missing maps for table content
|
||||||
if (token.type === "tr_open") {
|
if (token.type === "tr_open") {
|
||||||
trMap = token.map;
|
trMap = token.map;
|
||||||
|
@ -1475,7 +1480,7 @@ function annotateTokens(tokens, lines) {
|
||||||
helpers.forEachInlineCodeSpan(token.content, function handleInlineCodeSpan(code) {
|
helpers.forEachInlineCodeSpan(token.content, function handleInlineCodeSpan(code) {
|
||||||
codeSpanExtraLines.push(code.split(helpers.newLineRe).length - 1);
|
codeSpanExtraLines.push(code.split(helpers.newLineRe).length - 1);
|
||||||
});
|
});
|
||||||
(token.children || []).forEach(function forChild(child) {
|
for (const child of (token.children || [])) {
|
||||||
child.lineNumber = lineNumber;
|
child.lineNumber = lineNumber;
|
||||||
child.line = lines[lineNumber - 1];
|
child.line = lines[lineNumber - 1];
|
||||||
if ((child.type === "softbreak") || (child.type === "hardbreak")) {
|
if ((child.type === "softbreak") || (child.type === "hardbreak")) {
|
||||||
|
@ -1484,9 +1489,9 @@ function annotateTokens(tokens, lines) {
|
||||||
else if (child.type === "code_inline") {
|
else if (child.type === "code_inline") {
|
||||||
lineNumber += codeSpanExtraLines.shift();
|
lineNumber += codeSpanExtraLines.shift();
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Map rule names/tags to canonical rule name.
|
* Map rule names/tags to canonical rule name.
|
||||||
|
@ -1497,24 +1502,24 @@ function annotateTokens(tokens, lines) {
|
||||||
function mapAliasToRuleNames(ruleList) {
|
function mapAliasToRuleNames(ruleList) {
|
||||||
const aliasToRuleNames = {};
|
const aliasToRuleNames = {};
|
||||||
// const tagToRuleNames = {};
|
// const tagToRuleNames = {};
|
||||||
ruleList.forEach(function forRule(rule) {
|
for (const rule of ruleList) {
|
||||||
const ruleName = rule.names[0].toUpperCase();
|
const ruleName = rule.names[0].toUpperCase();
|
||||||
// The following is useful for updating README.md:
|
// The following is useful for updating README.md:
|
||||||
// console.log(
|
// console.log(
|
||||||
// "* **[" + ruleName + "](doc/Rules.md#" + ruleName.toLowerCase() +
|
// "* **[" + ruleName + "](doc/Rules.md#" + ruleName.toLowerCase() +
|
||||||
// ")** *" + rule.names.slice(1).join("/") + "* - " + rule.description);
|
// ")** *" + rule.names.slice(1).join("/") + "* - " + rule.description);
|
||||||
rule.names.forEach(function forName(name) {
|
for (const name of rule.names) {
|
||||||
const nameUpper = name.toUpperCase();
|
const nameUpper = name.toUpperCase();
|
||||||
aliasToRuleNames[nameUpper] = [ruleName];
|
aliasToRuleNames[nameUpper] = [ruleName];
|
||||||
});
|
}
|
||||||
rule.tags.forEach(function forTag(tag) {
|
for (const tag of rule.tags) {
|
||||||
const tagUpper = tag.toUpperCase();
|
const tagUpper = tag.toUpperCase();
|
||||||
const ruleNames = aliasToRuleNames[tagUpper] || [];
|
const ruleNames = aliasToRuleNames[tagUpper] || [];
|
||||||
ruleNames.push(ruleName);
|
ruleNames.push(ruleName);
|
||||||
aliasToRuleNames[tagUpper] = ruleNames;
|
aliasToRuleNames[tagUpper] = ruleNames;
|
||||||
// tagToRuleNames[tag] = ruleName;
|
// tagToRuleNames[tag] = ruleName;
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
// The following is useful for updating README.md:
|
// The following is useful for updating README.md:
|
||||||
// Object.keys(tagToRuleNames).sort().forEach(function forTag(tag) {
|
// Object.keys(tagToRuleNames).sort().forEach(function forTag(tag) {
|
||||||
// console.log("* **" + tag + "** - " +
|
// console.log("* **" + tag + "** - " +
|
||||||
|
@ -1536,14 +1541,14 @@ function getEffectiveConfig(ruleList, config, aliasToRuleNames) {
|
||||||
const defaultKey = Object.keys(config).filter((key) => key.toUpperCase() === "DEFAULT");
|
const defaultKey = Object.keys(config).filter((key) => key.toUpperCase() === "DEFAULT");
|
||||||
const ruleDefault = (defaultKey.length === 0) || !!config[defaultKey[0]];
|
const ruleDefault = (defaultKey.length === 0) || !!config[defaultKey[0]];
|
||||||
const effectiveConfig = {};
|
const effectiveConfig = {};
|
||||||
ruleList.forEach((rule) => {
|
for (const rule of ruleList) {
|
||||||
const ruleName = rule.names[0].toUpperCase();
|
const ruleName = rule.names[0].toUpperCase();
|
||||||
effectiveConfig[ruleName] = ruleDefault;
|
effectiveConfig[ruleName] = ruleDefault;
|
||||||
});
|
}
|
||||||
deprecatedRuleNames.forEach((ruleName) => {
|
for (const ruleName of deprecatedRuleNames) {
|
||||||
effectiveConfig[ruleName] = false;
|
effectiveConfig[ruleName] = false;
|
||||||
});
|
}
|
||||||
Object.keys(config).forEach((key) => {
|
for (const key of Object.keys(config)) {
|
||||||
let value = config[key];
|
let value = config[key];
|
||||||
if (value) {
|
if (value) {
|
||||||
if (!(value instanceof Object)) {
|
if (!(value instanceof Object)) {
|
||||||
|
@ -1554,10 +1559,10 @@ function getEffectiveConfig(ruleList, config, aliasToRuleNames) {
|
||||||
value = false;
|
value = false;
|
||||||
}
|
}
|
||||||
const keyUpper = key.toUpperCase();
|
const keyUpper = key.toUpperCase();
|
||||||
(aliasToRuleNames[keyUpper] || []).forEach((ruleName) => {
|
for (const ruleName of (aliasToRuleNames[keyUpper] || [])) {
|
||||||
effectiveConfig[ruleName] = value;
|
effectiveConfig[ruleName] = value;
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
return effectiveConfig;
|
return effectiveConfig;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -1615,7 +1620,7 @@ function getEnabledRulesPerLineNumber(ruleList, lines, frontMatterLines, noInlin
|
||||||
// Helper functions
|
// Helper functions
|
||||||
// eslint-disable-next-line jsdoc/require-jsdoc
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
||||||
function handleInlineConfig(input, forEachMatch, forEachLine) {
|
function handleInlineConfig(input, forEachMatch, forEachLine) {
|
||||||
input.forEach((line, lineIndex) => {
|
for (const [lineIndex, line] of input.entries()) {
|
||||||
if (!noInlineConfig) {
|
if (!noInlineConfig) {
|
||||||
let match = null;
|
let match = null;
|
||||||
while ((match = helpers.inlineCommentStartRe.exec(line))) {
|
while ((match = helpers.inlineCommentStartRe.exec(line))) {
|
||||||
|
@ -1632,7 +1637,7 @@ function getEnabledRulesPerLineNumber(ruleList, lines, frontMatterLines, noInlin
|
||||||
if (forEachLine) {
|
if (forEachLine) {
|
||||||
forEachLine();
|
forEachLine();
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line jsdoc/require-jsdoc
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
||||||
function configureFile(action, parameter) {
|
function configureFile(action, parameter) {
|
||||||
|
@ -1649,11 +1654,11 @@ function getEnabledRulesPerLineNumber(ruleList, lines, frontMatterLines, noInlin
|
||||||
const enabled = (action.startsWith("ENABLE"));
|
const enabled = (action.startsWith("ENABLE"));
|
||||||
const trimmed = parameter && parameter.trim();
|
const trimmed = parameter && parameter.trim();
|
||||||
const items = trimmed ? trimmed.toUpperCase().split(/\s+/) : allRuleNames;
|
const items = trimmed ? trimmed.toUpperCase().split(/\s+/) : allRuleNames;
|
||||||
items.forEach((nameUpper) => {
|
for (const nameUpper of items) {
|
||||||
(aliasToRuleNames[nameUpper] || []).forEach((ruleName) => {
|
for (const ruleName of (aliasToRuleNames[nameUpper] || [])) {
|
||||||
state[ruleName] = enabled;
|
state[ruleName] = enabled;
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line jsdoc/require-jsdoc
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
||||||
|
@ -1691,11 +1696,11 @@ function getEnabledRulesPerLineNumber(ruleList, lines, frontMatterLines, noInlin
|
||||||
// Handle inline comments
|
// Handle inline comments
|
||||||
handleInlineConfig([lines.join("\n")], configureFile);
|
handleInlineConfig([lines.join("\n")], configureFile);
|
||||||
const effectiveConfig = getEffectiveConfig(ruleList, config, aliasToRuleNames);
|
const effectiveConfig = getEffectiveConfig(ruleList, config, aliasToRuleNames);
|
||||||
ruleList.forEach((rule) => {
|
for (const rule of ruleList) {
|
||||||
const ruleName = rule.names[0].toUpperCase();
|
const ruleName = rule.names[0].toUpperCase();
|
||||||
allRuleNames.push(ruleName);
|
allRuleNames.push(ruleName);
|
||||||
enabledRules[ruleName] = !!effectiveConfig[ruleName];
|
enabledRules[ruleName] = !!effectiveConfig[ruleName];
|
||||||
});
|
}
|
||||||
capturedRules = enabledRules;
|
capturedRules = enabledRules;
|
||||||
handleInlineConfig(lines, enableDisableFile);
|
handleInlineConfig(lines, enableDisableFile);
|
||||||
handleInlineConfig(lines, captureRestoreEnableDisable, updateLineState);
|
handleInlineConfig(lines, captureRestoreEnableDisable, updateLineState);
|
||||||
|
@ -2019,10 +2024,10 @@ function lintInput(options, synchronous, callback) {
|
||||||
3 : options.resultVersion;
|
3 : options.resultVersion;
|
||||||
const md = markdownIt({ "html": true });
|
const md = markdownIt({ "html": true });
|
||||||
const markdownItPlugins = options.markdownItPlugins || [];
|
const markdownItPlugins = options.markdownItPlugins || [];
|
||||||
markdownItPlugins.forEach(function forPlugin(plugin) {
|
for (const plugin of markdownItPlugins) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
md.use(...plugin);
|
md.use(...plugin);
|
||||||
});
|
}
|
||||||
const fs = options.fs || __webpack_require__(/*! fs */ "?ec0a");
|
const fs = options.fs || __webpack_require__(/*! fs */ "?ec0a");
|
||||||
const results = newResults(ruleList);
|
const results = newResults(ruleList);
|
||||||
let done = false;
|
let done = false;
|
||||||
|
@ -2429,12 +2434,12 @@ module.exports = {
|
||||||
const style = String(params.config.style || "consistent");
|
const style = String(params.config.style || "consistent");
|
||||||
let expectedStyle = style;
|
let expectedStyle = style;
|
||||||
const nestingStyles = [];
|
const nestingStyles = [];
|
||||||
flattenedLists().forEach((list) => {
|
for (const list of flattenedLists()) {
|
||||||
if (list.unordered) {
|
if (list.unordered) {
|
||||||
if (expectedStyle === "consistent") {
|
if (expectedStyle === "consistent") {
|
||||||
expectedStyle = unorderedListStyleFor(list.items[0]);
|
expectedStyle = unorderedListStyleFor(list.items[0]);
|
||||||
}
|
}
|
||||||
list.items.forEach((item) => {
|
for (const item of list.items) {
|
||||||
const itemStyle = unorderedListStyleFor(item);
|
const itemStyle = unorderedListStyleFor(item);
|
||||||
if (style === "sublist") {
|
if (style === "sublist") {
|
||||||
const nesting = list.nesting;
|
const nesting = list.nesting;
|
||||||
|
@ -2463,9 +2468,9 @@ module.exports = {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
addErrorDetailIf(onError, item.lineNumber, expectedStyle, itemStyle, null, null, range, fixInfo);
|
addErrorDetailIf(onError, item.lineNumber, expectedStyle, itemStyle, null, null, range, fixInfo);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2488,12 +2493,12 @@ module.exports = {
|
||||||
"description": "Inconsistent indentation for list items at the same level",
|
"description": "Inconsistent indentation for list items at the same level",
|
||||||
"tags": ["bullet", "ul", "indentation"],
|
"tags": ["bullet", "ul", "indentation"],
|
||||||
"function": function MD005(params, onError) {
|
"function": function MD005(params, onError) {
|
||||||
flattenedLists().forEach((list) => {
|
for (const list of flattenedLists()) {
|
||||||
const expectedIndent = list.indent;
|
const expectedIndent = list.indent;
|
||||||
let expectedEnd = 0;
|
let expectedEnd = 0;
|
||||||
let actualEnd = -1;
|
let actualEnd = -1;
|
||||||
let endMatching = false;
|
let endMatching = false;
|
||||||
list.items.forEach((item) => {
|
for (const item of list.items) {
|
||||||
const { line, lineNumber } = item;
|
const { line, lineNumber } = item;
|
||||||
const actualIndent = indentFor(item);
|
const actualIndent = indentFor(item);
|
||||||
let match = null;
|
let match = null;
|
||||||
|
@ -2528,8 +2533,8 @@ module.exports = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2552,16 +2557,16 @@ module.exports = {
|
||||||
"description": "Consider starting bulleted lists at the beginning of the line",
|
"description": "Consider starting bulleted lists at the beginning of the line",
|
||||||
"tags": ["bullet", "ul", "indentation"],
|
"tags": ["bullet", "ul", "indentation"],
|
||||||
"function": function MD006(params, onError) {
|
"function": function MD006(params, onError) {
|
||||||
flattenedLists().forEach((list) => {
|
for (const list of flattenedLists()) {
|
||||||
if (list.unordered && !list.nesting && (list.indent !== 0)) {
|
if (list.unordered && !list.nesting && (list.indent !== 0)) {
|
||||||
list.items.forEach((item) => {
|
for (const item of list.items) {
|
||||||
const { lineNumber, line } = item;
|
const { lineNumber, line } = item;
|
||||||
addErrorDetailIf(onError, lineNumber, 0, list.indent, null, null, rangeFromRegExp(line, listItemMarkerRe), {
|
addErrorDetailIf(onError, lineNumber, 0, list.indent, null, null, rangeFromRegExp(line, listItemMarkerRe), {
|
||||||
"deleteCount": line.length - line.trimStart().length
|
"deleteCount": line.length - line.trimStart().length
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2587,9 +2592,9 @@ module.exports = {
|
||||||
const indent = Number(params.config.indent || 2);
|
const indent = Number(params.config.indent || 2);
|
||||||
const startIndented = !!params.config.start_indented;
|
const startIndented = !!params.config.start_indented;
|
||||||
const startIndent = Number(params.config.start_indent || indent);
|
const startIndent = Number(params.config.start_indent || indent);
|
||||||
flattenedLists().forEach((list) => {
|
for (const list of flattenedLists()) {
|
||||||
if (list.unordered && list.parentsUnordered) {
|
if (list.unordered && list.parentsUnordered) {
|
||||||
list.items.forEach((item) => {
|
for (const item of list.items) {
|
||||||
const { lineNumber, line } = item;
|
const { lineNumber, line } = item;
|
||||||
const expectedIndent = (startIndented ? startIndent : 0) +
|
const expectedIndent = (startIndented ? startIndent : 0) +
|
||||||
(list.nesting * indent);
|
(list.nesting * indent);
|
||||||
|
@ -2606,9 +2611,9 @@ module.exports = {
|
||||||
"deleteCount": actualIndent,
|
"deleteCount": actualIndent,
|
||||||
"insertText": "".padEnd(expectedIndent)
|
"insertText": "".padEnd(expectedIndent)
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2879,11 +2884,11 @@ module.exports = {
|
||||||
const linkOnlyLineNumbers = [];
|
const linkOnlyLineNumbers = [];
|
||||||
filterTokens(params, "inline", (token) => {
|
filterTokens(params, "inline", (token) => {
|
||||||
let childTokenTypes = "";
|
let childTokenTypes = "";
|
||||||
token.children.forEach((child) => {
|
for (const child of token.children) {
|
||||||
if (child.type !== "text" || child.content !== "") {
|
if (child.type !== "text" || child.content !== "") {
|
||||||
childTokenTypes += tokenTypeMap[child.type] || "x";
|
childTokenTypes += tokenTypeMap[child.type] || "x";
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
if (linkOrImageOnlyLineRe.test(childTokenTypes)) {
|
if (linkOrImageOnlyLineRe.test(childTokenTypes)) {
|
||||||
linkOnlyLineNumbers.push(token.lineNumber);
|
linkOnlyLineNumbers.push(token.lineNumber);
|
||||||
}
|
}
|
||||||
|
@ -2930,7 +2935,7 @@ module.exports = {
|
||||||
"description": "Dollar signs used before commands without showing output",
|
"description": "Dollar signs used before commands without showing output",
|
||||||
"tags": ["code"],
|
"tags": ["code"],
|
||||||
"function": function MD014(params, onError) {
|
"function": function MD014(params, onError) {
|
||||||
["code_block", "fence"].forEach((type) => {
|
for (const type of ["code_block", "fence"]) {
|
||||||
filterTokens(params, type, (token) => {
|
filterTokens(params, type, (token) => {
|
||||||
const margin = (token.type === "fence") ? 1 : 0;
|
const margin = (token.type === "fence") ? 1 : 0;
|
||||||
const dollarInstances = [];
|
const dollarInstances = [];
|
||||||
|
@ -2951,16 +2956,16 @@ module.exports = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (allDollars) {
|
if (allDollars) {
|
||||||
dollarInstances.forEach((instance) => {
|
for (const instance of dollarInstances) {
|
||||||
const [i, lineTrim, column, length] = instance;
|
const [i, lineTrim, column, length] = instance;
|
||||||
addErrorContext(onError, i + 1, lineTrim, null, null, [column, length], {
|
addErrorContext(onError, i + 1, lineTrim, null, null, [column, length], {
|
||||||
"editColumn": column,
|
"editColumn": column,
|
||||||
"deleteCount": length
|
"deleteCount": length
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3362,7 +3367,7 @@ module.exports = {
|
||||||
"function": function MD027(params, onError) {
|
"function": function MD027(params, onError) {
|
||||||
let blockquoteNesting = 0;
|
let blockquoteNesting = 0;
|
||||||
let listItemNesting = 0;
|
let listItemNesting = 0;
|
||||||
params.tokens.forEach((token) => {
|
for (const token of params.tokens) {
|
||||||
const { content, lineNumber, type } = token;
|
const { content, lineNumber, type } = token;
|
||||||
if (type === "blockquote_open") {
|
if (type === "blockquote_open") {
|
||||||
blockquoteNesting++;
|
blockquoteNesting++;
|
||||||
|
@ -3392,7 +3397,7 @@ module.exports = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3416,7 +3421,7 @@ module.exports = {
|
||||||
"function": function MD028(params, onError) {
|
"function": function MD028(params, onError) {
|
||||||
let prevToken = {};
|
let prevToken = {};
|
||||||
let prevLineNumber = null;
|
let prevLineNumber = null;
|
||||||
params.tokens.forEach(function forToken(token) {
|
for (const token of params.tokens) {
|
||||||
if ((token.type === "blockquote_open") &&
|
if ((token.type === "blockquote_open") &&
|
||||||
(prevToken.type === "blockquote_close")) {
|
(prevToken.type === "blockquote_close")) {
|
||||||
for (let lineNumber = prevLineNumber; lineNumber < token.lineNumber; lineNumber++) {
|
for (let lineNumber = prevLineNumber; lineNumber < token.lineNumber; lineNumber++) {
|
||||||
|
@ -3427,7 +3432,7 @@ module.exports = {
|
||||||
if (token.type === "blockquote_open") {
|
if (token.type === "blockquote_open") {
|
||||||
prevLineNumber = token.map[1] + 1;
|
prevLineNumber = token.map[1] + 1;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3456,7 +3461,8 @@ module.exports = {
|
||||||
"tags": ["ol"],
|
"tags": ["ol"],
|
||||||
"function": function MD029(params, onError) {
|
"function": function MD029(params, onError) {
|
||||||
const style = String(params.config.style || "one_or_ordered");
|
const style = String(params.config.style || "one_or_ordered");
|
||||||
flattenedLists().filter((list) => !list.unordered).forEach((list) => {
|
const filteredLists = flattenedLists().filter((list) => !list.unordered);
|
||||||
|
for (const list of filteredLists) {
|
||||||
const { items } = list;
|
const { items } = list;
|
||||||
let current = 1;
|
let current = 1;
|
||||||
let incrementing = false;
|
let incrementing = false;
|
||||||
|
@ -3488,7 +3494,7 @@ module.exports = {
|
||||||
current = 1;
|
current = 1;
|
||||||
}
|
}
|
||||||
// Validate each list item marker
|
// Validate each list item marker
|
||||||
items.forEach((item) => {
|
for (const item of items) {
|
||||||
const match = orderedListItemMarkerRe.exec(item.line);
|
const match = orderedListItemMarkerRe.exec(item.line);
|
||||||
if (match) {
|
if (match) {
|
||||||
addErrorDetailIf(onError, item.lineNumber, String(current), match[1], "Style: " + listStyleExamples[listStyle], null, rangeFromRegExp(item.line, listItemMarkerRe));
|
addErrorDetailIf(onError, item.lineNumber, String(current), match[1], "Style: " + listStyleExamples[listStyle], null, rangeFromRegExp(item.line, listItemMarkerRe));
|
||||||
|
@ -3496,8 +3502,8 @@ module.exports = {
|
||||||
current++;
|
current++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3524,13 +3530,13 @@ module.exports = {
|
||||||
const olSingle = Number(params.config.ol_single || 1);
|
const olSingle = Number(params.config.ol_single || 1);
|
||||||
const ulMulti = Number(params.config.ul_multi || 1);
|
const ulMulti = Number(params.config.ul_multi || 1);
|
||||||
const olMulti = Number(params.config.ol_multi || 1);
|
const olMulti = Number(params.config.ol_multi || 1);
|
||||||
flattenedLists().forEach((list) => {
|
for (const list of flattenedLists()) {
|
||||||
const lineCount = list.lastLineIndex - list.open.map[0];
|
const lineCount = list.lastLineIndex - list.open.map[0];
|
||||||
const allSingle = lineCount === list.items.length;
|
const allSingle = lineCount === list.items.length;
|
||||||
const expectedSpaces = list.unordered ?
|
const expectedSpaces = list.unordered ?
|
||||||
(allSingle ? ulSingle : ulMulti) :
|
(allSingle ? ulSingle : ulMulti) :
|
||||||
(allSingle ? olSingle : olMulti);
|
(allSingle ? olSingle : olMulti);
|
||||||
list.items.forEach((item) => {
|
for (const item of list.items) {
|
||||||
const { line, lineNumber } = item;
|
const { line, lineNumber } = item;
|
||||||
const match = /^[\s>]*\S+(\s*)/.exec(line);
|
const match = /^[\s>]*\S+(\s*)/.exec(line);
|
||||||
const [{ "length": matchLength }, { "length": actualSpaces }] = match;
|
const [{ "length": matchLength }, { "length": actualSpaces }] = match;
|
||||||
|
@ -3545,8 +3551,8 @@ module.exports = {
|
||||||
}
|
}
|
||||||
addErrorDetailIf(onError, lineNumber, expectedSpaces, actualSpaces, null, null, [1, matchLength], fixInfo);
|
addErrorDetailIf(onError, lineNumber, expectedSpaces, actualSpaces, null, null, [1, matchLength], fixInfo);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3611,7 +3617,8 @@ module.exports = {
|
||||||
"tags": ["bullet", "ul", "ol", "blank_lines"],
|
"tags": ["bullet", "ul", "ol", "blank_lines"],
|
||||||
"function": function MD032(params, onError) {
|
"function": function MD032(params, onError) {
|
||||||
const { lines } = params;
|
const { lines } = params;
|
||||||
flattenedLists().filter((list) => !list.nesting).forEach((list) => {
|
const filteredLists = flattenedLists().filter((list) => !list.nesting);
|
||||||
|
for (const list of filteredLists) {
|
||||||
const firstIndex = list.open.map[0];
|
const firstIndex = list.open.map[0];
|
||||||
if (!isBlankLine(lines[firstIndex - 1])) {
|
if (!isBlankLine(lines[firstIndex - 1])) {
|
||||||
const line = lines[firstIndex];
|
const line = lines[firstIndex];
|
||||||
|
@ -3629,7 +3636,7 @@ module.exports = {
|
||||||
"insertText": `${quotePrefix}\n`
|
"insertText": `${quotePrefix}\n`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3703,7 +3710,7 @@ module.exports = {
|
||||||
"function": function MD034(params, onError) {
|
"function": function MD034(params, onError) {
|
||||||
filterTokens(params, "inline", (token) => {
|
filterTokens(params, "inline", (token) => {
|
||||||
let inLink = false;
|
let inLink = false;
|
||||||
token.children.forEach((child) => {
|
for (const child of token.children) {
|
||||||
const { content, line, lineNumber, type } = child;
|
const { content, line, lineNumber, type } = child;
|
||||||
let match = null;
|
let match = null;
|
||||||
if (type === "link_open") {
|
if (type === "link_open") {
|
||||||
|
@ -3739,7 +3746,7 @@ module.exports = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -3837,9 +3844,9 @@ module.exports = {
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
let state = base;
|
let state = base;
|
||||||
params.tokens.forEach(function forToken(token) {
|
for (const token of params.tokens) {
|
||||||
state = state(token);
|
state = state(token);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4101,7 +4108,7 @@ module.exports = {
|
||||||
let inLink = false;
|
let inLink = false;
|
||||||
let linkText = "";
|
let linkText = "";
|
||||||
let lineIndex = 0;
|
let lineIndex = 0;
|
||||||
children.forEach((child) => {
|
for (const child of children) {
|
||||||
const { content, markup, type } = child;
|
const { content, markup, type } = child;
|
||||||
if (type === "link_open") {
|
if (type === "link_open") {
|
||||||
inLink = true;
|
inLink = true;
|
||||||
|
@ -4139,7 +4146,7 @@ module.exports = {
|
||||||
`${markup}${content}${markup}` :
|
`${markup}${content}${markup}` :
|
||||||
(content || markup);
|
(content || markup);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -4240,15 +4247,15 @@ module.exports = {
|
||||||
let inLink = false;
|
let inLink = false;
|
||||||
let linkText = "";
|
let linkText = "";
|
||||||
let emptyLink = false;
|
let emptyLink = false;
|
||||||
token.children.forEach(function forChild(child) {
|
for (const child of token.children) {
|
||||||
if (child.type === "link_open") {
|
if (child.type === "link_open") {
|
||||||
inLink = true;
|
inLink = true;
|
||||||
linkText = "";
|
linkText = "";
|
||||||
child.attrs.forEach(function forAttr(attr) {
|
for (const attr of child.attrs) {
|
||||||
if (attr[0] === "href" && (!attr[1] || (attr[1] === "#"))) {
|
if (attr[0] === "href" && (!attr[1] || (attr[1] === "#"))) {
|
||||||
emptyLink = true;
|
emptyLink = true;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
else if (child.type === "link_close") {
|
else if (child.type === "link_close") {
|
||||||
inLink = false;
|
inLink = false;
|
||||||
|
@ -4267,7 +4274,7 @@ module.exports = {
|
||||||
else if (inLink) {
|
else if (inLink) {
|
||||||
linkText += child.content;
|
linkText += child.content;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -4293,9 +4300,9 @@ module.exports = {
|
||||||
const requiredHeadings = params.config.headings || params.config.headers;
|
const requiredHeadings = params.config.headings || params.config.headers;
|
||||||
if (Array.isArray(requiredHeadings)) {
|
if (Array.isArray(requiredHeadings)) {
|
||||||
const levels = {};
|
const levels = {};
|
||||||
[1, 2, 3, 4, 5, 6].forEach((level) => {
|
for (const level of [1, 2, 3, 4, 5, 6]) {
|
||||||
levels["h" + level] = "######".substr(-level);
|
levels["h" + level] = "######".substr(-level);
|
||||||
});
|
}
|
||||||
let i = 0;
|
let i = 0;
|
||||||
let matchAny = false;
|
let matchAny = false;
|
||||||
let hasError = false;
|
let hasError = false;
|
||||||
|
@ -4466,15 +4473,14 @@ module.exports = {
|
||||||
"tags": ["code"],
|
"tags": ["code"],
|
||||||
"function": function MD046(params, onError) {
|
"function": function MD046(params, onError) {
|
||||||
let expectedStyle = String(params.config.style || "consistent");
|
let expectedStyle = String(params.config.style || "consistent");
|
||||||
params.tokens
|
const codeBlocksAndFences = params.tokens.filter((token) => (token.type === "code_block") || (token.type === "fence"));
|
||||||
.filter((token) => token.type === "code_block" || token.type === "fence")
|
for (const token of codeBlocksAndFences) {
|
||||||
.forEach((token) => {
|
|
||||||
const { lineNumber, type } = token;
|
const { lineNumber, type } = token;
|
||||||
if (expectedStyle === "consistent") {
|
if (expectedStyle === "consistent") {
|
||||||
expectedStyle = tokenTypeToStyle[type];
|
expectedStyle = tokenTypeToStyle[type];
|
||||||
}
|
}
|
||||||
addErrorDetailIf(onError, lineNumber, expectedStyle, tokenTypeToStyle[type]);
|
addErrorDetailIf(onError, lineNumber, expectedStyle, tokenTypeToStyle[type]);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4527,15 +4533,14 @@ module.exports = {
|
||||||
"function": function MD048(params, onError) {
|
"function": function MD048(params, onError) {
|
||||||
const style = String(params.config.style || "consistent");
|
const style = String(params.config.style || "consistent");
|
||||||
let expectedStyle = style;
|
let expectedStyle = style;
|
||||||
params.tokens
|
const fenceTokens = params.tokens.filter((token) => token.type === "fence");
|
||||||
.filter((token) => token.type === "fence")
|
for (const fenceToken of fenceTokens) {
|
||||||
.forEach((fenceToken) => {
|
|
||||||
const { lineNumber, markup } = fenceToken;
|
const { lineNumber, markup } = fenceToken;
|
||||||
if (expectedStyle === "consistent") {
|
if (expectedStyle === "consistent") {
|
||||||
expectedStyle = fencedCodeBlockStyleFor(markup);
|
expectedStyle = fencedCodeBlockStyleFor(markup);
|
||||||
}
|
}
|
||||||
addErrorDetailIf(onError, lineNumber, expectedStyle, fencedCodeBlockStyleFor(markup));
|
addErrorDetailIf(onError, lineNumber, expectedStyle, fencedCodeBlockStyleFor(markup));
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4825,12 +4830,12 @@ const rules = [
|
||||||
__webpack_require__(/*! ./md052 */ "../lib/md052.js"),
|
__webpack_require__(/*! ./md052 */ "../lib/md052.js"),
|
||||||
__webpack_require__(/*! ./md053 */ "../lib/md053.js")
|
__webpack_require__(/*! ./md053 */ "../lib/md053.js")
|
||||||
];
|
];
|
||||||
rules.forEach((rule) => {
|
for (const rule of rules) {
|
||||||
const name = rule.names[0].toLowerCase();
|
const name = rule.names[0].toLowerCase();
|
||||||
// eslint-disable-next-line dot-notation
|
// eslint-disable-next-line dot-notation
|
||||||
rule["information"] =
|
rule["information"] =
|
||||||
new URL(`${homepage}/blob/v${version}/doc/Rules.md#${name}`);
|
new URL(`${homepage}/blob/v${version}/doc/Rules.md#${name}`);
|
||||||
});
|
}
|
||||||
module.exports = rules;
|
module.exports = rules;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
|
"target": "es2015", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
|
||||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
||||||
"strict": true, /* Enable all strict type-checking options. */
|
"strict": true, /* Enable all strict type-checking options. */
|
||||||
"noUnusedLocals": true, /* Report errors on unused locals. */
|
"noUnusedLocals": true, /* Report errors on unused locals. */
|
||||||
|
|
|
@ -328,11 +328,11 @@ module.exports.getLineMetadata = function getLineMetadata(params) {
|
||||||
filterTokens(params, "hr", (token) => {
|
filterTokens(params, "hr", (token) => {
|
||||||
lineMetadata[token.map[0]][6] = true;
|
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++) {
|
for (let i = token.map[0]; i < token.map[1]; i++) {
|
||||||
lineMetadata[i][7] = true;
|
lineMetadata[i][7] = true;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
return lineMetadata;
|
return lineMetadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -345,9 +345,9 @@ module.exports.getLineMetadata = function getLineMetadata(params) {
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function forEachLine(lineMetadata, handler) {
|
function forEachLine(lineMetadata, handler) {
|
||||||
lineMetadata.forEach(function forMetadata(metadata) {
|
for (const metadata of lineMetadata) {
|
||||||
handler(...metadata);
|
handler(...metadata);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
module.exports.forEachLine = forEachLine;
|
module.exports.forEachLine = forEachLine;
|
||||||
|
|
||||||
|
@ -359,7 +359,7 @@ module.exports.flattenLists = function flattenLists(tokens) {
|
||||||
let nesting = 0;
|
let nesting = 0;
|
||||||
const nestingStack = [];
|
const nestingStack = [];
|
||||||
let lastWithMap = { "map": [ 0, 1 ] };
|
let lastWithMap = { "map": [ 0, 1 ] };
|
||||||
tokens.forEach((token) => {
|
for (const token of tokens) {
|
||||||
if ((token.type === "bullet_list_open") ||
|
if ((token.type === "bullet_list_open") ||
|
||||||
(token.type === "ordered_list_open")) {
|
(token.type === "ordered_list_open")) {
|
||||||
// Save current context and start a new one
|
// Save current context and start a new one
|
||||||
|
@ -398,7 +398,7 @@ module.exports.flattenLists = function flattenLists(tokens) {
|
||||||
// Track last token with map
|
// Track last token with map
|
||||||
lastWithMap = token;
|
lastWithMap = token;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
return flattenedLists;
|
return flattenedLists;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -406,18 +406,18 @@ module.exports.flattenLists = function flattenLists(tokens) {
|
||||||
module.exports.forEachInlineChild =
|
module.exports.forEachInlineChild =
|
||||||
function forEachInlineChild(params, type, handler) {
|
function forEachInlineChild(params, type, handler) {
|
||||||
filterTokens(params, "inline", function forToken(token) {
|
filterTokens(params, "inline", function forToken(token) {
|
||||||
token.children.forEach(function forChild(child) {
|
for (const child of token.children) {
|
||||||
if (child.type === type) {
|
if (child.type === type) {
|
||||||
handler(child, token);
|
handler(child, token);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Calls the provided function for each heading's content
|
// Calls the provided function for each heading's content
|
||||||
module.exports.forEachHeading = function forEachHeading(params, handler) {
|
module.exports.forEachHeading = function forEachHeading(params, handler) {
|
||||||
let heading = null;
|
let heading = null;
|
||||||
params.tokens.forEach(function forToken(token) {
|
for (const token of params.tokens) {
|
||||||
if (token.type === "heading_open") {
|
if (token.type === "heading_open") {
|
||||||
heading = token;
|
heading = token;
|
||||||
} else if (token.type === "heading_close") {
|
} else if (token.type === "heading_close") {
|
||||||
|
@ -425,7 +425,7 @@ module.exports.forEachHeading = function forEachHeading(params, handler) {
|
||||||
} else if ((token.type === "inline") && heading) {
|
} else if ((token.type === "inline") && heading) {
|
||||||
handler(heading, token.content, token);
|
handler(heading, token.content, token);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -767,7 +767,7 @@ function emphasisMarkersInContent(params) {
|
||||||
const { lines } = params;
|
const { lines } = params;
|
||||||
const byLine = new Array(lines.length);
|
const byLine = new Array(lines.length);
|
||||||
// Search links
|
// Search links
|
||||||
lines.forEach((tokenLine, tokenLineIndex) => {
|
for (const [ tokenLineIndex, tokenLine ] of lines.entries()) {
|
||||||
const inLine = [];
|
const inLine = [];
|
||||||
forEachLink(tokenLine, (index, match) => {
|
forEachLink(tokenLine, (index, match) => {
|
||||||
let markerMatch = null;
|
let markerMatch = null;
|
||||||
|
@ -776,7 +776,7 @@ function emphasisMarkersInContent(params) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
byLine[tokenLineIndex] = inLine;
|
byLine[tokenLineIndex] = inLine;
|
||||||
});
|
}
|
||||||
// Search code spans
|
// Search code spans
|
||||||
filterTokens(params, "inline", (token) => {
|
filterTokens(params, "inline", (token) => {
|
||||||
const { children, lineNumber, map } = token;
|
const { children, lineNumber, map } = token;
|
||||||
|
@ -786,7 +786,7 @@ function emphasisMarkersInContent(params) {
|
||||||
tokenLines.join("\n"),
|
tokenLines.join("\n"),
|
||||||
(code, lineIndex, column, tickCount) => {
|
(code, lineIndex, column, tickCount) => {
|
||||||
const codeLines = code.split(newLineRe);
|
const codeLines = code.split(newLineRe);
|
||||||
codeLines.forEach((codeLine, codeLineIndex) => {
|
for (const [ codeLineIndex, codeLine ] of codeLines.entries()) {
|
||||||
const byLineIndex = lineNumber - 1 + lineIndex + codeLineIndex;
|
const byLineIndex = lineNumber - 1 + lineIndex + codeLineIndex;
|
||||||
const inLine = byLine[byLineIndex];
|
const inLine = byLine[byLineIndex];
|
||||||
const codeLineOffset = codeLineIndex ? 0 : column - 1 + tickCount;
|
const codeLineOffset = codeLineIndex ? 0 : column - 1 + tickCount;
|
||||||
|
@ -795,7 +795,7 @@ function emphasisMarkersInContent(params) {
|
||||||
inLine.push(codeLineOffset + match.index);
|
inLine.push(codeLineOffset + match.index);
|
||||||
}
|
}
|
||||||
byLine[byLineIndex] = inLine;
|
byLine[byLineIndex] = inLine;
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -952,7 +952,7 @@ function getPreferredLineEnding(input, os) {
|
||||||
let lf = 0;
|
let lf = 0;
|
||||||
let crlf = 0;
|
let crlf = 0;
|
||||||
const endings = input.match(newLineRe) || [];
|
const endings = input.match(newLineRe) || [];
|
||||||
endings.forEach((ending) => {
|
for (const ending of endings) {
|
||||||
// eslint-disable-next-line default-case
|
// eslint-disable-next-line default-case
|
||||||
switch (ending) {
|
switch (ending) {
|
||||||
case "\r":
|
case "\r":
|
||||||
|
@ -965,7 +965,7 @@ function getPreferredLineEnding(input, os) {
|
||||||
crlf++;
|
crlf++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
let preferredLineEnding = null;
|
let preferredLineEnding = null;
|
||||||
if (!cr && !lf && !crlf) {
|
if (!cr && !lf && !crlf) {
|
||||||
preferredLineEnding = (os && os.EOL) || "\n";
|
preferredLineEnding = (os && os.EOL) || "\n";
|
||||||
|
@ -1053,8 +1053,10 @@ function applyFixes(input, errors) {
|
||||||
return unique;
|
return unique;
|
||||||
});
|
});
|
||||||
// Collapse insert/no-delete and no-insert/delete for same line/column
|
// Collapse insert/no-delete and no-insert/delete for same line/column
|
||||||
lastFixInfo = {};
|
lastFixInfo = {
|
||||||
fixInfos.forEach((fixInfo) => {
|
"lineNumber": -1
|
||||||
|
};
|
||||||
|
for (const fixInfo of fixInfos) {
|
||||||
if (
|
if (
|
||||||
(fixInfo.lineNumber === lastFixInfo.lineNumber) &&
|
(fixInfo.lineNumber === lastFixInfo.lineNumber) &&
|
||||||
(fixInfo.editColumn === lastFixInfo.editColumn) &&
|
(fixInfo.editColumn === lastFixInfo.editColumn) &&
|
||||||
|
@ -1066,12 +1068,12 @@ function applyFixes(input, errors) {
|
||||||
lastFixInfo.lineNumber = 0;
|
lastFixInfo.lineNumber = 0;
|
||||||
}
|
}
|
||||||
lastFixInfo = fixInfo;
|
lastFixInfo = fixInfo;
|
||||||
});
|
}
|
||||||
fixInfos = fixInfos.filter((fixInfo) => fixInfo.lineNumber);
|
fixInfos = fixInfos.filter((fixInfo) => fixInfo.lineNumber);
|
||||||
// Apply all (remaining/updated) fixes
|
// Apply all (remaining/updated) fixes
|
||||||
let lastLineIndex = -1;
|
let lastLineIndex = -1;
|
||||||
let lastEditIndex = -1;
|
let lastEditIndex = -1;
|
||||||
fixInfos.forEach((fixInfo) => {
|
for (const fixInfo of fixInfos) {
|
||||||
const { lineNumber, editColumn, deleteCount } = fixInfo;
|
const { lineNumber, editColumn, deleteCount } = fixInfo;
|
||||||
const lineIndex = lineNumber - 1;
|
const lineIndex = lineNumber - 1;
|
||||||
const editIndex = editColumn - 1;
|
const editIndex = editColumn - 1;
|
||||||
|
@ -1085,7 +1087,7 @@ function applyFixes(input, errors) {
|
||||||
}
|
}
|
||||||
lastLineIndex = lineIndex;
|
lastLineIndex = lineIndex;
|
||||||
lastEditIndex = editIndex;
|
lastEditIndex = editIndex;
|
||||||
});
|
}
|
||||||
// Return corrected input
|
// Return corrected input
|
||||||
return lines.filter((line) => line !== null).join(lineEnding);
|
return lines.filter((line) => line !== null).join(lineEnding);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,32 +29,32 @@ function validateRuleList(ruleList, synchronous) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
const allIds = {};
|
const allIds = {};
|
||||||
ruleList.forEach(function forRule(rule, index) {
|
for (const [ index, rule ] of ruleList.entries()) {
|
||||||
const customIndex = index - rules.length;
|
const customIndex = index - rules.length;
|
||||||
// eslint-disable-next-line jsdoc/require-jsdoc
|
// eslint-disable-next-line no-inner-declarations, jsdoc/require-jsdoc
|
||||||
function newError(property) {
|
function newError(property) {
|
||||||
return new Error(
|
return new Error(
|
||||||
"Property '" + property + "' of custom rule at index " +
|
"Property '" + property + "' of custom rule at index " +
|
||||||
customIndex + " is incorrect.");
|
customIndex + " is incorrect.");
|
||||||
}
|
}
|
||||||
[ "names", "tags" ].forEach(function forProperty(property) {
|
for (const property of [ "names", "tags" ]) {
|
||||||
const value = rule[property];
|
const value = rule[property];
|
||||||
if (!result &&
|
if (!result &&
|
||||||
(!value || !Array.isArray(value) || (value.length === 0) ||
|
(!value || !Array.isArray(value) || (value.length === 0) ||
|
||||||
!value.every(helpers.isString) || value.some(helpers.isEmptyString))) {
|
!value.every(helpers.isString) || value.some(helpers.isEmptyString))) {
|
||||||
result = newError(property);
|
result = newError(property);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
[
|
for (const propertyInfo of [
|
||||||
[ "description", "string" ],
|
[ "description", "string" ],
|
||||||
[ "function", "function" ]
|
[ "function", "function" ]
|
||||||
].forEach(function forProperty(propertyInfo) {
|
]) {
|
||||||
const property = propertyInfo[0];
|
const property = propertyInfo[0];
|
||||||
const value = rule[property];
|
const value = rule[property];
|
||||||
if (!result && (!value || (typeof value !== propertyInfo[1]))) {
|
if (!result && (!value || (typeof value !== propertyInfo[1]))) {
|
||||||
result = newError(property);
|
result = newError(property);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
if (
|
if (
|
||||||
!result &&
|
!result &&
|
||||||
rule.information &&
|
rule.information &&
|
||||||
|
@ -76,24 +76,25 @@ function validateRuleList(ruleList, synchronous) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (!result) {
|
if (!result) {
|
||||||
rule.names.forEach(function forName(name) {
|
for (const name of rule.names) {
|
||||||
const nameUpper = name.toUpperCase();
|
const nameUpper = name.toUpperCase();
|
||||||
if (!result && (allIds[nameUpper] !== undefined)) {
|
if (!result && (allIds[nameUpper] !== undefined)) {
|
||||||
result = new Error("Name '" + name + "' of custom rule at index " +
|
result = new Error("Name '" + name + "' of custom rule at index " +
|
||||||
customIndex + " is already used as a name or tag.");
|
customIndex + " is already used as a name or tag.");
|
||||||
}
|
}
|
||||||
allIds[nameUpper] = true;
|
allIds[nameUpper] = true;
|
||||||
});
|
}
|
||||||
rule.tags.forEach(function forTag(tag) {
|
for (const tag of rule.tags) {
|
||||||
const tagUpper = tag.toUpperCase();
|
const tagUpper = tag.toUpperCase();
|
||||||
if (!result && allIds[tagUpper]) {
|
if (!result && allIds[tagUpper]) {
|
||||||
result = new Error("Tag '" + tag + "' of custom rule at index " +
|
result = new Error("Tag '" + tag + "' of custom rule at index " +
|
||||||
customIndex + " is already used as a name.");
|
customIndex + " is already used as a name.");
|
||||||
}
|
}
|
||||||
allIds[tagUpper] = false;
|
allIds[tagUpper] = false;
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
// @ts-ignore
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,10 +112,10 @@ function newResults(ruleList) {
|
||||||
const results = [];
|
const results = [];
|
||||||
const keys = Object.keys(lintResults);
|
const keys = Object.keys(lintResults);
|
||||||
keys.sort();
|
keys.sort();
|
||||||
keys.forEach(function forFile(file) {
|
for (const file of keys) {
|
||||||
const fileResults = lintResults[file];
|
const fileResults = lintResults[file];
|
||||||
if (Array.isArray(fileResults)) {
|
if (Array.isArray(fileResults)) {
|
||||||
fileResults.forEach(function forResult(result) {
|
for (const result of fileResults) {
|
||||||
const ruleMoniker = result.ruleNames ?
|
const ruleMoniker = result.ruleNames ?
|
||||||
result.ruleNames.join("/") :
|
result.ruleNames.join("/") :
|
||||||
(result.ruleName + "/" + result.ruleAlias);
|
(result.ruleName + "/" + result.ruleAlias);
|
||||||
|
@ -129,30 +130,32 @@ function newResults(ruleList) {
|
||||||
(result.errorContext ?
|
(result.errorContext ?
|
||||||
" [Context: \"" + result.errorContext + "\"]" :
|
" [Context: \"" + result.errorContext + "\"]" :
|
||||||
""));
|
""));
|
||||||
});
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!ruleNameToRule) {
|
if (!ruleNameToRule) {
|
||||||
ruleNameToRule = {};
|
ruleNameToRule = {};
|
||||||
ruleList.forEach(function forRule(rule) {
|
for (const rule of ruleList) {
|
||||||
const ruleName = rule.names[0].toUpperCase();
|
const ruleName = rule.names[0].toUpperCase();
|
||||||
ruleNameToRule[ruleName] = rule;
|
ruleNameToRule[ruleName] = rule;
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
Object.keys(fileResults).forEach(function forRule(ruleName) {
|
for (const [ ruleName, ruleResults ] of Object.entries(fileResults)) {
|
||||||
const rule = ruleNameToRule[ruleName.toUpperCase()];
|
const rule = ruleNameToRule[ruleName.toUpperCase()];
|
||||||
const ruleResults = fileResults[ruleName];
|
for (const lineNumber of ruleResults) {
|
||||||
ruleResults.forEach(function forLine(lineNumber) {
|
// @ts-ignore
|
||||||
const nameIndex = Math.min(useAlias ? 1 : 0, rule.names.length - 1);
|
const nameIndex = Math.min(useAlias ? 1 : 0, rule.names.length - 1);
|
||||||
const result =
|
const result =
|
||||||
file + ": " +
|
file + ": " +
|
||||||
lineNumber + ": " +
|
lineNumber + ": " +
|
||||||
|
// @ts-ignore
|
||||||
rule.names[nameIndex] + " " +
|
rule.names[nameIndex] + " " +
|
||||||
|
// @ts-ignore
|
||||||
rule.description;
|
rule.description;
|
||||||
results.push(result);
|
results.push(result);
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
return results.join("\n");
|
return results.join("\n");
|
||||||
}
|
}
|
||||||
Object.defineProperty(lintResults, "toString", { "value": toString });
|
Object.defineProperty(lintResults, "toString", { "value": toString });
|
||||||
|
@ -196,7 +199,7 @@ function removeFrontMatter(content, frontMatter) {
|
||||||
*/
|
*/
|
||||||
function annotateTokens(tokens, lines) {
|
function annotateTokens(tokens, lines) {
|
||||||
let trMap = null;
|
let trMap = null;
|
||||||
tokens.forEach(function forToken(token) {
|
for (const token of tokens) {
|
||||||
// Provide missing maps for table content
|
// Provide missing maps for table content
|
||||||
if (token.type === "tr_open") {
|
if (token.type === "tr_open") {
|
||||||
trMap = token.map;
|
trMap = token.map;
|
||||||
|
@ -228,7 +231,7 @@ function annotateTokens(tokens, lines) {
|
||||||
codeSpanExtraLines.push(code.split(helpers.newLineRe).length - 1);
|
codeSpanExtraLines.push(code.split(helpers.newLineRe).length - 1);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
(token.children || []).forEach(function forChild(child) {
|
for (const child of (token.children || [])) {
|
||||||
child.lineNumber = lineNumber;
|
child.lineNumber = lineNumber;
|
||||||
child.line = lines[lineNumber - 1];
|
child.line = lines[lineNumber - 1];
|
||||||
if ((child.type === "softbreak") || (child.type === "hardbreak")) {
|
if ((child.type === "softbreak") || (child.type === "hardbreak")) {
|
||||||
|
@ -236,9 +239,9 @@ function annotateTokens(tokens, lines) {
|
||||||
} else if (child.type === "code_inline") {
|
} else if (child.type === "code_inline") {
|
||||||
lineNumber += codeSpanExtraLines.shift();
|
lineNumber += codeSpanExtraLines.shift();
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -250,24 +253,24 @@ function annotateTokens(tokens, lines) {
|
||||||
function mapAliasToRuleNames(ruleList) {
|
function mapAliasToRuleNames(ruleList) {
|
||||||
const aliasToRuleNames = {};
|
const aliasToRuleNames = {};
|
||||||
// const tagToRuleNames = {};
|
// const tagToRuleNames = {};
|
||||||
ruleList.forEach(function forRule(rule) {
|
for (const rule of ruleList) {
|
||||||
const ruleName = rule.names[0].toUpperCase();
|
const ruleName = rule.names[0].toUpperCase();
|
||||||
// The following is useful for updating README.md:
|
// The following is useful for updating README.md:
|
||||||
// console.log(
|
// console.log(
|
||||||
// "* **[" + ruleName + "](doc/Rules.md#" + ruleName.toLowerCase() +
|
// "* **[" + ruleName + "](doc/Rules.md#" + ruleName.toLowerCase() +
|
||||||
// ")** *" + rule.names.slice(1).join("/") + "* - " + rule.description);
|
// ")** *" + rule.names.slice(1).join("/") + "* - " + rule.description);
|
||||||
rule.names.forEach(function forName(name) {
|
for (const name of rule.names) {
|
||||||
const nameUpper = name.toUpperCase();
|
const nameUpper = name.toUpperCase();
|
||||||
aliasToRuleNames[nameUpper] = [ ruleName ];
|
aliasToRuleNames[nameUpper] = [ ruleName ];
|
||||||
});
|
}
|
||||||
rule.tags.forEach(function forTag(tag) {
|
for (const tag of rule.tags) {
|
||||||
const tagUpper = tag.toUpperCase();
|
const tagUpper = tag.toUpperCase();
|
||||||
const ruleNames = aliasToRuleNames[tagUpper] || [];
|
const ruleNames = aliasToRuleNames[tagUpper] || [];
|
||||||
ruleNames.push(ruleName);
|
ruleNames.push(ruleName);
|
||||||
aliasToRuleNames[tagUpper] = ruleNames;
|
aliasToRuleNames[tagUpper] = ruleNames;
|
||||||
// tagToRuleNames[tag] = ruleName;
|
// tagToRuleNames[tag] = ruleName;
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
// The following is useful for updating README.md:
|
// The following is useful for updating README.md:
|
||||||
// Object.keys(tagToRuleNames).sort().forEach(function forTag(tag) {
|
// Object.keys(tagToRuleNames).sort().forEach(function forTag(tag) {
|
||||||
// console.log("* **" + tag + "** - " +
|
// console.log("* **" + tag + "** - " +
|
||||||
|
@ -292,14 +295,14 @@ function getEffectiveConfig(ruleList, config, aliasToRuleNames) {
|
||||||
);
|
);
|
||||||
const ruleDefault = (defaultKey.length === 0) || !!config[defaultKey[0]];
|
const ruleDefault = (defaultKey.length === 0) || !!config[defaultKey[0]];
|
||||||
const effectiveConfig = {};
|
const effectiveConfig = {};
|
||||||
ruleList.forEach((rule) => {
|
for (const rule of ruleList) {
|
||||||
const ruleName = rule.names[0].toUpperCase();
|
const ruleName = rule.names[0].toUpperCase();
|
||||||
effectiveConfig[ruleName] = ruleDefault;
|
effectiveConfig[ruleName] = ruleDefault;
|
||||||
});
|
}
|
||||||
deprecatedRuleNames.forEach((ruleName) => {
|
for (const ruleName of deprecatedRuleNames) {
|
||||||
effectiveConfig[ruleName] = false;
|
effectiveConfig[ruleName] = false;
|
||||||
});
|
}
|
||||||
Object.keys(config).forEach((key) => {
|
for (const key of Object.keys(config)) {
|
||||||
let value = config[key];
|
let value = config[key];
|
||||||
if (value) {
|
if (value) {
|
||||||
if (!(value instanceof Object)) {
|
if (!(value instanceof Object)) {
|
||||||
|
@ -309,10 +312,10 @@ function getEffectiveConfig(ruleList, config, aliasToRuleNames) {
|
||||||
value = false;
|
value = false;
|
||||||
}
|
}
|
||||||
const keyUpper = key.toUpperCase();
|
const keyUpper = key.toUpperCase();
|
||||||
(aliasToRuleNames[keyUpper] || []).forEach((ruleName) => {
|
for (const ruleName of (aliasToRuleNames[keyUpper] || [])) {
|
||||||
effectiveConfig[ruleName] = value;
|
effectiveConfig[ruleName] = value;
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
return effectiveConfig;
|
return effectiveConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,7 +381,7 @@ function getEnabledRulesPerLineNumber(
|
||||||
// Helper functions
|
// Helper functions
|
||||||
// eslint-disable-next-line jsdoc/require-jsdoc
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
||||||
function handleInlineConfig(input, forEachMatch, forEachLine) {
|
function handleInlineConfig(input, forEachMatch, forEachLine) {
|
||||||
input.forEach((line, lineIndex) => {
|
for (const [ lineIndex, line ] of input.entries()) {
|
||||||
if (!noInlineConfig) {
|
if (!noInlineConfig) {
|
||||||
let match = null;
|
let match = null;
|
||||||
while ((match = helpers.inlineCommentStartRe.exec(line))) {
|
while ((match = helpers.inlineCommentStartRe.exec(line))) {
|
||||||
|
@ -395,7 +398,7 @@ function getEnabledRulesPerLineNumber(
|
||||||
if (forEachLine) {
|
if (forEachLine) {
|
||||||
forEachLine();
|
forEachLine();
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line jsdoc/require-jsdoc
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
||||||
function configureFile(action, parameter) {
|
function configureFile(action, parameter) {
|
||||||
|
@ -417,11 +420,11 @@ function getEnabledRulesPerLineNumber(
|
||||||
const enabled = (action.startsWith("ENABLE"));
|
const enabled = (action.startsWith("ENABLE"));
|
||||||
const trimmed = parameter && parameter.trim();
|
const trimmed = parameter && parameter.trim();
|
||||||
const items = trimmed ? trimmed.toUpperCase().split(/\s+/) : allRuleNames;
|
const items = trimmed ? trimmed.toUpperCase().split(/\s+/) : allRuleNames;
|
||||||
items.forEach((nameUpper) => {
|
for (const nameUpper of items) {
|
||||||
(aliasToRuleNames[nameUpper] || []).forEach((ruleName) => {
|
for (const ruleName of (aliasToRuleNames[nameUpper] || [])) {
|
||||||
state[ruleName] = enabled;
|
state[ruleName] = enabled;
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line jsdoc/require-jsdoc
|
// eslint-disable-next-line jsdoc/require-jsdoc
|
||||||
|
@ -463,11 +466,11 @@ function getEnabledRulesPerLineNumber(
|
||||||
handleInlineConfig([ lines.join("\n") ], configureFile);
|
handleInlineConfig([ lines.join("\n") ], configureFile);
|
||||||
const effectiveConfig = getEffectiveConfig(
|
const effectiveConfig = getEffectiveConfig(
|
||||||
ruleList, config, aliasToRuleNames);
|
ruleList, config, aliasToRuleNames);
|
||||||
ruleList.forEach((rule) => {
|
for (const rule of ruleList) {
|
||||||
const ruleName = rule.names[0].toUpperCase();
|
const ruleName = rule.names[0].toUpperCase();
|
||||||
allRuleNames.push(ruleName);
|
allRuleNames.push(ruleName);
|
||||||
enabledRules[ruleName] = !!effectiveConfig[ruleName];
|
enabledRules[ruleName] = !!effectiveConfig[ruleName];
|
||||||
});
|
}
|
||||||
capturedRules = enabledRules;
|
capturedRules = enabledRules;
|
||||||
handleInlineConfig(lines, enableDisableFile);
|
handleInlineConfig(lines, enableDisableFile);
|
||||||
handleInlineConfig(lines, captureRestoreEnableDisable, updateLineState);
|
handleInlineConfig(lines, captureRestoreEnableDisable, updateLineState);
|
||||||
|
@ -844,10 +847,10 @@ function lintInput(options, synchronous, callback) {
|
||||||
3 : options.resultVersion;
|
3 : options.resultVersion;
|
||||||
const md = markdownIt({ "html": true });
|
const md = markdownIt({ "html": true });
|
||||||
const markdownItPlugins = options.markdownItPlugins || [];
|
const markdownItPlugins = options.markdownItPlugins || [];
|
||||||
markdownItPlugins.forEach(function forPlugin(plugin) {
|
for (const plugin of markdownItPlugins) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
md.use(...plugin);
|
md.use(...plugin);
|
||||||
});
|
}
|
||||||
const fs = options.fs || require("fs");
|
const fs = options.fs || require("fs");
|
||||||
const results = newResults(ruleList);
|
const results = newResults(ruleList);
|
||||||
let done = false;
|
let done = false;
|
||||||
|
|
|
@ -26,12 +26,12 @@ module.exports = {
|
||||||
const style = String(params.config.style || "consistent");
|
const style = String(params.config.style || "consistent");
|
||||||
let expectedStyle = style;
|
let expectedStyle = style;
|
||||||
const nestingStyles = [];
|
const nestingStyles = [];
|
||||||
flattenedLists().forEach((list) => {
|
for (const list of flattenedLists()) {
|
||||||
if (list.unordered) {
|
if (list.unordered) {
|
||||||
if (expectedStyle === "consistent") {
|
if (expectedStyle === "consistent") {
|
||||||
expectedStyle = unorderedListStyleFor(list.items[0]);
|
expectedStyle = unorderedListStyleFor(list.items[0]);
|
||||||
}
|
}
|
||||||
list.items.forEach((item) => {
|
for (const item of list.items) {
|
||||||
const itemStyle = unorderedListStyleFor(item);
|
const itemStyle = unorderedListStyleFor(item);
|
||||||
if (style === "sublist") {
|
if (style === "sublist") {
|
||||||
const nesting = list.nesting;
|
const nesting = list.nesting;
|
||||||
|
@ -69,8 +69,8 @@ module.exports = {
|
||||||
range,
|
range,
|
||||||
fixInfo
|
fixInfo
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,12 +11,12 @@ module.exports = {
|
||||||
"description": "Inconsistent indentation for list items at the same level",
|
"description": "Inconsistent indentation for list items at the same level",
|
||||||
"tags": [ "bullet", "ul", "indentation" ],
|
"tags": [ "bullet", "ul", "indentation" ],
|
||||||
"function": function MD005(params, onError) {
|
"function": function MD005(params, onError) {
|
||||||
flattenedLists().forEach((list) => {
|
for (const list of flattenedLists()) {
|
||||||
const expectedIndent = list.indent;
|
const expectedIndent = list.indent;
|
||||||
let expectedEnd = 0;
|
let expectedEnd = 0;
|
||||||
let actualEnd = -1;
|
let actualEnd = -1;
|
||||||
let endMatching = false;
|
let endMatching = false;
|
||||||
list.items.forEach((item) => {
|
for (const item of list.items) {
|
||||||
const { line, lineNumber } = item;
|
const { line, lineNumber } = item;
|
||||||
const actualIndent = indentFor(item);
|
const actualIndent = indentFor(item);
|
||||||
let match = null;
|
let match = null;
|
||||||
|
@ -63,7 +63,7 @@ module.exports = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,9 +12,9 @@ module.exports = {
|
||||||
"Consider starting bulleted lists at the beginning of the line",
|
"Consider starting bulleted lists at the beginning of the line",
|
||||||
"tags": [ "bullet", "ul", "indentation" ],
|
"tags": [ "bullet", "ul", "indentation" ],
|
||||||
"function": function MD006(params, onError) {
|
"function": function MD006(params, onError) {
|
||||||
flattenedLists().forEach((list) => {
|
for (const list of flattenedLists()) {
|
||||||
if (list.unordered && !list.nesting && (list.indent !== 0)) {
|
if (list.unordered && !list.nesting && (list.indent !== 0)) {
|
||||||
list.items.forEach((item) => {
|
for (const item of list.items) {
|
||||||
const { lineNumber, line } = item;
|
const { lineNumber, line } = item;
|
||||||
addErrorDetailIf(
|
addErrorDetailIf(
|
||||||
onError,
|
onError,
|
||||||
|
@ -27,8 +27,8 @@ module.exports = {
|
||||||
{
|
{
|
||||||
"deleteCount": line.length - line.trimStart().length
|
"deleteCount": line.length - line.trimStart().length
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,9 +14,9 @@ module.exports = {
|
||||||
const indent = Number(params.config.indent || 2);
|
const indent = Number(params.config.indent || 2);
|
||||||
const startIndented = !!params.config.start_indented;
|
const startIndented = !!params.config.start_indented;
|
||||||
const startIndent = Number(params.config.start_indent || indent);
|
const startIndent = Number(params.config.start_indent || indent);
|
||||||
flattenedLists().forEach((list) => {
|
for (const list of flattenedLists()) {
|
||||||
if (list.unordered && list.parentsUnordered) {
|
if (list.unordered && list.parentsUnordered) {
|
||||||
list.items.forEach((item) => {
|
for (const item of list.items) {
|
||||||
const { lineNumber, line } = item;
|
const { lineNumber, line } = item;
|
||||||
const expectedIndent =
|
const expectedIndent =
|
||||||
(startIndented ? startIndent : 0) +
|
(startIndented ? startIndent : 0) +
|
||||||
|
@ -42,8 +42,8 @@ module.exports = {
|
||||||
"deleteCount": actualIndent,
|
"deleteCount": actualIndent,
|
||||||
"insertText": "".padEnd(expectedIndent)
|
"insertText": "".padEnd(expectedIndent)
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -58,11 +58,11 @@ module.exports = {
|
||||||
const linkOnlyLineNumbers = [];
|
const linkOnlyLineNumbers = [];
|
||||||
filterTokens(params, "inline", (token) => {
|
filterTokens(params, "inline", (token) => {
|
||||||
let childTokenTypes = "";
|
let childTokenTypes = "";
|
||||||
token.children.forEach((child) => {
|
for (const child of token.children) {
|
||||||
if (child.type !== "text" || child.content !== "") {
|
if (child.type !== "text" || child.content !== "") {
|
||||||
childTokenTypes += tokenTypeMap[child.type] || "x";
|
childTokenTypes += tokenTypeMap[child.type] || "x";
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
if (linkOrImageOnlyLineRe.test(childTokenTypes)) {
|
if (linkOrImageOnlyLineRe.test(childTokenTypes)) {
|
||||||
linkOnlyLineNumbers.push(token.lineNumber);
|
linkOnlyLineNumbers.push(token.lineNumber);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ module.exports = {
|
||||||
"description": "Dollar signs used before commands without showing output",
|
"description": "Dollar signs used before commands without showing output",
|
||||||
"tags": [ "code" ],
|
"tags": [ "code" ],
|
||||||
"function": function MD014(params, onError) {
|
"function": function MD014(params, onError) {
|
||||||
[ "code_block", "fence" ].forEach((type) => {
|
for (const type of [ "code_block", "fence" ]) {
|
||||||
filterTokens(params, type, (token) => {
|
filterTokens(params, type, (token) => {
|
||||||
const margin = (token.type === "fence") ? 1 : 0;
|
const margin = (token.type === "fence") ? 1 : 0;
|
||||||
const dollarInstances = [];
|
const dollarInstances = [];
|
||||||
|
@ -31,7 +31,7 @@ module.exports = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (allDollars) {
|
if (allDollars) {
|
||||||
dollarInstances.forEach((instance) => {
|
for (const instance of dollarInstances) {
|
||||||
const [ i, lineTrim, column, length ] = instance;
|
const [ i, lineTrim, column, length ] = instance;
|
||||||
addErrorContext(
|
addErrorContext(
|
||||||
onError,
|
onError,
|
||||||
|
@ -45,9 +45,9 @@ module.exports = {
|
||||||
"deleteCount": length
|
"deleteCount": length
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,7 +13,7 @@ module.exports = {
|
||||||
"function": function MD027(params, onError) {
|
"function": function MD027(params, onError) {
|
||||||
let blockquoteNesting = 0;
|
let blockquoteNesting = 0;
|
||||||
let listItemNesting = 0;
|
let listItemNesting = 0;
|
||||||
params.tokens.forEach((token) => {
|
for (const token of params.tokens) {
|
||||||
const { content, lineNumber, type } = token;
|
const { content, lineNumber, type } = token;
|
||||||
if (type === "blockquote_open") {
|
if (type === "blockquote_open") {
|
||||||
blockquoteNesting++;
|
blockquoteNesting++;
|
||||||
|
@ -51,6 +51,6 @@ module.exports = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,7 +11,7 @@ module.exports = {
|
||||||
"function": function MD028(params, onError) {
|
"function": function MD028(params, onError) {
|
||||||
let prevToken = {};
|
let prevToken = {};
|
||||||
let prevLineNumber = null;
|
let prevLineNumber = null;
|
||||||
params.tokens.forEach(function forToken(token) {
|
for (const token of params.tokens) {
|
||||||
if ((token.type === "blockquote_open") &&
|
if ((token.type === "blockquote_open") &&
|
||||||
(prevToken.type === "blockquote_close")) {
|
(prevToken.type === "blockquote_close")) {
|
||||||
for (
|
for (
|
||||||
|
@ -25,6 +25,6 @@ module.exports = {
|
||||||
if (token.type === "blockquote_open") {
|
if (token.type === "blockquote_open") {
|
||||||
prevLineNumber = token.map[1] + 1;
|
prevLineNumber = token.map[1] + 1;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,7 +18,8 @@ module.exports = {
|
||||||
"tags": [ "ol" ],
|
"tags": [ "ol" ],
|
||||||
"function": function MD029(params, onError) {
|
"function": function MD029(params, onError) {
|
||||||
const style = String(params.config.style || "one_or_ordered");
|
const style = String(params.config.style || "one_or_ordered");
|
||||||
flattenedLists().filter((list) => !list.unordered).forEach((list) => {
|
const filteredLists = flattenedLists().filter((list) => !list.unordered);
|
||||||
|
for (const list of filteredLists) {
|
||||||
const { items } = list;
|
const { items } = list;
|
||||||
let current = 1;
|
let current = 1;
|
||||||
let incrementing = false;
|
let incrementing = false;
|
||||||
|
@ -49,7 +50,7 @@ module.exports = {
|
||||||
current = 1;
|
current = 1;
|
||||||
}
|
}
|
||||||
// Validate each list item marker
|
// Validate each list item marker
|
||||||
items.forEach((item) => {
|
for (const item of items) {
|
||||||
const match = orderedListItemMarkerRe.exec(item.line);
|
const match = orderedListItemMarkerRe.exec(item.line);
|
||||||
if (match) {
|
if (match) {
|
||||||
addErrorDetailIf(onError, item.lineNumber,
|
addErrorDetailIf(onError, item.lineNumber,
|
||||||
|
@ -60,7 +61,7 @@ module.exports = {
|
||||||
current++;
|
current++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,13 +14,13 @@ module.exports = {
|
||||||
const olSingle = Number(params.config.ol_single || 1);
|
const olSingle = Number(params.config.ol_single || 1);
|
||||||
const ulMulti = Number(params.config.ul_multi || 1);
|
const ulMulti = Number(params.config.ul_multi || 1);
|
||||||
const olMulti = Number(params.config.ol_multi || 1);
|
const olMulti = Number(params.config.ol_multi || 1);
|
||||||
flattenedLists().forEach((list) => {
|
for (const list of flattenedLists()) {
|
||||||
const lineCount = list.lastLineIndex - list.open.map[0];
|
const lineCount = list.lastLineIndex - list.open.map[0];
|
||||||
const allSingle = lineCount === list.items.length;
|
const allSingle = lineCount === list.items.length;
|
||||||
const expectedSpaces = list.unordered ?
|
const expectedSpaces = list.unordered ?
|
||||||
(allSingle ? ulSingle : ulMulti) :
|
(allSingle ? ulSingle : ulMulti) :
|
||||||
(allSingle ? olSingle : olMulti);
|
(allSingle ? olSingle : olMulti);
|
||||||
list.items.forEach((item) => {
|
for (const item of list.items) {
|
||||||
const { line, lineNumber } = item;
|
const { line, lineNumber } = item;
|
||||||
const match = /^[\s>]*\S+(\s*)/.exec(line);
|
const match = /^[\s>]*\S+(\s*)/.exec(line);
|
||||||
const [ { "length": matchLength }, { "length": actualSpaces } ] = match;
|
const [ { "length": matchLength }, { "length": actualSpaces } ] = match;
|
||||||
|
@ -44,7 +44,7 @@ module.exports = {
|
||||||
fixInfo
|
fixInfo
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,7 +13,8 @@ module.exports = {
|
||||||
"tags": [ "bullet", "ul", "ol", "blank_lines" ],
|
"tags": [ "bullet", "ul", "ol", "blank_lines" ],
|
||||||
"function": function MD032(params, onError) {
|
"function": function MD032(params, onError) {
|
||||||
const { lines } = params;
|
const { lines } = params;
|
||||||
flattenedLists().filter((list) => !list.nesting).forEach((list) => {
|
const filteredLists = flattenedLists().filter((list) => !list.nesting);
|
||||||
|
for (const list of filteredLists) {
|
||||||
const firstIndex = list.open.map[0];
|
const firstIndex = list.open.map[0];
|
||||||
if (!isBlankLine(lines[firstIndex - 1])) {
|
if (!isBlankLine(lines[firstIndex - 1])) {
|
||||||
const line = lines[firstIndex];
|
const line = lines[firstIndex];
|
||||||
|
@ -45,6 +46,6 @@ module.exports = {
|
||||||
"insertText": `${quotePrefix}\n`
|
"insertText": `${quotePrefix}\n`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,7 +11,7 @@ module.exports = {
|
||||||
"function": function MD034(params, onError) {
|
"function": function MD034(params, onError) {
|
||||||
filterTokens(params, "inline", (token) => {
|
filterTokens(params, "inline", (token) => {
|
||||||
let inLink = false;
|
let inLink = false;
|
||||||
token.children.forEach((child) => {
|
for (const child of token.children) {
|
||||||
const { content, line, lineNumber, type } = child;
|
const { content, line, lineNumber, type } = child;
|
||||||
let match = null;
|
let match = null;
|
||||||
if (type === "link_open") {
|
if (type === "link_open") {
|
||||||
|
@ -55,7 +55,7 @@ module.exports = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -49,8 +49,8 @@ module.exports = {
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
let state = base;
|
let state = base;
|
||||||
params.tokens.forEach(function forToken(token) {
|
for (const token of params.tokens) {
|
||||||
state = state(token);
|
state = state(token);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,7 +18,7 @@ module.exports = {
|
||||||
let inLink = false;
|
let inLink = false;
|
||||||
let linkText = "";
|
let linkText = "";
|
||||||
let lineIndex = 0;
|
let lineIndex = 0;
|
||||||
children.forEach((child) => {
|
for (const child of children) {
|
||||||
const { content, markup, type } = child;
|
const { content, markup, type } = child;
|
||||||
if (type === "link_open") {
|
if (type === "link_open") {
|
||||||
inLink = true;
|
inLink = true;
|
||||||
|
@ -61,7 +61,7 @@ module.exports = {
|
||||||
`${markup}${content}${markup}` :
|
`${markup}${content}${markup}` :
|
||||||
(content || markup);
|
(content || markup);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,15 +14,15 @@ module.exports = {
|
||||||
let inLink = false;
|
let inLink = false;
|
||||||
let linkText = "";
|
let linkText = "";
|
||||||
let emptyLink = false;
|
let emptyLink = false;
|
||||||
token.children.forEach(function forChild(child) {
|
for (const child of token.children) {
|
||||||
if (child.type === "link_open") {
|
if (child.type === "link_open") {
|
||||||
inLink = true;
|
inLink = true;
|
||||||
linkText = "";
|
linkText = "";
|
||||||
child.attrs.forEach(function forAttr(attr) {
|
for (const attr of child.attrs) {
|
||||||
if (attr[0] === "href" && (!attr[1] || (attr[1] === "#"))) {
|
if (attr[0] === "href" && (!attr[1] || (attr[1] === "#"))) {
|
||||||
emptyLink = true;
|
emptyLink = true;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
} else if (child.type === "link_close") {
|
} else if (child.type === "link_close") {
|
||||||
inLink = false;
|
inLink = false;
|
||||||
if (emptyLink) {
|
if (emptyLink) {
|
||||||
|
@ -43,7 +43,7 @@ module.exports = {
|
||||||
} else if (inLink) {
|
} else if (inLink) {
|
||||||
linkText += child.content;
|
linkText += child.content;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,9 +13,9 @@ module.exports = {
|
||||||
const requiredHeadings = params.config.headings || params.config.headers;
|
const requiredHeadings = params.config.headings || params.config.headers;
|
||||||
if (Array.isArray(requiredHeadings)) {
|
if (Array.isArray(requiredHeadings)) {
|
||||||
const levels = {};
|
const levels = {};
|
||||||
[ 1, 2, 3, 4, 5, 6 ].forEach((level) => {
|
for (const level of [ 1, 2, 3, 4, 5, 6 ]) {
|
||||||
levels["h" + level] = "######".substr(-level);
|
levels["h" + level] = "######".substr(-level);
|
||||||
});
|
}
|
||||||
let i = 0;
|
let i = 0;
|
||||||
let matchAny = false;
|
let matchAny = false;
|
||||||
let hasError = false;
|
let hasError = false;
|
||||||
|
|
27
lib/md046.js
27
lib/md046.js
|
@ -15,18 +15,19 @@ module.exports = {
|
||||||
"tags": [ "code" ],
|
"tags": [ "code" ],
|
||||||
"function": function MD046(params, onError) {
|
"function": function MD046(params, onError) {
|
||||||
let expectedStyle = String(params.config.style || "consistent");
|
let expectedStyle = String(params.config.style || "consistent");
|
||||||
params.tokens
|
const codeBlocksAndFences = params.tokens.filter(
|
||||||
.filter((token) => token.type === "code_block" || token.type === "fence")
|
(token) => (token.type === "code_block") || (token.type === "fence")
|
||||||
.forEach((token) => {
|
);
|
||||||
const { lineNumber, type } = token;
|
for (const token of codeBlocksAndFences) {
|
||||||
if (expectedStyle === "consistent") {
|
const { lineNumber, type } = token;
|
||||||
expectedStyle = tokenTypeToStyle[type];
|
if (expectedStyle === "consistent") {
|
||||||
}
|
expectedStyle = tokenTypeToStyle[type];
|
||||||
addErrorDetailIf(
|
}
|
||||||
onError,
|
addErrorDetailIf(
|
||||||
lineNumber,
|
onError,
|
||||||
expectedStyle,
|
lineNumber,
|
||||||
tokenTypeToStyle[type]);
|
expectedStyle,
|
||||||
});
|
tokenTypeToStyle[type]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
27
lib/md048.js
27
lib/md048.js
|
@ -11,19 +11,18 @@ module.exports = {
|
||||||
"function": function MD048(params, onError) {
|
"function": function MD048(params, onError) {
|
||||||
const style = String(params.config.style || "consistent");
|
const style = String(params.config.style || "consistent");
|
||||||
let expectedStyle = style;
|
let expectedStyle = style;
|
||||||
params.tokens
|
const fenceTokens = params.tokens.filter((token) => token.type === "fence");
|
||||||
.filter((token) => token.type === "fence")
|
for (const fenceToken of fenceTokens) {
|
||||||
.forEach((fenceToken) => {
|
const { lineNumber, markup } = fenceToken;
|
||||||
const { lineNumber, markup } = fenceToken;
|
if (expectedStyle === "consistent") {
|
||||||
if (expectedStyle === "consistent") {
|
expectedStyle = fencedCodeBlockStyleFor(markup);
|
||||||
expectedStyle = fencedCodeBlockStyleFor(markup);
|
}
|
||||||
}
|
addErrorDetailIf(
|
||||||
addErrorDetailIf(
|
onError,
|
||||||
onError,
|
lineNumber,
|
||||||
lineNumber,
|
expectedStyle,
|
||||||
expectedStyle,
|
fencedCodeBlockStyleFor(markup)
|
||||||
fencedCodeBlockStyleFor(markup)
|
);
|
||||||
);
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -54,10 +54,10 @@ const rules = [
|
||||||
require("./md052"),
|
require("./md052"),
|
||||||
require("./md053")
|
require("./md053")
|
||||||
];
|
];
|
||||||
rules.forEach((rule) => {
|
for (const rule of rules) {
|
||||||
const name = rule.names[0].toLowerCase();
|
const name = rule.names[0].toLowerCase();
|
||||||
// eslint-disable-next-line dot-notation
|
// eslint-disable-next-line dot-notation
|
||||||
rule["information"] =
|
rule["information"] =
|
||||||
new URL(`${homepage}/blob/v${version}/doc/Rules.md#${name}`);
|
new URL(`${homepage}/blob/v${version}/doc/Rules.md#${name}`);
|
||||||
});
|
}
|
||||||
module.exports = rules;
|
module.exports = rules;
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
"build-config": "npm run build-config-schema && npm run build-config-example",
|
"build-config": "npm run build-config-schema && npm run build-config-example",
|
||||||
"build-config-example": "node schema/build-config-example.js",
|
"build-config-example": "node schema/build-config-example.js",
|
||||||
"build-config-schema": "node schema/build-config-schema.js",
|
"build-config-schema": "node schema/build-config-schema.js",
|
||||||
"build-declaration": "tsc --allowJs --declaration --emitDeclarationOnly --resolveJsonModule lib/markdownlint.js && node scripts delete 'lib/{c,md,r}*.d.ts' 'helpers/*.d.ts'",
|
"build-declaration": "tsc --allowJs --declaration --emitDeclarationOnly --module commonjs --resolveJsonModule --target es2015 lib/markdownlint.js && node scripts delete 'lib/{c,md,r}*.d.ts' 'helpers/*.d.ts'",
|
||||||
"build-demo": "node scripts copy node_modules/markdown-it/dist/markdown-it.min.js demo/markdown-it.min.js && cd demo && webpack --no-stats",
|
"build-demo": "node scripts copy node_modules/markdown-it/dist/markdown-it.min.js demo/markdown-it.min.js && cd demo && webpack --no-stats",
|
||||||
"build-example": "npm install --no-save --ignore-scripts grunt grunt-cli gulp through2",
|
"build-example": "npm install --no-save --ignore-scripts grunt grunt-cli gulp through2",
|
||||||
"ci": "npm-run-all --continue-on-error --parallel build-config lint serial-declaration-demo test-cover && git diff --exit-code",
|
"ci": "npm-run-all --continue-on-error --parallel build-config lint serial-declaration-demo test-cover && git diff --exit-code",
|
||||||
|
|
|
@ -41,12 +41,12 @@ const schema = {
|
||||||
const tags = {};
|
const tags = {};
|
||||||
|
|
||||||
// Add rules
|
// Add rules
|
||||||
rules.forEach(function forRule(rule) {
|
for (const rule of rules) {
|
||||||
rule.tags.forEach(function forTag(tag) {
|
for (const tag of rule.tags) {
|
||||||
const tagRules = tags[tag] || [];
|
const tagRules = tags[tag] || [];
|
||||||
tagRules.push(rule.names[0]);
|
tagRules.push(rule.names[0]);
|
||||||
tags[tag] = tagRules;
|
tags[tag] = tagRules;
|
||||||
});
|
}
|
||||||
const scheme = {
|
const scheme = {
|
||||||
"description": rule.names.join("/") + " - " + rule.description,
|
"description": rule.names.join("/") + " - " + rule.description,
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
@ -472,22 +472,22 @@ rules.forEach(function forRule(rule) {
|
||||||
scheme.type = [ "boolean", "object" ];
|
scheme.type = [ "boolean", "object" ];
|
||||||
scheme.additionalProperties = false;
|
scheme.additionalProperties = false;
|
||||||
}
|
}
|
||||||
rule.names.forEach(function forName(name, index) {
|
for (const [ index, name ] of rule.names.entries()) {
|
||||||
schema.properties[name] = (index === 0) ? scheme : {
|
schema.properties[name] = (index === 0) ? scheme : {
|
||||||
"$ref": `#/properties/${rule.names[0]}`
|
"$ref": `#/properties/${rule.names[0]}`
|
||||||
};
|
};
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
// Add tags
|
// Add tags
|
||||||
Object.keys(tags).forEach(function forTag(tag) {
|
for (const [ tag, tagTags ] of Object.entries(tags)) {
|
||||||
const scheme = {
|
const scheme = {
|
||||||
"description": tag + " - " + tags[tag].join(", "),
|
"description": tag + " - " + tagTags.join(", "),
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": true
|
"default": true
|
||||||
};
|
};
|
||||||
schema.properties[tag] = scheme;
|
schema.properties[tag] = scheme;
|
||||||
});
|
}
|
||||||
|
|
||||||
// Write schema
|
// Write schema
|
||||||
const schemaFile = path.join(__dirname, "markdownlint-config-schema.json");
|
const schemaFile = path.join(__dirname, "markdownlint-config-schema.json");
|
||||||
|
|
|
@ -350,7 +350,7 @@ test.cb("customRulesNpmPackage", (t) => {
|
||||||
|
|
||||||
test("customRulesBadProperty", (t) => {
|
test("customRulesBadProperty", (t) => {
|
||||||
t.plan(27);
|
t.plan(27);
|
||||||
[
|
for (const testCase of [
|
||||||
{
|
{
|
||||||
"propertyName": "names",
|
"propertyName": "names",
|
||||||
"propertyValues":
|
"propertyValues":
|
||||||
|
@ -377,9 +377,9 @@ test("customRulesBadProperty", (t) => {
|
||||||
"propertyName": "function",
|
"propertyName": "function",
|
||||||
"propertyValues": [ null, "string", [] ]
|
"propertyValues": [ null, "string", [] ]
|
||||||
}
|
}
|
||||||
].forEach(function forTestCase(testCase) {
|
]) {
|
||||||
const { propertyName, propertyValues } = testCase;
|
const { propertyName, propertyValues } = testCase;
|
||||||
propertyValues.forEach(function forPropertyValue(propertyValue) {
|
for (const propertyValue of propertyValues) {
|
||||||
const badRule = { ...customRules.anyBlockquote };
|
const badRule = { ...customRules.anyBlockquote };
|
||||||
badRule[propertyName] = propertyValue;
|
badRule[propertyName] = propertyValue;
|
||||||
const options = {
|
const options = {
|
||||||
|
@ -395,8 +395,8 @@ test("customRulesBadProperty", (t) => {
|
||||||
},
|
},
|
||||||
"Did not get correct exception for missing property."
|
"Did not get correct exception for missing property."
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test.cb("customRulesUsedNameName", (t) => {
|
test.cb("customRulesUsedNameName", (t) => {
|
||||||
|
@ -639,7 +639,7 @@ test("customRulesOnErrorNullSync", (t) => {
|
||||||
|
|
||||||
test("customRulesOnErrorBad", (t) => {
|
test("customRulesOnErrorBad", (t) => {
|
||||||
t.plan(21);
|
t.plan(21);
|
||||||
[
|
for (const testCase of [
|
||||||
{
|
{
|
||||||
"propertyName": "lineNumber",
|
"propertyName": "lineNumber",
|
||||||
"subPropertyName": null,
|
"subPropertyName": null,
|
||||||
|
@ -685,9 +685,9 @@ test("customRulesOnErrorBad", (t) => {
|
||||||
"subPropertyName": "insertText",
|
"subPropertyName": "insertText",
|
||||||
"propertyValues": [ 10, [] ]
|
"propertyValues": [ 10, [] ]
|
||||||
}
|
}
|
||||||
].forEach(function forTestCase(testCase) {
|
]) {
|
||||||
const { propertyName, subPropertyName, propertyValues } = testCase;
|
const { propertyName, subPropertyName, propertyValues } = testCase;
|
||||||
propertyValues.forEach(function forPropertyValue(propertyValue) {
|
for (const propertyValue of propertyValues) {
|
||||||
const badObject = {
|
const badObject = {
|
||||||
"lineNumber": 1
|
"lineNumber": 1
|
||||||
};
|
};
|
||||||
|
@ -725,13 +725,13 @@ test("customRulesOnErrorBad", (t) => {
|
||||||
},
|
},
|
||||||
"Did not get correct exception for bad object."
|
"Did not get correct exception for bad object."
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test("customRulesOnErrorInvalid", (t) => {
|
test("customRulesOnErrorInvalid", (t) => {
|
||||||
t.plan(17);
|
t.plan(17);
|
||||||
[
|
for (const testCase of [
|
||||||
{
|
{
|
||||||
"propertyName": "lineNumber",
|
"propertyName": "lineNumber",
|
||||||
"subPropertyName": null,
|
"subPropertyName": null,
|
||||||
|
@ -757,9 +757,9 @@ test("customRulesOnErrorInvalid", (t) => {
|
||||||
"subPropertyName": "deleteCount",
|
"subPropertyName": "deleteCount",
|
||||||
"propertyValues": [ -2, 5 ]
|
"propertyValues": [ -2, 5 ]
|
||||||
}
|
}
|
||||||
].forEach(function forTestCase(testCase) {
|
]) {
|
||||||
const { propertyName, subPropertyName, propertyValues } = testCase;
|
const { propertyName, subPropertyName, propertyValues } = testCase;
|
||||||
propertyValues.forEach(function forPropertyValue(propertyValue) {
|
for (const propertyValue of propertyValues) {
|
||||||
const badObject = {
|
const badObject = {
|
||||||
"lineNumber": 1
|
"lineNumber": 1
|
||||||
};
|
};
|
||||||
|
@ -797,13 +797,13 @@ test("customRulesOnErrorInvalid", (t) => {
|
||||||
},
|
},
|
||||||
"Did not get correct exception for invalid object."
|
"Did not get correct exception for invalid object."
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test("customRulesOnErrorValid", (t) => {
|
test("customRulesOnErrorValid", (t) => {
|
||||||
t.plan(24);
|
t.plan(24);
|
||||||
[
|
for (const testCase of [
|
||||||
{
|
{
|
||||||
"propertyName": "lineNumber",
|
"propertyName": "lineNumber",
|
||||||
"subPropertyName": null,
|
"subPropertyName": null,
|
||||||
|
@ -835,9 +835,9 @@ test("customRulesOnErrorValid", (t) => {
|
||||||
"propertyValues":
|
"propertyValues":
|
||||||
[ "", "1", "123456", "\n", "\nText", "Text\n", "\nText\n" ]
|
[ "", "1", "123456", "\n", "\nText", "Text\n", "\nText\n" ]
|
||||||
}
|
}
|
||||||
].forEach(function forTestCase(testCase) {
|
]) {
|
||||||
const { propertyName, subPropertyName, propertyValues } = testCase;
|
const { propertyName, subPropertyName, propertyValues } = testCase;
|
||||||
propertyValues.forEach(function forPropertyValue(propertyValue) {
|
for (const propertyValue of propertyValues) {
|
||||||
const goodObject = {
|
const goodObject = {
|
||||||
"lineNumber": 1
|
"lineNumber": 1
|
||||||
};
|
};
|
||||||
|
@ -864,8 +864,8 @@ test("customRulesOnErrorValid", (t) => {
|
||||||
};
|
};
|
||||||
markdownlint.sync(options);
|
markdownlint.sync(options);
|
||||||
t.truthy(true);
|
t.truthy(true);
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test.cb("customRulesOnErrorLazy", (t) => {
|
test.cb("customRulesOnErrorLazy", (t) => {
|
||||||
|
@ -1424,7 +1424,7 @@ const stringScenarios = [
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
[
|
for (const flavor of [
|
||||||
[
|
[
|
||||||
"customRulesThrowString",
|
"customRulesThrowString",
|
||||||
() => {
|
() => {
|
||||||
|
@ -1437,7 +1437,7 @@ const stringScenarios = [
|
||||||
throw new Error(errorMessage);
|
throw new Error(errorMessage);
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
].forEach((flavor) => {
|
]) {
|
||||||
const [ name, func ] = flavor;
|
const [ name, func ] = flavor;
|
||||||
const customRule = [
|
const customRule = [
|
||||||
{
|
{
|
||||||
|
@ -1461,7 +1461,7 @@ const stringScenarios = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
stringScenarios.forEach((inputs) => {
|
for (const inputs of stringScenarios) {
|
||||||
const [ subname, files, strings ] = inputs;
|
const [ subname, files, strings ] = inputs;
|
||||||
|
|
||||||
test.cb(`${name}${subname}UnhandledAsync`, (t) => {
|
test.cb(`${name}${subname}UnhandledAsync`, (t) => {
|
||||||
|
@ -1530,10 +1530,10 @@ const stringScenarios = [
|
||||||
});
|
});
|
||||||
t.deepEqual(actualResult, expectedResult, "Undetected issues.");
|
t.deepEqual(actualResult, expectedResult, "Undetected issues.");
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
[
|
for (const flavor of [
|
||||||
[
|
[
|
||||||
"customRulesAsyncExceptionString",
|
"customRulesAsyncExceptionString",
|
||||||
() => {
|
() => {
|
||||||
|
@ -1570,7 +1570,7 @@ const stringScenarios = [
|
||||||
"customRulesAsyncRejectError",
|
"customRulesAsyncRejectError",
|
||||||
() => Promise.reject(new Error(errorMessage))
|
() => Promise.reject(new Error(errorMessage))
|
||||||
]
|
]
|
||||||
].forEach((flavor) => {
|
]) {
|
||||||
const [ name, func ] = flavor;
|
const [ name, func ] = flavor;
|
||||||
const customRule = {
|
const customRule = {
|
||||||
"names": [ "name" ],
|
"names": [ "name" ],
|
||||||
|
@ -1579,7 +1579,7 @@ const stringScenarios = [
|
||||||
"asynchronous": true,
|
"asynchronous": true,
|
||||||
"function": func
|
"function": func
|
||||||
};
|
};
|
||||||
stringScenarios.forEach((inputs) => {
|
for (const inputs of stringScenarios) {
|
||||||
const [ subname, files, strings ] = inputs;
|
const [ subname, files, strings ] = inputs;
|
||||||
|
|
||||||
test.cb(`${name}${subname}Unhandled`, (t) => {
|
test.cb(`${name}${subname}Unhandled`, (t) => {
|
||||||
|
@ -1630,5 +1630,5 @@ const stringScenarios = [
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
|
|
|
@ -8,8 +8,10 @@ const test = require("ava").default;
|
||||||
const markdownlint = require("../lib/markdownlint");
|
const markdownlint = require("../lib/markdownlint");
|
||||||
|
|
||||||
// Simulates typing each test file to validate handling of partial input
|
// Simulates typing each test file to validate handling of partial input
|
||||||
const files = fs.readdirSync("./test");
|
const files = fs
|
||||||
files.filter((file) => /\.md$/.test(file)).forEach((file) => {
|
.readdirSync("./test")
|
||||||
|
.filter((file) => /\.md$/.test(file));
|
||||||
|
for (const file of files) {
|
||||||
const strings = {};
|
const strings = {};
|
||||||
let content = fs.readFileSync(path.join("./test", file), "utf8");
|
let content = fs.readFileSync(path.join("./test", file), "utf8");
|
||||||
while (content) {
|
while (content) {
|
||||||
|
@ -25,4 +27,4 @@ files.filter((file) => /\.md$/.test(file)).forEach((file) => {
|
||||||
});
|
});
|
||||||
t.pass();
|
t.pass();
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
|
@ -219,11 +219,11 @@ bar`
|
||||||
"_"
|
"_"
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
testCases.forEach(function forTestCase(testCase) {
|
for (const testCase of testCases) {
|
||||||
const [ markdown, expected, replacement ] = testCase;
|
const [ markdown, expected, replacement ] = testCase;
|
||||||
const actual = helpers.unescapeMarkdown(markdown, replacement);
|
const actual = helpers.unescapeMarkdown(markdown, replacement);
|
||||||
t.is(actual, expected);
|
t.is(actual, expected);
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test("isBlankLine", (t) => {
|
test("isBlankLine", (t) => {
|
||||||
|
@ -253,7 +253,9 @@ test("isBlankLine", (t) => {
|
||||||
"text --> <!--text--> <!--text--> <!-- text",
|
"text --> <!--text--> <!--text--> <!-- text",
|
||||||
"text --> --> <!--text--> <!--text--> <!-- <!-- text"
|
"text --> --> <!--text--> <!--text--> <!-- <!-- text"
|
||||||
];
|
];
|
||||||
blankLines.forEach((line) => t.true(helpers.isBlankLine(line), line || ""));
|
for (const line of blankLines) {
|
||||||
|
t.true(helpers.isBlankLine(line), line || "");
|
||||||
|
}
|
||||||
const nonBlankLines = [
|
const nonBlankLines = [
|
||||||
"text",
|
"text",
|
||||||
" text ",
|
" text ",
|
||||||
|
@ -266,7 +268,9 @@ test("isBlankLine", (t) => {
|
||||||
"text --> <!--text--> text <!--text--> <!-- text",
|
"text --> <!--text--> text <!--text--> <!-- text",
|
||||||
"text --> --> <!--text--> text <!--text--> <!-- <!-- text"
|
"text --> --> <!--text--> text <!--text--> <!-- <!-- text"
|
||||||
];
|
];
|
||||||
nonBlankLines.forEach((line) => t.true(!helpers.isBlankLine(line), line));
|
for (const line of nonBlankLines) {
|
||||||
|
t.true(!helpers.isBlankLine(line), line);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test("includesSorted", (t) => {
|
test("includesSorted", (t) => {
|
||||||
|
@ -280,11 +284,11 @@ test("includesSorted", (t) => {
|
||||||
[ 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 ],
|
[ 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 ],
|
||||||
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 ]
|
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 ]
|
||||||
];
|
];
|
||||||
inputs.forEach((input) => {
|
for (const input of inputs) {
|
||||||
for (let i = 0; i <= 21; i++) {
|
for (let i = 0; i <= 21; i++) {
|
||||||
t.is(helpers.includesSorted(input, i), input.includes(i));
|
t.is(helpers.includesSorted(input, i), input.includes(i));
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test("forEachInlineCodeSpan", (t) => {
|
test("forEachInlineCodeSpan", (t) => {
|
||||||
|
@ -377,7 +381,7 @@ test("forEachInlineCodeSpan", (t) => {
|
||||||
"expecteds": [ [ "code", 1, 1, 1 ] ]
|
"expecteds": [ [ "code", 1, 1, 1 ] ]
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
testCases.forEach((testCase) => {
|
for (const testCase of testCases) {
|
||||||
const { input, expecteds } = testCase;
|
const { input, expecteds } = testCase;
|
||||||
helpers.forEachInlineCodeSpan(input, (code, line, column, ticks) => {
|
helpers.forEachInlineCodeSpan(input, (code, line, column, ticks) => {
|
||||||
const [ expectedCode, expectedLine, expectedColumn, expectedTicks ] =
|
const [ expectedCode, expectedLine, expectedColumn, expectedTicks ] =
|
||||||
|
@ -388,7 +392,7 @@ test("forEachInlineCodeSpan", (t) => {
|
||||||
t.is(ticks, expectedTicks, input);
|
t.is(ticks, expectedTicks, input);
|
||||||
});
|
});
|
||||||
t.is(expecteds.length, 0, "length");
|
t.is(expecteds.length, 0, "length");
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test("getPreferredLineEnding", (t) => {
|
test("getPreferredLineEnding", (t) => {
|
||||||
|
@ -412,11 +416,11 @@ test("getPreferredLineEnding", (t) => {
|
||||||
[ "t\nt\r\nt\nt", "\n" ],
|
[ "t\nt\r\nt\nt", "\n" ],
|
||||||
[ "t\rt\t\rt", "\r" ]
|
[ "t\rt\t\rt", "\r" ]
|
||||||
];
|
];
|
||||||
testCases.forEach((testCase) => {
|
for (const testCase of testCases) {
|
||||||
const [ input, expected ] = testCase;
|
const [ input, expected ] = testCase;
|
||||||
const actual = helpers.getPreferredLineEnding(input);
|
const actual = helpers.getPreferredLineEnding(input);
|
||||||
t.is(actual, expected, "Incorrect line ending returned.");
|
t.is(actual, expected, "Incorrect line ending returned.");
|
||||||
});
|
}
|
||||||
t.is(helpers.getPreferredLineEnding("", null), "\n");
|
t.is(helpers.getPreferredLineEnding("", null), "\n");
|
||||||
t.is(helpers.getPreferredLineEnding("", { "EOL": "\n" }), "\n");
|
t.is(helpers.getPreferredLineEnding("", { "EOL": "\n" }), "\n");
|
||||||
t.is(helpers.getPreferredLineEnding("", { "EOL": "\r\n" }), "\r\n");
|
t.is(helpers.getPreferredLineEnding("", { "EOL": "\r\n" }), "\r\n");
|
||||||
|
@ -463,12 +467,12 @@ test("applyFix", (t) => {
|
||||||
"Hello world.\r\n"
|
"Hello world.\r\n"
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
testCases.forEach((testCase) => {
|
for (const testCase of testCases) {
|
||||||
const [ line, fixInfo, lineEnding, expected ] = testCase;
|
const [ line, fixInfo, lineEnding, expected ] = testCase;
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const actual = helpers.applyFix(line, fixInfo, lineEnding);
|
const actual = helpers.applyFix(line, fixInfo, lineEnding);
|
||||||
t.is(actual, expected, "Incorrect fix applied.");
|
t.is(actual, expected, "Incorrect fix applied.");
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test("applyFixes", (t) => {
|
test("applyFixes", (t) => {
|
||||||
|
@ -941,12 +945,12 @@ test("applyFixes", (t) => {
|
||||||
"Hello world"
|
"Hello world"
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
testCases.forEach((testCase) => {
|
for (const testCase of testCases) {
|
||||||
const [ input, errors, expected ] = testCase;
|
const [ input, errors, expected ] = testCase;
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const actual = helpers.applyFixes(input, errors);
|
const actual = helpers.applyFixes(input, errors);
|
||||||
t.is(actual, expected, "Incorrect fix applied.");
|
t.is(actual, expected, "Incorrect fix applied.");
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test("deepFreeze", (t) => {
|
test("deepFreeze", (t) => {
|
||||||
|
@ -962,7 +966,7 @@ test("deepFreeze", (t) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
t.is(helpers.deepFreeze(obj), obj, "Did not return object.");
|
t.is(helpers.deepFreeze(obj), obj, "Did not return object.");
|
||||||
[
|
for (const scenario of [
|
||||||
() => {
|
() => {
|
||||||
obj.prop = false;
|
obj.prop = false;
|
||||||
},
|
},
|
||||||
|
@ -978,9 +982,9 @@ test("deepFreeze", (t) => {
|
||||||
() => {
|
() => {
|
||||||
obj.sub.sub.prop = "zero";
|
obj.sub.sub.prop = "zero";
|
||||||
}
|
}
|
||||||
].forEach((scenario) => {
|
]) {
|
||||||
t.throws(scenario, null, "Assigned to frozen object.");
|
t.throws(scenario, null, "Assigned to frozen object.");
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test("forEachLink", (t) => {
|
test("forEachLink", (t) => {
|
||||||
|
|
|
@ -36,18 +36,18 @@ function createTestForFile(file) {
|
||||||
.then((params) => {
|
.then((params) => {
|
||||||
const [ config, content, results ] = params;
|
const [ config, content, results ] = params;
|
||||||
// Canonicalize version number
|
// Canonicalize version number
|
||||||
const errors = results[file];
|
const errors = results[file]
|
||||||
errors
|
.filter((error) => !!error.ruleInformation);
|
||||||
.filter((error) => !!error.ruleInformation)
|
for (const error of errors) {
|
||||||
.forEach((error) => {
|
error.ruleInformation =
|
||||||
error.ruleInformation =
|
|
||||||
error.ruleInformation.replace(/v\d+\.\d+\.\d+/, "v0.0.0");
|
error.ruleInformation.replace(/v\d+\.\d+\.\d+/, "v0.0.0");
|
||||||
});
|
}
|
||||||
// Match identified issues by MD### markers
|
// Match identified issues by MD### markers
|
||||||
const marker = /\{(MD\d+)(?::(\d+))?\}/g;
|
const marker = /\{(MD\d+)(?::(\d+))?\}/g;
|
||||||
const lines = content.split(helpers.newLineRe);
|
const lines = content.split(helpers.newLineRe);
|
||||||
const expected = {};
|
const expected = {};
|
||||||
lines.forEach((line, index) => {
|
// @ts-ignore
|
||||||
|
for (const [ index, line ] of lines.entries()) {
|
||||||
let match = null;
|
let match = null;
|
||||||
while ((match = marker.exec(line))) {
|
while ((match = marker.exec(line))) {
|
||||||
const rule = match[1];
|
const rule = match[1];
|
||||||
|
@ -55,17 +55,17 @@ function createTestForFile(file) {
|
||||||
const indices = expected[rule] = expected[rule] || [];
|
const indices = expected[rule] = expected[rule] || [];
|
||||||
indices.push(match[2] ? Number.parseInt(match[2], 10) : index + 1);
|
indices.push(match[2] ? Number.parseInt(match[2], 10) : index + 1);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
if (Object.keys(expected).length > 0) {
|
if (Object.keys(expected).length > 0) {
|
||||||
const actual = {};
|
const actual = {};
|
||||||
errors.forEach((error) => {
|
for (const error of errors) {
|
||||||
const rule = error.ruleNames[0];
|
const rule = error.ruleNames[0];
|
||||||
// eslint-disable-next-line no-multi-assign
|
// eslint-disable-next-line no-multi-assign
|
||||||
const indices = actual[rule] = actual[rule] || [];
|
const indices = actual[rule] = actual[rule] || [];
|
||||||
if (indices[indices.length - 1] !== error.lineNumber) {
|
if (indices[indices.length - 1] !== error.lineNumber) {
|
||||||
indices.push(error.lineNumber);
|
indices.push(error.lineNumber);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
t.deepEqual(actual, expected, "Too few or too many issues found.");
|
t.deepEqual(actual, expected, "Too few or too many issues found.");
|
||||||
}
|
}
|
||||||
// Create snapshot
|
// Create snapshot
|
||||||
|
@ -91,10 +91,13 @@ function createTestForFile(file) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
require("fs").readdirSync("./test")
|
const files = require("fs")
|
||||||
.filter((file) => /\.md$/.test(file))
|
.readdirSync("./test")
|
||||||
|
.filter((file) => /\.md$/.test(file));
|
||||||
|
for (const file of files) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
.forEach((file) => test(
|
test(
|
||||||
file,
|
file,
|
||||||
createTestForFile(path.join("./test", file))
|
createTestForFile(path.join("./test", file))
|
||||||
));
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -433,9 +433,9 @@ test.cb("styleFiles", (t) => {
|
||||||
t.plan(4);
|
t.plan(4);
|
||||||
fs.readdir("./style", function readdir(err, files) {
|
fs.readdir("./style", function readdir(err, files) {
|
||||||
t.falsy(err);
|
t.falsy(err);
|
||||||
files.forEach(function forFile(file) {
|
for (const file of files) {
|
||||||
t.truthy(require(path.join("../style", file)), "Unable to load/parse.");
|
t.truthy(require(path.join("../style", file)), "Unable to load/parse.");
|
||||||
});
|
}
|
||||||
t.end();
|
t.end();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -847,13 +847,13 @@ test.cb("customFileSystemAsync", (t) => {
|
||||||
test.cb("readme", (t) => {
|
test.cb("readme", (t) => {
|
||||||
t.plan(125);
|
t.plan(125);
|
||||||
const tagToRules = {};
|
const tagToRules = {};
|
||||||
rules.forEach(function forRule(rule) {
|
for (const rule of rules) {
|
||||||
rule.tags.forEach(function forTag(tag) {
|
for (const tag of rule.tags) {
|
||||||
const tagRules = tagToRules[tag] || [];
|
const tagRules = tagToRules[tag] || [];
|
||||||
tagRules.push(rule.names[0]);
|
tagRules.push(rule.names[0]);
|
||||||
tagToRules[tag] = tagRules;
|
tagToRules[tag] = tagRules;
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
fs.readFile("README.md", "utf8",
|
fs.readFile("README.md", "utf8",
|
||||||
function readFile(err, contents) {
|
function readFile(err, contents) {
|
||||||
t.falsy(err);
|
t.falsy(err);
|
||||||
|
@ -864,7 +864,7 @@ test.cb("readme", (t) => {
|
||||||
let seenTags = false;
|
let seenTags = false;
|
||||||
let inTags = false;
|
let inTags = false;
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
md.parse(contents, {}).forEach(function forToken(token) {
|
for (const token of md.parse(contents, {})) {
|
||||||
if (
|
if (
|
||||||
(token.type === "bullet_list_open") &&
|
(token.type === "bullet_list_open") &&
|
||||||
(token.level === 0)
|
(token.level === 0)
|
||||||
|
@ -909,7 +909,7 @@ test.cb("readme", (t) => {
|
||||||
delete tagToRules[tag];
|
delete tagToRules[tag];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
const ruleLeft = rulesLeft.shift();
|
const ruleLeft = rulesLeft.shift();
|
||||||
t.true(!ruleLeft,
|
t.true(!ruleLeft,
|
||||||
"Missing rule documentation for " +
|
"Missing rule documentation for " +
|
||||||
|
@ -943,7 +943,7 @@ test.cb("rules", (t) => {
|
||||||
"Missing parameters for rule " + r.names + ".");
|
"Missing parameters for rule " + r.names + ".");
|
||||||
};
|
};
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
md.parse(contents, {}).forEach(function forToken(token) {
|
for (const token of md.parse(contents, {})) {
|
||||||
if ((token.type === "heading_open") && (token.tag === "h2")) {
|
if ((token.type === "heading_open") && (token.tag === "h2")) {
|
||||||
inHeading = true;
|
inHeading = true;
|
||||||
} else if (token.type === "heading_close") {
|
} else if (token.type === "heading_close") {
|
||||||
|
@ -995,7 +995,7 @@ test.cb("rules", (t) => {
|
||||||
ruleUsesParams = null;
|
ruleUsesParams = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
const ruleLeft = rulesLeft.shift();
|
const ruleLeft = rulesLeft.shift();
|
||||||
t.true(!ruleLeft,
|
t.true(!ruleLeft,
|
||||||
"Missing rule documentation for " +
|
"Missing rule documentation for " +
|
||||||
|
@ -1013,13 +1013,15 @@ test("validateJsonUsingConfigSchemaStrict", (t) => {
|
||||||
const jsConfigFileRe = /^jsconfig\.json$/i;
|
const jsConfigFileRe = /^jsconfig\.json$/i;
|
||||||
const wrongTypesFileRe = /wrong-types-in-config-file.json$/i;
|
const wrongTypesFileRe = /wrong-types-in-config-file.json$/i;
|
||||||
const testDirectory = __dirname;
|
const testDirectory = __dirname;
|
||||||
const testFiles = fs.readdirSync(testDirectory);
|
const testFiles = fs
|
||||||
testFiles.filter(function filterFile(file) {
|
.readdirSync(testDirectory)
|
||||||
return jsonFileRe.test(file) &&
|
.filter(function filterFile(file) {
|
||||||
!resultsFileRe.test(file) &&
|
return jsonFileRe.test(file) &&
|
||||||
!jsConfigFileRe.test(file) &&
|
!resultsFileRe.test(file) &&
|
||||||
!wrongTypesFileRe.test(file);
|
!jsConfigFileRe.test(file) &&
|
||||||
}).forEach(function forFile(file) {
|
!wrongTypesFileRe.test(file);
|
||||||
|
});
|
||||||
|
for (const file of testFiles) {
|
||||||
const data = fs.readFileSync(
|
const data = fs.readFileSync(
|
||||||
path.join(testDirectory, file),
|
path.join(testDirectory, file),
|
||||||
"utf8"
|
"utf8"
|
||||||
|
@ -1028,7 +1030,7 @@ test("validateJsonUsingConfigSchemaStrict", (t) => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
tv4.validate(JSON.parse(data), configSchemaStrict),
|
tv4.validate(JSON.parse(data), configSchemaStrict),
|
||||||
file + "\n" + JSON.stringify(tv4.error, null, 2));
|
file + "\n" + JSON.stringify(tv4.error, null, 2));
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test("validateConfigSchemaAllowsUnknownProperties", (t) => {
|
test("validateConfigSchemaAllowsUnknownProperties", (t) => {
|
||||||
|
@ -1043,7 +1045,7 @@ test("validateConfigSchemaAllowsUnknownProperties", (t) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
testCases.forEach((testCase) => {
|
for (const testCase of testCases) {
|
||||||
t.true(
|
t.true(
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
tv4.validate(testCase, configSchema),
|
tv4.validate(testCase, configSchema),
|
||||||
|
@ -1052,7 +1054,7 @@ test("validateConfigSchemaAllowsUnknownProperties", (t) => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
tv4.validate(testCase, configSchemaStrict),
|
tv4.validate(testCase, configSchemaStrict),
|
||||||
"Unknown property allowed when strict: " + JSON.stringify(testCase));
|
"Unknown property allowed when strict: " + JSON.stringify(testCase));
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test("validateConfigSchemaAppliesToUnknownProperties", (t) => {
|
test("validateConfigSchemaAppliesToUnknownProperties", (t) => {
|
||||||
|
@ -1099,20 +1101,23 @@ test("validateConfigExampleJson", async(t) => {
|
||||||
|
|
||||||
test("allBuiltInRulesHaveValidUrl", (t) => {
|
test("allBuiltInRulesHaveValidUrl", (t) => {
|
||||||
t.plan(147);
|
t.plan(147);
|
||||||
rules.forEach(function forRule(rule) {
|
for (const rule of rules) {
|
||||||
|
// @ts-ignore
|
||||||
t.truthy(rule.information);
|
t.truthy(rule.information);
|
||||||
|
// @ts-ignore
|
||||||
t.true(Object.getPrototypeOf(rule.information) === URL.prototype);
|
t.true(Object.getPrototypeOf(rule.information) === URL.prototype);
|
||||||
const name = rule.names[0].toLowerCase();
|
const name = rule.names[0].toLowerCase();
|
||||||
t.is(
|
t.is(
|
||||||
|
// @ts-ignore
|
||||||
rule.information.href,
|
rule.information.href,
|
||||||
`${homepage}/blob/v${version}/doc/Rules.md#${name}`
|
`${homepage}/blob/v${version}/doc/Rules.md#${name}`
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test("someCustomRulesHaveValidUrl", (t) => {
|
test("someCustomRulesHaveValidUrl", (t) => {
|
||||||
t.plan(8);
|
t.plan(8);
|
||||||
customRules.all.forEach(function forRule(rule) {
|
for (const rule of customRules.all) {
|
||||||
t.true(!rule.information ||
|
t.true(!rule.information ||
|
||||||
(Object.getPrototypeOf(rule.information) === URL.prototype));
|
(Object.getPrototypeOf(rule.information) === URL.prototype));
|
||||||
if (rule === customRules.anyBlockquote) {
|
if (rule === customRules.anyBlockquote) {
|
||||||
|
@ -1126,7 +1131,7 @@ test("someCustomRulesHaveValidUrl", (t) => {
|
||||||
`${homepage}/blob/main/test/rules/letters-E-X.js`
|
`${homepage}/blob/main/test/rules/letters-E-X.js`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test.cb("markdownItPluginsSingle", (t) => {
|
test.cb("markdownItPluginsSingle", (t) => {
|
||||||
|
|
|
@ -11,12 +11,12 @@ module.exports = {
|
||||||
),
|
),
|
||||||
"tags": [ "test" ],
|
"tags": [ "test" ],
|
||||||
"function": function rule(params, onError) {
|
"function": function rule(params, onError) {
|
||||||
params.tokens.filter(function filterToken(token) {
|
for (const inline of params.tokens.filter(function filterToken(token) {
|
||||||
return token.type === "inline";
|
return token.type === "inline";
|
||||||
}).forEach(function forToken(inline) {
|
})) {
|
||||||
inline.children.filter(function filterChild(child) {
|
for (const text of inline.children.filter(function filterChild(child) {
|
||||||
return child.type === "text";
|
return child.type === "text";
|
||||||
}).forEach(function forChild(text) {
|
})) {
|
||||||
const index = text.content.toLowerCase().indexOf("ex");
|
const index = text.content.toLowerCase().indexOf("ex");
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
onError({
|
onError({
|
||||||
|
@ -24,7 +24,7 @@ module.exports = {
|
||||||
"context": text.content.substr(index - 1, 4)
|
"context": text.content.substr(index - 1, 4)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -36,14 +36,14 @@ module.exports = {
|
||||||
.then((config) => {
|
.then((config) => {
|
||||||
config = cleanJsdocRulesFromEslintConfig(config);
|
config = cleanJsdocRulesFromEslintConfig(config);
|
||||||
const results = linter.verify(fence.content, config);
|
const results = linter.verify(fence.content, config);
|
||||||
results.forEach((result) => {
|
for (const result of results) {
|
||||||
const lineNumber = fence.lineNumber + result.line;
|
const lineNumber = fence.lineNumber + result.line;
|
||||||
onError({
|
onError({
|
||||||
"lineNumber": lineNumber,
|
"lineNumber": lineNumber,
|
||||||
"detail": result.message,
|
"detail": result.message,
|
||||||
"context": params.lines[lineNumber - 1]
|
"context": params.lines[lineNumber - 1]
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
|
|
|
@ -7,13 +7,13 @@ module.exports = {
|
||||||
"description": "Sample rule",
|
"description": "Sample rule",
|
||||||
"tags": [ "sample" ],
|
"tags": [ "sample" ],
|
||||||
"function": function rule(params, onError) {
|
"function": function rule(params, onError) {
|
||||||
params.tokens.forEach((token) => {
|
for (const token of params.tokens) {
|
||||||
if (token.type === "hr") {
|
if (token.type === "hr") {
|
||||||
onError({
|
onError({
|
||||||
"lineNumber": token.lineNumber,
|
"lineNumber": token.lineNumber,
|
||||||
"detail": "Sample error for hr"
|
"detail": "Sample error for hr"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue