3 const _ = require("lodash");
4 const optionsMatches = require("../../utils/optionsMatches");
5 const postcss = require("postcss");
6 const report = require("../../utils/report");
7 const ruleMessages = require("../../utils/ruleMessages");
8 const shorthandData = require("../../reference/shorthandData");
9 const validateOptions = require("../../utils/validateOptions");
11 const ruleName = "declaration-block-no-redundant-longhand-properties";
13 const messages = ruleMessages(ruleName, {
14 expected: props => `Expected shorthand property "${props}"`
17 const rule = function(actual, options) {
18 return (root, result) => {
19 const validOptions = validateOptions(
26 ignoreShorthands: [_.isString]
35 const longhandProperties = _.transform(
37 (result, values, key) => {
38 if (optionsMatches(options, "ignoreShorthands", key)) {
42 values.forEach(value => {
43 (result[value] || (result[value] = [])).push(key);
48 root.walkRules(check);
49 root.walkAtRules(check);
51 function check(statement) {
52 const longhandDeclarations = {};
53 // Shallow iteration so nesting doesn't produce
55 statement.each(node => {
56 if (node.type !== "decl") {
60 const prop = node.prop.toLowerCase();
61 const unprefixedProp = postcss.vendor.unprefixed(prop);
62 const prefix = postcss.vendor.prefix(prop);
64 const shorthandProperties = longhandProperties[unprefixedProp];
66 if (!shorthandProperties) {
70 shorthandProperties.forEach(shorthandProperty => {
71 const prefixedShorthandProperty = prefix + shorthandProperty;
73 if (!longhandDeclarations[prefixedShorthandProperty]) {
74 longhandDeclarations[prefixedShorthandProperty] = [];
77 longhandDeclarations[prefixedShorthandProperty].push(prop);
79 const prefixedShorthandData = shorthandData[shorthandProperty].map(
87 prefixedShorthandData.sort(),
88 longhandDeclarations[prefixedShorthandProperty].sort()
98 message: messages.expected(prefixedShorthandProperty)
106 rule.ruleName = ruleName;
107 rule.messages = messages;
108 module.exports = rule;