diff --git a/src/lib/index.ts b/src/lib/index.ts index 5b3fb76..bc7eecd 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -303,6 +303,7 @@ export function format_atrule_prelude( return prelude .replaceAll(/\s*([:,])/g, prelude.toLowerCase().includes('selector(') ? '$1' : '$1 ') // force whitespace after colon or comma, except inside `selector()` .replaceAll(/\)([a-zA-Z])/g, ') $1') // force whitespace between closing parenthesis and following text (usually and|or) + .replaceAll(/\b(and|or|not|only)\(/gi, '$1 (') // force whitespace between media/supports keywords and opening parenthesis .replaceAll(/\s*(=>|>=|<=)\s*/g, `${optional_space}$1${optional_space}`) // add optional spacing around =>, >= and <= .replaceAll(/([^<>=\s])([<>])([^<>=\s])/g, `$1${optional_space}$2${optional_space}$3`) // add spacing around < or > except when it's part of <=, >=, => .replaceAll(/([^<>=\s])\s+([<>])\s+([^<>=\s])/g, `$1${optional_space}$2${optional_space}$3`) // handle spaces around < or > when they already have surrounding whitespace diff --git a/test/api.test.ts b/test/api.test.ts index eeba20b..15ee988 100644 --- a/test/api.test.ts +++ b/test/api.test.ts @@ -103,7 +103,22 @@ describe('format_atrule_prelude', () => { }) test('adds space between ) and following word', () => { - expect(format_atrule_prelude('(width > 0)and(height > 0)')).toBe('(width > 0) and(height > 0)') + expect(format_atrule_prelude('(width > 0)and(height > 0)')).toBe('(width > 0) and (height > 0)') + }) + + test('adds space between media keyword "and" and opening parenthesis', () => { + expect(format_atrule_prelude('(width > 0)and(height > 0)', { minify: true })).toBe( + '(width>0) and (height>0)', + ) + }) + + test('adds space between media keyword "not" and opening parenthesis', () => { + expect(format_atrule_prelude('not(color)')).toBe('not (color)') + expect(format_atrule_prelude('not(color)', { minify: true })).toBe('not (color)') + }) + + test('adds space between media keyword "or" and opening parenthesis', () => { + expect(format_atrule_prelude('(width > 0)or(height > 0)')).toBe('(width > 0) or (height > 0)') }) test('lowercases function names', () => { diff --git a/test/atrules.test.ts b/test/atrules.test.ts index db63db4..651890f 100644 --- a/test/atrules.test.ts +++ b/test/atrules.test.ts @@ -373,6 +373,48 @@ test('minify: keeps necessary whitespace between keywords', () => { expect(actual).toEqual(expected) }) +test('minify: keeps necessary whitespace in @media all and screen', () => { + let actual = minify(`@media all and screen {}`) + let expected = `@media all and screen{}` + expect(actual).toEqual(expected) +}) + +test('minify: keeps whitespace between "and" keyword and following media feature', () => { + let actual = minify(`@media screen and (min-width: 100px) {}`) + let expected = `@media screen and (min-width:100px){}` + expect(actual).toEqual(expected) +}) + +test('minify: keeps whitespace between "and" keywords with adjacent media features', () => { + let actual = minify(`@media (min-width: 100px) and (max-width: 200px) {}`) + let expected = `@media (min-width:100px) and (max-width:200px){}` + expect(actual).toEqual(expected) +}) + +test('minify: keeps whitespace between "not" keyword and media feature', () => { + let actual = minify(`@media not (color) {}`) + let expected = `@media not (color){}` + expect(actual).toEqual(expected) +}) + +test('minify: keeps whitespace between "not" keyword and media type', () => { + let actual = minify(`@media not screen {}`) + let expected = `@media not screen{}` + expect(actual).toEqual(expected) +}) + +test('minify: keeps whitespace between "only" keyword and media type', () => { + let actual = minify(`@media only screen {}`) + let expected = `@media only screen{}` + expect(actual).toEqual(expected) +}) + +test('minify: keeps whitespace between "or" keyword and media feature', () => { + let actual = minify(`@media (min-width: 100px) or (max-width: 200px) {}`) + let expected = `@media (min-width:100px) or (max-width:200px){}` + expect(actual).toEqual(expected) +}) + // oxlint-disable-next-line vitest/no-disabled-tests test.skip('preserves comments', () => { let actual = format(`