Skip to content

Commit c7af9a9

Browse files
Add optional replace override to parser
Update `domToReact` and `htmlToReact` to have a second and optional argument which is an object with a `replace` method. The method will give the user access to the DOM node object and if a valid React element is returned, then it will override the node. Thus, the user can set the logic or condition in which a node is replaced with a custom React element. Add tests to check that the option works as expected. Tidy up and organize HTML to React tests.
1 parent 006d5c2 commit c7af9a9

File tree

3 files changed

+104
-33
lines changed

3 files changed

+104
-33
lines changed

index.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ var domToReact = require('./lib/dom-to-react');
99
/**
1010
* Convert HTML to React.
1111
*
12-
* @param {String} html - The HTML.
12+
* @param {String} html - The HTML.
13+
* @param {Object} [options] - The additional options.
14+
* @param {Function} [options.replace] - The replace method.
1315
* @return {ReactElement|Array}
1416
*/
15-
function htmlToReact(html) {
16-
return domToReact(htmlToDOM(html));
17+
function htmlToReact(html, options) {
18+
return domToReact(htmlToDOM(html), options);
1719
}
1820

1921
/**

lib/dom-to-react.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,33 @@ var attributesToProps = require('./attributes-to-props');
99
/**
1010
* Convert DOM nodes to React elements.
1111
*
12-
* @param {Array} nodes - The DOM nodes.
12+
* @param {Array} nodes - The DOM nodes.
13+
* @param {Object} [options] - The additional options.
14+
* @param {Function} [options.replace] - The replace method.
1315
* @return {ReactElement|Array}
1416
*/
15-
function domToReact(nodes) {
17+
function domToReact(nodes, options) {
18+
options = options || {};
1619
var result = [];
1720
var node;
21+
var isReplacePresent = typeof options.replace === 'function';
22+
var replacement;
1823
var props;
1924
var children;
2025

2126
for (var i = 0, len = nodes.length; i < len; i++) {
2227
node = nodes[i];
2328

29+
// replace with custom React element (if applicable)
30+
if (isReplacePresent) {
31+
replacement = options.replace(node);
32+
33+
if (React.isValidElement(replacement)) {
34+
result.push(replacement);
35+
continue;
36+
}
37+
}
38+
2439
if (node.type === 'text') {
2540
result.push(node.data);
2641
continue;

test/html-to-react.js

Lines changed: 82 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -22,40 +22,94 @@ function render(reactElement) {
2222
/**
2323
* Tests for `htmlToReact`.
2424
*/
25-
describe('html-to-react parser', function() {
25+
describe('html-to-react', function() {
2626

27-
it('converts single HTML element to React', function() {
28-
var html = data.html.single;
29-
var reactElement = Parser(html);
30-
assert.equal(render(reactElement), html);
31-
});
27+
/**
28+
* Parser conversion.
29+
*/
30+
describe('parser', function() {
3231

33-
it('converts single HTML element and ignores comment', function() {
34-
var html = data.html.single;
35-
// comment should be ignored
36-
var reactElement = Parser(html + data.html.comment);
37-
assert.equal(render(reactElement), html);
38-
});
32+
it('converts single HTML element to React', function() {
33+
var html = data.html.single;
34+
var reactElement = Parser(html);
35+
assert.equal(render(reactElement), html);
36+
});
3937

40-
it('converts multiple HTML elements to React', function() {
41-
var html = data.html.multiple;
42-
var reactElements = Parser(html);
43-
assert.equal(
44-
render(React.createElement('div', {}, reactElements)),
45-
'<div>' + html + '</div>'
46-
);
47-
});
38+
it('converts single HTML element and ignores comment', function() {
39+
var html = data.html.single;
40+
// comment should be ignored
41+
var reactElement = Parser(html + data.html.comment);
42+
assert.equal(render(reactElement), html);
43+
});
44+
45+
it('converts multiple HTML elements to React', function() {
46+
var html = data.html.multiple;
47+
var reactElements = Parser(html);
48+
assert.equal(
49+
render(React.createElement('div', {}, reactElements)),
50+
'<div>' + html + '</div>'
51+
);
52+
});
53+
54+
it('converts complex HTML to React', function() {
55+
var html = data.html.complex;
56+
var reactElement = Parser(html);
57+
assert.equal(render(reactElement), html);
58+
});
59+
60+
it('converts SVG to React', function() {
61+
var svg = data.svg.complex;
62+
var reactElement = Parser(svg);
63+
assert.equal(render(reactElement), svg);
64+
});
4865

49-
it('converts complex HTML to React', function() {
50-
var html = data.html.complex;
51-
var reactElement = Parser(html);
52-
assert.equal(render(reactElement), html);
5366
});
5467

55-
it('converts SVG to React', function() {
56-
var svg = data.svg.complex;
57-
var reactElement = Parser(svg);
58-
assert.equal(render(reactElement), svg);
68+
/**
69+
* Options.
70+
*/
71+
describe('options', function() {
72+
73+
describe('replace', function() {
74+
75+
it('overrides the element if replace is valid', function() {
76+
var html = data.html.complex;
77+
var reactElement = Parser(html, {
78+
replace: function(node) {
79+
if (node.name === 'title') {
80+
return React.createElement('meta', { charSet: 'utf-8' });
81+
}
82+
}
83+
});
84+
assert.equal(
85+
render(reactElement),
86+
html.replace('<title>Title</title>', '<meta charset="utf-8"/>')
87+
);
88+
});
89+
90+
it('does not override the element if replace is invalid', function() {
91+
var html = data.html.complex;
92+
var reactElement = Parser(html, {
93+
replace: function(node) {
94+
if (node.attribs && node.attribs.id === 'header') {
95+
return {
96+
type: 'h1',
97+
props: { children: 'Heading' }
98+
};
99+
}
100+
}
101+
});
102+
assert.notEqual(
103+
render(reactElement),
104+
html.replace(
105+
'<header id="header">Header</header>',
106+
'<h1>Heading</h1>'
107+
)
108+
);
109+
});
110+
111+
});
112+
59113
});
60114

61115
});

0 commit comments

Comments
 (0)