epiphany/node_modules/postcss-sorting/lib/validateOptions.js
2023-12-09 22:48:07 -08:00

208 lines
4.6 KiB
JavaScript

const isString = require('./isString');
module.exports = function validateOptions(options) {
if (options === undefined || options === null) {
return false;
}
if (!isObject(options)) {
return reportError('Options should be an object.');
}
if (options.order !== undefined && options.order !== null) {
const validatedOrder = validateOrder(options.order);
const { isValid, message } = validatedOrder;
if (!isValid) {
return reportInvalidOption('order', message);
}
}
if (options['properties-order'] !== undefined && options['properties-order'] !== null) {
const validatedPropertiesOrder = validatePropertiesOrder(options['properties-order']);
const { isValid, message } = validatedPropertiesOrder;
if (!isValid) {
return reportInvalidOption('properties-order', message);
}
}
if (
options['unspecified-properties-position'] !== undefined &&
options['unspecified-properties-position'] !== null
) {
const validatedUnspecifiedPropertiesPosition = validateUnspecifiedPropertiesPosition(
options['unspecified-properties-position']
);
const { isValid, message } = validatedUnspecifiedPropertiesPosition;
if (!isValid) {
return reportInvalidOption('unspecified-properties-position', message);
}
}
return true;
};
function reportError(errorMessage) {
return `postcss-sorting: ${errorMessage}`;
}
function reportInvalidOption(optionName, optionError = 'Invalid value') {
return reportError(`${optionName}: ${optionError}`);
}
function keywordsList(keywords) {
return keywords.join(', ');
}
function validateOrder(options) {
// Otherwise, begin checking array options
if (!Array.isArray(options)) {
return {
isValid: false,
message: 'Should be an array',
};
}
const keywords = [
'custom-properties',
'dollar-variables',
'at-variables',
'declarations',
'rules',
'at-rules',
];
// Every item in the array must be a certain string or an object
// with a "type" property
if (
!options.every((item) => {
if (isString(item)) {
return keywords.includes(item);
}
return isObject(item) && item.type !== undefined;
})
) {
return {
isValid: false,
message: `Every item in the array must be an object with a "type" property, or one of keywords: ${keywordsList(
keywords
)}.`,
};
}
const objectItems = options.filter(isObject);
let wrongObjectItem;
if (
!objectItems.every((item) => {
let result = true;
if (item.type !== 'at-rule' && item.type !== 'rule') {
wrongObjectItem = `"type" could be 'at-rule' or 'rule' only`;
return false;
}
if (item.type === 'at-rule') {
// if parameter is specified, name should be specified also
if (item.parameter !== undefined && item.name === undefined) {
wrongObjectItem = `"at-rule" with "parameter" should also has a "name"`;
return false;
}
if (item.hasBlock !== undefined) {
result = item.hasBlock === true || item.hasBlock === false;
}
if (item.name !== undefined) {
result = isString(item.name) && item.name.length;
}
if (item.parameter !== undefined) {
result =
(isString(item.parameter) && item.parameter.length) ||
isRegExp(item.parameter);
}
}
if (item.type === 'rule') {
if (item.selector !== undefined) {
result =
(isString(item.selector) && item.selector.length) ||
isRegExp(item.selector);
}
}
if (!result) {
wrongObjectItem = `Following option is incorrect: ${JSON.stringify(item)}`;
}
return result;
})
) {
return {
isValid: false,
message: wrongObjectItem,
};
}
return {
isValid: true,
};
}
function validatePropertiesOrder(options) {
// Return true early if alphabetical
if (options === 'alphabetical') {
return {
isValid: true,
};
}
// Otherwise, begin checking array options
if (!Array.isArray(options)) {
return {
isValid: false,
message: 'Should be an array',
};
}
// Every item in the array must be a string
if (!options.every((item) => isString(item))) {
return {
isValid: false,
message: 'Array should contain strings only',
};
}
return {
isValid: true,
};
}
function validateUnspecifiedPropertiesPosition(options) {
const keywords = ['top', 'bottom', 'bottomAlphabetical'];
if (isString(options) && keywords.includes(options)) {
return {
isValid: true,
};
}
return {
isValid: false,
message: `Option should be one of the following values: ${keywordsList(keywords)}.`,
};
}
function isRegExp(value) {
return Object.prototype.toString.call(value) === '[object RegExp]';
}
function isObject(value) {
return typeof value === 'object' && value !== null;
}