1- const TAG_SET = 0 ;
2- const PROPS_SET = 1 ;
3- const PROPS_ASSIGN = 2 ;
4- const CHILD_RECURSE = 3 ;
5- const CHILD_APPEND = 4 ;
6-
71const MODE_SLASH = 0 ;
82const MODE_TEXT = 1 ;
9- const MODE_WHITESPACE = 3 ;
10- const MODE_TAGNAME = 4 ;
11- const MODE_ATTRIBUTE = 5 ;
12-
13- export const evaluate = ( h , current , fields ) => {
14- const args = [ '' , null ] ;
15-
16- for ( let i = 1 ; i < current . length ; i ++ ) {
17- const field = current [ i ++ ] ;
18- const value = field ? fields [ field ] : current [ i ] ;
19-
20- const code = current [ ++ i ] ;
21- if ( code === TAG_SET ) {
22- args [ 0 ] = value ;
23- }
24- else if ( code === PROPS_SET ) {
25- ( args [ 1 ] = args [ 1 ] || { } ) [ current [ ++ i ] ] = value ;
26- }
27- else if ( code === PROPS_ASSIGN ) {
28- args [ 1 ] = Object . assign ( args [ 1 ] || { } , value ) ;
29- }
30- else if ( code === CHILD_RECURSE ) {
31- args . push ( evaluate ( h , value , fields ) ) ;
32- }
33- else { // code === CHILD_APPEND
34- args . push ( value ) ;
35- }
36- }
37-
38- // eslint-disable-next-line prefer-spread
39- return h . apply ( null , args ) ;
40- } ;
3+ const MODE_WHITESPACE = 2 ;
4+ const MODE_TAGNAME = 3 ;
5+ const MODE_ATTRIBUTE = 4 ;
416
42- /** Create a template function given strings from a tagged template. */
43- export const build = ( statics ) => {
7+ export const build = ( h , fields ) => {
8+ const root = [ ] ;
9+ const stack = [ ] ;
4410 let mode = MODE_TEXT ;
4511 let buffer = '' ;
4612 let quote = '' ;
47- let fallbackPropValue = true ;
48- let current = [ ] ;
13+ let args = root ;
4914 let char , propName , idx ;
5015
51- const commit = field => {
52- if ( mode === MODE_TEXT ) {
53- if ( field || ( buffer = buffer . replace ( / ^ \s * \n \s * | \s * \n \s * $ / g, '' ) ) ) {
54- current . push ( field , buffer , CHILD_APPEND ) ;
55- }
16+ const commit = ( ) => {
17+ if ( mode === MODE_TEXT && ( buffer = buffer . replace ( / ^ \s * \n \s * | \s * \n \s * $ / g, '' ) ) ) {
18+ args . push ( buffer ) ;
5619 }
57- else if ( mode === MODE_TAGNAME && ( field || buffer ) ) {
58- current . push ( field , buffer , TAG_SET ) ;
20+ if ( mode === MODE_TAGNAME && buffer ) {
21+ args [ 0 ] = buffer ;
5922 mode = MODE_WHITESPACE ;
6023 }
61- else if ( mode === MODE_WHITESPACE && buffer === '...' ) {
62- current . push ( field , 0 , PROPS_ASSIGN ) ;
24+ else if ( mode === MODE_WHITESPACE && buffer ) {
25+ ( args [ 1 ] = args [ 1 ] || { } ) [ buffer ] = true ;
6326 }
64- else if ( mode ) { // mode === MODE_ATTRIBUTE || mode === MODE_WHITESPACE
65- if ( mode === MODE_WHITESPACE ) {
66- propName = buffer ;
67- buffer = '' ;
68- }
69- if ( propName ) {
70- current . push ( field , buffer || fallbackPropValue , PROPS_SET , propName ) ;
71- propName = '' ;
72- }
73- fallbackPropValue = true ;
27+ else if ( mode === MODE_ATTRIBUTE && propName ) {
28+ ( args [ 1 ] = args [ 1 ] || { } ) [ propName ] = buffer ;
29+ propName = '' ;
7430 }
7531 buffer = '' ;
7632 } ;
7733
78- for ( let i = 0 ; i < statics . length ; i ++ ) {
34+ for ( let i = 0 ; i < fields [ 0 ] . length ; i ++ ) {
7935 if ( i ) {
8036 if ( mode === MODE_TEXT ) {
8137 commit ( ) ;
38+ args . push ( fields [ i ] ) ;
39+ }
40+ else if ( mode === MODE_TAGNAME ) {
41+ args [ 0 ] = fields [ i ] ;
42+ mode = MODE_WHITESPACE ;
43+ }
44+ else if ( mode === MODE_WHITESPACE && buffer === '...' ) {
45+ args [ 1 ] = Object . assign ( args [ 1 ] || { } , fields [ i ] ) ;
8246 }
83- commit ( i ) ;
47+ else if ( mode === MODE_ATTRIBUTE && propName ) {
48+ ( args [ 1 ] = args [ 1 ] || { } ) [ propName ] = fields [ i ] ;
49+ propName = '' ;
50+ }
51+ buffer = '' ;
8452 }
8553
86- for ( let j = 0 ; j < statics [ i ] . length ; j ++ ) {
87- char = statics [ i ] [ j ] ;
54+ for ( let j = 0 ; j < fields [ 0 ] [ i ] . length ; j ++ ) {
55+ char = fields [ 0 ] [ i ] [ j ] ;
8856
8957 if ( mode === MODE_TEXT && char === '<' ) {
9058 // commit buffer
9159 commit ( ) ;
92- current = [ current ] ;
60+ stack . push ( args ) ;
61+ args = [ '' , null ] ;
62+ buffer = '' ;
9363 mode = MODE_TAGNAME ;
9464 }
9565 else if ( mode !== MODE_TEXT && ( char === quote || ! quote ) && ( idx = '\'">=/\t\n\r ' . indexOf ( char ) ) >= 0 ) {
@@ -100,31 +70,29 @@ export const build = (statics) => {
10070 else if ( idx === 2 ) {
10171 // char === '>'
10272 commit ( ) ;
103-
104- if ( ! mode ) {
105- // encountered a slash in current tag
106-
107- if ( current . length === 1 ) {
108- // no tag name or attributes before the slash
109- current = current [ 0 ] ;
110- }
111- current [ 0 ] . push ( 0 , current , CHILD_RECURSE ) ;
112- current = current [ 0 ] ;
113- }
11473 mode = MODE_TEXT ;
11574 }
11675 else if ( idx === 3 ) {
11776 // char === '='
11877 if ( mode ) {
11978 mode = MODE_ATTRIBUTE ;
12079 propName = buffer ;
121- buffer = fallbackPropValue = '' ;
80+ buffer = '' ;
12281 }
12382 }
12483 else if ( idx === 4 ) {
12584 // char === '/'
126- commit ( ) ;
127- mode = MODE_SLASH ;
85+ if ( mode ) {
86+ commit ( ) ;
87+ if ( mode === MODE_TAGNAME ) {
88+ // no tag name before the slash
89+ args = stack . pop ( ) ;
90+ }
91+ // eslint-disable-next-line prefer-spread
92+ mode = h . apply ( null , args ) ; // Use 'mode' as a temporary variable
93+ ( args = stack . pop ( ) ) . push ( mode ) ;
94+ mode = MODE_SLASH ;
95+ }
12896 }
12997 else if ( mode ) {
13098 // char is a whitespace
@@ -139,5 +107,5 @@ export const build = (statics) => {
139107 }
140108 }
141109 commit ( ) ;
142- return current ;
110+ return root . length < 2 ? root [ 0 ] : root ;
143111} ;
0 commit comments