From 2d0805c622e860fc670daa808b1b28b926b3bd66 Mon Sep 17 00:00:00 2001 From: "Reymart A. Calicdan" <163510169+rcalicdan@users.noreply.github.com> Date: Sun, 30 Aug 2026 15:38:13 +0000 Subject: [PATCH] try typhp --- .github/workflows/benchmark.yml | 10 +- .github/workflows/integration-tests.yml | 82 ++++++--- composer.json | 1 + packages/auth/composer.json | 5 +- .../auth/src/AccessControl/AccessControl.php | 4 +- .../PolicyBasedAccessControl.php | 4 +- .../AuthenticationAndOAuthSafetyTest.php | 3 + packages/cache/composer.json | 3 +- .../cache/src/Commands/CacheStatusCommand.php | 2 +- packages/clock/composer.json | 3 + packages/command-bus/composer.json | 3 + packages/console/composer.json | 5 +- .../src/Actions/ResolveConsoleInput.php | 2 +- packages/console/src/Components/Option.php | 2 +- packages/console/src/Console.php | 2 +- packages/console/src/ConsoleInputBuilder.php | 2 +- .../console/src/Input/ConsoleArgumentBag.php | 2 +- packages/container/composer.json | 5 +- packages/container/src/Container.php | 1 + packages/container/src/GenericContainer.php | 3 +- packages/core/composer.json | 3 +- packages/cryptography/composer.json | 5 +- .../tests/Encryption/EncryptionTest.php | 6 + packages/database/composer.json | 5 +- packages/database/src/functions.php | 2 +- packages/datetime/composer.json | 5 +- packages/datetime/typephp.php | 7 + packages/debug/composer.json | 3 +- packages/discovery/composer.json | 3 +- packages/discovery/src/BootDiscovery.php | 2 +- packages/discovery/src/DiscoveryCache.php | 2 +- packages/event-bus/composer.json | 5 +- packages/generation/composer.json | 5 +- .../generation/src/Php/StubFileGenerator.php | 4 +- .../Writers/NamespacedFileWriter.php | 2 +- packages/http-client/composer.json | 5 +- packages/http/composer.json | 5 +- packages/http/src/GenericResponse.php | 6 + packages/http/src/RequestHeaders.php | 2 +- packages/http/src/Responses/Json.php | 5 + packages/icon/composer.json | 5 +- packages/idempotency/composer.json | 5 +- packages/intl/composer.json | 5 +- packages/kv-store/composer.json | 3 +- packages/log/composer.json | 5 +- packages/mail/composer.json | 3 +- packages/mapper/composer.json | 5 +- packages/mcp/composer.json | 5 +- packages/process/composer.json | 5 +- packages/reflection/composer.json | 5 +- packages/router/composer.json | 5 +- packages/router/src/Exceptions/local/bun.lock | 2 +- .../Routing/Matching/GenericRouteMatcher.php | 2 +- packages/storage/composer.json | 3 +- packages/support/composer.json | 5 +- packages/support/src/Arr/ManipulatesArray.php | 8 +- packages/support/src/Arr/functions.php | 24 +-- packages/support/src/Namespace/functions.php | 2 +- packages/support/src/Regex/functions.php | 2 +- packages/validation/composer.json | 5 +- packages/view/composer.json | 5 +- packages/vite/composer.json | 5 +- stubs/class-stubs.stub | 71 +++++++ tests/Integration/Mailer/MailerTesterTest.php | 2 + .../Route/RequestToObjectMapperTest.php | 1 + .../Support/GeneratesArguments.php | 1 + typephp.php | 173 ++++++++++++++++++ 67 files changed, 486 insertions(+), 102 deletions(-) create mode 100644 packages/datetime/typephp.php create mode 100644 stubs/class-stubs.stub create mode 100644 typephp.php diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 2df8b3f093..6890b1171e 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -27,6 +27,10 @@ jobs: if: ${{ github.event.pull_request.base.ref == github.event.repository.default_branch }} name: Performance Regression Check runs-on: ubuntu-latest + + # Disable TypePHP completely for phpbench runs + env: + TYPEPHP_DISABLE: "true" steps: - name: Checkout PR branch @@ -42,7 +46,7 @@ jobs: coverage: none - name: Install dependencies - uses: ramsey/composer-install@v3 + run: composer update --no-interaction --prefer-dist --quiet - name: Benchmark base branch run: | @@ -73,8 +77,8 @@ jobs: echo "${{ github.event.pull_request.head.sha }}" > benchmark-artifact/head-sha.txt - name: Upload benchmark artifact - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v4 with: name: benchmark-result path: benchmark-artifact/ - retention-days: 1 + retention-days: 1 \ No newline at end of file diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 0ab2c4d504..4d4590a9e5 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -5,9 +5,13 @@ on: paths-ignore: - "docs/**" - ".github/**" + push: + branches: + - main workflow_dispatch: schedule: - cron: "0 0 * * *" + env: POSTGRES_USER: runner POSTGRES_PASSWORD: "" @@ -18,16 +22,43 @@ concurrency: cancel-in-progress: true jobs: - vitest: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - php: [8.5] - os: [ubuntu-latest] + discover-domains: + name: "Discover Integration Domains" + runs-on: ubuntu-latest + outputs: + domains: ${{ steps.scan.outputs.domains }} + steps: + - name: Checkout code + uses: actions/checkout@v4 - name: "Run tests: ${{ matrix.os }}" + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.3' + coverage: none + + - name: Scan Integration directories + id: scan + run: | + php -r ' + $domains = []; + foreach (glob("tests/Integration/*", GLOB_ONLYDIR) as $dir) { + $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir)); + foreach ($it as $file) { + if (str_ends_with($file->getFilename(), "Test.php")) { + $domains[] = basename($dir); + break; + } + } + } + sort($domains); + echo "domains=" . json_encode(array_values(array_unique($domains))) . "\n"; + ' >> $GITHUB_OUTPUT + + vitest: + runs-on: ubuntu-latest + name: "Run JS tests" steps: - name: Checkout code uses: actions/checkout@v4 @@ -35,9 +66,9 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: ${{ matrix.php }} + php-version: 8.5 extensions: dom, curl, libxml, mbstring, pcntl, fileinfo, pdo, sqlite, pdo_sqlite, pdo_mysql, pdo_pgsql, intl, ftp, zip - coverage: pcov + coverage: none - name: Setup Bun uses: oven-sh/setup-bun@v2 @@ -52,27 +83,29 @@ jobs: run: bun run test phpunit: + needs: discover-domains runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-latest] php: [8.5] - database: [sqlite, mysql, postgres] + database: [sqlite] stability: [prefer-stable] + domain: ${{ fromJson(needs.discover-domains.outputs.domains) }} include: - - os: windows-latest + - os: ubuntu-latest php: 8.5 - database: sqlite + database: mysql stability: prefer-stable + domain: Database - os: ubuntu-latest php: 8.5 - database: sqlite - stability: prefer-lowest - env: - POSTGRES_USER: ${{ matrix.os == 'windows-latest' && 'postgres' || 'runner' }} + database: postgres + stability: prefer-stable + domain: Database - name: "Run tests: PHP ${{ matrix.php }} - ${{ matrix.database }} - ${{ matrix.stability }} - ${{ matrix.os }}" + name: "${{ matrix.domain }} (PHP ${{ matrix.php }} - ${{ matrix.database }})" steps: - name: Checkout code @@ -83,7 +116,7 @@ jobs: with: php-version: ${{ matrix.php }} extensions: dom, curl, libxml, mbstring, pcntl, fileinfo, pdo, sqlite, pdo_sqlite, pdo_mysql, pdo_pgsql, intl, ftp, zip - coverage: pcov + coverage: none - name: Setup problem matchers run: | @@ -91,10 +124,13 @@ jobs: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" - name: Install dependencies - run: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --ignore-platform-reqs + run: composer update --${{ matrix.stability }} --prefer-dist --no-interaction --ignore-platform-reqs + + - name: Warm Up TypePHP Cache + run: php vendor/bin/typephp cache:warm - name: "Setup Redis" - if: ${{ matrix.os != 'windows-latest' }} + if: ${{ matrix.domain == 'Cache' || matrix.domain == 'Framework' }} uses: supercharge/redis-github-action@1.8.1 - name: "Setup MySQL" @@ -125,5 +161,5 @@ jobs: - name: List discovered locations run: php ./tempest discovery:status - - name: Execute tests - run: php -d"error_reporting = E_ALL & ~E_DEPRECATED" -dmemory_limit=2G vendor/bin/paratest --runner WrapperRunner --processes 4 + - name: Execute domain tests + run: php -d"error_reporting = E_ALL & ~E_DEPRECATED" -dmemory_limit=2G vendor/bin/paratest --runner WrapperRunner --processes 4 tests/Integration/${{ matrix.domain }} \ No newline at end of file diff --git a/composer.json b/composer.json index 8b52e1f50f..e8cbf187c2 100644 --- a/composer.json +++ b/composer.json @@ -91,6 +91,7 @@ "tempest/blade": "dev-main", "thenetworg/oauth2-azure": "^2.2", "twig/twig": "^3.16", + "typephp/typephp" : "^0.7.1", "vertisan/oauth2-twitch-helix": "^2.0", "wohali/oauth2-discord-new": "^1.2" }, diff --git a/packages/auth/composer.json b/packages/auth/composer.json index 6de3c46073..1c6821dac1 100644 --- a/packages/auth/composer.json +++ b/packages/auth/composer.json @@ -22,7 +22,8 @@ "adam-paterson/oauth2-slack": "^1.1", "wohali/oauth2-discord-new": "^1.2", "smolblog/oauth2-twitter": "^1.0", - "vertisan/oauth2-twitch-helix": "^2.0" + "vertisan/oauth2-twitch-helix": "^2.0", + "typephp/typephp": "^0.7.1" }, "autoload": { "psr-4": { @@ -44,4 +45,4 @@ }, "license": "MIT", "minimum-stability": "dev" -} +} \ No newline at end of file diff --git a/packages/auth/src/AccessControl/AccessControl.php b/packages/auth/src/AccessControl/AccessControl.php index 5d4f18fbb5..5475ce9cc2 100644 --- a/packages/auth/src/AccessControl/AccessControl.php +++ b/packages/auth/src/AccessControl/AccessControl.php @@ -6,8 +6,8 @@ use UnitEnum; /** - * @template TSubject of object - * @template TResource of object + * @template TSubject of object = object + * @template TResource of object = object */ interface AccessControl { diff --git a/packages/auth/src/AccessControl/PolicyBasedAccessControl.php b/packages/auth/src/AccessControl/PolicyBasedAccessControl.php index 88cb780da9..19bd8b97ab 100644 --- a/packages/auth/src/AccessControl/PolicyBasedAccessControl.php +++ b/packages/auth/src/AccessControl/PolicyBasedAccessControl.php @@ -17,9 +17,7 @@ use UnitEnum; /** - * @template TSubject of object - * @template TResource of object - * @implements AccessControl + * @implements AccessControl */ final readonly class PolicyBasedAccessControl implements AccessControl { diff --git a/packages/auth/tests/AuthenticationAndOAuthSafetyTest.php b/packages/auth/tests/AuthenticationAndOAuthSafetyTest.php index 09ae269d8e..8de10595b1 100644 --- a/packages/auth/tests/AuthenticationAndOAuthSafetyTest.php +++ b/packages/auth/tests/AuthenticationAndOAuthSafetyTest.php @@ -16,6 +16,9 @@ final class AuthenticationAndOAuthSafetyTest extends TestCase { + /** + * @typephp-ignore + */ #[Test] public function database_authenticatable_resolver_rejects_non_authenticatable_classes(): void { diff --git a/packages/cache/composer.json b/packages/cache/composer.json index b09bb78e11..37202f32e8 100644 --- a/packages/cache/composer.json +++ b/packages/cache/composer.json @@ -11,7 +11,8 @@ "tempest/container": "3.x-dev" }, "require-dev": { - "tempest/clock": "3.x-dev" + "tempest/clock": "3.x-dev", + "typephp/typephp": "^0.7.1" }, "autoload": { "psr-4": { diff --git a/packages/cache/src/Commands/CacheStatusCommand.php b/packages/cache/src/Commands/CacheStatusCommand.php index 7c2c70e189..bb8e7c8a79 100644 --- a/packages/cache/src/Commands/CacheStatusCommand.php +++ b/packages/cache/src/Commands/CacheStatusCommand.php @@ -50,7 +50,7 @@ public function __invoke(bool $internal = true): void $this->console->header('Internal caches'); foreach ([ConfigCache::class, ViewCache::class, IconCache::class] as $cacheName) { - /** @var Cache $cache */ + /** @var ConfigCache|ViewCache|IconCache $cache */ $cache = $this->container->get($cacheName); $this->console->keyValue( diff --git a/packages/clock/composer.json b/packages/clock/composer.json index 307bf62ce7..7403598d9a 100644 --- a/packages/clock/composer.json +++ b/packages/clock/composer.json @@ -6,6 +6,9 @@ "psr/clock": "^1.0.0", "tempest/datetime": "3.x-dev" }, + "require-dev": { + "typephp/typephp": "^0.7.1" + }, "autoload": { "psr-4": { "Tempest\\Clock\\": "src" diff --git a/packages/command-bus/composer.json b/packages/command-bus/composer.json index 125adee1b3..ec65e2e41a 100644 --- a/packages/command-bus/composer.json +++ b/packages/command-bus/composer.json @@ -7,6 +7,9 @@ "tempest/console": "3.x-dev", "tempest/container": "3.x-dev" }, + "require-dev": { + "typephp/typephp": "^0.7.1" + }, "autoload": { "files": [ "src/functions.php" diff --git a/packages/console/composer.json b/packages/console/composer.json index 66e7894867..2bf7662871 100644 --- a/packages/console/composer.json +++ b/packages/console/composer.json @@ -16,6 +16,9 @@ "tempest/validation": "3.x-dev", "ext-readline": "*" }, + "require-dev": { + "typephp/typephp": "^0.7.1" + }, "suggest": { "ext-pcntl": "Required to use some interactive console components.", "ext-posix": "Required to use some interactive console components." @@ -34,4 +37,4 @@ "bin/tempest", "bin/tempest-complete" ] -} +} \ No newline at end of file diff --git a/packages/console/src/Actions/ResolveConsoleInput.php b/packages/console/src/Actions/ResolveConsoleInput.php index afc5923324..6c32d22219 100644 --- a/packages/console/src/Actions/ResolveConsoleInput.php +++ b/packages/console/src/Actions/ResolveConsoleInput.php @@ -12,7 +12,7 @@ final readonly class ResolveConsoleInput { /** - * @param list $argumentDefinitions + * @param ConsoleArgumentDefinition[] $argumentDefinitions * * @return array{0: list, 1: list} */ diff --git a/packages/console/src/Components/Option.php b/packages/console/src/Components/Option.php index 08aaab83ee..1ab353559d 100644 --- a/packages/console/src/Components/Option.php +++ b/packages/console/src/Components/Option.php @@ -12,7 +12,7 @@ */ final class Option { - /** @var T */ + /** @var (T is UnitEnum ? string : T) */ public mixed $displayValue { get { if (! $this->value instanceof UnitEnum) { diff --git a/packages/console/src/Console.php b/packages/console/src/Console.php index 0e86223202..c2b0d5d213 100644 --- a/packages/console/src/Console.php +++ b/packages/console/src/Console.php @@ -86,7 +86,7 @@ public function progressBar(iterable $data, Closure $handler): array; /** * Asks the user to select an option from a list using a closure. * - * @param Closure(string $search): array $search + * @param Closure(?string $search): array $search */ public function search(string $label, Closure $search, bool $multiple = false, string|array|null $default = null): mixed; diff --git a/packages/console/src/ConsoleInputBuilder.php b/packages/console/src/ConsoleInputBuilder.php index 2d034d1deb..4c04e02418 100644 --- a/packages/console/src/ConsoleInputBuilder.php +++ b/packages/console/src/ConsoleInputBuilder.php @@ -17,7 +17,7 @@ public function __construct( ) {} /** - * @return array + * @return list */ public function build(): array { diff --git a/packages/console/src/Input/ConsoleArgumentBag.php b/packages/console/src/Input/ConsoleArgumentBag.php index f399b40f12..5b6cafa314 100644 --- a/packages/console/src/Input/ConsoleArgumentBag.php +++ b/packages/console/src/Input/ConsoleArgumentBag.php @@ -13,7 +13,7 @@ final class ConsoleArgumentBag /** @var ConsoleInputArgument[] */ private(set) array $arguments = []; - /** @var string[] */ + /** @var (string|null)[] */ private array $path = []; /** diff --git a/packages/container/composer.json b/packages/container/composer.json index 0d0473a7c7..66a8c27734 100644 --- a/packages/container/composer.json +++ b/packages/container/composer.json @@ -8,6 +8,9 @@ "tempest/reflection": "3.x-dev", "psr/container": "^2.0" }, + "require-dev": { + "typephp/typephp": "^0.7.1" + }, "autoload": { "files": [ "src/functions.php" @@ -21,4 +24,4 @@ "Tempest\\Container\\Tests\\": "tests" } } -} +} \ No newline at end of file diff --git a/packages/container/src/Container.php b/packages/container/src/Container.php index dba11e198a..a5ff8243e5 100644 --- a/packages/container/src/Container.php +++ b/packages/container/src/Container.php @@ -21,6 +21,7 @@ public function singleton(string $className, mixed $definition, string|UnitEnum| public function config(object $config): self; /** + * @typephp-ignore * @template TClassName of object * @param class-string $className * @return TClassName diff --git a/packages/container/src/GenericContainer.php b/packages/container/src/GenericContainer.php index 752fca8f24..11110d24e3 100644 --- a/packages/container/src/GenericContainer.php +++ b/packages/container/src/GenericContainer.php @@ -199,6 +199,7 @@ public function config(object $config): self } /** + * @typephp-ignore * @template TClassName of object * @param class-string $className * @return TClassName @@ -515,7 +516,7 @@ private function autowire(string $className, mixed ...$params): object } /** - * @return ParameterReflector[] + * @return list */ private function autowireDependencies(MethodReflector|FunctionReflector $method, array $parameters = []): array { diff --git a/packages/core/composer.json b/packages/core/composer.json index 63db9d3755..236256c5b5 100644 --- a/packages/core/composer.json +++ b/packages/core/composer.json @@ -15,7 +15,8 @@ }, "require-dev": { "tempest/validation": "3.x-dev", - "tempest/intl": "3.x-dev" + "tempest/intl": "3.x-dev", + "typephp/typephp": "^0.7.1" }, "autoload": { "psr-4": { diff --git a/packages/cryptography/composer.json b/packages/cryptography/composer.json index 396473f1fd..830aabc5ec 100644 --- a/packages/cryptography/composer.json +++ b/packages/cryptography/composer.json @@ -9,6 +9,9 @@ "tempest/support": "3.x-dev", "tempest/clock": "3.x-dev" }, + "require-dev": { + "typephp/typephp": "^0.7.1" + }, "autoload": { "psr-4": { "Tempest\\Cryptography\\": "src" @@ -19,4 +22,4 @@ "Tempest\\Cryptography\\Tests\\": "tests" } } -} +} \ No newline at end of file diff --git a/packages/cryptography/tests/Encryption/EncryptionTest.php b/packages/cryptography/tests/Encryption/EncryptionTest.php index 1e174f7081..bf46968e0c 100644 --- a/packages/cryptography/tests/Encryption/EncryptionTest.php +++ b/packages/cryptography/tests/Encryption/EncryptionTest.php @@ -69,6 +69,9 @@ public function time_protection(): void } #[Test] + /** + * @typephp-ignore + */ public function wrong_key(): void { $this->expectException(SignatureMismatched::class); @@ -81,6 +84,9 @@ public function wrong_key(): void } #[Test] + /** + * @typephp-ignore + */ public function missing_key(): void { $this->expectException(EncryptionKeyWasInvalid::class); diff --git a/packages/database/composer.json b/packages/database/composer.json index f518a46c7b..e3b793bcd8 100644 --- a/packages/database/composer.json +++ b/packages/database/composer.json @@ -12,6 +12,9 @@ "tempest/intl": "3.x-dev", "tempest/support": "3.x-dev" }, + "require-dev": { + "typephp/typephp": "^0.7.1" + }, "autoload": { "psr-4": { "Tempest\\Database\\": "src" @@ -25,4 +28,4 @@ "Tempest\\Database\\Tests\\": "tests" } } -} +} \ No newline at end of file diff --git a/packages/database/src/functions.php b/packages/database/src/functions.php index 423f932126..e3ac3e08d8 100644 --- a/packages/database/src/functions.php +++ b/packages/database/src/functions.php @@ -9,7 +9,7 @@ * Creates a new query builder instance for the given model or table name. * * @template TModel - * @param TModel $model + * @param class-string|string|TModel $model * @return QueryBuilder */ function query(string|object $model): QueryBuilder diff --git a/packages/datetime/composer.json b/packages/datetime/composer.json index 62d53b90fe..8d0932e4b8 100644 --- a/packages/datetime/composer.json +++ b/packages/datetime/composer.json @@ -8,6 +8,9 @@ "tempest/intl": "3.x-dev", "tempest/support": "3.x-dev" }, + "require-dev": { + "typephp/typephp": "^0.7.1" + }, "autoload": { "psr-4": { "Tempest\\DateTime\\": "src" @@ -22,4 +25,4 @@ "Tempest\\DateTime\\Tests\\": "tests" } } -} +} \ No newline at end of file diff --git a/packages/datetime/typephp.php b/packages/datetime/typephp.php new file mode 100644 index 0000000000..cb2df062bf --- /dev/null +++ b/packages/datetime/typephp.php @@ -0,0 +1,7 @@ + [ + 'src/**', + ], +]; diff --git a/packages/debug/composer.json b/packages/debug/composer.json index df1cf96856..f9f06fb9d1 100644 --- a/packages/debug/composer.json +++ b/packages/debug/composer.json @@ -9,7 +9,8 @@ "symfony/var-dumper": "^7.1|^8.0" }, "require-dev": { - "tempest/console": "3.x-dev" + "tempest/console": "3.x-dev", + "typephp/typephp": "^0.7.1" }, "autoload": { "psr-4": { diff --git a/packages/discovery/composer.json b/packages/discovery/composer.json index 35b8f927c6..cd7b711b8a 100644 --- a/packages/discovery/composer.json +++ b/packages/discovery/composer.json @@ -12,7 +12,8 @@ }, "require-dev": { "tempest/container": "3.x-dev", - "php-di/php-di": "^7.0" + "php-di/php-di": "^7.0", + "typephp/typephp": "^0.7.1" }, "autoload": { "psr-4": { diff --git a/packages/discovery/src/BootDiscovery.php b/packages/discovery/src/BootDiscovery.php index f013d9f2d4..77d80e50e4 100644 --- a/packages/discovery/src/BootDiscovery.php +++ b/packages/discovery/src/BootDiscovery.php @@ -279,7 +279,7 @@ private function resolveDiscovery(string $discoveryClass): Discovery $discovery = null; try { - /** @var Discovery $discovery */ + /** @var ?Discovery $discovery */ $discovery = $this->container->get($discoveryClass); } catch (NotFoundExceptionInterface) { // @mago-expect lint:no-empty-catch-clause diff --git a/packages/discovery/src/DiscoveryCache.php b/packages/discovery/src/DiscoveryCache.php index 9f7873bd7f..ceae8aed91 100644 --- a/packages/discovery/src/DiscoveryCache.php +++ b/packages/discovery/src/DiscoveryCache.php @@ -39,7 +39,7 @@ public function withStrategy(DiscoveryCacheStrategy $strategy): self } /** - * @return array, DiscoveryItems> + * @return array, list> */ public function restore(DiscoveryLocation $location): ?array { diff --git a/packages/event-bus/composer.json b/packages/event-bus/composer.json index 08a532fb61..bd2cd418a1 100644 --- a/packages/event-bus/composer.json +++ b/packages/event-bus/composer.json @@ -7,6 +7,9 @@ "tempest/container": "3.x-dev", "tempest/reflection": "3.x-dev" }, + "require-dev": { + "typephp/typephp": "^0.7.1" + }, "autoload": { "files": [ "src/functions.php" @@ -22,4 +25,4 @@ }, "license": "MIT", "minimum-stability": "dev" -} +} \ No newline at end of file diff --git a/packages/generation/composer.json b/packages/generation/composer.json index c77fda6d55..96ac001951 100644 --- a/packages/generation/composer.json +++ b/packages/generation/composer.json @@ -14,7 +14,8 @@ "require-dev": { "spatie/phpunit-snapshot-assertions": "^5.1.8", "phpunit/phpunit": "^12.5.22", - "tempest/container": "3.x-dev" + "tempest/container": "3.x-dev", + "typephp/typephp": "^0.7.1" }, "autoload": { "psr-4": { @@ -26,4 +27,4 @@ "Tempest\\Generation\\Tests\\": "tests" } } -} +} \ No newline at end of file diff --git a/packages/generation/src/Php/StubFileGenerator.php b/packages/generation/src/Php/StubFileGenerator.php index 71eb87ea84..5357cb44b4 100644 --- a/packages/generation/src/Php/StubFileGenerator.php +++ b/packages/generation/src/Php/StubFileGenerator.php @@ -26,7 +26,7 @@ final class StubFileGenerator * @param StubFile $stubFile The stub file to use for the generation. It must be of type CLASS_FILE. * @param string $targetPath The path where the generated file will be saved including the filename and extension. * @param bool $shouldOverride Whether the generator should override the file if it already exists. - * @param array $replacements An array of key-value pairs to replace in the stub file. + * @param array $replacements An array of key-value pairs to replace in the stub file. * The keys are the placeholders in the stub file (e.g. 'DummyNamespace') * The values are the replacements for the placeholders (e.g. 'App\Models') * @@ -88,7 +88,7 @@ public function generateClassFile( * @param StubFile $stubFile The stub file to use for the generation. It must be of type RAW_FILE. * @param string $targetPath The path where the generated file will be saved including the filename and extension. * @param bool $shouldOverride Whether the generator should override the file if it already exists. - * @param array $replacements An array of key-value pairs to replace in the stub file. + * @param array $replacements An array of key-value pairs to replace in the stub file. * The keys are the placeholders in the stub file (e.g. 'dummy-content') * The values are the replacements for the placeholders (e.g. 'real content') * diff --git a/packages/generation/src/TypeScript/Writers/NamespacedFileWriter.php b/packages/generation/src/TypeScript/Writers/NamespacedFileWriter.php index bac72fb716..49df1f508b 100644 --- a/packages/generation/src/TypeScript/Writers/NamespacedFileWriter.php +++ b/packages/generation/src/TypeScript/Writers/NamespacedFileWriter.php @@ -58,7 +58,7 @@ private function generateContent(TypeScriptOutput $output): string } /** - * @param TypeDefinition[]|InterfaceDefinition[] $definitions + * @param array $definitions */ private function generateNamespace(string $namespace, array $definitions): string { diff --git a/packages/http-client/composer.json b/packages/http-client/composer.json index 89227ca40d..0132295edb 100644 --- a/packages/http-client/composer.json +++ b/packages/http-client/composer.json @@ -14,7 +14,8 @@ }, "require-dev": { "guzzlehttp/psr7": "^2.6.1", - "phpunit/phpunit": "^12.5.22" + "phpunit/phpunit": "^12.5.22", + "typephp/typephp": "^0.7.1" }, "autoload": { "psr-4": { @@ -26,4 +27,4 @@ "Tempest\\HttpClient\\Tests\\": "tests" } } -} +} \ No newline at end of file diff --git a/packages/http/composer.json b/packages/http/composer.json index aa1367bc8e..41880668b4 100644 --- a/packages/http/composer.json +++ b/packages/http/composer.json @@ -16,6 +16,9 @@ "psr/http-message": "^1.0|^2.0", "symfony/uid": "^7.1|^8.0" }, + "require-dev": { + "typephp/typephp": "^0.7.1" + }, "autoload": { "psr-4": { "Tempest\\Http\\": "src" @@ -29,4 +32,4 @@ "Tempest\\Http\\Tests\\": "tests" } } -} +} \ No newline at end of file diff --git a/packages/http/src/GenericResponse.php b/packages/http/src/GenericResponse.php index a5b9c78236..0b1c093072 100644 --- a/packages/http/src/GenericResponse.php +++ b/packages/http/src/GenericResponse.php @@ -12,6 +12,12 @@ final class GenericResponse implements Response { use IsResponse; + /** + * @param Status $status + * @param Generator|View|string|array|JsonSerializable|null $body + * @param array|list
$headers + * @param View|null $view + */ public function __construct( Status $status, Generator|View|string|array|JsonSerializable|null $body = null, diff --git a/packages/http/src/RequestHeaders.php b/packages/http/src/RequestHeaders.php index b4253b906c..0d1b4734fc 100644 --- a/packages/http/src/RequestHeaders.php +++ b/packages/http/src/RequestHeaders.php @@ -14,7 +14,7 @@ final readonly class RequestHeaders implements ArrayAccess, IteratorAggregate { /** - * @param array $headers + * @param array $headers */ public static function normalizeFromArray(array $headers): self { diff --git a/packages/http/src/Responses/Json.php b/packages/http/src/Responses/Json.php index 86f04e7b84..9756055714 100644 --- a/packages/http/src/Responses/Json.php +++ b/packages/http/src/Responses/Json.php @@ -13,6 +13,11 @@ final class Json implements Response { use IsResponse; + /** + * @param JsonSerializable|array|null $body + * @param Status|null $status + * @param array|list<\Tempest\Http\Header> $headers + */ public function __construct(JsonSerializable|array|null $body = null, ?Status $status = null, array $headers = []) { $this->status = $status ?? Status::OK; diff --git a/packages/icon/composer.json b/packages/icon/composer.json index d9fbb60d64..0506ad7075 100644 --- a/packages/icon/composer.json +++ b/packages/icon/composer.json @@ -10,6 +10,9 @@ "tempest/support": "3.x-dev", "symfony/cache": "^7.3|^8.0" }, + "require-dev": { + "typephp/typephp": "^0.7.1" + }, "suggest": { "tempest/event-bus": "For events support" }, @@ -26,4 +29,4 @@ "Tempest\\Icon\\Tests\\": "tests" } } -} +} \ No newline at end of file diff --git a/packages/idempotency/composer.json b/packages/idempotency/composer.json index 2d31593980..b00fe807d2 100644 --- a/packages/idempotency/composer.json +++ b/packages/idempotency/composer.json @@ -13,6 +13,9 @@ "tempest/command-bus": "3.x-dev", "tempest/core": "3.x-dev" }, + "require-dev": { + "typephp/typephp": "^0.7.1" + }, "license": "MIT", "autoload": { "psr-4": { @@ -25,4 +28,4 @@ } }, "minimum-stability": "dev" -} +} \ No newline at end of file diff --git a/packages/intl/composer.json b/packages/intl/composer.json index 39cd9156bb..12dae25962 100644 --- a/packages/intl/composer.json +++ b/packages/intl/composer.json @@ -13,6 +13,9 @@ "ext-intl": "*", "ext-dom": "*" }, + "require-dev": { + "typephp/typephp": "^0.7.1" + }, "suggest": { "tempest/datetime": "In order to use the `datetime` function", "tempest/icon": "In order to use the `icon` function", @@ -32,4 +35,4 @@ "Tempest\\Intl\\Tests\\": "tests" } } -} +} \ No newline at end of file diff --git a/packages/kv-store/composer.json b/packages/kv-store/composer.json index 8da053793c..122239b449 100644 --- a/packages/kv-store/composer.json +++ b/packages/kv-store/composer.json @@ -10,7 +10,8 @@ "tempest/event-bus": "3.x-dev" }, "require-dev": { - "predis/predis": "^3.0.0" + "predis/predis": "^3.0.0", + "typephp/typephp": "^0.7.1" }, "autoload": { "psr-4": { diff --git a/packages/log/composer.json b/packages/log/composer.json index 7be95e40ee..ca1ad98b39 100644 --- a/packages/log/composer.json +++ b/packages/log/composer.json @@ -9,6 +9,9 @@ "psr/log": "^3.0.0", "tempest/container": "3.x-dev" }, + "require-dev": { + "typephp/typephp": "^0.7.1" + }, "autoload": { "psr-4": { "Tempest\\Log\\": "src" @@ -19,4 +22,4 @@ "Tempest\\Log\\Tests\\": "tests" } } -} +} \ No newline at end of file diff --git a/packages/mail/composer.json b/packages/mail/composer.json index 96ec57a238..2803e20964 100644 --- a/packages/mail/composer.json +++ b/packages/mail/composer.json @@ -12,7 +12,8 @@ }, "require-dev": { "symfony/postmark-mailer": "^7.2.6|^8.0", - "symfony/amazon-mailer": "^7.2.0|^8.0" + "symfony/amazon-mailer": "^7.2.0|^8.0", + "typephp/typephp": "^0.7.1" }, "suggest": { "tempest/storage": "For storage attachment support" diff --git a/packages/mapper/composer.json b/packages/mapper/composer.json index 59b7dff803..b70ff77704 100644 --- a/packages/mapper/composer.json +++ b/packages/mapper/composer.json @@ -10,6 +10,9 @@ "tempest/support": "3.x-dev", "tempest/validation": "3.x-dev" }, + "require-dev": { + "typephp/typephp": "^0.7.1" + }, "autoload": { "files": [ "src/functions.php" @@ -23,4 +26,4 @@ "Tempest\\Mapper\\Tests\\": "tests" } } -} +} \ No newline at end of file diff --git a/packages/mcp/composer.json b/packages/mcp/composer.json index ea632359a3..2a1e6e4bca 100644 --- a/packages/mcp/composer.json +++ b/packages/mcp/composer.json @@ -14,6 +14,9 @@ "tempest/support": "3.x-dev", "tempest/validation": "3.x-dev" }, + "require-dev": { + "typephp/typephp": "^0.7.1" + }, "autoload": { "psr-4": { "Tempest\\Mcp\\": "src" @@ -26,4 +29,4 @@ }, "license": "MIT", "minimum-stability": "dev" -} +} \ No newline at end of file diff --git a/packages/process/composer.json b/packages/process/composer.json index 70e199197c..736a6b28a2 100644 --- a/packages/process/composer.json +++ b/packages/process/composer.json @@ -10,6 +10,9 @@ "tempest/support": "3.x-dev", "tempest/datetime": "3.x-dev" }, + "require-dev": { + "typephp/typephp": "^0.7.1" + }, "autoload": { "psr-4": { "Tempest\\Process\\": "src" @@ -20,4 +23,4 @@ "Tempest\\Process\\Tests\\": "tests" } } -} +} \ No newline at end of file diff --git a/packages/reflection/composer.json b/packages/reflection/composer.json index 2e5525bb8e..83270c6728 100644 --- a/packages/reflection/composer.json +++ b/packages/reflection/composer.json @@ -6,6 +6,9 @@ "require": { "php": "^8.5" }, + "require-dev": { + "typephp/typephp": "^0.7.1" + }, "autoload": { "psr-4": { "Tempest\\Reflection\\": "src" @@ -19,4 +22,4 @@ "Tempest\\Reflection\\Tests\\": "tests" } } -} +} \ No newline at end of file diff --git a/packages/router/composer.json b/packages/router/composer.json index 8a176a5a80..f707ea68a1 100644 --- a/packages/router/composer.json +++ b/packages/router/composer.json @@ -10,6 +10,9 @@ "tempest/highlight": "^2.11.4", "symfony/var-exporter": "^7.1|^8.0" }, + "require-dev": { + "typephp/typephp": "^0.7.1" + }, "autoload": { "files": [ "src/functions.php" @@ -23,4 +26,4 @@ "Tempest\\Router\\Tests\\": "tests" } } -} +} \ No newline at end of file diff --git a/packages/router/src/Exceptions/local/bun.lock b/packages/router/src/Exceptions/local/bun.lock index ce071a8da5..c72be941b6 100644 --- a/packages/router/src/Exceptions/local/bun.lock +++ b/packages/router/src/Exceptions/local/bun.lock @@ -142,7 +142,7 @@ "@nuxt/devtools-kit": ["@nuxt/devtools-kit@3.1.1", "", { "dependencies": { "@nuxt/kit": "^4.2.1", "execa": "^8.0.1" }, "peerDependencies": { "vite": ">=6.0" } }, "sha512-sjiKFeDCOy1SyqezSgyV4rYNfQewC64k/GhOsuJgRF+wR2qr6KTVhO6u2B+csKs74KrMrnJprQBgud7ejvOXAQ=="], - "@nuxt/fonts": ["@nuxt/fonts@0.12.1", "", { "dependencies": { "@nuxt/devtools-kit": "^3.0.1", "@nuxt/kit": "^4.2.1", "consola": "^3.4.2", "css-tree": "^3.1.0", "defu": "^6.1.4", "esbuild": "^0.25.12", "fontaine": "^0.7.0", "fontless": "^0.1.0", "h3": "^1.15.4", "jiti": "^2.6.1", "magic-regexp": "^0.10.0", "magic-string": "^0.30.21", "node-fetch-native": "^1.6.7", "ohash": "^2.0.11", "pathe": "^2.0.3", "sirv": "^3.0.2", "tinyglobby": "^0.2.15", "ufo": "^1.6.1", "unifont": "^0.6.0", "unplugin": "^2.3.10", "unstorage": "^1.17.2" } }, "sha512-ALajI/HE+uqqL/PWkWwaSUm1IdpyGPbP3mYGy2U1l26/o4lUZBxjFaduMxaZ85jS5yQeJfCu2eEHANYFjAoujQ=="], + "@nuxt/fonts": ["@nuxt/fonts@0.12.1", "", { "dependencies": { "@nuxt/devtools-kit": "^3.0.1", "@nuxt/kit": "^4.2.1", "consola": "^3.4.2", "css-tree": "^3.1.0", "defu": "^6.1.4", "esbuild": "^0.25.12", "fontaine": "^0.7.1", "fontless": "^0.1.0", "h3": "^1.15.4", "jiti": "^2.6.1", "magic-regexp": "^0.10.0", "magic-string": "^0.30.21", "node-fetch-native": "^1.6.7", "ohash": "^2.0.11", "pathe": "^2.0.3", "sirv": "^3.0.2", "tinyglobby": "^0.2.15", "ufo": "^1.6.1", "unifont": "^0.6.0", "unplugin": "^2.3.10", "unstorage": "^1.17.2" } }, "sha512-ALajI/HE+uqqL/PWkWwaSUm1IdpyGPbP3mYGy2U1l26/o4lUZBxjFaduMxaZ85jS5yQeJfCu2eEHANYFjAoujQ=="], "@nuxt/icon": ["@nuxt/icon@2.1.1", "", { "dependencies": { "@iconify/collections": "^1.0.628", "@iconify/types": "^2.0.0", "@iconify/utils": "^3.1.0", "@iconify/vue": "^5.0.0", "@nuxt/devtools-kit": "^3.1.1", "@nuxt/kit": "^4.2.2", "consola": "^3.4.2", "local-pkg": "^1.1.2", "mlly": "^1.8.0", "ohash": "^2.0.11", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^3.10.0", "tinyglobby": "^0.2.15" } }, "sha512-KX991xA64ttUQYXnLFafOw8EYxmmGRtnd2z1P9PjMOeSxxLXxUL1v9fKH2njqtPkamiOI0fvthxfJpJ4uH71sw=="], diff --git a/packages/router/src/Routing/Matching/GenericRouteMatcher.php b/packages/router/src/Routing/Matching/GenericRouteMatcher.php index ba52658592..5aa930c723 100644 --- a/packages/router/src/Routing/Matching/GenericRouteMatcher.php +++ b/packages/router/src/Routing/Matching/GenericRouteMatcher.php @@ -73,7 +73,7 @@ private function matchDynamicRoute(Request $request): ?MatchedRoute * Extracts route parameters from the routeMatches * * @param array $routeMatches - * @return array + * @return array */ private function extractParams(DiscoveredRoute $route, array $routeMatches): array { diff --git a/packages/storage/composer.json b/packages/storage/composer.json index f270b6b078..ae556bf782 100644 --- a/packages/storage/composer.json +++ b/packages/storage/composer.json @@ -20,7 +20,8 @@ "league/flysystem-google-cloud-storage": "^3.25.1", "league/mime-type-detection": "^1.16", "microsoft/azure-storage-blob": "^1.5", - "tempest/support": "3.x-dev" + "tempest/support": "3.x-dev", + "typephp/typephp": "^0.7.1" }, "autoload": { "psr-4": { diff --git a/packages/support/composer.json b/packages/support/composer.json index bc700e6caa..1ceb029c94 100644 --- a/packages/support/composer.json +++ b/packages/support/composer.json @@ -8,6 +8,9 @@ "voku/portable-ascii": "^2.0.3", "symfony/uid": "^7.1|^8.0" }, + "require-dev": { + "typephp/typephp": "^0.7.1" + }, "autoload": { "psr-4": { "Tempest\\Support\\": "src" @@ -37,4 +40,4 @@ "Tempest\\Support\\Tests\\": "tests" } } -} +} \ No newline at end of file diff --git a/packages/support/src/Arr/ManipulatesArray.php b/packages/support/src/Arr/ManipulatesArray.php index 8e2bd52504..68d15576e8 100644 --- a/packages/support/src/Arr/ManipulatesArray.php +++ b/packages/support/src/Arr/ManipulatesArray.php @@ -214,8 +214,6 @@ public function pluck(string $value, ?string $key = null): self /** * Prepends the specified values to the array. * - * @param TValue $values - * * @return static */ public function prepend(mixed ...$values): self @@ -226,8 +224,6 @@ public function prepend(mixed ...$values): self /** * Appends the specified values to the instance. * - * @param TValue $values - * * @return static */ public function append(mixed ...$values): self @@ -327,7 +323,7 @@ public function intersect(array|self ...$arrays): self /** * Returns a new instance of the array with only the items whose keys are present in all of the given arrays. * - * @param array|static ...$arrays + * @param array|static ...$arrays * * @return static */ @@ -828,7 +824,7 @@ public function slice(int $offset, ?int $length = null): self * * @param (Closure(TValue): bool) $predicate * - * @return static, array>> + * @return static> */ public function partition(Closure $predicate): self { diff --git a/packages/support/src/Arr/functions.php b/packages/support/src/Arr/functions.php index f0b8a66308..57a0856bb6 100644 --- a/packages/support/src/Arr/functions.php +++ b/packages/support/src/Arr/functions.php @@ -346,12 +346,10 @@ function pluck(iterable $array, string $value, ?string $key = null): array * * @template TKey of array-key * @template TValue - * @template TPrepended * * @param iterable $array - * @param TPrepended $values * - * @return array + * @return array */ function prepend(iterable $array, mixed ...$values): array { @@ -369,12 +367,10 @@ function prepend(iterable $array, mixed ...$values): array * * @template TKey of array-key * @template TValue - * @template TAppended * * @param iterable $array - * @param TAppended $values * - * @return array + * @return array */ function append(iterable $array, mixed ...$values): array { @@ -499,8 +495,8 @@ function unique(iterable $array, Closure|string|null $key = null, bool $shouldBe * @template TKey of array-key * @template TValue * - * @param iterable $array - * @param array ...$arrays + * @param array $array + * @param array ...$arrays * * @return array */ @@ -531,8 +527,8 @@ function diff_keys(iterable $array, array ...$arrays): array * @template TKey of array-key * @template TValue * - * @param iterable $array - * @param array ...$arrays + * @param array $array + * @param array ...$arrays * * @return array */ @@ -547,8 +543,8 @@ function intersect(iterable $array, array ...$arrays): array * @template TKey of array-key * @template TValue * - * @param iterable $array - * @param array ...$arrays + * @param iterable $array + * @param array ...$arrays * * @return array */ @@ -647,7 +643,7 @@ function first(iterable $array, ?Closure $filter = null, mixed $default = null): * * @param iterable $array * - * @return TValue + * @return TValue|null */ function at(iterable $array, int $index, mixed $default = null): mixed { @@ -1093,7 +1089,7 @@ function undot(iterable $array): array * * @param iterable $array * - * @return array + * @return array */ function dot(iterable $array, string $prefix = ''): array { diff --git a/packages/support/src/Namespace/functions.php b/packages/support/src/Namespace/functions.php index e296c903ed..393cefbd6f 100644 --- a/packages/support/src/Namespace/functions.php +++ b/packages/support/src/Namespace/functions.php @@ -64,7 +64,7 @@ function to_namespace(Stringable|string $path, Stringable|string|null $root = nu * Converts the given file system path to the equivalent specified PSR-4 namespace. * The given path is expected to be absolute or relative to the root path. An exception will be thrown otherwise. * - * @param array $namespaces + * @param Psr4Namespace|array $namespaces * * ## Example * ```php diff --git a/packages/support/src/Regex/functions.php b/packages/support/src/Regex/functions.php index a59e604948..c609a9850b 100644 --- a/packages/support/src/Regex/functions.php +++ b/packages/support/src/Regex/functions.php @@ -135,7 +135,7 @@ function matches(string $subject, string $pattern, int $offset = 0): bool /** * Returns the '$haystack' string with all occurrences of `$pattern` replaced by `$replacement`. * - * @param non-empty-string $pattern The pattern to search for. + * @param non-empty-string|non-empty-string[] $pattern The pattern to search for. * @param null|positive-int $limit The maximum possible replacements for $pattern within $haystack. */ function replace(array|string $haystack, array|string $pattern, Closure|array|string $replacement, ?int $limit = null): string diff --git a/packages/validation/composer.json b/packages/validation/composer.json index 8b38f1b550..25b5e50c96 100644 --- a/packages/validation/composer.json +++ b/packages/validation/composer.json @@ -12,6 +12,9 @@ "tempest/intl": "3.x-dev", "tempest/datetime": "3.x-dev" }, + "require-dev": { + "typephp/typephp": "^0.7.1" + }, "autoload": { "psr-4": { "Tempest\\Validation\\": "src" @@ -22,4 +25,4 @@ "Tempest\\Validation\\Tests\\": "tests" } } -} +} \ No newline at end of file diff --git a/packages/view/composer.json b/packages/view/composer.json index ee1c114a32..48c7cea840 100644 --- a/packages/view/composer.json +++ b/packages/view/composer.json @@ -12,6 +12,9 @@ "league/commonmark": "^2.7", "symfony/cache": "^7.3|^8.0" }, + "require-dev": { + "typephp/typephp": "^0.7.1" + }, "autoload": { "files": [ "src/functions.php" @@ -25,4 +28,4 @@ "Tempest\\View\\Tests\\": "tests" } } -} +} \ No newline at end of file diff --git a/packages/vite/composer.json b/packages/vite/composer.json index 844454c4c5..e1974abda8 100644 --- a/packages/vite/composer.json +++ b/packages/vite/composer.json @@ -6,6 +6,9 @@ "require": { "php": "^8.5" }, + "require-dev": { + "typephp/typephp": "^0.7.1" + }, "autoload": { "psr-4": { "Tempest\\Vite\\": "src" @@ -19,4 +22,4 @@ "Tempest\\Vite\\Tests\\": "tests" } } -} +} \ No newline at end of file diff --git a/stubs/class-stubs.stub b/stubs/class-stubs.stub new file mode 100644 index 0000000000..82f2e75057 --- /dev/null +++ b/stubs/class-stubs.stub @@ -0,0 +1,71 @@ +expectException(InvalidArgumentException::class); @@ -24,6 +25,7 @@ public function assert_sent_must_have_valid_class_string(): void } #[Test] + /** @typephp-ignore */ public function assert_sent_must_have_class_string_that_implements_email(): void { $this->expectException(InvalidArgumentException::class); diff --git a/tests/Integration/Route/RequestToObjectMapperTest.php b/tests/Integration/Route/RequestToObjectMapperTest.php index f2cacaa37d..4aa9455c86 100644 --- a/tests/Integration/Route/RequestToObjectMapperTest.php +++ b/tests/Integration/Route/RequestToObjectMapperTest.php @@ -120,6 +120,7 @@ public function validation_fails_for_enum(): void } } + /** @typephp-ignore */ #[Test] public function reserved_properties_cannot_be_mapped(): void { diff --git a/tests/Integration/Support/GeneratesArguments.php b/tests/Integration/Support/GeneratesArguments.php index c0c668aeb4..e263d684ed 100644 --- a/tests/Integration/Support/GeneratesArguments.php +++ b/tests/Integration/Support/GeneratesArguments.php @@ -84,6 +84,7 @@ private function generateArgument(ReflectionNamedType|ReflectionUnionType|Reflec 'iterable' => [], 'array' => [], 'bool' => true, + 'mixed' => 'tempest', default => null, }; } diff --git a/typephp.php b/typephp.php new file mode 100644 index 0000000000..53c3034cb7 --- /dev/null +++ b/typephp.php @@ -0,0 +1,173 @@ + false): TypePHP boots normally, but turns all + | runtime checks into instant no-ops (pass-through mode). + | - Bootstrap Prevention (TYPEPHP_DISABLE=true): To completely prevent TypePHP + | from booting or registering its stream wrapper during Composer autoload, + | set the environment variable TYPEPHP_DISABLE=true or define('TYPEPHP_DISABLE', true) + | before requiring 'vendor/autoload.php'. + */ + 'enabled' => true, + + /* + |-------------------------------------------------------------------------- + | Function Boundary Contracts (@param & @return) + |-------------------------------------------------------------------------- + | Controls whether function and method parameter/return contracts are enforced. + | When enabled, all parameter and return types (generics, shapes, scalars) + | are enforced uniformly to maintain type state consistency. + */ + 'params' => true, + 'returns' => true, + + /* + |-------------------------------------------------------------------------- + | Respect Ignore Docblock Tags + |-------------------------------------------------------------------------- + | When true (default), @typephp-ignore and @typephp-ignore-file docblock tags + | skip type-checking on specific methods/files. Set to false in CI/CD or + | audit runs to force type-checking on all ignored methods without deleting + | the docblock tags from source code. + */ + 'respect_ignore_tags' => true, + + /* + |-------------------------------------------------------------------------- + | Enable Caching & Cache Directory + |-------------------------------------------------------------------------- + | When enabled, transformed PHP files are cached on disk for speed. + | Set to false to run AST transformations purely in RAM (php://memory). + | + | 'cache_dir' determines where these files are stored. By default (null), + | it uses your system's temp directory. You can change this to a path + | inside your project, e.g., __DIR__ . '/storage/framework/typephp'. + | TypePHP will automatically protect this directory from being re-transformed. + */ + 'cache' => true, + 'cache_dir' => null, + + /* + |-------------------------------------------------------------------------- + | Registered Extensions + |-------------------------------------------------------------------------- + | Explicitly list third-party extension classes that provide path overrides. + */ + 'extensions' => [ + // \Acme\Domain\TypePHPExtension::class, + ], + + /* + |-------------------------------------------------------------------------- + | Array Validation Strategy + |-------------------------------------------------------------------------- + | Controls how collections (list, array, Type[]) are verified: + | + | - 'full' : (Default / Strict) 100% exhaustive scan. Checks every single + | item in every array, guaranteeing every single offending item + | is caught without exception. + | + | - 'hybrid' : (Beartype O(1) Mode) Fast boundary + random sampling on + | arrays > 128 items. Ideal for massive production datasets. + */ + 'array_validation' => 'hybrid', + + /* + |-------------------------------------------------------------------------- + | Respect Native Parameter Nullability + |-------------------------------------------------------------------------- + | When true (default), if a native PHP parameter explicitly declares + | nullable syntax (e.g. ?array $param = null), TypePHP permits null even + | if the DocBlock author omitted "|null" (e.g. @param string[] $param). + | + | Set to false for strict pedantic enforcement where DocBlocks are the + | absolute law and null is rejected unless explicitly typed in the DocBlock. + */ + 'respect_native_nullability' => true, + + /* + |-------------------------------------------------------------------------- + | Inline Variable Validation (@var $x = ...) + |-------------------------------------------------------------------------- + | Fine-grained control over which type categories are enforced on local + | variable assignments with inline @var Type $var docblocks. + | + | Supported options: + | - 'properties': Validates class property assignments (e.g. $this->id = 1). + | - 'generics' : Prebinds generic template instances (e.g. Collection). + | - 'callables' : Wraps inline callbacks (e.g. callable(int): string). + | - 'scalars' : Enforces scalar constraints (e.g. positive-int, non-empty-string). + | - 'arrays' : Enforces array shapes, lists, & typed arrays (e.g. array{id: int}, int[]). + | - 'objects' : Enforces class instance checks (e.g. @var User $user). + */ + 'inline_vars' => [ + 'properties' => true, + 'generics' => true, + 'callables' => true, + 'scalars' => true, + 'arrays' => true, + 'objects' => true, + ], + + /* + |-------------------------------------------------------------------------- + | Stub Files (DocBlock Overrides for Third-Party & Vendor Packages) + |-------------------------------------------------------------------------- + | Path globs or specific file paths containing stub files (.stub, .stub.php, .php) + | that override inaccurate or missing DocBlocks in third-party vendor packages. + */ + 'stubs' => [ + 'stubs/**', + ], + + /* + |-------------------------------------------------------------------------- + | Included Paths & Whitelisting + |-------------------------------------------------------------------------- + | Globs or specific file paths that should be intercepted and type-checked. + | + | Pattern Specificity: + | More specific patterns take precedence over broader rules. + | You can specify directory globs (e.g. 'src/**'), single vendor packages + | (e.g. 'vendor/my-org/my-package/**'), or single specific files + | (vendor/monologvendor/monolog/monolog/src/Monolog/Logger.php'). + | You can use "*" glob to match any file. + */ + 'include' => [ + 'src/**', + 'packages/**/src/**', + ], + + /* + |-------------------------------------------------------------------------- + | Excluded Paths & Single-File Blacklisting + |-------------------------------------------------------------------------- + | Globs or specific file paths that should be ignored by the type checker. + | You can exclude entire directories (e.g. 'vendor/**') or blacklist + | single legacy files inside included directories (e.g. 'src/Legacy/File.php'). + */ + 'exclude' => [ + 'vendor/**', + 'storage/**', + 'var/**', + 'cache/**', + '.tempest/**', + 'tests/**', + 'packages/**/src/Migrations/**', + 'packages/**/src/Migration/**', + 'packages/**/Migrations/**', + 'packages/**/Migration/**', + '**/Migrations/**', + '**/Migration/**', + ], +];