Skip to content

Commit

Permalink
fix: enable client parser to retain carriage return characters (#902)
Browse files Browse the repository at this point in the history
* fix: enable client parser to retain carriage return characters

* fix: enable client parser to retain carriage return characters

* chore: only find \r not \n

* chore: add missing tests

* chore: add missing tests
  • Loading branch information
kingflamez authored Dec 4, 2024
1 parent c4fc01e commit fe2e993
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 6 deletions.
14 changes: 9 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/client/domparser.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { escapeSpecialCharacters } from './utilities';

// constants
const HTML = 'html';
const HEAD = 'head';
Expand Down Expand Up @@ -116,6 +118,9 @@ if (template && template.content) {
* @returns - DOM nodes.
*/
export default function domparser(html: string): NodeList {
// Escape special characters before parsing
html = escapeSpecialCharacters(html);

const match = html.match(FIRST_TAG_REGEX);
const firstTagName = match && match[1] ? match[1].toLowerCase() : '';

Expand Down
22 changes: 21 additions & 1 deletion src/client/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,26 @@ function formatTagName(tagName: string): string {
return tagName;
}

/**
* Escapes special characters before parsing.
*
* @param html - The HTML string.
* @returns - HTML string with escaped special characters.
*/
export function escapeSpecialCharacters(html: string): string {
return html.replace(/\r/g, '\\r');
}

/**
* Reverts escaped special characters back to actual characters.
*
* @param text - The text with escaped characters.
* @returns - Text with escaped characters reverted.
*/
export function revertEscapedCharacters(text: string): string {
return text.replace(/\\r/g, '\r');
}

/**
* Transforms DOM nodes to `domhandler` nodes.
*
Expand Down Expand Up @@ -95,7 +115,7 @@ export function formatDOM(
}

case 3:
current = new Text(node.nodeValue!);
current = new Text(revertEscapedCharacters(node.nodeValue!));
break;

case 8:
Expand Down
22 changes: 22 additions & 0 deletions test/cases/html.js
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,28 @@ module.exports = [
data: ' ',
},

// text with special characters
{
name: 'text with carriage return',
data: 'Hello\rWorld',
},
{
name: 'text with multiple carriage returns',
data: 'Hello\rDear\rWorld',
},
{
name: 'text with mixed newlines and carriage returns',
data: 'Hello\rWorld\nNew\rLine',
},
{
name: 'text with carriage return in tag',
data: '<div>Hello\rWorld</div>',
},
{
name: 'nested tags with carriage returns',
data: '<div>Hello\r<span>Beautiful\r</span>World</div>',
},

// custom tag
{
name: 'custom tag',
Expand Down
60 changes: 60 additions & 0 deletions test/server/client.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { expect } from 'chai';

import { formatDOM } from '../../src/client/utilities';
import { revertEscapedCharacters } from '../../src/client/utilities';
import { escapeSpecialCharacters } from '../../src/client/utilities';

describe('client utilities', () => {
describe('formatDOM', () => {
Expand All @@ -10,4 +12,62 @@ describe('client utilities', () => {
).to.deep.equal([]);
});
});

describe('escapeSpecialCharacters', () => {
it('escapes carriage return characters', () => {
const input = 'Hello\rWorld';
const expected = 'Hello\\rWorld';
expect(escapeSpecialCharacters(input)).to.equal(expected);
});

it('does not modify strings without special characters', () => {
const input = 'Hello World';
expect(escapeSpecialCharacters(input)).to.equal(input);
});

it('handles empty strings', () => {
expect(escapeSpecialCharacters('')).to.equal('');
});

it('handles multiple carriage returns', () => {
const input = 'Hello\rDear\rWorld';
const expected = 'Hello\\rDear\\rWorld';
expect(escapeSpecialCharacters(input)).to.equal(expected);
});

it('only escapes carriage returns', () => {
const input = 'Hello\rWorld\n'; // \n should not be affected
const expected = 'Hello\\rWorld\n';
expect(escapeSpecialCharacters(input)).to.equal(expected);
});
});

describe('revertEscapedCharacters', () => {
it('reverts escaped carriage return characters', () => {
const input = 'Hello\\rWorld';
const expected = 'Hello\rWorld';
expect(revertEscapedCharacters(input)).to.equal(expected);
});

it('does not modify strings without escaped characters', () => {
const input = 'Hello World';
expect(revertEscapedCharacters(input)).to.equal(input);
});

it('handles empty strings', () => {
expect(revertEscapedCharacters('')).to.equal('');
});

it('handles multiple escaped carriage returns', () => {
const input = 'Hello\\rDear\\rWorld';
const expected = 'Hello\rDear\rWorld';
expect(revertEscapedCharacters(input)).to.equal(expected);
});

it('only reverts escaped carriage returns', () => {
const input = 'Hello\\rWorld\\n'; // \n should not be affected
const expected = 'Hello\rWorld\\n';
expect(revertEscapedCharacters(input)).to.equal(expected);
});
});
});

0 comments on commit fe2e993

Please sign in to comment.