media-query-parser
Advanced tools
Comparing version 3.0.0-beta.0 to 3.0.0-beta.1
@@ -1,3 +0,3 @@ | ||
import { MediaCondition, MediaFeature, MediaQuery, MediaQueryList, ParserError, ParserToken, RatioToken, ValidRange } from "../shared.js"; | ||
type ConvenientToken = ParserToken | (RatioToken & { | ||
import { MediaCondition, MediaFeature, MediaQuery, MediaQueryList, ParserError, ParserToken, RatioToken, ValidRange } from "../utils.js"; | ||
export type ConvenientToken = ParserToken | (RatioToken & { | ||
hasSpaceBefore: boolean; | ||
@@ -8,2 +8,9 @@ hasSpaceAfter: boolean; | ||
}); | ||
export type UncheckedRange = { | ||
leftToken?: ConvenientToken | undefined; | ||
leftOp?: ">=" | "<=" | ">" | "<" | "=" | undefined; | ||
feature: string; | ||
rightOp?: ">=" | "<=" | ">" | "<" | "=" | undefined; | ||
rightToken?: ConvenientToken | undefined; | ||
}; | ||
export declare const isParserError: (value: unknown) => value is ParserError; | ||
@@ -15,3 +22,4 @@ export declare const splitMediaQueryList: (tokens: ParserToken[]) => Array<ParserToken[]>; | ||
export declare const readMediaFeature: (parsingTokens: ParserToken[]) => MediaFeature | ParserError; | ||
export declare const readRange: (convenientTokens: ConvenientToken[]) => ValidRange | ParserError; | ||
export {}; | ||
export declare const readRange: (convenientTokens: ConvenientToken[]) => (ValidRange & { | ||
feature: string; | ||
}) | ParserError; |
@@ -32,3 +32,3 @@ export const isParserError = e => 'object' == typeof e && null !== e && 'errid' in e | ||
if (1 === t.length && 0 === t[0].length) | ||
return {type: 'query-list', mediaQueries: [{type: 'query', mediaType: 'all'}]} | ||
return {type: 'query-list', mediaQueries: [{type: 'query'}]} | ||
{ | ||
@@ -38,3 +38,3 @@ const e = [] | ||
const t = readMediaQuery(r) | ||
isParserError(t) ? e.push({type: 'query', mediaPrefix: 'not', mediaType: 'all'}) : e.push(t) | ||
isParserError(t) ? e.push({type: 'query', prefix: 'not'}) : e.push(t) | ||
} | ||
@@ -49,3 +49,3 @@ return {type: 'query-list', mediaQueries: e} | ||
if ('(' === i.type) { | ||
const r = readMediaCondition(e, !1) | ||
const r = readMediaCondition(e, !0) | ||
if (isParserError(r)) { | ||
@@ -55,3 +55,3 @@ const {start: n, end: a} = null !== (t = e.at(1)) && void 0 !== t ? t : i | ||
} | ||
return {type: 'query', mediaType: 'all', mediaCondition: r} | ||
return {type: 'query', mediaCondition: r} | ||
} | ||
@@ -74,10 +74,5 @@ if ('ident' === i.type) { | ||
type: 'query', | ||
mediaType: 'all', | ||
mediaCondition: {type: 'condition', operator: 'not', children: [t]} | ||
} | ||
} | ||
if (void 0 === t) { | ||
const {start: e, end: t} = l | ||
return {errid: 'EXPECT_LPAREN_OR_TYPE', start: e, end: t} | ||
} | ||
{ | ||
@@ -90,3 +85,3 @@ const {start: e, end: t} = l | ||
const {value: e, start: r, end: n} = l | ||
if ('all' === e) a = 'all' | ||
if ('all' === e) a = void 0 | ||
else if ('print' === e || 'screen' === e) a = e | ||
@@ -105,16 +100,23 @@ else { | ||
return {errid: 'EXPECT_TYPE', start: r, end: n} | ||
;(t = 'not' === t ? void 0 : 'not'), (a = 'all') | ||
;(t = 'not' === t ? void 0 : 'not'), (a = void 0) | ||
} | ||
} | ||
if (o + 1 === e.length) return {type: 'query', mediaPrefix: t, mediaType: a} | ||
if (o + 1 === e.length) return {type: 'query', prefix: t, mediaType: a} | ||
{ | ||
const r = e[o + 1] | ||
if ('ident' === r.type && 'and' === r.value) { | ||
const r = readMediaCondition(e.slice(o + 2), !1), | ||
i = e.at(-1), | ||
{start: d, end: s} = | ||
null !== (n = e.at(o + 2)) && void 0 !== n ? n : {start: i.end + 1, end: i.end + 1} | ||
return isParserError(r) | ||
? {errid: 'EXPECT_CONDITION', start: d, end: s, child: r} | ||
: {type: 'query', mediaPrefix: t, mediaType: a, mediaCondition: r} | ||
const r = e.at(-1), | ||
i = e.at(o + 2) | ||
let d, | ||
s = r.end + 1 | ||
if ('ident' === (null == i ? void 0 : i.type) && 'not' === i.value) { | ||
s += 1 | ||
const t = readMediaCondition(e.slice(o + 3), !1) | ||
d = isParserError(t) ? t : {type: 'condition', operator: 'not', children: [t]} | ||
} else d = readMediaCondition(e.slice(o + 2), !1) | ||
const {start: l, end: u} = | ||
null !== (n = e.at(o + 2)) && void 0 !== n ? n : {start: s, end: s} | ||
return isParserError(d) | ||
? {errid: 'EXPECT_CONDITION', start: l, end: u, child: d} | ||
: {type: 'query', prefix: t, mediaType: a, mediaCondition: d} | ||
} | ||
@@ -167,3 +169,3 @@ return {errid: 'EXPECT_AND', start: r.start, end: r.end} | ||
return {errid: 'MIX_AND_WITH_OR', start: n.start, end: n.end} | ||
if ('or' === n.value && !t) return {errid: 'OR_AT_TOP_LEVEL', start: n.start, end: n.end} | ||
if ('or' === n.value && !t) return {errid: 'MIX_AND_WITH_OR', start: n.start, end: n.end} | ||
const d = readMediaCondition(e.slice(a + 2), t, n.value) | ||
@@ -182,3 +184,3 @@ return isParserError(d) | ||
const r = e[e.length - 1] | ||
if (')' !== r.type) return {errid: 'EXPECT_RPAREN', start: r.start, end: r.end} | ||
if (')' !== r.type) return {errid: 'EXPECT_RPAREN', start: r.end + 1, end: r.end + 1} | ||
const n = [e[0]] | ||
@@ -231,3 +233,3 @@ for (let t = 1; t < e.length; t++) { | ||
const {hasSpaceBefore: a, hasSpaceAfter: d, start: s, end: o, ...l} = e | ||
return {type: 'feature', context: 'value', mediaPrefix: t, feature: r, value: l} | ||
return {type: 'feature', context: 'value', prefix: t, feature: r, value: l} | ||
} | ||
@@ -238,5 +240,8 @@ return {errid: 'EXPECT_VALUE', start: e.start, end: e.end} | ||
const e = readRange(n) | ||
return isParserError(e) | ||
? {errid: 'EXPECT_RANGE', start: t.start, end: n[n.length - 1].end, child: e} | ||
: {type: 'feature', context: 'range', feature: e.featureName, range: e} | ||
if (isParserError(e)) | ||
return {errid: 'EXPECT_RANGE', start: t.start, end: n[n.length - 1].end, child: e} | ||
{ | ||
const {feature: t, ...r} = e | ||
return {type: 'feature', context: 'range', feature: t, range: r} | ||
} | ||
} | ||
@@ -264,3 +269,3 @@ return {errid: 'INVALID_FEATURE', start: t.start, end: e[e.length - 1].end} | ||
if (')' !== l.type) return {errid: 'EXPECT_RPAREN', start: l.start, end: l.end} | ||
const u = {featureName: ''}, | ||
const u = {feature: ''}, | ||
p = | ||
@@ -287,3 +292,3 @@ 'number' === e[1].type || | ||
if ('ident' !== e[1].type) return {errid: 'INVALID_RANGE', start: e[0].start, end: l.end} | ||
u.featureName = e[1].value | ||
u.feature = e[1].value | ||
} | ||
@@ -300,3 +305,3 @@ const t = | ||
if ('ident' !== r.type) return {errid: 'INVALID_RANGE', start: e[0].start, end: l.end} | ||
if (((u.featureName = r.value), e.length >= 7)) { | ||
if (((u.feature = r.value), e.length >= 7)) { | ||
const r = e[t + 1], | ||
@@ -331,30 +336,30 @@ n = e[t + 2] | ||
let n | ||
const {leftToken: i, leftOp: f, featureName: c, rightOp: y, rightToken: E} = u | ||
let h, v | ||
const {leftToken: i, leftOp: f, feature: c, rightOp: y, rightToken: h} = u | ||
let E, v | ||
if (void 0 !== i) | ||
if ('ident' === i.type) { | ||
const {type: e, value: t} = i | ||
'infinite' === t && (h = {type: e, value: t}) | ||
'infinite' === t && (E = {type: e, value: t}) | ||
} else if ('number' === i.type || 'dimension' === i.type || 'ratio' === i.type) { | ||
const {hasSpaceBefore: e, hasSpaceAfter: t, start: r, end: n, ...a} = i | ||
h = a | ||
E = a | ||
} | ||
if (void 0 !== E) | ||
if ('ident' === E.type) { | ||
const {type: e, value: t} = E | ||
if (void 0 !== h) | ||
if ('ident' === h.type) { | ||
const {type: e, value: t} = h | ||
'infinite' === t && (v = {type: e, value: t}) | ||
} else if ('number' === E.type || 'dimension' === E.type || 'ratio' === E.type) { | ||
const {hasSpaceBefore: e, hasSpaceAfter: t, start: r, end: n, ...i} = E | ||
} else if ('number' === h.type || 'dimension' === h.type || 'ratio' === h.type) { | ||
const {hasSpaceBefore: e, hasSpaceAfter: t, start: r, end: n, ...i} = h | ||
v = i | ||
} | ||
if (void 0 !== h && void 0 !== v) | ||
if (void 0 !== E && void 0 !== v) | ||
if (('<' !== f && '<=' !== f) || ('<' !== y && '<=' !== y)) { | ||
if (('>' !== f && '>=' !== f) || ('>' !== y && '>=' !== y)) | ||
return {errid: 'INVALID_RANGE', start: e[0].start, end: l.end} | ||
n = {leftToken: h, leftOp: f, featureName: c, rightOp: y, rightToken: v} | ||
} else n = {leftToken: h, leftOp: f, featureName: c, rightOp: y, rightToken: v} | ||
n = {leftToken: E, leftOp: f, feature: c, rightOp: y, rightToken: v} | ||
} else n = {leftToken: E, leftOp: f, feature: c, rightOp: y, rightToken: v} | ||
else | ||
((void 0 === h && void 0 === f && void 0 !== y && void 0 !== v) || | ||
(void 0 !== h && void 0 !== f && void 0 === y && void 0 === v)) && | ||
(n = {leftToken: h, leftOp: f, featureName: c, rightOp: y, rightToken: v}) | ||
((void 0 === E && void 0 === f && void 0 !== y && void 0 !== v) || | ||
(void 0 !== E && void 0 !== f && void 0 === y && void 0 === v)) && | ||
(n = {leftToken: E, leftOp: f, feature: c, rightOp: y, rightToken: v}) | ||
return null != n ? n : {errid: 'INVALID_RANGE', start: e[0].start, end: l.end} | ||
@@ -361,0 +366,0 @@ } |
@@ -1,2 +0,2 @@ | ||
import { MediaCondition, MediaFeature, MediaQuery, MediaQueryList, ParserErrId, ValidRange, ValidValueToken } from "../shared.js"; | ||
import { MediaCondition, MediaFeature, MediaQuery, MediaQueryList, ParserErrId, ValidRange, ValidValueToken } from "../utils.js"; | ||
export type LiteMediaQueryList = { | ||
@@ -6,4 +6,4 @@ mediaQueries: LiteMediaQuery[]; | ||
export type LiteMediaQuery = { | ||
mediaPrefix?: "not" | "only"; | ||
mediaType: "all" | "screen" | "print"; | ||
prefix?: "not" | "only"; | ||
mediaType?: "screen" | "print"; | ||
mediaCondition?: LiteMediaCondition; | ||
@@ -22,3 +22,3 @@ }; | ||
context: "value"; | ||
mediaPrefix?: "min" | "max"; | ||
prefix?: "min" | "max"; | ||
feature: string; | ||
@@ -34,3 +34,3 @@ value: ValidValueToken; | ||
export declare const toLiteMediaCondition: ({ operator, children, }: MediaCondition) => LiteMediaCondition; | ||
export declare const toLiteMediaQuery: ({ mediaType, mediaCondition, mediaPrefix, }: MediaQuery) => LiteMediaQuery; | ||
export declare const toLiteMediaQuery: ({ mediaType, mediaCondition, prefix, }: MediaQuery) => LiteMediaQuery; | ||
export declare const toLiteMediaQueryList: (mediaQueryList: MediaQueryList) => LiteMediaQueryList; | ||
@@ -37,0 +37,0 @@ export declare const parseLiteMediaQueryList: (str: string) => LiteMediaQueryList; |
@@ -9,5 +9,5 @@ import {lexer as e} from '../lexer/lexer.js' | ||
}) | ||
export const toLiteMediaQuery = ({mediaType: e, mediaCondition: t, mediaPrefix: i}) => ({ | ||
export const toLiteMediaQuery = ({mediaType: e, mediaCondition: t, prefix: i}) => ({ | ||
mediaType: e, | ||
mediaPrefix: i, | ||
prefix: i, | ||
mediaCondition: t ? toLiteMediaCondition(t) : t | ||
@@ -27,11 +27,7 @@ }) | ||
const a = i(e(o)) | ||
if ('boolean' == typeof r) expect(t(a)).not.toBe(r) | ||
else if ('string' == typeof r) { | ||
if ((expect(t(a)).toBe(!0), t(a))) { | ||
let e = a.child, | ||
t = a.errid | ||
for (; e; ) (t = e.errid), (e = e.child) | ||
expect(t).toBe(r) | ||
} | ||
} else expect(!t(a)).toBe(!0), t(a) || expect(toLiteMediaQuery(a)).toEqual(r) | ||
'boolean' == typeof r | ||
? expect(t(a)).not.toBe(r) | ||
: 'string' == typeof r | ||
? (expect(t(a)).toBe(!0), t(a) && expect(a.errid).toBe(r)) | ||
: (expect(!t(a)).toBe(!0), t(a) || expect(toLiteMediaQuery(a)).toEqual(r)) | ||
} | ||
@@ -38,0 +34,0 @@ export const isEqualish = (e, t) => { |
@@ -1,4 +0,4 @@ | ||
import { MediaQueryList, MediaQuery, MediaCondition } from "../shared.js"; | ||
import { MediaQueryList, MediaQuery, MediaCondition } from "../utils.js"; | ||
export declare const flattenMediaQueryList: (mediaQueryList: MediaQueryList) => MediaQueryList; | ||
export declare const flattenMediaQuery: (mediaQuery: MediaQuery) => MediaQuery; | ||
export declare const flattenMediaCondition: (mediaCondition: MediaCondition) => MediaCondition; |
@@ -5,25 +5,31 @@ export const flattenMediaQueryList = e => ({ | ||
}) | ||
export const flattenMediaQuery = e => { | ||
if (void 0 === e.mediaCondition) return e | ||
let i = flattenMediaCondition(e.mediaCondition) | ||
return ( | ||
void 0 === i.operator && | ||
1 === i.children.length && | ||
'children' in i.children[0] && | ||
(i = i.children[0]), | ||
{type: 'query', mediaPrefix: e.mediaPrefix, mediaType: e.mediaType, mediaCondition: i} | ||
) | ||
} | ||
export const flattenMediaQuery = e => | ||
e.mediaCondition | ||
? { | ||
type: 'query', | ||
prefix: e.prefix, | ||
mediaType: e.mediaType, | ||
mediaCondition: flattenMediaCondition(e.mediaCondition) | ||
} | ||
: e | ||
export const flattenMediaCondition = e => { | ||
const i = [] | ||
const o = [] | ||
for (const t of e.children) | ||
if ('condition' === t.type) { | ||
const o = flattenMediaCondition(t) | ||
void 0 === o.operator && 1 === o.children.length | ||
? i.push(o.children[0]) | ||
: o.operator !== e.operator || ('and' !== o.operator && 'or' !== o.operator) | ||
? i.push(o) | ||
: i.push(...o.children) | ||
} else i.push(t) | ||
return {type: 'condition', operator: e.operator, children: i} | ||
const i = flattenMediaCondition(t) | ||
void 0 === i.operator && 1 === i.children.length | ||
? o.push(i.children[0]) | ||
: i.operator !== e.operator || ('and' !== i.operator && 'or' !== i.operator) | ||
? o.push(i) | ||
: o.push(...i.children) | ||
} else o.push(t) | ||
if (1 === o.length) { | ||
const t = o[0] | ||
if ('condition' === t.type) { | ||
if (void 0 === e.operator) return t | ||
if ('not' === e.operator && 'not' === t.operator) | ||
return {type: 'condition', children: t.children} | ||
} | ||
} | ||
return {type: 'condition', operator: e.operator, children: o} | ||
} |
@@ -1,2 +0,2 @@ | ||
import { MediaQueryList, MediaQuery, MediaCondition, MediaFeature, MediaFeatureBoolean, MediaFeatureValue, MediaFeatureRange, ValidValueToken, ValidRangeToken, RatioToken, NumberToken, DimensionToken, IdentToken } from "../shared.js"; | ||
import { MediaQueryList, MediaQuery, MediaCondition, MediaFeature, MediaFeatureBoolean, MediaFeatureValue, MediaFeatureRange, ValidValueToken, ValidRangeToken, RatioToken, NumberToken, DimensionToken, IdentToken } from "../utils.js"; | ||
export declare const generateMediaQueryList: (mediaQueryList: MediaQueryList) => string; | ||
@@ -3,0 +3,0 @@ export declare const generateMediaQuery: (mediaQuery: MediaQuery) => string; |
export const generateMediaQueryList = e => e.mediaQueries.map(e => generateMediaQuery(e)).join(', ') | ||
export const generateMediaQuery = e => { | ||
var n | ||
let t = '' | ||
e.mediaPrefix && (t += e.mediaPrefix + ' ') | ||
e.prefix && (t += e.prefix + ' ') | ||
if ( | ||
((void 0 !== e.mediaPrefix || !e.mediaCondition || 'all' !== e.mediaType) && | ||
((t += e.mediaType), e.mediaCondition && (t += ' and')), | ||
((void 0 !== e.prefix || !e.mediaCondition || void 0 !== e.mediaType) && | ||
((t += null !== (n = e.mediaType) && void 0 !== n ? n : 'all'), | ||
e.mediaCondition && (t += ' and')), | ||
e.mediaCondition) | ||
) { | ||
'' !== t && (t += ' ') | ||
const n = generateMediaCondition(e.mediaCondition) | ||
void 0 === e.mediaCondition.operator || | ||
'and' === e.mediaCondition.operator || | ||
('not' === e.mediaCondition.operator && '' === t) | ||
? (t += n.slice(1, -1)) | ||
: (t += n) | ||
t += | ||
'or' !== e.mediaCondition.operator || !t | ||
? generateMediaCondition(e.mediaCondition).slice(1, -1) | ||
: generateMediaCondition(e.mediaCondition) | ||
} | ||
@@ -21,23 +21,22 @@ return t | ||
export const generateMediaCondition = e => { | ||
let t = '(' | ||
if (void 0 === e.operator || 'not' === e.operator) { | ||
'not' === e.operator && (t += 'not ') | ||
const n = e.children[0] | ||
t += 'feature' === n.type ? generateMediaFeature(n) : generateMediaCondition(n) | ||
let n = '(' | ||
if ('not' === e.operator) { | ||
const t = e.children[0] | ||
n += 'not ' + ('feature' === t.type ? generateMediaFeature(t) : generateMediaCondition(t)) | ||
} else | ||
for (const n of e.children) | ||
t.length > 1 && (t += ' ' + e.operator + ' '), | ||
(t += 'feature' === n.type ? generateMediaFeature(n) : generateMediaCondition(n)) | ||
return (t += ')'), t | ||
for (const t of e.children) | ||
n.length > 1 && (n += ' ' + e.operator + ' '), | ||
(n += 'feature' === t.type ? generateMediaFeature(t) : generateMediaCondition(t)) | ||
return (n += ')'), n | ||
} | ||
export const generateMediaFeature = e => { | ||
let t = '(' | ||
let n = '(' | ||
return ( | ||
'boolean' === e.context | ||
? (t += generateMediaFeatureBoolean(e)) | ||
? (n += generateMediaFeatureBoolean(e)) | ||
: 'value' === e.context | ||
? (t += generateMediaFeatureValue(e)) | ||
: (t += generateMediaFeatureRange(e)), | ||
(t += ')'), | ||
t | ||
? (n += generateMediaFeatureValue(e)) | ||
: (n += generateMediaFeatureRange(e)), | ||
(n += ')'), | ||
n | ||
) | ||
@@ -47,10 +46,10 @@ } | ||
export const generateMediaFeatureValue = e => | ||
(e.mediaPrefix ? `${e.mediaPrefix}-` : '') + e.feature + ': ' + generateValidValueToken(e.value) | ||
(e.prefix ? `${e.prefix}-` : '') + e.feature + ': ' + generateValidValueToken(e.value) | ||
export const generateMediaFeatureRange = e => { | ||
let t = '' | ||
let n = '' | ||
return ( | ||
e.range.leftOp && (t += `${generateValidRangeToken(e.range.leftToken)} ${e.range.leftOp} `), | ||
(t += e.feature), | ||
e.range.rightOp && (t += ` ${e.range.rightOp} ${generateValidRangeToken(e.range.rightToken)}`), | ||
t | ||
e.range.leftOp && (n += `${generateValidRangeToken(e.range.leftToken)} ${e.range.leftOp} `), | ||
(n += e.feature), | ||
e.range.rightOp && (n += ` ${e.range.rightOp} ${generateValidRangeToken(e.range.rightToken)}`), | ||
n | ||
) | ||
@@ -57,0 +56,0 @@ } |
/**! media-query-parser | Tom Golden <oss@tom.bio> (https://tom.bio) | @license MIT */ | ||
import { MediaQueryList, ParserError, MediaQuery, MediaCondition, MediaFeature, ValidValueToken } from "./shared.js"; | ||
import { MediaQueryList, ParserError, MediaQuery, MediaCondition, MediaFeature, ValidValueToken } from "./utils.js"; | ||
/** | ||
@@ -18,4 +18,4 @@ * creates an AST from a **media-query-list** string; parses comma-separated media queries correctly | ||
* // {type: "query", mediaType: "print"}, | ||
* // {type: "query", mediaPrefix: "not", mediaType: "all"}, | ||
* // {type: "query", mediaType: "all", mediaCondition: ...} | ||
* // {type: "query", prefix: "not"}, | ||
* // {type: "query", mediaCondition: ...} | ||
* // ], | ||
@@ -37,3 +37,2 @@ * // } | ||
* // }, | ||
* // mediaType: "all", | ||
* // } | ||
@@ -44,3 +43,3 @@ * ``` | ||
/** | ||
* creates an AST from a **media-condition** string - including parentheses | ||
* creates an AST from a **media-condition** string | ||
* | ||
@@ -84,3 +83,3 @@ * @example | ||
* // feature: "width", | ||
* // mediaPrefix: "min", | ||
* // prefix: "min", | ||
* // value: { type: "dimension", flag: "number", unit: "px", value: 768 }, | ||
@@ -97,11 +96,4 @@ * // } | ||
* ```ts | ||
* console.log(stringify(parseMediaFeature(`(min-width: 768px)`))); | ||
* // "(min-width: 768px)" | ||
* ``` | ||
* | ||
* @example | ||
* ```ts | ||
* console.log(stringify({ | ||
* type: "query", | ||
* mediaType: "all", | ||
* mediaCondition: { | ||
@@ -114,4 +106,14 @@ * type: "condition", | ||
* ``` | ||
* | ||
* note: stringifying a MediaCondition directly will always wrap the condition with parentheses. | ||
* sometimes they are redundant, but calling this with a MediaQuery will remove them for you. | ||
* e.g. `stringify({ type: 'query', mediaType: 'all', mediaCondition: <your condition> })` | ||
* | ||
* @example | ||
* ```ts | ||
* console.log(stringify(parseMediaFeature(`(min-width: 768px)`))); | ||
* // "(min-width: 768px)" | ||
* ``` | ||
*/ | ||
export declare const stringify: (node: MediaQueryList | MediaQuery | MediaCondition | MediaFeature | ValidValueToken) => string; | ||
export * from "./shared.js"; | ||
export * from "./utils.js"; |
/**! media-query-parser | Tom Golden <oss@tom.bio> (https://tom.bio) | @license MIT */ | ||
import { | ||
readMediaQueryList as r, | ||
readMediaQuery as e, | ||
readMediaCondition as t, | ||
readMediaQuery as t, | ||
readMediaCondition as e, | ||
readMediaFeature as o | ||
@@ -11,6 +11,6 @@ } from './ast/ast.js' | ||
flattenMediaQuery as n, | ||
flattenMediaCondition as a | ||
flattenMediaCondition as i | ||
} from './flatten/flatten.js' | ||
import { | ||
generateMediaQueryList as i, | ||
generateMediaQueryList as a, | ||
generateMediaQuery as u, | ||
@@ -21,27 +21,32 @@ generateMediaCondition as c, | ||
} from './generator/generator.js' | ||
import {lexer as m} from './lexer/lexer.js' | ||
import {isParserError as d} from './shared.js' | ||
export const parseMediaQueryList = e => { | ||
const t = m(e) | ||
return d(t) ? t : s(r(t)) | ||
import {deleteUndefinedValues as m, invertParserError as l} from './internals.js' | ||
import {lexer as x} from './lexer/lexer.js' | ||
import {isParserError as d} from './utils.js' | ||
export const parseMediaQueryList = t => { | ||
const e = x(t) | ||
return d(e) ? l(e) : m(s(r(e))) | ||
} | ||
export const parseMediaQuery = r => { | ||
const t = m(r) | ||
if (d(t)) return t | ||
const e = x(r) | ||
if (d(e)) return l(e) | ||
{ | ||
const r = e(t) | ||
return d(r) ? r : n(r) | ||
const r = t(e) | ||
return d(r) ? l(r) : m(n(r)) | ||
} | ||
} | ||
export const parseMediaCondition = r => { | ||
const e = m(r) | ||
if (d(e)) return e | ||
const t = x(r) | ||
if (d(t)) return l(t) | ||
{ | ||
const r = t(e, !0) | ||
return d(r) ? r : a(r) | ||
const r = e(t, !0) | ||
return d(r) ? l(r) : m(i(r)) | ||
} | ||
} | ||
export const parseMediaFeature = r => { | ||
const e = m(r) | ||
return d(e) ? e : o(e) | ||
const t = x(r) | ||
if (d(t)) return l(t) | ||
{ | ||
const r = o(t) | ||
return d(r) ? r : m(r) | ||
} | ||
} | ||
@@ -51,3 +56,3 @@ export const stringify = r => { | ||
case 'query-list': | ||
return i(r) | ||
return a(r) | ||
case 'query': | ||
@@ -63,2 +68,2 @@ return u(r) | ||
} | ||
export * from './shared.js' | ||
export * from './utils.js' |
@@ -1,2 +0,2 @@ | ||
import { ParserToken, ParserError } from "../shared.js"; | ||
import { ParserToken, ParserError } from "../utils.js"; | ||
export declare const lexer: (cssStr: string) => ParserToken[] | ParserError; |
@@ -1,2 +0,2 @@ | ||
import { CSSToken, ParserToken, ParserError } from "../shared.js"; | ||
import { CSSToken, ParserToken, ParserError } from "../utils.js"; | ||
export declare const convertToParserTokens: (cssTokens: CSSToken[]) => ParserToken[] | ParserError; |
@@ -1,2 +0,2 @@ | ||
import { CSSToken, ParserError } from "../shared.js"; | ||
import { CSSToken, ParserError } from "../utils.js"; | ||
export declare const codepointsToTokens: (codepoints: number[], index?: number) => CSSToken[] | ParserError; | ||
@@ -3,0 +3,0 @@ export declare const consumeString: (codepoints: number[], index: number) => [number, string] | null; |
@@ -7,49 +7,47 @@ const e = 10, | ||
r = 65, | ||
o = 90, | ||
l = 92, | ||
i = 95, | ||
a = 97, | ||
f = 122, | ||
c = 128 | ||
export const codepointsToTokens = (p, d = 0) => { | ||
const h = [] | ||
for (; d < p.length; d += 1) { | ||
const m = p.at(d), | ||
g = d | ||
if (47 === m && 42 === p.at(d + 1)) { | ||
d += 2 | ||
for (let e = p.at(d); void 0 !== e; e = p.at(++d)) | ||
if (42 === e && 47 === p.at(d + 1)) { | ||
d += 1 | ||
o = 92, | ||
l = 97, | ||
i = 122, | ||
a = 128 | ||
export const codepointsToTokens = (f, c = 0) => { | ||
const p = [] | ||
for (; c < f.length; c += 1) { | ||
const d = f.at(c), | ||
h = c | ||
if (47 === d && 42 === f.at(c + 1)) { | ||
c += 2 | ||
for (let e = f.at(c); void 0 !== e; e = f.at(++c)) | ||
if (42 === e && 47 === f.at(c + 1)) { | ||
c += 1 | ||
break | ||
} | ||
} else if (9 === m || m === t || m === e) { | ||
let n = p.at(++d) | ||
for (; 9 === n || n === t || n === e; ) n = p.at(++d) | ||
d -= 1 | ||
const s = h.at(-1) | ||
} else if (9 === d || d === t || d === e) { | ||
let n = f.at(++c) | ||
for (; 9 === n || n === t || n === e; ) n = f.at(++c) | ||
c -= 1 | ||
const s = p.at(-1) | ||
'whitespace' === (null == s ? void 0 : s.type) | ||
? (h.pop(), h.push({type: 'whitespace', start: s.start, end: d})) | ||
: h.push({type: 'whitespace', start: g, end: d}) | ||
} else if (34 === m) { | ||
const e = consumeString(p, d) | ||
if (null === e) return {errid: 'INVALID_STRING', start: d, end: d} | ||
? (p.pop(), p.push({type: 'whitespace', start: s.start, end: c})) | ||
: p.push({type: 'whitespace', start: h, end: c}) | ||
} else if (34 === d) { | ||
const e = consumeString(f, c) | ||
if (null === e) return {errid: 'INVALID_STRING', start: c, end: c} | ||
const [t, n] = e | ||
;(d = t), h.push({type: 'string', value: n, start: g, end: d}) | ||
} else if (35 === m) { | ||
if (d + 1 < p.length) { | ||
const t = p.at(d + 1) | ||
;(c = t), p.push({type: 'string', value: n, start: h, end: c}) | ||
} else if (35 === d) { | ||
if (c + 1 < f.length) { | ||
const t = f.at(c + 1) | ||
if ( | ||
t === i || | ||
(t >= r && t <= o) || | ||
(t >= a && t <= f) || | ||
t >= c || | ||
95 === t || | ||
(t >= r && t <= 90) || | ||
(t >= l && t <= i) || | ||
t >= a || | ||
(t >= s && t <= u) || | ||
(t === l && d + 2 < p.length && p.at(d + 2) !== e) | ||
(t === o && c + 2 < f.length && f.at(c + 2) !== e) | ||
) { | ||
const e = wouldStartIdentifier(p, d + 1) ? 'id' : 'unrestricted', | ||
t = consumeIdentUnsafe(p, d + 1) | ||
const e = wouldStartIdentifier(f, c + 1) ? 'id' : 'unrestricted', | ||
t = consumeIdentUnsafe(f, c + 1) | ||
if (null !== t) { | ||
const [n, s] = t | ||
;(d = n), h.push({type: 'hash', value: s.toLowerCase(), flag: e, start: g, end: d}) | ||
;(c = n), p.push({type: 'hash', value: s.toLowerCase(), flag: e, start: h, end: c}) | ||
continue | ||
@@ -59,18 +57,18 @@ } | ||
} | ||
h.push({type: 'delim', value: m, start: g, end: d}) | ||
} else if (39 === m) { | ||
const e = consumeString(p, d) | ||
if (null === e) return {errid: 'INVALID_STRING', start: d, end: d} | ||
p.push({type: 'delim', value: d, start: h, end: c}) | ||
} else if (39 === d) { | ||
const e = consumeString(f, c) | ||
if (null === e) return {errid: 'INVALID_STRING', start: c, end: c} | ||
const [t, n] = e | ||
;(d = t), h.push({type: 'string', value: n, start: g, end: d}) | ||
} else if (40 === m) h.push({type: '(', start: g, end: d}) | ||
else if (41 === m) h.push({type: ')', start: g, end: d}) | ||
else if (43 === m) { | ||
const e = consumeNumeric(p, d) | ||
if (null === e) h.push({type: 'delim', value: m, start: g, end: d}) | ||
;(c = t), p.push({type: 'string', value: n, start: h, end: c}) | ||
} else if (40 === d) p.push({type: '(', start: h, end: c}) | ||
else if (41 === d) p.push({type: ')', start: h, end: c}) | ||
else if (43 === d) { | ||
const e = consumeNumeric(f, c) | ||
if (null === e) p.push({type: 'delim', value: d, start: h, end: c}) | ||
else { | ||
const [t, n] = e | ||
;(d = t), | ||
;(c = t), | ||
'dimension' === n[0] | ||
? h.push({ | ||
? p.push({ | ||
type: 'dimension', | ||
@@ -80,17 +78,17 @@ value: n[1], | ||
flag: 'number', | ||
start: g, | ||
end: d | ||
start: h, | ||
end: c | ||
}) | ||
: 'number' === n[0] | ||
? h.push({type: n[0], value: n[1], flag: n[2], start: g, end: d}) | ||
: h.push({type: n[0], value: n[1], flag: 'number', start: g, end: d}) | ||
? p.push({type: n[0], value: n[1], flag: n[2], start: h, end: c}) | ||
: p.push({type: n[0], value: n[1], flag: 'number', start: h, end: c}) | ||
} | ||
} else if (44 === m) h.push({type: 'comma', start: g, end: d}) | ||
else if (m === n) { | ||
const e = consumeNumeric(p, d) | ||
} else if (44 === d) p.push({type: 'comma', start: h, end: c}) | ||
else if (d === n) { | ||
const e = consumeNumeric(f, c) | ||
if (null !== e) { | ||
const [t, n] = e | ||
;(d = t), | ||
;(c = t), | ||
'dimension' === n[0] | ||
? h.push({ | ||
? p.push({ | ||
type: 'dimension', | ||
@@ -100,32 +98,32 @@ value: n[1], | ||
flag: 'number', | ||
start: g, | ||
end: d | ||
start: h, | ||
end: c | ||
}) | ||
: 'number' === n[0] | ||
? h.push({type: n[0], value: n[1], flag: n[2], start: g, end: d}) | ||
: h.push({type: n[0], value: n[1], flag: 'number', start: g, end: d}) | ||
? p.push({type: n[0], value: n[1], flag: n[2], start: h, end: c}) | ||
: p.push({type: n[0], value: n[1], flag: 'number', start: h, end: c}) | ||
continue | ||
} | ||
if (d + 2 < p.length) { | ||
const e = p.at(d + 1), | ||
t = p.at(d + 2) | ||
if (c + 2 < f.length) { | ||
const e = f.at(c + 1), | ||
t = f.at(c + 2) | ||
if (e === n && 62 === t) { | ||
;(d += 2), h.push({type: 'CDC', start: g, end: d}) | ||
;(c += 2), p.push({type: 'CDC', start: h, end: c}) | ||
continue | ||
} | ||
} | ||
const t = consumeIdentLike(p, d) | ||
const t = consumeIdentLike(f, c) | ||
if (null !== t) { | ||
const [e, n, s] = t | ||
;(d = e), h.push({type: s, value: n, start: g, end: d}) | ||
;(c = e), p.push({type: s, value: n, start: h, end: c}) | ||
continue | ||
} | ||
h.push({type: 'delim', value: m, start: g, end: d}) | ||
} else if (46 === m) { | ||
const e = consumeNumeric(p, d) | ||
p.push({type: 'delim', value: d, start: h, end: c}) | ||
} else if (46 === d) { | ||
const e = consumeNumeric(f, c) | ||
if (null !== e) { | ||
const [t, n] = e | ||
;(d = t), | ||
;(c = t), | ||
'dimension' === n[0] | ||
? h.push({ | ||
? p.push({ | ||
type: 'dimension', | ||
@@ -135,42 +133,42 @@ value: n[1], | ||
flag: 'number', | ||
start: g, | ||
end: d | ||
start: h, | ||
end: c | ||
}) | ||
: 'number' === n[0] | ||
? h.push({type: n[0], value: n[1], flag: n[2], start: g, end: d}) | ||
: h.push({type: n[0], value: n[1], flag: 'number', start: g, end: d}) | ||
? p.push({type: n[0], value: n[1], flag: n[2], start: h, end: c}) | ||
: p.push({type: n[0], value: n[1], flag: 'number', start: h, end: c}) | ||
continue | ||
} | ||
h.push({type: 'delim', value: m, start: g, end: d}) | ||
} else if (58 === m) h.push({type: 'colon', start: g, end: d}) | ||
else if (59 === m) h.push({type: 'semicolon', start: g, end: d}) | ||
else if (60 === m) { | ||
if (d + 3 < p.length) { | ||
const e = p.at(d + 1), | ||
t = p.at(d + 2), | ||
s = p.at(d + 3) | ||
p.push({type: 'delim', value: d, start: h, end: c}) | ||
} else if (58 === d) p.push({type: 'colon', start: h, end: c}) | ||
else if (59 === d) p.push({type: 'semicolon', start: h, end: c}) | ||
else if (60 === d) { | ||
if (c + 3 < f.length) { | ||
const e = f.at(c + 1), | ||
t = f.at(c + 2), | ||
s = f.at(c + 3) | ||
if (33 === e && t === n && s === n) { | ||
;(d += 3), h.push({type: 'CDO', start: g, end: d}) | ||
;(c += 3), p.push({type: 'CDO', start: h, end: c}) | ||
continue | ||
} | ||
} | ||
h.push({type: 'delim', value: m, start: g, end: d}) | ||
} else if (64 === m) { | ||
const e = consumeIdent(p, d + 1) | ||
p.push({type: 'delim', value: d, start: h, end: c}) | ||
} else if (64 === d) { | ||
const e = consumeIdent(f, c + 1) | ||
if (null !== e) { | ||
const [t, n] = e | ||
;(d = t), h.push({type: 'at-keyword', value: n.toLowerCase(), start: g, end: d}) | ||
;(c = t), p.push({type: 'at-keyword', value: n.toLowerCase(), start: h, end: c}) | ||
continue | ||
} | ||
h.push({type: 'delim', value: m, start: g, end: d}) | ||
} else if (91 === m) h.push({type: '[', start: g, end: d}) | ||
else if (93 === m) h.push({type: ']', start: g, end: d}) | ||
else if (123 === m) h.push({type: '{', start: g, end: d}) | ||
else if (125 === m) h.push({type: '}', start: g, end: d}) | ||
else if (m >= s && m <= u) { | ||
const e = consumeNumeric(p, d), | ||
p.push({type: 'delim', value: d, start: h, end: c}) | ||
} else if (91 === d) p.push({type: '[', start: h, end: c}) | ||
else if (93 === d) p.push({type: ']', start: h, end: c}) | ||
else if (123 === d) p.push({type: '{', start: h, end: c}) | ||
else if (125 === d) p.push({type: '}', start: h, end: c}) | ||
else if (d >= s && d <= u) { | ||
const e = consumeNumeric(f, c), | ||
[t, n] = e | ||
;(d = t), | ||
;(c = t), | ||
'dimension' === n[0] | ||
? h.push({ | ||
? p.push({ | ||
type: 'dimension', | ||
@@ -180,21 +178,18 @@ value: n[1], | ||
flag: 'number', | ||
start: g, | ||
end: d | ||
start: h, | ||
end: c | ||
}) | ||
: 'number' === n[0] | ||
? h.push({type: n[0], value: n[1], flag: n[2], start: g, end: d}) | ||
: h.push({type: n[0], value: n[1], flag: 'number', start: g, end: d}) | ||
} else if (m === i || (m >= r && m <= o) || (m >= a && m <= f) || m >= c || m === l) { | ||
const t = p.at(d + 1) | ||
if (m !== l || (void 0 !== t && t !== e)) { | ||
const e = consumeIdentLike(p, d) | ||
if (null === e) h.push({type: 'delim', value: m, start: g, end: d}) | ||
else { | ||
const [t, n, s] = e | ||
;(d = t), h.push({type: s, value: n, start: g, end: d}) | ||
} | ||
} else h.push({type: 'delim', value: m, start: g, end: d}) | ||
} else h.push({type: 'delim', value: m, start: g, end: d}) | ||
? p.push({type: n[0], value: n[1], flag: n[2], start: h, end: c}) | ||
: p.push({type: n[0], value: n[1], flag: 'number', start: h, end: c}) | ||
} else if (95 === d || (d >= r && d <= 90) || (d >= l && d <= i) || d >= a || d === o) { | ||
const e = consumeIdentLike(f, c) | ||
if (null === e) p.push({type: 'delim', value: d, start: h, end: c}) | ||
else { | ||
const [t, n, s] = e | ||
;(c = t), p.push({type: s, value: n, start: h, end: c}) | ||
} | ||
} else p.push({type: 'delim', value: d, start: h, end: c}) | ||
} | ||
return h.push({type: 'EOF', start: d, end: d}), h | ||
return p.push({type: 'EOF', start: c, end: c}), p | ||
} | ||
@@ -208,3 +203,3 @@ export const consumeString = (t, n) => { | ||
if (n === s) return [r, String.fromCodePoint(...u)] | ||
if (n === l) { | ||
if (n === o) { | ||
const e = consumeEscape(t, r) | ||
@@ -227,4 +222,4 @@ if (null === e) return null | ||
if (void 0 === u) return !1 | ||
if (u === n || u === i || (u >= r && u <= o) || (u >= a && u <= f) || u >= c) return !0 | ||
if (u === l) { | ||
if (u === n || 95 === u || (u >= r && u <= 90) || (u >= l && u <= i) || u >= a) return !0 | ||
if (u === o) { | ||
if (t.length <= s + 2) return !1 | ||
@@ -235,4 +230,4 @@ return t.at(s + 2) !== e | ||
} | ||
if (u === i || (u >= r && u <= o) || (u >= a && u <= f) || u >= c) return !0 | ||
if (u === l) { | ||
if (95 === u || (u >= r && u <= 90) || (u >= l && u <= i) || u >= a) return !0 | ||
if (u === o) { | ||
if (t.length <= s + 1) return !1 | ||
@@ -243,15 +238,15 @@ return t.at(s + 1) !== e | ||
} | ||
export const consumeEscape = (n, o) => { | ||
if (n.length <= o + 1) return null | ||
if (n.at(o) !== l) return null | ||
const i = n.at(o + 1) | ||
if (i === e) return null | ||
if ((i >= s && i <= u) || (i >= r && i <= 70) || (i >= a && i <= 102)) { | ||
const l = [i], | ||
f = Math.min(o + 7, n.length) | ||
let c = o + 2 | ||
export const consumeEscape = (n, i) => { | ||
if (n.length <= i + 1) return null | ||
if (n.at(i) !== o) return null | ||
const a = n.at(i + 1) | ||
if (a === e) return null | ||
if ((a >= s && a <= u) || (a >= r && a <= 70) || (a >= l && a <= 102)) { | ||
const o = [a], | ||
f = Math.min(i + 7, n.length) | ||
let c = i + 2 | ||
for (; c < f; c += 1) { | ||
const e = n.at(c) | ||
if (!((e >= s && e <= u) || (e >= r && e <= 70) || (e >= a && e <= 102))) break | ||
l.push(e) | ||
if (!((e >= s && e <= u) || (e >= r && e <= 70) || (e >= l && e <= 102))) break | ||
o.push(e) | ||
} | ||
@@ -262,5 +257,5 @@ if (c < n.length) { | ||
} | ||
return [c - 1, Number.parseInt(String.fromCodePoint(...l), 16)] | ||
return [c - 1, Number.parseInt(String.fromCodePoint(...o), 16)] | ||
} | ||
return [o + 1, i] | ||
return [i + 1, a] | ||
} | ||
@@ -327,12 +322,12 @@ export const consumeNumeric = (e, t) => { | ||
if (e.length <= t) return null | ||
const l = [] | ||
for (let p = e.at(t); t < e.length; p = e.at(++t)) { | ||
const o = [] | ||
for (let f = e.at(t); t < e.length; f = e.at(++t)) { | ||
if ( | ||
!( | ||
p === n || | ||
p === i || | ||
(p >= r && p <= o) || | ||
(p >= a && p <= f) || | ||
p >= c || | ||
(p >= s && p <= u) | ||
f === n || | ||
95 === f || | ||
(f >= r && f <= 90) || | ||
(f >= l && f <= i) || | ||
f >= a || | ||
(f >= s && f <= u) | ||
) | ||
@@ -344,3 +339,3 @@ ) { | ||
const [e, s] = n | ||
l.push(s), (t = e) | ||
o.push(s), (t = e) | ||
continue | ||
@@ -351,34 +346,7 @@ } | ||
} | ||
l.push(p) | ||
o.push(f) | ||
} | ||
return 0 === t ? null : [t - 1, String.fromCodePoint(...l)] | ||
return 0 === t ? null : [t - 1, String.fromCodePoint(...o)] | ||
} | ||
export const consumeIdent = (e, t) => { | ||
if (e.length <= t || !wouldStartIdentifier(e, t)) return null | ||
const l = [] | ||
for (let p = e.at(t); t < e.length; p = e.at(++t)) { | ||
if ( | ||
!( | ||
p === n || | ||
p === i || | ||
(p >= r && p <= o) || | ||
(p >= a && p <= f) || | ||
p >= c || | ||
(p >= s && p <= u) | ||
) | ||
) { | ||
{ | ||
const n = consumeEscape(e, t) | ||
if (null !== n) { | ||
const [e, s] = n | ||
l.push(s), (t = e) | ||
continue | ||
} | ||
} | ||
break | ||
} | ||
l.push(p) | ||
} | ||
return [t - 1, String.fromCodePoint(...l)] | ||
} | ||
export const consumeIdent = (e, t) => (wouldStartIdentifier(e, t) ? consumeIdentUnsafe(e, t) : null) | ||
export const consumeUrl = (n, s) => { | ||
@@ -388,14 +356,14 @@ let u = n.at(s) | ||
const r = [] | ||
let o = !1 | ||
let l = !1 | ||
for (; s < n.length; ) { | ||
if (41 === u) return [s, String.fromCodePoint(...r)] | ||
if (34 === u || 39 === u || 40 === u) return null | ||
if (9 === u || u === t || u === e) !o && r.length > 0 && (o = !0) | ||
else if (u === l) { | ||
if (9 === u || u === t || u === e) !l && r.length > 0 && (l = !0) | ||
else if (u === o) { | ||
const e = consumeEscape(n, s) | ||
if (null === e || o) return null | ||
if (null === e || l) return null | ||
const [t, u] = e | ||
r.push(u), (s = t) | ||
} else { | ||
if (o) return null | ||
if (l) return null | ||
r.push(u) | ||
@@ -402,0 +370,0 @@ } |
{ | ||
"name": "media-query-parser", | ||
"description": "Parse CSS media queries (spec-compliant)", | ||
"version": "3.0.0-beta.0", | ||
"version": "3.0.0-beta.1", | ||
"license": "MIT", | ||
@@ -82,2 +82,8 @@ "keywords": [ | ||
"clearMocks": true, | ||
"collectCoverageFrom": [ | ||
"lib/**/*.ts", | ||
"!**/test-helpers.ts", | ||
"!**/node_modules/**", | ||
"!**/vendor/**" | ||
], | ||
"coverageReporters": [ | ||
@@ -84,0 +90,0 @@ "json-summary", |
@@ -19,3 +19,3 @@ # `media-query-parser` | ||
- **Zero-dependencies** | ||
- **Well tested** | ||
- **Well tested** - every single line | ||
- **TypeScript friendly** | ||
@@ -27,6 +27,36 @@ | ||
**_[You can try it out!](https://tbjgolden.github.io/media-query-parser/)_** | ||
![banner](banner.svg) | ||
## Why? | ||
Other CSS parsers (e.g. css-tree and postcss) do not support all media query syntax out of the box. | ||
Further, the only other media query parser that I'm aware of is `postcss-media-query-parser` - which | ||
is specific to postcss and doesn't parse newer syntax like range expressions (i.e. | ||
`(width >= 768px)`). | ||
This package is a spec-compliant media query parser that can be used in Node/Deno/etc, or on the | ||
client that precisely matches the spec right down to the quirks. | ||
These are valid media queries that this library supports: | ||
```css | ||
@media (768px <= width < 1200px); | ||
@media only print and (color); | ||
@media not (not (not (((hover) or ((not (color))))))); | ||
@media (🐈: 😸 /* if cat happy */) { | ||
/* this query has valid syntax, but is clearly not a real feature. | ||
(see `media-query-fns` for feature checking) */ | ||
} | ||
``` | ||
These are invalid media queries that this library will detect: | ||
```css | ||
@media (color) or (hover); /* or cannot be at top level */ | ||
@media (min-width: calc(50vw + 10px)); /* functions aren't valid values */ | ||
@media not((color)); /* operators need whitespace */ | ||
@media (768px < = width < 1200px); /* cannot have a space between `<` and `=` */ | ||
``` | ||
## Install | ||
@@ -40,2 +70,4 @@ | ||
> The shape of Errors are | ||
## Usage | ||
@@ -48,3 +80,3 @@ | ||
const mediaQuery = parseMediaQuery("screen and (width <= 768px)"); | ||
const mediaQuery = parseMediaQuery("screen and (min-width: 768px)"); | ||
if (!isParserError(mediaQuery)) { | ||
@@ -57,23 +89,15 @@ console.log(mediaQuery); | ||
// type: "condition", | ||
// children: [ | ||
// { | ||
// type: "feature", | ||
// feature: "width", | ||
// context: "range", | ||
// range: { | ||
// featureName: "width", | ||
// rightOp: "<=", | ||
// rightToken: { | ||
// type: "dimension", | ||
// value: 768, | ||
// unit: "px", | ||
// flag: "number" | ||
// }, | ||
// }, | ||
// children: [{ | ||
// type: "feature", | ||
// context: "value", | ||
// prefix: "min", | ||
// feature: "width", | ||
// value: { | ||
// type: "dimension", value: 768, unit: "px", flag: "number" | ||
// }, | ||
// ], | ||
// }], | ||
// }, | ||
// } | ||
console.log(stringify(mediaQuery.mediaCondition.children[0])); | ||
// "(width <= 768px)" | ||
// "(min-width: 768px)" | ||
} | ||
@@ -84,17 +108,4 @@ ``` | ||
## Considerations & Caveats | ||
### [**Full Docs**](https://tbjgolden.github.io/media-query-parser/) | ||
This library **does**: | ||
- follow the spec's CSS syntax / media query parsing rules | ||
- remove extra layers from unnecessary parentheses `(((((max-width: 768px)))))` | ||
- handle unusual whitespace anywhere that the spec allows it | ||
This library **will not**: | ||
- sanity check the actual media features or their types beyond the parser rules; so | ||
`(max-power: infinite)` is as valid as `(min-width: 768px)` | ||
- support `calc()` or `var()` - functions are disallowed by the spec, even though some browsers seem | ||
to support them. If/when the spec allows them they'll be added in a new major version | ||
## Contributing | ||
@@ -101,0 +112,0 @@ |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
54085
25
1450
120
0