🆙 Add cms i using 🆙

This commit is contained in:
Remco
2025-11-25 22:42:56 +01:00
parent 94704e0925
commit d44196149e
35591 changed files with 3601123 additions and 0 deletions
@@ -0,0 +1,360 @@
<?php
namespace Filament\Upgrade\Commands;
use Exception;
use Filament\Facades\Filament;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Process;
use Illuminate\Support\Str;
use ReflectionClass;
use RuntimeException;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Input\InputOption;
#[AsCommand(name: 'filament:upgrade-directory-structure-to-v4')]
class UpgradeDirectoryStructureToV4Command extends Command
{
protected $description = 'Upgrade Filament directory structure from v3 to v4';
protected $name = 'filament:upgrade-directory-structure-to-v4';
protected string $phpactorPath;
/**
* @var array<string, array<string, string>>
*/
protected array $movedFiles = [];
protected ?string $currentResource = null;
/**
* @return array<InputOption>
*/
protected function getOptions(): array
{
return [
new InputOption(
name: 'dry-run',
shortcut: 'D',
mode: InputOption::VALUE_NONE,
description: 'Preview changes without executing them',
),
];
}
protected function formatPath(string $path): string
{
return str_replace(base_path() . DIRECTORY_SEPARATOR, '', $path);
}
public function handle(): int
{
$isDryRun = $this->option('dry-run');
if (! $isDryRun && ! $this->components->confirm('This command will modify your Filament resources and clusters to match the new v4 directory structure. Please commit any changes you have made to your project before continuing. Do you want to continue?', default: true)) {
$this->components->info('Migration cancelled.');
return self::FAILURE;
}
$this->components->info('Starting migration from Filament v3 to v4...');
if ($isDryRun) {
$this->newLine();
$this->components->info('Running in dry-run mode. No changes will be made.');
$this->newLine();
}
if (! $isDryRun) {
$this->downloadPhpactor();
} else {
$this->phpactorPath = base_path('vendor' . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'phpactor.phar');
}
$panels = Filament::getPanels();
foreach ($panels as $panel) {
$resources = $panel->getResources();
if (count($resources) > 0) {
$this->components->info('Processing resources in ' . $panel->getId() . ' panel');
foreach ($resources as $resourceClass) {
$this->processResource($resourceClass, $isDryRun);
}
$this->newLine();
}
$clusters = $panel->getClusters();
if (count($clusters) > 0) {
$this->components->info('Processing resources in ' . $panel->getId() . ' panel');
foreach ($clusters as $clusterClass) {
$this->processCluster($clusterClass, $isDryRun);
}
$this->newLine();
}
}
if ($isDryRun) {
$this->components->info('Dry run completed. Run without --dry-run to apply changes.');
} else {
$this->components->info('Migration completed successfully!');
}
return self::SUCCESS;
}
protected function downloadPhpactor(): void
{
$this->phpactorPath = base_path('vendor' . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'phpactor.phar');
if (File::exists($this->phpactorPath)) {
$this->components->info('Phpactor already exists at: ' . $this->formatPath($this->phpactorPath));
return;
}
$this->components->task('Downloading phpactor', function () {
$process = Process::command(
'curl -Lo ' . $this->phpactorPath . ' https://github.com/phpactor/phpactor/releases/latest/download/phpactor.phar'
);
$processOutput = $process->run();
if (! $processOutput->successful()) {
$this->error('Failed to download phpactor: ' . $processOutput->errorOutput());
throw new RuntimeException('Failed to download phpactor');
}
chmod($this->phpactorPath, 0755);
return true;
});
}
/**
* @param class-string $resourceClass
*/
protected function processResource(string $resourceClass, bool $isDryRun = false): void
{
$resourceReflection = new ReflectionClass($resourceClass);
$resourcePath = $resourceReflection->getFileName();
if ($resourcePath === false) {
$this->components->warn("Could not get file path for resource: {$resourceClass}");
return;
}
if ($this->isVendorPath($resourcePath)) {
$this->components->warn('Skipping resource in vendor directory');
return;
}
$resourceBaseName = class_basename($resourceClass);
$resourceDirectory = dirname($resourcePath);
$this->currentResource = $resourceBaseName;
$resourceName = Str::replaceEnd('Resource', '', $resourceBaseName);
$pluralizedName = Str::plural($resourceName);
$newResourceDirectory = $resourceDirectory . DIRECTORY_SEPARATOR . $pluralizedName;
if ($this->isVendorPath($newResourceDirectory)) {
$this->components->warn('Skipping resource with destination in vendor directory');
return;
}
$this->findAndMoveRelatedClasses($resourceClass, $resourceDirectory, $newResourceDirectory, $resourceBaseName, $isDryRun);
$newResourcePath = $newResourceDirectory . DIRECTORY_SEPARATOR . $resourceBaseName . '.php';
$this->moveClass($resourcePath, $newResourcePath, $isDryRun);
}
/**
* @param class-string $clusterClass
*/
protected function processCluster(string $clusterClass, bool $isDryRun = false): void
{
$clusterReflection = new ReflectionClass($clusterClass);
$clusterPath = $clusterReflection->getFileName();
if ($clusterPath === false) {
$this->components->warn("Could not get file path for cluster: {$clusterClass}");
return;
}
if ($this->isVendorPath($clusterPath)) {
$this->components->warn('Skipping cluster in vendor directory');
return;
}
$clusterBaseName = class_basename($clusterClass);
$clusterDirectory = dirname($clusterPath);
$this->currentResource = $clusterBaseName;
$endsWithCluster = Str::endsWith($clusterBaseName, 'Cluster');
if ($endsWithCluster) {
$newClusterBaseName = $clusterBaseName;
$newClusterDirectory = $clusterDirectory . DIRECTORY_SEPARATOR . $clusterBaseName;
} else {
$newClusterBaseName = $clusterBaseName . 'Cluster';
$newClusterDirectory = $clusterDirectory . DIRECTORY_SEPARATOR . $clusterBaseName;
}
if ($this->isVendorPath($newClusterDirectory)) {
$this->components->warn('Skipping cluster with destination in vendor directory');
return;
}
$newClusterPath = $newClusterDirectory . DIRECTORY_SEPARATOR . $newClusterBaseName . '.php';
$this->moveClass($clusterPath, $newClusterPath, $isDryRun);
}
protected function findAndMoveRelatedClasses(string $resourceClass, string $resourceDirectory, string $newResourceDirectory, string $resourceBaseName, bool $isDryRun = false): void
{
$files = $this->findPhpFiles($resourceDirectory);
$relatedFiles = [];
foreach ($files as $file) {
if (basename($file) === $resourceBaseName . '.php') {
continue;
}
if (strpos($file, $resourceDirectory . DIRECTORY_SEPARATOR . $resourceBaseName) === false) {
continue;
}
$relatedFiles[] = $file;
}
foreach ($relatedFiles as $file) {
$relativePath = str_replace($resourceDirectory, '', $file);
$resourceDirectoryPattern = DIRECTORY_SEPARATOR . $resourceBaseName . DIRECTORY_SEPARATOR;
if (strpos($relativePath, $resourceDirectoryPattern) === 0) {
$relativePath = substr($relativePath, strlen($resourceDirectoryPattern));
$relativePath = DIRECTORY_SEPARATOR . $relativePath;
}
$newPath = $newResourceDirectory . $relativePath;
$this->moveClass($file, $newPath, $isDryRun);
}
}
protected function isVendorPath(string $path): bool
{
return str_contains($path, DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR);
}
/**
* @return array<int, string>
*/
protected function findPhpFiles(string $directory): array
{
$files = [];
if (! File::exists($directory)) {
return $files;
}
if ($this->isVendorPath($directory)) {
return $files;
}
$items = File::allFiles($directory);
foreach ($items as $item) {
$pathname = $item->getPathname();
if ($this->isVendorPath($pathname)) {
continue;
}
if ($item->getExtension() === 'php') {
$files[] = $pathname;
}
}
return $files;
}
protected function moveClass(string $sourcePath, string $destinationPath, bool $isDryRun = false): void
{
if ($this->isVendorPath($sourcePath)) {
$this->components->warn('Skipping file in vendor directory');
return;
}
if ($this->isVendorPath($destinationPath)) {
$this->components->warn('Skipping move to vendor directory');
return;
}
if ($isDryRun) {
if ($this->currentResource && (! isset($this->movedFiles[$this->currentResource]) || empty($this->movedFiles[$this->currentResource]))) {
$this->line(' <fg=yellow;options=bold>' . $this->currentResource . '</>');
$this->movedFiles[$this->currentResource] = [];
} elseif (! $this->currentResource && (! isset($this->movedFiles['Other']) || empty($this->movedFiles['Other']))) {
$this->line(' <fg=yellow;options=bold>Other</>');
$this->movedFiles['Other'] = [];
}
$this->line(' • ' . $this->formatPath($sourcePath) . ' → ' . $this->formatPath($destinationPath));
if ($this->currentResource) {
$this->movedFiles[$this->currentResource][$sourcePath] = $destinationPath;
} else {
$this->movedFiles['Other'][$sourcePath] = $destinationPath;
}
return;
}
try {
$process = Process::command(
"php {$this->phpactorPath} class:move {$sourcePath} {$destinationPath}"
);
$process->timeout(60);
$processOutput = $process->run();
if ($processOutput->successful()) {
if ($this->currentResource && (! isset($this->movedFiles[$this->currentResource]) || empty($this->movedFiles[$this->currentResource]))) {
$this->line(' <fg=yellow;options=bold>' . $this->currentResource . '</>');
$this->movedFiles[$this->currentResource] = [];
} elseif (! $this->currentResource && (! isset($this->movedFiles['Other']) || empty($this->movedFiles['Other']))) {
$this->line(' <fg=yellow;options=bold>Other</>');
$this->movedFiles['Other'] = [];
}
$this->line(' • ' . $this->formatPath($sourcePath) . ' → ' . $this->formatPath($destinationPath));
if ($this->currentResource) {
$this->movedFiles[$this->currentResource][$sourcePath] = $destinationPath;
} else {
$this->movedFiles['Other'][$sourcePath] = $destinationPath;
}
} else {
$this->components->error('Failed to move class: ' . $processOutput->errorOutput());
}
} catch (Exception $exception) {
$this->components->error('Exception occurred while moving class: ' . $exception->getMessage());
}
}
}
@@ -0,0 +1,87 @@
<?php
namespace Filament\Upgrade\Rector;
use PhpParser\Node;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Name\FullyQualified;
use PHPStan\Analyser\Scope;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PhpParser\Node\BetterNodeFinder;
use Rector\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
class AddPanelParamToRouteMethodsRector extends AbstractRector
{
public function __construct(
protected BetterNodeFinder $betterNodeFinder
) {}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
'Prepend `Filament::getCurrentOrDefaultPanel()` or `$panel` to static method calls to `getRoutePath()`, `getRelativeRouteName()`, etc.',
[
new CodeSample(
'Page::getRoutePath();',
'Page::getRoutePath(Filament\Facades\Filament::getCurrentOrDefaultPanel());'
),
new CodeSample(
'Page::getRoutePath($param1, $param2);',
'Page::getRoutePath(Filament\Facades\Filament::getCurrentOrDefaultPanel(), $param1, $param2);'
),
]
);
}
public function getChanges(): array
{
return [
'getRoutePath',
'getRelativeRouteName',
'getRoutePrefix',
'prependClusterRouteBaseName',
'prependClusterSlug',
];
}
public function getNodeTypes(): array
{
return [StaticCall::class];
}
public function refactor(Node $node): ?Node
{
if (! $node instanceof StaticCall) {
return null;
}
if (! in_array($node->name->name, $this->getChanges())) {
return null;
}
$scope = $node->getAttribute(AttributeKey::SCOPE);
$isPanelVariableDefinedInScope = false;
if ($scope instanceof Scope) {
$isPanelVariableDefinedInScope = in_array('panel', $scope->getDefinedVariables());
}
if ($isPanelVariableDefinedInScope) {
// Assuming `$panel` variable always refers to a panel in Filament-context...
$panelArg = new Node\Arg(new Variable('panel'));
} else {
$getCurrentOrDefaultPanelStaticCall = new StaticCall(new FullyQualified('Filament\Facades\Filament'), 'getCurrentOrDefaultPanel');
$panelArg = new Node\Arg($getCurrentOrDefaultPanelStaticCall);
}
// Prepend new argument...
array_unshift($node->args, $panelArg);
return $node;
}
}
@@ -0,0 +1,101 @@
<?php
namespace Filament\Upgrade\Rector;
use PhpParser\Node;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\TraitUse;
use PHPStan\Reflection\ClassReflection;
use Rector\Contract\Rector\ConfigurableRectorInterface;
use Rector\PHPStan\ScopeFetcher;
use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer;
use Rector\Rector\AbstractRector;
use Rector\Reflection\ReflectionResolver;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @see AddInterfaceByTraitRector
*/
class AddTraitByTraitRector extends AbstractRector implements ConfigurableRectorInterface
{
/**
* @var array<string, string>
*/
private array $traitByTrait = [];
public function __construct(
protected readonly TestsNodeAnalyzer $testsNodeAnalyzer,
protected readonly ReflectionResolver $reflectionResolver,
) {}
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Add trait by used trait', []);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [Class_::class];
}
/**
* @param Class_ $node
*/
public function refactor(Node $node): ?Node
{
$scope = ScopeFetcher::fetch($node);
$classReflection = $scope->getClassReflection();
if (! ($classReflection instanceof ClassReflection)) {
return null;
}
$hasChanged = false;
foreach ($this->traitByTrait as $traitName => $newTraitName) {
if (! $classReflection->hasTraitUse($traitName)) {
continue;
}
if ($classReflection->hasTraitUse($newTraitName)) {
continue;
}
foreach ($node->stmts as $stmt) {
if (! ($stmt instanceof TraitUse)) {
continue;
}
foreach ($stmt->traits as $trait) {
if ($this->isName($trait, $newTraitName)) {
break 3;
}
}
}
$traitUse = new TraitUse([new FullyQualified($newTraitName)]);
$node->stmts = array_merge([$traitUse], $node->stmts);
$hasChanged = true;
}
if (! $hasChanged) {
return null;
}
return $node;
}
/**
* @param array<string, string> $configuration
*/
public function configure(array $configuration): void
{
$this->traitByTrait = $configuration;
}
}
@@ -0,0 +1,143 @@
<?php
namespace Filament\Upgrade\Rector;
use Filament\Forms\Components\DateTimePicker;
use Filament\Schemas\Schema;
use Filament\Tables\Table;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\ArrowFunction;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Expr\StaticPropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\Expression;
use PhpParser\Node\VarLikeIdentifier;
use PHPStan\Type\ObjectType;
use Rector\Rector\AbstractRector;
class ConvertStaticConfigurationToConfigureUsingFunction extends AbstractRector
{
/**
* @return array<array{
* class: class-string | array<class-string>,
* properties: array<string>,
* }>
*/
public function getChanges(): array
{
return [
[
'class' => [
DateTimePicker::class,
Schema::class,
Table::class,
],
'properties' => [
'defaultDateDisplayFormat',
'defaultDateTimeDisplayFormat',
'defaultTimeDisplayFormat',
],
],
[
'class' => [
DateTimePicker::class,
],
'properties' => [
'defaultDateTimeWithSecondsDisplayFormat',
'defaultTimeWithSecondsDisplayFormat',
],
],
[
'class' => [
Schema::class,
Table::class,
],
'properties' => [
'defaultCurrency',
'defaultIsoDateDisplayFormat',
'defaultIsoDateTimeDisplayFormat',
'defaultIsoTimeDisplayFormat',
'defaultNumberLocale',
],
],
];
}
public function getNodeTypes(): array
{
return [Expression::class];
}
public function refactor(Node $node): ?Expression
{
if (! ($node instanceof Expression)) {
return null;
}
if (! ($node->expr instanceof Assign)) {
return null;
}
if (! ($node->expr->var instanceof StaticPropertyFetch)) {
return null;
}
if (! ($node->expr->var->class instanceof FullyQualified)) {
return null;
}
if (! ($node->expr->var->name instanceof VarLikeIdentifier)) {
return null;
}
foreach ($this->getChanges() as $change) {
foreach ((is_array($change['class']) ? $change['class'] : [$change['class']]) as $class) {
if (! $this->isObjectType($node->expr->var->class, new ObjectType($class))) {
continue;
}
foreach ($change['properties'] as $property) {
if (! $this->isName($node->expr->var->name, $property)) {
continue;
}
$node->expr = new StaticCall(
class: $node->expr->var->class,
name: new Identifier('configureUsing'),
args: [
new Arg(
value: new ArrowFunction(
subNodes: [
'params' => [
new Param(
var: new Variable(lcfirst(class_basename($node->expr->var->class->toCodeString()))),
type: $node->expr->var->class,
),
],
'expr' => new MethodCall(
var: new Variable(lcfirst(class_basename($node->expr->var->class->toCodeString()))),
name: new Identifier($node->expr->var->name->toString()),
args: [
new Arg(
value: $node->expr->expr,
),
],
),
],
),
),
],
);
return $node;
}
}
}
}
}
@@ -0,0 +1,126 @@
<?php
namespace Filament\Upgrade\Rector;
use Filament\Schemas\Schema;
use PhpParser\Node;
use PhpParser\Node\Expr\ArrowFunction;
use PhpParser\Node\Expr\Closure;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Function_;
use Rector\Naming\ExpectedNameResolver\MatchParamTypeExpectedNameResolver;
use Rector\Naming\Guard\BreakingVariableRenameGuard;
use Rector\Naming\Naming\ExpectedNameResolver;
use Rector\Naming\ParamRenamer\ParamRenamer;
use Rector\Naming\Rector\ClassMethod\RenameParamToMatchTypeRector;
use Rector\Naming\ValueObject\ParamRename;
use Rector\Naming\ValueObjectFactory\ParamRenameFactory;
use Rector\Rector\AbstractRector;
use Rector\ValueObject\MethodName;
/**
* @see RenameParamToMatchTypeRector
*/
class RenameSchemaParamToMatchTypeRector extends AbstractRector
{
/**
* @readonly
*/
private BreakingVariableRenameGuard $breakingVariableRenameGuard;
/**
* @readonly
*/
private ExpectedNameResolver $expectedNameResolver;
/**
* @readonly
*/
private MatchParamTypeExpectedNameResolver $matchParamTypeExpectedNameResolver;
/**
* @readonly
*/
private ParamRenameFactory $paramRenameFactory;
/**
* @readonly
*/
private ParamRenamer $paramRenamer;
private bool $hasChanged = \false;
public function __construct(BreakingVariableRenameGuard $breakingVariableRenameGuard, ExpectedNameResolver $expectedNameResolver, MatchParamTypeExpectedNameResolver $matchParamTypeExpectedNameResolver, ParamRenameFactory $paramRenameFactory, ParamRenamer $paramRenamer)
{
$this->breakingVariableRenameGuard = $breakingVariableRenameGuard;
$this->expectedNameResolver = $expectedNameResolver;
$this->matchParamTypeExpectedNameResolver = $matchParamTypeExpectedNameResolver;
$this->paramRenameFactory = $paramRenameFactory;
$this->paramRenamer = $paramRenamer;
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [ClassMethod::class, Function_::class, Closure::class, ArrowFunction::class];
}
/**
* @param ClassMethod|Function_|Closure|ArrowFunction $node
*/
public function refactor(Node $node): ?Node
{
$this->hasChanged = \false;
foreach ($node->params as $param) {
if ((! $param->type) || (! $this->isName($param->type, Schema::class))) {
continue;
}
$expectedName = $this->expectedNameResolver->resolveForParamIfNotYet($param);
if ($expectedName === null) {
continue;
}
if ($this->shouldSkipParam($param, $expectedName, $node)) {
continue;
}
$expectedName = $this->matchParamTypeExpectedNameResolver->resolve($param);
if ($expectedName === null) {
continue;
}
$paramRename = $this->paramRenameFactory->createFromResolvedExpectedName($node, $param, $expectedName);
if (! $paramRename instanceof ParamRename) {
continue;
}
$this->paramRenamer->rename($paramRename);
$this->hasChanged = \true;
}
if (! $this->hasChanged) {
return null;
}
return $node;
}
/**
* @param ClassMethod|Function_|Closure|ArrowFunction $classMethod
*/
private function shouldSkipParam(Param $param, string $expectedName, $classMethod): bool
{
/** @var string $paramName */
$paramName = $this->getName($param);
if ($this->breakingVariableRenameGuard->shouldSkipParam($paramName, $expectedName, $classMethod, $param)) {
return \true;
}
if (! $classMethod instanceof ClassMethod) {
return \false;
}
// promoted property
if (! $this->isName($classMethod, MethodName::CONSTRUCT)) {
return \false;
}
return $param->isPromoted();
}
}
@@ -0,0 +1,67 @@
<?php
namespace Filament\Upgrade\Rector;
use PhpParser\Node;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Name\FullyQualified;
use Rector\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
class ReplaceStringPanelParamWithPanelParamRector extends AbstractRector
{
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
'Replaces the first argument with `Filament::getPanel(...)` in static method calls to `getRouteName()` and `getRouteBaseName()`',
[
new CodeSample(
'Page::getRouteName(\'admin\');',
'Page::getRouteName(Filament\Facades\Filament::getPanel(\'admin\'));'
),
]
);
}
public function getChanges(): array
{
return [
'getRouteName',
'getRouteBaseName',
];
}
public function getNodeTypes(): array
{
return [StaticCall::class];
}
public function refactor(Node $node): ?Node
{
if (! $node instanceof StaticCall) {
return null;
}
if (! in_array($node->name->name, $this->getChanges())) {
return null;
}
// Only act on static calls with arguments...
if (! count($node->args)) {
return null;
}
// Wrap first argument into `Filament::getPanel(...)` static call...
$getPanelStaticCall = new StaticCall(
new FullyQualified('Filament\Facades\Filament'),
'getPanel',
[new Node\Arg($node->args[0]->value)]
);
// Replace only first argument...
$node->args[0] = new Node\Arg($getPanelStaticCall);
return $node;
}
}
@@ -0,0 +1,216 @@
<?php
namespace Filament\Upgrade\Rector;
use Closure;
use Filament\Pages\Dashboard;
use Filament\Pages\Page;
use Filament\Pages\Tenancy\EditTenantProfile;
use Filament\Pages\Tenancy\RegisterTenant;
use Filament\Resources\Pages\CreateRecord;
use Filament\Resources\Pages\ViewRecord;
use Filament\Resources\Resource;
use Filament\Tables\Contracts\HasTable;
use PhpParser\Modifiers;
use PhpParser\Node;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Enum_;
use PhpParser\Node\UnionType;
use PHPStan\Type\ObjectType;
use Rector\Rector\AbstractRector;
class SimpleMethodChangesRector extends AbstractRector
{
/**
* @return array<array{
* class: class-string | array<class-string>,
* classIdentifier: string,
* changes: array<string, Closure>,
* }>
*/
public function getChanges(): array
{
$prependPanelParamModifier = static function (ClassMethod $node): void {
$panelParam = new Param(new Variable('panel'), type: new FullyQualified('Filament\\Panel'));
foreach ($node->getParams() as $param) {
if ($param->var->name === 'panel') {
return;
}
}
array_unshift($node->params, $panelParam);
};
$prependNullablePanelParamModifier = static function (ClassMethod $node): void {
$panelParam = new Param(
var: new Variable('panel'),
type: new Node\NullableType(new FullyQualified('Filament\\Panel')),
default: new Node\Expr\ConstFetch(new Node\Name('null'))
);
foreach ($node->getParams() as $param) {
if ($param->var->name === 'panel') {
return;
}
}
array_unshift($node->params, $panelParam);
};
return [
[
'class' => [
Page::class,
EditTenantProfile::class,
RegisterTenant::class,
],
'changes' => [
'getFooterWidgetsColumns' => function (ClassMethod $node): void {
$node->returnType = new UnionType([new Identifier('int'), new Identifier('array')]);
},
'getHeaderWidgetsColumns' => function (ClassMethod $node): void {
$node->returnType = new UnionType([new Identifier('int'), new Identifier('array')]);
},
'getSubNavigationPosition' => function (ClassMethod $node): void {
$node->flags &= Modifiers::STATIC;
},
'getRoutePath' => $prependPanelParamModifier,
'getRelativeRouteName' => $prependPanelParamModifier,
'getSlug' => $prependNullablePanelParamModifier,
'prependClusterSlug' => $prependPanelParamModifier,
'prependClusterRouteBaseName' => $prependPanelParamModifier,
],
],
[
'class' => [
Resource::class,
],
'changes' => [
'getRelativeRouteName' => $prependPanelParamModifier,
'getRoutePrefix' => $prependPanelParamModifier,
'getSlug' => $prependNullablePanelParamModifier,
],
],
[
'class' => [
CreateRecord::class,
],
'changes' => [
'canCreateAnother' => function (ClassMethod $node): void {
$node->flags &= ~Modifiers::STATIC;
},
],
],
[
'class' => [
ViewRecord::class,
],
'changes' => [
'infolist' => function (ClassMethod $node): void {
$param = new Param(new Variable('schema'));
$param->type = new FullyQualified('Filament\\Schemas\\Schema');
$node->params = [$param];
},
],
],
[
'class' => [
Dashboard::class,
],
'changes' => [
'getColumns' => function (ClassMethod $node): void {
$node->returnType = new UnionType([new Identifier('int'), new Identifier('array')]);
},
],
],
[
'class' => [
HasTable::class,
],
'changes' => [
'getTableRecordKey' => function (ClassMethod $node): void {
$param = $node->getParams()[0];
$param->type = new UnionType([new FullyQualified('Illuminate\\Database\\Eloquent\\Model'), new Identifier('array')]);
},
],
],
];
}
public function getNodeTypes(): array
{
return [Class_::class, Enum_::class];
}
/**
* @param Class_ | Enum_ $node
*/
public function refactor(Node $node): ?Node
{
$touched = false;
foreach ($this->getChanges() as $change) {
if (! $this->isClassMatchingChange($node, $change)) {
continue;
}
foreach ($change['changes'] as $methodName => $modifier) {
foreach ($node->getMethods() as $method) {
if (! $this->isName($method, $methodName)) {
continue;
}
$modifier($method);
$touched = true;
}
}
}
return $touched ? $node : null;
}
/**
* @param array{
* class: class-string | array<class-string>,
* classIdentifier: string,
* } $change
*/
public function isClassMatchingChange(Class_ | Enum_ $class, array $change): bool
{
if (! array_key_exists('class', $change)) {
return true;
}
$classes = is_array($change['class']) ?
$change['class'] :
[$change['class']];
$classes = array_map(fn (string $class): string => ltrim($class, '\\'), $classes);
foreach ($classes as $classToCheck) {
if ($class instanceof Enum_) {
foreach ($class->implements as $enumInterface) {
if ($enumInterface->toString() === $classToCheck) {
return true;
}
}
continue;
}
if ($this->isObjectType($class, new ObjectType($classToCheck))) {
return true;
}
}
return false;
}
}
@@ -0,0 +1,195 @@
<?php
namespace Filament\Upgrade\Rector;
use Closure;
use Filament\Auth\Pages\EditProfile;
use Filament\Pages\BasePage;
use Filament\Pages\Page;
use Filament\Pages\SimplePage;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Resources\Resource;
use Filament\Widgets\ChartWidget;
use Filament\Widgets\StatsOverviewWidget;
use Filament\Widgets\Widget;
use PhpParser\Modifiers;
use PhpParser\Node;
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\UnionType;
use PHPStan\Type\ObjectType;
use Rector\Rector\AbstractRector;
class SimplePropertyChangesRector extends AbstractRector
{
/**
* @return array<array{
* class: class-string | array<class-string>,
* classIdentifier: string,
* changes: array<string, Closure>,
* }>
*/
public function getChanges(): array
{
return [
[
'class' => [
BasePage::class,
RelationManager::class,
Widget::class,
],
'changes' => [
'view' => function (Property $node): void {
$node->flags &= ~Modifiers::STATIC;
},
],
],
[
'class' => [
SimplePage::class,
EditProfile::class,
],
'changes' => [
'maxWidth' => function (Property $node): void {
$node->type = new UnionType([new FullyQualified('Filament\\Support\\Enums\\Width'), new Name('string'), new Name('null')]);
},
],
],
[
'class' => [
BasePage::class,
],
'changes' => [
'maxContentWidth' => function (Property $node): void {
$node->type = new UnionType([new FullyQualified('Filament\\Support\\Enums\\Width'), new Name('string'), new Name('null')]);
},
],
],
[
'class' => [
Resource::class,
Page::class,
],
'changes' => [
'activeNavigationIcon' => function (Property $node): void {
$node->type = new Name('string | \BackedEnum | null');
},
'navigationIcon' => function (Property $node): void {
$node->type = new Name('string | \BackedEnum | null');
},
'navigationGroup' => function (Property $node): void {
$node->type = new Name('string | \UnitEnum | null');
},
'subNavigationPosition' => function (Property $node): void {
$node->type = new Name('?\Filament\Pages\Enums\SubNavigationPosition');
},
],
],
[
'class' => [
RelationManager::class,
],
'changes' => [
'icon' => function (Property $node): void {
$node->type = new Name('string | \BackedEnum | null');
},
],
],
[
'class' => [
ChartWidget::class,
StatsOverviewWidget::class,
],
'changes' => [
'pollingInterval' => function (Property $node): void {
$node->flags &= ~Modifiers::STATIC;
},
],
],
[
'class' => [
ChartWidget::class,
],
'changes' => [
'color' => function (Property $node): void {
$node->flags &= ~Modifiers::STATIC;
},
'heading' => function (Property $node): void {
$node->flags &= ~Modifiers::STATIC;
},
'description' => function (Property $node): void {
$node->flags &= ~Modifiers::STATIC;
},
'maxHeight' => function (Property $node): void {
$node->flags &= ~Modifiers::STATIC;
},
'options' => function (Property $node): void {
$node->flags &= ~Modifiers::STATIC;
},
],
],
];
}
public function getNodeTypes(): array
{
return [Class_::class];
}
/**
* @param Class_ $node
*/
public function refactor(Node $node): ?Node
{
$touched = false;
foreach ($this->getChanges() as $change) {
if (! $this->isClassMatchingChange($node, $change)) {
continue;
}
foreach ($change['changes'] as $propertyName => $modifier) {
foreach ($node->getProperties() as $property) {
if (! $this->isName($property, $propertyName)) {
continue;
}
$modifier($property);
$touched = true;
}
}
}
return $touched ? $node : null;
}
/**
* @param array{
* class: class-string | array<class-string>,
* classIdentifier: string,
* } $change
*/
public function isClassMatchingChange(Class_ $class, array $change): bool
{
if (! array_key_exists('class', $change)) {
return true;
}
$classes = is_array($change['class']) ?
$change['class'] :
[$change['class']];
$classes = array_map(fn (string $class): string => ltrim($class, '\\'), $classes);
foreach ($classes as $classToCheck) {
if ($this->isObjectType($class, new ObjectType($classToCheck))) {
return true;
}
}
return false;
}
}
@@ -0,0 +1,16 @@
<?php
namespace Filament\Upgrade;
use Filament\Upgrade\Commands\UpgradeDirectoryStructureToV4Command;
use Illuminate\Support\ServiceProvider;
class UpgradeServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->commands([
UpgradeDirectoryStructureToV4Command::class,
]);
}
}
@@ -0,0 +1,236 @@
<?php
use function Laravel\Prompts\confirm;
use function Termwind\render;
render('<p class="text-blue font-bold">Checking PHP version compatibility with v4...</p>');
if (version_compare(PHP_VERSION, '8.2.0', '<')) {
$detected = PHP_VERSION;
render('<p class="text-red font-bold">Incompatible PHP version detected</p>');
render("<p>Detected PHP {$detected}. Filament v4 and Laravel 11 require PHP 8.2+ for language features, performance improvements, and security fixes. Please upgrade your PHP runtime to 8.2 or higher before proceeding.</p>");
render(<<<'HTML'
<p class="bg-red-600 text-red-50 mt-1">
<strong>Upgrade aborted because PHP version is below 8.2</strong>
</p>
HTML);
exit(1);
}
render('<p class="text-blue font-bold">Checking Laravel version compatibility with v4...</p>');
$laravelVersion = null;
try {
if (file_exists('composer.lock')) {
$lock = json_decode(file_get_contents('composer.lock'), true);
$packages = array_merge($lock['packages'] ?? [], $lock['packages-dev'] ?? []);
foreach ($packages as $package) {
if (($package['name'] ?? '') === 'laravel/framework') {
$laravelVersion = ltrim((string) ($package['version'] ?? ''), 'v');
break;
}
}
}
} catch (Throwable $exception) {
}
if ($laravelVersion !== null && version_compare($laravelVersion, '11.28.0', '<')) {
render('<p class="text-red font-bold">Incompatible Laravel version detected</p>');
render("<p>Detected Laravel {$laravelVersion}. Filament v4 targets Laravel v11.28+ to rely on framework changes and fixes introduced in v11.28 and later. Please upgrade Laravel to at least v11.28 before continuing.</p>v");
render(<<<'HTML'
<p class="bg-red-600 text-red-50 mt-1">
<strong>Upgrade aborted because Laravel version is below 11.28</strong>
</p>
HTML);
exit(1);
}
render('<p class="text-blue font-bold">Checking plugin compatibility with v4...</p>');
$composer = json_decode(file_get_contents('composer.json'), true);
$deps = $composer['require'] ?? [];
$allPackages = array_keys($deps);
$plugins = array_filter($allPackages, function ($plugin) {
if (str_starts_with($plugin, 'filament/')) {
return false;
}
try {
$composerPath = "vendor/{$plugin}/composer.json";
if (! file_exists($composerPath)) {
return false;
}
$composerContent = file_get_contents($composerPath);
$composer = json_decode($composerContent, true);
if (! $composer || ! is_array($composer)) {
return false;
}
$requires = $composer['require'] ?? [];
foreach ($requires as $key => $value) {
if (str_starts_with($key, 'filament/')) {
return true;
}
}
return false;
} catch (Exception $exception) {
render("<p class=\"text-red\">Error checking if {$plugin} requires a filament/* package: " . $exception->getMessage() . '</p>');
}
return false;
});
// Initialize a shared global cache for Packagist data to be reused by the bin/filament-v4 script.
$GLOBALS['FILAMENT_UPGRADE_PACKAGIST'] = $GLOBALS['FILAMENT_UPGRADE_PACKAGIST'] ?? [
'versions' => [], // [plugin => ['stable' => versionsArray, 'dev' => versionsArray]]
'compatibility' => [], // [plugin => ['version' => string, 'isPrerelease' => bool] | null]
'plugins' => [], // list of detected third-party plugins
];
$GLOBALS['FILAMENT_UPGRADE_PACKAGIST']['plugins'] = array_values($plugins);
$incompatiblePlugins = [];
foreach ($plugins as $plugin) {
$version = $deps[$plugin];
$compatibility = $GLOBALS['FILAMENT_UPGRADE_PACKAGIST']['compatibility'][$plugin] ?? null;
$url = "https://repo.packagist.org/p2/{$plugin}.json";
try {
$versions = $GLOBALS['FILAMENT_UPGRADE_PACKAGIST']['versions'][$plugin]['stable'] ?? null;
if ($versions === null) {
$json = @file_get_contents($url);
if ($json) {
$data = json_decode($json, true);
$versions = $data['packages'][$plugin] ?? [];
$GLOBALS['FILAMENT_UPGRADE_PACKAGIST']['versions'][$plugin]['stable'] = $versions;
} else {
$versions = [];
$GLOBALS['FILAMENT_UPGRADE_PACKAGIST']['versions'][$plugin]['stable'] = $versions;
}
}
if ($compatibility === null && $versions) {
foreach ($versions as $checkingVersion) {
$requires = $checkingVersion['require'] ?? [];
foreach ($requires as $dep => $constraint) {
if (! str_starts_with($dep, 'filament/')) {
continue;
}
if (preg_match("/\^\s*4(?:\.|$)|~\s*4(?:\.|$)|>=\s*4(?:\.|$)/", (string) $constraint)) {
$compatibility = [
'version' => $checkingVersion['version'],
'isPrerelease' => false,
];
break;
}
}
}
}
if ($compatibility === null) {
$devVersions = $GLOBALS['FILAMENT_UPGRADE_PACKAGIST']['versions'][$plugin]['dev'] ?? null;
if ($devVersions === null) {
$devUrl = "https://repo.packagist.org/p2/{$plugin}~dev.json";
$devJson = @file_get_contents($devUrl);
if ($devJson) {
$devData = json_decode($devJson, true);
$devVersions = $devData['packages'][$plugin] ?? [];
$GLOBALS['FILAMENT_UPGRADE_PACKAGIST']['versions'][$plugin]['dev'] = $devVersions;
} else {
$devVersions = [];
$GLOBALS['FILAMENT_UPGRADE_PACKAGIST']['versions'][$plugin]['dev'] = $devVersions;
}
}
foreach ($devVersions as $checkingVersion) {
$requires = $checkingVersion['require'] ?? [];
foreach ($requires as $dep => $constraint) {
if (! str_starts_with($dep, 'filament/')) {
continue;
}
if (preg_match("/\^\s*4(?:\.|$)|~\s*4(?:\.|$)|>=\s*4(?:\.|$)/", (string) $constraint)) {
$compatibility = [
'version' => $checkingVersion['version'],
'isPrerelease' => true,
];
break;
}
}
}
}
// If still unknown and we couldn't fetch any versions from Packagist, but the package exists locally in vendor,
// assume it's a private/non-Packagist package and do not block the upgrade.
if ($compatibility === null) {
$stableEmpty = empty($GLOBALS['FILAMENT_UPGRADE_PACKAGIST']['versions'][$plugin]['stable'] ?? []);
$devEmpty = empty($GLOBALS['FILAMENT_UPGRADE_PACKAGIST']['versions'][$plugin]['dev'] ?? []);
$isInstalledLocally = file_exists("vendor/{$plugin}/composer.json");
if ($stableEmpty && $devEmpty && $isInstalledLocally) {
// Mark as compatible (unknown) to avoid blocking; we cache this decision.
$compatibility = [
'version' => 'unknown',
'isPrerelease' => false,
];
}
}
if (! array_key_exists($plugin, $GLOBALS['FILAMENT_UPGRADE_PACKAGIST']['compatibility'])) {
$GLOBALS['FILAMENT_UPGRADE_PACKAGIST']['compatibility'][$plugin] = $compatibility;
}
if ($compatibility === null) {
$incompatiblePlugins[] = $plugin;
}
} catch (Exception $exception) {
$incompatiblePlugins[] = $plugin;
}
}
if ($incompatiblePlugins) {
$pluginList = implode(', ', $incompatiblePlugins);
render('<p class="text-red font-bold mt-1">Incompatible plugins found!</p>');
render('<p>The following plugins are incompatible with Filament v4 and need to be removed before upgrading:</p>');
render("<p class=\"text-red\">{$pluginList}</p>");
render('<p>You could temporarily remove them from your composer.json file until they\'ve been upgraded, replace them with a similar plugin that is compatible with v4, wait for the plugins to be upgraded before upgrading your app, or even write PRs to help the authors upgrade them.</p>');
$continue = confirm(
label: 'Do you want to continue even though there are incompatible plugins?',
default: false,
yes: 'Yes - Continue anyway',
no: 'No - Abort upgrade',
hint: 'You\'ll need to manually remove / fix the listed plugins.',
);
if (! $continue) {
render(<<<'HTML'
<p class="bg-red-600 text-red-50 mt-1">
<strong>Upgrade aborted because of incompatible plugins</strong>
</p>
HTML);
exit(1);
}
}
@@ -0,0 +1,343 @@
<?php
use Filament\Actions\Action;
use Filament\Actions\Concerns\InteractsWithActions;
use Filament\Actions\Contracts\HasActions;
use Filament\Facades\Filament;
use Filament\FilamentManager;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Infolists\Concerns\InteractsWithInfolists;
use Filament\Schemas\Components\Component;
use Filament\Schemas\Schema;
use Filament\Support\Colors\Color;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Filters\BaseFilter;
use Filament\Tables\Table;
use Filament\Upgrade\Rector;
use Filament\Upgrade\Rector\AddTraitByTraitRector;
use Filament\Widgets\Widget;
use Rector\Config\RectorConfig;
use Rector\Renaming\Rector\MethodCall\RenameMethodRector;
use Rector\Renaming\Rector\Name\RenameClassRector;
use Rector\Renaming\Rector\PropertyFetch\RenamePropertyRector;
use Rector\Renaming\Rector\String_\RenameStringRector;
use Rector\Renaming\ValueObject\MethodCallRename;
use Rector\Renaming\ValueObject\RenameProperty;
use Rector\Transform\Rector\Class_\AddInterfaceByTraitRector;
return static function (RectorConfig $rectorConfig): void {
$rectorConfig->importNames();
$rectorConfig->importShortClasses();
$rectorConfig->ruleWithConfiguration(
RenameClassRector::class,
[
'Filament\\Forms\\Commands\\MakeLayoutComponentCommand' => 'Filament\\Schemas\\Commands\\MakeComponentCommand',
'Filament\\Pages\\Actions\\Action' => 'Filament\\Actions\\Action',
'Filament\\Forms\\Components\\BelongsToManyCheckboxList' => 'Filament\\Forms\\Components\\CheckboxList',
'Filament\\Forms\\Components\\BelongsToManyMultiSelect' => 'Filament\\Forms\\Components\\MultiSelect',
'Filament\\Forms\\Components\\BelongsToSelect' => 'Filament\\Forms\\Components\\Select',
'Filament\\Forms\\Components\\Card' => 'Filament\\Schemas\\Components\\Section',
'Filament\\Forms\\Components\\HasManyRepeater' => 'Filament\\Forms\\Components\\RelationshipRepeater',
'Filament\\Forms\\Components\\MorphManyRepeater' => 'Filament\\Forms\\Components\\RelationshipRepeater',
'Filament\\Actions\\Exceptions\\Hold' => 'Filament\\Support\\Exceptions\\Halt',
'Filament\\Actions\\Modal\\Actions' => 'Filament\\Actions\\Action',
'Filament\\Forms\\Components\\Concerns\\HasExtraAlpineAttributes' => 'Filament\\Support\\Concerns\\HasExtraAlpineAttributes',
'Filament\\Forms\\Components\\Concerns\\HasExtraAttributes' => 'Filament\\Support\\Concerns\\HasExtraAttributes',
'Filament\\Infolists\\Components\\Card' => 'Filament\\Schemas\\Components\\Section',
'Filament\\Http\\Livewire\\Auth\\Login' => 'Filament\\Auth\\Pages\\Login',
'Filament\\Navigation\\UserMenuItem' => 'Filament\\Navigation\\MenuItem',
'Filament\\Pages\\Actions\\Modal\\Actions\\Action' => 'Filament\\Actions\\Action',
'Filament\\Pages\\Actions\\Modal\\Actions\\ButtonAction' => 'Filament\\Actions\\Action',
'Filament\\Pages\\Actions\\ActionGroup' => 'Filament\\Actions\\ActionGroup',
'Filament\\Pages\\Actions\\ButtonAction' => 'Filament\\Actions\\Action',
'Filament\\Pages\\Actions\\CreateAction' => 'Filament\\Actions\\CreateAction',
'Filament\\Pages\\Actions\\DeleteAction' => 'Filament\\Actions\\DeleteAction',
'Filament\\Pages\\Actions\\EditAction' => 'Filament\\Actions\\EditAction',
'Filament\\Pages\\Actions\\ForceDeleteAction' => 'Filament\\Actions\\ForceDeleteAction',
'Filament\\Pages\\Actions\\ReplicateAction' => 'Filament\\Actions\\ReplicateAction',
'Filament\\Pages\\Actions\\RestoreAction' => 'Filament\\Actions\\RestoreAction',
'Filament\\Pages\\Actions\\SelectAction' => 'Filament\\Actions\\SelectAction',
'Filament\\Pages\\Actions\\ViewAction' => 'Filament\\Actions\\ViewAction',
'Filament\\Resources\\Pages\\ListRecords\\Tab' => 'Filament\\Resources\\Components\\Tab',
'Filament\\Tables\\Actions\\Modal\\Actions\\Action' => 'Filament\\Actions\\Action',
'Filament\\Tables\\Actions\\Modal\\Actions\\ButtonAction' => 'Filament\\Actions\\Action',
'Filament\\Tables\\Actions\\LinkAction' => 'Filament\\Actions\\Action',
'Filament\\Tables\\Columns\\Concerns\\HasExtraAttributes' => 'Filament\\Support\\Concerns\\HasExtraAttributes',
'Filament\\Widgets\\StatsOverviewWidget\\Card' => 'Filament\\Widgets\\StatsOverviewWidget\\Stat',
'Filament\\Forms\\Concerns\\BelongsToLivewire' => 'Filament\\Schemas\\Concerns\\BelongsToLivewire',
'Filament\\Forms\\Concerns\\BelongsToModel' => 'Filament\\Schemas\\Concerns\\BelongsToModel',
'Filament\\Forms\\Concerns\\BelongsToParentComponent' => 'Filament\\Schemas\\Concerns\\BelongsToParentComponent',
'Filament\\Forms\\Concerns\\CanBeDisabled' => 'Filament\\Schemas\\Concerns\\CanBeDisabled',
'Filament\\Forms\\Concerns\\CanBeHidden' => 'Filament\\Schemas\\Concerns\\CanBeHidden',
'Filament\\Forms\\Concerns\\CanBeValidated' => 'Filament\\Schemas\\Concerns\\CanBeValidated',
'Filament\\Forms\\Concerns\\Cloneable' => 'Filament\\Schemas\\Concerns\\Cloneable',
'Filament\\Forms\\Concerns\\HasComponents' => 'Filament\\Schemas\\Concerns\\HasComponents',
'Filament\\Forms\\Concerns\\HasFieldWrapper' => 'Filament\\Schemas\\Concerns\\HasFieldWrapper',
'Filament\\Forms\\Concerns\\HasInlineLabels' => 'Filament\\Schemas\\Concerns\\HasInlineLabels',
'Filament\\Forms\\Concerns\\HasOperation' => 'Filament\\Schemas\\Concerns\\HasOperation',
'Filament\\Forms\\Concerns\\HasState' => 'Filament\\Schemas\\Concerns\\HasState',
'Filament\\Forms\\Concerns\\HasColumns' => 'Filament\\Schemas\\Concerns\\HasColumns',
'Filament\\Forms\\Concerns\\HasName' => 'Filament\\Schemas\\Concerns\\HasName',
'Filament\\Infolists\\Concerns\\HasName' => 'Filament\\Schemas\\Concerns\\HasName',
'Filament\\Infolists\\Concerns\\HasColumns' => 'Filament\\Schemas\\Concerns\\HasColumns',
'Filament\\Infolists\\Infolist' => 'Filament\\Schemas\\Schema',
'Filament\\Forms\\Concerns\\HasStateBindingModifiers' => 'Filament\\Schemas\\Concerns\\HasStateBindingModifiers',
'Filament\\Forms\\Form' => 'Filament\\Schemas\\Schema',
'Filament\\Forms\\Get' => 'Filament\\Schemas\\Components\\Utilities\\Get',
'Filament\\Forms\\Set' => 'Filament\\Schemas\\Components\\Utilities\\Set',
'Filament\\Forms\\Components\\Component' => 'Filament\\Schemas\\Components\\Component',
'Filament\\Forms\\Components\\Concerns\\BelongsToContainer' => 'Filament\\Schemas\\Components\\Concerns\\BelongsToContainer',
'Filament\\Forms\\Components\\Concerns\\BelongsToModel' => 'Filament\\Schemas\\Components\\Concerns\\BelongsToModel',
'Filament\\Forms\\Components\\Concerns\\CanBeConcealed' => 'Filament\\Schemas\\Components\\Concerns\\CanBeConcealed',
'Filament\\Forms\\Components\\Concerns\\CanBeDisabled' => 'Filament\\Schemas\\Components\\Concerns\\CanBeDisabled',
'Filament\\Forms\\Components\\Concerns\\CanBeHidden' => 'Filament\\Schemas\\Components\\Concerns\\CanBeHidden',
'Filament\\Forms\\Components\\Concerns\\CanBeRepeated' => 'Filament\\Schemas\\Components\\Concerns\\CanBeRepeated',
'Filament\\Forms\\Components\\Concerns\\CanSpanColumns' => 'Filament\\Schemas\\Components\\Concerns\\CanSpanColumns',
'Filament\\Forms\\Components\\Concerns\\Cloneable' => 'Filament\\Schemas\\Components\\Concerns\\Cloneable',
'Filament\\Forms\\Components\\Concerns\\HasActions' => 'Filament\\Schemas\\Components\\Concerns\\HasActions',
'Filament\\Forms\\Components\\Concerns\\HasChildComponents' => 'Filament\\Schemas\\Components\\Concerns\\HasChildComponents',
'Filament\\Forms\\Components\\Concerns\\HasFieldWrapper' => 'Filament\\Schemas\\Components\\Concerns\\HasFieldWrapper',
'Filament\\Forms\\Components\\Concerns\\HasId' => 'Filament\\Schemas\\Components\\Concerns\\HasId',
'Filament\\Forms\\Components\\Concerns\\HasInlineLabel' => 'Filament\\Schemas\\Components\\Concerns\\HasInlineLabel',
'Filament\\Forms\\Components\\Concerns\\HasKey' => 'Filament\\Schemas\\Components\\Concerns\\HasKey',
'Filament\\Forms\\Components\\Concerns\\HasLabel' => 'Filament\\Schemas\\Components\\Concerns\\HasLabel',
'Filament\\Forms\\Components\\Concerns\\HasMaxWidth' => 'Filament\\Schemas\\Components\\Concerns\\HasMaxWidth',
'Filament\\Forms\\Components\\Concerns\\HasMeta' => 'Filament\\Schemas\\Components\\Concerns\\HasMeta',
'Filament\\Forms\\Components\\Concerns\\HasState' => 'Filament\\Schemas\\Components\\Concerns\\HasState',
'Filament\\Forms\\Components\\Actions\\Concerns\\BelongsToComponent' => 'Filament\\Actions\\Concerns\\BelongsToSchemaComponent',
'Filament\\Forms\\Components\\Actions' => 'Filament\\Schemas\\Components\\Actions',
'Filament\\Forms\\Components\\Actions\\Action' => 'Filament\\Actions\\Action',
'Filament\\Forms\\Components\\Tabs' => 'Filament\\Schemas\\Components\\Tabs',
'Filament\\Forms\\Components\\Tabs\\Tab' => 'Filament\\Schemas\\Components\\Tabs\\Tab',
'Filament\\Forms\\Components\\Contracts\\CanConcealComponents' => 'Filament\\Schemas\\Components\\Contracts\\CanConcealComponents',
'Filament\\Forms\\Components\\Wizard' => 'Filament\\Schemas\\Components\\Wizard',
'Filament\\Forms\\Components\\Wizard\\Step' => 'Filament\\Schemas\\Components\\Wizard\\Step',
'Filament\\Forms\\Components\\Fieldset' => 'Filament\\Schemas\\Components\\Fieldset',
'Filament\\Forms\\Components\\Concerns\\EntanglesStateWithSingularRelationship' => 'Filament\\Schemas\\Components\\Concerns\\EntanglesStateWithSingularRelationship',
'Filament\\Forms\\Components\\Contracts\\CanEntangleWithSingularRelationships' => 'Filament\\Schemas\\Components\\Contracts\\CanEntangleWithSingularRelationships',
'Filament\\Forms\\Components\\Grid' => 'Filament\\Schemas\\Components\\Grid',
'Filament\\Forms\\Components\\Group' => 'Filament\\Schemas\\Components\\Group',
'Filament\\Forms\\Components\\Livewire' => 'Filament\\Schemas\\Components\\Livewire',
'Filament\\Forms\\Components\\Section' => 'Filament\\Schemas\\Components\\Section',
'Filament\\Forms\\Components\\Split' => 'Filament\\Schemas\\Components\\Flex',
'Filament\\Forms\\Components\\View' => 'Filament\\Schemas\\Components\\View',
'Filament\\Forms\\Components\\Concerns\\CanBeCollapsed' => 'Filament\\Schemas\\Components\\Concerns\\CanBeCollapsed',
'Filament\\Forms\\Components\\Concerns\\CanBeCompacted' => 'Filament\\Schemas\\Components\\Concerns\\CanBeCompact',
'Filament\\Forms\\Components\\Concerns\\HasFooterActions' => 'Filament\\Schemas\\Components\\Concerns\\HasFooterActions',
'Filament\\Forms\\Components\\Concerns\\HasHeaderActions' => 'Filament\\Schemas\\Components\\Concerns\\HasHeaderActions',
'Filament\\Forms\\ComponentContainer' => 'Filament\\Schemas\\Schema',
'Filament\\Infolists\\ComponentContainer' => 'Filament\\Schemas\\Schema',
'Filament\\Infolists\\Concerns\\BelongsToLivewire' => 'Filament\\Schemas\\Concerns\\BelongsToLivewire',
'Filament\\Infolists\\Concerns\\BelongsToParentComponent' => 'Filament\\Schemas\\Concerns\\BelongsToParentComponent',
'Filament\\Infolists\\Concerns\\CanBeHidden' => 'Filament\\Schemas\\Concerns\\CanBeHidden',
'Filament\\Infolists\\Concerns\\Cloneable' => 'Filament\\Schemas\\Concerns\\Cloneable',
'Filament\\Infolists\\Concerns\\HasComponents' => 'Filament\\Schemas\\Concerns\\HasComponents',
'Filament\\Infolists\\Concerns\\HasInlineLabels' => 'Filament\\Schemas\\Concerns\\HasInlineLabels',
'Filament\\Infolists\\Concerns\\HasState' => 'Filament\\Schemas\\Concerns\\HasState',
'Filament\\Infolists\\Concerns\\HasEntryWrapper' => 'Filament\\Schemas\\Concerns\\HasEntryWrapper',
'Filament\\Infolists\\Components\\Actions\\Action' => 'Filament\\Actions\\Action',
'Filament\\Infolists\\Components\\Component' => 'Filament\\Schemas\\Components\\Component',
'Filament\\Infolists\\Components\\Actions\\Concerns\\BelongsToInfolist' => 'Filament\\Actions\\Concerns\\BelongsToSchemaComponent',
'Filament\\Infolists\\Components\\Concerns\\BelongsToContainer' => 'Filament\\Schemas\\Components\\Concerns\\BelongsToContainer',
'Filament\\Infolists\\Components\\Concerns\\CanBeHidden' => 'Filament\\Schemas\\Components\\Concerns\\CanBeHidden',
'Filament\\Infolists\\Components\\Concerns\\CanSpanColumns' => 'Filament\\Schemas\\Components\\Concerns\\CanSpanColumns',
'Filament\\Infolists\\Components\\Concerns\\Cloneable' => 'Filament\\Schemas\\Components\\Concerns\\Cloneable',
'Filament\\Infolists\\Components\\Concerns\\HasActions' => 'Filament\\Schemas\\Components\\Concerns\\HasActions',
'Filament\\Infolists\\Components\\Concerns\\HasChildComponents' => 'Filament\\Schemas\\Components\\Concerns\\HasChildComponents',
'Filament\\Infolists\\Components\\Concerns\\HasId' => 'Filament\\Schemas\\Components\\Concerns\\HasId',
'Filament\\Infolists\\Components\\Concerns\\HasInlineLabel' => 'Filament\\Schemas\\Components\\Concerns\\HasInlineLabel',
'Filament\\Infolists\\Components\\Concerns\\HasKey' => 'Filament\\Schemas\\Components\\Concerns\\HasKey',
'Filament\\Infolists\\Components\\Concerns\\HasLabel' => 'Filament\\Schemas\\Components\\Concerns\\HasLabel',
'Filament\\Infolists\\Components\\Concerns\\HasMaxWidth' => 'Filament\\Schemas\\Components\\Concerns\\HasMaxWidth',
'Filament\\Infolists\\Components\\Concerns\\HasEntryWrapper' => 'Filament\\Schemas\\Components\\Concerns\\HasEntryWrapper',
'Filament\\Infolists\\Components\\Concerns\\HasMeta' => 'Filament\\Schemas\\Components\\Concerns\\HasMeta',
'Filament\\Infolists\\Components\\Concerns\\HasState' => 'Filament\\Schemas\\Components\\Concerns\\HasState',
'Filament\\Infolists\\Components\\Concerns\\CanGetStateFromRelationships' => 'Filament\\Schemas\\Components\\Concerns\\CanGetStateFromRelationships',
'Filament\\Infolists\\Components\\Contracts\\HasAffixActions' => 'Filament\\Schemas\\Components\\Contracts\\HasAffixActions',
'Filament\\Forms\\Components\\Contracts\\HasAffixActions' => 'Filament\\Schemas\\Components\\Contracts\\HasAffixActions',
'Filament\\Forms\\Components\\Contracts\\HasExtraItemActions' => 'Filament\\Schemas\\Components\\Contracts\\HasExtraItemActions',
'Filament\\Infolists\\Commands\\MakeLayoutComponentCommand' => 'Filament\\Schemas\\Commands\\MakeComponentCommand',
'Filament\\Infolists\\Components\\Actions' => 'Filament\\Schemas\\Components\\Actions',
'Filament\\Infolists\\Components\\Tabs' => 'Filament\\Schemas\\Components\\Tabs',
'Filament\\Infolists\\Components\\Tabs\\Tab' => 'Filament\\Schemas\\Components\\Tabs\\Tab',
'Filament\\Infolists\\Components\\Fieldset' => 'Filament\\Schemas\\Components\\Fieldset',
'Filament\\Infolists\\Components\\Concerns\\EntanglesStateWithSingularRelationship' => 'Filament\\Schemas\\Components\\Concerns\\EntanglesStateWithSingularRelationship',
'Filament\\Infolists\\Components\\Grid' => 'Filament\\Schemas\\Components\\Grid',
'Filament\\Infolists\\Components\\Group' => 'Filament\\Schemas\\Components\\Group',
'Filament\\Infolists\\Components\\Livewire' => 'Filament\\Schemas\\Components\\Livewire',
'Filament\\Infolists\\Components\\Section' => 'Filament\\Schemas\\Components\\Section',
'Filament\\Infolists\\Components\\Split' => 'Filament\\Schemas\\Components\\Flex',
'Filament\\Infolists\\Components\\View' => 'Filament\\Schemas\\Components\\View',
'Filament\\Infolists\\Components\\Concerns\\CanBeCollapsed' => 'Filament\\Schemas\\Components\\Concerns\\CanBeCollapsed',
'Filament\\Infolists\\Components\\Concerns\\CanBeCompacted' => 'Filament\\Schemas\\Components\\Concerns\\CanBeCompact',
'Filament\\Infolists\\Components\\Concerns\\HasFooterActions' => 'Filament\\Schemas\\Components\\Concerns\\HasFooterActions',
'Filament\\Infolists\\Components\\Concerns\\HasHeaderActions' => 'Filament\\Schemas\\Components\\Concerns\\HasHeaderActions',
'Filament\\Actions\\MountableAction' => 'Filament\\Actions\\Action',
'Filament\\Tables\\Actions\\Action' => 'Filament\\Actions\\Action',
'Filament\\Tables\\Actions\\BulkAction' => 'Filament\\Actions\\BulkAction',
'Filament\\Tables\\Actions\\AssociateAction' => 'Filament\\Actions\\AssociateAction',
'Filament\\Tables\\Actions\\AttachAction' => 'Filament\\Actions\\AttachAction',
'Filament\\Tables\\Actions\\BulkActionGroup' => 'Filament\\Actions\\BulkActionGroup',
'Filament\\Tables\\Actions\\ButtonAction' => 'Filament\\Actions\\ButtonAction',
'Filament\\Tables\\Actions\\DeleteBulkAction' => 'Filament\\Actions\\DeleteBulkAction',
'Filament\\Tables\\Actions\\DetachAction' => 'Filament\\Actions\\DetachAction',
'Filament\\Tables\\Actions\\DetachBulkAction' => 'Filament\\Actions\\DetachBulkAction',
'Filament\\Tables\\Actions\\DissociateAction' => 'Filament\\Actions\\DissociateAction',
'Filament\\Tables\\Actions\\DissociateBulkAction' => 'Filament\\Actions\\DissociateBulkAction',
'Filament\\Tables\\Actions\\ExportBulkAction' => 'Filament\\Actions\\ExportBulkAction',
'Filament\\Tables\\Actions\\ForceDeleteBulkAction' => 'Filament\\Actions\\ForceDeleteBulkAction',
'Filament\\Tables\\Actions\\IconButtonAction' => 'Filament\\Actions\\IconButtonAction',
'Filament\\Tables\\Actions\\RestoreBulkAction' => 'Filament\\Actions\\RestoreBulkAction',
'Filament\\Tables\\Actions\\ActionGroup' => 'Filament\\Actions\\ActionGroup',
'Filament\\Tables\\Actions\\CreateAction' => 'Filament\\Actions\\CreateAction',
'Filament\\Tables\\Actions\\DeleteAction' => 'Filament\\Actions\\DeleteAction',
'Filament\\Tables\\Actions\\EditAction' => 'Filament\\Actions\\EditAction',
'Filament\\Tables\\Actions\\ExportAction' => 'Filament\\Actions\\ExportAction',
'Filament\\Tables\\Actions\\ForceDeleteAction' => 'Filament\\Actions\\ForceDeleteAction',
'Filament\\Tables\\Actions\\ImportAction' => 'Filament\\Actions\\ImportAction',
'Filament\\Tables\\Actions\\ReplicateAction' => 'Filament\\Actions\\ReplicateAction',
'Filament\\Tables\\Actions\\RestoreAction' => 'Filament\\Actions\\RestoreAction',
'Filament\\Tables\\Actions\\SelectAction' => 'Filament\\Actions\\SelectAction',
'Filament\\Tables\\Actions\\ViewAction' => 'Filament\\Actions\\ViewAction',
'Filament\\Actions\\StaticAction' => 'Filament\\Actions\\Action',
'Filament\\Notifications\\Actions\\Action' => 'Filament\\Actions\\Action',
'Filament\\Notifications\\Actions\\ActionGroup' => 'Filament\\Actions\\ActionGroup',
'Filament\\GlobalSearch\\Actions\\Action' => 'Filament\\Actions\\Action',
'Filament\\Support\\Concerns\\HasExtraSidebarAttributes' => 'Filament\\Navigation\\Concerns\\HasExtraSidebarAttributes',
'Filament\\Support\\Concerns\\HasExtraTopbarAttributes' => 'Filament\\Navigation\\Concerns\\HasExtraTopbarAttributes',
'Filament\\Support\\Concerns\\CanPersistTab' => 'Filament\\Schemas\\Components\\Concerns\\CanPersistTab',
'Filament\\Support\\Concerns\\HasDescription' => 'Filament\\Schemas\\Components\\Concerns\\HasDescription',
'Filament\\Support\\Concerns\\HasFooterActionsAlignment' => 'Filament\\Schemas\\Components\\Concerns\\HasFooterActionsAlignment',
'Filament\\Support\\Concerns\\HasHeading' => 'Filament\\Schemas\\Components\\Concerns\\HasHeading',
'Filament\\Support\\Concerns\\ResolvesDynamicLivewireProperties' => 'Filament\\Schemas\\Concerns\\ResolvesDynamicLivewireProperties',
'Filament\\Pages\\SubNavigationPosition' => 'Filament\\Pages\\Enums\\SubNavigationPosition',
'Filament\\Resources\\Pages\\ContentTabPosition' => 'Filament\\Resources\\Pages\\Enums\\ContentTabPosition',
'Filament\\Tables\\Columns\\Concerns\\HasTooltip' => 'Filament\\Support\\Concerns\\HasTooltip',
'Filament\\Actions\\Concerns\\HasTooltip' => 'Filament\\Support\\Concerns\\HasTooltip',
'Filament\\Infolists\\Components\\Concerns\\HasTooltip' => 'Filament\\Support\\Concerns\\HasTooltip',
'Filament\\Infolists\\Components\\Concerns\\HasFontFamily' => 'Filament\\Support\\Concerns\\HasFontFamily',
'Filament\\Infolists\\Components\\Concerns\\HasWeight' => 'Filament\\Support\\Concerns\\HasWeight',
'Filament\\Tables\\Columns\\Concerns\\HasFontFamily' => 'Filament\\Support\\Concerns\\HasFontFamily',
'Filament\\Tables\\Columns\\Concerns\\HasWeight' => 'Filament\\Support\\Concerns\\HasWeight',
'Filament\\Resources\\Components\\Tab' => 'Filament\\Schemas\\Components\\Tabs\\Tab',
'Filament\\Billing\\Providers\\Contracts\\Provider' => 'Filament\\Billing\\Providers\\Contracts\\BillingProvider',
'Filament\\GlobalSearch\\Contracts\\GlobalSearchProvider' => 'Filament\\GlobalSearch\\Providers\\Contracts\\GlobalSearchProvider',
'Filament\\GlobalSearch\\DefaultGlobalSearchProvider' => 'Filament\\GlobalSearch\\Providers\\DefaultGlobalSearchProvider',
'Filament\\Events\\Auth\\Registered' => 'Filament\\Auth\\Events\\Registered',
'Filament\\Http\\Controllers\\Auth\\EmailVerificationController' => 'Filament\\Auth\\Http\\Controllers\\EmailVerificationController',
'Filament\\Http\\Controllers\\Auth\\LogoutController' => 'Filament\\Auth\\Http\\Controllers\\LogoutController',
'Filament\\Http\\Responses\\Auth\\Contracts\\EmailVerificationResponse' => 'Filament\\Auth\\Http\\Responses\\Contracts\\EmailVerificationResponse',
'Filament\\Http\\Responses\\Auth\\Contracts\\LoginResponse' => 'Filament\\Auth\\Http\\Responses\\Contracts\\LoginResponse',
'Filament\\Http\\Responses\\Auth\\Contracts\\LogoutResponse' => 'Filament\\Auth\\Http\\Responses\\Contracts\\LogoutResponse',
'Filament\\Http\\Responses\\Auth\\Contracts\\PasswordResetResponse' => 'Filament\\Auth\\Http\\Responses\\Contracts\\PasswordResetResponse',
'Filament\\Http\\Responses\\Auth\\Contracts\\RegistrationResponse' => 'Filament\\Auth\\Http\\Responses\\Contracts\\RegistrationResponse',
'Filament\\Http\\Responses\\Auth\\EmailVerificationResponse' => 'Filament\\Auth\\Http\\Responses\\EmailVerificationResponse',
'Filament\\Http\\Responses\\Auth\\LoginResponse' => 'Filament\\Auth\\Http\\Responses\\LoginResponse',
'Filament\\Http\\Responses\\Auth\\LogoutResponse' => 'Filament\\Auth\\Http\\Responses\\LogoutResponse',
'Filament\\Http\\Responses\\Auth\\PasswordResetResponse' => 'Filament\\Auth\\Http\\Responses\\PasswordResetResponse',
'Filament\\Http\\Responses\\Auth\\RegistrationResponse' => 'Filament\\Auth\\Http\\Responses\\RegistrationResponse',
'Filament\\Notifications\\Auth\\ResetPassword' => 'Filament\\Auth\\Notifications\\ResetPassword',
'Filament\\Notifications\\Auth\\VerifyEmail' => 'Filament\\Auth\\Notifications\\VerifyEmail',
'Filament\\Pages\\Auth\\EditProfile' => 'Filament\\Auth\\Pages\\EditProfile',
'Filament\\Pages\\Auth\\EmailVerification\\EmailVerificationPrompt' => 'Filament\\Auth\\Pages\\EmailVerification\\EmailVerificationPrompt',
'Filament\\Pages\\Auth\\Login' => 'Filament\\Auth\\Pages\\Login',
'Filament\\Pages\\Auth\\PasswordReset\\RequestPasswordReset' => 'Filament\\Auth\\Pages\\PasswordReset\\RequestPasswordReset',
'Filament\\Pages\\Auth\\PasswordReset\\ResetPassword' => 'Filament\\Auth\\Pages\\PasswordReset\\ResetPassword',
'Filament\\Pages\\Auth\\Register' => 'Filament\\Auth\\Pages\\Register',
'Filament\\Support\\Enums\\MaxWidth' => 'Filament\\Support\\Enums\\Width',
'Filament\\Infolists\\Components\\IconEntry\\IconEntrySize' => 'Filament\\Support\\Enums\\IconSize',
'Filament\\Infolists\\Components\\TextEntry\\TextEntrySize' => 'Filament\\Support\\Enums\\TextSize',
'Filament\\Tables\\Columns\\IconColumn\\IconColumnSize' => 'Filament\\Support\\Enums\\IconSize',
'Filament\\Tables\\Columns\\TextColumn\\TextColumnSize' => 'Filament\\Support\\Enums\\TextSize',
'Filament\\Support\\View\\Components\\Modal' => 'Filament\\Support\\View\\Components\\ModalComponent',
'Filament\\Support\\Enums\\ActionSize' => 'Filament\\Support\\Enums\\Size',
'Filament\\SpatieLaravelTranslatablePlugin' => 'LaraZeus\\SpatieTranslatable\\SpatieTranslatablePlugin',
'Filament\\Resources\\Concerns\\Translatable' => 'LaraZeus\\SpatieTranslatable\\Resources\\Concerns\\Translatable',
'Filament\\Resources\\Pages\\ListRecords\\Concerns\\Translatable' => 'LaraZeus\\SpatieTranslatable\\Resources\\Pages\\ListRecords\\Concerns\\Translatable',
'Filament\\Resources\\Pages\\CreateRecord\\Concerns\\Translatable' => 'LaraZeus\\SpatieTranslatable\\Resources\\Pages\\CreateRecord\\Concerns\\Translatable',
'Filament\\Resources\\Pages\\EditRecord\\Concerns\\Translatable' => 'LaraZeus\\SpatieTranslatable\\Resources\\Pages\\EditRecord\\Concerns\\Translatable',
'Filament\\Resources\\Pages\\ViewRecord\\Concerns\\Translatable' => 'LaraZeus\\SpatieTranslatable\\Resources\\Pages\\ViewRecord\\Concerns\\Translatable',
'Filament\\Resources\\Pages\\ManageRecords\\Concerns\\Translatable' => 'LaraZeus\\SpatieTranslatable\\Resources\\Pages\\ManageRecords\\Concerns\\Translatable',
'Filament\\Actions\\LocaleSwitcher' => 'LaraZeus\\SpatieTranslatable\\Actions\\LocaleSwitcher',
'Filament\\Tables\\Actions\\LocaleSwitcher' => 'LaraZeus\\SpatieTranslatable\\Actions\\LocaleSwitcher',
'Filament\\Tables\\Enums\\ActionsPosition' => 'Filament\\Tables\\Enums\\RecordActionsPosition',
],
);
$rectorConfig->ruleWithConfiguration(
RenameStringRector::class,
[
'filament-forms::components.actions' => 'filament-schemas::components.actions',
'filament-forms::components.tabs' => 'filament-schemas::components.tabs',
'filament-forms::components.tabs.tab' => 'filament-schemas::components.tabs.tab',
'filament-forms::components.wizard' => 'filament-schemas::components.wizard',
'filament-forms::components.wizard.step' => 'filament-schemas::components.wizard.step',
'filament-forms::components.fieldset' => 'filament-schemas::components.fieldset',
'filament-forms::components.grid' => 'filament-schemas::components.grid',
'filament-forms::components.group' => 'filament-schemas::components.grid',
'filament-forms::components.livewire' => 'filament-schemas::components.livewire',
'filament-forms::components.section' => 'filament-schemas::components.section',
'filament-forms::components.split' => 'filament-schemas::components.split',
'filament-infolists::components.actions' => 'filament-schemas::components.actions',
'filament-infolists::components.tabs' => 'filament-schemas::components.tabs',
'filament-infolists::components.tabs.tab' => 'filament-schemas::components.tabs.tab',
'filament-infolists::components.fieldset' => 'filament-schemas::components.fieldset',
'filament-infolists::components.grid' => 'filament-schemas::components.grid',
'filament-infolists::components.group' => 'filament-schemas::components.grid',
'filament-infolists::components.livewire' => 'filament-schemas::components.livewire',
'filament-infolists::components.section' => 'filament-schemas::components.section',
'filament-infolists::components.split' => 'filament-schemas::components.split',
],
);
$rectorConfig->ruleWithConfiguration(
RenamePropertyRector::class,
[
new RenameProperty(Widget::class, 'filters', 'pageFilters'),
],
);
$rectorConfig->rules([
Rector\AddPanelParamToRouteMethodsRector::class,
Rector\ReplaceStringPanelParamWithPanelParamRector::class,
Rector\SimpleMethodChangesRector::class,
Rector\SimplePropertyChangesRector::class,
Rector\RenameSchemaParamToMatchTypeRector::class,
Rector\ConvertStaticConfigurationToConfigureUsingFunction::class,
]);
$rectorConfig->ruleWithConfiguration(RenameMethodRector::class, [
new MethodCallRename(Action::class, 'infolist', 'schema'),
new MethodCallRename(Action::class, 'form', 'schema'),
new MethodCallRename(Action::class, 'mutateFormDataUsing', 'mutateDataUsing'),
new MethodCallRename(Component::class, 'getChildComponents', 'getDefaultChildComponents'),
new MethodCallRename(Component::class, 'getChildComponentContainer', 'getChildSchema'),
new MethodCallRename(Component::class, 'getChildComponentContainers', 'getChildSchemas'),
new MethodCallRename(BaseFilter::class, 'form', 'schema'),
new MethodCallRename(Schema::class, 'schema', 'components'),
new MethodCallRename(FilamentManager::class, 'getCurrentPanel', 'getCurrentOrDefaultPanel'),
new MethodCallRename(Filament::class, 'getCurrentPanel', 'getCurrentOrDefaultPanel'),
new MethodCallRename(Color::class, 'hex', 'generateV3Palette'),
new MethodCallRename(Color::class, 'rgb', 'generateV3Palette'),
new MethodCallRename(Table::class, 'actions', 'recordActions'),
new MethodCallRename(Table::class, 'pushActions', 'pushRecordActions'),
new MethodCallRename(Table::class, 'actionsColumnLabel', 'recordActionsColumnLabel'),
new MethodCallRename(Table::class, 'actionsAlignment', 'recordActionsAlignment'),
new MethodCallRename(Table::class, 'actionsPosition', 'recordActionsPosition'),
new MethodCallRename(Table::class, 'bulkActions', 'toolbarActions'),
new MethodCallRename(Table::class, 'pushBulkActions', 'pushToolbarActions'),
]);
$rectorConfig->ruleWithConfiguration(AddInterfaceByTraitRector::class, [
InteractsWithForms::class => HasActions::class,
InteractsWithInfolists::class => HasActions::class,
InteractsWithTable::class => HasActions::class,
]);
$rectorConfig->ruleWithConfiguration(AddTraitByTraitRector::class, [
InteractsWithForms::class => InteractsWithActions::class,
InteractsWithInfolists::class => InteractsWithActions::class,
InteractsWithTable::class => InteractsWithActions::class,
]);
};