mirror of
https://github.com/usetrmnl/byos_laravel.git
synced 2026-01-13 15:07:49 +00:00
This commit is contained in:
parent
4de32e9d47
commit
5abc452770
8 changed files with 109 additions and 2440 deletions
|
|
@ -1,11 +0,0 @@
|
||||||
{
|
|
||||||
"mcpServers": {
|
|
||||||
"laravel-boost": {
|
|
||||||
"command": "php",
|
|
||||||
"args": [
|
|
||||||
"artisan",
|
|
||||||
"boost:mcp"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,581 +0,0 @@
|
||||||
---
|
|
||||||
alwaysApply: true
|
|
||||||
---
|
|
||||||
<laravel-boost-guidelines>
|
|
||||||
=== foundation rules ===
|
|
||||||
|
|
||||||
# Laravel Boost Guidelines
|
|
||||||
|
|
||||||
The Laravel Boost guidelines are specifically curated by Laravel maintainers for this application. These guidelines should be followed closely to enhance the user's satisfaction building Laravel applications.
|
|
||||||
|
|
||||||
## Foundational Context
|
|
||||||
This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions.
|
|
||||||
|
|
||||||
- php - 8.4.13
|
|
||||||
- laravel/framework (LARAVEL) - v12
|
|
||||||
- laravel/prompts (PROMPTS) - v0
|
|
||||||
- laravel/sanctum (SANCTUM) - v4
|
|
||||||
- laravel/socialite (SOCIALITE) - v5
|
|
||||||
- livewire/flux (FLUXUI_FREE) - v2
|
|
||||||
- livewire/livewire (LIVEWIRE) - v3
|
|
||||||
- livewire/volt (VOLT) - v1
|
|
||||||
- larastan/larastan (LARASTAN) - v3
|
|
||||||
- laravel/mcp (MCP) - v0
|
|
||||||
- laravel/pint (PINT) - v1
|
|
||||||
- laravel/sail (SAIL) - v1
|
|
||||||
- pestphp/pest (PEST) - v4
|
|
||||||
- phpunit/phpunit (PHPUNIT) - v12
|
|
||||||
- rector/rector (RECTOR) - v2
|
|
||||||
- tailwindcss (TAILWINDCSS) - v4
|
|
||||||
|
|
||||||
|
|
||||||
## Conventions
|
|
||||||
- You must follow all existing code conventions used in this application. When creating or editing a file, check sibling files for the correct structure, approach, naming.
|
|
||||||
- Use descriptive names for variables and methods. For example, `isRegisteredForDiscounts`, not `discount()`.
|
|
||||||
- Check for existing components to reuse before writing a new one.
|
|
||||||
|
|
||||||
## Verification Scripts
|
|
||||||
- Do not create verification scripts or tinker when tests cover that functionality and prove it works. Unit and feature tests are more important.
|
|
||||||
|
|
||||||
## Application Structure & Architecture
|
|
||||||
- Stick to existing directory structure - don't create new base folders without approval.
|
|
||||||
- Do not change the application's dependencies without approval.
|
|
||||||
|
|
||||||
## Frontend Bundling
|
|
||||||
- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run `npm run build`, `npm run dev`, or `composer run dev`. Ask them.
|
|
||||||
|
|
||||||
## Replies
|
|
||||||
- Be concise in your explanations - focus on what's important rather than explaining obvious details.
|
|
||||||
|
|
||||||
## Documentation Files
|
|
||||||
- You must only create documentation files if explicitly requested by the user.
|
|
||||||
|
|
||||||
|
|
||||||
=== boost rules ===
|
|
||||||
|
|
||||||
## Laravel Boost
|
|
||||||
- Laravel Boost is an MCP server that comes with powerful tools designed specifically for this application. Use them.
|
|
||||||
|
|
||||||
## Artisan
|
|
||||||
- Use the `list-artisan-commands` tool when you need to call an Artisan command to double check the available parameters.
|
|
||||||
|
|
||||||
## URLs
|
|
||||||
- Whenever you share a project URL with the user you should use the `get-absolute-url` tool to ensure you're using the correct scheme, domain / IP, and port.
|
|
||||||
|
|
||||||
## Tinker / Debugging
|
|
||||||
- You should use the `tinker` tool when you need to execute PHP to debug code or query Eloquent models directly.
|
|
||||||
- Use the `database-query` tool when you only need to read from the database.
|
|
||||||
|
|
||||||
## Reading Browser Logs With the `browser-logs` Tool
|
|
||||||
- You can read browser logs, errors, and exceptions using the `browser-logs` tool from Boost.
|
|
||||||
- Only recent browser logs will be useful - ignore old logs.
|
|
||||||
|
|
||||||
## Searching Documentation (Critically Important)
|
|
||||||
- Boost comes with a powerful `search-docs` tool you should use before any other approaches. This tool automatically passes a list of installed packages and their versions to the remote Boost API, so it returns only version-specific documentation specific for the user's circumstance. You should pass an array of packages to filter on if you know you need docs for particular packages.
|
|
||||||
- The 'search-docs' tool is perfect for all Laravel related packages, including Laravel, Inertia, Livewire, Filament, Tailwind, Pest, Nova, Nightwatch, etc.
|
|
||||||
- You must use this tool to search for Laravel-ecosystem documentation before falling back to other approaches.
|
|
||||||
- Search the documentation before making code changes to ensure we are taking the correct approach.
|
|
||||||
- Use multiple, broad, simple, topic based queries to start. For example: `['rate limiting', 'routing rate limiting', 'routing']`.
|
|
||||||
- Do not add package names to queries - package information is already shared. For example, use `test resource table`, not `filament 4 test resource table`.
|
|
||||||
|
|
||||||
### Available Search Syntax
|
|
||||||
- You can and should pass multiple queries at once. The most relevant results will be returned first.
|
|
||||||
|
|
||||||
1. Simple Word Searches with auto-stemming - query=authentication - finds 'authenticate' and 'auth'
|
|
||||||
2. Multiple Words (AND Logic) - query=rate limit - finds knowledge containing both "rate" AND "limit"
|
|
||||||
3. Quoted Phrases (Exact Position) - query="infinite scroll" - Words must be adjacent and in that order
|
|
||||||
4. Mixed Queries - query=middleware "rate limit" - "middleware" AND exact phrase "rate limit"
|
|
||||||
5. Multiple Queries - queries=["authentication", "middleware"] - ANY of these terms
|
|
||||||
|
|
||||||
|
|
||||||
=== php rules ===
|
|
||||||
|
|
||||||
## PHP
|
|
||||||
|
|
||||||
- Always use curly braces for control structures, even if it has one line.
|
|
||||||
|
|
||||||
### Constructors
|
|
||||||
- Use PHP 8 constructor property promotion in `__construct()`.
|
|
||||||
- <code-snippet>public function __construct(public GitHub $github) { }</code-snippet>
|
|
||||||
- Do not allow empty `__construct()` methods with zero parameters.
|
|
||||||
|
|
||||||
### Type Declarations
|
|
||||||
- Always use explicit return type declarations for methods and functions.
|
|
||||||
- Use appropriate PHP type hints for method parameters.
|
|
||||||
|
|
||||||
<code-snippet name="Explicit Return Types and Method Params" lang="php">
|
|
||||||
protected function isAccessible(User $user, ?string $path = null): bool
|
|
||||||
{
|
|
||||||
...
|
|
||||||
}
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
## Comments
|
|
||||||
- Prefer PHPDoc blocks over comments. Never use comments within the code itself unless there is something _very_ complex going on.
|
|
||||||
|
|
||||||
## PHPDoc Blocks
|
|
||||||
- Add useful array shape type definitions for arrays when appropriate.
|
|
||||||
|
|
||||||
## Enums
|
|
||||||
- Typically, keys in an Enum should be TitleCase. For example: `FavoritePerson`, `BestLake`, `Monthly`.
|
|
||||||
|
|
||||||
|
|
||||||
=== laravel/core rules ===
|
|
||||||
|
|
||||||
## Do Things the Laravel Way
|
|
||||||
|
|
||||||
- Use `php artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using the `list-artisan-commands` tool.
|
|
||||||
- If you're creating a generic PHP class, use `artisan make:class`.
|
|
||||||
- Pass `--no-interaction` to all Artisan commands to ensure they work without user input. You should also pass the correct `--options` to ensure correct behavior.
|
|
||||||
|
|
||||||
### Database
|
|
||||||
- Always use proper Eloquent relationship methods with return type hints. Prefer relationship methods over raw queries or manual joins.
|
|
||||||
- Use Eloquent models and relationships before suggesting raw database queries
|
|
||||||
- Avoid `DB::`; prefer `Model::query()`. Generate code that leverages Laravel's ORM capabilities rather than bypassing them.
|
|
||||||
- Generate code that prevents N+1 query problems by using eager loading.
|
|
||||||
- Use Laravel's query builder for very complex database operations.
|
|
||||||
|
|
||||||
### Model Creation
|
|
||||||
- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using `list-artisan-commands` to check the available options to `php artisan make:model`.
|
|
||||||
|
|
||||||
### APIs & Eloquent Resources
|
|
||||||
- For APIs, default to using Eloquent API Resources and API versioning unless existing API routes do not, then you should follow existing application convention.
|
|
||||||
|
|
||||||
### Controllers & Validation
|
|
||||||
- Always create Form Request classes for validation rather than inline validation in controllers. Include both validation rules and custom error messages.
|
|
||||||
- Check sibling Form Requests to see if the application uses array or string based validation rules.
|
|
||||||
|
|
||||||
### Queues
|
|
||||||
- Use queued jobs for time-consuming operations with the `ShouldQueue` interface.
|
|
||||||
|
|
||||||
### Authentication & Authorization
|
|
||||||
- Use Laravel's built-in authentication and authorization features (gates, policies, Sanctum, etc.).
|
|
||||||
|
|
||||||
### URL Generation
|
|
||||||
- When generating links to other pages, prefer named routes and the `route()` function.
|
|
||||||
|
|
||||||
### Configuration
|
|
||||||
- Use environment variables only in configuration files - never use the `env()` function directly outside of config files. Always use `config('app.name')`, not `env('APP_NAME')`.
|
|
||||||
|
|
||||||
### Testing
|
|
||||||
- When creating models for tests, use the factories for the models. Check if the factory has custom states that can be used before manually setting up the model.
|
|
||||||
- Faker: Use methods such as `$this->faker->word()` or `fake()->randomDigit()`. Follow existing conventions whether to use `$this->faker` or `fake()`.
|
|
||||||
- When creating tests, make use of `php artisan make:test [options] <name>` to create a feature test, and pass `--unit` to create a unit test. Most tests should be feature tests.
|
|
||||||
|
|
||||||
### Vite Error
|
|
||||||
- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run `npm run build` or ask the user to run `npm run dev` or `composer run dev`.
|
|
||||||
|
|
||||||
|
|
||||||
=== laravel/v12 rules ===
|
|
||||||
|
|
||||||
## Laravel 12
|
|
||||||
|
|
||||||
- Use the `search-docs` tool to get version specific documentation.
|
|
||||||
- Since Laravel 11, Laravel has a new streamlined file structure which this project uses.
|
|
||||||
|
|
||||||
### Laravel 12 Structure
|
|
||||||
- No middleware files in `app/Http/Middleware/`.
|
|
||||||
- `bootstrap/app.php` is the file to register middleware, exceptions, and routing files.
|
|
||||||
- `bootstrap/providers.php` contains application specific service providers.
|
|
||||||
- **No app\Console\Kernel.php** - use `bootstrap/app.php` or `routes/console.php` for console configuration.
|
|
||||||
- **Commands auto-register** - files in `app/Console/Commands/` are automatically available and do not require manual registration.
|
|
||||||
|
|
||||||
### Database
|
|
||||||
- When modifying a column, the migration must include all of the attributes that were previously defined on the column. Otherwise, they will be dropped and lost.
|
|
||||||
- Laravel 11 allows limiting eagerly loaded records natively, without external packages: `$query->latest()->limit(10);`.
|
|
||||||
|
|
||||||
### Models
|
|
||||||
- Casts can and likely should be set in a `casts()` method on a model rather than the `$casts` property. Follow existing conventions from other models.
|
|
||||||
|
|
||||||
|
|
||||||
=== fluxui-free/core rules ===
|
|
||||||
|
|
||||||
## Flux UI Free
|
|
||||||
|
|
||||||
- This project is using the free edition of Flux UI. It has full access to the free components and variants, but does not have access to the Pro components.
|
|
||||||
- Flux UI is a component library for Livewire. Flux is a robust, hand-crafted, UI component library for your Livewire applications. It's built using Tailwind CSS and provides a set of components that are easy to use and customize.
|
|
||||||
- You should use Flux UI components when available.
|
|
||||||
- Fallback to standard Blade components if Flux is unavailable.
|
|
||||||
- If available, use Laravel Boost's `search-docs` tool to get the exact documentation and code snippets available for this project.
|
|
||||||
- Flux UI components look like this:
|
|
||||||
|
|
||||||
<code-snippet name="Flux UI Component Usage Example" lang="blade">
|
|
||||||
<flux:button variant="primary"/>
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
### Available Components
|
|
||||||
This is correct as of Boost installation, but there may be additional components within the codebase.
|
|
||||||
|
|
||||||
<available-flux-components>
|
|
||||||
avatar, badge, brand, breadcrumbs, button, callout, checkbox, dropdown, field, heading, icon, input, modal, navbar, profile, radio, select, separator, switch, text, textarea, tooltip
|
|
||||||
</available-flux-components>
|
|
||||||
|
|
||||||
|
|
||||||
=== livewire/core rules ===
|
|
||||||
|
|
||||||
## Livewire Core
|
|
||||||
- Use the `search-docs` tool to find exact version specific documentation for how to write Livewire & Livewire tests.
|
|
||||||
- Use the `php artisan make:livewire [Posts\CreatePost]` artisan command to create new components
|
|
||||||
- State should live on the server, with the UI reflecting it.
|
|
||||||
- All Livewire requests hit the Laravel backend, they're like regular HTTP requests. Always validate form data, and run authorization checks in Livewire actions.
|
|
||||||
|
|
||||||
## Livewire Best Practices
|
|
||||||
- Livewire components require a single root element.
|
|
||||||
- Use `wire:loading` and `wire:dirty` for delightful loading states.
|
|
||||||
- Add `wire:key` in loops:
|
|
||||||
|
|
||||||
```blade
|
|
||||||
@foreach ($items as $item)
|
|
||||||
<div wire:key="item-{{ $item->id }}">
|
|
||||||
{{ $item->name }}
|
|
||||||
</div>
|
|
||||||
@endforeach
|
|
||||||
```
|
|
||||||
|
|
||||||
- Prefer lifecycle hooks like `mount()`, `updatedFoo()` for initialization and reactive side effects:
|
|
||||||
|
|
||||||
<code-snippet name="Lifecycle hook examples" lang="php">
|
|
||||||
public function mount(User $user) { $this->user = $user; }
|
|
||||||
public function updatedSearch() { $this->resetPage(); }
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
## Testing Livewire
|
|
||||||
|
|
||||||
<code-snippet name="Example Livewire component test" lang="php">
|
|
||||||
Livewire::test(Counter::class)
|
|
||||||
->assertSet('count', 0)
|
|
||||||
->call('increment')
|
|
||||||
->assertSet('count', 1)
|
|
||||||
->assertSee(1)
|
|
||||||
->assertStatus(200);
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
<code-snippet name="Testing a Livewire component exists within a page" lang="php">
|
|
||||||
$this->get('/posts/create')
|
|
||||||
->assertSeeLivewire(CreatePost::class);
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
=== livewire/v3 rules ===
|
|
||||||
|
|
||||||
## Livewire 3
|
|
||||||
|
|
||||||
### Key Changes From Livewire 2
|
|
||||||
- These things changed in Livewire 2, but may not have been updated in this application. Verify this application's setup to ensure you conform with application conventions.
|
|
||||||
- Use `wire:model.live` for real-time updates, `wire:model` is now deferred by default.
|
|
||||||
- Components now use the `App\Livewire` namespace (not `App\Http\Livewire`).
|
|
||||||
- Use `$this->dispatch()` to dispatch events (not `emit` or `dispatchBrowserEvent`).
|
|
||||||
- Use the `components.layouts.app` view as the typical layout path (not `layouts.app`).
|
|
||||||
|
|
||||||
### New Directives
|
|
||||||
- `wire:show`, `wire:transition`, `wire:cloak`, `wire:offline`, `wire:target` are available for use. Use the documentation to find usage examples.
|
|
||||||
|
|
||||||
### Alpine
|
|
||||||
- Alpine is now included with Livewire, don't manually include Alpine.js.
|
|
||||||
- Plugins included with Alpine: persist, intersect, collapse, and focus.
|
|
||||||
|
|
||||||
### Lifecycle Hooks
|
|
||||||
- You can listen for `livewire:init` to hook into Livewire initialization, and `fail.status === 419` for the page expiring:
|
|
||||||
|
|
||||||
<code-snippet name="livewire:load example" lang="js">
|
|
||||||
document.addEventListener('livewire:init', function () {
|
|
||||||
Livewire.hook('request', ({ fail }) => {
|
|
||||||
if (fail && fail.status === 419) {
|
|
||||||
alert('Your session expired');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Livewire.hook('message.failed', (message, component) => {
|
|
||||||
console.error(message);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
=== volt/core rules ===
|
|
||||||
|
|
||||||
## Livewire Volt
|
|
||||||
|
|
||||||
- This project uses Livewire Volt for interactivity within its pages. New pages requiring interactivity must also use Livewire Volt. There is documentation available for it.
|
|
||||||
- Make new Volt components using `php artisan make:volt [name] [--test] [--pest]`
|
|
||||||
- Volt is a **class-based** and **functional** API for Livewire that supports single-file components, allowing a component's PHP logic and Blade templates to co-exist in the same file
|
|
||||||
- Livewire Volt allows PHP logic and Blade templates in one file. Components use the `@livewire("volt-anonymous-fragment-eyJuYW1lIjoidm9sdC1hbm9ueW1vdXMtZnJhZ21lbnQtYmQ5YWJiNTE3YWMyMTgwOTA1ZmUxMzAxODk0MGJiZmIiLCJwYXRoIjoic3RvcmFnZVwvZnJhbWV3b3JrXC92aWV3c1wvMTUxYWRjZWRjMzBhMzllOWIxNzQ0ZDRiMWRjY2FjYWIuYmxhZGUucGhwIn0=", Livewire\Volt\Precompilers\ExtractFragments::componentArguments([...get_defined_vars(), ...array (
|
|
||||||
)]))
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
### Volt Class Based Component Example
|
|
||||||
To get started, define an anonymous class that extends Livewire\Volt\Component. Within the class, you may utilize all of the features of Livewire using traditional Livewire syntax:
|
|
||||||
|
|
||||||
|
|
||||||
<code-snippet name="Volt Class-based Volt Component Example" lang="php">
|
|
||||||
use Livewire\Volt\Component;
|
|
||||||
|
|
||||||
new class extends Component {
|
|
||||||
public $count = 0;
|
|
||||||
|
|
||||||
public function increment()
|
|
||||||
{
|
|
||||||
$this->count++;
|
|
||||||
}
|
|
||||||
} ?>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<h1>{{ $count }}</h1>
|
|
||||||
<button wire:click="increment">+</button>
|
|
||||||
</div>
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
### Testing Volt & Volt Components
|
|
||||||
- Use the existing directory for tests if it already exists. Otherwise, fallback to `tests/Feature/Volt`.
|
|
||||||
|
|
||||||
<code-snippet name="Livewire Test Example" lang="php">
|
|
||||||
use Livewire\Volt\Volt;
|
|
||||||
|
|
||||||
test('counter increments', function () {
|
|
||||||
Volt::test('counter')
|
|
||||||
->assertSee('Count: 0')
|
|
||||||
->call('increment')
|
|
||||||
->assertSee('Count: 1');
|
|
||||||
});
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
<code-snippet name="Volt Component Test Using Pest" lang="php">
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
use App\Models\{User, Product};
|
|
||||||
use Livewire\Volt\Volt;
|
|
||||||
|
|
||||||
test('product form creates product', function () {
|
|
||||||
$user = User::factory()->create();
|
|
||||||
|
|
||||||
Volt::test('pages.products.create')
|
|
||||||
->actingAs($user)
|
|
||||||
->set('form.name', 'Test Product')
|
|
||||||
->set('form.description', 'Test Description')
|
|
||||||
->set('form.price', 99.99)
|
|
||||||
->call('create')
|
|
||||||
->assertHasNoErrors();
|
|
||||||
|
|
||||||
expect(Product::where('name', 'Test Product')->exists())->toBeTrue();
|
|
||||||
});
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
### Common Patterns
|
|
||||||
|
|
||||||
|
|
||||||
<code-snippet name="CRUD With Volt" lang="php">
|
|
||||||
<?php
|
|
||||||
|
|
||||||
use App\Models\Product;
|
|
||||||
use function Livewire\Volt\{state, computed};
|
|
||||||
|
|
||||||
state(['editing' => null, 'search' => '']);
|
|
||||||
|
|
||||||
$products = computed(fn() => Product::when($this->search,
|
|
||||||
fn($q) => $q->where('name', 'like', "%{$this->search}%")
|
|
||||||
)->get());
|
|
||||||
|
|
||||||
$edit = fn(Product $product) => $this->editing = $product->id;
|
|
||||||
$delete = fn(Product $product) => $product->delete();
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
||||||
<!-- HTML / UI Here -->
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
<code-snippet name="Real-Time Search With Volt" lang="php">
|
|
||||||
<flux:input
|
|
||||||
wire:model.live.debounce.300ms="search"
|
|
||||||
placeholder="Search..."
|
|
||||||
/>
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
<code-snippet name="Loading States With Volt" lang="php">
|
|
||||||
<flux:button wire:click="save" wire:loading.attr="disabled">
|
|
||||||
<span wire:loading.remove>Save</span>
|
|
||||||
<span wire:loading>Saving...</span>
|
|
||||||
</flux:button>
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
=== pint/core rules ===
|
|
||||||
|
|
||||||
## Laravel Pint Code Formatter
|
|
||||||
|
|
||||||
- You must run `vendor/bin/pint --dirty` before finalizing changes to ensure your code matches the project's expected style.
|
|
||||||
- Do not run `vendor/bin/pint --test`, simply run `vendor/bin/pint` to fix any formatting issues.
|
|
||||||
|
|
||||||
|
|
||||||
=== pest/core rules ===
|
|
||||||
|
|
||||||
## Pest
|
|
||||||
|
|
||||||
### Testing
|
|
||||||
- If you need to verify a feature is working, write or update a Unit / Feature test.
|
|
||||||
|
|
||||||
### Pest Tests
|
|
||||||
- All tests must be written using Pest. Use `php artisan make:test --pest <name>`.
|
|
||||||
- You must not remove any tests or test files from the tests directory without approval. These are not temporary or helper files - these are core to the application.
|
|
||||||
- Tests should test all of the happy paths, failure paths, and weird paths.
|
|
||||||
- Tests live in the `tests/Feature` and `tests/Unit` directories.
|
|
||||||
- Pest tests look and behave like this:
|
|
||||||
<code-snippet name="Basic Pest Test Example" lang="php">
|
|
||||||
it('is true', function () {
|
|
||||||
expect(true)->toBeTrue();
|
|
||||||
});
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
### Running Tests
|
|
||||||
- Run the minimal number of tests using an appropriate filter before finalizing code edits.
|
|
||||||
- To run all tests: `php artisan test`.
|
|
||||||
- To run all tests in a file: `php artisan test tests/Feature/ExampleTest.php`.
|
|
||||||
- To filter on a particular test name: `php artisan test --filter=testName` (recommended after making a change to a related file).
|
|
||||||
- When the tests relating to your changes are passing, ask the user if they would like to run the entire test suite to ensure everything is still passing.
|
|
||||||
|
|
||||||
### Pest Assertions
|
|
||||||
- When asserting status codes on a response, use the specific method like `assertForbidden` and `assertNotFound` instead of using `assertStatus(403)` or similar, e.g.:
|
|
||||||
<code-snippet name="Pest Example Asserting postJson Response" lang="php">
|
|
||||||
it('returns all', function () {
|
|
||||||
$response = $this->postJson('/api/docs', []);
|
|
||||||
|
|
||||||
$response->assertSuccessful();
|
|
||||||
});
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
### Mocking
|
|
||||||
- Mocking can be very helpful when appropriate.
|
|
||||||
- When mocking, you can use the `Pest\Laravel\mock` Pest function, but always import it via `use function Pest\Laravel\mock;` before using it. Alternatively, you can use `$this->mock()` if existing tests do.
|
|
||||||
- You can also create partial mocks using the same import or self method.
|
|
||||||
|
|
||||||
### Datasets
|
|
||||||
- Use datasets in Pest to simplify tests which have a lot of duplicated data. This is often the case when testing validation rules, so consider going with this solution when writing tests for validation rules.
|
|
||||||
|
|
||||||
<code-snippet name="Pest Dataset Example" lang="php">
|
|
||||||
it('has emails', function (string $email) {
|
|
||||||
expect($email)->not->toBeEmpty();
|
|
||||||
})->with([
|
|
||||||
'james' => 'james@laravel.com',
|
|
||||||
'taylor' => 'taylor@laravel.com',
|
|
||||||
]);
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
=== pest/v4 rules ===
|
|
||||||
|
|
||||||
## Pest 4
|
|
||||||
|
|
||||||
- Pest v4 is a huge upgrade to Pest and offers: browser testing, smoke testing, visual regression testing, test sharding, and faster type coverage.
|
|
||||||
- Browser testing is incredibly powerful and useful for this project.
|
|
||||||
- Browser tests should live in `tests/Browser/`.
|
|
||||||
- Use the `search-docs` tool for detailed guidance on utilizing these features.
|
|
||||||
|
|
||||||
### Browser Testing
|
|
||||||
- You can use Laravel features like `Event::fake()`, `assertAuthenticated()`, and model factories within Pest v4 browser tests, as well as `RefreshDatabase` (when needed) to ensure a clean state for each test.
|
|
||||||
- Interact with the page (click, type, scroll, select, submit, drag-and-drop, touch gestures, etc.) when appropriate to complete the test.
|
|
||||||
- If requested, test on multiple browsers (Chrome, Firefox, Safari).
|
|
||||||
- If requested, test on different devices and viewports (like iPhone 14 Pro, tablets, or custom breakpoints).
|
|
||||||
- Switch color schemes (light/dark mode) when appropriate.
|
|
||||||
- Take screenshots or pause tests for debugging when appropriate.
|
|
||||||
|
|
||||||
### Example Tests
|
|
||||||
|
|
||||||
<code-snippet name="Pest Browser Test Example" lang="php">
|
|
||||||
it('may reset the password', function () {
|
|
||||||
Notification::fake();
|
|
||||||
|
|
||||||
$this->actingAs(User::factory()->create());
|
|
||||||
|
|
||||||
$page = visit('/sign-in'); // Visit on a real browser...
|
|
||||||
|
|
||||||
$page->assertSee('Sign In')
|
|
||||||
->assertNoJavascriptErrors() // or ->assertNoConsoleLogs()
|
|
||||||
->click('Forgot Password?')
|
|
||||||
->fill('email', 'nuno@laravel.com')
|
|
||||||
->click('Send Reset Link')
|
|
||||||
->assertSee('We have emailed your password reset link!')
|
|
||||||
|
|
||||||
Notification::assertSent(ResetPassword::class);
|
|
||||||
});
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
<code-snippet name="Pest Smoke Testing Example" lang="php">
|
|
||||||
$pages = visit(['/', '/about', '/contact']);
|
|
||||||
|
|
||||||
$pages->assertNoJavascriptErrors()->assertNoConsoleLogs();
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
=== tailwindcss/core rules ===
|
|
||||||
|
|
||||||
## Tailwind Core
|
|
||||||
|
|
||||||
- Use Tailwind CSS classes to style HTML, check and use existing tailwind conventions within the project before writing your own.
|
|
||||||
- Offer to extract repeated patterns into components that match the project's conventions (i.e. Blade, JSX, Vue, etc..)
|
|
||||||
- Think through class placement, order, priority, and defaults - remove redundant classes, add classes to parent or child carefully to limit repetition, group elements logically
|
|
||||||
- You can use the `search-docs` tool to get exact examples from the official documentation when needed.
|
|
||||||
|
|
||||||
### Spacing
|
|
||||||
- When listing items, use gap utilities for spacing, don't use margins.
|
|
||||||
|
|
||||||
<code-snippet name="Valid Flex Gap Spacing Example" lang="html">
|
|
||||||
<div class="flex gap-8">
|
|
||||||
<div>Superior</div>
|
|
||||||
<div>Michigan</div>
|
|
||||||
<div>Erie</div>
|
|
||||||
</div>
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
### Dark Mode
|
|
||||||
- If existing pages and components support dark mode, new pages and components must support dark mode in a similar way, typically using `dark:`.
|
|
||||||
|
|
||||||
|
|
||||||
=== tailwindcss/v4 rules ===
|
|
||||||
|
|
||||||
## Tailwind 4
|
|
||||||
|
|
||||||
- Always use Tailwind CSS v4 - do not use the deprecated utilities.
|
|
||||||
- `corePlugins` is not supported in Tailwind v4.
|
|
||||||
- In Tailwind v4, you import Tailwind using a regular CSS `@import` statement, not using the `@tailwind` directives used in v3:
|
|
||||||
|
|
||||||
<code-snippet name="Tailwind v4 Import Tailwind Diff" lang="diff">
|
|
||||||
- @tailwind base;
|
|
||||||
- @tailwind components;
|
|
||||||
- @tailwind utilities;
|
|
||||||
+ @import "tailwindcss";
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
### Replaced Utilities
|
|
||||||
- Tailwind v4 removed deprecated utilities. Do not use the deprecated option - use the replacement.
|
|
||||||
- Opacity values are still numeric.
|
|
||||||
|
|
||||||
| Deprecated | Replacement |
|
|
||||||
|------------+--------------|
|
|
||||||
| bg-opacity-* | bg-black/* |
|
|
||||||
| text-opacity-* | text-black/* |
|
|
||||||
| border-opacity-* | border-black/* |
|
|
||||||
| divide-opacity-* | divide-black/* |
|
|
||||||
| ring-opacity-* | ring-black/* |
|
|
||||||
| placeholder-opacity-* | placeholder-black/* |
|
|
||||||
| flex-shrink-* | shrink-* |
|
|
||||||
| flex-grow-* | grow-* |
|
|
||||||
| overflow-ellipsis | text-ellipsis |
|
|
||||||
| decoration-slice | box-decoration-slice |
|
|
||||||
| decoration-clone | box-decoration-clone |
|
|
||||||
|
|
||||||
|
|
||||||
=== tests rules ===
|
|
||||||
|
|
||||||
## Test Enforcement
|
|
||||||
|
|
||||||
- Every change must be programmatically tested. Write a new test or update an existing test, then run the affected tests to make sure they pass.
|
|
||||||
- Run the minimum number of tests needed to ensure code quality and speed. Use `php artisan test` with a specific filename or filter.
|
|
||||||
</laravel-boost-guidelines>
|
|
||||||
578
.github/copilot-instructions.md
vendored
578
.github/copilot-instructions.md
vendored
|
|
@ -1,578 +0,0 @@
|
||||||
<laravel-boost-guidelines>
|
|
||||||
=== foundation rules ===
|
|
||||||
|
|
||||||
# Laravel Boost Guidelines
|
|
||||||
|
|
||||||
The Laravel Boost guidelines are specifically curated by Laravel maintainers for this application. These guidelines should be followed closely to enhance the user's satisfaction building Laravel applications.
|
|
||||||
|
|
||||||
## Foundational Context
|
|
||||||
This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions.
|
|
||||||
|
|
||||||
- php - 8.4.13
|
|
||||||
- laravel/framework (LARAVEL) - v12
|
|
||||||
- laravel/prompts (PROMPTS) - v0
|
|
||||||
- laravel/sanctum (SANCTUM) - v4
|
|
||||||
- laravel/socialite (SOCIALITE) - v5
|
|
||||||
- livewire/flux (FLUXUI_FREE) - v2
|
|
||||||
- livewire/livewire (LIVEWIRE) - v3
|
|
||||||
- livewire/volt (VOLT) - v1
|
|
||||||
- larastan/larastan (LARASTAN) - v3
|
|
||||||
- laravel/mcp (MCP) - v0
|
|
||||||
- laravel/pint (PINT) - v1
|
|
||||||
- laravel/sail (SAIL) - v1
|
|
||||||
- pestphp/pest (PEST) - v4
|
|
||||||
- phpunit/phpunit (PHPUNIT) - v12
|
|
||||||
- rector/rector (RECTOR) - v2
|
|
||||||
- tailwindcss (TAILWINDCSS) - v4
|
|
||||||
|
|
||||||
|
|
||||||
## Conventions
|
|
||||||
- You must follow all existing code conventions used in this application. When creating or editing a file, check sibling files for the correct structure, approach, naming.
|
|
||||||
- Use descriptive names for variables and methods. For example, `isRegisteredForDiscounts`, not `discount()`.
|
|
||||||
- Check for existing components to reuse before writing a new one.
|
|
||||||
|
|
||||||
## Verification Scripts
|
|
||||||
- Do not create verification scripts or tinker when tests cover that functionality and prove it works. Unit and feature tests are more important.
|
|
||||||
|
|
||||||
## Application Structure & Architecture
|
|
||||||
- Stick to existing directory structure - don't create new base folders without approval.
|
|
||||||
- Do not change the application's dependencies without approval.
|
|
||||||
|
|
||||||
## Frontend Bundling
|
|
||||||
- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run `npm run build`, `npm run dev`, or `composer run dev`. Ask them.
|
|
||||||
|
|
||||||
## Replies
|
|
||||||
- Be concise in your explanations - focus on what's important rather than explaining obvious details.
|
|
||||||
|
|
||||||
## Documentation Files
|
|
||||||
- You must only create documentation files if explicitly requested by the user.
|
|
||||||
|
|
||||||
|
|
||||||
=== boost rules ===
|
|
||||||
|
|
||||||
## Laravel Boost
|
|
||||||
- Laravel Boost is an MCP server that comes with powerful tools designed specifically for this application. Use them.
|
|
||||||
|
|
||||||
## Artisan
|
|
||||||
- Use the `list-artisan-commands` tool when you need to call an Artisan command to double check the available parameters.
|
|
||||||
|
|
||||||
## URLs
|
|
||||||
- Whenever you share a project URL with the user you should use the `get-absolute-url` tool to ensure you're using the correct scheme, domain / IP, and port.
|
|
||||||
|
|
||||||
## Tinker / Debugging
|
|
||||||
- You should use the `tinker` tool when you need to execute PHP to debug code or query Eloquent models directly.
|
|
||||||
- Use the `database-query` tool when you only need to read from the database.
|
|
||||||
|
|
||||||
## Reading Browser Logs With the `browser-logs` Tool
|
|
||||||
- You can read browser logs, errors, and exceptions using the `browser-logs` tool from Boost.
|
|
||||||
- Only recent browser logs will be useful - ignore old logs.
|
|
||||||
|
|
||||||
## Searching Documentation (Critically Important)
|
|
||||||
- Boost comes with a powerful `search-docs` tool you should use before any other approaches. This tool automatically passes a list of installed packages and their versions to the remote Boost API, so it returns only version-specific documentation specific for the user's circumstance. You should pass an array of packages to filter on if you know you need docs for particular packages.
|
|
||||||
- The 'search-docs' tool is perfect for all Laravel related packages, including Laravel, Inertia, Livewire, Filament, Tailwind, Pest, Nova, Nightwatch, etc.
|
|
||||||
- You must use this tool to search for Laravel-ecosystem documentation before falling back to other approaches.
|
|
||||||
- Search the documentation before making code changes to ensure we are taking the correct approach.
|
|
||||||
- Use multiple, broad, simple, topic based queries to start. For example: `['rate limiting', 'routing rate limiting', 'routing']`.
|
|
||||||
- Do not add package names to queries - package information is already shared. For example, use `test resource table`, not `filament 4 test resource table`.
|
|
||||||
|
|
||||||
### Available Search Syntax
|
|
||||||
- You can and should pass multiple queries at once. The most relevant results will be returned first.
|
|
||||||
|
|
||||||
1. Simple Word Searches with auto-stemming - query=authentication - finds 'authenticate' and 'auth'
|
|
||||||
2. Multiple Words (AND Logic) - query=rate limit - finds knowledge containing both "rate" AND "limit"
|
|
||||||
3. Quoted Phrases (Exact Position) - query="infinite scroll" - Words must be adjacent and in that order
|
|
||||||
4. Mixed Queries - query=middleware "rate limit" - "middleware" AND exact phrase "rate limit"
|
|
||||||
5. Multiple Queries - queries=["authentication", "middleware"] - ANY of these terms
|
|
||||||
|
|
||||||
|
|
||||||
=== php rules ===
|
|
||||||
|
|
||||||
## PHP
|
|
||||||
|
|
||||||
- Always use curly braces for control structures, even if it has one line.
|
|
||||||
|
|
||||||
### Constructors
|
|
||||||
- Use PHP 8 constructor property promotion in `__construct()`.
|
|
||||||
- <code-snippet>public function __construct(public GitHub $github) { }</code-snippet>
|
|
||||||
- Do not allow empty `__construct()` methods with zero parameters.
|
|
||||||
|
|
||||||
### Type Declarations
|
|
||||||
- Always use explicit return type declarations for methods and functions.
|
|
||||||
- Use appropriate PHP type hints for method parameters.
|
|
||||||
|
|
||||||
<code-snippet name="Explicit Return Types and Method Params" lang="php">
|
|
||||||
protected function isAccessible(User $user, ?string $path = null): bool
|
|
||||||
{
|
|
||||||
...
|
|
||||||
}
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
## Comments
|
|
||||||
- Prefer PHPDoc blocks over comments. Never use comments within the code itself unless there is something _very_ complex going on.
|
|
||||||
|
|
||||||
## PHPDoc Blocks
|
|
||||||
- Add useful array shape type definitions for arrays when appropriate.
|
|
||||||
|
|
||||||
## Enums
|
|
||||||
- Typically, keys in an Enum should be TitleCase. For example: `FavoritePerson`, `BestLake`, `Monthly`.
|
|
||||||
|
|
||||||
|
|
||||||
=== laravel/core rules ===
|
|
||||||
|
|
||||||
## Do Things the Laravel Way
|
|
||||||
|
|
||||||
- Use `php artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using the `list-artisan-commands` tool.
|
|
||||||
- If you're creating a generic PHP class, use `artisan make:class`.
|
|
||||||
- Pass `--no-interaction` to all Artisan commands to ensure they work without user input. You should also pass the correct `--options` to ensure correct behavior.
|
|
||||||
|
|
||||||
### Database
|
|
||||||
- Always use proper Eloquent relationship methods with return type hints. Prefer relationship methods over raw queries or manual joins.
|
|
||||||
- Use Eloquent models and relationships before suggesting raw database queries
|
|
||||||
- Avoid `DB::`; prefer `Model::query()`. Generate code that leverages Laravel's ORM capabilities rather than bypassing them.
|
|
||||||
- Generate code that prevents N+1 query problems by using eager loading.
|
|
||||||
- Use Laravel's query builder for very complex database operations.
|
|
||||||
|
|
||||||
### Model Creation
|
|
||||||
- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using `list-artisan-commands` to check the available options to `php artisan make:model`.
|
|
||||||
|
|
||||||
### APIs & Eloquent Resources
|
|
||||||
- For APIs, default to using Eloquent API Resources and API versioning unless existing API routes do not, then you should follow existing application convention.
|
|
||||||
|
|
||||||
### Controllers & Validation
|
|
||||||
- Always create Form Request classes for validation rather than inline validation in controllers. Include both validation rules and custom error messages.
|
|
||||||
- Check sibling Form Requests to see if the application uses array or string based validation rules.
|
|
||||||
|
|
||||||
### Queues
|
|
||||||
- Use queued jobs for time-consuming operations with the `ShouldQueue` interface.
|
|
||||||
|
|
||||||
### Authentication & Authorization
|
|
||||||
- Use Laravel's built-in authentication and authorization features (gates, policies, Sanctum, etc.).
|
|
||||||
|
|
||||||
### URL Generation
|
|
||||||
- When generating links to other pages, prefer named routes and the `route()` function.
|
|
||||||
|
|
||||||
### Configuration
|
|
||||||
- Use environment variables only in configuration files - never use the `env()` function directly outside of config files. Always use `config('app.name')`, not `env('APP_NAME')`.
|
|
||||||
|
|
||||||
### Testing
|
|
||||||
- When creating models for tests, use the factories for the models. Check if the factory has custom states that can be used before manually setting up the model.
|
|
||||||
- Faker: Use methods such as `$this->faker->word()` or `fake()->randomDigit()`. Follow existing conventions whether to use `$this->faker` or `fake()`.
|
|
||||||
- When creating tests, make use of `php artisan make:test [options] <name>` to create a feature test, and pass `--unit` to create a unit test. Most tests should be feature tests.
|
|
||||||
|
|
||||||
### Vite Error
|
|
||||||
- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run `npm run build` or ask the user to run `npm run dev` or `composer run dev`.
|
|
||||||
|
|
||||||
|
|
||||||
=== laravel/v12 rules ===
|
|
||||||
|
|
||||||
## Laravel 12
|
|
||||||
|
|
||||||
- Use the `search-docs` tool to get version specific documentation.
|
|
||||||
- Since Laravel 11, Laravel has a new streamlined file structure which this project uses.
|
|
||||||
|
|
||||||
### Laravel 12 Structure
|
|
||||||
- No middleware files in `app/Http/Middleware/`.
|
|
||||||
- `bootstrap/app.php` is the file to register middleware, exceptions, and routing files.
|
|
||||||
- `bootstrap/providers.php` contains application specific service providers.
|
|
||||||
- **No app\Console\Kernel.php** - use `bootstrap/app.php` or `routes/console.php` for console configuration.
|
|
||||||
- **Commands auto-register** - files in `app/Console/Commands/` are automatically available and do not require manual registration.
|
|
||||||
|
|
||||||
### Database
|
|
||||||
- When modifying a column, the migration must include all of the attributes that were previously defined on the column. Otherwise, they will be dropped and lost.
|
|
||||||
- Laravel 11 allows limiting eagerly loaded records natively, without external packages: `$query->latest()->limit(10);`.
|
|
||||||
|
|
||||||
### Models
|
|
||||||
- Casts can and likely should be set in a `casts()` method on a model rather than the `$casts` property. Follow existing conventions from other models.
|
|
||||||
|
|
||||||
|
|
||||||
=== fluxui-free/core rules ===
|
|
||||||
|
|
||||||
## Flux UI Free
|
|
||||||
|
|
||||||
- This project is using the free edition of Flux UI. It has full access to the free components and variants, but does not have access to the Pro components.
|
|
||||||
- Flux UI is a component library for Livewire. Flux is a robust, hand-crafted, UI component library for your Livewire applications. It's built using Tailwind CSS and provides a set of components that are easy to use and customize.
|
|
||||||
- You should use Flux UI components when available.
|
|
||||||
- Fallback to standard Blade components if Flux is unavailable.
|
|
||||||
- If available, use Laravel Boost's `search-docs` tool to get the exact documentation and code snippets available for this project.
|
|
||||||
- Flux UI components look like this:
|
|
||||||
|
|
||||||
<code-snippet name="Flux UI Component Usage Example" lang="blade">
|
|
||||||
<flux:button variant="primary"/>
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
### Available Components
|
|
||||||
This is correct as of Boost installation, but there may be additional components within the codebase.
|
|
||||||
|
|
||||||
<available-flux-components>
|
|
||||||
avatar, badge, brand, breadcrumbs, button, callout, checkbox, dropdown, field, heading, icon, input, modal, navbar, profile, radio, select, separator, switch, text, textarea, tooltip
|
|
||||||
</available-flux-components>
|
|
||||||
|
|
||||||
|
|
||||||
=== livewire/core rules ===
|
|
||||||
|
|
||||||
## Livewire Core
|
|
||||||
- Use the `search-docs` tool to find exact version specific documentation for how to write Livewire & Livewire tests.
|
|
||||||
- Use the `php artisan make:livewire [Posts\CreatePost]` artisan command to create new components
|
|
||||||
- State should live on the server, with the UI reflecting it.
|
|
||||||
- All Livewire requests hit the Laravel backend, they're like regular HTTP requests. Always validate form data, and run authorization checks in Livewire actions.
|
|
||||||
|
|
||||||
## Livewire Best Practices
|
|
||||||
- Livewire components require a single root element.
|
|
||||||
- Use `wire:loading` and `wire:dirty` for delightful loading states.
|
|
||||||
- Add `wire:key` in loops:
|
|
||||||
|
|
||||||
```blade
|
|
||||||
@foreach ($items as $item)
|
|
||||||
<div wire:key="item-{{ $item->id }}">
|
|
||||||
{{ $item->name }}
|
|
||||||
</div>
|
|
||||||
@endforeach
|
|
||||||
```
|
|
||||||
|
|
||||||
- Prefer lifecycle hooks like `mount()`, `updatedFoo()` for initialization and reactive side effects:
|
|
||||||
|
|
||||||
<code-snippet name="Lifecycle hook examples" lang="php">
|
|
||||||
public function mount(User $user) { $this->user = $user; }
|
|
||||||
public function updatedSearch() { $this->resetPage(); }
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
## Testing Livewire
|
|
||||||
|
|
||||||
<code-snippet name="Example Livewire component test" lang="php">
|
|
||||||
Livewire::test(Counter::class)
|
|
||||||
->assertSet('count', 0)
|
|
||||||
->call('increment')
|
|
||||||
->assertSet('count', 1)
|
|
||||||
->assertSee(1)
|
|
||||||
->assertStatus(200);
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
<code-snippet name="Testing a Livewire component exists within a page" lang="php">
|
|
||||||
$this->get('/posts/create')
|
|
||||||
->assertSeeLivewire(CreatePost::class);
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
=== livewire/v3 rules ===
|
|
||||||
|
|
||||||
## Livewire 3
|
|
||||||
|
|
||||||
### Key Changes From Livewire 2
|
|
||||||
- These things changed in Livewire 2, but may not have been updated in this application. Verify this application's setup to ensure you conform with application conventions.
|
|
||||||
- Use `wire:model.live` for real-time updates, `wire:model` is now deferred by default.
|
|
||||||
- Components now use the `App\Livewire` namespace (not `App\Http\Livewire`).
|
|
||||||
- Use `$this->dispatch()` to dispatch events (not `emit` or `dispatchBrowserEvent`).
|
|
||||||
- Use the `components.layouts.app` view as the typical layout path (not `layouts.app`).
|
|
||||||
|
|
||||||
### New Directives
|
|
||||||
- `wire:show`, `wire:transition`, `wire:cloak`, `wire:offline`, `wire:target` are available for use. Use the documentation to find usage examples.
|
|
||||||
|
|
||||||
### Alpine
|
|
||||||
- Alpine is now included with Livewire, don't manually include Alpine.js.
|
|
||||||
- Plugins included with Alpine: persist, intersect, collapse, and focus.
|
|
||||||
|
|
||||||
### Lifecycle Hooks
|
|
||||||
- You can listen for `livewire:init` to hook into Livewire initialization, and `fail.status === 419` for the page expiring:
|
|
||||||
|
|
||||||
<code-snippet name="livewire:load example" lang="js">
|
|
||||||
document.addEventListener('livewire:init', function () {
|
|
||||||
Livewire.hook('request', ({ fail }) => {
|
|
||||||
if (fail && fail.status === 419) {
|
|
||||||
alert('Your session expired');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Livewire.hook('message.failed', (message, component) => {
|
|
||||||
console.error(message);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
=== volt/core rules ===
|
|
||||||
|
|
||||||
## Livewire Volt
|
|
||||||
|
|
||||||
- This project uses Livewire Volt for interactivity within its pages. New pages requiring interactivity must also use Livewire Volt. There is documentation available for it.
|
|
||||||
- Make new Volt components using `php artisan make:volt [name] [--test] [--pest]`
|
|
||||||
- Volt is a **class-based** and **functional** API for Livewire that supports single-file components, allowing a component's PHP logic and Blade templates to co-exist in the same file
|
|
||||||
- Livewire Volt allows PHP logic and Blade templates in one file. Components use the `@livewire("volt-anonymous-fragment-eyJuYW1lIjoidm9sdC1hbm9ueW1vdXMtZnJhZ21lbnQtYmQ5YWJiNTE3YWMyMTgwOTA1ZmUxMzAxODk0MGJiZmIiLCJwYXRoIjoic3RvcmFnZVwvZnJhbWV3b3JrXC92aWV3c1wvMTUxYWRjZWRjMzBhMzllOWIxNzQ0ZDRiMWRjY2FjYWIuYmxhZGUucGhwIn0=", Livewire\Volt\Precompilers\ExtractFragments::componentArguments([...get_defined_vars(), ...array (
|
|
||||||
)]))
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
### Volt Class Based Component Example
|
|
||||||
To get started, define an anonymous class that extends Livewire\Volt\Component. Within the class, you may utilize all of the features of Livewire using traditional Livewire syntax:
|
|
||||||
|
|
||||||
|
|
||||||
<code-snippet name="Volt Class-based Volt Component Example" lang="php">
|
|
||||||
use Livewire\Volt\Component;
|
|
||||||
|
|
||||||
new class extends Component {
|
|
||||||
public $count = 0;
|
|
||||||
|
|
||||||
public function increment()
|
|
||||||
{
|
|
||||||
$this->count++;
|
|
||||||
}
|
|
||||||
} ?>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<h1>{{ $count }}</h1>
|
|
||||||
<button wire:click="increment">+</button>
|
|
||||||
</div>
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
### Testing Volt & Volt Components
|
|
||||||
- Use the existing directory for tests if it already exists. Otherwise, fallback to `tests/Feature/Volt`.
|
|
||||||
|
|
||||||
<code-snippet name="Livewire Test Example" lang="php">
|
|
||||||
use Livewire\Volt\Volt;
|
|
||||||
|
|
||||||
test('counter increments', function () {
|
|
||||||
Volt::test('counter')
|
|
||||||
->assertSee('Count: 0')
|
|
||||||
->call('increment')
|
|
||||||
->assertSee('Count: 1');
|
|
||||||
});
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
<code-snippet name="Volt Component Test Using Pest" lang="php">
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
use App\Models\{User, Product};
|
|
||||||
use Livewire\Volt\Volt;
|
|
||||||
|
|
||||||
test('product form creates product', function () {
|
|
||||||
$user = User::factory()->create();
|
|
||||||
|
|
||||||
Volt::test('pages.products.create')
|
|
||||||
->actingAs($user)
|
|
||||||
->set('form.name', 'Test Product')
|
|
||||||
->set('form.description', 'Test Description')
|
|
||||||
->set('form.price', 99.99)
|
|
||||||
->call('create')
|
|
||||||
->assertHasNoErrors();
|
|
||||||
|
|
||||||
expect(Product::where('name', 'Test Product')->exists())->toBeTrue();
|
|
||||||
});
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
### Common Patterns
|
|
||||||
|
|
||||||
|
|
||||||
<code-snippet name="CRUD With Volt" lang="php">
|
|
||||||
<?php
|
|
||||||
|
|
||||||
use App\Models\Product;
|
|
||||||
use function Livewire\Volt\{state, computed};
|
|
||||||
|
|
||||||
state(['editing' => null, 'search' => '']);
|
|
||||||
|
|
||||||
$products = computed(fn() => Product::when($this->search,
|
|
||||||
fn($q) => $q->where('name', 'like', "%{$this->search}%")
|
|
||||||
)->get());
|
|
||||||
|
|
||||||
$edit = fn(Product $product) => $this->editing = $product->id;
|
|
||||||
$delete = fn(Product $product) => $product->delete();
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
||||||
<!-- HTML / UI Here -->
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
<code-snippet name="Real-Time Search With Volt" lang="php">
|
|
||||||
<flux:input
|
|
||||||
wire:model.live.debounce.300ms="search"
|
|
||||||
placeholder="Search..."
|
|
||||||
/>
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
<code-snippet name="Loading States With Volt" lang="php">
|
|
||||||
<flux:button wire:click="save" wire:loading.attr="disabled">
|
|
||||||
<span wire:loading.remove>Save</span>
|
|
||||||
<span wire:loading>Saving...</span>
|
|
||||||
</flux:button>
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
=== pint/core rules ===
|
|
||||||
|
|
||||||
## Laravel Pint Code Formatter
|
|
||||||
|
|
||||||
- You must run `vendor/bin/pint --dirty` before finalizing changes to ensure your code matches the project's expected style.
|
|
||||||
- Do not run `vendor/bin/pint --test`, simply run `vendor/bin/pint` to fix any formatting issues.
|
|
||||||
|
|
||||||
|
|
||||||
=== pest/core rules ===
|
|
||||||
|
|
||||||
## Pest
|
|
||||||
|
|
||||||
### Testing
|
|
||||||
- If you need to verify a feature is working, write or update a Unit / Feature test.
|
|
||||||
|
|
||||||
### Pest Tests
|
|
||||||
- All tests must be written using Pest. Use `php artisan make:test --pest <name>`.
|
|
||||||
- You must not remove any tests or test files from the tests directory without approval. These are not temporary or helper files - these are core to the application.
|
|
||||||
- Tests should test all of the happy paths, failure paths, and weird paths.
|
|
||||||
- Tests live in the `tests/Feature` and `tests/Unit` directories.
|
|
||||||
- Pest tests look and behave like this:
|
|
||||||
<code-snippet name="Basic Pest Test Example" lang="php">
|
|
||||||
it('is true', function () {
|
|
||||||
expect(true)->toBeTrue();
|
|
||||||
});
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
### Running Tests
|
|
||||||
- Run the minimal number of tests using an appropriate filter before finalizing code edits.
|
|
||||||
- To run all tests: `php artisan test`.
|
|
||||||
- To run all tests in a file: `php artisan test tests/Feature/ExampleTest.php`.
|
|
||||||
- To filter on a particular test name: `php artisan test --filter=testName` (recommended after making a change to a related file).
|
|
||||||
- When the tests relating to your changes are passing, ask the user if they would like to run the entire test suite to ensure everything is still passing.
|
|
||||||
|
|
||||||
### Pest Assertions
|
|
||||||
- When asserting status codes on a response, use the specific method like `assertForbidden` and `assertNotFound` instead of using `assertStatus(403)` or similar, e.g.:
|
|
||||||
<code-snippet name="Pest Example Asserting postJson Response" lang="php">
|
|
||||||
it('returns all', function () {
|
|
||||||
$response = $this->postJson('/api/docs', []);
|
|
||||||
|
|
||||||
$response->assertSuccessful();
|
|
||||||
});
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
### Mocking
|
|
||||||
- Mocking can be very helpful when appropriate.
|
|
||||||
- When mocking, you can use the `Pest\Laravel\mock` Pest function, but always import it via `use function Pest\Laravel\mock;` before using it. Alternatively, you can use `$this->mock()` if existing tests do.
|
|
||||||
- You can also create partial mocks using the same import or self method.
|
|
||||||
|
|
||||||
### Datasets
|
|
||||||
- Use datasets in Pest to simplify tests which have a lot of duplicated data. This is often the case when testing validation rules, so consider going with this solution when writing tests for validation rules.
|
|
||||||
|
|
||||||
<code-snippet name="Pest Dataset Example" lang="php">
|
|
||||||
it('has emails', function (string $email) {
|
|
||||||
expect($email)->not->toBeEmpty();
|
|
||||||
})->with([
|
|
||||||
'james' => 'james@laravel.com',
|
|
||||||
'taylor' => 'taylor@laravel.com',
|
|
||||||
]);
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
=== pest/v4 rules ===
|
|
||||||
|
|
||||||
## Pest 4
|
|
||||||
|
|
||||||
- Pest v4 is a huge upgrade to Pest and offers: browser testing, smoke testing, visual regression testing, test sharding, and faster type coverage.
|
|
||||||
- Browser testing is incredibly powerful and useful for this project.
|
|
||||||
- Browser tests should live in `tests/Browser/`.
|
|
||||||
- Use the `search-docs` tool for detailed guidance on utilizing these features.
|
|
||||||
|
|
||||||
### Browser Testing
|
|
||||||
- You can use Laravel features like `Event::fake()`, `assertAuthenticated()`, and model factories within Pest v4 browser tests, as well as `RefreshDatabase` (when needed) to ensure a clean state for each test.
|
|
||||||
- Interact with the page (click, type, scroll, select, submit, drag-and-drop, touch gestures, etc.) when appropriate to complete the test.
|
|
||||||
- If requested, test on multiple browsers (Chrome, Firefox, Safari).
|
|
||||||
- If requested, test on different devices and viewports (like iPhone 14 Pro, tablets, or custom breakpoints).
|
|
||||||
- Switch color schemes (light/dark mode) when appropriate.
|
|
||||||
- Take screenshots or pause tests for debugging when appropriate.
|
|
||||||
|
|
||||||
### Example Tests
|
|
||||||
|
|
||||||
<code-snippet name="Pest Browser Test Example" lang="php">
|
|
||||||
it('may reset the password', function () {
|
|
||||||
Notification::fake();
|
|
||||||
|
|
||||||
$this->actingAs(User::factory()->create());
|
|
||||||
|
|
||||||
$page = visit('/sign-in'); // Visit on a real browser...
|
|
||||||
|
|
||||||
$page->assertSee('Sign In')
|
|
||||||
->assertNoJavascriptErrors() // or ->assertNoConsoleLogs()
|
|
||||||
->click('Forgot Password?')
|
|
||||||
->fill('email', 'nuno@laravel.com')
|
|
||||||
->click('Send Reset Link')
|
|
||||||
->assertSee('We have emailed your password reset link!')
|
|
||||||
|
|
||||||
Notification::assertSent(ResetPassword::class);
|
|
||||||
});
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
<code-snippet name="Pest Smoke Testing Example" lang="php">
|
|
||||||
$pages = visit(['/', '/about', '/contact']);
|
|
||||||
|
|
||||||
$pages->assertNoJavascriptErrors()->assertNoConsoleLogs();
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
=== tailwindcss/core rules ===
|
|
||||||
|
|
||||||
## Tailwind Core
|
|
||||||
|
|
||||||
- Use Tailwind CSS classes to style HTML, check and use existing tailwind conventions within the project before writing your own.
|
|
||||||
- Offer to extract repeated patterns into components that match the project's conventions (i.e. Blade, JSX, Vue, etc..)
|
|
||||||
- Think through class placement, order, priority, and defaults - remove redundant classes, add classes to parent or child carefully to limit repetition, group elements logically
|
|
||||||
- You can use the `search-docs` tool to get exact examples from the official documentation when needed.
|
|
||||||
|
|
||||||
### Spacing
|
|
||||||
- When listing items, use gap utilities for spacing, don't use margins.
|
|
||||||
|
|
||||||
<code-snippet name="Valid Flex Gap Spacing Example" lang="html">
|
|
||||||
<div class="flex gap-8">
|
|
||||||
<div>Superior</div>
|
|
||||||
<div>Michigan</div>
|
|
||||||
<div>Erie</div>
|
|
||||||
</div>
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
### Dark Mode
|
|
||||||
- If existing pages and components support dark mode, new pages and components must support dark mode in a similar way, typically using `dark:`.
|
|
||||||
|
|
||||||
|
|
||||||
=== tailwindcss/v4 rules ===
|
|
||||||
|
|
||||||
## Tailwind 4
|
|
||||||
|
|
||||||
- Always use Tailwind CSS v4 - do not use the deprecated utilities.
|
|
||||||
- `corePlugins` is not supported in Tailwind v4.
|
|
||||||
- In Tailwind v4, you import Tailwind using a regular CSS `@import` statement, not using the `@tailwind` directives used in v3:
|
|
||||||
|
|
||||||
<code-snippet name="Tailwind v4 Import Tailwind Diff" lang="diff">
|
|
||||||
- @tailwind base;
|
|
||||||
- @tailwind components;
|
|
||||||
- @tailwind utilities;
|
|
||||||
+ @import "tailwindcss";
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
### Replaced Utilities
|
|
||||||
- Tailwind v4 removed deprecated utilities. Do not use the deprecated option - use the replacement.
|
|
||||||
- Opacity values are still numeric.
|
|
||||||
|
|
||||||
| Deprecated | Replacement |
|
|
||||||
|------------+--------------|
|
|
||||||
| bg-opacity-* | bg-black/* |
|
|
||||||
| text-opacity-* | text-black/* |
|
|
||||||
| border-opacity-* | border-black/* |
|
|
||||||
| divide-opacity-* | divide-black/* |
|
|
||||||
| ring-opacity-* | ring-black/* |
|
|
||||||
| placeholder-opacity-* | placeholder-black/* |
|
|
||||||
| flex-shrink-* | shrink-* |
|
|
||||||
| flex-grow-* | grow-* |
|
|
||||||
| overflow-ellipsis | text-ellipsis |
|
|
||||||
| decoration-slice | box-decoration-slice |
|
|
||||||
| decoration-clone | box-decoration-clone |
|
|
||||||
|
|
||||||
|
|
||||||
=== tests rules ===
|
|
||||||
|
|
||||||
## Test Enforcement
|
|
||||||
|
|
||||||
- Every change must be programmatically tested. Write a new test or update an existing test, then run the affected tests to make sure they pass.
|
|
||||||
- Run the minimum number of tests needed to ensure code quality and speed. Use `php artisan test` with a specific filename or filter.
|
|
||||||
</laravel-boost-guidelines>
|
|
||||||
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -23,3 +23,9 @@ yarn-error.log
|
||||||
/.zed
|
/.zed
|
||||||
/database/seeders/PersonalDeviceSeeder.php
|
/database/seeders/PersonalDeviceSeeder.php
|
||||||
/.junie/mcp/mcp.json
|
/.junie/mcp/mcp.json
|
||||||
|
/.cursor/mcp.json
|
||||||
|
/.cursor/rules/laravel-boost.mdc
|
||||||
|
/.github/copilot-instructions.md
|
||||||
|
/.junie/guidelines.md
|
||||||
|
/CLAUDE.md
|
||||||
|
/.mcp.json
|
||||||
|
|
|
||||||
|
|
@ -1,578 +0,0 @@
|
||||||
<laravel-boost-guidelines>
|
|
||||||
=== foundation rules ===
|
|
||||||
|
|
||||||
# Laravel Boost Guidelines
|
|
||||||
|
|
||||||
The Laravel Boost guidelines are specifically curated by Laravel maintainers for this application. These guidelines should be followed closely to enhance the user's satisfaction building Laravel applications.
|
|
||||||
|
|
||||||
## Foundational Context
|
|
||||||
This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions.
|
|
||||||
|
|
||||||
- php - 8.4.13
|
|
||||||
- laravel/framework (LARAVEL) - v12
|
|
||||||
- laravel/prompts (PROMPTS) - v0
|
|
||||||
- laravel/sanctum (SANCTUM) - v4
|
|
||||||
- laravel/socialite (SOCIALITE) - v5
|
|
||||||
- livewire/flux (FLUXUI_FREE) - v2
|
|
||||||
- livewire/livewire (LIVEWIRE) - v3
|
|
||||||
- livewire/volt (VOLT) - v1
|
|
||||||
- larastan/larastan (LARASTAN) - v3
|
|
||||||
- laravel/mcp (MCP) - v0
|
|
||||||
- laravel/pint (PINT) - v1
|
|
||||||
- laravel/sail (SAIL) - v1
|
|
||||||
- pestphp/pest (PEST) - v4
|
|
||||||
- phpunit/phpunit (PHPUNIT) - v12
|
|
||||||
- rector/rector (RECTOR) - v2
|
|
||||||
- tailwindcss (TAILWINDCSS) - v4
|
|
||||||
|
|
||||||
|
|
||||||
## Conventions
|
|
||||||
- You must follow all existing code conventions used in this application. When creating or editing a file, check sibling files for the correct structure, approach, naming.
|
|
||||||
- Use descriptive names for variables and methods. For example, `isRegisteredForDiscounts`, not `discount()`.
|
|
||||||
- Check for existing components to reuse before writing a new one.
|
|
||||||
|
|
||||||
## Verification Scripts
|
|
||||||
- Do not create verification scripts or tinker when tests cover that functionality and prove it works. Unit and feature tests are more important.
|
|
||||||
|
|
||||||
## Application Structure & Architecture
|
|
||||||
- Stick to existing directory structure - don't create new base folders without approval.
|
|
||||||
- Do not change the application's dependencies without approval.
|
|
||||||
|
|
||||||
## Frontend Bundling
|
|
||||||
- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run `npm run build`, `npm run dev`, or `composer run dev`. Ask them.
|
|
||||||
|
|
||||||
## Replies
|
|
||||||
- Be concise in your explanations - focus on what's important rather than explaining obvious details.
|
|
||||||
|
|
||||||
## Documentation Files
|
|
||||||
- You must only create documentation files if explicitly requested by the user.
|
|
||||||
|
|
||||||
|
|
||||||
=== boost rules ===
|
|
||||||
|
|
||||||
## Laravel Boost
|
|
||||||
- Laravel Boost is an MCP server that comes with powerful tools designed specifically for this application. Use them.
|
|
||||||
|
|
||||||
## Artisan
|
|
||||||
- Use the `list-artisan-commands` tool when you need to call an Artisan command to double check the available parameters.
|
|
||||||
|
|
||||||
## URLs
|
|
||||||
- Whenever you share a project URL with the user you should use the `get-absolute-url` tool to ensure you're using the correct scheme, domain / IP, and port.
|
|
||||||
|
|
||||||
## Tinker / Debugging
|
|
||||||
- You should use the `tinker` tool when you need to execute PHP to debug code or query Eloquent models directly.
|
|
||||||
- Use the `database-query` tool when you only need to read from the database.
|
|
||||||
|
|
||||||
## Reading Browser Logs With the `browser-logs` Tool
|
|
||||||
- You can read browser logs, errors, and exceptions using the `browser-logs` tool from Boost.
|
|
||||||
- Only recent browser logs will be useful - ignore old logs.
|
|
||||||
|
|
||||||
## Searching Documentation (Critically Important)
|
|
||||||
- Boost comes with a powerful `search-docs` tool you should use before any other approaches. This tool automatically passes a list of installed packages and their versions to the remote Boost API, so it returns only version-specific documentation specific for the user's circumstance. You should pass an array of packages to filter on if you know you need docs for particular packages.
|
|
||||||
- The 'search-docs' tool is perfect for all Laravel related packages, including Laravel, Inertia, Livewire, Filament, Tailwind, Pest, Nova, Nightwatch, etc.
|
|
||||||
- You must use this tool to search for Laravel-ecosystem documentation before falling back to other approaches.
|
|
||||||
- Search the documentation before making code changes to ensure we are taking the correct approach.
|
|
||||||
- Use multiple, broad, simple, topic based queries to start. For example: `['rate limiting', 'routing rate limiting', 'routing']`.
|
|
||||||
- Do not add package names to queries - package information is already shared. For example, use `test resource table`, not `filament 4 test resource table`.
|
|
||||||
|
|
||||||
### Available Search Syntax
|
|
||||||
- You can and should pass multiple queries at once. The most relevant results will be returned first.
|
|
||||||
|
|
||||||
1. Simple Word Searches with auto-stemming - query=authentication - finds 'authenticate' and 'auth'
|
|
||||||
2. Multiple Words (AND Logic) - query=rate limit - finds knowledge containing both "rate" AND "limit"
|
|
||||||
3. Quoted Phrases (Exact Position) - query="infinite scroll" - Words must be adjacent and in that order
|
|
||||||
4. Mixed Queries - query=middleware "rate limit" - "middleware" AND exact phrase "rate limit"
|
|
||||||
5. Multiple Queries - queries=["authentication", "middleware"] - ANY of these terms
|
|
||||||
|
|
||||||
|
|
||||||
=== php rules ===
|
|
||||||
|
|
||||||
## PHP
|
|
||||||
|
|
||||||
- Always use curly braces for control structures, even if it has one line.
|
|
||||||
|
|
||||||
### Constructors
|
|
||||||
- Use PHP 8 constructor property promotion in `__construct()`.
|
|
||||||
- <code-snippet>public function __construct(public GitHub $github) { }</code-snippet>
|
|
||||||
- Do not allow empty `__construct()` methods with zero parameters.
|
|
||||||
|
|
||||||
### Type Declarations
|
|
||||||
- Always use explicit return type declarations for methods and functions.
|
|
||||||
- Use appropriate PHP type hints for method parameters.
|
|
||||||
|
|
||||||
<code-snippet name="Explicit Return Types and Method Params" lang="php">
|
|
||||||
protected function isAccessible(User $user, ?string $path = null): bool
|
|
||||||
{
|
|
||||||
...
|
|
||||||
}
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
## Comments
|
|
||||||
- Prefer PHPDoc blocks over comments. Never use comments within the code itself unless there is something _very_ complex going on.
|
|
||||||
|
|
||||||
## PHPDoc Blocks
|
|
||||||
- Add useful array shape type definitions for arrays when appropriate.
|
|
||||||
|
|
||||||
## Enums
|
|
||||||
- Typically, keys in an Enum should be TitleCase. For example: `FavoritePerson`, `BestLake`, `Monthly`.
|
|
||||||
|
|
||||||
|
|
||||||
=== laravel/core rules ===
|
|
||||||
|
|
||||||
## Do Things the Laravel Way
|
|
||||||
|
|
||||||
- Use `php artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using the `list-artisan-commands` tool.
|
|
||||||
- If you're creating a generic PHP class, use `artisan make:class`.
|
|
||||||
- Pass `--no-interaction` to all Artisan commands to ensure they work without user input. You should also pass the correct `--options` to ensure correct behavior.
|
|
||||||
|
|
||||||
### Database
|
|
||||||
- Always use proper Eloquent relationship methods with return type hints. Prefer relationship methods over raw queries or manual joins.
|
|
||||||
- Use Eloquent models and relationships before suggesting raw database queries
|
|
||||||
- Avoid `DB::`; prefer `Model::query()`. Generate code that leverages Laravel's ORM capabilities rather than bypassing them.
|
|
||||||
- Generate code that prevents N+1 query problems by using eager loading.
|
|
||||||
- Use Laravel's query builder for very complex database operations.
|
|
||||||
|
|
||||||
### Model Creation
|
|
||||||
- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using `list-artisan-commands` to check the available options to `php artisan make:model`.
|
|
||||||
|
|
||||||
### APIs & Eloquent Resources
|
|
||||||
- For APIs, default to using Eloquent API Resources and API versioning unless existing API routes do not, then you should follow existing application convention.
|
|
||||||
|
|
||||||
### Controllers & Validation
|
|
||||||
- Always create Form Request classes for validation rather than inline validation in controllers. Include both validation rules and custom error messages.
|
|
||||||
- Check sibling Form Requests to see if the application uses array or string based validation rules.
|
|
||||||
|
|
||||||
### Queues
|
|
||||||
- Use queued jobs for time-consuming operations with the `ShouldQueue` interface.
|
|
||||||
|
|
||||||
### Authentication & Authorization
|
|
||||||
- Use Laravel's built-in authentication and authorization features (gates, policies, Sanctum, etc.).
|
|
||||||
|
|
||||||
### URL Generation
|
|
||||||
- When generating links to other pages, prefer named routes and the `route()` function.
|
|
||||||
|
|
||||||
### Configuration
|
|
||||||
- Use environment variables only in configuration files - never use the `env()` function directly outside of config files. Always use `config('app.name')`, not `env('APP_NAME')`.
|
|
||||||
|
|
||||||
### Testing
|
|
||||||
- When creating models for tests, use the factories for the models. Check if the factory has custom states that can be used before manually setting up the model.
|
|
||||||
- Faker: Use methods such as `$this->faker->word()` or `fake()->randomDigit()`. Follow existing conventions whether to use `$this->faker` or `fake()`.
|
|
||||||
- When creating tests, make use of `php artisan make:test [options] <name>` to create a feature test, and pass `--unit` to create a unit test. Most tests should be feature tests.
|
|
||||||
|
|
||||||
### Vite Error
|
|
||||||
- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run `npm run build` or ask the user to run `npm run dev` or `composer run dev`.
|
|
||||||
|
|
||||||
|
|
||||||
=== laravel/v12 rules ===
|
|
||||||
|
|
||||||
## Laravel 12
|
|
||||||
|
|
||||||
- Use the `search-docs` tool to get version specific documentation.
|
|
||||||
- Since Laravel 11, Laravel has a new streamlined file structure which this project uses.
|
|
||||||
|
|
||||||
### Laravel 12 Structure
|
|
||||||
- No middleware files in `app/Http/Middleware/`.
|
|
||||||
- `bootstrap/app.php` is the file to register middleware, exceptions, and routing files.
|
|
||||||
- `bootstrap/providers.php` contains application specific service providers.
|
|
||||||
- **No app\Console\Kernel.php** - use `bootstrap/app.php` or `routes/console.php` for console configuration.
|
|
||||||
- **Commands auto-register** - files in `app/Console/Commands/` are automatically available and do not require manual registration.
|
|
||||||
|
|
||||||
### Database
|
|
||||||
- When modifying a column, the migration must include all of the attributes that were previously defined on the column. Otherwise, they will be dropped and lost.
|
|
||||||
- Laravel 11 allows limiting eagerly loaded records natively, without external packages: `$query->latest()->limit(10);`.
|
|
||||||
|
|
||||||
### Models
|
|
||||||
- Casts can and likely should be set in a `casts()` method on a model rather than the `$casts` property. Follow existing conventions from other models.
|
|
||||||
|
|
||||||
|
|
||||||
=== fluxui-free/core rules ===
|
|
||||||
|
|
||||||
## Flux UI Free
|
|
||||||
|
|
||||||
- This project is using the free edition of Flux UI. It has full access to the free components and variants, but does not have access to the Pro components.
|
|
||||||
- Flux UI is a component library for Livewire. Flux is a robust, hand-crafted, UI component library for your Livewire applications. It's built using Tailwind CSS and provides a set of components that are easy to use and customize.
|
|
||||||
- You should use Flux UI components when available.
|
|
||||||
- Fallback to standard Blade components if Flux is unavailable.
|
|
||||||
- If available, use Laravel Boost's `search-docs` tool to get the exact documentation and code snippets available for this project.
|
|
||||||
- Flux UI components look like this:
|
|
||||||
|
|
||||||
<code-snippet name="Flux UI Component Usage Example" lang="blade">
|
|
||||||
<flux:button variant="primary"/>
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
### Available Components
|
|
||||||
This is correct as of Boost installation, but there may be additional components within the codebase.
|
|
||||||
|
|
||||||
<available-flux-components>
|
|
||||||
avatar, badge, brand, breadcrumbs, button, callout, checkbox, dropdown, field, heading, icon, input, modal, navbar, profile, radio, select, separator, switch, text, textarea, tooltip
|
|
||||||
</available-flux-components>
|
|
||||||
|
|
||||||
|
|
||||||
=== livewire/core rules ===
|
|
||||||
|
|
||||||
## Livewire Core
|
|
||||||
- Use the `search-docs` tool to find exact version specific documentation for how to write Livewire & Livewire tests.
|
|
||||||
- Use the `php artisan make:livewire [Posts\CreatePost]` artisan command to create new components
|
|
||||||
- State should live on the server, with the UI reflecting it.
|
|
||||||
- All Livewire requests hit the Laravel backend, they're like regular HTTP requests. Always validate form data, and run authorization checks in Livewire actions.
|
|
||||||
|
|
||||||
## Livewire Best Practices
|
|
||||||
- Livewire components require a single root element.
|
|
||||||
- Use `wire:loading` and `wire:dirty` for delightful loading states.
|
|
||||||
- Add `wire:key` in loops:
|
|
||||||
|
|
||||||
```blade
|
|
||||||
@foreach ($items as $item)
|
|
||||||
<div wire:key="item-{{ $item->id }}">
|
|
||||||
{{ $item->name }}
|
|
||||||
</div>
|
|
||||||
@endforeach
|
|
||||||
```
|
|
||||||
|
|
||||||
- Prefer lifecycle hooks like `mount()`, `updatedFoo()` for initialization and reactive side effects:
|
|
||||||
|
|
||||||
<code-snippet name="Lifecycle hook examples" lang="php">
|
|
||||||
public function mount(User $user) { $this->user = $user; }
|
|
||||||
public function updatedSearch() { $this->resetPage(); }
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
## Testing Livewire
|
|
||||||
|
|
||||||
<code-snippet name="Example Livewire component test" lang="php">
|
|
||||||
Livewire::test(Counter::class)
|
|
||||||
->assertSet('count', 0)
|
|
||||||
->call('increment')
|
|
||||||
->assertSet('count', 1)
|
|
||||||
->assertSee(1)
|
|
||||||
->assertStatus(200);
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
<code-snippet name="Testing a Livewire component exists within a page" lang="php">
|
|
||||||
$this->get('/posts/create')
|
|
||||||
->assertSeeLivewire(CreatePost::class);
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
=== livewire/v3 rules ===
|
|
||||||
|
|
||||||
## Livewire 3
|
|
||||||
|
|
||||||
### Key Changes From Livewire 2
|
|
||||||
- These things changed in Livewire 2, but may not have been updated in this application. Verify this application's setup to ensure you conform with application conventions.
|
|
||||||
- Use `wire:model.live` for real-time updates, `wire:model` is now deferred by default.
|
|
||||||
- Components now use the `App\Livewire` namespace (not `App\Http\Livewire`).
|
|
||||||
- Use `$this->dispatch()` to dispatch events (not `emit` or `dispatchBrowserEvent`).
|
|
||||||
- Use the `components.layouts.app` view as the typical layout path (not `layouts.app`).
|
|
||||||
|
|
||||||
### New Directives
|
|
||||||
- `wire:show`, `wire:transition`, `wire:cloak`, `wire:offline`, `wire:target` are available for use. Use the documentation to find usage examples.
|
|
||||||
|
|
||||||
### Alpine
|
|
||||||
- Alpine is now included with Livewire, don't manually include Alpine.js.
|
|
||||||
- Plugins included with Alpine: persist, intersect, collapse, and focus.
|
|
||||||
|
|
||||||
### Lifecycle Hooks
|
|
||||||
- You can listen for `livewire:init` to hook into Livewire initialization, and `fail.status === 419` for the page expiring:
|
|
||||||
|
|
||||||
<code-snippet name="livewire:load example" lang="js">
|
|
||||||
document.addEventListener('livewire:init', function () {
|
|
||||||
Livewire.hook('request', ({ fail }) => {
|
|
||||||
if (fail && fail.status === 419) {
|
|
||||||
alert('Your session expired');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Livewire.hook('message.failed', (message, component) => {
|
|
||||||
console.error(message);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
=== volt/core rules ===
|
|
||||||
|
|
||||||
## Livewire Volt
|
|
||||||
|
|
||||||
- This project uses Livewire Volt for interactivity within its pages. New pages requiring interactivity must also use Livewire Volt. There is documentation available for it.
|
|
||||||
- Make new Volt components using `php artisan make:volt [name] [--test] [--pest]`
|
|
||||||
- Volt is a **class-based** and **functional** API for Livewire that supports single-file components, allowing a component's PHP logic and Blade templates to co-exist in the same file
|
|
||||||
- Livewire Volt allows PHP logic and Blade templates in one file. Components use the `@livewire("volt-anonymous-fragment-eyJuYW1lIjoidm9sdC1hbm9ueW1vdXMtZnJhZ21lbnQtYmQ5YWJiNTE3YWMyMTgwOTA1ZmUxMzAxODk0MGJiZmIiLCJwYXRoIjoic3RvcmFnZVwvZnJhbWV3b3JrXC92aWV3c1wvMTUxYWRjZWRjMzBhMzllOWIxNzQ0ZDRiMWRjY2FjYWIuYmxhZGUucGhwIn0=", Livewire\Volt\Precompilers\ExtractFragments::componentArguments([...get_defined_vars(), ...array (
|
|
||||||
)]))
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
### Volt Class Based Component Example
|
|
||||||
To get started, define an anonymous class that extends Livewire\Volt\Component. Within the class, you may utilize all of the features of Livewire using traditional Livewire syntax:
|
|
||||||
|
|
||||||
|
|
||||||
<code-snippet name="Volt Class-based Volt Component Example" lang="php">
|
|
||||||
use Livewire\Volt\Component;
|
|
||||||
|
|
||||||
new class extends Component {
|
|
||||||
public $count = 0;
|
|
||||||
|
|
||||||
public function increment()
|
|
||||||
{
|
|
||||||
$this->count++;
|
|
||||||
}
|
|
||||||
} ?>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<h1>{{ $count }}</h1>
|
|
||||||
<button wire:click="increment">+</button>
|
|
||||||
</div>
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
### Testing Volt & Volt Components
|
|
||||||
- Use the existing directory for tests if it already exists. Otherwise, fallback to `tests/Feature/Volt`.
|
|
||||||
|
|
||||||
<code-snippet name="Livewire Test Example" lang="php">
|
|
||||||
use Livewire\Volt\Volt;
|
|
||||||
|
|
||||||
test('counter increments', function () {
|
|
||||||
Volt::test('counter')
|
|
||||||
->assertSee('Count: 0')
|
|
||||||
->call('increment')
|
|
||||||
->assertSee('Count: 1');
|
|
||||||
});
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
<code-snippet name="Volt Component Test Using Pest" lang="php">
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
use App\Models\{User, Product};
|
|
||||||
use Livewire\Volt\Volt;
|
|
||||||
|
|
||||||
test('product form creates product', function () {
|
|
||||||
$user = User::factory()->create();
|
|
||||||
|
|
||||||
Volt::test('pages.products.create')
|
|
||||||
->actingAs($user)
|
|
||||||
->set('form.name', 'Test Product')
|
|
||||||
->set('form.description', 'Test Description')
|
|
||||||
->set('form.price', 99.99)
|
|
||||||
->call('create')
|
|
||||||
->assertHasNoErrors();
|
|
||||||
|
|
||||||
expect(Product::where('name', 'Test Product')->exists())->toBeTrue();
|
|
||||||
});
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
### Common Patterns
|
|
||||||
|
|
||||||
|
|
||||||
<code-snippet name="CRUD With Volt" lang="php">
|
|
||||||
<?php
|
|
||||||
|
|
||||||
use App\Models\Product;
|
|
||||||
use function Livewire\Volt\{state, computed};
|
|
||||||
|
|
||||||
state(['editing' => null, 'search' => '']);
|
|
||||||
|
|
||||||
$products = computed(fn() => Product::when($this->search,
|
|
||||||
fn($q) => $q->where('name', 'like', "%{$this->search}%")
|
|
||||||
)->get());
|
|
||||||
|
|
||||||
$edit = fn(Product $product) => $this->editing = $product->id;
|
|
||||||
$delete = fn(Product $product) => $product->delete();
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
||||||
<!-- HTML / UI Here -->
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
<code-snippet name="Real-Time Search With Volt" lang="php">
|
|
||||||
<flux:input
|
|
||||||
wire:model.live.debounce.300ms="search"
|
|
||||||
placeholder="Search..."
|
|
||||||
/>
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
<code-snippet name="Loading States With Volt" lang="php">
|
|
||||||
<flux:button wire:click="save" wire:loading.attr="disabled">
|
|
||||||
<span wire:loading.remove>Save</span>
|
|
||||||
<span wire:loading>Saving...</span>
|
|
||||||
</flux:button>
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
=== pint/core rules ===
|
|
||||||
|
|
||||||
## Laravel Pint Code Formatter
|
|
||||||
|
|
||||||
- You must run `vendor/bin/pint --dirty` before finalizing changes to ensure your code matches the project's expected style.
|
|
||||||
- Do not run `vendor/bin/pint --test`, simply run `vendor/bin/pint` to fix any formatting issues.
|
|
||||||
|
|
||||||
|
|
||||||
=== pest/core rules ===
|
|
||||||
|
|
||||||
## Pest
|
|
||||||
|
|
||||||
### Testing
|
|
||||||
- If you need to verify a feature is working, write or update a Unit / Feature test.
|
|
||||||
|
|
||||||
### Pest Tests
|
|
||||||
- All tests must be written using Pest. Use `php artisan make:test --pest <name>`.
|
|
||||||
- You must not remove any tests or test files from the tests directory without approval. These are not temporary or helper files - these are core to the application.
|
|
||||||
- Tests should test all of the happy paths, failure paths, and weird paths.
|
|
||||||
- Tests live in the `tests/Feature` and `tests/Unit` directories.
|
|
||||||
- Pest tests look and behave like this:
|
|
||||||
<code-snippet name="Basic Pest Test Example" lang="php">
|
|
||||||
it('is true', function () {
|
|
||||||
expect(true)->toBeTrue();
|
|
||||||
});
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
### Running Tests
|
|
||||||
- Run the minimal number of tests using an appropriate filter before finalizing code edits.
|
|
||||||
- To run all tests: `php artisan test`.
|
|
||||||
- To run all tests in a file: `php artisan test tests/Feature/ExampleTest.php`.
|
|
||||||
- To filter on a particular test name: `php artisan test --filter=testName` (recommended after making a change to a related file).
|
|
||||||
- When the tests relating to your changes are passing, ask the user if they would like to run the entire test suite to ensure everything is still passing.
|
|
||||||
|
|
||||||
### Pest Assertions
|
|
||||||
- When asserting status codes on a response, use the specific method like `assertForbidden` and `assertNotFound` instead of using `assertStatus(403)` or similar, e.g.:
|
|
||||||
<code-snippet name="Pest Example Asserting postJson Response" lang="php">
|
|
||||||
it('returns all', function () {
|
|
||||||
$response = $this->postJson('/api/docs', []);
|
|
||||||
|
|
||||||
$response->assertSuccessful();
|
|
||||||
});
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
### Mocking
|
|
||||||
- Mocking can be very helpful when appropriate.
|
|
||||||
- When mocking, you can use the `Pest\Laravel\mock` Pest function, but always import it via `use function Pest\Laravel\mock;` before using it. Alternatively, you can use `$this->mock()` if existing tests do.
|
|
||||||
- You can also create partial mocks using the same import or self method.
|
|
||||||
|
|
||||||
### Datasets
|
|
||||||
- Use datasets in Pest to simplify tests which have a lot of duplicated data. This is often the case when testing validation rules, so consider going with this solution when writing tests for validation rules.
|
|
||||||
|
|
||||||
<code-snippet name="Pest Dataset Example" lang="php">
|
|
||||||
it('has emails', function (string $email) {
|
|
||||||
expect($email)->not->toBeEmpty();
|
|
||||||
})->with([
|
|
||||||
'james' => 'james@laravel.com',
|
|
||||||
'taylor' => 'taylor@laravel.com',
|
|
||||||
]);
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
=== pest/v4 rules ===
|
|
||||||
|
|
||||||
## Pest 4
|
|
||||||
|
|
||||||
- Pest v4 is a huge upgrade to Pest and offers: browser testing, smoke testing, visual regression testing, test sharding, and faster type coverage.
|
|
||||||
- Browser testing is incredibly powerful and useful for this project.
|
|
||||||
- Browser tests should live in `tests/Browser/`.
|
|
||||||
- Use the `search-docs` tool for detailed guidance on utilizing these features.
|
|
||||||
|
|
||||||
### Browser Testing
|
|
||||||
- You can use Laravel features like `Event::fake()`, `assertAuthenticated()`, and model factories within Pest v4 browser tests, as well as `RefreshDatabase` (when needed) to ensure a clean state for each test.
|
|
||||||
- Interact with the page (click, type, scroll, select, submit, drag-and-drop, touch gestures, etc.) when appropriate to complete the test.
|
|
||||||
- If requested, test on multiple browsers (Chrome, Firefox, Safari).
|
|
||||||
- If requested, test on different devices and viewports (like iPhone 14 Pro, tablets, or custom breakpoints).
|
|
||||||
- Switch color schemes (light/dark mode) when appropriate.
|
|
||||||
- Take screenshots or pause tests for debugging when appropriate.
|
|
||||||
|
|
||||||
### Example Tests
|
|
||||||
|
|
||||||
<code-snippet name="Pest Browser Test Example" lang="php">
|
|
||||||
it('may reset the password', function () {
|
|
||||||
Notification::fake();
|
|
||||||
|
|
||||||
$this->actingAs(User::factory()->create());
|
|
||||||
|
|
||||||
$page = visit('/sign-in'); // Visit on a real browser...
|
|
||||||
|
|
||||||
$page->assertSee('Sign In')
|
|
||||||
->assertNoJavascriptErrors() // or ->assertNoConsoleLogs()
|
|
||||||
->click('Forgot Password?')
|
|
||||||
->fill('email', 'nuno@laravel.com')
|
|
||||||
->click('Send Reset Link')
|
|
||||||
->assertSee('We have emailed your password reset link!')
|
|
||||||
|
|
||||||
Notification::assertSent(ResetPassword::class);
|
|
||||||
});
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
<code-snippet name="Pest Smoke Testing Example" lang="php">
|
|
||||||
$pages = visit(['/', '/about', '/contact']);
|
|
||||||
|
|
||||||
$pages->assertNoJavascriptErrors()->assertNoConsoleLogs();
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
=== tailwindcss/core rules ===
|
|
||||||
|
|
||||||
## Tailwind Core
|
|
||||||
|
|
||||||
- Use Tailwind CSS classes to style HTML, check and use existing tailwind conventions within the project before writing your own.
|
|
||||||
- Offer to extract repeated patterns into components that match the project's conventions (i.e. Blade, JSX, Vue, etc..)
|
|
||||||
- Think through class placement, order, priority, and defaults - remove redundant classes, add classes to parent or child carefully to limit repetition, group elements logically
|
|
||||||
- You can use the `search-docs` tool to get exact examples from the official documentation when needed.
|
|
||||||
|
|
||||||
### Spacing
|
|
||||||
- When listing items, use gap utilities for spacing, don't use margins.
|
|
||||||
|
|
||||||
<code-snippet name="Valid Flex Gap Spacing Example" lang="html">
|
|
||||||
<div class="flex gap-8">
|
|
||||||
<div>Superior</div>
|
|
||||||
<div>Michigan</div>
|
|
||||||
<div>Erie</div>
|
|
||||||
</div>
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
### Dark Mode
|
|
||||||
- If existing pages and components support dark mode, new pages and components must support dark mode in a similar way, typically using `dark:`.
|
|
||||||
|
|
||||||
|
|
||||||
=== tailwindcss/v4 rules ===
|
|
||||||
|
|
||||||
## Tailwind 4
|
|
||||||
|
|
||||||
- Always use Tailwind CSS v4 - do not use the deprecated utilities.
|
|
||||||
- `corePlugins` is not supported in Tailwind v4.
|
|
||||||
- In Tailwind v4, you import Tailwind using a regular CSS `@import` statement, not using the `@tailwind` directives used in v3:
|
|
||||||
|
|
||||||
<code-snippet name="Tailwind v4 Import Tailwind Diff" lang="diff">
|
|
||||||
- @tailwind base;
|
|
||||||
- @tailwind components;
|
|
||||||
- @tailwind utilities;
|
|
||||||
+ @import "tailwindcss";
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
### Replaced Utilities
|
|
||||||
- Tailwind v4 removed deprecated utilities. Do not use the deprecated option - use the replacement.
|
|
||||||
- Opacity values are still numeric.
|
|
||||||
|
|
||||||
| Deprecated | Replacement |
|
|
||||||
|------------+--------------|
|
|
||||||
| bg-opacity-* | bg-black/* |
|
|
||||||
| text-opacity-* | text-black/* |
|
|
||||||
| border-opacity-* | border-black/* |
|
|
||||||
| divide-opacity-* | divide-black/* |
|
|
||||||
| ring-opacity-* | ring-black/* |
|
|
||||||
| placeholder-opacity-* | placeholder-black/* |
|
|
||||||
| flex-shrink-* | shrink-* |
|
|
||||||
| flex-grow-* | grow-* |
|
|
||||||
| overflow-ellipsis | text-ellipsis |
|
|
||||||
| decoration-slice | box-decoration-slice |
|
|
||||||
| decoration-clone | box-decoration-clone |
|
|
||||||
|
|
||||||
|
|
||||||
=== tests rules ===
|
|
||||||
|
|
||||||
## Test Enforcement
|
|
||||||
|
|
||||||
- Every change must be programmatically tested. Write a new test or update an existing test, then run the affected tests to make sure they pass.
|
|
||||||
- Run the minimum number of tests needed to ensure code quality and speed. Use `php artisan test` with a specific filename or filter.
|
|
||||||
</laravel-boost-guidelines>
|
|
||||||
11
.mcp.json
11
.mcp.json
|
|
@ -1,11 +0,0 @@
|
||||||
{
|
|
||||||
"mcpServers": {
|
|
||||||
"laravel-boost": {
|
|
||||||
"command": "php",
|
|
||||||
"args": [
|
|
||||||
"artisan",
|
|
||||||
"boost:mcp"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
578
CLAUDE.md
578
CLAUDE.md
|
|
@ -1,578 +0,0 @@
|
||||||
<laravel-boost-guidelines>
|
|
||||||
=== foundation rules ===
|
|
||||||
|
|
||||||
# Laravel Boost Guidelines
|
|
||||||
|
|
||||||
The Laravel Boost guidelines are specifically curated by Laravel maintainers for this application. These guidelines should be followed closely to enhance the user's satisfaction building Laravel applications.
|
|
||||||
|
|
||||||
## Foundational Context
|
|
||||||
This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions.
|
|
||||||
|
|
||||||
- php - 8.4.13
|
|
||||||
- laravel/framework (LARAVEL) - v12
|
|
||||||
- laravel/prompts (PROMPTS) - v0
|
|
||||||
- laravel/sanctum (SANCTUM) - v4
|
|
||||||
- laravel/socialite (SOCIALITE) - v5
|
|
||||||
- livewire/flux (FLUXUI_FREE) - v2
|
|
||||||
- livewire/livewire (LIVEWIRE) - v3
|
|
||||||
- livewire/volt (VOLT) - v1
|
|
||||||
- larastan/larastan (LARASTAN) - v3
|
|
||||||
- laravel/mcp (MCP) - v0
|
|
||||||
- laravel/pint (PINT) - v1
|
|
||||||
- laravel/sail (SAIL) - v1
|
|
||||||
- pestphp/pest (PEST) - v4
|
|
||||||
- phpunit/phpunit (PHPUNIT) - v12
|
|
||||||
- rector/rector (RECTOR) - v2
|
|
||||||
- tailwindcss (TAILWINDCSS) - v4
|
|
||||||
|
|
||||||
|
|
||||||
## Conventions
|
|
||||||
- You must follow all existing code conventions used in this application. When creating or editing a file, check sibling files for the correct structure, approach, naming.
|
|
||||||
- Use descriptive names for variables and methods. For example, `isRegisteredForDiscounts`, not `discount()`.
|
|
||||||
- Check for existing components to reuse before writing a new one.
|
|
||||||
|
|
||||||
## Verification Scripts
|
|
||||||
- Do not create verification scripts or tinker when tests cover that functionality and prove it works. Unit and feature tests are more important.
|
|
||||||
|
|
||||||
## Application Structure & Architecture
|
|
||||||
- Stick to existing directory structure - don't create new base folders without approval.
|
|
||||||
- Do not change the application's dependencies without approval.
|
|
||||||
|
|
||||||
## Frontend Bundling
|
|
||||||
- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run `npm run build`, `npm run dev`, or `composer run dev`. Ask them.
|
|
||||||
|
|
||||||
## Replies
|
|
||||||
- Be concise in your explanations - focus on what's important rather than explaining obvious details.
|
|
||||||
|
|
||||||
## Documentation Files
|
|
||||||
- You must only create documentation files if explicitly requested by the user.
|
|
||||||
|
|
||||||
|
|
||||||
=== boost rules ===
|
|
||||||
|
|
||||||
## Laravel Boost
|
|
||||||
- Laravel Boost is an MCP server that comes with powerful tools designed specifically for this application. Use them.
|
|
||||||
|
|
||||||
## Artisan
|
|
||||||
- Use the `list-artisan-commands` tool when you need to call an Artisan command to double check the available parameters.
|
|
||||||
|
|
||||||
## URLs
|
|
||||||
- Whenever you share a project URL with the user you should use the `get-absolute-url` tool to ensure you're using the correct scheme, domain / IP, and port.
|
|
||||||
|
|
||||||
## Tinker / Debugging
|
|
||||||
- You should use the `tinker` tool when you need to execute PHP to debug code or query Eloquent models directly.
|
|
||||||
- Use the `database-query` tool when you only need to read from the database.
|
|
||||||
|
|
||||||
## Reading Browser Logs With the `browser-logs` Tool
|
|
||||||
- You can read browser logs, errors, and exceptions using the `browser-logs` tool from Boost.
|
|
||||||
- Only recent browser logs will be useful - ignore old logs.
|
|
||||||
|
|
||||||
## Searching Documentation (Critically Important)
|
|
||||||
- Boost comes with a powerful `search-docs` tool you should use before any other approaches. This tool automatically passes a list of installed packages and their versions to the remote Boost API, so it returns only version-specific documentation specific for the user's circumstance. You should pass an array of packages to filter on if you know you need docs for particular packages.
|
|
||||||
- The 'search-docs' tool is perfect for all Laravel related packages, including Laravel, Inertia, Livewire, Filament, Tailwind, Pest, Nova, Nightwatch, etc.
|
|
||||||
- You must use this tool to search for Laravel-ecosystem documentation before falling back to other approaches.
|
|
||||||
- Search the documentation before making code changes to ensure we are taking the correct approach.
|
|
||||||
- Use multiple, broad, simple, topic based queries to start. For example: `['rate limiting', 'routing rate limiting', 'routing']`.
|
|
||||||
- Do not add package names to queries - package information is already shared. For example, use `test resource table`, not `filament 4 test resource table`.
|
|
||||||
|
|
||||||
### Available Search Syntax
|
|
||||||
- You can and should pass multiple queries at once. The most relevant results will be returned first.
|
|
||||||
|
|
||||||
1. Simple Word Searches with auto-stemming - query=authentication - finds 'authenticate' and 'auth'
|
|
||||||
2. Multiple Words (AND Logic) - query=rate limit - finds knowledge containing both "rate" AND "limit"
|
|
||||||
3. Quoted Phrases (Exact Position) - query="infinite scroll" - Words must be adjacent and in that order
|
|
||||||
4. Mixed Queries - query=middleware "rate limit" - "middleware" AND exact phrase "rate limit"
|
|
||||||
5. Multiple Queries - queries=["authentication", "middleware"] - ANY of these terms
|
|
||||||
|
|
||||||
|
|
||||||
=== php rules ===
|
|
||||||
|
|
||||||
## PHP
|
|
||||||
|
|
||||||
- Always use curly braces for control structures, even if it has one line.
|
|
||||||
|
|
||||||
### Constructors
|
|
||||||
- Use PHP 8 constructor property promotion in `__construct()`.
|
|
||||||
- <code-snippet>public function __construct(public GitHub $github) { }</code-snippet>
|
|
||||||
- Do not allow empty `__construct()` methods with zero parameters.
|
|
||||||
|
|
||||||
### Type Declarations
|
|
||||||
- Always use explicit return type declarations for methods and functions.
|
|
||||||
- Use appropriate PHP type hints for method parameters.
|
|
||||||
|
|
||||||
<code-snippet name="Explicit Return Types and Method Params" lang="php">
|
|
||||||
protected function isAccessible(User $user, ?string $path = null): bool
|
|
||||||
{
|
|
||||||
...
|
|
||||||
}
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
## Comments
|
|
||||||
- Prefer PHPDoc blocks over comments. Never use comments within the code itself unless there is something _very_ complex going on.
|
|
||||||
|
|
||||||
## PHPDoc Blocks
|
|
||||||
- Add useful array shape type definitions for arrays when appropriate.
|
|
||||||
|
|
||||||
## Enums
|
|
||||||
- Typically, keys in an Enum should be TitleCase. For example: `FavoritePerson`, `BestLake`, `Monthly`.
|
|
||||||
|
|
||||||
|
|
||||||
=== laravel/core rules ===
|
|
||||||
|
|
||||||
## Do Things the Laravel Way
|
|
||||||
|
|
||||||
- Use `php artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using the `list-artisan-commands` tool.
|
|
||||||
- If you're creating a generic PHP class, use `artisan make:class`.
|
|
||||||
- Pass `--no-interaction` to all Artisan commands to ensure they work without user input. You should also pass the correct `--options` to ensure correct behavior.
|
|
||||||
|
|
||||||
### Database
|
|
||||||
- Always use proper Eloquent relationship methods with return type hints. Prefer relationship methods over raw queries or manual joins.
|
|
||||||
- Use Eloquent models and relationships before suggesting raw database queries
|
|
||||||
- Avoid `DB::`; prefer `Model::query()`. Generate code that leverages Laravel's ORM capabilities rather than bypassing them.
|
|
||||||
- Generate code that prevents N+1 query problems by using eager loading.
|
|
||||||
- Use Laravel's query builder for very complex database operations.
|
|
||||||
|
|
||||||
### Model Creation
|
|
||||||
- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using `list-artisan-commands` to check the available options to `php artisan make:model`.
|
|
||||||
|
|
||||||
### APIs & Eloquent Resources
|
|
||||||
- For APIs, default to using Eloquent API Resources and API versioning unless existing API routes do not, then you should follow existing application convention.
|
|
||||||
|
|
||||||
### Controllers & Validation
|
|
||||||
- Always create Form Request classes for validation rather than inline validation in controllers. Include both validation rules and custom error messages.
|
|
||||||
- Check sibling Form Requests to see if the application uses array or string based validation rules.
|
|
||||||
|
|
||||||
### Queues
|
|
||||||
- Use queued jobs for time-consuming operations with the `ShouldQueue` interface.
|
|
||||||
|
|
||||||
### Authentication & Authorization
|
|
||||||
- Use Laravel's built-in authentication and authorization features (gates, policies, Sanctum, etc.).
|
|
||||||
|
|
||||||
### URL Generation
|
|
||||||
- When generating links to other pages, prefer named routes and the `route()` function.
|
|
||||||
|
|
||||||
### Configuration
|
|
||||||
- Use environment variables only in configuration files - never use the `env()` function directly outside of config files. Always use `config('app.name')`, not `env('APP_NAME')`.
|
|
||||||
|
|
||||||
### Testing
|
|
||||||
- When creating models for tests, use the factories for the models. Check if the factory has custom states that can be used before manually setting up the model.
|
|
||||||
- Faker: Use methods such as `$this->faker->word()` or `fake()->randomDigit()`. Follow existing conventions whether to use `$this->faker` or `fake()`.
|
|
||||||
- When creating tests, make use of `php artisan make:test [options] <name>` to create a feature test, and pass `--unit` to create a unit test. Most tests should be feature tests.
|
|
||||||
|
|
||||||
### Vite Error
|
|
||||||
- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run `npm run build` or ask the user to run `npm run dev` or `composer run dev`.
|
|
||||||
|
|
||||||
|
|
||||||
=== laravel/v12 rules ===
|
|
||||||
|
|
||||||
## Laravel 12
|
|
||||||
|
|
||||||
- Use the `search-docs` tool to get version specific documentation.
|
|
||||||
- Since Laravel 11, Laravel has a new streamlined file structure which this project uses.
|
|
||||||
|
|
||||||
### Laravel 12 Structure
|
|
||||||
- No middleware files in `app/Http/Middleware/`.
|
|
||||||
- `bootstrap/app.php` is the file to register middleware, exceptions, and routing files.
|
|
||||||
- `bootstrap/providers.php` contains application specific service providers.
|
|
||||||
- **No app\Console\Kernel.php** - use `bootstrap/app.php` or `routes/console.php` for console configuration.
|
|
||||||
- **Commands auto-register** - files in `app/Console/Commands/` are automatically available and do not require manual registration.
|
|
||||||
|
|
||||||
### Database
|
|
||||||
- When modifying a column, the migration must include all of the attributes that were previously defined on the column. Otherwise, they will be dropped and lost.
|
|
||||||
- Laravel 11 allows limiting eagerly loaded records natively, without external packages: `$query->latest()->limit(10);`.
|
|
||||||
|
|
||||||
### Models
|
|
||||||
- Casts can and likely should be set in a `casts()` method on a model rather than the `$casts` property. Follow existing conventions from other models.
|
|
||||||
|
|
||||||
|
|
||||||
=== fluxui-free/core rules ===
|
|
||||||
|
|
||||||
## Flux UI Free
|
|
||||||
|
|
||||||
- This project is using the free edition of Flux UI. It has full access to the free components and variants, but does not have access to the Pro components.
|
|
||||||
- Flux UI is a component library for Livewire. Flux is a robust, hand-crafted, UI component library for your Livewire applications. It's built using Tailwind CSS and provides a set of components that are easy to use and customize.
|
|
||||||
- You should use Flux UI components when available.
|
|
||||||
- Fallback to standard Blade components if Flux is unavailable.
|
|
||||||
- If available, use Laravel Boost's `search-docs` tool to get the exact documentation and code snippets available for this project.
|
|
||||||
- Flux UI components look like this:
|
|
||||||
|
|
||||||
<code-snippet name="Flux UI Component Usage Example" lang="blade">
|
|
||||||
<flux:button variant="primary"/>
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
### Available Components
|
|
||||||
This is correct as of Boost installation, but there may be additional components within the codebase.
|
|
||||||
|
|
||||||
<available-flux-components>
|
|
||||||
avatar, badge, brand, breadcrumbs, button, callout, checkbox, dropdown, field, heading, icon, input, modal, navbar, profile, radio, select, separator, switch, text, textarea, tooltip
|
|
||||||
</available-flux-components>
|
|
||||||
|
|
||||||
|
|
||||||
=== livewire/core rules ===
|
|
||||||
|
|
||||||
## Livewire Core
|
|
||||||
- Use the `search-docs` tool to find exact version specific documentation for how to write Livewire & Livewire tests.
|
|
||||||
- Use the `php artisan make:livewire [Posts\CreatePost]` artisan command to create new components
|
|
||||||
- State should live on the server, with the UI reflecting it.
|
|
||||||
- All Livewire requests hit the Laravel backend, they're like regular HTTP requests. Always validate form data, and run authorization checks in Livewire actions.
|
|
||||||
|
|
||||||
## Livewire Best Practices
|
|
||||||
- Livewire components require a single root element.
|
|
||||||
- Use `wire:loading` and `wire:dirty` for delightful loading states.
|
|
||||||
- Add `wire:key` in loops:
|
|
||||||
|
|
||||||
```blade
|
|
||||||
@foreach ($items as $item)
|
|
||||||
<div wire:key="item-{{ $item->id }}">
|
|
||||||
{{ $item->name }}
|
|
||||||
</div>
|
|
||||||
@endforeach
|
|
||||||
```
|
|
||||||
|
|
||||||
- Prefer lifecycle hooks like `mount()`, `updatedFoo()` for initialization and reactive side effects:
|
|
||||||
|
|
||||||
<code-snippet name="Lifecycle hook examples" lang="php">
|
|
||||||
public function mount(User $user) { $this->user = $user; }
|
|
||||||
public function updatedSearch() { $this->resetPage(); }
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
## Testing Livewire
|
|
||||||
|
|
||||||
<code-snippet name="Example Livewire component test" lang="php">
|
|
||||||
Livewire::test(Counter::class)
|
|
||||||
->assertSet('count', 0)
|
|
||||||
->call('increment')
|
|
||||||
->assertSet('count', 1)
|
|
||||||
->assertSee(1)
|
|
||||||
->assertStatus(200);
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
<code-snippet name="Testing a Livewire component exists within a page" lang="php">
|
|
||||||
$this->get('/posts/create')
|
|
||||||
->assertSeeLivewire(CreatePost::class);
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
=== livewire/v3 rules ===
|
|
||||||
|
|
||||||
## Livewire 3
|
|
||||||
|
|
||||||
### Key Changes From Livewire 2
|
|
||||||
- These things changed in Livewire 2, but may not have been updated in this application. Verify this application's setup to ensure you conform with application conventions.
|
|
||||||
- Use `wire:model.live` for real-time updates, `wire:model` is now deferred by default.
|
|
||||||
- Components now use the `App\Livewire` namespace (not `App\Http\Livewire`).
|
|
||||||
- Use `$this->dispatch()` to dispatch events (not `emit` or `dispatchBrowserEvent`).
|
|
||||||
- Use the `components.layouts.app` view as the typical layout path (not `layouts.app`).
|
|
||||||
|
|
||||||
### New Directives
|
|
||||||
- `wire:show`, `wire:transition`, `wire:cloak`, `wire:offline`, `wire:target` are available for use. Use the documentation to find usage examples.
|
|
||||||
|
|
||||||
### Alpine
|
|
||||||
- Alpine is now included with Livewire, don't manually include Alpine.js.
|
|
||||||
- Plugins included with Alpine: persist, intersect, collapse, and focus.
|
|
||||||
|
|
||||||
### Lifecycle Hooks
|
|
||||||
- You can listen for `livewire:init` to hook into Livewire initialization, and `fail.status === 419` for the page expiring:
|
|
||||||
|
|
||||||
<code-snippet name="livewire:load example" lang="js">
|
|
||||||
document.addEventListener('livewire:init', function () {
|
|
||||||
Livewire.hook('request', ({ fail }) => {
|
|
||||||
if (fail && fail.status === 419) {
|
|
||||||
alert('Your session expired');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Livewire.hook('message.failed', (message, component) => {
|
|
||||||
console.error(message);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
=== volt/core rules ===
|
|
||||||
|
|
||||||
## Livewire Volt
|
|
||||||
|
|
||||||
- This project uses Livewire Volt for interactivity within its pages. New pages requiring interactivity must also use Livewire Volt. There is documentation available for it.
|
|
||||||
- Make new Volt components using `php artisan make:volt [name] [--test] [--pest]`
|
|
||||||
- Volt is a **class-based** and **functional** API for Livewire that supports single-file components, allowing a component's PHP logic and Blade templates to co-exist in the same file
|
|
||||||
- Livewire Volt allows PHP logic and Blade templates in one file. Components use the `@livewire("volt-anonymous-fragment-eyJuYW1lIjoidm9sdC1hbm9ueW1vdXMtZnJhZ21lbnQtYmQ5YWJiNTE3YWMyMTgwOTA1ZmUxMzAxODk0MGJiZmIiLCJwYXRoIjoic3RvcmFnZVwvZnJhbWV3b3JrXC92aWV3c1wvMTUxYWRjZWRjMzBhMzllOWIxNzQ0ZDRiMWRjY2FjYWIuYmxhZGUucGhwIn0=", Livewire\Volt\Precompilers\ExtractFragments::componentArguments([...get_defined_vars(), ...array (
|
|
||||||
)]))
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
### Volt Class Based Component Example
|
|
||||||
To get started, define an anonymous class that extends Livewire\Volt\Component. Within the class, you may utilize all of the features of Livewire using traditional Livewire syntax:
|
|
||||||
|
|
||||||
|
|
||||||
<code-snippet name="Volt Class-based Volt Component Example" lang="php">
|
|
||||||
use Livewire\Volt\Component;
|
|
||||||
|
|
||||||
new class extends Component {
|
|
||||||
public $count = 0;
|
|
||||||
|
|
||||||
public function increment()
|
|
||||||
{
|
|
||||||
$this->count++;
|
|
||||||
}
|
|
||||||
} ?>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<h1>{{ $count }}</h1>
|
|
||||||
<button wire:click="increment">+</button>
|
|
||||||
</div>
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
### Testing Volt & Volt Components
|
|
||||||
- Use the existing directory for tests if it already exists. Otherwise, fallback to `tests/Feature/Volt`.
|
|
||||||
|
|
||||||
<code-snippet name="Livewire Test Example" lang="php">
|
|
||||||
use Livewire\Volt\Volt;
|
|
||||||
|
|
||||||
test('counter increments', function () {
|
|
||||||
Volt::test('counter')
|
|
||||||
->assertSee('Count: 0')
|
|
||||||
->call('increment')
|
|
||||||
->assertSee('Count: 1');
|
|
||||||
});
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
<code-snippet name="Volt Component Test Using Pest" lang="php">
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
use App\Models\{User, Product};
|
|
||||||
use Livewire\Volt\Volt;
|
|
||||||
|
|
||||||
test('product form creates product', function () {
|
|
||||||
$user = User::factory()->create();
|
|
||||||
|
|
||||||
Volt::test('pages.products.create')
|
|
||||||
->actingAs($user)
|
|
||||||
->set('form.name', 'Test Product')
|
|
||||||
->set('form.description', 'Test Description')
|
|
||||||
->set('form.price', 99.99)
|
|
||||||
->call('create')
|
|
||||||
->assertHasNoErrors();
|
|
||||||
|
|
||||||
expect(Product::where('name', 'Test Product')->exists())->toBeTrue();
|
|
||||||
});
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
### Common Patterns
|
|
||||||
|
|
||||||
|
|
||||||
<code-snippet name="CRUD With Volt" lang="php">
|
|
||||||
<?php
|
|
||||||
|
|
||||||
use App\Models\Product;
|
|
||||||
use function Livewire\Volt\{state, computed};
|
|
||||||
|
|
||||||
state(['editing' => null, 'search' => '']);
|
|
||||||
|
|
||||||
$products = computed(fn() => Product::when($this->search,
|
|
||||||
fn($q) => $q->where('name', 'like', "%{$this->search}%")
|
|
||||||
)->get());
|
|
||||||
|
|
||||||
$edit = fn(Product $product) => $this->editing = $product->id;
|
|
||||||
$delete = fn(Product $product) => $product->delete();
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
||||||
<!-- HTML / UI Here -->
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
<code-snippet name="Real-Time Search With Volt" lang="php">
|
|
||||||
<flux:input
|
|
||||||
wire:model.live.debounce.300ms="search"
|
|
||||||
placeholder="Search..."
|
|
||||||
/>
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
<code-snippet name="Loading States With Volt" lang="php">
|
|
||||||
<flux:button wire:click="save" wire:loading.attr="disabled">
|
|
||||||
<span wire:loading.remove>Save</span>
|
|
||||||
<span wire:loading>Saving...</span>
|
|
||||||
</flux:button>
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
=== pint/core rules ===
|
|
||||||
|
|
||||||
## Laravel Pint Code Formatter
|
|
||||||
|
|
||||||
- You must run `vendor/bin/pint --dirty` before finalizing changes to ensure your code matches the project's expected style.
|
|
||||||
- Do not run `vendor/bin/pint --test`, simply run `vendor/bin/pint` to fix any formatting issues.
|
|
||||||
|
|
||||||
|
|
||||||
=== pest/core rules ===
|
|
||||||
|
|
||||||
## Pest
|
|
||||||
|
|
||||||
### Testing
|
|
||||||
- If you need to verify a feature is working, write or update a Unit / Feature test.
|
|
||||||
|
|
||||||
### Pest Tests
|
|
||||||
- All tests must be written using Pest. Use `php artisan make:test --pest <name>`.
|
|
||||||
- You must not remove any tests or test files from the tests directory without approval. These are not temporary or helper files - these are core to the application.
|
|
||||||
- Tests should test all of the happy paths, failure paths, and weird paths.
|
|
||||||
- Tests live in the `tests/Feature` and `tests/Unit` directories.
|
|
||||||
- Pest tests look and behave like this:
|
|
||||||
<code-snippet name="Basic Pest Test Example" lang="php">
|
|
||||||
it('is true', function () {
|
|
||||||
expect(true)->toBeTrue();
|
|
||||||
});
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
### Running Tests
|
|
||||||
- Run the minimal number of tests using an appropriate filter before finalizing code edits.
|
|
||||||
- To run all tests: `php artisan test`.
|
|
||||||
- To run all tests in a file: `php artisan test tests/Feature/ExampleTest.php`.
|
|
||||||
- To filter on a particular test name: `php artisan test --filter=testName` (recommended after making a change to a related file).
|
|
||||||
- When the tests relating to your changes are passing, ask the user if they would like to run the entire test suite to ensure everything is still passing.
|
|
||||||
|
|
||||||
### Pest Assertions
|
|
||||||
- When asserting status codes on a response, use the specific method like `assertForbidden` and `assertNotFound` instead of using `assertStatus(403)` or similar, e.g.:
|
|
||||||
<code-snippet name="Pest Example Asserting postJson Response" lang="php">
|
|
||||||
it('returns all', function () {
|
|
||||||
$response = $this->postJson('/api/docs', []);
|
|
||||||
|
|
||||||
$response->assertSuccessful();
|
|
||||||
});
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
### Mocking
|
|
||||||
- Mocking can be very helpful when appropriate.
|
|
||||||
- When mocking, you can use the `Pest\Laravel\mock` Pest function, but always import it via `use function Pest\Laravel\mock;` before using it. Alternatively, you can use `$this->mock()` if existing tests do.
|
|
||||||
- You can also create partial mocks using the same import or self method.
|
|
||||||
|
|
||||||
### Datasets
|
|
||||||
- Use datasets in Pest to simplify tests which have a lot of duplicated data. This is often the case when testing validation rules, so consider going with this solution when writing tests for validation rules.
|
|
||||||
|
|
||||||
<code-snippet name="Pest Dataset Example" lang="php">
|
|
||||||
it('has emails', function (string $email) {
|
|
||||||
expect($email)->not->toBeEmpty();
|
|
||||||
})->with([
|
|
||||||
'james' => 'james@laravel.com',
|
|
||||||
'taylor' => 'taylor@laravel.com',
|
|
||||||
]);
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
=== pest/v4 rules ===
|
|
||||||
|
|
||||||
## Pest 4
|
|
||||||
|
|
||||||
- Pest v4 is a huge upgrade to Pest and offers: browser testing, smoke testing, visual regression testing, test sharding, and faster type coverage.
|
|
||||||
- Browser testing is incredibly powerful and useful for this project.
|
|
||||||
- Browser tests should live in `tests/Browser/`.
|
|
||||||
- Use the `search-docs` tool for detailed guidance on utilizing these features.
|
|
||||||
|
|
||||||
### Browser Testing
|
|
||||||
- You can use Laravel features like `Event::fake()`, `assertAuthenticated()`, and model factories within Pest v4 browser tests, as well as `RefreshDatabase` (when needed) to ensure a clean state for each test.
|
|
||||||
- Interact with the page (click, type, scroll, select, submit, drag-and-drop, touch gestures, etc.) when appropriate to complete the test.
|
|
||||||
- If requested, test on multiple browsers (Chrome, Firefox, Safari).
|
|
||||||
- If requested, test on different devices and viewports (like iPhone 14 Pro, tablets, or custom breakpoints).
|
|
||||||
- Switch color schemes (light/dark mode) when appropriate.
|
|
||||||
- Take screenshots or pause tests for debugging when appropriate.
|
|
||||||
|
|
||||||
### Example Tests
|
|
||||||
|
|
||||||
<code-snippet name="Pest Browser Test Example" lang="php">
|
|
||||||
it('may reset the password', function () {
|
|
||||||
Notification::fake();
|
|
||||||
|
|
||||||
$this->actingAs(User::factory()->create());
|
|
||||||
|
|
||||||
$page = visit('/sign-in'); // Visit on a real browser...
|
|
||||||
|
|
||||||
$page->assertSee('Sign In')
|
|
||||||
->assertNoJavascriptErrors() // or ->assertNoConsoleLogs()
|
|
||||||
->click('Forgot Password?')
|
|
||||||
->fill('email', 'nuno@laravel.com')
|
|
||||||
->click('Send Reset Link')
|
|
||||||
->assertSee('We have emailed your password reset link!')
|
|
||||||
|
|
||||||
Notification::assertSent(ResetPassword::class);
|
|
||||||
});
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
<code-snippet name="Pest Smoke Testing Example" lang="php">
|
|
||||||
$pages = visit(['/', '/about', '/contact']);
|
|
||||||
|
|
||||||
$pages->assertNoJavascriptErrors()->assertNoConsoleLogs();
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
=== tailwindcss/core rules ===
|
|
||||||
|
|
||||||
## Tailwind Core
|
|
||||||
|
|
||||||
- Use Tailwind CSS classes to style HTML, check and use existing tailwind conventions within the project before writing your own.
|
|
||||||
- Offer to extract repeated patterns into components that match the project's conventions (i.e. Blade, JSX, Vue, etc..)
|
|
||||||
- Think through class placement, order, priority, and defaults - remove redundant classes, add classes to parent or child carefully to limit repetition, group elements logically
|
|
||||||
- You can use the `search-docs` tool to get exact examples from the official documentation when needed.
|
|
||||||
|
|
||||||
### Spacing
|
|
||||||
- When listing items, use gap utilities for spacing, don't use margins.
|
|
||||||
|
|
||||||
<code-snippet name="Valid Flex Gap Spacing Example" lang="html">
|
|
||||||
<div class="flex gap-8">
|
|
||||||
<div>Superior</div>
|
|
||||||
<div>Michigan</div>
|
|
||||||
<div>Erie</div>
|
|
||||||
</div>
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
### Dark Mode
|
|
||||||
- If existing pages and components support dark mode, new pages and components must support dark mode in a similar way, typically using `dark:`.
|
|
||||||
|
|
||||||
|
|
||||||
=== tailwindcss/v4 rules ===
|
|
||||||
|
|
||||||
## Tailwind 4
|
|
||||||
|
|
||||||
- Always use Tailwind CSS v4 - do not use the deprecated utilities.
|
|
||||||
- `corePlugins` is not supported in Tailwind v4.
|
|
||||||
- In Tailwind v4, you import Tailwind using a regular CSS `@import` statement, not using the `@tailwind` directives used in v3:
|
|
||||||
|
|
||||||
<code-snippet name="Tailwind v4 Import Tailwind Diff" lang="diff">
|
|
||||||
- @tailwind base;
|
|
||||||
- @tailwind components;
|
|
||||||
- @tailwind utilities;
|
|
||||||
+ @import "tailwindcss";
|
|
||||||
</code-snippet>
|
|
||||||
|
|
||||||
|
|
||||||
### Replaced Utilities
|
|
||||||
- Tailwind v4 removed deprecated utilities. Do not use the deprecated option - use the replacement.
|
|
||||||
- Opacity values are still numeric.
|
|
||||||
|
|
||||||
| Deprecated | Replacement |
|
|
||||||
|------------+--------------|
|
|
||||||
| bg-opacity-* | bg-black/* |
|
|
||||||
| text-opacity-* | text-black/* |
|
|
||||||
| border-opacity-* | border-black/* |
|
|
||||||
| divide-opacity-* | divide-black/* |
|
|
||||||
| ring-opacity-* | ring-black/* |
|
|
||||||
| placeholder-opacity-* | placeholder-black/* |
|
|
||||||
| flex-shrink-* | shrink-* |
|
|
||||||
| flex-grow-* | grow-* |
|
|
||||||
| overflow-ellipsis | text-ellipsis |
|
|
||||||
| decoration-slice | box-decoration-slice |
|
|
||||||
| decoration-clone | box-decoration-clone |
|
|
||||||
|
|
||||||
|
|
||||||
=== tests rules ===
|
|
||||||
|
|
||||||
## Test Enforcement
|
|
||||||
|
|
||||||
- Every change must be programmatically tested. Write a new test or update an existing test, then run the affected tests to make sure they pass.
|
|
||||||
- Run the minimum number of tests needed to ensure code quality and speed. Use `php artisan test` with a specific filename or filter.
|
|
||||||
</laravel-boost-guidelines>
|
|
||||||
206
composer.lock
generated
206
composer.lock
generated
|
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "9122624c0df3b24bc94c7c866aa4e17c",
|
"content-hash": "d6d201899ecc5b1243e9a481c22c5732",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "aws/aws-crt-php",
|
"name": "aws/aws-crt-php",
|
||||||
|
|
@ -62,16 +62,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "aws/aws-sdk-php",
|
"name": "aws/aws-sdk-php",
|
||||||
"version": "3.357.0",
|
"version": "3.359.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/aws/aws-sdk-php.git",
|
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||||
"reference": "0325c653b022aedb38f397cf559ab4d0f7967901"
|
"reference": "7231e7c309d6262855289511d6ee124fafbe664f"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/0325c653b022aedb38f397cf559ab4d0f7967901",
|
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/7231e7c309d6262855289511d6ee124fafbe664f",
|
||||||
"reference": "0325c653b022aedb38f397cf559ab4d0f7967901",
|
"reference": "7231e7c309d6262855289511d6ee124fafbe664f",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -153,9 +153,9 @@
|
||||||
"support": {
|
"support": {
|
||||||
"forum": "https://github.com/aws/aws-sdk-php/discussions",
|
"forum": "https://github.com/aws/aws-sdk-php/discussions",
|
||||||
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
||||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.357.0"
|
"source": "https://github.com/aws/aws-sdk-php/tree/3.359.0"
|
||||||
},
|
},
|
||||||
"time": "2025-10-22T19:43:07+00:00"
|
"time": "2025-10-29T00:06:16+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "bnussbau/laravel-trmnl-blade",
|
"name": "bnussbau/laravel-trmnl-blade",
|
||||||
|
|
@ -1618,16 +1618,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/framework",
|
"name": "laravel/framework",
|
||||||
"version": "v12.35.1",
|
"version": "v12.36.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/laravel/framework.git",
|
"url": "https://github.com/laravel/framework.git",
|
||||||
"reference": "d6d6e3cb68238e2fb25b440f222442adef5a8a15"
|
"reference": "5247c8f4139e5266cd42bbe13de131604becd7e1"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/laravel/framework/zipball/d6d6e3cb68238e2fb25b440f222442adef5a8a15",
|
"url": "https://api.github.com/repos/laravel/framework/zipball/5247c8f4139e5266cd42bbe13de131604becd7e1",
|
||||||
"reference": "d6d6e3cb68238e2fb25b440f222442adef5a8a15",
|
"reference": "5247c8f4139e5266cd42bbe13de131604becd7e1",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -1833,7 +1833,7 @@
|
||||||
"issues": "https://github.com/laravel/framework/issues",
|
"issues": "https://github.com/laravel/framework/issues",
|
||||||
"source": "https://github.com/laravel/framework"
|
"source": "https://github.com/laravel/framework"
|
||||||
},
|
},
|
||||||
"time": "2025-10-23T15:25:03+00:00"
|
"time": "2025-10-28T15:13:16+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/prompts",
|
"name": "laravel/prompts",
|
||||||
|
|
@ -2021,16 +2021,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/socialite",
|
"name": "laravel/socialite",
|
||||||
"version": "v5.23.0",
|
"version": "v5.23.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/laravel/socialite.git",
|
"url": "https://github.com/laravel/socialite.git",
|
||||||
"reference": "e9e0fc83b9d8d71c8385a5da20e5b95ca6234cf5"
|
"reference": "83d7523c97c1101d288126948947891319eef800"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/laravel/socialite/zipball/e9e0fc83b9d8d71c8385a5da20e5b95ca6234cf5",
|
"url": "https://api.github.com/repos/laravel/socialite/zipball/83d7523c97c1101d288126948947891319eef800",
|
||||||
"reference": "e9e0fc83b9d8d71c8385a5da20e5b95ca6234cf5",
|
"reference": "83d7523c97c1101d288126948947891319eef800",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -2089,7 +2089,7 @@
|
||||||
"issues": "https://github.com/laravel/socialite/issues",
|
"issues": "https://github.com/laravel/socialite/issues",
|
||||||
"source": "https://github.com/laravel/socialite"
|
"source": "https://github.com/laravel/socialite"
|
||||||
},
|
},
|
||||||
"time": "2025-07-23T14:16:08+00:00"
|
"time": "2025-10-27T15:36:41+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/tinker",
|
"name": "laravel/tinker",
|
||||||
|
|
@ -2842,16 +2842,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "livewire/flux",
|
"name": "livewire/flux",
|
||||||
"version": "v2.6.0",
|
"version": "v2.6.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/livewire/flux.git",
|
"url": "https://github.com/livewire/flux.git",
|
||||||
"reference": "3cb2ea40978449da74b3814eeef75f0388124224"
|
"reference": "227b88db0a02db91666af2303ea6727a3af78c51"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/livewire/flux/zipball/3cb2ea40978449da74b3814eeef75f0388124224",
|
"url": "https://api.github.com/repos/livewire/flux/zipball/227b88db0a02db91666af2303ea6727a3af78c51",
|
||||||
"reference": "3cb2ea40978449da74b3814eeef75f0388124224",
|
"reference": "227b88db0a02db91666af2303ea6727a3af78c51",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -2859,7 +2859,7 @@
|
||||||
"illuminate/support": "^10.0|^11.0|^12.0",
|
"illuminate/support": "^10.0|^11.0|^12.0",
|
||||||
"illuminate/view": "^10.0|^11.0|^12.0",
|
"illuminate/view": "^10.0|^11.0|^12.0",
|
||||||
"laravel/prompts": "^0.1|^0.2|^0.3",
|
"laravel/prompts": "^0.1|^0.2|^0.3",
|
||||||
"livewire/livewire": "^3.5.19",
|
"livewire/livewire": "^3.5.19|^4.0",
|
||||||
"php": "^8.1",
|
"php": "^8.1",
|
||||||
"symfony/console": "^6.0|^7.0"
|
"symfony/console": "^6.0|^7.0"
|
||||||
},
|
},
|
||||||
|
|
@ -2902,9 +2902,9 @@
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/livewire/flux/issues",
|
"issues": "https://github.com/livewire/flux/issues",
|
||||||
"source": "https://github.com/livewire/flux/tree/v2.6.0"
|
"source": "https://github.com/livewire/flux/tree/v2.6.1"
|
||||||
},
|
},
|
||||||
"time": "2025-10-13T23:17:18+00:00"
|
"time": "2025-10-28T21:12:05+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "livewire/livewire",
|
"name": "livewire/livewire",
|
||||||
|
|
@ -4420,16 +4420,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "psy/psysh",
|
"name": "psy/psysh",
|
||||||
"version": "v0.12.13",
|
"version": "v0.12.14",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/bobthecow/psysh.git",
|
"url": "https://github.com/bobthecow/psysh.git",
|
||||||
"reference": "d86c2f750e72017a5cdb1b9f1cef468a5cbacd1e"
|
"reference": "95c29b3756a23855a30566b745d218bee690bef2"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/d86c2f750e72017a5cdb1b9f1cef468a5cbacd1e",
|
"url": "https://api.github.com/repos/bobthecow/psysh/zipball/95c29b3756a23855a30566b745d218bee690bef2",
|
||||||
"reference": "d86c2f750e72017a5cdb1b9f1cef468a5cbacd1e",
|
"reference": "95c29b3756a23855a30566b745d218bee690bef2",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -4450,7 +4450,6 @@
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"composer/class-map-generator": "Improved tab completion performance with better class discovery.",
|
"composer/class-map-generator": "Improved tab completion performance with better class discovery.",
|
||||||
"ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)",
|
"ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)",
|
||||||
"ext-pdo-sqlite": "The doc command requires SQLite to work.",
|
|
||||||
"ext-posix": "If you have PCNTL, you'll want the POSIX extension as well."
|
"ext-posix": "If you have PCNTL, you'll want the POSIX extension as well."
|
||||||
},
|
},
|
||||||
"bin": [
|
"bin": [
|
||||||
|
|
@ -4494,9 +4493,9 @@
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/bobthecow/psysh/issues",
|
"issues": "https://github.com/bobthecow/psysh/issues",
|
||||||
"source": "https://github.com/bobthecow/psysh/tree/v0.12.13"
|
"source": "https://github.com/bobthecow/psysh/tree/v0.12.14"
|
||||||
},
|
},
|
||||||
"time": "2025-10-20T22:48:29+00:00"
|
"time": "2025-10-27T17:15:31+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "ralouphie/getallheaders",
|
"name": "ralouphie/getallheaders",
|
||||||
|
|
@ -4962,16 +4961,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/console",
|
"name": "symfony/console",
|
||||||
"version": "v7.3.4",
|
"version": "v7.3.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/console.git",
|
"url": "https://github.com/symfony/console.git",
|
||||||
"reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db"
|
"reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/console/zipball/2b9c5fafbac0399a20a2e82429e2bd735dcfb7db",
|
"url": "https://api.github.com/repos/symfony/console/zipball/cdb80fa5869653c83cfe1a9084a673b6daf57ea7",
|
||||||
"reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db",
|
"reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -5036,7 +5035,7 @@
|
||||||
"terminal"
|
"terminal"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/console/tree/v7.3.4"
|
"source": "https://github.com/symfony/console/tree/v7.3.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
|
@ -5056,7 +5055,7 @@
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2025-09-22T15:31:00+00:00"
|
"time": "2025-10-14T15:46:26+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/css-selector",
|
"name": "symfony/css-selector",
|
||||||
|
|
@ -5433,16 +5432,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/finder",
|
"name": "symfony/finder",
|
||||||
"version": "v7.3.2",
|
"version": "v7.3.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/finder.git",
|
"url": "https://github.com/symfony/finder.git",
|
||||||
"reference": "2a6614966ba1074fa93dae0bc804227422df4dfe"
|
"reference": "9f696d2f1e340484b4683f7853b273abff94421f"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe",
|
"url": "https://api.github.com/repos/symfony/finder/zipball/9f696d2f1e340484b4683f7853b273abff94421f",
|
||||||
"reference": "2a6614966ba1074fa93dae0bc804227422df4dfe",
|
"reference": "9f696d2f1e340484b4683f7853b273abff94421f",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -5477,7 +5476,7 @@
|
||||||
"description": "Finds files and directories via an intuitive fluent interface",
|
"description": "Finds files and directories via an intuitive fluent interface",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/finder/tree/v7.3.2"
|
"source": "https://github.com/symfony/finder/tree/v7.3.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
|
@ -5497,20 +5496,20 @@
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2025-07-15T13:41:35+00:00"
|
"time": "2025-10-15T18:45:57+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/http-foundation",
|
"name": "symfony/http-foundation",
|
||||||
"version": "v7.3.4",
|
"version": "v7.3.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/http-foundation.git",
|
"url": "https://github.com/symfony/http-foundation.git",
|
||||||
"reference": "c061c7c18918b1b64268771aad04b40be41dd2e6"
|
"reference": "ce31218c7cac92eab280762c4375fb70a6f4f897"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/c061c7c18918b1b64268771aad04b40be41dd2e6",
|
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/ce31218c7cac92eab280762c4375fb70a6f4f897",
|
||||||
"reference": "c061c7c18918b1b64268771aad04b40be41dd2e6",
|
"reference": "ce31218c7cac92eab280762c4375fb70a6f4f897",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -5560,7 +5559,7 @@
|
||||||
"description": "Defines an object-oriented layer for the HTTP specification",
|
"description": "Defines an object-oriented layer for the HTTP specification",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/http-foundation/tree/v7.3.4"
|
"source": "https://github.com/symfony/http-foundation/tree/v7.3.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
|
@ -5580,20 +5579,20 @@
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2025-09-16T08:38:17+00:00"
|
"time": "2025-10-24T21:42:11+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/http-kernel",
|
"name": "symfony/http-kernel",
|
||||||
"version": "v7.3.4",
|
"version": "v7.3.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/http-kernel.git",
|
"url": "https://github.com/symfony/http-kernel.git",
|
||||||
"reference": "b796dffea7821f035047235e076b60ca2446e3cf"
|
"reference": "24fd3f123532e26025f49f1abefcc01a69ef15ab"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/b796dffea7821f035047235e076b60ca2446e3cf",
|
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/24fd3f123532e26025f49f1abefcc01a69ef15ab",
|
||||||
"reference": "b796dffea7821f035047235e076b60ca2446e3cf",
|
"reference": "24fd3f123532e26025f49f1abefcc01a69ef15ab",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -5678,7 +5677,7 @@
|
||||||
"description": "Provides a structured process for converting a Request into a Response",
|
"description": "Provides a structured process for converting a Request into a Response",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/http-kernel/tree/v7.3.4"
|
"source": "https://github.com/symfony/http-kernel/tree/v7.3.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
|
@ -5698,20 +5697,20 @@
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2025-09-27T12:32:17+00:00"
|
"time": "2025-10-28T10:19:01+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/mailer",
|
"name": "symfony/mailer",
|
||||||
"version": "v7.3.4",
|
"version": "v7.3.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/mailer.git",
|
"url": "https://github.com/symfony/mailer.git",
|
||||||
"reference": "ab97ef2f7acf0216955f5845484235113047a31d"
|
"reference": "fd497c45ba9c10c37864e19466b090dcb60a50ba"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/mailer/zipball/ab97ef2f7acf0216955f5845484235113047a31d",
|
"url": "https://api.github.com/repos/symfony/mailer/zipball/fd497c45ba9c10c37864e19466b090dcb60a50ba",
|
||||||
"reference": "ab97ef2f7acf0216955f5845484235113047a31d",
|
"reference": "fd497c45ba9c10c37864e19466b090dcb60a50ba",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -5762,7 +5761,7 @@
|
||||||
"description": "Helps sending emails",
|
"description": "Helps sending emails",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/mailer/tree/v7.3.4"
|
"source": "https://github.com/symfony/mailer/tree/v7.3.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
|
@ -5782,7 +5781,7 @@
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2025-09-17T05:51:54+00:00"
|
"time": "2025-10-24T14:27:20+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/mime",
|
"name": "symfony/mime",
|
||||||
|
|
@ -7278,16 +7277,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/var-dumper",
|
"name": "symfony/var-dumper",
|
||||||
"version": "v7.3.4",
|
"version": "v7.3.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/var-dumper.git",
|
"url": "https://github.com/symfony/var-dumper.git",
|
||||||
"reference": "b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb"
|
"reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb",
|
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/476c4ae17f43a9a36650c69879dcf5b1e6ae724d",
|
||||||
"reference": "b8abe7daf2730d07dfd4b2ee1cecbf0dd2fbdabb",
|
"reference": "476c4ae17f43a9a36650c69879dcf5b1e6ae724d",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -7341,7 +7340,7 @@
|
||||||
"dump"
|
"dump"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/var-dumper/tree/v7.3.4"
|
"source": "https://github.com/symfony/var-dumper/tree/v7.3.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
|
@ -7361,7 +7360,7 @@
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2025-09-11T10:12:26+00:00"
|
"time": "2025-09-27T09:00:46+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/var-exporter",
|
"name": "symfony/var-exporter",
|
||||||
|
|
@ -7446,16 +7445,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/yaml",
|
"name": "symfony/yaml",
|
||||||
"version": "v7.3.3",
|
"version": "v7.3.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/yaml.git",
|
"url": "https://github.com/symfony/yaml.git",
|
||||||
"reference": "d4f4a66866fe2451f61296924767280ab5732d9d"
|
"reference": "90208e2fc6f68f613eae7ca25a2458a931b1bacc"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/d4f4a66866fe2451f61296924767280ab5732d9d",
|
"url": "https://api.github.com/repos/symfony/yaml/zipball/90208e2fc6f68f613eae7ca25a2458a931b1bacc",
|
||||||
"reference": "d4f4a66866fe2451f61296924767280ab5732d9d",
|
"reference": "90208e2fc6f68f613eae7ca25a2458a931b1bacc",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -7498,7 +7497,7 @@
|
||||||
"description": "Loads and dumps YAML files",
|
"description": "Loads and dumps YAML files",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/yaml/tree/v7.3.3"
|
"source": "https://github.com/symfony/yaml/tree/v7.3.5"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
|
@ -7518,7 +7517,7 @@
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2025-08-27T11:34:33+00:00"
|
"time": "2025-09-27T09:00:46+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "tijsverkoyen/css-to-inline-styles",
|
"name": "tijsverkoyen/css-to-inline-styles",
|
||||||
|
|
@ -8458,16 +8457,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/boost",
|
"name": "laravel/boost",
|
||||||
"version": "v1.4.0",
|
"version": "v1.6.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/laravel/boost.git",
|
"url": "https://github.com/laravel/boost.git",
|
||||||
"reference": "8d2dedf7779c2e175a02a176dec38e6f9b35352b"
|
"reference": "29d1c7c5a816d2b55c39f50bb07bdbca6c595b09"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/laravel/boost/zipball/8d2dedf7779c2e175a02a176dec38e6f9b35352b",
|
"url": "https://api.github.com/repos/laravel/boost/zipball/29d1c7c5a816d2b55c39f50bb07bdbca6c595b09",
|
||||||
"reference": "8d2dedf7779c2e175a02a176dec38e6f9b35352b",
|
"reference": "29d1c7c5a816d2b55c39f50bb07bdbca6c595b09",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -8478,7 +8477,7 @@
|
||||||
"illuminate/support": "^10.49.0|^11.45.3|^12.28.1",
|
"illuminate/support": "^10.49.0|^11.45.3|^12.28.1",
|
||||||
"laravel/mcp": "^0.2.0|^0.3.0",
|
"laravel/mcp": "^0.2.0|^0.3.0",
|
||||||
"laravel/prompts": "0.1.25|^0.3.6",
|
"laravel/prompts": "0.1.25|^0.3.6",
|
||||||
"laravel/roster": "^0.2.8",
|
"laravel/roster": "^0.2.9",
|
||||||
"php": "^8.1"
|
"php": "^8.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
|
@ -8520,20 +8519,20 @@
|
||||||
"issues": "https://github.com/laravel/boost/issues",
|
"issues": "https://github.com/laravel/boost/issues",
|
||||||
"source": "https://github.com/laravel/boost"
|
"source": "https://github.com/laravel/boost"
|
||||||
},
|
},
|
||||||
"time": "2025-10-14T01:13:19+00:00"
|
"time": "2025-10-28T17:43:53+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/mcp",
|
"name": "laravel/mcp",
|
||||||
"version": "v0.3.0",
|
"version": "v0.3.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/laravel/mcp.git",
|
"url": "https://github.com/laravel/mcp.git",
|
||||||
"reference": "4e1389eedb4741a624e26cc3660b31bae04c4342"
|
"reference": "13f80d68bb409a0952142a2433f14d536a7940e3"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/laravel/mcp/zipball/4e1389eedb4741a624e26cc3660b31bae04c4342",
|
"url": "https://api.github.com/repos/laravel/mcp/zipball/13f80d68bb409a0952142a2433f14d536a7940e3",
|
||||||
"reference": "4e1389eedb4741a624e26cc3660b31bae04c4342",
|
"reference": "13f80d68bb409a0952142a2433f14d536a7940e3",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -8554,7 +8553,7 @@
|
||||||
"orchestra/testbench": "^8.36.0|^9.15.0|^10.6.0",
|
"orchestra/testbench": "^8.36.0|^9.15.0|^10.6.0",
|
||||||
"pestphp/pest": "^2.36.0|^3.8.4|^4.1.0",
|
"pestphp/pest": "^2.36.0|^3.8.4|^4.1.0",
|
||||||
"phpstan/phpstan": "^2.1.27",
|
"phpstan/phpstan": "^2.1.27",
|
||||||
"rector/rector": "^2.1.7"
|
"rector/rector": "^2.2.4"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
|
|
@ -8593,7 +8592,7 @@
|
||||||
"issues": "https://github.com/laravel/mcp/issues",
|
"issues": "https://github.com/laravel/mcp/issues",
|
||||||
"source": "https://github.com/laravel/mcp"
|
"source": "https://github.com/laravel/mcp"
|
||||||
},
|
},
|
||||||
"time": "2025-10-07T14:28:56+00:00"
|
"time": "2025-10-24T15:36:29+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/pail",
|
"name": "laravel/pail",
|
||||||
|
|
@ -8803,16 +8802,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "laravel/sail",
|
"name": "laravel/sail",
|
||||||
"version": "v1.46.0",
|
"version": "v1.47.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/laravel/sail.git",
|
"url": "https://github.com/laravel/sail.git",
|
||||||
"reference": "eb90c4f113c4a9637b8fdd16e24cfc64f2b0ae6e"
|
"reference": "9a11e822238167ad8b791e4ea51155d25cf4d8f2"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/laravel/sail/zipball/eb90c4f113c4a9637b8fdd16e24cfc64f2b0ae6e",
|
"url": "https://api.github.com/repos/laravel/sail/zipball/9a11e822238167ad8b791e4ea51155d25cf4d8f2",
|
||||||
"reference": "eb90c4f113c4a9637b8fdd16e24cfc64f2b0ae6e",
|
"reference": "9a11e822238167ad8b791e4ea51155d25cf4d8f2",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -8825,7 +8824,7 @@
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"orchestra/testbench": "^7.0|^8.0|^9.0|^10.0",
|
"orchestra/testbench": "^7.0|^8.0|^9.0|^10.0",
|
||||||
"phpstan/phpstan": "^1.10"
|
"phpstan/phpstan": "^2.0"
|
||||||
},
|
},
|
||||||
"bin": [
|
"bin": [
|
||||||
"bin/sail"
|
"bin/sail"
|
||||||
|
|
@ -8862,7 +8861,7 @@
|
||||||
"issues": "https://github.com/laravel/sail/issues",
|
"issues": "https://github.com/laravel/sail/issues",
|
||||||
"source": "https://github.com/laravel/sail"
|
"source": "https://github.com/laravel/sail"
|
||||||
},
|
},
|
||||||
"time": "2025-09-23T13:44:39+00:00"
|
"time": "2025-10-28T13:55:29+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "mockery/mockery",
|
"name": "mockery/mockery",
|
||||||
|
|
@ -9583,16 +9582,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "pestphp/pest-plugin-profanity",
|
"name": "pestphp/pest-plugin-profanity",
|
||||||
"version": "v4.1.0",
|
"version": "v4.2.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/pestphp/pest-plugin-profanity.git",
|
"url": "https://github.com/pestphp/pest-plugin-profanity.git",
|
||||||
"reference": "e279c844b6868da92052be27b5202c2ad7216e80"
|
"reference": "c37e5e2c7136ee4eae12082e7952332bc1c6600a"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/pestphp/pest-plugin-profanity/zipball/e279c844b6868da92052be27b5202c2ad7216e80",
|
"url": "https://api.github.com/repos/pestphp/pest-plugin-profanity/zipball/c37e5e2c7136ee4eae12082e7952332bc1c6600a",
|
||||||
"reference": "e279c844b6868da92052be27b5202c2ad7216e80",
|
"reference": "c37e5e2c7136ee4eae12082e7952332bc1c6600a",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -9633,9 +9632,9 @@
|
||||||
"unit"
|
"unit"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/pestphp/pest-plugin-profanity/tree/v4.1.0"
|
"source": "https://github.com/pestphp/pest-plugin-profanity/tree/v4.2.0"
|
||||||
},
|
},
|
||||||
"time": "2025-09-10T06:17:03+00:00"
|
"time": "2025-10-28T23:14:11+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phar-io/manifest",
|
"name": "phar-io/manifest",
|
||||||
|
|
@ -10471,16 +10470,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "rector/rector",
|
"name": "rector/rector",
|
||||||
"version": "2.2.5",
|
"version": "2.2.6",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/rectorphp/rector.git",
|
"url": "https://github.com/rectorphp/rector.git",
|
||||||
"reference": "fb9418af7777dfb1c87a536dc58398b5b07c74b9"
|
"reference": "5c5bbc956b9a056a26cb593379253104b7ed9c2d"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/rectorphp/rector/zipball/fb9418af7777dfb1c87a536dc58398b5b07c74b9",
|
"url": "https://api.github.com/repos/rectorphp/rector/zipball/5c5bbc956b9a056a26cb593379253104b7ed9c2d",
|
||||||
"reference": "fb9418af7777dfb1c87a536dc58398b5b07c74b9",
|
"reference": "5c5bbc956b9a056a26cb593379253104b7ed9c2d",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
|
@ -10519,7 +10518,7 @@
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/rectorphp/rector/issues",
|
"issues": "https://github.com/rectorphp/rector/issues",
|
||||||
"source": "https://github.com/rectorphp/rector/tree/2.2.5"
|
"source": "https://github.com/rectorphp/rector/tree/2.2.6"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
|
|
@ -10527,7 +10526,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2025-10-23T11:22:37+00:00"
|
"time": "2025-10-27T11:35:56+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/cli-parser",
|
"name": "sebastian/cli-parser",
|
||||||
|
|
@ -11596,6 +11595,7 @@
|
||||||
"platform": {
|
"platform": {
|
||||||
"php": "^8.2",
|
"php": "^8.2",
|
||||||
"ext-imagick": "*",
|
"ext-imagick": "*",
|
||||||
|
"ext-simplexml": "*",
|
||||||
"ext-zip": "*"
|
"ext-zip": "*"
|
||||||
},
|
},
|
||||||
"platform-dev": {},
|
"platform-dev": {},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue