diff --git a/README.md b/README.md index e8ad80a..5576da0 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,7 @@ php smelly-code-detector inspect-method {path} | --protected | Show only protected methods.| | --without-constructor | Hide constructors.| | --sort-by=smell | Sort order (smell, loc, arg, ccl), default smell.| +| --json | Render metrics in JSON| ## Examples @@ -151,7 +152,7 @@ php smelly-code-detector inspect-class {path} | --protected | Show only protected methods.| | --without-constructor | Hide constructors.| | --sort-by=smell | Sort order (count, smell, avg), default smell.| - +| --json | Render metrics in JSON| ## Examples diff --git a/app/Commands/InspectClassCommand.php b/app/Commands/InspectClassCommand.php index 29ee148..2ff5381 100644 --- a/app/Commands/InspectClassCommand.php +++ b/app/Commands/InspectClassCommand.php @@ -14,9 +14,11 @@ }; use App\Modules\Render\ { + RendererFactory, RenderService, Pipes\SortRows, Pipes\CutRows, + Dtos\Option, }; class InspectClassCommand extends Command @@ -38,7 +40,9 @@ class InspectClassCommand extends Command {--private : Show only private methods.} {--protected : Show only protected methods.} {--without-constructor : Hide constructors.} - {--sort-by=smell : Sort order (count, smell, avg).}'; + {--sort-by=smell : Sort order (count, smell, avg).} + {--json : Render metrics in JSON.} + '; /** * The description of the command. @@ -49,7 +53,7 @@ class InspectClassCommand extends Command public function handle(): void { - $this->info('❀ PHP Smelly Code Detector ❀'); + $this->hello(); $files = $this->getAllFiles(); @@ -59,10 +63,7 @@ public function handle(): void $rows = $this->prepareMetricsToBeDisplayed($metrics); - $this->display([ - 'displayableRows' => $rows, - 'numberOfRows' => count($metrics), - ]); + $this->display($rows, $metrics); } private function analysisMetricsBag(array $analysis): array @@ -114,11 +115,16 @@ private function prepareMetricsToBeDisplayed(array $metrics): array ); } - private function makeHtml(array $attributes): ViewContract + private function display(array $rows, array $metrics): void { - return View::make('inspect-class', [ - 'displayableRows' => $attributes['displayableRows'], - 'numberOfRows' => $attributes['numberOfRows'], - ]); + $renderer = $this->makeRendererInstance(); + + $renderer->display( + view: 'inspect-class', + attributes: [ + 'displayableRows' => $rows, + 'numberOfRows' => count($metrics), + ], + ); } } diff --git a/app/Commands/InspectMethodCommand.php b/app/Commands/InspectMethodCommand.php index e8031aa..9b99ae3 100644 --- a/app/Commands/InspectMethodCommand.php +++ b/app/Commands/InspectMethodCommand.php @@ -39,7 +39,9 @@ class InspectMethodCommand extends Command {--private : Show only private methods.} {--protected : Show only protected methods.} {--without-constructor : Hide constructors.} - {--sort-by=smell : Sort order (smell, loc, arg, ccl).}'; + {--sort-by=smell : Sort order (smell, loc, arg, ccl).} + {--json : Render metrics in JSON.} + '; /** * The description of the command. @@ -53,7 +55,7 @@ class InspectMethodCommand extends Command */ public function handle(): void { - $this->info('❀ PHP Smelly Code Detector ❀'); + $this->hello(); $files = $this->getAllFiles(); @@ -63,10 +65,7 @@ public function handle(): void $rows = $this->prepareMetricsToBeDisplayed($metrics); - $this->display([ - 'displayableRows' => $rows, - 'numberOfRows' => count($metrics), - ]); + $this->display($rows, $metrics); } private function analysisMetricsBag(array $analysis): array @@ -119,11 +118,16 @@ private function prepareMetricsToBeDisplayed(array $metrics): array ); } - private function makeHtml(array $attributes): ViewContract + private function display(array $rows, array $metrics): void { - return View::make('inspect-method', [ - 'displayableRows' => $attributes['displayableRows'], - 'numberOfRows' => $attributes['numberOfRows'], - ]); + $renderer = $this->makeRendererInstance(); + + $renderer->display( + view: 'inspect-method', + attributes: [ + 'displayableRows' => $rows, + 'numberOfRows' => count($metrics), + ], + ); } } diff --git a/app/Commands/Traits/HtmlRenderingTrait.php b/app/Commands/Traits/HtmlRenderingTrait.php index 1ad3d78..b7788f1 100644 --- a/app/Commands/Traits/HtmlRenderingTrait.php +++ b/app/Commands/Traits/HtmlRenderingTrait.php @@ -2,25 +2,31 @@ namespace App\Commands\Traits; -use Termwind\HtmlRenderer; -use Symfony\Component\Console\Output\OutputInterface; -use Illuminate\Contracts\View\View as ViewContract; +use App\Modules\Render\RendererFactory; +use App\Modules\Render\Dtos\Option; +use App\Modules\Render\Contracts\Renderer; trait HtmlRenderingTrait { - abstract protected function makeHtml(array $attributes): ViewContract; + abstract private function display(array $rows, array $metrics): void; - protected function display(array $attributes): void + protected function hello() { - $html = $this->makeHtml($attributes); + /** + * In the case of rendering in JSON, + * the prompt should not be polluted + */ + $mustSayHello = ! $this->option('json'); - $this->renderHtml($html); + if ($mustSayHello) { + $this->info('❀ PHP Smelly Code Detector ❀'); + } } - private function renderHtml($html): void + protected function makeRendererInstance(): Renderer { - $htmlRenderer = new HtmlRenderer(); - - $htmlRenderer->render($html, OutputInterface::OUTPUT_NORMAL); + return app(RendererFactory::class)->from( + Option::fromCommand($this->options()), + ); } } diff --git a/app/Modules/Render/Contracts/Renderer.php b/app/Modules/Render/Contracts/Renderer.php new file mode 100644 index 0000000..541a904 --- /dev/null +++ b/app/Modules/Render/Contracts/Renderer.php @@ -0,0 +1,8 @@ + JsonRenderer::class, + 'view' => ViewRenderer::class, + ]; + + public function from(Option $option): Renderer + { + $renderer = $this->renderers[$option->type->value]; + + return app($renderer); + } +} diff --git a/app/Modules/Render/Renderers/JsonRenderer.php b/app/Modules/Render/Renderers/JsonRenderer.php new file mode 100644 index 0000000..694592b --- /dev/null +++ b/app/Modules/Render/Renderers/JsonRenderer.php @@ -0,0 +1,13 @@ +makeHtml($view, $attributes); + + $this->renderHtml($html); + } + + protected function makeHtml(string $view, array $attributes): ViewContract + { + return $this->view->make($view, $attributes); + } + + private function renderHtml(ViewContract $html): void + { + $this->htmlRenderer->render($html, OutputInterface::OUTPUT_NORMAL); + } +} diff --git a/phpstan.neon b/phpstan.neon index d10dfb5..90c4bf4 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -4,4 +4,5 @@ parameters: level: 5 ignoreErrors: - '#Match expression does not handle remaining value: mixed#' - - '#Property App\\Modules\\Analyzer\\Visitors\\ClassMethodVisitor::\$metrics is never read, only written\.#' \ No newline at end of file + - '#Property App\\Modules\\Analyzer\\Visitors\\ClassMethodVisitor::\$metrics is never read, only written\.#' + - '#Parameter \#1 \$html of method Termwind\\HtmlRenderer::render\(\) expects string, Illuminate\\Contracts\\View\\View given\.#' \ No newline at end of file diff --git a/tests/Unit/Render/RendererFactoryTest.php b/tests/Unit/Render/RendererFactoryTest.php new file mode 100644 index 0000000..cbdf923 --- /dev/null +++ b/tests/Unit/Render/RendererFactoryTest.php @@ -0,0 +1,44 @@ +from( + Option::fromCommand(attributes: [ + 'json' => true, + ]), + ); + + $this->assertInstanceOf(JsonRenderer::class, $renderer); + } + + /** + * @test + */ + public function it_able_to_instantiate_view_renderer(): void + { + $factory = new RendererFactory(); + + $renderer = $factory->from( + Option::fromCommand(attributes: [ + 'json' => false, + ]), + ); + + $this->assertInstanceOf(ViewRenderer::class, $renderer); + } +}