From bb4179ad3101d2b66ddf73c97c86b3d7e7be8fb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Kr=C3=A4mer?= Date: Tue, 14 Oct 2025 23:18:03 +0200 Subject: [PATCH 1/2] Fixing PHPStan findings --- src/Application.php | 21 +++++- src/Command/CognitiveMetricsCommand.php | 70 ++++--------------- .../CognitiveAnalysis/OutputHandler.php | 47 +++++++++++++ .../CognitiveAnalysis/ValidationHandler.php | 66 +++++++++++++++++ 4 files changed, 145 insertions(+), 59 deletions(-) create mode 100644 src/Command/Handler/CognitiveAnalysis/OutputHandler.php create mode 100644 src/Command/Handler/CognitiveAnalysis/ValidationHandler.php diff --git a/src/Application.php b/src/Application.php index 0809b89..9723def 100644 --- a/src/Application.php +++ b/src/Application.php @@ -33,7 +33,9 @@ use Phauthentic\CognitiveCodeAnalysis\Command\Handler\CognitiveAnalysis\BaselineHandler; use Phauthentic\CognitiveCodeAnalysis\Command\Handler\CognitiveAnalysis\ConfigurationLoadHandler; use Phauthentic\CognitiveCodeAnalysis\Command\Handler\CognitiveAnalysis\CoverageLoadHandler; +use Phauthentic\CognitiveCodeAnalysis\Command\Handler\CognitiveAnalysis\OutputHandler; use Phauthentic\CognitiveCodeAnalysis\Command\Handler\CognitiveAnalysis\SortingHandler; +use Phauthentic\CognitiveCodeAnalysis\Command\Handler\CognitiveAnalysis\ValidationHandler; use Phauthentic\CognitiveCodeAnalysis\Command\Handler\CognitiveMetricsReportHandler; use Phauthentic\CognitiveCodeAnalysis\Command\Presentation\ChurnTextRenderer; use Phauthentic\CognitiveCodeAnalysis\Command\Presentation\CognitiveMetricTextRenderer; @@ -230,6 +232,20 @@ private function registerCommandHandlers(): void new Reference(CognitiveMetricsSorter::class), ]) ->setPublic(true); + + $this->containerBuilder->register(ValidationHandler::class, ValidationHandler::class) + ->setArguments([ + new Reference(CognitiveMetricsValidationSpecificationFactory::class), + new Reference(CognitiveMetricsReportHandler::class), + ]) + ->setPublic(true); + + $this->containerBuilder->register(OutputHandler::class, OutputHandler::class) + ->setArguments([ + new Reference(CognitiveMetricsReportHandler::class), + new Reference(CognitiveMetricTextRendererInterface::class), + ]) + ->setPublic(true); } private function bootstrap(): void @@ -306,13 +322,12 @@ private function registerCommands(): void $this->containerBuilder->register(CognitiveMetricsCommand::class, CognitiveMetricsCommand::class) ->setArguments([ new Reference(MetricsFacade::class), - new Reference(CognitiveMetricTextRendererInterface::class), - new Reference(CognitiveMetricsReportHandler::class), new Reference(ConfigurationLoadHandler::class), new Reference(CoverageLoadHandler::class), new Reference(BaselineHandler::class), new Reference(SortingHandler::class), - new Reference(CognitiveMetricsValidationSpecificationFactory::class), + new Reference(ValidationHandler::class), + new Reference(OutputHandler::class), ]) ->setPublic(true); diff --git a/src/Command/CognitiveMetricsCommand.php b/src/Command/CognitiveMetricsCommand.php index 2d9ebab..eeccf64 100644 --- a/src/Command/CognitiveMetricsCommand.php +++ b/src/Command/CognitiveMetricsCommand.php @@ -8,13 +8,10 @@ use Phauthentic\CognitiveCodeAnalysis\Command\Handler\CognitiveAnalysis\BaselineHandler; use Phauthentic\CognitiveCodeAnalysis\Command\Handler\CognitiveAnalysis\ConfigurationLoadHandler; use Phauthentic\CognitiveCodeAnalysis\Command\Handler\CognitiveAnalysis\CoverageLoadHandler; +use Phauthentic\CognitiveCodeAnalysis\Command\Handler\CognitiveAnalysis\OutputHandler; use Phauthentic\CognitiveCodeAnalysis\Command\Handler\CognitiveAnalysis\SortingHandler; -use Phauthentic\CognitiveCodeAnalysis\Command\Handler\CognitiveMetricsReportHandler; -use Phauthentic\CognitiveCodeAnalysis\Command\Presentation\CognitiveMetricTextRendererInterface; +use Phauthentic\CognitiveCodeAnalysis\Command\Handler\CognitiveAnalysis\ValidationHandler; use Phauthentic\CognitiveCodeAnalysis\Command\CognitiveMetricsSpecifications\CognitiveMetricsCommandContext; -use Phauthentic\CognitiveCodeAnalysis\Command\CognitiveMetricsSpecifications\CompositeCognitiveMetricsValidationSpecification; -use Phauthentic\CognitiveCodeAnalysis\Command\CognitiveMetricsSpecifications\CognitiveMetricsValidationSpecificationFactory; -use Phauthentic\CognitiveCodeAnalysis\Command\CognitiveMetricsSpecifications\CustomExporterValidation; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; @@ -23,8 +20,6 @@ /** * Command to parse PHP files or directories and output method metrics. - * - * @SuppressWarnings("CyclomaticComplexity") */ #[AsCommand( name: 'analyse', @@ -43,20 +38,16 @@ class CognitiveMetricsCommand extends Command public const OPTION_COVERAGE_CLOVER = 'coverage-clover'; private const ARGUMENT_PATH = 'path'; - private CompositeCognitiveMetricsValidationSpecification $specification; - public function __construct( readonly private MetricsFacade $metricsFacade, - readonly private CognitiveMetricTextRendererInterface $renderer, - readonly private CognitiveMetricsReportHandler $reportHandler, readonly private ConfigurationLoadHandler $configHandler, readonly private CoverageLoadHandler $coverageHandler, readonly private BaselineHandler $baselineHandler, readonly private SortingHandler $sortingHandler, - readonly private CognitiveMetricsValidationSpecificationFactory $specificationFactory + readonly private ValidationHandler $validationHandler, + readonly private OutputHandler $outputHandler ) { parent::__construct(); - $this->specification = $this->specificationFactory->create(); } @@ -137,9 +128,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int { $context = new CognitiveMetricsCommandContext($input); - // Validate all specifications - if (!$this->specification->isSatisfiedBy($context)) { - return $this->handleValidationError($context, $output); + // Run initial validation + $validationResult = $this->validationHandler->validate($context); + if ($validationResult->isFailure()) { + return $validationResult->toCommandStatus($output); } // Load configuration @@ -148,16 +140,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int return $configResult->toCommandStatus($output); } - // Validate custom exporters after config is loaded - if ($context->hasReportOptions()) { - $customExporterValidation = new CustomExporterValidation( - $this->reportHandler->getReportFactory(), - $this->reportHandler->getConfigService() - ); - - if (!$customExporterValidation->isSatisfiedBy($context)) { - return $this->handleValidationError($context, $output, $customExporterValidation); - } + // Run custom exporter validation after config is loaded + $customExporterResult = $this->validationHandler->validateCustomExporter($context); + if ($customExporterResult->isFailure()) { + return $customExporterResult->toCommandStatus($output); } // Load coverage reader @@ -184,35 +170,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int return $sortResult->toCommandStatus($output); } - // Generate report or display results - if ($context->hasReportOptions()) { - return $this->reportHandler->handle( - $sortResult->getData(), - $context->getReportType(), - $context->getReportFile() - ); - } - - $this->renderer->render($sortResult->getData(), $output); - - return Command::SUCCESS; - } - - - /** - * Handle validation errors with consistent error output. - */ - private function handleValidationError( - CognitiveMetricsCommandContext $context, - OutputInterface $output, - ?CustomExporterValidation $customExporterValidation = null - ): int { - $errorMessage = $customExporterValidation !== null - ? $customExporterValidation->getErrorMessageWithContext($context) - : $this->specification->getDetailedErrorMessage($context); - - $output->writeln('' . $errorMessage . ''); - - return Command::FAILURE; + // Handle output (report or console rendering) + return $this->outputHandler->handle($sortResult->getData(), $context, $output); } } diff --git a/src/Command/Handler/CognitiveAnalysis/OutputHandler.php b/src/Command/Handler/CognitiveAnalysis/OutputHandler.php new file mode 100644 index 0000000..d1e0c98 --- /dev/null +++ b/src/Command/Handler/CognitiveAnalysis/OutputHandler.php @@ -0,0 +1,47 @@ +hasReportOptions()) { + return $this->reportHandler->handle( + $collection, + $context->getReportType(), + $context->getReportFile() + ); + } + + $this->renderer->render($collection, $output); + return Command::SUCCESS; + } +} diff --git a/src/Command/Handler/CognitiveAnalysis/ValidationHandler.php b/src/Command/Handler/CognitiveAnalysis/ValidationHandler.php new file mode 100644 index 0000000..68cd9b0 --- /dev/null +++ b/src/Command/Handler/CognitiveAnalysis/ValidationHandler.php @@ -0,0 +1,66 @@ +specificationFactory->create(); + + if (!$specification->isSatisfiedBy($context)) { + $errorMessage = $specification->getDetailedErrorMessage($context); + return OperationResult::failure($errorMessage); + } + + return OperationResult::success(); + } + + /** + * Run custom exporter validation after configuration is loaded. + * Only validates if report options are provided. + * Returns success result if no report options or validation passes. + * Returns failure result with detailed error message if validation fails. + */ + public function validateCustomExporter(CognitiveMetricsCommandContext $context): OperationResult + { + if (!$context->hasReportOptions()) { + return OperationResult::success(); + } + + $customExporterValidation = new CustomExporterValidation( + $this->reportHandler->getReportFactory(), + $this->reportHandler->getConfigService() + ); + + if (!$customExporterValidation->isSatisfiedBy($context)) { + $errorMessage = $customExporterValidation->getErrorMessageWithContext($context); + return OperationResult::failure($errorMessage); + } + + return OperationResult::success(); + } +} From db26816c88427c4f98fbe095e37b73388c4a97d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Kr=C3=A4mer?= Date: Wed, 15 Oct 2025 00:16:33 +0200 Subject: [PATCH 2/2] Updating readme.md --- readme.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 556ad7e..5adc8e4 100644 --- a/readme.md +++ b/readme.md @@ -6,13 +6,29 @@ Cognitive Code Analysis is an approach to understanding and improving code by fo [Source: Human Cognitive Limitations. Broad, Consistent, Clinical Application of Physiological Principles Will Require Decision Support](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5822395/) +## Features 💎 + +* Cognitive Complexity Analysis: + * Calculates a cognitive complexity score for each class and method + * Provides detailed cognitive complexity metrics + * Generate reports in various formats (JSON, CSV, HTML) + * Baseline comparison to track complexity changes over time + * Configurable thresholds and weights for complexity analysis + * Optional result cache for faster subsequent runs (must be enabled in config) + * Custom report generators + * Also provides Halstead Complexity Metrics (must be enabled in config) + * Also provides Cyclomatic Complexity Metrics (must be enabled in config) +* Cognitive Complexity Churn Analysis to identify hotspots in the codebase + * Generate reports in various formats (JSON, CSV, HTML) + * Custom report generators + ## Installation ⚙️ ```bash composer require --dev phauthentic/cognitive-code-analysis ``` -## Running it +## Running it 🧑‍💻 Cognitive Complexity Analysis