@@ -2,18 +2,27 @@ export const shrink_jsx = (content: string): string => {
22 const lines = content . split ( / \r ? \n / )
33 const result : string [ ] = [ ]
44 let is_in_block_comment = false
5- let skip_body_depth = 0
5+ const block_stack : { is_skipped : boolean ; is_type_decl ?: boolean } [ ] = [ ]
66 let last_code_buffer = ''
7+ let is_in_string : false | '"' | "'" | '`' = false
8+ let jsx_tag_state : 'none' | 'name' | 'attributes' = 'none'
9+ let jsx_attribute_brace_depth = 0
10+ let global_paren_depth = 0
11+ let use_effect_start_depth = - 1
712
813 for ( const line of lines ) {
914 let processed_line = ''
1015 let i = 0
11- let is_in_string : false | '"' | "'" | '`' = false
1216
1317 while ( i < line . length ) {
1418 const char = line [ i ]
1519 const next_char = line [ i + 1 ]
1620
21+ const current_skipped =
22+ block_stack . length > 0
23+ ? block_stack [ block_stack . length - 1 ] . is_skipped
24+ : false
25+
1726 if ( is_in_block_comment ) {
1827 if ( char == '*' && next_char == '/' ) {
1928 is_in_block_comment = false
@@ -26,7 +35,11 @@ export const shrink_jsx = (content: string): string => {
2635
2736 if ( is_in_string ) {
2837 if ( char == '\\' ) {
29- if ( skip_body_depth == 0 ) {
38+ if (
39+ jsx_tag_state !== 'attributes' &&
40+ ! current_skipped &&
41+ use_effect_start_depth === - 1
42+ ) {
3043 processed_line += char + ( next_char || '' )
3144 }
3245 last_code_buffer += char + ( next_char || '' )
@@ -36,7 +49,11 @@ export const shrink_jsx = (content: string): string => {
3649 if ( char === is_in_string ) {
3750 is_in_string = false
3851 }
39- if ( skip_body_depth == 0 ) {
52+ if (
53+ jsx_tag_state !== 'attributes' &&
54+ ! current_skipped &&
55+ use_effect_start_depth === - 1
56+ ) {
4057 processed_line += char
4158 }
4259 last_code_buffer += char
@@ -46,7 +63,11 @@ export const shrink_jsx = (content: string): string => {
4663
4764 if ( char == '"' || char === "'" || char == '`' ) {
4865 is_in_string = char
49- if ( skip_body_depth == 0 ) {
66+ if (
67+ jsx_tag_state !== 'attributes' &&
68+ ! current_skipped &&
69+ use_effect_start_depth === - 1
70+ ) {
5071 processed_line += char
5172 }
5273 last_code_buffer += char
@@ -64,41 +85,163 @@ export const shrink_jsx = (content: string): string => {
6485 continue
6586 }
6687
67- if ( char == '{' ) {
68- if ( skip_body_depth > 0 ) {
69- skip_body_depth ++
88+ if ( jsx_tag_state === 'attributes' ) {
89+ if ( char === '{' ) {
90+ jsx_attribute_brace_depth ++
91+ } else if ( char === '}' ) {
92+ if ( jsx_attribute_brace_depth > 0 ) {
93+ jsx_attribute_brace_depth --
94+ }
95+ } else if (
96+ char === '/' &&
97+ next_char === '>' &&
98+ jsx_attribute_brace_depth === 0
99+ ) {
100+ jsx_tag_state = 'none'
101+ if ( ! current_skipped && use_effect_start_depth === - 1 ) {
102+ processed_line += '/>'
103+ }
104+ last_code_buffer += '/>'
105+ i += 2
106+ continue
107+ } else if ( char === '>' && jsx_attribute_brace_depth === 0 ) {
108+ jsx_tag_state = 'none'
109+ if ( ! current_skipped && use_effect_start_depth === - 1 ) {
110+ processed_line += '>'
111+ }
112+ last_code_buffer += '>'
113+ i ++
114+ continue
115+ }
116+ last_code_buffer += char
117+ i ++
118+ continue
119+ }
120+
121+ if ( char === '<' && next_char && / [ a - z A - Z ] / . test ( next_char ) ) {
122+ const trimmed_buffer = last_code_buffer . trimEnd ( )
123+ const last_non_space = trimmed_buffer . slice ( - 1 )
124+ const is_jsx_context =
125+ [ '(' , '=' , ':' , '>' , '?' , '&' , '|' , ',' , '{' , '[' ] . includes (
126+ last_non_space
127+ ) || / ( ^ | \W ) ( r e t u r n | y i e l d | a w a i t | d e f a u l t ) $ / . test ( trimmed_buffer )
128+
129+ if ( is_jsx_context ) {
130+ jsx_tag_state = 'name'
131+ }
132+ } else if ( jsx_tag_state === 'name' ) {
133+ if ( / \s / . test ( char ) ) {
134+ jsx_tag_state = 'attributes'
135+ jsx_attribute_brace_depth = 0
70136 last_code_buffer += char
71137 i ++
72138 continue
73- } else {
74- const is_keeper =
75- / ( ^ | \s ) ( c l a s s | i n t e r f a c e | e n u m | n a m e s p a c e | t y p e ) ( \s | $ ) / . test (
76- last_code_buffer
77- ) || / ( ^ | \s ) ( i m p o r t | e x p o r t | d e f a u l t ) \s * $ / . test ( last_code_buffer )
78- const is_object_literal = / ( = | : | \( ) \s * $ / . test (
79- last_code_buffer . trimEnd ( )
80- )
81-
82- if ( ! is_keeper && ! is_object_literal ) {
83- skip_body_depth = 1
84- processed_line += `{}`
85- last_code_buffer += '{}'
86- i ++
87- continue
88- } else {
89- last_code_buffer = ''
90- }
139+ } else if ( char === '>' ) {
140+ jsx_tag_state = 'none'
141+ } else if ( char === '/' && next_char === '>' ) {
142+ jsx_tag_state = 'none'
91143 }
92- } else if ( char == '}' ) {
93- if ( skip_body_depth > 0 ) {
94- skip_body_depth --
144+ }
145+
146+ if ( char === '(' ) {
147+ global_paren_depth ++
148+ if (
149+ use_effect_start_depth === - 1 &&
150+ / ( ^ | \W ) ( R e a c t \. ) ? u s e E f f e c t \s * $ / . test ( last_code_buffer )
151+ ) {
152+ use_effect_start_depth = global_paren_depth
153+ processed_line = processed_line . replace ( / ( R e a c t \. ) ? u s e E f f e c t \s * $ / , '' )
95154 last_code_buffer += char
96155 i ++
97156 continue
98157 }
158+ } else if ( char === ')' ) {
159+ if ( use_effect_start_depth === global_paren_depth ) {
160+ use_effect_start_depth = - 1
161+ global_paren_depth --
162+ last_code_buffer += char
163+ i ++
164+ continue
165+ }
166+ global_paren_depth --
167+ }
168+
169+ if ( char == '{' ) {
170+ const is_keeper =
171+ / ( ^ | \s ) ( c l a s s | i n t e r f a c e | e n u m | n a m e s p a c e | t y p e ) ( \s | $ ) / . test (
172+ last_code_buffer
173+ ) || / ( ^ | \s ) ( i m p o r t | e x p o r t | d e f a u l t ) \s * $ / . test ( last_code_buffer )
174+ const is_object_literal = / ( = | : | \( ) \s * $ / . test (
175+ last_code_buffer . trimEnd ( )
176+ )
177+
178+ const last_statement = last_code_buffer . split ( / [ { ; } ] / ) . pop ( ) || ''
179+ const is_type_decl = / ( ^ | \s ) ( i n t e r f a c e | t y p e ) \b / . test ( last_statement )
180+
181+ let parent_skipped = current_skipped
182+ if ( use_effect_start_depth !== - 1 ) {
183+ parent_skipped = true
184+ }
185+ const should_skip = parent_skipped || ( ! is_keeper && ! is_object_literal )
186+
187+ block_stack . push ( { is_skipped : should_skip , is_type_decl } )
188+
189+ if ( ! parent_skipped ) {
190+ processed_line += '{'
191+ }
192+
193+ last_code_buffer += '{'
194+ i ++
195+ continue
196+ } else if ( char == '}' ) {
197+ let parent_skipped =
198+ block_stack . length > 1
199+ ? block_stack [ block_stack . length - 2 ] . is_skipped
200+ : false
201+ if ( use_effect_start_depth !== - 1 ) {
202+ parent_skipped = true
203+ }
204+
205+ if ( ! parent_skipped ) {
206+ processed_line += '}'
207+ }
208+
209+ if ( block_stack . length > 0 ) {
210+ block_stack . pop ( )
211+ }
212+ last_code_buffer += '}'
213+ i ++
214+ continue
215+ }
216+
217+ let active_skipped =
218+ block_stack . length > 0
219+ ? block_stack [ block_stack . length - 1 ] . is_skipped
220+ : false
221+ let parent_skipped =
222+ block_stack . length > 1
223+ ? block_stack [ block_stack . length - 2 ] . is_skipped
224+ : false
225+
226+ if ( use_effect_start_depth !== - 1 ) {
227+ active_skipped = true
228+ parent_skipped = true
229+ }
230+
231+ if ( active_skipped && ! parent_skipped && use_effect_start_depth === - 1 ) {
232+ if ( / ( ^ | \W ) r e t u r n $ / . test ( last_code_buffer ) && / \W / . test ( char ) ) {
233+ block_stack [ block_stack . length - 1 ] . is_skipped = false
234+ const prefix =
235+ processed_line . length === 0 ? line . match ( / ^ \s * / ) ?. [ 0 ] || '' : ''
236+ processed_line += prefix + 'return'
237+ }
99238 }
100239
101- if ( skip_body_depth == 0 ) {
240+ if (
241+ ( block_stack . length === 0 ||
242+ ! block_stack [ block_stack . length - 1 ] . is_skipped ) &&
243+ use_effect_start_depth === - 1
244+ ) {
102245 processed_line += char
103246 }
104247 last_code_buffer += char
@@ -107,7 +250,31 @@ export const shrink_jsx = (content: string): string => {
107250
108251 const trimmed = processed_line . trim ( )
109252 if ( trimmed ) {
110- result . push ( processed_line . trimEnd ( ) . replace ( / ; + $ / , '' ) )
253+ let final_line = processed_line . trimEnd ( ) . replace ( / ; + $ / , '' )
254+
255+ const ends_with_open_or_comma = / [ [ ( { , ] $ / . test ( final_line )
256+ if (
257+ ! ends_with_open_or_comma &&
258+ ! final_line . includes ( '=>' ) &&
259+ / ^ \s * (?: e x p o r t \s + ) ? (?: c o n s t | l e t | v a r ) \s + / . test ( final_line )
260+ ) {
261+ const match = final_line . match (
262+ / ^ ( \s * (?: e x p o r t \s + ) ? (?: c o n s t | l e t | v a r ) \s + (?: \[ [ ^ \] ] + \] | \{ [ ^ } ] + \} | [ ^ \s = : ] + ) (?: \s * : [ ^ = ] + ) ? ) \s * = (? ! > ) .+ $ /
263+ )
264+ if ( match ) {
265+ final_line = match [ 1 ] . trimEnd ( )
266+ }
267+ }
268+
269+ const in_type_decl = block_stack . some ( ( b ) => b . is_type_decl )
270+ if ( in_type_decl && ! ends_with_open_or_comma ) {
271+ final_line = final_line . replace (
272+ / ^ ( \s * [ ' " ] ? [ a - z A - Z 0 - 9 _ ? - ] + [ ' " ] ? ) \s * : .* $ / ,
273+ '$1'
274+ )
275+ }
276+
277+ result . push ( final_line )
111278 }
112279
113280 last_code_buffer += ' '
0 commit comments