import { generate, parse } from 'css-tree'; import { sanitizeDeclarations } from './sanitize-declarations.js'; describe('sanitizeDeclarations', () => { it('converts border-radius:calc(Infinity * 1px) to border-radius:9999px', () => { let root = parse(`.rounded-full { border-radius: calc(Infinity * 1px); } `); sanitizeDeclarations(root); expect(generate(root)).toBe('.rounded-full{border-radius:9999px}'); root = parse(`.rounded-full { border-radius: calc(infinity * 1px); } `); sanitizeDeclarations(root); expect(generate(root)).toBe('.rounded-full{border-radius:9999px}'); root = parse(`.rounded-full { border-radius: calc(infinity*1px); } `); sanitizeDeclarations(root); expect(generate(root)).toBe('.rounded-full{border-radius:9999px}'); root = parse(`.rounded-full { border-radius: calc(Infinity*1px); } `); sanitizeDeclarations(root); expect(generate(root)).toBe('.rounded-full{border-radius:9999px}'); }); it('separates padding-block and padding-inline', () => { let root = parse(`.box { padding-inline: 4px 14; } `); sanitizeDeclarations(root); expect(generate(root)).toMatchInlineSnapshot( `".box{padding-right:14;padding-left:4px}"`, ); root = parse(`.box { padding-block: 10px 20%; } `); sanitizeDeclarations(root); expect(generate(root)).toMatchInlineSnapshot( `".box{padding-bottom:20%;padding-top:10px}"`, ); root = parse(`.box { padding-inline: 99rem; } `); sanitizeDeclarations(root); expect(generate(root)).toMatchInlineSnapshot( `".box{padding-right:99rem;padding-left:99rem}"`, ); root = parse(`.box { padding-block: 8px; } `); sanitizeDeclarations(root); expect(generate(root)).toMatchInlineSnapshot( `".box{padding-bottom:8px;padding-top:8px}"`, ); }); it('should do separation of margin-block and margin-inline', () => { let root = parse(`.box { margin-inline: 4px 14; } `); sanitizeDeclarations(root); expect(generate(root)).toMatchInlineSnapshot( `".box{margin-right:14;margin-left:4px}"`, ); root = parse(`.box { margin-block: 10px 20%; } `); sanitizeDeclarations(root); expect(generate(root)).toMatchInlineSnapshot( `".box{margin-bottom:20%;margin-top:10px}"`, ); root = parse(`.box { margin-inline: 99rem; } `); sanitizeDeclarations(root); expect(generate(root)).toMatchInlineSnapshot( `".box{margin-right:99rem;margin-left:99rem}"`, ); root = parse(`.box { margin-block: 8px; } `); sanitizeDeclarations(root); expect(generate(root)).toMatchInlineSnapshot( `".box{margin-bottom:8px;margin-top:8px}"`, ); }); test('oklch to rgb conversion', () => { let stylesheet = parse('div { color: oklch(90.5% 0.2 180); }'); sanitizeDeclarations(stylesheet); expect( generate(stylesheet), 'conversion without alpha', ).toMatchInlineSnapshot(`"div{color:rgb(0,255,229)}"`); stylesheet = parse('div { color: oklch(96.6% 0.147 107 / 80%); }'); sanitizeDeclarations(stylesheet); expect(generate(stylesheet), 'conversion with alpha').toMatchInlineSnapshot( `"div{color:rgb(255,251,126,0.8)}"`, ); stylesheet = parse('div { color: oklch(96.6% 0.147 107deg / 80%); }'); sanitizeDeclarations(stylesheet); expect( generate(stylesheet), 'conversion with deg unit', ).toMatchInlineSnapshot(`"div{color:rgb(255,251,126,0.8)}"`); stylesheet = parse('div { color: oklch(92.6% 0.0546 218 / 50%); }'); sanitizeDeclarations(stylesheet); expect(generate(stylesheet)).toMatchInlineSnapshot( `"div{color:rgb(191,240,255,0.5)}"`, ); stylesheet = parse('div { color: oklch(88.3% 0.102 329); }'); sanitizeDeclarations(stylesheet); expect(generate(stylesheet)).toMatchInlineSnapshot( `"div{color:rgb(255,193,250)}"`, ); stylesheet = parse('div { color: oklch(69.3% 0.206 42.8); }'); sanitizeDeclarations(stylesheet); expect(generate(stylesheet)).toMatchInlineSnapshot( `"div{color:rgb(255,100,0)}"`, ); }); test('rgba space syntax to comma syntax conversion', () => { let stylesheet = parse('div { color: rgb(255 0 128); }'); sanitizeDeclarations(stylesheet); expect( generate(stylesheet), 'conversion with space syntax and no alpha', ).toMatchInlineSnapshot(`"div{color:rgb(255,0,128)}"`); stylesheet = parse('div { color: rgb(255 0 128 / 0.5); }'); sanitizeDeclarations(stylesheet); expect( generate(stylesheet), 'conversion with space syntax and alpha', ).toMatchInlineSnapshot(`"div{color:rgb(255,0,128,0.5)}"`); stylesheet = parse('div { color: rgb(100% 0% 50% / 50%); }'); sanitizeDeclarations(stylesheet); expect( generate(stylesheet), 'conversion with percentage values', ).toMatchInlineSnapshot(`"div{color:rgb(255,0,128,0.5)}"`); stylesheet = parse('div { color: rgb(255 0 128 / 50%); }'); sanitizeDeclarations(stylesheet); expect( generate(stylesheet), 'conversion with space syntax and alpha with a percetange syntax', ).toMatchInlineSnapshot(`"div{color:rgb(255,0,128,0.5)}"`); stylesheet = parse('div { color: rgb(255 0 128 / 1); }'); sanitizeDeclarations(stylesheet); expect(generate(stylesheet)).toMatchInlineSnapshot( `"div{color:rgb(255,0,128)}"`, ); stylesheet = parse( 'div { background: linear-gradient(rgb(255 0 0), rgb(0 255 0 / 0.8)); }', ); sanitizeDeclarations(stylesheet); expect(generate(stylesheet)).toMatchInlineSnapshot( `"div{background:linear-gradient(rgb(255,0,0),rgb(0,255,0,0.8))}"`, ); stylesheet = parse('div { color: rgb( 255 0 128 / 0.7 ); }'); sanitizeDeclarations(stylesheet); expect(generate(stylesheet)).toMatchInlineSnapshot( `"div{color:rgb(255,0,128,0.7)}"`, ); stylesheet = parse('div { color: rgb(0 0 0); }'); sanitizeDeclarations(stylesheet); expect(generate(stylesheet)).toMatchInlineSnapshot( `"div{color:rgb(0,0,0)}"`, ); stylesheet = parse('div { color: rgb(255, 0, 128); }'); sanitizeDeclarations(stylesheet); expect( generate(stylesheet), 'treatment for already supported rgb syntax', ).toMatchInlineSnapshot(`"div{color:rgb(255,0,128)}"`); }); test('hex to rgb conversion', () => { let stylesheet = parse('div { color: #f0a; }'); sanitizeDeclarations(stylesheet); expect( generate(stylesheet), '3-digit hex without alpha', ).toMatchInlineSnapshot(`"div{color:rgb(255,0,170)}"`); stylesheet = parse('div { color: #f0a8; }'); sanitizeDeclarations(stylesheet); expect( generate(stylesheet), '4-digit hex with alpha', ).toMatchInlineSnapshot(`"div{color:rgb(255,0,170,0.5333333333333333)}"`); stylesheet = parse('div { color: #ff00aa; }'); sanitizeDeclarations(stylesheet); expect( generate(stylesheet), '6-digit hex without alpha', ).toMatchInlineSnapshot(`"div{color:rgb(255,0,170)}"`); stylesheet = parse('div { color: #ff00aa80; }'); sanitizeDeclarations(stylesheet); expect( generate(stylesheet), '8-digit hex with alpha', ).toMatchInlineSnapshot(`"div{color:rgb(255,0,170,0.5019607843137255)}"`); stylesheet = parse('div { color: #000; }'); sanitizeDeclarations(stylesheet); expect(generate(stylesheet)).toMatchInlineSnapshot( `"div{color:rgb(0,0,0)}"`, ); stylesheet = parse('div { color: #fff; }'); sanitizeDeclarations(stylesheet); expect(generate(stylesheet)).toMatchInlineSnapshot( `"div{color:rgb(255,255,255)}"`, ); stylesheet = parse('div { color: #ff0000; }'); sanitizeDeclarations(stylesheet); expect(generate(stylesheet)).toMatchInlineSnapshot( `"div{color:rgb(255,0,0)}"`, ); stylesheet = parse('div { color: #00ff00; }'); sanitizeDeclarations(stylesheet); expect(generate(stylesheet)).toMatchInlineSnapshot( `"div{color:rgb(0,255,0)}"`, ); stylesheet = parse('div { color: #0000ff; }'); sanitizeDeclarations(stylesheet); expect(generate(stylesheet)).toMatchInlineSnapshot( `"div{color:rgb(0,0,255)}"`, ); stylesheet = parse('div { color: #abcdef; }'); sanitizeDeclarations(stylesheet); expect(generate(stylesheet)).toMatchInlineSnapshot( `"div{color:rgb(171,205,239)}"`, ); stylesheet = parse('div { color: #ABCDEF; }'); sanitizeDeclarations(stylesheet); expect(generate(stylesheet)).toMatchInlineSnapshot( `"div{color:rgb(171,205,239)}"`, ); stylesheet = parse('div { color: #AbCdEf; }'); sanitizeDeclarations(stylesheet); expect(generate(stylesheet), 'mixed casing').toMatchInlineSnapshot( `"div{color:rgb(171,205,239)}"`, ); stylesheet = parse('div { color: #ff000000; }'); sanitizeDeclarations(stylesheet); expect(generate(stylesheet)).toMatchInlineSnapshot( `"div{color:rgb(255,0,0,0)}"`, ); stylesheet = parse('div { color: #ff0000ff; }'); sanitizeDeclarations(stylesheet); expect(generate(stylesheet)).toMatchInlineSnapshot( `"div{color:rgb(255,0,0)}"`, ); stylesheet = parse( 'div { background: linear-gradient(#ff0000, #00ff00, #0000ff); }', ); sanitizeDeclarations(stylesheet); expect(generate(stylesheet)).toMatchInlineSnapshot( `"div{background:linear-gradient(rgb(255,0,0),rgb(0,255,0),rgb(0,0,255))}"`, ); stylesheet = parse( 'div { background: linear-gradient(#ff0000, rgb(0 255 0), oklch(50% 0.2 240)); }', ); sanitizeDeclarations(stylesheet); const result = generate(stylesheet); expect(result).toMatchInlineSnapshot( `"div{background:linear-gradient(rgb(255,0,0),rgb(0,255,0),rgb(0,105,199))}"`, ); stylesheet = parse( 'div { content: "Visit our site at example.com#section"; }', ); sanitizeDeclarations(stylesheet); expect(generate(stylesheet)).toMatchInlineSnapshot( `"div{content:"Visit our site at example.com#section"}"`, ); stylesheet = parse(` div { color: #ff0000; background-color: #00ff00; border-color: #0000ff; box-shadow: 0 0 10px #333; } `); sanitizeDeclarations(stylesheet); expect(generate(stylesheet)).toMatchInlineSnapshot( `"div{color:rgb(255,0,0);background-color:rgb(0,255,0);border-color:rgb(0,0,255);box-shadow:0 0 10px rgb(51,51,51)}"`, ); }); it('handles transparency generated with color-mix', () => { const stylesheet = parse(` .bg-blue-600/50 { background-color: color-mix(in oklab, oklch(54.6% 0.245 262.881) 60%, transparent); } `); sanitizeDeclarations(stylesheet); const result = generate(stylesheet); expect(result).toMatchInlineSnapshot( `".bg-blue-600/50{background-color:rgb(21,93,252,60%)}"`, ); }); describe('complex scenarios', () => { it('handles multiple declarations with different rgb formats', () => { const stylesheet = parse(` div { color: rgb(255 0 128 / 0.5); background-color: rgb(0 255 0); border-color: rgb(128, 128, 128); } `); sanitizeDeclarations(stylesheet); const result = generate(stylesheet); expect(result).toMatchInlineSnapshot( `"div{color:rgb(255,0,128,0.5);background-color:rgb(0,255,0);border-color:rgb(128,128,128)}"`, ); }); it('handles nested rules', () => { const stylesheet = parse(` @media (min-width: 768px) { div { color: rgb(255 0 128 / 0.8); } } `); sanitizeDeclarations(stylesheet); expect(generate(stylesheet)).toMatchInlineSnapshot( `"@media (min-width:768px){div{color:rgb(255,0,128,0.8)}}"`, ); }); it('processes at-rule declarations', () => { const stylesheet = parse(` @keyframes fade { from { background: rgb(255 0 0 / 0); } to { background: rgb(255 0 0 / 1); } } `); sanitizeDeclarations(stylesheet); const result = generate(stylesheet); expect(result).toMatchInlineSnapshot( `"@keyframes fade{from{background:rgb(255,0,0,0)}to{background:rgb(255,0,0)}}"`, ); }); }); });