From 83ad969ab6c3030c132c8098c8c1c2bf89ebff42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Vernet?= Date: Fri, 18 Oct 2024 18:19:49 +0200 Subject: [PATCH 1/2] feat: lint twig files with twigstan --- .github/workflows/symfony.yml | 4 +- .gitignore | 4 + castor.php | 11 +- composer.json | 3 +- composer.lock | 560 ++++++++++++++++-- src/Kernel.php | 12 + .../App/Controller/ComposerAction.html.twig | 2 + templates/App/Controller/FormAction.html.twig | 7 +- templates/App/Controller/HomeAction.html.twig | 2 + templates/_form.html.twig | 2 + .../TwigBundle/Exception/error.html.twig | 5 + twig-loader.php | 15 + twigstan.php | 24 + vendor-bin/php-cs-fixer/composer.lock | 8 +- 14 files changed, 615 insertions(+), 44 deletions(-) create mode 100644 twig-loader.php create mode 100644 twigstan.php diff --git a/.github/workflows/symfony.yml b/.github/workflows/symfony.yml index 70cbb52..891f7ad 100644 --- a/.github/workflows/symfony.yml +++ b/.github/workflows/symfony.yml @@ -49,7 +49,7 @@ jobs: strategy: fail-fast: true matrix: - php-versions: ['8.2', '8.3'] + php-versions: ['8.3'] runs-on: ubuntu-latest # Setup ———————————————————————————————————————————————————————————————— @@ -122,5 +122,7 @@ jobs: run: castor lint:php - name: PHPStan static analysis run: castor stan + - name: Lint Twig templates with twigstan + run: castor lint:twigstan # The end. 🙃 diff --git a/.gitignore b/.gitignore index b0de3ae..5374e73 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,7 @@ .phpunit.result.cache .phpunit.cache ###< phpunit/phpunit ### + +###> twigstan/twigstan ### +.twigstan +###< twigstan/twigstan ### diff --git a/castor.php b/castor.php index f3c6c9c..7ace00d 100644 --- a/castor.php +++ b/castor.php @@ -205,6 +205,14 @@ function lint_twig(): int return exit_code('bin/console lint:twig templates/'); } +#[AsTask(name: 'twigstan', namespace: 'lint', description: 'Lint Twig files with twigstan', aliases: ['lint-twigstan'])] +function lint_twigstan(): int +{ + title('lint:twigstan'); + + return exit_code('vendor/bin/twigstan'); +} + #[AsTask(name: 'yaml', namespace: 'lint', description: 'Lint Yaml files', aliases: ['lint-yaml'])] function lint_yaml(): int { @@ -220,7 +228,8 @@ function lint_all(): int $ec1 = lint_php(); $ec2 = lint_container(); $ec3 = lint_twig(); - $ec4 = lint_yaml(); + $ec4 = lint_twigstan(); + $ec5 = lint_yaml(); return success($ec1 + $ec2 + $ec3 + $ec4); diff --git a/composer.json b/composer.json index 27b1a20..5423ca0 100644 --- a/composer.json +++ b/composer.json @@ -57,7 +57,8 @@ "symfony/maker-bundle": "^1.61", "symfony/requirements-checker": "^2.0", "symfony/stopwatch": "~7.1.0", - "symfony/web-profiler-bundle": "~7.1.0" + "symfony/web-profiler-bundle": "~7.1.0", + "twigstan/twigstan": "dev-main" }, "replace": { "symfony/polyfill-ctype": "*", diff --git a/composer.lock b/composer.lock index fea43a0..e9112df 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": "e037fde2e1ee94aa91287693db228676", + "content-hash": "cd107877e98e704b89041f3b7cfadf57", "packages": [ { "name": "composer/semver", @@ -4739,23 +4739,23 @@ }, { "name": "twig/extra-bundle", - "version": "v3.13.0", + "version": "v3.15.0", "source": { "type": "git", "url": "https://github.com/twigphp/twig-extra-bundle.git", - "reference": "21a9a7aa9f79d4493bb6fed4eb2794339f9551f5" + "reference": "9746573ca4bc1cd03a767a183faadaf84e0c31fa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/twig-extra-bundle/zipball/21a9a7aa9f79d4493bb6fed4eb2794339f9551f5", - "reference": "21a9a7aa9f79d4493bb6fed4eb2794339f9551f5", + "url": "https://api.github.com/repos/twigphp/twig-extra-bundle/zipball/9746573ca4bc1cd03a767a183faadaf84e0c31fa", + "reference": "9746573ca4bc1cd03a767a183faadaf84e0c31fa", "shasum": "" }, "require": { "php": ">=8.0.2", "symfony/framework-bundle": "^5.4|^6.4|^7.0", "symfony/twig-bundle": "^5.4|^6.4|^7.0", - "twig/twig": "^3.0|^4.0" + "twig/twig": "^3.2|^4.0" }, "require-dev": { "league/commonmark": "^1.0|^2.0", @@ -4797,7 +4797,7 @@ "twig" ], "support": { - "source": "https://github.com/twigphp/twig-extra-bundle/tree/v3.13.0" + "source": "https://github.com/twigphp/twig-extra-bundle/tree/v3.15.0" }, "funding": [ { @@ -4809,11 +4809,11 @@ "type": "tidelift" } ], - "time": "2024-09-01T20:39:12+00:00" + "time": "2024-09-26T19:22:23+00:00" }, { "name": "twig/markdown-extra", - "version": "v3.13.0", + "version": "v3.15.0", "source": { "type": "git", "url": "https://github.com/twigphp/markdown-extra.git", @@ -4869,7 +4869,7 @@ "twig" ], "support": { - "source": "https://github.com/twigphp/markdown-extra/tree/v3.13.0" + "source": "https://github.com/twigphp/markdown-extra/tree/v3.15.0" }, "funding": [ { @@ -4885,16 +4885,16 @@ }, { "name": "twig/twig", - "version": "v3.14.2", + "version": "v3.15.0", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "0b6f9d8370bb3b7f1ce5313ed8feb0fafd6e399a" + "reference": "2d5b3964cc21d0188633d7ddce732dc8e874db02" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/0b6f9d8370bb3b7f1ce5313ed8feb0fafd6e399a", - "reference": "0b6f9d8370bb3b7f1ce5313ed8feb0fafd6e399a", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/2d5b3964cc21d0188633d7ddce732dc8e874db02", + "reference": "2d5b3964cc21d0188633d7ddce732dc8e874db02", "shasum": "" }, "require": { @@ -4948,7 +4948,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.14.2" + "source": "https://github.com/twigphp/Twig/tree/v3.15.0" }, "funding": [ { @@ -4960,7 +4960,7 @@ "type": "tidelift" } ], - "time": "2024-11-07T12:36:22+00:00" + "time": "2024-11-17T15:59:19+00:00" } ], "packages-dev": [ @@ -5239,6 +5239,363 @@ ], "time": "2024-11-08T17:47:46+00:00" }, + { + "name": "nette/bootstrap", + "version": "v3.2.4", + "source": { + "type": "git", + "url": "https://github.com/nette/bootstrap.git", + "reference": "4876d25955b4164d714bc17c265f664f6594685b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/bootstrap/zipball/4876d25955b4164d714bc17c265f664f6594685b", + "reference": "4876d25955b4164d714bc17c265f664f6594685b", + "shasum": "" + }, + "require": { + "nette/di": "^3.1", + "nette/utils": "^3.2.1 || ^4.0", + "php": "8.0 - 8.4" + }, + "conflict": { + "tracy/tracy": "<2.6" + }, + "require-dev": { + "latte/latte": "^2.8 || ^3.0", + "nette/application": "^3.1", + "nette/caching": "^3.0", + "nette/database": "^3.0", + "nette/forms": "^3.0", + "nette/http": "^3.0", + "nette/mail": "^3.0 || ^4.0", + "nette/robot-loader": "^3.0 || ^4.0", + "nette/safe-stream": "^2.2", + "nette/security": "^3.0", + "nette/tester": "^2.4", + "phpstan/phpstan-nette": "^1.0", + "tracy/tracy": "^2.9" + }, + "suggest": { + "nette/robot-loader": "to use Configurator::createRobotLoader()", + "tracy/tracy": "to use Configurator::enableTracy()" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🅱 Nette Bootstrap: the simple way to configure and bootstrap your Nette application.", + "homepage": "https://nette.org", + "keywords": [ + "bootstrapping", + "configurator", + "nette" + ], + "support": { + "issues": "https://github.com/nette/bootstrap/issues", + "source": "https://github.com/nette/bootstrap/tree/v3.2.4" + }, + "time": "2024-06-18T22:13:57+00:00" + }, + { + "name": "nette/di", + "version": "v3.2.3", + "source": { + "type": "git", + "url": "https://github.com/nette/di.git", + "reference": "9b9bfb43dac31c7804b2c8900217046cc0ca3307" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/di/zipball/9b9bfb43dac31c7804b2c8900217046cc0ca3307", + "reference": "9b9bfb43dac31c7804b2c8900217046cc0ca3307", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-tokenizer": "*", + "nette/neon": "^3.3 || ^4.0", + "nette/php-generator": "^4.1.6", + "nette/robot-loader": "^4.0", + "nette/schema": "^1.2.5", + "nette/utils": "^4.0", + "php": "8.1 - 8.4" + }, + "require-dev": { + "nette/tester": "^2.5.2", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "💎 Nette Dependency Injection Container: Flexible, compiled and full-featured DIC with perfectly usable autowiring and support for all new PHP features.", + "homepage": "https://nette.org", + "keywords": [ + "compiled", + "di", + "dic", + "factory", + "ioc", + "nette", + "static" + ], + "support": { + "issues": "https://github.com/nette/di/issues", + "source": "https://github.com/nette/di/tree/v3.2.3" + }, + "time": "2024-10-05T03:14:33+00:00" + }, + { + "name": "nette/neon", + "version": "v3.4.4", + "source": { + "type": "git", + "url": "https://github.com/nette/neon.git", + "reference": "3411aa86b104e2d5b7e760da4600865ead963c3c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/neon/zipball/3411aa86b104e2d5b7e760da4600865ead963c3c", + "reference": "3411aa86b104e2d5b7e760da4600865ead963c3c", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": "8.0 - 8.4" + }, + "require-dev": { + "nette/tester": "^2.4", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.7" + }, + "bin": [ + "bin/neon-lint" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🍸 Nette NEON: encodes and decodes NEON file format.", + "homepage": "https://ne-on.org", + "keywords": [ + "export", + "import", + "neon", + "nette", + "yaml" + ], + "support": { + "issues": "https://github.com/nette/neon/issues", + "source": "https://github.com/nette/neon/tree/v3.4.4" + }, + "time": "2024-10-04T22:00:08+00:00" + }, + { + "name": "nette/php-generator", + "version": "v4.1.6", + "source": { + "type": "git", + "url": "https://github.com/nette/php-generator.git", + "reference": "c90961e782ae86e517fe5ed732eb2b512945565b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/php-generator/zipball/c90961e782ae86e517fe5ed732eb2b512945565b", + "reference": "c90961e782ae86e517fe5ed732eb2b512945565b", + "shasum": "" + }, + "require": { + "nette/utils": "^3.2.9 || ^4.0", + "php": "8.0 - 8.4" + }, + "require-dev": { + "jetbrains/phpstorm-attributes": "dev-master", + "nette/tester": "^2.4", + "nikic/php-parser": "^4.18 || ^5.0", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.8" + }, + "suggest": { + "nikic/php-parser": "to use ClassType::from(withBodies: true) & ClassType::fromCode()" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🐘 Nette PHP Generator: generates neat PHP code for you. Supports new PHP 8.3 features.", + "homepage": "https://nette.org", + "keywords": [ + "code", + "nette", + "php", + "scaffolding" + ], + "support": { + "issues": "https://github.com/nette/php-generator/issues", + "source": "https://github.com/nette/php-generator/tree/v4.1.6" + }, + "time": "2024-09-10T09:31:55+00:00" + }, + { + "name": "nette/robot-loader", + "version": "v4.0.3", + "source": { + "type": "git", + "url": "https://github.com/nette/robot-loader.git", + "reference": "45d67753fb4865bb718e9a6c9be69cc9470137b7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/robot-loader/zipball/45d67753fb4865bb718e9a6c9be69cc9470137b7", + "reference": "45d67753fb4865bb718e9a6c9be69cc9470137b7", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "nette/utils": "^4.0", + "php": "8.0 - 8.4" + }, + "require-dev": { + "nette/tester": "^2.4", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🍀 Nette RobotLoader: high performance and comfortable autoloader that will search and autoload classes within your application.", + "homepage": "https://nette.org", + "keywords": [ + "autoload", + "class", + "interface", + "nette", + "trait" + ], + "support": { + "issues": "https://github.com/nette/robot-loader/issues", + "source": "https://github.com/nette/robot-loader/tree/v4.0.3" + }, + "time": "2024-06-18T20:26:39+00:00" + }, { "name": "nikic/php-parser", "version": "v5.3.1", @@ -5463,18 +5820,65 @@ }, "time": "2024-09-04T20:21:43+00:00" }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.33.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/82a311fd3690fb2bf7b64d5c98f912b3dd746140", + "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^4.15", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.33.0" + }, + "time": "2024-10-13T11:25:22+00:00" + }, { "name": "phpstan/phpstan", - "version": "2.0.1", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "ab4e9b4415a5fc9e4d27f7fe16c8bc9d067dcd6d" + "reference": "6c98c7600fc717b2c78c11ef60040d5b1e359c82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/ab4e9b4415a5fc9e4d27f7fe16c8bc9d067dcd6d", - "reference": "ab4e9b4415a5fc9e4d27f7fe16c8bc9d067dcd6d", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/6c98c7600fc717b2c78c11ef60040d5b1e359c82", + "reference": "6c98c7600fc717b2c78c11ef60040d5b1e359c82", "shasum": "" }, "require": { @@ -5519,7 +5923,7 @@ "type": "github" } ], - "time": "2024-11-11T15:43:04+00:00" + "time": "2024-11-17T14:17:00+00:00" }, { "name": "phpstan/phpstan-symfony", @@ -6021,12 +6425,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "1b71197bf4ffb07c6beb67162144e07052aac77c" + "reference": "9f1d9b2460cdd0422e8cfd58763bf3156ad7f487" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/1b71197bf4ffb07c6beb67162144e07052aac77c", - "reference": "1b71197bf4ffb07c6beb67162144e07052aac77c", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/9f1d9b2460cdd0422e8cfd58763bf3156ad7f487", + "reference": "9f1d9b2460cdd0422e8cfd58763bf3156ad7f487", "shasum": "" }, "conflict": { @@ -6072,6 +6476,7 @@ "azuracast/azuracast": "<0.18.3", "backdrop/backdrop": "<1.27.3|>=1.28,<1.28.2", "backpack/crud": "<3.4.9", + "backpack/filemanager": "<3.0.9", "bacula-web/bacula-web": "<8.0.0.0-RC2-dev", "badaso/core": "<2.7", "bagisto/bagisto": "<2.1", @@ -6403,7 +6808,7 @@ "mojo42/jirafeau": "<4.4", "mongodb/mongodb": ">=1,<1.9.2", "monolog/monolog": ">=1.8,<1.12", - "moodle/moodle": "<4.3.6|>=4.4,<4.4.2", + "moodle/moodle": "<4.3.6|>=4.4,<4.4.4", "mos/cimage": "<0.7.19", "movim/moxl": ">=0.8,<=0.10", "movingbytes/social-network": "<=1.2.1", @@ -6717,7 +7122,7 @@ "ua-parser/uap-php": "<3.8", "uasoft-indonesia/badaso": "<=2.9.7", "unisharp/laravel-filemanager": "<2.6.4", - "unopim/unopim": "<0.1.4", + "unopim/unopim": "<0.1.5", "userfrosting/userfrosting": ">=0.3.1,<4.6.3", "usmanhalalit/pixie": "<1.0.3|>=2,<2.0.2", "uvdesk/community-skeleton": "<=1.1.1", @@ -6854,7 +7259,7 @@ "type": "tidelift" } ], - "time": "2024-11-13T16:05:45+00:00" + "time": "2024-11-13T19:05:18+00:00" }, { "name": "sebastian/cli-parser", @@ -8134,16 +8539,16 @@ }, { "name": "symfony/requirements-checker", - "version": "v2.0.2", + "version": "v2.0.3", "source": { "type": "git", "url": "https://github.com/symfony/requirements-checker.git", - "reference": "10e35b45057bd44ad1bffbde9e92fe1bb11d7a3b" + "reference": "e68f11c6753d586fb465e17c6c3c8e8d9f642627" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/requirements-checker/zipball/10e35b45057bd44ad1bffbde9e92fe1bb11d7a3b", - "reference": "10e35b45057bd44ad1bffbde9e92fe1bb11d7a3b", + "url": "https://api.github.com/repos/symfony/requirements-checker/zipball/e68f11c6753d586fb465e17c6c3c8e8d9f642627", + "reference": "e68f11c6753d586fb465e17c6c3c8e8d9f642627", "shasum": "" }, "require": { @@ -8175,7 +8580,7 @@ ], "support": { "issues": "https://github.com/symfony/requirements-checker/issues", - "source": "https://github.com/symfony/requirements-checker/tree/v2.0.2" + "source": "https://github.com/symfony/requirements-checker/tree/v2.0.3" }, "funding": [ { @@ -8191,7 +8596,7 @@ "type": "tidelift" } ], - "time": "2024-11-09T08:04:39+00:00" + "time": "2024-11-14T22:24:57+00:00" }, { "name": "symfony/stopwatch", @@ -8385,12 +8790,95 @@ } ], "time": "2024-03-03T12:36:25+00:00" + }, + { + "name": "twigstan/twigstan", + "version": "dev-main", + "source": { + "type": "git", + "url": "https://github.com/twigstan/twigstan.git", + "reference": "860b910ae4377e1889d1daa43792085993868511" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigstan/twigstan/zipball/860b910ae4377e1889d1daa43792085993868511", + "reference": "860b910ae4377e1889d1daa43792085993868511", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.2", + "nette/bootstrap": "^3.2", + "nette/di": "^3.2.2", + "nette/neon": "^3.4", + "nikic/php-parser": "^5.1.0", + "php": "^8.3", + "phpstan/phpdoc-parser": "^1.30", + "phpstan/phpstan": "^1.12.8 || ^2.0", + "symfony/console": "^7.1", + "symfony/filesystem": "^7.1", + "symfony/finder": "^7.1", + "symfony/process": "^7.1", + "twig/twig": "^3.13" + }, + "require-dev": { + "editorconfig-checker/editorconfig-checker": "^10.6", + "ergebnis/composer-normalize": "^2.43", + "erickskrauch/php-cs-fixer-custom-fixers": "^1.3", + "friendsofphp/php-cs-fixer": "^3.59", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan-deprecation-rules": "^1.2", + "phpstan/phpstan-strict-rules": "^1.6", + "phpstan/phpstan-symfony": "^1.4", + "phpunit/phpunit": "^11.4", + "shipmonk/composer-dependency-analyser": "^1.7", + "staabm/phpstan-todo-by": "^0.1.32", + "symfony/form": "^7.1", + "symfony/framework-bundle": "^7.1", + "symfony/http-foundation": "^7.1", + "symfony/http-kernel": "^7.1", + "symfony/routing": "^7.1", + "symfony/twig-bridge": "^7.1", + "symfony/var-dumper": "^7.1", + "ticketswap/phpstan-error-formatter": "^1.0.3", + "vincentlanglet/twig-cs-fixer": "^3.1" + }, + "default-branch": true, + "bin": [ + "bin/twigstan" + ], + "type": "library", + "autoload": { + "psr-4": { + "TwigStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "TwigStan is a static analyzer for Twig templates powered by PHPStan", + "keywords": [ + "static analysis", + "twig" + ], + "support": { + "issues": "https://github.com/twigstan/twigstan/issues", + "source": "https://github.com/twigstan/twigstan/tree/main" + }, + "funding": [ + { + "url": "https://github.com/twigstan", + "type": "github" + } + ], + "time": "2024-11-16T18:55:02+00:00" } ], "aliases": [], "minimum-stability": "beta", "stability-flags": { - "roave/security-advisories": 20 + "roave/security-advisories": 20, + "twigstan/twigstan": 20 }, "prefer-stable": true, "prefer-lowest": false, @@ -8403,6 +8891,6 @@ "ext-simplexml": "*", "ext-xml": "*" }, - "platform-dev": [], - "plugin-api-version": "2.3.0" + "platform-dev": {}, + "plugin-api-version": "2.6.0" } diff --git a/src/Kernel.php b/src/Kernel.php index 4cf4eed..e5f03d4 100644 --- a/src/Kernel.php +++ b/src/Kernel.php @@ -5,9 +5,21 @@ namespace App; use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Kernel as BaseKernel; final class Kernel extends BaseKernel { use MicroKernelTrait; + + protected function build(ContainerBuilder $container): void + { + $container->addCompilerPass(new class implements CompilerPassInterface { + public function process(ContainerBuilder $container): void + { + $container->getDefinition('twig')->setPublic(true); + } + }); + } } diff --git a/templates/App/Controller/ComposerAction.html.twig b/templates/App/Controller/ComposerAction.html.twig index bc05f67..6bd033b 100644 --- a/templates/App/Controller/ComposerAction.html.twig +++ b/templates/App/Controller/ComposerAction.html.twig @@ -1,5 +1,7 @@ {% extends 'base.html.twig' %} +{% types { composer: 'string' } %} + {% block body %}

Composer ⚡

diff --git a/templates/App/Controller/FormAction.html.twig b/templates/App/Controller/FormAction.html.twig index 6601f31..341e840 100644 --- a/templates/App/Controller/FormAction.html.twig +++ b/templates/App/Controller/FormAction.html.twig @@ -1,5 +1,10 @@ {% extends 'base.html.twig' %} +{% types { + dto: 'App\\Dto\\RegisterFormDto', + form: 'Symfony\\Component\\Form\\FormView' +} %} + {% set h2 = 'Form example' %} {% block title %}{{ h2 }} | {{ brand }}{% endblock %} @@ -45,7 +50,7 @@ Birthay - {{ dto.birthday|date('Y-m-d') }} + {{ dto.birthday ? dto.birthday|date('Y-m-d') : 'NA' }} diff --git a/templates/App/Controller/HomeAction.html.twig b/templates/App/Controller/HomeAction.html.twig index e53daee..58fef57 100644 --- a/templates/App/Controller/HomeAction.html.twig +++ b/templates/App/Controller/HomeAction.html.twig @@ -1,5 +1,7 @@ {% extends 'base.html.twig' %} +{% types { readme: 'string' } %} + {% block body %}

This page displays the README.md file of the GitHub repository.

diff --git a/templates/_form.html.twig b/templates/_form.html.twig index 73db647..38eaf98 100644 --- a/templates/_form.html.twig +++ b/templates/_form.html.twig @@ -1,3 +1,5 @@ +{% types { form: 'Symfony\\Component\\Form\\FormView' } %} +
{{ form(form, {'attr': {'novalidate': 'novalidate'}}) }}
\ No newline at end of file diff --git a/templates/bundles/TwigBundle/Exception/error.html.twig b/templates/bundles/TwigBundle/Exception/error.html.twig index 957e2fa..2426670 100644 --- a/templates/bundles/TwigBundle/Exception/error.html.twig +++ b/templates/bundles/TwigBundle/Exception/error.html.twig @@ -1,5 +1,10 @@ {% extends 'base.html.twig' %} +{% types { + status_code: 'int', + status_text: 'string', +} %} + {% block icon %}⛔️{% endblock %} {% block title %}Error {{ status_code }}{% endblock %} diff --git a/twig-loader.php b/twig-loader.php new file mode 100644 index 0000000..de2d526 --- /dev/null +++ b/twig-loader.php @@ -0,0 +1,15 @@ +bootEnv(__DIR__.'/.env'); + +$kernel = new Kernel($_ENV['APP_ENV'], (bool) $_ENV['APP_DEBUG']); +$kernel->boot(); + +return $kernel->getContainer()->get('twig'); diff --git a/twigstan.php b/twigstan.php new file mode 100644 index 0000000..0928a4c --- /dev/null +++ b/twigstan.php @@ -0,0 +1,24 @@ +reportUnmatchedIgnoredErrors(true) + ->phpstanConfigurationFile(__DIR__.'/phpstan.neon') + ->phpstanMemoryLimit(false) + ->twigEnvironmentLoader(__DIR__.'/twig-loader.php') + ->twigPaths(__DIR__.'/templates') + // ->twigPaths(__DIR__ . '/tests/EndToEnd/Types') + // ->twigExcludes('something.html.twig') + // ->phpPaths(__DIR__ . '/tests/Fixtures') + // ->phpExcludes('something.php') + // ->ignoreErrors( + // TwigStan\Error\IgnoreError::create('#SomeOther#', 'someIdentifier.someValue', __DIR__ . '/some/path.php'), + // TwigStan\Error\IgnoreError::message('#SomePattern#'), + // TwigStan\Error\IgnoreError::identifier('someIdentifier'), + // TwigStan\Error\IgnoreError::path(__DIR__ . '/some/path.php'), + // TwigStan\Error\IgnoreError::messageAndIdentifier('#SomePattern#', 'someIdentifier'), + // TwigStan\Error\IgnoreError::messageAndPath('#SomePattern#', __DIR__ . '/some/path.php'), + // TwigStan\Error\IgnoreError::identifierAndPath('someIdentifier', __DIR__ . '/some/path.php'), + // ) + ->create(); diff --git a/vendor-bin/php-cs-fixer/composer.lock b/vendor-bin/php-cs-fixer/composer.lock index c660d95..95c2cad 100644 --- a/vendor-bin/php-cs-fixer/composer.lock +++ b/vendor-bin/php-cs-fixer/composer.lock @@ -2541,10 +2541,10 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, - "platform": [], - "platform-dev": [], - "plugin-api-version": "2.3.0" + "platform": {}, + "platform-dev": {}, + "plugin-api-version": "2.6.0" } From a310c9de9676385a9c7753f1c43d09cca72ea651 Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Mon, 21 Oct 2024 21:21:22 +0200 Subject: [PATCH 2/2] TwigStan tweaks (#99) --- composer.json | 2 +- composer.lock | 49 ++++++++++--------- src/Kernel.php | 12 ----- .../App/Controller/ComposerAction.html.twig | 2 - templates/App/Controller/FormAction.html.twig | 5 -- templates/App/Controller/HomeAction.html.twig | 2 - twig-loader.php | 4 +- twigstan.php | 18 ++----- 8 files changed, 32 insertions(+), 62 deletions(-) diff --git a/composer.json b/composer.json index 5423ca0..e87e433 100644 --- a/composer.json +++ b/composer.json @@ -49,7 +49,7 @@ "require-dev": { "bamarni/composer-bin-plugin": "^1.8", "phpstan/extension-installer": "^1.3", - "phpstan/phpstan-symfony": "^2.0", + "phpstan/phpstan-symfony": "^1.0", "phpunit/phpunit": "^11.0", "roave/security-advisories": "dev-latest", "symfony/browser-kit": "~7.1.0", diff --git a/composer.lock b/composer.lock index e9112df..f3e08df 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": "cd107877e98e704b89041f3b7cfadf57", + "content-hash": "67fcdc4cef755ca3c9a28b2c8bab3e32", "packages": [ { "name": "composer/semver", @@ -5869,20 +5869,20 @@ }, { "name": "phpstan/phpstan", - "version": "2.0.2", + "version": "1.12.11", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "6c98c7600fc717b2c78c11ef60040d5b1e359c82" + "reference": "0d1fc20a962a91be578bcfe7cf939e6e1a2ff733" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/6c98c7600fc717b2c78c11ef60040d5b1e359c82", - "reference": "6c98c7600fc717b2c78c11ef60040d5b1e359c82", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0d1fc20a962a91be578bcfe7cf939e6e1a2ff733", + "reference": "0d1fc20a962a91be578bcfe7cf939e6e1a2ff733", "shasum": "" }, "require": { - "php": "^7.4|^8.0" + "php": "^7.2|^8.0" }, "conflict": { "phpstan/phpstan-shim": "*" @@ -5923,35 +5923,36 @@ "type": "github" } ], - "time": "2024-11-17T14:17:00+00:00" + "time": "2024-11-17T14:08:01+00:00" }, { "name": "phpstan/phpstan-symfony", - "version": "2.0.0", + "version": "1.4.12", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-symfony.git", - "reference": "1ef4dce2baabd464c2dd3109d051bad94efa1e79" + "reference": "c7b7e7f520893621558bfbfdb2694d4364565c1d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/1ef4dce2baabd464c2dd3109d051bad94efa1e79", - "reference": "1ef4dce2baabd464c2dd3109d051bad94efa1e79", + "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/c7b7e7f520893621558bfbfdb2694d4364565c1d", + "reference": "c7b7e7f520893621558bfbfdb2694d4364565c1d", "shasum": "" }, "require": { "ext-simplexml": "*", - "php": "^7.4 || ^8.0", - "phpstan/phpstan": "^2.0" + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.12" }, "conflict": { "symfony/framework-bundle": "<3.0" }, "require-dev": { + "nikic/php-parser": "^4.13.0", "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpstan-phpunit": "^2.0", - "phpstan/phpstan-strict-rules": "^2.0", - "phpunit/phpunit": "^9.6", + "phpstan/phpstan-phpunit": "^1.3.11", + "phpstan/phpstan-strict-rules": "^1.5.1", + "phpunit/phpunit": "^8.5.29 || ^9.5", "psr/container": "1.0 || 1.1.1", "symfony/config": "^5.4 || ^6.1", "symfony/console": "^5.4 || ^6.1", @@ -5992,9 +5993,9 @@ "description": "Symfony Framework extensions and rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-symfony/issues", - "source": "https://github.com/phpstan/phpstan-symfony/tree/2.0.0" + "source": "https://github.com/phpstan/phpstan-symfony/tree/1.4.12" }, - "time": "2024-11-06T10:13:40+00:00" + "time": "2024-11-06T10:13:18+00:00" }, { "name": "phpunit/php-code-coverage", @@ -8797,12 +8798,12 @@ "source": { "type": "git", "url": "https://github.com/twigstan/twigstan.git", - "reference": "860b910ae4377e1889d1daa43792085993868511" + "reference": "0b377246f9df05ea40eaa444fe43247a4eb89615" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigstan/twigstan/zipball/860b910ae4377e1889d1daa43792085993868511", - "reference": "860b910ae4377e1889d1daa43792085993868511", + "url": "https://api.github.com/repos/twigstan/twigstan/zipball/0b377246f9df05ea40eaa444fe43247a4eb89615", + "reference": "0b377246f9df05ea40eaa444fe43247a4eb89615", "shasum": "" }, "require": { @@ -8813,12 +8814,12 @@ "nikic/php-parser": "^5.1.0", "php": "^8.3", "phpstan/phpdoc-parser": "^1.30", - "phpstan/phpstan": "^1.12.8 || ^2.0", + "phpstan/phpstan": "^1.12.8", "symfony/console": "^7.1", "symfony/filesystem": "^7.1", "symfony/finder": "^7.1", "symfony/process": "^7.1", - "twig/twig": "^3.13" + "twig/twig": "3.15.0" }, "require-dev": { "editorconfig-checker/editorconfig-checker": "^10.6", @@ -8871,7 +8872,7 @@ "type": "github" } ], - "time": "2024-11-16T18:55:02+00:00" + "time": "2024-11-18T08:17:03+00:00" } ], "aliases": [], diff --git a/src/Kernel.php b/src/Kernel.php index e5f03d4..4cf4eed 100644 --- a/src/Kernel.php +++ b/src/Kernel.php @@ -5,21 +5,9 @@ namespace App; use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; -use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; -use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Kernel as BaseKernel; final class Kernel extends BaseKernel { use MicroKernelTrait; - - protected function build(ContainerBuilder $container): void - { - $container->addCompilerPass(new class implements CompilerPassInterface { - public function process(ContainerBuilder $container): void - { - $container->getDefinition('twig')->setPublic(true); - } - }); - } } diff --git a/templates/App/Controller/ComposerAction.html.twig b/templates/App/Controller/ComposerAction.html.twig index 6bd033b..bc05f67 100644 --- a/templates/App/Controller/ComposerAction.html.twig +++ b/templates/App/Controller/ComposerAction.html.twig @@ -1,7 +1,5 @@ {% extends 'base.html.twig' %} -{% types { composer: 'string' } %} - {% block body %}

Composer ⚡

diff --git a/templates/App/Controller/FormAction.html.twig b/templates/App/Controller/FormAction.html.twig index 341e840..409a945 100644 --- a/templates/App/Controller/FormAction.html.twig +++ b/templates/App/Controller/FormAction.html.twig @@ -1,10 +1,5 @@ {% extends 'base.html.twig' %} -{% types { - dto: 'App\\Dto\\RegisterFormDto', - form: 'Symfony\\Component\\Form\\FormView' -} %} - {% set h2 = 'Form example' %} {% block title %}{{ h2 }} | {{ brand }}{% endblock %} diff --git a/templates/App/Controller/HomeAction.html.twig b/templates/App/Controller/HomeAction.html.twig index 58fef57..e53daee 100644 --- a/templates/App/Controller/HomeAction.html.twig +++ b/templates/App/Controller/HomeAction.html.twig @@ -1,7 +1,5 @@ {% extends 'base.html.twig' %} -{% types { readme: 'string' } %} - {% block body %}

This page displays the README.md file of the GitHub repository.

diff --git a/twig-loader.php b/twig-loader.php index de2d526..76e9de1 100644 --- a/twig-loader.php +++ b/twig-loader.php @@ -9,7 +9,7 @@ (new Dotenv())->bootEnv(__DIR__.'/.env'); -$kernel = new Kernel($_ENV['APP_ENV'], (bool) $_ENV['APP_DEBUG']); +$kernel = new Kernel('test', true); $kernel->boot(); -return $kernel->getContainer()->get('twig'); +return $kernel->getContainer()->get('test.service_container')->get('twig'); diff --git a/twigstan.php b/twigstan.php index 0928a4c..7c45286 100644 --- a/twigstan.php +++ b/twigstan.php @@ -2,23 +2,13 @@ declare(strict_types=1); -return TwigStan\Config\TwigStanConfig::configure(__DIR__) +use TwigStan\Config\TwigStanConfig; + +return TwigStanConfig::configure(__DIR__) ->reportUnmatchedIgnoredErrors(true) ->phpstanConfigurationFile(__DIR__.'/phpstan.neon') ->phpstanMemoryLimit(false) ->twigEnvironmentLoader(__DIR__.'/twig-loader.php') ->twigPaths(__DIR__.'/templates') - // ->twigPaths(__DIR__ . '/tests/EndToEnd/Types') - // ->twigExcludes('something.html.twig') - // ->phpPaths(__DIR__ . '/tests/Fixtures') - // ->phpExcludes('something.php') - // ->ignoreErrors( - // TwigStan\Error\IgnoreError::create('#SomeOther#', 'someIdentifier.someValue', __DIR__ . '/some/path.php'), - // TwigStan\Error\IgnoreError::message('#SomePattern#'), - // TwigStan\Error\IgnoreError::identifier('someIdentifier'), - // TwigStan\Error\IgnoreError::path(__DIR__ . '/some/path.php'), - // TwigStan\Error\IgnoreError::messageAndIdentifier('#SomePattern#', 'someIdentifier'), - // TwigStan\Error\IgnoreError::messageAndPath('#SomePattern#', __DIR__ . '/some/path.php'), - // TwigStan\Error\IgnoreError::identifierAndPath('someIdentifier', __DIR__ . '/some/path.php'), - // ) + ->phpPaths(__DIR__.'/src/Controller') ->create();