diff --git a/src/Commands/RemoveComponentCommand.php b/src/Commands/RemoveComponentCommand.php
index a9de8f7..5fd9619 100644
--- a/src/Commands/RemoveComponentCommand.php
+++ b/src/Commands/RemoveComponentCommand.php
@@ -2,11 +2,8 @@
namespace Sheaf\Cli\Commands;
-use Sheaf\Cli\Services\ComponentInstaller;
-use Sheaf\Cli\Support\InstallationConfig;
use Illuminate\Console\Command;
use Illuminate\Support\Arr;
-use Illuminate\Support\Str;
use Sheaf\Cli\Services\ComponentRemover;
use function Laravel\Prompts\text;
@@ -14,9 +11,6 @@
class RemoveComponentCommand extends Command
{
- public function __construct(protected ComponentRemover $componentRemover) {
- parent::__construct();
- }
/**
* The name and signature of the console command.
*
@@ -39,14 +33,20 @@ public function handle()
{
$componentNames = $this->getComponentName();
+ $success = Command::SUCCESS;
+
+ $componentRemover = new ComponentRemover($this);
foreach ($componentNames as $name) {
$this->banner("Removing all $name files");
- $this->componentRemover->remove($name);
+ $success = $componentRemover->remove($name);
+ }
+
+ if($success === Command::SUCCESS) {
+ $this->info("+ updated sheaf-lock.json and sheaf.json files");
}
- $this->info("+ updated sheaf-lock.json and sheaf.json files");
return Command::SUCCESS;
}
diff --git a/src/Services/ComponentInstaller.php b/src/Services/ComponentInstaller.php
index 6e8e07b..dde7200 100644
--- a/src/Services/ComponentInstaller.php
+++ b/src/Services/ComponentInstaller.php
@@ -126,6 +126,6 @@ public function handleOverwriteChoice()
public function confirmDestructiveAction()
{
- return confirm("All the component files will be overwritten, you might lose your modifications. are you sure you want to processed?");
+ return confirm("All the component files will be overwritten, you might lose your modifications. are you sure you want to proceed?");
}
}
diff --git a/src/Services/ComponentRemover.php b/src/Services/ComponentRemover.php
index 21da607..13aa063 100644
--- a/src/Services/ComponentRemover.php
+++ b/src/Services/ComponentRemover.php
@@ -3,36 +3,48 @@
namespace Sheaf\Cli\Services;
+use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
-use Symfony\Component\Console\Output\ConsoleOutput;
-
class ComponentRemover
{
protected $output;
protected $componentName;
- public function __construct()
+ public function __construct(protected $command)
{
- $this->output = new ConsoleOutput();
}
public function remove($name)
{
$this->componentName = $name;
+ $isExists = $this->checkComponentExistence();
+
+ if(!$isExists) {
+ $this->message("Component is not installed in this project.");
+ return Command::FAILURE;
+ }
+
$this->deleteComponentFiles();
$this->cleaningSheafLock($name);
}
+ protected function checkComponentExistence()
+ {
+
+ return File::exists(resource_path("views/components/ui/{$this->componentName}")) ||
+ File::exists(resource_path("views/components/ui/{$this->componentName}.blade.php"));
+ }
+
protected function deleteComponentFiles()
{
$componentDirectory = resource_path("views/components/ui/{$this->componentName}");
if (File::isDirectory($componentDirectory)) {
File::deleteDirectory($componentDirectory);
- $this->message("+ Deleted directory: $componentDirectory");
+ $this->message("+ Deleted directory: resources/views/components/ui/{$this->componentName}");
}
$componentFile = resource_path("views/components/ui/{$this->componentName}.blade.php");
@@ -74,11 +86,15 @@ protected function cleaningFiles(&$sheafLock)
protected function cleaningDependencies(&$sheafLock)
{
+ if(!isset($sheafLock['internalDependencies'])) {
+ return;
+ }
+
foreach ($sheafLock['internalDependencies'] as $dep => $components) {
$remainingComponents = $this->removeComponentFromList($components);
if (empty($remainingComponents)) {
- $remover = new self();
+ $remover = new self($this->command);
$remover->remove($dep);
unset($sheafLock['internalDependencies'][$dep]);
@@ -91,6 +107,10 @@ protected function cleaningDependencies(&$sheafLock)
protected function cleaningHelpers(&$sheafLock)
{
+ if(!isset($sheafLock['helpers'])) {
+ return;
+ }
+
foreach ($sheafLock['helpers'] as $helper => $components) {
$remainingComponents = $this->removeComponentFromList($components);
@@ -136,6 +156,6 @@ protected function deleteHelperFile($helper)
protected function message(string $message)
{
- $this->output->writeln("$message");
+ $this->command->info("$message");
}
}
diff --git a/tests/Feature/Commands/InstallCommandTest.php b/tests/Feature/Commands/InstallCommandTest.php
index 7c71de1..415aaaf 100644
--- a/tests/Feature/Commands/InstallCommandTest.php
+++ b/tests/Feature/Commands/InstallCommandTest.php
@@ -1,30 +1,14 @@
artisan("sheaf:install separator")
->assertExitCode(0)
->run();
$this->view('components.ui.separator.index');
+ $this->artisan("sheaf:remove separator");
});
it("installs a component along with its dependencies when confirmed", function () {
@@ -35,24 +19,27 @@
->run();
$this->view("components.ui.radio.group", ['slot' => 'default']);
+
+ $this->artisan("sheaf:remove radio");
});
it("overwrites existing component files when forced", function () {
$this->artisan("sheaf:install separator")
- ->assertExitCode(0)
- ->run();
+ ->assertExitCode(0)
+ ->run();
$this->artisan("sheaf:install separator")
- ->expectsQuestion("Component 'Separator' already exists. What would you like to do?", "overwrite")
- ->expectsQuestion("All the component files will be overwritten, you might lose your modifications. are you sure you want to processed?", "yes")
- ->expectsOutputToContain("All component files will be overwritten.")
- ->assertExitCode(0)
- ->run();
+ ->expectsQuestion("Component 'Separator' already exists. What would you like to do?", "overwrite")
+ ->expectsQuestion("All the component files will be overwritten, you might lose your modifications. are you sure you want to proceed?", "yes")
+ ->expectsOutputToContain("All component files will be overwritten.")
+ ->assertExitCode(0)
+ ->run();
$this->view("components.ui.separator.index");
+ $this->artisan("sheaf:remove separator");
});
it("installs only dependencies when the component already exists and that option is chosen", function () {
@@ -60,26 +47,27 @@
$command = 'sheaf:install separator';
$this->artisan($command)
- ->assertExitCode(0)
- ->run();
+ ->assertExitCode(0)
+ ->run();
$this->artisan($command)
- ->expectsQuestion("Component 'Separator' already exists. What would you like to do?", "dependencies")
- ->expectsOutputToContain("Skipping component files, checking dependencies...")
- ->assertExitCode(0)
- ->run();
+ ->expectsQuestion("Component 'Separator' already exists. What would you like to do?", "dependencies")
+ ->expectsOutputToContain("Skipping component files, checking dependencies...")
+ ->assertExitCode(0)
+ ->run();
$this->view("components.ui.separator.index");
+ $this->artisan("sheaf:remove separator");
});
it("simulates component installation with the dry-run option", function () {
$this->artisan("sheaf:install alerts --dry-run")
- ->expectsOutputToContain("Preview: Installing Alerts (Dry Run)")
- ->expectsOutputToContain("Will create")
- ->assertExitCode(0)
- ->run();
+ ->expectsOutputToContain("Preview: Installing Alerts (Dry Run)")
+ ->expectsOutputToContain("Will create")
+ ->assertExitCode(0)
+ ->run();
expect(view()->exists("components.ui.alerts.index"))->toBeFalse();
-});
\ No newline at end of file
+});
diff --git a/tests/Feature/Commands/RemoveCommandTest.php b/tests/Feature/Commands/RemoveCommandTest.php
new file mode 100644
index 0000000..026e038
--- /dev/null
+++ b/tests/Feature/Commands/RemoveCommandTest.php
@@ -0,0 +1,88 @@
+artisan("sheaf:install $component")
+ ->assertExitCode(0)
+ ->run();
+
+
+ expect(File::isDirectory($componentDirectory))->toBeTrue();
+
+ $this->view("components.ui.$component.index");
+
+ $this->artisan("sheaf:remove $component")
+ ->assertExitCode(0)
+ ->expectsOutputToContain("Deleted directory: resources/views/components/ui/$component")
+ ->run();
+
+ expect(File::isDirectory($componentDirectory))->toBeFalse();
+
+ $sheafLock = File::get(base_path("sheaf-lock.json"));
+
+ expect($sheafLock)->not->toContain("$component");
+});
+
+it("quits successfully when attempting to remove a non-installed component", function () {
+
+ $component = 'modal';
+ $componentDirectory = resource_path("views/components/ui/$component");
+
+
+ $this->artisan("sheaf:remove $component")
+ ->assertExitCode(0)
+ ->expectsOutputToContain("Component is not installed in this project.")
+ ->run();
+
+ expect(File::isDirectory($componentDirectory))->toBeFalse();
+
+ $sheafLock = File::get(base_path("sheaf-lock.json"));
+
+ expect($sheafLock)->not->toContain("$component");
+});
+
+
+it("removes an installed component with dependencies", function () {
+
+ $component = 'select';
+ $dependency = 'icon';
+ $helper = 'popup';
+ $baseDirectory = resource_path("views/components/ui/");
+
+ //* using force option to ensure the command runs
+ $this->artisan("sheaf:install $component --force --internal-deps")
+ ->assertExitCode(0)
+ ->run();
+
+ expect(File::isDirectory("$baseDirectory/$component"))->toBeTrue();
+ expect(File::isDirectory("$baseDirectory/$dependency"))->toBeTrue();
+ expect(File::exists("$baseDirectory/$helper.blade.php"))->toBeTrue();
+
+ expect(view()->exists("components.ui.$component.index"))->toBeTrue();
+ expect(view()->exists("components.ui.$dependency.index"))->toBeTrue();
+ expect(view()->exists("components.ui.$helper"))->toBeTrue();
+
+
+ $this->artisan("sheaf:remove $component")
+ ->assertExitCode(0)
+ ->expectsOutputToContain("Deleted directory: resources/views/components/ui/$component")
+ ->expectsOutputToContain("Deleted directory: resources/views/components/ui/$dependency")
+ ->expectsOutputToContain("Removed internal dependency: $dependency (no longer used.)")
+ ->expectsOutputToContain("Removed helper: $helper (no longer used.)")
+ ->run();
+
+ expect(File::isDirectory("$baseDirectory/$component"))->toBeFalse();
+ expect(File::isDirectory("$baseDirectory/$dependency"))->toBeFalse();
+
+ $sheafLock = File::get(base_path("sheaf-lock.json"));
+
+ expect($sheafLock)->not->toContain("$component");
+ expect($sheafLock)->not->toContain("$dependency");
+});