3 const declarationValueIndex = require("../../utils/declarationValueIndex");
4 const functionArgumentsSearch = require("../../utils/functionArgumentsSearch");
5 const postcss = require("postcss");
6 const report = require("../../utils/report");
7 const ruleMessages = require("../../utils/ruleMessages");
8 const validateOptions = require("../../utils/validateOptions");
9 const valueParser = require("postcss-value-parser");
11 const ruleName = "function-linear-gradient-no-nonstandard-direction";
13 const messages = ruleMessages(ruleName, {
14 rejected: "Unexpected nonstandard direction"
17 function isStandardDirection(source, withToPrefix) {
18 const regexp = withToPrefix
19 ? /^to (top|left|bottom|right)(?: (top|left|bottom|right))?$/
20 : /^(top|left|bottom|right)(?: (top|left|bottom|right))?$/;
22 const matches = source.match(regexp);
26 if (matches.length === 2) {
29 // Cannot repeat side-or-corner, e.g. "to top top"
30 if (matches.length === 3 && matches[1] !== matches[2]) {
36 const rule = function(actual) {
37 return (root, result) => {
38 const validOptions = validateOptions(result, ruleName, { actual });
43 root.walkDecls(decl => {
44 valueParser(decl.value).walk(valueNode => {
45 if (valueNode.type !== "function") {
48 functionArgumentsSearch(
49 valueParser.stringify(valueNode).toLowerCase(),
51 (expression, expressionIndex) => {
52 const firstArg = expression.split(",")[0].trim();
54 // If the first character is a number, we can assume the user intends an angle
55 if (/[\d.]/.test(firstArg[0])) {
56 if (/^[\d.]+(?:deg|grad|rad|turn)$/.test(firstArg)) {
63 // The first argument may not be a direction: it may be an angle,
64 // or a color stop (in which case user gets default direction, "to bottom")
65 // cf. https://drafts.csswg.org/css-images-3/#linear-gradient-syntax
66 if (!/left|right|top|bottom/.test(firstArg)) {
70 const withToPrefix = !postcss.vendor.prefix(valueNode.value);
71 if (!isStandardDirection(firstArg, withToPrefix)) {
78 message: messages.rejected,
81 declarationValueIndex(decl) +
82 valueNode.sourceIndex +
95 rule.ruleName = ruleName;
96 rule.messages = messages;
97 module.exports = rule;