UNPKG

2.87 kBJavaScriptView Raw
1'use strict';
2
3const declarationValueIndex = require('../../utils/declarationValueIndex');
4const functionArgumentsSearch = require('../../utils/functionArgumentsSearch');
5const isStandardSyntaxValue = require('../../utils/isStandardSyntaxValue');
6const postcss = require('postcss');
7const report = require('../../utils/report');
8const ruleMessages = require('../../utils/ruleMessages');
9const validateOptions = require('../../utils/validateOptions');
10const valueParser = require('postcss-value-parser');
11
12const ruleName = 'function-linear-gradient-no-nonstandard-direction';
13
14const messages = ruleMessages(ruleName, {
15 rejected: 'Unexpected nonstandard direction',
16});
17
18function isStandardDirection(source, withToPrefix) {
19 const regexp = withToPrefix
20 ? /^to (top|left|bottom|right)(?: (top|left|bottom|right))?$/
21 : /^(top|left|bottom|right)(?: (top|left|bottom|right))?$/;
22
23 const matches = source.match(regexp);
24
25 if (!matches) {
26 return false;
27 }
28
29 if (matches.length === 2) {
30 return true;
31 }
32
33 // Cannot repeat side-or-corner, e.g. "to top top"
34 if (matches.length === 3 && matches[1] !== matches[2]) {
35 return true;
36 }
37
38 return false;
39}
40
41const rule = function(actual) {
42 return (root, result) => {
43 const validOptions = validateOptions(result, ruleName, { actual });
44
45 if (!validOptions) {
46 return;
47 }
48
49 root.walkDecls((decl) => {
50 valueParser(decl.value).walk((valueNode) => {
51 if (valueNode.type !== 'function') {
52 return;
53 }
54
55 functionArgumentsSearch(
56 valueParser.stringify(valueNode).toLowerCase(),
57 'linear-gradient',
58 (expression, expressionIndex) => {
59 const firstArg = expression.split(',')[0].trim();
60
61 // If the first arg is not standard, return early
62 if (!isStandardSyntaxValue(firstArg)) {
63 return;
64 }
65
66 // If the first character is a number, we can assume the user intends an angle
67 if (/[\d.]/.test(firstArg[0])) {
68 if (/^[\d.]+(?:deg|grad|rad|turn)$/.test(firstArg)) {
69 return;
70 }
71
72 complain();
73
74 return;
75 }
76
77 // The first argument may not be a direction: it may be an angle,
78 // or a color stop (in which case user gets default direction, "to bottom")
79 // cf. https://drafts.csswg.org/css-images-3/#linear-gradient-syntax
80 if (!/left|right|top|bottom/.test(firstArg)) {
81 return;
82 }
83
84 const withToPrefix = !postcss.vendor.prefix(valueNode.value);
85
86 if (!isStandardDirection(firstArg, withToPrefix)) {
87 complain();
88
89 return;
90 }
91
92 function complain() {
93 report({
94 message: messages.rejected,
95 node: decl,
96 index: declarationValueIndex(decl) + valueNode.sourceIndex + expressionIndex,
97 result,
98 ruleName,
99 });
100 }
101 },
102 );
103 });
104 });
105 };
106};
107
108rule.ruleName = ruleName;
109rule.messages = messages;
110module.exports = rule;