You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

185 lines
6.0 KiB

4 years ago
'use strict';
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var postcss = _interopDefault(require('postcss'));
var parser = _interopDefault(require('postcss-values-parser'));
var convertColors = require('@csstools/convert-colors');
function _slicedToArray(arr, i) {
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest();
}
function _arrayWithHoles(arr) {
if (Array.isArray(arr)) return arr;
}
function _iterableToArrayLimit(arr, i) {
var _arr = [];
var _n = true;
var _d = false;
var _e = undefined;
try {
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
_arr.push(_s.value);
if (i && _arr.length === i) break;
}
} catch (err) {
_d = true;
_e = err;
} finally {
try {
if (!_n && _i["return"] != null) _i["return"]();
} finally {
if (_d) throw _e;
}
}
return _arr;
}
function _nonIterableRest() {
throw new TypeError("Invalid attempt to destructure non-iterable instance");
}
var index = postcss.plugin('postcss-color-gray', opts => root => {
// walk all declarations likely containing a gray() function
root.walkDecls(decl => {
if (hasGrayFunction(decl)) {
const originalValue = decl.value; // parse the declaration value
const ast = parser(originalValue).parse(); // walk every node in the value that contains a gray() function
ast.walk(node => {
const _getFunctionGrayArgs = getFunctionGrayArgs(node),
_getFunctionGrayArgs2 = _slicedToArray(_getFunctionGrayArgs, 2),
lightness = _getFunctionGrayArgs2[0],
alpha = _getFunctionGrayArgs2[1];
if (lightness !== undefined) {
// rename the gray() function to rgb()
node.value = 'rgb'; // convert the lab gray lightness into rgb
const _lab2rgb$map = convertColors.lab2rgb(lightness, 0, 0).map(channel => Math.max(Math.min(Math.round(channel * 2.55), 255), 0)),
_lab2rgb$map2 = _slicedToArray(_lab2rgb$map, 3),
r = _lab2rgb$map2[0],
g = _lab2rgb$map2[1],
b = _lab2rgb$map2[2]; // preserve the slash nodes within rgb()
const openingSlash = node.first;
const closingSlash = node.last;
node.removeAll() // replace the contents of rgb with `(r,g,b`
.append(openingSlash).append(parser.number({
value: r
})).append(parser.comma({
value: ','
})).append(parser.number({
value: g
})).append(parser.comma({
value: ','
})).append(parser.number({
value: b
})); // if an alpha channel was defined
if (alpha < 1) {
// rename the rgb() function to rgba()
node.value += 'a';
node // append the contents of rgba with `,a`
.append(parser.comma({
value: ','
})).append(parser.number({
value: alpha
}));
} // append the contents of rgb/rgba with `)`
node.append(closingSlash);
}
});
const modifiedValue = ast.toString(); // if the modified value has changed from the original value
if (originalValue !== modifiedValue) {
// if the original gray() color is to be preserved
if (Object(opts).preserve) {
// insert the declaration value with the fallback before the current declaration
decl.cloneBefore({
value: modifiedValue
});
} else {
// otherwise, overwrite the declaration value with the fallback
decl.value = modifiedValue;
}
}
}
});
}); // return whether a string contains a gray() function
const hasGrayFunctionRegExp = /(^|[^\w-])gray\(/i;
const hasGrayFunction = decl => hasGrayFunctionRegExp.test(Object(decl).value); // return whether a node matches a specific type
const isNumber = node => Object(node).type === 'number';
const isOperator = node => Object(node).type === 'operator';
const isFunction = node => Object(node).type === 'func';
const isCalcRegExp = /^calc$/i;
const isFunctionCalc = node => isFunction(node) && isCalcRegExp.test(node.value);
const isGrayRegExp = /^gray$/i;
const isFunctionGrayWithArgs = node => isFunction(node) && isGrayRegExp.test(node.value) && node.nodes && node.nodes.length;
const isNumberPercentage = node => isNumber(node) && node.unit === '%';
const isNumberUnitless = node => isNumber(node) && node.unit === '';
const isOperatorSlash = node => isOperator(node) && node.value === '/'; // return valid values from a node, otherwise undefined
const getNumberUnitless = node => isNumberUnitless(node) ? Number(node.value) : undefined;
const getOperatorSlash = node => isOperatorSlash(node) ? null : undefined;
const getAlpha = node => isFunctionCalc(node) ? String(node) : isNumberUnitless(node) ? Number(node.value) : isNumberPercentage(node) ? Number(node.value) / 100 : undefined; // return valid arguments from a gray() function
const functionalGrayArgs = [getNumberUnitless, getOperatorSlash, getAlpha];
const getFunctionGrayArgs = node => {
const validArgs = []; // if the node is a gray() function with arguments
if (isFunctionGrayWithArgs(node)) {
// get all the gray() function arguments between `(` and `)`
const nodes = node.nodes.slice(1, -1); // validate each argument
for (const index in nodes) {
const arg = typeof functionalGrayArgs[index] === 'function' ? functionalGrayArgs[index](nodes[index]) : undefined; // if the argument was validated
if (arg !== undefined) {
// push any non-null argument to the valid arguments array
if (arg !== null) {
validArgs.push(arg);
}
} else {
// otherwise, return an empty array
return [];
}
} // return the valid arguments array
return validArgs;
} else {
// otherwise, return an empty array
return [];
}
};
module.exports = index;