From f876ba5b3d4cfd6f2f3deedc6c938595e26eada4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Mon, 4 Aug 2025 19:18:45 +0900 Subject: [PATCH 01/14] fix: add CR to the line ending pattern --- src/language/markdown-source-code.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/language/markdown-source-code.js b/src/language/markdown-source-code.js index 01e7f43f..69e93819 100644 --- a/src/language/markdown-source-code.js +++ b/src/language/markdown-source-code.js @@ -167,7 +167,7 @@ export class MarkdownSourceCode extends TextSourceCodeBase { * @param {Root} options.ast The root AST node. */ constructor({ text, ast }) { - super({ ast, text }); + super({ ast, text, lineEndingPattern: /\n|\r|\r\n/u }); this.ast = ast; // need to traverse the source code to get the inline config nodes From 1a30634eb34172c3468f19c530d1a6b4d0950697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Wed, 20 Aug 2025 22:54:49 +0900 Subject: [PATCH 02/14] wip: add test --- tests/language/markdown-source-code.test.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/language/markdown-source-code.test.js b/tests/language/markdown-source-code.test.js index a92ca1ee..fe656533 100644 --- a/tests/language/markdown-source-code.test.js +++ b/tests/language/markdown-source-code.test.js @@ -66,6 +66,22 @@ describe("MarkdownSourceCode", () => { sourceCode = new MarkdownSourceCode({ text: markdownText, ast }); }); + describe("constructor", () => { + it("should create a MarkdownSourceCode instance", () => { + const mdSourceCode = new MarkdownSourceCode({ + text: markdownText, + ast, + }); + + assert.strictEqual( + mdSourceCode.constructor.name, + "MarkdownSourceCode", + ); + assert.strictEqual(mdSourceCode.ast, ast); + assert.strictEqual(mdSourceCode.text, markdownText); + }); + }); + describe("getText()", () => { it("should return the text of the Markdown source code", () => { assert.strictEqual(sourceCode.getText(), markdownText); From b427e82e947f8ec7c58e6cae51071b09a52352e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Wed, 20 Aug 2025 23:11:45 +0900 Subject: [PATCH 03/14] wip: add more tests --- tests/language/markdown-source-code.test.js | 61 ++++++++++++++++++--- 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/tests/language/markdown-source-code.test.js b/tests/language/markdown-source-code.test.js index fe656533..7483b6b0 100644 --- a/tests/language/markdown-source-code.test.js +++ b/tests/language/markdown-source-code.test.js @@ -68,17 +68,62 @@ describe("MarkdownSourceCode", () => { describe("constructor", () => { it("should create a MarkdownSourceCode instance", () => { - const mdSourceCode = new MarkdownSourceCode({ - text: markdownText, - ast, - }); - assert.strictEqual( - mdSourceCode.constructor.name, + sourceCode.constructor.name, "MarkdownSourceCode", ); - assert.strictEqual(mdSourceCode.ast, ast); - assert.strictEqual(mdSourceCode.text, markdownText); + assert.strictEqual(sourceCode.ast, ast); + assert.strictEqual(sourceCode.text, markdownText); + }); + + it("should parse LF line endings", () => { + const text = "lumir\nlumir"; + const sourceCodeWithLF = new MarkdownSourceCode({ + text, + ast: fromMarkdown(text), + }); + + assert.deepStrictEqual(sourceCodeWithLF.lines, ["lumir", "lumir"]); + }); + + it("should parse CR line endings", () => { + const text = "lumir\rlumir"; + const sourceCodeWithCR = new MarkdownSourceCode({ + text, + ast: fromMarkdown(text), + }); + + assert.deepStrictEqual(sourceCodeWithCR.lines, ["lumir", "lumir"]); + }); + + it("should parse CRLF line endings", () => { + // TODO: Bug: Should work once https://github.com/eslint/rewrite/pull/212 is merged. + const text = "lumir\r\nlumir"; + const sourceCodeWithCRLF = new MarkdownSourceCode({ + text, + ast: fromMarkdown(text), + }); + + assert.deepStrictEqual(sourceCodeWithCRLF.lines, [ + "lumir", + "lumir", + ]); + }); + + it("should parse LF CR CRLF line endings", () => { + // TODO: Bug: Should work once https://github.com/eslint/rewrite/pull/212 is merged. + const text = "lumir\nlumir\rlumir\r\nlumir"; + const sourceCodeWithLFCRCRLF = new MarkdownSourceCode({ + text, + ast: fromMarkdown(text), + }); + + assert.deepStrictEqual(sourceCodeWithLFCRCRLF.lines, [ + "lumir", + "lumir", + "lumir", + "lumir", + ]); }); }); From 4e8343582aaf1e5aa186a593021c72ae4a3f6ffd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Wed, 20 Aug 2025 23:16:26 +0900 Subject: [PATCH 04/14] wip: mark error prone patterns --- src/language/markdown-source-code.js | 4 ++-- src/processor.js | 8 ++++---- src/rules/no-missing-atx-heading-space.js | 2 +- src/rules/no-reversed-media-syntax.js | 2 +- src/util.js | 8 +++++--- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/language/markdown-source-code.js b/src/language/markdown-source-code.js index 69e93819..ef123fb1 100644 --- a/src/language/markdown-source-code.js +++ b/src/language/markdown-source-code.js @@ -97,13 +97,13 @@ function extractInlineConfigCommentsFromHTML(node) { start.column += startColumnOffset; start.offset += match.index; - const commentLineCount = comment.split("\n").length - 1; + const commentLineCount = comment.split("\n").length - 1; // TODO end.line = start.line + commentLineCount; end.column = commentLineCount === 0 ? start.column + comment.length - : comment.length - comment.lastIndexOf("\n"); + : comment.length - comment.lastIndexOf("\n"); // TODO end.offset = start.offset + comment.length; comments.push( diff --git a/src/processor.js b/src/processor.js index c86781c5..07aaa539 100644 --- a/src/processor.js +++ b/src/processor.js @@ -164,7 +164,7 @@ function getBlockRangeMap(text, node, comments) { * line. */ const code = text.slice(startOffset, node.position.end.offset); - const lines = code.split("\n"); + const lines = code.split("\n"); // TODO /* * The parser trims leading whitespace from each line of code within the @@ -344,7 +344,7 @@ function preprocess(sourceText, filename) { return { filename: fileNameFromMeta(block) ?? `${index}.${fileExtension}`, - text: [...block.comments, block.value, ""].join("\n"), + text: [...block.comments, block.value, ""].join("\n"), // TODO }; }); } @@ -375,7 +375,7 @@ function adjustFix(block, fix) { return range + block.rangeMap[i - 1].md; }) ), - text: fix.text.replace(/\n/gu, `\n${block.baseIndentText}`), + text: fix.text.replace(/\n/gu, `\n${block.baseIndentText}`), // TODO }; } @@ -386,7 +386,7 @@ function adjustFix(block, fix) { */ function adjustBlock(block) { const leadingCommentLines = block.comments.reduce( - (count, comment) => count + comment.split("\n").length, + (count, comment) => count + comment.split("\n").length, // TODO 0, ); diff --git a/src/rules/no-missing-atx-heading-space.js b/src/rules/no-missing-atx-heading-space.js index ee54fcef..a29ae4a1 100644 --- a/src/rules/no-missing-atx-heading-space.js +++ b/src/rules/no-missing-atx-heading-space.js @@ -21,7 +21,7 @@ const leadingAtxHeadingHashPattern = /^(#{1,6})(?:[^# \t]|$)/u; const trailingAtxHeadingHashPattern = /(? - match.replace(/[^\n]/gu, " "), + return value.replace( + htmlCommentPattern, + match => match.replace(/[^\n]/gu, " "), // TODO ); } From d43082e9dd0b9fa8ae28ac11f8875adaf3b9587c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Wed, 8 Oct 2025 19:49:12 +0900 Subject: [PATCH 05/14] wip --- tests/language/markdown-source-code.test.js | 61 --------------------- 1 file changed, 61 deletions(-) diff --git a/tests/language/markdown-source-code.test.js b/tests/language/markdown-source-code.test.js index bde78de4..b4011af7 100644 --- a/tests/language/markdown-source-code.test.js +++ b/tests/language/markdown-source-code.test.js @@ -66,67 +66,6 @@ describe("MarkdownSourceCode", () => { sourceCode = new MarkdownSourceCode({ text: markdownText, ast }); }); - describe("constructor", () => { - it("should create a MarkdownSourceCode instance", () => { - assert.strictEqual( - sourceCode.constructor.name, - "MarkdownSourceCode", - ); - assert.strictEqual(sourceCode.ast, ast); - assert.strictEqual(sourceCode.text, markdownText); - }); - - it("should parse LF line endings", () => { - const text = "lumir\nlumir"; - const sourceCodeWithLF = new MarkdownSourceCode({ - text, - ast: fromMarkdown(text), - }); - - assert.deepStrictEqual(sourceCodeWithLF.lines, ["lumir", "lumir"]); - }); - - it("should parse CR line endings", () => { - const text = "lumir\rlumir"; - const sourceCodeWithCR = new MarkdownSourceCode({ - text, - ast: fromMarkdown(text), - }); - - assert.deepStrictEqual(sourceCodeWithCR.lines, ["lumir", "lumir"]); - }); - - it("should parse CRLF line endings", () => { - // TODO: Bug: Should work once https://github.com/eslint/rewrite/pull/212 is merged. - const text = "lumir\r\nlumir"; - const sourceCodeWithCRLF = new MarkdownSourceCode({ - text, - ast: fromMarkdown(text), - }); - - assert.deepStrictEqual(sourceCodeWithCRLF.lines, [ - "lumir", - "lumir", - ]); - }); - - it("should parse LF CR CRLF line endings", () => { - // TODO: Bug: Should work once https://github.com/eslint/rewrite/pull/212 is merged. - const text = "lumir\nlumir\rlumir\r\nlumir"; - const sourceCodeWithLFCRCRLF = new MarkdownSourceCode({ - text, - ast: fromMarkdown(text), - }); - - assert.deepStrictEqual(sourceCodeWithLFCRCRLF.lines, [ - "lumir", - "lumir", - "lumir", - "lumir", - ]); - }); - }); - describe("getText()", () => { it("should return the text of the Markdown source code", () => { assert.strictEqual(sourceCode.getText(), markdownText); From bc16d7a003a515d8b85879b4109b04887d337e82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Wed, 8 Oct 2025 19:50:05 +0900 Subject: [PATCH 06/14] wip --- src/util.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/util.js b/src/util.js index 36cf9954..b69e80eb 100644 --- a/src/util.js +++ b/src/util.js @@ -7,6 +7,12 @@ // Regex Patterns //----------------------------------------------------------------------------- +/** + * Line ending pattern to match all line endings (CRLF, CR, LF). (CommonMark spec) + * @see https://spec.commonmark.org/0.31.2/#line-ending + */ +export const lineEndingPattern = /\r\n|[\r\n]/u; + /** * CommonMark does not allow any white space between the brackets in a reference link. * If that pattern is detected, then it's treated as text and not as a link. This pattern @@ -24,16 +30,16 @@ export const htmlCommentPattern = //gu; //----------------------------------------------------------------------------- /** - * Checks if a frontmatter block contains a title matching the given pattern - * @param {string} value The frontmatter content - * @param {RegExp|null} pattern The pattern to match against - * @returns {boolean} Whether a title was found + * Checks if a frontmatter block contains a title matching the given pattern. + * @param {string} value The frontmatter content. + * @param {RegExp|null} pattern The pattern to match against. + * @returns {boolean} Whether a title was found. */ export function frontmatterHasTitle(value, pattern) { if (!pattern) { return false; } - const lines = value.split("\n"); + const lines = value.split(lineEndingPattern); for (const line of lines) { if (pattern.test(line)) { return true; From db11bb8fc59a064227ea8d2e26f047200dc006dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Wed, 8 Oct 2025 20:04:19 +0900 Subject: [PATCH 07/14] wip --- src/rules/no-html.js | 2 +- src/rules/no-reference-like-urls.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rules/no-html.js b/src/rules/no-html.js index 2d25932b..ec29629c 100644 --- a/src/rules/no-html.js +++ b/src/rules/no-html.js @@ -20,7 +20,7 @@ const htmlTagPattern = /<(?[a-z0-9]+(?:-[a-z0-9]+)*)(?:\s(?:[^>"']|"[^"]*"|'[^']*')*)?>/giu; -const lineEndingPattern = /\r\n?|\n/u; +const lineEndingPattern = /\r\n?|\n/u; // TODO //----------------------------------------------------------------------------- // Rule Definition diff --git a/src/rules/no-reference-like-urls.js b/src/rules/no-reference-like-urls.js index a151abe3..f58d0d56 100644 --- a/src/rules/no-reference-like-urls.js +++ b/src/rules/no-reference-like-urls.js @@ -27,7 +27,7 @@ import { normalizeIdentifier } from "micromark-util-normalize-identifier"; /** Pattern to match both inline links: `[text](url)` and images: `![alt](url)`, with optional title */ const linkOrImagePattern = - /(?!)?\[(?