Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions src/Commands/RemoveComponentCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,15 @@

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;

class RemoveComponentCommand extends Command
{

public function __construct(protected ComponentRemover $componentRemover) {
parent::__construct();
}
/**
* The name and signature of the console command.
*
Expand All @@ -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;
}

Expand Down
2 changes: 1 addition & 1 deletion src/Services/ComponentInstaller.php
Original file line number Diff line number Diff line change
Expand Up @@ -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?");
}
}
34 changes: 27 additions & 7 deletions src/Services/ComponentRemover.php
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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]);
Expand All @@ -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);

Expand Down Expand Up @@ -136,6 +156,6 @@ protected function deleteHelperFile($helper)

protected function message(string $message)
{
$this->output->writeln("<fg=green>$message</fg=green>");
$this->command->info("<fg=green>$message</fg=green>");
}
}
60 changes: 24 additions & 36 deletions tests/Feature/Commands/InstallCommandTest.php
Original file line number Diff line number Diff line change
@@ -1,30 +1,14 @@
<?php

use Illuminate\Console\BufferedConsoleOutput;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\File;

afterAll(function () {
if(File::exists(resource_path('views/components/ui/separator'))) {
File::deleteDirectory(resource_path('views/components/ui/separator'));
}

if (File::exists(resource_path('views/components/ui/icon'))) {
File::deleteDirectory(resource_path('views/components/ui/icon'));
}

if (File::exists(resource_path('views/components/ui/radio'))) {
File::deleteDirectory(resource_path('views/components/ui/radio'));
}
});

it("installs a component without dependencies", function () {

$this->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 () {
Expand All @@ -35,51 +19,55 @@
->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 () {

$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();
});
});
88 changes: 88 additions & 0 deletions tests/Feature/Commands/RemoveCommandTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

use Illuminate\Console\BufferedConsoleOutput;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\File;

it("removes an installed component", function () {

$component = 'separator';
$componentDirectory = resource_path("views/components/ui/$component");

$this->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");
});