Skip to content

Commit 4c63b41

Browse files
committed
Add useNativeSpread flag to support {...a,...b} style props spreads
1 parent 29a7fb8 commit 4c63b41

File tree

1 file changed

+26
-9
lines changed

1 file changed

+26
-9
lines changed

packages/babel-plugin-htm/index.mjs

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@ import htm from 'htm';
77
* @param {string} [options.tag=html] The tagged template "tag" function name to process.
88
* @param {boolean} [options.monomorphic=false] Output monomorphic inline objects instead of using String literals.
99
* @param {boolean} [options.useBuiltIns=false] Use the native Object.assign instead of trying to polyfill it.
10+
* @param {boolean} [options.useNativeSpread=false] Use the native { ...a, ...b } syntax for prop spreads.
1011
* @param {boolean} [options.variableArity=true] If `false`, always passes exactly 3 arguments to the pragma function.
1112
*/
1213
export default function htmBabelPlugin({ types: t }, options = {}) {
1314
const pragma = options.pragma===false ? false : dottedIdentifier(options.pragma || 'h');
1415
const useBuiltIns = options.useBuiltIns;
16+
const useNativeSpread = options.useNativeSpread;
1517
const inlineVNodes = options.monomorphic || pragma===false;
1618

1719
const symbol = Symbol();
@@ -31,7 +33,11 @@ export default function htmBabelPlugin({ types: t }, options = {}) {
3133
const end = parts.pop() || '';
3234
return new RegExp(parts.join('/'), end);
3335
}
34-
36+
37+
function propertyValue(valueOrNode) {
38+
return t.isNode(valueOrNode) ? valueOrNode : t.valueToNode(valueOrNode);
39+
}
40+
3541
function propertyName(key) {
3642
if (key.match(/(^\d|[^a-z0-9_$])/i)) return t.stringLiteral(key);
3743
return t.identifier(key);
@@ -99,21 +105,32 @@ export default function htmBabelPlugin({ types: t }, options = {}) {
99105
if (args.length === 2 && !t.isNode(args[0]) && Object.keys(args[0]).length === 0) {
100106
return propsNode(args[1]);
101107
}
108+
109+
if (useNativeSpread) {
110+
const properties = [];
111+
args.forEach(arg => {
112+
if (t.isNode(arg)) {
113+
properties.push(t.spreadElement(arg));
114+
}
115+
else {
116+
Object.keys(arg).forEach(key => {
117+
const value = arg[key];
118+
properties.push(t.objectProperty(propertyName(key), propertyValue(value)));
119+
});
120+
}
121+
});
122+
return t.objectExpression(properties);
123+
}
124+
102125
const helper = useBuiltIns ? dottedIdentifier('Object.assign') : state.addHelper('extends');
103126
return t.callExpression(helper, args.map(propsNode));
104127
}
105128

106129
function propsNode(props) {
107130
return t.isNode(props) ? props : t.objectExpression(
108131
Object.keys(props).map(key => {
109-
let value = props[key];
110-
if (typeof value==='string') {
111-
value = t.stringLiteral(value);
112-
}
113-
else if (typeof value==='boolean') {
114-
value = t.booleanLiteral(value);
115-
}
116-
return t.objectProperty(propertyName(key), value);
132+
const value = props[key];
133+
return t.objectProperty(propertyName(key), propertyValue(value));
117134
})
118135
);
119136
}

0 commit comments

Comments
 (0)