diff --git a/demo/markdownlint-browser.js b/demo/markdownlint-browser.js index 471f04e7..8b3f66fe 100644 --- a/demo/markdownlint-browser.js +++ b/demo/markdownlint-browser.js @@ -927,28 +927,34 @@ module.exports.applyFixes = applyFixes; * @param {number} lineIndex Line index to check. * @param {string} search Text to search for. * @param {string} replace Text to replace with. + * @param {number} [instance] Instance on the line (1-based). * @returns {Object} Range and fixInfo wrapper. */ -function getRangeAndFixInfoIfFound(lines, lineIndex, search, replace) { - var range = null; - var fixInfo = null; - var searchIndex = lines[lineIndex].indexOf(search); - if (searchIndex !== -1) { - var column = searchIndex + 1; - var length = search.length; - range = [column, length]; - fixInfo = { - "editColumn": column, - "deleteCount": length, - "insertText": replace +module.exports.getRangeAndFixInfoIfFound = + function (lines, lineIndex, search, replace, instance) { + if (instance === void 0) { instance = 1; } + var range = null; + var fixInfo = null; + var searchIndex = -1; + while (instance > 0) { + searchIndex = lines[lineIndex].indexOf(search, searchIndex + 1); + instance--; + } + if (searchIndex !== -1) { + var column = searchIndex + 1; + var length = search.length; + range = [column, length]; + fixInfo = { + "editColumn": column, + "deleteCount": length, + "insertText": replace + }; + } + return { + range: range, + fixInfo: fixInfo }; - } - return { - range: range, - fixInfo: fixInfo }; -} -module.exports.getRangeAndFixInfoIfFound = getRangeAndFixInfoIfFound; /** * Gets the next (subsequent) child token if it is of the expected type. * @@ -4411,6 +4417,8 @@ module.exports = { "tags": ["emphasis"], "function": function MD049(params, onError) { var expectedStyle = String(params.config.style || "consistent"); + var lastLineNumber = -1; + var instances = new Map(); forEachInlineChild(params, "em_open", function (token, parent) { var lineNumber = token.lineNumber, markup = token.markup; var markupStyle = emphasisOrStrongStyleFor(markup); @@ -4425,7 +4433,12 @@ module.exports = { var actual = "".concat(markup).concat(content).concat(markup); var expectedMarkup = (expectedStyle === "asterisk") ? "*" : "_"; var expected = "".concat(expectedMarkup).concat(content).concat(expectedMarkup); - rangeAndFixInfo = getRangeAndFixInfoIfFound(params.lines, lineNumber - 1, actual, expected); + if (lastLineNumber !== lineNumber) { + lastLineNumber = lineNumber; + instances.clear(); + } + instances.set(expected, (instances.get(expected) || 0) + 1); + rangeAndFixInfo = getRangeAndFixInfoIfFound(params.lines, lineNumber - 1, actual, expected, instances.get(expected)); } addError(onError, lineNumber, "Expected: ".concat(expectedStyle, "; Actual: ").concat(markupStyle), null, rangeAndFixInfo.range, rangeAndFixInfo.fixInfo); } @@ -4452,6 +4465,8 @@ module.exports = { "tags": ["emphasis"], "function": function MD050(params, onError) { var expectedStyle = String(params.config.style || "consistent"); + var lastLineNumber = -1; + var instances = new Map(); forEachInlineChild(params, "strong_open", function (token, parent) { var lineNumber = token.lineNumber, markup = token.markup; var markupStyle = emphasisOrStrongStyleFor(markup); @@ -4466,7 +4481,12 @@ module.exports = { var actual = "".concat(markup).concat(content).concat(markup); var expectedMarkup = (expectedStyle === "asterisk") ? "**" : "__"; var expected = "".concat(expectedMarkup).concat(content).concat(expectedMarkup); - rangeAndFixInfo = getRangeAndFixInfoIfFound(params.lines, lineNumber - 1, actual, expected); + if (lastLineNumber !== lineNumber) { + lastLineNumber = lineNumber; + instances.clear(); + } + instances.set(expected, (instances.get(expected) || 0) + 1); + rangeAndFixInfo = getRangeAndFixInfoIfFound(params.lines, lineNumber - 1, actual, expected, instances.get(expected)); } addError(onError, lineNumber, "Expected: ".concat(expectedStyle, "; Actual: ").concat(markupStyle), null, rangeAndFixInfo.range, rangeAndFixInfo.fixInfo); } diff --git a/helpers/helpers.js b/helpers/helpers.js index 95d508d6..9bd7ccde 100644 --- a/helpers/helpers.js +++ b/helpers/helpers.js @@ -950,28 +950,33 @@ module.exports.applyFixes = applyFixes; * @param {number} lineIndex Line index to check. * @param {string} search Text to search for. * @param {string} replace Text to replace with. + * @param {number} [instance] Instance on the line (1-based). * @returns {Object} Range and fixInfo wrapper. */ -function getRangeAndFixInfoIfFound(lines, lineIndex, search, replace) { - let range = null; - let fixInfo = null; - const searchIndex = lines[lineIndex].indexOf(search); - if (searchIndex !== -1) { - const column = searchIndex + 1; - const length = search.length; - range = [ column, length ]; - fixInfo = { - "editColumn": column, - "deleteCount": length, - "insertText": replace +module.exports.getRangeAndFixInfoIfFound = + (lines, lineIndex, search, replace, instance = 1) => { + let range = null; + let fixInfo = null; + let searchIndex = -1; + while (instance > 0) { + searchIndex = lines[lineIndex].indexOf(search, searchIndex + 1); + instance--; + } + if (searchIndex !== -1) { + const column = searchIndex + 1; + const length = search.length; + range = [ column, length ]; + fixInfo = { + "editColumn": column, + "deleteCount": length, + "insertText": replace + }; + } + return { + range, + fixInfo }; - } - return { - range, - fixInfo }; -} -module.exports.getRangeAndFixInfoIfFound = getRangeAndFixInfoIfFound; /** * Gets the next (subsequent) child token if it is of the expected type. diff --git a/lib/md049.js b/lib/md049.js index 4d36df55..74aaf809 100644 --- a/lib/md049.js +++ b/lib/md049.js @@ -11,6 +11,8 @@ module.exports = { "tags": [ "emphasis" ], "function": function MD049(params, onError) { let expectedStyle = String(params.config.style || "consistent"); + let lastLineNumber = -1; + const instances = new Map(); forEachInlineChild(params, "em_open", (token, parent) => { const { lineNumber, markup } = token; const markupStyle = emphasisOrStrongStyleFor(markup); @@ -27,8 +29,17 @@ module.exports = { const actual = `${markup}${content}${markup}`; const expectedMarkup = (expectedStyle === "asterisk") ? "*" : "_"; const expected = `${expectedMarkup}${content}${expectedMarkup}`; + if (lastLineNumber !== lineNumber) { + lastLineNumber = lineNumber; + instances.clear(); + } + instances.set(expected, (instances.get(expected) || 0) + 1); rangeAndFixInfo = getRangeAndFixInfoIfFound( - params.lines, lineNumber - 1, actual, expected + params.lines, + lineNumber - 1, + actual, + expected, + instances.get(expected) ); } addError( diff --git a/lib/md050.js b/lib/md050.js index 2ca9260e..28c53f91 100644 --- a/lib/md050.js +++ b/lib/md050.js @@ -11,6 +11,8 @@ module.exports = { "tags": [ "emphasis" ], "function": function MD050(params, onError) { let expectedStyle = String(params.config.style || "consistent"); + let lastLineNumber = -1; + const instances = new Map(); forEachInlineChild(params, "strong_open", (token, parent) => { const { lineNumber, markup } = token; const markupStyle = emphasisOrStrongStyleFor(markup); @@ -27,8 +29,17 @@ module.exports = { const actual = `${markup}${content}${markup}`; const expectedMarkup = (expectedStyle === "asterisk") ? "**" : "__"; const expected = `${expectedMarkup}${content}${expectedMarkup}`; + if (lastLineNumber !== lineNumber) { + lastLineNumber = lineNumber; + instances.clear(); + } + instances.set(expected, (instances.get(expected) || 0) + 1); rangeAndFixInfo = getRangeAndFixInfoIfFound( - params.lines, lineNumber - 1, actual, expected + params.lines, + lineNumber - 1, + actual, + expected, + instances.get(expected) ); } addError( diff --git a/test/detailed-results-MD041-MD050.json b/test/detailed-results-MD041-MD050.json index 1016951d..606024a6 100644 --- a/test/detailed-results-MD041-MD050.json +++ b/test/detailed-results-MD041-MD050.json @@ -1,5 +1,6 @@ { "default": true, + "MD013": false, "MD043": { "headings": [ "# Heading" diff --git a/test/detailed-results-MD041-MD050.md b/test/detailed-results-MD041-MD050.md index d4b6fd0b..6c8cac05 100644 --- a/test/detailed-results-MD041-MD050.md +++ b/test/detailed-results-MD041-MD050.md @@ -42,4 +42,8 @@ strong **emphasis spanning** many lines +Inconsistent _double_ text _interleaved_ text _double_ _interleaved_ emphasis. + +Inconsistent **double** text **interleaved** text **double** **interleaved** strong emphasis. + Missing newline character \ No newline at end of file diff --git a/test/detailed-results-MD041-MD050.md.fixed b/test/detailed-results-MD041-MD050.md.fixed index a26adc9b..056612f1 100644 --- a/test/detailed-results-MD041-MD050.md.fixed +++ b/test/detailed-results-MD041-MD050.md.fixed @@ -42,4 +42,8 @@ strong **emphasis spanning** many lines +Inconsistent *double* text *interleaved* text *double* *interleaved* emphasis. + +Inconsistent __double__ text __interleaved__ text __double__ __interleaved__ strong emphasis. + Missing newline character diff --git a/test/detailed-results-MD041-MD050.results.json b/test/detailed-results-MD041-MD050.results.json index e4c35d34..eb8f6e2e 100644 --- a/test/detailed-results-MD041-MD050.results.json +++ b/test/detailed-results-MD041-MD050.results.json @@ -78,7 +78,7 @@ "fixInfo": null }, { - "lineNumber": 45, + "lineNumber": 49, "ruleNames": [ "MD043", "required-headings", @@ -178,7 +178,7 @@ "fixInfo": null }, { - "lineNumber": 45, + "lineNumber": 49, "ruleNames": [ "MD047", "single-trailing-newline" @@ -262,6 +262,86 @@ "emphasis-style" ] }, + { + "errorContext": null, + "errorDetail": "Expected: asterisk; Actual: underscore", + "errorRange": [ + 14, + 8 + ], + "fixInfo": { + "deleteCount": 8, + "editColumn": 14, + "insertText": "*double*" + }, + "lineNumber": 45, + "ruleDescription": "Emphasis style should be consistent", + "ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md049", + "ruleNames": [ + "MD049", + "emphasis-style" + ] + }, + { + "errorContext": null, + "errorDetail": "Expected: asterisk; Actual: underscore", + "errorRange": [ + 28, + 13 + ], + "fixInfo": { + "deleteCount": 13, + "editColumn": 28, + "insertText": "*interleaved*" + }, + "lineNumber": 45, + "ruleDescription": "Emphasis style should be consistent", + "ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md049", + "ruleNames": [ + "MD049", + "emphasis-style" + ] + }, + { + "errorContext": null, + "errorDetail": "Expected: asterisk; Actual: underscore", + "errorRange": [ + 47, + 8 + ], + "fixInfo": { + "deleteCount": 8, + "editColumn": 47, + "insertText": "*double*" + }, + "lineNumber": 45, + "ruleDescription": "Emphasis style should be consistent", + "ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md049", + "ruleNames": [ + "MD049", + "emphasis-style" + ] + }, + { + "errorContext": null, + "errorDetail": "Expected: asterisk; Actual: underscore", + "errorRange": [ + 56, + 13 + ], + "fixInfo": { + "deleteCount": 13, + "editColumn": 56, + "insertText": "*interleaved*" + }, + "lineNumber": 45, + "ruleDescription": "Emphasis style should be consistent", + "ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md049", + "ruleNames": [ + "MD049", + "emphasis-style" + ] + }, { "errorContext": null, "errorDetail": "Expected: underscore; Actual: asterisk", @@ -314,5 +394,85 @@ "MD050", "strong-style" ] + }, + { + "errorContext": null, + "errorDetail": "Expected: underscore; Actual: asterisk", + "errorRange": [ + 14, + 10 + ], + "fixInfo": { + "deleteCount": 10, + "editColumn": 14, + "insertText": "__double__" + }, + "lineNumber": 47, + "ruleDescription": "Strong style should be consistent", + "ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md050", + "ruleNames": [ + "MD050", + "strong-style" + ] + }, + { + "errorContext": null, + "errorDetail": "Expected: underscore; Actual: asterisk", + "errorRange": [ + 30, + 15 + ], + "fixInfo": { + "deleteCount": 15, + "editColumn": 30, + "insertText": "__interleaved__" + }, + "lineNumber": 47, + "ruleDescription": "Strong style should be consistent", + "ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md050", + "ruleNames": [ + "MD050", + "strong-style" + ] + }, + { + "errorContext": null, + "errorDetail": "Expected: underscore; Actual: asterisk", + "errorRange": [ + 51, + 10 + ], + "fixInfo": { + "deleteCount": 10, + "editColumn": 51, + "insertText": "__double__" + }, + "lineNumber": 47, + "ruleDescription": "Strong style should be consistent", + "ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md050", + "ruleNames": [ + "MD050", + "strong-style" + ] + }, + { + "errorContext": null, + "errorDetail": "Expected: underscore; Actual: asterisk", + "errorRange": [ + 62, + 15 + ], + "fixInfo": { + "deleteCount": 15, + "editColumn": 62, + "insertText": "__interleaved__" + }, + "lineNumber": 47, + "ruleDescription": "Strong style should be consistent", + "ruleInformation": "https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/Rules.md#md050", + "ruleNames": [ + "MD050", + "strong-style" + ] } ] \ No newline at end of file