Browse Source

Early returns

shalvah 2 years ago
parent
commit
82c539f6d8
1 changed files with 282 additions and 280 deletions
  1. 282 280
      src/Extracting/ParsesValidationRules.php

+ 282 - 280
src/Extracting/ParsesValidationRules.php

@@ -211,289 +211,291 @@ trait ParsesValidationRules
             return true;
         }
 
-        if (is_string($rule)) {
-            try {
-                // Convert string rules into rule + arguments (eg "in:1,2" becomes ["in", ["1", "2"]])
-                $parsedRule = $this->parseStringRuleIntoRuleAndArguments($rule);
-                [$rule, $arguments] = $parsedRule;
+        if (!is_string($rule)) {
+            return false;
+        }
 
-                $dependentRules = ['between', 'max', 'min', 'size', 'gt', 'gte', 'lt', 'lte', 'before', 'after', 'before_or_equal', 'after_or_equal'];
-                if ($independentOnly && in_array($rule, $dependentRules)) {
-                    return false;
-                }
+        try {
+            // Convert string rules into rule + arguments (eg "in:1,2" becomes ["in", ["1", "2"]])
+            $parsedRule = $this->parseStringRuleIntoRuleAndArguments($rule);
+            [$rule, $arguments] = $parsedRule;
 
-                switch ($rule) {
-                    case 'required':
-                        $parameterData['required'] = true;
-                        break;
-                    case 'accepted':
-                        $parameterData['required'] = true;
-                        $parameterData['type'] = 'boolean';
-                        $parameterData['description'] .= ' Must be accepted.';
-                        $parameterData['setter'] = fn() => true;
-                        break;
-
-                    /*
-                    * Primitive types. No description should be added
-                    */
-                    case 'bool':
-                    case 'boolean':
-                        $parameterData['setter'] = function () {
-                            return Arr::random([true, false]);
-                        };
-                        $parameterData['type'] = 'boolean';
-                        break;
-                    case 'string':
-                        $parameterData['setter'] = function () use ($parameterData) {
-                            return $this->generateDummyValue('string', ['name' => $parameterData['name']]);
-                        };
-                        $parameterData['type'] = 'string';
-                        break;
-                    case 'int':
-                    case 'integer':
-                        $parameterData['setter'] = function () {
-                            return $this->generateDummyValue('integer');
-                        };
-                        $parameterData['type'] = 'integer';
-                        break;
-                    case 'numeric':
-                        $parameterData['setter'] = function () {
-                            return $this->generateDummyValue('number');
-                        };
-                        $parameterData['type'] = 'number';
-                        break;
-                    case 'array':
-                        $parameterData['setter'] = function () {
-                            return [$this->generateDummyValue('string')];
-                        };
-                        $parameterData['type'] = 'array'; // The cleanup code in normaliseArrayAndObjectParameters() will set this to a valid type (x[] or object)
-                        break;
-                    case 'file':
-                        $parameterData['type'] = 'file';
-                        $parameterData['description'] .= ' Must be a file.';
-                        $parameterData['setter'] = function () {
-                            return $this->generateDummyValue('file');
-                        };
-                        break;
-
-                    /**
-                     * Special string types
-                     */
-                    case 'alpha':
-                        $parameterData['description'] .= " Must contain only letters.";
-                        $parameterData['setter'] = function () {
-                            return $this->getFaker()->lexify('??????');
-                        };
-                        break;
-                    case 'alpha_dash':
-                        $parameterData['description'] .= " Must contain only letters, numbers, dashes and underscores.";
-                        $parameterData['setter'] = function () {
-                            return $this->getFaker()->lexify('???-???_?');
-                        };
-                        break;
-                    case 'alpha_num':
-                        $parameterData['description'] .= " Must contain only letters and numbers.";
-                        $parameterData['setter'] = function () {
-                            return $this->getFaker()->bothify('#?#???#');
-                        };
-                        break;
-                    case 'timezone':
-                        // Laravel's message merely says "The value must be a valid zone"
-                        $parameterData['description'] .= " Must be a valid time zone, such as <code>Africa/Accra</code>.";
-                        $parameterData['setter'] = $this->getFakeFactoryByName('timezone');
-                        break;
-                    case 'email':
-                        $parameterData['description'] .= ' ' . $this->getDescription($rule);
-                        $parameterData['setter'] = $this->getFakeFactoryByName('email');
-                        $parameterData['type'] = 'string';
-                        break;
-                    case 'url':
-                        $parameterData['setter'] = $this->getFakeFactoryByName('url');
-                        $parameterData['type'] = 'string';
-                        // Laravel's message is "The value format is invalid". Ugh.🤮
-                        $parameterData['description'] .= " Must be a valid URL.";
-                        break;
-                    case 'ip':
-                        $parameterData['description'] .= ' ' . $this->getDescription($rule);
-                        $parameterData['type'] = 'string';
-                        $parameterData['setter'] = function () {
-                            return $this->getFaker()->ipv4();
-                        };
-                        break;
-                    case 'json':
-                        $parameterData['type'] = 'string';
-                        $parameterData['description'] .= ' ' . $this->getDescription($rule);
-                        $parameterData['setter'] = function () {
-                            return json_encode([$this->getFaker()->word(), $this->getFaker()->word(),]);
-                        };
-                        break;
-                    case 'date':
-                        $parameterData['type'] = 'string';
-                        $parameterData['description'] .= ' ' . $this->getDescription($rule);
-                        $parameterData['setter'] = fn() => date('Y-m-d\TH:i:s', time());
-                        break;
-                    case 'date_format':
-                        $parameterData['type'] = 'string';
-                        // Laravel description here is "The value must match the format Y-m-d". Not descriptive enough.
-                        $parameterData['description'] .= " Must be a valid date in the format <code>{$arguments[0]}</code>.";
-                        $parameterData['setter'] = function () use ($arguments) {
-                            return date($arguments[0], time());
-                        };
-                        break;
-                    case 'after':
-                    case 'after_or_equal':
-                        $parameterData['type'] = 'string';
-                        $parameterData['description'] .= ' ' . $this->getDescription($rule, [':date' => "<code>{$arguments[0]}</code>"]);
-                        // TODO introduce the concept of "modifiers", like date_format
-                        // The startDate may refer to another field, in which case, we just ignore it for now.
-                        $startDate = isset($allParameters[$arguments[0]]) ? 'today' : $arguments[0];
-                        $parameterData['setter'] = fn() => $this->getFaker()->dateTimeBetween($startDate, '+100 years')->format('Y-m-d');
-                        break;
-                    case 'before':
-                    case 'before_or_equal':
-                        $parameterData['type'] = 'string';
-                        // The argument can be either another field or a date
-                        // The endDate may refer to another field, in which case, we just ignore it for now.
-                        $endDate = isset($allParameters[$arguments[0]]) ? 'today' : $arguments[0];
-                        $parameterData['description'] .= ' ' . $this->getDescription($rule, [':date' => "<code>{$arguments[0]}</code>"]);
-                        $parameterData['setter'] = fn() => $this->getFaker()->dateTimeBetween('-30 years', $endDate)->format('Y-m-d');
-                        break;
-                    case 'starts_with':
-                        $parameterData['description'] .= ' Must start with one of ' . w::getListOfValuesAsFriendlyHtmlString($arguments);
-                        $parameterData['setter'] = fn() => $this->getFaker()->lexify("{$arguments[0]}????");;
-                        break;
-                    case 'ends_with':
-                        $parameterData['description'] .= ' Must end with one of ' . w::getListOfValuesAsFriendlyHtmlString($arguments);
-                        $parameterData['setter'] = fn() => $this->getFaker()->lexify("????{$arguments[0]}");;
-                        break;
-                    case 'uuid':
-                        $parameterData['description'] .= ' ' . $this->getDescription($rule) . ' ';
-                        $parameterData['setter'] = $this->getFakeFactoryByName('uuid');
-                        break;
-                    case 'regex':
-                        $parameterData['description'] .= ' ' . $this->getDescription($rule, [':regex' => $arguments[0]]);
-                        $parameterData['setter'] = fn() => $this->getFaker()->regexify($arguments[0]);;
-                        break;
-
-                    /**
-                     * Special number types.
-                     */
-                    case 'digits':
-                        $parameterData['description'] .= ' ' . $this->getDescription($rule, [':digits' => $arguments[0]]);
-                        $parameterData['setter'] = fn() => $this->getFaker()->numerify(str_repeat("#", $arguments[0]));
-                        $parameterData['type'] = 'string';
-                        break;
-                    case 'digits_between':
-                        $parameterData['description'] .= ' ' . $this->getDescription($rule, [':min' => $arguments[0], ':max' => $arguments[1]]);
-                        $parameterData['setter'] = fn() => $this->getFaker()->numerify(str_repeat("#", rand($arguments[0], $arguments[1])));
-                        $parameterData['type'] = 'string';
-                        break;
-
-                    /**
-                     * These rules can apply to numbers, strings, arrays or files
-                     */
-                    case 'size':
-                        $parameterData['description'] .= ' ' . $this->getDescription(
-                                $rule, [':size' => $arguments[0]], $this->getLaravelValidationBaseTypeMapping($parameterData['type'])
-                            );
-                        $parameterData['setter'] = $this->getDummyValueGenerator($parameterData['type'], ['size' => $arguments[0]]);
-                        break;
-                    case 'min':
-                        $parameterData['description'] .= ' ' . $this->getDescription(
-                                $rule, [':min' => $arguments[0]], $this->getLaravelValidationBaseTypeMapping($parameterData['type'])
-                            );
-                        $parameterData['setter'] = $this->getDummyDataGeneratorBetween($parameterData['type'], floatval($arguments[0]), fieldName: $parameterData['name']);
-                        break;
-                    case 'max':
-                        $parameterData['description'] .= ' ' . $this->getDescription(
-                                $rule, [':max' => $arguments[0]], $this->getLaravelValidationBaseTypeMapping($parameterData['type'])
-                            );
-                        $max = min($arguments[0], 25);
-                        $parameterData['setter'] = $this->getDummyDataGeneratorBetween($parameterData['type'], 1, $max, $parameterData['name']);
-                        break;
-                    case 'between':
-                        $parameterData['description'] .= ' ' . $this->getDescription(
-                                $rule, [':min' => $arguments[0], ':max' => $arguments[1]], $this->getLaravelValidationBaseTypeMapping($parameterData['type'])
-                            );
-                        // Avoid exponentially complex operations by using the minimum length
-                        $parameterData['setter'] = $this->getDummyDataGeneratorBetween($parameterData['type'], floatval($arguments[0]), floatval($arguments[0]) + 1, $parameterData['name']);
-                        break;
-
-                    /**
-                     * Special file types.
-                     */
-                    case 'image':
-                        $parameterData['type'] = 'file';
-                        $parameterData['description'] .= ' ' . $this->getDescription($rule) . ' ';
-                        $parameterData['setter'] = function () {
-                            // This is fine because the file example generator generates an image
-                            return $this->generateDummyValue('file');
-                        };
-                        break;
-
-                    /**
-                     * Other rules.
-                     */
-                    case 'in':
-                        // Not using the rule description here because it only says "The attribute is invalid"
-                        $parameterData['description'] .= ' Must be one of ' . w::getListOfValuesAsFriendlyHtmlString($arguments) . ' ';
-                        $parameterData['setter'] = function () use ($arguments) {
-                            return Arr::random($arguments);
-                        };
-                        break;
-
-                    /**
-                     * These rules only add a description. Generating valid examples is too complex.
-                     */
-                    case 'not_in':
-                        $parameterData['description'] .= ' Must not be one of ' . w::getListOfValuesAsFriendlyHtmlString($arguments) . ' ';
-                        break;
-                    case 'required_if':
-                        $parameterData['description'] .= ' ' . $this->getDescription(
-                                $rule, [':other' => "<code>{$arguments[0]}</code>", ':value' => w::getListOfValuesAsFriendlyHtmlString(array_slice($arguments, 1))]
-                            ) . ' ';
-                        break;
-                    case 'required_unless':
-                        $parameterData['description'] .= ' ' . $this->getDescription(
-                                $rule, [':other' => "<code>" . array_shift($arguments) . "</code>", ':values' => w::getListOfValuesAsFriendlyHtmlString($arguments)]
-                            ) . ' ';
-                        break;
-                    case 'required_with':
-                        $parameterData['description'] .= ' ' . $this->getDescription(
-                                $rule, [':values' => w::getListOfValuesAsFriendlyHtmlString($arguments)]
-                            ) . ' ';
-                        break;
-                    case 'required_without':
-                        $description = $this->getDescription(
-                                $rule, [':values' => w::getListOfValuesAsFriendlyHtmlString($arguments)]
-                            ) . ' ';
-                        $parameterData['description'] .= str_replace('must be present', 'is not present', $description);
-                        break;
-                    case 'required_with_all':
-                    case 'required_without_all':
-                        $parameterData['description'] .= ' ' . $this->getDescription(
-                                $rule, [':values' => w::getListOfValuesAsFriendlyHtmlString($arguments, "and")]
-                            ) . ' ';
-                        break;
-                    case 'accepted_if':
-                        $parameterData['type'] = 'boolean';
-                        $parameterData['description'] .= " Must be accepted when <code>$arguments[0]</code> is " . w::getListOfValuesAsFriendlyHtmlString(array_slice($arguments, 1));
-                        $parameterData['setter'] = fn() => true;
-                        break;
-                    case 'same':
-                    case 'different':
-                        $parameterData['description'] .= ' ' . $this->getDescription(
-                                $rule, [':other' => "<code>{$arguments[0]}</code>"]
-                            ) . ' ';
-                        break;
-
-                    default:
-                        // Other rules not supported
-                        break;
-                }
-            } catch (Throwable $e) {
-                throw CouldntProcessValidationRule::forParam($parameterData['name'], $rule, $e);
+            $dependentRules = ['between', 'max', 'min', 'size', 'gt', 'gte', 'lt', 'lte', 'before', 'after', 'before_or_equal', 'after_or_equal'];
+            if ($independentOnly && in_array($rule, $dependentRules)) {
+                return false;
+            }
+
+            switch ($rule) {
+                case 'required':
+                    $parameterData['required'] = true;
+                    break;
+                case 'accepted':
+                    $parameterData['required'] = true;
+                    $parameterData['type'] = 'boolean';
+                    $parameterData['description'] .= ' Must be accepted.';
+                    $parameterData['setter'] = fn() => true;
+                    break;
+
+                /*
+                * Primitive types. No description should be added
+                */
+                case 'bool':
+                case 'boolean':
+                    $parameterData['setter'] = function () {
+                        return Arr::random([true, false]);
+                    };
+                    $parameterData['type'] = 'boolean';
+                    break;
+                case 'string':
+                    $parameterData['setter'] = function () use ($parameterData) {
+                        return $this->generateDummyValue('string', ['name' => $parameterData['name']]);
+                    };
+                    $parameterData['type'] = 'string';
+                    break;
+                case 'int':
+                case 'integer':
+                    $parameterData['setter'] = function () {
+                        return $this->generateDummyValue('integer');
+                    };
+                    $parameterData['type'] = 'integer';
+                    break;
+                case 'numeric':
+                    $parameterData['setter'] = function () {
+                        return $this->generateDummyValue('number');
+                    };
+                    $parameterData['type'] = 'number';
+                    break;
+                case 'array':
+                    $parameterData['setter'] = function () {
+                        return [$this->generateDummyValue('string')];
+                    };
+                    $parameterData['type'] = 'array'; // The cleanup code in normaliseArrayAndObjectParameters() will set this to a valid type (x[] or object)
+                    break;
+                case 'file':
+                    $parameterData['type'] = 'file';
+                    $parameterData['description'] .= ' Must be a file.';
+                    $parameterData['setter'] = function () {
+                        return $this->generateDummyValue('file');
+                    };
+                    break;
+
+                /**
+                 * Special string types
+                 */
+                case 'alpha':
+                    $parameterData['description'] .= " Must contain only letters.";
+                    $parameterData['setter'] = function () {
+                        return $this->getFaker()->lexify('??????');
+                    };
+                    break;
+                case 'alpha_dash':
+                    $parameterData['description'] .= " Must contain only letters, numbers, dashes and underscores.";
+                    $parameterData['setter'] = function () {
+                        return $this->getFaker()->lexify('???-???_?');
+                    };
+                    break;
+                case 'alpha_num':
+                    $parameterData['description'] .= " Must contain only letters and numbers.";
+                    $parameterData['setter'] = function () {
+                        return $this->getFaker()->bothify('#?#???#');
+                    };
+                    break;
+                case 'timezone':
+                    // Laravel's message merely says "The value must be a valid zone"
+                    $parameterData['description'] .= " Must be a valid time zone, such as <code>Africa/Accra</code>.";
+                    $parameterData['setter'] = $this->getFakeFactoryByName('timezone');
+                    break;
+                case 'email':
+                    $parameterData['description'] .= ' ' . $this->getDescription($rule);
+                    $parameterData['setter'] = $this->getFakeFactoryByName('email');
+                    $parameterData['type'] = 'string';
+                    break;
+                case 'url':
+                    $parameterData['setter'] = $this->getFakeFactoryByName('url');
+                    $parameterData['type'] = 'string';
+                    // Laravel's message is "The value format is invalid". Ugh.🤮
+                    $parameterData['description'] .= " Must be a valid URL.";
+                    break;
+                case 'ip':
+                    $parameterData['description'] .= ' ' . $this->getDescription($rule);
+                    $parameterData['type'] = 'string';
+                    $parameterData['setter'] = function () {
+                        return $this->getFaker()->ipv4();
+                    };
+                    break;
+                case 'json':
+                    $parameterData['type'] = 'string';
+                    $parameterData['description'] .= ' ' . $this->getDescription($rule);
+                    $parameterData['setter'] = function () {
+                        return json_encode([$this->getFaker()->word(), $this->getFaker()->word(),]);
+                    };
+                    break;
+                case 'date':
+                    $parameterData['type'] = 'string';
+                    $parameterData['description'] .= ' ' . $this->getDescription($rule);
+                    $parameterData['setter'] = fn() => date('Y-m-d\TH:i:s', time());
+                    break;
+                case 'date_format':
+                    $parameterData['type'] = 'string';
+                    // Laravel description here is "The value must match the format Y-m-d". Not descriptive enough.
+                    $parameterData['description'] .= " Must be a valid date in the format <code>{$arguments[0]}</code>.";
+                    $parameterData['setter'] = function () use ($arguments) {
+                        return date($arguments[0], time());
+                    };
+                    break;
+                case 'after':
+                case 'after_or_equal':
+                    $parameterData['type'] = 'string';
+                    $parameterData['description'] .= ' ' . $this->getDescription($rule, [':date' => "<code>{$arguments[0]}</code>"]);
+                    // TODO introduce the concept of "modifiers", like date_format
+                    // The startDate may refer to another field, in which case, we just ignore it for now.
+                    $startDate = isset($allParameters[$arguments[0]]) ? 'today' : $arguments[0];
+                    $parameterData['setter'] = fn() => $this->getFaker()->dateTimeBetween($startDate, '+100 years')->format('Y-m-d');
+                    break;
+                case 'before':
+                case 'before_or_equal':
+                    $parameterData['type'] = 'string';
+                    // The argument can be either another field or a date
+                    // The endDate may refer to another field, in which case, we just ignore it for now.
+                    $endDate = isset($allParameters[$arguments[0]]) ? 'today' : $arguments[0];
+                    $parameterData['description'] .= ' ' . $this->getDescription($rule, [':date' => "<code>{$arguments[0]}</code>"]);
+                    $parameterData['setter'] = fn() => $this->getFaker()->dateTimeBetween('-30 years', $endDate)->format('Y-m-d');
+                    break;
+                case 'starts_with':
+                    $parameterData['description'] .= ' Must start with one of ' . w::getListOfValuesAsFriendlyHtmlString($arguments);
+                    $parameterData['setter'] = fn() => $this->getFaker()->lexify("{$arguments[0]}????");;
+                    break;
+                case 'ends_with':
+                    $parameterData['description'] .= ' Must end with one of ' . w::getListOfValuesAsFriendlyHtmlString($arguments);
+                    $parameterData['setter'] = fn() => $this->getFaker()->lexify("????{$arguments[0]}");;
+                    break;
+                case 'uuid':
+                    $parameterData['description'] .= ' ' . $this->getDescription($rule) . ' ';
+                    $parameterData['setter'] = $this->getFakeFactoryByName('uuid');
+                    break;
+                case 'regex':
+                    $parameterData['description'] .= ' ' . $this->getDescription($rule, [':regex' => $arguments[0]]);
+                    $parameterData['setter'] = fn() => $this->getFaker()->regexify($arguments[0]);;
+                    break;
+
+                /**
+                 * Special number types.
+                 */
+                case 'digits':
+                    $parameterData['description'] .= ' ' . $this->getDescription($rule, [':digits' => $arguments[0]]);
+                    $parameterData['setter'] = fn() => $this->getFaker()->numerify(str_repeat("#", $arguments[0]));
+                    $parameterData['type'] = 'string';
+                    break;
+                case 'digits_between':
+                    $parameterData['description'] .= ' ' . $this->getDescription($rule, [':min' => $arguments[0], ':max' => $arguments[1]]);
+                    $parameterData['setter'] = fn() => $this->getFaker()->numerify(str_repeat("#", rand($arguments[0], $arguments[1])));
+                    $parameterData['type'] = 'string';
+                    break;
+
+                /**
+                 * These rules can apply to numbers, strings, arrays or files
+                 */
+                case 'size':
+                    $parameterData['description'] .= ' ' . $this->getDescription(
+                            $rule, [':size' => $arguments[0]], $this->getLaravelValidationBaseTypeMapping($parameterData['type'])
+                        );
+                    $parameterData['setter'] = $this->getDummyValueGenerator($parameterData['type'], ['size' => $arguments[0]]);
+                    break;
+                case 'min':
+                    $parameterData['description'] .= ' ' . $this->getDescription(
+                            $rule, [':min' => $arguments[0]], $this->getLaravelValidationBaseTypeMapping($parameterData['type'])
+                        );
+                    $parameterData['setter'] = $this->getDummyDataGeneratorBetween($parameterData['type'], floatval($arguments[0]), fieldName: $parameterData['name']);
+                    break;
+                case 'max':
+                    $parameterData['description'] .= ' ' . $this->getDescription(
+                            $rule, [':max' => $arguments[0]], $this->getLaravelValidationBaseTypeMapping($parameterData['type'])
+                        );
+                    $max = min($arguments[0], 25);
+                    $parameterData['setter'] = $this->getDummyDataGeneratorBetween($parameterData['type'], 1, $max, $parameterData['name']);
+                    break;
+                case 'between':
+                    $parameterData['description'] .= ' ' . $this->getDescription(
+                            $rule, [':min' => $arguments[0], ':max' => $arguments[1]], $this->getLaravelValidationBaseTypeMapping($parameterData['type'])
+                        );
+                    // Avoid exponentially complex operations by using the minimum length
+                    $parameterData['setter'] = $this->getDummyDataGeneratorBetween($parameterData['type'], floatval($arguments[0]), floatval($arguments[0]) + 1, $parameterData['name']);
+                    break;
+
+                /**
+                 * Special file types.
+                 */
+                case 'image':
+                    $parameterData['type'] = 'file';
+                    $parameterData['description'] .= ' ' . $this->getDescription($rule) . ' ';
+                    $parameterData['setter'] = function () {
+                        // This is fine because the file example generator generates an image
+                        return $this->generateDummyValue('file');
+                    };
+                    break;
+
+                /**
+                 * Other rules.
+                 */
+                case 'in':
+                    // Not using the rule description here because it only says "The attribute is invalid"
+                    $parameterData['description'] .= ' Must be one of ' . w::getListOfValuesAsFriendlyHtmlString($arguments) . ' ';
+                    $parameterData['setter'] = function () use ($arguments) {
+                        return Arr::random($arguments);
+                    };
+                    break;
+
+                /**
+                 * These rules only add a description. Generating valid examples is too complex.
+                 */
+                case 'not_in':
+                    $parameterData['description'] .= ' Must not be one of ' . w::getListOfValuesAsFriendlyHtmlString($arguments) . ' ';
+                    break;
+                case 'required_if':
+                    $parameterData['description'] .= ' ' . $this->getDescription(
+                            $rule, [':other' => "<code>{$arguments[0]}</code>", ':value' => w::getListOfValuesAsFriendlyHtmlString(array_slice($arguments, 1))]
+                        ) . ' ';
+                    break;
+                case 'required_unless':
+                    $parameterData['description'] .= ' ' . $this->getDescription(
+                            $rule, [':other' => "<code>" . array_shift($arguments) . "</code>", ':values' => w::getListOfValuesAsFriendlyHtmlString($arguments)]
+                        ) . ' ';
+                    break;
+                case 'required_with':
+                    $parameterData['description'] .= ' ' . $this->getDescription(
+                            $rule, [':values' => w::getListOfValuesAsFriendlyHtmlString($arguments)]
+                        ) . ' ';
+                    break;
+                case 'required_without':
+                    $description = $this->getDescription(
+                            $rule, [':values' => w::getListOfValuesAsFriendlyHtmlString($arguments)]
+                        ) . ' ';
+                    $parameterData['description'] .= str_replace('must be present', 'is not present', $description);
+                    break;
+                case 'required_with_all':
+                case 'required_without_all':
+                    $parameterData['description'] .= ' ' . $this->getDescription(
+                            $rule, [':values' => w::getListOfValuesAsFriendlyHtmlString($arguments, "and")]
+                        ) . ' ';
+                    break;
+                case 'accepted_if':
+                    $parameterData['type'] = 'boolean';
+                    $parameterData['description'] .= " Must be accepted when <code>$arguments[0]</code> is " . w::getListOfValuesAsFriendlyHtmlString(array_slice($arguments, 1));
+                    $parameterData['setter'] = fn() => true;
+                    break;
+                case 'same':
+                case 'different':
+                    $parameterData['description'] .= ' ' . $this->getDescription(
+                            $rule, [':other' => "<code>{$arguments[0]}</code>"]
+                        ) . ' ';
+                    break;
+
+                default:
+                    // Other rules not supported
+                    break;
             }
+        } catch (Throwable $e) {
+            throw CouldntProcessValidationRule::forParam($parameterData['name'], $rule, $e);
         }
 
         return true;