11import htm from 'htm' ;
22
3- // htm() uses the HTML parser, which serializes attribute values.
4- // this is a problem, because composite values here can be made up
5- // of strings and AST nodes, which serialize to [object Object].
6- // Since the handoff from AST node handling to htm() is synchronous,
7- // this global lookup will always reflect the corresponding
8- // AST-derived values for the current htm() invocation.
9- let currentExpressions ;
10-
113/**
124 * @param {Babel } babel
135 * @param {object } options
@@ -64,7 +56,7 @@ export default function htmBabelPlugin({ types: t }, options = {}) {
6456 options . monomorphic && t . objectProperty ( propertyName ( 'text' ) , t . nullLiteral ( ) )
6557 ] . filter ( Boolean ) ) ;
6658 }
67-
59+
6860 return t . callExpression ( pragma , [ tag , props , children ] ) ;
6961 }
7062
@@ -85,48 +77,49 @@ export default function htmBabelPlugin({ types: t }, options = {}) {
8577 child = child . trim ( ) ;
8678 }
8779 if ( typeof child === 'string' ) {
88- const matches = child . match ( / \$ \$ \$ _ h _ \[ ( \d + ) \] / ) ;
89- if ( matches ) return currentExpressions [ matches [ 1 ] ] ;
9080 return stringValue ( child ) ;
9181 }
9282 return child ;
9383 }
9484
9585 function h ( tag , props ) {
9686 if ( typeof tag === 'string' ) {
97- const matches = tag . match ( / \$ \$ \$ _ h _ \[ ( \d + ) \] / ) ;
98- if ( matches ) tag = currentExpressions [ matches [ 1 ] ] ;
99- else tag = t . stringLiteral ( tag ) ;
87+ tag = t . stringLiteral ( tag ) ;
10088 }
10189
102- //const propsNode = props==null || Object.keys(props).length===0 ? t.nullLiteral() : t.objectExpression(
103- const propsNode = t . objectExpression (
104- Object . keys ( props ) . map ( key => {
105- let value = props [ key ] ;
106- if ( typeof value === 'string' ) {
107- const tokenizer = / \$ \$ \$ _ h _ \[ ( \d + ) \] / g;
108- let token , lhs , root , index = 0 , lastIndex = 0 ;
109- const append = expr => {
110- if ( lhs ) expr = t . binaryExpression ( '+' , lhs , expr ) ;
111- root = lhs = expr ;
112- } ;
113- while ( ( token = tokenizer . exec ( value ) ) ) {
114- append ( t . stringLiteral ( value . substring ( index , token . index ) ) ) ;
115- append ( currentExpressions [ token [ 1 ] ] ) ;
116- index = token . index ;
117- lastIndex = tokenizer . lastIndex ;
118- }
119- if ( lastIndex < value . length ) {
120- append ( t . stringLiteral ( value . substring ( lastIndex ) ) ) ;
90+ let propsNode ;
91+
92+ if ( t . isObjectExpression ( props ) ) {
93+ propsNode = props ;
94+ for ( let i in props ) {
95+ if ( props . hasOwnProperty ( i ) && props [ i ] && props [ i ] . type ) {
96+ for ( let j = 0 ; j < props . properties . length ; j ++ ) {
97+ if ( props . properties [ j ] . start > props [ i ] . start ) {
98+ props . properties . splice ( j , 0 , t . objectProperty ( propertyName ( i ) , props [ i ] ) ) ;
99+ break ;
100+ }
121101 }
122- value = root ;
123- }
124- else if ( typeof value === 'boolean' ) {
125- value = t . booleanLiteral ( value ) ;
102+ delete props [ i ] ;
126103 }
127- return t . objectProperty ( propertyName ( key ) , value ) ;
128- } )
129- ) ;
104+ }
105+ }
106+ else {
107+ propsNode = t . objectExpression (
108+ 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+ else if ( typeof value === 'number' ) {
117+ value = t . stringLiteral ( value + '' ) ;
118+ }
119+ return t . objectProperty ( propertyName ( key ) , value ) ;
120+ } )
121+ ) ;
122+ }
130123
131124 // recursive iteration of possibly nested arrays of children.
132125 let children = [ ] ;
@@ -164,8 +157,7 @@ export default function htmBabelPlugin({ types: t }, options = {}) {
164157 if ( htmlName [ 0 ] === '/' ? patternStringToRegExp ( htmlName ) . test ( tag ) : tag === htmlName ) {
165158 const statics = path . node . quasi . quasis . map ( e => e . value . raw ) ;
166159 const expr = path . node . quasi . expressions ;
167- currentExpressions = expr ;
168- path . replaceWith ( html ( statics , ...expr . map ( ( p , i ) => `$$$_h_[${ i } ]` ) ) ) ;
160+ path . replaceWith ( html ( statics , ...expr ) ) ;
169161 }
170162 }
171163 }
0 commit comments