Skip to content

Commit

Permalink
Improve media query validation messaging (#684)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattcompiles authored May 31, 2022
1 parent 64378b0 commit e531251
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 42 deletions.
5 changes: 5 additions & 0 deletions .changeset/orange-mirrors-shake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@vanilla-extract/css': patch
---

Improve media query validation messaging
3 changes: 1 addition & 2 deletions packages/css/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,17 +110,16 @@
"@emotion/hash": "^0.8.0",
"@vanilla-extract/private": "^1.0.3",
"chalk": "^4.1.1",
"css-mediaquery": "^0.1.2",
"css-what": "^5.0.1",
"cssesc": "^3.0.0",
"csstype": "^3.0.7",
"deep-object-diff": "^1.1.0",
"deepmerge": "^4.2.2",
"escape-string-regexp": "^4.0.0",
"media-query-parser": "^2.0.2",
"outdent": "^0.8.0"
},
"devDependencies": {
"@types/css-mediaquery": "^0.1.1",
"@types/cssesc": "^3.0.0"
}
}
66 changes: 55 additions & 11 deletions packages/css/src/validateMediaQuery.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ describe('validateMediaQuery', () => {
'(min-width: 30em) and (orientation: landscape)',
'only screen and (min-width: 320px) and (max-width: 480px) and (resolution: 150dpi)',
'not screen and (color), print and (color)',
'(prefers-reduced-motion)',
'(prefers-reduced-motion: no-preference)',
];

validMediaQueries.forEach((query) =>
Expand All @@ -20,17 +22,59 @@ describe('validateMediaQuery', () => {
});

describe('invalid media queries', () => {
const invalidMediaQueries = [
'',
'random query',
'(min-height: 600px',
'min-width: 600px)',
];
it('empty query', () => {
expect(() => validateMediaQuery('')).toThrowErrorMatchingInlineSnapshot(`
"Invalid media query: \\"\\"
invalidMediaQueries.forEach((query) =>
it(query, () => {
expect(() => validateMediaQuery(query)).toThrow();
}),
);
Query is empty
Read more on MDN: https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries"
`);
});

it('random query', () => {
expect(() => validateMediaQuery('random query'))
.toThrowErrorMatchingInlineSnapshot(`
"Invalid media query: \\"random query\\"
Unknown ident 'random' in media query
Read more on MDN: https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries"
`);
});

it('(min-height: 600px', () => {
expect(() => validateMediaQuery('(min-height: 600px'))
.toThrowErrorMatchingInlineSnapshot(`
"Invalid media query: \\"(min-height: 600px\\"
Invalid media condition
Expected media condition after '('
Read more on MDN: https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries"
`);
});

it('min-width: 600px)', () => {
expect(() => validateMediaQuery('min-width: 600px)'))
.toThrowErrorMatchingInlineSnapshot(`
"Invalid media query: \\"min-width: 600px)\\"
Unknown ident 'min-width' in media query
Read more on MDN: https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries"
`);
});

it('prefers-reduced-motion: no-preference', () => {
expect(() => validateMediaQuery('prefers-reduced-motion: no-preference'))
.toThrowErrorMatchingInlineSnapshot(`
"Invalid media query: \\"prefers-reduced-motion: no-preference\\"
Unknown ident 'prefers-reduced-motion' in media query
Read more on MDN: https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries"
`);
});
});
});
34 changes: 17 additions & 17 deletions packages/css/src/validateMediaQuery.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import outdent from 'outdent';
import { parse } from 'css-mediaquery';
import { toAST } from 'media-query-parser';

const mediaTypes = ['all', 'print', 'screen'];
const createMediaQueryError = (mediaQuery: string, msg: string) =>
new Error(
outdent`
Invalid media query: "${mediaQuery}"
export const validateMediaQuery = (mediaQuery: string) => {
const { type, expressions } = parse(mediaQuery)?.[0];
${msg}
const isAllQuery = mediaQuery === 'all';
const isValidType = mediaTypes.includes(type);
Read more on MDN: https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries
`,
);

// If the parser returns all for the type, we should have expressions
// or the query should match 'all' otherwise it is invalid
if (!isValidType || (!isAllQuery && type === 'all' && !expressions.length)) {
throw new Error(
outdent`
Invalid media query: ${mediaQuery}
export const validateMediaQuery = (mediaQuery: string) => {
if (mediaQuery === '') {
throw createMediaQueryError(mediaQuery, 'Query is empty');
}

A media query can contain an optional media type and any number of media feature expressions.
Read more on MDN: https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries
`,
);
try {
toAST(mediaQuery);
} catch (e: any) {
throw createMediaQueryError(mediaQuery, e.message);
}
};
20 changes: 8 additions & 12 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit e531251

Please sign in to comment.