Skip to content

Commit

Permalink
fix(formatting): Fix JSX delimiters escaping in string
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Improve string escaping of string that contains JSX delimiters (`{`,`}`,`<`,`>`)

Before:
```
console.log(reactElementToJsxString(<div>{`Mustache :{`}</div>);

// <div>Mustache :&lbrace;</div>
```

Now:
```
console.log(reactElementToJsxString(<div>{`Mustache :{`}</div>);

// <div>{`Mustache :{`}</div>
```
  • Loading branch information
armandabric committed Aug 3, 2017
1 parent d18809e commit 6e0eea3
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 35 deletions.
21 changes: 17 additions & 4 deletions src/formatter/formatTreeNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,30 @@ import formatReactElementNode from './formatReactElementNode';
import type { Options } from './../options';
import type { TreeNode } from './../tree';

const escape = (s: string): string =>
s.replace(/{/g, '&lbrace;').replace(/}/g, '&rbrace;');
const jsxStopChars = ['<', '>', '{', '}'];
const shouldBeEscaped = (s: string) =>
jsxStopChars.some(jsxStopChar => s.includes(jsxStopChar));

const escape = (s: string) => {
if (!shouldBeEscaped(s)) {
return s;
}

return `{\`${s}\`}`;
};

export default (
node: TreeNode,
inline: boolean,
lvl: number,
options: Options
): string => {
if (node.type === 'string' || node.type === 'number') {
return node.value ? escape(node.value.toString()) : '';
if (node.type === 'number') {
return String(node.value);
}

if (node.type === 'string') {
return node.value ? escape(String(node.value)) : '';
}

if (node.type === 'ReactElement') {
Expand Down
66 changes: 63 additions & 3 deletions src/formatter/formatTreeNode.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,70 @@

import formatTreeNode from './formatTreeNode';

jest.mock('./formatReactElementNode', () => () =>
'<MockedFormatReactElementNodeResult />'
);

describe('formatTreeNode', () => {
it('should escape JSX entity on string node', () => {
it('should format number tree node', () => {
expect(formatTreeNode({ type: 'number', value: 42 }, true, 0, {})).toBe(
'42'
);
});

it('should format string tree node', () => {
expect(formatTreeNode({ type: 'string', value: 'foo' }, true, 0, {})).toBe(
'foo'
);
});

it('should format react element tree node', () => {
expect(
formatTreeNode(
{
type: 'ReactElement',
displayName: 'Foo',
},
true,
0,
{}
)
).toBe('<MockedFormatReactElementNodeResult />');
});

const jsxDelimiters = ['<', '>', '{', '}'];
jsxDelimiters.forEach(char => {
it(`should escape string that contains the JSX delimiter "${char}"`, () => {
expect(
formatTreeNode(
{ type: 'string', value: `I contain ${char}, is will be escaped` },
true,
0,
{}
)
).toBe(`{\`I contain ${char}, is will be escaped\`}`);
});
});

it('should preserve the format of string', () => {
expect(formatTreeNode({ type: 'string', value: 'foo\nbar' }, true, 0, {}))
.toBe(`foo
bar`);

expect(
formatTreeNode({ type: 'string', value: '{ foo: "bar" }' }, true, 0, {})
).toBe('&lbrace; foo: "bar" &rbrace;');
formatTreeNode(
{
type: 'string',
value: JSON.stringify({ foo: 'bar' }, null, 2),
},
false,
0,
{
tabStop: 2,
}
)
).toBe(`{\`{
"foo": "bar"
}\`}`);
});
});
32 changes: 4 additions & 28 deletions src/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,16 +206,16 @@ describe('reactElementToJSXString(ReactElement)', () => {
);
});

it('reactElementToJSXString(<script type="application/json+ld">&lbrace; hello: \'world\' &rbrace;</script>)', () => {
it('reactElementToJSXString(<script type="application/json+ld">{`{ hello: \'world\' }`}</script>)', () => {
expect(
reactElementToJSXString(
<script type="application/json+ld">
&lbrace; hello: 'world' &rbrace;
{`{ hello: 'world' }`}
</script>
)
).toEqual(
`<script type="application/json+ld">
&lbrace; hello: 'world' &rbrace;
{\`{ hello: 'world' }\`}
</script>`
);
});
Expand All @@ -227,31 +227,7 @@ describe('reactElementToJSXString(ReactElement)', () => {
)
).toEqual(
`<script type="application/json+ld">
&lbrace; hello: 'world' &rbrace;
</script>`
);
});

it('reactElementToJSXString(<script type="application/json+ld">\\u007B hello: \'world\' \\u007D</script>)', () => {
expect(
reactElementToJSXString(
<script type="application/json+ld">\u007B hello: 'world' \u007D</script>
)
).toEqual(
`<script type="application/json+ld">
\\u007B hello: 'world' \\u007D
</script>`
);
});

it('reactElementToJSXString(<script type="application/json+ld">{ hello: \'world\' }</script>)', () => {
expect(
reactElementToJSXString(
<script type="application/json+ld">{`{ hello: 'world' }`}</script>
)
).toEqual(
`<script type="application/json+ld">
&lbrace; hello: 'world' &rbrace;
{\`{ hello: 'world' }\`}
</script>`
);
});
Expand Down

0 comments on commit 6e0eea3

Please sign in to comment.