@@ -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 */
1213export 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 - z 0 - 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