Skip to content

Commit 67bb3af

Browse files
committed
refactor: simplifications
1 parent ad70461 commit 67bb3af

File tree

3 files changed

+112
-138
lines changed

3 files changed

+112
-138
lines changed

docs/refactoring/CLEANUP_SUMMARY.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
### Debug Files (Root Directory)
66

7-
- `debug-transform.js` - Temporary debugging script
87
- `detailed-debug.js` - Detailed transformation debugging
98
- `property-debug.js` - Property transformation debugging
109
- `test-debug.js` - General test debugging

packages/css-if-polyfill/src/transform.js

Lines changed: 82 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,10 @@ const extractIfFunctions = (cssText) => {
186186
/**
187187
* Parse if() function content - supports both single conditions and multiple chained conditions
188188
*/
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) => {
191193
const segments = [];
192194
let currentSegment = '';
193195
let parenDepth = 0;
@@ -230,7 +232,51 @@ const parseIfFunction = (content) => {
230232
segments.push(currentSegment.trim());
231233
}
232234

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);
234280
const conditions = [];
235281
let elseValue = null;
236282

@@ -243,39 +289,7 @@ const parseIfFunction = (content) => {
243289
}
244290

245291
// 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);
279293
if (colonIndex === -1) {
280294
throw new Error('Invalid if() function: missing colon in segment');
281295
}
@@ -304,21 +318,10 @@ const parseIfFunction = (content) => {
304318
throw new Error('Invalid if() function: missing else clause');
305319
}
306320

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
318321
return {
319322
conditions,
320-
falseValue: elseValue,
321-
isMultipleConditions: true
323+
elseValue,
324+
isMultipleConditions: conditions.length > 1
322325
};
323326
};
324327

@@ -344,60 +347,13 @@ const transformPropertyToNative = (selector, property, value) => {
344347
try {
345348
const parsed = parseIfFunction(ifFunc.content);
346349

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+
);
397354

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
401357
runtimeRules.push({
402358
selector,
403359
property,
@@ -407,31 +363,35 @@ const transformPropertyToNative = (selector, property, value) => {
407363
continue;
408364
}
409365

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(
428369
ifFunc.fullFunction,
429-
parsed.falseValue
370+
parsed.elseValue
430371
);
431372
nativeRules.push({
432373
condition: null, // No condition = fallback
433-
rule: `${selector} { ${property}: ${falseValue}; }`
374+
rule: `${selector} { ${property}: ${fallbackValue}; }`
434375
});
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+
}
435395
} catch (error) {
436396
// If parsing fails, fall back to runtime processing
437397
runtimeRules.push({

packages/css-if-polyfill/test/transform-engine.test.js

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,15 @@ describe('CSS Transform Engine - Detailed Testing', () => {
5555
const parsed = parseIfFunction(content);
5656

5757
expect(parsed).toEqual({
58-
conditionType: 'media',
59-
conditionExpression: 'min-width: 768px',
60-
trueValue: 'blue',
61-
falseValue: 'red'
58+
conditions: [
59+
{
60+
conditionType: 'media',
61+
conditionExpression: 'min-width: 768px',
62+
value: 'blue'
63+
}
64+
],
65+
elseValue: 'red',
66+
isMultipleConditions: false
6267
});
6368
});
6469

@@ -67,10 +72,15 @@ describe('CSS Transform Engine - Detailed Testing', () => {
6772
const parsed = parseIfFunction(content);
6873

6974
expect(parsed).toEqual({
70-
conditionType: 'supports',
71-
conditionExpression: 'display: grid',
72-
trueValue: 'transparent',
73-
falseValue: 'white'
75+
conditions: [
76+
{
77+
conditionType: 'supports',
78+
conditionExpression: 'display: grid',
79+
value: 'transparent'
80+
}
81+
],
82+
elseValue: 'white',
83+
isMultipleConditions: false
7484
});
7585
});
7686

@@ -79,10 +89,15 @@ describe('CSS Transform Engine - Detailed Testing', () => {
7989
const parsed = parseIfFunction(content);
8090

8191
expect(parsed).toEqual({
82-
conditionType: 'style',
83-
conditionExpression: '--large',
84-
trueValue: '24px',
85-
falseValue: '16px'
92+
conditions: [
93+
{
94+
conditionType: 'style',
95+
conditionExpression: '--large',
96+
value: '24px'
97+
}
98+
],
99+
elseValue: '16px',
100+
isMultipleConditions: false
86101
});
87102
});
88103

@@ -91,10 +106,10 @@ describe('CSS Transform Engine - Detailed Testing', () => {
91106
'media(min-width: 768px): linear-gradient(to right, blue, navy); else: solid red';
92107
const parsed = parseIfFunction(content);
93108

94-
expect(parsed.trueValue).toBe(
109+
expect(parsed.conditions[0].value).toBe(
95110
'linear-gradient(to right, blue, navy)'
96111
);
97-
expect(parsed.falseValue).toBe('solid red');
112+
expect(parsed.elseValue).toBe('solid red');
98113
});
99114

100115
test('throws error for malformed if() functions', () => {
@@ -105,7 +120,7 @@ describe('CSS Transform Engine - Detailed Testing', () => {
105120
parseIfFunction('invalid-condition: blue; else: red')
106121
).toThrow('unknown condition type');
107122
expect(() => parseIfFunction('blue; else: red')).toThrow(
108-
'missing else clause'
123+
'missing colon'
109124
);
110125
});
111126
});

0 commit comments

Comments
 (0)