diff --git a/composer.json b/composer.json index e6a384ef1..ee2f8844f 100644 --- a/composer.json +++ b/composer.json @@ -32,12 +32,12 @@ "ergebnis/composer-normalize": "^2.50", "friendsofphp/php-cs-fixer": "^3.94", "phpstan/extension-installer": "^1.4", - "phpstan/phpstan": "^1.12", - "phpstan/phpstan-strict-rules": "^1.6", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-strict-rules": "^2.0", "phpunit/phpunit": "^10.5", "symfony/console": "^6.4", "symplify/monorepo-builder": "^11.2.0", - "symplify/phpstan-rules": "^13.0" + "symplify/phpstan-rules": "^14.9" }, "replace": { "symfony/polyfill-php80": "*", diff --git a/composer.lock b/composer.lock index caa88f7da..9d31b269c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "a4c16f301d12c383128e62eacaf5ff33", + "content-hash": "a539658a6108a63f5757061bda1439ce", "packages": [ { "name": "brotkrueml/twig-codehighlight", @@ -1487,16 +1487,16 @@ }, { "name": "nette/utils", - "version": "v4.0.8", + "version": "v4.0.10", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede" + "reference": "2778deb6aab136c8db4ed1f4d6e9f465ca2dbee3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/c930ca4e3cf4f17dcfb03037703679d2396d2ede", - "reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede", + "url": "https://api.github.com/repos/nette/utils/zipball/2778deb6aab136c8db4ed1f4d6e9f465ca2dbee3", + "reference": "2778deb6aab136c8db4ed1f4d6e9f465ca2dbee3", "shasum": "" }, "require": { @@ -1570,9 +1570,9 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.0.8" + "source": "https://github.com/nette/utils/tree/v4.0.10" }, - "time": "2025-08-06T21:43:34+00:00" + "time": "2025-12-01T17:30:42+00:00" }, { "name": "phpdocumentor/dev-server", @@ -5335,28 +5335,28 @@ }, { "name": "webmozart/assert", - "version": "1.11.0", + "version": "1.12.1", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + "reference": "9be6926d8b485f55b9229203f962b51ed377ba68" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", - "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/9be6926d8b485f55b9229203f962b51ed377ba68", + "reference": "9be6926d8b485f55b9229203f962b51ed377ba68", "shasum": "" }, "require": { "ext-ctype": "*", + "ext-date": "*", + "ext-filter": "*", "php": "^7.2 || ^8.0" }, - "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<4.6.1 || 4.6.2" - }, - "require-dev": { - "phpunit/phpunit": "^8.5.13" + "suggest": { + "ext-intl": "", + "ext-simplexml": "", + "ext-spl": "" }, "type": "library", "extra": { @@ -5387,9 +5387,9 @@ ], "support": { "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.11.0" + "source": "https://github.com/webmozarts/assert/tree/1.12.1" }, - "time": "2022-06-03T18:03:27+00:00" + "time": "2025-10-29T15:56:20+00:00" } ], "packages-dev": [ @@ -6797,20 +6797,15 @@ }, { "name": "phpstan/phpstan", - "version": "1.12.23", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "29201e7a743a6ab36f91394eab51889a82631428" - }, + "version": "2.1.39", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/29201e7a743a6ab36f91394eab51889a82631428", - "reference": "29201e7a743a6ab36f91394eab51889a82631428", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/c6f73a2af4cbcd99c931d0fb8f08548cc0fa8224", + "reference": "c6f73a2af4cbcd99c931d0fb8f08548cc0fa8224", "shasum": "" }, "require": { - "php": "^7.2|^8.0" + "php": "^7.4|^8.0" }, "conflict": { "phpstan/phpstan-shim": "*" @@ -6851,32 +6846,31 @@ "type": "github" } ], - "time": "2025-03-23T14:57:32+00:00" + "time": "2026-02-11T14:48:56+00:00" }, { "name": "phpstan/phpstan-strict-rules", - "version": "1.6.2", + "version": "2.0.10", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-strict-rules.git", - "reference": "b564ca479e7e735f750aaac4935af965572a7845" + "reference": "1aba28b697c1e3b6bbec8a1725f8b11b6d3e5a5f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/b564ca479e7e735f750aaac4935af965572a7845", - "reference": "b564ca479e7e735f750aaac4935af965572a7845", + "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/1aba28b697c1e3b6bbec8a1725f8b11b6d3e5a5f", + "reference": "1aba28b697c1e3b6bbec8a1725f8b11b6d3e5a5f", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.12.4" + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.1.39" }, "require-dev": { - "nikic/php-parser": "^4.13.0", "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpstan-deprecation-rules": "^1.1", - "phpstan/phpstan-phpunit": "^1.0", - "phpunit/phpunit": "^9.5" + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^9.6" }, "type": "phpstan-extension", "extra": { @@ -6896,11 +6890,14 @@ "MIT" ], "description": "Extra strict and opinionated rules for PHPStan", + "keywords": [ + "static analysis" + ], "support": { "issues": "https://github.com/phpstan/phpstan-strict-rules/issues", - "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.6.2" + "source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.10" }, - "time": "2025-01-19T13:02:24+00:00" + "time": "2026-02-11T14:17:32+00:00" }, { "name": "phpunit/php-code-coverage", @@ -8506,23 +8503,23 @@ }, { "name": "symplify/phpstan-rules", - "version": "13.0.1", + "version": "14.9.11", "source": { "type": "git", "url": "https://github.com/symplify/phpstan-rules.git", - "reference": "c117396f4d7fe30704233c033244114e0fbea3f0" + "reference": "5ea4bbd9357cba253aada506dd96d37d7069ac3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symplify/phpstan-rules/zipball/c117396f4d7fe30704233c033244114e0fbea3f0", - "reference": "c117396f4d7fe30704233c033244114e0fbea3f0", + "url": "https://api.github.com/repos/symplify/phpstan-rules/zipball/5ea4bbd9357cba253aada506dd96d37d7069ac3b", + "reference": "5ea4bbd9357cba253aada506dd96d37d7069ac3b", "shasum": "" }, "require": { - "nette/utils": "^3.2.9 || ^4.0", - "php": "^7.2|^8.0", - "phpstan/phpstan": "^1.10.30", - "webmozart/assert": "^1.11" + "nette/utils": "^3.2|^4.0", + "php": "^7.4|^8.0", + "phpstan/phpstan": "^2.1.33", + "webmozart/assert": "^1.12 || ^2.0" }, "type": "phpstan-extension", "extra": { @@ -8533,6 +8530,9 @@ } }, "autoload": { + "files": [ + "src/functions/fast-functions.php" + ], "psr-4": { "Symplify\\PHPStanRules\\": "src" } @@ -8544,7 +8544,7 @@ "description": "Set of Symplify rules for PHPStan", "support": { "issues": "https://github.com/symplify/phpstan-rules/issues", - "source": "https://github.com/symplify/phpstan-rules/tree/13.0.1" + "source": "https://github.com/symplify/phpstan-rules/tree/14.9.11" }, "funding": [ { @@ -8556,7 +8556,7 @@ "type": "github" } ], - "time": "2024-08-23T09:02:23+00:00" + "time": "2026-01-05T13:53:59+00:00" }, { "name": "theseer/tokenizer", @@ -8624,5 +8624,5 @@ "platform-overrides": { "php": "8.1.27" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } diff --git a/packages/typo3-docs-theme/src/Api/Typo3ApiService.php b/packages/typo3-docs-theme/src/Api/Typo3ApiService.php index 42768fb09..7ddd47486 100644 --- a/packages/typo3-docs-theme/src/Api/Typo3ApiService.php +++ b/packages/typo3-docs-theme/src/Api/Typo3ApiService.php @@ -135,6 +135,7 @@ private function decodeJson(string $jsonData): ?array return null; } + /** @var array> $apiData */ return $apiData; } diff --git a/packages/typo3-docs-theme/src/Compiler/NodeTransformers/AttachFileObjectsToFileTextRoleTransformer.php b/packages/typo3-docs-theme/src/Compiler/NodeTransformers/AttachFileObjectsToFileTextRoleTransformer.php index 0f80d121d..4b4b4f6f8 100644 --- a/packages/typo3-docs-theme/src/Compiler/NodeTransformers/AttachFileObjectsToFileTextRoleTransformer.php +++ b/packages/typo3-docs-theme/src/Compiler/NodeTransformers/AttachFileObjectsToFileTextRoleTransformer.php @@ -64,7 +64,7 @@ public function enterNode(Node $node, CompilerContextInterface $compilerContext) return $node; } - public function leaveNode(Node $node, CompilerContextInterface $compilerContext): Node|null + public function leaveNode(Node $node, CompilerContextInterface $compilerContext): Node { return $node; } diff --git a/packages/typo3-docs-theme/src/Compiler/NodeTransformers/CollectFileObjectsTransformer.php b/packages/typo3-docs-theme/src/Compiler/NodeTransformers/CollectFileObjectsTransformer.php index 39eb6ba34..0937f2d2b 100644 --- a/packages/typo3-docs-theme/src/Compiler/NodeTransformers/CollectFileObjectsTransformer.php +++ b/packages/typo3-docs-theme/src/Compiler/NodeTransformers/CollectFileObjectsTransformer.php @@ -48,7 +48,7 @@ public function enterNode(Node $node, CompilerContextInterface $compilerContext) return $node; } - public function leaveNode(Node $node, CompilerContextInterface $compilerContext): Node|null + public function leaveNode(Node $node, CompilerContextInterface $compilerContext): Node { return $node; } diff --git a/packages/typo3-docs-theme/src/Compiler/NodeTransformers/CollectPrefixLinkTargetsTransformer.php b/packages/typo3-docs-theme/src/Compiler/NodeTransformers/CollectPrefixLinkTargetsTransformer.php index 61fa4d65d..33407d1f0 100644 --- a/packages/typo3-docs-theme/src/Compiler/NodeTransformers/CollectPrefixLinkTargetsTransformer.php +++ b/packages/typo3-docs-theme/src/Compiler/NodeTransformers/CollectPrefixLinkTargetsTransformer.php @@ -104,7 +104,7 @@ public function enterNode(Node $node, CompilerContextInterface $compilerContext) return $node; } - public function leaveNode(Node $node, CompilerContextInterface $compilerContext): Node|null + public function leaveNode(Node $node, CompilerContextInterface $compilerContext): Node { if ($node instanceof DocumentNode) { $this->documentStack->pop(); diff --git a/packages/typo3-docs-theme/src/Compiler/NodeTransformers/ConfvalMenuNodeTransformer.php b/packages/typo3-docs-theme/src/Compiler/NodeTransformers/ConfvalMenuNodeTransformer.php index df27d5302..6d6fa9f62 100644 --- a/packages/typo3-docs-theme/src/Compiler/NodeTransformers/ConfvalMenuNodeTransformer.php +++ b/packages/typo3-docs-theme/src/Compiler/NodeTransformers/ConfvalMenuNodeTransformer.php @@ -35,7 +35,7 @@ public function enterNode(Node $node, CompilerContextInterface $compilerContext) return $node; } - public function leaveNode(Node $node, CompilerContextInterface $compilerContext): Node|null + public function leaveNode(Node $node, CompilerContextInterface $compilerContext): Node { assert($node instanceof ConfvalMenuNode); if (count($node->getConfvals()) > 0) { diff --git a/packages/typo3-docs-theme/src/Compiler/NodeTransformers/RedirectsNodeTransformer.php b/packages/typo3-docs-theme/src/Compiler/NodeTransformers/RedirectsNodeTransformer.php index 29756a775..8f99f3e89 100644 --- a/packages/typo3-docs-theme/src/Compiler/NodeTransformers/RedirectsNodeTransformer.php +++ b/packages/typo3-docs-theme/src/Compiler/NodeTransformers/RedirectsNodeTransformer.php @@ -35,7 +35,7 @@ public function enterNode(Node $node, CompilerContextInterface $compilerContext) return $node; } - public function leaveNode(Node $node, CompilerContextInterface $compilerContext): Node|null + public function leaveNode(Node $node, CompilerContextInterface $compilerContext): Node { assert($node instanceof CrossReferenceNode); if ($node->getInterlinkDomain() === '') { diff --git a/packages/typo3-docs-theme/src/Compiler/NodeTransformers/RemoveInterlinkSelfReferencesFromCrossReferenceNodeTransformer.php b/packages/typo3-docs-theme/src/Compiler/NodeTransformers/RemoveInterlinkSelfReferencesFromCrossReferenceNodeTransformer.php index 4bc8c8af6..145e490b5 100644 --- a/packages/typo3-docs-theme/src/Compiler/NodeTransformers/RemoveInterlinkSelfReferencesFromCrossReferenceNodeTransformer.php +++ b/packages/typo3-docs-theme/src/Compiler/NodeTransformers/RemoveInterlinkSelfReferencesFromCrossReferenceNodeTransformer.php @@ -35,7 +35,7 @@ public function enterNode(Node $node, CompilerContextInterface $compilerContext) return $node; } - public function leaveNode(Node $node, CompilerContextInterface $compilerContext): Node|null + public function leaveNode(Node $node, CompilerContextInterface $compilerContext): Node { assert($node instanceof CrossReferenceNode); if (!$this->themeSettings->hasSettings('interlink_shortcode')) { diff --git a/packages/typo3-docs-theme/src/Compiler/NodeTransformers/ReplacePermalinksNodeTransformer.php b/packages/typo3-docs-theme/src/Compiler/NodeTransformers/ReplacePermalinksNodeTransformer.php index cddf94557..4edb1c41c 100644 --- a/packages/typo3-docs-theme/src/Compiler/NodeTransformers/ReplacePermalinksNodeTransformer.php +++ b/packages/typo3-docs-theme/src/Compiler/NodeTransformers/ReplacePermalinksNodeTransformer.php @@ -32,7 +32,7 @@ public function enterNode(Node $node, CompilerContextInterface $compilerContext) return $node; } - public function leaveNode(Node $node, CompilerContextInterface $compilerContext): Node|null + public function leaveNode(Node $node, CompilerContextInterface $compilerContext): Node { assert($node instanceof HyperLinkNode); if (!str_starts_with($node->getTargetReference(), 'https://docs.typo3.org/permalink/')) { diff --git a/packages/typo3-docs-theme/src/Compiler/NodeTransformers/Typo3TalkNodeTransformer.php b/packages/typo3-docs-theme/src/Compiler/NodeTransformers/Typo3TalkNodeTransformer.php index 229b66daa..88d0217ab 100644 --- a/packages/typo3-docs-theme/src/Compiler/NodeTransformers/Typo3TalkNodeTransformer.php +++ b/packages/typo3-docs-theme/src/Compiler/NodeTransformers/Typo3TalkNodeTransformer.php @@ -46,7 +46,7 @@ public function enterNode(Node $node, CompilerContextInterface $compilerContext) return $node; } - public function leaveNode(Node $node, CompilerContextInterface $compilerContext): Node|null + public function leaveNode(Node $node, CompilerContextInterface $compilerContext): Node { if ($node instanceof DocumentNode) { $this->sectionStack = []; diff --git a/packages/typo3-docs-theme/src/DependencyInjection/Typo3DocsThemeExtension.php b/packages/typo3-docs-theme/src/DependencyInjection/Typo3DocsThemeExtension.php index 05984ef7c..2cd1bf4c2 100644 --- a/packages/typo3-docs-theme/src/DependencyInjection/Typo3DocsThemeExtension.php +++ b/packages/typo3-docs-theme/src/DependencyInjection/Typo3DocsThemeExtension.php @@ -32,7 +32,7 @@ class Typo3DocsThemeExtension extends Extension implements PrependExtensionInter YoutubeNode::class => 'body/directive/youtube.html.twig', ]; - /** @param mixed[] $configs */ + /** @param array $configs */ public function load(array $configs, ContainerBuilder $container): void { $loader = new PhpFileLoader( diff --git a/packages/typo3-docs-theme/src/Directives/FigureDirective.php b/packages/typo3-docs-theme/src/Directives/FigureDirective.php index 3e2d45fba..c0e21bfd2 100644 --- a/packages/typo3-docs-theme/src/Directives/FigureDirective.php +++ b/packages/typo3-docs-theme/src/Directives/FigureDirective.php @@ -93,7 +93,7 @@ public function process( 'align' => $scalarOptions['align'] ?? null, ]); - $figureNode = new FigureNode($image, new CollectionNode($collectionNode->getChildren())); + $figureNode = new FigureNode($image, new CollectionNode(array_values($collectionNode->getChildren()))); // Build filtered options - copy all options but validate zoom mode // We must set all options ourselves because DirectiveRule::postProcessNode diff --git a/packages/typo3-docs-theme/src/Directives/GroupTabDirective.php b/packages/typo3-docs-theme/src/Directives/GroupTabDirective.php index 10b0cda80..7ab240986 100644 --- a/packages/typo3-docs-theme/src/Directives/GroupTabDirective.php +++ b/packages/typo3-docs-theme/src/Directives/GroupTabDirective.php @@ -47,7 +47,7 @@ protected function processSub( $directive->getData(), $directive->getDataNode() ?? new InlineCompoundNode(), $key, - $collectionNode->getChildren(), + array_values($collectionNode->getChildren()), ); } } diff --git a/packages/typo3-docs-theme/src/Directives/IncludeDirective.php b/packages/typo3-docs-theme/src/Directives/IncludeDirective.php index 84cb4a2ee..47cc5bb62 100644 --- a/packages/typo3-docs-theme/src/Directives/IncludeDirective.php +++ b/packages/typo3-docs-theme/src/Directives/IncludeDirective.php @@ -159,7 +159,7 @@ public function getCollectionFromPath(\League\Flysystem\FilesystemInterface|\php if ($directive->getOptionBool('show-buttons')) { $buttons[] = new EditOnGithubIncludeNode($path); } - return new CollectionNode(array_merge($buttons, $document->getChildren())); + return new CollectionNode(array_values(array_merge($buttons, $document->getChildren()))); } /** diff --git a/packages/typo3-docs-theme/src/Directives/SiteSetSettingsDirective.php b/packages/typo3-docs-theme/src/Directives/SiteSetSettingsDirective.php index 74038e342..cda78f18e 100644 --- a/packages/typo3-docs-theme/src/Directives/SiteSetSettingsDirective.php +++ b/packages/typo3-docs-theme/src/Directives/SiteSetSettingsDirective.php @@ -63,6 +63,10 @@ public function processNode( if (!is_array($yamlData) || !is_array($yamlData['settings'] ?? false)) { throw new FileLoadingException(sprintf('The .. typo3:site-set-settings:: source at path %s did not contain any settings ', $directive->getData())); } + /** @var array> $settings */ + $settings = $yamlData['settings']; + /** @var array> $yamlCategories */ + $yamlCategories = is_array($yamlData['categories'] ?? null) ? $yamlData['categories'] : []; } catch (FileLoadingException $exception) { $this->logger->warning($exception->getMessage(), $blockContext->getLoggerInformation()); return $this->getErrorNode(); @@ -85,9 +89,9 @@ public function processNode( $labelContents = ''; // Assume all EXT: references are relative to the rendered PROJECT - $labelsFile = $labelsFile ? - preg_replace('/^EXT:[^\/]*\//', 'PROJECT:/', $labelsFile) : - dirname($setConfigurationFile) . '/labels.xlf'; + $labelsFile = is_string($labelsFile) && $labelsFile !== '' + ? (preg_replace('/^EXT:[^\/]*\//', 'PROJECT:/', $labelsFile) ?? $labelsFile) + : dirname($setConfigurationFile) . '/labels.xlf'; try { $labelContents = $this->loadFileFromDocumentation($blockContext, $labelsFile); } catch (FileLoadingException $exception) { @@ -102,7 +106,8 @@ public function processNode( if ($xml->loadXML($labelContents)) { foreach ($xml->getElementsByTagName('trans-unit') as $label) { $id = $label->getAttribute('id'); - $value = ($label->getElementsByTagName('source')[0] ?? null)?->textContent ?? ''; + $sourceElements = $label->getElementsByTagName('source'); + $value = $sourceElements->length > 0 ? ($sourceElements->item(0)->textContent ?? '') : ''; if (!$value) { continue; } @@ -117,7 +122,7 @@ public function processNode( } } - return $this->buildConfvalMenu($directive, $yamlData['settings'], $yamlData['categories'] ?? [], $labels, $descriptions, $categoryLabels); + return $this->buildConfvalMenu($directive, $settings, $yamlCategories, $labels, $descriptions, $categoryLabels); } /** @@ -174,7 +179,7 @@ private function getErrorNode(): ParagraphNode } /** - * @param array> $settings + * @param array> $settings * @param array> $categories * @param array $labels * @param array $descriptions @@ -187,18 +192,24 @@ public function buildConfvalMenu(Directive $directive, array $settings, array $c $idPrefix = $directive->getOptionString('name') . '-'; } $categoryArray = $this->buildCategoryArray($categories, $categoryLabels); + /** @var list> $rootCategories */ $rootCategories = []; foreach ($categoryArray as $key => $category) { - if (isset($categoryArray[$category['parent']])) { - assert(is_array($categoryArray[$category['parent']]['children'])); - $categoryArray[$category['parent']]['children'][] = &$categoryArray[$key]; + $parent = is_string($category['parent'] ?? null) ? $category['parent'] : ''; + if ($parent !== '' && isset($categoryArray[$parent])) { + assert(is_array($categoryArray[$parent]['children'])); + $categoryArray[$parent]['children'][] = &$categoryArray[$key]; } else { $rootCategories[] = &$categoryArray[$key]; } } foreach ($settings as $key => $setting) { - $confval = $this->buildConfval($setting, $idPrefix, $key, $directive, $labels, $descriptions, $categoryArray); - $this->assignConfvalsToCategories($setting['category'] ?? '', $categoryArray, $confval, $rootCategories); + if (!is_array($setting)) { + continue; + } + $confval = $this->buildConfval($setting, $idPrefix, (string) $key, $directive, $labels, $descriptions, $categoryArray); + $settingCategory = is_string($setting['category'] ?? null) ? $setting['category'] : ''; + $this->assignConfvalsToCategories($settingCategory, $categoryArray, $confval, $rootCategories); } $confvals = $this->buildCategoryConfvals($rootCategories, $idPrefix, $directive); $reservedParameterNames = [ @@ -237,13 +248,14 @@ public function buildConfvalMenu(Directive $directive, array $settings, array $c /** - * @param array> $setting + * @param array $setting * @param array $labels * @param array $descriptions - * @param array> $categoryArray + * @param array> $categoryArray */ public function buildConfval(array $setting, string $idPrefix, string $key, Directive $directive, array $labels, array $descriptions, array $categoryArray): ConfvalNode { + /** @var list $content */ $content = []; $description = $setting['description'] ?? $descriptions[$key] ?? false; if (is_string($description)) { @@ -315,12 +327,13 @@ private function customPrint(mixed $value): string /** - * @param array> $categoryArray + * @param array> $categoryArray */ private function getCategoryRootline(array $categoryArray, string $key): string { - $label = $categoryArray[$key]['label'] ?? $key; - $parent = $categoryArray[$key]['parent'] ?? ''; + $categoryEntry = $categoryArray[$key] ?? []; + $label = is_string($categoryEntry['label'] ?? null) ? $categoryEntry['label'] : $key; + $parent = is_string($categoryEntry['parent'] ?? null) ? $categoryEntry['parent'] : ''; if ($parent === '') { return $label; } @@ -331,7 +344,7 @@ private function getCategoryRootline(array $categoryArray, string $key): string } /** - * @param array> $categories + * @param array> $categories * @param array $categoryLabels * @return array> */ @@ -352,7 +365,7 @@ public function buildCategoryArray(array $categories, array $categoryLabels): ar /** * @param array> $categoryArray - * @param array> $rootCategories + * @param list> $rootCategories */ public function assignConfvalsToCategories(string $category, array &$categoryArray, ConfvalNode $confval, array &$rootCategories): void { @@ -371,7 +384,7 @@ public function assignConfvalsToCategories(string $category, array &$categoryArr } /** - * @param array> $categories + * @param list> $categories * @return ConfvalNode[] */ private function buildCategoryConfvals(array $categories, string $idPrefix, Directive $directive): array @@ -382,23 +395,24 @@ private function buildCategoryConfvals(array $categories, string $idPrefix, Dire $confvals = []; foreach ($categories as $category) { $children = []; - if (is_array($category['children'] ?? false)) { - $children = $this->buildCategoryConfvals($category['children'], $idPrefix, $directive); + $categoryChildren = $category['children'] ?? []; + if (is_array($categoryChildren) && $categoryChildren !== []) { + /** @var list> $categoryChildren */ + $children = $this->buildCategoryConfvals($categoryChildren, $idPrefix, $directive); } - $key = $category['key']; + $key = is_string($category['key'] ?? null) ? $category['key'] : ''; if ($key === '') { $key = '_global'; } - assert(is_string($key)); $additionalFields = []; $additionalFields['searchFacet'] = new InlineCompoundNode([new PlainTextInlineNode(self::CATEGORY_FACET)]); - $label = $category['label']; + $label = is_string($category['label'] ?? null) ? $category['label'] : ''; if ($label !== '') { - assert(is_string($label)); $additionalFields['Label'] = new InlineCompoundNode([new PlainTextInlineNode($label)]); } - assert(is_array($category['confvals'])); + /** @var list $categoryConfvals */ + $categoryConfvals = is_array($category['confvals'] ?? null) ? $category['confvals'] : []; $confvals[] = new ConfvalNode( $this->anchorNormalizer->reduceAnchor($idPrefix . 'category-' . $key), $key, @@ -406,7 +420,7 @@ private function buildCategoryConfvals(array $categories, string $idPrefix, Dire false, null, $additionalFields, - array_merge($children, $category['confvals']), + array_values(array_merge($children, $categoryConfvals)), $directive->getOptionBool('noindex'), ); } diff --git a/packages/typo3-docs-theme/src/Directives/Typo3FileDirective.php b/packages/typo3-docs-theme/src/Directives/Typo3FileDirective.php index c68ea4b0c..cebd08ae0 100644 --- a/packages/typo3-docs-theme/src/Directives/Typo3FileDirective.php +++ b/packages/typo3-docs-theme/src/Directives/Typo3FileDirective.php @@ -47,7 +47,7 @@ protected function processSub( BlockContext $blockContext, CollectionNode $collectionNode, Directive $directive, - ): Node|null { + ): Node { $filename = $directive->getData(); $path = $directive->getOptionString('path'); $language = $directive->getOptionString('language'); diff --git a/packages/typo3-docs-theme/src/Directives/ViewHelperDirective.php b/packages/typo3-docs-theme/src/Directives/ViewHelperDirective.php index 59649eeb1..047c29910 100644 --- a/packages/typo3-docs-theme/src/Directives/ViewHelperDirective.php +++ b/packages/typo3-docs-theme/src/Directives/ViewHelperDirective.php @@ -95,12 +95,20 @@ public function processNode( $noindex = $directive->getOptionBool('noindex'); + /** @var array $data */ $data = $json['viewHelpers'][$directive->getData()]; - $viewHelperNode = $this->getViewHelperNode($directive, $data, $json['sourceEdit'] ?? [], $blockContext, $noindex); + /** @var array $sourceEdit */ + $sourceEdit = is_array($json['sourceEdit'] ?? null) ? $json['sourceEdit'] : []; + $viewHelperNode = $this->getViewHelperNode($directive, $data, $sourceEdit, $blockContext, $noindex); + /** @var array $arguments */ $arguments = []; - foreach ($json['viewHelpers'][$directive->getData()]['argumentDefinitions'] ?? [] as $argumentDefinition) { - if (is_array($argumentDefinition)) { - $arguments[$this->getString($argumentDefinition, 'name')] = $this->getArgument($argumentDefinition, $viewHelperNode, $noindex); + $argumentDefs = $data['argumentDefinitions'] ?? []; + if (is_array($argumentDefs)) { + foreach ($argumentDefs as $argumentDefinition) { + if (is_array($argumentDefinition)) { + /** @var array $argumentDefinition */ + $arguments[$this->getString($argumentDefinition, 'name')] = $this->getArgument($argumentDefinition, $viewHelperNode, $noindex); + } } } if ($sortBy === 'name') { @@ -155,35 +163,45 @@ public function getArgument(array $argumentDefinition, ViewHelperNode $viewHelpe private function getViewHelperNode(Directive $directive, array $data, array $sourceEdit, BlockContext $blockContext, bool $noindex): ViewHelperNode { $rawDocumentation = $this->getString($data, 'documentation'); + /** @var list $description */ $description = []; + /** @var list $sections */ $sections = []; + /** @var list $examples */ $examples = []; if (str_contains($rawDocumentation, '```')) { - $node = $this->markupLanguageParser->parse($blockContext->getDocumentParserContext()->getContext(), $rawDocumentation); - $collectionNode = new CollectionNode($node->getValue()); - foreach ($node->getValue() as $node) { - if ($node instanceof ParagraphNode) { - $description[] = $node; + $documentNode = $this->markupLanguageParser->parse($blockContext->getDocumentParserContext()->getContext(), $rawDocumentation); + $rawValue = $documentNode->getValue(); + /** @var list $childNodes */ + $childNodes = is_array($rawValue) ? array_values($rawValue) : []; + $collectionNode = new CollectionNode($childNodes); + foreach ($childNodes as $childNode) { + if ($childNode instanceof ParagraphNode) { + $description[] = $childNode; } - if ($node instanceof CodeNode) { - $examples[] = $node; + if ($childNode instanceof CodeNode) { + $examples[] = $childNode; } } } else { $rstContentBlockContext = new BlockContext($blockContext->getDocumentParserContext(), $rawDocumentation, false); - $collectionNode = $this->startingRule->apply($rstContentBlockContext); - foreach ($collectionNode->getValue() as $node) { - if (!$node instanceof SectionNode) { - $description[] = $node; + $parsedNode = $this->startingRule->apply($rstContentBlockContext); + $rawValue = $parsedNode?->getValue(); + /** @var list $collectionChildren */ + $collectionChildren = is_array($rawValue) ? array_values($rawValue) : []; + $collectionNode = new CollectionNode($collectionChildren); + foreach ($collectionChildren as $childNode) { + if (!$childNode instanceof SectionNode) { + $description[] = $childNode; } } - foreach ($collectionNode->getValue() as $node) { - if ($node instanceof SectionNode) { - $title = $node->getTitle()->toString(); + foreach ($collectionChildren as $childNode) { + if ($childNode instanceof SectionNode) { + $title = $childNode->getTitle()->toString(); if (stripos($title, 'example') !== false) { // Case-insensitive check for 'example' - $examples[] = $node; + $examples[] = $childNode; } else { - $sections[] = $node; + $sections[] = $childNode; } } } @@ -201,19 +219,22 @@ private function getViewHelperNode(Directive $directive, array $data, array $sou $display = array_map('trim', explode(',', $directive->getOptionString('display'))); } $viewHelperId = $this->anchorNormalizer->reduceAnchor($className); + $rawDocs = $collectionNode->getValue(); + /** @var list $documentationNodes */ + $documentationNodes = is_array($rawDocs) ? $rawDocs : []; $viewHelperNode = new ViewHelperNode( id: $viewHelperId, tagName: $this->getString($data, 'tagName'), shortClassName: $shortClassName, namespace: $nameSpace, className: $className, - documentation: $collectionNode?->getValue() ?? [], + documentation: $documentationNodes, description: $description, sections: $sections, examples: $examples, xmlNamespace: $xmlNamespace, allowsArbitraryArguments: ($data['allowsArbitraryArguments'] ?? false) === true, - docTags: $data['docTags'] ?? [], + docTags: $this->extractDocTags($data), gitHubLink: $gitHubLink, noindex: $noindex, display: $display, @@ -222,6 +243,25 @@ className: $className, return $viewHelperNode; } + /** + * @param array $data + * @return array + */ + private function extractDocTags(array $data): array + { + $docTags = $data['docTags'] ?? []; + if (!is_array($docTags)) { + return []; + } + $result = []; + foreach ($docTags as $key => $value) { + if (is_string($key) && is_scalar($value)) { + $result[$key] = (string) $value; + } + } + return $result; + } + private function getErrorNode(): ParagraphNode { return new ParagraphNode([new InlineCompoundNode([new PlainTextInlineNode('The ViewHelper cannot be displayed.')])]); diff --git a/packages/typo3-docs-theme/src/EventListeners/AddThemeSettingsToProjectNode.php b/packages/typo3-docs-theme/src/EventListeners/AddThemeSettingsToProjectNode.php index e65e1a148..f1e4f7caf 100644 --- a/packages/typo3-docs-theme/src/EventListeners/AddThemeSettingsToProjectNode.php +++ b/packages/typo3-docs-theme/src/EventListeners/AddThemeSettingsToProjectNode.php @@ -21,7 +21,8 @@ public function __invoke(PostProjectNodeCreated $event): void // Native parsing of argv because we do not have the original ArgvInput // available, and neither the InputDefinition. That's ok for the // very basic parsing of a global option. - if (in_array('--minimal-test', $_SERVER['argv'] ?? [], true)) { + $argv = (array) ($_SERVER['argv'] ?? []); + if (in_array('--minimal-test', $argv, true)) { $settings = $event->getSettings(); // Set up input arguments for our minimal test. Will override diff --git a/packages/typo3-docs-theme/src/Inventory/Typo3InventoryRepository.php b/packages/typo3-docs-theme/src/Inventory/Typo3InventoryRepository.php index 81cc92494..96fd09752 100644 --- a/packages/typo3-docs-theme/src/Inventory/Typo3InventoryRepository.php +++ b/packages/typo3-docs-theme/src/Inventory/Typo3InventoryRepository.php @@ -133,6 +133,7 @@ private function tryLoadInventoryJson(string $reducedKey, string $inventoryUrl): if ($json === []) { return false; } + /** @var array $json */ $this->loadInventoryFromJson($inventoryUrl, $json, $reducedKey); return true; } catch (ClientException) { @@ -141,7 +142,7 @@ private function tryLoadInventoryJson(string $reducedKey, string $inventoryUrl): } /** - * @param array $json + * @param array $json */ private function loadInventoryFromJson(string $inventoryUrl, array $json, string $reducedKey): void { diff --git a/packages/typo3-docs-theme/src/Nodes/ConfvalMenuNode.php b/packages/typo3-docs-theme/src/Nodes/ConfvalMenuNode.php index e9ae43c51..77d821029 100644 --- a/packages/typo3-docs-theme/src/Nodes/ConfvalMenuNode.php +++ b/packages/typo3-docs-theme/src/Nodes/ConfvalMenuNode.php @@ -35,7 +35,7 @@ public function __construct( private readonly bool $noindex = false, private readonly string $facet = 'Option', ) { - parent::__construct('confval-menu', $plainContent, $content, $value); + parent::__construct('confval-menu', $plainContent, $content, array_values($value)); } public function getId(): string diff --git a/packages/typo3-docs-theme/src/Nodes/DirectoryTree/DirectoryTreeListItemNode.php b/packages/typo3-docs-theme/src/Nodes/DirectoryTree/DirectoryTreeListItemNode.php index 911c041c9..b6fa1b4b7 100644 --- a/packages/typo3-docs-theme/src/Nodes/DirectoryTree/DirectoryTreeListItemNode.php +++ b/packages/typo3-docs-theme/src/Nodes/DirectoryTree/DirectoryTreeListItemNode.php @@ -18,7 +18,7 @@ public function __construct( private readonly string $name, private readonly array $subLists, ) { - parent::__construct($items); + parent::__construct(array_values($items)); } public function getName(): string diff --git a/packages/typo3-docs-theme/src/Nodes/DirectoryTree/DirectoryTreeListNode.php b/packages/typo3-docs-theme/src/Nodes/DirectoryTree/DirectoryTreeListNode.php index 5109a4af1..6f072b939 100644 --- a/packages/typo3-docs-theme/src/Nodes/DirectoryTree/DirectoryTreeListNode.php +++ b/packages/typo3-docs-theme/src/Nodes/DirectoryTree/DirectoryTreeListNode.php @@ -12,7 +12,7 @@ final class DirectoryTreeListNode extends CompoundNode */ public function __construct(array $items, private readonly string $name) { - parent::__construct($items); + parent::__construct(array_values($items)); } public function getName(): string diff --git a/packages/typo3-docs-theme/src/Nodes/GlossaryNode.php b/packages/typo3-docs-theme/src/Nodes/GlossaryNode.php index 1bea24a8c..876535fe9 100644 --- a/packages/typo3-docs-theme/src/Nodes/GlossaryNode.php +++ b/packages/typo3-docs-theme/src/Nodes/GlossaryNode.php @@ -18,7 +18,7 @@ public function __construct( array $value = [], protected array $entries = [], ) { - parent::__construct('glossary', $plainContent, $content, $value); + parent::__construct('glossary', $plainContent, $content, array_values($value)); } /** diff --git a/packages/typo3-docs-theme/src/Nodes/MainMenuJsonNode.php b/packages/typo3-docs-theme/src/Nodes/MainMenuJsonNode.php index 03a2c3f4e..608388865 100644 --- a/packages/typo3-docs-theme/src/Nodes/MainMenuJsonNode.php +++ b/packages/typo3-docs-theme/src/Nodes/MainMenuJsonNode.php @@ -16,7 +16,7 @@ public function __construct( protected readonly InlineCompoundNode $content, array $value = [], ) { - parent::__construct('main-menu-json', $plainContent, $content, $value); + parent::__construct('main-menu-json', $plainContent, $content, array_values($value)); } } diff --git a/packages/typo3-docs-theme/src/Nodes/ViewHelperNode.php b/packages/typo3-docs-theme/src/Nodes/ViewHelperNode.php index 8e88b5f8b..e3f850fb3 100644 --- a/packages/typo3-docs-theme/src/Nodes/ViewHelperNode.php +++ b/packages/typo3-docs-theme/src/Nodes/ViewHelperNode.php @@ -41,7 +41,7 @@ public function __construct( private readonly array $display = [], private array $arguments = [], ) { - parent::__construct('viewhelper', $tagName, new InlineCompoundNode([new PlainTextInlineNode($tagName)]), $documentation); + parent::__construct('viewhelper', $tagName, new InlineCompoundNode([new PlainTextInlineNode($tagName)]), array_values($documentation)); } /** @@ -131,7 +131,7 @@ public function getArguments(): array } /** - * @param ViewHelperArgumentNode[] $arguments + * @param array $arguments */ public function setArguments(array $arguments): void { diff --git a/packages/typo3-docs-theme/src/Twig/TwigExtension.php b/packages/typo3-docs-theme/src/Twig/TwigExtension.php index dad53fd35..e3cc2635b 100644 --- a/packages/typo3-docs-theme/src/Twig/TwigExtension.php +++ b/packages/typo3-docs-theme/src/Twig/TwigExtension.php @@ -699,9 +699,8 @@ public function getPagerLinks(array $context): array */ public function getSingleHtmlLink(array $context): ?string { - /** @var RenderContext|null $renderContext */ $renderContext = $context['env'] ?? null; - if (!$renderContext) { + if (!$renderContext instanceof RenderContext) { return null; } @@ -729,9 +728,8 @@ public function getSingleHtmlLink(array $context): ?string */ public function getTopPageLink(array $context): ?PageLinkNode { - /** @var RenderContext|null $renderContext */ $renderContext = $context['env'] ?? null; - if (!$renderContext) { + if (!$renderContext instanceof RenderContext) { return null; } diff --git a/packages/typo3-guides-cli/src/Command/ConfigureCommand.php b/packages/typo3-guides-cli/src/Command/ConfigureCommand.php index dfd24edd5..f78b4de61 100644 --- a/packages/typo3-guides-cli/src/Command/ConfigureCommand.php +++ b/packages/typo3-guides-cli/src/Command/ConfigureCommand.php @@ -255,7 +255,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int $output->writeln(print_r($input->getOptions(), true)); } - $config = $input->getArgument('input') . '/guides.xml'; + $inputPath = $input->getArgument('input'); + if (!is_string($inputPath)) { + $output->writeln('Input argument must be a string path'); + return Command::FAILURE; + } + $config = $inputPath . '/guides.xml'; if ($output->isVeryVerbose()) { $output->writeln(sprintf('Config: %s', $config)); @@ -337,6 +342,8 @@ private function operateOnXmlProject(\SimpleXMLElement $xml, InputInterface $inp private function operateOnXmlGuides(\SimpleXMLElement $xml, InputInterface $input, OutputInterface $output): bool { + $guides = $xml->xpath('/ns:guides'); + $guidesVariables = [ 'input' => $input->getOption('guides-input'), 'input-file' => $input->getOption('guides-input-file'), diff --git a/packages/typo3-guides-cli/src/Command/InitCommand.php b/packages/typo3-guides-cli/src/Command/InitCommand.php index 01adc3729..e6c96ef21 100644 --- a/packages/typo3-guides-cli/src/Command/InitCommand.php +++ b/packages/typo3-guides-cli/src/Command/InitCommand.php @@ -46,8 +46,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int { if ($input->getOption('working-dir')) { $workdir = $input->getOption('working-dir'); - assert(is_string($workdir)); - $workdir = (string) $workdir; + if (!is_string($workdir)) { + $output->writeln('Working directory must be a string'); + return Command::INVALID; + } if (chdir($workdir)) { $output->writeln('Changed working directory to ' . getcwd() . ''); @@ -98,7 +100,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $composerInfo->getComposerName() ); $projectNameQuestion->setValidator(function ($answer) { - if (is_null($answer) || trim($answer) === '') { + if (!is_string($answer) || trim($answer) === '') { throw new \RuntimeException('The project title cannot be empty.'); } return $answer; @@ -125,6 +127,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int ] ); $repositoryUrl = $helper->ask($input, $output, $question); + if (!is_string($repositoryUrl)) { + $repositoryUrl = ''; + } $question = $this->createValidatedUrlQuestion( 'Where can users report issues? [%s]', @@ -149,7 +154,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $question = new Question('Do you want generate some Documentation? (yes/no) ', 'yes'); $question->setValidator(function ($answer) { - if (!in_array(strtolower($answer), [ + if (!is_string($answer) || !in_array(strtolower($answer), [ 'yes', 'y', 'no', @@ -173,6 +178,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int if (is_string($siteSet) && $siteSet !== '') { $question = new Question('Enter the path to your site set: '); $siteSetPath = $helper->ask($input, $output, $question); + if (!is_string($siteSetPath)) { + $siteSetPath = ''; + } if (is_file($siteSetPath . '/settings.definitions.yaml')) { $siteSetDefinition = $siteSetPath . '/settings.definitions.yaml'; } @@ -192,9 +200,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int mkdir($outputDir, 0o777, true); } - assert(is_string($repositoryUrl ?? '')); $editOnGitHub = null; - if (str_starts_with($repositoryUrl ?? '', 'https://github.com/')) { + if (str_starts_with($repositoryUrl, 'https://github.com/')) { $editOnGitHub = str_replace('https://github.com/', '', $repositoryUrl); } // Define your data @@ -275,6 +282,7 @@ private function fetchComposerArray(): array|null return null; } + /** @var array $composerJson */ return $composerJson; } diff --git a/packages/typo3-guides-cli/src/Command/MigrateSettingsCommand.php b/packages/typo3-guides-cli/src/Command/MigrateSettingsCommand.php index ffd3a5ecf..195219bc9 100644 --- a/packages/typo3-guides-cli/src/Command/MigrateSettingsCommand.php +++ b/packages/typo3-guides-cli/src/Command/MigrateSettingsCommand.php @@ -57,8 +57,13 @@ protected function configure(): void protected function execute(InputInterface $input, OutputInterface $output): int { - $settingsFile = $input->getArgument('input') . '/Settings.cfg'; - $guidesFile = $input->getArgument('input') . '/guides.xml'; + $inputPath = $input->getArgument('input'); + if (!is_string($inputPath)) { + $output->writeln('Input argument must be a string path'); + return Command::FAILURE; + } + $settingsFile = $inputPath . '/Settings.cfg'; + $guidesFile = $inputPath . '/guides.xml'; if (file_exists($guidesFile) && !$input->getOption('force')) { $output->writeln('Target file already exists in specified directory (' . $guidesFile . ')'); diff --git a/packages/typo3-guides-cli/src/Migration/SettingsMigrator.php b/packages/typo3-guides-cli/src/Migration/SettingsMigrator.php index ce68c77d0..ba4de1fe5 100644 --- a/packages/typo3-guides-cli/src/Migration/SettingsMigrator.php +++ b/packages/typo3-guides-cli/src/Migration/SettingsMigrator.php @@ -56,7 +56,7 @@ public function migrate(array $legacySettings): MigrationResult // Attach the element to the root XML $this->xmlDocument->appendChild($guides); - return new MigrationResult($this->xmlDocument, $this->convertedSettings, $messages); + return new MigrationResult($this->xmlDocument, $this->convertedSettings, array_values($messages)); } private function createRootElement(): \DOMElement @@ -158,6 +158,7 @@ private function createInventorySection(): array return $inventories; } + /** @return list */ private function collectUnmigratedLegacySettings(): array { $messages = []; diff --git a/packages/typo3-guides-cli/src/Repository/LegacySettingsRepository.php b/packages/typo3-guides-cli/src/Repository/LegacySettingsRepository.php index 17380cc2b..d632ab3b7 100644 --- a/packages/typo3-guides-cli/src/Repository/LegacySettingsRepository.php +++ b/packages/typo3-guides-cli/src/Repository/LegacySettingsRepository.php @@ -37,6 +37,7 @@ public function get(string $filePath): array throw FileException::notParsable($filePath); } + /** @var array> $settings */ return $settings; } } diff --git a/packages/typo3-guides-cli/src/XmlValidator.php b/packages/typo3-guides-cli/src/XmlValidator.php index 3694233e1..066e98817 100644 --- a/packages/typo3-guides-cli/src/XmlValidator.php +++ b/packages/typo3-guides-cli/src/XmlValidator.php @@ -70,7 +70,7 @@ public function validate(): bool } // Custom error handler function within the class - private function errorHandler(mixed $errno, string $errstr): void + private function errorHandler(int $errno, string $errstr): void { $this->errors[] = 'xxx' . $errno . ': ' . $errstr; } diff --git a/packages/typo3-guides-extension/src/Command/RunDecorator.php b/packages/typo3-guides-extension/src/Command/RunDecorator.php index cf5d471da..b97fa0051 100644 --- a/packages/typo3-guides-extension/src/Command/RunDecorator.php +++ b/packages/typo3-guides-extension/src/Command/RunDecorator.php @@ -249,6 +249,9 @@ public function renderSingleLocalization(string $availableLocalization, array $b { $localInputDirectives = []; foreach ($baseInputDirectives as $baseInputDirectiveKey => $baseInputDirectiveValue) { + if (!is_scalar($baseInputDirectiveValue)) { + continue; + } $localInputDirectives[$baseInputDirectiveKey] = $baseInputDirectiveValue . DIRECTORY_SEPARATOR . $availableLocalization; } $output->writeln(sprintf('Trying to render %s ...', $availableLocalization)); @@ -285,7 +288,7 @@ public function renderSingleLocalization(string $availableLocalization, array $b $process = new Process($processArguments); $output->writeln(sprintf('SUB-PROCESS: %s', $process->getCommandLine())); $hasErrors = false; - $result = $process->run(function ($type, $buffer) use ($output, &$hasErrors): void { + $result = $process->run(function (string $type, string $buffer) use ($output, &$hasErrors): void { if ($type === Process::ERR) { $output->write('' . $buffer . ''); $hasErrors = true; diff --git a/packages/typo3-version-handling/src/Packagist/PackagistService.php b/packages/typo3-version-handling/src/Packagist/PackagistService.php index 92977f4dc..b8374be13 100644 --- a/packages/typo3-version-handling/src/Packagist/PackagistService.php +++ b/packages/typo3-version-handling/src/Packagist/PackagistService.php @@ -22,11 +22,22 @@ public function getComposerInfo(string $composerName): ComposerPackage // Decode JSON response $packageData = json_decode($packageResponse, true); - if (!isset($packageData['packages'][$composerName][0]) || !is_array($packageData['packages'][$composerName][0])) { + if (!is_array($packageData)) { $this->cache[$composerName] = new ComposerPackage($composerName, 'composer req ' . $composerName, 'not found'); return $this->cache[$composerName]; } - $packageVersionData = $packageData['packages'][$composerName][0]; + $packages = $packageData['packages'] ?? null; + if (!is_array($packages)) { + $this->cache[$composerName] = new ComposerPackage($composerName, 'composer req ' . $composerName, 'not found'); + return $this->cache[$composerName]; + } + $composerVersions = $packages[$composerName] ?? null; + if (!is_array($composerVersions) || !isset($composerVersions[0]) || !is_array($composerVersions[0])) { + $this->cache[$composerName] = new ComposerPackage($composerName, 'composer req ' . $composerName, 'not found'); + return $this->cache[$composerName]; + } + /** @var array $packageVersionData */ + $packageVersionData = $composerVersions[0]; $this->cache[$composerName] = $this->getComposerInfoFromJson( $packageVersionData, @@ -99,9 +110,8 @@ public function fetchPackageData(string $url): bool|string if ($this->timeoutOccurred) { return false; } - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 10); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); $errorNumber = curl_errno($ch); diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 3af0ed08c..065bb7d77 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,66 +1,31 @@ parameters: ignoreErrors: - - message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" - count: 2 - path: packages/typo3-docs-theme/src/Directives/ViewHelperDirective.php - - - - message: "#^Cannot call method getValue\\(\\) on phpDocumentor\\\\Guides\\\\Nodes\\\\Node\\|null\\.$#" - count: 2 - path: packages/typo3-docs-theme/src/Directives/ViewHelperDirective.php - - - - message: "#^Parameter \\$description of class T3Docs\\\\Typo3DocsTheme\\\\Nodes\\\\ViewHelperNode constructor expects array\\, array\\, mixed\\> given\\.$#" - count: 1 - path: packages/typo3-docs-theme/src/Directives/ViewHelperDirective.php - - - - message: "#^Parameter \\$docTags of class T3Docs\\\\Typo3DocsTheme\\\\Nodes\\\\ViewHelperNode constructor expects array\\, mixed given\\.$#" - count: 1 - path: packages/typo3-docs-theme/src/Directives/ViewHelperDirective.php - - - - message: "#^Parameter \\$documentation of class T3Docs\\\\Typo3DocsTheme\\\\Nodes\\\\ViewHelperNode constructor expects array\\, mixed given\\.$#" - count: 1 - path: packages/typo3-docs-theme/src/Directives/ViewHelperDirective.php - - - - message: "#^Result of && is always false\\.$#" + message: '#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\.$#' + identifier: foreach.nonIterable count: 1 - path: packages/typo3-guides-cli/src/Command/ConfigureCommand.php + path: packages/typo3-docs-theme/src/Compiler/NodeTransformers/CollectPrefixLinkTargetsTransformer.php - - message: "#^SimpleXMLElement does not accept string\\.$#" - count: 4 - path: packages/typo3-guides-cli/src/Command/ConfigureCommand.php - - - - message: "#^Undefined variable\\: \\$guides$#" + message: '#^Binary operation "\." between mixed and string results in an error\.$#' + identifier: binaryOp.invalid count: 2 - path: packages/typo3-guides-cli/src/Command/ConfigureCommand.php - - - - message: "#^Variable \\$guides in isset\\(\\) is never defined\\.$#" - count: 1 - path: packages/typo3-guides-cli/src/Command/ConfigureCommand.php - - - - message: "#^Method T3Docs\\\\GuidesCli\\\\Migration\\\\SettingsMigrator\\:\\:collectUnmigratedLegacySettings\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: packages/typo3-guides-cli/src/Migration/SettingsMigrator.php + path: packages/typo3-docs-theme/src/Compiler/NodeTransformers/CollectPrefixLinkTargetsTransformer.php - - message: "#^Cannot access offset 'packages' on mixed\\.$#" - count: 1 - path: packages/typo3-version-handling/src/Packagist/PackagistService.php + message: '#^Parameter \#1 \$rawAnchor of method phpDocumentor\\Guides\\ReferenceResolvers\\AnchorNormalizer\:\:reduceAnchor\(\) expects string, mixed given\.$#' + identifier: argument.type + count: 2 + path: packages/typo3-docs-theme/src/Compiler/NodeTransformers/CollectPrefixLinkTargetsTransformer.php - - message: "#^Cannot access offset 0 on mixed\\.$#" - count: 1 - path: packages/typo3-version-handling/src/Packagist/PackagistService.php + message: '#^Parameter \#3 \$title of class phpDocumentor\\Guides\\Meta\\InternalTarget constructor expects string\|null, mixed given\.$#' + identifier: argument.type + count: 2 + path: packages/typo3-docs-theme/src/Compiler/NodeTransformers/CollectPrefixLinkTargetsTransformer.php - - message: "#^Cannot access offset string on mixed\\.$#" - count: 1 - path: packages/typo3-version-handling/src/Packagist/PackagistService.php + message: '#^Parameter \#1 \$configs \(array\\) of method T3Docs\\Typo3DocsTheme\\DependencyInjection\\Typo3DocsThemeExtension\:\:load\(\) should be contravariant with parameter \$configs \(array\\>\) of method Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface\:\:load\(\)$#' + identifier: method.childParameterType + count: 2 + path: packages/typo3-docs-theme/src/DependencyInjection/Typo3DocsThemeExtension.php diff --git a/phpstan.neon b/phpstan.neon index 94775d0de..86f7c36ef 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,14 +1,11 @@ includes: - phpstan-baseline.neon -rules: - - Symplify\PHPStanRules\Rules\AnnotateRegexClassConstWithRegexLinkRule - - Symplify\PHPStanRules\Rules\RegexSuffixInRegexConstantRule parameters: phpVersion: 80100 level: max strictRules: allRules: false - strictCalls: true + strictFunctionCalls: true requireParentConstructorCall: true inferPrivatePropertyTypeFromConstructor: true treatPhpDocTypesAsCertain: false