From d1cf85341381ee5aa687b55e4ac7fc47553826fa Mon Sep 17 00:00:00 2001 From: YoussefACHCHIRAJ Date: Sat, 11 Oct 2025 21:51:11 +0100 Subject: [PATCH 1/4] feat: remove component command - removing component and related dependencies and helpers --- src/Commands/RemoveComponentCommand.php | 76 +++++++++++++++++++ ...Command.php => UpdateComponentCommand.php} | 2 +- src/ServiceProvider.php | 6 +- src/Services/ComponentHttpClient.php | 19 +++++ src/Services/ComponentRemover.php | 72 ++++++++++++++++++ src/Services/JavaScriptAssetService.php | 23 ++++++ src/Services/SheafConfig.php | 4 +- .../Installation/FullInstallationStrategy.php | 54 +++++++++++++ 8 files changed, 251 insertions(+), 5 deletions(-) create mode 100644 src/Commands/RemoveComponentCommand.php rename src/Commands/{UpdateCommand.php => UpdateComponentCommand.php} (96%) create mode 100644 src/Services/ComponentRemover.php diff --git a/src/Commands/RemoveComponentCommand.php b/src/Commands/RemoveComponentCommand.php new file mode 100644 index 0000000..2d721d1 --- /dev/null +++ b/src/Commands/RemoveComponentCommand.php @@ -0,0 +1,76 @@ +getComponentName(); + + foreach ($componentNames as $name) { + + $this->banner("Removing all $name files"); + + $this->componentRemover->remove($name); + } + + return Command::SUCCESS; + } + + private function getComponentName() + { + $componentName = $this->argument('name'); + + + if (!$componentName) { + $componentName = text(label: 'What are the component(s) you would like to remove?', placeholder: 'button', required: true); + } + + + return Arr::wrap($componentName); + } + + public function banner(string $title): void + { + $length = strlen(" {$title}") + 4; + + $this->newLine(); + $this->line(str_repeat("═", $length)); + $this->line(" {$title}"); + $this->line(str_repeat("═", $length)); + $this->newLine(); + } +} diff --git a/src/Commands/UpdateCommand.php b/src/Commands/UpdateComponentCommand.php similarity index 96% rename from src/Commands/UpdateCommand.php rename to src/Commands/UpdateComponentCommand.php index c029e8b..242708b 100644 --- a/src/Commands/UpdateCommand.php +++ b/src/Commands/UpdateComponentCommand.php @@ -5,7 +5,7 @@ use Illuminate\Console\Command; use Sheaf\Cli\Services\ComponentUpdater; -class UpdateCommand extends Command +class UpdateComponentCommand extends Command { /** * The name and signature of the console command. diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 7bca8ec..3664459 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -9,7 +9,8 @@ use Sheaf\Cli\Commands\LogoutCommand; use Sheaf\Cli\Commands\WhoAmICommand; use Illuminate\Support\ServiceProvider as SupportServiceProvider; -use Sheaf\Cli\Commands\UpdateCommand; +use Sheaf\Cli\Commands\RemoveComponentCommand; +use Sheaf\Cli\Commands\UpdateComponentCommand; class ServiceProvider extends SupportServiceProvider { @@ -22,7 +23,8 @@ public function boot() $this->commands([InstallComponentCommand::class]); $this->commands([LogoutCommand::class]); $this->commands([WhoAmICommand::class]); - $this->commands([UpdateCommand::class]); + $this->commands([UpdateComponentCommand::class]); + $this->commands([RemoveComponentCommand::class]); } $this->publishes( diff --git a/src/Services/ComponentHttpClient.php b/src/Services/ComponentHttpClient.php index 0ac1874..114fe01 100644 --- a/src/Services/ComponentHttpClient.php +++ b/src/Services/ComponentHttpClient.php @@ -16,6 +16,25 @@ public function __construct() $this->baseUrl = config('sheaf.cli.server_url'); $this->token = SheafConfig::getUserToken(); } + + public function fetchComponentFilesPath(string $name) { + $url = "{$this->baseUrl}/api/cli/components/$name/files"; + + $response = Http::asJson()->get($url); + + if ($response->failed()) { + $component = Str::of($name)->headline(); + $message = array_key_exists('message', $response->json() ?? []) ? $response->json()['message'] : ""; + + throw new Exception("Failed to install the component '$component'. \n $message"); + } + + return [ + 'success' => true, + 'data' => $response->collect() + ]; + + } public function fetchResources(string $componentName) { diff --git a/src/Services/ComponentRemover.php b/src/Services/ComponentRemover.php new file mode 100644 index 0000000..3f44461 --- /dev/null +++ b/src/Services/ComponentRemover.php @@ -0,0 +1,72 @@ +cleaningSheafLock($name); + } + + protected function cleaningSheafLock($name) + { + $sheafLockPath = base_path('sheaf-lock.json'); + + + $sheafLock = []; + + if (File::exists($sheafLockPath)) { + $sheafLock = json_decode(File::get($sheafLockPath), true) ?: []; + } + + foreach ($sheafLock['files'] as $path => $components) { + $components = array_values(array_filter($components, fn($c) => $c !== $name)); + + if (empty($components)) { + File::delete($path); + unset($sheafLock['files'][$path]); + } else { + $sheafLock['files'][$path] = $components; + } + } + + foreach ($sheafLock['internalDependencies'] as $dep => $components) { + $components = array_values(array_filter($components, fn($c) => $c !== $name)); + + if (empty($components)) { + $remover = new self(); + + $remover->remove($dep); + unset($sheafLock['internalDependencies'][$dep]); + }else { + $sheafLock['internalDependencies'][$dep] = $components; + } + } + + foreach ($sheafLock['helpers'] as $helper => $components) { + $components = array_values(array_filter($components, fn($c) => $c !== $name)); + + if (empty($components)) { + File::delete(resource_path("views/components/ui/$helper.blade.php")); + unset($sheafLock['helpers'][$helper]); + }else { + $sheafLock['helpers'][$helper] = $components; + } + } + + File::put($sheafLockPath, json_encode($sheafLock, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); + } +} diff --git a/src/Services/JavaScriptAssetService.php b/src/Services/JavaScriptAssetService.php index fac7eab..6576f3c 100644 --- a/src/Services/JavaScriptAssetService.php +++ b/src/Services/JavaScriptAssetService.php @@ -124,6 +124,7 @@ public function SetupLivewire() protected function createUtilsFile(): bool { $path = resource_path("js/utils.js"); + $this->updateSheafLock("resources/js/utils.js", "dark-theme"); if (File::exists($path) && !$this->forceOverwrite) { $this->command->warn("File already exists: utils.js"); @@ -301,4 +302,26 @@ protected function hasLivewire3(): bool return version_compare($version, 'v3.0.0', '>='); } + + protected function updateSheafLock($path, $name) { + + $sheafLockPath = base_path('sheaf-lock.json'); + + $sheafLock = []; + + if(File::exists($sheafLockPath)) { + $sheafLock = json_decode(File::get($sheafLockPath), true) ?: []; + } + + $sheafLock['files'] ??= []; + $sheafLock['files'][$path] ??= []; + + if(!in_array($name, $sheafLock['files'][$path], true)) { + $sheafLock['files'][$path][] = $name; + } + + File::put($sheafLockPath, json_encode($sheafLock, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); + + } + } diff --git a/src/Services/SheafConfig.php b/src/Services/SheafConfig.php index 25a7976..d637bc3 100644 --- a/src/Services/SheafConfig.php +++ b/src/Services/SheafConfig.php @@ -118,7 +118,7 @@ public static function saveInstalledComponent(string $componentName) 'installationTime' => time() ]; - File::put(base_path('sheaf.json'), json_encode($installedComponents, true)); + File::put(base_path('sheaf.json'), json_encode($installedComponents, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); } public static function getInstalledComponents() @@ -126,7 +126,7 @@ public static function getInstalledComponents() $installedComponents = []; if (File::exists(base_path('sheaf.json'))) { - $installedComponents = json_decode(File::get(base_path('sheaf.json')), true); + $installedComponents = json_decode(File::get(base_path('sheaf.json')), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); } return $installedComponents; diff --git a/src/Strategies/Installation/FullInstallationStrategy.php b/src/Strategies/Installation/FullInstallationStrategy.php index 2982f71..156fa89 100644 --- a/src/Strategies/Installation/FullInstallationStrategy.php +++ b/src/Strategies/Installation/FullInstallationStrategy.php @@ -8,6 +8,8 @@ use Sheaf\Cli\Services\SheafConfig; use Sheaf\Cli\Traits\CanHandleDependenciesInstallation; use Illuminate\Console\Command; +use Illuminate\Support\Arr; +use Illuminate\Support\Facades\File; class FullInstallationStrategy extends BaseInstallationStrategy { @@ -24,10 +26,12 @@ public function execute($componentResources): int $this->reportInstallation($createdFiles); + $this->runInitialization(); $this->installDependencies($componentResources->get('dependencies')); + $this->updateSheafLock($createdFiles, $componentResources->get('dependencies')); return Command::SUCCESS; } @@ -48,4 +52,54 @@ private function reportInstallation(array $createdFiles): void } } + private function updateSheafLock($createdFiles, $dependencies) + { + $sheafLockPath = base_path("sheaf-lock.json"); + + $sheafLock = []; + + if (File::exists($sheafLockPath)) { + $sheafLock = json_decode(File::get($sheafLockPath), true) ?: []; + } + + + $sheafLock['files'] ??= []; + + foreach ($createdFiles as $file) { + if(str_contains($file['path'], "resources/views/components/ui/{$this->componentName}")) continue; + + $sheafLock['files'][$file['path']] ??= []; + if (!in_array($this->componentName, $sheafLock['files'][$file['path']], true)) { + $sheafLock['files'][$file['path']][] = $this->componentName; + } + } + + if ($dependencies && array_key_exists('helpers', $dependencies)) { + $sheafLock['helpers'] ??= []; + + foreach ($dependencies['helpers'] as $helper => $value) { + $sheafLock['helpers'][$helper] ??= []; + + if (!in_array($this->componentName, $sheafLock['helpers'][$helper], true)) { + $sheafLock['helpers'][$helper][] = $this->componentName; + } + } + } + + + if ($dependencies && array_key_exists('internal', $dependencies) && $depInternal = Arr::wrap($dependencies['internal'])) { + $sheafLock['internalDependencies'] ??= []; + + foreach ($depInternal as $dep => $value) { + $sheafLock['internalDependencies'][$dep] ??= []; + + if (!in_array($this->componentName, $sheafLock['internalDependencies'][$dep], true)) { + $sheafLock['internalDependencies'][$dep][] = $this->componentName; + } + } + } + + + File::put($sheafLockPath, json_encode($sheafLock, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); + } } From 03ba8b20c042351f92f7ca8cc95f2640042860e6 Mon Sep 17 00:00:00 2001 From: YoussefACHCHIRAJ Date: Sat, 11 Oct 2025 22:00:31 +0100 Subject: [PATCH 2/4] style: adding output to the remove command --- src/Commands/RemoveComponentCommand.php | 2 +- src/Services/ComponentRemover.php | 20 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/Commands/RemoveComponentCommand.php b/src/Commands/RemoveComponentCommand.php index 2d721d1..5264607 100644 --- a/src/Commands/RemoveComponentCommand.php +++ b/src/Commands/RemoveComponentCommand.php @@ -46,7 +46,7 @@ public function handle() $this->componentRemover->remove($name); } - + $this->info("+ updated sheaf-lock.json file"); return Command::SUCCESS; } diff --git a/src/Services/ComponentRemover.php b/src/Services/ComponentRemover.php index 3f44461..551fc36 100644 --- a/src/Services/ComponentRemover.php +++ b/src/Services/ComponentRemover.php @@ -4,10 +4,17 @@ namespace Sheaf\Cli\Services; use Illuminate\Support\Facades\File; +use Symfony\Component\Console\Output\ConsoleOutput; + class ComponentRemover { + protected $output; + public function __construct() + { + $this->output = new ConsoleOutput(); + } public function remove($name) { @@ -16,6 +23,7 @@ public function remove($name) if (File::isDirectory($componentDirectory)) { File::deleteDirectory($componentDirectory); + $this->message("+ Deleted directory: $componentDirectory"); } $this->cleaningSheafLock($name); @@ -38,6 +46,7 @@ protected function cleaningSheafLock($name) if (empty($components)) { File::delete($path); unset($sheafLock['files'][$path]); + $this->message("+ Removed File: $path"); } else { $sheafLock['files'][$path] = $components; } @@ -51,7 +60,8 @@ protected function cleaningSheafLock($name) $remover->remove($dep); unset($sheafLock['internalDependencies'][$dep]); - }else { + $this->message("+ Removed internal dependency: $dep (no longer used.)"); + } else { $sheafLock['internalDependencies'][$dep] = $components; } } @@ -62,11 +72,17 @@ protected function cleaningSheafLock($name) if (empty($components)) { File::delete(resource_path("views/components/ui/$helper.blade.php")); unset($sheafLock['helpers'][$helper]); - }else { + $this->message("+ Removed helper: $helper (no longer used.)"); + } else { $sheafLock['helpers'][$helper] = $components; } } File::put($sheafLockPath, json_encode($sheafLock, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); } + + + protected function message(string $message) { + $this->output->writeln("$message"); + } } From f3222334b2ab10a10a4baaa0095301641c424b93 Mon Sep 17 00:00:00 2001 From: YoussefACHCHIRAJ Date: Sun, 12 Oct 2025 00:45:23 +0100 Subject: [PATCH 3/4] refactor: cleaning remove command code --- src/Services/ComponentRemover.php | 82 ++++++++++++++----- src/Services/SheafConfig.php | 27 +++++- .../Installation/FullInstallationStrategy.php | 75 +++++++++-------- 3 files changed, 125 insertions(+), 59 deletions(-) diff --git a/src/Services/ComponentRemover.php b/src/Services/ComponentRemover.php index 551fc36..fc869dc 100644 --- a/src/Services/ComponentRemover.php +++ b/src/Services/ComponentRemover.php @@ -10,6 +10,7 @@ class ComponentRemover { protected $output; + protected $componentName; public function __construct() { @@ -18,71 +19,112 @@ public function __construct() public function remove($name) { + $this->componentName = $name; - $componentDirectory = resource_path("views/components/ui/$name"); + $this->deleteComponentFiles(); + + $this->cleaningSheafLock($name); + } + + protected function deleteComponentFiles() + { + $componentDirectory = resource_path("views/components/ui/{$this->componentName}"); if (File::isDirectory($componentDirectory)) { File::deleteDirectory($componentDirectory); $this->message("+ Deleted directory: $componentDirectory"); } - $this->cleaningSheafLock($name); + $componentFile = resource_path("views/components/ui/{$this->componentName}.blade.php"); + + if(File::exists($componentFile)) { + File::delete($componentFile); + } } protected function cleaningSheafLock($name) { - $sheafLockPath = base_path('sheaf-lock.json'); + $sheafLock = SheafConfig::loadSheafLock(); + $this->cleaningFiles($sheafLock); - $sheafLock = []; + $this->cleaningDependencies($sheafLock); - if (File::exists($sheafLockPath)) { - $sheafLock = json_decode(File::get($sheafLockPath), true) ?: []; - } + $this->cleaningHelpers($sheafLock); + + SheafConfig::saveSheafLock($sheafLock); + } + protected function cleaningFiles(&$sheafLock) + { foreach ($sheafLock['files'] as $path => $components) { - $components = array_values(array_filter($components, fn($c) => $c !== $name)); + $remainingComponents = $this->removeComponentFromList($components); - if (empty($components)) { - File::delete($path); + if (empty($remainingComponents)) { + $this->deleteFile($path); unset($sheafLock['files'][$path]); $this->message("+ Removed File: $path"); } else { - $sheafLock['files'][$path] = $components; + $sheafLock['files'][$path] = $remainingComponents; } } + } + protected function cleaningDependencies(&$sheafLock) + { foreach ($sheafLock['internalDependencies'] as $dep => $components) { - $components = array_values(array_filter($components, fn($c) => $c !== $name)); + $remainingComponents = $this->removeComponentFromList($components); - if (empty($components)) { + if (empty($remainingComponents)) { $remover = new self(); $remover->remove($dep); unset($sheafLock['internalDependencies'][$dep]); $this->message("+ Removed internal dependency: $dep (no longer used.)"); } else { - $sheafLock['internalDependencies'][$dep] = $components; + $sheafLock['internalDependencies'][$dep] = $remainingComponents; } } + } + protected function cleaningHelpers(&$sheafLock) + { foreach ($sheafLock['helpers'] as $helper => $components) { - $components = array_values(array_filter($components, fn($c) => $c !== $name)); + $remainingComponents = $this->removeComponentFromList($components); - if (empty($components)) { - File::delete(resource_path("views/components/ui/$helper.blade.php")); + if (empty($remainingComponents)) { + $this->deleteHelperFile($helper); unset($sheafLock['helpers'][$helper]); $this->message("+ Removed helper: $helper (no longer used.)"); } else { - $sheafLock['helpers'][$helper] = $components; + $sheafLock['helpers'][$helper] = $remainingComponents; } } + } - File::put($sheafLockPath, json_encode($sheafLock, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); + protected function removeComponentFromList($components) + { + return array_values(array_filter($components, fn($c) => $c !== $this->componentName)); } + protected function deleteFile($path) + { + if (File::exists($path)) { + File::delete($path); + } + } - protected function message(string $message) { + protected function deleteHelperFile($helper) + { + $path = resource_path("views/components/ui/$helper.blade.php"); + + if (File::exists($path)) { + File::delete($path); + } + } + + protected function message(string $message) + { $this->output->writeln("$message"); } } diff --git a/src/Services/SheafConfig.php b/src/Services/SheafConfig.php index d637bc3..a394f93 100644 --- a/src/Services/SheafConfig.php +++ b/src/Services/SheafConfig.php @@ -11,7 +11,7 @@ public static function saveLoggedInUserCredentials(string $email, string $token) { $configFile = self::configFile(); - if(File::exists($configFile)) { + if (File::exists($configFile)) { $data = File::get($configFile); $data = json_decode($data, true); } @@ -53,7 +53,7 @@ public static function getProjectHash() try { $configFile = self::configFile(); - if(!File::exists($configFile)) { + if (!File::exists($configFile)) { return self::saveProjectHash(); } @@ -81,7 +81,7 @@ public static function getUserToken() try { $configFile = self::configFile(); - if(!File::exists($configFile)) { + if (!File::exists($configFile)) { return null; } @@ -98,7 +98,7 @@ public static function getConfigFile() try { $configFile = self::configFile(); - if(!File::exists($configFile)) { + if (!File::exists($configFile)) { return null; } @@ -131,4 +131,23 @@ public static function getInstalledComponents() return $installedComponents; } + + public static function loadSheafLock(): array + { + $sheafLockPath = base_path('sheaf-lock.json'); + + if (!File::exists($sheafLockPath)) { + return []; + } + + return json_decode(File::get($sheafLockPath), true) ?: []; + } + + public static function saveSheafLock(array $sheafLock): void + { + File::put( + base_path('sheaf-lock.json'), + json_encode($sheafLock, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) + ); + } } diff --git a/src/Strategies/Installation/FullInstallationStrategy.php b/src/Strategies/Installation/FullInstallationStrategy.php index 156fa89..2dbde73 100644 --- a/src/Strategies/Installation/FullInstallationStrategy.php +++ b/src/Strategies/Installation/FullInstallationStrategy.php @@ -43,7 +43,7 @@ public function runInitialization() $this->initInstallationConfigForFilesInstallation($this->installationConfig); } - private function reportInstallation(array $createdFiles): void + protected function reportInstallation(array $createdFiles): void { $this->reportSuccess(); @@ -52,54 +52,59 @@ private function reportInstallation(array $createdFiles): void } } - private function updateSheafLock($createdFiles, $dependencies) + protected function updateSheafLock($files, $dependencies) { - $sheafLockPath = base_path("sheaf-lock.json"); + $sheafLock = SheafConfig::loadSheafLock(); - $sheafLock = []; - if (File::exists($sheafLockPath)) { - $sheafLock = json_decode(File::get($sheafLockPath), true) ?: []; - } + $this->updateFilesInLock($sheafLock, $files); + $this->updateDependenciesInLock($sheafLock, $dependencies); + + SheafConfig::saveSheafLock($sheafLock); + } - + + protected function updateFilesInLock(&$sheafLock, $files) + { $sheafLock['files'] ??= []; - - foreach ($createdFiles as $file) { - if(str_contains($file['path'], "resources/views/components/ui/{$this->componentName}")) continue; - $sheafLock['files'][$file['path']] ??= []; - if (!in_array($this->componentName, $sheafLock['files'][$file['path']], true)) { - $sheafLock['files'][$file['path']][] = $this->componentName; - } + foreach ($files as $file) { + if ($this->shouldSkipFile($file['path'])) continue; + + $this->addComponentToLockEntry($sheafLock['files'], $file['path']); } - - if ($dependencies && array_key_exists('helpers', $dependencies)) { - $sheafLock['helpers'] ??= []; + } - foreach ($dependencies['helpers'] as $helper => $value) { - $sheafLock['helpers'][$helper] ??= []; + protected function updateDependenciesInLock(&$sheafLock, $dependencies) + { + if (isset($dependencies['helpers'])) { + $this->addComponentToLockSection($sheafLock, 'helpers', $dependencies['helpers']); + } - if (!in_array($this->componentName, $sheafLock['helpers'][$helper], true)) { - $sheafLock['helpers'][$helper][] = $this->componentName; - } - } + if (isset($dependencies['internal'])) { + $this->addComponentToLockSection($sheafLock, 'internalDependencies', Arr::wrap($dependencies['internal'])); } + } + protected function shouldSkipFile($path) + { + return str_contains($path, "resources/views/components/ui/{$this->componentName}"); + } - if ($dependencies && array_key_exists('internal', $dependencies) && $depInternal = Arr::wrap($dependencies['internal'])) { - $sheafLock['internalDependencies'] ??= []; - - foreach ($depInternal as $dep => $value) { - $sheafLock['internalDependencies'][$dep] ??= []; + protected function addComponentToLockSection(&$sheafLock, $section, $items) + { + $sheafLock[$section] ??= []; - if (!in_array($this->componentName, $sheafLock['internalDependencies'][$dep], true)) { - $sheafLock['internalDependencies'][$dep][] = $this->componentName; - } - } + foreach ($items as $item => $value) { + $this->addComponentToLockEntry($sheafLock[$section], $item); } + } - - File::put($sheafLockPath, json_encode($sheafLock, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); + protected function addComponentToLockEntry(&$lockSection, $key) + { + $lockSection[$key] ??= []; + if (!in_array($this->componentName, $lockSection[$key], true)) { + $lockSection[$key][] = $this->componentName; + } } } From 87ee06cbd52c956048e19670f55b627fff29f44f Mon Sep 17 00:00:00 2001 From: YoussefACHCHIRAJ Date: Sun, 12 Oct 2025 01:11:09 +0100 Subject: [PATCH 4/4] fix: sheaf-lock file updating for all install startegies --- src/Commands/InstallComponentCommand.php | 2 + src/Commands/RemoveComponentCommand.php | 2 +- src/Commands/WhoAmICommand.php | 2 +- src/Services/ComponentRemover.php | 13 +++- src/Services/ComponentUpdater.php | 8 +-- src/Services/SheafConfig.php | 34 +++++---- .../Installation/DependencyOnlyStrategy.php | 5 ++ .../Installation/FullInstallationStrategy.php | 60 ++-------------- .../Installation/SkipDependenciesStrategy.php | 3 + .../CanHandleDependenciesInstallation.php | 8 +-- src/Traits/CanUpdateSheafLock.php | 71 +++++++++++++++++++ 11 files changed, 126 insertions(+), 82 deletions(-) create mode 100644 src/Traits/CanUpdateSheafLock.php diff --git a/src/Commands/InstallComponentCommand.php b/src/Commands/InstallComponentCommand.php index 475d4bb..5b6c3e2 100644 --- a/src/Commands/InstallComponentCommand.php +++ b/src/Commands/InstallComponentCommand.php @@ -58,6 +58,7 @@ public function handle() $result = (new ComponentInstaller($this, $this->components, $installationConfig))->install($name); if ($result === Command::SUCCESS) { + $this->info(" ✓ Updated sheaf.json and sheaf-lock.json"); $this->components->info("Full documentation: https://sheafui.dev/docs/components/{$name}"); } } @@ -91,6 +92,7 @@ public function getBannerTitle(string $title) { $formattedTitle = Str::of($title)->headline(); + return match (true) { $this->option('only-deps') => "Installing {$formattedTitle} Dependencies Only", $this->option('dry-run') => "Preview: Installing {$formattedTitle} (Dry Run)", diff --git a/src/Commands/RemoveComponentCommand.php b/src/Commands/RemoveComponentCommand.php index 5264607..a9de8f7 100644 --- a/src/Commands/RemoveComponentCommand.php +++ b/src/Commands/RemoveComponentCommand.php @@ -46,7 +46,7 @@ public function handle() $this->componentRemover->remove($name); } - $this->info("+ updated sheaf-lock.json file"); + $this->info("+ updated sheaf-lock.json and sheaf.json files"); return Command::SUCCESS; } diff --git a/src/Commands/WhoAmICommand.php b/src/Commands/WhoAmICommand.php index 4af14cf..2f24954 100644 --- a/src/Commands/WhoAmICommand.php +++ b/src/Commands/WhoAmICommand.php @@ -28,7 +28,7 @@ class WhoAmICommand extends Command */ public function handle() { - $currentUser = SheafConfig::getConfigFile(); + $currentUser = SheafConfig::getCurrentUser(); if(!$currentUser) { $this->components->warn("You're not log in. please login first with your sheaf account."); diff --git a/src/Services/ComponentRemover.php b/src/Services/ComponentRemover.php index fc869dc..21da607 100644 --- a/src/Services/ComponentRemover.php +++ b/src/Services/ComponentRemover.php @@ -37,7 +37,7 @@ protected function deleteComponentFiles() $componentFile = resource_path("views/components/ui/{$this->componentName}.blade.php"); - if(File::exists($componentFile)) { + if (File::exists($componentFile)) { File::delete($componentFile); } } @@ -52,6 +52,8 @@ protected function cleaningSheafLock($name) $this->cleaningHelpers($sheafLock); + $this->updateSheafFile(); + SheafConfig::saveSheafLock($sheafLock); } @@ -102,6 +104,15 @@ protected function cleaningHelpers(&$sheafLock) } } + protected function updateSheafFile() + { + $sheafFile = SheafConfig::getSheafFile(); + + unset($sheafFile['components'][$this->componentName]); + + SheafConfig::saveSheafFile($sheafFile); + } + protected function removeComponentFromList($components) { return array_values(array_filter($components, fn($c) => $c !== $this->componentName)); diff --git a/src/Services/ComponentUpdater.php b/src/Services/ComponentUpdater.php index 5c3bdfb..ddc8ec2 100644 --- a/src/Services/ComponentUpdater.php +++ b/src/Services/ComponentUpdater.php @@ -108,17 +108,17 @@ public function installComponent() public function needsUpdate($lastModified) { - $installedComponents = SheafConfig::getInstalledComponents(); + $sheafFile = SheafConfig::getSheafFile(); - if (!$installedComponents) { + if (!$sheafFile) { return true; } - if (!array_key_exists($this->component, $installedComponents['components'])) { + if (!array_key_exists($this->component, $sheafFile['components'])) { return true; } - return $installedComponents['components'][$this->component]['installationTime'] < $lastModified; + return $sheafFile['components'][$this->component]['installationTime'] < $lastModified; } diff --git a/src/Services/SheafConfig.php b/src/Services/SheafConfig.php index a394f93..066a71d 100644 --- a/src/Services/SheafConfig.php +++ b/src/Services/SheafConfig.php @@ -9,7 +9,7 @@ class SheafConfig { public static function saveLoggedInUserCredentials(string $email, string $token) { - $configFile = self::configFile(); + $configFile = self::configFilePath(); if (File::exists($configFile)) { $data = File::get($configFile); @@ -27,7 +27,7 @@ public static function saveLoggedInUserCredentials(string $email, string $token) public static function saveProjectHash() { - $configFile = self::configFile(); + $configFile = self::configFilePath(); $data = []; @@ -51,7 +51,7 @@ public static function saveProjectHash() public static function getProjectHash() { try { - $configFile = self::configFile(); + $configFile = self::configFilePath(); if (!File::exists($configFile)) { return self::saveProjectHash(); @@ -71,7 +71,7 @@ public static function getProjectHash() } } - public static function configFile() + public static function configFilePath() { return base_path('sheaf.json'); } @@ -79,7 +79,7 @@ public static function configFile() public static function getUserToken() { try { - $configFile = self::configFile(); + $configFile = self::configFilePath(); if (!File::exists($configFile)) { return null; @@ -93,10 +93,10 @@ public static function getUserToken() } } - public static function getConfigFile() + public static function getCurrentUser() { try { - $configFile = self::configFile(); + $configFile = self::configFilePath(); if (!File::exists($configFile)) { return null; @@ -112,24 +112,28 @@ public static function getConfigFile() public static function saveInstalledComponent(string $componentName) { - $installedComponents = self::getInstalledComponents(); + $sheafFile = self::getSheafFile(); - $installedComponents['components'][$componentName] = [ + $sheafFile['components'][$componentName] = [ 'installationTime' => time() ]; - File::put(base_path('sheaf.json'), json_encode($installedComponents, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); + self::saveSheafFile($sheafFile); } - public static function getInstalledComponents() + public static function saveSheafFile($sheafFile) { + File::put(self::configFilePath(), json_encode($sheafFile, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); + } + + public static function getSheafFile() { - $installedComponents = []; + $sheafFile = []; - if (File::exists(base_path('sheaf.json'))) { - $installedComponents = json_decode(File::get(base_path('sheaf.json')), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); + if (File::exists(self::configFilePath())) { + $sheafFile = json_decode(File::get(self::configFilePath()), true); } - return $installedComponents; + return $sheafFile; } public static function loadSheafLock(): array diff --git a/src/Strategies/Installation/DependencyOnlyStrategy.php b/src/Strategies/Installation/DependencyOnlyStrategy.php index 50801c8..a3dc11f 100644 --- a/src/Strategies/Installation/DependencyOnlyStrategy.php +++ b/src/Strategies/Installation/DependencyOnlyStrategy.php @@ -6,10 +6,12 @@ use Sheaf\Cli\Contracts\BaseInstallationStrategy; use Sheaf\Cli\Traits\CanHandleDependenciesInstallation; use Illuminate\Console\Command; +use Sheaf\Cli\Traits\CanUpdateSheafLock; class DependencyOnlyStrategy extends BaseInstallationStrategy { use CanHandleDependenciesInstallation; + use CanUpdateSheafLock; public function execute($componentResources): int { @@ -28,6 +30,9 @@ public function execute($componentResources): int $this->installDependencies($dependencies); + $this->updateSheafLock(null, $dependencies, $this->componentName); + + return Command::SUCCESS; } diff --git a/src/Strategies/Installation/FullInstallationStrategy.php b/src/Strategies/Installation/FullInstallationStrategy.php index 2dbde73..b5a6826 100644 --- a/src/Strategies/Installation/FullInstallationStrategy.php +++ b/src/Strategies/Installation/FullInstallationStrategy.php @@ -10,12 +10,14 @@ use Illuminate\Console\Command; use Illuminate\Support\Arr; use Illuminate\Support\Facades\File; +use Sheaf\Cli\Traits\CanUpdateSheafLock; class FullInstallationStrategy extends BaseInstallationStrategy { use CanHandleDependenciesInstallation; use CanHandleFilesInstallation; + use CanUpdateSheafLock; public function execute($componentResources): int { @@ -31,7 +33,7 @@ public function execute($componentResources): int $this->installDependencies($componentResources->get('dependencies')); - $this->updateSheafLock($createdFiles, $componentResources->get('dependencies')); + $this->updateSheafLock($createdFiles, $componentResources->get('dependencies'), $this->componentName); return Command::SUCCESS; } @@ -52,59 +54,5 @@ protected function reportInstallation(array $createdFiles): void } } - protected function updateSheafLock($files, $dependencies) - { - $sheafLock = SheafConfig::loadSheafLock(); - - - $this->updateFilesInLock($sheafLock, $files); - $this->updateDependenciesInLock($sheafLock, $dependencies); - - SheafConfig::saveSheafLock($sheafLock); - } - - - protected function updateFilesInLock(&$sheafLock, $files) - { - $sheafLock['files'] ??= []; - - foreach ($files as $file) { - if ($this->shouldSkipFile($file['path'])) continue; - - $this->addComponentToLockEntry($sheafLock['files'], $file['path']); - } - } - - protected function updateDependenciesInLock(&$sheafLock, $dependencies) - { - if (isset($dependencies['helpers'])) { - $this->addComponentToLockSection($sheafLock, 'helpers', $dependencies['helpers']); - } - - if (isset($dependencies['internal'])) { - $this->addComponentToLockSection($sheafLock, 'internalDependencies', Arr::wrap($dependencies['internal'])); - } - } - - protected function shouldSkipFile($path) - { - return str_contains($path, "resources/views/components/ui/{$this->componentName}"); - } - - protected function addComponentToLockSection(&$sheafLock, $section, $items) - { - $sheafLock[$section] ??= []; - - foreach ($items as $item => $value) { - $this->addComponentToLockEntry($sheafLock[$section], $item); - } - } - - protected function addComponentToLockEntry(&$lockSection, $key) - { - $lockSection[$key] ??= []; - if (!in_array($this->componentName, $lockSection[$key], true)) { - $lockSection[$key][] = $this->componentName; - } - } + } diff --git a/src/Strategies/Installation/SkipDependenciesStrategy.php b/src/Strategies/Installation/SkipDependenciesStrategy.php index 4ab5556..449c1a8 100644 --- a/src/Strategies/Installation/SkipDependenciesStrategy.php +++ b/src/Strategies/Installation/SkipDependenciesStrategy.php @@ -8,6 +8,7 @@ use Sheaf\Cli\Services\SheafConfig; use Illuminate\Console\Command; use Illuminate\Support\Facades\File; +use Sheaf\Cli\Traits\CanUpdateSheafLock; use function Laravel\Prompts\confirm; use function Laravel\Prompts\select; @@ -15,6 +16,7 @@ class SkipDependenciesStrategy extends BaseInstallationStrategy { use CanHandleFilesInstallation; + use CanUpdateSheafLock; public function execute($componentResources): int { @@ -29,6 +31,7 @@ public function execute($componentResources): int $createdFiles = $this->installFiles($componentResources->get('files')); SheafConfig::saveInstalledComponent($this->componentName); + $this->updateSheafLock($createdFiles, null, $this->componentName); $this->reportInstallation($createdFiles); diff --git a/src/Traits/CanHandleDependenciesInstallation.php b/src/Traits/CanHandleDependenciesInstallation.php index c1c2623..a518e22 100644 --- a/src/Traits/CanHandleDependenciesInstallation.php +++ b/src/Traits/CanHandleDependenciesInstallation.php @@ -163,20 +163,20 @@ public function installExternalDeps(array $deps) public function shouldInstallDependency($dependency, $info) { - $installedComponents = SheafConfig::getInstalledComponents(); + $sheafFile = SheafConfig::getSheafFile(); if(!File::exists(resource_path("views/components/ui/$dependency"))) { return true; } - if (!$installedComponents) { + if (!$sheafFile) { return true; } - if (!array_key_exists($dependency, $installedComponents['components'])) { + if (!array_key_exists($dependency, $sheafFile['components'])) { return true; } - return $installedComponents['components'][$dependency]['installationTime'] < $info['lastModified']; + return $sheafFile['components'][$dependency]['installationTime'] < $info['lastModified']; } } diff --git a/src/Traits/CanUpdateSheafLock.php b/src/Traits/CanUpdateSheafLock.php new file mode 100644 index 0000000..2e5b092 --- /dev/null +++ b/src/Traits/CanUpdateSheafLock.php @@ -0,0 +1,71 @@ +name = $name; + + $this->updateFilesInLock($sheafLock, $files); + $this->updateDependenciesInLock($sheafLock, $dependencies); + + SheafConfig::saveSheafLock($sheafLock); + } + + + protected function updateFilesInLock(&$sheafLock, $files) + { + if(!$files) return; + + $sheafLock['files'] ??= []; + + foreach ($files as $file) { + if ($this->shouldSkipFile($file['path'])) continue; + + $this->addComponentToLockEntry($sheafLock['files'], $file['path']); + } + } + + protected function updateDependenciesInLock(&$sheafLock, $dependencies) + { + if(!$dependencies) return; + + if (isset($dependencies['helpers'])) { + $this->addComponentToLockSection($sheafLock, 'helpers', $dependencies['helpers']); + } + + if (isset($dependencies['internal'])) { + $this->addComponentToLockSection($sheafLock, 'internalDependencies', Arr::wrap($dependencies['internal'])); + } + } + + protected function shouldSkipFile($path) + { + return str_contains($path, "resources/views/components/ui/{$this->name}"); + } + + protected function addComponentToLockSection(&$sheafLock, $section, $items) + { + $sheafLock[$section] ??= []; + + foreach ($items as $item => $value) { + $this->addComponentToLockEntry($sheafLock[$section], $item); + } + } + + protected function addComponentToLockEntry(&$lockSection, $key) + { + $lockSection[$key] ??= []; + if (!in_array($this->name, $lockSection[$key], true)) { + $lockSection[$key][] = $this->name; + } + } +} \ No newline at end of file