Skip to content

Commit

Permalink
First pass: support enum in tags, attributes, and rules
Browse files Browse the repository at this point in the history
  • Loading branch information
shalvah committed Aug 20, 2023
1 parent 1f94ac5 commit d3970ae
Show file tree
Hide file tree
Showing 9 changed files with 64 additions and 13 deletions.
1 change: 1 addition & 0 deletions camel/Extraction/Parameter.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class Parameter extends BaseDTO
public bool $required = false;
public mixed $example = null;
public string $type = 'string';
public array $enumValues = [];

public function __construct(array $parameters = [])
{
Expand Down
24 changes: 24 additions & 0 deletions src/Attributes/GenericParam.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public function __construct(
public ?string $description = '',
public ?bool $required = true,
public mixed $example = null, /* Pass 'No-example' to omit the example */
public mixed $enum = null, // Can pass a list of values, or a native PHP enum
) {
}

Expand All @@ -24,6 +25,29 @@ public function toArray()
"type" => $this->type,
"required" => $this->required,
"example" => $this->example,
"enumValues" => $this->getEnumValues(),
];
}

protected function getEnumValues()
{
if (!$this->enum) {
return null;
}

if (is_array($this->enum)) {
return $this->enum;
}

if (function_exists('enum_exists') && enum_exists($this->enum)) {
return array_map(
fn ($case) => $case->value,
$this->enum::cases()
);
}

throw new \InvalidArgumentException(
'The enum property of a parameter must be either a PHP enum or an array of values'
);
}
}
18 changes: 17 additions & 1 deletion src/Extracting/ParamHelpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Faker\Factory;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;

trait ParamHelpers
Expand Down Expand Up @@ -46,6 +47,10 @@ protected function getFaker(): \Faker\Generator

protected function generateDummyValue(string $type, array $hints = [])
{
if(!empty($hints['enumValues'])) {
return Arr::random($hints['enumValues']);
}

$fakeFactory = $this->getDummyValueGenerator($type, $hints);

return $fakeFactory();
Expand Down Expand Up @@ -232,13 +237,24 @@ protected function shouldExcludeExample(string $description): bool
protected function parseExampleFromParamDescription(string $description, string $type): array
{
$example = null;
$enumValues = [];

if (preg_match('/(.*)\bExample:\s*([\s\S]+)\s*/s', $description, $content)) {
$description = trim($content[1]);

// Examples are parsed as strings by default, we need to cast them properly
$example = $this->castToType($content[2], $type);
}

return [$description, $example];
if (preg_match('/(.*)\bEnum:\s*([\s\S]+)\s*/s', $description, $content)) {
$description = trim($content[1]);

$enumValues = array_map(
fn ($value) => $this->castToType($value, $type),
explode($content[2], ',')
);
}

return [$description, $example, $enumValues];
}
}
2 changes: 2 additions & 0 deletions src/Extracting/ParsesValidationRules.php
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ protected function parseRule($rule, array &$parameterData, bool $independentOnly
if (enum_exists($type) && method_exists($type, 'tryFrom')) {
$cases = array_map(fn ($case) => $case->value, $type::cases());
$parameterData['type'] = gettype($cases[0]);
$parameterData['enumValues'] = $cases;
$parameterData['description'] .= ' Must be one of ' . w::getListOfValuesAsFriendlyHtmlString($cases) . ' ';
$parameterData['setter'] = fn () => Arr::random($cases);
}
Expand Down Expand Up @@ -464,6 +465,7 @@ protected function parseRule($rule, array &$parameterData, bool $independentOnly
* Other rules.
*/
case 'in':
$parameterData['enumValues'] = $arguments;
// 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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ public function parseTag(string $tagContent): array
}

$type = static::normalizeTypeName($type);
[$description, $example] = $this->getDescriptionAndExample($description, $type, $tagContent, $name);
[$description, $example, $enumValues] =
$this->getDescriptionAndExample($description, $type, $tagContent, $name);

return compact('name', 'type', 'description', 'required', 'example');
return compact('name', 'type', 'description', 'required', 'example', 'enumValues');
}
}
16 changes: 10 additions & 6 deletions src/Extracting/Strategies/GetFieldsFromTagStrategy.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,21 @@ public function getFromTags(array $tagsOnMethod, array $tagsOnClass = []): array

abstract protected function parseTag(string $tagContent): array;

protected function getDescriptionAndExample(string $description, string $type, string $tagContent, string $fieldName): array
protected function getDescriptionAndExample(
string $description, string $type, string $tagContent, string $fieldName
): array
{
[$description, $example] = $this->parseExampleFromParamDescription($description, $type);
$example = $this->setExampleIfNeeded($example, $type, $tagContent, $fieldName);
return [$description, $example];
[$description, $example, $enumValues] = $this->parseExampleFromParamDescription($description, $type);
$example = $this->setExampleIfNeeded($example, $type, $tagContent, $fieldName, $enumValues);
return [$description, $example, $enumValues];
}

protected function setExampleIfNeeded(mixed $currentExample, string $type, string $tagContent, string $fieldName): mixed
protected function setExampleIfNeeded(
mixed $currentExample, string $type, string $tagContent, string $fieldName, ?array $enumValues = []
): mixed
{
return (is_null($currentExample) && !$this->shouldExcludeExample($tagContent))
? $this->generateDummyValue($type, hints: ['name' => $fieldName])
? $this->generateDummyValue($type, hints: ['name' => $fieldName, 'enumValues' => $enumValues])
: $currentExample;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,9 @@ public function parseTag(string $tagContent): array

}

[$description, $example] = $this->getDescriptionAndExample($description, $type, $tagContent, $name);
[$description, $example, $enumValues] =
$this->getDescriptionAndExample($description, $type, $tagContent, $name);

return compact('name', 'description', 'required', 'example', 'type');
return compact('name', 'description', 'required', 'example', 'type', 'enumValues');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ protected function parseTag(string $tagContent): array
: static::normalizeTypeName($type);
}

[$description, $example] = $this->getDescriptionAndExample($description, $type, $tagContent, $name);
[$description, $example, $enumValues] =
$this->getDescriptionAndExample($description, $type, $tagContent, $name);

return compact('name', 'description', 'required', 'example', 'type');
return compact('name', 'description', 'required', 'example', 'type', 'enumValues');
}
}
1 change: 1 addition & 0 deletions tests/GenerateDocumentation/OutputTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,7 @@ public function will_not_overwrite_manually_modified_content_unless_force_flag_i
'required' => true,
'example' => 6,
'type' => 'integer',
'enumValues' => [],
'custom' => [],
];
$group['endpoints'][0]['urlParameters']['a_param'] = $extraParam;
Expand Down

0 comments on commit d3970ae

Please sign in to comment.