From edd70e135ffb66afcfc1bea86f671f02aeef4830 Mon Sep 17 00:00:00 2001 From: Pushpak Chhajed Date: Thu, 30 Oct 2025 20:25:24 +0530 Subject: [PATCH 1/7] Add Wayfinder package support and guidelines Signed-off-by: Pushpak Chhajed --- .ai/wayfinder/core.blade.php | 70 +++++++++++++++ all.php | 1 + .../Feature/Install/GuidelineComposerTest.php | 88 +++++++++++++++++++ 3 files changed, 159 insertions(+) create mode 100644 .ai/wayfinder/core.blade.php diff --git a/.ai/wayfinder/core.blade.php b/.ai/wayfinder/core.blade.php new file mode 100644 index 00000000..da080ba1 --- /dev/null +++ b/.ai/wayfinder/core.blade.php @@ -0,0 +1,70 @@ +@php +/** @var \Laravel\Boost\Install\GuidelineAssist $assist */ +@endphp +## Laravel Wayfinder + +Generates fully-typed TypeScript functions for Laravel controllers and routes. Import endpoints as functions—never hardcode URLs. Provides type safety and automatic synchronization between backend routes and frontend code. + +### Setup + +- Run `php artisan wayfinder:generate`, install `npm i -D @laravel/vite-plugin-wayfinder`, add `wayfinder()` to `vite.config.js`. +- Add `wayfinder/`, `actions/`, `routes/` to `.gitignore`. + +### Development Guidelines + +- **Always use `search-docs`** before implementing any Wayfinder features +- Prefer named imports for tree-shaking (e.g., `import { show } from '@/actions/...'`) +- Avoid default controller imports (prevents tree-shaking) +- Run `wayfinder:generate` after route changes if Vite plugin isn't installed + +**Features:** + +- **Route Objects**: Functions return `{ url, method }` objects — `show(1)` → `{ url: "/posts/1", method: "get" }` +- **URL Extraction**: Use `.url()` to get URL string — `show.url(1)` → `"/posts/1"` +- **HTTP Methods**: Call `.get()`, `.post()`, `.patch()`, `.put()`, `.delete()` for specific methods — `show.head(1)` → `{ url: "/posts/1", method: "head" }` +- **Parameter Binding**: Detects route keys (e.g., `{post:slug}`) and accepts matching object properties — `show("my-post")` or `show({ slug: "my-post" })` +- **Invokable Controllers**: Import and invoke directly as functions — `import StorePost from '@/actions/.../StorePostController'; StorePost()` +- **Named Routes**: Import from `@/routes/` for non-controller routes — `import { show } from '@/routes/post'; show(1)` for route name `post.show` +- **Form Support**: Use `.form()` with `--with-form` flag for HTML form attributes — `
` → `action="/posts" method="post"` +- **Query Parameters**: Pass `{ query: {...} }` in options to append params — `show(1, { query: { page: 1 } })` → `"/posts/1?page=1"` +- **Query Merging**: Use `mergeQuery` to merge with `window.location.search`, set values to `null` to remove — `show(1, { mergeQuery: { page: 2, sort: null } })` + +**Basic Usage:** +@verbatim + + // Import controller methods (tree-shakable) + import { show, store, update } from '@/actions/App/Http/Controllers/PostController' + + // Get route object with URL and method + show(1) // { url: "/posts/1", method: "get" } + + // Get just the URL + show.url(1) // "/posts/1" + + // Use specific HTTP methods + show.get(1) // { url: "/posts/1", method: "get" } + show.head(1) // { url: "/posts/1", method: "head" } + + // Import named routes + import { show as postShow } from '@/routes/post' // For route name 'post.show' + postShow(1) // { url: "/posts/1", method: "get" } + +@endverbatim + +@if($assist->roster->uses(\Laravel\Roster\Enums\Packages::INERTIA_LARAVEL) || $assist->roster->uses(\Laravel\Roster\Enums\Packages::INERTIA_REACT) || $assist->roster->uses(\Laravel\Roster\Enums\Packages::INERTIA_VUE) || $assist->roster->uses(\Laravel\Roster\Enums\Packages::INERTIA_SVELTE)) +### Wayfinder + Inertia +@if($assist->inertia()->hasFormComponent()) +If your application uses the `` component, you can use Wayfinder to generate form attributes automatically. + @if($assist->roster->uses(\Laravel\Roster\Enums\Packages::INERTIA_REACT)) + @boostsnippet("Wayfinder Form Component (React)", "typescript") +
+ @endboostsnippet + @endif + @if($assist->roster->uses(\Laravel\Roster\Enums\Packages::INERTIA_VUE)) + @boostsnippet("Wayfinder Form Component (Vue)", "vue") +
+ @endboostsnippet + @endif +@endif +@endif + diff --git a/all.php b/all.php index 1d5f4043..0469f1a9 100644 --- a/all.php +++ b/all.php @@ -54,6 +54,7 @@ public function packages(): \Laravel\Roster\PackageCollection 'folio' => \Laravel\Roster\Enums\Packages::FOLIO, 'pennant' => \Laravel\Roster\Enums\Packages::PENNANT, 'tailwindcss' => \Laravel\Roster\Enums\Packages::TAILWINDCSS, + 'wayfinder' => \Laravel\Roster\Enums\Packages::WAYFINDER, ]; if (isset($enumMapping[$packageName])) { diff --git a/tests/Feature/Install/GuidelineComposerTest.php b/tests/Feature/Install/GuidelineComposerTest.php index 44639c27..d3e22a28 100644 --- a/tests/Feature/Install/GuidelineComposerTest.php +++ b/tests/Feature/Install/GuidelineComposerTest.php @@ -426,3 +426,91 @@ ->toContain('Run `npm install` to install dependencies') ->toContain('Package manager: npm'); }); + +test('includes wayfinder guidelines with inertia integration when both packages are present', function (): void { + $packages = new PackageCollection([ + new Package(Packages::LARAVEL, 'laravel/framework', '11.0.0'), + new Package(Packages::WAYFINDER, 'laravel/wayfinder', '1.0.0'), + new Package(Packages::INERTIA_REACT, 'inertiajs/inertia-react', '2.1.2'), + new Package(Packages::INERTIA_LARAVEL, 'inertiajs/inertia-laravel', '2.1.2'), + ]); + + $this->roster->shouldReceive('packages')->andReturn($packages); + + $this->roster->shouldReceive('uses')->with(Packages::INERTIA_LARAVEL)->andReturn(true); + $this->roster->shouldReceive('uses')->with(Packages::INERTIA_REACT)->andReturn(true); + $this->roster->shouldReceive('uses')->with(Packages::INERTIA_VUE)->andReturn(false); + $this->roster->shouldReceive('uses')->with(Packages::INERTIA_SVELTE)->andReturn(false); + + $this->roster->shouldReceive('usesVersion') + ->with(Packages::INERTIA_LARAVEL, '2.1.0', '>=') + ->andReturn(true); + $this->roster->shouldReceive('usesVersion') + ->with(Packages::INERTIA_REACT, '2.1.0', '>=') + ->andReturn(true); + $this->roster->shouldReceive('usesVersion') + ->with(Packages::INERTIA_VUE, '2.1.0', '>=') + ->andReturn(false); + $this->roster->shouldReceive('usesVersion') + ->with(Packages::INERTIA_SVELTE, '2.1.0', '>=') + ->andReturn(false); + + $this->roster->shouldReceive('usesVersion') + ->with(Packages::INERTIA_LARAVEL, '2.1.2', '>=') + ->andReturn(true); + $this->roster->shouldReceive('usesVersion') + ->with(Packages::INERTIA_REACT, '2.1.2', '>=') + ->andReturn(true); + $this->roster->shouldReceive('usesVersion') + ->with(Packages::INERTIA_VUE, '2.1.2', '>=') + ->andReturn(false); + $this->roster->shouldReceive('usesVersion') + ->with(Packages::INERTIA_SVELTE, '2.1.2', '>=') + ->andReturn(false); + + $guidelines = $this->composer->compose(); + + expect($guidelines) + ->toContain('=== wayfinder/core rules ===') + ->toContain('Wayfinder + Inertia') + ->toContain('Wayfinder Form Component (React)') + ->toContain('
') + ->toContain('## Laravel Wayfinder'); +}); + +test('includes wayfinder guidelines without inertia integration when inertia is not present', function (): void { + $packages = new PackageCollection([ + new Package(Packages::LARAVEL, 'laravel/framework', '11.0.0'), + new Package(Packages::WAYFINDER, 'laravel/wayfinder', '1.0.0'), + ]); + + $this->roster->shouldReceive('packages')->andReturn($packages); + + $this->roster->shouldReceive('uses')->with(Packages::INERTIA_LARAVEL)->andReturn(false); + $this->roster->shouldReceive('uses')->with(Packages::INERTIA_REACT)->andReturn(false); + $this->roster->shouldReceive('uses')->with(Packages::INERTIA_VUE)->andReturn(false); + $this->roster->shouldReceive('uses')->with(Packages::INERTIA_SVELTE)->andReturn(false); + + $this->roster->shouldReceive('usesVersion') + ->with(Packages::INERTIA_LARAVEL, Mockery::any(), '>=') + ->andReturn(false); + $this->roster->shouldReceive('usesVersion') + ->with(Packages::INERTIA_REACT, Mockery::any(), '>=') + ->andReturn(false); + $this->roster->shouldReceive('usesVersion') + ->with(Packages::INERTIA_VUE, Mockery::any(), '>=') + ->andReturn(false); + $this->roster->shouldReceive('usesVersion') + ->with(Packages::INERTIA_SVELTE, Mockery::any(), '>=') + ->andReturn(false); + + $guidelines = $this->composer->compose(); + + expect($guidelines) + ->toContain('=== wayfinder/core rules ===') + ->toContain('## Laravel Wayfinder') + ->toContain('import { show } from \'@/actions/') + ->not->toContain('Wayfinder + Inertia') + ->not->toContain('Wayfinder Form Component'); +}); + From a428558c2ebce8df945643e67d6b8fe1cb4df9f1 Mon Sep 17 00:00:00 2001 From: pushpak1300 <31663512+pushpak1300@users.noreply.github.com> Date: Thu, 30 Oct 2025 14:55:52 +0000 Subject: [PATCH 2/7] Fix code styling --- tests/Feature/Install/GuidelineComposerTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Feature/Install/GuidelineComposerTest.php b/tests/Feature/Install/GuidelineComposerTest.php index d3e22a28..87c2c77b 100644 --- a/tests/Feature/Install/GuidelineComposerTest.php +++ b/tests/Feature/Install/GuidelineComposerTest.php @@ -513,4 +513,3 @@ ->not->toContain('Wayfinder + Inertia') ->not->toContain('Wayfinder Form Component'); }); - From 67fded98db9ce33ddcbedf39abbb7d258bff3b18 Mon Sep 17 00:00:00 2001 From: Pushpak Chhajed Date: Fri, 31 Oct 2025 18:13:23 +0530 Subject: [PATCH 3/7] Update core.blade.php Signed-off-by: Pushpak Chhajed --- .ai/wayfinder/core.blade.php | 95 ++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 42 deletions(-) diff --git a/.ai/wayfinder/core.blade.php b/.ai/wayfinder/core.blade.php index da080ba1..3163a670 100644 --- a/.ai/wayfinder/core.blade.php +++ b/.ai/wayfinder/core.blade.php @@ -3,68 +3,79 @@ @endphp ## Laravel Wayfinder -Generates fully-typed TypeScript functions for Laravel controllers and routes. Import endpoints as functions—never hardcode URLs. Provides type safety and automatic synchronization between backend routes and frontend code. - -### Setup - -- Run `php artisan wayfinder:generate`, install `npm i -D @laravel/vite-plugin-wayfinder`, add `wayfinder()` to `vite.config.js`. -- Add `wayfinder/`, `actions/`, `routes/` to `.gitignore`. +Wayfinder Generates fully-typed TypeScript functions for Laravel controllers and routes which you can import endpoints as functions and types. It Provides type safety and automatic synchronization between backend routes and frontend code. ### Development Guidelines -- **Always use `search-docs`** before implementing any Wayfinder features -- Prefer named imports for tree-shaking (e.g., `import { show } from '@/actions/...'`) +- Always use `search-docs` to check wayfinder correct usage before implementing any features. +- Always Prefer named imports for tree-shaking (e.g., `import { show } from '@/actions/...'`) - Avoid default controller imports (prevents tree-shaking) - Run `wayfinder:generate` after route changes if Vite plugin isn't installed **Features:** -- **Route Objects**: Functions return `{ url, method }` objects — `show(1)` → `{ url: "/posts/1", method: "get" }` -- **URL Extraction**: Use `.url()` to get URL string — `show.url(1)` → `"/posts/1"` -- **HTTP Methods**: Call `.get()`, `.post()`, `.patch()`, `.put()`, `.delete()` for specific methods — `show.head(1)` → `{ url: "/posts/1", method: "head" }` -- **Parameter Binding**: Detects route keys (e.g., `{post:slug}`) and accepts matching object properties — `show("my-post")` or `show({ slug: "my-post" })` -- **Invokable Controllers**: Import and invoke directly as functions — `import StorePost from '@/actions/.../StorePostController'; StorePost()` -- **Named Routes**: Import from `@/routes/` for non-controller routes — `import { show } from '@/routes/post'; show(1)` for route name `post.show` -- **Form Support**: Use `.form()` with `--with-form` flag for HTML form attributes — `` → `action="/posts" method="post"` -- **Query Parameters**: Pass `{ query: {...} }` in options to append params — `show(1, { query: { page: 1 } })` → `"/posts/1?page=1"` -- **Query Merging**: Use `mergeQuery` to merge with `window.location.search`, set values to `null` to remove — `show(1, { mergeQuery: { page: 2, sort: null } })` +- Route Objects: Functions return `{ url, method }` objects — `show(1)` → `{ url: "/posts/1", method: "get" }` +- URL Extraction: Use `.url()` to get URL string — `show.url(1)` → `"/posts/1"` +- HTTP Methods: Call `.get()`, `.post()`, `.patch()`, `.put()`, `.delete()` for specific methods — `show.head(1)` → `{ url: "/posts/1", method: "head" }` +- Parameter Binding: Detects route keys (e.g., `{post:slug}`) and accepts matching object properties — `show("my-post")` or `show({ slug: "my-post" })` +- Invokable Controllers: Import and invoke directly as functions. eg `import StorePost from '@/actions/.../StorePostController'; StorePost()` +- Named Routes: Import from `@/routes/` for non-controller routes.eg `import { show } from '@/routes/post'; show(1)` for route name `post.show` +- Form Support: Use `.form()` with `--with-form` flag for HTML form attributes — `` → `action="/posts" method="post"` +- Query Parameters: Pass `{ query: {...} }` in options to append params — `show(1, { query: { page: 1 } })` → `"/posts/1?page=1"` +- Query Merging: Use `mergeQuery` to merge with `window.location.search`, set values to `null` to remove — `show(1, { mergeQuery: { page: 2, sort: null } })` **Basic Usage:** @verbatim - - // Import controller methods (tree-shakable) - import { show, store, update } from '@/actions/App/Http/Controllers/PostController' + + // Import controller methods (tree-shakable) + import { show, store, update } from '@/actions/App/Http/Controllers/PostController' - // Get route object with URL and method - show(1) // { url: "/posts/1", method: "get" } + // Get route object with URL and method + show(1) // { url: "/posts/1", method: "get" } - // Get just the URL - show.url(1) // "/posts/1" + // Get just the URL + show.url(1) // "/posts/1" - // Use specific HTTP methods - show.get(1) // { url: "/posts/1", method: "get" } - show.head(1) // { url: "/posts/1", method: "head" } + // Use specific HTTP methods + show.get(1) // { url: "/posts/1", method: "get" } + show.head(1) // { url: "/posts/1", method: "head" } - // Import named routes - import { show as postShow } from '@/routes/post' // For route name 'post.show' - postShow(1) // { url: "/posts/1", method: "get" } - + // Import named routes + import { show as postShow } from '@/routes/post' // For route name 'post.show' + postShow(1) // { url: "/posts/1", method: "get" } + @endverbatim @if($assist->roster->uses(\Laravel\Roster\Enums\Packages::INERTIA_LARAVEL) || $assist->roster->uses(\Laravel\Roster\Enums\Packages::INERTIA_REACT) || $assist->roster->uses(\Laravel\Roster\Enums\Packages::INERTIA_VUE) || $assist->roster->uses(\Laravel\Roster\Enums\Packages::INERTIA_SVELTE)) ### Wayfinder + Inertia @if($assist->inertia()->hasFormComponent()) -If your application uses the `` component, you can use Wayfinder to generate form attributes automatically. - @if($assist->roster->uses(\Laravel\Roster\Enums\Packages::INERTIA_REACT)) - @boostsnippet("Wayfinder Form Component (React)", "typescript") - - @endboostsnippet - @endif - @if($assist->roster->uses(\Laravel\Roster\Enums\Packages::INERTIA_VUE)) - @boostsnippet("Wayfinder Form Component (Vue)", "vue") -
- @endboostsnippet - @endif +If your application uses the `
` component from Inertia, you can use Wayfinder to generate form action and method automatically. +@if($assist->roster->uses(\Laravel\Roster\Enums\Packages::INERTIA_REACT)) +@boostsnippet("Wayfinder Form Component (React)", "typescript") +
+@endboostsnippet +@endif +@if($assist->roster->uses(\Laravel\Roster\Enums\Packages::INERTIA_VUE)) +@boostsnippet("Wayfinder Form Component (Vue)", "vue") +
+@endboostsnippet +@endif +@if($assist->roster->uses(\Laravel\Roster\Enums\Packages::INERTIA_SVELTE)) +@boostsnippet("Wayfinder Form Component (Svelte)", "svelte") +
+@endboostsnippet +@endif +@else +If your application uses the `useForm` component from Inertia, you can directly submit to the wayfinder generated functions. + + import { store } from "@/actions/App/Http/Controllers/ExampleController"; + + const form = useForm({ + name: "My Big Post", + }); + + form.submit(store()); + @endif @endif From ecb46479f65ec90f134321eb093bbc1eee0721f5 Mon Sep 17 00:00:00 2001 From: Pushpak Chhajed Date: Fri, 31 Oct 2025 18:22:03 +0530 Subject: [PATCH 4/7] Update tests Signed-off-by: Pushpak Chhajed --- .../Feature/Install/GuidelineComposerTest.php | 82 ++++++++++++++++--- 1 file changed, 72 insertions(+), 10 deletions(-) diff --git a/tests/Feature/Install/GuidelineComposerTest.php b/tests/Feature/Install/GuidelineComposerTest.php index 87c2c77b..5d69a87d 100644 --- a/tests/Feature/Install/GuidelineComposerTest.php +++ b/tests/Feature/Install/GuidelineComposerTest.php @@ -23,7 +23,6 @@ $this->herd = Mockery::mock(Herd::class); $this->herd->shouldReceive('isInstalled')->andReturn(false)->byDefault(); - // Bind the mock to the service container so it's used everywhere $this->app->instance(Roster::class, $this->roster); $this->composer = new GuidelineComposer($this->roster, $this->herd); @@ -443,37 +442,100 @@ $this->roster->shouldReceive('uses')->with(Packages::INERTIA_SVELTE)->andReturn(false); $this->roster->shouldReceive('usesVersion') - ->with(Packages::INERTIA_LARAVEL, '2.1.0', '>=') + ->with(Packages::INERTIA_LARAVEL, Mockery::any(), '>=') ->andReturn(true); $this->roster->shouldReceive('usesVersion') - ->with(Packages::INERTIA_REACT, '2.1.0', '>=') + ->with(Packages::INERTIA_REACT, Mockery::any(), '>=') ->andReturn(true); $this->roster->shouldReceive('usesVersion') - ->with(Packages::INERTIA_VUE, '2.1.0', '>=') + ->with(Packages::INERTIA_VUE, Mockery::any(), '>=') ->andReturn(false); $this->roster->shouldReceive('usesVersion') - ->with(Packages::INERTIA_SVELTE, '2.1.0', '>=') + ->with(Packages::INERTIA_SVELTE, Mockery::any(), '>=') ->andReturn(false); + $guidelines = $this->composer->compose(); + + expect($guidelines) + ->toContain('=== wayfinder/core rules ===') + ->toContain('Wayfinder + Inertia') + ->toContain('Wayfinder Form Component (React)') + ->toContain('
') + ->toContain('## Laravel Wayfinder'); +}); + +test('includes wayfinder guidelines with inertia vue integration', function (): void { + $packages = new PackageCollection([ + new Package(Packages::LARAVEL, 'laravel/framework', '11.0.0'), + new Package(Packages::WAYFINDER, 'laravel/wayfinder', '1.0.0'), + new Package(Packages::INERTIA_VUE, 'inertiajs/inertia-vue', '2.1.2'), + new Package(Packages::INERTIA_LARAVEL, 'inertiajs/inertia-laravel', '2.1.2'), + ]); + + $this->roster->shouldReceive('packages')->andReturn($packages); + + $this->roster->shouldReceive('uses')->with(Packages::INERTIA_LARAVEL)->andReturn(true); + $this->roster->shouldReceive('uses')->with(Packages::INERTIA_REACT)->andReturn(false); + $this->roster->shouldReceive('uses')->with(Packages::INERTIA_VUE)->andReturn(true); + $this->roster->shouldReceive('uses')->with(Packages::INERTIA_SVELTE)->andReturn(false); + $this->roster->shouldReceive('usesVersion') - ->with(Packages::INERTIA_LARAVEL, '2.1.2', '>=') + ->with(Packages::INERTIA_LARAVEL, Mockery::any(), '>=') ->andReturn(true); $this->roster->shouldReceive('usesVersion') - ->with(Packages::INERTIA_REACT, '2.1.2', '>=') + ->with(Packages::INERTIA_REACT, Mockery::any(), '>=') + ->andReturn(false); + $this->roster->shouldReceive('usesVersion') + ->with(Packages::INERTIA_VUE, Mockery::any(), '>=') ->andReturn(true); $this->roster->shouldReceive('usesVersion') - ->with(Packages::INERTIA_VUE, '2.1.2', '>=') + ->with(Packages::INERTIA_SVELTE, Mockery::any(), '>=') + ->andReturn(false); + + $guidelines = $this->composer->compose(); + + expect($guidelines) + ->toContain('=== wayfinder/core rules ===') + ->toContain('Wayfinder + Inertia') + ->toContain('Wayfinder Form Component (Vue)') + ->toContain('') + ->toContain('## Laravel Wayfinder'); +}); + +test('includes wayfinder guidelines with inertia svelte integration', function (): void { + $packages = new PackageCollection([ + new Package(Packages::LARAVEL, 'laravel/framework', '11.0.0'), + new Package(Packages::WAYFINDER, 'laravel/wayfinder', '1.0.0'), + new Package(Packages::INERTIA_SVELTE, 'inertiajs/inertia-svelte', '2.1.2'), + new Package(Packages::INERTIA_LARAVEL, 'inertiajs/inertia-laravel', '2.1.2'), + ]); + + $this->roster->shouldReceive('packages')->andReturn($packages); + + $this->roster->shouldReceive('uses')->with(Packages::INERTIA_LARAVEL)->andReturn(true); + $this->roster->shouldReceive('uses')->with(Packages::INERTIA_REACT)->andReturn(false); + $this->roster->shouldReceive('uses')->with(Packages::INERTIA_VUE)->andReturn(false); + $this->roster->shouldReceive('uses')->with(Packages::INERTIA_SVELTE)->andReturn(true); + + $this->roster->shouldReceive('usesVersion') + ->with(Packages::INERTIA_LARAVEL, Mockery::any(), '>=') + ->andReturn(true); + $this->roster->shouldReceive('usesVersion') + ->with(Packages::INERTIA_REACT, Mockery::any(), '>=') ->andReturn(false); $this->roster->shouldReceive('usesVersion') - ->with(Packages::INERTIA_SVELTE, '2.1.2', '>=') + ->with(Packages::INERTIA_VUE, Mockery::any(), '>=') ->andReturn(false); + $this->roster->shouldReceive('usesVersion') + ->with(Packages::INERTIA_SVELTE, Mockery::any(), '>=') + ->andReturn(true); $guidelines = $this->composer->compose(); expect($guidelines) ->toContain('=== wayfinder/core rules ===') ->toContain('Wayfinder + Inertia') - ->toContain('Wayfinder Form Component (React)') + ->toContain('Wayfinder Form Component (Svelte)') ->toContain('') ->toContain('## Laravel Wayfinder'); }); From 96d32f1e73d633421b35954cdfd81040eafed7d7 Mon Sep 17 00:00:00 2001 From: Pushpak Chhajed Date: Fri, 31 Oct 2025 18:29:01 +0530 Subject: [PATCH 5/7] Update Test Signed-off-by: Pushpak Chhajed --- tests/Feature/Install/GuidelineComposerTest.php | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tests/Feature/Install/GuidelineComposerTest.php b/tests/Feature/Install/GuidelineComposerTest.php index 5d69a87d..84e1e95e 100644 --- a/tests/Feature/Install/GuidelineComposerTest.php +++ b/tests/Feature/Install/GuidelineComposerTest.php @@ -36,7 +36,6 @@ ]); $this->roster->shouldReceive('packages')->andReturn($packages); - // Mock all Inertia package version checks $this->roster->shouldReceive('usesVersion') ->with(Packages::INERTIA_LARAVEL, '2.1.0', '>=') ->andReturn($shouldIncludeForm); @@ -461,7 +460,10 @@ ->toContain('Wayfinder + Inertia') ->toContain('Wayfinder Form Component (React)') ->toContain('') - ->toContain('## Laravel Wayfinder'); + ->toContain('## Laravel Wayfinder') + ->not->toContain('Wayfinder Form Component (Vue)') + ->not->toContain('Wayfinder Form Component (Svelte)') + ->not->toContain(''); }); test('includes wayfinder guidelines with inertia vue integration', function (): void { @@ -499,7 +501,9 @@ ->toContain('Wayfinder + Inertia') ->toContain('Wayfinder Form Component (Vue)') ->toContain('') - ->toContain('## Laravel Wayfinder'); + ->toContain('## Laravel Wayfinder') + ->not->toContain('Wayfinder Form Component (React)') + ->not->toContain('Wayfinder Form Component (Svelte)'); }); test('includes wayfinder guidelines with inertia svelte integration', function (): void { @@ -537,7 +541,10 @@ ->toContain('Wayfinder + Inertia') ->toContain('Wayfinder Form Component (Svelte)') ->toContain('') - ->toContain('## Laravel Wayfinder'); + ->toContain('## Laravel Wayfinder') + ->not->toContain('Wayfinder Form Component (React)') + ->not->toContain('Wayfinder Form Component (Vue)') + ->not->toContain(''); }); test('includes wayfinder guidelines without inertia integration when inertia is not present', function (): void { From 8e2836d0281d96b97f43f123b52ed5c0dbfd281a Mon Sep 17 00:00:00 2001 From: Joe Tannenbaum Date: Fri, 31 Oct 2025 09:23:28 -0400 Subject: [PATCH 6/7] Update core.blade.php --- .ai/wayfinder/core.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ai/wayfinder/core.blade.php b/.ai/wayfinder/core.blade.php index 3163a670..9ae7b1f9 100644 --- a/.ai/wayfinder/core.blade.php +++ b/.ai/wayfinder/core.blade.php @@ -3,7 +3,7 @@ @endphp ## Laravel Wayfinder -Wayfinder Generates fully-typed TypeScript functions for Laravel controllers and routes which you can import endpoints as functions and types. It Provides type safety and automatic synchronization between backend routes and frontend code. +Wayfinder generates TypeScript functions and types for Laravel controllers and routes which you can import into your client side code. It provides type safety and automatic synchronization between backend routes and frontend code. ### Development Guidelines From fbc3de97592b7de92c3af4fe6ad5b3c438983474 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Wed, 5 Nov 2025 15:38:45 -0600 Subject: [PATCH 7/7] Update core.blade.php --- .ai/wayfinder/core.blade.php | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/.ai/wayfinder/core.blade.php b/.ai/wayfinder/core.blade.php index 9ae7b1f9..da8c4292 100644 --- a/.ai/wayfinder/core.blade.php +++ b/.ai/wayfinder/core.blade.php @@ -6,41 +6,39 @@ Wayfinder generates TypeScript functions and types for Laravel controllers and routes which you can import into your client side code. It provides type safety and automatic synchronization between backend routes and frontend code. ### Development Guidelines - - Always use `search-docs` to check wayfinder correct usage before implementing any features. - Always Prefer named imports for tree-shaking (e.g., `import { show } from '@/actions/...'`) - Avoid default controller imports (prevents tree-shaking) - Run `wayfinder:generate` after route changes if Vite plugin isn't installed -**Features:** - -- Route Objects: Functions return `{ url, method }` objects — `show(1)` → `{ url: "/posts/1", method: "get" }` -- URL Extraction: Use `.url()` to get URL string — `show.url(1)` → `"/posts/1"` +### Feature Overview +- Form Support: Use `.form()` with `--with-form` flag for HTML form attributes — `` → `action="/posts" method="post"` - HTTP Methods: Call `.get()`, `.post()`, `.patch()`, `.put()`, `.delete()` for specific methods — `show.head(1)` → `{ url: "/posts/1", method: "head" }` +- Invokable Controllers: Import and invoke directly as functions. For example, `import StorePost from '@/actions/.../StorePostController'; StorePost()` +- Named Routes: Import from `@/routes/` for non-controller routes. For example, `import { show } from '@/routes/post'; show(1)` for route name `post.show` - Parameter Binding: Detects route keys (e.g., `{post:slug}`) and accepts matching object properties — `show("my-post")` or `show({ slug: "my-post" })` -- Invokable Controllers: Import and invoke directly as functions. eg `import StorePost from '@/actions/.../StorePostController'; StorePost()` -- Named Routes: Import from `@/routes/` for non-controller routes.eg `import { show } from '@/routes/post'; show(1)` for route name `post.show` -- Form Support: Use `.form()` with `--with-form` flag for HTML form attributes — `` → `action="/posts" method="post"` -- Query Parameters: Pass `{ query: {...} }` in options to append params — `show(1, { query: { page: 1 } })` → `"/posts/1?page=1"` - Query Merging: Use `mergeQuery` to merge with `window.location.search`, set values to `null` to remove — `show(1, { mergeQuery: { page: 2, sort: null } })` +- Query Parameters: Pass `{ query: {...} }` in options to append params — `show(1, { query: { page: 1 } })` → `"/posts/1?page=1"` +- Route Objects: Functions return `{ url, method }` shaped objects — `show(1)` → `{ url: "/posts/1", method: "get" }` +- URL Extraction: Use `.url()` to get URL string — `show.url(1)` → `"/posts/1"` -**Basic Usage:** +### Example Usage @verbatim - + // Import controller methods (tree-shakable) import { show, store, update } from '@/actions/App/Http/Controllers/PostController' - // Get route object with URL and method + // Get route object with URL and method... show(1) // { url: "/posts/1", method: "get" } - // Get just the URL + // Get just the URL... show.url(1) // "/posts/1" - // Use specific HTTP methods + // Use specific HTTP methods... show.get(1) // { url: "/posts/1", method: "get" } show.head(1) // { url: "/posts/1", method: "head" } - // Import named routes + // Import named routes... import { show as postShow } from '@/routes/post' // For route name 'post.show' postShow(1) // { url: "/posts/1", method: "get" } @@ -67,7 +65,8 @@ @endif @else If your application uses the `useForm` component from Inertia, you can directly submit to the wayfinder generated functions. - + + import { store } from "@/actions/App/Http/Controllers/ExampleController"; const form = useForm({ @@ -78,4 +77,3 @@ @endif @endif -