From 535fd12c72ee7f10d465bcc875e0eb1c33f7a5f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Wed, 8 Oct 2025 18:56:06 +0900 Subject: [PATCH 1/4] fix: add CR to `MarkdownSourceCode` --- src/language/markdown-source-code.js | 3 +- src/util.js | 6 ++ tests/language/markdown-source-code.test.js | 61 +++++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/src/language/markdown-source-code.js b/src/language/markdown-source-code.js index 2c45f96b..ddb8f84c 100644 --- a/src/language/markdown-source-code.js +++ b/src/language/markdown-source-code.js @@ -13,6 +13,7 @@ import { ConfigCommentParser, Directive, } from "@eslint/plugin-kit"; +import { lineEndingPattern } from "../util.js"; //----------------------------------------------------------------------------- // Types @@ -152,7 +153,7 @@ export class MarkdownSourceCode extends TextSourceCodeBase { * @param {Root} options.ast The root AST node. */ constructor({ text, ast }) { - super({ ast, text }); + super({ ast, text, lineEndingPattern }); this.ast = ast; // need to traverse the source code to get the inline config nodes diff --git a/src/util.js b/src/util.js index 36cf9954..1b97d8be 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 diff --git a/tests/language/markdown-source-code.test.js b/tests/language/markdown-source-code.test.js index b4011af7..2a4a98cb 100644 --- a/tests/language/markdown-source-code.test.js +++ b/tests/language/markdown-source-code.test.js @@ -66,6 +66,67 @@ 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); + }); + }); + + describe("lines", () => { + 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", () => { + 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", () => { + 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 f2f00b110e63afbe6ac129b81c936c8c69697168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Wed, 8 Oct 2025 19:09:23 +0900 Subject: [PATCH 2/4] wip: util --- src/util.js | 10 +++++----- tests/util.test.js | 20 +++++++++++++++++++- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/util.js b/src/util.js index 1b97d8be..b69e80eb 100644 --- a/src/util.js +++ b/src/util.js @@ -30,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; diff --git a/tests/util.test.js b/tests/util.test.js index f5c2de57..a744c394 100644 --- a/tests/util.test.js +++ b/tests/util.test.js @@ -36,7 +36,7 @@ describe("util", () => { ); }); - it("should return true if the pattern matches any line in multiline frontmatter", () => { + it("should return true if the pattern matches any line in multiline frontmatter (LF)", () => { const frontmatter = [ "description: Test", "title: My Document", @@ -45,6 +45,24 @@ describe("util", () => { assert.strictEqual(frontmatterHasTitle(frontmatter, pattern), true); }); + it("should return true if the pattern matches any line in multiline frontmatter (CR)", () => { + const frontmatter = [ + "description: Test", + "title: My Document", + "author: lumirlumir", + ].join("\r"); + assert.strictEqual(frontmatterHasTitle(frontmatter, pattern), true); + }); + + it("should return true if the pattern matches any line in multiline frontmatter (CRLF)", () => { + const frontmatter = [ + "description: Test", + "title: My Document", + "author: lumirlumir", + ].join("\r\n"); + assert.strictEqual(frontmatterHasTitle(frontmatter, pattern), true); + }); + it("should return false for empty frontmatter", () => { const frontmatter = ""; assert.strictEqual( From 7dce7c2687e7cb39c7bf11122039fdc3696b21a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Wed, 8 Oct 2025 19:11:46 +0900 Subject: [PATCH 3/4] wip --- tests/language/markdown-source-code.test.js | 26 ++++++++++----------- tests/util.test.js | 12 +++++----- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/tests/language/markdown-source-code.test.js b/tests/language/markdown-source-code.test.js index 2a4a98cb..970b3218 100644 --- a/tests/language/markdown-source-code.test.js +++ b/tests/language/markdown-source-code.test.js @@ -78,14 +78,17 @@ describe("MarkdownSourceCode", () => { }); describe("lines", () => { - it("should parse LF line endings", () => { - const text = "lumir\nlumir"; - const sourceCodeWithLF = new MarkdownSourceCode({ + it("should parse CRLF line endings", () => { + const text = "lumir\r\nlumir"; + const sourceCodeWithCRLF = new MarkdownSourceCode({ text, ast: fromMarkdown(text), }); - assert.deepStrictEqual(sourceCodeWithLF.lines, ["lumir", "lumir"]); + assert.deepStrictEqual(sourceCodeWithCRLF.lines, [ + "lumir", + "lumir", + ]); }); it("should parse CR line endings", () => { @@ -98,21 +101,18 @@ describe("MarkdownSourceCode", () => { assert.deepStrictEqual(sourceCodeWithCR.lines, ["lumir", "lumir"]); }); - it("should parse CRLF line endings", () => { - const text = "lumir\r\nlumir"; - const sourceCodeWithCRLF = new MarkdownSourceCode({ + it("should parse LF line endings", () => { + const text = "lumir\nlumir"; + const sourceCodeWithLF = new MarkdownSourceCode({ text, ast: fromMarkdown(text), }); - assert.deepStrictEqual(sourceCodeWithCRLF.lines, [ - "lumir", - "lumir", - ]); + assert.deepStrictEqual(sourceCodeWithLF.lines, ["lumir", "lumir"]); }); - it("should parse LF CR CRLF line endings", () => { - const text = "lumir\nlumir\rlumir\r\nlumir"; + it("should parse CRLF CR LF line endings", () => { + const text = "lumir\r\nlumir\rlumir\nlumir"; const sourceCodeWithLFCRCRLF = new MarkdownSourceCode({ text, ast: fromMarkdown(text), diff --git a/tests/util.test.js b/tests/util.test.js index a744c394..ccaaf5f8 100644 --- a/tests/util.test.js +++ b/tests/util.test.js @@ -36,12 +36,12 @@ describe("util", () => { ); }); - it("should return true if the pattern matches any line in multiline frontmatter (LF)", () => { + it("should return true if the pattern matches any line in multiline frontmatter (CRLF)", () => { const frontmatter = [ "description: Test", "title: My Document", - "author: xbinaryx", - ].join("\n"); + "author: lumirlumir", + ].join("\r\n"); assert.strictEqual(frontmatterHasTitle(frontmatter, pattern), true); }); @@ -54,12 +54,12 @@ describe("util", () => { assert.strictEqual(frontmatterHasTitle(frontmatter, pattern), true); }); - it("should return true if the pattern matches any line in multiline frontmatter (CRLF)", () => { + it("should return true if the pattern matches any line in multiline frontmatter (LF)", () => { const frontmatter = [ "description: Test", "title: My Document", - "author: lumirlumir", - ].join("\r\n"); + "author: xbinaryx", + ].join("\n"); assert.strictEqual(frontmatterHasTitle(frontmatter, pattern), true); }); From e3f0000bc0bcc5c9a8e47a4ff959d683036b0b65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A3=A8=EB=B0=80LuMir?= Date: Wed, 8 Oct 2025 19:13:23 +0900 Subject: [PATCH 4/4] wip: typo --- tests/language/markdown-source-code.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/language/markdown-source-code.test.js b/tests/language/markdown-source-code.test.js index 970b3218..daac0ca2 100644 --- a/tests/language/markdown-source-code.test.js +++ b/tests/language/markdown-source-code.test.js @@ -113,12 +113,12 @@ describe("MarkdownSourceCode", () => { it("should parse CRLF CR LF line endings", () => { const text = "lumir\r\nlumir\rlumir\nlumir"; - const sourceCodeWithLFCRCRLF = new MarkdownSourceCode({ + const sourceCodeWithCRLFCRLF = new MarkdownSourceCode({ text, ast: fromMarkdown(text), }); - assert.deepStrictEqual(sourceCodeWithLFCRCRLF.lines, [ + assert.deepStrictEqual(sourceCodeWithCRLFCRLF.lines, [ "lumir", "lumir", "lumir",