diff --git a/src/Console/Command/AbstractCommand.php b/src/Console/Command/AbstractCommand.php index c5b5d60..357a123 100644 --- a/src/Console/Command/AbstractCommand.php +++ b/src/Console/Command/AbstractCommand.php @@ -267,6 +267,9 @@ protected function resetPromptEnvironment(): void /** * Safely get environment variable with sanitization + * + * @param string $name + * @return string|null */ private function getEnvVar(string $name): ?string { @@ -281,6 +284,9 @@ private function getEnvVar(string $name): ?string /** * Securely retrieve environment variable without direct superglobal access + * + * @param string $name + * @return string|null */ private function getSecureEnvironmentValue(string $name): ?string { @@ -329,6 +335,10 @@ private function getCachedEnvironmentVariables(): array /** * Sanitize environment value based on variable type + * + * @param string $name + * @param string $value + * @return string|null */ private function sanitizeEnvironmentValue(string $name, string $value): ?string { @@ -343,6 +353,9 @@ private function sanitizeEnvironmentValue(string $name, string $value): ?string /** * Sanitize numeric values (COLUMNS, LINES) + * + * @param string $value + * @return string|null */ private function sanitizeNumericValue(string $value): ?string { @@ -352,6 +365,9 @@ private function sanitizeNumericValue(string $value): ?string /** * Sanitize terminal type values + * + * @param string $value + * @return string|null */ private function sanitizeTermValue(string $value): ?string { @@ -364,6 +380,9 @@ private function sanitizeTermValue(string $value): ?string /** * Sanitize boolean-like values + * + * @param string $value + * @return string|null */ private function sanitizeBooleanValue(string $value): ?string { @@ -373,6 +392,9 @@ private function sanitizeBooleanValue(string $value): ?string /** * Sanitize alphanumeric values + * + * @param string $value + * @return string|null */ private function sanitizeAlphanumericValue(string $value): ?string { @@ -385,6 +407,9 @@ private function sanitizeAlphanumericValue(string $value): ?string /** * Safely get server variable with sanitization + * + * @param string $name + * @return string|null */ private function getServerVar(string $name): ?string { @@ -403,6 +428,10 @@ private function getServerVar(string $name): ?string /** * Safely set environment variable with validation + * + * @param string $name + * @param string $value + * @return void */ private function setEnvVar(string $name, string $value): void { @@ -419,6 +448,10 @@ private function setEnvVar(string $name, string $value): void /** * Securely store environment variable without direct superglobal access + * + * @param string $name + * @param string $value + * @return void */ private function setSecureEnvironmentValue(string $name, string $value): void { @@ -436,6 +469,9 @@ private function clearEnvironmentCache(): void /** * Securely remove environment variable from cache + * + * @param string $name + * @return void */ private function removeSecureEnvironmentValue(string $name): void { diff --git a/src/Console/Command/Dev/InspectorCommand.php b/src/Console/Command/Dev/InspectorCommand.php index 0fe9674..a7824c2 100644 --- a/src/Console/Command/Dev/InspectorCommand.php +++ b/src/Console/Command/Dev/InspectorCommand.php @@ -22,6 +22,13 @@ class InspectorCommand extends AbstractCommand private const XML_PATH_INSPECTOR_ENABLED = 'dev/mageforge_inspector/enabled'; private const ARGUMENT_ACTION = 'action'; + /** + * @param WriterInterface $configWriter + * @param State $state + * @param CacheManager $cacheManager + * @param ScopeConfigInterface $scopeConfig + * @param string|null $name + */ public function __construct( private readonly WriterInterface $configWriter, private readonly State $state, diff --git a/src/Console/Command/Hyva/CompatibilityCheckCommand.php b/src/Console/Command/Hyva/CompatibilityCheckCommand.php index c2dad3d..452a5b9 100644 --- a/src/Console/Command/Hyva/CompatibilityCheckCommand.php +++ b/src/Console/Command/Hyva/CompatibilityCheckCommand.php @@ -34,12 +34,20 @@ class CompatibilityCheckCommand extends AbstractCommand private const SCOPE_THIRD_PARTY = 'third-party'; private const SCOPE_ALL = 'all'; + /** + * @param CompatibilityChecker $compatibilityChecker + */ public function __construct( private readonly CompatibilityChecker $compatibilityChecker ) { parent::__construct(); } + /** + * Configure command options. + * + * @return void + */ protected function configure(): void { $this->setName($this->getCommandName('hyva', 'compatibility:check')) @@ -71,6 +79,13 @@ protected function configure(): void ); } + /** + * Execute compatibility check command. + * + * @param InputInterface $input + * @param OutputInterface $output + * @return int + */ protected function executeCommand(InputInterface $input, OutputInterface $output): int { // Check if we're in interactive mode (no options provided) @@ -88,6 +103,10 @@ protected function executeCommand(InputInterface $input, OutputInterface $output /** * Run interactive mode with Laravel Prompts + * + * @param InputInterface $input + * @param OutputInterface $output + * @return int */ private function runInteractiveMode(InputInterface $input, OutputInterface $output): int { @@ -168,6 +187,10 @@ private function runInteractiveMode(InputInterface $input, OutputInterface $outp /** * Run direct mode with command line options + * + * @param InputInterface $input + * @param OutputInterface $output + * @return int */ private function runDirectMode(InputInterface $input, OutputInterface $output): int { @@ -183,6 +206,14 @@ private function runDirectMode(InputInterface $input, OutputInterface $output): /** * Run the actual compatibility scan + * + * @param bool $showAll + * @param bool $thirdPartyOnly + * @param bool $includeVendor + * @param bool $detailed + * @param bool $incompatibleOnly + * @param OutputInterface $output + * @return int */ private function runScan( bool $showAll, diff --git a/src/Console/Command/System/CheckCommand.php b/src/Console/Command/System/CheckCommand.php index 884ad6c..a1749e5 100644 --- a/src/Console/Command/System/CheckCommand.php +++ b/src/Console/Command/System/CheckCommand.php @@ -41,7 +41,9 @@ public function __construct( } /** - * {@inheritdoc} + * Configure command. + * + * @return void */ protected function configure(): void { @@ -51,7 +53,11 @@ protected function configure(): void } /** - * {@inheritdoc} + * Execute command. + * + * @param InputInterface $input + * @param OutputInterface $output + * @return int */ protected function executeCommand(InputInterface $input, OutputInterface $output): int { diff --git a/src/Console/Command/System/VersionCommand.php b/src/Console/Command/System/VersionCommand.php index 64392af..b7fe959 100644 --- a/src/Console/Command/System/VersionCommand.php +++ b/src/Console/Command/System/VersionCommand.php @@ -29,7 +29,9 @@ public function __construct( } /** - * {@inheritdoc} + * Configure command. + * + * @return void */ protected function configure(): void { @@ -39,7 +41,11 @@ protected function configure(): void } /** - * {@inheritdoc} + * Execute command. + * + * @param InputInterface $input + * @param OutputInterface $output + * @return int */ protected function executeCommand(InputInterface $input, OutputInterface $output): int { diff --git a/src/Console/Command/Theme/BuildCommand.php b/src/Console/Command/Theme/BuildCommand.php index 6b1e208..19fd134 100644 --- a/src/Console/Command/Theme/BuildCommand.php +++ b/src/Console/Command/Theme/BuildCommand.php @@ -39,7 +39,9 @@ public function __construct( } /** - * {@inheritdoc} + * Configure command. + * + * @return void */ protected function configure(): void { @@ -54,7 +56,11 @@ protected function configure(): void } /** - * {@inheritdoc} + * Execute command. + * + * @param InputInterface $input + * @param OutputInterface $output + * @return int */ protected function executeCommand(InputInterface $input, OutputInterface $output): int { diff --git a/src/Console/Command/Theme/CleanCommand.php b/src/Console/Command/Theme/CleanCommand.php index 1c46226..a4ef033 100644 --- a/src/Console/Command/Theme/CleanCommand.php +++ b/src/Console/Command/Theme/CleanCommand.php @@ -37,7 +37,9 @@ public function __construct( } /** - * {@inheritdoc} + * Configure command. + * + * @return void */ protected function configure(): void { @@ -64,7 +66,11 @@ protected function configure(): void } /** - * {@inheritdoc} + * Execute command. + * + * @param InputInterface $input + * @param OutputInterface $output + * @return int */ protected function executeCommand(InputInterface $input, OutputInterface $output): int { diff --git a/src/Console/Command/Theme/ListCommand.php b/src/Console/Command/Theme/ListCommand.php index ed3839a..a077433 100644 --- a/src/Console/Command/Theme/ListCommand.php +++ b/src/Console/Command/Theme/ListCommand.php @@ -26,7 +26,9 @@ public function __construct( } /** - * {@inheritdoc} + * Configure command. + * + * @return void */ protected function configure(): void { @@ -36,7 +38,11 @@ protected function configure(): void } /** - * {@inheritdoc} + * Execute command. + * + * @param InputInterface $input + * @param OutputInterface $output + * @return int */ protected function executeCommand(InputInterface $input, OutputInterface $output): int { diff --git a/src/Console/Command/Theme/TokensCommand.php b/src/Console/Command/Theme/TokensCommand.php index f6daf36..676638d 100644 --- a/src/Console/Command/Theme/TokensCommand.php +++ b/src/Console/Command/Theme/TokensCommand.php @@ -42,7 +42,9 @@ public function __construct( } /** - * {@inheritdoc} + * Configure command. + * + * @return void */ protected function configure(): void { @@ -57,7 +59,11 @@ protected function configure(): void } /** - * {@inheritdoc} + * Execute command. + * + * @param InputInterface $input + * @param OutputInterface $output + * @return int */ protected function executeCommand(InputInterface $input, OutputInterface $output): int { @@ -86,6 +92,12 @@ protected function executeCommand(InputInterface $input, OutputInterface $output return Cli::RETURN_SUCCESS; } + /** + * Resolve theme code from argument or interactive prompt. + * + * @param string|null $themeCode + * @return string|null + */ private function selectTheme(?string $themeCode): ?string { if (!empty($themeCode)) { @@ -112,6 +124,13 @@ private function selectTheme(?string $themeCode): ?string } } + /** + * Validate that the theme exists and is a Hyva theme. + * + * @param string $themeCode + * @param OutputInterface $output + * @return string|null + */ private function validateHyvaTheme(string $themeCode, OutputInterface $output): ?string { $themePath = $this->themePath->getPath($themeCode); @@ -150,6 +169,13 @@ private function validateHyvaTheme(string $themeCode, OutputInterface $output): return $themePath; } + /** + * Validate that the tailwind directory exists for the theme. + * + * @param string $themePath + * @param string $themeCode + * @return string|null + */ private function validateTailwindDirectory(string $themePath, string $themeCode): ?string { $tailwindPath = rtrim($themePath, '/') . '/web/tailwind'; @@ -167,6 +193,14 @@ private function validateTailwindDirectory(string $themePath, string $themeCode) return $tailwindPath; } + /** + * Run token generation in the tailwind directory. + * + * @param string $tailwindPath + * @param string $themeCode + * @param bool $isVerbose + * @return bool + */ private function generateTokens(string $tailwindPath, string $themeCode, bool $isVerbose): bool { if ($isVerbose) { @@ -197,6 +231,14 @@ private function generateTokens(string $tailwindPath, string $themeCode, bool $i } } + /** + * Report and store generated token output. + * + * @param string $tailwindPath + * @param string $themePath + * @param string $themeCode + * @return void + */ private function handleOutputFile(string $tailwindPath, string $themePath, string $themeCode): void { $isVendorTheme = str_contains($themePath, '/vendor/'); @@ -215,6 +257,13 @@ private function handleOutputFile(string $tailwindPath, string $themePath, strin $this->io->newLine(); } + /** + * Copy generated tokens to var/generated for vendor themes. + * + * @param string $sourceFilePath + * @param string $themeCode + * @return string + */ private function copyToVarGenerated(string $sourceFilePath, string $themeCode): string { $currentDir = getcwd(); diff --git a/src/Console/Command/Theme/WatchCommand.php b/src/Console/Command/Theme/WatchCommand.php index 91d1800..e15ea73 100644 --- a/src/Console/Command/Theme/WatchCommand.php +++ b/src/Console/Command/Theme/WatchCommand.php @@ -36,9 +36,11 @@ public function __construct( } /** - * {@inheritdoc} + * Configure command. + * + * @return void */ - protected function configure() + protected function configure(): void { $this->setName($this->getCommandName('theme', 'watch')) ->setDescription('Watches theme files for changes and rebuilds them automatically') @@ -57,7 +59,11 @@ protected function configure() } /** - * {@inheritdoc} + * Execute command. + * + * @param InputInterface $input + * @param OutputInterface $output + * @return int */ protected function executeCommand(InputInterface $input, OutputInterface $output): int { diff --git a/src/Model/Config/Source/InspectorTheme.php b/src/Model/Config/Source/InspectorTheme.php index df7a58e..bd01e19 100644 --- a/src/Model/Config/Source/InspectorTheme.php +++ b/src/Model/Config/Source/InspectorTheme.php @@ -9,6 +9,8 @@ class InspectorTheme implements OptionSourceInterface { /** + * Return available inspector themes as options. + * * @return array> */ public function toOptionArray(): array diff --git a/src/Model/TemplateEngine/Decorator/InspectorHints.php b/src/Model/TemplateEngine/Decorator/InspectorHints.php index e738330..2090f21 100644 --- a/src/Model/TemplateEngine/Decorator/InspectorHints.php +++ b/src/Model/TemplateEngine/Decorator/InspectorHints.php @@ -17,6 +17,9 @@ */ class InspectorHints implements TemplateEngineInterface { + /** + * Magento root path resolved at runtime. + */ private string $magentoRoot; /** diff --git a/src/Model/TemplateEngine/Plugin/InspectorHints.php b/src/Model/TemplateEngine/Plugin/InspectorHints.php index 751206d..d715105 100644 --- a/src/Model/TemplateEngine/Plugin/InspectorHints.php +++ b/src/Model/TemplateEngine/Plugin/InspectorHints.php @@ -22,6 +22,13 @@ class InspectorHints { private const XML_PATH_INSPECTOR_ENABLED = 'dev/mageforge_inspector/enabled'; + /** + * @param ScopeConfigInterface $scopeConfig + * @param StoreManagerInterface $storeManager + * @param DevHelper $devHelper + * @param InspectorHintsFactory $inspectorHintsFactory + * @param State $state + */ public function __construct( private readonly ScopeConfigInterface $scopeConfig, private readonly StoreManagerInterface $storeManager, diff --git a/src/Model/ThemePath.php b/src/Model/ThemePath.php index e4c739e..1048564 100644 --- a/src/Model/ThemePath.php +++ b/src/Model/ThemePath.php @@ -9,11 +9,20 @@ class ThemePath { + /** + * @param ComponentRegistrarInterface $componentRegistrar + */ public function __construct( private readonly ComponentRegistrarInterface $componentRegistrar ) { } + /** + * Get the filesystem path for a theme code. + * + * @param string $themeCode + * @return string|null + */ public function getPath(string $themeCode): ?string { $registeredThemes = $this->componentRegistrar->getPaths(ComponentRegistrar::THEME); diff --git a/src/Service/CacheCleaner.php b/src/Service/CacheCleaner.php index be1f14c..fecfbb1 100644 --- a/src/Service/CacheCleaner.php +++ b/src/Service/CacheCleaner.php @@ -9,11 +9,21 @@ class CacheCleaner { + /** + * @param Shell $shell + */ public function __construct( private readonly Shell $shell ) { } + /** + * Clean Magento cache types used by frontend builds. + * + * @param SymfonyStyle $io + * @param bool $isVerbose + * @return bool + */ public function clean(SymfonyStyle $io, bool $isVerbose): bool { try { diff --git a/src/Service/DependencyChecker.php b/src/Service/DependencyChecker.php index 6a03d67..1367992 100644 --- a/src/Service/DependencyChecker.php +++ b/src/Service/DependencyChecker.php @@ -5,8 +5,8 @@ namespace OpenForgeProject\MageForge\Service; use Magento\Framework\Filesystem\Driver\File; -use Symfony\Component\Console\Style\SymfonyStyle; use Magento\Framework\Shell; +use Symfony\Component\Console\Style\SymfonyStyle; class DependencyChecker { @@ -16,12 +16,23 @@ class DependencyChecker private const GRUNTFILE_SAMPLE = 'Gruntfile.js.sample'; private const NODE_MODULES = 'node_modules'; + /** + * @param File $fileDriver + * @param Shell $shell + */ public function __construct( private readonly File $fileDriver, private readonly Shell $shell ) { } + /** + * Verify Magento frontend build dependencies and prompt for fixes. + * + * @param SymfonyStyle $io + * @param bool $isVerbose + * @return bool + */ public function checkDependencies(SymfonyStyle $io, bool $isVerbose): bool { if (!$this->checkPackageJson($io, $isVerbose) || !$this->checkNodeModules($io, $isVerbose)) { @@ -33,6 +44,13 @@ public function checkDependencies(SymfonyStyle $io, bool $isVerbose): bool return true; } + /** + * Ensure package.json exists, offering to copy from sample if needed. + * + * @param SymfonyStyle $io + * @param bool $isVerbose + * @return bool + */ private function checkPackageJson(SymfonyStyle $io, bool $isVerbose): bool { if (!$this->fileDriver->isFile(self::PACKAGE_JSON)) { @@ -62,6 +80,13 @@ private function checkPackageJson(SymfonyStyle $io, bool $isVerbose): bool return true; } + /** + * Ensure node_modules exists, offering to run npm install if needed. + * + * @param SymfonyStyle $io + * @param bool $isVerbose + * @return bool + */ private function checkNodeModules(SymfonyStyle $io, bool $isVerbose): bool { if (!$this->fileDriver->isDirectory(self::NODE_MODULES)) { @@ -92,6 +117,15 @@ private function checkNodeModules(SymfonyStyle $io, bool $isVerbose): bool return true; } + /** + * Ensure a file exists, offering to copy from a sample if present. + * + * @param SymfonyStyle $io + * @param string $file + * @param string $sampleFile + * @param bool $isVerbose + * @return bool + */ private function checkFile(SymfonyStyle $io, string $file, string $sampleFile, bool $isVerbose): bool { if (!$this->fileDriver->isFile($file)) { diff --git a/src/Service/GruntTaskRunner.php b/src/Service/GruntTaskRunner.php index 395ec66..375cd5d 100644 --- a/src/Service/GruntTaskRunner.php +++ b/src/Service/GruntTaskRunner.php @@ -5,18 +5,29 @@ namespace OpenForgeProject\MageForge\Service; use Magento\Framework\Shell; -use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; class GruntTaskRunner { private const GRUNT_PATH = 'node_modules/.bin/grunt'; + /** + * @param Shell $shell + */ public function __construct( private readonly Shell $shell ) { } + /** + * Run the standard Grunt clean and less tasks. + * + * @param SymfonyStyle $io + * @param OutputInterface $output + * @param bool $isVerbose + * @return bool + */ public function runTasks( SymfonyStyle $io, OutputInterface $output, diff --git a/src/Service/Hyva/CompatibilityChecker.php b/src/Service/Hyva/CompatibilityChecker.php index f5337d7..232ec18 100644 --- a/src/Service/Hyva/CompatibilityChecker.php +++ b/src/Service/Hyva/CompatibilityChecker.php @@ -17,6 +17,10 @@ */ class CompatibilityChecker { + /** + * @param ComponentRegistrarInterface $componentRegistrar + * @param ModuleScanner $moduleScanner + */ public function __construct( private readonly ComponentRegistrarInterface $componentRegistrar, private readonly ModuleScanner $moduleScanner @@ -54,7 +58,10 @@ public function check( 'hasIncompatibilities' => false, ]; - $io->text(sprintf('Scanning %d modules for Hyvä compatibility...', count($modules))); + $io->text(sprintf( + 'Scanning %d modules for Hyvä compatibility...', + count($modules) + )); $io->newLine(); foreach ($modules as $moduleName => $modulePath) { @@ -110,6 +117,9 @@ public function check( /** * Check if module is a vendor module + * + * @param string $modulePath + * @return bool */ private function isVendorModule(string $modulePath): bool { @@ -118,6 +128,9 @@ private function isVendorModule(string $modulePath): bool /** * Check if module is a core Magento module + * + * @param string $moduleName + * @return bool */ private function isMagentoModule(string $moduleName): bool { @@ -155,6 +168,7 @@ public function formatResultsForDisplay(array $results, bool $showAll = false): * Get status display string with colors * * @param array $moduleData + * @return string */ private function getStatusDisplay(array $moduleData): string { @@ -177,6 +191,7 @@ private function getStatusDisplay(array $moduleData): string * Get issues display string * * @param array $moduleData + * @return string */ private function getIssuesDisplay(array $moduleData): string { diff --git a/src/Service/Hyva/IncompatibilityDetector.php b/src/Service/Hyva/IncompatibilityDetector.php index b5700c6..9cc1275 100644 --- a/src/Service/Hyva/IncompatibilityDetector.php +++ b/src/Service/Hyva/IncompatibilityDetector.php @@ -94,6 +94,9 @@ class IncompatibilityDetector ], ]; + /** + * @param File $fileDriver + */ public function __construct( private readonly File $fileDriver ) { @@ -102,6 +105,7 @@ public function __construct( /** * Detect incompatibilities in a file * + * @param string $filePath * @return array> Array of issues with keys: pattern, description, severity, line */ public function detectInFile(string $filePath): array @@ -129,6 +133,9 @@ public function detectInFile(string $filePath): array /** * Map file extension to pattern type + * + * @param string $extension + * @return string */ private function mapExtensionToType(string $extension): string { @@ -169,6 +176,9 @@ private function scanContentForPatterns(array $lines, array $patterns): array /** * Get severity color for console output + * + * @param string $severity + * @return string */ public function getSeverityColor(string $severity): string { @@ -181,6 +191,9 @@ public function getSeverityColor(string $severity): string /** * Get severity symbol + * + * @param string $severity + * @return string */ public function getSeveritySymbol(string $severity): string { diff --git a/src/Service/Hyva/ModuleScanner.php b/src/Service/Hyva/ModuleScanner.php index 8b7d7e3..e3f35e7 100644 --- a/src/Service/Hyva/ModuleScanner.php +++ b/src/Service/Hyva/ModuleScanner.php @@ -17,6 +17,10 @@ class ModuleScanner private const SCAN_EXTENSIONS = ['js', 'xml', 'phtml']; private const EXCLUDE_DIRECTORIES = ['Test', 'tests', 'node_modules', 'vendor']; + /** + * @param File $fileDriver + * @param IncompatibilityDetector $incompatibilityDetector + */ public function __construct( private readonly File $fileDriver, private readonly IncompatibilityDetector $incompatibilityDetector @@ -26,6 +30,7 @@ public function __construct( /** * Scan a module directory for compatibility issues * + * @param string $modulePath * @return array Array with structure: ['files' => [], 'totalIssues' => int, 'criticalIssues' => int] */ public function scanModule(string $modulePath): array @@ -66,6 +71,7 @@ public function scanModule(string $modulePath): array /** * Recursively find all relevant files in a directory * + * @param string $directory * @return array */ private function findRelevantFiles(string $directory): array @@ -134,6 +140,9 @@ private function isHyvaCompatibilityPackage(array $composerData): bool /** * Check if module has Hyvä compatibility package (public wrapper) + * + * @param string $modulePath + * @return bool */ public function hasHyvaCompatibilityPackage(string $modulePath): bool { @@ -168,6 +177,7 @@ public function hasHyvaCompatibilityPackage(string $modulePath): bool /** * Get module info from composer.json * + * @param string $modulePath * @return array */ public function getModuleInfo(string $modulePath): array diff --git a/src/Service/Inspector/Cache/BlockCacheCollector.php b/src/Service/Inspector/Cache/BlockCacheCollector.php index 0973338..8601ff1 100644 --- a/src/Service/Inspector/Cache/BlockCacheCollector.php +++ b/src/Service/Inspector/Cache/BlockCacheCollector.php @@ -12,6 +12,33 @@ * * Measures render time and extracts cache configuration with strict type safety (PHPStan Level 8). * + * @phpstan-type CacheInfo array{ + * cacheable: bool, + * lifetime: int|null, + * cacheKey: string, + * cacheTags: array, + * pageCacheable: bool + * } + * @phpstan-type RenderMetrics array{ + * renderTimeMs: float, + * startTime: int, + * endTime: int + * } + * @phpstan-type PerformanceExport array{ + * renderTime: string, + * timestamp: int + * } + * @phpstan-type CacheExport array{ + * cacheable: bool, + * lifetime: int|null, + * key: string, + * tags: array, + * pageCacheable: bool + * } + * @phpstan-type FormattedMetrics array{ + * performance: PerformanceExport, + * cache: CacheExport + * } */ class BlockCacheCollector { @@ -22,6 +49,7 @@ public function __construct( private readonly LayoutInterface $layout ) { } + /** * Get cache information from block * @@ -29,7 +57,8 @@ public function __construct( * to satisfy PHPStan Level 8 requirements. * * @param BlockInterface $block - * @return array{cacheable: bool, lifetime: int|null, cacheKey: string, cacheTags: array, pageCacheable: bool} + * @return array + * @phpstan-return CacheInfo */ public function getCacheInfo(BlockInterface $block): array { @@ -168,7 +197,7 @@ private function resolveCacheTags(BlockInterface $block): array * Check if current page is cacheable * * Checks layout configuration to determine if page has cacheable="false" attribute. - * If ANY block on the page is marked as non-cacheable in layout XML, the entire page is non-cacheable. + * If any block on the page is marked as non-cacheable in layout XML, the page is non-cacheable. * * @return bool True if page is cacheable, false otherwise */ @@ -207,16 +236,22 @@ private function isPageCacheable(): bool /** * Format metrics for JSON export to frontend * - * @param array{renderTimeMs: float, startTime: int, endTime: int} $renderMetrics - * @param array{cacheable: bool, lifetime: int|null, cacheKey: string, cacheTags: array, pageCacheable: bool} $cacheMetrics - * @return array{performance: array{renderTime: string, timestamp: int}, cache: array{cacheable: bool, lifetime: int|null, key: string, tags: array, pageCacheable: bool}} + * @param array $renderMetrics + * @param array $cacheMetrics + * @return array + * @phpstan-param RenderMetrics $renderMetrics + * @phpstan-param CacheInfo $cacheMetrics + * @phpstan-return FormattedMetrics */ public function formatMetricsForJson(array $renderMetrics, array $cacheMetrics): array { + $timestamp = (int) ($renderMetrics['startTime'] / 1_000_000_000); + return [ 'performance' => [ 'renderTime' => number_format($renderMetrics['renderTimeMs'], 2), - 'timestamp' => (int)($renderMetrics['startTime'] / 1_000_000_000), // Convert ns to seconds + // Convert ns to seconds. + 'timestamp' => $timestamp, ], 'cache' => [ 'cacheable' => $cacheMetrics['cacheable'], diff --git a/src/Service/NodePackageManager.php b/src/Service/NodePackageManager.php index 22a9e79..f286c4f 100644 --- a/src/Service/NodePackageManager.php +++ b/src/Service/NodePackageManager.php @@ -13,6 +13,10 @@ */ class NodePackageManager { + /** + * @param Shell $shell + * @param FileDriver $fileDriver + */ public function __construct( private readonly Shell $shell, private readonly FileDriver $fileDriver diff --git a/src/Service/NodeSetupValidator.php b/src/Service/NodeSetupValidator.php index 5bfac02..25bfced 100644 --- a/src/Service/NodeSetupValidator.php +++ b/src/Service/NodeSetupValidator.php @@ -7,6 +7,7 @@ use Magento\Framework\Filesystem\Driver\File as FileDriver; use Symfony\Component\Console\Style\SymfonyStyle; use function Laravel\Prompts\confirm; + /** * Service for validating and restoring Node.js setup files for Magento Standard themes */ diff --git a/src/Service/StandardThemeBuilder.php b/src/Service/StandardThemeBuilder.php index 27d2230..f6e0980 100644 --- a/src/Service/StandardThemeBuilder.php +++ b/src/Service/StandardThemeBuilder.php @@ -9,6 +9,13 @@ class StandardThemeBuilder { + /** + * Create a standard theme builder. + * + * @param DependencyChecker $dependencyChecker + * @param GruntTaskRunner $gruntTaskRunner + * @param StaticContentDeployer $staticContentDeployer + */ public function __construct( private readonly DependencyChecker $dependencyChecker, private readonly GruntTaskRunner $gruntTaskRunner, @@ -17,6 +24,8 @@ public function __construct( } /** + * Build assets for a standard Magento theme. + * * @param string $themeCode * @param SymfonyStyle $io * @param OutputInterface $output diff --git a/src/Service/StaticContentCleaner.php b/src/Service/StaticContentCleaner.php index 311a261..eacaa60 100644 --- a/src/Service/StaticContentCleaner.php +++ b/src/Service/StaticContentCleaner.php @@ -17,6 +17,10 @@ */ class StaticContentCleaner { + /** + * @param State $state + * @param ThemeCleaner $themeCleaner + */ public function __construct( private readonly State $state, private readonly ThemeCleaner $themeCleaner diff --git a/src/Service/StaticContentDeployer.php b/src/Service/StaticContentDeployer.php index 5d99bae..49b2f24 100644 --- a/src/Service/StaticContentDeployer.php +++ b/src/Service/StaticContentDeployer.php @@ -11,12 +11,25 @@ class StaticContentDeployer { + /** + * @param Shell $shell + * @param State $state + */ public function __construct( private readonly Shell $shell, private readonly State $state ) { } + /** + * Deploy static content for a theme when not in developer mode. + * + * @param string $themeCode + * @param SymfonyStyle $io + * @param OutputInterface $output + * @param bool $isVerbose + * @return bool + */ public function deploy( string $themeCode, SymfonyStyle $io, diff --git a/src/Service/SymlinkCleaner.php b/src/Service/SymlinkCleaner.php index cd7376b..036da19 100644 --- a/src/Service/SymlinkCleaner.php +++ b/src/Service/SymlinkCleaner.php @@ -17,6 +17,10 @@ */ class SymlinkCleaner { + /** + * @param File $fileDriver + * @param State $state + */ public function __construct( private readonly File $fileDriver, private readonly State $state diff --git a/src/Service/ThemeBuilder/BuilderFactory.php b/src/Service/ThemeBuilder/BuilderFactory.php index b1e071f..2f8412a 100644 --- a/src/Service/ThemeBuilder/BuilderFactory.php +++ b/src/Service/ThemeBuilder/BuilderFactory.php @@ -9,11 +9,23 @@ class BuilderFactory /** @var array */ private array $builders = []; + /** + * Register a builder by name. + * + * @param BuilderInterface $builder + * @return void + */ public function addBuilder(BuilderInterface $builder): void { $this->builders[$builder->getName()] = $builder; } + /** + * Create a builder by type name. + * + * @param string $type + * @return BuilderInterface + */ public function create(string $type): BuilderInterface { if (!isset($this->builders[$type])) { @@ -24,6 +36,8 @@ public function create(string $type): BuilderInterface } /** + * Get a list of available builder names. + * * @return array */ public function getAvailableBuilders(): array diff --git a/src/Service/ThemeBuilder/BuilderInterface.php b/src/Service/ThemeBuilder/BuilderInterface.php index 8469960..266f3cb 100644 --- a/src/Service/ThemeBuilder/BuilderInterface.php +++ b/src/Service/ThemeBuilder/BuilderInterface.php @@ -9,9 +9,70 @@ interface BuilderInterface { + /** + * Detect whether the builder can handle the theme at the given path. + * + * @param string $themePath + * @return bool + */ public function detect(string $themePath): bool; - public function build(string $themeCode, string $themePath, SymfonyStyle $io, OutputInterface $output, bool $isVerbose): bool; + + /** + * Build the theme assets. + * + * @param string $themeCode + * @param string $themePath + * @param SymfonyStyle $io + * @param OutputInterface $output + * @param bool $isVerbose + * @return bool + */ + public function build( + string $themeCode, + string $themePath, + SymfonyStyle $io, + OutputInterface $output, + bool $isVerbose + ): bool; + + /** + * Get the builder name used for registration. + * + * @return string + */ public function getName(): string; - public function autoRepair(string $themePath, SymfonyStyle $io, OutputInterface $output, bool $isVerbose): bool; - public function watch(string $themeCode, string $themePath, SymfonyStyle $io, OutputInterface $output, bool $isVerbose): bool; + + /** + * Repair missing dependencies or setup prior to build. + * + * @param string $themePath + * @param SymfonyStyle $io + * @param OutputInterface $output + * @param bool $isVerbose + * @return bool + */ + public function autoRepair( + string $themePath, + SymfonyStyle $io, + OutputInterface $output, + bool $isVerbose + ): bool; + + /** + * Run the theme watch process. + * + * @param string $themeCode + * @param string $themePath + * @param SymfonyStyle $io + * @param OutputInterface $output + * @param bool $isVerbose + * @return bool + */ + public function watch( + string $themeCode, + string $themePath, + SymfonyStyle $io, + OutputInterface $output, + bool $isVerbose + ): bool; } diff --git a/src/Service/ThemeBuilder/BuilderPool.php b/src/Service/ThemeBuilder/BuilderPool.php index 1633b82..04259ff 100644 --- a/src/Service/ThemeBuilder/BuilderPool.php +++ b/src/Service/ThemeBuilder/BuilderPool.php @@ -14,6 +14,12 @@ public function __construct( ) { } + /** + * Get the first builder that matches the theme path. + * + * @param string $themePath + * @return BuilderInterface|null + */ public function getBuilder(string $themePath): ?BuilderInterface { foreach ($this->builders as $builder) { @@ -26,6 +32,8 @@ public function getBuilder(string $themePath): ?BuilderInterface } /** + * Get all registered builders. + * * @return BuilderInterface[] */ public function getBuilders(): array diff --git a/src/Service/ThemeBuilder/HyvaThemes/Builder.php b/src/Service/ThemeBuilder/HyvaThemes/Builder.php index 9903fe9..fe6a110 100644 --- a/src/Service/ThemeBuilder/HyvaThemes/Builder.php +++ b/src/Service/ThemeBuilder/HyvaThemes/Builder.php @@ -19,6 +19,15 @@ class Builder implements BuilderInterface { private const THEME_NAME = 'HyvaThemes'; + /** + * @param Shell $shell + * @param File $fileDriver + * @param StaticContentDeployer $staticContentDeployer + * @param StaticContentCleaner $staticContentCleaner + * @param CacheCleaner $cacheCleaner + * @param SymlinkCleaner $symlinkCleaner + * @param NodePackageManager $nodePackageManager + */ public function __construct( private readonly Shell $shell, private readonly File $fileDriver, @@ -30,6 +39,12 @@ public function __construct( ) { } + /** + * Detect whether the theme is a Hyva theme. + * + * @param string $themePath + * @return bool + */ public function detect(string $themePath): bool { // normalize path @@ -60,14 +75,35 @@ public function detect(string $themePath): bool return false; } - public function build(string $themeCode, string $themePath, SymfonyStyle $io, OutputInterface $output, bool $isVerbose): bool + /** + * Build Hyva theme assets. + * + * @param string $themeCode + * @param string $themePath + * @param SymfonyStyle $io + * @param OutputInterface $output + * @param bool $isVerbose + * @return bool + */ + public function build( + string $themeCode, + string $themePath, + SymfonyStyle $io, + OutputInterface $output, + bool $isVerbose + ): bool { if (!$this->detect($themePath)) { return false; } // Clean static content if in developer mode - if (!$this->staticContentCleaner->cleanIfNeeded($themeCode, $io, $output, $isVerbose)) { + if (!$this->staticContentCleaner->cleanIfNeeded( + $themeCode, + $io, + $output, + $isVerbose + )) { return false; } @@ -89,7 +125,12 @@ public function build(string $themeCode, string $themePath, SymfonyStyle $io, Ou } // Deploy static content - if (!$this->staticContentDeployer->deploy($themeCode, $io, $output, $isVerbose)) { + if (!$this->staticContentDeployer->deploy( + $themeCode, + $io, + $output, + $isVerbose + )) { return false; } @@ -99,6 +140,10 @@ public function build(string $themeCode, string $themePath, SymfonyStyle $io, Ou /** * Generate Hyva configuration + * + * @param SymfonyStyle $io + * @param bool $isVerbose + * @return bool */ private function generateHyvaConfig(SymfonyStyle $io, bool $isVerbose): bool { @@ -119,6 +164,11 @@ private function generateHyvaConfig(SymfonyStyle $io, bool $isVerbose): bool /** * Build the Hyva theme + * + * @param string $themePath + * @param SymfonyStyle $io + * @param bool $isVerbose + * @return bool */ private function buildTheme(string $themePath, SymfonyStyle $io, bool $isVerbose): bool { @@ -155,6 +205,15 @@ private function buildTheme(string $themePath, SymfonyStyle $io, bool $isVerbose } } + /** + * Validate and repair Node dependencies for Hyva theme. + * + * @param string $themePath + * @param SymfonyStyle $io + * @param OutputInterface $output + * @param bool $isVerbose + * @return bool + */ public function autoRepair(string $themePath, SymfonyStyle $io, OutputInterface $output, bool $isVerbose): bool { $tailwindPath = rtrim($themePath, '/') . '/web/tailwind'; @@ -164,7 +223,11 @@ public function autoRepair(string $themePath, SymfonyStyle $io, OutputInterface if ($isVerbose) { $io->warning('Node modules out of sync or missing. Installing dependencies...'); } - if (!$this->nodePackageManager->installNodeModules($tailwindPath, $io, $isVerbose)) { + if (!$this->nodePackageManager->installNodeModules( + $tailwindPath, + $io, + $isVerbose + )) { return false; } } @@ -177,14 +240,35 @@ public function autoRepair(string $themePath, SymfonyStyle $io, OutputInterface return true; } - public function watch(string $themeCode, string $themePath, SymfonyStyle $io, OutputInterface $output, bool $isVerbose): bool + /** + * Run watch mode for Hyva theme assets. + * + * @param string $themeCode + * @param string $themePath + * @param SymfonyStyle $io + * @param OutputInterface $output + * @param bool $isVerbose + * @return bool + */ + public function watch( + string $themeCode, + string $themePath, + SymfonyStyle $io, + OutputInterface $output, + bool $isVerbose + ): bool { if (!$this->detect($themePath)) { return false; } // Clean static content if in developer mode - if (!$this->staticContentCleaner->cleanIfNeeded($themeCode, $io, $output, $isVerbose)) { + if (!$this->staticContentCleaner->cleanIfNeeded( + $themeCode, + $io, + $output, + $isVerbose + )) { return false; } @@ -223,6 +307,11 @@ public function watch(string $themeCode, string $themePath, SymfonyStyle $io, Ou return true; } + /** + * Get the builder name. + * + * @return string + */ public function getName(): string { return self::THEME_NAME; diff --git a/src/Service/ThemeBuilder/MagentoStandard/Builder.php b/src/Service/ThemeBuilder/MagentoStandard/Builder.php index ce1db8d..664abad 100644 --- a/src/Service/ThemeBuilder/MagentoStandard/Builder.php +++ b/src/Service/ThemeBuilder/MagentoStandard/Builder.php @@ -9,7 +9,6 @@ use OpenForgeProject\MageForge\Service\CacheCleaner; use OpenForgeProject\MageForge\Service\GruntTaskRunner; use OpenForgeProject\MageForge\Service\NodePackageManager; -use OpenForgeProject\MageForge\Service\NodeSetupValidator; use OpenForgeProject\MageForge\Service\StaticContentCleaner; use OpenForgeProject\MageForge\Service\StaticContentDeployer; use OpenForgeProject\MageForge\Service\SymlinkCleaner; @@ -21,6 +20,16 @@ class Builder implements BuilderInterface { private const THEME_NAME = 'MagentoStandard'; + /** + * @param Shell $shell + * @param File $fileDriver + * @param StaticContentDeployer $staticContentDeployer + * @param StaticContentCleaner $staticContentCleaner + * @param CacheCleaner $cacheCleaner + * @param SymlinkCleaner $symlinkCleaner + * @param NodePackageManager $nodePackageManager + * @param GruntTaskRunner $gruntTaskRunner + */ public function __construct( private readonly Shell $shell, private readonly File $fileDriver, @@ -29,11 +38,16 @@ public function __construct( private readonly CacheCleaner $cacheCleaner, private readonly SymlinkCleaner $symlinkCleaner, private readonly NodePackageManager $nodePackageManager, - private readonly GruntTaskRunner $gruntTaskRunner, - private readonly NodeSetupValidator $nodeSetupValidator + private readonly GruntTaskRunner $gruntTaskRunner ) { } + /** + * Detect whether the theme is a standard Magento theme. + * + * @param string $themePath + * @return bool + */ public function detect(string $themePath): bool { // normalize path @@ -45,14 +59,34 @@ public function detect(string $themePath): bool && !$this->fileDriver->isExists($themePath . '/web/tailwind'); } - public function build(string $themeCode, string $themePath, SymfonyStyle $io, OutputInterface $output, bool $isVerbose): bool - { + /** + * Build Magento standard theme assets. + * + * @param string $themeCode + * @param string $themePath + * @param SymfonyStyle $io + * @param OutputInterface $output + * @param bool $isVerbose + * @return bool + */ + public function build( + string $themeCode, + string $themePath, + SymfonyStyle $io, + OutputInterface $output, + bool $isVerbose + ): bool { if (!$this->detect($themePath)) { return false; } // Clean static content if in developer mode - if (!$this->staticContentCleaner->cleanIfNeeded($themeCode, $io, $output, $isVerbose)) { + if (!$this->staticContentCleaner->cleanIfNeeded( + $themeCode, + $io, + $output, + $isVerbose + )) { return false; } @@ -85,6 +119,12 @@ public function build(string $themeCode, string $themePath, SymfonyStyle $io, Ou /** * Process Node.js and Grunt setup + * + * @param string $themePath + * @param SymfonyStyle $io + * @param OutputInterface $output + * @param bool $isVerbose + * @return bool */ private function processNodeSetup( string $themePath, @@ -92,13 +132,6 @@ private function processNodeSetup( OutputInterface $output, bool $isVerbose ): bool { - $rootPath = '.'; - - // Validate and restore Node.js setup files if needed - if (!$this->nodeSetupValidator->validateAndRestore($rootPath, $io, $isVerbose)) { - return false; - } - // Check if Node/Grunt setup exists if (!$this->autoRepair($themePath, $io, $output, $isVerbose)) { return false; @@ -113,6 +146,15 @@ private function processNodeSetup( return $this->gruntTaskRunner->runTasks($io, $output, $isVerbose); } + /** + * Validate and repair Node/Grunt dependencies for the theme. + * + * @param string $themePath + * @param SymfonyStyle $io + * @param OutputInterface $output + * @param bool $isVerbose + * @return bool + */ public function autoRepair(string $themePath, SymfonyStyle $io, OutputInterface $output, bool $isVerbose): bool { $rootPath = '.'; @@ -140,10 +182,12 @@ public function autoRepair(string $themePath, SymfonyStyle $io, OutputInterface return true; } - - /** * Install Grunt if it's missing + * + * @param SymfonyStyle $io + * @param bool $isVerbose + * @return bool */ private function installGruntIfMissing(SymfonyStyle $io, bool $isVerbose): bool { @@ -172,6 +216,9 @@ private function installGruntIfMissing(SymfonyStyle $io, bool $isVerbose): bool /** * Check for outdated packages and report them + * + * @param SymfonyStyle $io + * @return void */ private function checkOutdatedPackages(SymfonyStyle $io): void { @@ -186,26 +233,52 @@ private function checkOutdatedPackages(SymfonyStyle $io): void } } - public function watch(string $themeCode, string $themePath, SymfonyStyle $io, OutputInterface $output, bool $isVerbose): bool - { + /** + * Run watch mode for Magento standard theme assets. + * + * @param string $themeCode + * @param string $themePath + * @param SymfonyStyle $io + * @param OutputInterface $output + * @param bool $isVerbose + * @return bool + */ + public function watch( + string $themeCode, + string $themePath, + SymfonyStyle $io, + OutputInterface $output, + bool $isVerbose + ): bool { if (!$this->detect($themePath)) { return false; } // Vendor themes cannot be watched (read-only) if ($this->isVendorTheme($themePath)) { - $io->error('Watch mode is not supported for vendor themes. Vendor themes are read-only and should have pre-built assets.'); + $io->error( + 'Watch mode is not supported for vendor themes. Vendor themes are read-only and ' + . 'should have pre-built assets.' + ); return false; } // Check if Node/Grunt setup is intentionally absent if (!$this->hasNodeSetup()) { - $io->error('Watch mode requires Node.js/Grunt setup. No package.json, package-lock.json, node_modules, or grunt-config.json found.'); + $io->error( + 'Watch mode requires Node.js/Grunt setup. No package.json, package-lock.json, ' + . 'node_modules, or grunt-config.json found.' + ); return false; } // Clean static content if in developer mode - if (!$this->staticContentCleaner->cleanIfNeeded($themeCode, $io, $output, $isVerbose)) { + if (!$this->staticContentCleaner->cleanIfNeeded( + $themeCode, + $io, + $output, + $isVerbose + )) { return false; } @@ -237,6 +310,11 @@ public function watch(string $themeCode, string $themePath, SymfonyStyle $io, Ou return true; } + /** + * Get the builder name. + * + * @return string + */ public function getName(): string { return self::THEME_NAME; @@ -253,10 +331,20 @@ private function hasNodeSetup(): bool { $rootPath = '.'; - return $this->fileDriver->isExists($rootPath . '/package.json') - || $this->fileDriver->isExists($rootPath . '/package-lock.json') - || $this->fileDriver->isExists($rootPath . '/gruntfile.js') - || $this->fileDriver->isExists($rootPath . '/grunt-config.json'); + $files = [ + 'package.json', + 'package-lock.json', + 'gruntfile.js', + 'grunt-config.json', + ]; + + foreach ($files as $file) { + if ($this->fileDriver->isExists($rootPath . '/' . $file)) { + return true; + } + } + + return false; } /** diff --git a/src/Service/ThemeBuilder/TailwindCSS/Builder.php b/src/Service/ThemeBuilder/TailwindCSS/Builder.php index 0f40b56..9e000cb 100644 --- a/src/Service/ThemeBuilder/TailwindCSS/Builder.php +++ b/src/Service/ThemeBuilder/TailwindCSS/Builder.php @@ -19,6 +19,15 @@ class Builder implements BuilderInterface { private const THEME_NAME = 'TailwindCSS'; + /** + * @param Shell $shell + * @param File $fileDriver + * @param StaticContentDeployer $staticContentDeployer + * @param StaticContentCleaner $staticContentCleaner + * @param CacheCleaner $cacheCleaner + * @param SymlinkCleaner $symlinkCleaner + * @param NodePackageManager $nodePackageManager + */ public function __construct( private readonly Shell $shell, private readonly File $fileDriver, @@ -30,6 +39,12 @@ public function __construct( ) { } + /** + * Detect whether the theme is a TailwindCSS theme (non-Hyva). + * + * @param string $themePath + * @return bool + */ public function detect(string $themePath): bool { // normalize path @@ -60,14 +75,34 @@ public function detect(string $themePath): bool return false; } - public function build(string $themeCode, string $themePath, SymfonyStyle $io, OutputInterface $output, bool $isVerbose): bool - { + /** + * Build TailwindCSS theme assets. + * + * @param string $themeCode + * @param string $themePath + * @param SymfonyStyle $io + * @param OutputInterface $output + * @param bool $isVerbose + * @return bool + */ + public function build( + string $themeCode, + string $themePath, + SymfonyStyle $io, + OutputInterface $output, + bool $isVerbose + ): bool { if (!$this->detect($themePath)) { return false; } // Clean static content if in developer mode - if (!$this->staticContentCleaner->cleanIfNeeded($themeCode, $io, $output, $isVerbose)) { + if (!$this->staticContentCleaner->cleanIfNeeded( + $themeCode, + $io, + $output, + $isVerbose + )) { return false; } @@ -114,7 +149,12 @@ public function build(string $themeCode, string $themePath, SymfonyStyle $io, Ou chdir($currentDir); // Deploy static content - if (!$this->staticContentDeployer->deploy($themeCode, $io, $output, $isVerbose)) { + if (!$this->staticContentDeployer->deploy( + $themeCode, + $io, + $output, + $isVerbose + )) { return false; } @@ -126,8 +166,21 @@ public function build(string $themeCode, string $themePath, SymfonyStyle $io, Ou return true; } - public function autoRepair(string $themePath, SymfonyStyle $io, OutputInterface $output, bool $isVerbose): bool - { + /** + * Validate and repair Node dependencies for the theme. + * + * @param string $themePath + * @param SymfonyStyle $io + * @param OutputInterface $output + * @param bool $isVerbose + * @return bool + */ + public function autoRepair( + string $themePath, + SymfonyStyle $io, + OutputInterface $output, + bool $isVerbose + ): bool { $tailwindPath = rtrim($themePath, '/') . '/web/tailwind'; // Check if node_modules is in sync with package-lock.json @@ -135,7 +188,11 @@ public function autoRepair(string $themePath, SymfonyStyle $io, OutputInterface if ($isVerbose) { $io->warning('Node modules out of sync or missing. Installing npm dependencies...'); } - if (!$this->nodePackageManager->installNodeModules($tailwindPath, $io, $isVerbose)) { + if (!$this->nodePackageManager->installNodeModules( + $tailwindPath, + $io, + $isVerbose + )) { return false; } } @@ -148,19 +205,44 @@ public function autoRepair(string $themePath, SymfonyStyle $io, OutputInterface return true; } + /** + * Get the builder name. + * + * @return string + */ public function getName(): string { return self::THEME_NAME; } - public function watch(string $themeCode, string $themePath, SymfonyStyle $io, OutputInterface $output, bool $isVerbose): bool - { + /** + * Run watch mode for TailwindCSS theme assets. + * + * @param string $themeCode + * @param string $themePath + * @param SymfonyStyle $io + * @param OutputInterface $output + * @param bool $isVerbose + * @return bool + */ + public function watch( + string $themeCode, + string $themePath, + SymfonyStyle $io, + OutputInterface $output, + bool $isVerbose + ): bool { if (!$this->detect($themePath)) { return false; } // Clean static content if in developer mode - if (!$this->staticContentCleaner->cleanIfNeeded($themeCode, $io, $output, $isVerbose)) { + if (!$this->staticContentCleaner->cleanIfNeeded( + $themeCode, + $io, + $output, + $isVerbose + )) { return false; } diff --git a/src/Service/ThemeCleaner.php b/src/Service/ThemeCleaner.php index 3646985..866bc07 100644 --- a/src/Service/ThemeCleaner.php +++ b/src/Service/ThemeCleaner.php @@ -16,6 +16,9 @@ */ class ThemeCleaner { + /** + * @param Filesystem $filesystem + */ public function __construct( private readonly Filesystem $filesystem ) {