diff --git a/README.md b/README.md index 0dc71bf1..adc000e8 100644 --- a/README.md +++ b/README.md @@ -155,13 +155,22 @@ appropriate place (HTML comments don't appear in the final markup): * Disable all rules: `` * Enable all rules: `` +* Disable all rules for the next line only: `` * Disable one or more rules by name: `` * Enable one or more rules by name: `` +* Disable one or more rules by name for the next line only: `` * Capture the current rule configuration: `` * Restore the captured rule configuration: `` For example: +```markdown + +deliberate space * in * emphasis +``` + +Or: + ```markdown deliberate space * in * emphasis diff --git a/helpers/helpers.js b/helpers/helpers.js index 65f37f30..2609808a 100644 --- a/helpers/helpers.js +++ b/helpers/helpers.js @@ -17,7 +17,7 @@ module.exports.frontMatterRe = // Regular expression for matching inline disable/enable comments const inlineCommentRe = // eslint-disable-next-line max-len - //ig; + //ig; module.exports.inlineCommentRe = inlineCommentRe; // Regular expressions for range matching diff --git a/lib/markdownlint.js b/lib/markdownlint.js index bb8772f0..b64cf969 100644 --- a/lib/markdownlint.js +++ b/lib/markdownlint.js @@ -322,13 +322,13 @@ function getEnabledRulesPerLineNumber( // eslint-disable-next-line jsdoc/require-jsdoc function handleInlineConfig(perLine, forEachMatch, forEachLine) { const input = perLine ? lines : [ lines.join("\n") ]; - input.forEach((line) => { + input.forEach((line, lineIndex) => { if (!noInlineConfig) { let match = null; while ((match = helpers.inlineCommentRe.exec(line))) { const action = (match[1] || match[3]).toUpperCase(); const parameter = match[2] || match[4]; - forEachMatch(action, parameter); + forEachMatch(action, parameter, lineIndex + 1); } } if (forEachLine) { @@ -351,21 +351,21 @@ function getEnabledRulesPerLineNumber( } } // eslint-disable-next-line jsdoc/require-jsdoc - function applyEnableDisable(action, parameter) { + function applyEnableDisable(action, parameter, state) { const enabled = (action.startsWith("ENABLE")); const items = parameter ? parameter.trim().toUpperCase().split(/\s+/) : allRuleNames; items.forEach((nameUpper) => { (aliasToRuleNames[nameUpper] || []).forEach((ruleName) => { - enabledRules[ruleName] = enabled; + state[ruleName] = enabled; }); }); } // eslint-disable-next-line jsdoc/require-jsdoc function enableDisableFile(action, parameter) { if ((action === "ENABLE-FILE") || (action === "DISABLE-FILE")) { - applyEnableDisable(action, parameter); + applyEnableDisable(action, parameter, enabledRules); } } // eslint-disable-next-line jsdoc/require-jsdoc @@ -376,12 +376,22 @@ function getEnabledRulesPerLineNumber( enabledRules = { ...capturedRules }; } else if ((action === "ENABLE") || (action === "DISABLE")) { enabledRules = { ...enabledRules }; - applyEnableDisable(action, parameter); + applyEnableDisable(action, parameter, enabledRules); } } // eslint-disable-next-line jsdoc/require-jsdoc function updateLineState() { - enabledRulesPerLineNumber.push(enabledRules); + enabledRulesPerLineNumber.push({ ...enabledRules }); + } + // eslint-disable-next-line jsdoc/require-jsdoc + function disableNextLine(action, parameter, lineNumber) { + if (action === "DISABLE-NEXT-LINE") { + applyEnableDisable( + action, + parameter, + enabledRulesPerLineNumber[lineNumber + 1] || {} + ); + } } // Handle inline comments handleInlineConfig(false, configureFile); @@ -395,6 +405,7 @@ function getEnabledRulesPerLineNumber( capturedRules = enabledRules; handleInlineConfig(true, enableDisableFile); handleInlineConfig(true, captureRestoreEnableDisable, updateLineState); + handleInlineConfig(true, disableNextLine); // Return results return { effectiveConfig, diff --git a/test/inline-disable-enable.md b/test/inline-disable-enable.md index 8fa8948f..5be3829d 100644 --- a/test/inline-disable-enable.md +++ b/test/inline-disable-enable.md @@ -67,3 +67,26 @@ hard tab {MD010} / space *in * emphasis {MD037} / space `in ` code hard tab {MD010} / space *in * emphasis {MD037} / space `in ` code {MD038} embedded {MD033} HTML + + + +hard tab {MD010} / space *in * emphasis {MD037} / space `in ` code {MD038} + +hard tab / space *in * emphasis / space `in ` code +hard tab {MD010} / space *in * emphasis {MD037} / space `in ` code {MD038} +hard tab {MD010} / space *in * emphasis {MD037} / space `in ` code {MD038} +hard tab / space *in * emphasis / space `in ` code +hard tab {MD010} / space *in * emphasis {MD037} / space `in ` code {MD038} + +hard tab / space *in * emphasis {MD037} / space `in ` code +hard tab {MD010} / space *in * emphasis {MD037} / space `in ` code {MD038} + +hard tab / space *in * emphasis {MD037} / space `in ` code +hard tab {MD010} / space *in * emphasis {MD037} / space `in ` code {MD038} + +hard tab / space *in * emphasis {MD037} / space `in ` code {MD038} + +hard tab / space *in * emphasis {MD037} / space `in ` code +hard tab / space *in * emphasis {MD037} / space `in ` code {MD038} + + \ No newline at end of file