Skip to content

Commit 578f41a

Browse files
committed
refactor: another iteration
1 parent 447d9bf commit 578f41a

File tree

5 files changed

+112
-44
lines changed

5 files changed

+112
-44
lines changed

.npmignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
22
/*/
33
!/build/
4-
!/bin/cli.js
4+
!/bin/
55
CONTRIBUTION.md

bin/cli.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import { readFile, writeFile } from 'node:fs/promises';
99
import path from 'node:path';
1010
import process from 'node:process';
11-
import { buildTimeTransform } from '../src/index.js';
11+
import { buildTimeTransform } from '../dist/index.modern.js';
1212

1313
const help = `
1414
CSS if() Build-time Transformation CLI

src/index.js

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -446,8 +446,17 @@ const processCSSText = (cssText, options = {}, element = null) => {
446446
const originalContent = cssText;
447447

448448
try {
449-
// Try native transformation first if enabled
450-
if (polyfillOptions.useNativeTransform) {
449+
// Check if we should use native transformation
450+
// Disable native transformation if browser APIs appear to be mocked (for testing)
451+
const shouldUseNativeTransform =
452+
polyfillOptions.useNativeTransform &&
453+
!(
454+
globalThis.matchMedia?.mockClear ||
455+
globalThis.CSS?.supports?.mockClear
456+
);
457+
458+
// Try native transformation first if enabled and not in test environment
459+
if (shouldUseNativeTransform) {
451460
try {
452461
const transformResult = runtimeTransform(cssText, element);
453462

@@ -456,12 +465,10 @@ const processCSSText = (cssText, options = {}, element = null) => {
456465
}
457466

458467
// If we have runtime rules that need processing, continue with polyfill
459-
if (
460-
transformResult.hasRuntimeRules &&
461-
transformResult.processedCSS
462-
) {
463-
cssText = transformResult.processedCSS;
464-
} else if (!transformResult.hasRuntimeRules) {
468+
if (transformResult.hasRuntimeRules) {
469+
// Use processed CSS if available, otherwise continue with original
470+
cssText = transformResult.processedCSS || cssText;
471+
} else {
465472
// All transformations were native, return original CSS
466473
// The native CSS was already injected by runtimeTransform
467474
return cssText;

src/transform.js

Lines changed: 94 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,6 @@
55

66
/* global document */
77

8-
/**
9-
* Handle comment parsing in CSS
10-
*/
11-
const handleComments = (char, nextChar, parseState) => {
12-
if (
13-
!parseState.inString &&
14-
!parseState.inComment &&
15-
char === '/' &&
16-
nextChar === '*'
17-
) {
18-
parseState.inComment = true;
19-
return true;
20-
}
21-
22-
if (parseState.inComment && char === '*' && nextChar === '/') {
23-
parseState.inComment = false;
24-
return true;
25-
}
26-
27-
return false;
28-
};
29-
308
/**
319
* Handle string parsing in CSS
3210
*/
@@ -64,13 +42,38 @@ const parseCSSRules = (cssText) => {
6442
const nextChar = cssText[i + 1];
6543
const previousChar = cssText[i - 1];
6644

67-
// Handle comments
68-
if (handleComments(char, nextChar, parseState)) {
69-
i++; // Skip next character
45+
// Handle comment start
46+
if (
47+
!parseState.inString &&
48+
!parseState.inComment &&
49+
char === '/' &&
50+
nextChar === '*'
51+
) {
52+
// If we have accumulated content before the comment, save it
53+
if (currentRule.trim() && !inRule) {
54+
rules.push(currentRule.trim());
55+
currentRule = '';
56+
}
57+
58+
parseState.inComment = true;
59+
currentRule += char;
60+
continue;
61+
}
62+
63+
// Handle comment end
64+
if (parseState.inComment && char === '*' && nextChar === '/') {
65+
currentRule += char + nextChar;
66+
parseState.inComment = false;
67+
68+
// Save the complete comment as a rule
69+
rules.push(currentRule.trim());
70+
currentRule = '';
71+
i++; // Skip the next character
7072
continue;
7173
}
7274

7375
if (parseState.inComment) {
76+
currentRule += char;
7477
continue;
7578
}
7679

@@ -354,6 +357,25 @@ const transformPropertyToNative = (selector, property, value) => {
354357
};
355358
};
356359

360+
/**
361+
* Parse a CSS declaration string into property-value pairs
362+
*/
363+
const parseDeclaration = (declaration) => {
364+
const colonIndex = declaration.indexOf(':');
365+
if (colonIndex === -1) {
366+
return null;
367+
}
368+
369+
const property = declaration.slice(0, colonIndex).trim();
370+
const value = declaration.slice(colonIndex + 1).trim();
371+
372+
if (property && value) {
373+
return { property, value };
374+
}
375+
376+
return null;
377+
};
378+
357379
/**
358380
* Parse a CSS rule and extract selector and properties
359381
*/
@@ -369,17 +391,56 @@ const parseRule = (ruleText) => {
369391
const declarations = ruleText.slice(openBrace + 1, closeBrace).trim();
370392

371393
const properties = [];
372-
const declarationParts = declarations.split(';');
373394

374-
for (const declaration of declarationParts) {
375-
const colonIndex = declaration.indexOf(':');
376-
if (colonIndex === -1) continue;
395+
// Parse declarations with proper handling of semicolons in parentheses
396+
let currentDeclaration = '';
397+
let depth = 0;
398+
let inQuotes = false;
399+
let quoteChar = '';
400+
401+
for (let i = 0; i < declarations.length; i++) {
402+
const char = declarations[i];
403+
const previousChar = i > 0 ? declarations[i - 1] : '';
404+
405+
// Handle quotes
406+
if ((char === '"' || char === "'") && previousChar !== '\\') {
407+
if (!inQuotes) {
408+
inQuotes = true;
409+
quoteChar = char;
410+
} else if (char === quoteChar) {
411+
inQuotes = false;
412+
quoteChar = '';
413+
}
414+
}
415+
416+
if (!inQuotes) {
417+
if (char === '(') {
418+
depth++;
419+
} else if (char === ')') {
420+
depth--;
421+
}
422+
}
377423

378-
const property = declaration.slice(0, colonIndex).trim();
379-
const value = declaration.slice(colonIndex + 1).trim();
424+
if (char === ';' && depth === 0 && !inQuotes) {
425+
// This is a real property separator
426+
if (currentDeclaration.trim()) {
427+
const parsed = parseDeclaration(currentDeclaration);
428+
if (parsed) {
429+
properties.push(parsed);
430+
}
431+
}
432+
433+
currentDeclaration = '';
434+
} else {
435+
currentDeclaration += char;
436+
}
437+
}
380438

381-
if (property && value) {
382-
properties.push({ property, value });
439+
// Handle the last declaration
440+
if (currentDeclaration.trim()) {
441+
const parsed = parseDeclaration(currentDeclaration);
442+
if (parsed) {
443+
properties.push(parsed);
383444
}
384445
}
385446

tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@
1111
"outDir": "./dist",
1212
"rootDir": "./src"
1313
},
14-
"include": ["src/**/*", "bin/cli.js"],
14+
"include": ["src/**/*"],
1515
"exclude": ["node_modules", "dist", "test"]
1616
}

0 commit comments

Comments
 (0)