mirror of
https://github.com/DavidAnson/markdownlint.git
synced 2025-12-17 06:20:12 +01:00
Add support for disabling/enabling rules within Markdown content (fixes #5).
This commit is contained in:
parent
071bba88fc
commit
31141cc3ed
10 changed files with 192 additions and 42 deletions
30
README.md
30
README.md
|
|
@ -104,6 +104,33 @@ See [Rules.md](doc/Rules.md) for more details.
|
||||||
* **url** - MD034
|
* **url** - MD034
|
||||||
* **whitespace** - MD009, MD010, MD012, MD027, MD028, MD030, MD037, MD038, MD039
|
* **whitespace** - MD009, MD010, MD012, MD027, MD028, MD030, MD037, MD038, MD039
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Rules can be enabled, disabled, and configured via `options.config` (described
|
||||||
|
below) to define the expected behavior for a set of inputs. To enable or disable
|
||||||
|
rules within a file, add one of these markers to the appropriate place (HTML
|
||||||
|
comments don't appear in the final markup):
|
||||||
|
|
||||||
|
* Disable all rules: `<!-- markdownlint-disable -->`
|
||||||
|
* Enable all rules: `<!-- markdownlint-enable -->`
|
||||||
|
* Disable one or more rules: `<!-- markdownlint-disable MD001 MD002 -->`
|
||||||
|
* Enable one or more rules: `<!-- markdownlint-enable MD001 MD002 -->`
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```md
|
||||||
|
<!-- markdownlint-disable MD037 -->
|
||||||
|
deliberate space * in * emphasis
|
||||||
|
<!-- markdownlint-enable MD037 -->
|
||||||
|
```
|
||||||
|
|
||||||
|
Changes take effect starting with the line a comment is on, so the following
|
||||||
|
has no effect:
|
||||||
|
|
||||||
|
```md
|
||||||
|
space * in * emphasis <!-- markdownlint-disable --> <!-- markdownlint-enable -->
|
||||||
|
```
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
Standard asynchronous interface:
|
Standard asynchronous interface:
|
||||||
|
|
@ -209,7 +236,8 @@ rule to `true` or `false` includes/excludes all rules by default. Enabling or
|
||||||
disabling a tag name (ex: `whitespace`) affects all rules having that tag.
|
disabling a tag name (ex: `whitespace`) affects all rules having that tag.
|
||||||
|
|
||||||
The `default` rule is applied first, then keys are processed in order from top
|
The `default` rule is applied first, then keys are processed in order from top
|
||||||
to bottom with later values overriding earlier ones.
|
to bottom with later values overriding earlier ones. Keys (including rule names,
|
||||||
|
tags, and `default`) are not case-sensitive.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
var openFile = document.getElementById("openFile");
|
var openFile = document.getElementById("openFile");
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
var markdownit = window.markdownit();
|
var markdownit = window.markdownit({ "html": true });
|
||||||
var newLineRe = /\r\n|\r|\n/;
|
var newLineRe = /\r\n|\r|\n/;
|
||||||
var rulesMd = "https://github.com/DavidAnson/markdownlint" +
|
var rulesMd = "https://github.com/DavidAnson/markdownlint" +
|
||||||
"/blob/master/doc/Rules.md";
|
"/blob/master/doc/Rules.md";
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,11 @@ var rules = require("./rules");
|
||||||
var shared = require("./shared");
|
var shared = require("./shared");
|
||||||
|
|
||||||
// Mappings from rule to description and tag to rules
|
// Mappings from rule to description and tag to rules
|
||||||
|
var allRuleNames = [];
|
||||||
var ruleToDescription = {};
|
var ruleToDescription = {};
|
||||||
var tagUpperToRules = {};
|
var tagUpperToRules = {};
|
||||||
rules.forEach(function forRule(rule) {
|
rules.forEach(function forRule(rule) {
|
||||||
|
allRuleNames.push(rule.name);
|
||||||
ruleToDescription[rule.name] = rule.desc;
|
ruleToDescription[rule.name] = rule.desc;
|
||||||
// The following is useful for updating README.md
|
// The following is useful for updating README.md
|
||||||
// console.log("* **" + rule.name + "** - " + rule.desc);
|
// console.log("* **" + rule.name + "** - " + rule.desc);
|
||||||
|
|
@ -55,11 +57,11 @@ function uniqueFilterForSorted(value, index, array) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lints a single string
|
// Lints a single string
|
||||||
function lintContent(content, config, frontMatter) {
|
function lintContent(content, config, frontMatter) { // eslint-disable-line
|
||||||
// Remove front matter (if present at beginning of content)
|
// Remove front matter (if present at beginning of content)
|
||||||
var frontMatterLines = 0;
|
var frontMatterLines = 0;
|
||||||
if (frontMatter) {
|
if (frontMatter) {
|
||||||
var frontMatterMatch = frontMatter.exec(content);
|
var frontMatterMatch = content.match(frontMatter);
|
||||||
if (frontMatterMatch && !frontMatterMatch.index) {
|
if (frontMatterMatch && !frontMatterMatch.index) {
|
||||||
var contentMatched = frontMatterMatch[0];
|
var contentMatched = frontMatterMatch[0];
|
||||||
content = content.slice(contentMatched.length);
|
content = content.slice(contentMatched.length);
|
||||||
|
|
@ -93,12 +95,6 @@ function lintContent(content, config, frontMatter) {
|
||||||
}
|
}
|
||||||
tokenLists[token.type].push(token);
|
tokenLists[token.type].push(token);
|
||||||
});
|
});
|
||||||
// Create parameters for rules
|
|
||||||
var params = {
|
|
||||||
"tokens": tokens,
|
|
||||||
"tokenLists": tokenLists,
|
|
||||||
"lines": lines
|
|
||||||
};
|
|
||||||
// Merge rules/tags and sanitize config
|
// Merge rules/tags and sanitize config
|
||||||
var defaultKey = Object.keys(config).filter(function forKey(key) {
|
var defaultKey = Object.keys(config).filter(function forKey(key) {
|
||||||
return key.toUpperCase() === "DEFAULT";
|
return key.toUpperCase() === "DEFAULT";
|
||||||
|
|
@ -126,22 +122,64 @@ function lintContent(content, config, frontMatter) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Run each enabled rule
|
// Create mapping of enabled rules per line
|
||||||
|
var enabledRules = {};
|
||||||
|
rules.forEach(function forRule(rule) {
|
||||||
|
enabledRules[rule.name] = !!mergedRules[rule.name];
|
||||||
|
});
|
||||||
|
function forMatch(match) {
|
||||||
|
var enabled = match[1].toUpperCase() === "EN";
|
||||||
|
var items = match[2] ?
|
||||||
|
match[2].trim().toUpperCase().split(/\s+/) :
|
||||||
|
allRuleNames;
|
||||||
|
items.forEach(function forItem(nameUpper) {
|
||||||
|
if (ruleToDescription[nameUpper]) {
|
||||||
|
enabledRules[nameUpper] = enabled;
|
||||||
|
} else if (tagUpperToRules[nameUpper]) {
|
||||||
|
tagUpperToRules[nameUpper].forEach(function forRule(ruleName) {
|
||||||
|
enabledRules[ruleName] = enabled;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var enabledRulesPerLineNumber = [ null ];
|
||||||
|
lines.forEach(function forLine(line) {
|
||||||
|
var match = shared.inlineCommentRe.exec(line);
|
||||||
|
if (match) {
|
||||||
|
enabledRules = shared.clone(enabledRules);
|
||||||
|
while (match) {
|
||||||
|
forMatch(match);
|
||||||
|
match = shared.inlineCommentRe.exec(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enabledRulesPerLineNumber.push(enabledRules);
|
||||||
|
});
|
||||||
|
// Create parameters for rules
|
||||||
|
var params = {
|
||||||
|
"tokens": tokens,
|
||||||
|
"tokenLists": tokenLists,
|
||||||
|
"lines": lines
|
||||||
|
};
|
||||||
|
// Run each rule
|
||||||
var result = {};
|
var result = {};
|
||||||
rules.forEach(function forRule(rule) {
|
rules.forEach(function forRule(rule) {
|
||||||
if (mergedRules[rule.name]) {
|
// Configure rule
|
||||||
// Configure rule
|
params.options = mergedRules[rule.name];
|
||||||
params.options = mergedRules[rule.name];
|
var errors = [];
|
||||||
var errors = [];
|
rule.func(params, errors);
|
||||||
rule.func(params, errors);
|
// Record any errors (significant performance benefit from length check)
|
||||||
// Record any errors
|
if (errors.length) {
|
||||||
if (errors.length) {
|
errors.sort(numberComparison);
|
||||||
errors.sort(numberComparison);
|
var filteredErrors = errors
|
||||||
result[rule.name] = errors
|
.filter(uniqueFilterForSorted)
|
||||||
.filter(uniqueFilterForSorted)
|
.filter(function removeDisabledRules(lineNumber) {
|
||||||
.map(function adjustLineNumbers(error) {
|
return enabledRulesPerLineNumber[lineNumber][rule.name];
|
||||||
return error + frontMatterLines;
|
})
|
||||||
});
|
.map(function adjustLineNumbers(error) {
|
||||||
|
return error + frontMatterLines;
|
||||||
|
});
|
||||||
|
if (filteredErrors.length) {
|
||||||
|
result[rule.name] = filteredErrors;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
13
lib/rules.js
13
lib/rules.js
|
|
@ -640,12 +640,13 @@ module.exports = [
|
||||||
"desc": "Inline HTML",
|
"desc": "Inline HTML",
|
||||||
"tags": [ "html" ],
|
"tags": [ "html" ],
|
||||||
"func": function MD033(params, errors) {
|
"func": function MD033(params, errors) {
|
||||||
filterTokens(params, "html_block", function forToken(token) {
|
function forToken(token) {
|
||||||
errors.push(token.lineNumber);
|
if (token.content.search(shared.inlineCommentRe) === -1) {
|
||||||
});
|
errors.push(token.lineNumber);
|
||||||
forEachInlineChild(params, "html_inline", function forToken(token) {
|
}
|
||||||
errors.push(token.lineNumber);
|
}
|
||||||
});
|
filterTokens(params, "html_block", forToken);
|
||||||
|
forEachInlineChild(params, "html_inline", forToken);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,5 +6,23 @@ module.exports.newLineRe = /\r\n|\r|\n/;
|
||||||
// Regular expression for matching common front matter
|
// Regular expression for matching common front matter
|
||||||
module.exports.frontMatterRe = /^---$[^]*?^---$(\r\n|\r|\n)/m;
|
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;
|
||||||
|
|
||||||
// readFile options for reading with the UTF-8 encoding
|
// readFile options for reading with the UTF-8 encoding
|
||||||
module.exports.utf8Encoding = { "encoding": "utf8" };
|
module.exports.utf8Encoding = { "encoding": "utf8" };
|
||||||
|
|
||||||
|
// Applies key/value pairs from src to dst, returning dst
|
||||||
|
function assign(dst, src) {
|
||||||
|
Object.keys(src).forEach(function forKey(key) {
|
||||||
|
dst[key] = src[key];
|
||||||
|
});
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
module.exports.assign = assign;
|
||||||
|
|
||||||
|
// Clones the key/value pairs of obj, returning the clone
|
||||||
|
module.exports.clone = function clone(obj) {
|
||||||
|
return assign({}, obj);
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,6 @@
|
||||||
"cpy": "^3.4.0",
|
"cpy": "^3.4.0",
|
||||||
"eslint": "^0.24.1",
|
"eslint": "^0.24.1",
|
||||||
"istanbul": "^0.3.17",
|
"istanbul": "^0.3.17",
|
||||||
"lodash.assign": "^3.2.0",
|
|
||||||
"lodash.clone": "^3.0.2",
|
|
||||||
"nodeunit": "^0.9.1",
|
"nodeunit": "^0.9.1",
|
||||||
"q": "^1.4.0",
|
"q": "^1.4.0",
|
||||||
"rimraf": "^2.4.2",
|
"rimraf": "^2.4.2",
|
||||||
|
|
|
||||||
69
test/inline-disable-enable.md
Normal file
69
test/inline-disable-enable.md
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
# Header
|
||||||
|
|
||||||
|
hard tab {MD010} / space * in * emphasis {MD037} / space ` in ` code {MD038}
|
||||||
|
|
||||||
|
<!-- markdownlint-disable-->
|
||||||
|
|
||||||
|
hard tab / space * in * emphasis / space ` in ` code
|
||||||
|
|
||||||
|
<!--MARKDOWNLINT-ENABLE -->
|
||||||
|
|
||||||
|
hard tab {MD010} / space * in * emphasis {MD037} / space ` in ` code {MD038}
|
||||||
|
|
||||||
|
<!-- markdownlint-disable MD010-->
|
||||||
|
|
||||||
|
hard tab / space * in * emphasis {MD037} / space ` in ` code {MD038}
|
||||||
|
|
||||||
|
<!-- markdownlint-ENABLE MD010 -->
|
||||||
|
|
||||||
|
hard tab {MD010} / space * in * emphasis {MD037} / space ` in ` code {MD038}
|
||||||
|
|
||||||
|
<!-- markdownlint-disable MD010 MD038 -->
|
||||||
|
|
||||||
|
hard tab / space * in * emphasis {MD037} / space ` in ` code
|
||||||
|
|
||||||
|
<!-- MARKDOWNLINT-enable MD010 MD038 -->
|
||||||
|
|
||||||
|
hard tab {MD010} / space * in * emphasis {MD037} / space ` in ` code {MD038}
|
||||||
|
|
||||||
|
before <!-- markdownlint-disable MD010 --> <!-- markdownlint-disable MD038 --> after
|
||||||
|
|
||||||
|
hard tab / space * in * emphasis {MD037} / space ` in ` code
|
||||||
|
|
||||||
|
before<!-- markdownlint-enable MD010 --><!-- markdownlint-enable MD038 -->after
|
||||||
|
|
||||||
|
hard tab {MD010} / space * in * emphasis {MD037} / space ` in ` code {MD038}
|
||||||
|
|
||||||
|
<!-- markdownlint-disable hard_tab code -->
|
||||||
|
|
||||||
|
hard tab / space * in * emphasis {MD037} / space ` in ` code
|
||||||
|
|
||||||
|
<!-- markdownlint-enable whitespace -->
|
||||||
|
|
||||||
|
hard tab {MD010} / space * in * emphasis {MD037} / space ` in ` code {MD038}
|
||||||
|
|
||||||
|
hard tab {MD010} <!-- markdownlint-disable --> <!-- markdownlint-enable -->
|
||||||
|
|
||||||
|
hard tab {MD010} / space * in * emphasis {MD037} / space ` in ` code {MD038}
|
||||||
|
|
||||||
|
hard tab <!-- markdownlint-disable md010 -->
|
||||||
|
<!-- markdownlint-enable md010 -->
|
||||||
|
|
||||||
|
hard tab {MD010} / space * in * emphasis {MD037} / space ` in ` code {MD038}
|
||||||
|
|
||||||
|
<!-- markdownlint-enable -->
|
||||||
|
hard tab {MD010} / space * in * emphasis {MD037} / space ` in ` code {MD038}
|
||||||
|
<!-- markdownlint-disable -->
|
||||||
|
<!-- markdownlint-disable -->
|
||||||
|
hard tab / space * in * emphasis / space ` in ` code
|
||||||
|
<!-- markdownlint-enable -->
|
||||||
|
|
||||||
|
hard tab {MD010} / space * in * emphasis {MD037} / space ` in ` code {MD038}
|
||||||
|
|
||||||
|
<!-- markdownlint-disable NotATag MD038 -->
|
||||||
|
hard tab {MD010} / space * in * emphasis {MD037} / space ` in ` code
|
||||||
|
<!-- markdownlint-enable NotATag MD038 -->
|
||||||
|
|
||||||
|
hard tab {MD010} / space * in * emphasis {MD037} / space ` in ` code {MD038}
|
||||||
|
|
||||||
|
embedded <b>{MD033}</b> HTML
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
{
|
|
||||||
"default": true,
|
|
||||||
"MD003": false
|
|
||||||
}
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
<!-- markdownlint-disable MD003 -->
|
||||||
|
|
||||||
* list
|
* list
|
||||||
* list
|
* list
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@
|
||||||
var fs = require("fs");
|
var fs = require("fs");
|
||||||
var path = require("path");
|
var path = require("path");
|
||||||
var md = require("markdown-it")();
|
var md = require("markdown-it")();
|
||||||
var assign = require("lodash.assign");
|
|
||||||
var clone = require("lodash.clone");
|
|
||||||
var Q = require("q");
|
var Q = require("q");
|
||||||
var markdownlint = require("../lib/markdownlint");
|
var markdownlint = require("../lib/markdownlint");
|
||||||
var shared = require("../lib/shared");
|
var shared = require("../lib/shared");
|
||||||
|
|
@ -26,11 +24,11 @@ function createTestForFile(file) {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function noConfigFile() {
|
function noConfigFile() {
|
||||||
return null;
|
return {};
|
||||||
})
|
})
|
||||||
.then(
|
.then(
|
||||||
function lintWithConfig(config) {
|
function lintWithConfig(config) {
|
||||||
var mergedConfig = assign(clone(defaultConfig), config);
|
var mergedConfig = shared.assign(shared.clone(defaultConfig), config);
|
||||||
return Q.nfcall(markdownlint, {
|
return Q.nfcall(markdownlint, {
|
||||||
"files": [ file ],
|
"files": [ file ],
|
||||||
"config": mergedConfig
|
"config": mergedConfig
|
||||||
|
|
@ -416,7 +414,8 @@ module.exports.enableTag = function enableTag(test) {
|
||||||
],
|
],
|
||||||
"config": {
|
"config": {
|
||||||
"default": false,
|
"default": false,
|
||||||
"spaces": true
|
"spaces": true,
|
||||||
|
"notatag": true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
markdownlint(options, function callback(err, actualResult) {
|
markdownlint(options, function callback(err, actualResult) {
|
||||||
|
|
@ -442,7 +441,8 @@ module.exports.enableTagMixedCase = function enableTagMixedCase(test) {
|
||||||
],
|
],
|
||||||
"config": {
|
"config": {
|
||||||
"DeFaUlT": false,
|
"DeFaUlT": false,
|
||||||
"SpAcEs": true
|
"SpAcEs": true,
|
||||||
|
"NoTaTaG": true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
markdownlint(options, function callback(err, actualResult) {
|
markdownlint(options, function callback(err, actualResult) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue