From 02691ddee97101e61b9953ac9b95c4229a6cb536 Mon Sep 17 00:00:00 2001 From: Ga eun Lee Date: Mon, 24 Aug 2026 16:52:35 +0900 Subject: [PATCH 1/8] fix: correct www autofix in no-bare-urls --- src/rules/no-bare-urls.js | 11 ++++++++++- tests/rules/no-bare-urls.test.js | 13 +++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/rules/no-bare-urls.js b/src/rules/no-bare-urls.js index 30f0d834..17b125fb 100644 --- a/src/rules/no-bare-urls.js +++ b/src/rules/no-bare-urls.js @@ -168,7 +168,16 @@ export default /** @satisfies {NoBareUrlsRuleDefinition} */ ({ node: linkNode, messageId: "bareUrl", fix(fixer) { - return fixer.replaceText(linkNode, `<${text}>`); + let replacementUrl = `<${text}>`; + + if (url === `http://${text}`) { + replacementUrl = `[${text}](${url})`; + } + + return fixer.replaceText( + linkNode, + replacementUrl, + ); }, }); } diff --git a/tests/rules/no-bare-urls.test.js b/tests/rules/no-bare-urls.test.js index df9d171b..0b25ae19 100644 --- a/tests/rules/no-bare-urls.test.js +++ b/tests/rules/no-bare-urls.test.js @@ -73,6 +73,19 @@ ruleTester.run("no-bare-urls", rule, { " Code https://example.com/code?type=indent code", ], invalid: [ + { + code: "Visit www.example.com for details.", + output: "Visit [www.example.com](http://www.example.com) for details.", + errors: [ + { + messageId: "bareUrl", + line: 1, + column: 7, + endLine: 1, + endColumn: 22, + }, + ], + }, { code: "https://www.example.com/", output: "", From a874ed87ce0d15f28b904ddbad2bf2885e0de9b1 Mon Sep 17 00:00:00 2001 From: Ga eun Lee Date: Mon, 24 Aug 2026 16:58:47 +0900 Subject: [PATCH 2/8] refactor: clarify replacement variable in no-bare-urls --- src/rules/no-bare-urls.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rules/no-bare-urls.js b/src/rules/no-bare-urls.js index 17b125fb..dec5c68f 100644 --- a/src/rules/no-bare-urls.js +++ b/src/rules/no-bare-urls.js @@ -168,15 +168,15 @@ export default /** @satisfies {NoBareUrlsRuleDefinition} */ ({ node: linkNode, messageId: "bareUrl", fix(fixer) { - let replacementUrl = `<${text}>`; + let replacementText = `<${text}>`; if (url === `http://${text}`) { - replacementUrl = `[${text}](${url})`; + replacementText = `[${text}](${url})`; } return fixer.replaceText( linkNode, - replacementUrl, + replacementText, ); }, }); From 01f697628b1c83c5665b24051e3c1505c9c18b66 Mon Sep 17 00:00:00 2001 From: Ga eun Lee Date: Mon, 24 Aug 2026 17:01:16 +0900 Subject: [PATCH 3/8] refactor: clarify www autolink handling --- src/rules/no-bare-urls.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rules/no-bare-urls.js b/src/rules/no-bare-urls.js index dec5c68f..f9f14f5d 100644 --- a/src/rules/no-bare-urls.js +++ b/src/rules/no-bare-urls.js @@ -169,7 +169,7 @@ export default /** @satisfies {NoBareUrlsRuleDefinition} */ ({ messageId: "bareUrl", fix(fixer) { let replacementText = `<${text}>`; - + // GFM parses `www` autolinks with an `http://` URL. if (url === `http://${text}`) { replacementText = `[${text}](${url})`; } From 548fe33ccd3ecc561a0d9a8f24d835dfc56e4124 Mon Sep 17 00:00:00 2001 From: Ga eun Lee Date: Wed, 26 Aug 2026 23:55:59 +0900 Subject: [PATCH 4/8] test: add no-bare-urls autofix edge cases --- src/rules/no-bare-urls.js | 7 +++- tests/rules/no-bare-urls.test.js | 65 ++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/rules/no-bare-urls.js b/src/rules/no-bare-urls.js index f9f14f5d..b020dab3 100644 --- a/src/rules/no-bare-urls.js +++ b/src/rules/no-bare-urls.js @@ -171,7 +171,12 @@ export default /** @satisfies {NoBareUrlsRuleDefinition} */ ({ let replacementText = `<${text}>`; // GFM parses `www` autolinks with an `http://` URL. if (url === `http://${text}`) { - replacementText = `[${text}](${url})`; + const escapedLinkDestination = url.replace( + /[\\()]/gu, + "\\$&", + ); + + replacementText = `[${text}](${escapedLinkDestination})`; } return fixer.replaceText( diff --git a/tests/rules/no-bare-urls.test.js b/tests/rules/no-bare-urls.test.js index 0b25ae19..2f8bb56b 100644 --- a/tests/rules/no-bare-urls.test.js +++ b/tests/rules/no-bare-urls.test.js @@ -86,6 +86,71 @@ ruleTester.run("no-bare-urls", rule, { }, ], }, + { + code: "www.google.com/search?q=(business))+ok", + output: "[www.google.com/search?q=(business))+ok](http://www.google.com/search?q=\\(business\\)\\)+ok)", + errors: [ + { + messageId: "bareUrl", + line: 1, + column: 1, + endLine: 1, + endColumn: 39, + }, + ], + }, + { + code: "www.example.com/a\\*b", + output: "[www.example.com/a\\\\\\*b](http://www.example.com/a\\\\*b)", + errors: [ + { + messageId: "bareUrl", + line: 1, + column: 1, + endLine: 1, + endColumn: 21, + }, + ], + }, + { + code: "www.example.com/a]b", + output: "[www.example.com/a\\]b](http://www.example.com/a]b)", + errors: [ + { + messageId: "bareUrl", + line: 1, + column: 1, + endLine: 1, + endColumn: 20, + }, + ], + }, + { + code: "www.example.com/a*b*c", + output: "[www.example.com/a\\*b\\*c](http://www.example.com/a*b*c)", + errors: [ + { + messageId: "bareUrl", + line: 1, + column: 1, + endLine: 1, + endColumn: 22, + }, + ], + }, + { + code: "www.example.com/a~b~c", + output: "[www.example.com/a\\~b\\~c](http://www.example.com/a~b~c)", + errors: [ + { + messageId: "bareUrl", + line: 1, + column: 1, + endLine: 1, + endColumn: 22, + }, + ], + }, { code: "https://www.example.com/", output: "", From ef0c2f1daa900e4d53e2d7286b40cc5401eee87e Mon Sep 17 00:00:00 2001 From: Ga eun Lee Date: Thu, 27 Aug 2026 01:00:06 +0900 Subject: [PATCH 5/8] fix: escape special characters in www autolinks --- src/rules/no-bare-urls.js | 6 +++++- tests/rules/no-bare-urls.test.js | 26 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/rules/no-bare-urls.js b/src/rules/no-bare-urls.js index b020dab3..7a018956 100644 --- a/src/rules/no-bare-urls.js +++ b/src/rules/no-bare-urls.js @@ -171,12 +171,16 @@ export default /** @satisfies {NoBareUrlsRuleDefinition} */ ({ let replacementText = `<${text}>`; // GFM parses `www` autolinks with an `http://` URL. if (url === `http://${text}`) { + const escapedLinkText = text.replace( + /[[\]\\*_~`]/gu, + "\\$&", + ); const escapedLinkDestination = url.replace( /[\\()]/gu, "\\$&", ); - replacementText = `[${text}](${escapedLinkDestination})`; + replacementText = `[${escapedLinkText}](${escapedLinkDestination})`; } return fixer.replaceText( diff --git a/tests/rules/no-bare-urls.test.js b/tests/rules/no-bare-urls.test.js index 2f8bb56b..ba3db031 100644 --- a/tests/rules/no-bare-urls.test.js +++ b/tests/rules/no-bare-urls.test.js @@ -125,6 +125,19 @@ ruleTester.run("no-bare-urls", rule, { }, ], }, + { + code: "www.example.com/a[b", + output: "[www.example.com/a\\[b](http://www.example.com/a[b)", + errors: [ + { + messageId: "bareUrl", + line: 1, + column: 1, + endLine: 1, + endColumn: 20, + }, + ], + }, { code: "www.example.com/a*b*c", output: "[www.example.com/a\\*b\\*c](http://www.example.com/a*b*c)", @@ -151,6 +164,19 @@ ruleTester.run("no-bare-urls", rule, { }, ], }, + { + code: "www.example.com/a`b`c", + output: "[www.example.com/a\\`b\\`c](http://www.example.com/a`b`c)", + errors: [ + { + messageId: "bareUrl", + line: 1, + column: 1, + endLine: 1, + endColumn: 22, + }, + ], + }, { code: "https://www.example.com/", output: "", From 294e787a94bcd4114ff967e4819289bd18cf5fcd Mon Sep 17 00:00:00 2001 From: Ga eun Lee Date: Fri, 18 Sep 2026 12:24:07 +0900 Subject: [PATCH 6/8] test: add no-bare-urls autofix regression tests --- tests/rules/no-bare-urls.test.js | 61 ++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/tests/rules/no-bare-urls.test.js b/tests/rules/no-bare-urls.test.js index ba3db031..08c6519e 100644 --- a/tests/rules/no-bare-urls.test.js +++ b/tests/rules/no-bare-urls.test.js @@ -177,6 +177,67 @@ ruleTester.run("no-bare-urls", rule, { }, ], }, + { + code: "www.example.com/$a$b$c", + output: "[www.example.com/\\$a\\$b\\$c](http://www.example.com/$a$b$c)", + languageOptions: { + math: true, + }, + errors: [ + { + messageId: "bareUrl", + line: 1, + column: 1, + endLine: 1, + endColumn: 25, + }, + ], + }, + { + code: dedent` + | URL | + | --- | + | www.example.com/a\|b |`, + output: dedent` + | URL | + | --- | + | [www.example.com/a\\\|b](http://www.example.com/a\\\|b) |`, + errors: [ + { + messageId: "bareUrl", + line: 3, + column: 3, + endLine: 3, + endColumn: 23, + }, + ], + }, + { + code: "www.example.com/a&b", + output: "[www.example.com/a\\&b](http://www.example.com/a\\&b)", + errors: [ + { + messageId: "bareUrl", + line: 1, + column: 1, + endLine: 1, + endColumn: 24, + }, + ], + }, + { + code: "www.example.com/a&b", + output: "[www.example.com/a\\&b](http://www.example.com/a\\&b)", + errors: [ + { + messageId: "bareUrl", + line: 1, + column: 1, + endLine: 1, + endColumn: 24, + }, + ], + }, { code: "https://www.example.com/", output: "", From 8c48e34574111b15cf37f44d0d7d91a1b1747dfd Mon Sep 17 00:00:00 2001 From: Ga eun Lee Date: Fri, 18 Sep 2026 12:44:04 +0900 Subject: [PATCH 7/8] fix: escape dollar signs and ampersands in www autolinks --- src/rules/no-bare-urls.js | 4 ++-- tests/rules/no-bare-urls.test.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rules/no-bare-urls.js b/src/rules/no-bare-urls.js index 7a018956..28e6e1b7 100644 --- a/src/rules/no-bare-urls.js +++ b/src/rules/no-bare-urls.js @@ -172,11 +172,11 @@ export default /** @satisfies {NoBareUrlsRuleDefinition} */ ({ // GFM parses `www` autolinks with an `http://` URL. if (url === `http://${text}`) { const escapedLinkText = text.replace( - /[[\]\\*_~`]/gu, + /[[\]\\*_~`$&]/gu, "\\$&", ); const escapedLinkDestination = url.replace( - /[\\()]/gu, + /[\\()&]/gu, "\\$&", ); diff --git a/tests/rules/no-bare-urls.test.js b/tests/rules/no-bare-urls.test.js index 08c6519e..0338de38 100644 --- a/tests/rules/no-bare-urls.test.js +++ b/tests/rules/no-bare-urls.test.js @@ -189,7 +189,7 @@ ruleTester.run("no-bare-urls", rule, { line: 1, column: 1, endLine: 1, - endColumn: 25, + endColumn: 23, }, ], }, From 1706710bad5ae857abba4b60b76d21db89fa9448 Mon Sep 17 00:00:00 2001 From: Ga eun Lee Date: Fri, 18 Sep 2026 12:50:19 +0900 Subject: [PATCH 8/8] fix: preserve escaped pipes in www autolinks --- src/rules/no-bare-urls.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/rules/no-bare-urls.js b/src/rules/no-bare-urls.js index 28e6e1b7..0f806688 100644 --- a/src/rules/no-bare-urls.js +++ b/src/rules/no-bare-urls.js @@ -41,6 +41,8 @@ //----------------------------------------------------------------------------- const htmlTagNamePattern = /^<(?[^!>][^/\s>]*)/u; +const linkTextSpecialCharacterPattern = /[[\]\\*_~`$&|]/gu; +const linkDestinationSpecialCharacterPattern = /[\\()&|]/gu; /** * Parses an HTML tag to extract its name and closing status @@ -172,11 +174,11 @@ export default /** @satisfies {NoBareUrlsRuleDefinition} */ ({ // GFM parses `www` autolinks with an `http://` URL. if (url === `http://${text}`) { const escapedLinkText = text.replace( - /[[\]\\*_~`$&]/gu, + linkTextSpecialCharacterPattern, "\\$&", ); const escapedLinkDestination = url.replace( - /[\\()&]/gu, + linkDestinationSpecialCharacterPattern, "\\$&", );