From 14a7529ce7d5ace2dda110816bd681568e34cb6d Mon Sep 17 00:00:00 2001 From: David Anson Date: Tue, 11 Jul 2023 22:17:53 -0700 Subject: [PATCH] Snapshot custom rule definitions to prevent them from changing dynamically. --- demo/markdownlint-browser.js | 5 ++- lib/markdownlint.js | 6 +++- test/markdownlint-test-custom-rules.js | 45 ++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/demo/markdownlint-browser.js b/demo/markdownlint-browser.js index adbe25cc..6501a7be 100644 --- a/demo/markdownlint-browser.js +++ b/demo/markdownlint-browser.js @@ -2628,8 +2628,11 @@ function lintInput(options, synchronous, callback) { // Normalize inputs options = options || {}; callback = callback || function noop() {}; + var customRuleList = [options.customRules || []].flat().map(function (rule) { + return _objectSpread({}, rule); + }); // eslint-disable-next-line unicorn/prefer-spread - var ruleList = rules.concat(options.customRules || []); + var ruleList = rules.concat(customRuleList); var ruleErr = validateRuleList(ruleList, synchronous); if (ruleErr) { callback(ruleErr); diff --git a/lib/markdownlint.js b/lib/markdownlint.js index 697a9d09..38bc22f9 100644 --- a/lib/markdownlint.js +++ b/lib/markdownlint.js @@ -869,8 +869,12 @@ function lintInput(options, synchronous, callback) { // Normalize inputs options = options || {}; callback = callback || function noop() {}; + const customRuleList = + [ options.customRules || [] ] + .flat() + .map((rule) => ({ ...rule })); // eslint-disable-next-line unicorn/prefer-spread - const ruleList = rules.concat(options.customRules || []); + const ruleList = rules.concat(customRuleList); const ruleErr = validateRuleList(ruleList, synchronous); if (ruleErr) { callback(ruleErr); diff --git a/test/markdownlint-test-custom-rules.js b/test/markdownlint-test-custom-rules.js index 5e582de0..7aefe592 100644 --- a/test/markdownlint-test-custom-rules.js +++ b/test/markdownlint-test-custom-rules.js @@ -479,6 +479,51 @@ test("customRulesUsedTagName", (t) => new Promise((resolve) => { }); })); +test("customRulesDefinitionStatic", (t) => new Promise((resolve) => { + t.plan(2); + const options = { + "customRules": [ + { + "names": [ "name" ], + "description": "description", + "information": new URL("https://example.com/information"), + "tags": [ "tag" ], + "function": (params, onError) => { + const definition = options.customRules[0]; + definition.names = [ "changed" ]; + definition.description = "changed"; + definition.information = new URL("https://example.com/changed"); + onError({ + "lineNumber": 1 + }); + } + } + ], + "strings": { + "string": "# Heading\n" + } + }; + markdownlint(options, (err, actualResult) => { + t.falsy(err); + const expectedResult = { + "string": [ + { + "lineNumber": 1, + "ruleNames": [ "name" ], + "ruleDescription": "description", + "ruleInformation": "https://example.com/information", + "errorDetail": null, + "errorContext": null, + "errorRange": null, + "fixInfo": null + } + ] + }; + t.deepEqual(actualResult, expectedResult, "Undetected issues."); + resolve(); + }); +})); + test("customRulesThrowForFile", (t) => new Promise((resolve) => { t.plan(4); const exceptionMessage = "Test exception message";