diff --git a/demo/markdownlint-browser.js b/demo/markdownlint-browser.js index 46d33528..821348bf 100644 --- a/demo/markdownlint-browser.js +++ b/demo/markdownlint-browser.js @@ -551,7 +551,7 @@ module.exports.codeBlockAndSpanRanges = function (params, lineMetadata) { // Add code block ranges (excludes fences) forEachLine(lineMetadata, function (line, lineIndex, inCode, onFence) { if (inCode && !onFence) { - exclusions.push(lineIndex, 0, line.length); + exclusions.push([lineIndex, 0, line.length]); } }); // Add code span ranges (excludes ticks) @@ -2326,8 +2326,8 @@ module.exports = { "use strict"; // @ts-check -var _a = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"), addError = _a.addError, forEachLine = _a.forEachLine; -var lineMetadata = __webpack_require__(/*! ./cache */ "../lib/cache.js").lineMetadata; +var _a = __webpack_require__(/*! ../helpers */ "../helpers/helpers.js"), addError = _a.addError, forEachLine = _a.forEachLine, overlapsAnyRange = _a.overlapsAnyRange; +var _b = __webpack_require__(/*! ./cache */ "../lib/cache.js"), codeBlockAndSpanRanges = _b.codeBlockAndSpanRanges, lineMetadata = _b.lineMetadata; var tabRe = /\t+/g; module.exports = { "names": ["MD010", "no-hard-tabs"], @@ -2335,22 +2335,26 @@ module.exports = { "tags": ["whitespace", "hard_tab"], "function": function MD010(params, onError) { var codeBlocks = params.config.code_blocks; - var includeCodeBlocks = (codeBlocks === undefined) ? true : !!codeBlocks; + var includeCode = (codeBlocks === undefined) ? true : !!codeBlocks; var spacesPerTab = params.config.spaces_per_tab; var spaceMultiplier = (spacesPerTab === undefined) ? 1 : Math.max(0, Number(spacesPerTab)); + var exclusions = includeCode ? [] : codeBlockAndSpanRanges(); forEachLine(lineMetadata(), function (line, lineIndex, inCode) { - if (!inCode || includeCodeBlocks) { + if (includeCode || !inCode) { var match = null; while ((match = tabRe.exec(line)) !== null) { - var column = match.index + 1; + var index = match.index; + var column = index + 1; var length = match[0].length; - addError(onError, lineIndex + 1, "Column: " + column, null, [column, length], { - "editColumn": column, - "deleteCount": length, - "insertText": "".padEnd(length * spaceMultiplier) - }); + if (!overlapsAnyRange(exclusions, lineIndex, index, length)) { + addError(onError, lineIndex + 1, "Column: " + column, null, [column, length], { + "editColumn": column, + "deleteCount": length, + "insertText": "".padEnd(length * spaceMultiplier) + }); + } } } }); diff --git a/doc/Rules.md b/doc/Rules.md index 13471b78..7c3bd922 100644 --- a/doc/Rules.md +++ b/doc/Rules.md @@ -424,12 +424,14 @@ Some text * Spaces used to indent the list item instead ``` -You have the option to exclude this rule for code blocks. To do so, set the -`code_blocks` parameter to `false`. Code blocks are included by default since -handling of tabs by tools is often inconsistent (ex: using 4 vs. 8 spaces). +You have the option to exclude this rule for code blocks and spans. To do so, +set the `code_blocks` parameter to `false`. Code blocks and spans are included +by default since handling of tabs by Markdown tools can be inconsistent (e.g., +using 4 vs. 8 spaces). -If you would like the fixer to change tabs to x spaces, then configure the `spaces_per_tab` -parameter to the number x. The default value would be 1. +By default, violations of this rule are fixed by replacing the tab with 1 space +character. To use a different number of spaces, set the `spaces_per_tab` +parameter to the desired value. Rationale: Hard tabs are often rendered inconsistently by different editors and can be harder to work with than spaces. diff --git a/helpers/helpers.js b/helpers/helpers.js index bf48e4c2..c8c4fea7 100644 --- a/helpers/helpers.js +++ b/helpers/helpers.js @@ -555,7 +555,7 @@ module.exports.codeBlockAndSpanRanges = (params, lineMetadata) => { // Add code block ranges (excludes fences) forEachLine(lineMetadata, (line, lineIndex, inCode, onFence) => { if (inCode && !onFence) { - exclusions.push(lineIndex, 0, line.length); + exclusions.push([ lineIndex, 0, line.length ]); } }); // Add code span ranges (excludes ticks) diff --git a/lib/md010.js b/lib/md010.js index de20f6cc..2a359313 100644 --- a/lib/md010.js +++ b/lib/md010.js @@ -2,8 +2,8 @@ "use strict"; -const { addError, forEachLine } = require("../helpers"); -const { lineMetadata } = require("./cache"); +const { addError, forEachLine, overlapsAnyRange } = require("../helpers"); +const { codeBlockAndSpanRanges, lineMetadata } = require("./cache"); const tabRe = /\t+/g; @@ -13,28 +13,33 @@ module.exports = { "tags": [ "whitespace", "hard_tab" ], "function": function MD010(params, onError) { const codeBlocks = params.config.code_blocks; - const includeCodeBlocks = (codeBlocks === undefined) ? true : !!codeBlocks; + const includeCode = (codeBlocks === undefined) ? true : !!codeBlocks; const spacesPerTab = params.config.spaces_per_tab; const spaceMultiplier = (spacesPerTab === undefined) ? 1 : Math.max(0, Number(spacesPerTab)); + const exclusions = includeCode ? [] : codeBlockAndSpanRanges(); forEachLine(lineMetadata(), (line, lineIndex, inCode) => { - if (!inCode || includeCodeBlocks) { + if (includeCode || !inCode) { let match = null; while ((match = tabRe.exec(line)) !== null) { - const column = match.index + 1; + const { index } = match; + const column = index + 1; const length = match[0].length; - addError( - onError, - lineIndex + 1, - "Column: " + column, - null, - [ column, length ], - { - "editColumn": column, - "deleteCount": length, - "insertText": "".padEnd(length * spaceMultiplier) - }); + if (!overlapsAnyRange(exclusions, lineIndex, index, length)) { + addError( + onError, + lineIndex + 1, + "Column: " + column, + null, + [ column, length ], + { + "editColumn": column, + "deleteCount": length, + "insertText": "".padEnd(length * spaceMultiplier) + } + ); + } } } }); diff --git a/test/code-with-tabs-allowed.md b/test/code-with-tabs-allowed.md new file mode 100644 index 00000000..b86f0a36 --- /dev/null +++ b/test/code-with-tabs-allowed.md @@ -0,0 +1,33 @@ +# Code With Tabs Allowed + +Text text {MD010} + +Text `code code` text + +Text ` code` text + +Text `code ` text + +Text `code code +code code +code code` text + + console.log(" "); + +```js +console.log(" "); +``` + +```j s {MD010} +console.log(" "); +``` + + console.log(""); + + diff --git a/test/code-with-tabs-blocked.md b/test/code-with-tabs-blocked.md new file mode 100644 index 00000000..10464557 --- /dev/null +++ b/test/code-with-tabs-blocked.md @@ -0,0 +1,33 @@ +# Code With Tabs Blocked + +Text text {MD010} + +Text `code code` text {MD010} + +Text ` code` text {MD010} + +Text `code ` text {MD010} + +Text `code code +code code {MD010} +code code` text + + console.log(" "); // {MD010} + +```js +console.log(" "); // {MD010} +``` + +```j s {MD010} +console.log(" "); // {MD010} +``` + + console.log(""); // {MD010} + +