Add rule aliases, support throughout (fixes #1).

This commit is contained in:
David Anson 2016-01-12 21:29:17 -08:00
parent b7342485d9
commit 9546cc520e
9 changed files with 283 additions and 101 deletions

View file

@ -7,38 +7,46 @@ var shared = require("./shared");
// Mappings from rule to description and tag to rules
var allRuleNames = [];
var ruleToDescription = {};
var tagUpperToRules = {};
var ruleNameToRule = {};
var idUpperToRuleNames = {};
rules.forEach(function forRule(rule) {
allRuleNames.push(rule.name);
ruleToDescription[rule.name] = rule.desc;
ruleNameToRule[rule.name] = rule;
// The following is useful for updating README.md
// console.log("* **" + rule.name + "** - " + rule.desc);
// console.log("* **" + rule.name + "** *" +
// rule.aliases.join(", ") + "* - " + rule.desc);
rule.tags.forEach(function forTag(tag) {
var tagUpper = tag.toUpperCase();
var tags = tagUpperToRules[tagUpper] || [];
tags.push(rule.name);
tagUpperToRules[tagUpper] = tags;
var ruleNames = idUpperToRuleNames[tagUpper] || [];
ruleNames.push(rule.name);
idUpperToRuleNames[tagUpper] = ruleNames;
});
rule.aliases.forEach(function forAlias(alias) {
var aliasUpper = alias.toUpperCase();
idUpperToRuleNames[aliasUpper] = [ rule.name ];
});
});
// The following is useful for updating README.md
// Object.keys(tagToRules).sort().forEach(function forTag(tag) {
// console.log("* **" + tag + "** - " + tagToRules[tag].join(", "));
// Object.keys(idUpperToRuleNames).sort().forEach(function forTag(tag) {
// console.log("* **" + tag + "** - " + idUpperToRuleNames[tag].join(", "));
// });
// Class for results with toString for pretty display
function Results() { }
Results.prototype.toString = function resultsToString() {
Results.prototype.toString = function resultsToString(useAlias) {
var that = this;
var results = [];
Object.keys(that).forEach(function forFile(file) {
var fileResults = that[file];
Object.keys(fileResults).forEach(function forRule(rule) {
var ruleResults = fileResults[rule];
Object.keys(fileResults).forEach(function forRule(ruleName) {
var rule = ruleNameToRule[ruleName];
var ruleResults = fileResults[ruleName];
ruleResults.forEach(function forLine(lineNumber) {
var result =
file + ": " + lineNumber + ": " +
rule + " " + ruleToDescription[rule];
file + ": " +
lineNumber + ": " +
(useAlias ? rule.aliases[0] : rule.name) + " " +
rule.desc;
results.push(result);
});
});
@ -114,10 +122,10 @@ function lintContent(content, config, frontMatter) { // eslint-disable-line
value = false;
}
var keyUpper = key.toUpperCase();
if (ruleToDescription[keyUpper]) {
if (ruleNameToRule[keyUpper]) {
mergedRules[keyUpper] = value;
} else if (tagUpperToRules[keyUpper]) {
tagUpperToRules[keyUpper].forEach(function forRule(ruleName) {
} else if (idUpperToRuleNames[keyUpper]) {
idUpperToRuleNames[keyUpper].forEach(function forRule(ruleName) {
mergedRules[ruleName] = value;
});
}
@ -133,10 +141,10 @@ function lintContent(content, config, frontMatter) { // eslint-disable-line
match[2].trim().toUpperCase().split(/\s+/) :
allRuleNames;
items.forEach(function forItem(nameUpper) {
if (ruleToDescription[nameUpper]) {
if (ruleNameToRule[nameUpper]) {
enabledRules[nameUpper] = enabled;
} else if (tagUpperToRules[nameUpper]) {
tagUpperToRules[nameUpper].forEach(function forRule(ruleName) {
} else if (idUpperToRuleNames[nameUpper]) {
idUpperToRuleNames[nameUpper].forEach(function forRule(ruleName) {
enabledRules[ruleName] = enabled;
});
}

View file

@ -153,6 +153,7 @@ module.exports = [
"name": "MD001",
"desc": "Header levels should only increment by one level at a time",
"tags": [ "headers" ],
"aliases": [ "header-increment" ],
"func": function MD001(params, errors) {
var prevLevel = 0;
filterTokens(params, "heading_open", function forToken(token) {
@ -169,6 +170,7 @@ module.exports = [
"name": "MD002",
"desc": "First header should be a h1 header",
"tags": [ "headers" ],
"aliases": [ "first-header-h1" ],
"func": function MD002(params, errors) {
params.tokens.every(function forToken(token) {
if (token.type === "heading_open") {
@ -186,6 +188,7 @@ module.exports = [
"name": "MD003",
"desc": "Header style",
"tags": [ "headers" ],
"aliases": [ "header-style" ],
"func": function MD003(params, errors) {
var style = params.options.style || "consistent";
filterTokens(params, "heading_open", function forToken(token) {
@ -207,6 +210,7 @@ module.exports = [
"name": "MD004",
"desc": "Unordered list style",
"tags": [ "bullet", "ul" ],
"aliases": [ "ul-style" ],
"func": function MD004(params, errors) {
var style = params.options.style || "consistent";
flattenLists(params).forEach(function forList(list) {
@ -228,6 +232,7 @@ module.exports = [
"name": "MD005",
"desc": "Inconsistent indentation for list items at the same level",
"tags": [ "bullet", "ul", "indentation" ],
"aliases": [ "list-indent" ],
"func": function MD005(params, errors) {
flattenLists(params).forEach(function forList(list) {
var indent = indentFor(list.items[0]);
@ -244,6 +249,7 @@ module.exports = [
"name": "MD006",
"desc": "Consider starting bulleted lists at the beginning of the line",
"tags": [ "bullet", "ul", "indentation" ],
"aliases": [ "ul-start-left" ],
"func": function MD006(params, errors) {
flattenLists(params).forEach(function forList(list) {
if (!list.ordered && !list.nesting && indentFor(list.open)) {
@ -257,6 +263,7 @@ module.exports = [
"name": "MD007",
"desc": "Unordered list indentation",
"tags": [ "bullet", "ul", "indentation" ],
"aliases": [ "ul-indent" ],
"func": function MD007(params, errors) {
var optionsIndent = params.options.indent || 2;
var prevIndent = 0;
@ -277,6 +284,7 @@ module.exports = [
"name": "MD009",
"desc": "Trailing spaces",
"tags": [ "whitespace" ],
"aliases": [ "no-trailing-spaces" ],
"func": function MD009(params, errors) {
var brSpaces = params.options.br_spaces || 0;
params.lines.forEach(function forLine(line, lineIndex) {
@ -293,6 +301,7 @@ module.exports = [
"name": "MD010",
"desc": "Hard tabs",
"tags": [ "whitespace", "hard_tab" ],
"aliases": [ "no-hard-tabs" ],
"func": function MD010(params, errors) {
params.lines.forEach(function forLine(line, lineIndex) {
if (/\t/.test(line)) {
@ -306,6 +315,7 @@ module.exports = [
"name": "MD011",
"desc": "Reversed link syntax",
"tags": [ "links" ],
"aliases": [ "no-reversed-links" ],
"func": function MD011(params, errors) {
forEachInlineChild(params, "text", function forToken(token) {
if (/\([^)]+\)\[[^\]]+\]/.test(token.content)) {
@ -319,6 +329,7 @@ module.exports = [
"name": "MD012",
"desc": "Multiple consecutive blank lines",
"tags": [ "whitespace", "blank_lines" ],
"aliases": [ "no-multiple-blanks" ],
"func": function MD012(params, errors) {
var prevLine = "-";
forEachLine(params, function forLine(line, lineIndex, inCode) {
@ -335,6 +346,7 @@ module.exports = [
"name": "MD013",
"desc": "Line length",
"tags": [ "line_length" ],
"aliases": [ "line-length" ],
"func": function MD013(params, errors) {
var lineLength = params.options.line_length || 80;
var codeBlocks = params.options.code_blocks;
@ -357,6 +369,7 @@ module.exports = [
"name": "MD014",
"desc": "Dollar signs used before commands without showing output",
"tags": [ "code" ],
"aliases": [ "commands-show-output" ],
"func": function MD014(params, errors) {
[ "code_block", "fence" ].forEach(function forType(type) {
filterTokens(params, type, function forToken(token) {
@ -376,6 +389,7 @@ module.exports = [
"name": "MD018",
"desc": "No space after hash on atx style header",
"tags": [ "headers", "atx", "spaces" ],
"aliases": [ "no-missing-space-atx" ],
"func": function MD018(params, errors) {
forEachLine(params, function forLine(line, lineIndex, inCode) {
if (!inCode && /^#+[^#\s]/.test(line) && !/#$/.test(line)) {
@ -389,6 +403,7 @@ module.exports = [
"name": "MD019",
"desc": "Multiple spaces after hash on atx style header",
"tags": [ "headers", "atx", "spaces" ],
"aliases": [ "no-multiple-space-atx" ],
"func": function MD019(params, errors) {
filterTokens(params, "heading_open", function forToken(token) {
if ((headingStyleFor(token) === "atx") &&
@ -403,6 +418,7 @@ module.exports = [
"name": "MD020",
"desc": "No space inside hashes on closed atx style header",
"tags": [ "headers", "atx_closed", "spaces" ],
"aliases": [ "no-missing-space-closed-atx" ],
"func": function MD020(params, errors) {
forEachLine(params, function forLine(line, lineIndex, inCode) {
if (!inCode && /^#+[^#]*[^\\]#+$/.test(line) &&
@ -417,6 +433,7 @@ module.exports = [
"name": "MD021",
"desc": "Multiple spaces inside hashes on closed atx style header",
"tags": [ "headers", "atx_closed", "spaces" ],
"aliases": [ "no-multiple-space-closed-atx" ],
"func": function MD021(params, errors) {
filterTokens(params, "heading_open", function forToken(token) {
if ((headingStyleFor(token) === "atx_closed") &&
@ -431,6 +448,7 @@ module.exports = [
"name": "MD022",
"desc": "Headers should be surrounded by blank lines",
"tags": [ "headers", "blank_lines" ],
"aliases": [ "blanks-around-headers" ],
"func": function MD022(params, errors) {
var prevHeadingLineNumber = 0;
var prevMaxLineIndex = -1;
@ -471,6 +489,7 @@ module.exports = [
"name": "MD023",
"desc": "Headers must start at the beginning of the line",
"tags": [ "headers", "spaces" ],
"aliases": [ "header-start-left" ],
"func": function MD023(params, errors) {
filterTokens(params, "heading_open", function forToken(token) {
if (/^\s/.test(token.line)) {
@ -484,6 +503,7 @@ module.exports = [
"name": "MD024",
"desc": "Multiple headers with the same content",
"tags": [ "headers" ],
"aliases": [ "no-duplicate-header" ],
"func": function MD024(params, errors) {
var knownContent = [];
forEachHeading(params, function forHeading(heading, content) {
@ -500,6 +520,7 @@ module.exports = [
"name": "MD025",
"desc": "Multiple top level headers in the same document",
"tags": [ "headers" ],
"aliases": [ "single-h1" ],
"func": function MD025(params, errors) {
var hasTopLevelHeading = false;
filterTokens(params, "heading_open", function forToken(token) {
@ -518,6 +539,7 @@ module.exports = [
"name": "MD026",
"desc": "Trailing punctuation in header",
"tags": [ "headers" ],
"aliases": [ "no-trailing-punctuation" ],
"func": function MD026(params, errors) {
var punctuation = params.options.punctuation || ".,;:!?";
var re = new RegExp("[" + punctuation + "]$");
@ -533,6 +555,7 @@ module.exports = [
"name": "MD027",
"desc": "Multiple spaces after blockquote symbol",
"tags": [ "blockquote", "whitespace", "indentation" ],
"aliases": [ "no-multiple-space-blockquote" ],
"func": function MD027(params, errors) {
var inBlockquote = false;
params.tokens.forEach(function forToken(token) {
@ -557,6 +580,7 @@ module.exports = [
"name": "MD028",
"desc": "Blank line inside blockquote",
"tags": [ "blockquote", "whitespace" ],
"aliases": [ "no-blanks-blockquote" ],
"func": function MD028(params, errors) {
var prevToken = {};
params.tokens.forEach(function forToken(token) {
@ -573,6 +597,7 @@ module.exports = [
"name": "MD029",
"desc": "Ordered list item prefix",
"tags": [ "ol" ],
"aliases": [ "ol-prefix" ],
"func": function MD029(params, errors) {
var style = params.options.style || "one";
flattenLists(params).forEach(function forList(list) {
@ -596,6 +621,7 @@ module.exports = [
"name": "MD030",
"desc": "Spaces after list markers",
"tags": [ "ol", "ul", "whitespace" ],
"aliases": [ "list-marker-space" ],
"func": function MD030(params, errors) {
var ulSingle = params.options.ul_single || 1;
var olSingle = params.options.ol_single || 1;
@ -621,6 +647,7 @@ module.exports = [
"name": "MD031",
"desc": "Fenced code blocks should be surrounded by blank lines",
"tags": [ "code", "blank_lines" ],
"aliases": [ "blanks-around-fences" ],
"func": function MD031(params, errors) {
var lines = params.lines;
forEachLine(params, function forLine(line, i, inCode, onFence) {
@ -636,6 +663,7 @@ module.exports = [
"name": "MD032",
"desc": "Lists should be surrounded by blank lines",
"tags": [ "bullet", "ul", "ol", "blank_lines" ],
"aliases": [ "blanks-around-lists" ],
"func": function MD032(params, errors) {
var inList = false;
var prevLine = "";
@ -658,6 +686,7 @@ module.exports = [
"name": "MD033",
"desc": "Inline HTML",
"tags": [ "html" ],
"aliases": [ "no-inline-html" ],
"func": function MD033(params, errors) {
var allowedElements = (params.options.allowed_elements || [])
.map(function forElement(element) {
@ -690,6 +719,7 @@ module.exports = [
"name": "MD034",
"desc": "Bare URL used",
"tags": [ "links", "url" ],
"aliases": [ "no-bare-urls" ],
"func": function MD034(params, errors) {
filterTokens(params, "inline", function forToken(token) {
var inLink = false;
@ -712,6 +742,7 @@ module.exports = [
"name": "MD035",
"desc": "Horizontal rule style",
"tags": [ "hr" ],
"aliases": [ "hr-style" ],
"func": function MD035(params, errors) {
var style = params.options.style || "consistent";
filterTokens(params, "hr", function forToken(token) {
@ -729,6 +760,7 @@ module.exports = [
"name": "MD036",
"desc": "Emphasis used instead of a header",
"tags": [ "headers", "emphasis" ],
"aliases": [ "no-emphasis-as-header" ],
"func": function MD036(params, errors) {
function base(token) {
if (token.type === "paragraph_open") {
@ -760,6 +792,7 @@ module.exports = [
"name": "MD037",
"desc": "Spaces inside emphasis markers",
"tags": [ "whitespace", "emphasis" ],
"aliases": [ "no-space-in-emphasis" ],
"func": function MD037(params, errors) {
forEachInlineChild(params, "text", function forToken(token) {
if (/\s(\*\*?|__?)\s.+\1/.test(token.content) ||
@ -774,6 +807,7 @@ module.exports = [
"name": "MD038",
"desc": "Spaces inside code span elements",
"tags": [ "whitespace", "code" ],
"aliases": [ "no-space-in-code" ],
"func": function MD038(params, errors) {
forEachInlineChild(params, "code_inline",
function forToken(token, inline) {
@ -788,6 +822,7 @@ module.exports = [
"name": "MD039",
"desc": "Spaces inside link text",
"tags": [ "whitespace", "links" ],
"aliases": [ "no-space-in-links" ],
"func": function MD039(params, errors) {
filterTokens(params, "inline", function forToken(token) {
var inLink = false;
@ -821,6 +856,7 @@ module.exports = [
"name": "MD040",
"desc": "Fenced code blocks should have a language specified",
"tags": [ "code", "language" ],
"aliases": [ "fenced-code-language" ],
"func": function MD040(params, errors) {
filterTokens(params, "fence", function forToken(token) {
if (!token.info.trim()) {
@ -834,6 +870,7 @@ module.exports = [
"name": "MD041",
"desc": "First line in file should be a top level header",
"tags": [ "headers" ],
"aliases": [ "first-line-h1" ],
"func": function MD041(params, errors) {
var firstHeader = null;
params.tokens.every(function forToken(token) {

View file

@ -8,7 +8,7 @@ module.exports.frontMatterRe = /^---$[^]*?^---$(\r\n|\r|\n)/m;
// Regular expression for matching inline disable/enable comments
module.exports.inlineCommentRe =
/<!--\s*markdownlint-(dis|en)able((?:\s+[a-z0-9_]+)*)\s*-->/ig;
/<!--\s*markdownlint-(dis|en)able((?:\s+[a-z0-9_\-]+)*)\s*-->/ig;
// readFile options for reading with the UTF-8 encoding
module.exports.utf8Encoding = { "encoding": "utf8" };