+++ /dev/null
-"use strict";
-
-const isStandardSyntaxDeclaration = require("../../utils/isStandardSyntaxDeclaration");
-const isStandardSyntaxProperty = require("../../utils/isStandardSyntaxProperty");
-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 ruleName = "shorthand-property-no-redundant-values";
-
-const messages = ruleMessages(ruleName, {
- rejected: (unexpected, expected) =>
- `Unexpected longhand value '${unexpected}' instead of '${expected}'`
-});
-
-// Only these shorthand properties can have values, that can be written in shorter form (remove repetitions)
-const shorthandableProperties = new Set([
- "margin",
- "padding",
- "border-color",
- "border-radius",
- "border-style",
- "border-width",
- "grid-gap"
-]);
-
-const ignoredCharacters = [
- "+",
- "-",
- "*",
- "/",
- "(",
- ")",
- "$",
- "@",
- "--",
- "var("
-];
-
-function isIgnoredCharacters(value) {
- return ignoredCharacters.some(char => value.indexOf(char) !== -1);
-}
-
-function canCondense(top, right) {
- const bottom =
- arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
- const left =
- arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
-
- const lowerTop = top.toLowerCase();
- const lowerRight = right.toLowerCase();
- const lowerBottom = bottom && bottom.toLowerCase();
- const lowerLeft = left && left.toLowerCase();
-
- if (canCondenseToOneValue(lowerTop, lowerRight, lowerBottom, lowerLeft)) {
- return [top];
- } else if (
- canCondenseToTwoValues(lowerTop, lowerRight, lowerBottom, lowerLeft)
- ) {
- return [top, right];
- } else if (
- canCondenseToThreeValues(lowerTop, lowerRight, lowerBottom, lowerLeft)
- ) {
- return [top, right, bottom];
- } else {
- return [top, right, bottom, left];
- }
-}
-
-function canCondenseToOneValue(top, right, bottom, left) {
- if (top !== right) {
- return false;
- }
-
- return (top === bottom && (bottom === left || !left)) || (!bottom && !left);
-}
-
-function canCondenseToTwoValues(top, right, bottom, left) {
- return (
- (top === bottom && right === left) ||
- (top === bottom && !left && top !== right)
- );
-}
-
-function canCondenseToThreeValues(top, right, bottom, left) {
- return right === left;
-}
-
-const rule = function(actual, secondary, context) {
- return (root, result) => {
- const validOptions = validateOptions(result, ruleName, { actual });
- if (!validOptions) {
- return;
- }
-
- root.walkDecls(decl => {
- if (
- !isStandardSyntaxDeclaration(decl) ||
- !isStandardSyntaxProperty(decl.prop)
- ) {
- return;
- }
-
- const prop = decl.prop,
- value = decl.value;
-
- const normalizedProp = postcss.vendor.unprefixed(prop.toLowerCase());
-
- // Ignore not shorthandable properties, and math operations
- if (
- isIgnoredCharacters(value) ||
- !shorthandableProperties.has(normalizedProp)
- ) {
- return;
- }
-
- const valuesToShorthand = [];
-
- valueParser(value).walk(valueNode => {
- if (valueNode.type !== "word") {
- return;
- }
-
- valuesToShorthand.push(valueParser.stringify(valueNode));
- });
-
- if (valuesToShorthand.length <= 1 || valuesToShorthand.length > 4) {
- return;
- }
-
- const shortestForm = canCondense.apply(undefined, valuesToShorthand);
- const shortestFormString = shortestForm
- .filter(value => {
- return value;
- })
- .join(" ");
- const valuesFormString = valuesToShorthand.join(" ");
-
- if (shortestFormString.toLowerCase() === valuesFormString.toLowerCase()) {
- return;
- }
-
- if (context.fix) {
- decl.value = decl.value.replace(value, shortestFormString);
- } else {
- report({
- message: messages.rejected(value, shortestFormString),
- node: decl,
- result,
- ruleName
- });
- }
- });
- };
-};
-
-rule.ruleName = ruleName;
-rule.messages = messages;
-module.exports = rule;