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
21 changes: 18 additions & 3 deletions src/Commands/RemoveComponentCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Illuminate\Console\Command;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\File;
use Sheaf\Cli\Services\ComponentRemover;

use function Laravel\Prompts\text;
Expand Down Expand Up @@ -33,18 +34,25 @@ public function handle()
{

$componentNames = $this->getComponentName();
$success = Command::SUCCESS;
$sheafFileEdited = false;

$componentRemover = new ComponentRemover($this);

foreach ($componentNames as $name) {

$isExists = $this->checkComponentExistence($name);

if (!$isExists) {
$this->info("Component is not installed in this project.");
continue;
}
$this->banner("Removing all $name files");

$success = $componentRemover->remove($name);
$componentRemover->remove($name);
$sheafFileEdited = true;
}

if($success === Command::SUCCESS) {
if ($sheafFileEdited) {
$this->info("+ updated sheaf-lock.json and sheaf.json files");
}
return Command::SUCCESS;
Expand Down Expand Up @@ -73,4 +81,11 @@ public function banner(string $title): void
$this->line(str_repeat("═", $length));
$this->newLine();
}

protected function checkComponentExistence(string $name)
{

return File::exists(resource_path("views/components/ui/$name")) ||
File::exists(resource_path("views/components/ui/$name.blade.php"));
}
}
50 changes: 24 additions & 26 deletions src/Services/ComponentRemover.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,25 @@
use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;

use function Laravel\Prompts\confirm;

class ComponentRemover
{
protected $output;
protected $componentName;

public function __construct(protected $command)
{
}
public function __construct(protected $command) {}

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}");
Expand All @@ -54,7 +41,7 @@ protected function deleteComponentFiles()
}
}

protected function cleaningSheafLock($name)
protected function cleaningSheafLock()
{
$sheafLock = SheafConfig::loadSheafLock();

Expand Down Expand Up @@ -86,28 +73,39 @@ protected function cleaningFiles(&$sheafLock)

protected function cleaningDependencies(&$sheafLock)
{
if(!isset($sheafLock['internalDependencies'])) {
if (!isset($sheafLock['internalDependencies'])) {
return;
}

foreach ($sheafLock['internalDependencies'] as $dep => $components) {

if(!in_array($this->componentName, $components, true)) {
continue;
}
$remainingComponents = $this->removeComponentFromList($components);

if (empty($remainingComponents)) {
$remover = new self($this->command);
$sheafLock['internalDependencies'][$dep] = $remainingComponents;

if (!empty($remainingComponents)) {
continue;
}

$remover->remove($dep);
unset($sheafLock['internalDependencies'][$dep]);
$this->message("+ Removed internal dependency: $dep (no longer used.)");
} else {
$sheafLock['internalDependencies'][$dep] = $remainingComponents;
$confirm = confirm(label: "$dep is no longer used as a dependency, would you like to remove it?", default: false, hint: "If you use $dep somewhere else in your project, select no.");

if (!$confirm) {
continue;
}

$remover = new self($this->command);
$remover->remove($dep);
$this->message("+ Removed internal dependency: $dep (no longer used.)");
unset($sheafLock['internalDependencies'][$dep]);
}
}

protected function cleaningHelpers(&$sheafLock)
{
if(!isset($sheafLock['helpers'])) {
if (!isset($sheafLock['helpers'])) {
return;
}

Expand Down
27 changes: 18 additions & 9 deletions tests/Feature/Commands/InstallCommandTest.php
Original file line number Diff line number Diff line change
@@ -1,26 +1,35 @@
<?php

use Illuminate\Support\Facades\File;

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");
expect(view()->exists('components.ui.separator.index'))->toBeTrue();
$this->artisan("sheaf:remove separator")->run();
});

it("installs a component along with its dependencies when confirmed", function () {

$sheafLock = json_decode(File::get(base_path("sheaf-lock.json")), true);

if(isset($sheafLock['internalDependencies']['icon'])) {
$this->artisan("sheaf:remove icon radio")->run();
}

$this->artisan("sheaf:install radio")
->expectsQuestion('Install required dependencies?', 'yes')
->expectsQuestion('Install required dependencies?', true)
->assertExitCode(0)
->run();

$this->view("components.ui.radio.group", ['slot' => 'default']);

$this->artisan("sheaf:remove radio");
expect(view()->exists("components.ui.radio.group"))->toBeTrue();

$this->artisan("sheaf:remove radio")->expectsQuestion("icon is no longer used as a dependency, would you like to remove it?", true)->run();

});


Expand All @@ -37,9 +46,9 @@
->assertExitCode(0)
->run();

$this->view("components.ui.separator.index");
expect(view()->exists("components.ui.separator.index"))->toBeTrue();

$this->artisan("sheaf:remove separator");
$this->artisan("sheaf:remove separator")->run();
});

it("installs only dependencies when the component already exists and that option is chosen", function () {
Expand All @@ -56,9 +65,9 @@
->assertExitCode(0)
->run();

$this->view("components.ui.separator.index");
expect(view()->exists("components.ui.separator.index"))->toBeTrue();

$this->artisan("sheaf:remove separator");
$this->artisan("sheaf:remove separator")->run();
});


Expand Down
47 changes: 42 additions & 5 deletions tests/Feature/Commands/RemoveCommandTest.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<?php

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

it("removes an installed component", function () {
Expand Down Expand Up @@ -49,9 +47,9 @@
});


it("removes an installed component with dependencies", function () {
it("removes an installed component with dependencies after confirmation of removing dependencies", function () {

$component = 'select';
$component = 'autocomplete';
$dependency = 'icon';
$helper = 'popup';
$baseDirectory = resource_path("views/components/ui/");
Expand All @@ -69,9 +67,9 @@
expect(view()->exists("components.ui.$dependency.index"))->toBeTrue();
expect(view()->exists("components.ui.$helper"))->toBeTrue();


$this->artisan("sheaf:remove $component")
->assertExitCode(0)
->expectsQuestion("$dependency is no longer used as a dependency, would you like to remove it?", true)
->expectsOutputToContain("Deleted directory: resources/views/components/ui/$component")
->expectsOutputToContain("Deleted directory: resources/views/components/ui/$dependency")
->expectsOutputToContain("Removed internal dependency: $dependency (no longer used.)")
Expand All @@ -86,3 +84,42 @@
expect($sheafLock)->not->toContain("$component");
expect($sheafLock)->not->toContain("$dependency");
});

it("removes an installed component without dependencies after not confirming to remove dependencies", function () {

$component = 'autocomplete';
$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)
->expectsQuestion("$dependency is no longer used as a dependency, would you like to remove it?", false)
->doesntExpectOutputToContain("Deleted directory: resources/views/components/ui/$dependency")
->doesntExpectOutputToContain("Removed internal dependency: $dependency (no longer used.)")
->expectsOutputToContain("Deleted directory: resources/views/components/ui/$component")
->expectsOutputToContain("Removed helper: $helper (no longer used.)")
->run();

expect(File::isDirectory("$baseDirectory/$component"))->toBeFalse();
expect(File::isDirectory("$baseDirectory/$dependency"))->toBeTrue();

$sheafLock = File::get(base_path("sheaf-lock.json"));

expect($sheafLock)->not->toContain("$component");
expect($sheafLock)->toContain("$dependency");
});