UNPKG

4.59 kBJavaScriptView Raw
1"use strict";
2
3var _cssTree = _interopRequireDefault(require("css-tree"));
4
5var _cssMediaquery = _interopRequireDefault(require("css-mediaquery"));
6
7var _debug = _interopRequireDefault(require("debug"));
8
9function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
11const debuglog = (0, _debug.default)('penthouse:preformatting:nonMatchingMediaQueryRemover'); // only filters out:
12// - @print
13// - min-width > width OR min-height > height
14// (the latter only if !keepLargerMediaQueries -- which is the default)
15// - min-width > width AND max-width > width
16
17function _isMatchingMediaQuery(mediaQuery, matchConfig) {
18 // TODO: use the media query parsing from css-tree instead
19 let mediaAST;
20
21 try {
22 mediaAST = _cssMediaquery.default.parse(mediaQuery);
23 } catch (e) {
24 // cant parse, most likely browser cant either
25 return false;
26 }
27
28 var keep = mediaAST.some(function (mq) {
29 // not sure why css-mediaquery library sometimes flags the inverse as type,
30 // rather than the inverse field, but for our purposes we want to treat
31 // them the same.
32 const isInverse = mq.inverse || mq.type === 'not'; // f.e. @media all {}
33 // go for false positives over false negatives,
34 // i.e. accept @media randomThing {}
35
36 if (mq.expressions.length === 0) {
37 // the checks below are only valid if the media query has no other properties other than the media type
38 if (!isInverse && mq.type === 'print' || isInverse && mq.type === 'screen') {
39 return false;
40 }
41
42 return true;
43 }
44 /*
45 costructing the test to match against the mediaquery
46 if the mediaquery (mq) has "AND" conditions, mq.expressions is an array of feature objects { modifier, feature, value }
47 mq.expressions.length > 1
48 if the mediaquery (mq) has "OR" conditions, the mediaquery is split in _n_ mq objects,
49 each having an expressions array of 1 feature objects { modifier, feature, value }
50 */
51
52
53 return mq.expressions.some(function ({
54 modifier,
55 feature,
56 value
57 }) {
58 if (modifier === 'min') {
59 const constructedQuery = `(min-${feature}: ${value})`; // css-mediaquery does not match inversed queries correctly, hence the if..else below
60
61 if (!isInverse) {
62 return _cssMediaquery.default.match(constructedQuery, matchConfig);
63 } else {
64 return !_cssMediaquery.default.match(constructedQuery, matchConfig);
65 }
66 } else {
67 if (mq.expressions.length > 1) {
68 const constructedQuery = mq.expressions.map(({
69 modifier,
70 feature,
71 value
72 }) => `(${modifier}-${feature}: ${value})`).join(' and '); // css-mediaquery does not match inversed queries correctly, hence the if..else below
73
74 if (!isInverse) {
75 return _cssMediaquery.default.match(constructedQuery, matchConfig);
76 } else {
77 return !_cssMediaquery.default.match(constructedQuery, matchConfig);
78 }
79 } else {
80 return true;
81 }
82 }
83 });
84 });
85 return keep;
86}
87
88function nonMatchingMediaQueryRemover(ast, width, height, keepLargerMediaQueries = false) {
89 debuglog('BEFORE');
90 const matchConfig = {
91 type: 'screen',
92 width: width + 'px',
93 height: height + 'px'
94 };
95 const matchLargerMQConfig = {
96 type: 'screen',
97 width: '99999px',
98 height: '99999px'
99 };
100 debuglog('matchConfig: ' + JSON.stringify(matchConfig, null, 2) + '\n' + 'keepLargerMediaQueries: ' + keepLargerMediaQueries);
101
102 _cssTree.default.walk(ast, {
103 visit: 'Atrule',
104 enter: (atrule, item, list) => {
105 // ignore (keep) all non media query rules
106 if (_cssTree.default.keyword(atrule.name).name !== 'media') {
107 return;
108 } // this can happen - why? (atrule.prelude === null)
109 // and should we remove this rule here, or keep it?
110
111
112 if (!atrule.prelude) {
113 return;
114 }
115
116 const mediaQuery = _cssTree.default.generate(atrule.prelude); // ismatching true when mq must be kept
117 // if keep larger mq, keep if matching OR matching matchKeepLargeConfig
118
119
120 const isMatching = keepLargerMediaQueries ? _isMatchingMediaQuery(mediaQuery, matchConfig) || _isMatchingMediaQuery(mediaQuery, matchLargerMQConfig) : _isMatchingMediaQuery(mediaQuery, matchConfig);
121
122 if (!isMatching) {
123 debuglog('DROP: ' + `(${mediaQuery}), `);
124 list.remove(item);
125 } else {
126 debuglog('KEEP: ' + `(${mediaQuery}), `);
127 }
128 }
129 });
130
131 return ast;
132}
133
134module.exports = nonMatchingMediaQueryRemover;
\No newline at end of file