UNPKG

3.34 kBJavaScriptView Raw
1// @ts-nocheck
2
3'use strict';
4
5const _ = require('lodash');
6const declarationValueIndex = require('../../utils/declarationValueIndex');
7const keywordSets = require('../../reference/keywordSets');
8const optionsMatches = require('../../utils/optionsMatches');
9const postcss = require('postcss');
10const report = require('../../utils/report');
11const ruleMessages = require('../../utils/ruleMessages');
12const validateOptions = require('../../utils/validateOptions');
13const valueParser = require('postcss-value-parser');
14
15const ruleName = 'time-min-milliseconds';
16
17const messages = ruleMessages(ruleName, {
18 expected: (time) => `Expected a minimum of ${time} milliseconds`,
19});
20
21const DELAY_PROPERTIES = ['animation-delay', 'transition-delay'];
22
23function rule(minimum, options) {
24 return (root, result) => {
25 const validOptions = validateOptions(
26 result,
27 ruleName,
28 {
29 actual: minimum,
30 possible: _.isNumber,
31 },
32 {
33 actual: options,
34 possible: {
35 ignore: ['delay'],
36 },
37 optional: true,
38 },
39 );
40
41 if (!validOptions) {
42 return;
43 }
44
45 root.walkDecls((decl) => {
46 const propertyName = postcss.vendor.unprefixed(decl.prop.toLowerCase());
47
48 if (
49 keywordSets.longhandTimeProperties.has(propertyName) &&
50 !isIgnoredProperty(propertyName) &&
51 !isAcceptableTime(decl.value)
52 ) {
53 complain(decl);
54 }
55
56 if (keywordSets.shorthandTimeProperties.has(propertyName)) {
57 const valueListList = postcss.list.comma(decl.value);
58
59 for (const valueListString of valueListList) {
60 const valueList = postcss.list.space(valueListString);
61
62 if (optionsMatches(options, 'ignore', 'delay')) {
63 // Check only duration time values
64 const duration = getDuration(valueList);
65
66 if (duration && !isAcceptableTime(duration)) {
67 complain(decl, decl.value.indexOf(duration));
68 }
69 } else {
70 // Check all time values
71 for (const value of valueList) {
72 if (!isAcceptableTime(value)) {
73 complain(decl, decl.value.indexOf(value));
74 }
75 }
76 }
77 }
78 }
79 });
80
81 /**
82 * Get the duration within an `animation` or `transition` shorthand property value.
83 *
84 * @param {Node[]} valueList
85 *
86 * @returns {Node}
87 */
88 function getDuration(valueList) {
89 for (const value of valueList) {
90 const parsedTime = valueParser.unit(value);
91
92 if (!parsedTime) continue;
93
94 // The first numeric value in an animation shorthand is the duration.
95 return value;
96 }
97 }
98
99 function isIgnoredProperty(propertyName) {
100 if (optionsMatches(options, 'ignore', 'delay') && DELAY_PROPERTIES.includes(propertyName)) {
101 return true;
102 }
103
104 return false;
105 }
106
107 function isAcceptableTime(time) {
108 const parsedTime = valueParser.unit(time);
109
110 if (!parsedTime) return true;
111
112 if (parsedTime.number <= 0) {
113 return true;
114 }
115
116 if (parsedTime.unit.toLowerCase() === 'ms' && parsedTime.number < minimum) {
117 return false;
118 }
119
120 if (parsedTime.unit.toLowerCase() === 's' && parsedTime.number * 1000 < minimum) {
121 return false;
122 }
123
124 return true;
125 }
126
127 function complain(decl, offset = 0) {
128 report({
129 result,
130 ruleName,
131 message: messages.expected(minimum),
132 index: declarationValueIndex(decl) + offset,
133 node: decl,
134 });
135 }
136 };
137}
138
139rule.ruleName = ruleName;
140rule.messages = messages;
141module.exports = rule;