diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index 6336d8e..29f988f 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -53,3 +53,5 @@ c400a3c655b1157b8ff30f5c2ead30563fad972a
9ceb35f77a0bfefe8bf4b51d5026399f12ad79b0
8614c245e767ac74c2ca65697553b70bf54394ad
e7d3e86c6e045f09131ec7cdb3e2cf0887e7eb21
+7350f8fc64aa43ff050446bd64157a28f73e21d4
+bb927a60f808d44d10b6ffbd796982a3e5022c44
diff --git a/.idea/php.xml b/.idea/php.xml
index 4da245d..f7cbecb 100644
--- a/.idea/php.xml
+++ b/.idea/php.xml
@@ -18,13 +18,10 @@
-
-
-
@@ -83,31 +80,24 @@
-
-
-
-
-
-
-
@@ -116,6 +106,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/.idea/stdlib.iml b/.idea/stdlib.iml
index 101fa13..5e6660a 100644
--- a/.idea/stdlib.iml
+++ b/.idea/stdlib.iml
@@ -24,7 +24,6 @@
-
@@ -72,11 +71,6 @@
-
-
-
-
-
diff --git a/composer.json b/composer.json
index 8c36b64..93380a1 100644
--- a/composer.json
+++ b/composer.json
@@ -23,12 +23,12 @@
},
"require-dev": {
"mockery/mockery": "^1.6",
- "pestphp/pest": "^2.34 || ^3.0 || ^4.0",
+ "pestphp/pest": "^4",
"phpstan/extension-installer": "^1.3",
- "phpstan/phpstan": "^1.10",
- "rector/rector": "^1.0",
- "tightenco/duster": "^2.7 || ^3.0",
- "tomasvotruba/cognitive-complexity": "^0.2.3"
+ "phpstan/phpstan": "^2",
+ "rector/rector": "^2",
+ "tightenco/duster": "^3",
+ "tomasvotruba/cognitive-complexity": "^1"
},
"autoload": {
"psr-4": {
diff --git a/composer.lock b/composer.lock
index 03312bf..abd673b 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "d87f8ae3c632cd96db23f6304d6f50c7",
+ "content-hash": "5e755e57c6d94b86a69152b6f4fe6939",
"packages": [
{
"name": "brick/math",
- "version": "0.14.0",
+ "version": "0.14.1",
"source": {
"type": "git",
"url": "https://github.com/brick/math.git",
- "reference": "113a8ee2656b882d4c3164fa31aa6e12cbb7aaa2"
+ "reference": "f05858549e5f9d7bb45875a75583240a38a281d0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/brick/math/zipball/113a8ee2656b882d4c3164fa31aa6e12cbb7aaa2",
- "reference": "113a8ee2656b882d4c3164fa31aa6e12cbb7aaa2",
+ "url": "https://api.github.com/repos/brick/math/zipball/f05858549e5f9d7bb45875a75583240a38a281d0",
+ "reference": "f05858549e5f9d7bb45875a75583240a38a281d0",
"shasum": ""
},
"require": {
@@ -56,7 +56,7 @@
],
"support": {
"issues": "https://github.com/brick/math/issues",
- "source": "https://github.com/brick/math/tree/0.14.0"
+ "source": "https://github.com/brick/math/tree/0.14.1"
},
"funding": [
{
@@ -64,7 +64,7 @@
"type": "github"
}
],
- "time": "2025-08-29T12:40:03+00:00"
+ "time": "2025-11-24T14:40:29+00:00"
},
{
"name": "carbonphp/carbon-doctrine-types",
@@ -137,16 +137,16 @@
},
{
"name": "composer/ca-bundle",
- "version": "1.5.8",
+ "version": "1.5.9",
"source": {
"type": "git",
"url": "https://github.com/composer/ca-bundle.git",
- "reference": "719026bb30813accb68271fee7e39552a58e9f65"
+ "reference": "1905981ee626e6f852448b7aaa978f8666c5bc54"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/ca-bundle/zipball/719026bb30813accb68271fee7e39552a58e9f65",
- "reference": "719026bb30813accb68271fee7e39552a58e9f65",
+ "url": "https://api.github.com/repos/composer/ca-bundle/zipball/1905981ee626e6f852448b7aaa978f8666c5bc54",
+ "reference": "1905981ee626e6f852448b7aaa978f8666c5bc54",
"shasum": ""
},
"require": {
@@ -193,7 +193,7 @@
"support": {
"irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/ca-bundle/issues",
- "source": "https://github.com/composer/ca-bundle/tree/1.5.8"
+ "source": "https://github.com/composer/ca-bundle/tree/1.5.9"
},
"funding": [
{
@@ -205,26 +205,26 @@
"type": "github"
}
],
- "time": "2025-08-20T18:49:47+00:00"
+ "time": "2025-11-06T11:46:17+00:00"
},
{
"name": "composer/class-map-generator",
- "version": "1.6.2",
+ "version": "1.7.0",
"source": {
"type": "git",
"url": "https://github.com/composer/class-map-generator.git",
- "reference": "ba9f089655d4cdd64e762a6044f411ccdaec0076"
+ "reference": "2373419b7709815ed323ebf18c3c72d03ff4a8a6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/class-map-generator/zipball/ba9f089655d4cdd64e762a6044f411ccdaec0076",
- "reference": "ba9f089655d4cdd64e762a6044f411ccdaec0076",
+ "url": "https://api.github.com/repos/composer/class-map-generator/zipball/2373419b7709815ed323ebf18c3c72d03ff4a8a6",
+ "reference": "2373419b7709815ed323ebf18c3c72d03ff4a8a6",
"shasum": ""
},
"require": {
"composer/pcre": "^2.1 || ^3.1",
"php": "^7.2 || ^8.0",
- "symfony/finder": "^4.4 || ^5.3 || ^6 || ^7"
+ "symfony/finder": "^4.4 || ^5.3 || ^6 || ^7 || ^8"
},
"require-dev": {
"phpstan/phpstan": "^1.12 || ^2",
@@ -232,7 +232,7 @@
"phpstan/phpstan-phpunit": "^1 || ^2",
"phpstan/phpstan-strict-rules": "^1.1 || ^2",
"phpunit/phpunit": "^8",
- "symfony/filesystem": "^5.4 || ^6"
+ "symfony/filesystem": "^5.4 || ^6 || ^7 || ^8"
},
"type": "library",
"extra": {
@@ -262,7 +262,7 @@
],
"support": {
"issues": "https://github.com/composer/class-map-generator/issues",
- "source": "https://github.com/composer/class-map-generator/tree/1.6.2"
+ "source": "https://github.com/composer/class-map-generator/tree/1.7.0"
},
"funding": [
{
@@ -274,30 +274,31 @@
"type": "github"
}
],
- "time": "2025-08-20T18:52:43+00:00"
+ "time": "2025-11-19T10:41:15+00:00"
},
{
"name": "composer/composer",
- "version": "2.8.12",
+ "version": "2.9.2",
"source": {
"type": "git",
"url": "https://github.com/composer/composer.git",
- "reference": "3e38919bc9a2c3c026f2151b5e56d04084ce8f0b"
+ "reference": "8d5358f147c63a3a681b002076deff8c90e0b19d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/composer/zipball/3e38919bc9a2c3c026f2151b5e56d04084ce8f0b",
- "reference": "3e38919bc9a2c3c026f2151b5e56d04084ce8f0b",
+ "url": "https://api.github.com/repos/composer/composer/zipball/8d5358f147c63a3a681b002076deff8c90e0b19d",
+ "reference": "8d5358f147c63a3a681b002076deff8c90e0b19d",
"shasum": ""
},
"require": {
"composer/ca-bundle": "^1.5",
"composer/class-map-generator": "^1.4.0",
"composer/metadata-minifier": "^1.0",
- "composer/pcre": "^2.2 || ^3.2",
+ "composer/pcre": "^2.3 || ^3.3",
"composer/semver": "^3.3",
"composer/spdx-licenses": "^1.5.7",
"composer/xdebug-handler": "^2.0.2 || ^3.0.3",
+ "ext-json": "*",
"justinrainbow/json-schema": "^6.5.1",
"php": "^7.2.5 || ^8.0",
"psr/log": "^1.0 || ^2.0 || ^3.0",
@@ -305,13 +306,14 @@
"seld/jsonlint": "^1.4",
"seld/phar-utils": "^1.2",
"seld/signal-handler": "^2.0",
- "symfony/console": "^5.4.47 || ^6.4.25 || ^7.1.10",
- "symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.1.10",
- "symfony/finder": "^5.4.45 || ^6.4.24 || ^7.1.10",
+ "symfony/console": "^5.4.47 || ^6.4.25 || ^7.1.10 || ^8.0",
+ "symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.1.10 || ^8.0",
+ "symfony/finder": "^5.4.45 || ^6.4.24 || ^7.1.10 || ^8.0",
"symfony/polyfill-php73": "^1.24",
"symfony/polyfill-php80": "^1.24",
"symfony/polyfill-php81": "^1.24",
- "symfony/process": "^5.4.47 || ^6.4.25 || ^7.1.10"
+ "symfony/polyfill-php84": "^1.30",
+ "symfony/process": "^5.4.47 || ^6.4.25 || ^7.1.10 || ^8.0"
},
"require-dev": {
"phpstan/phpstan": "^1.11.8",
@@ -319,12 +321,13 @@
"phpstan/phpstan-phpunit": "^1.4.0",
"phpstan/phpstan-strict-rules": "^1.6.0",
"phpstan/phpstan-symfony": "^1.4.0",
- "symfony/phpunit-bridge": "^6.4.25 || ^7.3.3"
+ "symfony/phpunit-bridge": "^6.4.25 || ^7.3.3 || ^8.0"
},
"suggest": {
- "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages",
- "ext-zip": "Enabling the zip extension allows you to unzip archives",
- "ext-zlib": "Allow gzip compression of HTTP requests"
+ "ext-curl": "Provides HTTP support (will fallback to PHP streams if missing)",
+ "ext-openssl": "Enables access to repositories and packages over HTTPS",
+ "ext-zip": "Allows direct extraction of ZIP archives (unzip/7z binaries will be used instead if available)",
+ "ext-zlib": "Enables gzip for HTTP requests"
},
"bin": [
"bin/composer"
@@ -337,7 +340,7 @@
]
},
"branch-alias": {
- "dev-main": "2.8-dev"
+ "dev-main": "2.9-dev"
}
},
"autoload": {
@@ -372,7 +375,7 @@
"irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/composer/issues",
"security": "https://github.com/composer/composer/security/policy",
- "source": "https://github.com/composer/composer/tree/2.8.12"
+ "source": "https://github.com/composer/composer/tree/2.9.2"
},
"funding": [
{
@@ -384,7 +387,7 @@
"type": "github"
}
],
- "time": "2025-09-19T11:41:59+00:00"
+ "time": "2025-11-19T20:57:25+00:00"
},
{
"name": "composer/metadata-minifier",
@@ -849,7 +852,7 @@
},
{
"name": "illuminate/collections",
- "version": "v12.38.0",
+ "version": "v12.39.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/collections.git",
@@ -908,7 +911,7 @@
},
{
"name": "illuminate/conditionable",
- "version": "v12.38.0",
+ "version": "v12.39.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/conditionable.git",
@@ -954,7 +957,7 @@
},
{
"name": "illuminate/contracts",
- "version": "v12.38.0",
+ "version": "v12.39.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/contracts.git",
@@ -1002,7 +1005,7 @@
},
{
"name": "illuminate/macroable",
- "version": "v12.38.0",
+ "version": "v12.39.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/macroable.git",
@@ -1048,16 +1051,16 @@
},
{
"name": "illuminate/support",
- "version": "v12.37.0",
+ "version": "v12.39.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/support.git",
- "reference": "480df979c8ffe700d6adb6e6e64abe04b32e02e3"
+ "reference": "d9780f626aa79d6b7b9c18f0d886340a29c66659"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/illuminate/support/zipball/480df979c8ffe700d6adb6e6e64abe04b32e02e3",
- "reference": "480df979c8ffe700d6adb6e6e64abe04b32e02e3",
+ "url": "https://api.github.com/repos/illuminate/support/zipball/d9780f626aa79d6b7b9c18f0d886340a29c66659",
+ "reference": "d9780f626aa79d6b7b9c18f0d886340a29c66659",
"shasum": ""
},
"require": {
@@ -1123,20 +1126,20 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
- "time": "2025-10-31T16:20:10+00:00"
+ "time": "2025-11-16T14:43:22+00:00"
},
{
"name": "justinrainbow/json-schema",
- "version": "6.5.2",
+ "version": "6.6.1",
"source": {
"type": "git",
"url": "https://github.com/jsonrainbow/json-schema.git",
- "reference": "ac0d369c09653cf7af561f6d91a705bc617a87b8"
+ "reference": "fd8e5c6b1badb998844ad34ce0abcd71a0aeb396"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/ac0d369c09653cf7af561f6d91a705bc617a87b8",
- "reference": "ac0d369c09653cf7af561f6d91a705bc617a87b8",
+ "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/fd8e5c6b1badb998844ad34ce0abcd71a0aeb396",
+ "reference": "fd8e5c6b1badb998844ad34ce0abcd71a0aeb396",
"shasum": ""
},
"require": {
@@ -1196,9 +1199,9 @@
],
"support": {
"issues": "https://github.com/jsonrainbow/json-schema/issues",
- "source": "https://github.com/jsonrainbow/json-schema/tree/6.5.2"
+ "source": "https://github.com/jsonrainbow/json-schema/tree/6.6.1"
},
- "time": "2025-09-09T09:42:27+00:00"
+ "time": "2025-11-07T18:30:29+00:00"
},
{
"name": "marc-mabe/php-enum",
@@ -2056,16 +2059,16 @@
},
{
"name": "symfony/console",
- "version": "v7.3.4",
+ "version": "v7.3.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db"
+ "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/2b9c5fafbac0399a20a2e82429e2bd735dcfb7db",
- "reference": "2b9c5fafbac0399a20a2e82429e2bd735dcfb7db",
+ "url": "https://api.github.com/repos/symfony/console/zipball/c28ad91448f86c5f6d9d2c70f0cf68bf135f252a",
+ "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a",
"shasum": ""
},
"require": {
@@ -2130,7 +2133,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v7.3.4"
+ "source": "https://github.com/symfony/console/tree/v7.3.6"
},
"funding": [
{
@@ -2150,7 +2153,7 @@
"type": "tidelift"
}
],
- "time": "2025-09-22T15:31:00+00:00"
+ "time": "2025-11-04T01:21:42+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -2221,16 +2224,16 @@
},
{
"name": "symfony/filesystem",
- "version": "v7.3.2",
+ "version": "v7.3.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
- "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd"
+ "reference": "e9bcfd7837928ab656276fe00464092cc9e1826a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/edcbb768a186b5c3f25d0643159a787d3e63b7fd",
- "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/e9bcfd7837928ab656276fe00464092cc9e1826a",
+ "reference": "e9bcfd7837928ab656276fe00464092cc9e1826a",
"shasum": ""
},
"require": {
@@ -2267,7 +2270,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/filesystem/tree/v7.3.2"
+ "source": "https://github.com/symfony/filesystem/tree/v7.3.6"
},
"funding": [
{
@@ -2287,20 +2290,20 @@
"type": "tidelift"
}
],
- "time": "2025-07-07T08:17:47+00:00"
+ "time": "2025-11-05T09:52:27+00:00"
},
{
"name": "symfony/finder",
- "version": "v7.3.2",
+ "version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe"
+ "reference": "9f696d2f1e340484b4683f7853b273abff94421f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe",
- "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/9f696d2f1e340484b4683f7853b273abff94421f",
+ "reference": "9f696d2f1e340484b4683f7853b273abff94421f",
"shasum": ""
},
"require": {
@@ -2335,7 +2338,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/finder/tree/v7.3.2"
+ "source": "https://github.com/symfony/finder/tree/v7.3.5"
},
"funding": [
{
@@ -2355,7 +2358,7 @@
"type": "tidelift"
}
],
- "time": "2025-07-15T13:41:35+00:00"
+ "time": "2025-10-15T18:45:57+00:00"
},
{
"name": "symfony/polyfill-ctype",
@@ -3323,23 +3326,23 @@
},
{
"name": "symfony/property-info",
- "version": "v7.3.1",
+ "version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/property-info.git",
- "reference": "90586acbf2a6dd13bee4f09f09111c8bd4773970"
+ "reference": "0b346ed259dc5da43535caf243005fe7d4b0f051"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/property-info/zipball/90586acbf2a6dd13bee4f09f09111c8bd4773970",
- "reference": "90586acbf2a6dd13bee4f09f09111c8bd4773970",
+ "url": "https://api.github.com/repos/symfony/property-info/zipball/0b346ed259dc5da43535caf243005fe7d4b0f051",
+ "reference": "0b346ed259dc5da43535caf243005fe7d4b0f051",
"shasum": ""
},
"require": {
"php": ">=8.2",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/string": "^6.4|^7.0",
- "symfony/type-info": "~7.2.8|^7.3.1"
+ "symfony/type-info": "^7.3.5"
},
"conflict": {
"phpdocumentor/reflection-docblock": "<5.2",
@@ -3389,7 +3392,7 @@
"validator"
],
"support": {
- "source": "https://github.com/symfony/property-info/tree/v7.3.1"
+ "source": "https://github.com/symfony/property-info/tree/v7.3.5"
},
"funding": [
{
@@ -3400,12 +3403,16 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-06-27T19:55:54+00:00"
+ "time": "2025-10-05T22:12:41+00:00"
},
{
"name": "symfony/serializer",
@@ -3512,16 +3519,16 @@
},
{
"name": "symfony/service-contracts",
- "version": "v3.6.0",
+ "version": "v3.6.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
- "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4"
+ "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
- "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43",
+ "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43",
"shasum": ""
},
"require": {
@@ -3575,7 +3582,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/service-contracts/tree/v3.6.0"
+ "source": "https://github.com/symfony/service-contracts/tree/v3.6.1"
},
"funding": [
{
@@ -3586,12 +3593,16 @@
"url": "https://github.com/fabpot",
"type": "github"
},
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
- "time": "2025-04-25T09:37:31+00:00"
+ "time": "2025-07-15T11:30:57+00:00"
},
{
"name": "symfony/string",
@@ -3867,16 +3878,16 @@
},
{
"name": "symfony/type-info",
- "version": "v7.3.3",
+ "version": "v7.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/type-info.git",
- "reference": "aa64b58ed04517d4d730202dd035895743c23273"
+ "reference": "8b36f41421160db56914f897b57eaa6a830758b3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/type-info/zipball/aa64b58ed04517d4d730202dd035895743c23273",
- "reference": "aa64b58ed04517d4d730202dd035895743c23273",
+ "url": "https://api.github.com/repos/symfony/type-info/zipball/8b36f41421160db56914f897b57eaa6a830758b3",
+ "reference": "8b36f41421160db56914f897b57eaa6a830758b3",
"shasum": ""
},
"require": {
@@ -3926,7 +3937,7 @@
"type"
],
"support": {
- "source": "https://github.com/symfony/type-info/tree/v7.3.3"
+ "source": "https://github.com/symfony/type-info/tree/v7.3.5"
},
"funding": [
{
@@ -3946,7 +3957,7 @@
"type": "tidelift"
}
],
- "time": "2025-08-28T09:38:04+00:00"
+ "time": "2025-10-16T12:30:12+00:00"
},
{
"name": "voku/portable-ascii",
@@ -4026,16 +4037,16 @@
"packages-dev": [
{
"name": "brianium/paratest",
- "version": "v7.14.1",
+ "version": "v7.14.2",
"source": {
"type": "git",
"url": "https://github.com/paratestphp/paratest.git",
- "reference": "e1a93c38a94f4808faf75552e835666d3a6f8bb2"
+ "reference": "de06de1ae1203b11976c6ca01d6a9081c8b33d45"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/paratestphp/paratest/zipball/e1a93c38a94f4808faf75552e835666d3a6f8bb2",
- "reference": "e1a93c38a94f4808faf75552e835666d3a6f8bb2",
+ "url": "https://api.github.com/repos/paratestphp/paratest/zipball/de06de1ae1203b11976c6ca01d6a9081c8b33d45",
+ "reference": "de06de1ae1203b11976c6ca01d6a9081c8b33d45",
"shasum": ""
},
"require": {
@@ -4049,7 +4060,7 @@
"phpunit/php-code-coverage": "^12.4.0",
"phpunit/php-file-iterator": "^6",
"phpunit/php-timer": "^8",
- "phpunit/phpunit": "^12.4.0",
+ "phpunit/phpunit": "^12.4.1",
"sebastian/environment": "^8.0.3",
"symfony/console": "^6.4.20 || ^7.3.4",
"symfony/process": "^6.4.20 || ^7.3.4"
@@ -4059,7 +4070,7 @@
"ext-pcntl": "*",
"ext-pcov": "*",
"ext-posix": "*",
- "phpstan/phpstan": "^2.1.30",
+ "phpstan/phpstan": "^2.1.31",
"phpstan/phpstan-deprecation-rules": "^2.0.3",
"phpstan/phpstan-phpunit": "^2.0.7",
"phpstan/phpstan-strict-rules": "^2.0.7",
@@ -4103,7 +4114,7 @@
],
"support": {
"issues": "https://github.com/paratestphp/paratest/issues",
- "source": "https://github.com/paratestphp/paratest/tree/v7.14.1"
+ "source": "https://github.com/paratestphp/paratest/tree/v7.14.2"
},
"funding": [
{
@@ -4115,7 +4126,7 @@
"type": "paypal"
}
],
- "time": "2025-10-06T08:26:52+00:00"
+ "time": "2025-10-24T07:20:53+00:00"
},
{
"name": "doctrine/deprecations",
@@ -4553,16 +4564,16 @@
},
{
"name": "nikic/php-parser",
- "version": "v5.6.1",
+ "version": "v5.6.2",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2"
+ "reference": "3a454ca033b9e06b63282ce19562e892747449bb"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
- "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb",
+ "reference": "3a454ca033b9e06b63282ce19562e892747449bb",
"shasum": ""
},
"require": {
@@ -4605,22 +4616,22 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
- "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1"
+ "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2"
},
- "time": "2025-08-13T20:13:15+00:00"
+ "time": "2025-10-21T19:32:17+00:00"
},
{
"name": "nunomaduro/collision",
- "version": "v8.8.2",
+ "version": "v8.8.3",
"source": {
"type": "git",
"url": "https://github.com/nunomaduro/collision.git",
- "reference": "60207965f9b7b7a4ce15a0f75d57f9dadb105bdb"
+ "reference": "1dc9e88d105699d0fee8bb18890f41b274f6b4c4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nunomaduro/collision/zipball/60207965f9b7b7a4ce15a0f75d57f9dadb105bdb",
- "reference": "60207965f9b7b7a4ce15a0f75d57f9dadb105bdb",
+ "url": "https://api.github.com/repos/nunomaduro/collision/zipball/1dc9e88d105699d0fee8bb18890f41b274f6b4c4",
+ "reference": "1dc9e88d105699d0fee8bb18890f41b274f6b4c4",
"shasum": ""
},
"require": {
@@ -4642,7 +4653,7 @@
"laravel/sanctum": "^4.1.1",
"laravel/tinker": "^2.10.1",
"orchestra/testbench-core": "^9.12.0 || ^10.4",
- "pestphp/pest": "^3.8.2",
+ "pestphp/pest": "^3.8.2 || ^4.0.0",
"sebastian/environment": "^7.2.1 || ^8.0"
},
"type": "library",
@@ -4706,35 +4717,35 @@
"type": "patreon"
}
],
- "time": "2025-06-25T02:12:12+00:00"
+ "time": "2025-11-20T02:55:25+00:00"
},
{
"name": "nunomaduro/termwind",
- "version": "v2.3.1",
+ "version": "v2.3.3",
"source": {
"type": "git",
"url": "https://github.com/nunomaduro/termwind.git",
- "reference": "dfa08f390e509967a15c22493dc0bac5733d9123"
+ "reference": "6fb2a640ff502caace8e05fd7be3b503a7e1c017"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/dfa08f390e509967a15c22493dc0bac5733d9123",
- "reference": "dfa08f390e509967a15c22493dc0bac5733d9123",
+ "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/6fb2a640ff502caace8e05fd7be3b503a7e1c017",
+ "reference": "6fb2a640ff502caace8e05fd7be3b503a7e1c017",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": "^8.2",
- "symfony/console": "^7.2.6"
+ "symfony/console": "^7.3.6"
},
"require-dev": {
- "illuminate/console": "^11.44.7",
- "laravel/pint": "^1.22.0",
+ "illuminate/console": "^11.46.1",
+ "laravel/pint": "^1.25.1",
"mockery/mockery": "^1.6.12",
- "pestphp/pest": "^2.36.0 || ^3.8.2",
- "phpstan/phpstan": "^1.12.25",
+ "pestphp/pest": "^2.36.0 || ^3.8.4 || ^4.1.3",
+ "phpstan/phpstan": "^1.12.32",
"phpstan/phpstan-strict-rules": "^1.6.2",
- "symfony/var-dumper": "^7.2.6",
+ "symfony/var-dumper": "^7.3.5",
"thecodingmachine/phpstan-strict-rules": "^1.0.0"
},
"type": "library",
@@ -4777,7 +4788,7 @@
],
"support": {
"issues": "https://github.com/nunomaduro/termwind/issues",
- "source": "https://github.com/nunomaduro/termwind/tree/v2.3.1"
+ "source": "https://github.com/nunomaduro/termwind/tree/v2.3.3"
},
"funding": [
{
@@ -4793,20 +4804,20 @@
"type": "github"
}
],
- "time": "2025-05-08T08:14:37+00:00"
+ "time": "2025-11-20T02:34:59+00:00"
},
{
"name": "pestphp/pest",
- "version": "v4.1.2",
+ "version": "v4.1.4",
"source": {
"type": "git",
"url": "https://github.com/pestphp/pest.git",
- "reference": "08b09f2e98fc6830050c0237968b233768642d46"
+ "reference": "1a39826935b730b0bcad805013d4b2607b83fe3f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/pestphp/pest/zipball/08b09f2e98fc6830050c0237968b233768642d46",
- "reference": "08b09f2e98fc6830050c0237968b233768642d46",
+ "url": "https://api.github.com/repos/pestphp/pest/zipball/1a39826935b730b0bcad805013d4b2607b83fe3f",
+ "reference": "1a39826935b730b0bcad805013d4b2607b83fe3f",
"shasum": ""
},
"require": {
@@ -4818,12 +4829,12 @@
"pestphp/pest-plugin-mutate": "^4.0.1",
"pestphp/pest-plugin-profanity": "^4.1.0",
"php": "^8.3.0",
- "phpunit/phpunit": "^12.4.0",
+ "phpunit/phpunit": "^12.4.1",
"symfony/process": "^7.3.4"
},
"conflict": {
"filp/whoops": "<2.18.3",
- "phpunit/phpunit": ">12.4.0",
+ "phpunit/phpunit": ">12.4.1",
"sebastian/exporter": "<7.0.0",
"webmozart/assert": "<1.11.0"
},
@@ -4897,7 +4908,7 @@
],
"support": {
"issues": "https://github.com/pestphp/pest/issues",
- "source": "https://github.com/pestphp/pest/tree/v4.1.2"
+ "source": "https://github.com/pestphp/pest/tree/v4.1.4"
},
"funding": [
{
@@ -4909,7 +4920,7 @@
"type": "github"
}
],
- "time": "2025-10-05T19:09:49+00:00"
+ "time": "2025-11-20T02:59:27+00:00"
},
{
"name": "pestphp/pest-plugin",
@@ -5129,16 +5140,16 @@
},
{
"name": "pestphp/pest-plugin-profanity",
- "version": "v4.1.0",
+ "version": "v4.2.0",
"source": {
"type": "git",
"url": "https://github.com/pestphp/pest-plugin-profanity.git",
- "reference": "e279c844b6868da92052be27b5202c2ad7216e80"
+ "reference": "c37e5e2c7136ee4eae12082e7952332bc1c6600a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/pestphp/pest-plugin-profanity/zipball/e279c844b6868da92052be27b5202c2ad7216e80",
- "reference": "e279c844b6868da92052be27b5202c2ad7216e80",
+ "url": "https://api.github.com/repos/pestphp/pest-plugin-profanity/zipball/c37e5e2c7136ee4eae12082e7952332bc1c6600a",
+ "reference": "c37e5e2c7136ee4eae12082e7952332bc1c6600a",
"shasum": ""
},
"require": {
@@ -5179,9 +5190,9 @@
"unit"
],
"support": {
- "source": "https://github.com/pestphp/pest-plugin-profanity/tree/v4.1.0"
+ "source": "https://github.com/pestphp/pest-plugin-profanity/tree/v4.2.0"
},
- "time": "2025-09-10T06:17:03+00:00"
+ "time": "2025-10-28T23:14:11+00:00"
},
{
"name": "phar-io/manifest",
@@ -5356,16 +5367,16 @@
},
{
"name": "phpdocumentor/reflection-docblock",
- "version": "5.6.3",
+ "version": "5.6.4",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
- "reference": "94f8051919d1b0369a6bcc7931d679a511c03fe9"
+ "reference": "90a04bcbf03784066f16038e87e23a0a83cee3c2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94f8051919d1b0369a6bcc7931d679a511c03fe9",
- "reference": "94f8051919d1b0369a6bcc7931d679a511c03fe9",
+ "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/90a04bcbf03784066f16038e87e23a0a83cee3c2",
+ "reference": "90a04bcbf03784066f16038e87e23a0a83cee3c2",
"shasum": ""
},
"require": {
@@ -5414,22 +5425,22 @@
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
- "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.3"
+ "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.4"
},
- "time": "2025-08-01T19:43:32+00:00"
+ "time": "2025-11-17T21:13:10+00:00"
},
{
"name": "phpdocumentor/type-resolver",
- "version": "1.10.0",
+ "version": "1.11.1",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
- "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a"
+ "reference": "f626740b38009078de0dc8b2b9dc4e7f749c6eba"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/679e3ce485b99e84c775d28e2e96fade9a7fb50a",
- "reference": "679e3ce485b99e84c775d28e2e96fade9a7fb50a",
+ "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/f626740b38009078de0dc8b2b9dc4e7f749c6eba",
+ "reference": "f626740b38009078de0dc8b2b9dc4e7f749c6eba",
"shasum": ""
},
"require": {
@@ -5472,9 +5483,9 @@
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
- "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.10.0"
+ "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.11.1"
},
- "time": "2024-11-09T15:12:26+00:00"
+ "time": "2025-11-21T11:31:57+00:00"
},
{
"name": "phpstan/extension-installer",
@@ -5573,20 +5584,15 @@
},
{
"name": "phpstan/phpstan",
- "version": "1.12.28",
- "source": {
- "type": "git",
- "url": "https://github.com/phpstan/phpstan.git",
- "reference": "fcf8b71aeab4e1a1131d1783cef97b23a51b87a9"
- },
+ "version": "2.1.32",
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/fcf8b71aeab4e1a1131d1783cef97b23a51b87a9",
- "reference": "fcf8b71aeab4e1a1131d1783cef97b23a51b87a9",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e126cad1e30a99b137b8ed75a85a676450ebb227",
+ "reference": "e126cad1e30a99b137b8ed75a85a676450ebb227",
"shasum": ""
},
"require": {
- "php": "^7.2|^8.0"
+ "php": "^7.4|^8.0"
},
"conflict": {
"phpstan/phpstan-shim": "*"
@@ -5627,7 +5633,7 @@
"type": "github"
}
],
- "time": "2025-07-17T17:15:39+00:00"
+ "time": "2025-11-11T15:18:17+00:00"
},
{
"name": "phpunit/php-code-coverage",
@@ -5965,16 +5971,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "12.4.0",
+ "version": "12.4.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "f62aab5794e36ccd26860db2d1bbf89ac19028d9"
+ "reference": "fc5413a2e6d240d2f6d9317bdf7f0a24e73de194"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f62aab5794e36ccd26860db2d1bbf89ac19028d9",
- "reference": "f62aab5794e36ccd26860db2d1bbf89ac19028d9",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fc5413a2e6d240d2f6d9317bdf7f0a24e73de194",
+ "reference": "fc5413a2e6d240d2f6d9317bdf7f0a24e73de194",
"shasum": ""
},
"require": {
@@ -6042,7 +6048,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/12.4.0"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/12.4.1"
},
"funding": [
{
@@ -6066,25 +6072,25 @@
"type": "tidelift"
}
],
- "time": "2025-10-03T04:28:03+00:00"
+ "time": "2025-10-09T14:08:29+00:00"
},
{
"name": "rector/rector",
- "version": "1.2.10",
+ "version": "2.2.8",
"source": {
"type": "git",
"url": "https://github.com/rectorphp/rector.git",
- "reference": "40f9cf38c05296bd32f444121336a521a293fa61"
+ "reference": "303aa811649ccd1d32e51e62d5c85949d01b5f1b"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/rectorphp/rector/zipball/40f9cf38c05296bd32f444121336a521a293fa61",
- "reference": "40f9cf38c05296bd32f444121336a521a293fa61",
+ "url": "https://api.github.com/repos/rectorphp/rector/zipball/303aa811649ccd1d32e51e62d5c85949d01b5f1b",
+ "reference": "303aa811649ccd1d32e51e62d5c85949d01b5f1b",
"shasum": ""
},
"require": {
- "php": "^7.2|^8.0",
- "phpstan/phpstan": "^1.12.5"
+ "php": "^7.4|^8.0",
+ "phpstan/phpstan": "^2.1.32"
},
"conflict": {
"rector/rector-doctrine": "*",
@@ -6109,6 +6115,7 @@
"MIT"
],
"description": "Instant Upgrade and Automated Refactoring of any PHP code",
+ "homepage": "https://getrector.com/",
"keywords": [
"automation",
"dev",
@@ -6117,7 +6124,7 @@
],
"support": {
"issues": "https://github.com/rectorphp/rector/issues",
- "source": "https://github.com/rectorphp/rector/tree/1.2.10"
+ "source": "https://github.com/rectorphp/rector/tree/2.2.8"
},
"funding": [
{
@@ -6125,7 +6132,7 @@
"type": "github"
}
],
- "time": "2024-11-08T13:59:10+00:00"
+ "time": "2025-11-12T18:38:00+00:00"
},
{
"name": "sebastian/cli-parser",
@@ -7137,16 +7144,16 @@
},
{
"name": "theseer/tokenizer",
- "version": "1.2.3",
+ "version": "1.3.1",
"source": {
"type": "git",
"url": "https://github.com/theseer/tokenizer.git",
- "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
+ "reference": "b7489ce515e168639d17feec34b8847c326b0b3c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
- "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c",
+ "reference": "b7489ce515e168639d17feec34b8847c326b0b3c",
"shasum": ""
},
"require": {
@@ -7175,7 +7182,7 @@
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
"support": {
"issues": "https://github.com/theseer/tokenizer/issues",
- "source": "https://github.com/theseer/tokenizer/tree/1.2.3"
+ "source": "https://github.com/theseer/tokenizer/tree/1.3.1"
},
"funding": [
{
@@ -7183,7 +7190,7 @@
"type": "github"
}
],
- "time": "2024-03-03T12:36:25+00:00"
+ "time": "2025-11-17T20:03:58+00:00"
},
{
"name": "tightenco/duster",
@@ -7255,21 +7262,21 @@
},
{
"name": "tomasvotruba/cognitive-complexity",
- "version": "0.2.3",
+ "version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/TomasVotruba/cognitive-complexity.git",
- "reference": "02cde7462c6d0ae76b74d71b6e69a29e710cffb2"
+ "reference": "974586fbc31b448ec04cf7877767bbb775671c3f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/TomasVotruba/cognitive-complexity/zipball/02cde7462c6d0ae76b74d71b6e69a29e710cffb2",
- "reference": "02cde7462c6d0ae76b74d71b6e69a29e710cffb2",
+ "url": "https://api.github.com/repos/TomasVotruba/cognitive-complexity/zipball/974586fbc31b448ec04cf7877767bbb775671c3f",
+ "reference": "974586fbc31b448ec04cf7877767bbb775671c3f",
"shasum": ""
},
"require": {
- "php": "^7.2 || ^8.0",
- "phpstan/phpstan": "^1.10"
+ "php": "^7.4 || ^8.0",
+ "phpstan/phpstan": "^2"
},
"type": "phpstan-extension",
"extra": {
@@ -7291,7 +7298,7 @@
"description": "PHPStan rules to measure cognitive complexity of your classes and methods",
"support": {
"issues": "https://github.com/TomasVotruba/cognitive-complexity/issues",
- "source": "https://github.com/TomasVotruba/cognitive-complexity/tree/0.2.3"
+ "source": "https://github.com/TomasVotruba/cognitive-complexity/tree/1.0.0"
},
"funding": [
{
@@ -7303,32 +7310,32 @@
"type": "github"
}
],
- "time": "2024-01-03T13:13:16+00:00"
+ "time": "2024-12-13T10:28:54+00:00"
},
{
"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": {
@@ -7359,9 +7366,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"
}
],
"aliases": [],
diff --git a/docs/README.md b/docs/README.md
index 8638c82..95a4344 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -59,6 +59,12 @@ Date and time utilities with type-safe operations:
- **DayOfWeek** - Type-safe day representation with flexible conversion
- **Month** - Month enumeration with navigation capabilities
+### [Assertions](./assertions.md)
+
+Runtime assertion utilities for verifying programming assumptions:
+
+- **Assert** - Precondition, postcondition, and invariant verification with static analysis integration
+
### [Core Objects and Utilities](./core-objects.md)
Foundational classes providing system-wide functionality:
diff --git a/docs/assertions.md b/docs/assertions.md
new file mode 100644
index 0000000..de9a935
--- /dev/null
+++ b/docs/assertions.md
@@ -0,0 +1,272 @@
+# Assertions
+
+The `Assert` class provides runtime assertion utilities for verifying preconditions, postconditions, and invariants in your code. Unlike validation, assertions verify assumptions that **must** be true for the program to continue safely.
+
+## Purpose
+
+Runtime verification of programming assumptions with static analysis integration. When assertions fail, they indicate bugs that should be fixed rather than conditions that should be handled gracefully.
+
+## Key Methods
+
+### Boolean Assertions
+
+- `true(mixed $value)` - Asserts that a value is boolean true
+- `false(mixed $value)` - Asserts that a value is boolean false
+
+### Null Assertions
+
+- `notNull(mixed $value)` - Asserts that a value is not null
+
+### Type Assertions
+
+- `string(mixed $value)` - Asserts that a value is a string
+
+## Usage Scenarios
+
+### Precondition Verification
+
+Verify function inputs meet required assumptions:
+
+```php
+public function processUser(?User $user): void
+{
+ Assert::notNull($user);
+ // $user is guaranteed non-null here
+ $user->doSomething();
+}
+```
+
+### Type Narrowing with Static Analysis
+
+Use assertions to help static analysis tools understand type guarantees:
+
+```php
+function handleValue(mixed $value): void
+{
+ Assert::string($value);
+ // PHPStan now knows $value is string
+ echo strtoupper($value);
+}
+```
+
+### Postcondition Verification
+
+Verify function outputs meet expected conditions:
+
+```php
+public function findUser(int $id): User
+{
+ $user = $this->repository->find($id);
+ Assert::notNull($user);
+ return $user;
+}
+```
+
+### Invariant Checking
+
+Verify state consistency during complex operations:
+
+```php
+public function transfer(Account $from, Account $to, int $amount): void
+{
+ $totalBefore = $from->balance + $to->balance;
+
+ $from->withdraw($amount);
+ $to->deposit($amount);
+
+ $totalAfter = $from->balance + $to->balance;
+ Assert::true($totalBefore === $totalAfter);
+}
+```
+
+## When to Use Assertions
+
+### Use Assertions For:
+
+- **Programming errors** - Violations of assumed contracts or invariants
+- **Developer mistakes** - Incorrect API usage or invalid state
+- **Type narrowing** - Helping static analysis understand guarantees
+- **Defensive programming** - Fail fast when assumptions are violated
+- **Development debugging** - Catching bugs early in development
+
+### Don't Use Assertions For:
+
+- **User input validation** - Use validation classes instead
+- **Expected error conditions** - Use proper error handling
+- **Business logic validation** - Use domain-specific validation
+- **Recoverable errors** - Use exceptions meant to be caught
+- **Production-only checks** - Assertions should be permanent
+
+## Exception Handling
+
+### Should You Catch Assertion Exceptions?
+
+**Generally, no.** Assertion failures indicate programming errors that should halt execution:
+
+```php
+// DON'T catch assertion failures
+try {
+ Assert::notNull($user);
+ $user->doSomething();
+} catch (AssertionFailedException $e) {
+ // This masks a bug that should be fixed
+}
+```
+
+When an assertion fails, the program should crash with a clear error message indicating what assumption was violated. This helps developers identify and fix bugs quickly.
+
+### Exception Details
+
+- Throws: `AssertionFailedException`
+- Exit code: `ExitCode::GENERAL_ERROR`
+- Message: Descriptive text indicating which assertion failed
+
+### When Catching Is Acceptable
+
+Only catch assertion exceptions in specific scenarios:
+
+- **Testing** - Verify that assertions work correctly
+- **Framework-level error handling** - Global exception handlers that log and report
+- **Development tools** - IDE integrations or debugging utilities
+
+```php
+// Acceptable in tests
+test('throws when value is null', function () {
+ expect(fn() => Assert::notNull(null))
+ ->toThrow(AssertionFailedException::class);
+});
+```
+
+## Static Analysis Integration
+
+All assertion methods include PHPStan annotations for type narrowing:
+
+- `@phpstan-assert true $value` - Narrows to boolean true
+- `@phpstan-assert false $value` - Narrows to boolean false
+- `@phpstan-assert !null $value` - Narrows to non-null
+- `@phpstan-assert string $value` - Narrows to string type
+
+This enables static analysis tools to understand the guarantees provided by assertions:
+
+```php
+function example(mixed $value): void
+{
+ Assert::string($value);
+ // No PHPStan error: $value is known to be string
+ echo strtoupper($value);
+}
+```
+
+## Assertions vs Validation
+
+### Assertions
+
+- Verify **programming assumptions**
+- Should **never** fail in correct code
+- Indicate **bugs** when they fail
+- **Not** meant to be caught
+- Used for **development** and **debugging**
+
+### Validation
+
+- Verify **user input** or **external data**
+- **Expected** to fail sometimes
+- Indicate **invalid input** when they fail
+- **Meant** to be caught and handled
+- Used for **business logic** and **security**
+
+## Best Practices
+
+### Write Clear Assertion Messages
+
+Boolean assertions check the type first and provide specific error messages:
+
+```php
+Assert::true($value);
+// "Failed to assert true: value is not a boolean."
+// or "Failed to assert true."
+```
+
+### Fail Fast
+
+Place assertions early in functions to catch violations immediately:
+
+```php
+public function process(mixed $data): void
+{
+ Assert::string($data); // Fail fast
+ // Rest of function knows $data is string
+}
+```
+
+### Use Appropriate Assertion Types
+
+Choose the most specific assertion for your needs:
+
+```php
+// Good: Specific assertion
+Assert::string($value);
+
+// Bad: Too generic
+Assert::true(is_string($value));
+```
+
+### Don't Assert Expected Conditions
+
+Only assert conditions that indicate bugs:
+
+```php
+// Bad: User input validation should not use assertions
+Assert::true($email !== '');
+
+// Good: Use proper validation
+if ($email === '') {
+ throw new ValidationException('Email is required');
+}
+```
+
+## Performance Considerations
+
+- Assertions execute on every call in all environments
+- No performance overhead for assertion checking
+- Failed assertions halt execution immediately
+- Consider the cost of complex assertion conditions
+
+## Common Patterns
+
+### Guard Clauses with Assertions
+
+```php
+public function updateUser(?User $user): void
+{
+ Assert::notNull($user);
+ // Guaranteed non-null, continue safely
+ $user->update(['last_seen' => now()]);
+}
+```
+
+### Type-Safe Conversions
+
+```php
+public function formatName(mixed $name): string
+{
+ Assert::string($name);
+ return Str::title($name);
+}
+```
+
+### Invariant Maintenance
+
+```php
+public function setBalance(int $balance): void
+{
+ $this->balance = $balance;
+ Assert::true($this->balance >= 0);
+}
+```
+
+## Related Components
+
+- `AssertionFailedException` - Exception thrown on assertion failures
+- `ExitCode` - Provides exit code constants including `GENERAL_ERROR`
+- PHPStan - Static analysis tool that understands assertion annotations
\ No newline at end of file
diff --git a/phpstan.neon b/phpstan.neon
index 753f713..c8da40c 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -1,6 +1,3 @@
-#includes:
-# - phpstan-baseline.neon
-
parameters:
level: 8
paths:
@@ -11,6 +8,7 @@ parameters:
ignoreErrors:
- identifier: missingType.generics
- identifier: missingType.iterableValue
+ - identifier: trait.unused
- '#PHPDoc tag .+ #'
cognitive_complexity:
class: 50
diff --git a/src/Exceptions/AssertionFailedException.php b/src/Exceptions/AssertionFailedException.php
new file mode 100644
index 0000000..1af2e80
--- /dev/null
+++ b/src/Exceptions/AssertionFailedException.php
@@ -0,0 +1,19 @@
+newInstance();
$mapper = $direction === self::MAPPER_DIRECTION_OUTPUT
- ? ($mapNameInstance->output ?? $mapNameInstance->input)
+ ? $mapNameInstance->output
: $mapNameInstance->input;
- if ($mapper !== null) {
- return self::getMapperResult($mapper, $propertyName);
- }
+
+ return self::getMapperResult($mapper, $propertyName);
}
return null;
diff --git a/src/Objects/Support/Assert.php b/src/Objects/Support/Assert.php
new file mode 100644
index 0000000..498ecc2
--- /dev/null
+++ b/src/Objects/Support/Assert.php
@@ -0,0 +1,61 @@
+