Skip to content
This repository was archived by the owner on Aug 9, 2023. It is now read-only.

Commit ab844cc

Browse files
derhuerstwooorm
authored andcommitted
Add support for root nodes
Closes GH-10. Amended-by: Titus Wormer <tituswormer@gmail.com>
1 parent 666a3aa commit ab844cc

File tree

3 files changed

+80
-13
lines changed

3 files changed

+80
-13
lines changed

index.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,28 @@ function wrapper(h, node, prefix) {
1818
throw new Error('h is not a function');
1919
}
2020

21-
if (!is('element', node)) {
22-
throw new Error('Expected element, not `' + node + '`');
23-
}
24-
2521
r = react(h);
2622
v = vdom(h);
2723

2824
if (prefix === null || prefix === undefined) {
2925
prefix = r === true || v === true ? 'h-' : false;
3026
}
3127

28+
if (is('root', node)) {
29+
if (node.children.length === 1 && is('element', node.children[0])) {
30+
node = node.children[0];
31+
} else {
32+
node = {
33+
type: 'element',
34+
tagName: 'div',
35+
properties: {},
36+
children: node.children
37+
};
38+
}
39+
} else if (!is('element', node)) {
40+
throw new Error('Expected root or element, not `' + ((node && node.type) || node) + '`');
41+
}
42+
3243
return toH(h, node, {
3344
prefix: prefix,
3445
key: 0,

readme.md

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,24 @@ Transform [HAST][] to something else through a hyperscript DSL.
7878

7979
###### Caveats
8080

81-
Although there are lots of libs mentioning support for this interface,
82-
there are significant differences between them. For example, hyperscript
83-
doesn’t support classes in `attrs`, `virtual-dom/h` needs an `attributes`
84-
object inside `attrs` most of the time. `hast-to-hyperscript` works
85-
around these differences for:
81+
**Nodes**: Most hyperscript implementations only support elements and text (as
82+
leave nodes). HAST supports `doctype`, `comment`, and `root` as well.
83+
84+
* If anything other than an `element` or `root` node is given,
85+
`hast-to-hyperscript` throws
86+
* If a `root` is given with one element child, that element is
87+
transformed
88+
* If a `root` with no children, a non-element only child, or more than one
89+
children, the children are wrapped in a `div` element
90+
91+
If unknown nodes are found deeper in the tree, they are ignored: only `text`
92+
and `element` nodes are transformed.
93+
94+
**Support**: Although there are lots of libs mentioning support for this
95+
interface, there are significant differences between them. For example,
96+
hyperscript doesn’t support classes in `attrs`, `virtual-dom/h` needs an
97+
`attributes` object inside `attrs` most of the time. `hast-to-hyperscript`
98+
works around these differences for:
8699

87100
* [`React.createElement`][react]
88101
* [`virtual-dom/h`][vdom]

test.js

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,15 @@ test('hast-to-hyperscript', function (t) {
2828
t.test('should throw if not given a node', function (st) {
2929
t.throws(function () {
3030
toH(h);
31-
}, /Expected element, not `undefined`/);
31+
}, /Expected root or element, not `undefined`/);
3232

3333
t.throws(function () {
34-
toH(h, 'text');
35-
}, /Error: Expected element, not `text`/);
34+
toH(h, u('text', 'Alpha'));
35+
}, /Error: Expected root or element, not `text`/);
3636

3737
t.throws(function () {
3838
toH(h, u('text', 'value'));
39-
}, /Expected element/);
39+
}, /Expected root or element/);
4040

4141
st.end();
4242
});
@@ -274,6 +274,49 @@ test('hast-to-hyperscript', function (t) {
274274
st.end();
275275
});
276276

277+
t.test('flattens a `root` with one element child to that child', function (st) {
278+
var actual = toH(h, u('root', [u('element', {tagName: 'h1', properties: {id: 'a'}}, [])]));
279+
var expected = h('h1#a');
280+
var doc = '<h1 id="a"></h1>';
281+
282+
st.deepEqual(html(actual.outerHTML), html(doc), 'equal output');
283+
st.deepEqual(html(expected.outerHTML), html(doc), 'equal output baseline');
284+
st.end();
285+
});
286+
287+
t.test('flattens a `root` without children to a `div`', function (st) {
288+
var actual = toH(h, u('root', []));
289+
var expected = h('div');
290+
var doc = '<div></div>';
291+
292+
st.deepEqual(html(actual.outerHTML), html(doc), 'equal output');
293+
st.deepEqual(html(expected.outerHTML), html(doc), 'equal output baseline');
294+
st.end();
295+
});
296+
297+
t.test('flattens a `root` with a text child to a `div`', function (st) {
298+
var actual = toH(h, u('root', [u('text', 'Alpha')]));
299+
var expected = h('div', 'Alpha');
300+
var doc = '<div>Alpha</div>';
301+
302+
st.deepEqual(html(actual.outerHTML), html(doc), 'equal output');
303+
st.deepEqual(html(expected.outerHTML), html(doc), 'equal output baseline');
304+
st.end();
305+
});
306+
307+
t.test('flattens a `root` with more children to a `div`', function (st) {
308+
var actual = toH(h, u('root', [
309+
u('element', {tagName: 'h1'}, [u('text', 'Alpha')]),
310+
u('element', {tagName: 'p'}, [u('text', 'Bravo')])
311+
]));
312+
var expected = h('div', [h('h1', 'Alpha'), h('p', 'Bravo')]);
313+
var doc = '<div><h1>Alpha</h1><p>Bravo</p></div>';
314+
315+
st.deepEqual(html(actual.outerHTML), html(doc), 'equal output');
316+
st.deepEqual(html(expected.outerHTML), html(doc), 'equal output baseline');
317+
st.end();
318+
});
319+
277320
t.end();
278321
});
279322

0 commit comments

Comments
 (0)