blob: 1ff956a41e805415b7dea9faca226500613e45b0 [file] [log] [blame]
// @ts-nocheck
'use strict';
const declarationValueIndex = require('../../utils/declarationValueIndex');
const keywordSets = require('../../reference/keywordSets');
const optionsMatches = require('../../utils/optionsMatches');
const postcss = require('postcss');
const report = require('../../utils/report');
const ruleMessages = require('../../utils/ruleMessages');
const validateOptions = require('../../utils/validateOptions');
const valueParser = require('postcss-value-parser');
const vendor = require('../../utils/vendor');
const { isNumber } = require('../../utils/validateTypes');
const ruleName = 'time-min-milliseconds';
const messages = ruleMessages(ruleName, {
expected: (time) => `Expected a minimum of ${time} milliseconds`,
});
const DELAY_PROPERTIES = new Set(['animation-delay', 'transition-delay']);
function rule(minimum, options) {
return (root, result) => {
const validOptions = validateOptions(
result,
ruleName,
{
actual: minimum,
possible: isNumber,
},
{
actual: options,
possible: {
ignore: ['delay'],
},
optional: true,
},
);
if (!validOptions) {
return;
}
root.walkDecls((decl) => {
const propertyName = vendor.unprefixed(decl.prop.toLowerCase());
if (
keywordSets.longhandTimeProperties.has(propertyName) &&
!isIgnoredProperty(propertyName) &&
!isAcceptableTime(decl.value)
) {
complain(decl);
}
if (keywordSets.shorthandTimeProperties.has(propertyName)) {
const valueListList = postcss.list.comma(decl.value);
for (const valueListString of valueListList) {
const valueList = postcss.list.space(valueListString);
if (optionsMatches(options, 'ignore', 'delay')) {
// Check only duration time values
const duration = getDuration(valueList);
if (duration && !isAcceptableTime(duration)) {
complain(decl, decl.value.indexOf(duration));
}
} else {
// Check all time values
for (const value of valueList) {
if (!isAcceptableTime(value)) {
complain(decl, decl.value.indexOf(value));
}
}
}
}
}
});
/**
* Get the duration within an `animation` or `transition` shorthand property value.
*
* @param {Node[]} valueList
*
* @returns {Node}
*/
function getDuration(valueList) {
for (const value of valueList) {
const parsedTime = valueParser.unit(value);
if (!parsedTime) continue;
// The first numeric value in an animation shorthand is the duration.
return value;
}
}
function isIgnoredProperty(propertyName) {
if (optionsMatches(options, 'ignore', 'delay') && DELAY_PROPERTIES.has(propertyName)) {
return true;
}
return false;
}
function isAcceptableTime(time) {
const parsedTime = valueParser.unit(time);
if (!parsedTime) return true;
if (parsedTime.number <= 0) {
return true;
}
if (parsedTime.unit.toLowerCase() === 'ms' && parsedTime.number < minimum) {
return false;
}
if (parsedTime.unit.toLowerCase() === 's' && parsedTime.number * 1000 < minimum) {
return false;
}
return true;
}
function complain(decl, offset = 0) {
report({
result,
ruleName,
message: messages.expected(minimum),
index: declarationValueIndex(decl) + offset,
node: decl,
});
}
};
}
rule.ruleName = ruleName;
rule.messages = messages;
module.exports = rule;