From efafa7461ecf5f5f2eace1c31e91d8175a981f63 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Wed, 19 Feb 2020 22:51:02 +0100 Subject: [PATCH] Added type assertions for multiple methods not covered by existing `@psalm-assert` functionality (#160) * Added type assertions around `Assert::isMap()` to restrict key type * Added minimal type assertions around `Assert::stringNotEmpty()` * Added minimal type assertions for `Assert::isArrayAccessible()` * Minimal type assertions around `Assert::ip()` type inference * Minimal type assertions around `Assert::ip()` type inference * Added minimal type assertions for `Assert::email()` * Added type assertions for `Assert::same()` types * Corrected type declaration: `Assert::contains()` only works with strings Note: not a BC break, since the implementation uses `\strpos()`, which is designed to reject non-string parameters. * Corrected type declaration: `Assert::notContains()` only works with strings Note: not a BC break, since the implementation uses `\strpos()`, which is designed to reject non-string parameters. * Corrected type declaration: `Assert::notWhitespaceOnly()` only works with strings Note: not a BC break, since the implementation uses `\preg_match()`, which is designed to reject non-string parameters. * Corrected type declaration: `Assert::startsWith()` only works with strings Note: not a BC break, since the implementation uses `\strpos()`, which is designed to reject non-string parameters. * Added type assertions for `Assert::startsWithLetter()` * Corrected `Assert::endsWith()` parameter type: only works with `string` values anyway * Corrected `Assert::regex()` parameter types: only works with `string` values anyway * Corrected `Assert::notRegex()` parameter types: only works with `string` values anyway * Added type assertions on `Assert::unicodeLetters()` * Added type assertions on `Assert::alpha()`, `Assert::digits()`, `Assert::alnum()`, `Assert::lower()`, `Assert::upper()` * Corrected `Assert::length()` types - method only works with strings/integers * Corrected `Assert::minLength()`, `Assert::maxLength()`, `Assert::lengthBetween()` type declarations These methods only work with integers, so we should restrict their types. * Added type assertions for `Assert::fileExists()` * Added type assertions for `Assert::file()` and `Assert::directory()` * Corrected type declarations on `Assert::readable()`: works only with `string` values * Corrected type declarations on `Assert::writable()`: works only with `string` values * Added type assertions for `Assert::subclassOf()` * Added type assertions for `Assert::implementsInterface()` * Corrected type declarations for `Assert::count()` * Corrected type declarations for `Assert::minCount()`, `Assert::maxCount()` and `Assert::countBetween()` These methods only work with countable types * Verifying that `Assert::isList()` preserves list item types * Adding type assertions for `Assert::isNonEmptyMap()` * Corrected type declarations around `Assert::uuid()` - method only works with `string` parameters * Corrected type declarations for `Assert::throws()` - the method only works with `Throwable` class strings * Applied automated CS fixes * Skip static analysis tests for scenarios that require an upstream release of psalm first * PHP 5.3 COMPATIBILITY OMG NGHHHHHHHHHHHHHHHHH LOUD TEAPOT NOISES!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * Added `@psalm-assert !empty` assertions as per newer multiple-assertion upstream support Ref: https://github.com/vimeo/psalm/commit/74de32fefe504516119390035a4941374a8bcecd * Locking dependency of `vimeo/psalm` for the `ci` directory We don't want to run static analysis with constantly changing psalm semantics, as that jeopardizes the stability of CI for now * Disallow installation of `vimeo/psalm` `<3.7.3` together with `webmozart/assert` This is required due to upstream support of multiple `@psalm-assert` annotations. Specifically, we need support that was introduced in commit https://github.com/vimeo/psalm/commit/74de32fefe504516119390035a4941374a8bcecd * `filter_var()` accepts `string|object`, so the input is asserted to be `string|object` An object implementing `#__toString()` suffices for `filter_var()` to work, so we can't assume that after the assertion, the value being asserted upon is a `string`. Instead, `string|object` is our closest bet. Ref: https://github.com/webmozart/assert/pull/160#discussion_r355964035 Note: will fail until https://github.com/vimeo/psalm/issues/2452 has some sort of resolution. * `ctype_*()` functions can operate with integer ranges `-128~256` too These are extremely fucky interfaces, but PHP is a shitty language anyway. We need to support an input of `string|int` when validating for the `ctype_*()` of an input, but at least we can assert for the value to not be `empty()` when it passes such validation. Ref: https://github.com/vimeo/psalm/issues/2452 * Bump vimeo/psalm CI dependency to try out results of https://github.com/vimeo/psalm/issues/2452 discussion * Removing `@psalm-assert string|object` from `ip`, `ipv4`, `ipv6` and `email` validators (for now) Psalm currently *cannot* deal with union types in `@psalm-assert`, because all `@psalm-assert` expressions are implicitly inlined by the tool as `assert(type)` language expression. This means that `@psalm-assert string|object $foo` becomes `assert(is_string($foo) || is_object($foo))`, which is non-sensical in contexts where `$foo` may never be a `string` or an `object`, leading to impossible to avoid `TypeDoesNotContainType` or `RedundantCondition` reported psalm errors. Therefore, dropping the type assertion is a simplistic (for now) solution, hoping that upstream tooling will someday be able to deal with this sort of assertions in a more atomic manner. Ref: https://github.com/vimeo/psalm/issues/2452#issuecomment-564059160 Ref: https://github.com/vimeo/psalm/issues/2452#issuecomment-564441827 * More precise type-assertions around `!empty` for `Assert::alpha()` * Exclude `/ci` dir from package release (now includes a larger `composer.lock` that is otherwise downstream waste) * Marking pure API with `@psalm-pure` for usage in pure downstream consumers * Ensure that the lack of usage of the result of a pure operation such as `Assert::string()` will not be considered "redundant" Ref: https://github.com/vimeo/psalm/issues/2456 Ref: https://github.com/vimeo/psalm/commit/4b715cdbffea19a7eab6f72482027d2dd358aab2 Ref: https://github.com/webmozart/assert/pull/160#issuecomment-564491986 * Marked `Assert::reportInvalidArgument()` as `@psalm-pure` While this method can be replaced via subclassing, adding side-effects to it would break the basic invariants of the assertion library, specifically that it is *NOT* a hook for more business logic, but rather just assertions, pure where possible. * Simpler type tests for `Assert::subclassOf()`, which can lead to a union type result * Added type restrictions on `Assert::isAOf()` API * `Assert::same()` is not supposed to couple two types, since the types may already be the same If the types are already the same, then the type checker would expand the assertion into a redundant condition (unexpected) * `Assert::isNotA()` type restrictions added * `Assert::isAnyOf()` is pure, declared type restrictions * `Assert::isInstanceOfAny()` is pure, declared type restrictions * Overhauled static analysis tests, hunted down all `RedundantCondition` All imprecise `RedundantCondition` raised by `@psalm-assert` restricting on something that may have already been restricted have been hunted down with extensive type-specific tests. All methods that may not necessarily be pure have also been removed from purity annotations. * Conflict with anything but latest `vimeo/psalm`, which understands the `lowercase-string` type Ref: https://github.com/vimeo/psalm/releases/tag/3.9.0 * `Assert::isMap()` does not imply non-empty array anymore Ref: https://github.com/webmozart/assert/pull/160#discussion_r381315641 * Removed integer value support from `ctype_*`-based functions While these functions support integers, we do not necessarily intend downstream consumers to rely on the widened type. Ref: https://github.com/webmozart/assert/pull/160#discussion_r381313258 * Removed exclusions from static analysis test existence checks All functions that have `@psalm-assert` annotations now have static analysis tests. Ref: https://github.com/webmozart/assert/pull/160/files#r381317558 * Allow both `int` and `float` on limits for count-based assertions Ref: https://github.com/webmozart/assert/pull/160#discussion_r381314468 * `Assert::eq()`, `::notEq()` and `::uniqueValues()` are not pure due to `__toString` In fact, the following explains it: ```php 'foo' == new class { public function __toString() : string {echo 'hi'; return 'bar'; }}; ``` This is a fucking mess of a language, but it's what we have to deal with :-( Ref: https://github.com/webmozart/assert/pull/160#discussion_r381338579 Ref: https://github.com/webmozart/assert/pull/160#discussion_r381342563 Ref: https://github.com/webmozart/assert/pull/160#discussion_r381340837 --- .gitattributes | 3 +- .gitignore | 2 +- ci/composer.json | 2 +- ci/composer.lock | 1394 +++++++++++++++++ composer.json | 2 +- src/Assert.php | 242 ++- tests/ProjectCodeTest.php | 1 + tests/static-analysis/assert-alnum.php | 19 + tests/static-analysis/assert-alpha.php | 19 + tests/static-analysis/assert-boolean.php | 1 + tests/static-analysis/assert-classExists.php | 3 +- tests/static-analysis/assert-contains.php | 15 + tests/static-analysis/assert-count.php | 13 + tests/static-analysis/assert-countBetween.php | 17 + tests/static-analysis/assert-digits.php | 19 + tests/static-analysis/assert-directory.php | 17 + tests/static-analysis/assert-email.php | 17 + tests/static-analysis/assert-endsWith.php | 18 + tests/static-analysis/assert-eq.php | 12 + tests/static-analysis/assert-false.php | 1 + tests/static-analysis/assert-file.php | 17 + tests/static-analysis/assert-fileExists.php | 17 + tests/static-analysis/assert-float.php | 1 + tests/static-analysis/assert-greaterThan.php | 15 + .../static-analysis/assert-greaterThanEq.php | 15 + .../assert-implementsInterface.php | 45 + tests/static-analysis/assert-integer.php | 1 + tests/static-analysis/assert-integerish.php | 1 + .../assert-interfaceExists.php | 3 +- tests/static-analysis/assert-ip.php | 17 + tests/static-analysis/assert-ipv4.php | 17 + tests/static-analysis/assert-ipv6.php | 17 + tests/static-analysis/assert-isAOf.php | 23 + tests/static-analysis/assert-isAnyOf.php | 19 + tests/static-analysis/assert-isArray.php | 1 + .../assert-isArrayAccessible.php | 18 + tests/static-analysis/assert-isCallable.php | 1 + tests/static-analysis/assert-isCountable.php | 1 + tests/static-analysis/assert-isEmpty.php | 3 +- tests/static-analysis/assert-isInstanceOf.php | 1 + .../assert-isInstanceOfAny.php | 19 + tests/static-analysis/assert-isIterable.php | 1 + tests/static-analysis/assert-isList.php | 16 + tests/static-analysis/assert-isMap.php | 50 + .../static-analysis/assert-isNonEmptyList.php | 2 + .../static-analysis/assert-isNonEmptyMap.php | 50 + tests/static-analysis/assert-isNotA.php | 25 + .../static-analysis/assert-isTraversable.php | 1 + tests/static-analysis/assert-keyExists.php | 19 + tests/static-analysis/assert-keyNotExists.php | 19 + tests/static-analysis/assert-length.php | 18 + .../static-analysis/assert-lengthBetween.php | 21 + tests/static-analysis/assert-lessThan.php | 15 + tests/static-analysis/assert-lessThanEq.php | 15 + tests/static-analysis/assert-lower.php | 31 + tests/static-analysis/assert-maxCount.php | 14 + tests/static-analysis/assert-maxLength.php | 20 + tests/static-analysis/assert-methodExists.php | 18 + .../assert-methodNotExists.php | 18 + tests/static-analysis/assert-minCount.php | 14 + tests/static-analysis/assert-minLength.php | 20 + tests/static-analysis/assert-natural.php | 1 + tests/static-analysis/assert-notContains.php | 15 + tests/static-analysis/assert-notEmpty.php | 3 + tests/static-analysis/assert-notEq.php | 12 + .../static-analysis/assert-notInstanceOf.php | 1 + tests/static-analysis/assert-notNull.php | 3 + tests/static-analysis/assert-notRegex.php | 18 + tests/static-analysis/assert-notSame.php | 15 + .../assert-notWhitespaceOnly.php | 15 + tests/static-analysis/assert-null.php | 1 + tests/static-analysis/assert-numeric.php | 3 +- tests/static-analysis/assert-object.php | 1 + tests/static-analysis/assert-oneOf.php | 15 + .../static-analysis/assert-propertyExists.php | 18 + .../assert-propertyNotExists.php | 18 + tests/static-analysis/assert-range.php | 15 + tests/static-analysis/assert-readable.php | 17 + tests/static-analysis/assert-regex.php | 18 + tests/static-analysis/assert-resource.php | 1 + tests/static-analysis/assert-same.php | 19 + tests/static-analysis/assert-scalar.php | 1 + tests/static-analysis/assert-startsWith.php | 18 + .../assert-startsWithLetter.php | 18 + tests/static-analysis/assert-string.php | 16 + .../static-analysis/assert-stringNotEmpty.php | 16 + tests/static-analysis/assert-subclassOf.php | 22 + tests/static-analysis/assert-throws.php | 13 + tests/static-analysis/assert-true.php | 1 + .../static-analysis/assert-unicodeLetters.php | 18 + tests/static-analysis/assert-uniqueValues.php | 12 + tests/static-analysis/assert-upper.php | 18 + tests/static-analysis/assert-uuid.php | 18 + .../static-analysis/assert-validArrayKey.php | 10 +- tests/static-analysis/assert-writable.php | 17 + 95 files changed, 2798 insertions(+), 65 deletions(-) create mode 100644 ci/composer.lock create mode 100644 tests/static-analysis/assert-alnum.php create mode 100644 tests/static-analysis/assert-alpha.php create mode 100644 tests/static-analysis/assert-contains.php create mode 100644 tests/static-analysis/assert-count.php create mode 100644 tests/static-analysis/assert-countBetween.php create mode 100644 tests/static-analysis/assert-digits.php create mode 100644 tests/static-analysis/assert-directory.php create mode 100644 tests/static-analysis/assert-email.php create mode 100644 tests/static-analysis/assert-endsWith.php create mode 100644 tests/static-analysis/assert-eq.php create mode 100644 tests/static-analysis/assert-file.php create mode 100644 tests/static-analysis/assert-fileExists.php create mode 100644 tests/static-analysis/assert-greaterThan.php create mode 100644 tests/static-analysis/assert-greaterThanEq.php create mode 100644 tests/static-analysis/assert-implementsInterface.php create mode 100644 tests/static-analysis/assert-ip.php create mode 100644 tests/static-analysis/assert-ipv4.php create mode 100644 tests/static-analysis/assert-ipv6.php create mode 100644 tests/static-analysis/assert-isAOf.php create mode 100644 tests/static-analysis/assert-isAnyOf.php create mode 100644 tests/static-analysis/assert-isArrayAccessible.php create mode 100644 tests/static-analysis/assert-isInstanceOfAny.php create mode 100644 tests/static-analysis/assert-isMap.php create mode 100644 tests/static-analysis/assert-isNonEmptyMap.php create mode 100644 tests/static-analysis/assert-isNotA.php create mode 100644 tests/static-analysis/assert-keyExists.php create mode 100644 tests/static-analysis/assert-keyNotExists.php create mode 100644 tests/static-analysis/assert-length.php create mode 100644 tests/static-analysis/assert-lengthBetween.php create mode 100644 tests/static-analysis/assert-lessThan.php create mode 100644 tests/static-analysis/assert-lessThanEq.php create mode 100644 tests/static-analysis/assert-lower.php create mode 100644 tests/static-analysis/assert-maxCount.php create mode 100644 tests/static-analysis/assert-maxLength.php create mode 100644 tests/static-analysis/assert-methodExists.php create mode 100644 tests/static-analysis/assert-methodNotExists.php create mode 100644 tests/static-analysis/assert-minCount.php create mode 100644 tests/static-analysis/assert-minLength.php create mode 100644 tests/static-analysis/assert-notContains.php create mode 100644 tests/static-analysis/assert-notEq.php create mode 100644 tests/static-analysis/assert-notRegex.php create mode 100644 tests/static-analysis/assert-notSame.php create mode 100644 tests/static-analysis/assert-notWhitespaceOnly.php create mode 100644 tests/static-analysis/assert-oneOf.php create mode 100644 tests/static-analysis/assert-propertyExists.php create mode 100644 tests/static-analysis/assert-propertyNotExists.php create mode 100644 tests/static-analysis/assert-range.php create mode 100644 tests/static-analysis/assert-readable.php create mode 100644 tests/static-analysis/assert-regex.php create mode 100644 tests/static-analysis/assert-same.php create mode 100644 tests/static-analysis/assert-startsWith.php create mode 100644 tests/static-analysis/assert-startsWithLetter.php create mode 100644 tests/static-analysis/assert-stringNotEmpty.php create mode 100644 tests/static-analysis/assert-subclassOf.php create mode 100644 tests/static-analysis/assert-throws.php create mode 100644 tests/static-analysis/assert-unicodeLetters.php create mode 100644 tests/static-analysis/assert-uniqueValues.php create mode 100644 tests/static-analysis/assert-upper.php create mode 100644 tests/static-analysis/assert-uuid.php create mode 100644 tests/static-analysis/assert-writable.php diff --git a/.gitattributes b/.gitattributes index 688bd271..c2d04e6d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,5 +3,6 @@ /.styleci.yml export-ignore /.travis.yml export-ignore /appveyor.yml export-ignore +/ci export-ignore /phpunit.xml.dist export-ignore -/tests export-ignore \ No newline at end of file +/tests export-ignore diff --git a/.gitignore b/.gitignore index d1502b08..d5f483a1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ vendor/ -composer.lock +./composer.lock diff --git a/ci/composer.json b/ci/composer.json index 207b2eab..5e0f0597 100644 --- a/ci/composer.json +++ b/ci/composer.json @@ -1,5 +1,5 @@ { "require": { - "vimeo/psalm": "^3.8.5" + "vimeo/psalm": "^3.9.1" } } diff --git a/ci/composer.lock b/ci/composer.lock new file mode 100644 index 00000000..8b2b1d44 --- /dev/null +++ b/ci/composer.lock @@ -0,0 +1,1394 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "4ce4d8df2974bae91c2617c88ccf797e", + "packages": [ + { + "name": "amphp/amp", + "version": "v2.4.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/amp.git", + "reference": "2ac3b550c4997f2ec304faa63c8b2885079a2dc4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/amp/zipball/2ac3b550c4997f2ec304faa63c8b2885079a2dc4", + "reference": "2ac3b550c4997f2ec304faa63c8b2885079a2dc4", + "shasum": "" + }, + "require": { + "php": ">=7" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1", + "ext-json": "*", + "phpstan/phpstan": "^0.8.5", + "phpunit/phpunit": "^6.0.9 | ^7", + "react/promise": "^2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Amp\\": "lib" + }, + "files": [ + "lib/functions.php", + "lib/Internal/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A non-blocking concurrency framework for PHP applications.", + "homepage": "http://amphp.org/amp", + "keywords": [ + "async", + "asynchronous", + "awaitable", + "concurrency", + "event", + "event-loop", + "future", + "non-blocking", + "promise" + ], + "time": "2020-02-10T18:10:57+00:00" + }, + { + "name": "amphp/byte-stream", + "version": "v1.7.2", + "source": { + "type": "git", + "url": "https://github.com/amphp/byte-stream.git", + "reference": "1e52f1752b2e20e2a7e464476ef887a2388e3832" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/byte-stream/zipball/1e52f1752b2e20e2a7e464476ef887a2388e3832", + "reference": "1e52f1752b2e20e2a7e464476ef887a2388e3832", + "shasum": "" + }, + "require": { + "amphp/amp": "^2" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1", + "friendsofphp/php-cs-fixer": "^2.3", + "infection/infection": "^0.9.3", + "phpunit/phpunit": "^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Amp\\ByteStream\\": "lib" + }, + "files": [ + "lib/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A stream abstraction to make working with non-blocking I/O simple.", + "homepage": "http://amphp.org/byte-stream", + "keywords": [ + "amp", + "amphp", + "async", + "io", + "non-blocking", + "stream" + ], + "time": "2020-01-29T18:22:23+00:00" + }, + { + "name": "composer/semver", + "version": "1.5.1", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/c6bea70230ef4dd483e6bbcab6005f682ed3a8de", + "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.5 || ^5.0.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "time": "2020-01-13T12:06:48+00:00" + }, + { + "name": "composer/xdebug-handler", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "cbe23383749496fe0f373345208b79568e4bc248" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/cbe23383749496fe0f373345208b79568e4bc248", + "reference": "cbe23383749496fe0f373345208b79568e4bc248", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0", + "psr/log": "^1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8" + }, + "type": "library", + "autoload": { + "psr-4": { + "Composer\\XdebugHandler\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" + } + ], + "description": "Restarts a process without Xdebug.", + "keywords": [ + "Xdebug", + "performance" + ], + "time": "2019-11-06T16:40:04+00:00" + }, + { + "name": "felixfbecker/advanced-json-rpc", + "version": "v3.1.0", + "source": { + "type": "git", + "url": "https://github.com/felixfbecker/php-advanced-json-rpc.git", + "reference": "a407a6cb0325cd489c6dff57afcba6baeccc0483" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/a407a6cb0325cd489c6dff57afcba6baeccc0483", + "reference": "a407a6cb0325cd489c6dff57afcba6baeccc0483", + "shasum": "" + }, + "require": { + "netresearch/jsonmapper": "^1.0", + "php": ">=7.0", + "phpdocumentor/reflection-docblock": "^4.0.0 || ^5.0.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "AdvancedJsonRpc\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Felix Becker", + "email": "felix.b@outlook.com" + } + ], + "description": "A more advanced JSONRPC implementation", + "time": "2020-02-11T20:48:40+00:00" + }, + { + "name": "felixfbecker/language-server-protocol", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/felixfbecker/php-language-server-protocol.git", + "reference": "378801f6139bb74ac215d81cca1272af61df9a9f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/378801f6139bb74ac215d81cca1272af61df9a9f", + "reference": "378801f6139bb74ac215d81cca1272af61df9a9f", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpstan/phpstan": "*", + "phpunit/phpunit": "^6.3", + "squizlabs/php_codesniffer": "^3.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "LanguageServerProtocol\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Felix Becker", + "email": "felix.b@outlook.com" + } + ], + "description": "PHP classes for the Language Server Protocol", + "keywords": [ + "language", + "microsoft", + "php", + "server" + ], + "time": "2019-06-23T21:03:50+00:00" + }, + { + "name": "netresearch/jsonmapper", + "version": "v1.6.0", + "source": { + "type": "git", + "url": "https://github.com/cweiske/jsonmapper.git", + "reference": "0d4d1b48d682a93b6bfedf60b88c7750e9cb0b06" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/0d4d1b48d682a93b6bfedf60b88c7750e9cb0b06", + "reference": "0d4d1b48d682a93b6bfedf60b88c7750e9cb0b06", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "~4.8.35 || ~5.7 || ~6.4", + "squizlabs/php_codesniffer": "~1.5" + }, + "type": "library", + "autoload": { + "psr-0": { + "JsonMapper": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "OSL-3.0" + ], + "authors": [ + { + "name": "Christian Weiske", + "email": "cweiske@cweiske.de", + "homepage": "http://github.com/cweiske/jsonmapper/", + "role": "Developer" + } + ], + "description": "Map nested JSON structures onto PHP classes", + "time": "2019-08-15T19:41:25+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.3.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "9a9981c347c5c49d6dfe5cf826bb882b824080dc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/9a9981c347c5c49d6dfe5cf826bb882b824080dc", + "reference": "9a9981c347c5c49d6dfe5cf826bb882b824080dc", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "0.0.5", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "time": "2019-11-08T13:50:10+00:00" + }, + { + "name": "ocramius/package-versions", + "version": "1.5.1", + "source": { + "type": "git", + "url": "https://github.com/Ocramius/PackageVersions.git", + "reference": "1d32342b8c1eb27353c8887c366147b4c2da673c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/1d32342b8c1eb27353c8887c366147b4c2da673c", + "reference": "1d32342b8c1eb27353c8887c366147b4c2da673c", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0.0", + "php": "^7.3.0" + }, + "require-dev": { + "composer/composer": "^1.8.6", + "doctrine/coding-standard": "^6.0.0", + "ext-zip": "*", + "infection/infection": "^0.13.4", + "phpunit/phpunit": "^8.2.5", + "vimeo/psalm": "^3.4.9" + }, + "type": "composer-plugin", + "extra": { + "class": "PackageVersions\\Installer", + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "PackageVersions\\": "src/PackageVersions" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", + "time": "2019-07-17T15:49:50+00:00" + }, + { + "name": "openlss/lib-array2xml", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/nullivex/lib-array2xml.git", + "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nullivex/lib-array2xml/zipball/a91f18a8dfc69ffabe5f9b068bc39bb202c81d90", + "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "autoload": { + "psr-0": { + "LSS": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Bryan Tong", + "email": "bryan@nullivex.com", + "homepage": "https://www.nullivex.com" + }, + { + "name": "Tony Butler", + "email": "spudz76@gmail.com", + "homepage": "https://www.nullivex.com" + } + ], + "description": "Array2XML conversion library credit to lalit.org", + "homepage": "https://www.nullivex.com", + "keywords": [ + "array", + "array conversion", + "xml", + "xml conversion" + ], + "time": "2019-03-29T20:06:56+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a", + "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "~6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "time": "2018-08-07T13:53:10+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "a48807183a4b819072f26e347bbd0b5199a9d15f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/a48807183a4b819072f26e347bbd0b5199a9d15f", + "reference": "a48807183a4b819072f26e347bbd0b5199a9d15f", + "shasum": "" + }, + "require": { + "ext-filter": "^7.1", + "php": "^7.2", + "phpdocumentor/reflection-common": "^2.0", + "phpdocumentor/type-resolver": "^1.0", + "webmozart/assert": "^1" + }, + "require-dev": { + "doctrine/instantiator": "^1", + "mockery/mockery": "^1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "time": "2020-02-09T09:16:15+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", + "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", + "shasum": "" + }, + "require": { + "php": "^7.1", + "phpdocumentor/reflection-common": "^2.0" + }, + "require-dev": { + "ext-tokenizer": "^7.1", + "mockery/mockery": "~1", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "time": "2019-08-22T18:11:29+00:00" + }, + { + "name": "psr/container", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "time": "2017-02-14T16:28:37+00:00" + }, + { + "name": "psr/log", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801", + "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2019-11-01T11:05:21+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "c0c26c9188b538bfa985ae10c9f05d278f12060d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c0c26c9188b538bfa985ae10c9f05d278f12060d", + "reference": "c0c26c9188b538bfa985ae10c9f05d278f12060d", + "shasum": "" + }, + "require": { + "php": "^7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0", + "symfony/process": "^4 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "time": "2020-02-07T06:09:38+00:00" + }, + { + "name": "symfony/console", + "version": "v5.0.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "91c294166c38d8c0858a86fad76d8c14dc1144c8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/91c294166c38d8c0858a86fad76d8c14dc1144c8", + "reference": "91c294166c38d8c0858a86fad76d8c14dc1144c8", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.8", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "symfony/dependency-injection": "<4.4", + "symfony/event-dispatcher": "<4.4", + "symfony/lock": "<4.4", + "symfony/process": "<4.4" + }, + "provide": { + "psr/log-implementation": "1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^4.4|^5.0", + "symfony/dependency-injection": "^4.4|^5.0", + "symfony/event-dispatcher": "^4.4|^5.0", + "symfony/lock": "^4.4|^5.0", + "symfony/process": "^4.4|^5.0", + "symfony/var-dumper": "^4.4|^5.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "https://symfony.com", + "time": "2020-01-25T15:56:29+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.14.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "fbdeaec0df06cf3d51c93de80c7eb76e271f5a38" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/fbdeaec0df06cf3d51c93de80c7eb76e271f5a38", + "reference": "fbdeaec0df06cf3d51c93de80c7eb76e271f5a38", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.14-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "time": "2020-01-13T11:15:53+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.14.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "34094cfa9abe1f0f14f48f490772db7a775559f2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/34094cfa9abe1f0f14f48f490772db7a775559f2", + "reference": "34094cfa9abe1f0f14f48f490772db7a775559f2", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.14-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "time": "2020-01-13T11:15:53+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.14.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "5e66a0fa1070bf46bec4bea7962d285108edd675" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/5e66a0fa1070bf46bec4bea7962d285108edd675", + "reference": "5e66a0fa1070bf46bec4bea7962d285108edd675", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.14-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2020-01-13T11:15:53+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "144c5e51266b281231e947b51223ba14acf1a749" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/144c5e51266b281231e947b51223ba14acf1a749", + "reference": "144c5e51266b281231e947b51223ba14acf1a749", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "psr/container": "^1.0" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-11-18T17:27:11+00:00" + }, + { + "name": "vimeo/psalm", + "version": "3.9.1", + "source": { + "type": "git", + "url": "https://github.com/vimeo/psalm.git", + "reference": "201d54f23293bac70c9b8b75985114449b3b56eb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/201d54f23293bac70c9b8b75985114449b3b56eb", + "reference": "201d54f23293bac70c9b8b75985114449b3b56eb", + "shasum": "" + }, + "require": { + "amphp/amp": "^2.1", + "amphp/byte-stream": "^1.5", + "composer/semver": "^1.4", + "composer/xdebug-handler": "^1.1", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-simplexml": "*", + "ext-tokenizer": "*", + "felixfbecker/advanced-json-rpc": "^3.0.3", + "felixfbecker/language-server-protocol": "^1.4", + "netresearch/jsonmapper": "^1.0", + "nikic/php-parser": "^4.3", + "ocramius/package-versions": "^1.2", + "openlss/lib-array2xml": "^1.0", + "php": "^7.1.3|^8", + "sebastian/diff": "^3.0 || ^4.0", + "symfony/console": "^3.4.17 || ^4.1.6 || ^5.0", + "webmozart/glob": "^4.1", + "webmozart/path-util": "^2.3" + }, + "provide": { + "psalm/psalm": "self.version" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.2", + "ext-curl": "*", + "phpmyadmin/sql-parser": "5.1.0", + "phpspec/prophecy": ">=1.9.0", + "phpunit/phpunit": "^7.5.16 || ^8.0", + "psalm/plugin-phpunit": "^0.9", + "slevomat/coding-standard": "^5.0", + "squizlabs/php_codesniffer": "^3.5", + "symfony/process": "^4.3" + }, + "suggest": { + "ext-igbinary": "^2.0.5" + }, + "bin": [ + "psalm", + "psalm-language-server", + "psalm-plugin", + "psalm-refactor", + "psalter" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev", + "dev-2.x": "2.x-dev", + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psalm\\Plugin\\": "src/Psalm/Plugin", + "Psalm\\": "src/Psalm" + }, + "files": [ + "src/functions.php", + "src/spl_object_id.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matthew Brown" + } + ], + "description": "A static analysis tool for finding errors in PHP applications", + "keywords": [ + "code", + "inspection", + "php" + ], + "time": "2020-02-18T14:40:21+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "aed98a490f9a8f78468232db345ab9cf606cf598" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/aed98a490f9a8f78468232db345ab9cf606cf598", + "reference": "aed98a490f9a8f78468232db345ab9cf606cf598", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "vimeo/psalm": "<3.6.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.36 || ^7.5.13" + }, + "type": "library", + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "time": "2020-02-14T12:15:55+00:00" + }, + { + "name": "webmozart/glob", + "version": "4.1.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/glob.git", + "reference": "3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/glob/zipball/3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe", + "reference": "3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe", + "shasum": "" + }, + "require": { + "php": "^5.3.3|^7.0", + "webmozart/path-util": "^2.2" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1", + "symfony/filesystem": "^2.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Glob\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "A PHP implementation of Ant's glob.", + "time": "2015-12-29T11:14:33+00:00" + }, + { + "name": "webmozart/path-util", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/path-util.git", + "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/path-util/zipball/d939f7edc24c9a1bb9c0dee5cb05d8e859490725", + "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "webmozart/assert": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\PathUtil\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "A robust cross-platform utility for normalizing, comparing and modifying file paths.", + "time": "2015-12-17T08:42:14+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/composer.json b/composer.json index 34350b29..033a0224 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "phpunit/phpunit": "^4.8.36 || ^7.5.13" }, "conflict": { - "vimeo/psalm": "<3.6.0" + "vimeo/psalm": "<3.9.1" }, "autoload": { "psr-4": { diff --git a/src/Assert.php b/src/Assert.php index aa7653e3..cf0548a5 100644 --- a/src/Assert.php +++ b/src/Assert.php @@ -209,6 +209,7 @@ class Assert { /** + * @psalm-pure * @psalm-assert string $value * * @param mixed $value @@ -227,6 +228,10 @@ public static function string($value, $message = '') } /** + * @psalm-pure + * @psalm-assert string $value + * @psalm-assert !empty $value + * * @param mixed $value * @param string $message * @@ -239,6 +244,7 @@ public static function stringNotEmpty($value, $message = '') } /** + * @psalm-pure * @psalm-assert int $value * * @param mixed $value @@ -257,6 +263,7 @@ public static function integer($value, $message = '') } /** + * @psalm-pure * @psalm-assert numeric $value * * @param mixed $value @@ -275,6 +282,7 @@ public static function integerish($value, $message = '') } /** + * @psalm-pure * @psalm-assert float $value * * @param mixed $value @@ -293,6 +301,7 @@ public static function float($value, $message = '') } /** + * @psalm-pure * @psalm-assert numeric $value * * @param mixed $value @@ -311,6 +320,7 @@ public static function numeric($value, $message = '') } /** + * @psalm-pure * @psalm-assert int $value * * @param mixed $value @@ -329,6 +339,7 @@ public static function natural($value, $message = '') } /** + * @psalm-pure * @psalm-assert bool $value * * @param mixed $value @@ -347,6 +358,7 @@ public static function boolean($value, $message = '') } /** + * @psalm-pure * @psalm-assert scalar $value * * @param mixed $value @@ -365,6 +377,7 @@ public static function scalar($value, $message = '') } /** + * @psalm-pure * @psalm-assert object $value * * @param mixed $value @@ -383,6 +396,7 @@ public static function object($value, $message = '') } /** + * @psalm-pure * @psalm-assert resource $value * * @param mixed $value @@ -410,6 +424,7 @@ public static function resource($value, $type = null, $message = '') } /** + * @psalm-pure * @psalm-assert callable $value * * @param mixed $value @@ -428,6 +443,7 @@ public static function isCallable($value, $message = '') } /** + * @psalm-pure * @psalm-assert array $value * * @param mixed $value @@ -446,6 +462,7 @@ public static function isArray($value, $message = '') } /** + * @psalm-pure * @psalm-assert iterable $value * * @deprecated use "isIterable" or "isInstanceOf" instead @@ -474,6 +491,9 @@ public static function isTraversable($value, $message = '') } /** + * @psalm-pure + * @psalm-assert array|ArrayAccess $value + * * @param mixed $value * @param string $message * @@ -490,6 +510,7 @@ public static function isArrayAccessible($value, $message = '') } /** + * @psalm-pure * @psalm-assert countable $value * * @param mixed $value @@ -513,6 +534,7 @@ public static function isCountable($value, $message = '') } /** + * @psalm-pure * @psalm-assert iterable $value * * @param mixed $value @@ -531,6 +553,7 @@ public static function isIterable($value, $message = '') } /** + * @psalm-pure * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert ExpectedType $value @@ -553,6 +576,7 @@ public static function isInstanceOf($value, $class, $message = '') } /** + * @psalm-pure * @psalm-template ExpectedType of object * @psalm-param class-string $class * @psalm-assert !ExpectedType $value @@ -575,6 +599,9 @@ public static function notInstanceOf($value, $class, $message = '') } /** + * @psalm-pure + * @psalm-param array $classes + * * @param mixed $value * @param array $classes * @param string $message @@ -597,6 +624,11 @@ public static function isInstanceOfAny($value, array $classes, $message = '') } /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert ExpectedType|class-string $value + * * @param object|string $value * @param string $class * @param string $message @@ -617,6 +649,12 @@ public static function isAOf($value, $class, $message = '') } /** + * @psalm-pure + * @psalm-template UnexpectedType of object + * @psalm-param class-string $class + * @psalm-assert !UnexpectedType $value + * @psalm-assert !class-string $value + * * @param object|string $value * @param string $class * @param string $message @@ -637,6 +675,9 @@ public static function isNotA($value, $class, $message = '') } /** + * @psalm-pure + * @psalm-param array $classes + * * @param object|string $value * @param string[] $classes * @param string $message @@ -661,6 +702,7 @@ public static function isAnyOf($value, array $classes, $message = '') } /** + * @psalm-pure * @psalm-assert empty $value * * @param mixed $value @@ -679,6 +721,7 @@ public static function isEmpty($value, $message = '') } /** + * @psalm-pure * @psalm-assert !empty $value * * @param mixed $value @@ -697,6 +740,7 @@ public static function notEmpty($value, $message = '') } /** + * @psalm-pure * @psalm-assert null $value * * @param mixed $value @@ -715,6 +759,7 @@ public static function null($value, $message = '') } /** + * @psalm-pure * @psalm-assert !null $value * * @param mixed $value @@ -732,6 +777,7 @@ public static function notNull($value, $message = '') } /** + * @psalm-pure * @psalm-assert true $value * * @param mixed $value @@ -750,6 +796,7 @@ public static function true($value, $message = '') } /** + * @psalm-pure * @psalm-assert false $value * * @param mixed $value @@ -908,6 +955,8 @@ public static function notEq($value, $expect, $message = '') } /** + * @psalm-pure + * * @param mixed $value * @param mixed $expect * @param string $message @@ -926,6 +975,8 @@ public static function same($value, $expect, $message = '') } /** + * @psalm-pure + * * @param mixed $value * @param mixed $expect * @param string $message @@ -943,6 +994,8 @@ public static function notSame($value, $expect, $message = '') } /** + * @psalm-pure + * * @param mixed $value * @param mixed $limit * @param string $message @@ -961,6 +1014,8 @@ public static function greaterThan($value, $limit, $message = '') } /** + * @psalm-pure + * * @param mixed $value * @param mixed $limit * @param string $message @@ -979,6 +1034,8 @@ public static function greaterThanEq($value, $limit, $message = '') } /** + * @psalm-pure + * * @param mixed $value * @param mixed $limit * @param string $message @@ -997,6 +1054,8 @@ public static function lessThan($value, $limit, $message = '') } /** + * @psalm-pure + * * @param mixed $value * @param mixed $limit * @param string $message @@ -1017,6 +1076,8 @@ public static function lessThanEq($value, $limit, $message = '') /** * Inclusive range, so Assert::(3, 3, 5) passes. * + * @psalm-pure + * * @param mixed $value * @param mixed $min * @param mixed $max @@ -1039,6 +1100,8 @@ public static function range($value, $min, $max, $message = '') /** * Does strict comparison, so Assert::oneOf(3, ['3']) does not pass the assertion. * + * @psalm-pure + * * @param mixed $value * @param array $values * @param string $message @@ -1057,7 +1120,9 @@ public static function oneOf($value, array $values, $message = '') } /** - * @param mixed $value + * @psalm-pure + * + * @param string $value * @param string $subString * @param string $message * @@ -1075,7 +1140,9 @@ public static function contains($value, $subString, $message = '') } /** - * @param mixed $value + * @psalm-pure + * + * @param string $value * @param string $subString * @param string $message * @@ -1093,7 +1160,9 @@ public static function notContains($value, $subString, $message = '') } /** - * @param mixed $value + * @psalm-pure + * + * @param string $value * @param string $message * * @throws InvalidArgumentException @@ -1109,7 +1178,9 @@ public static function notWhitespaceOnly($value, $message = '') } /** - * @param mixed $value + * @psalm-pure + * + * @param string $value * @param string $prefix * @param string $message * @@ -1127,6 +1198,8 @@ public static function startsWith($value, $prefix, $message = '') } /** + * @psalm-pure + * * @param mixed $value * @param string $message * @@ -1154,7 +1227,9 @@ public static function startsWithLetter($value, $message = '') } /** - * @param mixed $value + * @psalm-pure + * + * @param string $value * @param string $suffix * @param string $message * @@ -1172,8 +1247,10 @@ public static function endsWith($value, $suffix, $message = '') } /** - * @param mixed $value - * @param mixed $pattern + * @psalm-pure + * + * @param string $value + * @param string $pattern * @param string $message * * @throws InvalidArgumentException @@ -1189,8 +1266,10 @@ public static function regex($value, $pattern, $message = '') } /** - * @param mixed $value - * @param mixed $pattern + * @psalm-pure + * + * @param string $value + * @param string $pattern * @param string $message * * @throws InvalidArgumentException @@ -1208,6 +1287,8 @@ public static function notRegex($value, $pattern, $message = '') } /** + * @psalm-pure + * * @param mixed $value * @param string $message * @@ -1226,6 +1307,8 @@ public static function unicodeLetters($value, $message = '') } /** + * @psalm-pure + * * @param mixed $value * @param string $message * @@ -1249,7 +1332,9 @@ public static function alpha($value, $message = '') } /** - * @param mixed $value + * @psalm-pure + * + * @param string $value * @param string $message * * @throws InvalidArgumentException @@ -1270,7 +1355,9 @@ public static function digits($value, $message = '') } /** - * @param mixed $value + * @psalm-pure + * + * @param string $value * @param string $message * * @throws InvalidArgumentException @@ -1291,7 +1378,10 @@ public static function alnum($value, $message = '') } /** - * @param mixed $value + * @psalm-pure + * @psalm-assert lowercase-string $value + * + * @param string $value * @param string $message * * @throws InvalidArgumentException @@ -1312,7 +1402,10 @@ public static function lower($value, $message = '') } /** - * @param mixed $value + * @psalm-pure + * @psalm-assert !lowercase-string $value + * + * @param string $value * @param string $message * * @throws InvalidArgumentException @@ -1333,8 +1426,10 @@ public static function upper($value, $message = '') } /** - * @param mixed $value - * @param mixed $length + * @psalm-pure + * + * @param string $value + * @param int $length * @param string $message * * @throws InvalidArgumentException @@ -1353,9 +1448,11 @@ public static function length($value, $length, $message = '') /** * Inclusive min. * - * @param mixed $value - * @param mixed $min - * @param string $message + * @psalm-pure + * + * @param string $value + * @param int|float $min + * @param string $message * * @throws InvalidArgumentException */ @@ -1373,9 +1470,11 @@ public static function minLength($value, $min, $message = '') /** * Inclusive max. * - * @param mixed $value - * @param mixed $max - * @param string $message + * @psalm-pure + * + * @param string $value + * @param int|float $max + * @param string $message * * @throws InvalidArgumentException */ @@ -1393,10 +1492,12 @@ public static function maxLength($value, $max, $message = '') /** * Inclusive , so Assert::lengthBetween('asd', 3, 5); passes the assertion. * - * @param mixed $value - * @param mixed $min - * @param mixed $max - * @param string $message + * @psalm-pure + * + * @param string $value + * @param int|float $min + * @param int|float $max + * @param string $message * * @throws InvalidArgumentException */ @@ -1471,7 +1572,7 @@ public static function directory($value, $message = '') } /** - * @param mixed $value + * @param string $value * @param string $message * * @throws InvalidArgumentException @@ -1487,7 +1588,7 @@ public static function readable($value, $message = '') } /** - * @param mixed $value + * @param string $value * @param string $message * * @throws InvalidArgumentException @@ -1503,8 +1604,6 @@ public static function writable($value, $message = '') } /** - * @psalm-assert class-string $value - * * @param mixed $value * @param string $message * @@ -1521,6 +1620,11 @@ public static function classExists($value, $message = '') } /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert class-string|ExpectedType $value + * * @param mixed $value * @param string|object $class * @param string $message @@ -1539,8 +1643,6 @@ public static function subclassOf($value, $class, $message = '') } /** - * @psalm-assert class-string $value - * * @param mixed $value * @param string $message * @@ -1557,6 +1659,11 @@ public static function interfaceExists($value, $message = '') } /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $interface + * @psalm-assert class-string $value + * * @param mixed $value * @param mixed $interface * @param string $message @@ -1575,6 +1682,9 @@ public static function implementsInterface($value, $interface, $message = '') } /** + * @psalm-pure + * @psalm-param class-string|object $classOrObject + * * @param string|object $classOrObject * @param mixed $property * @param string $message @@ -1592,6 +1702,9 @@ public static function propertyExists($classOrObject, $property, $message = '') } /** + * @psalm-pure + * @psalm-param class-string|object $classOrObject + * * @param string|object $classOrObject * @param mixed $property * @param string $message @@ -1609,6 +1722,9 @@ public static function propertyNotExists($classOrObject, $property, $message = ' } /** + * @psalm-pure + * @psalm-param class-string|object $classOrObject + * * @param string|object $classOrObject * @param mixed $method * @param string $message @@ -1626,6 +1742,9 @@ public static function methodExists($classOrObject, $method, $message = '') } /** + * @psalm-pure + * @psalm-param class-string|object $classOrObject + * * @param string|object $classOrObject * @param mixed $method * @param string $message @@ -1643,6 +1762,8 @@ public static function methodNotExists($classOrObject, $method, $message = '') } /** + * @psalm-pure + * * @param array $array * @param string|int $key * @param string $message @@ -1660,6 +1781,8 @@ public static function keyExists($array, $key, $message = '') } /** + * @psalm-pure + * * @param array $array * @param string|int $key * @param string $message @@ -1679,6 +1802,7 @@ public static function keyNotExists($array, $key, $message = '') /** * Checks if a value is a valid array key (int or string). * + * @psalm-pure * @psalm-assert array-key $value * * @param mixed $value @@ -1699,9 +1823,9 @@ public static function validArrayKey($value, $message = '') /** * Does not check if $array is countable, this can generate a warning on php versions after 7.2. * - * @param mixed $array - * @param mixed $number - * @param string $message + * @param Countable|array $array + * @param int $number + * @param string $message * * @throws InvalidArgumentException */ @@ -1717,9 +1841,9 @@ public static function count($array, $number, $message = '') /** * Does not check if $array is countable, this can generate a warning on php versions after 7.2. * - * @param mixed $array - * @param mixed $min - * @param string $message + * @param Countable|array $array + * @param int|float $min + * @param string $message * * @throws InvalidArgumentException */ @@ -1737,9 +1861,9 @@ public static function minCount($array, $min, $message = '') /** * Does not check if $array is countable, this can generate a warning on php versions after 7.2. * - * @param mixed $array - * @param mixed $max - * @param string $message + * @param Countable|array $array + * @param int|float $max + * @param string $message * * @throws InvalidArgumentException */ @@ -1757,10 +1881,10 @@ public static function maxCount($array, $max, $message = '') /** * Does not check if $array is countable, this can generate a warning on php versions after 7.2. * - * @param mixed $array - * @param mixed $min - * @param mixed $max - * @param string $message + * @param Countable|array $array + * @param int|float $min + * @param int|float $max + * @param string $message * * @throws InvalidArgumentException */ @@ -1779,6 +1903,7 @@ public static function countBetween($array, $min, $max, $message = '') } /** + * @psalm-pure * @psalm-assert list $array * * @param mixed $array @@ -1796,7 +1921,9 @@ public static function isList($array, $message = '') } /** - * @psalm-assert non-empty-list $array + * @psalm-pure + * @psalm-assert list $array + * @psalm-assert !empty $array * * @param mixed $array * @param string $message @@ -1810,6 +1937,11 @@ public static function isNonEmptyList($array, $message = '') } /** + * @psalm-pure + * @psalm-template T + * @psalm-param mixed|array $array + * @psalm-assert array $array + * * @param mixed $array * @param string $message * @@ -1828,6 +1960,12 @@ public static function isMap($array, $message = '') } /** + * @psalm-pure + * @psalm-template T + * @psalm-param mixed|array $array + * @psalm-assert array $array + * @psalm-assert !empty $array + * * @param mixed $array * @param string $message * @@ -1840,7 +1978,9 @@ public static function isNonEmptyMap($array, $message = '') } /** - * @param mixed $value + * @psalm-pure + * + * @param string $value * @param string $message * * @throws InvalidArgumentException @@ -1864,9 +2004,11 @@ public static function uuid($value, $message = '') } /** - * @param Closure $expression - * @param string|object $class - * @param string $message + * @psalm-param class-string + * + * @param Closure $expression + * @param string $class + * @param string $message * * @throws InvalidArgumentException */ @@ -1998,6 +2140,8 @@ protected static function strlen($value) * @param string $message * * @throws InvalidArgumentException + * + * @psalm-pure this method is not supposed to perform side-effects */ protected static function reportInvalidArgument($message) { diff --git a/tests/ProjectCodeTest.php b/tests/ProjectCodeTest.php index f6c4036e..b3e32b08 100644 --- a/tests/ProjectCodeTest.php +++ b/tests/ProjectCodeTest.php @@ -116,6 +116,7 @@ public function testHasThrowsAnnotation($method) public function testHasCorrespondingStaticAnalysisFile($method) { $doc = $method->getDocComment(); + if($doc === false || strpos($doc, '@psalm-assert') === false) { $this->addToAssertionCount(1); return; diff --git a/tests/static-analysis/assert-alnum.php b/tests/static-analysis/assert-alnum.php new file mode 100644 index 00000000..db322319 --- /dev/null +++ b/tests/static-analysis/assert-alnum.php @@ -0,0 +1,19 @@ + $value + */ +function consumeMixed($value): string +{ + Assert::implementsInterface($value, ImplementsInterfaceA::class); + + return $value; +} + +/** + * @psalm-pure + * + * @psalm-param class-string|class-string $value + * + * @psalm-return class-string $value + */ +function consumeSubclass(string $value): string +{ + Assert::implementsInterface($value, ImplementsInterfaceB::class); + + return $value; +} diff --git a/tests/static-analysis/assert-integer.php b/tests/static-analysis/assert-integer.php index 4f9969be..b5b12052 100644 --- a/tests/static-analysis/assert-integer.php +++ b/tests/static-analysis/assert-integer.php @@ -5,6 +5,7 @@ use Webmozart\Assert\Assert; /** + * @psalm-pure * @psalm-param mixed $value */ function consume($value): int diff --git a/tests/static-analysis/assert-integerish.php b/tests/static-analysis/assert-integerish.php index 067c6eb7..9151c047 100644 --- a/tests/static-analysis/assert-integerish.php +++ b/tests/static-analysis/assert-integerish.php @@ -5,6 +5,7 @@ use Webmozart\Assert\Assert; /** + * @psalm-pure * @psalm-param string|numeric $value * * @psalm-return numeric diff --git a/tests/static-analysis/assert-interfaceExists.php b/tests/static-analysis/assert-interfaceExists.php index f30cff21..967c148b 100644 --- a/tests/static-analysis/assert-interfaceExists.php +++ b/tests/static-analysis/assert-interfaceExists.php @@ -6,9 +6,8 @@ /** - * @param mixed $value + * @param class-string $value * - * @return string * @psalm-return class-string */ function consume($value): string diff --git a/tests/static-analysis/assert-ip.php b/tests/static-analysis/assert-ip.php new file mode 100644 index 00000000..7d1509f1 --- /dev/null +++ b/tests/static-analysis/assert-ip.php @@ -0,0 +1,17 @@ +|IsAOfA + */ +function consume($value) +{ + Assert::isAOf($value, IsAOfA::class); + + return $value; +} diff --git a/tests/static-analysis/assert-isAnyOf.php b/tests/static-analysis/assert-isAnyOf.php new file mode 100644 index 00000000..7208dabf --- /dev/null +++ b/tests/static-analysis/assert-isAnyOf.php @@ -0,0 +1,19 @@ + @@ -15,3 +17,17 @@ function consume($value): array return $value; } + +/** + * @psalm-pure + * + * @psalm-param array<\stdClass> $value + * + * @psalm-return list<\stdClass> + */ +function consumeWithPreciseItemType(array $value): array +{ + Assert::isList($value); + + return $value; +} diff --git a/tests/static-analysis/assert-isMap.php b/tests/static-analysis/assert-isMap.php new file mode 100644 index 00000000..d57f8c23 --- /dev/null +++ b/tests/static-analysis/assert-isMap.php @@ -0,0 +1,50 @@ + + */ +function consume($value): array +{ + Assert::isMap($value); + + return $value; +} + +/** + * Verifying that the type of the elements in the array is preserved by the assertion + * + * @psalm-pure + * + * @param array $value + * + * @return array + */ +function consumeWithSpecificValueType(array $value): array +{ + Assert::isMap($value); + + return $value; +} + +/** + * @psalm-pure + * + * @param array $value + * + * @return array + */ +function consumeAllowsForEmptyArrays(array $value): array +{ + Assert::isMap($value); + Assert::isEmpty($value); + + return $value; +} diff --git a/tests/static-analysis/assert-isNonEmptyList.php b/tests/static-analysis/assert-isNonEmptyList.php index 1e8d31b5..9435386f 100644 --- a/tests/static-analysis/assert-isNonEmptyList.php +++ b/tests/static-analysis/assert-isNonEmptyList.php @@ -5,6 +5,8 @@ use Webmozart\Assert\Assert; /** + * @psalm-pure + * * @psalm-param mixed $value * * @psalm-return non-empty-list diff --git a/tests/static-analysis/assert-isNonEmptyMap.php b/tests/static-analysis/assert-isNonEmptyMap.php new file mode 100644 index 00000000..20efaa8c --- /dev/null +++ b/tests/static-analysis/assert-isNonEmptyMap.php @@ -0,0 +1,50 @@ + + */ +function consume($value): array +{ + Assert::isNonEmptyMap($value); + + return $value; +} + +/** + * Verifying that the type of the elements in the array is preserved by the assertion + * + * @psalm-pure + * + * @param array $value + * + * @return array + */ +function consumeWithSpecificValueType(array $value): array +{ + Assert::isNonEmptyMap($value); + + return $value; +} + + +/** + * @psalm-pure + * + * @param array $value + * + * @return non-empty-array + */ +function consumeWillProduceNonEmptyArray(array $value): array +{ + Assert::isNonEmptyMap($value); + + return $value; +} diff --git a/tests/static-analysis/assert-isNotA.php b/tests/static-analysis/assert-isNotA.php new file mode 100644 index 00000000..22252089 --- /dev/null +++ b/tests/static-analysis/assert-isNotA.php @@ -0,0 +1,25 @@ +|SubclassOfA + */ +function consumeMixed($value) +{ + Assert::subclassOf($value, SubclassOfA::class); + + return $value; +} diff --git a/tests/static-analysis/assert-throws.php b/tests/static-analysis/assert-throws.php new file mode 100644 index 00000000..baee42f1 --- /dev/null +++ b/tests/static-analysis/assert-throws.php @@ -0,0 +1,13 @@ + $array * - * @return array + * @psalm-return array-key */ -function consume($value, array $array): array +function consume($value) { Assert::validArrayKey($value); - $array[$value] = 12; - - return $array; + return $value; } diff --git a/tests/static-analysis/assert-writable.php b/tests/static-analysis/assert-writable.php new file mode 100644 index 00000000..dc0606bf --- /dev/null +++ b/tests/static-analysis/assert-writable.php @@ -0,0 +1,17 @@ +