diff --git a/lib/markdownlint.js b/lib/markdownlint.js index 28647194..33ae82f7 100644 --- a/lib/markdownlint.js +++ b/lib/markdownlint.js @@ -296,6 +296,11 @@ function lineNumberComparison(a, b) { return a.lineNumber - b.lineNumber; } +// Function to return true for all inputs +function filterAllValues() { + return true; +} + // Function to return unique values from a sorted errors array function uniqueFilterForSortedErrors(value, index, array) { return (index === 0) || (value.lineNumber > array[index - 1].lineNumber); @@ -402,7 +407,9 @@ function lintContent( if (errors.length) { errors.sort(lineNumberComparison); const filteredErrors = errors - .filter(uniqueFilterForSortedErrors) + .filter((resultVersion === 3) ? + filterAllValues : + uniqueFilterForSortedErrors) .filter(function removeDisabledRules(error) { return enabledRulesPerLineNumber[error.lineNumber][ruleName]; }) diff --git a/lib/md010.js b/lib/md010.js index 55fd1ce8..e1bf1a6e 100644 --- a/lib/md010.js +++ b/lib/md010.js @@ -2,10 +2,10 @@ "use strict"; -const { addError, forEachLine, rangeFromRegExp } = require("../helpers"); +const { addError, forEachLine } = require("../helpers"); const { lineMetadata } = require("./cache"); -const tabRe = /\t+/; +const tabRe = /\t+/g; module.exports = { "names": [ "MD010", "no-hard-tabs" ], @@ -15,9 +15,17 @@ module.exports = { const codeBlocks = params.config.code_blocks; const includeCodeBlocks = (codeBlocks === undefined) ? true : !!codeBlocks; forEachLine(lineMetadata(), (line, lineIndex, inCode) => { - if (tabRe.test(line) && (!inCode || includeCodeBlocks)) { - addError(onError, lineIndex + 1, "Column: " + (line.indexOf("\t") + 1), - null, rangeFromRegExp(line, tabRe)); + if (!inCode || includeCodeBlocks) { + let match = null; + while ((match = tabRe.exec(line)) !== null) { + const column = match.index + 1; + addError( + onError, + lineIndex + 1, + "Column: " + column, + null, + [ column, match[0].length ]); + } } }); } diff --git a/test/markdownlint-test.js b/test/markdownlint-test.js index bac9f388..b19c5d72 100644 --- a/test/markdownlint-test.js +++ b/test/markdownlint-test.js @@ -67,7 +67,9 @@ function createTestForFile(file) { result2or3.forEach(function forResult(result) { const ruleName = result.ruleNames[0]; const lineNumbers = result0[ruleName] || []; - lineNumbers.push(result.lineNumber); + if (!lineNumbers.includes(result.lineNumber)) { + lineNumbers.push(result.lineNumber); + } result0[ruleName] = lineNumbers; }); return [ result0, result2or3 ]; @@ -523,6 +525,122 @@ module.exports.resultFormattingV3 = function resultFormattingV3(test) { }); }; +module.exports.onePerLineResultVersion0 = + function onePerLineResultVersion0(test) { + test.expect(2); + const options = { + "strings": { + "input": "# Heading\theading\t\theading\n" + }, + "resultVersion": 0 + }; + markdownlint(options, function callback(err, actualResult) { + test.ifError(err); + const expectedResult = { + "input": { + "MD010": [ 1 ] + } + }; + test.deepEqual(actualResult, expectedResult, "Undetected issues."); + test.done(); + }); + }; + +module.exports.onePerLineResultVersion1 = + function onePerLineResultVersion1(test) { + test.expect(2); + const options = { + "strings": { + "input": "# Heading\theading\t\theading\n" + }, + "resultVersion": 1 + }; + markdownlint(options, function callback(err, actualResult) { + test.ifError(err); + const expectedResult = { + "input": [ + { "lineNumber": 1, + "ruleName": "MD010", + "ruleAlias": "no-hard-tabs", + "ruleDescription": "Hard tabs", + "ruleInformation": + `${homepage}/blob/v${version}/doc/Rules.md#md010`, + "errorDetail": "Column: 10", + "errorContext": null, + "errorRange": [ 10, 1 ] } + ] + }; + test.deepEqual(actualResult, expectedResult, "Undetected issues."); + test.done(); + }); + }; + +module.exports.onePerLineResultVersion2 = + function onePerLineResultVersion2(test) { + test.expect(2); + const options = { + "strings": { + "input": "# Heading\theading\t\theading\n" + }, + "resultVersion": 2 + }; + markdownlint(options, function callback(err, actualResult) { + test.ifError(err); + const expectedResult = { + "input": [ + { "lineNumber": 1, + "ruleNames": [ "MD010", "no-hard-tabs" ], + "ruleDescription": "Hard tabs", + "ruleInformation": + `${homepage}/blob/v${version}/doc/Rules.md#md010`, + "errorDetail": "Column: 10", + "errorContext": null, + "errorRange": [ 10, 1 ] } + ] + }; + test.deepEqual(actualResult, expectedResult, "Undetected issues."); + test.done(); + }); + }; + +module.exports.manyPerLineResultVersion3 = + function manyPerLineResultVersion3(test) { + test.expect(2); + const options = { + "strings": { + "input": "# Heading\theading\t\theading\n" + }, + "resultVersion": 3 + }; + markdownlint(options, function callback(err, actualResult) { + test.ifError(err); + const expectedResult = { + "input": [ + { "lineNumber": 1, + "ruleNames": [ "MD010", "no-hard-tabs" ], + "ruleDescription": "Hard tabs", + "ruleInformation": + `${homepage}/blob/v${version}/doc/Rules.md#md010`, + "errorDetail": "Column: 10", + "errorContext": null, + "errorRange": [ 10, 1 ], + "fixInfo": null }, + { "lineNumber": 1, + "ruleNames": [ "MD010", "no-hard-tabs" ], + "ruleDescription": "Hard tabs", + "ruleInformation": + `${homepage}/blob/v${version}/doc/Rules.md#md010`, + "errorDetail": "Column: 18", + "errorContext": null, + "errorRange": [ 18, 2 ], + "fixInfo": null } + ] + }; + test.deepEqual(actualResult, expectedResult, "Undetected issues."); + test.done(); + }); + }; + module.exports.stringInputLineEndings = function stringInputLineEndings(test) { test.expect(2); const options = {