From 7de5a9f8085f564957a27f5e26b6bebc0bb6dbf8 Mon Sep 17 00:00:00 2001 From: Mehdi Lahlou Date: Fri, 31 Aug 2018 13:15:06 +0200 Subject: [PATCH 01/10] add: add vue.js `createElement` detection --- index.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/index.js b/index.js index 7962cc7..07d57fa 100644 --- a/index.js +++ b/index.js @@ -18,6 +18,7 @@ function wrapper(h, node, options) { var prefix var r var v + var vu if (typeof h !== 'function') { throw new Error('h is not a function') @@ -32,6 +33,7 @@ function wrapper(h, node, options) { r = react(h) v = vdom(h) + vu = vue(h) if (prefix === null || prefix === undefined) { prefix = r === true || v === true ? 'h-' : false @@ -60,6 +62,7 @@ function wrapper(h, node, options) { key: 0, react: r, vdom: v, + vue: vu, hyperscript: hyperscript(h) }) } @@ -192,6 +195,11 @@ function react(h) { ) } +// Check if `h` is vue `createElement`. +function vue(h) { + return h && h('div')._isVue === true +} + // Check if `h` is `hyperscript`. function hyperscript(h) { return Boolean(h && h.context && h.cleanup) From 226020d826e9e0724b2c1e5a5deca5e5aeb20ce2 Mon Sep 17 00:00:00 2001 From: Mehdi Lahlou Date: Sat, 1 Sep 2018 02:32:43 +0200 Subject: [PATCH 02/10] chore: fix vue.js `createElement` detection --- index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 07d57fa..dbe5b97 100644 --- a/index.js +++ b/index.js @@ -197,7 +197,11 @@ function react(h) { // Check if `h` is vue `createElement`. function vue(h) { - return h && h('div')._isVue === true + if (typeof h === 'undefined') { + return + } + var div = h('div') + return div && div.context && div.context._isVue === true } // Check if `h` is `hyperscript`. From 8289f0e43d90f54ce2704fcd135c547d548a40bb Mon Sep 17 00:00:00 2001 From: Mehdi Lahlou Date: Sat, 1 Sep 2018 03:18:16 +0200 Subject: [PATCH 03/10] add: add base `vue.js` support --- index.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index dbe5b97..91764ef 100644 --- a/index.js +++ b/index.js @@ -101,9 +101,9 @@ function toH(h, node, ctx) { if ( typeof attributes.style === 'string' && - (ctx.vdom === true || ctx.react === true) + (ctx.vdom === true || ctx.react === true || ctx.vue === true) ) { - // VDOM and React accept `style` as object. + // VDOM, React and Vue accept `style` as object. attributes.style = parseStyle(attributes.style, name) } @@ -173,6 +173,10 @@ function addAttribute(props, prop, value, ctx) { subprop = 'attributes' } else if (ctx.hyperscript === true) { subprop = 'attrs' + } else if (ctx.vue === true) { + if (info.property && info.property !== 'style') { + subprop = 'attrs' + } } } From a400d93116b64d496a6f89060a458e15a361c81a Mon Sep 17 00:00:00 2001 From: Mehdi Lahlou Date: Tue, 4 Sep 2018 03:46:44 +0200 Subject: [PATCH 04/10] add: add full `vue.js` support --- index.js | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 91764ef..53fda5f 100644 --- a/index.js +++ b/index.js @@ -11,6 +11,22 @@ var is = require('unist-util-is') var dashes = /-([a-z])/g +var vueUtils = { + isTopLevel: makeMap([ + 'class', + 'staticClass', + 'style', + 'key', + 'ref', + 'refInFor', + 'slot', + 'scopedSlots' + ]), + nestableRE: /^(props|domProps|on|nativeOn|hook)([\-_A-Z])/, + dirRE: /^v-/, + xlinkRE: /^xlink([A-Z])/ +} + module.exports = wrapper function wrapper(h, node, options) { @@ -174,8 +190,38 @@ function addAttribute(props, prop, value, ctx) { } else if (ctx.hyperscript === true) { subprop = 'attrs' } else if (ctx.vue === true) { - if (info.property && info.property !== 'style') { - subprop = 'attrs' + var name = info.property + if (!vueUtils.isTopLevel(name)) { + // nested modules + var nestMatch = name.match(vueUtils.nestableRE) + if (nestMatch) { + var prefix = nestMatch[1] + var suffix = name.replace(vueUtils.nestableRE, function(_, $1, $2) { + return $2 === '-' ? '' : $2.toLowerCase() + }) + info.attribute = suffix + subprop = prefix + } else if (vueUtils.dirRE.test(name)) { + // custom directive + name = name.replace(vueUtils.dirRE, '') + value = { + name: name, + value: value + } + value = props.directives ? props.directives.concat([value]) : [value] + info.attribute = 'directives' + } else { + // rest are nested under attrs + // guard xlink attributes + if (vueUtils.xlinkRE.test(name)) { + info.attribute = JSON.stringify( + name.replace(vueUtils.xlinkRE, function(m, p1) { + return 'xlink:' + p1.toLowerCase() + }) + ) + } + subprop = 'attrs' + } } } } @@ -246,3 +292,13 @@ function styleCase(val) { function styleReplacer($0, $1) { return $1.toUpperCase() } + +function makeMap(array) { + var map = array.reduce(function(acc, key) { + acc[key] = true + return acc + }, {}) + return function(val) { + return map[val] + } +} From 10a21401d2c0b52d3784a275bde6a96496641d4c Mon Sep 17 00:00:00 2001 From: Mehdi Lahlou Date: Wed, 5 Sep 2018 01:24:15 +0200 Subject: [PATCH 05/10] fix: refactor, separate and fix `vue.js` attributes merge --- index.js | 101 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 66 insertions(+), 35 deletions(-) diff --git a/index.js b/index.js index 53fda5f..afb4178 100644 --- a/index.js +++ b/index.js @@ -22,7 +22,7 @@ var vueUtils = { 'slot', 'scopedSlots' ]), - nestableRE: /^(props|domProps|on|nativeOn|hook)([\-_A-Z])/, + nestableRE: /^(props|domProps|on|nativeOn|hook)([-_A-Z])/, dirRE: /^v-/, xlinkRE: /^xlink([A-Z])/ } @@ -190,42 +190,10 @@ function addAttribute(props, prop, value, ctx) { } else if (ctx.hyperscript === true) { subprop = 'attrs' } else if (ctx.vue === true) { - var name = info.property - if (!vueUtils.isTopLevel(name)) { - // nested modules - var nestMatch = name.match(vueUtils.nestableRE) - if (nestMatch) { - var prefix = nestMatch[1] - var suffix = name.replace(vueUtils.nestableRE, function(_, $1, $2) { - return $2 === '-' ? '' : $2.toLowerCase() - }) - info.attribute = suffix - subprop = prefix - } else if (vueUtils.dirRE.test(name)) { - // custom directive - name = name.replace(vueUtils.dirRE, '') - value = { - name: name, - value: value - } - value = props.directives ? props.directives.concat([value]) : [value] - info.attribute = 'directives' - } else { - // rest are nested under attrs - // guard xlink attributes - if (vueUtils.xlinkRE.test(name)) { - info.attribute = JSON.stringify( - name.replace(vueUtils.xlinkRE, function(m, p1) { - return 'xlink:' + p1.toLowerCase() - }) - ) - } - subprop = 'attrs' - } - } + vueMergeAttributes(props, info, value) + return } } - if (subprop) { if (props[subprop] === undefined) { props[subprop] = {} @@ -237,6 +205,69 @@ function addAttribute(props, prop, value, ctx) { } } +function vueMergeAttributes(props, info, value) { + var groupProp = vueGroupAttribute(info, value) + var propName = groupProp.name + var propValue = groupProp.value + + props[propName] = + typeof propValue === 'object' + ? Object.assign({}, props[propName] || {}, propValue) + : Array.isArray(propValue) + ? [].concat(props[propName] || [], propValue) + : propValue +} + +function vueGroupAttribute(info, value) { + var name = info.property + var props = {} + + if (vueUtils.isTopLevel(name)) { + props.name = name + props.value = value + } else { + // Nested modules + var nestMatch = name.match(vueUtils.nestableRE) + if (nestMatch) { + var prefix = nestMatch[1] + var suffix = name.replace(vueUtils.nestableRE, function(_, $1, $2) { + return $2 === '-' ? '' : $2.toLowerCase() + }) + + var subProp = {} + subProp[suffix] = value + props.name = prefix + props.value = subProp + } else if (vueUtils.dirRE.test(info.attribute)) { + // Custom directive + props.name = 'directives' + props.value = [ + { + name: info.attribute.replace(vueUtils.dirRE, ''), + value: value + } + ] + } else { + // Rest are nested under attrs + // guard xlink attributes + var attribute = vueUtils.xlinkRE.test(info.attribute) + ? JSON.stringify( + info.attribute.replace(vueUtils.xlinkRE, function(m, p1) { + return 'xlink:' + p1.toLowerCase() + }) + ) + : info.attribute + + var attrs = {} + attrs[attribute] = value + props.name = 'attrs' + props.value = attrs + } + } + + return props +} + // Check if `h` is `react.createElement`. function react(h) { var node = h && h('div') From 3079be4f27a3184acf0661269f0e13bd21bf175b Mon Sep 17 00:00:00 2001 From: Mehdi Lahlou Date: Wed, 5 Sep 2018 01:40:00 +0200 Subject: [PATCH 06/10] chore: simplify `vue` h test --- index.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/index.js b/index.js index afb4178..93e8b82 100644 --- a/index.js +++ b/index.js @@ -278,10 +278,7 @@ function react(h) { // Check if `h` is vue `createElement`. function vue(h) { - if (typeof h === 'undefined') { - return - } - var div = h('div') + var div = h && h('div') return div && div.context && div.context._isVue === true } From 6b1e08d6b5855fda8c66abfdc98b8bf1ff29fd19 Mon Sep 17 00:00:00 2001 From: Mehdi Lahlou Date: Wed, 5 Sep 2018 02:02:30 +0200 Subject: [PATCH 07/10] chore(test): add `vue.js` test utils, add `vue` and `vue-server-renderer` devDependencies --- package.json | 2 ++ test.js | 3 +++ 2 files changed, 5 insertions(+) diff --git a/package.json b/package.json index c2941de..d3f66e6 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,8 @@ "unist-builder": "^1.0.1", "vdom-to-html": "^2.3.1", "virtual-dom": "^2.1.1", + "vue": "^2.5.17", + "vue-server-renderer": "^2.5.17", "xo": "^0.21.0" }, "scripts": { diff --git a/test.js b/test.js index e959512..410c60d 100644 --- a/test.js +++ b/test.js @@ -10,6 +10,9 @@ var r = require('react').createElement var rehype = require('rehype') var vToString = require('vdom-to-html') var rToString = require('react-dom/server').renderToStaticMarkup +var vueToString = require('vue-server-renderer').createRenderer({ + template: '' +}).renderToString var toH = require('.') var processor = rehype().data('settings', {fragment: true, position: false}) From eff435fec43a4faf449c9666177e19322ed1477f Mon Sep 17 00:00:00 2001 From: Mehdi Lahlou Date: Sun, 7 Oct 2018 02:51:54 +0200 Subject: [PATCH 08/10] chore: fix toplevel node determination method --- index.js | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/index.js b/index.js index 93e8b82..6230c2d 100644 --- a/index.js +++ b/index.js @@ -12,7 +12,7 @@ var is = require('unist-util-is') var dashes = /-([a-z])/g var vueUtils = { - isTopLevel: makeMap([ + topLevel: [ 'class', 'staticClass', 'style', @@ -21,7 +21,7 @@ var vueUtils = { 'refInFor', 'slot', 'scopedSlots' - ]), + ], nestableRE: /^(props|domProps|on|nativeOn|hook)([-_A-Z])/, dirRE: /^v-/, xlinkRE: /^xlink([A-Z])/ @@ -222,7 +222,7 @@ function vueGroupAttribute(info, value) { var name = info.property var props = {} - if (vueUtils.isTopLevel(name)) { + if (vueUtils.topLevel.indexOf(name) > -1) { props.name = name props.value = value } else { @@ -320,13 +320,3 @@ function styleCase(val) { function styleReplacer($0, $1) { return $1.toUpperCase() } - -function makeMap(array) { - var map = array.reduce(function(acc, key) { - acc[key] = true - return acc - }, {}) - return function(val) { - return map[val] - } -} From 9429e944f167e5f8e57872a5a00f93778b7243f8 Mon Sep 17 00:00:00 2001 From: Mehdi Lahlou Date: Sun, 7 Oct 2018 02:59:27 +0200 Subject: [PATCH 09/10] chore: fix `xlink` space detection --- index.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/index.js b/index.js index 6230c2d..70b34e4 100644 --- a/index.js +++ b/index.js @@ -250,13 +250,14 @@ function vueGroupAttribute(info, value) { } else { // Rest are nested under attrs // guard xlink attributes - var attribute = vueUtils.xlinkRE.test(info.attribute) - ? JSON.stringify( - info.attribute.replace(vueUtils.xlinkRE, function(m, p1) { - return 'xlink:' + p1.toLowerCase() - }) - ) - : info.attribute + var attribute = + info.space && info.space === 'xlink' + ? JSON.stringify( + info.attribute.replace(vueUtils.xlinkRE, function(m, p1) { + return 'xlink:' + p1.toLowerCase() + }) + ) + : info.attribute var attrs = {} attrs[attribute] = value From 301c2139f5cb8ec51e8e50ca3bb1fef2f2e3c744 Mon Sep 17 00:00:00 2001 From: Mehdi Lahlou Date: Sun, 7 Oct 2018 03:06:17 +0200 Subject: [PATCH 10/10] chore: separate prop assignation in group function --- index.js | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/index.js b/index.js index 70b34e4..6978d79 100644 --- a/index.js +++ b/index.js @@ -222,9 +222,12 @@ function vueGroupAttribute(info, value) { var name = info.property var props = {} + var processeddName + var processedValue + if (vueUtils.topLevel.indexOf(name) > -1) { - props.name = name - props.value = value + processeddName = name + processedValue = value } else { // Nested modules var nestMatch = name.match(vueUtils.nestableRE) @@ -236,12 +239,12 @@ function vueGroupAttribute(info, value) { var subProp = {} subProp[suffix] = value - props.name = prefix - props.value = subProp + processeddName = prefix + processedValue = subProp } else if (vueUtils.dirRE.test(info.attribute)) { // Custom directive - props.name = 'directives' - props.value = [ + processeddName = 'directives' + processedValue = [ { name: info.attribute.replace(vueUtils.dirRE, ''), value: value @@ -261,11 +264,14 @@ function vueGroupAttribute(info, value) { var attrs = {} attrs[attribute] = value - props.name = 'attrs' - props.value = attrs + processeddName = 'attrs' + processedValue = attrs } } + props.name = processeddName + props.value = processedValue + return props }