Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ Feat ] Add transform option #7

Merged
merged 4 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions Docs/fileselector.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,23 @@ $file2import = fileselector(

The closure will receive the value that has been entered and may return an error message, or `null` if the validation passes.

## Transforming Input

Additionally, you may make changes to the input before it gets validated by passing a closure to the `transform` argument.

```php
$path = fileselector(
label: 'Select a file to import.',
placeholder: 'E.g. ./vendor/autoload.php',
hint: 'Input the file path.',
validate: fn (string $value) => match (true) {
!is_readable($value) => 'Cannot read the file.',
default => null,
},
transform: fn ($value) => realpath($value),
);
```

## Filtering by File Extensions

Finally, you can filter the options by passing the lists of file extensions to the parameter `extensions`.
Expand Down
1 change: 1 addition & 0 deletions playground/fileselector.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
'.json',
'.php',
],
transform: fn ($value) => realpath($value),
);

var_dump($file2import);
Expand Down
1 change: 1 addition & 0 deletions src/FileSelector.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public function __construct(
public mixed $validate = null,
public string $hint = '',
public array $extensions = [],
public ?Closure $transform = null,
) {
static::$themes['default'][static::class] = FileSelectorRenderer::class;

Expand Down
31 changes: 28 additions & 3 deletions src/PatchedPrompt.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ public static function fakeKeyPresses(array $keys, Closure $closure): void
*/
public bool|string $required;

/**
* The transformation callback.
*/
public ?Closure $transform = null;

/**
* The validator callback or rules.
*/
Expand Down Expand Up @@ -208,7 +213,7 @@ public function prompt(): mixed
throw new FormRevertedException();
}

return $this->value();
return $this->transformedValue();
}

// `null` is a valid return value for this loop
Expand Down Expand Up @@ -371,7 +376,7 @@ protected function render(): void
*/
protected function submit(): void
{
$this->validate($this->value());
$this->validate($this->transformedValue());

if ($this->state !== 'error') {
$this->state = 'submit';
Expand Down Expand Up @@ -416,12 +421,32 @@ private function handleKeyPress(string $key): bool
}

if ($this->validated) {
$this->validate($this->value());
$this->validate($this->transformedValue());
}

return true;
}

/**
* Transform the input.
*/
private function transform(mixed $value): mixed
{
if (is_null($this->transform)) {
return $value;
}

return call_user_func($this->transform, $value);
}

/**
* Get the transformed value of the prompt.
*/
protected function transformedValue(): mixed
{
return $this->transform($this->value());
}

/**
* Validate the input.
*/
Expand Down
1 change: 1 addition & 0 deletions src/TabbedScrollableSelectPrompt.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public function __construct(
public bool|string $required = true,
public mixed $validate = null,
public string $hint = '',
public ?Closure $transform = null,
) {
static::$themes['default'][static::class] = TabbedScrollableSelectRenderer::class;

Expand Down
4 changes: 2 additions & 2 deletions src/helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* @param array<int, TOption>|Collection<int, TOption> $options
* @param int|Closure(Collection<int, TOption>): Collection<int, TOption> $default The default value for the prompt. If Closure, it is passed `$options` and should return a Collection containing only the desired record.
*/
function tabbedscrollableselect(string $label, array|Collection $options, int|Closure $default = 0, int $scroll = 14, int $max_width = 120, bool|string $required = true, mixed $validate = null, string $hint = ''): int|string|null
function tabbedscrollableselect(string $label, array|Collection $options, int|Closure $default = 0, int $scroll = 14, int $max_width = 120, bool|string $required = true, mixed $validate = null, string $hint = '', ?Closure $transform = null): int|string|null
{
return (new TabbedScrollableSelectPrompt(...func_get_args()))->prompt();
}
Expand All @@ -23,7 +23,7 @@ function tabbedscrollableselect(string $label, array|Collection $options, int|Cl
*
* @param array<string> $extensions
*/
function fileselector(string $label, string $placeholder = '', string $default = '', int $scroll = 5, bool|string $required = false, mixed $validate = null, string $hint = '', array $extensions = []): string
function fileselector(string $label, string $placeholder = '', string $default = '', int $scroll = 5, bool|string $required = false, mixed $validate = null, string $hint = '', array $extensions = [], ?Closure $transform = null): string
{
return (new FileSelector(...func_get_args()))->prompt();
}
11 changes: 11 additions & 0 deletions tests/Feature/FileSelectorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,14 @@

expect($result)->toBe('./composer.json');
});

it('transforms values', function () {
Prompt::fake(['v', 'e', 'n', 'd', 'o', 'r', Key::ENTER]);

$result = fileselector(
label: 'Select a file.',
transform: fn ($value) => realpath($value),
);

expect($result)->toBe(realpath('vendor'));
});
Loading