Skip to content

Commit d1ad828

Browse files
authored
fix: handle CR in MarkdownSourceCode and Front Matter util (#554)
* fix: add CR to `MarkdownSourceCode` * wip: util * wip * wip: typo
1 parent 8992a4d commit d1ad828

File tree

4 files changed

+93
-7
lines changed

4 files changed

+93
-7
lines changed

src/language/markdown-source-code.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
ConfigCommentParser,
1414
Directive,
1515
} from "@eslint/plugin-kit";
16+
import { lineEndingPattern } from "../util.js";
1617

1718
//-----------------------------------------------------------------------------
1819
// Types
@@ -152,7 +153,7 @@ export class MarkdownSourceCode extends TextSourceCodeBase {
152153
* @param {Root} options.ast The root AST node.
153154
*/
154155
constructor({ text, ast }) {
155-
super({ ast, text });
156+
super({ ast, text, lineEndingPattern });
156157
this.ast = ast;
157158

158159
// need to traverse the source code to get the inline config nodes

src/util.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77
// Regex Patterns
88
//-----------------------------------------------------------------------------
99

10+
/**
11+
* Line ending pattern to match all line endings (CRLF, CR, LF). (CommonMark spec)
12+
* @see https://spec.commonmark.org/0.31.2/#line-ending
13+
*/
14+
export const lineEndingPattern = /\r\n|[\r\n]/u;
15+
1016
/**
1117
* CommonMark does not allow any white space between the brackets in a reference link.
1218
* 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 = /<!--[\s\S]*?-->/gu;
2430
//-----------------------------------------------------------------------------
2531

2632
/**
27-
* Checks if a frontmatter block contains a title matching the given pattern
28-
* @param {string} value The frontmatter content
29-
* @param {RegExp|null} pattern The pattern to match against
30-
* @returns {boolean} Whether a title was found
33+
* Checks if a frontmatter block contains a title matching the given pattern.
34+
* @param {string} value The frontmatter content.
35+
* @param {RegExp|null} pattern The pattern to match against.
36+
* @returns {boolean} Whether a title was found.
3137
*/
3238
export function frontmatterHasTitle(value, pattern) {
3339
if (!pattern) {
3440
return false;
3541
}
36-
const lines = value.split("\n");
42+
const lines = value.split(lineEndingPattern);
3743
for (const line of lines) {
3844
if (pattern.test(line)) {
3945
return true;

tests/language/markdown-source-code.test.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,67 @@ describe("MarkdownSourceCode", () => {
6666
sourceCode = new MarkdownSourceCode({ text: markdownText, ast });
6767
});
6868

69+
describe("constructor", () => {
70+
it("should create a MarkdownSourceCode instance", () => {
71+
assert.strictEqual(
72+
sourceCode.constructor.name,
73+
"MarkdownSourceCode",
74+
);
75+
assert.strictEqual(sourceCode.ast, ast);
76+
assert.strictEqual(sourceCode.text, markdownText);
77+
});
78+
});
79+
80+
describe("lines", () => {
81+
it("should parse CRLF line endings", () => {
82+
const text = "lumir\r\nlumir";
83+
const sourceCodeWithCRLF = new MarkdownSourceCode({
84+
text,
85+
ast: fromMarkdown(text),
86+
});
87+
88+
assert.deepStrictEqual(sourceCodeWithCRLF.lines, [
89+
"lumir",
90+
"lumir",
91+
]);
92+
});
93+
94+
it("should parse CR line endings", () => {
95+
const text = "lumir\rlumir";
96+
const sourceCodeWithCR = new MarkdownSourceCode({
97+
text,
98+
ast: fromMarkdown(text),
99+
});
100+
101+
assert.deepStrictEqual(sourceCodeWithCR.lines, ["lumir", "lumir"]);
102+
});
103+
104+
it("should parse LF line endings", () => {
105+
const text = "lumir\nlumir";
106+
const sourceCodeWithLF = new MarkdownSourceCode({
107+
text,
108+
ast: fromMarkdown(text),
109+
});
110+
111+
assert.deepStrictEqual(sourceCodeWithLF.lines, ["lumir", "lumir"]);
112+
});
113+
114+
it("should parse CRLF CR LF line endings", () => {
115+
const text = "lumir\r\nlumir\rlumir\nlumir";
116+
const sourceCodeWithCRLFCRLF = new MarkdownSourceCode({
117+
text,
118+
ast: fromMarkdown(text),
119+
});
120+
121+
assert.deepStrictEqual(sourceCodeWithCRLFCRLF.lines, [
122+
"lumir",
123+
"lumir",
124+
"lumir",
125+
"lumir",
126+
]);
127+
});
128+
});
129+
69130
describe("getText()", () => {
70131
it("should return the text of the Markdown source code", () => {
71132
assert.strictEqual(sourceCode.getText(), markdownText);

tests/util.test.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,25 @@ describe("util", () => {
3636
);
3737
});
3838

39-
it("should return true if the pattern matches any line in multiline frontmatter", () => {
39+
it("should return true if the pattern matches any line in multiline frontmatter (CRLF)", () => {
40+
const frontmatter = [
41+
"description: Test",
42+
"title: My Document",
43+
"author: lumirlumir",
44+
].join("\r\n");
45+
assert.strictEqual(frontmatterHasTitle(frontmatter, pattern), true);
46+
});
47+
48+
it("should return true if the pattern matches any line in multiline frontmatter (CR)", () => {
49+
const frontmatter = [
50+
"description: Test",
51+
"title: My Document",
52+
"author: lumirlumir",
53+
].join("\r");
54+
assert.strictEqual(frontmatterHasTitle(frontmatter, pattern), true);
55+
});
56+
57+
it("should return true if the pattern matches any line in multiline frontmatter (LF)", () => {
4058
const frontmatter = [
4159
"description: Test",
4260
"title: My Document",

0 commit comments

Comments
 (0)