@@ -16,6 +16,7 @@ const CACHE = {};
1616const TEMPLATE = document . createElement ( 'template' ) ;
1717
1818const reg = / ( \$ _ h \[ \d + \] ) / g;
19+ const nomExp = / ( [ \w - ] + ) = / g;
1920
2021export default function html ( statics ) {
2122 const tpl = CACHE [ statics ] || ( CACHE [ statics ] = build ( statics ) ) ;
@@ -25,49 +26,61 @@ export default function html(statics) {
2526
2627/** Create a template function given strings from a tagged template. */
2728function build ( statics ) {
28- let str = statics [ 0 ] , i = 1 ;
29+ const noms = { } ;
30+ let str = '' , i = 0 ;
2931 while ( i < statics . length ) {
30- str += '$_h[' + i + ']' + statics [ i ++ ] ;
32+ getNoms ( statics [ i ] , noms ) ;
33+ str += statics [ i ++ ] + ( i < statics . length ? '$_h[' + i + ']' : '' ) ;
3134 }
3235 // Template string preprocessing:
3336 // - replace <${Foo}> with <c c@=${Foo}>
3437 // - replace <x /> with <x></x>
3538 // - replace <${Foo}>a<//>b with <c c@=${Foo}>a</c>b
3639 TEMPLATE . innerHTML = str . replace ( / < (?: ( \/ ) \/ | ( \/ ? ) ( \$ _ h \[ \d + \] ) ) / g, '<$1$2c c@=$3' ) . replace ( / < ( [ \w : - ] + ) ( \s [ ^ < > ] * ?) ? \/ > / gi, '<$1$2></$1>' ) . trim ( ) ;
37- return Function ( 'h' , '$_h' , 'return ' + walk ( ( TEMPLATE . content || TEMPLATE ) . firstChild ) ) ;
40+ return Function ( 'h' , '$_h' , 'return ' + walk ( ( TEMPLATE . content || TEMPLATE ) . firstChild , noms ) ) ;
3841}
3942
4043/** Traverse a DOM tree and serialize it to hyperscript function calls */
41- function walk ( n ) {
44+ function walk ( n , noms ) {
4245 if ( n . nodeType !== 1 ) {
4346 if ( n . nodeType === 3 && n . data ) return field ( n . data , ',' ) ;
4447 return 'null' ;
4548 }
46- let nodeName = `"${ n . localName } "` , str = '{ ' , sub = '' , end = '}' ;
49+ let nodeName = `"${ n . localName } "` , str = '' , pre , it , prevSpread , anySpread ;
4750 for ( let i = 0 ; i < n . attributes . length ; i ++ ) {
48- const { name, value } = n . attributes [ i ] ;
51+ let { name } = n . attributes [ i ] ;
52+ const { value } = n . attributes [ i ] ;
53+ name = noms [ name ] || name ;
4954 if ( name == 'c@' ) {
5055 nodeName = value ;
5156 continue ;
5257 }
5358 if ( name . substring ( 0 , 3 ) === '...' ) {
54- end = '})' ;
55- str = 'Object.assign(' + str + '},' + name . substring ( 3 ) + ',{' ;
56- sub = '' ;
57- continue ;
59+ it = name . substring ( 3 ) ;
60+ pre = str ? ( prevSpread ? ',' : '},' ) : '' ;
61+ prevSpread = anySpread = true ;
62+ }
63+ else {
64+ it = `"${ name . replace ( / : ( \w ) / g, upper ) } ":${ value ? field ( value , '+' ) : true } ` ;
65+ pre = str ? ( prevSpread ? ',{' : ',' ) : '{' ;
66+ prevSpread = false ;
5867 }
59- str += `${ sub } "${ name . replace ( / : ( \w ) / g, upper ) } ":${ value ? field ( value , '+' ) : true } ` ;
60- sub = ',' ;
68+ str += pre + it ;
6169 }
62- str = 'h(' + nodeName + ',' + str + end ;
70+ str = 'h(' + nodeName + ',' + ( str ? ( anySpread ? 'Object.assign({},' + str + ( prevSpread ? '' : '}' ) + ')' : str + '}' ) : '{}' ) ;
6371 let child = n . firstChild ;
6472 while ( child ) {
65- str += ',' + walk ( child ) ;
73+ str += ',' + walk ( child , noms ) ;
6674 child = child . nextSibling ;
6775 }
6876 return str + ')' ;
6977}
7078
79+ function getNoms ( str , noms ) {
80+ let nom ;
81+ while ( ( nom = nomExp . exec ( str ) ) !== null ) noms [ nom [ 1 ] . toLowerCase ( ) ] = nom [ 1 ] ;
82+ }
83+
7184function upper ( s , i ) {
7285 return i . toUpperCase ( ) ;
7386}
@@ -82,4 +95,4 @@ function field(value, sep) {
8295 if ( sep === ',' ) strValue = `[${ strValue } ]` ;
8396 }
8497 return strValue ;
85- }
98+ }
0 commit comments