Skip to content

Commit f172907

Browse files
Copilotjogibear9988
andcommitted
Initial exploration - no code changes yet
Co-authored-by: jogibear9988 <364896+jogibear9988@users.noreply.github.com>
1 parent c366dbb commit f172907

2 files changed

Lines changed: 90 additions & 0 deletions

File tree

test/complex_features.test.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { parse, stringify } from '../src/index';
2+
3+
function testParse(name: string, css: string): { name: string, ok: boolean, error?: string, roundTripDiff?: boolean } {
4+
try {
5+
const ast = parse(css);
6+
const out = stringify(ast);
7+
const compressed = stringify(ast, { compress: true });
8+
// Check round-trip
9+
const ast2 = parse(out);
10+
const out2 = stringify(ast2);
11+
if (out !== out2) {
12+
return { name, ok: false, roundTripDiff: true, error: `Round trip: [${out.substring(0, 100)}] vs [${out2.substring(0, 100)}]` };
13+
}
14+
return { name, ok: true };
15+
} catch (e: any) {
16+
return { name, ok: false, error: e.message };
17+
}
18+
}
19+
20+
const tests = [
21+
['color-mix()', `.box { color: color-mix(in srgb, red 50%, blue); }`],
22+
['oklch()', `.box { color: oklch(0.7 0.15 180); background: oklch(0.5 0.2 120 / 0.5); }`],
23+
['lab() and lch()', `.box { color: lab(50% 20 -30); background: lch(50% 30 180); }`],
24+
['hwb()', `.box { color: hwb(180 20% 30%); }`],
25+
['@supports complex', `@supports (display: grid) and (not (display: inline-grid)) { .grid { display: grid; } }\n@supports selector(:has(> .child)) { .parent:has(> .child) { color: red; } }`],
26+
['@property', `@property --my-color { syntax: "<color>"; inherits: false; initial-value: #c0ffee; }`],
27+
['@scope complex', `@scope (.card) to (.card-body > *) { :scope { padding: 1rem; } .title { font-size: 1.2em; } }`],
28+
['@layer with imports', `@layer base, components, utilities;\n@import url("base.css") layer(base);\n@layer components { .btn { padding: 0.5em 1em; } }`],
29+
['@container with style()', `@container style(--theme: dark) { .card { background: #333; } }\n@container sidebar (min-width: 400px) and style(--responsive: true) { .sidebar-content { display: flex; } }`],
30+
['Complex pseudo-class selectors', `:has(> img):not(:has(> img + *)) { aspect-ratio: 1; }\n:is(h1, h2, h3):where(.title, .heading) { font-weight: bold; }\n:has(+ .sibling) { margin-right: 1em; }`],
31+
['Math functions', `.box { width: calc(100% - 2rem); height: min(50vh, 300px); font-size: clamp(1rem, 2vw + 0.5rem, 2rem); }`],
32+
['Custom properties with complex fallbacks', `.box { color: var(--color, var(--fallback-color, blue)); background: var(--bg, linear-gradient(to right, red, blue)); }`],
33+
['@font-face with unicode-range', `@font-face { font-family: "Custom Font"; src: url("font.woff2") format("woff2"), url("font.woff") format("woff"); unicode-range: U+0025-00FF, U+4??; font-display: swap; font-weight: 100 900; }`],
34+
['Media range syntax', `@media (width > 600px) { .box { color: red; } }\n@media (400px <= width <= 800px) { .box { color: blue; } }`],
35+
['Nested media queries', `@media screen { @media (min-width: 768px) { @media (prefers-color-scheme: dark) { .box { color: white; } } } }`],
36+
['!important', `.box { color: red !important; background: linear-gradient(to right, red, blue) !important; --custom: value !important; }`],
37+
['CSS Grid complex', `.grid { grid-template-areas: "header header header" "sidebar main aside" "footer footer footer"; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }`],
38+
['Complex animations', `.box { animation: slide-in 0.5s ease-out forwards, fade-in 0.3s ease-in, pulse 2s infinite alternate; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); }`],
39+
['@keyframes complex values', `@keyframes complex-anim { from { transform: translateX(0) rotate(0deg) scale(1); } 25%, 75% { transform: translateX(50px) rotate(180deg); } to { transform: translateX(0); } }`],
40+
['Complex attribute selectors', `[data-value^="prefix"] { color: red; }\n[data-value$="suffix" i] { color: blue; }\ninput[type="text"][required]:not(:disabled) { border: 1px solid red; }`],
41+
['@starting-style nested', `.box { transition: opacity 0.5s; opacity: 1; @starting-style { opacity: 0; } }`],
42+
['@view-transition', `@view-transition { navigation: auto; }\n::view-transition-old(main) { animation-duration: 0.3s; }`],
43+
['Complex nesting with multiple selectors', `.card, .panel { padding: 1rem; & .title, & .heading { font-size: 1.5em; &:hover, &:focus { color: blue; } } @media (max-width: 768px) { padding: 0.5rem; } }`],
44+
['Deep nesting 6 levels', `.l1 { .l2 { .l3 { .l4 { .l5 { .l6 { color: red; } } } } } }`],
45+
['Empty rules', `.empty {}\n@media screen {}\n@layer utilities {}\n@keyframes empty {}`],
46+
['Minified CSS', `.box{color:red;background:blue;border:1px solid green}`],
47+
['Escaped chars in selectors', `.foo\\.bar { color: red; }\n.foo\\:bar { color: blue; }`],
48+
['@position-try', `@position-try --my-position { top: 10px; left: 20px; }`],
49+
['Multi-line grid-template-areas', `.grid {\n grid-template-areas:\n "header header"\n "sidebar main"\n "footer footer";\n}`],
50+
['@counter-style', `@counter-style thumbs { system: cyclic; symbols: "\\1F44D"; suffix: " "; }`],
51+
] as [string, string][];
52+
53+
describe('Complex CSS parsing', () => {
54+
for (const [name, css] of tests) {
55+
it(`should parse: ${name}`, () => {
56+
const result = testParse(name, css);
57+
if (!result.ok) {
58+
console.log(`FAIL: ${name}: ${result.error}`);
59+
}
60+
expect(result.ok).toBe(true);
61+
});
62+
}
63+
});

test/investigate.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { parse, stringify } from '../src/index';
2+
3+
describe('investigate issues', () => {
4+
it('empty rules round trip', () => {
5+
const css = '.empty {}\n@media screen {}\n@layer utilities {}\n@keyframes empty {}';
6+
const ast = parse(css);
7+
const out1 = stringify(ast);
8+
console.log('OUT1:', JSON.stringify(out1));
9+
const ast2 = parse(out1);
10+
const out2 = stringify(ast2);
11+
console.log('OUT2:', JSON.stringify(out2));
12+
// The issue is: .empty {} produces an empty rule with no declarations
13+
// On stringify it may produce just ".empty {\n}" with a trailing newline
14+
// Let's just check parse works
15+
expect(ast.stylesheet.rules.length).toBe(4);
16+
});
17+
18+
it('multi-line grid-template-areas round trip', () => {
19+
const css = `.grid {\n grid-template-areas:\n "header header"\n "sidebar main"\n "footer footer";\n}`;
20+
const ast = parse(css);
21+
const out1 = stringify(ast);
22+
console.log('GRID OUT1:', JSON.stringify(out1));
23+
const ast2 = parse(out1);
24+
const out2 = stringify(ast2);
25+
console.log('GRID OUT2:', JSON.stringify(out2));
26+
});
27+
});

0 commit comments

Comments
 (0)