Skip to content

Commit 4744eac

Browse files
committed
Split sort logic from configuration loading process
1 parent ed56f3a commit 4744eac

File tree

3 files changed

+276
-250
lines changed

3 files changed

+276
-250
lines changed

lib/create-sort.js

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
// ----------------------------------------
2+
// Private
3+
// ----------------------------------------
4+
5+
const minMaxWidth = /(!?\(\s*min(-device-)?-width)(.|\n)+\(\s*max(-device)?-width/i;
6+
const minWidth = /\(\s*min(-device)?-width/i;
7+
const maxMinWidth = /(!?\(\s*max(-device)?-width)(.|\n)+\(\s*min(-device)?-width/i;
8+
const maxWidth = /\(\s*max(-device)?-width/i;
9+
10+
const isMinWidth = _testQuery(minMaxWidth, maxMinWidth, minWidth);
11+
const isMaxWidth = _testQuery(maxMinWidth, minMaxWidth, maxWidth);
12+
13+
const minMaxHeight = /(!?\(\s*min(-device)?-height)(.|\n)+\(\s*max(-device)?-height/i;
14+
const minHeight = /\(\s*min(-device)?-height/i;
15+
const maxMinHeight = /(!?\(\s*max(-device)?-height)(.|\n)+\(\s*min(-device)?-height/i;
16+
const maxHeight = /\(\s*max(-device)?-height/i;
17+
18+
const isMinHeight = _testQuery(minMaxHeight, maxMinHeight, minHeight);
19+
const isMaxHeight = _testQuery(maxMinHeight, minMaxHeight, maxHeight);
20+
21+
const isPrint = /print/i;
22+
const isPrintOnly = /^print$/i;
23+
24+
const maxValue = Number.MAX_VALUE;
25+
26+
/**
27+
* Obtain the length of the media request in pixels.
28+
* Copy from original source `function inspectLength (length)`
29+
* {@link https://github.com/hail2u/node-css-mqpacker/blob/master/index.js#L58}
30+
* @private
31+
* @param {string} length
32+
* @return {number}
33+
*/
34+
function _getQueryLength(length) {
35+
length = /(-?\d*\.?\d+)(ch|em|ex|px|rem)/.exec(length);
36+
37+
if (length === null) {
38+
return maxValue;
39+
}
40+
41+
let number = length[1];
42+
const unit = length[2];
43+
44+
switch (unit) {
45+
case 'ch':
46+
number = parseFloat(number) * 8.8984375;
47+
break;
48+
49+
case 'em':
50+
case 'rem':
51+
number = parseFloat(number) * 16;
52+
break;
53+
54+
case 'ex':
55+
number = parseFloat(number) * 8.296875;
56+
break;
57+
58+
case 'px':
59+
number = parseFloat(number);
60+
break;
61+
}
62+
63+
return +number;
64+
}
65+
66+
/**
67+
* Wrapper for creating test functions
68+
* @private
69+
* @param {RegExp} doubleTestTrue
70+
* @param {RegExp} doubleTestFalse
71+
* @param {RegExp} singleTest
72+
* @return {Function}
73+
*/
74+
function _testQuery(doubleTestTrue, doubleTestFalse, singleTest) {
75+
/**
76+
* @param {string} query
77+
* @return {boolean}
78+
*/
79+
return function (query) {
80+
if (doubleTestTrue.test(query)) {
81+
return true;
82+
} else if (doubleTestFalse.test(query)) {
83+
return false;
84+
}
85+
return singleTest.test(query);
86+
};
87+
}
88+
89+
/**
90+
* @private
91+
* @param {string} a
92+
* @param {string} b
93+
* @return {number|null}
94+
*/
95+
function _testIsPrint(a, b) {
96+
const isPrintA = isPrint.test(a);
97+
const isPrintOnlyA = isPrintOnly.test(a);
98+
99+
const isPrintB = isPrint.test(b);
100+
const isPrintOnlyB = isPrintOnly.test(b);
101+
102+
if (isPrintA && isPrintB) {
103+
if (!isPrintOnlyA && isPrintOnlyB) {
104+
return 1;
105+
}
106+
if (isPrintOnlyA && !isPrintOnlyB) {
107+
return -1;
108+
}
109+
return a.localeCompare(b);
110+
}
111+
if (isPrintA) {
112+
return 1;
113+
}
114+
if (isPrintB) {
115+
return -1;
116+
}
117+
118+
return null;
119+
}
120+
121+
// ----------------------------------------
122+
// Public
123+
// ----------------------------------------
124+
125+
/**
126+
* @param {Object} [configuration]
127+
* @param {boolean} [configuration.unitlessMqAlwaysFirst]
128+
* @returns {(function(string, string): number)|*}
129+
*/
130+
module.exports = function createSort(configuration) {
131+
const config = configuration || {};
132+
133+
// eslint-disable-next-line no-unused-vars
134+
const UNITLESS_MQ_ALWAYS_FIRST = config.unitlessMqAlwaysFirst;
135+
136+
/**
137+
* Sorting an array with media queries
138+
* according to the mobile-first methodology.
139+
* @param {string} a
140+
* @param {string} b
141+
* @return {number} 1 / 0 / -1
142+
*/
143+
function sortCSSmq(a, b) {
144+
const testIsPrint = _testIsPrint(a, b);
145+
if (testIsPrint !== null) {
146+
return testIsPrint;
147+
}
148+
149+
const minA = isMinWidth(a) || isMinHeight(a);
150+
const maxA = isMaxWidth(a) || isMaxHeight(a);
151+
152+
const minB = isMinWidth(b) || isMinHeight(b);
153+
const maxB = isMaxWidth(b) || isMaxHeight(b);
154+
155+
if (minA && maxB) {
156+
return -1;
157+
}
158+
if (maxA && minB) {
159+
return 1;
160+
}
161+
162+
const lengthA = _getQueryLength(a);
163+
const lengthB = _getQueryLength(b);
164+
165+
if (lengthA === maxValue && lengthB === maxValue) {
166+
return a.localeCompare(b);
167+
} else if (lengthA === maxValue) {
168+
return 1;
169+
} else if (lengthB === maxValue) {
170+
return -1;
171+
}
172+
173+
if (lengthA > lengthB) {
174+
if (maxA) {
175+
return -1;
176+
}
177+
return 1;
178+
}
179+
180+
if (lengthA < lengthB) {
181+
if (maxA) {
182+
return 1;
183+
}
184+
return -1;
185+
}
186+
187+
return a.localeCompare(b);
188+
}
189+
190+
/**
191+
* Sorting an array with media queries
192+
* according to the desktop-first methodology.
193+
* @param {string} a
194+
* @param {string} b
195+
* @return {number} 1 / 0 / -1
196+
*/
197+
sortCSSmq.desktopFirst = function (a, b) {
198+
const testIsPrint = _testIsPrint(a, b);
199+
if (testIsPrint !== null) {
200+
return testIsPrint;
201+
}
202+
203+
const minA = isMinWidth(a) || isMinHeight(a);
204+
const maxA = isMaxWidth(a) || isMaxHeight(a);
205+
206+
const minB = isMinWidth(b) || isMinHeight(b);
207+
const maxB = isMaxWidth(b) || isMaxHeight(b);
208+
209+
if (minA && maxB) {
210+
return 1;
211+
}
212+
if (maxA && minB) {
213+
return -1;
214+
}
215+
216+
const lengthA = _getQueryLength(a);
217+
const lengthB = _getQueryLength(b);
218+
219+
if (lengthA === maxValue && lengthB === maxValue) {
220+
return a.localeCompare(b);
221+
} else if (lengthA === maxValue) {
222+
return 1;
223+
} else if (lengthB === maxValue) {
224+
return -1;
225+
}
226+
227+
if (lengthA > lengthB) {
228+
if (maxA) {
229+
return -1;
230+
}
231+
return 1;
232+
}
233+
234+
if (lengthA < lengthB) {
235+
if (maxA) {
236+
return 1;
237+
}
238+
return -1;
239+
}
240+
241+
return -a.localeCompare(b);
242+
};
243+
244+
return sortCSSmq;
245+
};

0 commit comments

Comments
 (0)