diff --git a/demo.js b/demo.js
new file mode 100644
index 0000000..24755bd
--- /dev/null
+++ b/demo.js
@@ -0,0 +1,34 @@
+import { renderMath } from './dist/index.js';
+
+// Test cases to demonstrate newline handling
+const testCases = [
+ {
+ name: "Basic newline conversion",
+ input: "First line\nSecond line\nThird line"
+ },
+ {
+ name: "Newlines with math (should preserve newlines in math)",
+ input: "Text line 1\nText line 2\n$\\begin{pmatrix} a \\\\ b \\end{pmatrix}$\nText line 3"
+ },
+ {
+ name: "Multiple consecutive newlines",
+ input: "Line 1\n\n\nLine 2"
+ },
+ {
+ name: "Mixed content with escaped characters",
+ input: "Price: \\$5\nNext line\nMath: $x=1$\nFinal line"
+ },
+ {
+ name: "LaTeX equation with internal newlines (should be preserved)",
+ input: "$$\\begin{align}\na &= 1\\\\\nb &= 2\n\\end{align}$$"
+ }
+];
+
+console.log("=== Newline Handling Demo ===\n");
+
+testCases.forEach((testCase, index) => {
+ console.log(`${index + 1}. ${testCase.name}`);
+ console.log(`Input: ${JSON.stringify(testCase.input)}`);
+ console.log(`Output: ${JSON.stringify(renderMath(testCase.input))}`);
+ console.log();
+});
\ No newline at end of file
diff --git a/src/index.test.ts b/src/index.test.ts
index f48c4e2..870ee07 100644
--- a/src/index.test.ts
+++ b/src/index.test.ts
@@ -1,5 +1,5 @@
import * as katex from "katex";
-import { renderMath, parseDelimiters, ParsedSegment, escapeRegex, replacePredefinedEscapeSequences, unescapeCharacters, revertEscapedCharacters } from "./index";
+import { renderMath, parseDelimiters, ParsedSegment, escapeRegex, replacePredefinedEscapeSequences, unescapeCharacters, revertEscapedCharacters, convertNewlinesToLatexBreaks } from "./index";
jest.mock("katex", () => ({
renderToString: jest.fn((str, options) => {
@@ -78,6 +78,35 @@ describe("Helper Functions", () => {
expect(revertEscapedCharacters(input)).toBe(input);
});
});
+
+ describe("convertNewlinesToLatexBreaks", () => {
+ it("should convert single newlines to LaTeX line breaks", () => {
+ const input = "Line 1\nLine 2";
+ const expected = "Line 1 \\\\\\\\ Line 2";
+ expect(convertNewlinesToLatexBreaks(input)).toBe(expected);
+ });
+
+ it("should convert multiple newlines to multiple LaTeX line breaks", () => {
+ const input = "Line 1\n\n\nLine 2";
+ const expected = "Line 1 \\\\\\\\ \\\\\\\\ \\\\\\\\ Line 2";
+ expect(convertNewlinesToLatexBreaks(input)).toBe(expected);
+ });
+
+ it("should handle empty strings", () => {
+ expect(convertNewlinesToLatexBreaks("")).toBe("");
+ });
+
+ it("should handle strings with no newlines", () => {
+ const input = "No newlines here";
+ expect(convertNewlinesToLatexBreaks(input)).toBe(input);
+ });
+
+ it("should handle newlines at start and end", () => {
+ const input = "\nStart\nEnd\n";
+ const expected = " \\\\\\\\ Start \\\\\\\\ End \\\\\\\\ ";
+ expect(convertNewlinesToLatexBreaks(input)).toBe(expected);
+ });
+ });
});
describe("parseDelimiters", () => {
@@ -322,4 +351,60 @@ describe("renderMath", () => {
expect(result).toContain('title="SomeOtherError: A different issue"');
});
});
+
+ describe("Newline Handling", () => {
+ beforeEach(() => {
+ // Reset mock to default behavior for newline tests
+ mockedKatex.renderToString.mockImplementation((str, options) => {
+ const displayClass = options?.displayMode ? "katex-display" : "";
+ const classList = ["katex", displayClass].filter(Boolean).join(" ");
+ return `${str}`;
+ });
+ });
+
+ it("should convert newlines to LaTeX line breaks in text segments", () => {
+ const input = "First line\nSecond line\nThird line";
+ const expected = "First line \\\\\\\\ Second line \\\\\\\\ Third line";
+ const result = renderMath(input);
+ expect(result).toBe(expected);
+ });
+
+ it("should convert newlines in text but preserve them in math", () => {
+ const input = "Text line 1\nText line 2\n$\\begin{pmatrix} a \\\\ b \\end{pmatrix}$\nText line 3";
+ const expected = "Text line 1 \\\\\\\\ Text line 2 \\\\\\\\ \\begin{pmatrix} a \\\\ b \\end{pmatrix} \\\\\\\\ Text line 3";
+ const result = renderMath(input);
+ expect(result).toBe(expected);
+ });
+
+ it("should handle multiple consecutive newlines", () => {
+ const input = "Line 1\n\n\nLine 2";
+ const expected = "Line 1 \\\\\\\\ \\\\\\\\ \\\\\\\\ Line 2";
+ const result = renderMath(input);
+ expect(result).toBe(expected);
+ });
+
+ it("should handle newlines at start and end of text", () => {
+ const input = "\nStart with newline\nEnd with newline\n";
+ const expected = " \\\\\\\\ Start with newline \\\\\\\\ End with newline \\\\\\\\ ";
+ const result = renderMath(input);
+ expect(result).toBe(expected);
+ });
+
+ it("should not affect newlines inside LaTeX equations", () => {
+ const input = "$\\begin{align}\na &= 1\\\\\nb &= 2\n\\end{align}$";
+ const mathContent = "\\begin{align}\na &= 1\\\\\nb &= 2\n\\end{align}";
+ const expected = `${mathContent}`;
+
+ const result = renderMath(input);
+ expect(result).toBe(expected);
+ expect(mockedKatex.renderToString).toHaveBeenCalledWith(mathContent, expect.any(Object));
+ });
+
+ it("should handle mixed newlines and escaped characters", () => {
+ const input = "Price: \\$5\nNext line\nMath: $x=1$\nFinal line";
+ const expected = "Price: $5 \\\\\\\\ Next line \\\\\\\\ Math: x=1 \\\\\\\\ Final line";
+ const result = renderMath(input);
+ expect(result).toBe(expected);
+ });
+ });
});
\ No newline at end of file
diff --git a/src/index.ts b/src/index.ts
index 31e550d..0789bd2 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -138,6 +138,16 @@ const revertEscapedCharacters = (input: string): string => {
return input.replace(unescapeAllPlaceholdersRegex, (match: string) => mathUnEscapes[match]);
};
+/**
+ * Converts newlines in text content to LaTeX line breaks.
+ * This function replaces `\n` with ` \\\\ ` which represents a line break in LaTeX.
+ * @param input - The text content to process.
+ * @returns The text with newlines converted to LaTeX line breaks.
+ */
+const convertNewlinesToLatexBreaks = (input: string): string => {
+ return input.replace(/\n/g, ' \\\\\\\\ ');
+};
+
/**
* Parses an input string to find and extract content enclosed within delimiters.
* It segments the input into an array of objects, distinguishing between regular
@@ -254,7 +264,9 @@ const renderMath = (input: string): string => {
let renderedOutput = '';
parsedInput.forEach((match: ParsedSegment) => {
if (match.type == 'text') {
- renderedOutput += unescapeCharacters(match.content);
+ // Convert newlines to LaTeX line breaks in text segments
+ const textWithLineBreaks = convertNewlinesToLatexBreaks(match.content);
+ renderedOutput += unescapeCharacters(textWithLineBreaks);
} else if (match.type == 'math') {
renderedOutput += katex
.renderToString(revertEscapedCharacters(match.content), {
@@ -281,6 +293,7 @@ export {
unescapeCharacters,
revertEscapedCharacters,
parseDelimiters,
+ convertNewlinesToLatexBreaks,
// Export types for use in tests
ParsedSegment,
Delimiter,