From 814b33f079ce1a63d0792ccace8651b4b9dea018 Mon Sep 17 00:00:00 2001 From: Thomas Hauschild <7961978+Morgy93@users.noreply.github.com> Date: Wed, 18 Mar 2026 22:02:02 +0100 Subject: [PATCH 01/14] fix: update phpstan level to 9 --- phpstan.neon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpstan.neon b/phpstan.neon index 8fc3894..0ec59d3 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -2,6 +2,6 @@ includes: - phar://phpstan.phar/conf/bleedingEdge.neon parameters: - level: 8 + level: 9 paths: - src From c1d8a821c6a988e841f995521e6743abba827718 Mon Sep 17 00:00:00 2001 From: Thomas Hauschild <7961978+Morgy93@users.noreply.github.com> Date: Wed, 18 Mar 2026 22:02:50 +0100 Subject: [PATCH 02/14] fix: update return type for getAllThemes method --- src/Model/ThemeList.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Model/ThemeList.php b/src/Model/ThemeList.php index c3219d7..de62623 100644 --- a/src/Model/ThemeList.php +++ b/src/Model/ThemeList.php @@ -5,6 +5,7 @@ namespace OpenForgeProject\MageForge\Model; use Magento\Framework\View\Design\Theme\ThemeList as MagentoThemeList; +use Magento\Framework\View\Design\ThemeInterface; class ThemeList { @@ -21,7 +22,7 @@ public function __construct( /** * Get all themes * - * @return array + * @return array */ public function getAllThemes(): array { From f2b209421a713badd798da7da150be072821d0f1 Mon Sep 17 00:00:00 2001 From: Thomas Hauschild <7961978+Morgy93@users.noreply.github.com> Date: Wed, 18 Mar 2026 22:29:05 +0100 Subject: [PATCH 03/14] fix: improve type checks and phpstan annotations --- src/Block/Inspector.php | 3 +- src/Console/Command/AbstractCommand.php | 2 +- src/Console/Command/Dev/InspectorCommand.php | 3 +- .../Hyva/CompatibilityCheckCommand.php | 16 ++++---- src/Console/Command/System/CheckCommand.php | 39 ++++++++++++------- src/Console/Command/System/VersionCommand.php | 9 ++++- src/Console/Command/Theme/BuildCommand.php | 2 + src/Console/Command/Theme/CleanCommand.php | 10 +++-- src/Console/Command/Theme/TokensCommand.php | 5 ++- src/Console/Command/Theme/WatchCommand.php | 5 +++ src/Model/ThemeList.php | 7 +++- src/Service/Hyva/CompatibilityChecker.php | 24 ++++-------- src/Service/Hyva/IncompatibilityDetector.php | 4 +- src/Service/Hyva/ModuleScanner.php | 15 +++++-- .../ThemeBuilder/HyvaThemes/Builder.php | 2 +- .../ThemeBuilder/TailwindCSS/Builder.php | 2 +- 16 files changed, 89 insertions(+), 59 deletions(-) diff --git a/src/Block/Inspector.php b/src/Block/Inspector.php index eaea02a..aa4d20a 100644 --- a/src/Block/Inspector.php +++ b/src/Block/Inspector.php @@ -89,7 +89,8 @@ public function getJsUrl(): string */ public function getTheme(): string { - return (string) $this->scopeConfig->getValue('mageforge/inspector/theme') ?: 'dark'; + $value = $this->scopeConfig->getValue('mageforge/inspector/theme'); + return is_string($value) && $value !== '' ? $value : 'dark'; } /** diff --git a/src/Console/Command/AbstractCommand.php b/src/Console/Command/AbstractCommand.php index 561402d..0959783 100644 --- a/src/Console/Command/AbstractCommand.php +++ b/src/Console/Command/AbstractCommand.php @@ -183,7 +183,7 @@ protected function handleInvalidThemeWithSuggestions( return null; } - return $selection; + return is_string($selection) ? $selection : null; } catch (\Exception $e) { $this->resetPromptEnvironment(); $this->io->error('Selection failed: ' . $e->getMessage()); diff --git a/src/Console/Command/Dev/InspectorCommand.php b/src/Console/Command/Dev/InspectorCommand.php index 7719e75..5ba4523 100644 --- a/src/Console/Command/Dev/InspectorCommand.php +++ b/src/Console/Command/Dev/InspectorCommand.php @@ -82,7 +82,8 @@ protected function configure(): void */ protected function executeCommand(InputInterface $input, OutputInterface $output): int { - $action = strtolower((string) $input->getArgument(self::ARGUMENT_ACTION)); + $arg = $input->getArgument(self::ARGUMENT_ACTION); + $action = strtolower(is_string($arg) ? $arg : ''); // Validate action if (!in_array($action, ['enable', 'disable', 'status'], true)) { diff --git a/src/Console/Command/Hyva/CompatibilityCheckCommand.php b/src/Console/Command/Hyva/CompatibilityCheckCommand.php index 4265c98..5904f1b 100644 --- a/src/Console/Command/Hyva/CompatibilityCheckCommand.php +++ b/src/Console/Command/Hyva/CompatibilityCheckCommand.php @@ -146,7 +146,7 @@ private function runInteractiveMode(InputInterface $input, OutputInterface $outp // Detailed view confirmation $detailedPrompt = new ConfirmPrompt(label: 'Show detailed file-level issues?', default: false); - $detailed = $detailedPrompt->prompt(); + $detailed = (bool) $detailedPrompt->prompt(); // Map selected options to flags $showAll = $displayMode === self::DISPLAY_MODE_SHOW_ALL; @@ -193,10 +193,10 @@ private function runInteractiveMode(InputInterface $input, OutputInterface $outp */ private function runDirectMode(InputInterface $input, OutputInterface $output): int { - $showAll = $input->getOption(self::OPTION_SHOW_ALL); - $thirdPartyOnly = $input->getOption(self::OPTION_THIRD_PARTY_ONLY); - $includeVendor = $input->getOption(self::OPTION_INCLUDE_VENDOR); - $detailed = $input->getOption(self::OPTION_DETAILED); + $showAll = (bool) $input->getOption(self::OPTION_SHOW_ALL); + $thirdPartyOnly = (bool) $input->getOption(self::OPTION_THIRD_PARTY_ONLY); + $includeVendor = (bool) $input->getOption(self::OPTION_INCLUDE_VENDOR); + $detailed = (bool) $input->getOption(self::OPTION_DETAILED); $this->io->title('Hyvä Theme Compatibility Check'); @@ -271,7 +271,7 @@ private function runScan( * Display compatibility check results * * @param array $results - * @phpstan-param array $results + * @phpstan-param array{modules: array>, totalIssues: int, criticalIssues: int}, moduleInfo: array{name: string, version: string, isHyvaAware: bool}}>, hasIncompatibilities: bool} $results * @param bool $showAll */ private function displayResults(array $results, bool $showAll): void @@ -292,7 +292,7 @@ private function displayResults(array $results, bool $showAll): void * Display detailed file-level issues * * @param array $results - * @phpstan-param array $results + * @phpstan-param array{modules: array>, totalIssues: int, criticalIssues: int}, moduleInfo: array{name: string, version: string, isHyvaAware: bool}}>, hasIncompatibilities: bool} $results */ private function displayDetailedIssues(array $results): void { @@ -333,7 +333,7 @@ private function displayDetailedIssues(array $results): void * Display summary statistics * * @param array $results - * @phpstan-param array $results + * @phpstan-param array{summary: array{total: int, compatible: int, incompatible: int, hyvaAware: int, criticalIssues: int, warningIssues: int}} $results */ private function displaySummary(array $results): void { diff --git a/src/Console/Command/System/CheckCommand.php b/src/Console/Command/System/CheckCommand.php index d8ec8f7..5060d92 100644 --- a/src/Console/Command/System/CheckCommand.php +++ b/src/Console/Command/System/CheckCommand.php @@ -162,8 +162,9 @@ private function getLatestLtsNodeVersion(): string return 'Unknown'; } + /** @var array> $nodes */ foreach ($nodes as $node) { - if (isset($node['lts']) && $node['lts'] !== false) { + if (isset($node['lts']) && $node['lts'] !== false && isset($node['version']) && is_string($node['version'])) { return trim($node['version'], 'v'); } } @@ -407,12 +408,15 @@ private function getSearchEngineFromMagentoConfig(): ?string private function checkSearchEngineViaDeploymentConfig($objectManager): ?string { try { + /** @var \Magento\Framework\App\DeploymentConfig $deploymentConfig */ $deploymentConfig = $objectManager->get(\Magento\Framework\App\DeploymentConfig::class); $engineConfig = $deploymentConfig->get('system/search/engine'); - if (!empty($engineConfig)) { - $host = $deploymentConfig->get('system/search/engine_host') ?: 'localhost'; - $port = $deploymentConfig->get('system/search/engine_port') ?: '9200'; + if (!empty($engineConfig) && is_string($engineConfig)) { + $hostRaw = $deploymentConfig->get('system/search/engine_host'); + $portRaw = $deploymentConfig->get('system/search/engine_port'); + $host = is_string($hostRaw) ? $hostRaw : 'localhost'; + $port = is_string($portRaw) ? $portRaw : '9200'; $url = "http://{$host}:{$port}"; if ($this->testElasticsearchConnection($url)) { @@ -439,12 +443,11 @@ private function checkSearchEngineViaDeploymentConfig($objectManager): ?string private function checkSearchEngineViaEngineResolver($objectManager): ?string { try { + /** @var \Magento\Framework\Search\EngineResolverInterface $engineResolver */ $engineResolver = $objectManager->get(\Magento\Framework\Search\EngineResolverInterface::class); - if ($engineResolver) { - $currentEngine = $engineResolver->getCurrentSearchEngine(); - if (!empty($currentEngine)) { - return ucfirst($currentEngine) . ' (Magento config)'; - } + $currentEngine = $engineResolver->getCurrentSearchEngine(); + if (!empty($currentEngine)) { + return ucfirst($currentEngine) . ' (Magento config)'; } } catch (\Exception $e) { if ($this->io->isVerbose()) { @@ -541,12 +544,16 @@ private function getSearchEngineHosts(): array */ private function formatSearchEngineVersion(array $info): string { - if (isset($info['version']['distribution']) && $info['version']['distribution'] === 'opensearch') { - return 'OpenSearch ' . $info['version']['number']; + $version = $info['version'] ?? null; + if (!is_array($version)) { + return 'Search Engine Available'; + } + if (isset($version['distribution']) && $version['distribution'] === 'opensearch') { + return 'OpenSearch ' . ($version['number'] ?? ''); } - if (isset($info['version']['number'])) { - return 'Elasticsearch ' . $info['version']['number']; + if (isset($version['number'])) { + return 'Elasticsearch ' . $version['number']; } return 'Search Engine Available'; @@ -597,6 +604,7 @@ private function tryMagentoHttpClient(string $url): ?array if ($status === 200 && !empty($response)) { $data = json_decode($response, true); if (is_array($data)) { + /** @var array $data */ return $data; } } @@ -734,9 +742,10 @@ private function getMagentoEnvironmentValue(string $name): ?string private function getValueFromDeploymentConfig($objectManager, string $name): ?string { try { + /** @var \Magento\Framework\App\DeploymentConfig $deploymentConfig */ $deploymentConfig = $objectManager->get(\Magento\Framework\App\DeploymentConfig::class); $envValue = $deploymentConfig->get('system/default/environment/' . $name); - if ($envValue !== null) { + if ($envValue !== null && is_scalar($envValue)) { return (string) $envValue; } } catch (\Exception $e) { @@ -760,7 +769,7 @@ private function getValueFromEnvironmentService($objectManager, string $name): ? try { $environmentService = $objectManager->get(\Magento\Framework\App\EnvironmentInterface::class); $method = 'get' . str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower($name)))); - if (method_exists($environmentService, $method)) { + if (is_object($environmentService) && method_exists($environmentService, $method)) { $value = $environmentService->$method(); if ($value !== null) { return (string) $value; diff --git a/src/Console/Command/System/VersionCommand.php b/src/Console/Command/System/VersionCommand.php index 9e58891..02f515c 100644 --- a/src/Console/Command/System/VersionCommand.php +++ b/src/Console/Command/System/VersionCommand.php @@ -73,7 +73,10 @@ private function getModuleVersion(): string try { $composerJson = $this->fileDriver->fileGetContents(__DIR__ . '/../../../../composer.json'); $composerData = json_decode($composerJson, true); - return $composerData['version'] ?? self::UNKNOWN_VERSION; + if (is_array($composerData) && isset($composerData['version']) && is_string($composerData['version'])) { + return $composerData['version']; + } + return self::UNKNOWN_VERSION; } catch (\Exception $e) { return self::UNKNOWN_VERSION; } @@ -96,7 +99,9 @@ private function getLatestVersion(): string if ($response->getStatusCode() === 200) { $data = json_decode($response->getBody()->getContents(), true); - return $data['tag_name'] ?? self::UNKNOWN_VERSION; + if (is_array($data) && isset($data['tag_name']) && is_string($data['tag_name'])) { + return $data['tag_name']; + } } } catch (\Exception $e) { if ($this->io->isVerbose()) { diff --git a/src/Console/Command/Theme/BuildCommand.php b/src/Console/Command/Theme/BuildCommand.php index 8d89536..457a91f 100644 --- a/src/Console/Command/Theme/BuildCommand.php +++ b/src/Console/Command/Theme/BuildCommand.php @@ -65,6 +65,7 @@ protected function configure(): void */ protected function executeCommand(InputInterface $input, OutputInterface $output): int { + /** @var array $themeCodes */ $themeCodes = $input->getArgument('themeCodes'); // Allow wildcards using the AbstractCommand helper @@ -106,6 +107,7 @@ protected function executeCommand(InputInterface $input, OutputInterface $output try { $themeCodes = $themeCodesPrompt->prompt(); \Laravel\Prompts\Prompt::terminal()->restoreTty(); + /** @var array $themeCodes */ // Reset environment $this->resetPromptEnvironment(); diff --git a/src/Console/Command/Theme/CleanCommand.php b/src/Console/Command/Theme/CleanCommand.php index 053ac26..dae0dff 100644 --- a/src/Console/Command/Theme/CleanCommand.php +++ b/src/Console/Command/Theme/CleanCommand.php @@ -70,7 +70,7 @@ protected function configure(): void */ protected function executeCommand(InputInterface $input, OutputInterface $output): int { - $dryRun = $input->getOption('dry-run'); + $dryRun = (bool) $input->getOption('dry-run'); if ($dryRun) { $this->io->note('DRY RUN MODE: No files will be deleted'); @@ -98,6 +98,7 @@ protected function executeCommand(InputInterface $input, OutputInterface $output */ private function resolveThemeCodes(InputInterface $input, OutputInterface $output): ?array { + /** @var array $themeCodes */ $themeCodes = $input->getArgument('themeCodes'); $cleanAll = $input->getOption('all'); @@ -163,7 +164,7 @@ private function selectThemesInteractively(OutputInterface $output): ?array /** * Display available themes for non-interactive environments * - * @param array $themes + * @param array<\Magento\Theme\Model\Theme> $themes * @return void */ private function displayAvailableThemes(array $themes): void @@ -189,7 +190,7 @@ private function displayAvailableThemes(array $themes): void * Prompt user to select themes * * @param array $options - * @param array $themes + * @param array<\Magento\Theme\Model\Theme> $themes * @return array|null */ private function promptForThemes(array $options, array $themes): ?array @@ -216,6 +217,7 @@ private function promptForThemes(array $options, array $themes): ?array return null; } + /** @var array $themeCodes */ return $themeCodes; } catch (\Exception $e) { $this->resetPromptEnvironment(); @@ -231,7 +233,7 @@ private function promptForThemes(array $options, array $themes): ?array * @param array $themeCodes * @param bool $dryRun * @param OutputInterface $output - * @return array [totalCleaned, failedThemes] + * @return array{int, array} [totalCleaned, failedThemes] */ private function processThemes(array $themeCodes, bool $dryRun, OutputInterface $output): array { diff --git a/src/Console/Command/Theme/TokensCommand.php b/src/Console/Command/Theme/TokensCommand.php index f97684a..f711216 100644 --- a/src/Console/Command/Theme/TokensCommand.php +++ b/src/Console/Command/Theme/TokensCommand.php @@ -68,7 +68,8 @@ protected function configure(): void */ protected function executeCommand(InputInterface $input, OutputInterface $output): int { - $themeCode = $this->selectTheme($input->getArgument('themeCode')); + $arg = $input->getArgument('themeCode'); + $themeCode = $this->selectTheme(is_string($arg) ? $arg : null); if ($themeCode === null) { return Cli::RETURN_FAILURE; } @@ -121,7 +122,7 @@ private function selectTheme(?string $themeCode): ?string try { $themeCode = $themeCodePrompt->prompt(); \Laravel\Prompts\Prompt::terminal()->restoreTty(); - return $themeCode; + return is_string($themeCode) ? $themeCode : null; } catch (\Exception $e) { $this->io->error('Interactive mode failed: ' . $e->getMessage()); return null; diff --git a/src/Console/Command/Theme/WatchCommand.php b/src/Console/Command/Theme/WatchCommand.php index eea1da9..4337eb4 100644 --- a/src/Console/Command/Theme/WatchCommand.php +++ b/src/Console/Command/Theme/WatchCommand.php @@ -87,6 +87,11 @@ protected function executeCommand(InputInterface $input, OutputInterface $output \Laravel\Prompts\Prompt::terminal()->restoreTty(); } + if (!is_string($themeCode)) { + $this->io->error('No valid theme code provided.'); + return self::FAILURE; + } + $themePath = $this->themePath->getPath($themeCode); if ($themePath === null) { // Try to suggest similar themes diff --git a/src/Model/ThemeList.php b/src/Model/ThemeList.php index de62623..184bc7b 100644 --- a/src/Model/ThemeList.php +++ b/src/Model/ThemeList.php @@ -6,6 +6,7 @@ use Magento\Framework\View\Design\Theme\ThemeList as MagentoThemeList; use Magento\Framework\View\Design\ThemeInterface; +use Magento\Theme\Model\Theme; class ThemeList { @@ -22,10 +23,12 @@ public function __construct( /** * Get all themes * - * @return array + * @return array */ public function getAllThemes(): array { - return $this->magentoThemeList->getItems(); + /** @var array $items */ + $items = $this->magentoThemeList->getItems(); + return $items; } } diff --git a/src/Service/Hyva/CompatibilityChecker.php b/src/Service/Hyva/CompatibilityChecker.php index de01676..da3f8b7 100644 --- a/src/Service/Hyva/CompatibilityChecker.php +++ b/src/Service/Hyva/CompatibilityChecker.php @@ -37,7 +37,7 @@ public function __construct( * @param bool $excludeVendor Whether to exclude modules from the vendor/ directory * @return array Results with structure: ['modules' => [], 'summary' => [], * 'hasIncompatibilities' => bool] - * @phpstan-return array{modules: array, summary: array, hasIncompatibilities: bool} + * @phpstan-return array{modules: array>, totalIssues: int, criticalIssues: int}, moduleInfo: array{name: string, version: string, isHyvaAware: bool}}>, summary: array{total: int, compatible: int, incompatible: int, hyvaAware: int, criticalIssues: int, warningIssues: int}, hasIncompatibilities: bool} */ public function check( SymfonyStyle $io, @@ -140,7 +140,7 @@ private function isMagentoModule(string $moduleName): bool * Format results for display * * @param array $results - * @phpstan-param array $results + * @phpstan-param array{modules: array>, totalIssues: int, criticalIssues: int}, moduleInfo: array{name: string, version: string, isHyvaAware: bool}}>} $results * @param bool $showAll * @return array> */ @@ -168,7 +168,7 @@ public function formatResultsForDisplay(array $results, bool $showAll = false): * Get status display string with colors * * @param array $moduleData - * @phpstan-param array $moduleData + * @phpstan-param array{compatible: bool, hasWarnings: bool, scanResult: array, moduleInfo: array} $moduleData * @return string */ private function getStatusDisplay(array $moduleData): string @@ -192,7 +192,7 @@ private function getStatusDisplay(array $moduleData): string * Get issues display string * * @param array $moduleData - * @phpstan-param array $moduleData + * @phpstan-param array{compatible: bool, hasWarnings: bool, scanResult: array{totalIssues: int, criticalIssues: int}, moduleInfo: array} $moduleData * @return string */ private function getIssuesDisplay(array $moduleData): string @@ -223,21 +223,13 @@ private function getIssuesDisplay(array $moduleData): string * * @param string $moduleName * @param array $moduleData - * @phpstan-param array $moduleData - * @return array> + * @phpstan-param array{compatible: bool, hasWarnings: bool, scanResult: array{files: array>, totalIssues: int, criticalIssues: int}, moduleInfo: array{name: string, version: string, isHyvaAware: bool}} $moduleData + * @return array}> */ public function getDetailedIssues(string $moduleName, array $moduleData): array { - // Safely access nested array structure - $scanResult = $moduleData['scanResult'] ?? []; - if (!is_array($scanResult)) { - return []; - } - - $files = $scanResult['files'] ?? []; - if (!is_array($files)) { - return []; - } + $scanResult = $moduleData['scanResult']; + $files = $scanResult['files']; $details = []; diff --git a/src/Service/Hyva/IncompatibilityDetector.php b/src/Service/Hyva/IncompatibilityDetector.php index 5edce53..c87567d 100644 --- a/src/Service/Hyva/IncompatibilityDetector.php +++ b/src/Service/Hyva/IncompatibilityDetector.php @@ -107,6 +107,7 @@ public function __construct( * * @param string $filePath * @return array> Array of issues with keys: pattern, description, severity, line + * @phpstan-return array */ public function detectInFile(string $filePath): array { @@ -153,8 +154,9 @@ private function mapExtensionToType(string $extension): string * @param array $lines * @param array $patterns * @return array> + * @phpstan-return array * @phpstan-param array $lines - * @phpstan-param array> $patterns + * @phpstan-param array $patterns */ private function scanContentForPatterns(array $lines, array $patterns): array { diff --git a/src/Service/Hyva/ModuleScanner.php b/src/Service/Hyva/ModuleScanner.php index 2fb17bc..2303d29 100644 --- a/src/Service/Hyva/ModuleScanner.php +++ b/src/Service/Hyva/ModuleScanner.php @@ -32,6 +32,7 @@ public function __construct( * * @param string $modulePath * @return array Array with structure: ['files' => [], 'totalIssues' => int, 'criticalIssues' => int] + * @phpstan-return array{files: array>, totalIssues: int, criticalIssues: int} */ public function scanModule(string $modulePath): array { @@ -120,14 +121,17 @@ private function isHyvaCompatibilityPackage(array $composerData): bool { // Check if this IS a Hyvä compatibility package $packageName = $composerData['name'] ?? ''; - if (str_starts_with($packageName, 'hyva-themes/') && str_contains($packageName, '-compat')) { + if (is_string($packageName) && str_starts_with($packageName, 'hyva-themes/') && str_contains($packageName, '-compat')) { return true; } // Check dependencies for Hyvä packages $requires = $composerData['require'] ?? []; + if (!is_array($requires)) { + return false; + } foreach ($requires as $package => $version) { - if (str_starts_with($package, 'hyva-themes/')) { + if (is_string($package) && str_starts_with($package, 'hyva-themes/')) { return true; } } @@ -157,6 +161,7 @@ public function hasHyvaCompatibilityPackage(string $modulePath): bool return false; } + /** @var array $composerData */ return $this->isHyvaCompatibilityPackage($composerData); } catch (\Exception $e) { return false; @@ -168,6 +173,7 @@ public function hasHyvaCompatibilityPackage(string $modulePath): bool * * @param string $modulePath * @return array + * @phpstan-return array{name: string, version: string, isHyvaAware: bool} */ public function getModuleInfo(string $modulePath): array { @@ -185,9 +191,10 @@ public function getModuleInfo(string $modulePath): array return ['name' => 'Unknown', 'version' => 'Unknown', 'isHyvaAware' => false]; } + /** @var array $composerData */ return [ - 'name' => $composerData['name'] ?? 'Unknown', - 'version' => $composerData['version'] ?? 'Unknown', + 'name' => is_string($composerData['name'] ?? null) ? $composerData['name'] : 'Unknown', + 'version' => is_string($composerData['version'] ?? null) ? $composerData['version'] : 'Unknown', 'isHyvaAware' => $this->isHyvaCompatibilityPackage($composerData), ]; } catch (\Exception $e) { diff --git a/src/Service/ThemeBuilder/HyvaThemes/Builder.php b/src/Service/ThemeBuilder/HyvaThemes/Builder.php index 4cb8ab0..defbf7d 100644 --- a/src/Service/ThemeBuilder/HyvaThemes/Builder.php +++ b/src/Service/ThemeBuilder/HyvaThemes/Builder.php @@ -68,7 +68,7 @@ public function detect(string $themePath): bool if ($this->fileDriver->isExists($themePath . '/composer.json')) { $composerContent = $this->fileDriver->fileGetContents($themePath . '/composer.json'); $composerJson = json_decode($composerContent, true); - if (isset($composerJson['name']) && str_contains($composerJson['name'], 'hyva')) { + if (is_array($composerJson) && isset($composerJson['name']) && is_string($composerJson['name']) && str_contains($composerJson['name'], 'hyva')) { return true; } } diff --git a/src/Service/ThemeBuilder/TailwindCSS/Builder.php b/src/Service/ThemeBuilder/TailwindCSS/Builder.php index ed8789d..633868f 100644 --- a/src/Service/ThemeBuilder/TailwindCSS/Builder.php +++ b/src/Service/ThemeBuilder/TailwindCSS/Builder.php @@ -68,7 +68,7 @@ public function detect(string $themePath): bool if ($this->fileDriver->isExists($themePath . '/composer.json')) { $composerContent = $this->fileDriver->fileGetContents($themePath . '/composer.json'); $composerJson = json_decode($composerContent, true); - if (!isset($composerJson['name']) && str_contains($composerJson['name'], 'hyva')) { + if (\is_array($composerJson) && isset($composerJson['name']) && \is_string($composerJson['name']) && !str_contains($composerJson['name'], 'hyva')) { return true; } } From 89a2a864ea59a7b6218927e96b2f43f1ada9a8b0 Mon Sep 17 00:00:00 2001 From: Thomas Hauschild <7961978+Morgy93@users.noreply.github.com> Date: Wed, 18 Mar 2026 22:29:13 +0100 Subject: [PATCH 04/14] fix: improve code formatting and type checks --- src/Console/Command/AbstractCommand.php | 23 ++++++++----------- src/Console/Command/System/CheckCommand.php | 11 ++++++--- src/Console/Command/Theme/BuildCommand.php | 6 ++--- src/Console/Command/Theme/CleanCommand.php | 2 +- src/Console/Command/Theme/TokensCommand.php | 2 +- src/Console/Command/Theme/WatchCommand.php | 2 +- src/Service/Hyva/ModuleScanner.php | 6 ++++- .../ThemeBuilder/HyvaThemes/Builder.php | 7 +++++- .../ThemeBuilder/TailwindCSS/Builder.php | 7 +++++- 9 files changed, 40 insertions(+), 26 deletions(-) diff --git a/src/Console/Command/AbstractCommand.php b/src/Console/Command/AbstractCommand.php index 0959783..e7bb887 100644 --- a/src/Console/Command/AbstractCommand.php +++ b/src/Console/Command/AbstractCommand.php @@ -6,8 +6,8 @@ use Laravel\Prompts\SelectPrompt; use Magento\Framework\Console\Cli; -use OpenForgeProject\MageForge\Service\ThemeSuggester; use OpenForgeProject\MageForge\Model\ThemeList; +use OpenForgeProject\MageForge\Service\ThemeSuggester; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -487,10 +487,8 @@ private function removeSecureEnvironmentValue(string $name): void * @param ThemeList $themeList * @return array */ - protected function resolveVendorThemes( - array $themeCodes, - ThemeList $themeList - ): array { + protected function resolveVendorThemes(array $themeCodes, ThemeList $themeList): array + { $resolved = []; $availableThemes = null; @@ -502,10 +500,7 @@ protected function resolveVendorThemes( if ($isExplicitWildcard || $isVendorOnly) { // Lazy-load themes only when needed if ($availableThemes === null) { - $availableThemes = array_map( - fn($theme) => $theme->getCode(), - $themeList->getAllThemes() - ); + $availableThemes = array_map(fn($theme) => $theme->getCode(), $themeList->getAllThemes()); } if ($isExplicitWildcard) { @@ -514,10 +509,10 @@ protected function resolveVendorThemes( $prefix = $code . '/'; // e.g. "Vendor" -> "Vendor/" } - $matched = array_filter( - $availableThemes, - fn(string $availableCode) => \str_starts_with($availableCode, $prefix) - ); + $matched = array_filter($availableThemes, fn(string $availableCode) => \str_starts_with( + $availableCode, + $prefix, + )); if (empty($matched)) { $this->io->warning(sprintf("No themes found for vendor/prefix '%s'", $prefix)); @@ -532,7 +527,7 @@ protected function resolveVendorThemes( "Resolved vendor '%s' to %d theme(s): %s", $code, count($matched), - implode(', ', $matched) + implode(', ', $matched), )); foreach ($matched as $match) { diff --git a/src/Console/Command/System/CheckCommand.php b/src/Console/Command/System/CheckCommand.php index 5060d92..b13ba98 100644 --- a/src/Console/Command/System/CheckCommand.php +++ b/src/Console/Command/System/CheckCommand.php @@ -164,7 +164,12 @@ private function getLatestLtsNodeVersion(): string /** @var array> $nodes */ foreach ($nodes as $node) { - if (isset($node['lts']) && $node['lts'] !== false && isset($node['version']) && is_string($node['version'])) { + if ( + isset($node['lts']) + && $node['lts'] !== false + && isset($node['version']) + && is_string($node['version']) + ) { return trim($node['version'], 'v'); } } @@ -669,8 +674,8 @@ private function getDiskSpace(): string $totalSpace = disk_total_space('.'); $freeSpace = disk_free_space('.'); - $totalGB = round((($totalSpace / 1024) / 1024) / 1024, 2); - $freeGB = round((($freeSpace / 1024) / 1024) / 1024, 2); + $totalGB = round($totalSpace / 1024 / 1024 / 1024, 2); + $freeGB = round($freeSpace / 1024 / 1024 / 1024, 2); $usedGB = round($totalGB - $freeGB, 2); $usedPercent = round(($usedGB / $totalGB) * 100, 2); diff --git a/src/Console/Command/Theme/BuildCommand.php b/src/Console/Command/Theme/BuildCommand.php index 457a91f..c1558a9 100644 --- a/src/Console/Command/Theme/BuildCommand.php +++ b/src/Console/Command/Theme/BuildCommand.php @@ -98,7 +98,7 @@ protected function executeCommand(InputInterface $input, OutputInterface $output label: 'Select themes to build', options: fn(string $value) => empty($value) ? $options - : array_values(array_filter($options, fn($option) => stripos((string)$option, $value) !== false)), + : array_values(array_filter($options, fn($option) => stripos((string) $option, $value) !== false)), placeholder: 'Type to search theme...', hint: 'Type to search, arrow keys to navigate, Space to toggle, Enter to confirm', required: false, @@ -357,14 +357,14 @@ private function displayBuildSummary(SymfonyStyle $io, array $successList, float $io->success(sprintf( '🚀 Successfully built %d theme(s). Build process completed in %.2f seconds.', $successCount, - $duration + $duration, )); $io->writeln('Summary:'); $io->newLine(); } else { $io->warning(sprintf( 'Build process completed in %.2f seconds, but no themes were built successfully.', - $duration + $duration, )); return; } diff --git a/src/Console/Command/Theme/CleanCommand.php b/src/Console/Command/Theme/CleanCommand.php index dae0dff..f6d1760 100644 --- a/src/Console/Command/Theme/CleanCommand.php +++ b/src/Console/Command/Theme/CleanCommand.php @@ -201,7 +201,7 @@ private function promptForThemes(array $options, array $themes): ?array label: 'Select themes to clean', options: fn(string $value) => empty($value) ? $options - : array_values(array_filter($options, fn($option) => stripos((string)$option, $value) !== false)), + : array_values(array_filter($options, fn($option) => stripos((string) $option, $value) !== false)), placeholder: 'Type to search theme...', hint: 'Type to search, arrow keys to navigate, Space to toggle, Enter to confirm', required: false, diff --git a/src/Console/Command/Theme/TokensCommand.php b/src/Console/Command/Theme/TokensCommand.php index f711216..11a3b46 100644 --- a/src/Console/Command/Theme/TokensCommand.php +++ b/src/Console/Command/Theme/TokensCommand.php @@ -113,7 +113,7 @@ private function selectTheme(?string $themeCode): ?string label: 'Select theme to generate tokens for', options: fn(string $value) => empty($value) ? $options - : array_values(array_filter($options, fn($option) => stripos((string)$option, $value) !== false)), + : array_values(array_filter($options, fn($option) => stripos((string) $option, $value) !== false)), placeholder: 'Type to search theme...', scroll: 10, hint: 'Type to search, arrow keys to navigate, Enter to confirm', diff --git a/src/Console/Command/Theme/WatchCommand.php b/src/Console/Command/Theme/WatchCommand.php index 4337eb4..ce47cf7 100644 --- a/src/Console/Command/Theme/WatchCommand.php +++ b/src/Console/Command/Theme/WatchCommand.php @@ -77,7 +77,7 @@ protected function executeCommand(InputInterface $input, OutputInterface $output label: 'Select theme to watch', options: fn(string $value) => empty($value) ? $options - : array_values(array_filter($options, fn($option) => stripos((string)$option, $value) !== false)), + : array_values(array_filter($options, fn($option) => stripos((string) $option, $value) !== false)), placeholder: 'Type to search theme...', scroll: 10, hint: 'Type to search, arrow keys to navigate, Enter to confirm', diff --git a/src/Service/Hyva/ModuleScanner.php b/src/Service/Hyva/ModuleScanner.php index 2303d29..a587e67 100644 --- a/src/Service/Hyva/ModuleScanner.php +++ b/src/Service/Hyva/ModuleScanner.php @@ -121,7 +121,11 @@ private function isHyvaCompatibilityPackage(array $composerData): bool { // Check if this IS a Hyvä compatibility package $packageName = $composerData['name'] ?? ''; - if (is_string($packageName) && str_starts_with($packageName, 'hyva-themes/') && str_contains($packageName, '-compat')) { + if ( + is_string($packageName) + && str_starts_with($packageName, 'hyva-themes/') + && str_contains($packageName, '-compat') + ) { return true; } diff --git a/src/Service/ThemeBuilder/HyvaThemes/Builder.php b/src/Service/ThemeBuilder/HyvaThemes/Builder.php index defbf7d..2b9fef1 100644 --- a/src/Service/ThemeBuilder/HyvaThemes/Builder.php +++ b/src/Service/ThemeBuilder/HyvaThemes/Builder.php @@ -68,7 +68,12 @@ public function detect(string $themePath): bool if ($this->fileDriver->isExists($themePath . '/composer.json')) { $composerContent = $this->fileDriver->fileGetContents($themePath . '/composer.json'); $composerJson = json_decode($composerContent, true); - if (is_array($composerJson) && isset($composerJson['name']) && is_string($composerJson['name']) && str_contains($composerJson['name'], 'hyva')) { + if ( + is_array($composerJson) + && isset($composerJson['name']) + && is_string($composerJson['name']) + && str_contains($composerJson['name'], 'hyva') + ) { return true; } } diff --git a/src/Service/ThemeBuilder/TailwindCSS/Builder.php b/src/Service/ThemeBuilder/TailwindCSS/Builder.php index 633868f..b6fff9a 100644 --- a/src/Service/ThemeBuilder/TailwindCSS/Builder.php +++ b/src/Service/ThemeBuilder/TailwindCSS/Builder.php @@ -68,7 +68,12 @@ public function detect(string $themePath): bool if ($this->fileDriver->isExists($themePath . '/composer.json')) { $composerContent = $this->fileDriver->fileGetContents($themePath . '/composer.json'); $composerJson = json_decode($composerContent, true); - if (\is_array($composerJson) && isset($composerJson['name']) && \is_string($composerJson['name']) && !str_contains($composerJson['name'], 'hyva')) { + if ( + \is_array($composerJson) + && isset($composerJson['name']) + && \is_string($composerJson['name']) + && !str_contains($composerJson['name'], 'hyva') + ) { return true; } } From d85bd058fe9e5b5f216dc464731cc0f0c1579eac Mon Sep 17 00:00:00 2001 From: Thomas Hauschild <7961978+Morgy93@users.noreply.github.com> Date: Wed, 18 Mar 2026 22:30:23 +0100 Subject: [PATCH 05/14] fix: simplify conditionals in various builders --- src/Console/Command/System/CheckCommand.php | 3 +-- src/Service/Hyva/ModuleScanner.php | 3 +-- src/Service/ThemeBuilder/HyvaThemes/Builder.php | 3 +-- src/Service/ThemeBuilder/TailwindCSS/Builder.php | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Console/Command/System/CheckCommand.php b/src/Console/Command/System/CheckCommand.php index b13ba98..56d1ab5 100644 --- a/src/Console/Command/System/CheckCommand.php +++ b/src/Console/Command/System/CheckCommand.php @@ -164,8 +164,7 @@ private function getLatestLtsNodeVersion(): string /** @var array> $nodes */ foreach ($nodes as $node) { - if ( - isset($node['lts']) + if (isset($node['lts']) && $node['lts'] !== false && isset($node['version']) && is_string($node['version']) diff --git a/src/Service/Hyva/ModuleScanner.php b/src/Service/Hyva/ModuleScanner.php index a587e67..6303b5c 100644 --- a/src/Service/Hyva/ModuleScanner.php +++ b/src/Service/Hyva/ModuleScanner.php @@ -121,8 +121,7 @@ private function isHyvaCompatibilityPackage(array $composerData): bool { // Check if this IS a Hyvä compatibility package $packageName = $composerData['name'] ?? ''; - if ( - is_string($packageName) + if (is_string($packageName) && str_starts_with($packageName, 'hyva-themes/') && str_contains($packageName, '-compat') ) { diff --git a/src/Service/ThemeBuilder/HyvaThemes/Builder.php b/src/Service/ThemeBuilder/HyvaThemes/Builder.php index 2b9fef1..c9043e4 100644 --- a/src/Service/ThemeBuilder/HyvaThemes/Builder.php +++ b/src/Service/ThemeBuilder/HyvaThemes/Builder.php @@ -68,8 +68,7 @@ public function detect(string $themePath): bool if ($this->fileDriver->isExists($themePath . '/composer.json')) { $composerContent = $this->fileDriver->fileGetContents($themePath . '/composer.json'); $composerJson = json_decode($composerContent, true); - if ( - is_array($composerJson) + if (is_array($composerJson) && isset($composerJson['name']) && is_string($composerJson['name']) && str_contains($composerJson['name'], 'hyva') diff --git a/src/Service/ThemeBuilder/TailwindCSS/Builder.php b/src/Service/ThemeBuilder/TailwindCSS/Builder.php index b6fff9a..838006f 100644 --- a/src/Service/ThemeBuilder/TailwindCSS/Builder.php +++ b/src/Service/ThemeBuilder/TailwindCSS/Builder.php @@ -68,8 +68,7 @@ public function detect(string $themePath): bool if ($this->fileDriver->isExists($themePath . '/composer.json')) { $composerContent = $this->fileDriver->fileGetContents($themePath . '/composer.json'); $composerJson = json_decode($composerContent, true); - if ( - \is_array($composerJson) + if (\is_array($composerJson) && isset($composerJson['name']) && \is_string($composerJson['name']) && !str_contains($composerJson['name'], 'hyva') From 732dc97062a867c39fde0ad30b053ae1e0d1b2f5 Mon Sep 17 00:00:00 2001 From: Thomas Hauschild <7961978+Morgy93@users.noreply.github.com> Date: Wed, 18 Mar 2026 22:37:13 +0100 Subject: [PATCH 06/14] fix: update phpstan types and annotations for compatibility --- .../Hyva/CompatibilityCheckCommand.php | 10 ++++++--- src/Service/Hyva/CompatibilityChecker.php | 21 +++++++++++++------ src/Service/Hyva/IncompatibilityDetector.php | 6 ++++-- src/Service/Hyva/ModuleScanner.php | 8 +++++-- 4 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/Console/Command/Hyva/CompatibilityCheckCommand.php b/src/Console/Command/Hyva/CompatibilityCheckCommand.php index 5904f1b..4cd297e 100644 --- a/src/Console/Command/Hyva/CompatibilityCheckCommand.php +++ b/src/Console/Command/Hyva/CompatibilityCheckCommand.php @@ -19,6 +19,10 @@ * * Scans modules for RequireJS, Knockout.js, jQuery, and UI Components usage * that would be incompatible with Hyvä themes. + * + * @phpstan-import-type CheckResults from \OpenForgeProject\MageForge\Service\Hyva\CompatibilityChecker + * @phpstan-import-type CheckSummary from \OpenForgeProject\MageForge\Service\Hyva\CompatibilityChecker + * @phpstan-import-type ModuleEntry from \OpenForgeProject\MageForge\Service\Hyva\CompatibilityChecker */ class CompatibilityCheckCommand extends AbstractCommand { @@ -271,7 +275,7 @@ private function runScan( * Display compatibility check results * * @param array $results - * @phpstan-param array{modules: array>, totalIssues: int, criticalIssues: int}, moduleInfo: array{name: string, version: string, isHyvaAware: bool}}>, hasIncompatibilities: bool} $results + * @phpstan-param CheckResults $results * @param bool $showAll */ private function displayResults(array $results, bool $showAll): void @@ -292,7 +296,7 @@ private function displayResults(array $results, bool $showAll): void * Display detailed file-level issues * * @param array $results - * @phpstan-param array{modules: array>, totalIssues: int, criticalIssues: int}, moduleInfo: array{name: string, version: string, isHyvaAware: bool}}>, hasIncompatibilities: bool} $results + * @phpstan-param CheckResults $results */ private function displayDetailedIssues(array $results): void { @@ -333,7 +337,7 @@ private function displayDetailedIssues(array $results): void * Display summary statistics * * @param array $results - * @phpstan-param array{summary: array{total: int, compatible: int, incompatible: int, hyvaAware: int, criticalIssues: int, warningIssues: int}} $results + * @phpstan-param array{summary: CheckSummary} $results */ private function displaySummary(array $results): void { diff --git a/src/Service/Hyva/CompatibilityChecker.php b/src/Service/Hyva/CompatibilityChecker.php index da3f8b7..3f57e15 100644 --- a/src/Service/Hyva/CompatibilityChecker.php +++ b/src/Service/Hyva/CompatibilityChecker.php @@ -9,12 +9,21 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; +// phpcs:disable Generic.Files.LineLength.TooLong /** * Service that orchestrates Hyvä compatibility checking across Magento modules * * This service scans modules, detects incompatibilities with Hyvä theme framework, * and provides formatted results with summary statistics. + * + * @phpstan-import-type ScanIssue from IncompatibilityDetector + * @phpstan-import-type ScanResult from ModuleScanner + * @phpstan-import-type ModuleInfo from ModuleScanner + * @phpstan-type ModuleEntry array{compatible: bool, hasWarnings: bool, scanResult: ScanResult, moduleInfo: ModuleInfo} + * @phpstan-type CheckSummary array{total: int, compatible: int, incompatible: int, hyvaAware: int, criticalIssues: int, warningIssues: int} + * @phpstan-type CheckResults array{modules: array, summary: CheckSummary, hasIncompatibilities: bool} */ +// phpcs:enable Generic.Files.LineLength.TooLong class CompatibilityChecker { /** @@ -37,7 +46,7 @@ public function __construct( * @param bool $excludeVendor Whether to exclude modules from the vendor/ directory * @return array Results with structure: ['modules' => [], 'summary' => [], * 'hasIncompatibilities' => bool] - * @phpstan-return array{modules: array>, totalIssues: int, criticalIssues: int}, moduleInfo: array{name: string, version: string, isHyvaAware: bool}}>, summary: array{total: int, compatible: int, incompatible: int, hyvaAware: int, criticalIssues: int, warningIssues: int}, hasIncompatibilities: bool} + * @phpstan-return CheckResults */ public function check( SymfonyStyle $io, @@ -140,7 +149,7 @@ private function isMagentoModule(string $moduleName): bool * Format results for display * * @param array $results - * @phpstan-param array{modules: array>, totalIssues: int, criticalIssues: int}, moduleInfo: array{name: string, version: string, isHyvaAware: bool}}>} $results + * @phpstan-param CheckResults $results * @param bool $showAll * @return array> */ @@ -168,7 +177,7 @@ public function formatResultsForDisplay(array $results, bool $showAll = false): * Get status display string with colors * * @param array $moduleData - * @phpstan-param array{compatible: bool, hasWarnings: bool, scanResult: array, moduleInfo: array} $moduleData + * @phpstan-param ModuleEntry $moduleData * @return string */ private function getStatusDisplay(array $moduleData): string @@ -192,7 +201,7 @@ private function getStatusDisplay(array $moduleData): string * Get issues display string * * @param array $moduleData - * @phpstan-param array{compatible: bool, hasWarnings: bool, scanResult: array{totalIssues: int, criticalIssues: int}, moduleInfo: array} $moduleData + * @phpstan-param ModuleEntry $moduleData * @return string */ private function getIssuesDisplay(array $moduleData): string @@ -223,8 +232,8 @@ private function getIssuesDisplay(array $moduleData): string * * @param string $moduleName * @param array $moduleData - * @phpstan-param array{compatible: bool, hasWarnings: bool, scanResult: array{files: array>, totalIssues: int, criticalIssues: int}, moduleInfo: array{name: string, version: string, isHyvaAware: bool}} $moduleData - * @return array}> + * @phpstan-param ModuleEntry $moduleData + * @return array}> */ public function getDetailedIssues(string $moduleName, array $moduleData): array { diff --git a/src/Service/Hyva/IncompatibilityDetector.php b/src/Service/Hyva/IncompatibilityDetector.php index c87567d..c3be313 100644 --- a/src/Service/Hyva/IncompatibilityDetector.php +++ b/src/Service/Hyva/IncompatibilityDetector.php @@ -11,6 +11,8 @@ * * Uses pattern matching to identify RequireJS, Knockout.js, jQuery, and UI Components * usage that would be problematic in a Hyvä environment. + * + * @phpstan-type ScanIssue array{description: string, severity: string, line: int, pattern: string} */ class IncompatibilityDetector { @@ -107,7 +109,7 @@ public function __construct( * * @param string $filePath * @return array> Array of issues with keys: pattern, description, severity, line - * @phpstan-return array + * @phpstan-return array */ public function detectInFile(string $filePath): array { @@ -154,7 +156,7 @@ private function mapExtensionToType(string $extension): string * @param array $lines * @param array $patterns * @return array> - * @phpstan-return array + * @phpstan-return array * @phpstan-param array $lines * @phpstan-param array $patterns */ diff --git a/src/Service/Hyva/ModuleScanner.php b/src/Service/Hyva/ModuleScanner.php index 6303b5c..8b280da 100644 --- a/src/Service/Hyva/ModuleScanner.php +++ b/src/Service/Hyva/ModuleScanner.php @@ -11,6 +11,10 @@ * * Recursively scans JavaScript, XML, and PHTML files within module directories * to identify patterns that may be incompatible with Hyvä themes. + * + * @phpstan-import-type ScanIssue from IncompatibilityDetector + * @phpstan-type ScanResult array{files: array>, totalIssues: int, criticalIssues: int} + * @phpstan-type ModuleInfo array{name: string, version: string, isHyvaAware: bool} */ class ModuleScanner { @@ -32,7 +36,7 @@ public function __construct( * * @param string $modulePath * @return array Array with structure: ['files' => [], 'totalIssues' => int, 'criticalIssues' => int] - * @phpstan-return array{files: array>, totalIssues: int, criticalIssues: int} + * @phpstan-return ScanResult */ public function scanModule(string $modulePath): array { @@ -176,7 +180,7 @@ public function hasHyvaCompatibilityPackage(string $modulePath): bool * * @param string $modulePath * @return array - * @phpstan-return array{name: string, version: string, isHyvaAware: bool} + * @phpstan-return ModuleInfo */ public function getModuleInfo(string $modulePath): array { From ee2921f6291104e2838dd86f56105b40e452e6c1 Mon Sep 17 00:00:00 2001 From: Thomas Hauschild <7961978+Morgy93@users.noreply.github.com> Date: Wed, 18 Mar 2026 22:52:44 +0100 Subject: [PATCH 07/14] fix: remove CheckCommand.php file --- src/Console/Command/System/CheckCommand.php.new | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/Console/Command/System/CheckCommand.php.new diff --git a/src/Console/Command/System/CheckCommand.php.new b/src/Console/Command/System/CheckCommand.php.new deleted file mode 100644 index e69de29..0000000 From 3b6a9d3a7c293ac9f722eb20f3137bb92a28fa04 Mon Sep 17 00:00:00 2001 From: Thomas Hauschild <7961978+Morgy93@users.noreply.github.com> Date: Wed, 18 Mar 2026 22:53:03 +0100 Subject: [PATCH 08/14] fix: ensure version number is a string in CheckCommand --- src/Console/Command/System/CheckCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Console/Command/System/CheckCommand.php b/src/Console/Command/System/CheckCommand.php index 56d1ab5..9ca26e7 100644 --- a/src/Console/Command/System/CheckCommand.php +++ b/src/Console/Command/System/CheckCommand.php @@ -553,11 +553,11 @@ private function formatSearchEngineVersion(array $info): string return 'Search Engine Available'; } if (isset($version['distribution']) && $version['distribution'] === 'opensearch') { - return 'OpenSearch ' . ($version['number'] ?? ''); + return 'OpenSearch ' . (is_string($version['number']) ? $version['number'] : ''); } if (isset($version['number'])) { - return 'Elasticsearch ' . $version['number']; + return 'Elasticsearch ' . (is_string($version['number']) ? $version['number'] : ''); } return 'Search Engine Available'; From e8641a06976abac642d72a71d037d869db8f58f4 Mon Sep 17 00:00:00 2001 From: Thomas Hauschild <7961978+Morgy93@users.noreply.github.com> Date: Wed, 18 Mar 2026 22:53:53 +0100 Subject: [PATCH 09/14] fix: remove unused import in ThemeList.php --- src/Model/ThemeList.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Model/ThemeList.php b/src/Model/ThemeList.php index 184bc7b..945abd1 100644 --- a/src/Model/ThemeList.php +++ b/src/Model/ThemeList.php @@ -5,7 +5,6 @@ namespace OpenForgeProject\MageForge\Model; use Magento\Framework\View\Design\Theme\ThemeList as MagentoThemeList; -use Magento\Framework\View\Design\ThemeInterface; use Magento\Theme\Model\Theme; class ThemeList From 840d135bac52d5a9aeba44bc9a396dccdbdf1f0c Mon Sep 17 00:00:00 2001 From: Thomas Hauschild <7961978+Morgy93@users.noreply.github.com> Date: Wed, 18 Mar 2026 22:55:08 +0100 Subject: [PATCH 10/14] fix: remove module path from compatibility results --- src/Service/Hyva/CompatibilityChecker.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Service/Hyva/CompatibilityChecker.php b/src/Service/Hyva/CompatibilityChecker.php index 3f57e15..51326ed 100644 --- a/src/Service/Hyva/CompatibilityChecker.php +++ b/src/Service/Hyva/CompatibilityChecker.php @@ -95,7 +95,6 @@ public function check( $hasWarnings = $scanResult['totalIssues'] > $scanResult['criticalIssues']; $results['modules'][$moduleName] = [ - 'path' => $modulePath, 'compatible' => $isCompatible, 'hasWarnings' => $hasWarnings, 'scanResult' => $scanResult, From 64d2ab0a7fe37316f9da147d13be509478079757 Mon Sep 17 00:00:00 2001 From: Thomas Hauschild <7961978+Morgy93@users.noreply.github.com> Date: Wed, 18 Mar 2026 23:03:55 +0100 Subject: [PATCH 11/14] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/Service/Hyva/CompatibilityChecker.php | 24 ++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/Service/Hyva/CompatibilityChecker.php b/src/Service/Hyva/CompatibilityChecker.php index 51326ed..d513639 100644 --- a/src/Service/Hyva/CompatibilityChecker.php +++ b/src/Service/Hyva/CompatibilityChecker.php @@ -9,7 +9,6 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; -// phpcs:disable Generic.Files.LineLength.TooLong /** * Service that orchestrates Hyvä compatibility checking across Magento modules * @@ -19,11 +18,26 @@ * @phpstan-import-type ScanIssue from IncompatibilityDetector * @phpstan-import-type ScanResult from ModuleScanner * @phpstan-import-type ModuleInfo from ModuleScanner - * @phpstan-type ModuleEntry array{compatible: bool, hasWarnings: bool, scanResult: ScanResult, moduleInfo: ModuleInfo} - * @phpstan-type CheckSummary array{total: int, compatible: int, incompatible: int, hyvaAware: int, criticalIssues: int, warningIssues: int} - * @phpstan-type CheckResults array{modules: array, summary: CheckSummary, hasIncompatibilities: bool} + * @phpstan-type ModuleEntry array{ + * compatible: bool, + * hasWarnings: bool, + * scanResult: ScanResult, + * moduleInfo: ModuleInfo + * } + * @phpstan-type CheckSummary array{ + * total: int, + * compatible: int, + * incompatible: int, + * hyvaAware: int, + * criticalIssues: int, + * warningIssues: int + * } + * @phpstan-type CheckResults array{ + * modules: array, + * summary: CheckSummary, + * hasIncompatibilities: bool + * } */ -// phpcs:enable Generic.Files.LineLength.TooLong class CompatibilityChecker { /** From c609da697ba1a8888972870270d0c88208d70654 Mon Sep 17 00:00:00 2001 From: Thomas Hauschild <7961978+Morgy93@users.noreply.github.com> Date: Wed, 18 Mar 2026 23:04:21 +0100 Subject: [PATCH 12/14] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/Console/Command/System/CheckCommand.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Console/Command/System/CheckCommand.php b/src/Console/Command/System/CheckCommand.php index 9ca26e7..774ec50 100644 --- a/src/Console/Command/System/CheckCommand.php +++ b/src/Console/Command/System/CheckCommand.php @@ -673,10 +673,24 @@ private function getDiskSpace(): string $totalSpace = disk_total_space('.'); $freeSpace = disk_free_space('.'); + if ($totalSpace === false || $freeSpace === false) { + return 'Unknown'; + } + + if ($totalSpace <= 0) { + $totalGB = 0.0; + $usedGB = 0.0; + $usedPercent = 0.0; + + return "$usedGB GB / $totalGB GB ($usedPercent%)"; + } + $totalGB = round($totalSpace / 1024 / 1024 / 1024, 2); $freeGB = round($freeSpace / 1024 / 1024 / 1024, 2); $usedGB = round($totalGB - $freeGB, 2); - $usedPercent = round(($usedGB / $totalGB) * 100, 2); + $usedPercent = $totalGB > 0.0 + ? round(($usedGB / $totalGB) * 100, 2) + : 0.0; return "$usedGB GB / $totalGB GB ($usedPercent%)"; } From 5e788cf298afc5846c2531a2d873f512714ba008 Mon Sep 17 00:00:00 2001 From: Thomas Hauschild <7961978+Morgy93@users.noreply.github.com> Date: Wed, 18 Mar 2026 23:04:44 +0100 Subject: [PATCH 13/14] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/Model/ThemeList.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Model/ThemeList.php b/src/Model/ThemeList.php index 945abd1..2eab627 100644 --- a/src/Model/ThemeList.php +++ b/src/Model/ThemeList.php @@ -5,7 +5,7 @@ namespace OpenForgeProject\MageForge\Model; use Magento\Framework\View\Design\Theme\ThemeList as MagentoThemeList; -use Magento\Theme\Model\Theme; +use Magento\Framework\View\Design\ThemeInterface; class ThemeList { @@ -22,11 +22,11 @@ public function __construct( /** * Get all themes * - * @return array + * @return array */ public function getAllThemes(): array { - /** @var array $items */ + /** @var array $items */ $items = $this->magentoThemeList->getItems(); return $items; } From 0af20784de409cc90b58dd68ab2d1c4492512be0 Mon Sep 17 00:00:00 2001 From: Thomas Hauschild <7961978+Morgy93@users.noreply.github.com> Date: Wed, 18 Mar 2026 23:11:14 +0100 Subject: [PATCH 14/14] fix: update type hints for theme parameters --- src/Console/Command/Theme/CleanCommand.php | 8 ++++---- src/Model/ThemeList.php | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Console/Command/Theme/CleanCommand.php b/src/Console/Command/Theme/CleanCommand.php index f6d1760..569c6a2 100644 --- a/src/Console/Command/Theme/CleanCommand.php +++ b/src/Console/Command/Theme/CleanCommand.php @@ -164,7 +164,7 @@ private function selectThemesInteractively(OutputInterface $output): ?array /** * Display available themes for non-interactive environments * - * @param array<\Magento\Theme\Model\Theme> $themes + * @param \Magento\Theme\Model\Theme[] $themes * @return void */ private function displayAvailableThemes(array $themes): void @@ -189,9 +189,9 @@ private function displayAvailableThemes(array $themes): void /** * Prompt user to select themes * - * @param array $options - * @param array<\Magento\Theme\Model\Theme> $themes - * @return array|null + * @param string[] $options + * @param \Magento\Theme\Model\Theme[] $themes + * @return string[]|null */ private function promptForThemes(array $options, array $themes): ?array { diff --git a/src/Model/ThemeList.php b/src/Model/ThemeList.php index 2eab627..939bbcb 100644 --- a/src/Model/ThemeList.php +++ b/src/Model/ThemeList.php @@ -5,7 +5,7 @@ namespace OpenForgeProject\MageForge\Model; use Magento\Framework\View\Design\Theme\ThemeList as MagentoThemeList; -use Magento\Framework\View\Design\ThemeInterface; +use Magento\Theme\Model\Theme; class ThemeList { @@ -22,11 +22,11 @@ public function __construct( /** * Get all themes * - * @return array + * @return array */ public function getAllThemes(): array { - /** @var array $items */ + /** @var array $items */ $items = $this->magentoThemeList->getItems(); return $items; }