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

Commit bed7d07

Browse files
wooormmedfreeman
andcommitted
Add support for Vue
Closes GH-7. Closes GH-17. Co-authored-by: Mehdi Lahlou <mehdi.lahlou@free.fr>
1 parent 75849d1 commit bed7d07

File tree

3 files changed

+138
-10
lines changed

3 files changed

+138
-10
lines changed

index.js

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ function wrapper(h, node, options) {
1818
var prefix
1919
var r
2020
var v
21+
var vd
2122

2223
if (typeof h !== 'function') {
2324
throw new Error('h is not a function')
@@ -31,10 +32,11 @@ function wrapper(h, node, options) {
3132
}
3233

3334
r = react(h)
34-
v = vdom(h)
35+
v = vue(h)
36+
vd = vdom(h)
3537

3638
if (prefix === null || prefix === undefined) {
37-
prefix = r === true || v === true ? 'h-' : false
39+
prefix = r === true || v === true || vd === true ? 'h-' : false
3840
}
3941

4042
if (is('root', node)) {
@@ -59,7 +61,8 @@ function wrapper(h, node, options) {
5961
prefix: prefix,
6062
key: 0,
6163
react: r,
62-
vdom: v,
64+
vue: v,
65+
vdom: vd,
6366
hyperscript: hyperscript(h)
6467
})
6568
}
@@ -98,9 +101,9 @@ function toH(h, node, ctx) {
98101

99102
if (
100103
typeof attributes.style === 'string' &&
101-
(ctx.vdom === true || ctx.react === true)
104+
(ctx.vdom === true || ctx.vue === true || ctx.react === true)
102105
) {
103-
// VDOM and React accept `style` as object.
106+
// VDOM, Vue, and React accept `style` as object.
104107
attributes.style = parseStyle(attributes.style, name)
105108
}
106109

@@ -165,7 +168,11 @@ function addAttribute(props, prop, value, ctx) {
165168
value = ''
166169
}
167170

168-
if (!info.mustUseProperty) {
171+
if (ctx.vue) {
172+
if (prop !== 'style') {
173+
subprop = 'attrs'
174+
}
175+
} else if (!info.mustUseProperty) {
169176
if (ctx.vdom === true) {
170177
subprop = 'attributes'
171178
} else if (ctx.hyperscript === true) {
@@ -202,6 +209,11 @@ function vdom(h) {
202209
return h && h('div').type === 'VirtualNode'
203210
}
204211

212+
function vue(h) {
213+
var node = h && h('div')
214+
return Boolean(node && node.context && node.context._isVue)
215+
}
216+
205217
function parseStyle(value, tagName) {
206218
var result = {}
207219

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
"unist-builder": "^1.0.1",
4848
"vdom-to-html": "^2.3.1",
4949
"virtual-dom": "^2.1.1",
50+
"vue": "^2.6.10",
51+
"vue-server-renderer": "^2.6.10",
5052
"xo": "^0.24.0"
5153
},
5254
"scripts": {
@@ -78,7 +80,8 @@
7880
"rules": {
7981
"unicorn/prefer-type-error": "off",
8082
"guard-for-in": "off",
81-
"no-self-compare": "off"
83+
"no-self-compare": "off",
84+
"complexity": "off"
8285
}
8386
},
8487
"remarkConfig": {

test.js

Lines changed: 116 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ var r = require('react').createElement
1010
var rehype = require('rehype')
1111
var vToString = require('vdom-to-html')
1212
var rToString = require('react-dom/server').renderToStaticMarkup
13+
var Vue = require('vue')
14+
var VueSSR = require('vue-server-renderer')
1315
var toH = require('.')
1416

1517
var processor = rehype().data('settings', {fragment: true, position: false})
@@ -382,6 +384,119 @@ test('hast-to-hyperscript', function(t) {
382384
st.end()
383385
})
384386

387+
t.test('should support `Vue`', function(st) {
388+
var baseline = doc.replace(/<div>/, '<div data-server-rendered="true">')
389+
var actual
390+
var expected
391+
392+
st.plan(3)
393+
394+
Promise.all([vueToString(actualRender), vueToString(expectedRender)])
395+
.then(function(all) {
396+
var actualString = all[0]
397+
var expectedString = all[0]
398+
399+
st.deepEqual(clean(actual), clean(expected), 'equal syntax trees')
400+
st.deepEqual(html(actualString), html(baseline), 'equal output')
401+
402+
st.deepEqual(
403+
html(expectedString),
404+
html(baseline),
405+
'equal output baseline'
406+
)
407+
})
408+
.catch(function(error) {
409+
st.ifErr(error, 'did not expect an error')
410+
})
411+
412+
function actualRender(h) {
413+
actual = toH(h, hast)
414+
return actual
415+
}
416+
417+
function expectedRender(h) {
418+
expected = h(
419+
'div',
420+
{key: 'h-1', attrs: {'data-server-rendered': 'true'}},
421+
[
422+
h(
423+
'h1',
424+
{
425+
key: 'h-2',
426+
attrs: {
427+
class: 'b c',
428+
id: 'a',
429+
hidden: true,
430+
height: 2
431+
}
432+
},
433+
[
434+
'bravo ',
435+
h(
436+
'strong',
437+
{
438+
key: 'h-3',
439+
style: {color: 'red'},
440+
attrs: {
441+
foo: 'bar',
442+
camelCase: 'on off',
443+
'data-123': '456',
444+
'data-some': 'yes',
445+
'aria-valuenow': '1'
446+
}
447+
},
448+
['charlie']
449+
),
450+
' delta',
451+
h('input', {
452+
key: 'h-4',
453+
attrs: {
454+
checked: true,
455+
type: 'file',
456+
accept: '.jpg, .jpeg'
457+
}
458+
})
459+
]
460+
),
461+
h(
462+
'svg',
463+
{
464+
key: 'h-5',
465+
attrs: {
466+
xmlns: 'http://www.w3.org/2000/svg',
467+
viewBox: '0 0 500 500'
468+
}
469+
},
470+
[h('circle', {key: 'h-6', attrs: {cx: 120, cy: 120, r: 100}})]
471+
)
472+
]
473+
)
474+
return expected
475+
}
476+
477+
function identity(value) {
478+
return value
479+
}
480+
481+
function vueToString(render) {
482+
return VueSSR.createRenderer({template: identity}).renderToString(
483+
new Vue({render: render}).$mount()
484+
)
485+
}
486+
487+
function clean(node) {
488+
remove(node)
489+
return json(node)
490+
}
491+
492+
function remove(node) {
493+
delete node.context
494+
if (node.children) {
495+
node.children.forEach(remove)
496+
}
497+
}
498+
})
499+
385500
t.test('should support keys', function(st) {
386501
st.equal(
387502
toH(h, u('element', {tagName: 'div'})).key,
@@ -504,9 +619,7 @@ test('hast-to-hyperscript', function(t) {
504619
st.end()
505620
})
506621

507-
t.test('flattens a `root` with one element child to that child', function(
508-
st
509-
) {
622+
t.test('flattens a `root` with one element to that child', function(st) {
510623
var actual = toH(
511624
h,
512625
u('root', [u('element', {tagName: 'h1', properties: {id: 'a'}}, [])])

0 commit comments

Comments
 (0)