@@ -186,8 +186,10 @@ const extractIfFunctions = (cssText) => {
186
186
/**
187
187
* Parse if() function content - supports both single conditions and multiple chained conditions
188
188
*/
189
- const parseIfFunction = ( content ) => {
190
- // Split content by semicolons, but respect parentheses and quotes
189
+ /**
190
+ * Split content by semicolons, respecting parentheses and quotes
191
+ */
192
+ const splitIfConditionSegments = ( content ) => {
191
193
const segments = [ ] ;
192
194
let currentSegment = '' ;
193
195
let parenDepth = 0 ;
@@ -230,7 +232,51 @@ const parseIfFunction = (content) => {
230
232
segments . push ( currentSegment . trim ( ) ) ;
231
233
}
232
234
233
- // Parse segments into conditions and values
235
+ return segments ;
236
+ } ;
237
+
238
+ /**
239
+ * Find colon outside of parentheses and quotes
240
+ */
241
+ const findConditionValueSeparator = ( segment ) => {
242
+ let parenDepth = 0 ;
243
+ let inQuotes = false ;
244
+ let quoteChar = '' ;
245
+
246
+ for ( let i = 0 ; i < segment . length ; i ++ ) {
247
+ const char = segment [ i ] ;
248
+ const previousChar = i > 0 ? segment [ i - 1 ] : '' ;
249
+
250
+ // Handle quotes
251
+ if ( ( char === '"' || char === "'" ) && previousChar !== '\\' ) {
252
+ if ( ! inQuotes ) {
253
+ inQuotes = true ;
254
+ quoteChar = char ;
255
+ } else if ( char === quoteChar ) {
256
+ inQuotes = false ;
257
+ quoteChar = '' ;
258
+ }
259
+ }
260
+
261
+ if ( ! inQuotes ) {
262
+ if ( char === '(' ) {
263
+ parenDepth ++ ;
264
+ } else if ( char === ')' ) {
265
+ parenDepth -- ;
266
+ } else if ( char === ':' && parenDepth === 0 ) {
267
+ return i ;
268
+ }
269
+ }
270
+ }
271
+
272
+ return - 1 ;
273
+ } ;
274
+
275
+ /**
276
+ * Parse if() function content - supports both single conditions and multiple chained conditions
277
+ */
278
+ const parseIfFunction = ( content ) => {
279
+ const segments = splitIfConditionSegments ( content ) ;
234
280
const conditions = [ ] ;
235
281
let elseValue = null ;
236
282
@@ -243,39 +289,7 @@ const parseIfFunction = (content) => {
243
289
}
244
290
245
291
// Parse condition: value format
246
- let colonIndex = - 1 ;
247
- let parenDepth = 0 ;
248
- let inQuotes = false ;
249
- let quoteChar = '' ;
250
-
251
- // Find the colon that's outside of parentheses and quotes
252
- for ( let i = 0 ; i < segment . length ; i ++ ) {
253
- const char = segment [ i ] ;
254
- const previousChar = i > 0 ? segment [ i - 1 ] : '' ;
255
-
256
- // Handle quotes
257
- if ( ( char === '"' || char === "'" ) && previousChar !== '\\' ) {
258
- if ( ! inQuotes ) {
259
- inQuotes = true ;
260
- quoteChar = char ;
261
- } else if ( char === quoteChar ) {
262
- inQuotes = false ;
263
- quoteChar = '' ;
264
- }
265
- }
266
-
267
- if ( ! inQuotes ) {
268
- if ( char === '(' ) {
269
- parenDepth ++ ;
270
- } else if ( char === ')' ) {
271
- parenDepth -- ;
272
- } else if ( char === ':' && parenDepth === 0 ) {
273
- colonIndex = i ;
274
- break ;
275
- }
276
- }
277
- }
278
-
292
+ const colonIndex = findConditionValueSeparator ( segment ) ;
279
293
if ( colonIndex === - 1 ) {
280
294
throw new Error ( 'Invalid if() function: missing colon in segment' ) ;
281
295
}
@@ -304,21 +318,10 @@ const parseIfFunction = (content) => {
304
318
throw new Error ( 'Invalid if() function: missing else clause' ) ;
305
319
}
306
320
307
- // For backward compatibility, if there's only one condition, return the old format
308
- if ( conditions . length === 1 ) {
309
- return {
310
- conditionType : conditions [ 0 ] . conditionType ,
311
- conditionExpression : conditions [ 0 ] . conditionExpression ,
312
- trueValue : conditions [ 0 ] . value ,
313
- falseValue : elseValue
314
- } ;
315
- }
316
-
317
- // For multiple conditions, return the new format
318
321
return {
319
322
conditions,
320
- falseValue : elseValue ,
321
- isMultipleConditions : true
323
+ elseValue,
324
+ isMultipleConditions : conditions . length > 1
322
325
} ;
323
326
} ;
324
327
@@ -344,60 +347,13 @@ const transformPropertyToNative = (selector, property, value) => {
344
347
try {
345
348
const parsed = parseIfFunction ( ifFunc . content ) ;
346
349
347
- // Handle multiple conditions format
348
- if ( parsed . isMultipleConditions ) {
349
- // Check if any condition uses style() - if so, needs runtime processing
350
- const hasStyleCondition = parsed . conditions . some (
351
- ( condition ) => condition . conditionType === 'style'
352
- ) ;
353
-
354
- if ( hasStyleCondition ) {
355
- // If any condition uses style(), fall back to runtime processing
356
- runtimeRules . push ( {
357
- selector,
358
- property,
359
- value,
360
- condition : parsed
361
- } ) ;
362
- continue ;
363
- }
364
-
365
- // All conditions are media() or supports() - can transform to native CSS
366
- // Create fallback rule first
367
- const fallbackValue = value . replace (
368
- ifFunc . fullFunction ,
369
- parsed . falseValue
370
- ) ;
371
- nativeRules . push ( {
372
- condition : null , // No condition = fallback
373
- rule : `${ selector } { ${ property } : ${ fallbackValue } ; }`
374
- } ) ;
375
-
376
- // Create conditional rules for each condition (in reverse order for CSS cascade)
377
- const { conditions } = parsed ;
378
- for ( let i = conditions . length - 1 ; i >= 0 ; i -- ) {
379
- const condition = conditions [ i ] ;
380
- const nativeCondition =
381
- condition . conditionType === 'media'
382
- ? `@media (${ condition . conditionExpression } )`
383
- : `@supports (${ condition . conditionExpression } )` ;
384
-
385
- const conditionalValue = value . replace (
386
- ifFunc . fullFunction ,
387
- condition . value
388
- ) ;
389
- nativeRules . push ( {
390
- condition : nativeCondition ,
391
- rule : `${ selector } { ${ property } : ${ conditionalValue } ; }`
392
- } ) ;
393
- }
394
-
395
- continue ;
396
- }
350
+ // Check if any condition uses style() - if so, needs runtime processing
351
+ const hasStyleCondition = parsed . conditions . some (
352
+ ( condition ) => condition . conditionType === 'style'
353
+ ) ;
397
354
398
- // Handle single condition format (backward compatibility)
399
- if ( parsed . conditionType === 'style' ) {
400
- // Style() conditions need runtime processing
355
+ if ( hasStyleCondition ) {
356
+ // If any condition uses style(), fall back to runtime processing
401
357
runtimeRules . push ( {
402
358
selector,
403
359
property,
@@ -407,31 +363,35 @@ const transformPropertyToNative = (selector, property, value) => {
407
363
continue ;
408
364
}
409
365
410
- // Media() and supports() can be transformed to native CSS
411
- const nativeCondition =
412
- parsed . conditionType === 'media'
413
- ? `@media (${ parsed . conditionExpression } )`
414
- : `@supports (${ parsed . conditionExpression } )` ;
415
-
416
- // Create conditional rule with true value
417
- const trueValue = value . replace (
418
- ifFunc . fullFunction ,
419
- parsed . trueValue
420
- ) ;
421
- nativeRules . push ( {
422
- condition : nativeCondition ,
423
- rule : `${ selector } { ${ property } : ${ trueValue } ; }`
424
- } ) ;
425
-
426
- // Create fallback rule with false value
427
- const falseValue = value . replace (
366
+ // All conditions are media() or supports() - can transform to native CSS
367
+ // Create fallback rule first
368
+ const fallbackValue = value . replace (
428
369
ifFunc . fullFunction ,
429
- parsed . falseValue
370
+ parsed . elseValue
430
371
) ;
431
372
nativeRules . push ( {
432
373
condition : null , // No condition = fallback
433
- rule : `${ selector } { ${ property } : ${ falseValue } ; }`
374
+ rule : `${ selector } { ${ property } : ${ fallbackValue } ; }`
434
375
} ) ;
376
+
377
+ // Create conditional rules for each condition (in reverse order for CSS cascade)
378
+ const { conditions } = parsed ;
379
+ for ( let i = conditions . length - 1 ; i >= 0 ; i -- ) {
380
+ const condition = conditions [ i ] ;
381
+ const nativeCondition =
382
+ condition . conditionType === 'media'
383
+ ? `@media (${ condition . conditionExpression } )`
384
+ : `@supports (${ condition . conditionExpression } )` ;
385
+
386
+ const conditionalValue = value . replace (
387
+ ifFunc . fullFunction ,
388
+ condition . value
389
+ ) ;
390
+ nativeRules . push ( {
391
+ condition : nativeCondition ,
392
+ rule : `${ selector } { ${ property } : ${ conditionalValue } ; }`
393
+ } ) ;
394
+ }
435
395
} catch ( error ) {
436
396
// If parsing fails, fall back to runtime processing
437
397
runtimeRules . push ( {
0 commit comments