Skip to content

Commit 6c7ac1d

Browse files
Merge pull request #923 from remarkablemark/fix/utilities
fix(client): don't break LaTeX when replacing carriage returns
2 parents bcda37e + d69bc66 commit 6c7ac1d

File tree

5 files changed

+62
-27
lines changed

5 files changed

+62
-27
lines changed

src/client/constants.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,11 @@ export const CASE_SENSITIVE_TAG_NAMES_MAP = CASE_SENSITIVE_TAG_NAMES.reduce(
4444
},
4545
{} as Record<string, string>,
4646
);
47+
48+
export const CARRIAGE_RETURN = '\r';
49+
export const CARRIAGE_RETURN_REGEX = new RegExp(CARRIAGE_RETURN, 'g');
50+
export const CARRIAGE_RETURN_PLACEHOLDER = `__HTML_DOM_PARSER_CARRIAGE_RETURN_PLACEHOLDER_${Date.now()}__`;
51+
export const CARRIAGE_RETURN_PLACEHOLDER_REGEX = new RegExp(
52+
CARRIAGE_RETURN_PLACEHOLDER,
53+
'g',
54+
);

src/client/utilities.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
import { Comment, Element, ProcessingInstruction, Text } from 'domhandler';
22

33
import type { DOMNode } from '../types';
4-
import { CASE_SENSITIVE_TAG_NAMES_MAP } from './constants';
4+
import {
5+
CARRIAGE_RETURN,
6+
CARRIAGE_RETURN_PLACEHOLDER,
7+
CARRIAGE_RETURN_PLACEHOLDER_REGEX,
8+
CARRIAGE_RETURN_REGEX,
9+
CASE_SENSITIVE_TAG_NAMES_MAP,
10+
} from './constants';
511

612
/**
713
* Gets case-sensitive tag name.
@@ -58,7 +64,7 @@ function formatTagName(tagName: string): string {
5864
* @returns - HTML string with escaped special characters.
5965
*/
6066
export function escapeSpecialCharacters(html: string): string {
61-
return html.replace(/\r/g, '\\r');
67+
return html.replace(CARRIAGE_RETURN_REGEX, CARRIAGE_RETURN_PLACEHOLDER);
6268
}
6369

6470
/**
@@ -68,7 +74,7 @@ export function escapeSpecialCharacters(html: string): string {
6874
* @returns - Text with escaped characters reverted.
6975
*/
7076
export function revertEscapedCharacters(text: string): string {
71-
return text.replace(/\\r/g, '\r');
77+
return text.replace(CARRIAGE_RETURN_PLACEHOLDER_REGEX, CARRIAGE_RETURN);
7278
}
7379

7480
/**

test/cases/html.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,16 @@ module.exports = [
327327
data: '<div>Hello\r<span>Beautiful\r</span>World</div>',
328328
},
329329

330+
// LaTeX
331+
{
332+
name: 'LaTeX',
333+
data: '<span class="math">\\left(\\right)\\rD\\rightarrow\\reals\\ni</span>',
334+
},
335+
{
336+
name: 'LaTeX with carriage return',
337+
data: '<span class="math">\\left(\\right)\\rD\\rightarrow\\reals\\ni</span>\r\n',
338+
},
339+
330340
// custom tag
331341
{
332342
name: 'custom tag',

test/cases/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,5 @@ module.exports = {
3434
html,
3535
svg,
3636
};
37+
38+
module.exports.default = module.exports;

test/server/client.test.ts

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { expect } from 'chai';
22

3+
import { CARRIAGE_RETURN_PLACEHOLDER } from '../../src/client/constants';
34
import { formatDOM } from '../../src/client/utilities';
45
import { revertEscapedCharacters } from '../../src/client/utilities';
56
import { escapeSpecialCharacters } from '../../src/client/utilities';
@@ -15,59 +16,67 @@ describe('client utilities', () => {
1516

1617
describe('escapeSpecialCharacters', () => {
1718
it('escapes carriage return characters', () => {
18-
const input = 'Hello\rWorld';
19-
const expected = 'Hello\\rWorld';
20-
expect(escapeSpecialCharacters(input)).to.equal(expected);
19+
expect(escapeSpecialCharacters('Hello\rWorld')).to.equal(
20+
`Hello${CARRIAGE_RETURN_PLACEHOLDER}World`,
21+
);
2122
});
2223

2324
it('does not modify strings without special characters', () => {
24-
const input = 'Hello World';
25-
expect(escapeSpecialCharacters(input)).to.equal(input);
25+
const text = 'Hello World';
26+
expect(escapeSpecialCharacters(text)).to.equal(text);
2627
});
2728

2829
it('handles empty strings', () => {
29-
expect(escapeSpecialCharacters('')).to.equal('');
30+
const text = '';
31+
expect(escapeSpecialCharacters(text)).to.equal(text);
3032
});
3133

3234
it('handles multiple carriage returns', () => {
33-
const input = 'Hello\rDear\rWorld';
34-
const expected = 'Hello\\rDear\\rWorld';
35-
expect(escapeSpecialCharacters(input)).to.equal(expected);
35+
expect(escapeSpecialCharacters('Hello\rDear\rWorld')).to.equal(
36+
`Hello${CARRIAGE_RETURN_PLACEHOLDER}Dear${CARRIAGE_RETURN_PLACEHOLDER}World`,
37+
);
3638
});
3739

3840
it('only escapes carriage returns', () => {
39-
const input = 'Hello\rWorld\n'; // \n should not be affected
40-
const expected = 'Hello\\rWorld\n';
41-
expect(escapeSpecialCharacters(input)).to.equal(expected);
41+
// `\n` and `\right` should not be affected
42+
expect(escapeSpecialCharacters('Hello\rWorld\n\right')).to.equal(
43+
`Hello${CARRIAGE_RETURN_PLACEHOLDER}World\n${CARRIAGE_RETURN_PLACEHOLDER}ight`,
44+
);
4245
});
4346
});
4447

4548
describe('revertEscapedCharacters', () => {
4649
it('reverts escaped carriage return characters', () => {
47-
const input = 'Hello\\rWorld';
48-
const expected = 'Hello\rWorld';
49-
expect(revertEscapedCharacters(input)).to.equal(expected);
50+
expect(
51+
revertEscapedCharacters(`Hello${CARRIAGE_RETURN_PLACEHOLDER}World`),
52+
).to.equal('Hello\rWorld');
5053
});
5154

5255
it('does not modify strings without escaped characters', () => {
53-
const input = 'Hello World';
54-
expect(revertEscapedCharacters(input)).to.equal(input);
56+
const text = 'Hello World';
57+
expect(revertEscapedCharacters(text)).to.equal(text);
5558
});
5659

5760
it('handles empty strings', () => {
58-
expect(revertEscapedCharacters('')).to.equal('');
61+
const text = '';
62+
expect(revertEscapedCharacters(text)).to.equal(text);
5963
});
6064

6165
it('handles multiple escaped carriage returns', () => {
62-
const input = 'Hello\\rDear\\rWorld';
63-
const expected = 'Hello\rDear\rWorld';
64-
expect(revertEscapedCharacters(input)).to.equal(expected);
66+
expect(
67+
revertEscapedCharacters(
68+
`Hello${CARRIAGE_RETURN_PLACEHOLDER}Dear${CARRIAGE_RETURN_PLACEHOLDER}World`,
69+
),
70+
).to.equal('Hello\rDear\rWorld');
6571
});
6672

6773
it('only reverts escaped carriage returns', () => {
68-
const input = 'Hello\\rWorld\\n'; // \n should not be affected
69-
const expected = 'Hello\rWorld\\n';
70-
expect(revertEscapedCharacters(input)).to.equal(expected);
74+
// `\n` and `\right` should not be affected
75+
expect(
76+
revertEscapedCharacters(
77+
`Hello${CARRIAGE_RETURN_PLACEHOLDER}World\\n\\right`,
78+
),
79+
).to.equal('Hello\rWorld\\n\\right');
7180
});
7281
});
7382
});

0 commit comments

Comments
 (0)