Skip to content

Commit

Permalink
Improve generated types to include optional types
Browse files Browse the repository at this point in the history
  • Loading branch information
alexmccabe committed Dec 18, 2023
1 parent 7963d8d commit 71502de
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 9 deletions.
8 changes: 7 additions & 1 deletion src/Output/Types.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Tightenco\Ziggy\Output;

use Illuminate\Support\Arr;
use Str;
use Stringable;
use Tightenco\Ziggy\Ziggy;

Expand All @@ -15,13 +16,18 @@ public function __construct(Ziggy $ziggy)
$this->ziggy = $ziggy;
}

private function isParamOptional(string $uri, string $param): bool
{
return Str::contains($uri, "{$param}?");
}

public function __toString(): string
{
$routes = collect($this->ziggy->toArray()['routes'])->map(function ($route) {
return collect($route['parameters'] ?? [])->map(function ($param) use ($route) {
return Arr::has($route, "bindings.{$param}")
? ['name' => $param, 'binding' => $route['bindings'][$param]]
: ['name' => $param];
: ['name' => $param, 'optional' => $this->isParamOptional($route['uri'], $param)];
});
});

Expand Down
21 changes: 18 additions & 3 deletions src/js/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,27 @@ type HasQueryParam = { _query?: Record<string, unknown> };
*/
type GenericRouteParamsObject = Record<keyof any, unknown> & HasQueryParam;
// `keyof any` essentially makes it function as a plain `Record`

/**
* Get only params for `optional: true` or `optional: false`.
*/
type GetParamsForOptionalSwitch<I extends readonly ParameterInfo[], TOptional extends boolean> = Extract<
I[number],
{ optional: TOptional }
>;

/**
* Map our parameter info to a routable object. We call twice to handle optional and non-optional params.
*/
type MapParamsToRoutable<I extends readonly ParameterInfo[]> =
{ [T in GetParamsForOptionalSwitch<I, true> as T['name']]?: Routable<T> } &
{ [T in GetParamsForOptionalSwitch<I, false> as T['name']]: Routable<T> }

/**
* An object of parameters for a specific named route.
*/
// TODO: The keys here could be non-optional (or more detailed) if we can determine which params are required/not.
type KnownRouteParamsObject<I extends readonly ParameterInfo[]> = {
[T in I[number] as T['name']]?: Routable<T>;
type KnownRouteParamsObject<I extends readonly ParameterInfo[], MappedParams = MapParamsToRoutable<I>> = {
[K in keyof MappedParams]: MappedParams[K]
} & GenericRouteParamsObject;
// `readonly` allows TypeScript to determine the actual values of all the
// parameter names inside the array, instead of just seeing `string`.
Expand Down
6 changes: 4 additions & 2 deletions tests/Unit/CommandRouteGeneratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ public function can_generate_dts_file()
{
app('router')->get('posts', $this->noop())->name('posts.index');
app('router')->post('posts/{post}/comments', PostCommentController::class)->name('postComments.store');
app('router')->post('posts/{post}/comments{postId?}', PostCommentController::class)->name('postComments.store');
app('router')->getRoutes()->refreshNameLookups();

Artisan::call('ziggy:generate', ['--types' => true]);
Expand All @@ -165,7 +166,7 @@ public function can_generate_dts_file()
/** @test */
public function can_generate_dts_file_with_scoped_bindings()
{
if (! $this->laravelVersion(7)) {
if (!$this->laravelVersion(7)) {
$this->markTestSkipped('Requires Laravel >=7');
}

Expand Down Expand Up @@ -275,7 +276,8 @@ public function __toString(): string

class PostCommentController
{
public function __invoke($post, $comment) {
public function __invoke($post, $comment)
{
//
}
}
6 changes: 4 additions & 2 deletions tests/fixtures/ziggy-7.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ declare module 'ziggy-js' {
"posts.index": [],
"postComments.show": [
{
"name": "post"
"name": "post",
"optional": false
},
{
"name": "comment",
Expand All @@ -13,7 +14,8 @@ declare module 'ziggy-js' {
],
"postComments.store": [
{
"name": "post"
"name": "post",
"optional": false
}
]
}
Expand Down
7 changes: 6 additions & 1 deletion tests/fixtures/ziggy.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ declare module 'ziggy-js' {
"posts.index": [],
"postComments.store": [
{
"name": "post"
"name": "post",
"optional": false
},
{
"name": "postId",
"optional": true
}
]
}
Expand Down

0 comments on commit 71502de

Please sign in to comment.