diff --git a/README.md b/README.md index 2dd385b..3356142 100644 --- a/README.md +++ b/README.md @@ -66,8 +66,14 @@ Tactix provides a Symfony Console command `tactix:report` that creates a static bin/console tactix:report # or, when installed as a dependency with optional output directory vendor/bin/console tactix:report --out-dir= +# Exclude specific namespaces from the report (can be used multiple times) +vendor/bin/console tactix:report --exclude-namespace="App\\CLI\\" --exclude-namespace="App\\Infrastructure\\" ``` +Options: +- `--out-dir`: Base output directory for reports (defaults to project root) +- `--exclude-namespace`: Namespace prefix to exclude from the report (can be used multiple times). By default, `Doctrine\\`, `Symfony\\`, and `Psr\\` namespaces are excluded. When you provide your own exclusions, you replace these defaults. + Notes: - the output files index.html, report.js, chart.js, styles.css are created - the command prints discovered classes and forbidden relations and finishes with `Report written to: ./report/index.html`. diff --git a/src/Command/ReportCommand.php b/src/Command/ReportCommand.php index e4dd496..d7b6936 100644 --- a/src/Command/ReportCommand.php +++ b/src/Command/ReportCommand.php @@ -41,16 +41,9 @@ public function __construct(private readonly SerializerInterface $serializer) protected function configure(): void { $this - ->addArgument( - 'folder', - InputArgument::REQUIRED, - 'The source code folder to be checked' - ) - ->addOption( - 'out-dir', - null, InputOption::VALUE_REQUIRED, - 'Base output directory for reports (defaults to project root)' - ) + ->addArgument('folder', InputArgument::REQUIRED, 'The source code folder to be checked') + ->addOption('out-dir', null, InputOption::VALUE_REQUIRED, 'Base output directory for reports (defaults to project root)') + ->addOption('exclude-namespace', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Namespace prefix to exclude from the report (can be used multiple times)') ; } @@ -91,27 +84,25 @@ private function doExecute(InputInterface $input, OutputInterface $output): void $io = new SymfonyStyle($input, $output); $io->title(sprintf('Report for "%s"', $folder)); + // Get user-provided namespace exclusions or use sensible defaults + /** @var string[] $excludeNamespaces */ + $excludeNamespaces = $input->getOption('exclude-namespace'); + + // If no exclusions provided, use common vendor/framework namespaces as defaults + if (empty($excludeNamespaces)) { + $excludeNamespaces = [ + 'Doctrine\\', + 'Symfony\\', + 'Psr\\', + ]; + } + /** @var Node[] */ $nodes = array_reduce( iterator_to_array(YieldNodes::from($folder)), new NodeReducer( ignoreTypes: IgnoreableTypes::VALUES, - shouldNotStartWith: [ - 'App\\Kernel', - 'App\\CLI\\', - 'App\\DDD\\', - 'Doctrine\\', - 'Symfony\\', - 'Psr\\', - 'PhpParser\\', - 'phpDocumentor\\', - 'Monolog\\', - 'OpenTelemetry\\', - 'Rx\\', - 'React\\', - 'InfluxDB2\\', - 'EasyCorp\\Bundle\\EasyAdminBundle\\', - ], + shouldNotStartWith: $excludeNamespaces, shouldNotContain: [ 'array<', 'array{',