Files
documentation/node_modules/sort-css-media-queries/lib/create-sort.js
2024-03-22 03:47:51 +05:30

266 lines
5.8 KiB
JavaScript

// ----------------------------------------
// Private
// ----------------------------------------
const minMaxWidth = /(!?\(\s*min(-device-)?-width)(.|\n)+\(\s*max(-device)?-width/i;
const minWidth = /\(\s*min(-device)?-width/i;
const maxMinWidth = /(!?\(\s*max(-device)?-width)(.|\n)+\(\s*min(-device)?-width/i;
const maxWidth = /\(\s*max(-device)?-width/i;
const isMinWidth = _testQuery(minMaxWidth, maxMinWidth, minWidth);
const isMaxWidth = _testQuery(maxMinWidth, minMaxWidth, maxWidth);
const minMaxHeight = /(!?\(\s*min(-device)?-height)(.|\n)+\(\s*max(-device)?-height/i;
const minHeight = /\(\s*min(-device)?-height/i;
const maxMinHeight = /(!?\(\s*max(-device)?-height)(.|\n)+\(\s*min(-device)?-height/i;
const maxHeight = /\(\s*max(-device)?-height/i;
const isMinHeight = _testQuery(minMaxHeight, maxMinHeight, minHeight);
const isMaxHeight = _testQuery(maxMinHeight, minMaxHeight, maxHeight);
const isPrint = /print/i;
const isPrintOnly = /^print$/i;
const maxValue = Number.MAX_VALUE;
/**
* Obtain the length of the media request in pixels.
* Copy from original source `function inspectLength (length)`
* {@link https://github.com/hail2u/node-css-mqpacker/blob/master/index.js#L58}
* @private
* @param {string} length
* @return {number}
*/
function _getQueryLength(query) {
let length = /(-?\d*\.?\d+)(ch|em|ex|px|rem)/.exec(query);
if (length === null && (isMinWidth(query) || isMinHeight(query))) {
length = /(\d)/.exec(query);
}
if (length === '0') {
return 0;
}
if (length === null) {
return maxValue;
}
let number = length[1];
const unit = length[2];
switch (unit) {
case 'ch':
number = parseFloat(number) * 8.8984375;
break;
case 'em':
case 'rem':
number = parseFloat(number) * 16;
break;
case 'ex':
number = parseFloat(number) * 8.296875;
break;
case 'px':
number = parseFloat(number);
break;
}
return +number;
}
/**
* Wrapper for creating test functions
* @private
* @param {RegExp} doubleTestTrue
* @param {RegExp} doubleTestFalse
* @param {RegExp} singleTest
* @return {Function}
*/
function _testQuery(doubleTestTrue, doubleTestFalse, singleTest) {
/**
* @param {string} query
* @return {boolean}
*/
return function (query) {
if (doubleTestTrue.test(query)) {
return true;
} else if (doubleTestFalse.test(query)) {
return false;
}
return singleTest.test(query);
};
}
/**
* @private
* @param {string} a
* @param {string} b
* @return {number|null}
*/
function _testIsPrint(a, b) {
const isPrintA = isPrint.test(a);
const isPrintOnlyA = isPrintOnly.test(a);
const isPrintB = isPrint.test(b);
const isPrintOnlyB = isPrintOnly.test(b);
if (isPrintA && isPrintB) {
if (!isPrintOnlyA && isPrintOnlyB) {
return 1;
}
if (isPrintOnlyA && !isPrintOnlyB) {
return -1;
}
return a.localeCompare(b);
}
if (isPrintA) {
return 1;
}
if (isPrintB) {
return -1;
}
return null;
}
// ----------------------------------------
// Public
// ----------------------------------------
/**
* @param {Object} [configuration]
* @param {boolean} [configuration.unitlessMqAlwaysFirst]
* @returns {(function(string, string): number)|*}
*/
module.exports = function createSort(configuration) {
const config = configuration || {};
const UNITLESS_MQ_ALWAYS_FIRST = config.unitlessMqAlwaysFirst;
/**
* Sorting an array with media queries
* according to the mobile-first methodology.
* @param {string} a
* @param {string} b
* @return {number} 1 / 0 / -1
*/
function sortCSSmq(a, b) {
const testIsPrint = _testIsPrint(a, b);
if (testIsPrint !== null) {
return testIsPrint;
}
const minA = isMinWidth(a) || isMinHeight(a);
const maxA = isMaxWidth(a) || isMaxHeight(a);
const minB = isMinWidth(b) || isMinHeight(b);
const maxB = isMaxWidth(b) || isMaxHeight(b);
if (UNITLESS_MQ_ALWAYS_FIRST && ((!minA && !maxA) || (!minB && !maxB))) {
if (!minA && !maxA && !minB && !maxB) {
return a.localeCompare(b);
}
return !minB && !maxB ? 1 : -1;
} else {
if (minA && maxB) {
return -1;
}
if (maxA && minB) {
return 1;
}
const lengthA = _getQueryLength(a);
const lengthB = _getQueryLength(b);
if (lengthA === maxValue && lengthB === maxValue) {
return a.localeCompare(b);
} else if (lengthA === maxValue) {
return 1;
} else if (lengthB === maxValue) {
return -1;
}
if (lengthA > lengthB) {
if (maxA) {
return -1;
}
return 1;
}
if (lengthA < lengthB) {
if (maxA) {
return 1;
}
return -1;
}
return a.localeCompare(b);
}
}
/**
* Sorting an array with media queries
* according to the desktop-first methodology.
* @param {string} a
* @param {string} b
* @return {number} 1 / 0 / -1
*/
sortCSSmq.desktopFirst = function (a, b) {
const testIsPrint = _testIsPrint(a, b);
if (testIsPrint !== null) {
return testIsPrint;
}
const minA = isMinWidth(a) || isMinHeight(a);
const maxA = isMaxWidth(a) || isMaxHeight(a);
const minB = isMinWidth(b) || isMinHeight(b);
const maxB = isMaxWidth(b) || isMaxHeight(b);
if (UNITLESS_MQ_ALWAYS_FIRST && ((!minA && !maxA) || (!minB && !maxB))) {
if (!minA && !maxA && !minB && !maxB) {
return a.localeCompare(b);
}
return !minB && !maxB ? 1 : -1;
} else {
if (minA && maxB) {
return 1;
}
if (maxA && minB) {
return -1;
}
const lengthA = _getQueryLength(a);
const lengthB = _getQueryLength(b);
if (lengthA === maxValue && lengthB === maxValue) {
return a.localeCompare(b);
} else if (lengthA === maxValue) {
return 1;
} else if (lengthB === maxValue) {
return -1;
}
if (lengthA > lengthB) {
if (maxA) {
return -1;
}
return 1;
}
if (lengthA < lengthB) {
if (maxA) {
return 1;
}
return -1;
}
return -a.localeCompare(b);
}
};
return sortCSSmq;
};