| // @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; |