diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index bec95c4494..0000000000 --- a/.editorconfig +++ /dev/null @@ -1,9 +0,0 @@ -root = true - -[*] -charset = utf-8 -end_of_line = lf -insert_final_newline = true -trim_trailing_whitespace = true -indent_style = space -indent_size = 4 diff --git a/.github/workflows/bare_run.yaml b/.github/workflows/bare_run.yaml index 41c80985f4..3586171d0a 100644 --- a/.github/workflows/bare_run.yaml +++ b/.github/workflows/bare_run.yaml @@ -1,9 +1,6 @@ -name: Bare Run on various PHP versions +name: Bare Run -on: - push: - tags: - - '*' +on: [pull_request, push] jobs: bare_run: @@ -12,12 +9,15 @@ jobs: strategy: fail-fast: false matrix: - php_version: ['7.2', '7.3', '7.4', '8.0', '8.1'] + php_version: ['7.2', '7.3', '7.4', '8.0', '8.2'] steps: - - uses: shivammathur/setup-php@v2 + - uses: actions/checkout@v2 + + - + uses: shivammathur/setup-php@v2 with: - php-version: ${{ matrix.php }} + php-version: ${{ matrix.php_version }} coverage: none - - run: composer require rector/swiss-knife --dev --ansi + - run: php bin/swiss-knife list --ansi diff --git a/.gitignore b/.gitignore deleted file mode 100644 index d026490bac..0000000000 --- a/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -composer.lock -/vendor - -.phpunit.cache diff --git a/bin/swiss-knife b/bin/swiss-knife index c77c8f8482..3badfda60e 100755 --- a/bin/swiss-knife +++ b/bin/swiss-knife @@ -1,4 +1,5 @@ #!/usr/bin/env php -create(); - $application = $container->make(Application::class); - $exitCode = $application->run(new ArgvInput(), new ConsoleOutput()); exit($exitCode); diff --git a/build/build-scoped.sh b/build/build-scoped.sh deleted file mode 100755 index e24cdf45fa..0000000000 --- a/build/build-scoped.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env bash - -# inspired from https://github.com/rectorphp/rector/blob/main/build/build-rector-scoped.sh - -# see https://stackoverflow.com/questions/66644233/how-to-propagate-colors-from-bash-script-to-github-action?noredirect=1#comment117811853_66644233 -export TERM=xterm-color - -# show errors -set -e - -# script fails if trying to access to an undefined variable -set -u - - -# functions -note() -{ - MESSAGE=$1; - printf "\n"; - echo "\033[0;33m[NOTE] $MESSAGE\033[0m"; -} - - -# configure here -BUILD_DIRECTORY=$1 -RESULT_DIRECTORY=$2 - -# --------------------------- - -note "Starts" - -# 2. scope it -note "Running scoper with '$RESULT_DIRECTORY' output directory" -wget https://github.com/humbug/php-scoper/releases/download/0.17.5/php-scoper.phar -N --no-verbose - -# create directory -mkdir "$RESULT_DIRECTORY" -p - -# Work around possible PHP memory limits -php -d memory_limit=-1 php-scoper.phar add-prefix bin src stubs vendor composer.json --output-dir "../$RESULT_DIRECTORY" --config scoper.php --force --ansi --working-dir "$BUILD_DIRECTORY" - -note "Show prefixed files in '$RESULT_DIRECTORY'" -ls -l $RESULT_DIRECTORY - -note "Dumping Composer Autoload" -composer dump-autoload --working-dir "$RESULT_DIRECTORY" --ansi --classmap-authoritative --no-dev - -# make bin/swiss-knife runnable without "php" -chmod 777 "$RESULT_DIRECTORY/bin/swiss-knife" -chmod 777 "$RESULT_DIRECTORY/bin/swiss-knife.php" - -note "Finished" diff --git a/build/rector-downgrade-php-72.php b/build/rector-downgrade-php-72.php deleted file mode 100644 index 68641a4596..0000000000 --- a/build/rector-downgrade-php-72.php +++ /dev/null @@ -1,15 +0,0 @@ -sets([DowngradeLevelSetList::DOWN_TO_PHP_72]); - - $rectorConfig->skip([ - '*/Tests/*', - '*/tests/*', - ]); -}; diff --git a/build/target-repository/.github/FUNDING.yml b/build/target-repository/.github/FUNDING.yml deleted file mode 100644 index f797866a90..0000000000 --- a/build/target-repository/.github/FUNDING.yml +++ /dev/null @@ -1,3 +0,0 @@ -# These are supported funding model platforms -github: tomasvotruba -custom: https://www.paypal.me/rectorphp diff --git a/build/target-repository/.github/workflows/bare_run.yaml b/build/target-repository/.github/workflows/bare_run.yaml deleted file mode 100644 index 3586171d0a..0000000000 --- a/build/target-repository/.github/workflows/bare_run.yaml +++ /dev/null @@ -1,23 +0,0 @@ -name: Bare Run - -on: [pull_request, push] - -jobs: - bare_run: - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - php_version: ['7.2', '7.3', '7.4', '8.0', '8.2'] - - steps: - - uses: actions/checkout@v2 - - - - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php_version }} - coverage: none - - - run: php bin/swiss-knife list --ansi diff --git a/build/target-repository/composer.json b/build/target-repository/composer.json deleted file mode 100644 index 6aba2bea17..0000000000 --- a/build/target-repository/composer.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "rector/swiss-knife", - "description": "Swiss knife in pocket of every upgrade architect", - "license": "MIT", - "require": { - "php": ">=7.2" - }, - "bin": [ - "bin/swiss-knife" - ] -} diff --git a/composer.json b/composer.json index fe3bb21f11..6aba2bea17 100644 --- a/composer.json +++ b/composer.json @@ -2,57 +2,10 @@ "name": "rector/swiss-knife", "description": "Swiss knife in pocket of every upgrade architect", "license": "MIT", - "bin": [ - "bin/swiss-knife" - ], "require": { - "php": ">=8.2", - "illuminate/container": "^10.43", - "nette/robot-loader": "^3.4", - "nette/utils": "^3.2", - "nikic/php-parser": "^4.18", - "symfony/console": "^6.4", - "symfony/process": "^6.4", - "symfony/finder": "^6.4", - "webmozart/assert": "^1.11" - }, - "require-dev": { - "icanhazstring/composer-unused": "^0.8.11", - "phpunit/phpunit": "^10.5", - "rector/rector": "^1.0", - "symplify/easy-coding-standard": "^12.1", - "tomasvotruba/class-leak": "^0.2", - "tracy/tracy": "^2.10" - }, - "autoload": { - "psr-4": { - "Rector\\SwissKnife\\": "src" - }, - "classmap": [ - "stubs" - ] - }, - "autoload-dev": { - "psr-4": { - "Rector\\SwissKnife\\Tests\\": "tests" - } + "php": ">=7.2" }, - "replace": { - "symfony/polyfill-ctype": "*", - "symfony/polyfill-intl-normalizer": "*", - "symfony/polyfill-mbstring": "*" - }, - "config": { - "sort-packages": true, - "platform-check": false, - "allow-plugins": { - "phpstan/extension-installer": true - } - }, - "scripts": { - "check-cs": "vendor/bin/ecs check --ansi", - "fix-cs": "vendor/bin/ecs check --fix --ansi", - "phpstan": "vendor/bin/phpstan analyse --ansi", - "rector": "vendor/bin/rector process --ansi" - } + "bin": [ + "bin/swiss-knife" + ] } diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000000..56148117be --- /dev/null +++ b/composer.lock @@ -0,0 +1,4276 @@ +{ + "_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": "bd56538313f8398f8246f599e7944495", + "packages": [ + { + "name": "illuminate/container", + "version": "v10.48.12", + "source": { + "type": "git", + "url": "https://github.com/illuminate/container.git", + "reference": "ddc26273085fad3c471b2602ad820e0097ff7939" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/illuminate/container/zipball/ddc26273085fad3c471b2602ad820e0097ff7939", + "reference": "ddc26273085fad3c471b2602ad820e0097ff7939", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^10.0", + "php": "^8.1", + "psr/container": "^1.1.1|^2.0.1" + }, + "provide": { + "psr/container-implementation": "1.1|2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "10.x-dev" + } + }, + "autoload": { + "psr-4": { + "Illuminate\\Container\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Illuminate Container package.", + "homepage": "https://laravel.com", + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "time": "2023-06-18T09:12:03+00:00" + }, + { + "name": "illuminate/contracts", + "version": "v10.48.12", + "source": { + "type": "git", + "url": "https://github.com/illuminate/contracts.git", + "reference": "8d7152c4a1f5d9cf7da3e8b71f23e4556f6138ac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/illuminate/contracts/zipball/8d7152c4a1f5d9cf7da3e8b71f23e4556f6138ac", + "reference": "8d7152c4a1f5d9cf7da3e8b71f23e4556f6138ac", + "shasum": "" + }, + "require": { + "php": "^8.1", + "psr/container": "^1.1.1|^2.0.1", + "psr/simple-cache": "^1.0|^2.0|^3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "10.x-dev" + } + }, + "autoload": { + "psr-4": { + "Illuminate\\Contracts\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Illuminate Contracts package.", + "homepage": "https://laravel.com", + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "time": "2024-01-15T18:52:32+00:00" + }, + { + "name": "nette/finder", + "version": "v2.6.0", + "source": { + "type": "git", + "url": "https://github.com/nette/finder.git", + "reference": "991aefb42860abeab8e003970c3809a9d83cb932" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/finder/zipball/991aefb42860abeab8e003970c3809a9d83cb932", + "reference": "991aefb42860abeab8e003970c3809a9d83cb932", + "shasum": "" + }, + "require": { + "nette/utils": "^2.4 || ^3.0", + "php": ">=7.1" + }, + "conflict": { + "nette/nette": "<2.2" + }, + "require-dev": { + "nette/tester": "^2.0", + "phpstan/phpstan": "^0.12", + "tracy/tracy": "^2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🔍 Nette Finder: find files and directories with an intuitive API.", + "homepage": "https://nette.org", + "keywords": [ + "filesystem", + "glob", + "iterator", + "nette" + ], + "support": { + "issues": "https://github.com/nette/finder/issues", + "source": "https://github.com/nette/finder/tree/v2.6.0" + }, + "time": "2022-10-13T01:31:15+00:00" + }, + { + "name": "nette/robot-loader", + "version": "v3.4.2", + "source": { + "type": "git", + "url": "https://github.com/nette/robot-loader.git", + "reference": "970c8f82be98ec54180c88a468cd2b057855d993" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/robot-loader/zipball/970c8f82be98ec54180c88a468cd2b057855d993", + "reference": "970c8f82be98ec54180c88a468cd2b057855d993", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "nette/finder": "^2.5 || ^3.0", + "nette/utils": "^3.0", + "php": ">=7.1" + }, + "require-dev": { + "nette/tester": "^2.0", + "phpstan/phpstan": "^0.12", + "tracy/tracy": "^2.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🍀 Nette RobotLoader: high performance and comfortable autoloader that will search and autoload classes within your application.", + "homepage": "https://nette.org", + "keywords": [ + "autoload", + "class", + "interface", + "nette", + "trait" + ], + "support": { + "issues": "https://github.com/nette/robot-loader/issues", + "source": "https://github.com/nette/robot-loader/tree/v3.4.2" + }, + "time": "2022-12-14T15:41:06+00:00" + }, + { + "name": "nette/utils", + "version": "v3.2.10", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "a4175c62652f2300c8017fb7e640f9ccb11648d2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/a4175c62652f2300c8017fb7e640f9ccb11648d2", + "reference": "a4175c62652f2300c8017fb7e640f9ccb11648d2", + "shasum": "" + }, + "require": { + "php": ">=7.2 <8.4" + }, + "conflict": { + "nette/di": "<3.0.6" + }, + "require-dev": { + "jetbrains/phpstorm-attributes": "dev-master", + "nette/tester": "~2.0", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.3" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()", + "ext-xml": "to use Strings::length() etc. when mbstring is not available" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "support": { + "issues": "https://github.com/nette/utils/issues", + "source": "https://github.com/nette/utils/tree/v3.2.10" + }, + "time": "2023-07-30T15:38:18+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.19.1", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4e1b88d21c69391150ace211e9eaf05810858d0b", + "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.1" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.9-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" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.1" + }, + "time": "2024-03-17T08:10:35+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://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" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, + { + "name": "psr/simple-cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" + }, + "time": "2021-10-29T13:26:27+00:00" + }, + { + "name": "symfony/console", + "version": "v6.4.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "a170e64ae10d00ba89e2acbb590dc2e54da8ad8f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/a170e64ae10d00ba89e2acbb590dc2e54da8ad8f", + "reference": "a170e64ae10d00ba89e2acbb590dc2e54da8ad8f", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^5.4|^6.0|^7.0" + }, + "conflict": { + "symfony/dependency-injection": "<5.4", + "symfony/dotenv": "<5.4", + "symfony/event-dispatcher": "<5.4", + "symfony/lock": "<5.4", + "symfony/process": "<5.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^5.4|^6.0|^7.0", + "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/stopwatch": "^5.4|^6.0|^7.0", + "symfony/var-dumper": "^5.4|^6.0|^7.0" + }, + "type": "library", + "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": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v6.4.7" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:22:46+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.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": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:32:20+00:00" + }, + { + "name": "symfony/finder", + "version": "v6.4.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "511c48990be17358c23bf45c5d71ab85d40fb764" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/511c48990be17358c23bf45c5d71ab85d40fb764", + "reference": "511c48990be17358c23bf45c5d71ab85d40fb764", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "symfony/filesystem": "^6.0|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "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": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v6.4.7" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-23T10:36:43+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.29.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/32a9da87d7b3245e09ac426c83d334ae9f06f80f", + "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "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 intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.29.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-01-29T20:11:03+00:00" + }, + { + "name": "symfony/process", + "version": "v6.4.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "cdb1c81c145fd5aa9b0038bab694035020943381" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/cdb1c81c145fd5aa9b0038bab694035020943381", + "reference": "cdb1c81c145fd5aa9b0038bab694035020943381", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "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": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v6.4.7" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:22:46+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "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" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.5.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:32:20+00:00" + }, + { + "name": "symfony/string", + "version": "v7.0.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "e405b5424dc2528e02e31ba26b83a79fd4eb8f63" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/e405b5424dc2528e02e31ba26b83a79fd4eb8f63", + "reference": "e405b5424dc2528e02e31ba26b83a79fd4eb8f63", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/error-handler": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "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": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v7.0.7" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:29:19+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "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" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "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" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.11.0" + }, + "time": "2022-06-03T18:03:27+00:00" + } + ], + "packages-dev": [ + { + "name": "composer-unused/contracts", + "version": "0.3.0", + "source": { + "type": "git", + "url": "https://github.com/composer-unused/contracts.git", + "reference": "5ec448d3ee80735dccad6a21a3266c377d0845ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer-unused/contracts/zipball/5ec448d3ee80735dccad6a21a3266c377d0845ae", + "reference": "5ec448d3ee80735dccad6a21a3266c377d0845ae", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "ComposerUnused\\Contracts\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andreas Frömer", + "email": "composer-unused@icanhazstring.com" + } + ], + "description": "Contract repository for composer-unused", + "support": { + "issues": "https://github.com/composer-unused/contracts/issues", + "source": "https://github.com/composer-unused/contracts/tree/0.3.0" + }, + "funding": [ + { + "url": "https://github.com/icanhazstring", + "type": "github" + } + ], + "time": "2023-03-17T00:41:49+00:00" + }, + { + "name": "composer-unused/symbol-parser", + "version": "0.2.5", + "source": { + "type": "git", + "url": "https://github.com/composer-unused/symbol-parser.git", + "reference": "96cee7244aea405e936247d42c49332d52d90ae7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer-unused/symbol-parser/zipball/96cee7244aea405e936247d42c49332d52d90ae7", + "reference": "96cee7244aea405e936247d42c49332d52d90ae7", + "shasum": "" + }, + "require": { + "composer-unused/contracts": "^0.3", + "nikic/php-parser": "^4.18 || ^5.0", + "php": "^7.4 || ^8.0", + "phpstan/phpdoc-parser": "^1.25", + "psr/container": "^1.0 || ^2.0", + "psr/log": "^1.1 || ^2 || ^3", + "symfony/finder": "^5.3 || ^6.0 || ^7.0" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.42", + "ext-ds": "*", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.6.10 || ^10.5", + "roave/security-advisories": "dev-master", + "squizlabs/php_codesniffer": "^3.9.0", + "symfony/serializer": "^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "ComposerUnused\\SymbolParser\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andreas Frömer", + "email": "composer-unused@icanhazstring.com" + } + ], + "description": "Toolkit to parse symbols from a composer package", + "homepage": "https://github.com/composer-unused/symbol-parser", + "keywords": [ + "composer", + "parser", + "symbol" + ], + "support": { + "issues": "https://github.com/composer-unused/symbol-parser/issues", + "source": "https://github.com/composer-unused/symbol-parser" + }, + "funding": [ + { + "url": "https://github.com/sponsors/icanhazstring", + "type": "github" + }, + { + "url": "https://paypal.me/icanhazstring", + "type": "other" + } + ], + "time": "2024-03-09T15:25:51+00:00" + }, + { + "name": "icanhazstring/composer-unused", + "version": "0.8.11", + "source": { + "type": "git", + "url": "https://github.com/composer-unused/composer-unused.git", + "reference": "4720206edc29a7da1913ece0e508f6d82fbcd905" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer-unused/composer-unused/zipball/4720206edc29a7da1913ece0e508f6d82fbcd905", + "reference": "4720206edc29a7da1913ece0e508f6d82fbcd905", + "shasum": "" + }, + "require": { + "composer-unused/contracts": "^0.3", + "composer-unused/symbol-parser": "^0.2.1", + "ext-json": "*", + "nikic/php-parser": "^4.15", + "ondram/ci-detector": "^4.1", + "php": "^7.4 || ^8.0", + "phpstan/phpdoc-parser": "^1.12", + "psr/container": "^1.0 || ^2.0", + "psr/log": "^1.1 || ^2 || ^3", + "symfony/config": "^4.4 || ^5.4 || ^6.0 || ^7.0", + "symfony/console": "^4.4 || ^5.4 || ^6.0 || ^7.0", + "symfony/dependency-injection": "^4.4.8 || ^5.4 || ^6.0 || ^7.0", + "symfony/property-access": "^4.4 || ^5.4 || ^6.0 || ^7.0", + "symfony/serializer": "^4.4 || ^5.4 || ^6.0 || ^7.0", + "symfony/validator": "^4.4 || ^5.4 || ^6.0 || ^7.0", + "webmozart/assert": "^1.10", + "webmozart/glob": "^4.4" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8", + "codeception/verify": "^3.0", + "dg/bypass-finals": "^1.5", + "ergebnis/composer-normalize": "^2.28", + "ext-ds": "*", + "ext-zend-opcache": "*", + "jangregor/phpstan-prophecy": "^1.0", + "php-ds/php-ds": "^1.4", + "phpspec/prophecy-phpunit": "^2.0.2", + "phpstan/extension-installer": "^1.3", + "phpstan/phpstan": "^1.10", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.6.13", + "roave/security-advisories": "dev-master", + "squizlabs/php_codesniffer": "^3.7" + }, + "bin": [ + "bin/composer-unused" + ], + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": true + } + }, + "autoload": { + "psr-4": { + "ComposerUnused\\ComposerUnused\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andreas Frömer", + "email": "composer-unused@icanhazstring.com" + } + ], + "description": "Show unused packages by scanning your code", + "homepage": "https://github.com/composer-unused/composer-unused", + "keywords": [ + "composer", + "php-parser", + "static analysis", + "unused" + ], + "support": { + "issues": "https://github.com/composer-unused/composer-unused/issues", + "source": "https://github.com/composer-unused/composer-unused" + }, + "funding": [ + { + "url": "https://github.com/sponsors/icanhazstring", + "type": "github" + }, + { + "url": "https://paypal.me/icanhazstring", + "type": "other" + } + ], + "time": "2023-11-30T14:35:29+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.11.1", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2023-03-08T13:26:56+00:00" + }, + { + "name": "ondram/ci-detector", + "version": "4.2.0", + "source": { + "type": "git", + "url": "https://github.com/OndraM/ci-detector.git", + "reference": "8b0223b5ed235fd377c75fdd1bfcad05c0f168b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/OndraM/ci-detector/zipball/8b0223b5ed235fd377c75fdd1bfcad05c0f168b8", + "reference": "8b0223b5ed235fd377c75fdd1bfcad05c0f168b8", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "ergebnis/composer-normalize": "^2.13.2", + "lmc/coding-standard": "^3.0.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.1.0", + "phpstan/phpstan": "^1.2.0", + "phpstan/phpstan-phpunit": "^1.0.0", + "phpunit/phpunit": "^9.6.13" + }, + "type": "library", + "autoload": { + "psr-4": { + "OndraM\\CiDetector\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ondřej Machulda", + "email": "ondrej.machulda@gmail.com" + } + ], + "description": "Detect continuous integration environment and provide unified access to properties of current build", + "keywords": [ + "CircleCI", + "Codeship", + "Wercker", + "adapter", + "appveyor", + "aws", + "aws codebuild", + "azure", + "azure devops", + "azure pipelines", + "bamboo", + "bitbucket", + "buddy", + "ci-info", + "codebuild", + "continuous integration", + "continuousphp", + "devops", + "drone", + "github", + "gitlab", + "interface", + "jenkins", + "pipelines", + "sourcehut", + "teamcity", + "travis" + ], + "support": { + "issues": "https://github.com/OndraM/ci-detector/issues", + "source": "https://github.com/OndraM/ci-detector/tree/4.2.0" + }, + "time": "2024-03-12T13:22:30+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.29.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "536889f2b340489d328f5ffb7b02bb6b183ddedc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/536889f2b340489d328f5ffb7b02bb6b183ddedc", + "reference": "536889f2b340489d328f5ffb7b02bb6b183ddedc", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^4.15", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.29.0" + }, + "time": "2024-05-06T12:04:23+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "1.11.2", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "0d5d4294a70deb7547db655c47685d680e39cfec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0d5d4294a70deb7547db655c47685d680e39cfec", + "reference": "0d5d4294a70deb7547db655c47685d680e39cfec", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2024-05-24T13:23:04+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "10.1.14", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/e3f51450ebffe8e0efdf7346ae966a656f7d5e5b", + "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=8.1", + "phpunit/php-file-iterator": "^4.0", + "phpunit/php-text-template": "^3.0", + "sebastian/code-unit-reverse-lookup": "^3.0", + "sebastian/complexity": "^3.0", + "sebastian/environment": "^6.0", + "sebastian/lines-of-code": "^2.0", + "sebastian/version": "^4.0", + "theseer/tokenizer": "^1.2.0" + }, + "require-dev": { + "phpunit/phpunit": "^10.1" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "10.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.14" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-12T15:33:41+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "4.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c", + "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-08-31T06:24:48+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", + "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^10.0" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:56:09+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748", + "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-08-31T14:07:24+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d", + "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:57:52+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "10.5.20", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "547d314dc24ec1e177720d45c6263fb226cc2ae3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/547d314dc24ec1e177720d45c6263fb226cc2ae3", + "reference": "547d314dc24ec1e177720d45c6263fb226cc2ae3", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.10.1", + "phar-io/manifest": "^2.0.3", + "phar-io/version": "^3.0.2", + "php": ">=8.1", + "phpunit/php-code-coverage": "^10.1.5", + "phpunit/php-file-iterator": "^4.0", + "phpunit/php-invoker": "^4.0", + "phpunit/php-text-template": "^3.0", + "phpunit/php-timer": "^6.0", + "sebastian/cli-parser": "^2.0", + "sebastian/code-unit": "^2.0", + "sebastian/comparator": "^5.0", + "sebastian/diff": "^5.0", + "sebastian/environment": "^6.0", + "sebastian/exporter": "^5.1", + "sebastian/global-state": "^6.0.1", + "sebastian/object-enumerator": "^5.0", + "sebastian/recursion-context": "^5.0", + "sebastian/type": "^4.0", + "sebastian/version": "^4.0" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "10.5-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.20" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2024-04-24T06:32:35+00:00" + }, + { + "name": "psr/log", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.0" + }, + "time": "2021-07-14T16:46:02+00:00" + }, + { + "name": "rector/rector", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/rectorphp/rector.git", + "reference": "556509e2dcf527369892b7d411379c4a02f31859" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rectorphp/rector/zipball/556509e2dcf527369892b7d411379c4a02f31859", + "reference": "556509e2dcf527369892b7d411379c4a02f31859", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0", + "phpstan/phpstan": "^1.11" + }, + "conflict": { + "rector/rector-doctrine": "*", + "rector/rector-downgrade-php": "*", + "rector/rector-phpunit": "*", + "rector/rector-symfony": "*" + }, + "suggest": { + "ext-dom": "To manipulate phpunit.xml via the custom-rule command" + }, + "bin": [ + "bin/rector" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Instant Upgrade and Automated Refactoring of any PHP code", + "keywords": [ + "automation", + "dev", + "migration", + "refactoring" + ], + "support": { + "issues": "https://github.com/rectorphp/rector/issues", + "source": "https://github.com/rectorphp/rector/tree/1.1.0" + }, + "funding": [ + { + "url": "https://github.com/tomasvotruba", + "type": "github" + } + ], + "time": "2024-05-18T09:40:27+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/c34583b87e7b7a8055bf6c450c2c77ce32a24084", + "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T07:12:49+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "a81fee9eef0b7a76af11d121767abc44c104e503" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503", + "reference": "a81fee9eef0b7a76af11d121767abc44c104e503", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:58:43+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", + "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:59:15+00:00" + }, + { + "name": "sebastian/comparator", + "version": "5.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "2db5010a484d53ebf536087a70b4a5423c102372" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2db5010a484d53ebf536087a70b4a5423c102372", + "reference": "2db5010a484d53ebf536087a70b4a5423c102372", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.1", + "sebastian/diff": "^5.0", + "sebastian/exporter": "^5.0" + }, + "require-dev": { + "phpunit/phpunit": "^10.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-08-14T13:18:12+00:00" + }, + { + "name": "sebastian/complexity", + "version": "3.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "68ff824baeae169ec9f2137158ee529584553799" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799", + "reference": "68ff824baeae169ec9f2137158ee529584553799", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-12-21T08:37:17+00:00" + }, + { + "name": "sebastian/diff", + "version": "5.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e", + "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0", + "symfony/process": "^6.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.1-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" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/5.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T07:15:17+00:00" + }, + { + "name": "sebastian/environment", + "version": "6.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "8074dbcd93529b357029f5cc5058fd3e43666984" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8074dbcd93529b357029f5cc5058fd3e43666984", + "reference": "8074dbcd93529b357029f5cc5058fd3e43666984", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "https://github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/6.1.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-23T08:47:14+00:00" + }, + { + "name": "sebastian/exporter", + "version": "5.1.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "955288482d97c19a372d3f31006ab3f37da47adf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/955288482d97c19a372d3f31006ab3f37da47adf", + "reference": "955288482d97c19a372d3f31006ab3f37da47adf", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.1", + "sebastian/recursion-context": "^5.0" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T07:17:12+00:00" + }, + { + "name": "sebastian/global-state", + "version": "6.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", + "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "sebastian/object-reflector": "^3.0", + "sebastian/recursion-context": "^5.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/6.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T07:19:19+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0", + "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-12-21T08:38:20+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906", + "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "sebastian/object-reflector": "^3.0", + "sebastian/recursion-context": "^5.0" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T07:08:32+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "24ed13d98130f0e7122df55d06c5c4942a577957" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957", + "reference": "24ed13d98130f0e7122df55d06c5c4942a577957", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T07:06:18+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "05909fb5bc7df4c52992396d0116aed689f93712" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/05909fb5bc7df4c52992396d0116aed689f93712", + "reference": "05909fb5bc7df4c52992396d0116aed689f93712", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T07:05:40+00:00" + }, + { + "name": "sebastian/type", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "462699a16464c3944eefc02ebdd77882bd3925bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf", + "reference": "462699a16464c3944eefc02ebdd77882bd3925bf", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/4.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T07:10:45+00:00" + }, + { + "name": "sebastian/version", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c51fa83a5d8f43f1402e3f32a005e6262244ef17", + "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-07T11:34:05+00:00" + }, + { + "name": "symfony/config", + "version": "v7.0.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "f66f908a975500aa4594258bf454dc66e3939eac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/f66f908a975500aa4594258bf454dc66e3939eac", + "reference": "f66f908a975500aa4594258bf454dc66e3939eac", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/filesystem": "^6.4|^7.0", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/finder": "<6.4", + "symfony/service-contracts": "<2.5" + }, + "require-dev": { + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "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": "Helps you find, load, combine, autofill and validate configuration values of any kind", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/config/tree/v7.0.7" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:29:19+00:00" + }, + { + "name": "symfony/dependency-injection", + "version": "v7.0.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/dependency-injection.git", + "reference": "4db1314337f4dd864113f88e08c9a7f98b1c1324" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/4db1314337f4dd864113f88e08c9a7f98b1c1324", + "reference": "4db1314337f4dd864113f88e08c9a7f98b1c1324", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/service-contracts": "^3.3", + "symfony/var-exporter": "^6.4|^7.0" + }, + "conflict": { + "ext-psr": "<1.1|>=2", + "symfony/config": "<6.4", + "symfony/finder": "<6.4", + "symfony/yaml": "<6.4" + }, + "provide": { + "psr/container-implementation": "1.1|2.0", + "symfony/service-implementation": "1.1|2.0|3.0" + }, + "require-dev": { + "symfony/config": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DependencyInjection\\": "" + }, + "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": "Allows you to standardize and centralize the way objects are constructed in your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dependency-injection/tree/v7.0.7" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:29:19+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v7.0.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "cc168be6fbdcdf3401f50ae863ee3818ed4338f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/cc168be6fbdcdf3401f50ae863ee3818ed4338f5", + "reference": "cc168be6fbdcdf3401f50ae863ee3818ed4338f5", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8", + "symfony/process": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "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": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v7.0.7" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:29:19+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.29.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", + "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-01-29T20:11:03+00:00" + }, + { + "name": "symfony/polyfill-php83", + "version": "v1.29.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php83.git", + "reference": "86fcae159633351e5fd145d1c47de6c528f8caff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/86fcae159633351e5fd145d1c47de6c528f8caff", + "reference": "86fcae159633351e5fd145d1c47de6c528f8caff", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "symfony/polyfill-php80": "^1.14" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php83\\": "" + }, + "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 8.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php83/tree/v1.29.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-01-29T20:11:03+00:00" + }, + { + "name": "symfony/property-access", + "version": "v7.0.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-access.git", + "reference": "8661b861480d2807eb2789ff99d034c0c71ab955" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-access/zipball/8661b861480d2807eb2789ff99d034c0c71ab955", + "reference": "8661b861480d2807eb2789ff99d034c0c71ab955", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/property-info": "^6.4|^7.0" + }, + "require-dev": { + "symfony/cache": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyAccess\\": "" + }, + "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": "Provides functions to read and write from/to an object or array using a simple string notation", + "homepage": "https://symfony.com", + "keywords": [ + "access", + "array", + "extraction", + "index", + "injection", + "object", + "property", + "property-path", + "reflection" + ], + "support": { + "source": "https://github.com/symfony/property-access/tree/v7.0.7" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:29:19+00:00" + }, + { + "name": "symfony/property-info", + "version": "v7.0.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/property-info.git", + "reference": "f0bdb46e19ab308527b324b7ec36161f6880a532" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/property-info/zipball/f0bdb46e19ab308527b324b7ec36161f6880a532", + "reference": "f0bdb46e19ab308527b324b7ec36161f6880a532", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/string": "^6.4|^7.0" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "<5.2", + "phpdocumentor/type-resolver": "<1.5.1", + "symfony/dependency-injection": "<6.4", + "symfony/serializer": "<6.4" + }, + "require-dev": { + "phpdocumentor/reflection-docblock": "^5.2", + "phpstan/phpdoc-parser": "^1.0", + "symfony/cache": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\PropertyInfo\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kévin Dunglas", + "email": "dunglas@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Extracts information about PHP class' properties using metadata of popular sources", + "homepage": "https://symfony.com", + "keywords": [ + "doctrine", + "phpdoc", + "property", + "symfony", + "type", + "validator" + ], + "support": { + "source": "https://github.com/symfony/property-info/tree/v7.0.7" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-28T11:44:19+00:00" + }, + { + "name": "symfony/serializer", + "version": "v7.0.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/serializer.git", + "reference": "08f0c517acf4b12dfc0d3963cd12f7b8023aea31" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/serializer/zipball/08f0c517acf4b12dfc0d3963cd12f7b8023aea31", + "reference": "08f0c517acf4b12dfc0d3963cd12f7b8023aea31", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/dependency-injection": "<6.4", + "symfony/property-access": "<6.4", + "symfony/property-info": "<6.4", + "symfony/uid": "<6.4", + "symfony/validator": "<6.4", + "symfony/yaml": "<6.4" + }, + "require-dev": { + "phpdocumentor/reflection-docblock": "^3.2|^4.0|^5.0", + "seld/jsonlint": "^1.10", + "symfony/cache": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/error-handler": "^6.4|^7.0", + "symfony/filesystem": "^6.4|^7.0", + "symfony/form": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/property-access": "^6.4|^7.0", + "symfony/property-info": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3", + "symfony/uid": "^6.4|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0", + "symfony/var-exporter": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Serializer\\": "" + }, + "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": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/serializer/tree/v7.0.7" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-28T11:44:19+00:00" + }, + { + "name": "symfony/translation-contracts", + "version": "v3.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/b9d2189887bb6b2e0367a9fc7136c5239ab9b05a", + "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "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 translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/translation-contracts/tree/v3.5.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:32:20+00:00" + }, + { + "name": "symfony/validator", + "version": "v7.0.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/validator.git", + "reference": "ab4e75b9d23ba70e78480aecbe4d8da15adf10eb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/validator/zipball/ab4e75b9d23ba70e78480aecbe4d8da15adf10eb", + "reference": "ab4e75b9d23ba70e78480aecbe4d8da15adf10eb", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php83": "^1.27", + "symfony/translation-contracts": "^2.5|^3" + }, + "conflict": { + "doctrine/lexer": "<1.1", + "symfony/dependency-injection": "<6.4", + "symfony/doctrine-bridge": "<7.0", + "symfony/expression-language": "<6.4", + "symfony/http-kernel": "<6.4", + "symfony/intl": "<6.4", + "symfony/property-info": "<6.4", + "symfony/translation": "<6.4.3|>=7.0,<7.0.3", + "symfony/yaml": "<6.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3|^4", + "symfony/cache": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/property-access": "^6.4|^7.0", + "symfony/property-info": "^6.4|^7.0", + "symfony/translation": "^6.4.3|^7.0.3", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Validator\\": "" + }, + "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": "Provides tools to validate values", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/validator/tree/v7.0.7" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-28T11:44:19+00:00" + }, + { + "name": "symfony/var-exporter", + "version": "v7.0.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "cdecc0022e40e90340ba1a59a3d5ccf069777078" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/cdecc0022e40e90340ba1a59a3d5ccf069777078", + "reference": "cdecc0022e40e90340ba1a59a3d5ccf069777078", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "symfony/property-access": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "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": "Allows exporting any serializable PHP data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "lazy-loading", + "proxy", + "serialize" + ], + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v7.0.7" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:29:19+00:00" + }, + { + "name": "symplify/easy-coding-standard", + "version": "12.2.0", + "source": { + "type": "git", + "url": "https://github.com/easy-coding-standard/easy-coding-standard.git", + "reference": "0b97c8e744217a8549efab3f971a982cbe0c310d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/easy-coding-standard/easy-coding-standard/zipball/0b97c8e744217a8549efab3f971a982cbe0c310d", + "reference": "0b97c8e744217a8549efab3f971a982cbe0c310d", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "conflict": { + "friendsofphp/php-cs-fixer": "<3.46", + "phpcsstandards/php_codesniffer": "<3.8", + "symplify/coding-standard": "<12.1" + }, + "suggest": { + "ext-dom": "Needed to support checkstyle output format in class CheckstyleOutputFormatter" + }, + "bin": [ + "bin/ecs" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Use Coding Standard with 0-knowledge of PHP-CS-Fixer and PHP_CodeSniffer", + "keywords": [ + "Code style", + "automation", + "fixer", + "static analysis" + ], + "support": { + "issues": "https://github.com/easy-coding-standard/easy-coding-standard/issues", + "source": "https://github.com/easy-coding-standard/easy-coding-standard/tree/12.2.0" + }, + "funding": [ + { + "url": "https://www.paypal.me/rectorphp", + "type": "custom" + }, + { + "url": "https://github.com/tomasvotruba", + "type": "github" + } + ], + "time": "2024-05-23T04:36:48+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "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" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:36:25+00:00" + }, + { + "name": "tomasvotruba/class-leak", + "version": "0.2.13", + "source": { + "type": "git", + "url": "https://github.com/TomasVotruba/class-leak.git", + "reference": "edb21c5ebfe7aa1c22fe4cf2d722c8e879af771f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/TomasVotruba/class-leak/zipball/edb21c5ebfe7aa1c22fe4cf2d722c8e879af771f", + "reference": "edb21c5ebfe7aa1c22fe4cf2d722c8e879af771f", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "bin": [ + "bin/class-leak", + "bin/class-leak.php" + ], + "type": "library", + "autoload": { + "psr-4": { + "TomasVotruba\\ClassLeak\\": "app" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Detect leaking classes", + "support": { + "issues": "https://github.com/TomasVotruba/class-leak/issues", + "source": "https://github.com/TomasVotruba/class-leak/tree/0.2.13" + }, + "funding": [ + { + "url": "https://www.paypal.me/rectorphp", + "type": "custom" + }, + { + "url": "https://github.com/tomasvotruba", + "type": "github" + } + ], + "time": "2024-04-26T08:36:22+00:00" + }, + { + "name": "tracy/tracy", + "version": "v2.10.7", + "source": { + "type": "git", + "url": "https://github.com/nette/tracy.git", + "reference": "7e7b25ba103968d5318d37db330b2e9c755dc765" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/tracy/zipball/7e7b25ba103968d5318d37db330b2e9c755dc765", + "reference": "7e7b25ba103968d5318d37db330b2e9c755dc765", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-session": "*", + "php": ">=8.0 <8.4" + }, + "conflict": { + "nette/di": "<3.0" + }, + "require-dev": { + "latte/latte": "^2.5", + "nette/di": "^3.0", + "nette/http": "^3.0", + "nette/mail": "^3.0", + "nette/tester": "^2.2", + "nette/utils": "^3.0", + "phpstan/phpstan": "^1.0", + "psr/log": "^1.0 || ^2.0 || ^3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.10-dev" + } + }, + "autoload": { + "files": [ + "src/Tracy/functions.php" + ], + "classmap": [ + "src" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "😎 Tracy: the addictive tool to ease debugging PHP code for cool developers. Friendly design, logging, profiler, advanced features like debugging AJAX calls or CLI support. You will love it.", + "homepage": "https://tracy.nette.org", + "keywords": [ + "Xdebug", + "debug", + "debugger", + "nette", + "profiler" + ], + "support": { + "issues": "https://github.com/nette/tracy/issues", + "source": "https://github.com/nette/tracy/tree/v2.10.7" + }, + "time": "2024-04-29T11:44:00+00:00" + }, + { + "name": "webmozart/glob", + "version": "4.7.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/glob.git", + "reference": "8a2842112d6916e61e0e15e316465b611f3abc17" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/glob/zipball/8a2842112d6916e61e0e15e316465b611f3abc17", + "reference": "8a2842112d6916e61e0e15e316465b611f3abc17", + "shasum": "" + }, + "require": { + "php": "^7.3 || ^8.0.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5", + "symfony/filesystem": "^5.3" + }, + "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.", + "support": { + "issues": "https://github.com/webmozarts/glob/issues", + "source": "https://github.com/webmozarts/glob/tree/4.7.0" + }, + "time": "2024-03-07T20:33:40+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=8.2" + }, + "platform-dev": [], + "plugin-api-version": "2.6.0" +} diff --git a/ecs.php b/ecs.php deleted file mode 100644 index b100e7aa29..0000000000 --- a/ecs.php +++ /dev/null @@ -1,10 +0,0 @@ -withPreparedSets(psr12: true, common: true, symplify: true) - ->withPaths([__DIR__ . '/src', __DIR__ . '/tests']) - ->withRootFiles(); diff --git a/full-tool-build.sh b/full-tool-build.sh deleted file mode 100644 index 94f37107f4..0000000000 --- a/full-tool-build.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -# add patches -composer install --ansi - -# but skip dev dependencies -composer update --no-dev --ansi - -# remove tests and useless files, to make downgraded, scoped and deployed codebase as small as possible -rm -rf tests - -# downgrade with rector -mkdir rector-local -composer require rector/rector --working-dir rector-local -rector-local/vendor/bin/rector process bin src vendor --config build/rector-downgrade-php-72.php --ansi - -# prefix -sh prefix-code.sh diff --git a/php-scoper.phar b/php-scoper.phar new file mode 100644 index 0000000000..34f64da97c Binary files /dev/null and b/php-scoper.phar differ diff --git a/phpstan.neon b/phpstan.neon deleted file mode 100644 index 7853ee8e0b..0000000000 --- a/phpstan.neon +++ /dev/null @@ -1,10 +0,0 @@ -parameters: - level: 8 - - paths: - - src - - tests - - excludePaths: - - */Fixture/* - - */Source/* diff --git a/phpunit.xml b/phpunit.xml deleted file mode 100644 index e89aa98b41..0000000000 --- a/phpunit.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - tests - tests/Testing/UnitTestFilePathsFinder/Fixture - - - diff --git a/prefix-code.sh b/prefix-code.sh deleted file mode 100644 index 4203c245d1..0000000000 --- a/prefix-code.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env bash - -# inspired from https://github.com/rectorphp/rector/blob/main/build/build-rector-scoped.sh - -# see https://stackoverflow.com/questions/66644233/how-to-propagate-colors-from-bash-script-to-github-action?noredirect=1#comment117811853_66644233 -export TERM=xterm-color - -# show errors -set -e - -# script fails if trying to access to an undefined variable -set -u - - -# functions -note() -{ - MESSAGE=$1; - printf "\n"; - echo "\033[0;33m[NOTE] $MESSAGE\033[0m"; -} - -# --------------------------- - -# 2. scope it -note "Downloading php-scoper 0.18.11" -wget https://github.com/humbug/php-scoper/releases/download/0.18.11/php-scoper.phar -N --no-verbose - - -note "Running php-scoper" - -# Work around possible PHP memory limits -php -d memory_limit=-1 php-scoper.phar add-prefix bin src vendor composer.json --config scoper.php --force --ansi --output-dir scoped-code - -# the output code is in "/scoped-code", lets move it up -# the local directories have to be empty to move easily -rm -r bin src vendor composer.json stubs -mv scoped-code/* . - -note "Dumping Composer Autoload" -composer dump-autoload --ansi --classmap-authoritative --no-dev - -# make bin/ecs runnable without "php" -chmod 777 "bin/swiss-knife" -chmod 777 "bin/swiss-knife.php" - -note "Finished" diff --git a/rector.php b/rector.php deleted file mode 100644 index f4ed81953c..0000000000 --- a/rector.php +++ /dev/null @@ -1,21 +0,0 @@ -withPaths([__DIR__ . '/src', __DIR__ . '/tests']) - ->withPhpSets() - ->withPreparedSets( - codeQuality: true, - deadCode: true, - typeDeclarations: true, - privatization: true, - earlyReturn: true, - codingStyle: true, - instanceOf: true, - naming: true - ) - ->withImportNames(removeUnusedImports: true) - ->withSkip(['*/scoper.php', '*/Source/*', '*/Fixture/*']); diff --git a/scoper.php b/scoper.php deleted file mode 100644 index 3dce32b33f..0000000000 --- a/scoper.php +++ /dev/null @@ -1,63 +0,0 @@ -format('Ym'); - -// @see https://github.com/humbug/php-scoper/blob/master/docs/further-reading.md -use Nette\Utils\Strings; - -// see https://github.com/humbug/php-scoper -return [ - 'prefix' => 'SwissKnife' . $timestamp, - 'expose-constants' => ['#^SYMFONY\_[\p{L}_]+$#'], - 'exclude-namespaces' => ['#^Rector\\\\SwissKnife#', '#^Symfony\\\\Polyfill#'], - 'exclude-files' => [ - // do not prefix "trigger_deprecation" from symfony - https://github.com/symfony/symfony/commit/0032b2a2893d3be592d4312b7b098fb9d71aca03 - // these paths are relative to this file location, so it should be in the root directory - 'vendor/symfony/deprecation-contracts/function.php', - 'stubs/PHPUnit/PHPUnit_Framework_TestCase.php', - ], - 'patchers' => [ - // unprefix test case class names - function (string $filePath, string $prefix, string $content): string { - if (! str_ends_with($filePath, 'packages/Testing/UnitTestFilter.php')) { - return $content; - } - - $content = Strings::replace( - $content, - '#' . $prefix . '\\\\PHPUnit\\\\Framework\\\\TestCase#', - 'PHPUnit\Framework\TestCase' - ); - - return Strings::replace( - $content, - '#' . $prefix . '\\\\PHPUnit_Framework_TestCase#', - 'PHPUnit_Framework_TestCase' - ); - }, - - // unprefix kernerl test case class names - function (string $filePath, string $prefix, string $content): string { - if (! str_ends_with($filePath, 'packages/Testing/UnitTestFilter.php')) { - return $content; - } - - $content = Strings::replace( - $content, - '#' . $prefix . '\\\\Symfony\\\\Bundle\\\\FrameworkBundle\\\\Test\\\\KernelTestCase#', - 'Symfony\Bundle\FrameworkBundle\Test\KernelTestCase' - ); - - return Strings::replace( - $content, - '#' . $prefix . '\\\\Symfony\\\\Component\\\\Form\\\\Test\\\\TypeTestCase', - 'Symfony\Component\Form\Test\TypeTestCase' - ); - }, - ], -]; diff --git a/src/Analyzer/NeedsFinalizeAnalyzer.php b/src/Analyzer/NeedsFinalizeAnalyzer.php index 6caa34f36f..237192f6df 100644 --- a/src/Analyzer/NeedsFinalizeAnalyzer.php +++ b/src/Analyzer/NeedsFinalizeAnalyzer.php @@ -1,41 +1,45 @@ cachedPhpParser = $cachedPhpParser; Assert::allString($excludedClasses); - $finalizingNodeTraverser = new NodeTraverser(); $this->needForFinalizeNodeVisitor = new NeedForFinalizeNodeVisitor($excludedClasses); $finalizingNodeTraverser->addVisitor($this->needForFinalizeNodeVisitor); - $this->finalizingNodeTraverser = $finalizingNodeTraverser; } - - public function isNeeded(string $filePath): bool + public function isNeeded(string $filePath) : bool { $stmts = $this->cachedPhpParser->parseFile($filePath); $this->finalizingNodeTraverser->traverse($stmts); - return $this->needForFinalizeNodeVisitor->isNeeded(); } } diff --git a/src/Command/CheckCommentedCodeCommand.php b/src/Command/CheckCommentedCodeCommand.php index 907fe1c913..27f321f09e 100644 --- a/src/Command/CheckCommentedCodeCommand.php +++ b/src/Command/CheckCommentedCodeCommand.php @@ -1,85 +1,70 @@ commentedCodeAnalyzer = $commentedCodeAnalyzer; + $this->symfonyStyle = $symfonyStyle; parent::__construct(); } - - protected function configure(): void + protected function configure() : void { $this->setName('check-commented-code'); - - $this->addArgument( - 'sources', - InputArgument::REQUIRED | InputArgument::IS_ARRAY, - 'One or more paths to check' - ); + $this->addArgument('sources', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'One or more paths to check'); $this->setDescription('Checks code for commented snippets'); - - $this->addOption( - 'line-limit', - null, - InputOption::VALUE_REQUIRED | InputOption::VALUE_OPTIONAL, - 'Amount of allowed comment lines in a row', - self::DEFAULT_LINE_LIMIT - ); + $this->addOption('line-limit', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_OPTIONAL, 'Amount of allowed comment lines in a row', self::DEFAULT_LINE_LIMIT); } - - protected function execute(InputInterface $input, OutputInterface $output): int + protected function execute(InputInterface $input, OutputInterface $output) : int { $sources = (array) $input->getArgument('sources'); $phpFileInfos = FilesFinder::findPhpFiles($sources); - - $message = sprintf('Analysing %d *.php files', count($phpFileInfos)); + $message = \sprintf('Analysing %d *.php files', \count($phpFileInfos)); $this->symfonyStyle->note($message); - $lineLimit = (int) $input->getOption('line-limit'); - $commentedLinesByFilePaths = []; foreach ($phpFileInfos as $phpFileInfo) { $commentedLines = $this->commentedCodeAnalyzer->process($phpFileInfo->getRealPath(), $lineLimit); - if ($commentedLines === []) { continue; } - $commentedLinesByFilePaths[$phpFileInfo->getRealPath()] = $commentedLines; } - if ($commentedLinesByFilePaths === []) { $this->symfonyStyle->success('No commented code found'); return self::SUCCESS; } - foreach ($commentedLinesByFilePaths as $filePath => $commentedLines) { foreach ($commentedLines as $commentedLine) { $messageLine = ' * ' . $filePath . ':' . $commentedLine; $this->symfonyStyle->writeln($messageLine); } } - $this->symfonyStyle->error('Errors found'); return self::FAILURE; } diff --git a/src/Command/CheckConflictsCommand.php b/src/Command/CheckConflictsCommand.php index 866a90da31..8af7014c3b 100644 --- a/src/Command/CheckConflictsCommand.php +++ b/src/Command/CheckConflictsCommand.php @@ -1,58 +1,58 @@ conflictResolver = $conflictResolver; + $this->symfonyStyle = $symfonyStyle; parent::__construct(); } - - protected function configure(): void + protected function configure() : void { $this->setName('check-conflicts'); - $this->setDescription('Check files for missed git conflicts'); $this->addArgument('sources', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'Path to project'); } - - protected function execute(InputInterface $input, OutputInterface $output): int + protected function execute(InputInterface $input, OutputInterface $output) : int { /** @var string[] $sources */ $sources = (array) $input->getArgument('sources'); - $fileInfos = FilesFinder::find($sources); $filePaths = []; foreach ($fileInfos as $fileInfo) { $filePaths[] = $fileInfo->getRealPath(); } - $conflictsCountByFilePath = $this->conflictResolver->extractFromFileInfos($filePaths); if ($conflictsCountByFilePath === []) { - $message = sprintf('No conflicts found in %d files', count($fileInfos)); + $message = \sprintf('No conflicts found in %d files', \count($fileInfos)); $this->symfonyStyle->success($message); - return self::SUCCESS; } - foreach ($conflictsCountByFilePath as $file => $conflictCount) { - $message = sprintf('File "%s" contains %d unresolved conflicts', $file, $conflictCount); + $message = \sprintf('File "%s" contains %d unresolved conflicts', $file, $conflictCount); $this->symfonyStyle->error($message); } - return self::FAILURE; } } diff --git a/src/Command/DumpEditorconfigCommand.php b/src/Command/DumpEditorconfigCommand.php index 7ff3938e13..d2d0cc15a5 100644 --- a/src/Command/DumpEditorconfigCommand.php +++ b/src/Command/DumpEditorconfigCommand.php @@ -1,40 +1,39 @@ symfonyStyle = $symfonyStyle; parent::__construct(); } - - protected function configure(): void + protected function configure() : void { $this->setName('dump-editorconfig'); $this->setDescription('Dump .editorconfig file to project root'); } - - protected function execute(InputInterface $input, OutputInterface $output): int + protected function execute(InputInterface $input, OutputInterface $output) : int { - $projectEditorconfigFilePath = getcwd() . '/.editorconfig'; - if (file_exists($projectEditorconfigFilePath)) { + $projectEditorconfigFilePath = \getcwd() . '/.editorconfig'; + if (\file_exists($projectEditorconfigFilePath)) { $this->symfonyStyle->error('.editorconfig file already exists'); return self::FAILURE; } - FileSystem::copy(__DIR__ . '/../../templates/.editorconfig', $projectEditorconfigFilePath); $this->symfonyStyle->success('.editorconfig file was created'); - return self::SUCCESS; } } diff --git a/src/Command/FinalizeClassesCommand.php b/src/Command/FinalizeClassesCommand.php index f5a2b5a327..13db4fcb4f 100644 --- a/src/Command/FinalizeClassesCommand.php +++ b/src/Command/FinalizeClassesCommand.php @@ -1,11 +1,10 @@ symfonyStyle = $symfonyStyle; + $this->parentClassResolver = $parentClassResolver; + $this->entityClassResolver = $entityClassResolver; + $this->cachedPhpParser = $cachedPhpParser; + $this->mockedClassResolver = $mockedClassResolver; parent::__construct(); } - - protected function configure(): void + protected function configure() : void { $this->setName('finalize-classes'); $this->setAliases(['finalise', 'finalise-classes']); - $this->setDescription('Finalize classes without children'); - $this->addArgument('paths', InputArgument::IS_ARRAY | InputArgument::REQUIRED, 'Directories to finalize'); - - $this->addOption( - 'skip-mocked', - null, - InputOption::VALUE_NONE, - 'Skip mocked classes as well (use only if unable to run bypass-finals package)' - ); - - $this->addOption( - 'dry-run', - null, - InputOption::VALUE_NONE, - 'Do no change anything, only list classes about to be finalized' - ); + $this->addOption('skip-mocked', null, InputOption::VALUE_NONE, 'Skip mocked classes as well (use only if unable to run bypass-finals package)'); + $this->addOption('dry-run', null, InputOption::VALUE_NONE, 'Do no change anything, only list classes about to be finalized'); } - /** * @return self::FAILURE|self::SUCCESS */ - protected function execute(InputInterface $input, OutputInterface $output): int + protected function execute(InputInterface $input, OutputInterface $output) : int { $paths = (array) $input->getArgument('paths'); $isDryRun = (bool) $input->getOption('dry-run'); $areMockedSkipped = (bool) $input->getOption('skip-mocked'); - $this->symfonyStyle->title('1. Detecting parent and entity classes'); - $phpFileInfos = PhpFilesFinder::find($paths); - // double to count for both parent and entity resolver $stepRatio = $areMockedSkipped ? 3 : 2; - - $this->symfonyStyle->progressStart($stepRatio * count($phpFileInfos)); - - $progressClosure = function (): void { + $this->symfonyStyle->progressStart($stepRatio * \count($phpFileInfos)); + $progressClosure = function () : void { $this->symfonyStyle->progressAdvance(); }; - $parentClassNames = $this->parentClassResolver->resolve($phpFileInfos, $progressClosure); $entityClassNames = $this->entityClassResolver->resolve($paths, $progressClosure); - $mockedClassNames = $areMockedSkipped ? $this->mockedClassResolver->resolve($paths, $progressClosure) : []; - $this->symfonyStyle->progressFinish(); - - $this->symfonyStyle->writeln(sprintf( - 'Found %d parent and %d entity classes', - count($parentClassNames), - count($entityClassNames) - )); - + $this->symfonyStyle->writeln(\sprintf('Found %d parent and %d entity classes', \count($parentClassNames), \count($entityClassNames))); if ($areMockedSkipped) { - $this->symfonyStyle->writeln(sprintf('Also %d mocked classes', count($mockedClassNames))); + $this->symfonyStyle->writeln(\sprintf('Also %d mocked classes', \count($mockedClassNames))); } - $this->symfonyStyle->newLine(1); - $this->symfonyStyle->title('2. Finalizing safe classes'); - - $excludedClasses = array_merge($parentClassNames, $entityClassNames, $mockedClassNames); + $excludedClasses = \array_merge($parentClassNames, $entityClassNames, $mockedClassNames); $needsFinalizeAnalyzer = new NeedsFinalizeAnalyzer($excludedClasses, $this->cachedPhpParser); - $finalizedFilePaths = []; - foreach ($phpFileInfos as $phpFileInfo) { // should be file be finalize, is not and is not excluded? - if (! $needsFinalizeAnalyzer->isNeeded($phpFileInfo->getRealPath())) { + if (!$needsFinalizeAnalyzer->isNeeded($phpFileInfo->getRealPath())) { continue; } - - $finalizedContents = Strings::replace( - $phpFileInfo->getContents(), - self::NEWLINE_CLASS_START_REGEX, - 'final class ' - ); - + $finalizedContents = Strings::replace($phpFileInfo->getContents(), self::NEWLINE_CLASS_START_REGEX, 'final class '); $finalizedFilePaths[] = PathHelper::relativeToCwd($phpFileInfo->getRealPath()); - - if ($isDryRun === false) { + if ($isDryRun === \false) { FileSystem::write($phpFileInfo->getRealPath(), $finalizedContents); } } - if ($finalizedFilePaths === []) { $this->symfonyStyle->success('Nothing to finalize'); return self::SUCCESS; } - $this->symfonyStyle->listing($finalizedFilePaths); - - $this->symfonyStyle->success(sprintf( - '%d classes %s finalized', - count($finalizedFilePaths), - $isDryRun ? 'would be' : 'were' - )); - + $this->symfonyStyle->success(\sprintf('%d classes %s finalized', \count($finalizedFilePaths), $isDryRun ? 'would be' : 'were')); return Command::SUCCESS; } } diff --git a/src/Command/FindMultiClassesCommand.php b/src/Command/FindMultiClassesCommand.php index bab77c1e86..a77dab9a99 100644 --- a/src/Command/FindMultiClassesCommand.php +++ b/src/Command/FindMultiClassesCommand.php @@ -1,73 +1,60 @@ multipleClassInOneFileFinder = $multipleClassInOneFileFinder; + $this->symfonyStyle = $symfonyStyle; parent::__construct(); } - - protected function configure(): void + protected function configure() : void { $this->setName('find-multi-classes'); - $this->setDescription('Find multiple classes in one file'); - - $this->addArgument( - 'sources', - InputArgument::REQUIRED | InputArgument::IS_ARRAY, - 'Path to source to analyse' - ); - - $this->addOption( - 'exclude-path', - null, - InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, - 'Path to exclude' - ); + $this->addArgument('sources', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'Path to source to analyse'); + $this->addOption('exclude-path', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Path to exclude'); } - - protected function execute(InputInterface $input, OutputInterface $output): int + protected function execute(InputInterface $input, OutputInterface $output) : int { /** @var string[] $source */ $source = $input->getArgument('sources'); - $excludedPaths = (array) $input->getOption('exclude-path'); - $phpFileInfos = PhpFilesFinder::find($source, $excludedPaths); - $multipleClassesByFile = $this->multipleClassInOneFileFinder->findInDirectories($source, $excludedPaths); if ($multipleClassesByFile === []) { - $this->symfonyStyle->success(sprintf('No file with 2+ classes found in %d files', count($phpFileInfos))); - + $this->symfonyStyle->success(\sprintf('No file with 2+ classes found in %d files', \count($phpFileInfos))); return self::SUCCESS; } - foreach ($multipleClassesByFile as $filePath => $classes) { // get relative path to getcwd() $relativeFilePath = PathHelper::relativeToCwd($filePath); - - $message = sprintf('File "%s" contains %d classes', $relativeFilePath, count($classes)); + $message = \sprintf('File "%s" contains %d classes', $relativeFilePath, \count($classes)); $this->symfonyStyle->section($message); $this->symfonyStyle->listing($classes); } - return self::FAILURE; } } diff --git a/src/Command/NamespaceToPSR4Command.php b/src/Command/NamespaceToPSR4Command.php index 67aa0e5db8..5c7c0855fc 100644 --- a/src/Command/NamespaceToPSR4Command.php +++ b/src/Command/NamespaceToPSR4Command.php @@ -1,117 +1,79 @@ symfonyStyle = $symfonyStyle; parent::__construct(); } - - protected function configure(): void + protected function configure() : void { $this->setName('namespace-to-psr-4'); - $this->setDescription('Change namespace in your PHP files to match PSR-4 root'); - - $this->addArgument( - 'path', - InputArgument::REQUIRED, - 'Single directory path to ensure namespace matches, e.g. "tests"' - ); - - $this->addOption( - 'namespace-root', - null, - InputOption::VALUE_REQUIRED, - 'Namespace root for files in provided path, e.g. "App\\Tests"' - ); + $this->addArgument('path', InputArgument::REQUIRED, 'Single directory path to ensure namespace matches, e.g. "tests"'); + $this->addOption('namespace-root', null, InputOption::VALUE_REQUIRED, 'Namespace root for files in provided path, e.g. "App\\Tests"'); } - protected function execute(InputInterface $input, OutputInterface $output) { $path = (string) $input->getArgument('path'); $namespaceRoot = (string) $input->getOption('namespace-root'); - $fileInfos = $this->findFilesInPath($path); - $changedFilesCount = 0; - /** @var SplFileInfo $fileInfo */ foreach ($fileInfos as $fileInfo) { $expectedNamespace = $this->resolveExpectedNamespace($namespaceRoot, $fileInfo); $expectedNamespaceLine = 'namespace ' . $expectedNamespace . ';'; - // 1. got the correct namespace - if (\str_contains($fileInfo->getContents(), $expectedNamespaceLine)) { + if (\strpos($fileInfo->getContents(), $expectedNamespaceLine) !== \false) { continue; } - // 2. incorrect namespace found - $this->symfonyStyle->note(sprintf( - 'File "%s"%s fixed to expected namespace "%s"', - $fileInfo->getRelativePathname(), - PHP_EOL, - $expectedNamespace - )); - + $this->symfonyStyle->note(\sprintf('File "%s"%s fixed to expected namespace "%s"', $fileInfo->getRelativePathname(), \PHP_EOL, $expectedNamespace)); // 3. replace - $correctedContents = Strings::replace( - $fileInfo->getContents(), - '#namespace (.*?);#', - $expectedNamespaceLine - ); - + $correctedContents = Strings::replace($fileInfo->getContents(), '#namespace (.*?);#', $expectedNamespaceLine); // 4. print file FileSystem::write($fileInfo->getRealPath(), $correctedContents); - ++$changedFilesCount; } - if ($changedFilesCount === 0) { - $this->symfonyStyle->success(sprintf('All %d files have correct namespace', count($fileInfos))); + $this->symfonyStyle->success(\sprintf('All %d files have correct namespace', \count($fileInfos))); } else { - $this->symfonyStyle->success(sprintf('Fixed %d files', $changedFilesCount)); + $this->symfonyStyle->success(\sprintf('Fixed %d files', $changedFilesCount)); } - return self::SUCCESS; } - /** * @return SplFileInfo[] */ - private function findFilesInPath(string $path): array + private function findFilesInPath(string $path) : array { - $finder = Finder::create() - ->files() - ->in([$path]) - ->name('*.php') - ->sortByName() - ->filter(static fn (SplFileInfo $fileInfo): bool => - // filter classes - str_contains($fileInfo->getContents(), 'class ')); - - return iterator_to_array($finder->getIterator()); + $finder = Finder::create()->files()->in([$path])->name('*.php')->sortByName()->filter(static function (SplFileInfo $fileInfo) : bool { + return \strpos($fileInfo->getContents(), 'class ') !== \false; + }); + return \iterator_to_array($finder->getIterator()); } - - private function resolveExpectedNamespace(string $namespaceRoot, SplFileInfo $fileInfo): string + private function resolveExpectedNamespace(string $namespaceRoot, SplFileInfo $fileInfo) : string { - $relativePathNamespace = str_replace('/', '\\', $fileInfo->getRelativePath()); + $relativePathNamespace = \str_replace('/', '\\', $fileInfo->getRelativePath()); return $namespaceRoot . '\\' . $relativePathNamespace; } } diff --git a/src/Command/PrettyJsonCommand.php b/src/Command/PrettyJsonCommand.php index ff56a10ba1..a58b4c03e0 100644 --- a/src/Command/PrettyJsonCommand.php +++ b/src/Command/PrettyJsonCommand.php @@ -1,93 +1,74 @@ symfonyStyle = $symfonyStyle; + $this->jsonAnalyzer = $jsonAnalyzer; parent::__construct(); } - - protected function configure(): void + protected function configure() : void { $this->setName('pretty-json'); - $this->setDescription('Turns JSON files from 1-line to pretty print format'); - - $this->addArgument( - 'sources', - InputArgument::REQUIRED | InputArgument::IS_ARRAY, - 'JSON file or directory with JSON files to prettify' - ); - + $this->addArgument('sources', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'JSON file or directory with JSON files to prettify'); $this->addOption('dry-run', null, InputOption::VALUE_NONE, 'Dry run - no changes will be made'); } - - protected function execute(InputInterface $input, OutputInterface $output): int + protected function execute(InputInterface $input, OutputInterface $output) : int { $sources = (array) $input->getArgument('sources'); $jsonFileInfos = FilesFinder::findJsonFiles($sources); - if ($jsonFileInfos === []) { $this->symfonyStyle->error('No *.json files found'); return self::FAILURE; } - - $message = sprintf('Analysing %d *.json files', count($jsonFileInfos)); + $message = \sprintf('Analysing %d *.json files', \count($jsonFileInfos)); $this->symfonyStyle->note($message); - $isDryRun = (bool) $input->getOption('dry-run'); - $printedFilePaths = []; - // convert file infos from uggly json to pretty json foreach ($jsonFileInfos as $jsonFileInfo) { $jsonContent = FileSystem::read($jsonFileInfo->getRealPath()); if ($this->jsonAnalyzer->isPrettyPrinted($jsonContent)) { - $this->symfonyStyle->writeln( - sprintf('File "%s" is already pretty', $jsonFileInfo->getRelativePathname()) - ); + $this->symfonyStyle->writeln(\sprintf('File "%s" is already pretty', $jsonFileInfo->getRelativePathname())); continue; } - // notify the file was changed $printedFilePaths[] = $jsonFileInfo->getRelativePathname(); - // nothing will be changed - if ($isDryRun === true) { + if ($isDryRun === \true) { continue; } - - $prettyJsonContent = Json::encode(Json::decode($jsonContent), JSON_PRETTY_PRINT); + $prettyJsonContent = Json::encode(Json::decode($jsonContent), \JSON_PRETTY_PRINT); FileSystem::write($jsonFileInfo->getRealPath(), $prettyJsonContent); } - - $successMessage = sprintf( - '%d file%s %s', - count($printedFilePaths), - count($printedFilePaths) === 1 ? '' : 's', - $isDryRun ? 'would be changed' : 'changed' - ); - + $successMessage = \sprintf('%d file%s %s', \count($printedFilePaths), \count($printedFilePaths) === 1 ? '' : 's', $isDryRun ? 'would be changed' : 'changed'); $this->symfonyStyle->success($successMessage); $this->symfonyStyle->listing($printedFilePaths); - return self::SUCCESS; } } diff --git a/src/Command/PrivatizeConstantsCommand.php b/src/Command/PrivatizeConstantsCommand.php index cc6c66ed8a..7fe190a498 100644 --- a/src/Command/PrivatizeConstantsCommand.php +++ b/src/Command/PrivatizeConstantsCommand.php @@ -1,167 +1,119 @@ .*?) of class (?[\w\\\\]+)#'; - + private const CONSTANT_MESSAGE_REGEX = '#constant (?.*?) of class (?[\\w\\\\]+)#'; /** * @var string * @see https://regex101.com/r/wkHZwX/1 */ - private const CONST_REGEX = '#( |\t| public )const #ms'; - - public function __construct( - private readonly SymfonyStyle $symfonyStyle - ) { + private const CONST_REGEX = '#( |\\t| public )const #ms'; + public function __construct(SymfonyStyle $symfonyStyle) + { + $this->symfonyStyle = $symfonyStyle; parent::__construct(); } - - protected function configure(): void + protected function configure() : void { $this->setName('privatize-constants'); - - $this->addArgument( - 'sources', - InputArgument::REQUIRED | InputArgument::IS_ARRAY, - 'One or more paths to check' - ); + $this->addArgument('sources', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'One or more paths to check'); $this->setDescription('Make class constants private if not used outside'); } - /** * @return Command::* */ - protected function execute(InputInterface $input, OutputInterface $output): int + protected function execute(InputInterface $input, OutputInterface $output) : int { $sources = (array) $input->getArgument('sources'); $phpFileInfos = FilesFinder::findPhpFiles($sources); - $this->privatizeClassConstants($phpFileInfos); - $phpstanResult = $this->runPHPStanAnalyse($sources); - foreach ($phpstanResult['files'] as $detail) { foreach ($detail['messages'] as $messageError) { // @todo check non-existing constants on child/parent access as well - // resolve errorMessage error details $classConstMatch = $this->resolveClassConstMatch($messageError['message']); - if (! $classConstMatch instanceof ClassConstMatch) { + if (!$classConstMatch instanceof ClassConstMatch) { continue; } - $classFileContents = FileSystem::read($classConstMatch->getClassFileName()); - // replace "private const NAME" with "public const NAME" - $changedFileContent = str_replace( - 'private const ' . $classConstMatch->getConstantName(), - 'public const ' . $classConstMatch->getConstantName(), - $classFileContents - ); - + $changedFileContent = \str_replace('private const ' . $classConstMatch->getConstantName(), 'public const ' . $classConstMatch->getConstantName(), $classFileContents); if ($changedFileContent === $classFileContents) { continue; } - FileSystem::write($classConstMatch->getClassFileName(), $changedFileContent); - - $this->symfonyStyle->note(sprintf( - 'Updated "%s" constant in "%s" file to public as used outside', - $classConstMatch->getConstantName(), - $classConstMatch->getClassFileName() - )); + $this->symfonyStyle->note(\sprintf('Updated "%s" constant in "%s" file to public as used outside', $classConstMatch->getConstantName(), $classConstMatch->getClassFileName())); } } - return self::SUCCESS; } - /** * @param SplFileInfo[] $phpFileInfos */ - private function privatizeClassConstants(array $phpFileInfos): void + private function privatizeClassConstants(array $phpFileInfos) : void { foreach ($phpFileInfos as $phpFileInfo) { $originalFileContent = $phpFileInfo->getContents(); - $fileContent = $this->makeClassConstantsPrivate($originalFileContent); if ($originalFileContent === $fileContent) { continue; } - FileSystem::write($phpFileInfo->getRealPath(), $fileContent); - - $this->symfonyStyle->note( - sprintf('Constants in "%s" file privatized', $phpFileInfo->getRelativePathname()) - ); + $this->symfonyStyle->note(\sprintf('Constants in "%s" file privatized', $phpFileInfo->getRelativePathname())); } } - - private function makeClassConstantsPrivate(string $fileContents): string + private function makeClassConstantsPrivate(string $fileContents) : string { $fileContent = Strings::replace($fileContents, self::CONST_REGEX, '$1private const '); - - return str_replace('public const ', 'private const ', $fileContent); + return \str_replace('public const ', 'private const ', $fileContent); } - /** * @param string[] $paths * @return array */ - private function runPHPStanAnalyse(array $paths): array + private function runPHPStanAnalyse(array $paths) : array { $this->symfonyStyle->note('Running PHPStan to spot false-private class constants'); - - $phpStanAnalyseProcess = new Process([ - 'vendor/bin/phpstan', - 'analyse', - ...$paths, - '--configuration', - __DIR__ . '/../../config/privatize-constants-phpstan-ruleset.neon', - '--error-format', - 'json', - ]); + $phpStanAnalyseProcess = new Process(\array_merge(['vendor/bin/phpstan', 'analyse'], $paths, ['--configuration', __DIR__ . '/../../config/privatize-constants-phpstan-ruleset.neon', '--error-format', 'json'])); $phpStanAnalyseProcess->run(); - $resultOutput = $phpStanAnalyseProcess->getOutput() ?: $phpStanAnalyseProcess->getErrorOutput(); - return json_decode($resultOutput, true); + return \json_decode($resultOutput, \true); } - - private function resolveClassConstMatch(string $errorMessage): ?ClassConstMatch + private function resolveClassConstMatch(string $errorMessage) : ?ClassConstMatch { - if (! str_contains($errorMessage, 'Access to private constant')) { + if (\strpos($errorMessage, 'Access to private constant') === \false) { return null; } - $match = Strings::match($errorMessage, self::CONSTANT_MESSAGE_REGEX); - - if (! isset($match['constant_name'], $match['class_name'])) { + if (!isset($match['constant_name'], $match['class_name'])) { return null; } - /** @var class-string $className */ $className = (string) $match['class_name']; - return new ClassConstMatch($className, (string) $match['constant_name']); } } diff --git a/src/Command/ValidateFileLengthCommand.php b/src/Command/ValidateFileLengthCommand.php index bada2397dd..5face99884 100644 --- a/src/Command/ValidateFileLengthCommand.php +++ b/src/Command/ValidateFileLengthCommand.php @@ -1,61 +1,60 @@ projectFilesFinder = $projectFilesFinder; + $this->symfonyStyle = $symfonyStyle; + $this->tooLongFilesResolver = $tooLongFilesResolver; parent::__construct(); } - - protected function configure(): void + protected function configure() : void { $this->setName('validate-file-length'); - $this->setDescription('Make sure the file path length are not breaking normal Windows max length'); $this->addArgument('sources', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'Path to project'); } - - protected function execute(InputInterface $input, OutputInterface $output): int + protected function execute(InputInterface $input, OutputInterface $output) : int { /** @var string[] $sources */ $sources = (array) $input->getArgument('sources'); - $fileInfos = $this->projectFilesFinder->find($sources); $tooLongFileInfos = $this->tooLongFilesResolver->resolve($fileInfos); - if ($tooLongFileInfos === []) { - $message = sprintf('Checked %d files - all fit max file length', count($fileInfos)); + $message = \sprintf('Checked %d files - all fit max file length', \count($fileInfos)); $this->symfonyStyle->success($message); - return self::SUCCESS; } - foreach ($tooLongFileInfos as $tooLongFileInfo) { - $message = sprintf( - 'Paths for file "%s" has %d chars, but must be shorter than %d.', - $tooLongFileInfo->getRealPath(), - strlen($tooLongFileInfo->getRealPath()), - TooLongFilesResolver::MAX_FILE_LENGTH - ); - + $message = \sprintf('Paths for file "%s" has %d chars, but must be shorter than %d.', $tooLongFileInfo->getRealPath(), \strlen($tooLongFileInfo->getRealPath()), TooLongFilesResolver::MAX_FILE_LENGTH); $this->symfonyStyle->warning($message); } - return self::FAILURE; } } diff --git a/src/Comments/CommentedCodeAnalyzer.php b/src/Comments/CommentedCodeAnalyzer.php index ed3ddd0131..bbcc6c7dc2 100644 --- a/src/Comments/CommentedCodeAnalyzer.php +++ b/src/Comments/CommentedCodeAnalyzer.php @@ -1,12 +1,10 @@ $fileLine) { - $isCommentLine = str_starts_with(trim((string) $fileLine), '//'); + $isCommentLine = \strncmp(\trim((string) $fileLine), '//', \strlen('//')) === 0; if ($isCommentLine) { ++$commentLinesCount; } else { @@ -39,12 +33,10 @@ public function process(string $filePath, int $commentedLinesCountLimit): array if ($commentLinesCount >= $commentedLinesCountLimit) { $commentedLines[] = $key; } - // reset counter $commentLinesCount = 0; } } - return $commentedLines; } } diff --git a/src/DependencyInjection/ContainerFactory.php b/src/DependencyInjection/ContainerFactory.php index f3cc784453..48725d5d28 100644 --- a/src/DependencyInjection/ContainerFactory.php +++ b/src/DependencyInjection/ContainerFactory.php @@ -1,12 +1,11 @@ singleton(Application::class, function (Container $container): Application { + $container->singleton(Application::class, function (Container $container) : Application { $application = new Application('Easy CI toolkit'); - - $commands = [ - $container->make(PrettyJsonCommand::class), - $container->make(CheckCommentedCodeCommand::class), - $container->make(CheckConflictsCommand::class), - $container->make(ValidateFileLengthCommand::class), - $container->make(DetectUnitTestsCommand::class), - $container->make(FindMultiClassesCommand::class), - $container->make(NamespaceToPSR4Command::class), - $container->make(DumpEditorconfigCommand::class), - $container->make(FinalizeClassesCommand::class), - $container->make(PrivatizeConstantsCommand::class), - ]; - + $commands = [$container->make(PrettyJsonCommand::class), $container->make(CheckCommentedCodeCommand::class), $container->make(CheckConflictsCommand::class), $container->make(ValidateFileLengthCommand::class), $container->make(DetectUnitTestsCommand::class), $container->make(FindMultiClassesCommand::class), $container->make(NamespaceToPSR4Command::class), $container->make(DumpEditorconfigCommand::class), $container->make(FinalizeClassesCommand::class), $container->make(PrivatizeConstantsCommand::class)]; $application->addCommands($commands); - // remove basic command to make output clear $this->hideDefaultCommands($application); - return $application; }); - // parser - $container->singleton(Parser::class, static function (): Parser { + $container->singleton(Parser::class, static function () : Parser { $phpParserFactory = new ParserFactory(); return $phpParserFactory->create(ParserFactory::PREFER_PHP7); }); - - $container->singleton( - SymfonyStyle::class, - static fn (): SymfonyStyle => new SymfonyStyle(new ArrayInput([]), new ConsoleOutput()) - ); - + $container->singleton(SymfonyStyle::class, static function () : SymfonyStyle { + return new SymfonyStyle(new ArrayInput([]), new ConsoleOutput()); + }); return $container; } - - public function hideDefaultCommands(Application $application): void + public function hideDefaultCommands(Application $application) : void { - $application->get('list') - ->setHidden(true); - $application->get('completion') - ->setHidden(true); - $application->get('help') - ->setHidden(true); + $application->get('list')->setHidden(\true); + $application->get('completion')->setHidden(\true); + $application->get('help')->setHidden(\true); } } diff --git a/src/EntityClassResolver.php b/src/EntityClassResolver.php index 530ce24525..94fd3df7e2 100644 --- a/src/EntityClassResolver.php +++ b/src/EntityClassResolver.php @@ -1,100 +1,84 @@ [\w+\\\\]+)\:\n#m'; - - public function __construct( - private CachedPhpParser $cachedPhpParser - ) { + private const YAML_ENTITY_CLASS_NAME_REGEX = '#^(?[\\w+\\\\]+)\\:\\n#m'; + public function __construct(CachedPhpParser $cachedPhpParser) + { + $this->cachedPhpParser = $cachedPhpParser; } - /** * @param string[] $paths * @return string[] */ - public function resolve(array $paths, ?callable $progressClosure = null): array + public function resolve(array $paths, ?callable $progressClosure = null) : array { Assert::allString($paths); Assert::allFileExists($paths); - // 1. resolve from yaml annotations $yamlEntityClassNames = $this->resolveYamlEntityClassNames($paths); - // 2. resolve from direct class names with namespace parts, doctrine annotation or docblock $phpFileInfos = PhpFilesFinder::find($paths); $entityClassNameCollectingNodeVisitor = new EntityClassNameCollectingNodeVisitor(); - $nodeTraverser = new NodeTraverser(); $nodeTraverser->addVisitor($entityClassNameCollectingNodeVisitor); $this->traverseFileInfos($phpFileInfos, $nodeTraverser, $progressClosure); - $markedEntityClassNames = $entityClassNameCollectingNodeVisitor->getEntityClassNames(); - - $entityClassNames = array_merge($yamlEntityClassNames, $markedEntityClassNames); - sort($entityClassNames); - - return array_unique($entityClassNames); + $entityClassNames = \array_merge($yamlEntityClassNames, $markedEntityClassNames); + \sort($entityClassNames); + return \array_unique($entityClassNames); } - /** * @param SplFileInfo[] $phpFileInfos */ - private function traverseFileInfos( - array $phpFileInfos, - NodeTraverser $nodeTraverser, - ?callable $progressClosure = null - ): void { + private function traverseFileInfos(array $phpFileInfos, NodeTraverser $nodeTraverser, ?callable $progressClosure = null) : void + { foreach ($phpFileInfos as $phpFileInfo) { $stmts = $this->cachedPhpParser->parseFile($phpFileInfo->getRealPath()); - $nodeTraverser->traverse($stmts); - - if (is_callable($progressClosure)) { + if (\is_callable($progressClosure)) { $progressClosure(); } } } - /** * @param string[] $paths * @return string[] */ - private function resolveYamlEntityClassNames(array $paths): array + private function resolveYamlEntityClassNames(array $paths) : array { $yamlFileInfos = YamlFilesFinder::find($paths); - $yamlEntityClassNames = []; - /** @var SplFileInfo $yamlFileInfo */ foreach ($yamlFileInfos as $yamlFileInfo) { $matches = Strings::matchAll($yamlFileInfo->getContents(), self::YAML_ENTITY_CLASS_NAME_REGEX); - foreach ($matches as $match) { $yamlEntityClassNames[] = $match['class_name']; } } - return $yamlEntityClassNames; } } diff --git a/src/FileSystem/JsonAnalyzer.php b/src/FileSystem/JsonAnalyzer.php index c3756c6a94..aefd6d3303 100644 --- a/src/FileSystem/JsonAnalyzer.php +++ b/src/FileSystem/JsonAnalyzer.php @@ -1,18 +1,16 @@ = 3) { - return true; + $lines = \explode(\PHP_EOL, $json); + if (\count($lines) >= 3) { + return \true; } - - return false; + return \false; } } diff --git a/src/FileSystem/PathHelper.php b/src/FileSystem/PathHelper.php index f4daf142ac..a2be542668 100644 --- a/src/FileSystem/PathHelper.php +++ b/src/FileSystem/PathHelper.php @@ -1,21 +1,18 @@ files() - ->in($paths) - ->sortByName(); - - return iterator_to_array($finder->getIterator()); + $finder = Finder::create()->files()->in($paths)->sortByName(); + return \iterator_to_array($finder->getIterator()); } - /** * @param string[] $sources * @return SplFileInfo[] */ - public static function findPhpFiles(array $sources): array + public static function findPhpFiles(array $sources) : array { $paths = []; foreach ($sources as $source) { - $paths[] = getcwd() . DIRECTORY_SEPARATOR . $source; + $paths[] = \getcwd() . \DIRECTORY_SEPARATOR . $source; } - - $finder = Finder::create() - ->files() - ->in($paths) - ->name('*.php') - ->notPath('vendor') - ->sortByName(); - - return iterator_to_array($finder->getIterator()); + $finder = Finder::create()->files()->in($paths)->name('*.php')->notPath('vendor')->sortByName(); + return \iterator_to_array($finder->getIterator()); } - /** * @param string[] $sources * @return SplFileInfo[] */ - public static function findJsonFiles(array $sources): array + public static function findJsonFiles(array $sources) : array { $jsonFileInfos = []; $directories = []; - foreach ($sources as $source) { - if (is_file($source)) { + if (\is_file($source)) { $jsonFileInfos[] = new SplFileInfo($source, '', $source); } else { $directories[] = $source; } } - - $jsonFileFinder = Finder::create() - ->files() - ->in($directories) - ->name('*.json') - ->sortByName(); - + $jsonFileFinder = Finder::create()->files()->in($directories)->name('*.json')->sortByName(); foreach ($jsonFileFinder->getIterator() as $fileInfo) { $jsonFileInfos[] = $fileInfo; } - return $jsonFileInfos; } } diff --git a/src/Finder/MultipleClassInOneFileFinder.php b/src/Finder/MultipleClassInOneFileFinder.php index 9c18d123e6..680c414896 100644 --- a/src/Finder/MultipleClassInOneFileFinder.php +++ b/src/Finder/MultipleClassInOneFileFinder.php @@ -1,32 +1,34 @@ phpClassLoader = $phpClassLoader; } - /** * @param string[] $directories * @param string[] $excludedPaths * @return array */ - public function findInDirectories(array $directories, array $excludedPaths): array + public function findInDirectories(array $directories, array $excludedPaths) : array { $fileByClasses = $this->phpClassLoader->load($directories, $excludedPaths); - $classesByFile = []; foreach ($fileByClasses as $class => $filePath) { $classesByFile[$filePath][] = $class; } - - return array_filter($classesByFile, static fn (array $classes): bool => count($classes) >= 2); + return \array_filter($classesByFile, static function (array $classes) : bool { + return \count($classes) >= 2; + }); } } diff --git a/src/Finder/PhpFilesFinder.php b/src/Finder/PhpFilesFinder.php index 45566a81cb..79afe831ef 100644 --- a/src/Finder/PhpFilesFinder.php +++ b/src/Finder/PhpFilesFinder.php @@ -1,13 +1,11 @@ files() - ->in($paths) - ->name('*.php') - // exclude paths, as notPaths() does no work - ->filter(static function (SplFileInfo $splFileInfo) use ($excludedPaths): bool { - foreach ($excludedPaths as $excludedPath) { - if (str_contains($splFileInfo->getRealPath(), $excludedPath)) { - return false; - } + $finder = Finder::create()->files()->in($paths)->name('*.php')->filter(static function (SplFileInfo $splFileInfo) use($excludedPaths) : bool { + foreach ($excludedPaths as $excludedPath) { + if (\strpos($splFileInfo->getRealPath(), $excludedPath) !== \false) { + return \false; } - - return true; - }); - - return iterator_to_array($finder->getIterator()); + } + return \true; + }); + return \iterator_to_array($finder->getIterator()); } } diff --git a/src/Finder/YamlFilesFinder.php b/src/Finder/YamlFilesFinder.php index f982070bc9..bd3b3a6bbc 100644 --- a/src/Finder/YamlFilesFinder.php +++ b/src/Finder/YamlFilesFinder.php @@ -1,30 +1,22 @@ files() - ->in($paths) - ->name('*.yml') - ->name('*.yaml'); - - return iterator_to_array($finder); + $finder = Finder::create()->files()->in($paths)->name('*.yml')->name('*.yaml'); + return \iterator_to_array($finder); } } diff --git a/src/Git/ConflictResolver.php b/src/Git/ConflictResolver.php index 063d9dc3c2..8efb3d52ab 100644 --- a/src/Git/ConflictResolver.php +++ b/src/Git/ConflictResolver.php @@ -1,12 +1,10 @@ extractFromFileInfo($filePath); if ($conflictCount === 0) { continue; } - // test fixtures, that should be ignored - if (str_contains((string) realpath($filePath), '/tests/Git/ConflictResolver/Fixture')) { + if (\strpos((string) \realpath($filePath), '/tests/Git/ConflictResolver/Fixture') !== \false) { continue; } - $conflictCountsByFilePath[$filePath] = $conflictCount; } - return $conflictCountsByFilePath; } } diff --git a/src/MockedClassResolver.php b/src/MockedClassResolver.php index 5417bb2cca..2b98f95b40 100644 --- a/src/MockedClassResolver.php +++ b/src/MockedClassResolver.php @@ -1,59 +1,51 @@ cachedPhpParser = $cachedPhpParser; } - /** * @param string[] $paths * @return string[] */ - public function resolve(array $paths, ?callable $progressClosure = null): array + public function resolve(array $paths, ?callable $progressClosure = null) : array { Assert::allString($paths); Assert::allFileExists($paths); - $phpFileInfos = PhpFilesFinder::find($paths); $mockedClassNameCollectingNodeVisitor = new MockedClassNameCollectingNodeVisitor(); - $nodeTraverser = new NodeTraverser(); $nodeTraverser->addVisitor($mockedClassNameCollectingNodeVisitor); $this->traverseFileInfos($phpFileInfos, $nodeTraverser, $progressClosure); - $mockedClassNames = $mockedClassNameCollectingNodeVisitor->getMockedClassNames(); - sort($mockedClassNames); - - return array_unique($mockedClassNames); + \sort($mockedClassNames); + return \array_unique($mockedClassNames); } - /** * @param SplFileInfo[] $phpFileInfos */ - private function traverseFileInfos( - array $phpFileInfos, - NodeTraverser $nodeTraverser, - ?callable $progressClosure = null - ): void { + private function traverseFileInfos(array $phpFileInfos, NodeTraverser $nodeTraverser, ?callable $progressClosure = null) : void + { foreach ($phpFileInfos as $phpFileInfo) { $stmts = $this->cachedPhpParser->parseFile($phpFileInfo->getRealPath()); - $nodeTraverser->traverse($stmts); - - if (is_callable($progressClosure)) { + if (\is_callable($progressClosure)) { $progressClosure(); } } diff --git a/src/ParentClassResolver.php b/src/ParentClassResolver.php index e3b6b6f2c4..3b683702c6 100644 --- a/src/ParentClassResolver.php +++ b/src/ParentClassResolver.php @@ -1,48 +1,42 @@ cachedPhpParser = $cachedPhpParser; } - /** * @param SplFileInfo[] $phpFileInfos * @return string[] */ - public function resolve(array $phpFileInfos, callable $progressClosure): array + public function resolve(array $phpFileInfos, callable $progressClosure) : array { $parentClassNameCollectingNodeVisitor = new ParentClassNameCollectingNodeVisitor(); - $nodeTraverser = new NodeTraverser(); $nodeTraverser->addVisitor($parentClassNameCollectingNodeVisitor); - $this->traverseFileInfos($phpFileInfos, $nodeTraverser, $progressClosure); - return $parentClassNameCollectingNodeVisitor->getParentClassNames(); } - /** * @param SplFileInfo[] $phpFileInfos */ - private function traverseFileInfos( - array $phpFileInfos, - NodeTraverser $nodeTraverser, - callable $progressClosure - ): void { + private function traverseFileInfos(array $phpFileInfos, NodeTraverser $nodeTraverser, callable $progressClosure) : void + { foreach ($phpFileInfos as $phpFileInfo) { $stmts = $this->cachedPhpParser->parseFile($phpFileInfo->getRealPath()); - $nodeTraverser->traverse($stmts); $progressClosure(); } diff --git a/src/PhpParser/CachedPhpParser.php b/src/PhpParser/CachedPhpParser.php index cfa60d1f26..c295150958 100644 --- a/src/PhpParser/CachedPhpParser.php +++ b/src/PhpParser/CachedPhpParser.php @@ -1,50 +1,47 @@ */ - private array $cachedStmts = []; - - public function __construct( - private readonly Parser $phpParser - ) { + private $cachedStmts = []; + public function __construct(Parser $phpParser) + { + $this->phpParser = $phpParser; } - /** * @return Stmt[] */ - public function parseFile(string $filePath): array + public function parseFile(string $filePath) : array { if (isset($this->cachedStmts[$filePath])) { return $this->cachedStmts[$filePath]; } - $fileContents = FileSystem::read($filePath); $stmts = $this->phpParser->parse($fileContents); - - if (is_array($stmts)) { + if (\is_array($stmts)) { $nodeTraverser = new NodeTraverser(); $nodeTraverser->addVisitor(new NameResolver()); $nodeTraverser->traverse($stmts); } - $this->cachedStmts[$filePath] = $stmts ?? []; - return $stmts ?? []; } } diff --git a/src/PhpParser/NodeVisitor/EntityClassNameCollectingNodeVisitor.php b/src/PhpParser/NodeVisitor/EntityClassNameCollectingNodeVisitor.php index 7c61429f36..65d95a815e 100644 --- a/src/PhpParser/NodeVisitor/EntityClassNameCollectingNodeVisitor.php +++ b/src/PhpParser/NodeVisitor/EntityClassNameCollectingNodeVisitor.php @@ -1,93 +1,77 @@ namespacedName instanceof Name) { + if (!$node->namespacedName instanceof Name) { return null; } - // dummy check for entity namespace - if (array_intersect(['Entity', 'Entities'], $node->namespacedName->getParts())) { + if (\array_intersect(['Entity', 'Entities'], $node->namespacedName->getParts())) { $this->entityClassNames[] = $node->namespacedName->toString(); return null; } - if ($this->hasEntityDocBlock($node) || $this->hasEntityAttribute($node)) { $this->entityClassNames[] = $node->namespacedName->toString(); return null; } - return null; } - /** * @return string[] */ - public function getEntityClassNames(): array + public function getEntityClassNames() : array { - $uniqueEntityClassNames = array_unique($this->entityClassNames); - sort($uniqueEntityClassNames); - + $uniqueEntityClassNames = \array_unique($this->entityClassNames); + \sort($uniqueEntityClassNames); return $uniqueEntityClassNames; } - - private function hasEntityDocBlock(Class_ $class): bool + private function hasEntityDocBlock(Class_ $class) : bool { $docComment = $class->getDocComment(); if ($docComment instanceof Doc) { // dummy check - if (! str_contains($docComment->getText(), '@')) { - return false; + if (\strpos($docComment->getText(), '@') === \false) { + return \false; } - - if (str_contains($docComment->getText(), 'Entity')) { - return true; + if (\strpos($docComment->getText(), 'Entity') !== \false) { + return \true; } - - if (str_contains($docComment->getText(), 'Embeddable')) { - return true; + if (\strpos($docComment->getText(), 'Embeddable') !== \false) { + return \true; } } - - return false; + return \false; } - - private function hasEntityAttribute(Class_ $class): bool + private function hasEntityAttribute(Class_ $class) : bool { foreach ($class->attrGroups as $attrGroup) { foreach ($attrGroup->attrs as $attr) { - if (str_ends_with($attr->name->toString(), 'Entity')) { - return true; + if (\substr_compare($attr->name->toString(), 'Entity', -\strlen('Entity')) === 0) { + return \true; } - - if (str_ends_with($attr->name->toString(), 'Embeddable')) { - return true; + if (\substr_compare($attr->name->toString(), 'Embeddable', -\strlen('Embeddable')) === 0) { + return \true; } } } - - return false; + return \false; } } diff --git a/src/PhpParser/NodeVisitor/MockedClassNameCollectingNodeVisitor.php b/src/PhpParser/NodeVisitor/MockedClassNameCollectingNodeVisitor.php index 4344397be0..a9e9eda0bb 100644 --- a/src/PhpParser/NodeVisitor/MockedClassNameCollectingNodeVisitor.php +++ b/src/PhpParser/NodeVisitor/MockedClassNameCollectingNodeVisitor.php @@ -1,45 +1,38 @@ name instanceof Identifier) { + if (!$node->name instanceof Identifier) { return null; } - $methodName = $node->name->toString(); - if (! in_array($methodName, ['getMock', 'createMock'], true)) { + if (!\in_array($methodName, ['getMock', 'createMock'], \true)) { return null; } - $mockedClassArg = $node->getArgs()[0] ?? null; - if (! $mockedClassArg instanceof Arg) { + if (!$mockedClassArg instanceof Arg) { return null; } - // get class name if ($mockedClassArg->value instanceof ClassConstFetch) { $mockedClass = $mockedClassArg->value->class; @@ -47,18 +40,15 @@ public function enterNode(Node $node) $this->mockedClassNames[] = $mockedClass->toString(); } } - return null; } - /** * @return string[] */ - public function getMockedClassNames(): array + public function getMockedClassNames() : array { - $uniqueMockedClassNames = array_unique($this->mockedClassNames); - sort($uniqueMockedClassNames); - + $uniqueMockedClassNames = \array_unique($this->mockedClassNames); + \sort($uniqueMockedClassNames); return $uniqueMockedClassNames; } } diff --git a/src/PhpParser/NodeVisitor/NeedForFinalizeNodeVisitor.php b/src/PhpParser/NodeVisitor/NeedForFinalizeNodeVisitor.php index a38fc2a1f3..c2c135354a 100644 --- a/src/PhpParser/NodeVisitor/NeedForFinalizeNodeVisitor.php +++ b/src/PhpParser/NodeVisitor/NeedForFinalizeNodeVisitor.php @@ -1,65 +1,61 @@ excludedClasses = $excludedClasses; } - /** * @param Node[] $nodes * @return Node[] */ - public function beforeTraverse(array $nodes): array + public function beforeTraverse(array $nodes) : array { // reset - $this->isNeeded = false; - + $this->isNeeded = \false; return $nodes; } - public function enterNode(Node $node) { - if (! $node instanceof Class_) { + if (!$node instanceof Class_) { return null; } - // nothing we can do if ($node->isFinal() || $node->isAnonymous() || $node->isAbstract()) { return null; } - // we need a name to make it work - if (! $node->namespacedName instanceof Name) { + if (!$node->namespacedName instanceof Name) { return null; } - $className = $node->namespacedName->toString(); - if (in_array($className, $this->excludedClasses, true)) { + if (\in_array($className, $this->excludedClasses, \true)) { return null; } - - $this->isNeeded = true; - + $this->isNeeded = \true; return null; } - - public function isNeeded(): bool + public function isNeeded() : bool { return $this->isNeeded; } diff --git a/src/PhpParser/NodeVisitor/ParentClassNameCollectingNodeVisitor.php b/src/PhpParser/NodeVisitor/ParentClassNameCollectingNodeVisitor.php index 5549996e9c..e05f71c5c2 100644 --- a/src/PhpParser/NodeVisitor/ParentClassNameCollectingNodeVisitor.php +++ b/src/PhpParser/NodeVisitor/ParentClassNameCollectingNodeVisitor.php @@ -1,63 +1,50 @@ extends instanceof Name) { + if (!$node->extends instanceof Name) { return null; } - $this->parentClassNames[] = $node->extends->toString(); - return null; } - /** * @return string[] */ - public function getParentClassNames(): array + public function getParentClassNames() : array { - $uniqueParentClassNames = array_unique($this->parentClassNames); - sort($uniqueParentClassNames); - + $uniqueParentClassNames = \array_unique($this->parentClassNames); + \sort($uniqueParentClassNames); // remove native classes - $namespacedClassNames = array_filter( - $uniqueParentClassNames, - static fn (string $parentClassName): bool => str_contains($parentClassName, '\\') - ); - + $namespacedClassNames = \array_filter($uniqueParentClassNames, static function (string $parentClassName) : bool { + return \strpos($parentClassName, '\\') !== \false; + }); // remove obviously vendor names - $namespacedClassNames = array_filter($namespacedClassNames, static function (string $className): bool { - if (str_contains($className, 'Symfony\\')) { - return false; + $namespacedClassNames = \array_filter($namespacedClassNames, static function (string $className) : bool { + if (\strpos($className, 'Symfony\\') !== \false) { + return \false; } - - if (str_contains($className, 'PHPStan\\')) { - return false; + if (\strpos($className, 'PHPStan\\') !== \false) { + return \false; } - - return ! str_contains($className, 'PhpParser\\'); + return \strpos($className, 'PhpParser\\') === \false; }); - - return array_values($namespacedClassNames); + return \array_values($namespacedClassNames); } } diff --git a/src/Resolver/TooLongFilesResolver.php b/src/Resolver/TooLongFilesResolver.php index c743e0ab5d..0b30e26b71 100644 --- a/src/Resolver/TooLongFilesResolver.php +++ b/src/Resolver/TooLongFilesResolver.php @@ -1,11 +1,9 @@ $this->isFileContentLongerThan($fileInfo, self::MAX_FILE_LENGTH) - ); + return \array_filter($fileInfos, function (SplFileInfo $fileInfo) : bool { + return $this->isFileContentLongerThan($fileInfo, self::MAX_FILE_LENGTH); + }); } - - private function isFileContentLongerThan(SplFileInfo $fileInfo, int $maxFileLenght): bool + private function isFileContentLongerThan(SplFileInfo $fileInfo, int $maxFileLenght) : bool { - $filePathLength = strlen($fileInfo->getRealPath()); + $filePathLength = \strlen($fileInfo->getRealPath()); return $filePathLength > $maxFileLenght; } } diff --git a/src/RobotLoader/PhpClassLoader.php b/src/RobotLoader/PhpClassLoader.php index 9b91c0f73f..b92a362ef0 100644 --- a/src/RobotLoader/PhpClassLoader.php +++ b/src/RobotLoader/PhpClassLoader.php @@ -2,8 +2,7 @@ namespace Rector\SwissKnife\RobotLoader; -use Nette\Loaders\RobotLoader; - +use SwissKnife202405\Nette\Loaders\RobotLoader; final class PhpClassLoader { /** @@ -11,15 +10,13 @@ final class PhpClassLoader * @param string[] $excludedPaths * @return array */ - public function load(array $directories, array $excludedPaths): array + public function load(array $directories, array $excludedPaths) : array { $robotLoader = new RobotLoader(); $robotLoader->addDirectory(...$directories); $robotLoader->excludeDirectory(...$excludedPaths); - - $robotLoader->setTempDirectory(sys_get_temp_dir() . '/multiple-classes'); + $robotLoader->setTempDirectory(\sys_get_temp_dir() . '/multiple-classes'); $robotLoader->rebuild(); - return $robotLoader->getIndexedClasses(); } } diff --git a/src/Testing/Command/DetectUnitTestsCommand.php b/src/Testing/Command/DetectUnitTestsCommand.php index b2818471a4..9749ce15ed 100644 --- a/src/Testing/Command/DetectUnitTestsCommand.php +++ b/src/Testing/Command/DetectUnitTestsCommand.php @@ -1,72 +1,65 @@ phpunitXmlPrinter = $phpunitXmlPrinter; + $this->symfonyStyle = $symfonyStyle; + $this->unitTestFilePathsFinder = $unitTestFilePathsFinder; parent::__construct(); } - - protected function configure(): void + protected function configure() : void { $this->setName('detect-unit-tests'); - $this->setDescription('Get list of tests in specific directory, that are considered "unit"'); - - $this->addArgument( - 'sources', - InputArgument::REQUIRED | InputArgument::IS_ARRAY, - 'Path to directory with tests' - ); + $this->addArgument('sources', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'Path to directory with tests'); } - - protected function execute(InputInterface $input, OutputInterface $output): int + protected function execute(InputInterface $input, OutputInterface $output) : int { $sources = (array) $input->getArgument('sources'); Assert::isArray($sources); Assert::allString($sources); - $unitTestCasesClassesToFilePaths = $this->unitTestFilePathsFinder->findInDirectories($sources); - if ($unitTestCasesClassesToFilePaths === []) { $this->symfonyStyle->note('No unit tests found in provided paths'); return self::SUCCESS; } - $filesPHPUnitXmlContents = $this->phpunitXmlPrinter->printFiles($unitTestCasesClassesToFilePaths); - FileSystem::write(self::OUTPUT_FILENAME, $filesPHPUnitXmlContents); - - $successMessage = sprintf( - 'List of %d unit tests was dumped into "%s"', - count($unitTestCasesClassesToFilePaths), - self::OUTPUT_FILENAME, - ); - + $successMessage = \sprintf('List of %d unit tests was dumped into "%s"', \count($unitTestCasesClassesToFilePaths), self::OUTPUT_FILENAME); $this->symfonyStyle->success($successMessage); - return self::SUCCESS; } } diff --git a/src/Testing/Finder/TestCaseClassFinder.php b/src/Testing/Finder/TestCaseClassFinder.php index 4b00f8a24b..d3e938a19e 100644 --- a/src/Testing/Finder/TestCaseClassFinder.php +++ b/src/Testing/Finder/TestCaseClassFinder.php @@ -1,46 +1,38 @@ */ - public function findInDirectories(array $directories): array + public function findInDirectories(array $directories) : array { $robotLoader = new RobotLoader(); $robotLoader->addDirectory(...$directories); $robotLoader->rebuild(); - $this->includeNonAutoloadedClasses($robotLoader->getIndexedClasses()); - return $robotLoader->getIndexedClasses(); } - /** * @param array $classesToFilePaths */ - private function includeNonAutoloadedClasses(array $classesToFilePaths): void + private function includeNonAutoloadedClasses(array $classesToFilePaths) : void { foreach ($classesToFilePaths as $class => $filePath) { - if (class_exists($class)) { + if (\class_exists($class)) { continue; } - - if (interface_exists($class)) { + if (\interface_exists($class)) { continue; } - - if (trait_exists($class)) { + if (\trait_exists($class)) { continue; } - require_once $filePath; } } diff --git a/src/Testing/Printer/PHPUnitXmlPrinter.php b/src/Testing/Printer/PHPUnitXmlPrinter.php index 8d593ac49e..f1b22aef2d 100644 --- a/src/Testing/Printer/PHPUnitXmlPrinter.php +++ b/src/Testing/Printer/PHPUnitXmlPrinter.php @@ -1,11 +1,9 @@ ' . $relativeFilePath . '' . PHP_EOL; + $fileContents .= '' . $relativeFilePath . '' . \PHP_EOL; } - return $fileContents; } } diff --git a/src/Testing/UnitTestFilePathsFinder.php b/src/Testing/UnitTestFilePathsFinder.php index 409b27d13b..230426bc16 100644 --- a/src/Testing/UnitTestFilePathsFinder.php +++ b/src/Testing/UnitTestFilePathsFinder.php @@ -1,30 +1,36 @@ testCaseClassFinder = $testCaseClassFinder; + $this->unitTestFilter = $unitTestFilter; } - /** * @param string[] $directories * @return array */ - public function findInDirectories(array $directories): array + public function findInDirectories(array $directories) : array { $testsCasesClassesToFilePaths = $this->testCaseClassFinder->findInDirectories($directories); - return $this->unitTestFilter->filter($testsCasesClassesToFilePaths); } } diff --git a/src/Testing/UnitTestFilter.php b/src/Testing/UnitTestFilter.php index 3927b26687..224be47de9 100644 --- a/src/Testing/UnitTestFilter.php +++ b/src/Testing/UnitTestFilter.php @@ -1,7 +1,6 @@ [] */ - private const NON_UNIT_TEST_CASE_CLASSES = [ - 'Symfony\Bundle\FrameworkBundle\Test\KernelTestCase', - 'Symfony\Component\Form\Test\TypeTestCase', - ]; - + private const NON_UNIT_TEST_CASE_CLASSES = ['SwissKnife202405\\Symfony\\Bundle\\FrameworkBundle\\Test\\KernelTestCase', 'SwissKnife202405\\Symfony\\Component\\Form\\Test\\TypeTestCase']; /** * @param array $testClassesToFilePaths * @return array */ - public function filter(array $testClassesToFilePaths): array + public function filter(array $testClassesToFilePaths) : array { - return array_filter( - $testClassesToFilePaths, - fn (string $testClass): bool => $this->isUnitTest($testClass), - ARRAY_FILTER_USE_KEY - ); + return \array_filter($testClassesToFilePaths, function (string $testClass) : bool { + return $this->isUnitTest($testClass); + }, \ARRAY_FILTER_USE_KEY); } - - private function isUnitTest(string $class): bool + private function isUnitTest(string $class) : bool { - if (! is_a($class, 'PHPUnit\Framework\TestCase', true) && ! is_a($class, 'PHPUnit_Framework_TestCase', true)) { - return false; + if (!\is_a($class, 'SwissKnife202405\\PHPUnit\\Framework\\TestCase', \true) && !\is_a($class, 'SwissKnife202405\\PHPUnit_Framework_TestCase', \true)) { + return \false; } - foreach (self::NON_UNIT_TEST_CASE_CLASSES as $nonUnitTestCaseClass) { // required special behavior - if (is_a($class, $nonUnitTestCaseClass, true)) { - return false; + if (\is_a($class, $nonUnitTestCaseClass, \true)) { + return \false; } } - - return true; + return \true; } } diff --git a/src/ValueObject/ClassConstMatch.php b/src/ValueObject/ClassConstMatch.php index 621ca3cbd9..64fa1f8a70 100644 --- a/src/ValueObject/ClassConstMatch.php +++ b/src/ValueObject/ClassConstMatch.php @@ -1,33 +1,38 @@ className = $className; + $this->constantName = $constantName; } - - public function getClassName(): string + public function getClassName() : string { return $this->className; } - - public function getConstantName(): string + public function getConstantName() : string { return $this->constantName; } - - public function getClassFileName(): string + public function getClassFileName() : string { $classReflection = new ReflectionClass($this->className); return (string) $classReflection->getFileName(); diff --git a/stubs/PHPUnit/KernelTestCase.php b/stubs/PHPUnit/KernelTestCase.php deleted file mode 100644 index 885e5e70c4..0000000000 --- a/stubs/PHPUnit/KernelTestCase.php +++ /dev/null @@ -1,6 +0,0 @@ -container = $containerFactory->create(); - } - - /** - * @template TType of object - * @param class-string $type - * @return TType - */ - protected function make(string $type): object - { - return $this->container->make($type); - } -} diff --git a/tests/Comments/CommentedCodeAnalyzerTest.php b/tests/Comments/CommentedCodeAnalyzerTest.php deleted file mode 100644 index 454c596675..0000000000 --- a/tests/Comments/CommentedCodeAnalyzerTest.php +++ /dev/null @@ -1,28 +0,0 @@ -commentedCodeAnalyzer = new CommentedCodeAnalyzer(); - } - - public function test(): void - { - $filePath = __DIR__ . '/Fixture/some_commented_code.php.inc'; - $commentedLines = $this->commentedCodeAnalyzer->process($filePath, 4); - $this->assertSame([], $commentedLines); - - $commentedLines = $this->commentedCodeAnalyzer->process($filePath, 2); - $this->assertSame([5], $commentedLines); - } -} diff --git a/tests/Comments/Fixture/some_commented_code.php.inc b/tests/Comments/Fixture/some_commented_code.php.inc deleted file mode 100644 index ea69c4fc36..0000000000 --- a/tests/Comments/Fixture/some_commented_code.php.inc +++ /dev/null @@ -1,5 +0,0 @@ -entityClassResolver = $this->make(EntityClassResolver::class); - } - - public function test(): void - { - $entityClasses = $this->entityClassResolver->resolve([__DIR__ . '/Fixture'], static function (): void { - }); - - $this->assertSame( - ['App\Some\Entity\Conference', 'App\Some\Entity\Project', 'App\Some\Entity\Talk', SomeEntity::class], - $entityClasses - ); - } -} diff --git a/tests/EntityClassResolver/Fixture/Entity/SomeEntity.php b/tests/EntityClassResolver/Fixture/Entity/SomeEntity.php deleted file mode 100644 index d6179671a0..0000000000 --- a/tests/EntityClassResolver/Fixture/Entity/SomeEntity.php +++ /dev/null @@ -1,7 +0,0 @@ -conflictResolver = new ConflictResolver(); - } - - #[DataProvider('provideData')] - public function test(string $filePath, int $expectedConflictCount): void - { - $unresolvedConflictCount = $this->conflictResolver->extractFromFileInfo($filePath); - $this->assertSame($expectedConflictCount, $unresolvedConflictCount); - } - - public static function provideData(): Iterator - { - yield [__DIR__ . '/Fixture/some_file.txt', 1]; - yield [__DIR__ . '/Fixture/some_other_file.txt', 1]; - yield [__DIR__ . '/Fixture/correct_file.txt', 0]; - } -} diff --git a/tests/Git/ConflictResolver/Fixture/correct_file.txt b/tests/Git/ConflictResolver/Fixture/correct_file.txt deleted file mode 100644 index d68dd4031d..0000000000 --- a/tests/Git/ConflictResolver/Fixture/correct_file.txt +++ /dev/null @@ -1,4 +0,0 @@ -a -b -c -d diff --git a/tests/Git/ConflictResolver/Fixture/some_file.txt b/tests/Git/ConflictResolver/Fixture/some_file.txt deleted file mode 100644 index 350fbbcd23..0000000000 --- a/tests/Git/ConflictResolver/Fixture/some_file.txt +++ /dev/null @@ -1,2 +0,0 @@ -<<<<<<<<< -CONFLICT \ No newline at end of file diff --git a/tests/Git/ConflictResolver/Fixture/some_other_file.txt b/tests/Git/ConflictResolver/Fixture/some_other_file.txt deleted file mode 100644 index 7cbb8c657c..0000000000 --- a/tests/Git/ConflictResolver/Fixture/some_other_file.txt +++ /dev/null @@ -1,6 +0,0 @@ -<<<<<<< HEAD -this is some content to mess with -content to append -======= -totally different content to merge later ->>>>>>> new_branch_to_merge_later diff --git a/tests/NeedsFinalizeAnalyzer/Fixture/abstract_class.php.inc b/tests/NeedsFinalizeAnalyzer/Fixture/abstract_class.php.inc deleted file mode 100644 index a10b6db82c..0000000000 --- a/tests/NeedsFinalizeAnalyzer/Fixture/abstract_class.php.inc +++ /dev/null @@ -1,9 +0,0 @@ -needsFinalizeAnalyzer = new NeedsFinalizeAnalyzer( - excludedClasses: ['Rector\SwissKnife\Tests\NeedsFinalizeAnalyzer\Fixture\ExcludedClass'], - cachedPhpParser: $this->make(CachedPhpParser::class), - ); - } - - #[DataProvider('provideData')] - public function test(string $filePath, bool $expected): void - { - $this->assertSame($expected, $this->needsFinalizeAnalyzer->isNeeded($filePath)); - } - - /** - * @return iterable - */ - public static function provideData(): iterable - { - yield [__DIR__ . '/Fixture/excluded_class.php.inc', false]; - yield [__DIR__ . '/Fixture/final_class.php.inc', false]; - yield [__DIR__ . '/Fixture/abstract_class.php.inc', false]; - yield [__DIR__ . '/Fixture/anonymous_class.php.inc', false]; - - yield [__DIR__ . '/Fixture/non_final_class.php.inc', true]; - } -} diff --git a/tests/ParentClassResolver/Fixture/AbstractNonParentClass.php b/tests/ParentClassResolver/Fixture/AbstractNonParentClass.php deleted file mode 100644 index 768cbe6be2..0000000000 --- a/tests/ParentClassResolver/Fixture/AbstractNonParentClass.php +++ /dev/null @@ -1,9 +0,0 @@ -parentClassResolver = $this->make(ParentClassResolver::class); - } - - public function test(): void - { - $parentClasses = $this->parentClassResolver->resolve( - PhpFilesFinder::find([__DIR__ . '/Fixture']), - static function (): void { - } - ); - - $this->assertSame( - [AbstractParentClass::class, ParentClass::class, ParentClassInSeparateNamespace::class], - $parentClasses - ); - } -} diff --git a/tests/SomeApp/templates/FirstName/SecondName/template.html.twig b/tests/SomeApp/templates/FirstName/SecondName/template.html.twig deleted file mode 100644 index 60f6bf95f4..0000000000 --- a/tests/SomeApp/templates/FirstName/SecondName/template.html.twig +++ /dev/null @@ -1 +0,0 @@ -{{ hi }} diff --git a/tests/SomeBundle/RealClassBundle.php b/tests/SomeBundle/RealClassBundle.php deleted file mode 100644 index 5a5a440747..0000000000 --- a/tests/SomeBundle/RealClassBundle.php +++ /dev/null @@ -1,12 +0,0 @@ -unitTestFilePathsFinder = new UnitTestFilePathsFinder( - new TestCaseClassFinder(), - new UnitTestFilter(), - ); - } - - public function test(): void - { - $unitTestFilePaths = $this->unitTestFilePathsFinder->findInDirectories([__DIR__ . '/Fixture']); - $this->assertCount(2, $unitTestFilePaths); - - $this->assertArrayHasKey(RandomTest::class, $unitTestFilePaths); - $this->assertArrayHasKey(OldSchoolTest::class, $unitTestFilePaths); - } -} diff --git a/vendor/autoload.php b/vendor/autoload.php new file mode 100644 index 0000000000..196fd4c475 --- /dev/null +++ b/vendor/autoload.php @@ -0,0 +1,25 @@ +realpath = \realpath($opened_path) ?: $opened_path; + $opened_path = $this->realpath; + $this->handle = \fopen($this->realpath, $mode); + $this->position = 0; + return (bool) $this->handle; + } + public function stream_read($count) + { + $data = \fread($this->handle, $count); + if ($this->position === 0) { + $data = \preg_replace('{^#!.*\\r?\\n}', '', $data); + } + $this->position += \strlen($data); + return $data; + } + public function stream_cast($castAs) + { + return $this->handle; + } + public function stream_close() + { + \fclose($this->handle); + } + public function stream_lock($operation) + { + return $operation ? \flock($this->handle, $operation) : \true; + } + public function stream_seek($offset, $whence) + { + if (0 === \fseek($this->handle, $offset, $whence)) { + $this->position = \ftell($this->handle); + return \true; + } + return \false; + } + public function stream_tell() + { + return $this->position; + } + public function stream_eof() + { + return \feof($this->handle); + } + public function stream_stat() + { + return array(); + } + public function stream_set_option($option, $arg1, $arg2) + { + return \true; + } + public function url_stat($path, $flags) + { + $path = \substr($path, 17); + if (\file_exists($path)) { + return \stat($path); + } + return \false; + } + } + } + if (\function_exists('stream_get_wrappers') && \in_array('phpvfscomposer', \stream_get_wrappers(), \true) || \function_exists('stream_wrapper_register') && \stream_wrapper_register('phpvfscomposer', 'SwissKnife202405\\Composer\\BinProxyWrapper')) { + return include "phpvfscomposer://" . __DIR__ . '/..' . '/nikic/php-parser/bin/php-parse'; + } +} +return include __DIR__ . '/..' . '/nikic/php-parser/bin/php-parse'; diff --git a/vendor/composer/ClassLoader.php b/vendor/composer/ClassLoader.php new file mode 100644 index 0000000000..7824d8f7ea --- /dev/null +++ b/vendor/composer/ClassLoader.php @@ -0,0 +1,579 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + /** @var \Closure(string):void */ + private static $includeFile; + + /** @var string|null */ + private $vendorDir; + + // PSR-4 + /** + * @var array> + */ + private $prefixLengthsPsr4 = array(); + /** + * @var array> + */ + private $prefixDirsPsr4 = array(); + /** + * @var list + */ + private $fallbackDirsPsr4 = array(); + + // PSR-0 + /** + * List of PSR-0 prefixes + * + * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2'))) + * + * @var array>> + */ + private $prefixesPsr0 = array(); + /** + * @var list + */ + private $fallbackDirsPsr0 = array(); + + /** @var bool */ + private $useIncludePath = false; + + /** + * @var array + */ + private $classMap = array(); + + /** @var bool */ + private $classMapAuthoritative = false; + + /** + * @var array + */ + private $missingClasses = array(); + + /** @var string|null */ + private $apcuPrefix; + + /** + * @var array + */ + private static $registeredLoaders = array(); + + /** + * @param string|null $vendorDir + */ + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + self::initializeIncludeClosure(); + } + + /** + * @return array> + */ + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); + } + + return array(); + } + + /** + * @return array> + */ + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + /** + * @return list + */ + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + /** + * @return list + */ + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + /** + * @return array Array of classname => path + */ + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + * + * @return void + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param list|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + * + * @return void + */ + public function add($prefix, $paths, $prepend = false) + { + $paths = (array) $paths; + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + $paths = (array) $paths; + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param list|string $paths The PSR-0 base directories + * + * @return void + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + * + * @return void + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + * + * @return void + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + * + * @return void + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + * + * @return void + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } + } + + /** + * Unregisters this instance as an autoloader. + * + * @return void + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return true|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + $includeFile = self::$includeFile; + $includeFile($file); + + return true; + } + + return null; + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + /** + * Returns the currently registered loaders keyed by their corresponding vendor directories. + * + * @return array + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + + /** + * @param string $class + * @param string $ext + * @return string|false + */ + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } + + /** + * @return void + */ + private static function initializeIncludeClosure() + { + if (self::$includeFile !== null) { + return; + } + + /** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + */ + self::$includeFile = \Closure::bind(static function($file) { + include $file; + }, null, null); + } +} diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php new file mode 100644 index 0000000000..efc45e8f86 --- /dev/null +++ b/vendor/composer/InstalledVersions.php @@ -0,0 +1,313 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Composer; + +use SwissKnife202405\Composer\Autoload\ClassLoader; +use SwissKnife202405\Composer\Semver\VersionParser; +/** + * This class is copied in every Composer installed project and available to all + * + * See also https://getcomposer.org/doc/07-runtime.md#installed-versions + * + * To require its presence, you can require `composer-runtime-api ^2.0` + * + * @final + */ +class InstalledVersions +{ + /** + * @var mixed[]|null + * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null + */ + private static $installed; + /** + * @var bool|null + */ + private static $canGetVendors; + /** + * @var array[] + * @psalm-var array}> + */ + private static $installedByVendor = array(); + /** + * Returns a list of all package names which are present, either by being installed, replaced or provided + * + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackages() + { + $packages = array(); + foreach (self::getInstalled() as $installed) { + $packages[] = \array_keys($installed['versions']); + } + if (1 === \count($packages)) { + return $packages[0]; + } + return \array_keys(\array_flip(\call_user_func_array('SwissKnife202405\\array_merge', $packages))); + } + /** + * Returns a list of all package names with a specific type e.g. 'library' + * + * @param string $type + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackagesByType($type) + { + $packagesByType = array(); + foreach (self::getInstalled() as $installed) { + foreach ($installed['versions'] as $name => $package) { + if (isset($package['type']) && $package['type'] === $type) { + $packagesByType[] = $name; + } + } + } + return $packagesByType; + } + /** + * Checks whether the given package is installed + * + * This also returns true if the package name is provided or replaced by another package + * + * @param string $packageName + * @param bool $includeDevRequirements + * @return bool + */ + public static function isInstalled($packageName, $includeDevRequirements = \true) + { + foreach (self::getInstalled() as $installed) { + if (isset($installed['versions'][$packageName])) { + return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === \false; + } + } + return \false; + } + /** + * Checks whether the given package satisfies a version constraint + * + * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: + * + * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') + * + * @param VersionParser $parser Install composer/semver to have access to this class and functionality + * @param string $packageName + * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package + * @return bool + */ + public static function satisfies(VersionParser $parser, $packageName, $constraint) + { + $constraint = $parser->parseConstraints((string) $constraint); + $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + return $provided->matches($constraint); + } + /** + * Returns a version constraint representing all the range(s) which are installed for a given package + * + * It is easier to use this via isInstalled() with the $constraint argument if you need to check + * whether a given version of a package is installed, and not just whether it exists + * + * @param string $packageName + * @return string Version constraint usable with composer/semver + */ + public static function getVersionRanges($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + $ranges = array(); + if (isset($installed['versions'][$packageName]['pretty_version'])) { + $ranges[] = $installed['versions'][$packageName]['pretty_version']; + } + if (\array_key_exists('aliases', $installed['versions'][$packageName])) { + $ranges = \array_merge($ranges, $installed['versions'][$packageName]['aliases']); + } + if (\array_key_exists('replaced', $installed['versions'][$packageName])) { + $ranges = \array_merge($ranges, $installed['versions'][$packageName]['replaced']); + } + if (\array_key_exists('provided', $installed['versions'][$packageName])) { + $ranges = \array_merge($ranges, $installed['versions'][$packageName]['provided']); + } + return \implode(' || ', $ranges); + } + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + if (!isset($installed['versions'][$packageName]['version'])) { + return null; + } + return $installed['versions'][$packageName]['version']; + } + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getPrettyVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + if (!isset($installed['versions'][$packageName]['pretty_version'])) { + return null; + } + return $installed['versions'][$packageName]['pretty_version']; + } + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference + */ + public static function getReference($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + if (!isset($installed['versions'][$packageName]['reference'])) { + return null; + } + return $installed['versions'][$packageName]['reference']; + } + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. + */ + public static function getInstallPath($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; + } + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + /** + * @return array + * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} + */ + public static function getRootPackage() + { + $installed = self::getInstalled(); + return $installed[0]['root']; + } + /** + * Returns the raw installed.php data for custom implementations + * + * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. + * @return array[] + * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} + */ + public static function getRawData() + { + @\trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', \E_USER_DEPRECATED); + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (\substr(__DIR__, -8, 1) !== 'C') { + self::$installed = (include __DIR__ . '/installed.php'); + } else { + self::$installed = array(); + } + } + return self::$installed; + } + /** + * Returns the raw data of all installed.php which are currently loaded for custom implementations + * + * @return array[] + * @psalm-return list}> + */ + public static function getAllRawData() + { + return self::getInstalled(); + } + /** + * Lets you reload the static array from another file + * + * This is only useful for complex integrations in which a project needs to use + * this class but then also needs to execute another project's autoloader in process, + * and wants to ensure both projects have access to their version of installed.php. + * + * A typical case would be PHPUnit, where it would need to make sure it reads all + * the data it needs from this class, then call reload() with + * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure + * the project in which it runs can then also use this class safely, without + * interference between PHPUnit's dependencies and the project's dependencies. + * + * @param array[] $data A vendor/composer/installed.php data set + * @return void + * + * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data + */ + public static function reload($data) + { + self::$installed = $data; + self::$installedByVendor = array(); + } + /** + * @return array[] + * @psalm-return list}> + */ + private static function getInstalled() + { + if (null === self::$canGetVendors) { + self::$canGetVendors = \method_exists('SwissKnife202405\\Composer\\Autoload\\ClassLoader', 'getRegisteredLoaders'); + } + $installed = array(); + if (self::$canGetVendors) { + foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + if (isset(self::$installedByVendor[$vendorDir])) { + $installed[] = self::$installedByVendor[$vendorDir]; + } elseif (\is_file($vendorDir . '/composer/installed.php')) { + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = (require $vendorDir . '/composer/installed.php'); + $installed[] = self::$installedByVendor[$vendorDir] = $required; + if (null === self::$installed && \strtr($vendorDir . '/composer', '\\', '/') === \strtr(__DIR__, '\\', '/')) { + self::$installed = $installed[\count($installed) - 1]; + } + } + } + } + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (\substr(__DIR__, -8, 1) !== 'C') { + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = (require __DIR__ . '/installed.php'); + self::$installed = $required; + } else { + self::$installed = array(); + } + } + if (self::$installed !== array()) { + $installed[] = self::$installed; + } + return $installed; + } +} diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE new file mode 100644 index 0000000000..f27399a042 --- /dev/null +++ b/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php new file mode 100644 index 0000000000..e45982954f --- /dev/null +++ b/vendor/composer/autoload_classmap.php @@ -0,0 +1,681 @@ + $vendorDir . '/composer/InstalledVersions.php', + 'PHPUnit_Framework_TestCase' => $baseDir . '/stubs/PHPUnit/PHPUnit_Framework_TestCase.php', + 'Rector\\SwissKnife\\Analyzer\\NeedsFinalizeAnalyzer' => $baseDir . '/src/Analyzer/NeedsFinalizeAnalyzer.php', + 'Rector\\SwissKnife\\Command\\CheckCommentedCodeCommand' => $baseDir . '/src/Command/CheckCommentedCodeCommand.php', + 'Rector\\SwissKnife\\Command\\CheckConflictsCommand' => $baseDir . '/src/Command/CheckConflictsCommand.php', + 'Rector\\SwissKnife\\Command\\DumpEditorconfigCommand' => $baseDir . '/src/Command/DumpEditorconfigCommand.php', + 'Rector\\SwissKnife\\Command\\FinalizeClassesCommand' => $baseDir . '/src/Command/FinalizeClassesCommand.php', + 'Rector\\SwissKnife\\Command\\FindMultiClassesCommand' => $baseDir . '/src/Command/FindMultiClassesCommand.php', + 'Rector\\SwissKnife\\Command\\NamespaceToPSR4Command' => $baseDir . '/src/Command/NamespaceToPSR4Command.php', + 'Rector\\SwissKnife\\Command\\PrettyJsonCommand' => $baseDir . '/src/Command/PrettyJsonCommand.php', + 'Rector\\SwissKnife\\Command\\PrivatizeConstantsCommand' => $baseDir . '/src/Command/PrivatizeConstantsCommand.php', + 'Rector\\SwissKnife\\Command\\ValidateFileLengthCommand' => $baseDir . '/src/Command/ValidateFileLengthCommand.php', + 'Rector\\SwissKnife\\Comments\\CommentedCodeAnalyzer' => $baseDir . '/src/Comments/CommentedCodeAnalyzer.php', + 'Rector\\SwissKnife\\DependencyInjection\\ContainerFactory' => $baseDir . '/src/DependencyInjection/ContainerFactory.php', + 'Rector\\SwissKnife\\EntityClassResolver' => $baseDir . '/src/EntityClassResolver.php', + 'Rector\\SwissKnife\\FileSystem\\JsonAnalyzer' => $baseDir . '/src/FileSystem/JsonAnalyzer.php', + 'Rector\\SwissKnife\\FileSystem\\PathHelper' => $baseDir . '/src/FileSystem/PathHelper.php', + 'Rector\\SwissKnife\\Finder\\FilesFinder' => $baseDir . '/src/Finder/FilesFinder.php', + 'Rector\\SwissKnife\\Finder\\MultipleClassInOneFileFinder' => $baseDir . '/src/Finder/MultipleClassInOneFileFinder.php', + 'Rector\\SwissKnife\\Finder\\PhpFilesFinder' => $baseDir . '/src/Finder/PhpFilesFinder.php', + 'Rector\\SwissKnife\\Finder\\YamlFilesFinder' => $baseDir . '/src/Finder/YamlFilesFinder.php', + 'Rector\\SwissKnife\\Git\\ConflictResolver' => $baseDir . '/src/Git/ConflictResolver.php', + 'Rector\\SwissKnife\\MockedClassResolver' => $baseDir . '/src/MockedClassResolver.php', + 'Rector\\SwissKnife\\ParentClassResolver' => $baseDir . '/src/ParentClassResolver.php', + 'Rector\\SwissKnife\\PhpParser\\CachedPhpParser' => $baseDir . '/src/PhpParser/CachedPhpParser.php', + 'Rector\\SwissKnife\\PhpParser\\NodeVisitor\\EntityClassNameCollectingNodeVisitor' => $baseDir . '/src/PhpParser/NodeVisitor/EntityClassNameCollectingNodeVisitor.php', + 'Rector\\SwissKnife\\PhpParser\\NodeVisitor\\MockedClassNameCollectingNodeVisitor' => $baseDir . '/src/PhpParser/NodeVisitor/MockedClassNameCollectingNodeVisitor.php', + 'Rector\\SwissKnife\\PhpParser\\NodeVisitor\\NeedForFinalizeNodeVisitor' => $baseDir . '/src/PhpParser/NodeVisitor/NeedForFinalizeNodeVisitor.php', + 'Rector\\SwissKnife\\PhpParser\\NodeVisitor\\ParentClassNameCollectingNodeVisitor' => $baseDir . '/src/PhpParser/NodeVisitor/ParentClassNameCollectingNodeVisitor.php', + 'Rector\\SwissKnife\\Resolver\\TooLongFilesResolver' => $baseDir . '/src/Resolver/TooLongFilesResolver.php', + 'Rector\\SwissKnife\\RobotLoader\\PhpClassLoader' => $baseDir . '/src/RobotLoader/PhpClassLoader.php', + 'Rector\\SwissKnife\\Testing\\Command\\DetectUnitTestsCommand' => $baseDir . '/src/Testing/Command/DetectUnitTestsCommand.php', + 'Rector\\SwissKnife\\Testing\\Finder\\TestCaseClassFinder' => $baseDir . '/src/Testing/Finder/TestCaseClassFinder.php', + 'Rector\\SwissKnife\\Testing\\Printer\\PHPUnitXmlPrinter' => $baseDir . '/src/Testing/Printer/PHPUnitXmlPrinter.php', + 'Rector\\SwissKnife\\Testing\\UnitTestFilePathsFinder' => $baseDir . '/src/Testing/UnitTestFilePathsFinder.php', + 'Rector\\SwissKnife\\Testing\\UnitTestFilter' => $baseDir . '/src/Testing/UnitTestFilter.php', + 'Rector\\SwissKnife\\ValueObject\\ClassConstMatch' => $baseDir . '/src/ValueObject/ClassConstMatch.php', + 'SwissKnife202405\\Illuminate\\Container\\BoundMethod' => $vendorDir . '/illuminate/container/BoundMethod.php', + 'SwissKnife202405\\Illuminate\\Container\\Container' => $vendorDir . '/illuminate/container/Container.php', + 'SwissKnife202405\\Illuminate\\Container\\ContextualBindingBuilder' => $vendorDir . '/illuminate/container/ContextualBindingBuilder.php', + 'SwissKnife202405\\Illuminate\\Container\\EntryNotFoundException' => $vendorDir . '/illuminate/container/EntryNotFoundException.php', + 'SwissKnife202405\\Illuminate\\Container\\RewindableGenerator' => $vendorDir . '/illuminate/container/RewindableGenerator.php', + 'SwissKnife202405\\Illuminate\\Container\\Util' => $vendorDir . '/illuminate/container/Util.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\Access\\Authorizable' => $vendorDir . '/illuminate/contracts/Auth/Access/Authorizable.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\Access\\Gate' => $vendorDir . '/illuminate/contracts/Auth/Access/Gate.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\Authenticatable' => $vendorDir . '/illuminate/contracts/Auth/Authenticatable.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\CanResetPassword' => $vendorDir . '/illuminate/contracts/Auth/CanResetPassword.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\Factory' => $vendorDir . '/illuminate/contracts/Auth/Factory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\Guard' => $vendorDir . '/illuminate/contracts/Auth/Guard.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\Middleware\\AuthenticatesRequests' => $vendorDir . '/illuminate/contracts/Auth/Middleware/AuthenticatesRequests.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\MustVerifyEmail' => $vendorDir . '/illuminate/contracts/Auth/MustVerifyEmail.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\PasswordBroker' => $vendorDir . '/illuminate/contracts/Auth/PasswordBroker.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\PasswordBrokerFactory' => $vendorDir . '/illuminate/contracts/Auth/PasswordBrokerFactory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\StatefulGuard' => $vendorDir . '/illuminate/contracts/Auth/StatefulGuard.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\SupportsBasicAuth' => $vendorDir . '/illuminate/contracts/Auth/SupportsBasicAuth.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\UserProvider' => $vendorDir . '/illuminate/contracts/Auth/UserProvider.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Broadcasting\\Broadcaster' => $vendorDir . '/illuminate/contracts/Broadcasting/Broadcaster.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Broadcasting\\Factory' => $vendorDir . '/illuminate/contracts/Broadcasting/Factory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Broadcasting\\HasBroadcastChannel' => $vendorDir . '/illuminate/contracts/Broadcasting/HasBroadcastChannel.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Broadcasting\\ShouldBeUnique' => $vendorDir . '/illuminate/contracts/Broadcasting/ShouldBeUnique.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Broadcasting\\ShouldBroadcast' => $vendorDir . '/illuminate/contracts/Broadcasting/ShouldBroadcast.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Broadcasting\\ShouldBroadcastNow' => $vendorDir . '/illuminate/contracts/Broadcasting/ShouldBroadcastNow.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Bus\\Dispatcher' => $vendorDir . '/illuminate/contracts/Bus/Dispatcher.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Bus\\QueueingDispatcher' => $vendorDir . '/illuminate/contracts/Bus/QueueingDispatcher.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Cache\\Factory' => $vendorDir . '/illuminate/contracts/Cache/Factory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Cache\\Lock' => $vendorDir . '/illuminate/contracts/Cache/Lock.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Cache\\LockProvider' => $vendorDir . '/illuminate/contracts/Cache/LockProvider.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Cache\\LockTimeoutException' => $vendorDir . '/illuminate/contracts/Cache/LockTimeoutException.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Cache\\Repository' => $vendorDir . '/illuminate/contracts/Cache/Repository.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Cache\\Store' => $vendorDir . '/illuminate/contracts/Cache/Store.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Config\\Repository' => $vendorDir . '/illuminate/contracts/Config/Repository.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Console\\Application' => $vendorDir . '/illuminate/contracts/Console/Application.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Console\\Isolatable' => $vendorDir . '/illuminate/contracts/Console/Isolatable.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Console\\Kernel' => $vendorDir . '/illuminate/contracts/Console/Kernel.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Console\\PromptsForMissingInput' => $vendorDir . '/illuminate/contracts/Console/PromptsForMissingInput.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Container\\BindingResolutionException' => $vendorDir . '/illuminate/contracts/Container/BindingResolutionException.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Container\\CircularDependencyException' => $vendorDir . '/illuminate/contracts/Container/CircularDependencyException.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Container\\Container' => $vendorDir . '/illuminate/contracts/Container/Container.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Container\\ContextualBindingBuilder' => $vendorDir . '/illuminate/contracts/Container/ContextualBindingBuilder.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Cookie\\Factory' => $vendorDir . '/illuminate/contracts/Cookie/Factory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Cookie\\QueueingFactory' => $vendorDir . '/illuminate/contracts/Cookie/QueueingFactory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Database\\Eloquent\\Builder' => $vendorDir . '/illuminate/contracts/Database/Eloquent/Builder.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Database\\Eloquent\\Castable' => $vendorDir . '/illuminate/contracts/Database/Eloquent/Castable.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Database\\Eloquent\\CastsAttributes' => $vendorDir . '/illuminate/contracts/Database/Eloquent/CastsAttributes.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Database\\Eloquent\\CastsInboundAttributes' => $vendorDir . '/illuminate/contracts/Database/Eloquent/CastsInboundAttributes.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Database\\Eloquent\\DeviatesCastableAttributes' => $vendorDir . '/illuminate/contracts/Database/Eloquent/DeviatesCastableAttributes.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Database\\Eloquent\\SerializesCastableAttributes' => $vendorDir . '/illuminate/contracts/Database/Eloquent/SerializesCastableAttributes.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Database\\Eloquent\\SupportsPartialRelations' => $vendorDir . '/illuminate/contracts/Database/Eloquent/SupportsPartialRelations.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Database\\Events\\MigrationEvent' => $vendorDir . '/illuminate/contracts/Database/Events/MigrationEvent.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Database\\ModelIdentifier' => $vendorDir . '/illuminate/contracts/Database/ModelIdentifier.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Database\\Query\\Builder' => $vendorDir . '/illuminate/contracts/Database/Query/Builder.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Database\\Query\\ConditionExpression' => $vendorDir . '/illuminate/contracts/Database/Query/ConditionExpression.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Database\\Query\\Expression' => $vendorDir . '/illuminate/contracts/Database/Query/Expression.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Debug\\ExceptionHandler' => $vendorDir . '/illuminate/contracts/Debug/ExceptionHandler.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Encryption\\DecryptException' => $vendorDir . '/illuminate/contracts/Encryption/DecryptException.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Encryption\\EncryptException' => $vendorDir . '/illuminate/contracts/Encryption/EncryptException.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Encryption\\Encrypter' => $vendorDir . '/illuminate/contracts/Encryption/Encrypter.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Encryption\\StringEncrypter' => $vendorDir . '/illuminate/contracts/Encryption/StringEncrypter.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Events\\Dispatcher' => $vendorDir . '/illuminate/contracts/Events/Dispatcher.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Events\\ShouldDispatchAfterCommit' => $vendorDir . '/illuminate/contracts/Events/ShouldDispatchAfterCommit.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Events\\ShouldHandleEventsAfterCommit' => $vendorDir . '/illuminate/contracts/Events/ShouldHandleEventsAfterCommit.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Filesystem\\Cloud' => $vendorDir . '/illuminate/contracts/Filesystem/Cloud.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Filesystem\\Factory' => $vendorDir . '/illuminate/contracts/Filesystem/Factory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Filesystem\\FileNotFoundException' => $vendorDir . '/illuminate/contracts/Filesystem/FileNotFoundException.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Filesystem\\Filesystem' => $vendorDir . '/illuminate/contracts/Filesystem/Filesystem.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Filesystem\\LockTimeoutException' => $vendorDir . '/illuminate/contracts/Filesystem/LockTimeoutException.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Foundation\\Application' => $vendorDir . '/illuminate/contracts/Foundation/Application.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Foundation\\CachesConfiguration' => $vendorDir . '/illuminate/contracts/Foundation/CachesConfiguration.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Foundation\\CachesRoutes' => $vendorDir . '/illuminate/contracts/Foundation/CachesRoutes.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Foundation\\ExceptionRenderer' => $vendorDir . '/illuminate/contracts/Foundation/ExceptionRenderer.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Foundation\\MaintenanceMode' => $vendorDir . '/illuminate/contracts/Foundation/MaintenanceMode.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Hashing\\Hasher' => $vendorDir . '/illuminate/contracts/Hashing/Hasher.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Http\\Kernel' => $vendorDir . '/illuminate/contracts/Http/Kernel.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Mail\\Attachable' => $vendorDir . '/illuminate/contracts/Mail/Attachable.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Mail\\Factory' => $vendorDir . '/illuminate/contracts/Mail/Factory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Mail\\MailQueue' => $vendorDir . '/illuminate/contracts/Mail/MailQueue.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Mail\\Mailable' => $vendorDir . '/illuminate/contracts/Mail/Mailable.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Mail\\Mailer' => $vendorDir . '/illuminate/contracts/Mail/Mailer.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Notifications\\Dispatcher' => $vendorDir . '/illuminate/contracts/Notifications/Dispatcher.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Notifications\\Factory' => $vendorDir . '/illuminate/contracts/Notifications/Factory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Pagination\\CursorPaginator' => $vendorDir . '/illuminate/contracts/Pagination/CursorPaginator.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Pagination\\LengthAwarePaginator' => $vendorDir . '/illuminate/contracts/Pagination/LengthAwarePaginator.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Pagination\\Paginator' => $vendorDir . '/illuminate/contracts/Pagination/Paginator.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Pipeline\\Hub' => $vendorDir . '/illuminate/contracts/Pipeline/Hub.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Pipeline\\Pipeline' => $vendorDir . '/illuminate/contracts/Pipeline/Pipeline.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Process\\InvokedProcess' => $vendorDir . '/illuminate/contracts/Process/InvokedProcess.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Process\\ProcessResult' => $vendorDir . '/illuminate/contracts/Process/ProcessResult.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\ClearableQueue' => $vendorDir . '/illuminate/contracts/Queue/ClearableQueue.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\EntityNotFoundException' => $vendorDir . '/illuminate/contracts/Queue/EntityNotFoundException.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\EntityResolver' => $vendorDir . '/illuminate/contracts/Queue/EntityResolver.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\Factory' => $vendorDir . '/illuminate/contracts/Queue/Factory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\Job' => $vendorDir . '/illuminate/contracts/Queue/Job.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\Monitor' => $vendorDir . '/illuminate/contracts/Queue/Monitor.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\Queue' => $vendorDir . '/illuminate/contracts/Queue/Queue.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\QueueableCollection' => $vendorDir . '/illuminate/contracts/Queue/QueueableCollection.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\QueueableEntity' => $vendorDir . '/illuminate/contracts/Queue/QueueableEntity.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\ShouldBeEncrypted' => $vendorDir . '/illuminate/contracts/Queue/ShouldBeEncrypted.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\ShouldBeUnique' => $vendorDir . '/illuminate/contracts/Queue/ShouldBeUnique.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\ShouldBeUniqueUntilProcessing' => $vendorDir . '/illuminate/contracts/Queue/ShouldBeUniqueUntilProcessing.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\ShouldQueue' => $vendorDir . '/illuminate/contracts/Queue/ShouldQueue.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\ShouldQueueAfterCommit' => $vendorDir . '/illuminate/contracts/Queue/ShouldQueueAfterCommit.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Redis\\Connection' => $vendorDir . '/illuminate/contracts/Redis/Connection.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Redis\\Connector' => $vendorDir . '/illuminate/contracts/Redis/Connector.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Redis\\Factory' => $vendorDir . '/illuminate/contracts/Redis/Factory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Redis\\LimiterTimeoutException' => $vendorDir . '/illuminate/contracts/Redis/LimiterTimeoutException.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Routing\\BindingRegistrar' => $vendorDir . '/illuminate/contracts/Routing/BindingRegistrar.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Routing\\Registrar' => $vendorDir . '/illuminate/contracts/Routing/Registrar.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Routing\\ResponseFactory' => $vendorDir . '/illuminate/contracts/Routing/ResponseFactory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Routing\\UrlGenerator' => $vendorDir . '/illuminate/contracts/Routing/UrlGenerator.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Routing\\UrlRoutable' => $vendorDir . '/illuminate/contracts/Routing/UrlRoutable.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Session\\Middleware\\AuthenticatesSessions' => $vendorDir . '/illuminate/contracts/Session/Middleware/AuthenticatesSessions.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Session\\Session' => $vendorDir . '/illuminate/contracts/Session/Session.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Support\\Arrayable' => $vendorDir . '/illuminate/contracts/Support/Arrayable.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Support\\CanBeEscapedWhenCastToString' => $vendorDir . '/illuminate/contracts/Support/CanBeEscapedWhenCastToString.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Support\\DeferrableProvider' => $vendorDir . '/illuminate/contracts/Support/DeferrableProvider.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Support\\DeferringDisplayableValue' => $vendorDir . '/illuminate/contracts/Support/DeferringDisplayableValue.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Support\\Htmlable' => $vendorDir . '/illuminate/contracts/Support/Htmlable.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Support\\Jsonable' => $vendorDir . '/illuminate/contracts/Support/Jsonable.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Support\\MessageBag' => $vendorDir . '/illuminate/contracts/Support/MessageBag.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Support\\MessageProvider' => $vendorDir . '/illuminate/contracts/Support/MessageProvider.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Support\\Renderable' => $vendorDir . '/illuminate/contracts/Support/Renderable.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Support\\Responsable' => $vendorDir . '/illuminate/contracts/Support/Responsable.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Support\\ValidatedData' => $vendorDir . '/illuminate/contracts/Support/ValidatedData.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Translation\\HasLocalePreference' => $vendorDir . '/illuminate/contracts/Translation/HasLocalePreference.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Translation\\Loader' => $vendorDir . '/illuminate/contracts/Translation/Loader.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Translation\\Translator' => $vendorDir . '/illuminate/contracts/Translation/Translator.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Validation\\DataAwareRule' => $vendorDir . '/illuminate/contracts/Validation/DataAwareRule.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Validation\\Factory' => $vendorDir . '/illuminate/contracts/Validation/Factory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Validation\\ImplicitRule' => $vendorDir . '/illuminate/contracts/Validation/ImplicitRule.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Validation\\InvokableRule' => $vendorDir . '/illuminate/contracts/Validation/InvokableRule.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Validation\\Rule' => $vendorDir . '/illuminate/contracts/Validation/Rule.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Validation\\UncompromisedVerifier' => $vendorDir . '/illuminate/contracts/Validation/UncompromisedVerifier.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Validation\\ValidatesWhenResolved' => $vendorDir . '/illuminate/contracts/Validation/ValidatesWhenResolved.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Validation\\ValidationRule' => $vendorDir . '/illuminate/contracts/Validation/ValidationRule.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Validation\\Validator' => $vendorDir . '/illuminate/contracts/Validation/Validator.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Validation\\ValidatorAwareRule' => $vendorDir . '/illuminate/contracts/Validation/ValidatorAwareRule.php', + 'SwissKnife202405\\Illuminate\\Contracts\\View\\Engine' => $vendorDir . '/illuminate/contracts/View/Engine.php', + 'SwissKnife202405\\Illuminate\\Contracts\\View\\Factory' => $vendorDir . '/illuminate/contracts/View/Factory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\View\\View' => $vendorDir . '/illuminate/contracts/View/View.php', + 'SwissKnife202405\\Illuminate\\Contracts\\View\\ViewCompilationException' => $vendorDir . '/illuminate/contracts/View/ViewCompilationException.php', + 'SwissKnife202405\\Nette\\ArgumentOutOfRangeException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'SwissKnife202405\\Nette\\DeprecatedException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'SwissKnife202405\\Nette\\DirectoryNotFoundException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'SwissKnife202405\\Nette\\FileNotFoundException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'SwissKnife202405\\Nette\\HtmlStringable' => $vendorDir . '/nette/utils/src/HtmlStringable.php', + 'SwissKnife202405\\Nette\\IOException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'SwissKnife202405\\Nette\\InvalidArgumentException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'SwissKnife202405\\Nette\\InvalidStateException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'SwissKnife202405\\Nette\\Iterators\\CachingIterator' => $vendorDir . '/nette/utils/src/Iterators/CachingIterator.php', + 'SwissKnife202405\\Nette\\Iterators\\Mapper' => $vendorDir . '/nette/utils/src/Iterators/Mapper.php', + 'SwissKnife202405\\Nette\\Loaders\\RobotLoader' => $vendorDir . '/nette/robot-loader/src/RobotLoader/RobotLoader.php', + 'SwissKnife202405\\Nette\\Localization\\ITranslator' => $vendorDir . '/nette/utils/src/compatibility.php', + 'SwissKnife202405\\Nette\\Localization\\Translator' => $vendorDir . '/nette/utils/src/Translator.php', + 'SwissKnife202405\\Nette\\MemberAccessException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'SwissKnife202405\\Nette\\NotImplementedException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'SwissKnife202405\\Nette\\NotSupportedException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'SwissKnife202405\\Nette\\OutOfRangeException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'SwissKnife202405\\Nette\\SmartObject' => $vendorDir . '/nette/utils/src/SmartObject.php', + 'SwissKnife202405\\Nette\\StaticClass' => $vendorDir . '/nette/utils/src/StaticClass.php', + 'SwissKnife202405\\Nette\\UnexpectedValueException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'SwissKnife202405\\Nette\\Utils\\ArrayHash' => $vendorDir . '/nette/utils/src/Utils/ArrayHash.php', + 'SwissKnife202405\\Nette\\Utils\\ArrayList' => $vendorDir . '/nette/utils/src/Utils/ArrayList.php', + 'SwissKnife202405\\Nette\\Utils\\Arrays' => $vendorDir . '/nette/utils/src/Utils/Arrays.php', + 'SwissKnife202405\\Nette\\Utils\\AssertionException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php', + 'SwissKnife202405\\Nette\\Utils\\Callback' => $vendorDir . '/nette/utils/src/Utils/Callback.php', + 'SwissKnife202405\\Nette\\Utils\\DateTime' => $vendorDir . '/nette/utils/src/Utils/DateTime.php', + 'SwissKnife202405\\Nette\\Utils\\FileSystem' => $vendorDir . '/nette/utils/src/Utils/FileSystem.php', + 'SwissKnife202405\\Nette\\Utils\\Finder' => $vendorDir . '/nette/finder/src/Utils/Finder.php', + 'SwissKnife202405\\Nette\\Utils\\Floats' => $vendorDir . '/nette/utils/src/Utils/Floats.php', + 'SwissKnife202405\\Nette\\Utils\\Helpers' => $vendorDir . '/nette/utils/src/Utils/Helpers.php', + 'SwissKnife202405\\Nette\\Utils\\Html' => $vendorDir . '/nette/utils/src/Utils/Html.php', + 'SwissKnife202405\\Nette\\Utils\\IHtmlString' => $vendorDir . '/nette/utils/src/compatibility.php', + 'SwissKnife202405\\Nette\\Utils\\Image' => $vendorDir . '/nette/utils/src/Utils/Image.php', + 'SwissKnife202405\\Nette\\Utils\\ImageException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php', + 'SwissKnife202405\\Nette\\Utils\\Json' => $vendorDir . '/nette/utils/src/Utils/Json.php', + 'SwissKnife202405\\Nette\\Utils\\JsonException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php', + 'SwissKnife202405\\Nette\\Utils\\ObjectHelpers' => $vendorDir . '/nette/utils/src/Utils/ObjectHelpers.php', + 'SwissKnife202405\\Nette\\Utils\\ObjectMixin' => $vendorDir . '/nette/utils/src/Utils/ObjectMixin.php', + 'SwissKnife202405\\Nette\\Utils\\Paginator' => $vendorDir . '/nette/utils/src/Utils/Paginator.php', + 'SwissKnife202405\\Nette\\Utils\\Random' => $vendorDir . '/nette/utils/src/Utils/Random.php', + 'SwissKnife202405\\Nette\\Utils\\Reflection' => $vendorDir . '/nette/utils/src/Utils/Reflection.php', + 'SwissKnife202405\\Nette\\Utils\\RegexpException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php', + 'SwissKnife202405\\Nette\\Utils\\Strings' => $vendorDir . '/nette/utils/src/Utils/Strings.php', + 'SwissKnife202405\\Nette\\Utils\\Type' => $vendorDir . '/nette/utils/src/Utils/Type.php', + 'SwissKnife202405\\Nette\\Utils\\UnknownImageFileException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php', + 'SwissKnife202405\\Nette\\Utils\\Validators' => $vendorDir . '/nette/utils/src/Utils/Validators.php', + 'SwissKnife202405\\PhpParser\\Builder' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder.php', + 'SwissKnife202405\\PhpParser\\BuilderFactory' => $vendorDir . '/nikic/php-parser/lib/PhpParser/BuilderFactory.php', + 'SwissKnife202405\\PhpParser\\BuilderHelpers' => $vendorDir . '/nikic/php-parser/lib/PhpParser/BuilderHelpers.php', + 'SwissKnife202405\\PhpParser\\Builder\\ClassConst' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/ClassConst.php', + 'SwissKnife202405\\PhpParser\\Builder\\Class_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/Class_.php', + 'SwissKnife202405\\PhpParser\\Builder\\Declaration' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/Declaration.php', + 'SwissKnife202405\\PhpParser\\Builder\\EnumCase' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/EnumCase.php', + 'SwissKnife202405\\PhpParser\\Builder\\Enum_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/Enum_.php', + 'SwissKnife202405\\PhpParser\\Builder\\FunctionLike' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/FunctionLike.php', + 'SwissKnife202405\\PhpParser\\Builder\\Function_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/Function_.php', + 'SwissKnife202405\\PhpParser\\Builder\\Interface_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/Interface_.php', + 'SwissKnife202405\\PhpParser\\Builder\\Method' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/Method.php', + 'SwissKnife202405\\PhpParser\\Builder\\Namespace_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/Namespace_.php', + 'SwissKnife202405\\PhpParser\\Builder\\Param' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/Param.php', + 'SwissKnife202405\\PhpParser\\Builder\\Property' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/Property.php', + 'SwissKnife202405\\PhpParser\\Builder\\TraitUse' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/TraitUse.php', + 'SwissKnife202405\\PhpParser\\Builder\\TraitUseAdaptation' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/TraitUseAdaptation.php', + 'SwissKnife202405\\PhpParser\\Builder\\Trait_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/Trait_.php', + 'SwissKnife202405\\PhpParser\\Builder\\Use_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Builder/Use_.php', + 'SwissKnife202405\\PhpParser\\Comment' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Comment.php', + 'SwissKnife202405\\PhpParser\\Comment\\Doc' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Comment/Doc.php', + 'SwissKnife202405\\PhpParser\\ConstExprEvaluationException' => $vendorDir . '/nikic/php-parser/lib/PhpParser/ConstExprEvaluationException.php', + 'SwissKnife202405\\PhpParser\\ConstExprEvaluator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/ConstExprEvaluator.php', + 'SwissKnife202405\\PhpParser\\Error' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Error.php', + 'SwissKnife202405\\PhpParser\\ErrorHandler' => $vendorDir . '/nikic/php-parser/lib/PhpParser/ErrorHandler.php', + 'SwissKnife202405\\PhpParser\\ErrorHandler\\Collecting' => $vendorDir . '/nikic/php-parser/lib/PhpParser/ErrorHandler/Collecting.php', + 'SwissKnife202405\\PhpParser\\ErrorHandler\\Throwing' => $vendorDir . '/nikic/php-parser/lib/PhpParser/ErrorHandler/Throwing.php', + 'SwissKnife202405\\PhpParser\\Internal\\DiffElem' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Internal/DiffElem.php', + 'SwissKnife202405\\PhpParser\\Internal\\Differ' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Internal/Differ.php', + 'SwissKnife202405\\PhpParser\\Internal\\PrintableNewAnonClassNode' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Internal/PrintableNewAnonClassNode.php', + 'SwissKnife202405\\PhpParser\\Internal\\TokenStream' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Internal/TokenStream.php', + 'SwissKnife202405\\PhpParser\\JsonDecoder' => $vendorDir . '/nikic/php-parser/lib/PhpParser/JsonDecoder.php', + 'SwissKnife202405\\PhpParser\\Lexer' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer.php', + 'SwissKnife202405\\PhpParser\\Lexer\\Emulative' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/Emulative.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\AttributeEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/AttributeEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\CoaleseEqualTokenEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/CoaleseEqualTokenEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\EnumTokenEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/EnumTokenEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\ExplicitOctalEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ExplicitOctalEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\FlexibleDocStringEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/FlexibleDocStringEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\FnTokenEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/FnTokenEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\KeywordEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/KeywordEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\MatchTokenEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/MatchTokenEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\NullsafeTokenEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/NullsafeTokenEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\NumericLiteralSeparatorEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/NumericLiteralSeparatorEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\ReadonlyFunctionTokenEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReadonlyFunctionTokenEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\ReadonlyTokenEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReadonlyTokenEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\ReverseEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReverseEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\TokenEmulator' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/TokenEmulator.php', + 'SwissKnife202405\\PhpParser\\NameContext' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NameContext.php', + 'SwissKnife202405\\PhpParser\\Node' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node.php', + 'SwissKnife202405\\PhpParser\\NodeAbstract' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeAbstract.php', + 'SwissKnife202405\\PhpParser\\NodeDumper' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeDumper.php', + 'SwissKnife202405\\PhpParser\\NodeFinder' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeFinder.php', + 'SwissKnife202405\\PhpParser\\NodeTraverser' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeTraverser.php', + 'SwissKnife202405\\PhpParser\\NodeTraverserInterface' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeTraverserInterface.php', + 'SwissKnife202405\\PhpParser\\NodeVisitor' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeVisitor.php', + 'SwissKnife202405\\PhpParser\\NodeVisitorAbstract' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeVisitorAbstract.php', + 'SwissKnife202405\\PhpParser\\NodeVisitor\\CloningVisitor' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeVisitor/CloningVisitor.php', + 'SwissKnife202405\\PhpParser\\NodeVisitor\\FindingVisitor' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeVisitor/FindingVisitor.php', + 'SwissKnife202405\\PhpParser\\NodeVisitor\\FirstFindingVisitor' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeVisitor/FirstFindingVisitor.php', + 'SwissKnife202405\\PhpParser\\NodeVisitor\\NameResolver' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeVisitor/NameResolver.php', + 'SwissKnife202405\\PhpParser\\NodeVisitor\\NodeConnectingVisitor' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeVisitor/NodeConnectingVisitor.php', + 'SwissKnife202405\\PhpParser\\NodeVisitor\\ParentConnectingVisitor' => $vendorDir . '/nikic/php-parser/lib/PhpParser/NodeVisitor/ParentConnectingVisitor.php', + 'SwissKnife202405\\PhpParser\\Node\\Arg' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Arg.php', + 'SwissKnife202405\\PhpParser\\Node\\Attribute' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Attribute.php', + 'SwissKnife202405\\PhpParser\\Node\\AttributeGroup' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/AttributeGroup.php', + 'SwissKnife202405\\PhpParser\\Node\\ComplexType' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/ComplexType.php', + 'SwissKnife202405\\PhpParser\\Node\\Const_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Const_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\ArrayDimFetch' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayDimFetch.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\ArrayItem' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayItem.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Array_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Array_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\ArrowFunction' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/ArrowFunction.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Assign' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Assign.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseOr.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseXor.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\Coalesce' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Coalesce.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\Concat' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Concat.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\Div' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Div.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\Minus' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Minus.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\Mod' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Mod.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\Mul' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Mul.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\Plus' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Plus.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\Pow' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Pow.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/ShiftLeft.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/ShiftRight.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignRef' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignRef.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseOr.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseXor.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BooleanAnd.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BooleanOr.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Coalesce' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Coalesce.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Concat' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Concat.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Div' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Div.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Equal' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Equal.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Greater' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Greater.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Identical' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Identical.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/LogicalAnd.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/LogicalOr.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/LogicalXor.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Minus' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Minus.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Mod' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Mod.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Mul' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Mul.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/NotEqual.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/NotIdentical.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Plus' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Plus.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Pow' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Pow.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/ShiftLeft.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/ShiftRight.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Smaller.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Spaceship' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Spaceship.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BitwiseNot' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BitwiseNot.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BooleanNot' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/BooleanNot.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\CallLike' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/CallLike.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Cast' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Cast\\Array_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Array_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Cast\\Bool_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Bool_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Cast\\Double' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Double.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Cast\\Int_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Int_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Cast\\Object_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Object_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Cast\\String_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/String_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Cast\\Unset_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Unset_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\ClassConstFetch' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/ClassConstFetch.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Clone_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Clone_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Closure' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Closure.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\ClosureUse' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/ClosureUse.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\ConstFetch' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/ConstFetch.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Empty_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Empty_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Error' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Error.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\ErrorSuppress' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/ErrorSuppress.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Eval_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Eval_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Exit_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Exit_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\FuncCall' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/FuncCall.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Include_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Include_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Instanceof_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Instanceof_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Isset_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Isset_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\List_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/List_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Match_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Match_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\MethodCall' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/MethodCall.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\New_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/New_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\NullsafeMethodCall' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/NullsafeMethodCall.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\NullsafePropertyFetch' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/NullsafePropertyFetch.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\PostDec' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/PostDec.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\PostInc' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/PostInc.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\PreDec' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/PreDec.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\PreInc' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/PreInc.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Print_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Print_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\PropertyFetch' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/PropertyFetch.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\ShellExec' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/ShellExec.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\StaticCall' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/StaticCall.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\StaticPropertyFetch' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/StaticPropertyFetch.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Ternary' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Ternary.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Throw_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Throw_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\UnaryMinus' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/UnaryMinus.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\UnaryPlus' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/UnaryPlus.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Variable' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Variable.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\YieldFrom' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/YieldFrom.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Yield_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Expr/Yield_.php', + 'SwissKnife202405\\PhpParser\\Node\\FunctionLike' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/FunctionLike.php', + 'SwissKnife202405\\PhpParser\\Node\\Identifier' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Identifier.php', + 'SwissKnife202405\\PhpParser\\Node\\IntersectionType' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/IntersectionType.php', + 'SwissKnife202405\\PhpParser\\Node\\MatchArm' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/MatchArm.php', + 'SwissKnife202405\\PhpParser\\Node\\Name' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Name.php', + 'SwissKnife202405\\PhpParser\\Node\\Name\\FullyQualified' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Name/FullyQualified.php', + 'SwissKnife202405\\PhpParser\\Node\\Name\\Relative' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Name/Relative.php', + 'SwissKnife202405\\PhpParser\\Node\\NullableType' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/NullableType.php', + 'SwissKnife202405\\PhpParser\\Node\\Param' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Param.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\DNumber' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/DNumber.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\Encapsed' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/Encapsed.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\EncapsedStringPart' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/EncapsedStringPart.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\LNumber' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/LNumber.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\MagicConst' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\MagicConst\\Class_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Class_.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\MagicConst\\Dir' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Dir.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\MagicConst\\File' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/File.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\MagicConst\\Function_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Function_.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\MagicConst\\Line' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Line.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\MagicConst\\Method' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Method.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Trait_.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\String_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Scalar/String_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Break_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Break_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Case_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Case_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Catch_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Catch_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\ClassConst' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassConst.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\ClassLike' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassLike.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\ClassMethod' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassMethod.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Class_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Class_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Const_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Const_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Continue_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Continue_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\DeclareDeclare' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/DeclareDeclare.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Declare_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Declare_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Do_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Do_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Echo_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Echo_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\ElseIf_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/ElseIf_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Else_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Else_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\EnumCase' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/EnumCase.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Enum_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Enum_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Expression' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Expression.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Finally_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Finally_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\For_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/For_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Foreach_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Foreach_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Function_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Function_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Global_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Global_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Goto_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Goto_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\GroupUse' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/GroupUse.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\HaltCompiler' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/HaltCompiler.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\If_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/If_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\InlineHTML' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/InlineHTML.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Interface_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Interface_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Label' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Label.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Namespace_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Namespace_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Nop' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Nop.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Property' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Property.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\PropertyProperty' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/PropertyProperty.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Return_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Return_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\StaticVar' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/StaticVar.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Static_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Static_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Switch_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Switch_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Throw_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Throw_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\TraitUse' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUse.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\TraitUseAdaptation' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\TraitUseAdaptation\\Alias' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\TraitUseAdaptation\\Precedence' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Trait_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Trait_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\TryCatch' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/TryCatch.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Unset_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Unset_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\UseUse' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/UseUse.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Use_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Use_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\While_' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/Stmt/While_.php', + 'SwissKnife202405\\PhpParser\\Node\\UnionType' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/UnionType.php', + 'SwissKnife202405\\PhpParser\\Node\\VarLikeIdentifier' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/VarLikeIdentifier.php', + 'SwissKnife202405\\PhpParser\\Node\\VariadicPlaceholder' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Node/VariadicPlaceholder.php', + 'SwissKnife202405\\PhpParser\\Parser' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Parser.php', + 'SwissKnife202405\\PhpParser\\ParserAbstract' => $vendorDir . '/nikic/php-parser/lib/PhpParser/ParserAbstract.php', + 'SwissKnife202405\\PhpParser\\ParserFactory' => $vendorDir . '/nikic/php-parser/lib/PhpParser/ParserFactory.php', + 'SwissKnife202405\\PhpParser\\Parser\\Multiple' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Parser/Multiple.php', + 'SwissKnife202405\\PhpParser\\Parser\\Php5' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Parser/Php5.php', + 'SwissKnife202405\\PhpParser\\Parser\\Php7' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Parser/Php7.php', + 'SwissKnife202405\\PhpParser\\Parser\\Tokens' => $vendorDir . '/nikic/php-parser/lib/PhpParser/Parser/Tokens.php', + 'SwissKnife202405\\PhpParser\\PrettyPrinterAbstract' => $vendorDir . '/nikic/php-parser/lib/PhpParser/PrettyPrinterAbstract.php', + 'SwissKnife202405\\PhpParser\\PrettyPrinter\\Standard' => $vendorDir . '/nikic/php-parser/lib/PhpParser/PrettyPrinter/Standard.php', + 'SwissKnife202405\\Psr\\Container\\ContainerExceptionInterface' => $vendorDir . '/psr/container/src/ContainerExceptionInterface.php', + 'SwissKnife202405\\Psr\\Container\\ContainerInterface' => $vendorDir . '/psr/container/src/ContainerInterface.php', + 'SwissKnife202405\\Psr\\Container\\NotFoundExceptionInterface' => $vendorDir . '/psr/container/src/NotFoundExceptionInterface.php', + 'SwissKnife202405\\Psr\\SimpleCache\\CacheException' => $vendorDir . '/psr/simple-cache/src/CacheException.php', + 'SwissKnife202405\\Psr\\SimpleCache\\CacheInterface' => $vendorDir . '/psr/simple-cache/src/CacheInterface.php', + 'SwissKnife202405\\Psr\\SimpleCache\\InvalidArgumentException' => $vendorDir . '/psr/simple-cache/src/InvalidArgumentException.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Application' => $vendorDir . '/symfony/console/Application.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Attribute\\AsCommand' => $vendorDir . '/symfony/console/Attribute/AsCommand.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\CI\\GithubActionReporter' => $vendorDir . '/symfony/console/CI/GithubActionReporter.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Color' => $vendorDir . '/symfony/console/Color.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\CommandLoader\\CommandLoaderInterface' => $vendorDir . '/symfony/console/CommandLoader/CommandLoaderInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\CommandLoader\\ContainerCommandLoader' => $vendorDir . '/symfony/console/CommandLoader/ContainerCommandLoader.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\CommandLoader\\FactoryCommandLoader' => $vendorDir . '/symfony/console/CommandLoader/FactoryCommandLoader.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Command\\Command' => $vendorDir . '/symfony/console/Command/Command.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Command\\CompleteCommand' => $vendorDir . '/symfony/console/Command/CompleteCommand.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Command\\DumpCompletionCommand' => $vendorDir . '/symfony/console/Command/DumpCompletionCommand.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Command\\HelpCommand' => $vendorDir . '/symfony/console/Command/HelpCommand.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Command\\LazyCommand' => $vendorDir . '/symfony/console/Command/LazyCommand.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Command\\ListCommand' => $vendorDir . '/symfony/console/Command/ListCommand.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Command\\LockableTrait' => $vendorDir . '/symfony/console/Command/LockableTrait.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Command\\SignalableCommandInterface' => $vendorDir . '/symfony/console/Command/SignalableCommandInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Command\\TraceableCommand' => $vendorDir . '/symfony/console/Command/TraceableCommand.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Completion\\CompletionInput' => $vendorDir . '/symfony/console/Completion/CompletionInput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Completion\\CompletionSuggestions' => $vendorDir . '/symfony/console/Completion/CompletionSuggestions.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Completion\\Output\\BashCompletionOutput' => $vendorDir . '/symfony/console/Completion/Output/BashCompletionOutput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Completion\\Output\\CompletionOutputInterface' => $vendorDir . '/symfony/console/Completion/Output/CompletionOutputInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Completion\\Output\\FishCompletionOutput' => $vendorDir . '/symfony/console/Completion/Output/FishCompletionOutput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Completion\\Output\\ZshCompletionOutput' => $vendorDir . '/symfony/console/Completion/Output/ZshCompletionOutput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Completion\\Suggestion' => $vendorDir . '/symfony/console/Completion/Suggestion.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\ConsoleEvents' => $vendorDir . '/symfony/console/ConsoleEvents.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Cursor' => $vendorDir . '/symfony/console/Cursor.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\DataCollector\\CommandDataCollector' => $vendorDir . '/symfony/console/DataCollector/CommandDataCollector.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Debug\\CliRequest' => $vendorDir . '/symfony/console/Debug/CliRequest.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\DependencyInjection\\AddConsoleCommandPass' => $vendorDir . '/symfony/console/DependencyInjection/AddConsoleCommandPass.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Descriptor\\ApplicationDescription' => $vendorDir . '/symfony/console/Descriptor/ApplicationDescription.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Descriptor\\Descriptor' => $vendorDir . '/symfony/console/Descriptor/Descriptor.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Descriptor\\DescriptorInterface' => $vendorDir . '/symfony/console/Descriptor/DescriptorInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Descriptor\\JsonDescriptor' => $vendorDir . '/symfony/console/Descriptor/JsonDescriptor.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Descriptor\\MarkdownDescriptor' => $vendorDir . '/symfony/console/Descriptor/MarkdownDescriptor.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Descriptor\\ReStructuredTextDescriptor' => $vendorDir . '/symfony/console/Descriptor/ReStructuredTextDescriptor.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Descriptor\\TextDescriptor' => $vendorDir . '/symfony/console/Descriptor/TextDescriptor.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Descriptor\\XmlDescriptor' => $vendorDir . '/symfony/console/Descriptor/XmlDescriptor.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\EventListener\\ErrorListener' => $vendorDir . '/symfony/console/EventListener/ErrorListener.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Event\\ConsoleCommandEvent' => $vendorDir . '/symfony/console/Event/ConsoleCommandEvent.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Event\\ConsoleErrorEvent' => $vendorDir . '/symfony/console/Event/ConsoleErrorEvent.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Event\\ConsoleEvent' => $vendorDir . '/symfony/console/Event/ConsoleEvent.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Event\\ConsoleSignalEvent' => $vendorDir . '/symfony/console/Event/ConsoleSignalEvent.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Event\\ConsoleTerminateEvent' => $vendorDir . '/symfony/console/Event/ConsoleTerminateEvent.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Exception\\CommandNotFoundException' => $vendorDir . '/symfony/console/Exception/CommandNotFoundException.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/console/Exception/ExceptionInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/console/Exception/InvalidArgumentException.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Exception\\InvalidOptionException' => $vendorDir . '/symfony/console/Exception/InvalidOptionException.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Exception\\LogicException' => $vendorDir . '/symfony/console/Exception/LogicException.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Exception\\MissingInputException' => $vendorDir . '/symfony/console/Exception/MissingInputException.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Exception\\NamespaceNotFoundException' => $vendorDir . '/symfony/console/Exception/NamespaceNotFoundException.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Exception\\RunCommandFailedException' => $vendorDir . '/symfony/console/Exception/RunCommandFailedException.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Exception\\RuntimeException' => $vendorDir . '/symfony/console/Exception/RuntimeException.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Formatter\\NullOutputFormatter' => $vendorDir . '/symfony/console/Formatter/NullOutputFormatter.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Formatter\\NullOutputFormatterStyle' => $vendorDir . '/symfony/console/Formatter/NullOutputFormatterStyle.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Formatter\\OutputFormatter' => $vendorDir . '/symfony/console/Formatter/OutputFormatter.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Formatter\\OutputFormatterInterface' => $vendorDir . '/symfony/console/Formatter/OutputFormatterInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Formatter\\OutputFormatterStyle' => $vendorDir . '/symfony/console/Formatter/OutputFormatterStyle.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Formatter\\OutputFormatterStyleInterface' => $vendorDir . '/symfony/console/Formatter/OutputFormatterStyleInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Formatter\\OutputFormatterStyleStack' => $vendorDir . '/symfony/console/Formatter/OutputFormatterStyleStack.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Formatter\\WrappableOutputFormatterInterface' => $vendorDir . '/symfony/console/Formatter/WrappableOutputFormatterInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\DebugFormatterHelper' => $vendorDir . '/symfony/console/Helper/DebugFormatterHelper.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\DescriptorHelper' => $vendorDir . '/symfony/console/Helper/DescriptorHelper.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\Dumper' => $vendorDir . '/symfony/console/Helper/Dumper.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\FormatterHelper' => $vendorDir . '/symfony/console/Helper/FormatterHelper.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\Helper' => $vendorDir . '/symfony/console/Helper/Helper.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\HelperInterface' => $vendorDir . '/symfony/console/Helper/HelperInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\HelperSet' => $vendorDir . '/symfony/console/Helper/HelperSet.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\InputAwareHelper' => $vendorDir . '/symfony/console/Helper/InputAwareHelper.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\OutputWrapper' => $vendorDir . '/symfony/console/Helper/OutputWrapper.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\ProcessHelper' => $vendorDir . '/symfony/console/Helper/ProcessHelper.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\ProgressBar' => $vendorDir . '/symfony/console/Helper/ProgressBar.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\ProgressIndicator' => $vendorDir . '/symfony/console/Helper/ProgressIndicator.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\QuestionHelper' => $vendorDir . '/symfony/console/Helper/QuestionHelper.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\SymfonyQuestionHelper' => $vendorDir . '/symfony/console/Helper/SymfonyQuestionHelper.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\Table' => $vendorDir . '/symfony/console/Helper/Table.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\TableCell' => $vendorDir . '/symfony/console/Helper/TableCell.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\TableCellStyle' => $vendorDir . '/symfony/console/Helper/TableCellStyle.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\TableRows' => $vendorDir . '/symfony/console/Helper/TableRows.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\TableSeparator' => $vendorDir . '/symfony/console/Helper/TableSeparator.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\TableStyle' => $vendorDir . '/symfony/console/Helper/TableStyle.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Input\\ArgvInput' => $vendorDir . '/symfony/console/Input/ArgvInput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Input\\ArrayInput' => $vendorDir . '/symfony/console/Input/ArrayInput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Input\\Input' => $vendorDir . '/symfony/console/Input/Input.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Input\\InputArgument' => $vendorDir . '/symfony/console/Input/InputArgument.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Input\\InputAwareInterface' => $vendorDir . '/symfony/console/Input/InputAwareInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Input\\InputDefinition' => $vendorDir . '/symfony/console/Input/InputDefinition.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Input\\InputInterface' => $vendorDir . '/symfony/console/Input/InputInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Input\\InputOption' => $vendorDir . '/symfony/console/Input/InputOption.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Input\\StreamableInputInterface' => $vendorDir . '/symfony/console/Input/StreamableInputInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Input\\StringInput' => $vendorDir . '/symfony/console/Input/StringInput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Logger\\ConsoleLogger' => $vendorDir . '/symfony/console/Logger/ConsoleLogger.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Messenger\\RunCommandContext' => $vendorDir . '/symfony/console/Messenger/RunCommandContext.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Messenger\\RunCommandMessage' => $vendorDir . '/symfony/console/Messenger/RunCommandMessage.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Messenger\\RunCommandMessageHandler' => $vendorDir . '/symfony/console/Messenger/RunCommandMessageHandler.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Output\\AnsiColorMode' => $vendorDir . '/symfony/console/Output/AnsiColorMode.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Output\\BufferedOutput' => $vendorDir . '/symfony/console/Output/BufferedOutput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Output\\ConsoleOutput' => $vendorDir . '/symfony/console/Output/ConsoleOutput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Output\\ConsoleOutputInterface' => $vendorDir . '/symfony/console/Output/ConsoleOutputInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Output\\ConsoleSectionOutput' => $vendorDir . '/symfony/console/Output/ConsoleSectionOutput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Output\\NullOutput' => $vendorDir . '/symfony/console/Output/NullOutput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Output\\Output' => $vendorDir . '/symfony/console/Output/Output.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Output\\OutputInterface' => $vendorDir . '/symfony/console/Output/OutputInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Output\\StreamOutput' => $vendorDir . '/symfony/console/Output/StreamOutput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Output\\TrimmedBufferOutput' => $vendorDir . '/symfony/console/Output/TrimmedBufferOutput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Question\\ChoiceQuestion' => $vendorDir . '/symfony/console/Question/ChoiceQuestion.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Question\\ConfirmationQuestion' => $vendorDir . '/symfony/console/Question/ConfirmationQuestion.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Question\\Question' => $vendorDir . '/symfony/console/Question/Question.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\SignalRegistry\\SignalMap' => $vendorDir . '/symfony/console/SignalRegistry/SignalMap.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\SignalRegistry\\SignalRegistry' => $vendorDir . '/symfony/console/SignalRegistry/SignalRegistry.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\SingleCommandApplication' => $vendorDir . '/symfony/console/SingleCommandApplication.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Style\\OutputStyle' => $vendorDir . '/symfony/console/Style/OutputStyle.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Style\\StyleInterface' => $vendorDir . '/symfony/console/Style/StyleInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Style\\SymfonyStyle' => $vendorDir . '/symfony/console/Style/SymfonyStyle.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Terminal' => $vendorDir . '/symfony/console/Terminal.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Tester\\ApplicationTester' => $vendorDir . '/symfony/console/Tester/ApplicationTester.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Tester\\CommandCompletionTester' => $vendorDir . '/symfony/console/Tester/CommandCompletionTester.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Tester\\CommandTester' => $vendorDir . '/symfony/console/Tester/CommandTester.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Tester\\Constraint\\CommandIsSuccessful' => $vendorDir . '/symfony/console/Tester/Constraint/CommandIsSuccessful.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Tester\\TesterTrait' => $vendorDir . '/symfony/console/Tester/TesterTrait.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Comparator\\Comparator' => $vendorDir . '/symfony/finder/Comparator/Comparator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Comparator\\DateComparator' => $vendorDir . '/symfony/finder/Comparator/DateComparator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Comparator\\NumberComparator' => $vendorDir . '/symfony/finder/Comparator/NumberComparator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Exception\\AccessDeniedException' => $vendorDir . '/symfony/finder/Exception/AccessDeniedException.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Exception\\DirectoryNotFoundException' => $vendorDir . '/symfony/finder/Exception/DirectoryNotFoundException.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Finder' => $vendorDir . '/symfony/finder/Finder.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Gitignore' => $vendorDir . '/symfony/finder/Gitignore.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Glob' => $vendorDir . '/symfony/finder/Glob.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\CustomFilterIterator' => $vendorDir . '/symfony/finder/Iterator/CustomFilterIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\DateRangeFilterIterator' => $vendorDir . '/symfony/finder/Iterator/DateRangeFilterIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\DepthRangeFilterIterator' => $vendorDir . '/symfony/finder/Iterator/DepthRangeFilterIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\ExcludeDirectoryFilterIterator' => $vendorDir . '/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\FileTypeFilterIterator' => $vendorDir . '/symfony/finder/Iterator/FileTypeFilterIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\FilecontentFilterIterator' => $vendorDir . '/symfony/finder/Iterator/FilecontentFilterIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\FilenameFilterIterator' => $vendorDir . '/symfony/finder/Iterator/FilenameFilterIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\LazyIterator' => $vendorDir . '/symfony/finder/Iterator/LazyIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\MultiplePcreFilterIterator' => $vendorDir . '/symfony/finder/Iterator/MultiplePcreFilterIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\PathFilterIterator' => $vendorDir . '/symfony/finder/Iterator/PathFilterIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\RecursiveDirectoryIterator' => $vendorDir . '/symfony/finder/Iterator/RecursiveDirectoryIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\SizeRangeFilterIterator' => $vendorDir . '/symfony/finder/Iterator/SizeRangeFilterIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\SortableIterator' => $vendorDir . '/symfony/finder/Iterator/SortableIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\VcsIgnoredFilterIterator' => $vendorDir . '/symfony/finder/Iterator/VcsIgnoredFilterIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\SplFileInfo' => $vendorDir . '/symfony/finder/SplFileInfo.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/process/Exception/ExceptionInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/process/Exception/InvalidArgumentException.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Exception\\LogicException' => $vendorDir . '/symfony/process/Exception/LogicException.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Exception\\ProcessFailedException' => $vendorDir . '/symfony/process/Exception/ProcessFailedException.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Exception\\ProcessSignaledException' => $vendorDir . '/symfony/process/Exception/ProcessSignaledException.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Exception\\ProcessTimedOutException' => $vendorDir . '/symfony/process/Exception/ProcessTimedOutException.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Exception\\RunProcessFailedException' => $vendorDir . '/symfony/process/Exception/RunProcessFailedException.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Exception\\RuntimeException' => $vendorDir . '/symfony/process/Exception/RuntimeException.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\ExecutableFinder' => $vendorDir . '/symfony/process/ExecutableFinder.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\InputStream' => $vendorDir . '/symfony/process/InputStream.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Messenger\\RunProcessContext' => $vendorDir . '/symfony/process/Messenger/RunProcessContext.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Messenger\\RunProcessMessage' => $vendorDir . '/symfony/process/Messenger/RunProcessMessage.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Messenger\\RunProcessMessageHandler' => $vendorDir . '/symfony/process/Messenger/RunProcessMessageHandler.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\PhpExecutableFinder' => $vendorDir . '/symfony/process/PhpExecutableFinder.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\PhpProcess' => $vendorDir . '/symfony/process/PhpProcess.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\PhpSubprocess' => $vendorDir . '/symfony/process/PhpSubprocess.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Pipes\\AbstractPipes' => $vendorDir . '/symfony/process/Pipes/AbstractPipes.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Pipes\\PipesInterface' => $vendorDir . '/symfony/process/Pipes/PipesInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Pipes\\UnixPipes' => $vendorDir . '/symfony/process/Pipes/UnixPipes.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Pipes\\WindowsPipes' => $vendorDir . '/symfony/process/Pipes/WindowsPipes.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Process' => $vendorDir . '/symfony/process/Process.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\ProcessUtils' => $vendorDir . '/symfony/process/ProcessUtils.php', + 'SwissKnife202405\\Symfony\\Component\\String\\AbstractString' => $vendorDir . '/symfony/string/AbstractString.php', + 'SwissKnife202405\\Symfony\\Component\\String\\AbstractUnicodeString' => $vendorDir . '/symfony/string/AbstractUnicodeString.php', + 'SwissKnife202405\\Symfony\\Component\\String\\ByteString' => $vendorDir . '/symfony/string/ByteString.php', + 'SwissKnife202405\\Symfony\\Component\\String\\CodePointString' => $vendorDir . '/symfony/string/CodePointString.php', + 'SwissKnife202405\\Symfony\\Component\\String\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/string/Exception/ExceptionInterface.php', + 'SwissKnife202405\\Symfony\\Component\\String\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/string/Exception/InvalidArgumentException.php', + 'SwissKnife202405\\Symfony\\Component\\String\\Exception\\RuntimeException' => $vendorDir . '/symfony/string/Exception/RuntimeException.php', + 'SwissKnife202405\\Symfony\\Component\\String\\Inflector\\EnglishInflector' => $vendorDir . '/symfony/string/Inflector/EnglishInflector.php', + 'SwissKnife202405\\Symfony\\Component\\String\\Inflector\\FrenchInflector' => $vendorDir . '/symfony/string/Inflector/FrenchInflector.php', + 'SwissKnife202405\\Symfony\\Component\\String\\Inflector\\InflectorInterface' => $vendorDir . '/symfony/string/Inflector/InflectorInterface.php', + 'SwissKnife202405\\Symfony\\Component\\String\\LazyString' => $vendorDir . '/symfony/string/LazyString.php', + 'SwissKnife202405\\Symfony\\Component\\String\\Slugger\\AsciiSlugger' => $vendorDir . '/symfony/string/Slugger/AsciiSlugger.php', + 'SwissKnife202405\\Symfony\\Component\\String\\Slugger\\SluggerInterface' => $vendorDir . '/symfony/string/Slugger/SluggerInterface.php', + 'SwissKnife202405\\Symfony\\Component\\String\\UnicodeString' => $vendorDir . '/symfony/string/UnicodeString.php', + 'SwissKnife202405\\Symfony\\Contracts\\Service\\Attribute\\Required' => $vendorDir . '/symfony/service-contracts/Attribute/Required.php', + 'SwissKnife202405\\Symfony\\Contracts\\Service\\Attribute\\SubscribedService' => $vendorDir . '/symfony/service-contracts/Attribute/SubscribedService.php', + 'SwissKnife202405\\Symfony\\Contracts\\Service\\ResetInterface' => $vendorDir . '/symfony/service-contracts/ResetInterface.php', + 'SwissKnife202405\\Symfony\\Contracts\\Service\\ServiceCollectionInterface' => $vendorDir . '/symfony/service-contracts/ServiceCollectionInterface.php', + 'SwissKnife202405\\Symfony\\Contracts\\Service\\ServiceLocatorTrait' => $vendorDir . '/symfony/service-contracts/ServiceLocatorTrait.php', + 'SwissKnife202405\\Symfony\\Contracts\\Service\\ServiceMethodsSubscriberTrait' => $vendorDir . '/symfony/service-contracts/ServiceMethodsSubscriberTrait.php', + 'SwissKnife202405\\Symfony\\Contracts\\Service\\ServiceProviderInterface' => $vendorDir . '/symfony/service-contracts/ServiceProviderInterface.php', + 'SwissKnife202405\\Symfony\\Contracts\\Service\\ServiceSubscriberInterface' => $vendorDir . '/symfony/service-contracts/ServiceSubscriberInterface.php', + 'SwissKnife202405\\Symfony\\Contracts\\Service\\ServiceSubscriberTrait' => $vendorDir . '/symfony/service-contracts/ServiceSubscriberTrait.php', + 'SwissKnife202405\\Webmozart\\Assert\\Assert' => $vendorDir . '/webmozart/assert/src/Assert.php', + 'SwissKnife202405\\Webmozart\\Assert\\InvalidArgumentException' => $vendorDir . '/webmozart/assert/src/InvalidArgumentException.php', + 'SwissKnife202405\\Webmozart\\Assert\\Mixin' => $vendorDir . '/webmozart/assert/src/Mixin.php', + 'Symfony\\Polyfill\\Intl\\Grapheme\\Grapheme' => $vendorDir . '/symfony/polyfill-intl-grapheme/Grapheme.php', +); diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php new file mode 100644 index 0000000000..1c4b8d7186 --- /dev/null +++ b/vendor/composer/autoload_files.php @@ -0,0 +1,12 @@ + $vendorDir . '/symfony/deprecation-contracts/function.php', + '8825ede83f2f289127722d4e842cf7e8' => $vendorDir . '/symfony/polyfill-intl-grapheme/bootstrap.php', + 'b6b991a57620e2fb6b2f66f03fe9ddc2' => $vendorDir . '/symfony/string/Resources/functions.php', +); diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php new file mode 100644 index 0000000000..15a2ff3ad6 --- /dev/null +++ b/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($vendorDir . '/symfony/polyfill-intl-grapheme'), + 'SwissKnife202405\\Webmozart\\Assert\\' => array($vendorDir . '/webmozart/assert/src'), + 'SwissKnife202405\\Symfony\\Contracts\\Service\\' => array($vendorDir . '/symfony/service-contracts'), + 'SwissKnife202405\\Symfony\\Component\\String\\' => array($vendorDir . '/symfony/string'), + 'SwissKnife202405\\Symfony\\Component\\Process\\' => array($vendorDir . '/symfony/process'), + 'SwissKnife202405\\Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'), + 'SwissKnife202405\\Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'), + 'SwissKnife202405\\Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'), + 'SwissKnife202405\\Psr\\Container\\' => array($vendorDir . '/psr/container/src'), + 'SwissKnife202405\\PhpParser\\' => array($vendorDir . '/nikic/php-parser/lib/PhpParser'), + 'SwissKnife202405\\Illuminate\\Contracts\\' => array($vendorDir . '/illuminate/contracts'), + 'SwissKnife202405\\Illuminate\\Container\\' => array($vendorDir . '/illuminate/container'), + 'Rector\\SwissKnife\\' => array($baseDir . '/src'), +); diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php new file mode 100644 index 0000000000..42f7116457 --- /dev/null +++ b/vendor/composer/autoload_real.php @@ -0,0 +1,49 @@ +setClassMapAuthoritative(true); + $loader->register(true); + + $filesToLoad = \Composer\Autoload\ComposerStaticInitbd56538313f8398f8246f599e7944495::$files; + $requireFile = \Closure::bind(static function ($fileIdentifier, $file) { + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + + require $file; + } + }, null, null); + foreach ($filesToLoad as $fileIdentifier => $file) { + $requireFile($fileIdentifier, $file); + } + + return $loader; + } +} diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php new file mode 100644 index 0000000000..472bbc132e --- /dev/null +++ b/vendor/composer/autoload_static.php @@ -0,0 +1,776 @@ + __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php', + '8825ede83f2f289127722d4e842cf7e8' => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme/bootstrap.php', + 'b6b991a57620e2fb6b2f66f03fe9ddc2' => __DIR__ . '/..' . '/symfony/string/Resources/functions.php', + ); + + public static $prefixLengthsPsr4 = array ( + 'S' => + array ( + 'Symfony\\Polyfill\\Intl\\Grapheme\\' => 31, + 'SwissKnife202405\\Webmozart\\Assert\\' => 34, + 'SwissKnife202405\\Symfony\\Contracts\\Service\\' => 43, + 'SwissKnife202405\\Symfony\\Component\\String\\' => 42, + 'SwissKnife202405\\Symfony\\Component\\Process\\' => 43, + 'SwissKnife202405\\Symfony\\Component\\Finder\\' => 42, + 'SwissKnife202405\\Symfony\\Component\\Console\\' => 43, + 'SwissKnife202405\\Psr\\SimpleCache\\' => 33, + 'SwissKnife202405\\Psr\\Container\\' => 31, + 'SwissKnife202405\\PhpParser\\' => 27, + 'SwissKnife202405\\Illuminate\\Contracts\\' => 38, + 'SwissKnife202405\\Illuminate\\Container\\' => 38, + ), + 'R' => + array ( + 'Rector\\SwissKnife\\' => 18, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Symfony\\Polyfill\\Intl\\Grapheme\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme', + ), + 'SwissKnife202405\\Webmozart\\Assert\\' => + array ( + 0 => __DIR__ . '/..' . '/webmozart/assert/src', + ), + 'SwissKnife202405\\Symfony\\Contracts\\Service\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/service-contracts', + ), + 'SwissKnife202405\\Symfony\\Component\\String\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/string', + ), + 'SwissKnife202405\\Symfony\\Component\\Process\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/process', + ), + 'SwissKnife202405\\Symfony\\Component\\Finder\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/finder', + ), + 'SwissKnife202405\\Symfony\\Component\\Console\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/console', + ), + 'SwissKnife202405\\Psr\\SimpleCache\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/simple-cache/src', + ), + 'SwissKnife202405\\Psr\\Container\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/container/src', + ), + 'SwissKnife202405\\PhpParser\\' => + array ( + 0 => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser', + ), + 'SwissKnife202405\\Illuminate\\Contracts\\' => + array ( + 0 => __DIR__ . '/..' . '/illuminate/contracts', + ), + 'SwissKnife202405\\Illuminate\\Container\\' => + array ( + 0 => __DIR__ . '/..' . '/illuminate/container', + ), + 'Rector\\SwissKnife\\' => + array ( + 0 => __DIR__ . '/../..' . '/src', + ), + ); + + public static $classMap = array ( + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + 'PHPUnit_Framework_TestCase' => __DIR__ . '/../..' . '/stubs/PHPUnit/PHPUnit_Framework_TestCase.php', + 'Rector\\SwissKnife\\Analyzer\\NeedsFinalizeAnalyzer' => __DIR__ . '/../..' . '/src/Analyzer/NeedsFinalizeAnalyzer.php', + 'Rector\\SwissKnife\\Command\\CheckCommentedCodeCommand' => __DIR__ . '/../..' . '/src/Command/CheckCommentedCodeCommand.php', + 'Rector\\SwissKnife\\Command\\CheckConflictsCommand' => __DIR__ . '/../..' . '/src/Command/CheckConflictsCommand.php', + 'Rector\\SwissKnife\\Command\\DumpEditorconfigCommand' => __DIR__ . '/../..' . '/src/Command/DumpEditorconfigCommand.php', + 'Rector\\SwissKnife\\Command\\FinalizeClassesCommand' => __DIR__ . '/../..' . '/src/Command/FinalizeClassesCommand.php', + 'Rector\\SwissKnife\\Command\\FindMultiClassesCommand' => __DIR__ . '/../..' . '/src/Command/FindMultiClassesCommand.php', + 'Rector\\SwissKnife\\Command\\NamespaceToPSR4Command' => __DIR__ . '/../..' . '/src/Command/NamespaceToPSR4Command.php', + 'Rector\\SwissKnife\\Command\\PrettyJsonCommand' => __DIR__ . '/../..' . '/src/Command/PrettyJsonCommand.php', + 'Rector\\SwissKnife\\Command\\PrivatizeConstantsCommand' => __DIR__ . '/../..' . '/src/Command/PrivatizeConstantsCommand.php', + 'Rector\\SwissKnife\\Command\\ValidateFileLengthCommand' => __DIR__ . '/../..' . '/src/Command/ValidateFileLengthCommand.php', + 'Rector\\SwissKnife\\Comments\\CommentedCodeAnalyzer' => __DIR__ . '/../..' . '/src/Comments/CommentedCodeAnalyzer.php', + 'Rector\\SwissKnife\\DependencyInjection\\ContainerFactory' => __DIR__ . '/../..' . '/src/DependencyInjection/ContainerFactory.php', + 'Rector\\SwissKnife\\EntityClassResolver' => __DIR__ . '/../..' . '/src/EntityClassResolver.php', + 'Rector\\SwissKnife\\FileSystem\\JsonAnalyzer' => __DIR__ . '/../..' . '/src/FileSystem/JsonAnalyzer.php', + 'Rector\\SwissKnife\\FileSystem\\PathHelper' => __DIR__ . '/../..' . '/src/FileSystem/PathHelper.php', + 'Rector\\SwissKnife\\Finder\\FilesFinder' => __DIR__ . '/../..' . '/src/Finder/FilesFinder.php', + 'Rector\\SwissKnife\\Finder\\MultipleClassInOneFileFinder' => __DIR__ . '/../..' . '/src/Finder/MultipleClassInOneFileFinder.php', + 'Rector\\SwissKnife\\Finder\\PhpFilesFinder' => __DIR__ . '/../..' . '/src/Finder/PhpFilesFinder.php', + 'Rector\\SwissKnife\\Finder\\YamlFilesFinder' => __DIR__ . '/../..' . '/src/Finder/YamlFilesFinder.php', + 'Rector\\SwissKnife\\Git\\ConflictResolver' => __DIR__ . '/../..' . '/src/Git/ConflictResolver.php', + 'Rector\\SwissKnife\\MockedClassResolver' => __DIR__ . '/../..' . '/src/MockedClassResolver.php', + 'Rector\\SwissKnife\\ParentClassResolver' => __DIR__ . '/../..' . '/src/ParentClassResolver.php', + 'Rector\\SwissKnife\\PhpParser\\CachedPhpParser' => __DIR__ . '/../..' . '/src/PhpParser/CachedPhpParser.php', + 'Rector\\SwissKnife\\PhpParser\\NodeVisitor\\EntityClassNameCollectingNodeVisitor' => __DIR__ . '/../..' . '/src/PhpParser/NodeVisitor/EntityClassNameCollectingNodeVisitor.php', + 'Rector\\SwissKnife\\PhpParser\\NodeVisitor\\MockedClassNameCollectingNodeVisitor' => __DIR__ . '/../..' . '/src/PhpParser/NodeVisitor/MockedClassNameCollectingNodeVisitor.php', + 'Rector\\SwissKnife\\PhpParser\\NodeVisitor\\NeedForFinalizeNodeVisitor' => __DIR__ . '/../..' . '/src/PhpParser/NodeVisitor/NeedForFinalizeNodeVisitor.php', + 'Rector\\SwissKnife\\PhpParser\\NodeVisitor\\ParentClassNameCollectingNodeVisitor' => __DIR__ . '/../..' . '/src/PhpParser/NodeVisitor/ParentClassNameCollectingNodeVisitor.php', + 'Rector\\SwissKnife\\Resolver\\TooLongFilesResolver' => __DIR__ . '/../..' . '/src/Resolver/TooLongFilesResolver.php', + 'Rector\\SwissKnife\\RobotLoader\\PhpClassLoader' => __DIR__ . '/../..' . '/src/RobotLoader/PhpClassLoader.php', + 'Rector\\SwissKnife\\Testing\\Command\\DetectUnitTestsCommand' => __DIR__ . '/../..' . '/src/Testing/Command/DetectUnitTestsCommand.php', + 'Rector\\SwissKnife\\Testing\\Finder\\TestCaseClassFinder' => __DIR__ . '/../..' . '/src/Testing/Finder/TestCaseClassFinder.php', + 'Rector\\SwissKnife\\Testing\\Printer\\PHPUnitXmlPrinter' => __DIR__ . '/../..' . '/src/Testing/Printer/PHPUnitXmlPrinter.php', + 'Rector\\SwissKnife\\Testing\\UnitTestFilePathsFinder' => __DIR__ . '/../..' . '/src/Testing/UnitTestFilePathsFinder.php', + 'Rector\\SwissKnife\\Testing\\UnitTestFilter' => __DIR__ . '/../..' . '/src/Testing/UnitTestFilter.php', + 'Rector\\SwissKnife\\ValueObject\\ClassConstMatch' => __DIR__ . '/../..' . '/src/ValueObject/ClassConstMatch.php', + 'SwissKnife202405\\Illuminate\\Container\\BoundMethod' => __DIR__ . '/..' . '/illuminate/container/BoundMethod.php', + 'SwissKnife202405\\Illuminate\\Container\\Container' => __DIR__ . '/..' . '/illuminate/container/Container.php', + 'SwissKnife202405\\Illuminate\\Container\\ContextualBindingBuilder' => __DIR__ . '/..' . '/illuminate/container/ContextualBindingBuilder.php', + 'SwissKnife202405\\Illuminate\\Container\\EntryNotFoundException' => __DIR__ . '/..' . '/illuminate/container/EntryNotFoundException.php', + 'SwissKnife202405\\Illuminate\\Container\\RewindableGenerator' => __DIR__ . '/..' . '/illuminate/container/RewindableGenerator.php', + 'SwissKnife202405\\Illuminate\\Container\\Util' => __DIR__ . '/..' . '/illuminate/container/Util.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\Access\\Authorizable' => __DIR__ . '/..' . '/illuminate/contracts/Auth/Access/Authorizable.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\Access\\Gate' => __DIR__ . '/..' . '/illuminate/contracts/Auth/Access/Gate.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\Authenticatable' => __DIR__ . '/..' . '/illuminate/contracts/Auth/Authenticatable.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\CanResetPassword' => __DIR__ . '/..' . '/illuminate/contracts/Auth/CanResetPassword.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\Factory' => __DIR__ . '/..' . '/illuminate/contracts/Auth/Factory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\Guard' => __DIR__ . '/..' . '/illuminate/contracts/Auth/Guard.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\Middleware\\AuthenticatesRequests' => __DIR__ . '/..' . '/illuminate/contracts/Auth/Middleware/AuthenticatesRequests.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\MustVerifyEmail' => __DIR__ . '/..' . '/illuminate/contracts/Auth/MustVerifyEmail.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\PasswordBroker' => __DIR__ . '/..' . '/illuminate/contracts/Auth/PasswordBroker.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\PasswordBrokerFactory' => __DIR__ . '/..' . '/illuminate/contracts/Auth/PasswordBrokerFactory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\StatefulGuard' => __DIR__ . '/..' . '/illuminate/contracts/Auth/StatefulGuard.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\SupportsBasicAuth' => __DIR__ . '/..' . '/illuminate/contracts/Auth/SupportsBasicAuth.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Auth\\UserProvider' => __DIR__ . '/..' . '/illuminate/contracts/Auth/UserProvider.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Broadcasting\\Broadcaster' => __DIR__ . '/..' . '/illuminate/contracts/Broadcasting/Broadcaster.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Broadcasting\\Factory' => __DIR__ . '/..' . '/illuminate/contracts/Broadcasting/Factory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Broadcasting\\HasBroadcastChannel' => __DIR__ . '/..' . '/illuminate/contracts/Broadcasting/HasBroadcastChannel.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Broadcasting\\ShouldBeUnique' => __DIR__ . '/..' . '/illuminate/contracts/Broadcasting/ShouldBeUnique.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Broadcasting\\ShouldBroadcast' => __DIR__ . '/..' . '/illuminate/contracts/Broadcasting/ShouldBroadcast.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Broadcasting\\ShouldBroadcastNow' => __DIR__ . '/..' . '/illuminate/contracts/Broadcasting/ShouldBroadcastNow.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Bus\\Dispatcher' => __DIR__ . '/..' . '/illuminate/contracts/Bus/Dispatcher.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Bus\\QueueingDispatcher' => __DIR__ . '/..' . '/illuminate/contracts/Bus/QueueingDispatcher.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Cache\\Factory' => __DIR__ . '/..' . '/illuminate/contracts/Cache/Factory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Cache\\Lock' => __DIR__ . '/..' . '/illuminate/contracts/Cache/Lock.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Cache\\LockProvider' => __DIR__ . '/..' . '/illuminate/contracts/Cache/LockProvider.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Cache\\LockTimeoutException' => __DIR__ . '/..' . '/illuminate/contracts/Cache/LockTimeoutException.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Cache\\Repository' => __DIR__ . '/..' . '/illuminate/contracts/Cache/Repository.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Cache\\Store' => __DIR__ . '/..' . '/illuminate/contracts/Cache/Store.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Config\\Repository' => __DIR__ . '/..' . '/illuminate/contracts/Config/Repository.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Console\\Application' => __DIR__ . '/..' . '/illuminate/contracts/Console/Application.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Console\\Isolatable' => __DIR__ . '/..' . '/illuminate/contracts/Console/Isolatable.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Console\\Kernel' => __DIR__ . '/..' . '/illuminate/contracts/Console/Kernel.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Console\\PromptsForMissingInput' => __DIR__ . '/..' . '/illuminate/contracts/Console/PromptsForMissingInput.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Container\\BindingResolutionException' => __DIR__ . '/..' . '/illuminate/contracts/Container/BindingResolutionException.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Container\\CircularDependencyException' => __DIR__ . '/..' . '/illuminate/contracts/Container/CircularDependencyException.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Container\\Container' => __DIR__ . '/..' . '/illuminate/contracts/Container/Container.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Container\\ContextualBindingBuilder' => __DIR__ . '/..' . '/illuminate/contracts/Container/ContextualBindingBuilder.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Cookie\\Factory' => __DIR__ . '/..' . '/illuminate/contracts/Cookie/Factory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Cookie\\QueueingFactory' => __DIR__ . '/..' . '/illuminate/contracts/Cookie/QueueingFactory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Database\\Eloquent\\Builder' => __DIR__ . '/..' . '/illuminate/contracts/Database/Eloquent/Builder.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Database\\Eloquent\\Castable' => __DIR__ . '/..' . '/illuminate/contracts/Database/Eloquent/Castable.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Database\\Eloquent\\CastsAttributes' => __DIR__ . '/..' . '/illuminate/contracts/Database/Eloquent/CastsAttributes.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Database\\Eloquent\\CastsInboundAttributes' => __DIR__ . '/..' . '/illuminate/contracts/Database/Eloquent/CastsInboundAttributes.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Database\\Eloquent\\DeviatesCastableAttributes' => __DIR__ . '/..' . '/illuminate/contracts/Database/Eloquent/DeviatesCastableAttributes.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Database\\Eloquent\\SerializesCastableAttributes' => __DIR__ . '/..' . '/illuminate/contracts/Database/Eloquent/SerializesCastableAttributes.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Database\\Eloquent\\SupportsPartialRelations' => __DIR__ . '/..' . '/illuminate/contracts/Database/Eloquent/SupportsPartialRelations.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Database\\Events\\MigrationEvent' => __DIR__ . '/..' . '/illuminate/contracts/Database/Events/MigrationEvent.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Database\\ModelIdentifier' => __DIR__ . '/..' . '/illuminate/contracts/Database/ModelIdentifier.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Database\\Query\\Builder' => __DIR__ . '/..' . '/illuminate/contracts/Database/Query/Builder.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Database\\Query\\ConditionExpression' => __DIR__ . '/..' . '/illuminate/contracts/Database/Query/ConditionExpression.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Database\\Query\\Expression' => __DIR__ . '/..' . '/illuminate/contracts/Database/Query/Expression.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Debug\\ExceptionHandler' => __DIR__ . '/..' . '/illuminate/contracts/Debug/ExceptionHandler.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Encryption\\DecryptException' => __DIR__ . '/..' . '/illuminate/contracts/Encryption/DecryptException.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Encryption\\EncryptException' => __DIR__ . '/..' . '/illuminate/contracts/Encryption/EncryptException.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Encryption\\Encrypter' => __DIR__ . '/..' . '/illuminate/contracts/Encryption/Encrypter.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Encryption\\StringEncrypter' => __DIR__ . '/..' . '/illuminate/contracts/Encryption/StringEncrypter.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Events\\Dispatcher' => __DIR__ . '/..' . '/illuminate/contracts/Events/Dispatcher.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Events\\ShouldDispatchAfterCommit' => __DIR__ . '/..' . '/illuminate/contracts/Events/ShouldDispatchAfterCommit.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Events\\ShouldHandleEventsAfterCommit' => __DIR__ . '/..' . '/illuminate/contracts/Events/ShouldHandleEventsAfterCommit.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Filesystem\\Cloud' => __DIR__ . '/..' . '/illuminate/contracts/Filesystem/Cloud.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Filesystem\\Factory' => __DIR__ . '/..' . '/illuminate/contracts/Filesystem/Factory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Filesystem\\FileNotFoundException' => __DIR__ . '/..' . '/illuminate/contracts/Filesystem/FileNotFoundException.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Filesystem\\Filesystem' => __DIR__ . '/..' . '/illuminate/contracts/Filesystem/Filesystem.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Filesystem\\LockTimeoutException' => __DIR__ . '/..' . '/illuminate/contracts/Filesystem/LockTimeoutException.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Foundation\\Application' => __DIR__ . '/..' . '/illuminate/contracts/Foundation/Application.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Foundation\\CachesConfiguration' => __DIR__ . '/..' . '/illuminate/contracts/Foundation/CachesConfiguration.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Foundation\\CachesRoutes' => __DIR__ . '/..' . '/illuminate/contracts/Foundation/CachesRoutes.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Foundation\\ExceptionRenderer' => __DIR__ . '/..' . '/illuminate/contracts/Foundation/ExceptionRenderer.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Foundation\\MaintenanceMode' => __DIR__ . '/..' . '/illuminate/contracts/Foundation/MaintenanceMode.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Hashing\\Hasher' => __DIR__ . '/..' . '/illuminate/contracts/Hashing/Hasher.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Http\\Kernel' => __DIR__ . '/..' . '/illuminate/contracts/Http/Kernel.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Mail\\Attachable' => __DIR__ . '/..' . '/illuminate/contracts/Mail/Attachable.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Mail\\Factory' => __DIR__ . '/..' . '/illuminate/contracts/Mail/Factory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Mail\\MailQueue' => __DIR__ . '/..' . '/illuminate/contracts/Mail/MailQueue.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Mail\\Mailable' => __DIR__ . '/..' . '/illuminate/contracts/Mail/Mailable.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Mail\\Mailer' => __DIR__ . '/..' . '/illuminate/contracts/Mail/Mailer.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Notifications\\Dispatcher' => __DIR__ . '/..' . '/illuminate/contracts/Notifications/Dispatcher.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Notifications\\Factory' => __DIR__ . '/..' . '/illuminate/contracts/Notifications/Factory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Pagination\\CursorPaginator' => __DIR__ . '/..' . '/illuminate/contracts/Pagination/CursorPaginator.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Pagination\\LengthAwarePaginator' => __DIR__ . '/..' . '/illuminate/contracts/Pagination/LengthAwarePaginator.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Pagination\\Paginator' => __DIR__ . '/..' . '/illuminate/contracts/Pagination/Paginator.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Pipeline\\Hub' => __DIR__ . '/..' . '/illuminate/contracts/Pipeline/Hub.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Pipeline\\Pipeline' => __DIR__ . '/..' . '/illuminate/contracts/Pipeline/Pipeline.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Process\\InvokedProcess' => __DIR__ . '/..' . '/illuminate/contracts/Process/InvokedProcess.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Process\\ProcessResult' => __DIR__ . '/..' . '/illuminate/contracts/Process/ProcessResult.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\ClearableQueue' => __DIR__ . '/..' . '/illuminate/contracts/Queue/ClearableQueue.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\EntityNotFoundException' => __DIR__ . '/..' . '/illuminate/contracts/Queue/EntityNotFoundException.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\EntityResolver' => __DIR__ . '/..' . '/illuminate/contracts/Queue/EntityResolver.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\Factory' => __DIR__ . '/..' . '/illuminate/contracts/Queue/Factory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\Job' => __DIR__ . '/..' . '/illuminate/contracts/Queue/Job.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\Monitor' => __DIR__ . '/..' . '/illuminate/contracts/Queue/Monitor.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\Queue' => __DIR__ . '/..' . '/illuminate/contracts/Queue/Queue.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\QueueableCollection' => __DIR__ . '/..' . '/illuminate/contracts/Queue/QueueableCollection.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\QueueableEntity' => __DIR__ . '/..' . '/illuminate/contracts/Queue/QueueableEntity.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\ShouldBeEncrypted' => __DIR__ . '/..' . '/illuminate/contracts/Queue/ShouldBeEncrypted.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\ShouldBeUnique' => __DIR__ . '/..' . '/illuminate/contracts/Queue/ShouldBeUnique.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\ShouldBeUniqueUntilProcessing' => __DIR__ . '/..' . '/illuminate/contracts/Queue/ShouldBeUniqueUntilProcessing.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\ShouldQueue' => __DIR__ . '/..' . '/illuminate/contracts/Queue/ShouldQueue.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Queue\\ShouldQueueAfterCommit' => __DIR__ . '/..' . '/illuminate/contracts/Queue/ShouldQueueAfterCommit.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Redis\\Connection' => __DIR__ . '/..' . '/illuminate/contracts/Redis/Connection.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Redis\\Connector' => __DIR__ . '/..' . '/illuminate/contracts/Redis/Connector.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Redis\\Factory' => __DIR__ . '/..' . '/illuminate/contracts/Redis/Factory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Redis\\LimiterTimeoutException' => __DIR__ . '/..' . '/illuminate/contracts/Redis/LimiterTimeoutException.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Routing\\BindingRegistrar' => __DIR__ . '/..' . '/illuminate/contracts/Routing/BindingRegistrar.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Routing\\Registrar' => __DIR__ . '/..' . '/illuminate/contracts/Routing/Registrar.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Routing\\ResponseFactory' => __DIR__ . '/..' . '/illuminate/contracts/Routing/ResponseFactory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Routing\\UrlGenerator' => __DIR__ . '/..' . '/illuminate/contracts/Routing/UrlGenerator.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Routing\\UrlRoutable' => __DIR__ . '/..' . '/illuminate/contracts/Routing/UrlRoutable.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Session\\Middleware\\AuthenticatesSessions' => __DIR__ . '/..' . '/illuminate/contracts/Session/Middleware/AuthenticatesSessions.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Session\\Session' => __DIR__ . '/..' . '/illuminate/contracts/Session/Session.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Support\\Arrayable' => __DIR__ . '/..' . '/illuminate/contracts/Support/Arrayable.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Support\\CanBeEscapedWhenCastToString' => __DIR__ . '/..' . '/illuminate/contracts/Support/CanBeEscapedWhenCastToString.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Support\\DeferrableProvider' => __DIR__ . '/..' . '/illuminate/contracts/Support/DeferrableProvider.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Support\\DeferringDisplayableValue' => __DIR__ . '/..' . '/illuminate/contracts/Support/DeferringDisplayableValue.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Support\\Htmlable' => __DIR__ . '/..' . '/illuminate/contracts/Support/Htmlable.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Support\\Jsonable' => __DIR__ . '/..' . '/illuminate/contracts/Support/Jsonable.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Support\\MessageBag' => __DIR__ . '/..' . '/illuminate/contracts/Support/MessageBag.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Support\\MessageProvider' => __DIR__ . '/..' . '/illuminate/contracts/Support/MessageProvider.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Support\\Renderable' => __DIR__ . '/..' . '/illuminate/contracts/Support/Renderable.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Support\\Responsable' => __DIR__ . '/..' . '/illuminate/contracts/Support/Responsable.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Support\\ValidatedData' => __DIR__ . '/..' . '/illuminate/contracts/Support/ValidatedData.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Translation\\HasLocalePreference' => __DIR__ . '/..' . '/illuminate/contracts/Translation/HasLocalePreference.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Translation\\Loader' => __DIR__ . '/..' . '/illuminate/contracts/Translation/Loader.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Translation\\Translator' => __DIR__ . '/..' . '/illuminate/contracts/Translation/Translator.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Validation\\DataAwareRule' => __DIR__ . '/..' . '/illuminate/contracts/Validation/DataAwareRule.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Validation\\Factory' => __DIR__ . '/..' . '/illuminate/contracts/Validation/Factory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Validation\\ImplicitRule' => __DIR__ . '/..' . '/illuminate/contracts/Validation/ImplicitRule.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Validation\\InvokableRule' => __DIR__ . '/..' . '/illuminate/contracts/Validation/InvokableRule.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Validation\\Rule' => __DIR__ . '/..' . '/illuminate/contracts/Validation/Rule.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Validation\\UncompromisedVerifier' => __DIR__ . '/..' . '/illuminate/contracts/Validation/UncompromisedVerifier.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Validation\\ValidatesWhenResolved' => __DIR__ . '/..' . '/illuminate/contracts/Validation/ValidatesWhenResolved.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Validation\\ValidationRule' => __DIR__ . '/..' . '/illuminate/contracts/Validation/ValidationRule.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Validation\\Validator' => __DIR__ . '/..' . '/illuminate/contracts/Validation/Validator.php', + 'SwissKnife202405\\Illuminate\\Contracts\\Validation\\ValidatorAwareRule' => __DIR__ . '/..' . '/illuminate/contracts/Validation/ValidatorAwareRule.php', + 'SwissKnife202405\\Illuminate\\Contracts\\View\\Engine' => __DIR__ . '/..' . '/illuminate/contracts/View/Engine.php', + 'SwissKnife202405\\Illuminate\\Contracts\\View\\Factory' => __DIR__ . '/..' . '/illuminate/contracts/View/Factory.php', + 'SwissKnife202405\\Illuminate\\Contracts\\View\\View' => __DIR__ . '/..' . '/illuminate/contracts/View/View.php', + 'SwissKnife202405\\Illuminate\\Contracts\\View\\ViewCompilationException' => __DIR__ . '/..' . '/illuminate/contracts/View/ViewCompilationException.php', + 'SwissKnife202405\\Nette\\ArgumentOutOfRangeException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'SwissKnife202405\\Nette\\DeprecatedException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'SwissKnife202405\\Nette\\DirectoryNotFoundException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'SwissKnife202405\\Nette\\FileNotFoundException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'SwissKnife202405\\Nette\\HtmlStringable' => __DIR__ . '/..' . '/nette/utils/src/HtmlStringable.php', + 'SwissKnife202405\\Nette\\IOException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'SwissKnife202405\\Nette\\InvalidArgumentException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'SwissKnife202405\\Nette\\InvalidStateException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'SwissKnife202405\\Nette\\Iterators\\CachingIterator' => __DIR__ . '/..' . '/nette/utils/src/Iterators/CachingIterator.php', + 'SwissKnife202405\\Nette\\Iterators\\Mapper' => __DIR__ . '/..' . '/nette/utils/src/Iterators/Mapper.php', + 'SwissKnife202405\\Nette\\Loaders\\RobotLoader' => __DIR__ . '/..' . '/nette/robot-loader/src/RobotLoader/RobotLoader.php', + 'SwissKnife202405\\Nette\\Localization\\ITranslator' => __DIR__ . '/..' . '/nette/utils/src/compatibility.php', + 'SwissKnife202405\\Nette\\Localization\\Translator' => __DIR__ . '/..' . '/nette/utils/src/Translator.php', + 'SwissKnife202405\\Nette\\MemberAccessException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'SwissKnife202405\\Nette\\NotImplementedException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'SwissKnife202405\\Nette\\NotSupportedException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'SwissKnife202405\\Nette\\OutOfRangeException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'SwissKnife202405\\Nette\\SmartObject' => __DIR__ . '/..' . '/nette/utils/src/SmartObject.php', + 'SwissKnife202405\\Nette\\StaticClass' => __DIR__ . '/..' . '/nette/utils/src/StaticClass.php', + 'SwissKnife202405\\Nette\\UnexpectedValueException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'SwissKnife202405\\Nette\\Utils\\ArrayHash' => __DIR__ . '/..' . '/nette/utils/src/Utils/ArrayHash.php', + 'SwissKnife202405\\Nette\\Utils\\ArrayList' => __DIR__ . '/..' . '/nette/utils/src/Utils/ArrayList.php', + 'SwissKnife202405\\Nette\\Utils\\Arrays' => __DIR__ . '/..' . '/nette/utils/src/Utils/Arrays.php', + 'SwissKnife202405\\Nette\\Utils\\AssertionException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php', + 'SwissKnife202405\\Nette\\Utils\\Callback' => __DIR__ . '/..' . '/nette/utils/src/Utils/Callback.php', + 'SwissKnife202405\\Nette\\Utils\\DateTime' => __DIR__ . '/..' . '/nette/utils/src/Utils/DateTime.php', + 'SwissKnife202405\\Nette\\Utils\\FileSystem' => __DIR__ . '/..' . '/nette/utils/src/Utils/FileSystem.php', + 'SwissKnife202405\\Nette\\Utils\\Finder' => __DIR__ . '/..' . '/nette/finder/src/Utils/Finder.php', + 'SwissKnife202405\\Nette\\Utils\\Floats' => __DIR__ . '/..' . '/nette/utils/src/Utils/Floats.php', + 'SwissKnife202405\\Nette\\Utils\\Helpers' => __DIR__ . '/..' . '/nette/utils/src/Utils/Helpers.php', + 'SwissKnife202405\\Nette\\Utils\\Html' => __DIR__ . '/..' . '/nette/utils/src/Utils/Html.php', + 'SwissKnife202405\\Nette\\Utils\\IHtmlString' => __DIR__ . '/..' . '/nette/utils/src/compatibility.php', + 'SwissKnife202405\\Nette\\Utils\\Image' => __DIR__ . '/..' . '/nette/utils/src/Utils/Image.php', + 'SwissKnife202405\\Nette\\Utils\\ImageException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php', + 'SwissKnife202405\\Nette\\Utils\\Json' => __DIR__ . '/..' . '/nette/utils/src/Utils/Json.php', + 'SwissKnife202405\\Nette\\Utils\\JsonException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php', + 'SwissKnife202405\\Nette\\Utils\\ObjectHelpers' => __DIR__ . '/..' . '/nette/utils/src/Utils/ObjectHelpers.php', + 'SwissKnife202405\\Nette\\Utils\\ObjectMixin' => __DIR__ . '/..' . '/nette/utils/src/Utils/ObjectMixin.php', + 'SwissKnife202405\\Nette\\Utils\\Paginator' => __DIR__ . '/..' . '/nette/utils/src/Utils/Paginator.php', + 'SwissKnife202405\\Nette\\Utils\\Random' => __DIR__ . '/..' . '/nette/utils/src/Utils/Random.php', + 'SwissKnife202405\\Nette\\Utils\\Reflection' => __DIR__ . '/..' . '/nette/utils/src/Utils/Reflection.php', + 'SwissKnife202405\\Nette\\Utils\\RegexpException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php', + 'SwissKnife202405\\Nette\\Utils\\Strings' => __DIR__ . '/..' . '/nette/utils/src/Utils/Strings.php', + 'SwissKnife202405\\Nette\\Utils\\Type' => __DIR__ . '/..' . '/nette/utils/src/Utils/Type.php', + 'SwissKnife202405\\Nette\\Utils\\UnknownImageFileException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php', + 'SwissKnife202405\\Nette\\Utils\\Validators' => __DIR__ . '/..' . '/nette/utils/src/Utils/Validators.php', + 'SwissKnife202405\\PhpParser\\Builder' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder.php', + 'SwissKnife202405\\PhpParser\\BuilderFactory' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/BuilderFactory.php', + 'SwissKnife202405\\PhpParser\\BuilderHelpers' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/BuilderHelpers.php', + 'SwissKnife202405\\PhpParser\\Builder\\ClassConst' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/ClassConst.php', + 'SwissKnife202405\\PhpParser\\Builder\\Class_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/Class_.php', + 'SwissKnife202405\\PhpParser\\Builder\\Declaration' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/Declaration.php', + 'SwissKnife202405\\PhpParser\\Builder\\EnumCase' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/EnumCase.php', + 'SwissKnife202405\\PhpParser\\Builder\\Enum_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/Enum_.php', + 'SwissKnife202405\\PhpParser\\Builder\\FunctionLike' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/FunctionLike.php', + 'SwissKnife202405\\PhpParser\\Builder\\Function_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/Function_.php', + 'SwissKnife202405\\PhpParser\\Builder\\Interface_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/Interface_.php', + 'SwissKnife202405\\PhpParser\\Builder\\Method' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/Method.php', + 'SwissKnife202405\\PhpParser\\Builder\\Namespace_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/Namespace_.php', + 'SwissKnife202405\\PhpParser\\Builder\\Param' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/Param.php', + 'SwissKnife202405\\PhpParser\\Builder\\Property' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/Property.php', + 'SwissKnife202405\\PhpParser\\Builder\\TraitUse' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/TraitUse.php', + 'SwissKnife202405\\PhpParser\\Builder\\TraitUseAdaptation' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/TraitUseAdaptation.php', + 'SwissKnife202405\\PhpParser\\Builder\\Trait_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/Trait_.php', + 'SwissKnife202405\\PhpParser\\Builder\\Use_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Builder/Use_.php', + 'SwissKnife202405\\PhpParser\\Comment' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Comment.php', + 'SwissKnife202405\\PhpParser\\Comment\\Doc' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Comment/Doc.php', + 'SwissKnife202405\\PhpParser\\ConstExprEvaluationException' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/ConstExprEvaluationException.php', + 'SwissKnife202405\\PhpParser\\ConstExprEvaluator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/ConstExprEvaluator.php', + 'SwissKnife202405\\PhpParser\\Error' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Error.php', + 'SwissKnife202405\\PhpParser\\ErrorHandler' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/ErrorHandler.php', + 'SwissKnife202405\\PhpParser\\ErrorHandler\\Collecting' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/ErrorHandler/Collecting.php', + 'SwissKnife202405\\PhpParser\\ErrorHandler\\Throwing' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/ErrorHandler/Throwing.php', + 'SwissKnife202405\\PhpParser\\Internal\\DiffElem' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Internal/DiffElem.php', + 'SwissKnife202405\\PhpParser\\Internal\\Differ' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Internal/Differ.php', + 'SwissKnife202405\\PhpParser\\Internal\\PrintableNewAnonClassNode' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Internal/PrintableNewAnonClassNode.php', + 'SwissKnife202405\\PhpParser\\Internal\\TokenStream' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Internal/TokenStream.php', + 'SwissKnife202405\\PhpParser\\JsonDecoder' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/JsonDecoder.php', + 'SwissKnife202405\\PhpParser\\Lexer' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer.php', + 'SwissKnife202405\\PhpParser\\Lexer\\Emulative' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/Emulative.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\AttributeEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/AttributeEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\CoaleseEqualTokenEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/CoaleseEqualTokenEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\EnumTokenEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/EnumTokenEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\ExplicitOctalEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ExplicitOctalEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\FlexibleDocStringEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/FlexibleDocStringEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\FnTokenEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/FnTokenEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\KeywordEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/KeywordEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\MatchTokenEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/MatchTokenEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\NullsafeTokenEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/NullsafeTokenEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\NumericLiteralSeparatorEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/NumericLiteralSeparatorEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\ReadonlyFunctionTokenEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReadonlyFunctionTokenEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\ReadonlyTokenEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReadonlyTokenEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\ReverseEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReverseEmulator.php', + 'SwissKnife202405\\PhpParser\\Lexer\\TokenEmulator\\TokenEmulator' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/TokenEmulator.php', + 'SwissKnife202405\\PhpParser\\NameContext' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NameContext.php', + 'SwissKnife202405\\PhpParser\\Node' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node.php', + 'SwissKnife202405\\PhpParser\\NodeAbstract' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeAbstract.php', + 'SwissKnife202405\\PhpParser\\NodeDumper' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeDumper.php', + 'SwissKnife202405\\PhpParser\\NodeFinder' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeFinder.php', + 'SwissKnife202405\\PhpParser\\NodeTraverser' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeTraverser.php', + 'SwissKnife202405\\PhpParser\\NodeTraverserInterface' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeTraverserInterface.php', + 'SwissKnife202405\\PhpParser\\NodeVisitor' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeVisitor.php', + 'SwissKnife202405\\PhpParser\\NodeVisitorAbstract' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeVisitorAbstract.php', + 'SwissKnife202405\\PhpParser\\NodeVisitor\\CloningVisitor' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeVisitor/CloningVisitor.php', + 'SwissKnife202405\\PhpParser\\NodeVisitor\\FindingVisitor' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeVisitor/FindingVisitor.php', + 'SwissKnife202405\\PhpParser\\NodeVisitor\\FirstFindingVisitor' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeVisitor/FirstFindingVisitor.php', + 'SwissKnife202405\\PhpParser\\NodeVisitor\\NameResolver' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeVisitor/NameResolver.php', + 'SwissKnife202405\\PhpParser\\NodeVisitor\\NodeConnectingVisitor' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeVisitor/NodeConnectingVisitor.php', + 'SwissKnife202405\\PhpParser\\NodeVisitor\\ParentConnectingVisitor' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/NodeVisitor/ParentConnectingVisitor.php', + 'SwissKnife202405\\PhpParser\\Node\\Arg' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Arg.php', + 'SwissKnife202405\\PhpParser\\Node\\Attribute' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Attribute.php', + 'SwissKnife202405\\PhpParser\\Node\\AttributeGroup' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/AttributeGroup.php', + 'SwissKnife202405\\PhpParser\\Node\\ComplexType' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/ComplexType.php', + 'SwissKnife202405\\PhpParser\\Node\\Const_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Const_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\ArrayDimFetch' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayDimFetch.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\ArrayItem' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayItem.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Array_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Array_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\ArrowFunction' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/ArrowFunction.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Assign' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Assign.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseAnd' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseOr' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseOr.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\BitwiseXor' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseXor.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\Coalesce' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Coalesce.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\Concat' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Concat.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\Div' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Div.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\Minus' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Minus.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\Mod' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Mod.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\Mul' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Mul.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\Plus' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Plus.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\Pow' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Pow.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\ShiftLeft' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/ShiftLeft.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignOp\\ShiftRight' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/ShiftRight.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\AssignRef' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/AssignRef.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseAnd' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseOr' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseOr.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\BitwiseXor' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseXor.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanAnd' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BooleanAnd.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\BooleanOr' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BooleanOr.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Coalesce' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Coalesce.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Concat' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Concat.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Div' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Div.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Equal' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Equal.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Greater' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Greater.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\GreaterOrEqual' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Identical' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Identical.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalAnd' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/LogicalAnd.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalOr' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/LogicalOr.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\LogicalXor' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/LogicalXor.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Minus' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Minus.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Mod' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Mod.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Mul' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Mul.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\NotEqual' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/NotEqual.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\NotIdentical' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/NotIdentical.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Plus' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Plus.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Pow' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Pow.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftLeft' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/ShiftLeft.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\ShiftRight' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/ShiftRight.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Smaller' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Smaller.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\SmallerOrEqual' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BinaryOp\\Spaceship' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Spaceship.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BitwiseNot' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BitwiseNot.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\BooleanNot' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/BooleanNot.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\CallLike' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/CallLike.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Cast' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Cast\\Array_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Array_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Cast\\Bool_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Bool_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Cast\\Double' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Double.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Cast\\Int_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Int_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Cast\\Object_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Object_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Cast\\String_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/String_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Cast\\Unset_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Unset_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\ClassConstFetch' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/ClassConstFetch.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Clone_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Clone_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Closure' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Closure.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\ClosureUse' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/ClosureUse.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\ConstFetch' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/ConstFetch.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Empty_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Empty_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Error' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Error.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\ErrorSuppress' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/ErrorSuppress.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Eval_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Eval_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Exit_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Exit_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\FuncCall' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/FuncCall.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Include_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Include_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Instanceof_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Instanceof_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Isset_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Isset_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\List_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/List_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Match_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Match_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\MethodCall' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/MethodCall.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\New_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/New_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\NullsafeMethodCall' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/NullsafeMethodCall.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\NullsafePropertyFetch' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/NullsafePropertyFetch.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\PostDec' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/PostDec.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\PostInc' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/PostInc.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\PreDec' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/PreDec.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\PreInc' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/PreInc.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Print_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Print_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\PropertyFetch' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/PropertyFetch.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\ShellExec' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/ShellExec.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\StaticCall' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/StaticCall.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\StaticPropertyFetch' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/StaticPropertyFetch.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Ternary' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Ternary.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Throw_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Throw_.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\UnaryMinus' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/UnaryMinus.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\UnaryPlus' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/UnaryPlus.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Variable' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Variable.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\YieldFrom' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/YieldFrom.php', + 'SwissKnife202405\\PhpParser\\Node\\Expr\\Yield_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Expr/Yield_.php', + 'SwissKnife202405\\PhpParser\\Node\\FunctionLike' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/FunctionLike.php', + 'SwissKnife202405\\PhpParser\\Node\\Identifier' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Identifier.php', + 'SwissKnife202405\\PhpParser\\Node\\IntersectionType' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/IntersectionType.php', + 'SwissKnife202405\\PhpParser\\Node\\MatchArm' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/MatchArm.php', + 'SwissKnife202405\\PhpParser\\Node\\Name' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Name.php', + 'SwissKnife202405\\PhpParser\\Node\\Name\\FullyQualified' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Name/FullyQualified.php', + 'SwissKnife202405\\PhpParser\\Node\\Name\\Relative' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Name/Relative.php', + 'SwissKnife202405\\PhpParser\\Node\\NullableType' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/NullableType.php', + 'SwissKnife202405\\PhpParser\\Node\\Param' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Param.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\DNumber' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/DNumber.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\Encapsed' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/Encapsed.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\EncapsedStringPart' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/EncapsedStringPart.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\LNumber' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/LNumber.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\MagicConst' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\MagicConst\\Class_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Class_.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\MagicConst\\Dir' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Dir.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\MagicConst\\File' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/File.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\MagicConst\\Function_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Function_.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\MagicConst\\Line' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Line.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\MagicConst\\Method' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Method.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\MagicConst\\Namespace_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\MagicConst\\Trait_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Trait_.php', + 'SwissKnife202405\\PhpParser\\Node\\Scalar\\String_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Scalar/String_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Break_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Break_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Case_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Case_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Catch_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Catch_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\ClassConst' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassConst.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\ClassLike' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassLike.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\ClassMethod' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassMethod.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Class_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Class_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Const_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Const_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Continue_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Continue_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\DeclareDeclare' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/DeclareDeclare.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Declare_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Declare_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Do_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Do_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Echo_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Echo_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\ElseIf_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/ElseIf_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Else_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Else_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\EnumCase' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/EnumCase.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Enum_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Enum_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Expression' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Expression.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Finally_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Finally_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\For_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/For_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Foreach_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Foreach_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Function_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Function_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Global_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Global_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Goto_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Goto_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\GroupUse' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/GroupUse.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\HaltCompiler' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/HaltCompiler.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\If_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/If_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\InlineHTML' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/InlineHTML.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Interface_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Interface_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Label' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Label.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Namespace_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Namespace_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Nop' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Nop.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Property' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Property.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\PropertyProperty' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/PropertyProperty.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Return_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Return_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\StaticVar' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/StaticVar.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Static_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Static_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Switch_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Switch_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Throw_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Throw_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\TraitUse' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUse.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\TraitUseAdaptation' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\TraitUseAdaptation\\Alias' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\TraitUseAdaptation\\Precedence' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Trait_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Trait_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\TryCatch' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/TryCatch.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Unset_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Unset_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\UseUse' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/UseUse.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\Use_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/Use_.php', + 'SwissKnife202405\\PhpParser\\Node\\Stmt\\While_' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/Stmt/While_.php', + 'SwissKnife202405\\PhpParser\\Node\\UnionType' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/UnionType.php', + 'SwissKnife202405\\PhpParser\\Node\\VarLikeIdentifier' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/VarLikeIdentifier.php', + 'SwissKnife202405\\PhpParser\\Node\\VariadicPlaceholder' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Node/VariadicPlaceholder.php', + 'SwissKnife202405\\PhpParser\\Parser' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Parser.php', + 'SwissKnife202405\\PhpParser\\ParserAbstract' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/ParserAbstract.php', + 'SwissKnife202405\\PhpParser\\ParserFactory' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/ParserFactory.php', + 'SwissKnife202405\\PhpParser\\Parser\\Multiple' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Parser/Multiple.php', + 'SwissKnife202405\\PhpParser\\Parser\\Php5' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Parser/Php5.php', + 'SwissKnife202405\\PhpParser\\Parser\\Php7' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Parser/Php7.php', + 'SwissKnife202405\\PhpParser\\Parser\\Tokens' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/Parser/Tokens.php', + 'SwissKnife202405\\PhpParser\\PrettyPrinterAbstract' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/PrettyPrinterAbstract.php', + 'SwissKnife202405\\PhpParser\\PrettyPrinter\\Standard' => __DIR__ . '/..' . '/nikic/php-parser/lib/PhpParser/PrettyPrinter/Standard.php', + 'SwissKnife202405\\Psr\\Container\\ContainerExceptionInterface' => __DIR__ . '/..' . '/psr/container/src/ContainerExceptionInterface.php', + 'SwissKnife202405\\Psr\\Container\\ContainerInterface' => __DIR__ . '/..' . '/psr/container/src/ContainerInterface.php', + 'SwissKnife202405\\Psr\\Container\\NotFoundExceptionInterface' => __DIR__ . '/..' . '/psr/container/src/NotFoundExceptionInterface.php', + 'SwissKnife202405\\Psr\\SimpleCache\\CacheException' => __DIR__ . '/..' . '/psr/simple-cache/src/CacheException.php', + 'SwissKnife202405\\Psr\\SimpleCache\\CacheInterface' => __DIR__ . '/..' . '/psr/simple-cache/src/CacheInterface.php', + 'SwissKnife202405\\Psr\\SimpleCache\\InvalidArgumentException' => __DIR__ . '/..' . '/psr/simple-cache/src/InvalidArgumentException.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Application' => __DIR__ . '/..' . '/symfony/console/Application.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Attribute\\AsCommand' => __DIR__ . '/..' . '/symfony/console/Attribute/AsCommand.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\CI\\GithubActionReporter' => __DIR__ . '/..' . '/symfony/console/CI/GithubActionReporter.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Color' => __DIR__ . '/..' . '/symfony/console/Color.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\CommandLoader\\CommandLoaderInterface' => __DIR__ . '/..' . '/symfony/console/CommandLoader/CommandLoaderInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\CommandLoader\\ContainerCommandLoader' => __DIR__ . '/..' . '/symfony/console/CommandLoader/ContainerCommandLoader.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\CommandLoader\\FactoryCommandLoader' => __DIR__ . '/..' . '/symfony/console/CommandLoader/FactoryCommandLoader.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Command\\Command' => __DIR__ . '/..' . '/symfony/console/Command/Command.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Command\\CompleteCommand' => __DIR__ . '/..' . '/symfony/console/Command/CompleteCommand.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Command\\DumpCompletionCommand' => __DIR__ . '/..' . '/symfony/console/Command/DumpCompletionCommand.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Command\\HelpCommand' => __DIR__ . '/..' . '/symfony/console/Command/HelpCommand.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Command\\LazyCommand' => __DIR__ . '/..' . '/symfony/console/Command/LazyCommand.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Command\\ListCommand' => __DIR__ . '/..' . '/symfony/console/Command/ListCommand.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Command\\LockableTrait' => __DIR__ . '/..' . '/symfony/console/Command/LockableTrait.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Command\\SignalableCommandInterface' => __DIR__ . '/..' . '/symfony/console/Command/SignalableCommandInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Command\\TraceableCommand' => __DIR__ . '/..' . '/symfony/console/Command/TraceableCommand.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Completion\\CompletionInput' => __DIR__ . '/..' . '/symfony/console/Completion/CompletionInput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Completion\\CompletionSuggestions' => __DIR__ . '/..' . '/symfony/console/Completion/CompletionSuggestions.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Completion\\Output\\BashCompletionOutput' => __DIR__ . '/..' . '/symfony/console/Completion/Output/BashCompletionOutput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Completion\\Output\\CompletionOutputInterface' => __DIR__ . '/..' . '/symfony/console/Completion/Output/CompletionOutputInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Completion\\Output\\FishCompletionOutput' => __DIR__ . '/..' . '/symfony/console/Completion/Output/FishCompletionOutput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Completion\\Output\\ZshCompletionOutput' => __DIR__ . '/..' . '/symfony/console/Completion/Output/ZshCompletionOutput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Completion\\Suggestion' => __DIR__ . '/..' . '/symfony/console/Completion/Suggestion.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\ConsoleEvents' => __DIR__ . '/..' . '/symfony/console/ConsoleEvents.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Cursor' => __DIR__ . '/..' . '/symfony/console/Cursor.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\DataCollector\\CommandDataCollector' => __DIR__ . '/..' . '/symfony/console/DataCollector/CommandDataCollector.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Debug\\CliRequest' => __DIR__ . '/..' . '/symfony/console/Debug/CliRequest.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\DependencyInjection\\AddConsoleCommandPass' => __DIR__ . '/..' . '/symfony/console/DependencyInjection/AddConsoleCommandPass.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Descriptor\\ApplicationDescription' => __DIR__ . '/..' . '/symfony/console/Descriptor/ApplicationDescription.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Descriptor\\Descriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/Descriptor.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Descriptor\\DescriptorInterface' => __DIR__ . '/..' . '/symfony/console/Descriptor/DescriptorInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Descriptor\\JsonDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/JsonDescriptor.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Descriptor\\MarkdownDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/MarkdownDescriptor.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Descriptor\\ReStructuredTextDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/ReStructuredTextDescriptor.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Descriptor\\TextDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/TextDescriptor.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Descriptor\\XmlDescriptor' => __DIR__ . '/..' . '/symfony/console/Descriptor/XmlDescriptor.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\EventListener\\ErrorListener' => __DIR__ . '/..' . '/symfony/console/EventListener/ErrorListener.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Event\\ConsoleCommandEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleCommandEvent.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Event\\ConsoleErrorEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleErrorEvent.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Event\\ConsoleEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleEvent.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Event\\ConsoleSignalEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleSignalEvent.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Event\\ConsoleTerminateEvent' => __DIR__ . '/..' . '/symfony/console/Event/ConsoleTerminateEvent.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Exception\\CommandNotFoundException' => __DIR__ . '/..' . '/symfony/console/Exception/CommandNotFoundException.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/console/Exception/ExceptionInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/console/Exception/InvalidArgumentException.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Exception\\InvalidOptionException' => __DIR__ . '/..' . '/symfony/console/Exception/InvalidOptionException.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Exception\\LogicException' => __DIR__ . '/..' . '/symfony/console/Exception/LogicException.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Exception\\MissingInputException' => __DIR__ . '/..' . '/symfony/console/Exception/MissingInputException.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Exception\\NamespaceNotFoundException' => __DIR__ . '/..' . '/symfony/console/Exception/NamespaceNotFoundException.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Exception\\RunCommandFailedException' => __DIR__ . '/..' . '/symfony/console/Exception/RunCommandFailedException.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/console/Exception/RuntimeException.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Formatter\\NullOutputFormatter' => __DIR__ . '/..' . '/symfony/console/Formatter/NullOutputFormatter.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Formatter\\NullOutputFormatterStyle' => __DIR__ . '/..' . '/symfony/console/Formatter/NullOutputFormatterStyle.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Formatter\\OutputFormatter' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatter.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Formatter\\OutputFormatterInterface' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatterInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Formatter\\OutputFormatterStyle' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatterStyle.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Formatter\\OutputFormatterStyleInterface' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatterStyleInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Formatter\\OutputFormatterStyleStack' => __DIR__ . '/..' . '/symfony/console/Formatter/OutputFormatterStyleStack.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Formatter\\WrappableOutputFormatterInterface' => __DIR__ . '/..' . '/symfony/console/Formatter/WrappableOutputFormatterInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\DebugFormatterHelper' => __DIR__ . '/..' . '/symfony/console/Helper/DebugFormatterHelper.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\DescriptorHelper' => __DIR__ . '/..' . '/symfony/console/Helper/DescriptorHelper.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\Dumper' => __DIR__ . '/..' . '/symfony/console/Helper/Dumper.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\FormatterHelper' => __DIR__ . '/..' . '/symfony/console/Helper/FormatterHelper.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\Helper' => __DIR__ . '/..' . '/symfony/console/Helper/Helper.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\HelperInterface' => __DIR__ . '/..' . '/symfony/console/Helper/HelperInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\HelperSet' => __DIR__ . '/..' . '/symfony/console/Helper/HelperSet.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\InputAwareHelper' => __DIR__ . '/..' . '/symfony/console/Helper/InputAwareHelper.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\OutputWrapper' => __DIR__ . '/..' . '/symfony/console/Helper/OutputWrapper.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\ProcessHelper' => __DIR__ . '/..' . '/symfony/console/Helper/ProcessHelper.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\ProgressBar' => __DIR__ . '/..' . '/symfony/console/Helper/ProgressBar.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\ProgressIndicator' => __DIR__ . '/..' . '/symfony/console/Helper/ProgressIndicator.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\QuestionHelper' => __DIR__ . '/..' . '/symfony/console/Helper/QuestionHelper.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\SymfonyQuestionHelper' => __DIR__ . '/..' . '/symfony/console/Helper/SymfonyQuestionHelper.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\Table' => __DIR__ . '/..' . '/symfony/console/Helper/Table.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\TableCell' => __DIR__ . '/..' . '/symfony/console/Helper/TableCell.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\TableCellStyle' => __DIR__ . '/..' . '/symfony/console/Helper/TableCellStyle.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\TableRows' => __DIR__ . '/..' . '/symfony/console/Helper/TableRows.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\TableSeparator' => __DIR__ . '/..' . '/symfony/console/Helper/TableSeparator.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Helper\\TableStyle' => __DIR__ . '/..' . '/symfony/console/Helper/TableStyle.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Input\\ArgvInput' => __DIR__ . '/..' . '/symfony/console/Input/ArgvInput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Input\\ArrayInput' => __DIR__ . '/..' . '/symfony/console/Input/ArrayInput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Input\\Input' => __DIR__ . '/..' . '/symfony/console/Input/Input.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Input\\InputArgument' => __DIR__ . '/..' . '/symfony/console/Input/InputArgument.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Input\\InputAwareInterface' => __DIR__ . '/..' . '/symfony/console/Input/InputAwareInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Input\\InputDefinition' => __DIR__ . '/..' . '/symfony/console/Input/InputDefinition.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Input\\InputInterface' => __DIR__ . '/..' . '/symfony/console/Input/InputInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Input\\InputOption' => __DIR__ . '/..' . '/symfony/console/Input/InputOption.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Input\\StreamableInputInterface' => __DIR__ . '/..' . '/symfony/console/Input/StreamableInputInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Input\\StringInput' => __DIR__ . '/..' . '/symfony/console/Input/StringInput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Logger\\ConsoleLogger' => __DIR__ . '/..' . '/symfony/console/Logger/ConsoleLogger.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Messenger\\RunCommandContext' => __DIR__ . '/..' . '/symfony/console/Messenger/RunCommandContext.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Messenger\\RunCommandMessage' => __DIR__ . '/..' . '/symfony/console/Messenger/RunCommandMessage.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Messenger\\RunCommandMessageHandler' => __DIR__ . '/..' . '/symfony/console/Messenger/RunCommandMessageHandler.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Output\\AnsiColorMode' => __DIR__ . '/..' . '/symfony/console/Output/AnsiColorMode.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Output\\BufferedOutput' => __DIR__ . '/..' . '/symfony/console/Output/BufferedOutput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Output\\ConsoleOutput' => __DIR__ . '/..' . '/symfony/console/Output/ConsoleOutput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Output\\ConsoleOutputInterface' => __DIR__ . '/..' . '/symfony/console/Output/ConsoleOutputInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Output\\ConsoleSectionOutput' => __DIR__ . '/..' . '/symfony/console/Output/ConsoleSectionOutput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Output\\NullOutput' => __DIR__ . '/..' . '/symfony/console/Output/NullOutput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Output\\Output' => __DIR__ . '/..' . '/symfony/console/Output/Output.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Output\\OutputInterface' => __DIR__ . '/..' . '/symfony/console/Output/OutputInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Output\\StreamOutput' => __DIR__ . '/..' . '/symfony/console/Output/StreamOutput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Output\\TrimmedBufferOutput' => __DIR__ . '/..' . '/symfony/console/Output/TrimmedBufferOutput.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Question\\ChoiceQuestion' => __DIR__ . '/..' . '/symfony/console/Question/ChoiceQuestion.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Question\\ConfirmationQuestion' => __DIR__ . '/..' . '/symfony/console/Question/ConfirmationQuestion.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Question\\Question' => __DIR__ . '/..' . '/symfony/console/Question/Question.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\SignalRegistry\\SignalMap' => __DIR__ . '/..' . '/symfony/console/SignalRegistry/SignalMap.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\SignalRegistry\\SignalRegistry' => __DIR__ . '/..' . '/symfony/console/SignalRegistry/SignalRegistry.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\SingleCommandApplication' => __DIR__ . '/..' . '/symfony/console/SingleCommandApplication.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Style\\OutputStyle' => __DIR__ . '/..' . '/symfony/console/Style/OutputStyle.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Style\\StyleInterface' => __DIR__ . '/..' . '/symfony/console/Style/StyleInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Style\\SymfonyStyle' => __DIR__ . '/..' . '/symfony/console/Style/SymfonyStyle.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Terminal' => __DIR__ . '/..' . '/symfony/console/Terminal.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Tester\\ApplicationTester' => __DIR__ . '/..' . '/symfony/console/Tester/ApplicationTester.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Tester\\CommandCompletionTester' => __DIR__ . '/..' . '/symfony/console/Tester/CommandCompletionTester.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Tester\\CommandTester' => __DIR__ . '/..' . '/symfony/console/Tester/CommandTester.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Tester\\Constraint\\CommandIsSuccessful' => __DIR__ . '/..' . '/symfony/console/Tester/Constraint/CommandIsSuccessful.php', + 'SwissKnife202405\\Symfony\\Component\\Console\\Tester\\TesterTrait' => __DIR__ . '/..' . '/symfony/console/Tester/TesterTrait.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Comparator\\Comparator' => __DIR__ . '/..' . '/symfony/finder/Comparator/Comparator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Comparator\\DateComparator' => __DIR__ . '/..' . '/symfony/finder/Comparator/DateComparator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Comparator\\NumberComparator' => __DIR__ . '/..' . '/symfony/finder/Comparator/NumberComparator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Exception\\AccessDeniedException' => __DIR__ . '/..' . '/symfony/finder/Exception/AccessDeniedException.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Exception\\DirectoryNotFoundException' => __DIR__ . '/..' . '/symfony/finder/Exception/DirectoryNotFoundException.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Finder' => __DIR__ . '/..' . '/symfony/finder/Finder.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Gitignore' => __DIR__ . '/..' . '/symfony/finder/Gitignore.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Glob' => __DIR__ . '/..' . '/symfony/finder/Glob.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\CustomFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/CustomFilterIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\DateRangeFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/DateRangeFilterIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\DepthRangeFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/DepthRangeFilterIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\ExcludeDirectoryFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\FileTypeFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/FileTypeFilterIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\FilecontentFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/FilecontentFilterIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\FilenameFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/FilenameFilterIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\LazyIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/LazyIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\MultiplePcreFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/MultiplePcreFilterIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\PathFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/PathFilterIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\RecursiveDirectoryIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/RecursiveDirectoryIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\SizeRangeFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/SizeRangeFilterIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\SortableIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/SortableIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\Iterator\\VcsIgnoredFilterIterator' => __DIR__ . '/..' . '/symfony/finder/Iterator/VcsIgnoredFilterIterator.php', + 'SwissKnife202405\\Symfony\\Component\\Finder\\SplFileInfo' => __DIR__ . '/..' . '/symfony/finder/SplFileInfo.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/process/Exception/ExceptionInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/process/Exception/InvalidArgumentException.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Exception\\LogicException' => __DIR__ . '/..' . '/symfony/process/Exception/LogicException.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Exception\\ProcessFailedException' => __DIR__ . '/..' . '/symfony/process/Exception/ProcessFailedException.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Exception\\ProcessSignaledException' => __DIR__ . '/..' . '/symfony/process/Exception/ProcessSignaledException.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Exception\\ProcessTimedOutException' => __DIR__ . '/..' . '/symfony/process/Exception/ProcessTimedOutException.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Exception\\RunProcessFailedException' => __DIR__ . '/..' . '/symfony/process/Exception/RunProcessFailedException.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/process/Exception/RuntimeException.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\ExecutableFinder' => __DIR__ . '/..' . '/symfony/process/ExecutableFinder.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\InputStream' => __DIR__ . '/..' . '/symfony/process/InputStream.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Messenger\\RunProcessContext' => __DIR__ . '/..' . '/symfony/process/Messenger/RunProcessContext.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Messenger\\RunProcessMessage' => __DIR__ . '/..' . '/symfony/process/Messenger/RunProcessMessage.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Messenger\\RunProcessMessageHandler' => __DIR__ . '/..' . '/symfony/process/Messenger/RunProcessMessageHandler.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\PhpExecutableFinder' => __DIR__ . '/..' . '/symfony/process/PhpExecutableFinder.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\PhpProcess' => __DIR__ . '/..' . '/symfony/process/PhpProcess.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\PhpSubprocess' => __DIR__ . '/..' . '/symfony/process/PhpSubprocess.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Pipes\\AbstractPipes' => __DIR__ . '/..' . '/symfony/process/Pipes/AbstractPipes.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Pipes\\PipesInterface' => __DIR__ . '/..' . '/symfony/process/Pipes/PipesInterface.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Pipes\\UnixPipes' => __DIR__ . '/..' . '/symfony/process/Pipes/UnixPipes.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Pipes\\WindowsPipes' => __DIR__ . '/..' . '/symfony/process/Pipes/WindowsPipes.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\Process' => __DIR__ . '/..' . '/symfony/process/Process.php', + 'SwissKnife202405\\Symfony\\Component\\Process\\ProcessUtils' => __DIR__ . '/..' . '/symfony/process/ProcessUtils.php', + 'SwissKnife202405\\Symfony\\Component\\String\\AbstractString' => __DIR__ . '/..' . '/symfony/string/AbstractString.php', + 'SwissKnife202405\\Symfony\\Component\\String\\AbstractUnicodeString' => __DIR__ . '/..' . '/symfony/string/AbstractUnicodeString.php', + 'SwissKnife202405\\Symfony\\Component\\String\\ByteString' => __DIR__ . '/..' . '/symfony/string/ByteString.php', + 'SwissKnife202405\\Symfony\\Component\\String\\CodePointString' => __DIR__ . '/..' . '/symfony/string/CodePointString.php', + 'SwissKnife202405\\Symfony\\Component\\String\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/string/Exception/ExceptionInterface.php', + 'SwissKnife202405\\Symfony\\Component\\String\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/string/Exception/InvalidArgumentException.php', + 'SwissKnife202405\\Symfony\\Component\\String\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/string/Exception/RuntimeException.php', + 'SwissKnife202405\\Symfony\\Component\\String\\Inflector\\EnglishInflector' => __DIR__ . '/..' . '/symfony/string/Inflector/EnglishInflector.php', + 'SwissKnife202405\\Symfony\\Component\\String\\Inflector\\FrenchInflector' => __DIR__ . '/..' . '/symfony/string/Inflector/FrenchInflector.php', + 'SwissKnife202405\\Symfony\\Component\\String\\Inflector\\InflectorInterface' => __DIR__ . '/..' . '/symfony/string/Inflector/InflectorInterface.php', + 'SwissKnife202405\\Symfony\\Component\\String\\LazyString' => __DIR__ . '/..' . '/symfony/string/LazyString.php', + 'SwissKnife202405\\Symfony\\Component\\String\\Slugger\\AsciiSlugger' => __DIR__ . '/..' . '/symfony/string/Slugger/AsciiSlugger.php', + 'SwissKnife202405\\Symfony\\Component\\String\\Slugger\\SluggerInterface' => __DIR__ . '/..' . '/symfony/string/Slugger/SluggerInterface.php', + 'SwissKnife202405\\Symfony\\Component\\String\\UnicodeString' => __DIR__ . '/..' . '/symfony/string/UnicodeString.php', + 'SwissKnife202405\\Symfony\\Contracts\\Service\\Attribute\\Required' => __DIR__ . '/..' . '/symfony/service-contracts/Attribute/Required.php', + 'SwissKnife202405\\Symfony\\Contracts\\Service\\Attribute\\SubscribedService' => __DIR__ . '/..' . '/symfony/service-contracts/Attribute/SubscribedService.php', + 'SwissKnife202405\\Symfony\\Contracts\\Service\\ResetInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ResetInterface.php', + 'SwissKnife202405\\Symfony\\Contracts\\Service\\ServiceCollectionInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceCollectionInterface.php', + 'SwissKnife202405\\Symfony\\Contracts\\Service\\ServiceLocatorTrait' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceLocatorTrait.php', + 'SwissKnife202405\\Symfony\\Contracts\\Service\\ServiceMethodsSubscriberTrait' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceMethodsSubscriberTrait.php', + 'SwissKnife202405\\Symfony\\Contracts\\Service\\ServiceProviderInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceProviderInterface.php', + 'SwissKnife202405\\Symfony\\Contracts\\Service\\ServiceSubscriberInterface' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceSubscriberInterface.php', + 'SwissKnife202405\\Symfony\\Contracts\\Service\\ServiceSubscriberTrait' => __DIR__ . '/..' . '/symfony/service-contracts/ServiceSubscriberTrait.php', + 'SwissKnife202405\\Webmozart\\Assert\\Assert' => __DIR__ . '/..' . '/webmozart/assert/src/Assert.php', + 'SwissKnife202405\\Webmozart\\Assert\\InvalidArgumentException' => __DIR__ . '/..' . '/webmozart/assert/src/InvalidArgumentException.php', + 'SwissKnife202405\\Webmozart\\Assert\\Mixin' => __DIR__ . '/..' . '/webmozart/assert/src/Mixin.php', + 'Symfony\\Polyfill\\Intl\\Grapheme\\Grapheme' => __DIR__ . '/..' . '/symfony/polyfill-intl-grapheme/Grapheme.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInitbd56538313f8398f8246f599e7944495::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInitbd56538313f8398f8246f599e7944495::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInitbd56538313f8398f8246f599e7944495::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json new file mode 100644 index 0000000000..248f630e54 --- /dev/null +++ b/vendor/composer/installed.json @@ -0,0 +1,1124 @@ +{ + "packages": [ + { + "name": "illuminate\/container", + "version": "v10.48.12", + "version_normalized": "10.48.12.0", + "source": { + "type": "git", + "url": "https:\/\/github.com\/illuminate\/container.git", + "reference": "ddc26273085fad3c471b2602ad820e0097ff7939" + }, + "dist": { + "type": "zip", + "url": "https:\/\/api.github.com\/repos\/illuminate\/container\/zipball\/ddc26273085fad3c471b2602ad820e0097ff7939", + "reference": "ddc26273085fad3c471b2602ad820e0097ff7939", + "shasum": "" + }, + "require": { + "illuminate\/contracts": "^10.0", + "php": "^8.1", + "psr\/container": "^1.1.1|^2.0.1" + }, + "provide": { + "psr\/container-implementation": "1.1|2.0" + }, + "time": "2023-06-18T09:12:03+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "10.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "SwissKnife202405\\Illuminate\\Container\\": "" + } + }, + "notification-url": "https:\/\/packagist.org\/downloads\/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Illuminate Container package.", + "homepage": "https:\/\/laravel.com", + "support": { + "issues": "https:\/\/github.com\/laravel\/framework\/issues", + "source": "https:\/\/github.com\/laravel\/framework" + }, + "install-path": "..\/illuminate\/container" + }, + { + "name": "illuminate\/contracts", + "version": "v10.48.12", + "version_normalized": "10.48.12.0", + "source": { + "type": "git", + "url": "https:\/\/github.com\/illuminate\/contracts.git", + "reference": "8d7152c4a1f5d9cf7da3e8b71f23e4556f6138ac" + }, + "dist": { + "type": "zip", + "url": "https:\/\/api.github.com\/repos\/illuminate\/contracts\/zipball\/8d7152c4a1f5d9cf7da3e8b71f23e4556f6138ac", + "reference": "8d7152c4a1f5d9cf7da3e8b71f23e4556f6138ac", + "shasum": "" + }, + "require": { + "php": "^8.1", + "psr\/container": "^1.1.1|^2.0.1", + "psr\/simple-cache": "^1.0|^2.0|^3.0" + }, + "time": "2024-01-15T18:52:32+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "10.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "SwissKnife202405\\Illuminate\\Contracts\\": "" + } + }, + "notification-url": "https:\/\/packagist.org\/downloads\/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Illuminate Contracts package.", + "homepage": "https:\/\/laravel.com", + "support": { + "issues": "https:\/\/github.com\/laravel\/framework\/issues", + "source": "https:\/\/github.com\/laravel\/framework" + }, + "install-path": "..\/illuminate\/contracts" + }, + { + "name": "nette\/finder", + "version": "v2.6.0", + "version_normalized": "2.6.0.0", + "source": { + "type": "git", + "url": "https:\/\/github.com\/nette\/finder.git", + "reference": "991aefb42860abeab8e003970c3809a9d83cb932" + }, + "dist": { + "type": "zip", + "url": "https:\/\/api.github.com\/repos\/nette\/finder\/zipball\/991aefb42860abeab8e003970c3809a9d83cb932", + "reference": "991aefb42860abeab8e003970c3809a9d83cb932", + "shasum": "" + }, + "require": { + "nette\/utils": "^2.4 || ^3.0", + "php": ">=7.1" + }, + "conflict": { + "nette\/nette": "<2.2" + }, + "require-dev": { + "nette\/tester": "^2.0", + "phpstan\/phpstan": "^0.12", + "tracy\/tracy": "^2.3" + }, + "time": "2022-10-13T01:31:15+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "installation-source": "dist", + "autoload": { + "classmap": [ + "src\/" + ] + }, + "notification-url": "https:\/\/packagist.org\/downloads\/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https:\/\/davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https:\/\/nette.org\/contributors" + } + ], + "description": "\ud83d\udd0d Nette Finder: find files and directories with an intuitive API.", + "homepage": "https:\/\/nette.org", + "keywords": [ + "filesystem", + "glob", + "iterator", + "nette" + ], + "support": { + "issues": "https:\/\/github.com\/nette\/finder\/issues", + "source": "https:\/\/github.com\/nette\/finder\/tree\/v2.6.0" + }, + "install-path": "..\/nette\/finder" + }, + { + "name": "nette\/robot-loader", + "version": "v3.4.2", + "version_normalized": "3.4.2.0", + "source": { + "type": "git", + "url": "https:\/\/github.com\/nette\/robot-loader.git", + "reference": "970c8f82be98ec54180c88a468cd2b057855d993" + }, + "dist": { + "type": "zip", + "url": "https:\/\/api.github.com\/repos\/nette\/robot-loader\/zipball\/970c8f82be98ec54180c88a468cd2b057855d993", + "reference": "970c8f82be98ec54180c88a468cd2b057855d993", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "nette\/finder": "^2.5 || ^3.0", + "nette\/utils": "^3.0", + "php": ">=7.1" + }, + "require-dev": { + "nette\/tester": "^2.0", + "phpstan\/phpstan": "^0.12", + "tracy\/tracy": "^2.3" + }, + "time": "2022-12-14T15:41:06+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.4-dev" + } + }, + "installation-source": "dist", + "autoload": { + "classmap": [ + "src\/" + ] + }, + "notification-url": "https:\/\/packagist.org\/downloads\/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https:\/\/davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https:\/\/nette.org\/contributors" + } + ], + "description": "\ud83c\udf40 Nette RobotLoader: high performance and comfortable autoloader that will search and autoload classes within your application.", + "homepage": "https:\/\/nette.org", + "keywords": [ + "autoload", + "class", + "interface", + "nette", + "trait" + ], + "support": { + "issues": "https:\/\/github.com\/nette\/robot-loader\/issues", + "source": "https:\/\/github.com\/nette\/robot-loader\/tree\/v3.4.2" + }, + "install-path": "..\/nette\/robot-loader" + }, + { + "name": "nette\/utils", + "version": "v3.2.10", + "version_normalized": "3.2.10.0", + "source": { + "type": "git", + "url": "https:\/\/github.com\/nette\/utils.git", + "reference": "a4175c62652f2300c8017fb7e640f9ccb11648d2" + }, + "dist": { + "type": "zip", + "url": "https:\/\/api.github.com\/repos\/nette\/utils\/zipball\/a4175c62652f2300c8017fb7e640f9ccb11648d2", + "reference": "a4175c62652f2300c8017fb7e640f9ccb11648d2", + "shasum": "" + }, + "require": { + "php": ">=7.2 <8.4" + }, + "conflict": { + "nette\/di": "<3.0.6" + }, + "require-dev": { + "jetbrains\/phpstorm-attributes": "dev-master", + "nette\/tester": "~2.0", + "phpstan\/phpstan": "^1.0", + "tracy\/tracy": "^2.3" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()", + "ext-xml": "to use Strings::length() etc. when mbstring is not available" + }, + "time": "2023-07-30T15:38:18+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "installation-source": "dist", + "autoload": { + "classmap": [ + "src\/" + ] + }, + "notification-url": "https:\/\/packagist.org\/downloads\/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https:\/\/davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https:\/\/nette.org\/contributors" + } + ], + "description": "\ud83d\udee0 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding\/decoding, validation, slug or strong password generating etc.", + "homepage": "https:\/\/nette.org", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "support": { + "issues": "https:\/\/github.com\/nette\/utils\/issues", + "source": "https:\/\/github.com\/nette\/utils\/tree\/v3.2.10" + }, + "install-path": "..\/nette\/utils" + }, + { + "name": "nikic\/php-parser", + "version": "v4.19.1", + "version_normalized": "4.19.1.0", + "source": { + "type": "git", + "url": "https:\/\/github.com\/nikic\/PHP-Parser.git", + "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b" + }, + "dist": { + "type": "zip", + "url": "https:\/\/api.github.com\/repos\/nikic\/PHP-Parser\/zipball\/4e1b88d21c69391150ace211e9eaf05810858d0b", + "reference": "4e1b88d21c69391150ace211e9eaf05810858d0b", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.1" + }, + "require-dev": { + "ircmaxell\/php-yacc": "^0.0.7", + "phpunit\/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "time": "2024-03-17T08:10:35+00:00", + "bin": [ + "bin\/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.9-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "SwissKnife202405\\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" + ], + "support": { + "issues": "https:\/\/github.com\/nikic\/PHP-Parser\/issues", + "source": "https:\/\/github.com\/nikic\/PHP-Parser\/tree\/v4.19.1" + }, + "install-path": "..\/nikic\/php-parser" + }, + { + "name": "psr\/container", + "version": "2.0.2", + "version_normalized": "2.0.2.0", + "source": { + "type": "git", + "url": "https:\/\/github.com\/php-fig\/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https:\/\/api.github.com\/repos\/php-fig\/container\/zipball\/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "time": "2021-11-05T16:47:00+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "SwissKnife202405\\Psr\\Container\\": "src\/" + } + }, + "notification-url": "https:\/\/packagist.org\/downloads\/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https:\/\/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" + ], + "support": { + "issues": "https:\/\/github.com\/php-fig\/container\/issues", + "source": "https:\/\/github.com\/php-fig\/container\/tree\/2.0.2" + }, + "install-path": "..\/psr\/container" + }, + { + "name": "psr\/simple-cache", + "version": "3.0.0", + "version_normalized": "3.0.0.0", + "source": { + "type": "git", + "url": "https:\/\/github.com\/php-fig\/simple-cache.git", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" + }, + "dist": { + "type": "zip", + "url": "https:\/\/api.github.com\/repos\/php-fig\/simple-cache\/zipball\/764e0b3939f5ca87cb904f570ef9be2d78a07865", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "time": "2021-10-29T13:26:27+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "SwissKnife202405\\Psr\\SimpleCache\\": "src\/" + } + }, + "notification-url": "https:\/\/packagist.org\/downloads\/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https:\/\/www.php-fig.org\/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https:\/\/github.com\/php-fig\/simple-cache\/tree\/3.0.0" + }, + "install-path": "..\/psr\/simple-cache" + }, + { + "name": "symfony\/console", + "version": "v6.4.7", + "version_normalized": "6.4.7.0", + "source": { + "type": "git", + "url": "https:\/\/github.com\/symfony\/console.git", + "reference": "a170e64ae10d00ba89e2acbb590dc2e54da8ad8f" + }, + "dist": { + "type": "zip", + "url": "https:\/\/api.github.com\/repos\/symfony\/console\/zipball\/a170e64ae10d00ba89e2acbb590dc2e54da8ad8f", + "reference": "a170e64ae10d00ba89e2acbb590dc2e54da8ad8f", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony\/deprecation-contracts": "^2.5|^3", + "symfony\/polyfill-mbstring": "~1.0", + "symfony\/service-contracts": "^2.5|^3", + "symfony\/string": "^5.4|^6.0|^7.0" + }, + "conflict": { + "symfony\/dependency-injection": "<5.4", + "symfony\/dotenv": "<5.4", + "symfony\/event-dispatcher": "<5.4", + "symfony\/lock": "<5.4", + "symfony\/process": "<5.4" + }, + "provide": { + "psr\/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr\/log": "^1|^2|^3", + "symfony\/config": "^5.4|^6.0|^7.0", + "symfony\/dependency-injection": "^5.4|^6.0|^7.0", + "symfony\/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony\/http-foundation": "^6.4|^7.0", + "symfony\/http-kernel": "^6.4|^7.0", + "symfony\/lock": "^5.4|^6.0|^7.0", + "symfony\/messenger": "^5.4|^6.0|^7.0", + "symfony\/process": "^5.4|^6.0|^7.0", + "symfony\/stopwatch": "^5.4|^6.0|^7.0", + "symfony\/var-dumper": "^5.4|^6.0|^7.0" + }, + "time": "2024-04-18T09:22:46+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "SwissKnife202405\\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": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https:\/\/symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], + "support": { + "source": "https:\/\/github.com\/symfony\/console\/tree\/v6.4.7" + }, + "funding": [ + { + "url": "https:\/\/symfony.com\/sponsor", + "type": "custom" + }, + { + "url": "https:\/\/github.com\/fabpot", + "type": "github" + }, + { + "url": "https:\/\/tidelift.com\/funding\/github\/packagist\/symfony\/symfony", + "type": "tidelift" + } + ], + "install-path": "..\/symfony\/console" + }, + { + "name": "symfony\/deprecation-contracts", + "version": "v3.5.0", + "version_normalized": "3.5.0.0", + "source": { + "type": "git", + "url": "https:\/\/github.com\/symfony\/deprecation-contracts.git", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" + }, + "dist": { + "type": "zip", + "url": "https:\/\/api.github.com\/repos\/symfony\/deprecation-contracts\/zipball\/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "time": "2024-04-18T09:32:20+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony\/contracts", + "url": "https:\/\/github.com\/symfony\/contracts" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "function.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": "A generic function and convention to trigger deprecation notices", + "homepage": "https:\/\/symfony.com", + "support": { + "source": "https:\/\/github.com\/symfony\/deprecation-contracts\/tree\/v3.5.0" + }, + "funding": [ + { + "url": "https:\/\/symfony.com\/sponsor", + "type": "custom" + }, + { + "url": "https:\/\/github.com\/fabpot", + "type": "github" + }, + { + "url": "https:\/\/tidelift.com\/funding\/github\/packagist\/symfony\/symfony", + "type": "tidelift" + } + ], + "install-path": "..\/symfony\/deprecation-contracts" + }, + { + "name": "symfony\/finder", + "version": "v6.4.7", + "version_normalized": "6.4.7.0", + "source": { + "type": "git", + "url": "https:\/\/github.com\/symfony\/finder.git", + "reference": "511c48990be17358c23bf45c5d71ab85d40fb764" + }, + "dist": { + "type": "zip", + "url": "https:\/\/api.github.com\/repos\/symfony\/finder\/zipball\/511c48990be17358c23bf45c5d71ab85d40fb764", + "reference": "511c48990be17358c23bf45c5d71ab85d40fb764", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "symfony\/filesystem": "^6.0|^7.0" + }, + "time": "2024-04-23T10:36:43+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "SwissKnife202405\\Symfony\\Component\\Finder\\": "" + }, + "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": "Finds files and directories via an intuitive fluent interface", + "homepage": "https:\/\/symfony.com", + "support": { + "source": "https:\/\/github.com\/symfony\/finder\/tree\/v6.4.7" + }, + "funding": [ + { + "url": "https:\/\/symfony.com\/sponsor", + "type": "custom" + }, + { + "url": "https:\/\/github.com\/fabpot", + "type": "github" + }, + { + "url": "https:\/\/tidelift.com\/funding\/github\/packagist\/symfony\/symfony", + "type": "tidelift" + } + ], + "install-path": "..\/symfony\/finder" + }, + { + "name": "symfony\/polyfill-intl-grapheme", + "version": "v1.29.0", + "version_normalized": "1.29.0.0", + "source": { + "type": "git", + "url": "https:\/\/github.com\/symfony\/polyfill-intl-grapheme.git", + "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f" + }, + "dist": { + "type": "zip", + "url": "https:\/\/api.github.com\/repos\/symfony\/polyfill-intl-grapheme\/zipball\/32a9da87d7b3245e09ac426c83d334ae9f06f80f", + "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "time": "2024-01-29T20:11:03+00:00", + "type": "library", + "extra": { + "thanks": { + "name": "symfony\/polyfill", + "url": "https:\/\/github.com\/symfony\/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "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 intl's grapheme_* functions", + "homepage": "https:\/\/symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https:\/\/github.com\/symfony\/polyfill-intl-grapheme\/tree\/v1.29.0" + }, + "funding": [ + { + "url": "https:\/\/symfony.com\/sponsor", + "type": "custom" + }, + { + "url": "https:\/\/github.com\/fabpot", + "type": "github" + }, + { + "url": "https:\/\/tidelift.com\/funding\/github\/packagist\/symfony\/symfony", + "type": "tidelift" + } + ], + "install-path": "..\/symfony\/polyfill-intl-grapheme" + }, + { + "name": "symfony\/process", + "version": "v6.4.7", + "version_normalized": "6.4.7.0", + "source": { + "type": "git", + "url": "https:\/\/github.com\/symfony\/process.git", + "reference": "cdb1c81c145fd5aa9b0038bab694035020943381" + }, + "dist": { + "type": "zip", + "url": "https:\/\/api.github.com\/repos\/symfony\/process\/zipball\/cdb1c81c145fd5aa9b0038bab694035020943381", + "reference": "cdb1c81c145fd5aa9b0038bab694035020943381", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "time": "2024-04-18T09:22:46+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "SwissKnife202405\\Symfony\\Component\\Process\\": "" + }, + "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": "Executes commands in sub-processes", + "homepage": "https:\/\/symfony.com", + "support": { + "source": "https:\/\/github.com\/symfony\/process\/tree\/v6.4.7" + }, + "funding": [ + { + "url": "https:\/\/symfony.com\/sponsor", + "type": "custom" + }, + { + "url": "https:\/\/github.com\/fabpot", + "type": "github" + }, + { + "url": "https:\/\/tidelift.com\/funding\/github\/packagist\/symfony\/symfony", + "type": "tidelift" + } + ], + "install-path": "..\/symfony\/process" + }, + { + "name": "symfony\/service-contracts", + "version": "v3.5.0", + "version_normalized": "3.5.0.0", + "source": { + "type": "git", + "url": "https:\/\/github.com\/symfony\/service-contracts.git", + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f" + }, + "dist": { + "type": "zip", + "url": "https:\/\/api.github.com\/repos\/symfony\/service-contracts\/zipball\/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr\/container": "^1.1|^2.0", + "symfony\/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "time": "2024-04-18T09:32:20+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony\/contracts", + "url": "https:\/\/github.com\/symfony\/contracts" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "SwissKnife202405\\Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "\/Test\/" + ] + }, + "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" + ], + "support": { + "source": "https:\/\/github.com\/symfony\/service-contracts\/tree\/v3.5.0" + }, + "funding": [ + { + "url": "https:\/\/symfony.com\/sponsor", + "type": "custom" + }, + { + "url": "https:\/\/github.com\/fabpot", + "type": "github" + }, + { + "url": "https:\/\/tidelift.com\/funding\/github\/packagist\/symfony\/symfony", + "type": "tidelift" + } + ], + "install-path": "..\/symfony\/service-contracts" + }, + { + "name": "symfony\/string", + "version": "v7.0.7", + "version_normalized": "7.0.7.0", + "source": { + "type": "git", + "url": "https:\/\/github.com\/symfony\/string.git", + "reference": "e405b5424dc2528e02e31ba26b83a79fd4eb8f63" + }, + "dist": { + "type": "zip", + "url": "https:\/\/api.github.com\/repos\/symfony\/string\/zipball\/e405b5424dc2528e02e31ba26b83a79fd4eb8f63", + "reference": "e405b5424dc2528e02e31ba26b83a79fd4eb8f63", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony\/polyfill-ctype": "~1.8", + "symfony\/polyfill-intl-grapheme": "~1.0", + "symfony\/polyfill-intl-normalizer": "~1.0", + "symfony\/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony\/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony\/error-handler": "^6.4|^7.0", + "symfony\/http-client": "^6.4|^7.0", + "symfony\/intl": "^6.4|^7.0", + "symfony\/translation-contracts": "^2.5|^3.0", + "symfony\/var-exporter": "^6.4|^7.0" + }, + "time": "2024-04-18T09:29:19+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "Resources\/functions.php" + ], + "psr-4": { + "SwissKnife202405\\Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "\/Tests\/" + ] + }, + "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": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https:\/\/symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https:\/\/github.com\/symfony\/string\/tree\/v7.0.7" + }, + "funding": [ + { + "url": "https:\/\/symfony.com\/sponsor", + "type": "custom" + }, + { + "url": "https:\/\/github.com\/fabpot", + "type": "github" + }, + { + "url": "https:\/\/tidelift.com\/funding\/github\/packagist\/symfony\/symfony", + "type": "tidelift" + } + ], + "install-path": "..\/symfony\/string" + }, + { + "name": "webmozart\/assert", + "version": "1.11.0", + "version_normalized": "1.11.0.0", + "source": { + "type": "git", + "url": "https:\/\/github.com\/webmozarts\/assert.git", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + }, + "dist": { + "type": "zip", + "url": "https:\/\/api.github.com\/repos\/webmozarts\/assert\/zipball\/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "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" + }, + "time": "2022-06-03T18:03:27+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "SwissKnife202405\\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" + ], + "support": { + "issues": "https:\/\/github.com\/webmozarts\/assert\/issues", + "source": "https:\/\/github.com\/webmozarts\/assert\/tree\/1.11.0" + }, + "install-path": "..\/webmozart\/assert" + } + ], + "dev": false, + "dev-package-names": [] +} \ No newline at end of file diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php new file mode 100644 index 0000000000..7d61333df9 --- /dev/null +++ b/vendor/composer/installed.php @@ -0,0 +1,5 @@ + array('name' => 'rector/swiss-knife', 'pretty_version' => '0.2.7', 'version' => '0.2.7.0', 'reference' => '8050337b2b7ea02395ddbf9e7fc9ce2321ef3fb8', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev' => \false), 'versions' => array('illuminate/container' => array('pretty_version' => 'v10.48.12', 'version' => '10.48.12.0', 'reference' => 'ddc26273085fad3c471b2602ad820e0097ff7939', 'type' => 'library', 'install_path' => __DIR__ . '/../illuminate/container', 'aliases' => array(), 'dev_requirement' => \false), 'illuminate/contracts' => array('pretty_version' => 'v10.48.12', 'version' => '10.48.12.0', 'reference' => '8d7152c4a1f5d9cf7da3e8b71f23e4556f6138ac', 'type' => 'library', 'install_path' => __DIR__ . '/../illuminate/contracts', 'aliases' => array(), 'dev_requirement' => \false), 'nette/finder' => array('pretty_version' => 'v2.6.0', 'version' => '2.6.0.0', 'reference' => '991aefb42860abeab8e003970c3809a9d83cb932', 'type' => 'library', 'install_path' => __DIR__ . '/../nette/finder', 'aliases' => array(), 'dev_requirement' => \false), 'nette/robot-loader' => array('pretty_version' => 'v3.4.2', 'version' => '3.4.2.0', 'reference' => '970c8f82be98ec54180c88a468cd2b057855d993', 'type' => 'library', 'install_path' => __DIR__ . '/../nette/robot-loader', 'aliases' => array(), 'dev_requirement' => \false), 'nette/utils' => array('pretty_version' => 'v3.2.10', 'version' => '3.2.10.0', 'reference' => 'a4175c62652f2300c8017fb7e640f9ccb11648d2', 'type' => 'library', 'install_path' => __DIR__ . '/../nette/utils', 'aliases' => array(), 'dev_requirement' => \false), 'nikic/php-parser' => array('pretty_version' => 'v4.19.1', 'version' => '4.19.1.0', 'reference' => '4e1b88d21c69391150ace211e9eaf05810858d0b', 'type' => 'library', 'install_path' => __DIR__ . '/../nikic/php-parser', 'aliases' => array(), 'dev_requirement' => \false), 'psr/container' => array('pretty_version' => '2.0.2', 'version' => '2.0.2.0', 'reference' => 'c71ecc56dfe541dbd90c5360474fbc405f8d5963', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/container', 'aliases' => array(), 'dev_requirement' => \false), 'psr/container-implementation' => array('dev_requirement' => \false, 'provided' => array(0 => '1.1|2.0')), 'psr/log-implementation' => array('dev_requirement' => \false, 'provided' => array(0 => '1.0|2.0|3.0')), 'psr/simple-cache' => array('pretty_version' => '3.0.0', 'version' => '3.0.0.0', 'reference' => '764e0b3939f5ca87cb904f570ef9be2d78a07865', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/simple-cache', 'aliases' => array(), 'dev_requirement' => \false), 'rector/swiss-knife' => array('pretty_version' => '0.2.7', 'version' => '0.2.7.0', 'reference' => '8050337b2b7ea02395ddbf9e7fc9ce2321ef3fb8', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/console' => array('pretty_version' => 'v6.4.7', 'version' => '6.4.7.0', 'reference' => 'a170e64ae10d00ba89e2acbb590dc2e54da8ad8f', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/console', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/deprecation-contracts' => array('pretty_version' => 'v3.5.0', 'version' => '3.5.0.0', 'reference' => '0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/deprecation-contracts', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/finder' => array('pretty_version' => 'v6.4.7', 'version' => '6.4.7.0', 'reference' => '511c48990be17358c23bf45c5d71ab85d40fb764', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/finder', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/polyfill-ctype' => array('dev_requirement' => \false, 'replaced' => array(0 => '*')), 'symfony/polyfill-intl-grapheme' => array('pretty_version' => 'v1.29.0', 'version' => '1.29.0.0', 'reference' => '32a9da87d7b3245e09ac426c83d334ae9f06f80f', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-grapheme', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/polyfill-intl-normalizer' => array('dev_requirement' => \false, 'replaced' => array(0 => '*')), 'symfony/polyfill-mbstring' => array('dev_requirement' => \false, 'replaced' => array(0 => '*')), 'symfony/process' => array('pretty_version' => 'v6.4.7', 'version' => '6.4.7.0', 'reference' => 'cdb1c81c145fd5aa9b0038bab694035020943381', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/process', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/service-contracts' => array('pretty_version' => 'v3.5.0', 'version' => '3.5.0.0', 'reference' => 'bd1d9e59a81d8fa4acdcea3f617c581f7475a80f', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/service-contracts', 'aliases' => array(), 'dev_requirement' => \false), 'symfony/string' => array('pretty_version' => 'v7.0.7', 'version' => '7.0.7.0', 'reference' => 'e405b5424dc2528e02e31ba26b83a79fd4eb8f63', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/string', 'aliases' => array(), 'dev_requirement' => \false), 'webmozart/assert' => array('pretty_version' => '1.11.0', 'version' => '1.11.0.0', 'reference' => '11cb2199493b2f8a3b53e7f19068fc6aac760991', 'type' => 'library', 'install_path' => __DIR__ . '/../webmozart/assert', 'aliases' => array(), 'dev_requirement' => \false))); diff --git a/vendor/illuminate/container/BoundMethod.php b/vendor/illuminate/container/BoundMethod.php new file mode 100644 index 0000000000..d3ddd949f8 --- /dev/null +++ b/vendor/illuminate/container/BoundMethod.php @@ -0,0 +1,170 @@ +make($segments[0]), $method], $parameters); + } + /** + * Call a method that has been bound to the container. + * + * @param \Illuminate\Container\Container $container + * @param callable $callback + * @param mixed $default + * @return mixed + */ + protected static function callBoundMethod($container, $callback, $default) + { + if (!\is_array($callback)) { + return Util::unwrapIfClosure($default); + } + // Here we need to turn the array callable into a Class@method string we can use to + // examine the container and see if there are any method bindings for this given + // method. If there are, we can call this method binding callback immediately. + $method = static::normalizeMethod($callback); + if ($container->hasMethodBinding($method)) { + return $container->callMethodBinding($method, $callback[0]); + } + return Util::unwrapIfClosure($default); + } + /** + * Normalize the given callback into a Class@method string. + * + * @param callable $callback + * @return string + */ + protected static function normalizeMethod($callback) + { + $class = \is_string($callback[0]) ? $callback[0] : \get_class($callback[0]); + return "{$class}@{$callback[1]}"; + } + /** + * Get all dependencies for a given method. + * + * @param \Illuminate\Container\Container $container + * @param callable|string $callback + * @param array $parameters + * @return array + * + * @throws \ReflectionException + */ + protected static function getMethodDependencies($container, $callback, array $parameters = []) + { + $dependencies = []; + foreach (static::getCallReflector($callback)->getParameters() as $parameter) { + static::addDependencyForCallParameter($container, $parameter, $parameters, $dependencies); + } + return \array_merge($dependencies, \array_values($parameters)); + } + /** + * Get the proper reflection instance for the given callback. + * + * @param callable|string $callback + * @return \ReflectionFunctionAbstract + * + * @throws \ReflectionException + */ + protected static function getCallReflector($callback) + { + if (\is_string($callback) && \strpos($callback, '::') !== \false) { + $callback = \explode('::', $callback); + } elseif (\is_object($callback) && !$callback instanceof Closure) { + $callback = [$callback, '__invoke']; + } + return \is_array($callback) ? new ReflectionMethod($callback[0], $callback[1]) : new ReflectionFunction($callback); + } + /** + * Get the dependency for the given call parameter. + * + * @param \Illuminate\Container\Container $container + * @param \ReflectionParameter $parameter + * @param array $parameters + * @param array $dependencies + * @return void + * + * @throws \Illuminate\Contracts\Container\BindingResolutionException + */ + protected static function addDependencyForCallParameter($container, $parameter, array &$parameters, &$dependencies) + { + if (\array_key_exists($paramName = $parameter->getName(), $parameters)) { + $dependencies[] = $parameters[$paramName]; + unset($parameters[$paramName]); + } elseif (!\is_null($className = Util::getParameterClassName($parameter))) { + if (\array_key_exists($className, $parameters)) { + $dependencies[] = $parameters[$className]; + unset($parameters[$className]); + } elseif ($parameter->isVariadic()) { + $variadicDependencies = $container->make($className); + $dependencies = \array_merge($dependencies, \is_array($variadicDependencies) ? $variadicDependencies : [$variadicDependencies]); + } else { + $dependencies[] = $container->make($className); + } + } elseif ($parameter->isDefaultValueAvailable()) { + $dependencies[] = $parameter->getDefaultValue(); + } elseif (!$parameter->isOptional() && !\array_key_exists($paramName, $parameters)) { + $message = "Unable to resolve dependency [{$parameter}] in class {$parameter->getDeclaringClass()->getName()}"; + throw new BindingResolutionException($message); + } + } + /** + * Determine if the given string is in Class@method syntax. + * + * @param mixed $callback + * @return bool + */ + protected static function isCallableWithAtSign($callback) + { + return \is_string($callback) && \strpos($callback, '@') !== \false; + } +} diff --git a/vendor/illuminate/container/Container.php b/vendor/illuminate/container/Container.php new file mode 100755 index 0000000000..ea358499e5 --- /dev/null +++ b/vendor/illuminate/container/Container.php @@ -0,0 +1,1293 @@ +getAlias($c); + } + return new ContextualBindingBuilder($this, $aliases); + } + /** + * Determine if the given abstract type has been bound. + * + * @param string $abstract + * @return bool + */ + public function bound($abstract) + { + return isset($this->bindings[$abstract]) || isset($this->instances[$abstract]) || $this->isAlias($abstract); + } + /** + * {@inheritdoc} + * + * @return bool + */ + public function has(string $id) : bool + { + return $this->bound($id); + } + /** + * Determine if the given abstract type has been resolved. + * + * @param string $abstract + * @return bool + */ + public function resolved($abstract) + { + if ($this->isAlias($abstract)) { + $abstract = $this->getAlias($abstract); + } + return isset($this->resolved[$abstract]) || isset($this->instances[$abstract]); + } + /** + * Determine if a given type is shared. + * + * @param string $abstract + * @return bool + */ + public function isShared($abstract) + { + return isset($this->instances[$abstract]) || isset($this->bindings[$abstract]['shared']) && $this->bindings[$abstract]['shared'] === \true; + } + /** + * Determine if a given string is an alias. + * + * @param string $name + * @return bool + */ + public function isAlias($name) + { + return isset($this->aliases[$name]); + } + /** + * Register a binding with the container. + * + * @param string $abstract + * @param \Closure|string|null $concrete + * @param bool $shared + * @return void + * + * @throws \TypeError + */ + public function bind($abstract, $concrete = null, $shared = \false) + { + $this->dropStaleInstances($abstract); + // If no concrete type was given, we will simply set the concrete type to the + // abstract type. After that, the concrete type to be registered as shared + // without being forced to state their classes in both of the parameters. + if (\is_null($concrete)) { + $concrete = $abstract; + } + // If the factory is not a Closure, it means it is just a class name which is + // bound into this container to the abstract type and we will just wrap it + // up inside its own Closure to give us more convenience when extending. + if (!$concrete instanceof Closure) { + if (!\is_string($concrete)) { + throw new TypeError(self::class . '::bind(): Argument #2 ($concrete) must be of type Closure|string|null'); + } + $concrete = $this->getClosure($abstract, $concrete); + } + $this->bindings[$abstract] = \compact('concrete', 'shared'); + // If the abstract type was already resolved in this container we'll fire the + // rebound listener so that any objects which have already gotten resolved + // can have their copy of the object updated via the listener callbacks. + if ($this->resolved($abstract)) { + $this->rebound($abstract); + } + } + /** + * Get the Closure to be used when building a type. + * + * @param string $abstract + * @param string $concrete + * @return \Closure + */ + protected function getClosure($abstract, $concrete) + { + return function ($container, $parameters = []) use($abstract, $concrete) { + if ($abstract == $concrete) { + return $container->build($concrete); + } + return $container->resolve($concrete, $parameters, $raiseEvents = \false); + }; + } + /** + * Determine if the container has a method binding. + * + * @param string $method + * @return bool + */ + public function hasMethodBinding($method) + { + return isset($this->methodBindings[$method]); + } + /** + * Bind a callback to resolve with Container::call. + * + * @param array|string $method + * @param \Closure $callback + * @return void + */ + public function bindMethod($method, $callback) + { + $this->methodBindings[$this->parseBindMethod($method)] = $callback; + } + /** + * Get the method to be bound in class@method format. + * + * @param array|string $method + * @return string + */ + protected function parseBindMethod($method) + { + if (\is_array($method)) { + return $method[0] . '@' . $method[1]; + } + return $method; + } + /** + * Get the method binding for the given method. + * + * @param string $method + * @param mixed $instance + * @return mixed + */ + public function callMethodBinding($method, $instance) + { + return \call_user_func($this->methodBindings[$method], $instance, $this); + } + /** + * Add a contextual binding to the container. + * + * @param string $concrete + * @param string $abstract + * @param \Closure|string $implementation + * @return void + */ + public function addContextualBinding($concrete, $abstract, $implementation) + { + $this->contextual[$concrete][$this->getAlias($abstract)] = $implementation; + } + /** + * Register a binding if it hasn't already been registered. + * + * @param string $abstract + * @param \Closure|string|null $concrete + * @param bool $shared + * @return void + */ + public function bindIf($abstract, $concrete = null, $shared = \false) + { + if (!$this->bound($abstract)) { + $this->bind($abstract, $concrete, $shared); + } + } + /** + * Register a shared binding in the container. + * + * @param string $abstract + * @param \Closure|string|null $concrete + * @return void + */ + public function singleton($abstract, $concrete = null) + { + $this->bind($abstract, $concrete, \true); + } + /** + * Register a shared binding if it hasn't already been registered. + * + * @param string $abstract + * @param \Closure|string|null $concrete + * @return void + */ + public function singletonIf($abstract, $concrete = null) + { + if (!$this->bound($abstract)) { + $this->singleton($abstract, $concrete); + } + } + /** + * Register a scoped binding in the container. + * + * @param string $abstract + * @param \Closure|string|null $concrete + * @return void + */ + public function scoped($abstract, $concrete = null) + { + $this->scopedInstances[] = $abstract; + $this->singleton($abstract, $concrete); + } + /** + * Register a scoped binding if it hasn't already been registered. + * + * @param string $abstract + * @param \Closure|string|null $concrete + * @return void + */ + public function scopedIf($abstract, $concrete = null) + { + if (!$this->bound($abstract)) { + $this->scoped($abstract, $concrete); + } + } + /** + * "Extend" an abstract type in the container. + * + * @param string $abstract + * @param \Closure $closure + * @return void + * + * @throws \InvalidArgumentException + */ + public function extend($abstract, Closure $closure) + { + $abstract = $this->getAlias($abstract); + if (isset($this->instances[$abstract])) { + $this->instances[$abstract] = $closure($this->instances[$abstract], $this); + $this->rebound($abstract); + } else { + $this->extenders[$abstract][] = $closure; + if ($this->resolved($abstract)) { + $this->rebound($abstract); + } + } + } + /** + * Register an existing instance as shared in the container. + * + * @param string $abstract + * @param mixed $instance + * @return mixed + */ + public function instance($abstract, $instance) + { + $this->removeAbstractAlias($abstract); + $isBound = $this->bound($abstract); + unset($this->aliases[$abstract]); + // We'll check to determine if this type has been bound before, and if it has + // we will fire the rebound callbacks registered with the container and it + // can be updated with consuming classes that have gotten resolved here. + $this->instances[$abstract] = $instance; + if ($isBound) { + $this->rebound($abstract); + } + return $instance; + } + /** + * Remove an alias from the contextual binding alias cache. + * + * @param string $searched + * @return void + */ + protected function removeAbstractAlias($searched) + { + if (!isset($this->aliases[$searched])) { + return; + } + foreach ($this->abstractAliases as $abstract => $aliases) { + foreach ($aliases as $index => $alias) { + if ($alias == $searched) { + unset($this->abstractAliases[$abstract][$index]); + } + } + } + } + /** + * Assign a set of tags to a given binding. + * + * @param array|string $abstracts + * @param array|mixed ...$tags + * @return void + */ + public function tag($abstracts, $tags) + { + $tags = \is_array($tags) ? $tags : \array_slice(\func_get_args(), 1); + foreach ($tags as $tag) { + if (!isset($this->tags[$tag])) { + $this->tags[$tag] = []; + } + foreach ((array) $abstracts as $abstract) { + $this->tags[$tag][] = $abstract; + } + } + } + /** + * Resolve all of the bindings for a given tag. + * + * @param string $tag + * @return iterable + */ + public function tagged($tag) + { + if (!isset($this->tags[$tag])) { + return []; + } + return new RewindableGenerator(function () use($tag) { + foreach ($this->tags[$tag] as $abstract) { + (yield $this->make($abstract)); + } + }, \count($this->tags[$tag])); + } + /** + * Alias a type to a different name. + * + * @param string $abstract + * @param string $alias + * @return void + * + * @throws \LogicException + */ + public function alias($abstract, $alias) + { + if ($alias === $abstract) { + throw new LogicException("[{$abstract}] is aliased to itself."); + } + $this->aliases[$alias] = $abstract; + $this->abstractAliases[$abstract][] = $alias; + } + /** + * Bind a new callback to an abstract's rebind event. + * + * @param string $abstract + * @param \Closure $callback + * @return mixed + */ + public function rebinding($abstract, Closure $callback) + { + $this->reboundCallbacks[$abstract = $this->getAlias($abstract)][] = $callback; + if ($this->bound($abstract)) { + return $this->make($abstract); + } + } + /** + * Refresh an instance on the given target and method. + * + * @param string $abstract + * @param mixed $target + * @param string $method + * @return mixed + */ + public function refresh($abstract, $target, $method) + { + return $this->rebinding($abstract, function ($app, $instance) use($target, $method) { + $target->{$method}($instance); + }); + } + /** + * Fire the "rebound" callbacks for the given abstract type. + * + * @param string $abstract + * @return void + */ + protected function rebound($abstract) + { + $instance = $this->make($abstract); + foreach ($this->getReboundCallbacks($abstract) as $callback) { + $callback($this, $instance); + } + } + /** + * Get the rebound callbacks for a given type. + * + * @param string $abstract + * @return array + */ + protected function getReboundCallbacks($abstract) + { + return $this->reboundCallbacks[$abstract] ?? []; + } + /** + * Wrap the given closure such that its dependencies will be injected when executed. + * + * @param \Closure $callback + * @param array $parameters + * @return \Closure + */ + public function wrap(Closure $callback, array $parameters = []) + { + return function () use($callback, $parameters) { + return $this->call($callback, $parameters); + }; + } + /** + * Call the given Closure / class@method and inject its dependencies. + * + * @param callable|string $callback + * @param array $parameters + * @param string|null $defaultMethod + * @return mixed + * + * @throws \InvalidArgumentException + */ + public function call($callback, array $parameters = [], $defaultMethod = null) + { + $pushedToBuildStack = \false; + if (($className = $this->getClassForCallable($callback)) && !\in_array($className, $this->buildStack, \true)) { + $this->buildStack[] = $className; + $pushedToBuildStack = \true; + } + $result = BoundMethod::call($this, $callback, $parameters, $defaultMethod); + if ($pushedToBuildStack) { + \array_pop($this->buildStack); + } + return $result; + } + /** + * Get the class name for the given callback, if one can be determined. + * + * @param callable|string $callback + * @return string|false + */ + protected function getClassForCallable($callback) + { + if (\PHP_VERSION_ID >= 80200) { + if (\is_callable($callback) && !($reflector = new ReflectionFunction(\Closure::fromCallable($callback)))->isAnonymous()) { + return $reflector->getClosureScopeClass()->name ?? \false; + } + return \false; + } + if (!\is_array($callback)) { + return \false; + } + return \is_string($callback[0]) ? $callback[0] : \get_class($callback[0]); + } + /** + * Get a closure to resolve the given type from the container. + * + * @param string $abstract + * @return \Closure + */ + public function factory($abstract) + { + return function () use($abstract) { + return $this->make($abstract); + }; + } + /** + * An alias function name for make(). + * + * @param string|callable $abstract + * @param array $parameters + * @return mixed + * + * @throws \Illuminate\Contracts\Container\BindingResolutionException + */ + public function makeWith($abstract, array $parameters = []) + { + return $this->make($abstract, $parameters); + } + /** + * Resolve the given type from the container. + * + * @param string|callable $abstract + * @param array $parameters + * @return mixed + * + * @throws \Illuminate\Contracts\Container\BindingResolutionException + */ + public function make($abstract, array $parameters = []) + { + return $this->resolve($abstract, $parameters); + } + /** + * {@inheritdoc} + * + * @return mixed + */ + public function get(string $id) + { + try { + return $this->resolve($id); + } catch (Exception $e) { + if ($this->has($id) || $e instanceof CircularDependencyException) { + throw $e; + } + throw new EntryNotFoundException($id, \is_int($e->getCode()) ? $e->getCode() : 0, $e); + } + } + /** + * Resolve the given type from the container. + * + * @param string|callable $abstract + * @param array $parameters + * @param bool $raiseEvents + * @return mixed + * + * @throws \Illuminate\Contracts\Container\BindingResolutionException + * @throws \Illuminate\Contracts\Container\CircularDependencyException + */ + protected function resolve($abstract, $parameters = [], $raiseEvents = \true) + { + $abstract = $this->getAlias($abstract); + // First we'll fire any event handlers which handle the "before" resolving of + // specific types. This gives some hooks the chance to add various extends + // calls to change the resolution of objects that they're interested in. + if ($raiseEvents) { + $this->fireBeforeResolvingCallbacks($abstract, $parameters); + } + $concrete = $this->getContextualConcrete($abstract); + $needsContextualBuild = !empty($parameters) || !\is_null($concrete); + // If an instance of the type is currently being managed as a singleton we'll + // just return an existing instance instead of instantiating new instances + // so the developer can keep using the same objects instance every time. + if (isset($this->instances[$abstract]) && !$needsContextualBuild) { + return $this->instances[$abstract]; + } + $this->with[] = $parameters; + if (\is_null($concrete)) { + $concrete = $this->getConcrete($abstract); + } + // We're ready to instantiate an instance of the concrete type registered for + // the binding. This will instantiate the types, as well as resolve any of + // its "nested" dependencies recursively until all have gotten resolved. + $object = $this->isBuildable($concrete, $abstract) ? $this->build($concrete) : $this->make($concrete); + // If we defined any extenders for this type, we'll need to spin through them + // and apply them to the object being built. This allows for the extension + // of services, such as changing configuration or decorating the object. + foreach ($this->getExtenders($abstract) as $extender) { + $object = $extender($object, $this); + } + // If the requested type is registered as a singleton we'll want to cache off + // the instances in "memory" so we can return it later without creating an + // entirely new instance of an object on each subsequent request for it. + if ($this->isShared($abstract) && !$needsContextualBuild) { + $this->instances[$abstract] = $object; + } + if ($raiseEvents) { + $this->fireResolvingCallbacks($abstract, $object); + } + // Before returning, we will also set the resolved flag to "true" and pop off + // the parameter overrides for this build. After those two things are done + // we will be ready to return back the fully constructed class instance. + $this->resolved[$abstract] = \true; + \array_pop($this->with); + return $object; + } + /** + * Get the concrete type for a given abstract. + * + * @param string|callable $abstract + * @return mixed + */ + protected function getConcrete($abstract) + { + // If we don't have a registered resolver or concrete for the type, we'll just + // assume each type is a concrete name and will attempt to resolve it as is + // since the container should be able to resolve concretes automatically. + if (isset($this->bindings[$abstract])) { + return $this->bindings[$abstract]['concrete']; + } + return $abstract; + } + /** + * Get the contextual concrete binding for the given abstract. + * + * @param string|callable $abstract + * @return \Closure|string|array|null + */ + protected function getContextualConcrete($abstract) + { + if (!\is_null($binding = $this->findInContextualBindings($abstract))) { + return $binding; + } + // Next we need to see if a contextual binding might be bound under an alias of the + // given abstract type. So, we will need to check if any aliases exist with this + // type and then spin through them and check for contextual bindings on these. + if (empty($this->abstractAliases[$abstract])) { + return; + } + foreach ($this->abstractAliases[$abstract] as $alias) { + if (!\is_null($binding = $this->findInContextualBindings($alias))) { + return $binding; + } + } + } + /** + * Find the concrete binding for the given abstract in the contextual binding array. + * + * @param string|callable $abstract + * @return \Closure|string|null + */ + protected function findInContextualBindings($abstract) + { + return $this->contextual[\end($this->buildStack)][$abstract] ?? null; + } + /** + * Determine if the given concrete is buildable. + * + * @param mixed $concrete + * @param string $abstract + * @return bool + */ + protected function isBuildable($concrete, $abstract) + { + return $concrete === $abstract || $concrete instanceof Closure; + } + /** + * Instantiate a concrete instance of the given type. + * + * @param \Closure|string $concrete + * @return mixed + * + * @throws \Illuminate\Contracts\Container\BindingResolutionException + * @throws \Illuminate\Contracts\Container\CircularDependencyException + */ + public function build($concrete) + { + // If the concrete type is actually a Closure, we will just execute it and + // hand back the results of the functions, which allows functions to be + // used as resolvers for more fine-tuned resolution of these objects. + if ($concrete instanceof Closure) { + return $concrete($this, $this->getLastParameterOverride()); + } + try { + $reflector = new ReflectionClass($concrete); + } catch (ReflectionException $e) { + throw new BindingResolutionException("Target class [{$concrete}] does not exist.", 0, $e); + } + // If the type is not instantiable, the developer is attempting to resolve + // an abstract type such as an Interface or Abstract Class and there is + // no binding registered for the abstractions so we need to bail out. + if (!$reflector->isInstantiable()) { + return $this->notInstantiable($concrete); + } + $this->buildStack[] = $concrete; + $constructor = $reflector->getConstructor(); + // If there are no constructors, that means there are no dependencies then + // we can just resolve the instances of the objects right away, without + // resolving any other types or dependencies out of these containers. + if (\is_null($constructor)) { + \array_pop($this->buildStack); + return new $concrete(); + } + $dependencies = $constructor->getParameters(); + // Once we have all the constructor's parameters we can create each of the + // dependency instances and then use the reflection instances to make a + // new instance of this class, injecting the created dependencies in. + try { + $instances = $this->resolveDependencies($dependencies); + } catch (BindingResolutionException $e) { + \array_pop($this->buildStack); + throw $e; + } + \array_pop($this->buildStack); + return $reflector->newInstanceArgs($instances); + } + /** + * Resolve all of the dependencies from the ReflectionParameters. + * + * @param \ReflectionParameter[] $dependencies + * @return array + * + * @throws \Illuminate\Contracts\Container\BindingResolutionException + */ + protected function resolveDependencies(array $dependencies) + { + $results = []; + foreach ($dependencies as $dependency) { + // If the dependency has an override for this particular build we will use + // that instead as the value. Otherwise, we will continue with this run + // of resolutions and let reflection attempt to determine the result. + if ($this->hasParameterOverride($dependency)) { + $results[] = $this->getParameterOverride($dependency); + continue; + } + // If the class is null, it means the dependency is a string or some other + // primitive type which we can not resolve since it is not a class and + // we will just bomb out with an error since we have no-where to go. + $result = \is_null(Util::getParameterClassName($dependency)) ? $this->resolvePrimitive($dependency) : $this->resolveClass($dependency); + if ($dependency->isVariadic()) { + $results = \array_merge($results, $result); + } else { + $results[] = $result; + } + } + return $results; + } + /** + * Determine if the given dependency has a parameter override. + * + * @param \ReflectionParameter $dependency + * @return bool + */ + protected function hasParameterOverride($dependency) + { + return \array_key_exists($dependency->name, $this->getLastParameterOverride()); + } + /** + * Get a parameter override for a dependency. + * + * @param \ReflectionParameter $dependency + * @return mixed + */ + protected function getParameterOverride($dependency) + { + return $this->getLastParameterOverride()[$dependency->name]; + } + /** + * Get the last parameter override. + * + * @return array + */ + protected function getLastParameterOverride() + { + return \count($this->with) ? \end($this->with) : []; + } + /** + * Resolve a non-class hinted primitive dependency. + * + * @param \ReflectionParameter $parameter + * @return mixed + * + * @throws \Illuminate\Contracts\Container\BindingResolutionException + */ + protected function resolvePrimitive(ReflectionParameter $parameter) + { + if (!\is_null($concrete = $this->getContextualConcrete('$' . $parameter->getName()))) { + return Util::unwrapIfClosure($concrete, $this); + } + if ($parameter->isDefaultValueAvailable()) { + return $parameter->getDefaultValue(); + } + if ($parameter->isVariadic()) { + return []; + } + $this->unresolvablePrimitive($parameter); + } + /** + * Resolve a class based dependency from the container. + * + * @param \ReflectionParameter $parameter + * @return mixed + * + * @throws \Illuminate\Contracts\Container\BindingResolutionException + */ + protected function resolveClass(ReflectionParameter $parameter) + { + try { + return $parameter->isVariadic() ? $this->resolveVariadicClass($parameter) : $this->make(Util::getParameterClassName($parameter)); + } catch (BindingResolutionException $e) { + if ($parameter->isDefaultValueAvailable()) { + \array_pop($this->with); + return $parameter->getDefaultValue(); + } + if ($parameter->isVariadic()) { + \array_pop($this->with); + return []; + } + throw $e; + } + } + /** + * Resolve a class based variadic dependency from the container. + * + * @param \ReflectionParameter $parameter + * @return mixed + */ + protected function resolveVariadicClass(ReflectionParameter $parameter) + { + $className = Util::getParameterClassName($parameter); + $abstract = $this->getAlias($className); + if (!\is_array($concrete = $this->getContextualConcrete($abstract))) { + return $this->make($className); + } + return \array_map(function ($abstract) { + return $this->resolve($abstract); + }, $concrete); + } + /** + * Throw an exception that the concrete is not instantiable. + * + * @param string $concrete + * @return void + * + * @throws \Illuminate\Contracts\Container\BindingResolutionException + */ + protected function notInstantiable($concrete) + { + if (!empty($this->buildStack)) { + $previous = \implode(', ', $this->buildStack); + $message = "Target [{$concrete}] is not instantiable while building [{$previous}]."; + } else { + $message = "Target [{$concrete}] is not instantiable."; + } + throw new BindingResolutionException($message); + } + /** + * Throw an exception for an unresolvable primitive. + * + * @param \ReflectionParameter $parameter + * @return void + * + * @throws \Illuminate\Contracts\Container\BindingResolutionException + */ + protected function unresolvablePrimitive(ReflectionParameter $parameter) + { + $message = "Unresolvable dependency resolving [{$parameter}] in class {$parameter->getDeclaringClass()->getName()}"; + throw new BindingResolutionException($message); + } + /** + * Register a new before resolving callback for all types. + * + * @param \Closure|string $abstract + * @param \Closure|null $callback + * @return void + */ + public function beforeResolving($abstract, Closure $callback = null) + { + if (\is_string($abstract)) { + $abstract = $this->getAlias($abstract); + } + if ($abstract instanceof Closure && \is_null($callback)) { + $this->globalBeforeResolvingCallbacks[] = $abstract; + } else { + $this->beforeResolvingCallbacks[$abstract][] = $callback; + } + } + /** + * Register a new resolving callback. + * + * @param \Closure|string $abstract + * @param \Closure|null $callback + * @return void + */ + public function resolving($abstract, Closure $callback = null) + { + if (\is_string($abstract)) { + $abstract = $this->getAlias($abstract); + } + if (\is_null($callback) && $abstract instanceof Closure) { + $this->globalResolvingCallbacks[] = $abstract; + } else { + $this->resolvingCallbacks[$abstract][] = $callback; + } + } + /** + * Register a new after resolving callback for all types. + * + * @param \Closure|string $abstract + * @param \Closure|null $callback + * @return void + */ + public function afterResolving($abstract, Closure $callback = null) + { + if (\is_string($abstract)) { + $abstract = $this->getAlias($abstract); + } + if ($abstract instanceof Closure && \is_null($callback)) { + $this->globalAfterResolvingCallbacks[] = $abstract; + } else { + $this->afterResolvingCallbacks[$abstract][] = $callback; + } + } + /** + * Fire all of the before resolving callbacks. + * + * @param string $abstract + * @param array $parameters + * @return void + */ + protected function fireBeforeResolvingCallbacks($abstract, $parameters = []) + { + $this->fireBeforeCallbackArray($abstract, $parameters, $this->globalBeforeResolvingCallbacks); + foreach ($this->beforeResolvingCallbacks as $type => $callbacks) { + if ($type === $abstract || \is_subclass_of($abstract, $type)) { + $this->fireBeforeCallbackArray($abstract, $parameters, $callbacks); + } + } + } + /** + * Fire an array of callbacks with an object. + * + * @param string $abstract + * @param array $parameters + * @param array $callbacks + * @return void + */ + protected function fireBeforeCallbackArray($abstract, $parameters, array $callbacks) + { + foreach ($callbacks as $callback) { + $callback($abstract, $parameters, $this); + } + } + /** + * Fire all of the resolving callbacks. + * + * @param string $abstract + * @param mixed $object + * @return void + */ + protected function fireResolvingCallbacks($abstract, $object) + { + $this->fireCallbackArray($object, $this->globalResolvingCallbacks); + $this->fireCallbackArray($object, $this->getCallbacksForType($abstract, $object, $this->resolvingCallbacks)); + $this->fireAfterResolvingCallbacks($abstract, $object); + } + /** + * Fire all of the after resolving callbacks. + * + * @param string $abstract + * @param mixed $object + * @return void + */ + protected function fireAfterResolvingCallbacks($abstract, $object) + { + $this->fireCallbackArray($object, $this->globalAfterResolvingCallbacks); + $this->fireCallbackArray($object, $this->getCallbacksForType($abstract, $object, $this->afterResolvingCallbacks)); + } + /** + * Get all callbacks for a given type. + * + * @param string $abstract + * @param object $object + * @param array $callbacksPerType + * @return array + */ + protected function getCallbacksForType($abstract, $object, array $callbacksPerType) + { + $results = []; + foreach ($callbacksPerType as $type => $callbacks) { + if ($type === $abstract || $object instanceof $type) { + $results = \array_merge($results, $callbacks); + } + } + return $results; + } + /** + * Fire an array of callbacks with an object. + * + * @param mixed $object + * @param array $callbacks + * @return void + */ + protected function fireCallbackArray($object, array $callbacks) + { + foreach ($callbacks as $callback) { + $callback($object, $this); + } + } + /** + * Get the container's bindings. + * + * @return array + */ + public function getBindings() + { + return $this->bindings; + } + /** + * Get the alias for an abstract if available. + * + * @param string $abstract + * @return string + */ + public function getAlias($abstract) + { + return isset($this->aliases[$abstract]) ? $this->getAlias($this->aliases[$abstract]) : $abstract; + } + /** + * Get the extender callbacks for a given type. + * + * @param string $abstract + * @return array + */ + protected function getExtenders($abstract) + { + return $this->extenders[$this->getAlias($abstract)] ?? []; + } + /** + * Remove all of the extender callbacks for a given type. + * + * @param string $abstract + * @return void + */ + public function forgetExtenders($abstract) + { + unset($this->extenders[$this->getAlias($abstract)]); + } + /** + * Drop all of the stale instances and aliases. + * + * @param string $abstract + * @return void + */ + protected function dropStaleInstances($abstract) + { + unset($this->instances[$abstract], $this->aliases[$abstract]); + } + /** + * Remove a resolved instance from the instance cache. + * + * @param string $abstract + * @return void + */ + public function forgetInstance($abstract) + { + unset($this->instances[$abstract]); + } + /** + * Clear all of the instances from the container. + * + * @return void + */ + public function forgetInstances() + { + $this->instances = []; + } + /** + * Clear all of the scoped instances from the container. + * + * @return void + */ + public function forgetScopedInstances() + { + foreach ($this->scopedInstances as $scoped) { + unset($this->instances[$scoped]); + } + } + /** + * Flush the container of all bindings and resolved instances. + * + * @return void + */ + public function flush() + { + $this->aliases = []; + $this->resolved = []; + $this->bindings = []; + $this->instances = []; + $this->abstractAliases = []; + $this->scopedInstances = []; + } + /** + * Get the globally available instance of the container. + * + * @return static + */ + public static function getInstance() + { + if (\is_null(static::$instance)) { + static::$instance = new static(); + } + return static::$instance; + } + /** + * Set the shared instance of the container. + * + * @param \Illuminate\Contracts\Container\Container|null $container + * @return \Illuminate\Contracts\Container\Container|static + */ + public static function setInstance(ContainerContract $container = null) + { + return static::$instance = $container; + } + /** + * Determine if a given offset exists. + * + * @param string $key + * @return bool + */ + public function offsetExists($key) : bool + { + return $this->bound($key); + } + /** + * Get the value at a given offset. + * + * @param string $key + * @return mixed + */ + #[\ReturnTypeWillChange] + public function offsetGet($key) + { + return $this->make($key); + } + /** + * Set the value at a given offset. + * + * @param string $key + * @param mixed $value + * @return void + */ + public function offsetSet($key, $value) : void + { + $this->bind($key, $value instanceof Closure ? $value : function () use($value) { + return $value; + }); + } + /** + * Unset the value at a given offset. + * + * @param string $key + * @return void + */ + public function offsetUnset($key) : void + { + unset($this->bindings[$key], $this->instances[$key], $this->resolved[$key]); + } + /** + * Dynamically access container services. + * + * @param string $key + * @return mixed + */ + public function __get($key) + { + return $this[$key]; + } + /** + * Dynamically set container services. + * + * @param string $key + * @param mixed $value + * @return void + */ + public function __set($key, $value) + { + $this[$key] = $value; + } +} diff --git a/vendor/illuminate/container/ContextualBindingBuilder.php b/vendor/illuminate/container/ContextualBindingBuilder.php new file mode 100644 index 0000000000..0c46bc0b36 --- /dev/null +++ b/vendor/illuminate/container/ContextualBindingBuilder.php @@ -0,0 +1,88 @@ +concrete = $concrete; + $this->container = $container; + } + /** + * Define the abstract target that depends on the context. + * + * @param string $abstract + * @return $this + */ + public function needs($abstract) + { + $this->needs = $abstract; + return $this; + } + /** + * Define the implementation for the contextual binding. + * + * @param \Closure|string|array $implementation + * @return void + */ + public function give($implementation) + { + foreach (Util::arrayWrap($this->concrete) as $concrete) { + $this->container->addContextualBinding($concrete, $this->needs, $implementation); + } + } + /** + * Define tagged services to be used as the implementation for the contextual binding. + * + * @param string $tag + * @return void + */ + public function giveTagged($tag) + { + $this->give(function ($container) use($tag) { + $taggedServices = $container->tagged($tag); + return \is_array($taggedServices) ? $taggedServices : \iterator_to_array($taggedServices); + }); + } + /** + * Specify the configuration item to bind as a primitive. + * + * @param string $key + * @param mixed $default + * @return void + */ + public function giveConfig($key, $default = null) + { + $this->give(function ($container) use($key, $default) { + return $container->get('config')->get($key, $default); + }); + } +} diff --git a/vendor/illuminate/container/EntryNotFoundException.php b/vendor/illuminate/container/EntryNotFoundException.php new file mode 100644 index 0000000000..2e00ea3fba --- /dev/null +++ b/vendor/illuminate/container/EntryNotFoundException.php @@ -0,0 +1,10 @@ +count = $count; + $this->generator = $generator; + } + /** + * Get an iterator from the generator. + * + * @return \Traversable + */ + public function getIterator() : Traversable + { + return ($this->generator)(); + } + /** + * Get the total number of tagged services. + * + * @return int + */ + public function count() : int + { + if (\is_callable($count = $this->count)) { + $this->count = $count(); + } + return $this->count; + } +} diff --git a/vendor/illuminate/container/Util.php b/vendor/illuminate/container/Util.php new file mode 100644 index 0000000000..3414ae061e --- /dev/null +++ b/vendor/illuminate/container/Util.php @@ -0,0 +1,65 @@ +getType(); + if (!$type instanceof ReflectionNamedType || $type->isBuiltin()) { + return null; + } + $name = $type->getName(); + if (!\is_null($class = $parameter->getDeclaringClass())) { + if ($name === 'self') { + return $class->getName(); + } + if ($name === 'parent' && ($parent = $class->getParentClass())) { + return $parent->getName(); + } + } + return $name; + } +} diff --git a/vendor/illuminate/container/composer.json b/vendor/illuminate/container/composer.json new file mode 100755 index 0000000000..a7385c1880 --- /dev/null +++ b/vendor/illuminate/container/composer.json @@ -0,0 +1,38 @@ +{ + "name": "illuminate\/container", + "description": "The Illuminate Container package.", + "license": "MIT", + "homepage": "https:\/\/laravel.com", + "support": { + "issues": "https:\/\/github.com\/laravel\/framework\/issues", + "source": "https:\/\/github.com\/laravel\/framework" + }, + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "require": { + "php": "^8.1", + "illuminate\/contracts": "^10.0", + "psr\/container": "^1.1.1|^2.0.1" + }, + "provide": { + "psr\/container-implementation": "1.1|2.0" + }, + "autoload": { + "psr-4": { + "SwissKnife202405\\Illuminate\\Container\\": "" + } + }, + "extra": { + "branch-alias": { + "dev-master": "10.x-dev" + } + }, + "config": { + "sort-packages": true + }, + "minimum-stability": "dev" +} \ No newline at end of file diff --git a/vendor/illuminate/contracts/Auth/Access/Authorizable.php b/vendor/illuminate/contracts/Auth/Access/Authorizable.php new file mode 100644 index 0000000000..411a340d0b --- /dev/null +++ b/vendor/illuminate/contracts/Auth/Access/Authorizable.php @@ -0,0 +1,15 @@ +|CastsAttributes|CastsInboundAttributes + */ + public static function castUsing(array $arguments); +} diff --git a/vendor/illuminate/contracts/Database/Eloquent/CastsAttributes.php b/vendor/illuminate/contracts/Database/Eloquent/CastsAttributes.php new file mode 100644 index 0000000000..82f0c3e144 --- /dev/null +++ b/vendor/illuminate/contracts/Database/Eloquent/CastsAttributes.php @@ -0,0 +1,32 @@ + $attributes + * @return TGet|null + */ + public function get(Model $model, string $key, $value, array $attributes); + /** + * Transform the attribute to its underlying model values. + * + * @param \Illuminate\Database\Eloquent\Model $model + * @param string $key + * @param mixed $value + * @param array $attributes + * @return mixed + */ + public function set(Model $model, string $key, $value, array $attributes); +} diff --git a/vendor/illuminate/contracts/Database/Eloquent/CastsInboundAttributes.php b/vendor/illuminate/contracts/Database/Eloquent/CastsInboundAttributes.php new file mode 100644 index 0000000000..9921e40e9f --- /dev/null +++ b/vendor/illuminate/contracts/Database/Eloquent/CastsInboundAttributes.php @@ -0,0 +1,18 @@ +id = $id; + $this->class = $class; + $this->relations = $relations; + $this->connection = $connection; + } + /** + * Specify the collection class that should be used when serializing / restoring collections. + * + * @param string|null $collectionClass + * @return $this + */ + public function useCollectionClass(?string $collectionClass) + { + $this->collectionClass = $collectionClass; + return $this; + } +} diff --git a/vendor/illuminate/contracts/Database/Query/Builder.php b/vendor/illuminate/contracts/Database/Query/Builder.php new file mode 100644 index 0000000000..384ce5ad3b --- /dev/null +++ b/vendor/illuminate/contracts/Database/Query/Builder.php @@ -0,0 +1,12 @@ + + */ + public function getQueueableIds(); + /** + * Get the relationships of the entities being queued. + * + * @return array + */ + public function getQueueableRelations(); + /** + * Get the connection of the entities being queued. + * + * @return string|null + */ + public function getQueueableConnection(); +} diff --git a/vendor/illuminate/contracts/Queue/QueueableEntity.php b/vendor/illuminate/contracts/Queue/QueueableEntity.php new file mode 100644 index 0000000000..91f282ceb2 --- /dev/null +++ b/vendor/illuminate/contracts/Queue/QueueableEntity.php @@ -0,0 +1,25 @@ + + */ + public function toArray(); +} diff --git a/vendor/illuminate/contracts/Support/CanBeEscapedWhenCastToString.php b/vendor/illuminate/contracts/Support/CanBeEscapedWhenCastToString.php new file mode 100644 index 0000000000..3216cc724a --- /dev/null +++ b/vendor/illuminate/contracts/Support/CanBeEscapedWhenCastToString.php @@ -0,0 +1,14 @@ +=7.1", + "nette\/utils": "^2.4 || ^3.0" + }, + "require-dev": { + "nette\/tester": "^2.0", + "tracy\/tracy": "^2.3", + "phpstan\/phpstan": "^0.12" + }, + "conflict": { + "nette\/nette": "<2.2" + }, + "autoload": { + "classmap": [ + "src\/" + ] + }, + "minimum-stability": "dev", + "scripts": { + "phpstan": "phpstan analyse", + "tester": "tester tests -s" + }, + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + } +} \ No newline at end of file diff --git a/vendor/nette/finder/license.md b/vendor/nette/finder/license.md new file mode 100644 index 0000000000..cf741bd05f --- /dev/null +++ b/vendor/nette/finder/license.md @@ -0,0 +1,60 @@ +Licenses +======== + +Good news! You may use Nette Framework under the terms of either +the New BSD License or the GNU General Public License (GPL) version 2 or 3. + +The BSD License is recommended for most projects. It is easy to understand and it +places almost no restrictions on what you can do with the framework. If the GPL +fits better to your project, you can use the framework under this license. + +You don't have to notify anyone which license you are using. You can freely +use Nette Framework in commercial projects as long as the copyright header +remains intact. + +Please be advised that the name "Nette Framework" is a protected trademark and its +usage has some limitations. So please do not use word "Nette" in the name of your +project or top-level domain, and choose a name that stands on its own merits. +If your stuff is good, it will not take long to establish a reputation for yourselves. + + +New BSD License +--------------- + +Copyright (c) 2004, 2014 David Grudl (https://davidgrudl.com) +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of "Nette Framework" nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +This software is provided by the copyright holders and contributors "as is" and +any express or implied warranties, including, but not limited to, the implied +warranties of merchantability and fitness for a particular purpose are +disclaimed. In no event shall the copyright owner or contributors be liable for +any direct, indirect, incidental, special, exemplary, or consequential damages +(including, but not limited to, procurement of substitute goods or services; +loss of use, data, or profits; or business interruption) however caused and on +any theory of liability, whether in contract, strict liability, or tort +(including negligence or otherwise) arising in any way out of the use of this +software, even if advised of the possibility of such damage. + + +GNU General Public License +-------------------------- + +GPL licenses are very very long, so instead of including them here we offer +you URLs with full text: + +- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html) +- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html) diff --git a/vendor/nette/finder/readme.md b/vendor/nette/finder/readme.md new file mode 100644 index 0000000000..6feeafb490 --- /dev/null +++ b/vendor/nette/finder/readme.md @@ -0,0 +1,159 @@ +Nette Finder: Files Searching +============================= + +[![Downloads this Month](https://img.shields.io/packagist/dm/nette/finder.svg)](https://packagist.org/packages/nette/finder) +[![Tests](https://github.com/nette/finder/workflows/Tests/badge.svg?branch=master)](https://github.com/nette/finder/actions) +[![Coverage Status](https://coveralls.io/repos/github/nette/finder/badge.svg?branch=master)](https://coveralls.io/github/nette/finder?branch=master) +[![Latest Stable Version](https://poser.pugx.org/nette/finder/v/stable)](https://github.com/nette/finder/releases) +[![License](https://img.shields.io/badge/license-New%20BSD-blue.svg)](https://github.com/nette/finder/blob/master/license.md) + + +Introduction +------------ + +Nette Finder makes browsing the directory structure really easy. + +Documentation can be found on the [website](https://doc.nette.org/finder). + + +[Support Me](https://github.com/sponsors/dg) +-------------------------------------------- + +Do you like Nette Finder? Are you looking forward to the new features? + +[![Buy me a coffee](https://files.nette.org/icons/donation-3.svg)](https://github.com/sponsors/dg) + +Thank you! + + +Installation +------------ + +```shell +composer require nette/finder +``` + +All examples assume the following class alias is defined: + +```php +use Nette\Utils\Finder; +``` + + +Searching for Files +------------------- + +How to find all `*.txt` files in `$dir` directory and all its subdirectories? + +```php +foreach (Finder::findFiles('*.txt')->from($dir) as $key => $file) { + // $key is a string containing absolute filename with path + // $file is an instance of SplFileInfo +} +``` + +The files in the `$file` variable are instances of the `SplFileInfo` class. + +If the directory does not exist, an `Nette\UnexpectedValueException` is thrown. + +And what about searching for files in a directory without subdirectories? Instead of `from()` use `in()`: + +```php +Finder::findFiles('*.txt')->in($dir) +``` + +Search by multiple masks and even multiple directories at once: + +```php +Finder::findFiles('*.txt', '*.php') + ->in($dir1, $dir2) // or from($dir1, $dir2) +``` + +Depth of search can be limited using the `limitDepth()` method. + + +Searching for Directories +------------------------- + +In addition to files, it is possible to search for directories using `Finder::findDirectories('subdir*')`. + +Or to search for files and directories together using `Finder::find('*.txt')`, the mask in this case only applies to files. When searching recursively with `from()`, the subdirectory is returned first, followed by the files in it, which can be reversed with `childFirst()`. + + +Mask +---- + +The mask does not have to describe only the file name, but also the path. Example: searching for `*.jpg` files located in a subdirectory starting with `imag`: + +```php +Finder::findFiles('imag*/*.jpg') +``` + +Thus, the known wildcards `*` and `?` represent any characters except the directory separator `/`. The double `**` represents any characters, including the directory separator: + +```php +Finder::findFiles('imag**/*.jpg') +// finds also image/subdir/file.jpg +``` + +In addition you can use in the mask ranges `[...]` or negative ranges `[!...]` known from regular expressions. Searching for `*.txt` files containing a digit in the name: + +```php +Finder::findFiles('*[0-9]*.txt') +``` + + +Excluding +--------- + +Use `exclude()` to pass masks that the file must not match. Searching for `*.txt` files, except those containing '`X`' in the name: + +```php +Finder::findFiles('*.txt') + ->exclude('*X*') +``` + +If `exclude()` is specified **after** `from()`, it applies to crawled subdirectories: + +```php +Finder::findFiles('*.php') + ->from($dir) + ->exclude('temp', '.git') +``` + + + +Filtering +--------- + +You can also filter the results, for example by file size. Here's how to find files of size between 100 and 200 bytes: + +```php +Finder::findFiles('*.php') + ->size('>=', 100) + ->size('<=', 200) + ->from($dir) +``` + +Filtering by date of last change. Example: searching for files changed in the last two weeks: + +```php +Finder::findFiles('*.php') + ->date('>', '- 2 weeks') + ->from($dir) +``` + +Both functions understand the operators `>`, `>=`, `<`, `<=`, `=`, `!=`. + +Here we traverse PHP files with number of lines greater than 1000. As a filter we use a custom callback: + +```php +$hasMoreThan100Lines = function (SplFileInfo $file): bool { + return count(file($file->getPathname())) > 1000; +}; + +Finder::findFiles('*.php') + ->filter($hasMoreThan100Lines) +``` + +Handy, right? You will certainly find a use for Finder in your applications. diff --git a/vendor/nette/finder/src/Utils/Finder.php b/vendor/nette/finder/src/Utils/Finder.php new file mode 100644 index 0000000000..419a01176f --- /dev/null +++ b/vendor/nette/finder/src/Utils/Finder.php @@ -0,0 +1,317 @@ + + * Finder::findFiles('*.php') + * ->size('> 10kB') + * ->from('.') + * ->exclude('temp'); + * + * + * @implements \IteratorAggregate + */ +class Finder implements \IteratorAggregate, \Countable +{ + use Nette\SmartObject; + /** @var callable[] extension methods */ + private static $extMethods = []; + /** @var array */ + private $paths = []; + /** @var array of filters */ + private $groups = []; + /** @var array filter for recursive traversing */ + private $exclude = []; + /** @var int */ + private $order = RecursiveIteratorIterator::SELF_FIRST; + /** @var int */ + private $maxDepth = -1; + /** @var array */ + private $cursor; + /** + * Begins search for files and directories matching mask. + * @param string ...$masks + * @return static + */ + public static function find(...$masks) : self + { + $masks = \is_array($tmp = \reset($masks)) ? $tmp : $masks; + return (new static())->select($masks, 'isDir')->select($masks, 'isFile'); + } + /** + * Begins search for files matching mask. + * @param string ...$masks + * @return static + */ + public static function findFiles(...$masks) : self + { + $masks = \is_array($tmp = \reset($masks)) ? $tmp : $masks; + return (new static())->select($masks, 'isFile'); + } + /** + * Begins search for directories matching mask. + * @param string ...$masks + * @return static + */ + public static function findDirectories(...$masks) : self + { + $masks = \is_array($tmp = \reset($masks)) ? $tmp : $masks; + return (new static())->select($masks, 'isDir'); + } + /** + * Creates filtering group by mask & type selector. + * @return static + */ + private function select(array $masks, string $type) : self + { + $this->cursor =& $this->groups[]; + $pattern = self::buildPattern($masks); + $this->filter(function (RecursiveDirectoryIterator $file) use($type, $pattern) : bool { + return !$file->isDot() && $file->{$type}() && (!$pattern || \preg_match($pattern, '/' . \strtr($file->getSubPathName(), '\\', '/'))); + }); + return $this; + } + /** + * Searches in the given folder(s). + * @param string ...$paths + * @return static + */ + public function in(...$paths) : self + { + $this->maxDepth = 0; + return $this->from(...$paths); + } + /** + * Searches recursively from the given folder(s). + * @param string ...$paths + * @return static + */ + public function from(...$paths) : self + { + if ($this->paths) { + throw new Nette\InvalidStateException('Directory to search has already been specified.'); + } + $this->paths = \is_array($tmp = \reset($paths)) ? $tmp : $paths; + $this->cursor =& $this->exclude; + return $this; + } + /** + * Shows folder content prior to the folder. + * @return static + */ + public function childFirst() : self + { + $this->order = RecursiveIteratorIterator::CHILD_FIRST; + return $this; + } + /** + * Converts Finder pattern to regular expression. + */ + private static function buildPattern(array $masks) : ?string + { + $pattern = []; + foreach ($masks as $mask) { + $mask = \rtrim(\strtr($mask, '\\', '/'), '/'); + $prefix = ''; + if ($mask === '') { + continue; + } elseif ($mask === '*') { + return null; + } elseif ($mask[0] === '/') { + // absolute fixing + $mask = \ltrim($mask, '/'); + $prefix = '(?<=^/)'; + } + $pattern[] = $prefix . \strtr(\preg_quote($mask, '#'), ['\\*\\*' => '.*', '\\*' => '[^/]*', '\\?' => '[^/]', '\\[\\!' => '[^', '\\[' => '[', '\\]' => ']', '\\-' => '-']); + } + return $pattern ? '#/(' . \implode('|', $pattern) . ')$#Di' : null; + } + /********************* iterator generator ****************d*g**/ + /** @deprecated */ + public function count() : int + { + \trigger_error('Nette\\Utils\\Finder::count is deprecated.', \E_USER_DEPRECATED); + return \iterator_count($this->getIterator()); + } + /** + * Returns iterator. + */ + public function getIterator() : \Iterator + { + if (!$this->paths) { + throw new Nette\InvalidStateException('Call in() or from() to specify directory to search.'); + } elseif (\count($this->paths) === 1) { + return $this->buildIterator((string) $this->paths[0]); + } + $iterator = new \AppendIterator(); + foreach ($this->paths as $path) { + $iterator->append($this->buildIterator((string) $path)); + } + return $iterator; + } + /** + * Returns per-path iterator. + */ + private function buildIterator(string $path) : \Iterator + { + $iterator = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::FOLLOW_SYMLINKS); + if ($this->exclude) { + $iterator = new \RecursiveCallbackFilterIterator($iterator, function ($foo, $bar, RecursiveDirectoryIterator $file) : bool { + if (!$file->isDot() && !$file->isFile()) { + foreach ($this->exclude as $filter) { + if (!$filter($file)) { + return \false; + } + } + } + return \true; + }); + } + if ($this->maxDepth !== 0) { + $iterator = new RecursiveIteratorIterator($iterator, $this->order); + $iterator->setMaxDepth($this->maxDepth); + } + $iterator = new \CallbackFilterIterator($iterator, function ($foo, $bar, \Iterator $file) : bool { + while ($file instanceof \OuterIterator) { + $file = $file->getInnerIterator(); + } + foreach ($this->groups as $filters) { + foreach ($filters as $filter) { + if (!$filter($file)) { + continue 2; + } + } + return \true; + } + return \false; + }); + return $iterator; + } + /********************* filtering ****************d*g**/ + /** + * Restricts the search using mask. + * Excludes directories from recursive traversing. + * @param string ...$masks + * @return static + */ + public function exclude(...$masks) : self + { + $masks = \is_array($tmp = \reset($masks)) ? $tmp : $masks; + $pattern = self::buildPattern($masks); + if ($pattern) { + $this->filter(function (RecursiveDirectoryIterator $file) use($pattern) : bool { + return !\preg_match($pattern, '/' . \strtr($file->getSubPathName(), '\\', '/')); + }); + } + return $this; + } + /** + * Restricts the search using callback. + * @param callable(RecursiveDirectoryIterator): bool $callback + * @return static + */ + public function filter(callable $callback) : self + { + $this->cursor[] = $callback; + return $this; + } + /** + * Limits recursion level. + * @return static + */ + public function limitDepth(int $depth) : self + { + $this->maxDepth = $depth; + return $this; + } + /** + * Restricts the search by size. + * @param string $operator "[operator] [size] [unit]" example: >=10kB + * @return static + */ + public function size(string $operator, ?int $size = null) : self + { + if (\func_num_args() === 1) { + // in $operator is predicate + if (!\preg_match('#^(?:([=<>!]=?|<>)\\s*)?((?:\\d*\\.)?\\d+)\\s*(K|M|G|)B?$#Di', $operator, $matches)) { + throw new Nette\InvalidArgumentException('Invalid size predicate format.'); + } + [, $operator, $size, $unit] = $matches; + static $units = ['' => 1, 'k' => 1000.0, 'm' => 1000000.0, 'g' => 1000000000.0]; + $size *= $units[\strtolower($unit)]; + $operator = $operator ?: '='; + } + return $this->filter(function (RecursiveDirectoryIterator $file) use($operator, $size) : bool { + return self::compare($file->getSize(), $operator, $size); + }); + } + /** + * Restricts the search by modified time. + * @param string $operator "[operator] [date]" example: >1978-01-23 + * @param string|int|\DateTimeInterface $date + * @return static + */ + public function date(string $operator, $date = null) : self + { + if (\func_num_args() === 1) { + // in $operator is predicate + if (!\preg_match('#^(?:([=<>!]=?|<>)\\s*)?(.+)$#Di', $operator, $matches)) { + throw new Nette\InvalidArgumentException('Invalid date predicate format.'); + } + [, $operator, $date] = $matches; + $operator = $operator ?: '='; + } + $date = DateTime::from($date)->format('U'); + return $this->filter(function (RecursiveDirectoryIterator $file) use($operator, $date) : bool { + return self::compare($file->getMTime(), $operator, $date); + }); + } + /** + * Compares two values. + */ + public static function compare($l, string $operator, $r) : bool + { + switch ($operator) { + case '>': + return $l > $r; + case '>=': + return $l >= $r; + case '<': + return $l < $r; + case '<=': + return $l <= $r; + case '=': + case '==': + return $l == $r; + case '!': + case '!=': + case '<>': + return $l != $r; + default: + throw new Nette\InvalidArgumentException("Unknown operator {$operator}."); + } + } + /********************* extension methods ****************d*g**/ + /** @deprecated */ + public function __call(string $name, array $args) + { + return isset(self::$extMethods[$name]) ? self::$extMethods[$name]($this, ...$args) : Nette\Utils\ObjectHelpers::strictCall(static::class, $name, \array_keys(self::$extMethods)); + } + /** @deprecated */ + public static function extensionMethod(string $name, callable $callback) : void + { + \trigger_error(__METHOD__ . '() is deprecated.', \E_USER_DEPRECATED); + self::$extMethods[$name] = $callback; + } +} diff --git a/vendor/nette/robot-loader/composer.json b/vendor/nette/robot-loader/composer.json new file mode 100644 index 0000000000..cad004ebef --- /dev/null +++ b/vendor/nette/robot-loader/composer.json @@ -0,0 +1,53 @@ +{ + "name": "nette\/robot-loader", + "description": "\ud83c\udf40 Nette RobotLoader: high performance and comfortable autoloader that will search and autoload classes within your application.", + "keywords": [ + "nette", + "autoload", + "class", + "trait", + "interface" + ], + "homepage": "https:\/\/nette.org", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https:\/\/davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https:\/\/nette.org\/contributors" + } + ], + "require": { + "php": ">=7.1", + "ext-tokenizer": "*", + "nette\/finder": "^2.5 || ^3.0", + "nette\/utils": "^3.0" + }, + "require-dev": { + "nette\/tester": "^2.0", + "tracy\/tracy": "^2.3", + "phpstan\/phpstan": "^0.12" + }, + "autoload": { + "classmap": [ + "src\/" + ] + }, + "minimum-stability": "dev", + "scripts": { + "phpstan": "phpstan analyse", + "tester": "tester tests -s" + }, + "extra": { + "branch-alias": { + "dev-master": "3.4-dev" + } + } +} \ No newline at end of file diff --git a/vendor/nette/robot-loader/license.md b/vendor/nette/robot-loader/license.md new file mode 100644 index 0000000000..cf741bd05f --- /dev/null +++ b/vendor/nette/robot-loader/license.md @@ -0,0 +1,60 @@ +Licenses +======== + +Good news! You may use Nette Framework under the terms of either +the New BSD License or the GNU General Public License (GPL) version 2 or 3. + +The BSD License is recommended for most projects. It is easy to understand and it +places almost no restrictions on what you can do with the framework. If the GPL +fits better to your project, you can use the framework under this license. + +You don't have to notify anyone which license you are using. You can freely +use Nette Framework in commercial projects as long as the copyright header +remains intact. + +Please be advised that the name "Nette Framework" is a protected trademark and its +usage has some limitations. So please do not use word "Nette" in the name of your +project or top-level domain, and choose a name that stands on its own merits. +If your stuff is good, it will not take long to establish a reputation for yourselves. + + +New BSD License +--------------- + +Copyright (c) 2004, 2014 David Grudl (https://davidgrudl.com) +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of "Nette Framework" nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +This software is provided by the copyright holders and contributors "as is" and +any express or implied warranties, including, but not limited to, the implied +warranties of merchantability and fitness for a particular purpose are +disclaimed. In no event shall the copyright owner or contributors be liable for +any direct, indirect, incidental, special, exemplary, or consequential damages +(including, but not limited to, procurement of substitute goods or services; +loss of use, data, or profits; or business interruption) however caused and on +any theory of liability, whether in contract, strict liability, or tort +(including negligence or otherwise) arising in any way out of the use of this +software, even if advised of the possibility of such damage. + + +GNU General Public License +-------------------------- + +GPL licenses are very very long, so instead of including them here we offer +you URLs with full text: + +- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html) +- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html) diff --git a/vendor/nette/robot-loader/ncs.php b/vendor/nette/robot-loader/ncs.php new file mode 100644 index 0000000000..dad0161f0d --- /dev/null +++ b/vendor/nette/robot-loader/ncs.php @@ -0,0 +1,13 @@ + \false, +]; diff --git a/vendor/nette/robot-loader/readme.md b/vendor/nette/robot-loader/readme.md new file mode 100644 index 0000000000..51036982b0 --- /dev/null +++ b/vendor/nette/robot-loader/readme.md @@ -0,0 +1,131 @@ +RobotLoader: comfortable autoloading +==================================== + +[![Downloads this Month](https://img.shields.io/packagist/dm/nette/robot-loader.svg)](https://packagist.org/packages/nette/robot-loader) +[![Tests](https://github.com/nette/robot-loader/workflows/Tests/badge.svg?branch=master)](https://github.com/nette/robot-loader/actions) +[![Coverage Status](https://coveralls.io/repos/github/nette/robot-loader/badge.svg?branch=master)](https://coveralls.io/github/nette/robot-loader?branch=master) +[![Latest Stable Version](https://poser.pugx.org/nette/robot-loader/v/stable)](https://github.com/nette/robot-loader/releases) +[![License](https://img.shields.io/badge/license-New%20BSD-blue.svg)](https://github.com/nette/robot-loader/blob/master/license.md) + + +Introduction +------------ + +RobotLoader is a tool that gives you comfort of automated class loading for your entire application including third-party libraries. + +- get rid of all `require` +- does not require strict directory or file naming conventions +- extremely fast +- no manual cache updates, everything runs automatically +- highly mature, stable and widely used library + +So we can forget about those famous code blocks: + +```php +require_once 'Utils/Page.php'; +require_once 'Utils/Style.php'; +require_once 'Utils/Paginator.php'; +... +``` + +[Support Me](https://github.com/sponsors/dg) +-------------------------------------------- + +Do you like RobotLoader? Are you looking forward to the new features? + +[![Buy me a coffee](https://files.nette.org/icons/donation-3.svg)](https://github.com/sponsors/dg) + +Thank you! + + +Installation +------------ + +The recommended way to install is via Composer: + +```shell +composer require nette/robot-loader +``` + +It requires PHP version 7.1 and supports PHP up to 8.2. + + +Usage +----- + +Like the Google robot crawls and indexes websites, [RobotLoader](https://api.nette.org/3.0/Nette/Loaders/RobotLoader.html) crawls all PHP scripts and records what classes and interfaces were found in them. These records are then saved in cache and used during all subsequent requests. You just need to specify what directories to index and where to save the cache: + +```php +$loader = new Nette\Loaders\RobotLoader; + +// directories to be indexed by RobotLoader (including subdirectories) +$loader->addDirectory(__DIR__ . '/app'); +$loader->addDirectory(__DIR__ . '/libs'); + +// use 'temp' directory for cache +$loader->setTempDirectory(__DIR__ . '/temp'); +$loader->register(); // Run the RobotLoader +``` + +And that's all. From now on, you don't need to use `require`. Great, isn't it? + +When RobotLoader encounters duplicate class name during indexing, it throws an exception and informs you about it. RobotLoader also automatically updates the cache when it has to load a class it doesn't know. We recommend disabling this on production servers, see [Caching](#Caching). + +If you want RobotLoader to skip some directories, use `$loader->excludeDirectory('temp')` (it can be called multiple times or you can pass multiple directories). + +By default, RobotLoader reports errors in PHP files by throwing exception `ParseError`. It can be disabled via `$loader->reportParseErrors(false)`. + + +PHP Files Analyzer +------------------ + +RobotLoader can also be used purely to find classes, interfaces, and trait in PHP files **without** using the autoloading feature: + +```php +$loader = new Nette\Loaders\RobotLoader; +$loader->addDirectory(__DIR__ . '/app'); + +// Scans directories for classes / intefaces / traits +$loader->rebuild(); + +// Returns array of class => filename pairs +$res = $loader->getIndexedClasses(); +``` + +Even with such use, you can use the cache. As a result, unmodified files will not be repeatedly analyzed when rescanning: + +```php +$loader = new Nette\Loaders\RobotLoader; +$loader->addDirectory(__DIR__ . '/app'); +$loader->setTempDirectory(__DIR__ . '/temp'); + +// Scans directories using a cache +$loader->refresh(); + +// Returns array of class => filename pairs +$res = $loader->getIndexedClasses(); +``` + +Caching +------- + +RobotLoader is very fast because it cleverly uses the cache. + +When developing with it, you have practically no idea that it runs on the background. It continuously updates the cache because it knows that classes and files can be created, deleted, renamed, etc. And it doesn't repeatedly scan unmodified files. + +When used on a production server, on the other hand, we recommend disabling the cache update using `$loader->setAutoRefresh(false)`, because the files are not changing. At the same time, it is necessary to **clear the cache** when uploading a new version on the hosting. + +Of course, the initial scanning of files, when the cache does not already exist, may take a few seconds for larger applications. RobotLoader has built-in prevention against [cache stampede](https://en.wikipedia.org/wiki/Cache_stampede). +This is a situation where production server receives a large number of concurrent requests and because RobotLoader's cache does not yet exist, they would all start scanning the files. Which spikes CPU and filesystem usage. +Fortunately, RobotLoader works in such a way that for multiple concurrent requests, only the first thread indexes the files, creates a cache, the others wait, and then use the cache. + + +PSR-4 +----- + +Today, Composer can be used for autoloading in compliance with PSR-4. Simply saying, it is a system where the namespaces and class names correspond to the directory structure and file names, ie `App\Router\RouterFactory` is located in the file `/path/to/App/Router/RouterFactory.php`. + +RobotLoader is not tied to any fixed structure, therefore, it is useful in situations where it does not suit you to have the directory structure designed as namespaces in PHP, or when you are developing an application that has historically not used such conventions. It is also possible to use both loaders together. + + +If you like RobotLoader, **[please make a donation now](https://nette.org/donate)**. Thank you! diff --git a/vendor/nette/robot-loader/src/RobotLoader/RobotLoader.php b/vendor/nette/robot-loader/src/RobotLoader/RobotLoader.php new file mode 100644 index 0000000000..0bf97aaecb --- /dev/null +++ b/vendor/nette/robot-loader/src/RobotLoader/RobotLoader.php @@ -0,0 +1,444 @@ + + * $loader = new Nette\Loaders\RobotLoader; + * $loader->addDirectory('app'); + * $loader->excludeDirectory('app/exclude'); + * $loader->setTempDirectory('temp'); + * $loader->register(); + * + */ +class RobotLoader +{ + use Nette\SmartObject; + private const RetryLimit = 3; + /** @var string[] */ + public $ignoreDirs = ['.*', '*.old', '*.bak', '*.tmp', 'temp']; + /** @var string[] */ + public $acceptFiles = ['*.php']; + /** @var bool */ + private $autoRebuild = \true; + /** @var bool */ + private $reportParseErrors = \true; + /** @var string[] */ + private $scanPaths = []; + /** @var string[] */ + private $excludeDirs = []; + /** @var array class => [file, time] */ + private $classes = []; + /** @var bool */ + private $cacheLoaded = \false; + /** @var bool */ + private $refreshed = \false; + /** @var array class => counter */ + private $missingClasses = []; + /** @var array file => mtime */ + private $emptyFiles = []; + /** @var string|null */ + private $tempDirectory; + /** @var bool */ + private $needSave = \false; + public function __construct() + { + if (!\extension_loaded('tokenizer')) { + throw new Nette\NotSupportedException('PHP extension Tokenizer is not loaded.'); + } + } + public function __destruct() + { + if ($this->needSave) { + $this->saveCache(); + } + } + /** + * Register autoloader. + */ + public function register(bool $prepend = \false) : self + { + \spl_autoload_register([$this, 'tryLoad'], \true, $prepend); + return $this; + } + /** + * Handles autoloading of classes, interfaces or traits. + */ + public function tryLoad(string $type) : void + { + $this->loadCache(); + $missing = $this->missingClasses[$type] ?? null; + if ($missing >= self::RetryLimit) { + return; + } + [$file, $mtime] = $this->classes[$type] ?? null; + if ($this->autoRebuild) { + if (!$this->refreshed) { + if (!$file || !\is_file($file)) { + $this->refreshClasses(); + [$file] = $this->classes[$type] ?? null; + $this->needSave = \true; + } elseif (\filemtime($file) !== $mtime) { + $this->updateFile($file); + [$file] = $this->classes[$type] ?? null; + $this->needSave = \true; + } + } + if (!$file || !\is_file($file)) { + $this->missingClasses[$type] = ++$missing; + $this->needSave = $this->needSave || $file || $missing <= self::RetryLimit; + unset($this->classes[$type]); + $file = null; + } + } + if ($file) { + (static function ($file) { + require $file; + })($file); + } + } + /** + * Add path or paths to list. + * @param string ...$paths absolute path + */ + public function addDirectory(...$paths) : self + { + if (\is_array($paths[0] ?? null)) { + \trigger_error(__METHOD__ . '() use variadics ...$paths to add an array of paths.', \E_USER_WARNING); + $paths = $paths[0]; + } + $this->scanPaths = \array_merge($this->scanPaths, $paths); + return $this; + } + public function reportParseErrors(bool $on = \true) : self + { + $this->reportParseErrors = $on; + return $this; + } + /** + * Excludes path or paths from list. + * @param string ...$paths absolute path + */ + public function excludeDirectory(...$paths) : self + { + if (\is_array($paths[0] ?? null)) { + \trigger_error(__METHOD__ . '() use variadics ...$paths to add an array of paths.', \E_USER_WARNING); + $paths = $paths[0]; + } + $this->excludeDirs = \array_merge($this->excludeDirs, $paths); + return $this; + } + /** + * @return array class => filename + */ + public function getIndexedClasses() : array + { + $this->loadCache(); + $res = []; + foreach ($this->classes as $class => [$file]) { + $res[$class] = $file; + } + return $res; + } + /** + * Rebuilds class list cache. + */ + public function rebuild() : void + { + $this->cacheLoaded = \true; + $this->classes = $this->missingClasses = $this->emptyFiles = []; + $this->refreshClasses(); + if ($this->tempDirectory) { + $this->saveCache(); + } + } + /** + * Refreshes class list cache. + */ + public function refresh() : void + { + $this->loadCache(); + if (!$this->refreshed) { + $this->refreshClasses(); + $this->saveCache(); + } + } + /** + * Refreshes $this->classes & $this->emptyFiles. + */ + private function refreshClasses() : void + { + $this->refreshed = \true; + // prevents calling refreshClasses() or updateFile() in tryLoad() + $files = $this->emptyFiles; + $classes = []; + foreach ($this->classes as $class => [$file, $mtime]) { + $files[$file] = $mtime; + $classes[$file][] = $class; + } + $this->classes = $this->emptyFiles = []; + foreach ($this->scanPaths as $path) { + $iterator = \is_file($path) ? [new SplFileInfo($path)] : $this->createFileIterator($path); + foreach ($iterator as $fileInfo) { + $mtime = $fileInfo->getMTime(); + $file = $fileInfo->getPathname(); + $foundClasses = isset($files[$file]) && $files[$file] === $mtime ? $classes[$file] ?? [] : $this->scanPhp($file); + if (!$foundClasses) { + $this->emptyFiles[$file] = $mtime; + } + $files[$file] = $mtime; + $classes[$file] = []; + // prevents the error when adding the same file twice + foreach ($foundClasses as $class) { + if (isset($this->classes[$class])) { + throw new Nette\InvalidStateException(\sprintf('Ambiguous class %s resolution; defined in %s and in %s.', $class, $this->classes[$class][0], $file)); + } + $this->classes[$class] = [$file, $mtime]; + unset($this->missingClasses[$class]); + } + } + } + } + /** + * Creates an iterator scaning directory for PHP files, subdirectories and 'netterobots.txt' files. + * @throws Nette\IOException if path is not found + */ + private function createFileIterator(string $dir) : Nette\Utils\Finder + { + if (!\is_dir($dir)) { + throw new Nette\IOException(\sprintf("File or directory '%s' not found.", $dir)); + } + $dir = \realpath($dir) ?: $dir; + // realpath does not work in phar + if (\is_string($ignoreDirs = $this->ignoreDirs)) { + \trigger_error(self::class . ': $ignoreDirs must be an array.', \E_USER_WARNING); + $ignoreDirs = \preg_split('#[,\\s]+#', $ignoreDirs); + } + $disallow = []; + foreach (\array_merge($ignoreDirs, $this->excludeDirs) as $item) { + if ($item = \realpath($item)) { + $disallow[\str_replace('\\', '/', $item)] = \true; + } + } + if (\is_string($acceptFiles = $this->acceptFiles)) { + \trigger_error(self::class . ': $acceptFiles must be an array.', \E_USER_WARNING); + $acceptFiles = \preg_split('#[,\\s]+#', $acceptFiles); + } + $iterator = Nette\Utils\Finder::findFiles(...$acceptFiles)->filter(function (SplFileInfo $file) use(&$disallow) { + return $file->getRealPath() === \false ? \true : !isset($disallow[\str_replace('\\', '/', $file->getRealPath())]); + })->from($dir)->exclude(...$ignoreDirs)->filter($filter = function (SplFileInfo $dir) use(&$disallow) { + if ($dir->getRealPath() === \false) { + return \true; + } + $path = \str_replace('\\', '/', $dir->getRealPath()); + if (\is_file("{$path}/netterobots.txt")) { + foreach (\file("{$path}/netterobots.txt") as $s) { + if (\preg_match('#^(?:disallow\\s*:)?\\s*(\\S+)#i', $s, $matches)) { + $disallow[$path . \rtrim('/' . \ltrim($matches[1], '/'), '/')] = \true; + } + } + } + return !isset($disallow[$path]); + }); + $filter(new SplFileInfo($dir)); + return $iterator; + } + private function updateFile(string $file) : void + { + foreach ($this->classes as $class => [$prevFile]) { + if ($file === $prevFile) { + unset($this->classes[$class]); + } + } + $foundClasses = \is_file($file) ? $this->scanPhp($file) : []; + foreach ($foundClasses as $class) { + [$prevFile, $prevMtime] = $this->classes[$class] ?? null; + if (isset($prevFile) && @\filemtime($prevFile) !== $prevMtime) { + // @ file may not exists + $this->updateFile($prevFile); + [$prevFile] = $this->classes[$class] ?? null; + } + if (isset($prevFile)) { + throw new Nette\InvalidStateException(\sprintf('Ambiguous class %s resolution; defined in %s and in %s.', $class, $prevFile, $file)); + } + $this->classes[$class] = [$file, \filemtime($file)]; + } + } + /** + * Searches classes, interfaces and traits in PHP file. + * @return string[] + */ + private function scanPhp(string $file) : array + { + $code = \file_get_contents($file); + $expected = \false; + $namespace = $name = ''; + $level = $minLevel = 0; + $classes = []; + try { + $tokens = \token_get_all($code, \TOKEN_PARSE); + } catch (\ParseError $e) { + if ($this->reportParseErrors) { + $rp = new \ReflectionProperty($e, 'file'); + $rp->setAccessible(\true); + $rp->setValue($e, $file); + throw $e; + } + $tokens = []; + } + foreach ($tokens as $token) { + if (\is_array($token)) { + switch ($token[0]) { + case \T_COMMENT: + case \T_DOC_COMMENT: + case \T_WHITESPACE: + continue 2; + case \T_STRING: + case \PHP_VERSION_ID < 80000 ? \T_NS_SEPARATOR : \T_NAME_QUALIFIED: + if ($expected) { + $name .= $token[1]; + } + continue 2; + case \T_NAMESPACE: + case \T_CLASS: + case \T_INTERFACE: + case \T_TRAIT: + case \PHP_VERSION_ID < 80100 ? \T_CLASS : \T_ENUM: + $expected = $token[0]; + $name = ''; + continue 2; + case \T_CURLY_OPEN: + case \T_DOLLAR_OPEN_CURLY_BRACES: + $level++; + } + } + if ($expected) { + if ($expected === \T_NAMESPACE) { + $namespace = $name ? $name . '\\' : ''; + $minLevel = $token === '{' ? 1 : 0; + } elseif ($name && $level === $minLevel) { + $classes[] = $namespace . $name; + } + $expected = null; + } + if ($token === '{') { + $level++; + } elseif ($token === '}') { + $level--; + } + } + return $classes; + } + /********************* caching ****************d*g**/ + /** + * Sets auto-refresh mode. + */ + public function setAutoRefresh(bool $on = \true) : self + { + $this->autoRebuild = $on; + return $this; + } + /** + * Sets path to temporary directory. + */ + public function setTempDirectory(string $dir) : self + { + Nette\Utils\FileSystem::createDir($dir); + $this->tempDirectory = $dir; + return $this; + } + /** + * Loads class list from cache. + */ + private function loadCache() : void + { + if ($this->cacheLoaded) { + return; + } + $this->cacheLoaded = \true; + $file = $this->generateCacheFileName(); + // Solving atomicity to work everywhere is really pain in the ass. + // 1) We want to do as little as possible IO calls on production and also directory and file can be not writable (#19) + // so on Linux we include the file directly without shared lock, therefore, the file must be created atomically by renaming. + // 2) On Windows file cannot be renamed-to while is open (ie by include() #11), so we have to acquire a lock. + $lock = \defined('PHP_WINDOWS_VERSION_BUILD') ? $this->acquireLock("{$file}.lock", \LOCK_SH) : null; + $data = @(include $file); + // @ file may not exist + if (\is_array($data)) { + [$this->classes, $this->missingClasses, $this->emptyFiles] = $data; + return; + } + if ($lock) { + \flock($lock, \LOCK_UN); + // release shared lock so we can get exclusive + } + $lock = $this->acquireLock("{$file}.lock", \LOCK_EX); + // while waiting for exclusive lock, someone might have already created the cache + $data = @(include $file); + // @ file may not exist + if (\is_array($data)) { + [$this->classes, $this->missingClasses, $this->emptyFiles] = $data; + return; + } + $this->classes = $this->missingClasses = $this->emptyFiles = []; + $this->refreshClasses(); + $this->saveCache($lock); + // On Windows concurrent creation and deletion of a file can cause a 'permission denied' error, + // therefore, we will not delete the lock file. Windows is really annoying. + } + /** + * Writes class list to cache. + * @param resource $lock + */ + private function saveCache($lock = null) : void + { + // we have to acquire a lock to be able safely rename file + // on Linux: that another thread does not rename the same named file earlier + // on Windows: that the file is not read by another thread + $file = $this->generateCacheFileName(); + $lock = $lock ?: $this->acquireLock("{$file}.lock", \LOCK_EX); + $code = "classes, $this->missingClasses, $this->emptyFiles], \true) . ";\n"; + if (\file_put_contents("{$file}.tmp", $code) !== \strlen($code) || !\rename("{$file}.tmp", $file)) { + @\unlink("{$file}.tmp"); + // @ file may not exist + throw new \RuntimeException(\sprintf("Unable to create '%s'.", $file)); + } + if (\function_exists('opcache_invalidate')) { + @\opcache_invalidate($file, \true); + // @ can be restricted + } + } + /** @return resource */ + private function acquireLock(string $file, int $mode) + { + $handle = @\fopen($file, 'w'); + // @ is escalated to exception + if (!$handle) { + throw new \RuntimeException(\sprintf("Unable to create file '%s'. %s", $file, \error_get_last()['message'])); + } elseif (!@\flock($handle, $mode)) { + // @ is escalated to exception + throw new \RuntimeException(\sprintf("Unable to acquire %s lock on file '%s'. %s", $mode & \LOCK_EX ? 'exclusive' : 'shared', $file, \error_get_last()['message'])); + } + return $handle; + } + private function generateCacheFileName() : string + { + if (!$this->tempDirectory) { + throw new \LogicException('Set path to temporary directory using setTempDirectory().'); + } + return $this->tempDirectory . '/' . \md5(\serialize($this->getCacheKey())) . '.php'; + } + protected function getCacheKey() : array + { + return [$this->ignoreDirs, $this->acceptFiles, $this->scanPaths, $this->excludeDirs, 'v2']; + } +} diff --git a/vendor/nette/utils/composer.json b/vendor/nette/utils/composer.json new file mode 100644 index 0000000000..c107f1f0c5 --- /dev/null +++ b/vendor/nette/utils/composer.json @@ -0,0 +1,72 @@ +{ + "name": "nette\/utils", + "description": "\ud83d\udee0 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding\/decoding, validation, slug or strong password generating etc.", + "keywords": [ + "nette", + "images", + "json", + "password", + "validation", + "utility", + "string", + "array", + "core", + "slugify", + "utf-8", + "unicode", + "paginator", + "datetime" + ], + "homepage": "https:\/\/nette.org", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https:\/\/davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https:\/\/nette.org\/contributors" + } + ], + "require": { + "php": ">=7.2 <8.4" + }, + "require-dev": { + "nette\/tester": "~2.0", + "tracy\/tracy": "^2.3", + "phpstan\/phpstan": "^1.0", + "jetbrains\/phpstorm-attributes": "dev-master" + }, + "conflict": { + "nette\/di": "<3.0.6" + }, + "suggest": { + "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-xml": "to use Strings::length() etc. when mbstring is not available", + "ext-gd": "to use Image", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()" + }, + "autoload": { + "classmap": [ + "src\/" + ] + }, + "minimum-stability": "dev", + "scripts": { + "phpstan": "phpstan analyse", + "tester": "tester tests -s" + }, + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + } +} \ No newline at end of file diff --git a/vendor/nette/utils/license.md b/vendor/nette/utils/license.md new file mode 100644 index 0000000000..cf741bd05f --- /dev/null +++ b/vendor/nette/utils/license.md @@ -0,0 +1,60 @@ +Licenses +======== + +Good news! You may use Nette Framework under the terms of either +the New BSD License or the GNU General Public License (GPL) version 2 or 3. + +The BSD License is recommended for most projects. It is easy to understand and it +places almost no restrictions on what you can do with the framework. If the GPL +fits better to your project, you can use the framework under this license. + +You don't have to notify anyone which license you are using. You can freely +use Nette Framework in commercial projects as long as the copyright header +remains intact. + +Please be advised that the name "Nette Framework" is a protected trademark and its +usage has some limitations. So please do not use word "Nette" in the name of your +project or top-level domain, and choose a name that stands on its own merits. +If your stuff is good, it will not take long to establish a reputation for yourselves. + + +New BSD License +--------------- + +Copyright (c) 2004, 2014 David Grudl (https://davidgrudl.com) +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name of "Nette Framework" nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +This software is provided by the copyright holders and contributors "as is" and +any express or implied warranties, including, but not limited to, the implied +warranties of merchantability and fitness for a particular purpose are +disclaimed. In no event shall the copyright owner or contributors be liable for +any direct, indirect, incidental, special, exemplary, or consequential damages +(including, but not limited to, procurement of substitute goods or services; +loss of use, data, or profits; or business interruption) however caused and on +any theory of liability, whether in contract, strict liability, or tort +(including negligence or otherwise) arising in any way out of the use of this +software, even if advised of the possibility of such damage. + + +GNU General Public License +-------------------------- + +GPL licenses are very very long, so instead of including them here we offer +you URLs with full text: + +- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html) +- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html) diff --git a/vendor/nette/utils/readme.md b/vendor/nette/utils/readme.md new file mode 100644 index 0000000000..5317b8e654 --- /dev/null +++ b/vendor/nette/utils/readme.md @@ -0,0 +1,54 @@ +Nette Utility Classes +===================== + +[![Downloads this Month](https://img.shields.io/packagist/dm/nette/utils.svg)](https://packagist.org/packages/nette/utils) +[![Tests](https://github.com/nette/utils/workflows/Tests/badge.svg?branch=master)](https://github.com/nette/utils/actions) +[![Coverage Status](https://coveralls.io/repos/github/nette/utils/badge.svg?branch=master)](https://coveralls.io/github/nette/utils?branch=master) +[![Latest Stable Version](https://poser.pugx.org/nette/utils/v/stable)](https://github.com/nette/utils/releases) +[![License](https://img.shields.io/badge/license-New%20BSD-blue.svg)](https://github.com/nette/utils/blob/master/license.md) + + +Introduction +------------ + +In package nette/utils you will find a set of [useful classes](https://doc.nette.org/utils) for everyday use: + +- [Arrays](https://doc.nette.org/utils/arrays) - manipulate arrays +- [Callback](https://doc.nette.org/utils/callback) - PHP callbacks +- [Date and Time](https://doc.nette.org/utils/datetime) - modify times and dates +- [Filesystem](https://doc.nette.org/utils/filesystem) - copying, renaming, … +- [Helper Functions](https://doc.nette.org/utils/helpers) +- [HTML elements](https://doc.nette.org/utils/html-elements) - generate HTML +- [Images](https://doc.nette.org/utils/images) - crop, resize, rotate images +- [JSON](https://doc.nette.org/utils/json) - encoding and decoding +- [Generating Random Strings](https://doc.nette.org/utils/random) +- [Paginator](https://doc.nette.org/utils/paginator) - pagination math +- [PHP Reflection](https://doc.nette.org/utils/reflection) +- [Strings](https://doc.nette.org/utils/strings) - useful text functions +- [SmartObject](https://doc.nette.org/utils/smartobject) - PHP object enhancements +- [Validation](https://doc.nette.org/utils/validators) - validate inputs +- [Type](https://doc.nette.org/utils/type) - PHP data type + + +Installation +------------ + +The recommended way to install is via Composer: + +``` +composer require nette/utils +``` + +- Nette Utils 3.2 is compatible with PHP 7.2 to 8.3 +- Nette Utils 3.1 is compatible with PHP 7.1 to 8.0 +- Nette Utils 3.0 is compatible with PHP 7.1 to 8.0 +- Nette Utils 2.5 is compatible with PHP 5.6 to 8.0 + +[Support Me](https://github.com/sponsors/dg) +-------------------------------------------- + +Do you like Nette Utils? Are you looking forward to the new features? + +[![Buy me a coffee](https://files.nette.org/icons/donation-3.svg)](https://github.com/sponsors/dg) + +Thank you! diff --git a/vendor/nette/utils/src/HtmlStringable.php b/vendor/nette/utils/src/HtmlStringable.php new file mode 100644 index 0000000000..95830dc418 --- /dev/null +++ b/vendor/nette/utils/src/HtmlStringable.php @@ -0,0 +1,17 @@ +getIterator(); + } while ($iterator instanceof \IteratorAggregate); + \assert($iterator instanceof \Iterator); + } elseif ($iterator instanceof \Iterator) { + } elseif ($iterator instanceof \Traversable) { + $iterator = new \IteratorIterator($iterator); + } else { + throw new Nette\InvalidArgumentException(\sprintf('Invalid argument passed to %s; array or Traversable expected, %s given.', self::class, \is_object($iterator) ? \get_class($iterator) : \gettype($iterator))); + } + parent::__construct($iterator, 0); + } + /** + * Is the current element the first one? + */ + public function isFirst(?int $gridWidth = null) : bool + { + return $this->counter === 1 || $gridWidth && $this->counter !== 0 && ($this->counter - 1) % $gridWidth === 0; + } + /** + * Is the current element the last one? + */ + public function isLast(?int $gridWidth = null) : bool + { + return !$this->hasNext() || $gridWidth && $this->counter % $gridWidth === 0; + } + /** + * Is the iterator empty? + */ + public function isEmpty() : bool + { + return $this->counter === 0; + } + /** + * Is the counter odd? + */ + public function isOdd() : bool + { + return $this->counter % 2 === 1; + } + /** + * Is the counter even? + */ + public function isEven() : bool + { + return $this->counter % 2 === 0; + } + /** + * Returns the counter. + */ + public function getCounter() : int + { + return $this->counter; + } + /** + * Returns the count of elements. + */ + public function count() : int + { + $inner = $this->getInnerIterator(); + if ($inner instanceof \Countable) { + return $inner->count(); + } else { + throw new Nette\NotSupportedException('Iterator is not countable.'); + } + } + /** + * Forwards to the next element. + */ + public function next() : void + { + parent::next(); + if (parent::valid()) { + $this->counter++; + } + } + /** + * Rewinds the Iterator. + */ + public function rewind() : void + { + parent::rewind(); + $this->counter = parent::valid() ? 1 : 0; + } + /** + * Returns the next key. + * @return mixed + */ + public function getNextKey() + { + return $this->getInnerIterator()->key(); + } + /** + * Returns the next element. + * @return mixed + */ + public function getNextValue() + { + return $this->getInnerIterator()->current(); + } +} diff --git a/vendor/nette/utils/src/Iterators/Mapper.php b/vendor/nette/utils/src/Iterators/Mapper.php new file mode 100644 index 0000000000..80581cbad0 --- /dev/null +++ b/vendor/nette/utils/src/Iterators/Mapper.php @@ -0,0 +1,27 @@ +callback = $callback; + } + #[\ReturnTypeWillChange] + public function current() + { + return ($this->callback)(parent::current(), parent::key()); + } +} diff --git a/vendor/nette/utils/src/SmartObject.php b/vendor/nette/utils/src/SmartObject.php new file mode 100644 index 0000000000..e32d3b0937 --- /dev/null +++ b/vendor/nette/utils/src/SmartObject.php @@ -0,0 +1,120 @@ +{$name} ?? null; + if (\is_iterable($handlers)) { + foreach ($handlers as $handler) { + $handler(...$args); + } + } elseif ($handlers !== null) { + throw new UnexpectedValueException("Property {$class}::\${$name} must be iterable or null, " . \gettype($handlers) . ' given.'); + } + } else { + ObjectHelpers::strictCall($class, $name); + } + } + /** + * @throws MemberAccessException + */ + public static function __callStatic(string $name, array $args) + { + ObjectHelpers::strictStaticCall(static::class, $name); + } + /** + * @return mixed + * @throws MemberAccessException if the property is not defined. + */ + public function &__get(string $name) + { + $class = static::class; + if ($prop = ObjectHelpers::getMagicProperties($class)[$name] ?? null) { + // property getter + if (!($prop & 0b1)) { + throw new MemberAccessException("Cannot read a write-only property {$class}::\${$name}."); + } + $m = ($prop & 0b10 ? 'get' : 'is') . \ucfirst($name); + if ($prop & 0b10000) { + $trace = \debug_backtrace(0, 1)[0]; + // suppose this method is called from __call() + $loc = isset($trace['file'], $trace['line']) ? " in {$trace['file']} on line {$trace['line']}" : ''; + \trigger_error("Property {$class}::\${$name} is deprecated, use {$class}::{$m}() method{$loc}.", \E_USER_DEPRECATED); + } + if ($prop & 0b100) { + // return by reference + return $this->{$m}(); + } else { + $val = $this->{$m}(); + return $val; + } + } else { + ObjectHelpers::strictGet($class, $name); + } + } + /** + * @param mixed $value + * @return void + * @throws MemberAccessException if the property is not defined or is read-only + */ + public function __set(string $name, $value) + { + $class = static::class; + if (ObjectHelpers::hasProperty($class, $name)) { + // unsetted property + $this->{$name} = $value; + } elseif ($prop = ObjectHelpers::getMagicProperties($class)[$name] ?? null) { + // property setter + if (!($prop & 0b1000)) { + throw new MemberAccessException("Cannot write to a read-only property {$class}::\${$name}."); + } + $m = 'set' . \ucfirst($name); + if ($prop & 0b10000) { + $trace = \debug_backtrace(0, 1)[0]; + // suppose this method is called from __call() + $loc = isset($trace['file'], $trace['line']) ? " in {$trace['file']} on line {$trace['line']}" : ''; + \trigger_error("Property {$class}::\${$name} is deprecated, use {$class}::{$m}() method{$loc}.", \E_USER_DEPRECATED); + } + $this->{$m}($value); + } else { + ObjectHelpers::strictSet($class, $name); + } + } + /** + * @return void + * @throws MemberAccessException + */ + public function __unset(string $name) + { + $class = static::class; + if (!ObjectHelpers::hasProperty($class, $name)) { + throw new MemberAccessException("Cannot unset the property {$class}::\${$name}."); + } + } + public function __isset(string $name) : bool + { + return isset(ObjectHelpers::getMagicProperties(static::class)[$name]); + } +} diff --git a/vendor/nette/utils/src/StaticClass.php b/vendor/nette/utils/src/StaticClass.php new file mode 100644 index 0000000000..66d1465972 --- /dev/null +++ b/vendor/nette/utils/src/StaticClass.php @@ -0,0 +1,32 @@ + + * @implements \ArrayAccess + */ +class ArrayHash extends \stdClass implements \ArrayAccess, \Countable, \IteratorAggregate +{ + /** + * Transforms array to ArrayHash. + * @param array $array + * @return static + */ + public static function from(array $array, bool $recursive = \true) + { + $obj = new static(); + foreach ($array as $key => $value) { + $obj->{$key} = $recursive && \is_array($value) ? static::from($value, \true) : $value; + } + return $obj; + } + /** + * Returns an iterator over all items. + * @return \RecursiveArrayIterator + */ + public function getIterator() : \RecursiveArrayIterator + { + return new \RecursiveArrayIterator((array) $this); + } + /** + * Returns items count. + */ + public function count() : int + { + return \count((array) $this); + } + /** + * Replaces or appends a item. + * @param array-key $key + * @param T $value + */ + public function offsetSet($key, $value) : void + { + if (!\is_scalar($key)) { + // prevents null + throw new Nette\InvalidArgumentException(\sprintf('Key must be either a string or an integer, %s given.', \gettype($key))); + } + $this->{$key} = $value; + } + /** + * Returns a item. + * @param array-key $key + * @return T + */ + #[\ReturnTypeWillChange] + public function offsetGet($key) + { + return $this->{$key}; + } + /** + * Determines whether a item exists. + * @param array-key $key + */ + public function offsetExists($key) : bool + { + return isset($this->{$key}); + } + /** + * Removes the element from this list. + * @param array-key $key + */ + public function offsetUnset($key) : void + { + unset($this->{$key}); + } +} diff --git a/vendor/nette/utils/src/Utils/ArrayList.php b/vendor/nette/utils/src/Utils/ArrayList.php new file mode 100644 index 0000000000..bd372c98dd --- /dev/null +++ b/vendor/nette/utils/src/Utils/ArrayList.php @@ -0,0 +1,111 @@ + + * @implements \ArrayAccess + */ +class ArrayList implements \ArrayAccess, \Countable, \IteratorAggregate +{ + use Nette\SmartObject; + /** @var mixed[] */ + private $list = []; + /** + * Transforms array to ArrayList. + * @param list $array + * @return static + */ + public static function from(array $array) + { + if (!Arrays::isList($array)) { + throw new Nette\InvalidArgumentException('Array is not valid list.'); + } + $obj = new static(); + $obj->list = $array; + return $obj; + } + /** + * Returns an iterator over all items. + * @return \ArrayIterator + */ + public function getIterator() : \ArrayIterator + { + return new \ArrayIterator($this->list); + } + /** + * Returns items count. + */ + public function count() : int + { + return \count($this->list); + } + /** + * Replaces or appends a item. + * @param int|null $index + * @param T $value + * @throws Nette\OutOfRangeException + */ + public function offsetSet($index, $value) : void + { + if ($index === null) { + $this->list[] = $value; + } elseif (!\is_int($index) || $index < 0 || $index >= \count($this->list)) { + throw new Nette\OutOfRangeException('Offset invalid or out of range'); + } else { + $this->list[$index] = $value; + } + } + /** + * Returns a item. + * @param int $index + * @return T + * @throws Nette\OutOfRangeException + */ + #[\ReturnTypeWillChange] + public function offsetGet($index) + { + if (!\is_int($index) || $index < 0 || $index >= \count($this->list)) { + throw new Nette\OutOfRangeException('Offset invalid or out of range'); + } + return $this->list[$index]; + } + /** + * Determines whether a item exists. + * @param int $index + */ + public function offsetExists($index) : bool + { + return \is_int($index) && $index >= 0 && $index < \count($this->list); + } + /** + * Removes the element at the specified position in this list. + * @param int $index + * @throws Nette\OutOfRangeException + */ + public function offsetUnset($index) : void + { + if (!\is_int($index) || $index < 0 || $index >= \count($this->list)) { + throw new Nette\OutOfRangeException('Offset invalid or out of range'); + } + \array_splice($this->list, $index, 1); + } + /** + * Prepends a item. + * @param T $value + */ + public function prepend($value) : void + { + $first = \array_slice($this->list, 0, 1); + $this->offsetSet(0, $value); + \array_splice($this->list, 1, 0, $first); + } +} diff --git a/vendor/nette/utils/src/Utils/Arrays.php b/vendor/nette/utils/src/Utils/Arrays.php new file mode 100644 index 0000000000..2b1f6c1b0e --- /dev/null +++ b/vendor/nette/utils/src/Utils/Arrays.php @@ -0,0 +1,394 @@ + $array + * @param array-key|array-key[] $key + * @param ?T $default + * @return ?T + * @throws Nette\InvalidArgumentException if item does not exist and default value is not provided + */ + public static function get(array $array, $key, $default = null) + { + foreach (is_array($key) ? $key : [$key] as $k) { + if (is_array($array) && \array_key_exists($k, $array)) { + $array = $array[$k]; + } else { + if (\func_num_args() < 3) { + throw new Nette\InvalidArgumentException("Missing item '{$k}'."); + } + return $default; + } + } + return $array; + } + /** + * Returns reference to array item. If the index does not exist, new one is created with value null. + * @template T + * @param array $array + * @param array-key|array-key[] $key + * @return ?T + * @throws Nette\InvalidArgumentException if traversed item is not an array + */ + public static function &getRef(array &$array, $key) + { + foreach (is_array($key) ? $key : [$key] as $k) { + if (is_array($array) || $array === null) { + $array =& $array[$k]; + } else { + throw new Nette\InvalidArgumentException('Traversed item is not an array.'); + } + } + return $array; + } + /** + * Recursively merges two fields. It is useful, for example, for merging tree structures. It behaves as + * the + operator for array, ie. it adds a key/value pair from the second array to the first one and retains + * the value from the first array in the case of a key collision. + * @template T1 + * @template T2 + * @param array $array1 + * @param array $array2 + * @return array + */ + public static function mergeTree(array $array1, array $array2) : array + { + $res = $array1 + $array2; + foreach (\array_intersect_key($array1, $array2) as $k => $v) { + if (is_array($v) && is_array($array2[$k])) { + $res[$k] = self::mergeTree($v, $array2[$k]); + } + } + return $res; + } + /** + * Returns zero-indexed position of given array key. Returns null if key is not found. + * @param array-key $key + * @return int|null offset if it is found, null otherwise + */ + public static function getKeyOffset(array $array, $key) : ?int + { + return Helpers::falseToNull(\array_search(self::toKey($key), \array_keys($array), \true)); + } + /** + * @deprecated use getKeyOffset() + */ + public static function searchKey(array $array, $key) : ?int + { + return self::getKeyOffset($array, $key); + } + /** + * Tests an array for the presence of value. + * @param mixed $value + */ + public static function contains(array $array, $value) : bool + { + return \in_array($value, $array, \true); + } + /** + * Returns the first item from the array or null if array is empty. + * @template T + * @param array $array + * @return ?T + */ + public static function first(array $array) + { + return count($array) ? \reset($array) : null; + } + /** + * Returns the last item from the array or null if array is empty. + * @template T + * @param array $array + * @return ?T + */ + public static function last(array $array) + { + return count($array) ? \end($array) : null; + } + /** + * Inserts the contents of the $inserted array into the $array immediately after the $key. + * If $key is null (or does not exist), it is inserted at the beginning. + * @param array-key|null $key + */ + public static function insertBefore(array &$array, $key, array $inserted) : void + { + $offset = $key === null ? 0 : (int) self::getKeyOffset($array, $key); + $array = \array_slice($array, 0, $offset, \true) + $inserted + \array_slice($array, $offset, count($array), \true); + } + /** + * Inserts the contents of the $inserted array into the $array before the $key. + * If $key is null (or does not exist), it is inserted at the end. + * @param array-key|null $key + */ + public static function insertAfter(array &$array, $key, array $inserted) : void + { + if ($key === null || ($offset = self::getKeyOffset($array, $key)) === null) { + $offset = count($array) - 1; + } + $array = \array_slice($array, 0, $offset + 1, \true) + $inserted + \array_slice($array, $offset + 1, count($array), \true); + } + /** + * Renames key in array. + * @param array-key $oldKey + * @param array-key $newKey + */ + public static function renameKey(array &$array, $oldKey, $newKey) : bool + { + $offset = self::getKeyOffset($array, $oldKey); + if ($offset === null) { + return \false; + } + $val =& $array[$oldKey]; + $keys = \array_keys($array); + $keys[$offset] = $newKey; + $array = \array_combine($keys, $array); + $array[$newKey] =& $val; + return \true; + } + /** + * Returns only those array items, which matches a regular expression $pattern. + * @param string[] $array + * @return string[] + */ + public static function grep( + array $array, + /** + * @language + */ + string $pattern, + int $flags = 0 + ) : array + { + return Strings::pcre('preg_grep', [$pattern, $array, $flags]); + } + /** + * Transforms multidimensional array to flat array. + */ + public static function flatten(array $array, bool $preserveKeys = \false) : array + { + $res = []; + $cb = $preserveKeys ? function ($v, $k) use(&$res) : void { + $res[$k] = $v; + } : function ($v) use(&$res) : void { + $res[] = $v; + }; + \array_walk_recursive($array, $cb); + return $res; + } + /** + * Checks if the array is indexed in ascending order of numeric keys from zero, a.k.a list. + * @param mixed $value + */ + public static function isList($value) : bool + { + $arrayIsListFunction = function (array $array) : bool { + if (\function_exists('array_is_list')) { + return \array_is_list($array); + } + if ($array === []) { + return \true; + } + $current_key = 0; + foreach ($array as $key => $noop) { + if ($key !== $current_key) { + return \false; + } + ++$current_key; + } + return \true; + }; + return is_array($value) && (\PHP_VERSION_ID < 80100 ? !$value || \array_keys($value) === \range(0, count($value) - 1) : $arrayIsListFunction($value)); + } + /** + * Reformats table to associative tree. Path looks like 'field|field[]field->field=field'. + * @param string|string[] $path + * @return array|\stdClass + */ + public static function associate(array $array, $path) + { + $parts = is_array($path) ? $path : \preg_split('#(\\[\\]|->|=|\\|)#', $path, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY); + if (!$parts || $parts === ['->'] || $parts[0] === '=' || $parts[0] === '|') { + throw new Nette\InvalidArgumentException("Invalid path '{$path}'."); + } + $res = $parts[0] === '->' ? new \stdClass() : []; + foreach ($array as $rowOrig) { + $row = (array) $rowOrig; + $x =& $res; + for ($i = 0; $i < count($parts); $i++) { + $part = $parts[$i]; + if ($part === '[]') { + $x =& $x[]; + } elseif ($part === '=') { + if (isset($parts[++$i])) { + $x = $row[$parts[$i]]; + $row = null; + } + } elseif ($part === '->') { + if (isset($parts[++$i])) { + if ($x === null) { + $x = new \stdClass(); + } + $x =& $x->{$row[$parts[$i]]}; + } else { + $row = is_object($rowOrig) ? $rowOrig : (object) $row; + } + } elseif ($part !== '|') { + $x =& $x[(string) $row[$part]]; + } + } + if ($x === null) { + $x = $row; + } + } + return $res; + } + /** + * Normalizes array to associative array. Replace numeric keys with their values, the new value will be $filling. + * @param mixed $filling + */ + public static function normalize(array $array, $filling = null) : array + { + $res = []; + foreach ($array as $k => $v) { + $res[is_int($k) ? $v : $k] = is_int($k) ? $filling : $v; + } + return $res; + } + /** + * Returns and removes the value of an item from an array. If it does not exist, it throws an exception, + * or returns $default, if provided. + * @template T + * @param array $array + * @param array-key $key + * @param ?T $default + * @return ?T + * @throws Nette\InvalidArgumentException if item does not exist and default value is not provided + */ + public static function pick(array &$array, $key, $default = null) + { + if (\array_key_exists($key, $array)) { + $value = $array[$key]; + unset($array[$key]); + return $value; + } elseif (\func_num_args() < 3) { + throw new Nette\InvalidArgumentException("Missing item '{$key}'."); + } else { + return $default; + } + } + /** + * Tests whether at least one element in the array passes the test implemented by the + * provided callback with signature `function ($value, $key, array $array): bool`. + */ + public static function some(iterable $array, callable $callback) : bool + { + foreach ($array as $k => $v) { + if ($callback($v, $k, $array)) { + return \true; + } + } + return \false; + } + /** + * Tests whether all elements in the array pass the test implemented by the provided function, + * which has the signature `function ($value, $key, array $array): bool`. + */ + public static function every(iterable $array, callable $callback) : bool + { + foreach ($array as $k => $v) { + if (!$callback($v, $k, $array)) { + return \false; + } + } + return \true; + } + /** + * Calls $callback on all elements in the array and returns the array of return values. + * The callback has the signature `function ($value, $key, array $array): bool`. + */ + public static function map(iterable $array, callable $callback) : array + { + $res = []; + foreach ($array as $k => $v) { + $res[$k] = $callback($v, $k, $array); + } + return $res; + } + /** + * Invokes all callbacks and returns array of results. + * @param callable[] $callbacks + */ + public static function invoke(iterable $callbacks, ...$args) : array + { + $res = []; + foreach ($callbacks as $k => $cb) { + $res[$k] = $cb(...$args); + } + return $res; + } + /** + * Invokes method on every object in an array and returns array of results. + * @param object[] $objects + */ + public static function invokeMethod(iterable $objects, string $method, ...$args) : array + { + $res = []; + foreach ($objects as $k => $obj) { + $res[$k] = $obj->{$method}(...$args); + } + return $res; + } + /** + * Copies the elements of the $array array to the $object object and then returns it. + * @template T of object + * @param T $object + * @return T + */ + public static function toObject(iterable $array, $object) + { + foreach ($array as $k => $v) { + $object->{$k} = $v; + } + return $object; + } + /** + * Converts value to array key. + * @param mixed $value + * @return array-key + */ + public static function toKey($value) + { + return \key([$value => null]); + } + /** + * Returns copy of the $array where every item is converted to string + * and prefixed by $prefix and suffixed by $suffix. + * @param string[] $array + * @return string[] + */ + public static function wrap(array $array, string $prefix = '', string $suffix = '') : array + { + $res = []; + foreach ($array as $k => $v) { + $res[$k] = $prefix . $v . $suffix; + } + return $res; + } +} diff --git a/vendor/nette/utils/src/Utils/Callback.php b/vendor/nette/utils/src/Utils/Callback.php new file mode 100644 index 0000000000..84487d1307 --- /dev/null +++ b/vendor/nette/utils/src/Utils/Callback.php @@ -0,0 +1,151 @@ +getMessage()); + } + } + /** + * Invokes callback. + * @return mixed + * @deprecated + */ + public static function invoke($callable, ...$args) + { + \trigger_error(__METHOD__ . '() is deprecated, use native invoking.', \E_USER_DEPRECATED); + self::check($callable); + return $callable(...$args); + } + /** + * Invokes callback with an array of parameters. + * @return mixed + * @deprecated + */ + public static function invokeArgs($callable, array $args = []) + { + \trigger_error(__METHOD__ . '() is deprecated, use native invoking.', \E_USER_DEPRECATED); + self::check($callable); + return $callable(...$args); + } + /** + * Invokes internal PHP function with own error handler. + * @return mixed + */ + public static function invokeSafe(string $function, array $args, callable $onError) + { + $prev = \set_error_handler(function ($severity, $message, $file) use($onError, &$prev, $function) : ?bool { + if ($file === __FILE__) { + $msg = \ini_get('html_errors') ? Html::htmlToText($message) : $message; + $msg = \preg_replace("#^{$function}\\(.*?\\): #", '', $msg); + if ($onError($msg, $severity) !== \false) { + return null; + } + } + return $prev ? $prev(...\func_get_args()) : \false; + }); + try { + return $function(...$args); + } finally { + \restore_error_handler(); + } + } + /** + * Checks that $callable is valid PHP callback. Otherwise throws exception. If the $syntax is set to true, only verifies + * that $callable has a valid structure to be used as a callback, but does not verify if the class or method actually exists. + * @param mixed $callable + * @return callable + * @throws Nette\InvalidArgumentException + */ + public static function check($callable, bool $syntax = \false) + { + if (!\is_callable($callable, $syntax)) { + throw new Nette\InvalidArgumentException($syntax ? 'Given value is not a callable type.' : \sprintf("Callback '%s' is not callable.", self::toString($callable))); + } + return $callable; + } + /** + * Converts PHP callback to textual form. Class or method may not exists. + * @param mixed $callable + */ + public static function toString($callable) : string + { + if ($callable instanceof \Closure) { + $inner = self::unwrap($callable); + return '{closure' . ($inner instanceof \Closure ? '}' : ' ' . self::toString($inner) . '}'); + } elseif (is_string($callable) && $callable[0] === "\x00") { + return '{lambda}'; + } else { + \is_callable(is_object($callable) ? [$callable, '__invoke'] : $callable, \true, $textual); + return $textual; + } + } + /** + * Returns reflection for method or function used in PHP callback. + * @param callable $callable type check is escalated to ReflectionException + * @return \ReflectionMethod|\ReflectionFunction + * @throws \ReflectionException if callback is not valid + */ + public static function toReflection($callable) : \ReflectionFunctionAbstract + { + if ($callable instanceof \Closure) { + $callable = self::unwrap($callable); + } + if (is_string($callable) && \strpos($callable, '::')) { + return new \ReflectionMethod($callable); + } elseif (is_array($callable)) { + return new \ReflectionMethod($callable[0], $callable[1]); + } elseif (is_object($callable) && !$callable instanceof \Closure) { + return new \ReflectionMethod($callable, '__invoke'); + } else { + return new \ReflectionFunction($callable); + } + } + /** + * Checks whether PHP callback is function or static method. + */ + public static function isStatic(callable $callable) : bool + { + return is_string(is_array($callable) ? $callable[0] : $callable); + } + /** + * Unwraps closure created by Closure::fromCallable(). + * @return callable|array + */ + public static function unwrap(\Closure $closure) + { + $r = new \ReflectionFunction($closure); + $class = $r->getClosureScopeClass(); + if (\substr($r->name, -1) === '}') { + return $closure; + } elseif (($obj = $r->getClosureThis()) && $class && \get_class($obj) === $class->name) { + return [$obj, $r->name]; + } elseif ($class) { + return [$class->name, $r->name]; + } else { + return $r->name; + } + } +} diff --git a/vendor/nette/utils/src/Utils/DateTime.php b/vendor/nette/utils/src/Utils/DateTime.php new file mode 100644 index 0000000000..f93b87a745 --- /dev/null +++ b/vendor/nette/utils/src/Utils/DateTime.php @@ -0,0 +1,105 @@ +format('Y-m-d H:i:s.u'), $time->getTimezone()); + } elseif (\is_numeric($time)) { + if ($time <= self::YEAR) { + $time += \time(); + } + return (new static('@' . $time))->setTimezone(new \DateTimeZone(\date_default_timezone_get())); + } else { + // textual or null + return new static((string) $time); + } + } + /** + * Creates DateTime object. + * @return static + * @throws Nette\InvalidArgumentException if the date and time are not valid. + */ + public static function fromParts(int $year, int $month, int $day, int $hour = 0, int $minute = 0, float $second = 0.0) + { + $s = \sprintf('%04d-%02d-%02d %02d:%02d:%02.5F', $year, $month, $day, $hour, $minute, $second); + if (!\checkdate($month, $day, $year) || $hour < 0 || $hour > 23 || $minute < 0 || $minute > 59 || $second < 0 || $second >= 60) { + throw new Nette\InvalidArgumentException("Invalid date '{$s}'"); + } + return new static($s); + } + /** + * Returns new DateTime object formatted according to the specified format. + * @param string $format The format the $time parameter should be in + * @param string $time + * @param string|\DateTimeZone $timezone (default timezone is used if null is passed) + * @return static|false + */ + #[\ReturnTypeWillChange] + public static function createFromFormat($format, $time, $timezone = null) + { + if ($timezone === null) { + $timezone = new \DateTimeZone(\date_default_timezone_get()); + } elseif (\is_string($timezone)) { + $timezone = new \DateTimeZone($timezone); + } elseif (!$timezone instanceof \DateTimeZone) { + throw new Nette\InvalidArgumentException('Invalid timezone given'); + } + $date = parent::createFromFormat($format, $time, $timezone); + return $date ? static::from($date) : \false; + } + /** + * Returns JSON representation in ISO 8601 (used by JavaScript). + */ + public function jsonSerialize() : string + { + return $this->format('c'); + } + /** + * Returns the date and time in the format 'Y-m-d H:i:s'. + */ + public function __toString() : string + { + return $this->format('Y-m-d H:i:s'); + } + /** + * Creates a copy with a modified time. + * @return static + */ + public function modifyClone(string $modify = '') + { + $dolly = clone $this; + return $modify ? $dolly->modify($modify) : $dolly; + } +} diff --git a/vendor/nette/utils/src/Utils/FileSystem.php b/vendor/nette/utils/src/Utils/FileSystem.php new file mode 100644 index 0000000000..7bf3831ffd --- /dev/null +++ b/vendor/nette/utils/src/Utils/FileSystem.php @@ -0,0 +1,186 @@ +getPathname()); + } + foreach ($iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($origin, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST) as $item) { + if ($item->isDir()) { + static::createDir($target . '/' . $iterator->getSubPathName()); + } else { + static::copy($item->getPathname(), $target . '/' . $iterator->getSubPathName()); + } + } + } else { + static::createDir(\dirname($target)); + if (($s = @\fopen($origin, 'rb')) && ($d = @\fopen($target, 'wb')) && @\stream_copy_to_stream($s, $d) === \false) { + // @ is escalated to exception + throw new Nette\IOException(\sprintf("Unable to copy file '%s' to '%s'. %s", self::normalizePath($origin), self::normalizePath($target), Helpers::getLastError())); + } + } + } + /** + * Deletes a file or an entire directory if exists. If the directory is not empty, it deletes its contents first. + * @throws Nette\IOException on error occurred + */ + public static function delete(string $path) : void + { + if (\is_file($path) || \is_link($path)) { + $func = \DIRECTORY_SEPARATOR === '\\' && \is_dir($path) ? 'rmdir' : 'unlink'; + if (!@$func($path)) { + // @ is escalated to exception + throw new Nette\IOException(\sprintf("Unable to delete '%s'. %s", self::normalizePath($path), Helpers::getLastError())); + } + } elseif (\is_dir($path)) { + foreach (new \FilesystemIterator($path) as $item) { + static::delete($item->getPathname()); + } + if (!@\rmdir($path)) { + // @ is escalated to exception + throw new Nette\IOException(\sprintf("Unable to delete directory '%s'. %s", self::normalizePath($path), Helpers::getLastError())); + } + } + } + /** + * Renames or moves a file or a directory. Overwrites existing files and directories by default. + * @throws Nette\IOException on error occurred + * @throws Nette\InvalidStateException if $overwrite is set to false and destination already exists + */ + public static function rename(string $origin, string $target, bool $overwrite = \true) : void + { + if (!$overwrite && \file_exists($target)) { + throw new Nette\InvalidStateException(\sprintf("File or directory '%s' already exists.", self::normalizePath($target))); + } elseif (!\file_exists($origin)) { + throw new Nette\IOException(\sprintf("File or directory '%s' not found.", self::normalizePath($origin))); + } else { + static::createDir(\dirname($target)); + if (\realpath($origin) !== \realpath($target)) { + static::delete($target); + } + if (!@\rename($origin, $target)) { + // @ is escalated to exception + throw new Nette\IOException(\sprintf("Unable to rename file or directory '%s' to '%s'. %s", self::normalizePath($origin), self::normalizePath($target), Helpers::getLastError())); + } + } + } + /** + * Reads the content of a file. + * @throws Nette\IOException on error occurred + */ + public static function read(string $file) : string + { + $content = @\file_get_contents($file); + // @ is escalated to exception + if ($content === \false) { + throw new Nette\IOException(\sprintf("Unable to read file '%s'. %s", self::normalizePath($file), Helpers::getLastError())); + } + return $content; + } + /** + * Writes the string to a file. + * @throws Nette\IOException on error occurred + */ + public static function write(string $file, string $content, ?int $mode = 0666) : void + { + static::createDir(\dirname($file)); + if (@\file_put_contents($file, $content) === \false) { + // @ is escalated to exception + throw new Nette\IOException(\sprintf("Unable to write file '%s'. %s", self::normalizePath($file), Helpers::getLastError())); + } + if ($mode !== null && !@\chmod($file, $mode)) { + // @ is escalated to exception + throw new Nette\IOException(\sprintf("Unable to chmod file '%s' to mode %s. %s", self::normalizePath($file), \decoct($mode), Helpers::getLastError())); + } + } + /** + * Sets file permissions to `$fileMode` or directory permissions to `$dirMode`. + * Recursively traverses and sets permissions on the entire contents of the directory as well. + * @throws Nette\IOException on error occurred + */ + public static function makeWritable(string $path, int $dirMode = 0777, int $fileMode = 0666) : void + { + if (\is_file($path)) { + if (!@\chmod($path, $fileMode)) { + // @ is escalated to exception + throw new Nette\IOException(\sprintf("Unable to chmod file '%s' to mode %s. %s", self::normalizePath($path), \decoct($fileMode), Helpers::getLastError())); + } + } elseif (\is_dir($path)) { + foreach (new \FilesystemIterator($path) as $item) { + static::makeWritable($item->getPathname(), $dirMode, $fileMode); + } + if (!@\chmod($path, $dirMode)) { + // @ is escalated to exception + throw new Nette\IOException(\sprintf("Unable to chmod directory '%s' to mode %s. %s", self::normalizePath($path), \decoct($dirMode), Helpers::getLastError())); + } + } else { + throw new Nette\IOException(\sprintf("File or directory '%s' not found.", self::normalizePath($path))); + } + } + /** + * Determines if the path is absolute. + */ + public static function isAbsolute(string $path) : bool + { + return (bool) \preg_match('#([a-z]:)?[/\\\\]|[a-z][a-z0-9+.-]*://#Ai', $path); + } + /** + * Normalizes `..` and `.` and directory separators in path. + */ + public static function normalizePath(string $path) : string + { + $parts = $path === '' ? [] : \preg_split('~[/\\\\]+~', $path); + $res = []; + foreach ($parts as $part) { + if ($part === '..' && $res && \end($res) !== '..' && \end($res) !== '') { + \array_pop($res); + } elseif ($part !== '.') { + $res[] = $part; + } + } + return $res === [''] ? \DIRECTORY_SEPARATOR : \implode(\DIRECTORY_SEPARATOR, $res); + } + /** + * Joins all segments of the path and normalizes the result. + */ + public static function joinPaths(string ...$paths) : string + { + return self::normalizePath(\implode('/', $paths)); + } +} diff --git a/vendor/nette/utils/src/Utils/Floats.php b/vendor/nette/utils/src/Utils/Floats.php new file mode 100644 index 0000000000..43189361ea --- /dev/null +++ b/vendor/nette/utils/src/Utils/Floats.php @@ -0,0 +1,83 @@ + $b it returns 1 + * @throws \LogicException if one of parameters is NAN + */ + public static function compare(float $a, float $b) : int + { + if (\is_nan($a) || \is_nan($b)) { + throw new \LogicException('Trying to compare NAN'); + } elseif (!\is_finite($a) && !\is_finite($b) && $a === $b) { + return 0; + } + $diff = \abs($a - $b); + if ($diff < self::Epsilon || $diff / \max(\abs($a), \abs($b)) < self::Epsilon) { + return 0; + } + return $a < $b ? -1 : 1; + } + /** + * Returns true if $a = $b + * @throws \LogicException if one of parameters is NAN + */ + public static function areEqual(float $a, float $b) : bool + { + return self::compare($a, $b) === 0; + } + /** + * Returns true if $a < $b + * @throws \LogicException if one of parameters is NAN + */ + public static function isLessThan(float $a, float $b) : bool + { + return self::compare($a, $b) < 0; + } + /** + * Returns true if $a <= $b + * @throws \LogicException if one of parameters is NAN + */ + public static function isLessThanOrEqualTo(float $a, float $b) : bool + { + return self::compare($a, $b) <= 0; + } + /** + * Returns true if $a > $b + * @throws \LogicException if one of parameters is NAN + */ + public static function isGreaterThan(float $a, float $b) : bool + { + return self::compare($a, $b) > 0; + } + /** + * Returns true if $a >= $b + * @throws \LogicException if one of parameters is NAN + */ + public static function isGreaterThanOrEqualTo(float $a, float $b) : bool + { + return self::compare($a, $b) >= 0; + } +} diff --git a/vendor/nette/utils/src/Utils/Helpers.php b/vendor/nette/utils/src/Utils/Helpers.php new file mode 100644 index 0000000000..183ce3971e --- /dev/null +++ b/vendor/nette/utils/src/Utils/Helpers.php @@ -0,0 +1,78 @@ + $max) { + throw new Nette\InvalidArgumentException("Minimum ({$min}) is not less than maximum ({$max})."); + } + return \min(\max($value, $min), $max); + } + /** + * Looks for a string from possibilities that is most similar to value, but not the same (for 8-bit encoding). + * @param string[] $possibilities + */ + public static function getSuggestion(array $possibilities, string $value) : ?string + { + $best = null; + $min = (\strlen($value) / 4 + 1) * 10 + 0.1; + foreach (\array_unique($possibilities) as $item) { + if ($item !== $value && ($len = \levenshtein($item, $value, 10, 11, 10)) < $min) { + $min = $len; + $best = $item; + } + } + return $best; + } +} diff --git a/vendor/nette/utils/src/Utils/Html.php b/vendor/nette/utils/src/Utils/Html.php new file mode 100644 index 0000000000..1cf04515e0 --- /dev/null +++ b/vendor/nette/utils/src/Utils/Html.php @@ -0,0 +1,744 @@ + element's attributes */ + public $attrs = []; + /** @var bool use XHTML syntax? */ + public static $xhtml = \false; + /** @var array void elements */ + public static $emptyElements = ['img' => 1, 'hr' => 1, 'br' => 1, 'input' => 1, 'meta' => 1, 'area' => 1, 'embed' => 1, 'keygen' => 1, 'source' => 1, 'base' => 1, 'col' => 1, 'link' => 1, 'param' => 1, 'basefont' => 1, 'frame' => 1, 'isindex' => 1, 'wbr' => 1, 'command' => 1, 'track' => 1]; + /** @var array nodes */ + protected $children = []; + /** @var string element's name */ + private $name; + /** @var bool is element empty? */ + private $isEmpty; + /** + * Constructs new HTML element. + * @param array|string $attrs element's attributes or plain text content + * @return static + */ + public static function el(?string $name = null, $attrs = null) + { + $el = new static(); + $parts = \explode(' ', (string) $name, 2); + $el->setName($parts[0]); + if (is_array($attrs)) { + $el->attrs = $attrs; + } elseif ($attrs !== null) { + $el->setText($attrs); + } + if (isset($parts[1])) { + foreach (Strings::matchAll($parts[1] . ' ', '#([a-z0-9:-]+)(?:=(["\'])?(.*?)(?(2)\\2|\\s))?#i') as $m) { + $el->attrs[$m[1]] = $m[3] ?? \true; + } + } + return $el; + } + /** + * Returns an object representing HTML text. + */ + public static function fromHtml(string $html) : self + { + return (new static())->setHtml($html); + } + /** + * Returns an object representing plain text. + */ + public static function fromText(string $text) : self + { + return (new static())->setText($text); + } + /** + * Converts to HTML. + */ + public final function toHtml() : string + { + return $this->render(); + } + /** + * Converts to plain text. + */ + public final function toText() : string + { + return $this->getText(); + } + /** + * Converts given HTML code to plain text. + */ + public static function htmlToText(string $html) : string + { + return \html_entity_decode(\strip_tags($html), \ENT_QUOTES | \ENT_HTML5, 'UTF-8'); + } + /** + * Changes element's name. + * @return static + */ + public final function setName(string $name, ?bool $isEmpty = null) + { + $this->name = $name; + $this->isEmpty = $isEmpty ?? isset(static::$emptyElements[$name]); + return $this; + } + /** + * Returns element's name. + */ + public final function getName() : string + { + return $this->name; + } + /** + * Is element empty? + */ + public final function isEmpty() : bool + { + return $this->isEmpty; + } + /** + * Sets multiple attributes. + * @return static + */ + public function addAttributes(array $attrs) + { + $this->attrs = \array_merge($this->attrs, $attrs); + return $this; + } + /** + * Appends value to element's attribute. + * @param mixed $value + * @param mixed $option + * @return static + */ + public function appendAttribute(string $name, $value, $option = \true) + { + if (is_array($value)) { + $prev = isset($this->attrs[$name]) ? (array) $this->attrs[$name] : []; + $this->attrs[$name] = $value + $prev; + } elseif ((string) $value === '') { + $tmp =& $this->attrs[$name]; + // appending empty value? -> ignore, but ensure it exists + } elseif (!isset($this->attrs[$name]) || is_array($this->attrs[$name])) { + // needs array + $this->attrs[$name][$value] = $option; + } else { + $this->attrs[$name] = [$this->attrs[$name] => \true, $value => $option]; + } + return $this; + } + /** + * Sets element's attribute. + * @param mixed $value + * @return static + */ + public function setAttribute(string $name, $value) + { + $this->attrs[$name] = $value; + return $this; + } + /** + * Returns element's attribute. + * @return mixed + */ + public function getAttribute(string $name) + { + return $this->attrs[$name] ?? null; + } + /** + * Unsets element's attribute. + * @return static + */ + public function removeAttribute(string $name) + { + unset($this->attrs[$name]); + return $this; + } + /** + * Unsets element's attributes. + * @return static + */ + public function removeAttributes(array $attributes) + { + foreach ($attributes as $name) { + unset($this->attrs[$name]); + } + return $this; + } + /** + * Overloaded setter for element's attribute. + * @param mixed $value + */ + public final function __set(string $name, $value) : void + { + $this->attrs[$name] = $value; + } + /** + * Overloaded getter for element's attribute. + * @return mixed + */ + public final function &__get(string $name) + { + return $this->attrs[$name]; + } + /** + * Overloaded tester for element's attribute. + */ + public final function __isset(string $name) : bool + { + return isset($this->attrs[$name]); + } + /** + * Overloaded unsetter for element's attribute. + */ + public final function __unset(string $name) : void + { + unset($this->attrs[$name]); + } + /** + * Overloaded setter for element's attribute. + * @return mixed + */ + public final function __call(string $m, array $args) + { + $p = \substr($m, 0, 3); + if ($p === 'get' || $p === 'set' || $p === 'add') { + $m = \substr($m, 3); + $m[0] = $m[0] | " "; + if ($p === 'get') { + return $this->attrs[$m] ?? null; + } elseif ($p === 'add') { + $args[] = \true; + } + } + if (\count($args) === 0) { + // invalid + } elseif (\count($args) === 1) { + // set + $this->attrs[$m] = $args[0]; + } else { + // add + $this->appendAttribute($m, $args[0], $args[1]); + } + return $this; + } + /** + * Special setter for element's attribute. + * @return static + */ + public final function href(string $path, ?array $query = null) + { + if ($query) { + $query = \http_build_query($query, '', '&'); + if ($query !== '') { + $path .= '?' . $query; + } + } + $this->attrs['href'] = $path; + return $this; + } + /** + * Setter for data-* attributes. Booleans are converted to 'true' resp. 'false'. + * @param mixed $value + * @return static + */ + public function data(string $name, $value = null) + { + if (\func_num_args() === 1) { + $this->attrs['data'] = $name; + } else { + $this->attrs["data-{$name}"] = \is_bool($value) ? \json_encode($value) : $value; + } + return $this; + } + /** + * Sets element's HTML content. + * @param HtmlStringable|string $html + * @return static + */ + public final function setHtml($html) + { + $this->children = [(string) $html]; + return $this; + } + /** + * Returns element's HTML content. + */ + public final function getHtml() : string + { + return \implode('', $this->children); + } + /** + * Sets element's textual content. + * @param HtmlStringable|string|int|float $text + * @return static + */ + public final function setText($text) + { + if (!$text instanceof HtmlStringable) { + $text = \htmlspecialchars((string) $text, \ENT_NOQUOTES, 'UTF-8'); + } + $this->children = [(string) $text]; + return $this; + } + /** + * Returns element's textual content. + */ + public final function getText() : string + { + return self::htmlToText($this->getHtml()); + } + /** + * Adds new element's child. + * @param HtmlStringable|string $child Html node or raw HTML string + * @return static + */ + public final function addHtml($child) + { + return $this->insert(null, $child); + } + /** + * Appends plain-text string to element content. + * @param HtmlStringable|string|int|float $text + * @return static + */ + public function addText($text) + { + if (!$text instanceof HtmlStringable) { + $text = \htmlspecialchars((string) $text, \ENT_NOQUOTES, 'UTF-8'); + } + return $this->insert(null, $text); + } + /** + * Creates and adds a new Html child. + * @param array|string $attrs element's attributes or raw HTML string + * @return static created element + */ + public final function create(string $name, $attrs = null) + { + $this->insert(null, $child = static::el($name, $attrs)); + return $child; + } + /** + * Inserts child node. + * @param HtmlStringable|string $child Html node or raw HTML string + * @return static + */ + public function insert(?int $index, $child, bool $replace = \false) + { + $child = $child instanceof self ? $child : (string) $child; + if ($index === null) { + // append + $this->children[] = $child; + } else { + // insert or replace + \array_splice($this->children, $index, $replace ? 1 : 0, [$child]); + } + return $this; + } + /** + * Inserts (replaces) child node (\ArrayAccess implementation). + * @param int|null $index position or null for appending + * @param Html|string $child Html node or raw HTML string + */ + public final function offsetSet($index, $child) : void + { + $this->insert($index, $child, \true); + } + /** + * Returns child node (\ArrayAccess implementation). + * @param int $index + * @return HtmlStringable|string + */ + #[\ReturnTypeWillChange] + public final function offsetGet($index) + { + return $this->children[$index]; + } + /** + * Exists child node? (\ArrayAccess implementation). + * @param int $index + */ + public final function offsetExists($index) : bool + { + return isset($this->children[$index]); + } + /** + * Removes child node (\ArrayAccess implementation). + * @param int $index + */ + public function offsetUnset($index) : void + { + if (isset($this->children[$index])) { + \array_splice($this->children, $index, 1); + } + } + /** + * Returns children count. + */ + public final function count() : int + { + return \count($this->children); + } + /** + * Removes all children. + */ + public function removeChildren() : void + { + $this->children = []; + } + /** + * Iterates over elements. + * @return \ArrayIterator + */ + public final function getIterator() : \ArrayIterator + { + return new \ArrayIterator($this->children); + } + /** + * Returns all children. + */ + public final function getChildren() : array + { + return $this->children; + } + /** + * Renders element's start tag, content and end tag. + */ + public final function render(?int $indent = null) : string + { + $s = $this->startTag(); + if (!$this->isEmpty) { + // add content + if ($indent !== null) { + $indent++; + } + foreach ($this->children as $child) { + if ($child instanceof self) { + $s .= $child->render($indent); + } else { + $s .= $child; + } + } + // add end tag + $s .= $this->endTag(); + } + if ($indent !== null) { + return "\n" . \str_repeat("\t", $indent - 1) . $s . "\n" . \str_repeat("\t", \max(0, $indent - 2)); + } + return $s; + } + public final function __toString() : string + { + try { + return $this->render(); + } catch (\Throwable $e) { + if (\PHP_VERSION_ID >= 70400) { + throw $e; + } + \trigger_error('Exception in ' . __METHOD__ . "(): {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}", \E_USER_ERROR); + return ''; + } + } + /** + * Returns element's start tag. + */ + public final function startTag() : string + { + return $this->name ? '<' . $this->name . $this->attributes() . (static::$xhtml && $this->isEmpty ? ' />' : '>') : ''; + } + /** + * Returns element's end tag. + */ + public final function endTag() : string + { + return $this->name && !$this->isEmpty ? 'name . '>' : ''; + } + /** + * Returns element's attributes. + * @internal + */ + public final function attributes() : string + { + if (!is_array($this->attrs)) { + return ''; + } + $s = ''; + $attrs = $this->attrs; + foreach ($attrs as $key => $value) { + if ($value === null || $value === \false) { + continue; + } elseif ($value === \true) { + if (static::$xhtml) { + $s .= ' ' . $key . '="' . $key . '"'; + } else { + $s .= ' ' . $key; + } + continue; + } elseif (is_array($value)) { + if (\strncmp($key, 'data-', 5) === 0) { + $value = Json::encode($value); + } else { + $tmp = null; + foreach ($value as $k => $v) { + if ($v != null) { + // intentionally ==, skip nulls & empty string + // composite 'style' vs. 'others' + $tmp[] = $v === \true ? $k : (is_string($k) ? $k . ':' . $v : $v); + } + } + if ($tmp === null) { + continue; + } + $value = \implode($key === 'style' || !\strncmp($key, 'on', 2) ? ';' : ' ', $tmp); + } + } elseif (is_float($value)) { + $value = \rtrim(\rtrim(\number_format($value, 10, '.', ''), '0'), '.'); + } else { + $value = (string) $value; + } + $q = \strpos($value, '"') === \false ? '"' : "'"; + $s .= ' ' . $key . '=' . $q . \str_replace(['&', $q, '<'], ['&', $q === '"' ? '"' : ''', self::$xhtml ? '<' : '<'], $value) . (\strpos($value, '`') !== \false && \strpbrk($value, ' <>"\'') === \false ? ' ' : '') . $q; + } + $s = \str_replace('@', '@', $s); + return $s; + } + /** + * Clones all children too. + */ + public function __clone() + { + foreach ($this->children as $key => $value) { + if (is_object($value)) { + $this->children[$key] = clone $value; + } + } + } +} diff --git a/vendor/nette/utils/src/Utils/Image.php b/vendor/nette/utils/src/Utils/Image.php new file mode 100644 index 0000000000..c8e61064be --- /dev/null +++ b/vendor/nette/utils/src/Utils/Image.php @@ -0,0 +1,611 @@ + + * $image = Image::fromFile('nette.jpg'); + * $image->resize(150, 100); + * $image->sharpen(); + * $image->send(); + * + * + * @method Image affine(array $affine, array $clip = null) + * @method array affineMatrixConcat(array $m1, array $m2) + * @method array affineMatrixGet(int $type, mixed $options = null) + * @method void alphaBlending(bool $on) + * @method void antialias(bool $on) + * @method void arc($x, $y, $w, $h, $start, $end, $color) + * @method void char(int $font, $x, $y, string $char, $color) + * @method void charUp(int $font, $x, $y, string $char, $color) + * @method int colorAllocate($red, $green, $blue) + * @method int colorAllocateAlpha($red, $green, $blue, $alpha) + * @method int colorAt($x, $y) + * @method int colorClosest($red, $green, $blue) + * @method int colorClosestAlpha($red, $green, $blue, $alpha) + * @method int colorClosestHWB($red, $green, $blue) + * @method void colorDeallocate($color) + * @method int colorExact($red, $green, $blue) + * @method int colorExactAlpha($red, $green, $blue, $alpha) + * @method void colorMatch(Image $image2) + * @method int colorResolve($red, $green, $blue) + * @method int colorResolveAlpha($red, $green, $blue, $alpha) + * @method void colorSet($index, $red, $green, $blue) + * @method array colorsForIndex($index) + * @method int colorsTotal() + * @method int colorTransparent($color = null) + * @method void convolution(array $matrix, float $div, float $offset) + * @method void copy(Image $src, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH) + * @method void copyMerge(Image $src, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH, $opacity) + * @method void copyMergeGray(Image $src, $dstX, $dstY, $srcX, $srcY, $srcW, $srcH, $opacity) + * @method void copyResampled(Image $src, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH) + * @method void copyResized(Image $src, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH) + * @method Image cropAuto(int $mode = -1, float $threshold = .5, int $color = -1) + * @method void ellipse($cx, $cy, $w, $h, $color) + * @method void fill($x, $y, $color) + * @method void filledArc($cx, $cy, $w, $h, $s, $e, $color, $style) + * @method void filledEllipse($cx, $cy, $w, $h, $color) + * @method void filledPolygon(array $points, $numPoints, $color) + * @method void filledRectangle($x1, $y1, $x2, $y2, $color) + * @method void fillToBorder($x, $y, $border, $color) + * @method void filter($filtertype) + * @method void flip(int $mode) + * @method array ftText($size, $angle, $x, $y, $col, string $fontFile, string $text, array $extrainfo = null) + * @method void gammaCorrect(float $inputgamma, float $outputgamma) + * @method array getClip() + * @method int interlace($interlace = null) + * @method bool isTrueColor() + * @method void layerEffect($effect) + * @method void line($x1, $y1, $x2, $y2, $color) + * @method void openPolygon(array $points, int $num_points, int $color) + * @method void paletteCopy(Image $source) + * @method void paletteToTrueColor() + * @method void polygon(array $points, $numPoints, $color) + * @method array psText(string $text, $font, $size, $color, $backgroundColor, $x, $y, $space = null, $tightness = null, float $angle = null, $antialiasSteps = null) + * @method void rectangle($x1, $y1, $x2, $y2, $col) + * @method mixed resolution(int $res_x = null, int $res_y = null) + * @method Image rotate(float $angle, $backgroundColor) + * @method void saveAlpha(bool $saveflag) + * @method Image scale(int $newWidth, int $newHeight = -1, int $mode = IMG_BILINEAR_FIXED) + * @method void setBrush(Image $brush) + * @method void setClip(int $x1, int $y1, int $x2, int $y2) + * @method void setInterpolation(int $method = IMG_BILINEAR_FIXED) + * @method void setPixel($x, $y, $color) + * @method void setStyle(array $style) + * @method void setThickness($thickness) + * @method void setTile(Image $tile) + * @method void string($font, $x, $y, string $s, $col) + * @method void stringUp($font, $x, $y, string $s, $col) + * @method void trueColorToPalette(bool $dither, $ncolors) + * @method array ttfText($size, $angle, $x, $y, $color, string $fontfile, string $text) + * @property-read positive-int $width + * @property-read positive-int $height + * @property-read resource|\GdImage $imageResource + */ +class Image +{ + use Nette\SmartObject; + /** Prevent from getting resized to a bigger size than the original */ + public const SHRINK_ONLY = 0b1; + /** Resizes to a specified width and height without keeping aspect ratio */ + public const STRETCH = 0b10; + /** Resizes to fit into a specified width and height and preserves aspect ratio */ + public const FIT = 0b0; + /** Resizes while bounding the smaller dimension to the specified width or height and preserves aspect ratio */ + public const FILL = 0b100; + /** Resizes to the smallest possible size to completely cover specified width and height and reserves aspect ratio */ + public const EXACT = 0b1000; + /** image types */ + public const JPEG = \IMAGETYPE_JPEG, PNG = \IMAGETYPE_PNG, GIF = \IMAGETYPE_GIF, WEBP = \IMAGETYPE_WEBP, AVIF = 19, BMP = \IMAGETYPE_BMP; + public const EMPTY_GIF = "GIF89a\x01\x00\x01\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00!\xf9\x04\x01\x00\x00\x00\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02D\x01\x00;"; + private const Formats = [self::JPEG => 'jpeg', self::PNG => 'png', self::GIF => 'gif', self::WEBP => 'webp', self::AVIF => 'avif', self::BMP => 'bmp']; + /** @var resource|\GdImage */ + private $image; + /** + * Returns RGB color (0..255) and transparency (0..127). + */ + public static function rgb(int $red, int $green, int $blue, int $transparency = 0) : array + { + return ['red' => \max(0, \min(255, $red)), 'green' => \max(0, \min(255, $green)), 'blue' => \max(0, \min(255, $blue)), 'alpha' => \max(0, \min(127, $transparency))]; + } + /** + * Reads an image from a file and returns its type in $type. + * @throws Nette\NotSupportedException if gd extension is not loaded + * @throws UnknownImageFileException if file not found or file type is not known + * @return static + */ + public static function fromFile(string $file, ?int &$type = null) + { + if (!\extension_loaded('gd')) { + throw new Nette\NotSupportedException('PHP extension GD is not loaded.'); + } + $type = self::detectTypeFromFile($file); + if (!$type) { + throw new UnknownImageFileException(\is_file($file) ? "Unknown type of file '{$file}'." : "File '{$file}' not found."); + } + return self::invokeSafe('imagecreatefrom' . self::Formats[$type], $file, "Unable to open file '{$file}'.", __METHOD__); + } + /** + * Reads an image from a string and returns its type in $type. + * @return static + * @throws Nette\NotSupportedException if gd extension is not loaded + * @throws ImageException + */ + public static function fromString(string $s, ?int &$type = null) + { + if (!\extension_loaded('gd')) { + throw new Nette\NotSupportedException('PHP extension GD is not loaded.'); + } + $type = self::detectTypeFromString($s); + if (!$type) { + throw new UnknownImageFileException('Unknown type of image.'); + } + return self::invokeSafe('imagecreatefromstring', $s, 'Unable to open image from string.', __METHOD__); + } + private static function invokeSafe(string $func, string $arg, string $message, string $callee) : self + { + $errors = []; + $res = Callback::invokeSafe($func, [$arg], function (string $message) use(&$errors) : void { + $errors[] = $message; + }); + if (!$res) { + throw new ImageException($message . ' Errors: ' . \implode(', ', $errors)); + } elseif ($errors) { + \trigger_error($callee . '(): ' . \implode(', ', $errors), \E_USER_WARNING); + } + return new static($res); + } + /** + * Creates a new true color image of the given dimensions. The default color is black. + * @param positive-int $width + * @param positive-int $height + * @return static + * @throws Nette\NotSupportedException if gd extension is not loaded + */ + public static function fromBlank(int $width, int $height, ?array $color = null) + { + if (!\extension_loaded('gd')) { + throw new Nette\NotSupportedException('PHP extension GD is not loaded.'); + } + if ($width < 1 || $height < 1) { + throw new Nette\InvalidArgumentException('Image width and height must be greater than zero.'); + } + $image = \imagecreatetruecolor($width, $height); + if ($color) { + $color += ['alpha' => 0]; + $color = \imagecolorresolvealpha($image, $color['red'], $color['green'], $color['blue'], $color['alpha']); + \imagealphablending($image, \false); + \imagefilledrectangle($image, 0, 0, $width - 1, $height - 1, $color); + \imagealphablending($image, \true); + } + return new static($image); + } + /** + * Returns the type of image from file. + */ + public static function detectTypeFromFile(string $file, &$width = null, &$height = null) : ?int + { + [$width, $height, $type] = @\getimagesize($file); + // @ - files smaller than 12 bytes causes read error + return isset(self::Formats[$type]) ? $type : null; + } + /** + * Returns the type of image from string. + */ + public static function detectTypeFromString(string $s, &$width = null, &$height = null) : ?int + { + [$width, $height, $type] = @\getimagesizefromstring($s); + // @ - strings smaller than 12 bytes causes read error + return isset(self::Formats[$type]) ? $type : null; + } + /** + * Returns the file extension for the given `Image::XXX` constant. + */ + public static function typeToExtension(int $type) : string + { + if (!isset(self::Formats[$type])) { + throw new Nette\InvalidArgumentException("Unsupported image type '{$type}'."); + } + return self::Formats[$type]; + } + /** + * Returns the `Image::XXX` constant for given file extension. + */ + public static function extensionToType(string $extension) : int + { + $extensions = \array_flip(self::Formats) + ['jpg' => self::JPEG]; + $extension = \strtolower($extension); + if (!isset($extensions[$extension])) { + throw new Nette\InvalidArgumentException("Unsupported file extension '{$extension}'."); + } + return $extensions[$extension]; + } + /** + * Returns the mime type for the given `Image::XXX` constant. + */ + public static function typeToMimeType(int $type) : string + { + return 'image/' . self::typeToExtension($type); + } + /** + * Wraps GD image. + * @param resource|\GdImage $image + */ + public function __construct($image) + { + $this->setImageResource($image); + \imagesavealpha($image, \true); + } + /** + * Returns image width. + * @return positive-int + */ + public function getWidth() : int + { + return \imagesx($this->image); + } + /** + * Returns image height. + * @return positive-int + */ + public function getHeight() : int + { + return \imagesy($this->image); + } + /** + * Sets image resource. + * @param resource|\GdImage $image + * @return static + */ + protected function setImageResource($image) + { + if (!$image instanceof \GdImage && !(\is_resource($image) && \get_resource_type($image) === 'gd')) { + throw new Nette\InvalidArgumentException('Image is not valid.'); + } + $this->image = $image; + return $this; + } + /** + * Returns image GD resource. + * @return resource|\GdImage + */ + public function getImageResource() + { + return $this->image; + } + /** + * Scales an image. + * @param int|string|null $width in pixels or percent + * @param int|string|null $height in pixels or percent + * @return static + */ + public function resize($width, $height, int $flags = self::FIT) + { + if ($flags & self::EXACT) { + return $this->resize($width, $height, self::FILL)->crop('50%', '50%', $width, $height); + } + [$newWidth, $newHeight] = static::calculateSize($this->getWidth(), $this->getHeight(), $width, $height, $flags); + if ($newWidth !== $this->getWidth() || $newHeight !== $this->getHeight()) { + // resize + $newImage = static::fromBlank($newWidth, $newHeight, self::rgb(0, 0, 0, 127))->getImageResource(); + \imagecopyresampled($newImage, $this->image, 0, 0, 0, 0, $newWidth, $newHeight, $this->getWidth(), $this->getHeight()); + $this->image = $newImage; + } + if ($width < 0 || $height < 0) { + \imageflip($this->image, $width < 0 ? $height < 0 ? \IMG_FLIP_BOTH : \IMG_FLIP_HORIZONTAL : \IMG_FLIP_VERTICAL); + } + return $this; + } + /** + * Calculates dimensions of resized image. + * @param int|string|null $newWidth in pixels or percent + * @param int|string|null $newHeight in pixels or percent + */ + public static function calculateSize(int $srcWidth, int $srcHeight, $newWidth, $newHeight, int $flags = self::FIT) : array + { + if ($newWidth === null) { + } elseif (self::isPercent($newWidth)) { + $newWidth = (int) \round($srcWidth / 100 * \abs($newWidth)); + $percents = \true; + } else { + $newWidth = \abs($newWidth); + } + if ($newHeight === null) { + } elseif (self::isPercent($newHeight)) { + $newHeight = (int) \round($srcHeight / 100 * \abs($newHeight)); + $flags |= empty($percents) ? 0 : self::STRETCH; + } else { + $newHeight = \abs($newHeight); + } + if ($flags & self::STRETCH) { + // non-proportional + if (!$newWidth || !$newHeight) { + throw new Nette\InvalidArgumentException('For stretching must be both width and height specified.'); + } + if ($flags & self::SHRINK_ONLY) { + $newWidth = (int) \round($srcWidth * \min(1, $newWidth / $srcWidth)); + $newHeight = (int) \round($srcHeight * \min(1, $newHeight / $srcHeight)); + } + } else { + // proportional + if (!$newWidth && !$newHeight) { + throw new Nette\InvalidArgumentException('At least width or height must be specified.'); + } + $scale = []; + if ($newWidth > 0) { + // fit width + $scale[] = $newWidth / $srcWidth; + } + if ($newHeight > 0) { + // fit height + $scale[] = $newHeight / $srcHeight; + } + if ($flags & self::FILL) { + $scale = [\max($scale)]; + } + if ($flags & self::SHRINK_ONLY) { + $scale[] = 1; + } + $scale = \min($scale); + $newWidth = (int) \round($srcWidth * $scale); + $newHeight = (int) \round($srcHeight * $scale); + } + return [\max($newWidth, 1), \max($newHeight, 1)]; + } + /** + * Crops image. + * @param int|string $left in pixels or percent + * @param int|string $top in pixels or percent + * @param int|string $width in pixels or percent + * @param int|string $height in pixels or percent + * @return static + */ + public function crop($left, $top, $width, $height) + { + [$r['x'], $r['y'], $r['width'], $r['height']] = static::calculateCutout($this->getWidth(), $this->getHeight(), $left, $top, $width, $height); + if (\gd_info()['GD Version'] === 'bundled (2.1.0 compatible)') { + $this->image = \imagecrop($this->image, $r); + \imagesavealpha($this->image, \true); + } else { + $newImage = static::fromBlank($r['width'], $r['height'], self::RGB(0, 0, 0, 127))->getImageResource(); + \imagecopy($newImage, $this->image, 0, 0, $r['x'], $r['y'], $r['width'], $r['height']); + $this->image = $newImage; + } + return $this; + } + /** + * Calculates dimensions of cutout in image. + * @param int|string $left in pixels or percent + * @param int|string $top in pixels or percent + * @param int|string $newWidth in pixels or percent + * @param int|string $newHeight in pixels or percent + */ + public static function calculateCutout(int $srcWidth, int $srcHeight, $left, $top, $newWidth, $newHeight) : array + { + if (self::isPercent($newWidth)) { + $newWidth = (int) \round($srcWidth / 100 * $newWidth); + } + if (self::isPercent($newHeight)) { + $newHeight = (int) \round($srcHeight / 100 * $newHeight); + } + if (self::isPercent($left)) { + $left = (int) \round(($srcWidth - $newWidth) / 100 * $left); + } + if (self::isPercent($top)) { + $top = (int) \round(($srcHeight - $newHeight) / 100 * $top); + } + if ($left < 0) { + $newWidth += $left; + $left = 0; + } + if ($top < 0) { + $newHeight += $top; + $top = 0; + } + $newWidth = \min($newWidth, $srcWidth - $left); + $newHeight = \min($newHeight, $srcHeight - $top); + return [$left, $top, $newWidth, $newHeight]; + } + /** + * Sharpens image a little bit. + * @return static + */ + public function sharpen() + { + \imageconvolution($this->image, [ + // my magic numbers ;) + [-1, -1, -1], + [-1, 24, -1], + [-1, -1, -1], + ], 16, 0); + return $this; + } + /** + * Puts another image into this image. + * @param int|string $left in pixels or percent + * @param int|string $top in pixels or percent + * @param int<0, 100> $opacity 0..100 + * @return static + */ + public function place(self $image, $left = 0, $top = 0, int $opacity = 100) + { + $opacity = \max(0, \min(100, $opacity)); + if ($opacity === 0) { + return $this; + } + $width = $image->getWidth(); + $height = $image->getHeight(); + if (self::isPercent($left)) { + $left = (int) \round(($this->getWidth() - $width) / 100 * $left); + } + if (self::isPercent($top)) { + $top = (int) \round(($this->getHeight() - $height) / 100 * $top); + } + $output = $input = $image->image; + if ($opacity < 100) { + $tbl = []; + for ($i = 0; $i < 128; $i++) { + $tbl[$i] = \round(127 - (127 - $i) * $opacity / 100); + } + $output = \imagecreatetruecolor($width, $height); + \imagealphablending($output, \false); + if (!$image->isTrueColor()) { + $input = $output; + \imagefilledrectangle($output, 0, 0, $width, $height, \imagecolorallocatealpha($output, 0, 0, 0, 127)); + \imagecopy($output, $image->image, 0, 0, 0, 0, $width, $height); + } + for ($x = 0; $x < $width; $x++) { + for ($y = 0; $y < $height; $y++) { + $c = \imagecolorat($input, $x, $y); + $c = ($c & 0xffffff) + ($tbl[$c >> 24] << 24); + \imagesetpixel($output, $x, $y, $c); + } + } + \imagealphablending($output, \true); + } + \imagecopy($this->image, $output, $left, $top, 0, 0, $width, $height); + return $this; + } + /** + * Saves image to the file. Quality is in the range 0..100 for JPEG (default 85), WEBP (default 80) and AVIF (default 30) and 0..9 for PNG (default 9). + * @throws ImageException + */ + public function save(string $file, ?int $quality = null, ?int $type = null) : void + { + $type = $type ?? self::extensionToType(\pathinfo($file, \PATHINFO_EXTENSION)); + $this->output($type, $quality, $file); + } + /** + * Outputs image to string. Quality is in the range 0..100 for JPEG (default 85), WEBP (default 80) and AVIF (default 30) and 0..9 for PNG (default 9). + */ + public function toString(int $type = self::JPEG, ?int $quality = null) : string + { + return Helpers::capture(function () use($type, $quality) { + $this->output($type, $quality); + }); + } + /** + * Outputs image to string. + */ + public function __toString() : string + { + try { + return $this->toString(); + } catch (\Throwable $e) { + if (\func_num_args() || \PHP_VERSION_ID >= 70400) { + throw $e; + } + \trigger_error('Exception in ' . __METHOD__ . "(): {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}", \E_USER_ERROR); + return ''; + } + } + /** + * Outputs image to browser. Quality is in the range 0..100 for JPEG (default 85), WEBP (default 80) and AVIF (default 30) and 0..9 for PNG (default 9). + * @throws ImageException + */ + public function send(int $type = self::JPEG, ?int $quality = null) : void + { + \header('Content-Type: ' . self::typeToMimeType($type)); + $this->output($type, $quality); + } + /** + * Outputs image to browser or file. + * @throws ImageException + */ + private function output(int $type, ?int $quality, ?string $file = null) : void + { + switch ($type) { + case self::JPEG: + $quality = $quality === null ? 85 : \max(0, \min(100, $quality)); + $success = @\imagejpeg($this->image, $file, $quality); + // @ is escalated to exception + break; + case self::PNG: + $quality = $quality === null ? 9 : \max(0, \min(9, $quality)); + $success = @\imagepng($this->image, $file, $quality); + // @ is escalated to exception + break; + case self::GIF: + $success = @\imagegif($this->image, $file); + // @ is escalated to exception + break; + case self::WEBP: + $quality = $quality === null ? 80 : \max(0, \min(100, $quality)); + $success = @\imagewebp($this->image, $file, $quality); + // @ is escalated to exception + break; + case self::AVIF: + $quality = $quality === null ? 30 : \max(0, \min(100, $quality)); + $success = @\imageavif($this->image, $file, $quality); + // @ is escalated to exception + break; + case self::BMP: + $success = @\imagebmp($this->image, $file); + // @ is escalated to exception + break; + default: + throw new Nette\InvalidArgumentException("Unsupported image type '{$type}'."); + } + if (!$success) { + throw new ImageException(Helpers::getLastError() ?: 'Unknown error'); + } + } + /** + * Call to undefined method. + * @return mixed + * @throws Nette\MemberAccessException + */ + public function __call(string $name, array $args) + { + $function = 'image' . $name; + if (!\function_exists($function)) { + ObjectHelpers::strictCall(static::class, $name); + } + foreach ($args as $key => $value) { + if ($value instanceof self) { + $args[$key] = $value->getImageResource(); + } elseif (\is_array($value) && isset($value['red'])) { + // rgb + $args[$key] = \imagecolorallocatealpha($this->image, $value['red'], $value['green'], $value['blue'], $value['alpha']) ?: \imagecolorresolvealpha($this->image, $value['red'], $value['green'], $value['blue'], $value['alpha']); + } + } + $res = $function($this->image, ...$args); + return $res instanceof \GdImage || \is_resource($res) && \get_resource_type($res) === 'gd' ? $this->setImageResource($res) : $res; + } + public function __clone() + { + \ob_start(function () { + }); + \imagepng($this->image, null, 0); + $this->setImageResource(\imagecreatefromstring(\ob_get_clean())); + } + /** + * @param int|string $num in pixels or percent + */ + private static function isPercent(&$num) : bool + { + if (\is_string($num) && \substr($num, -1) === '%') { + $num = (float) \substr($num, 0, -1); + return \true; + } elseif (\is_int($num) || $num === (string) (int) $num) { + $num = (int) $num; + return \false; + } + throw new Nette\InvalidArgumentException("Expected dimension in int|string, '{$num}' given."); + } + /** + * Prevents serialization. + */ + public function __sleep() : array + { + throw new Nette\NotSupportedException('You cannot serialize or unserialize ' . self::class . ' instances.'); + } +} diff --git a/vendor/nette/utils/src/Utils/Json.php b/vendor/nette/utils/src/Utils/Json.php new file mode 100644 index 0000000000..95a3cb3bf5 --- /dev/null +++ b/vendor/nette/utils/src/Utils/Json.php @@ -0,0 +1,49 @@ +getProperties(\ReflectionProperty::IS_PUBLIC), function ($p) { + return !$p->isStatic(); + }), self::parseFullDoc($rc, '~^[ \\t*]*@property(?:-read)?[ \\t]+(?:\\S+[ \\t]+)??\\$(\\w+)~m')), $name); + throw new MemberAccessException("Cannot read an undeclared property {$class}::\${$name}" . ($hint ? ", did you mean \${$hint}?" : '.')); + } + /** + * @return never + * @throws MemberAccessException + */ + public static function strictSet(string $class, string $name) : void + { + $rc = new \ReflectionClass($class); + $hint = self::getSuggestion(\array_merge(\array_filter($rc->getProperties(\ReflectionProperty::IS_PUBLIC), function ($p) { + return !$p->isStatic(); + }), self::parseFullDoc($rc, '~^[ \\t*]*@property(?:-write)?[ \\t]+(?:\\S+[ \\t]+)??\\$(\\w+)~m')), $name); + throw new MemberAccessException("Cannot write to an undeclared property {$class}::\${$name}" . ($hint ? ", did you mean \${$hint}?" : '.')); + } + /** + * @return never + * @throws MemberAccessException + */ + public static function strictCall(string $class, string $method, array $additionalMethods = []) : void + { + $trace = \debug_backtrace(0, 3); + // suppose this method is called from __call() + $context = ($trace[1]['function'] ?? null) === '__call' ? $trace[2]['class'] ?? null : null; + if ($context && \is_a($class, $context, \true) && \method_exists($context, $method)) { + // called parent::$method() + $class = \get_parent_class($context); + } + if (\method_exists($class, $method)) { + // insufficient visibility + $rm = new \ReflectionMethod($class, $method); + $visibility = $rm->isPrivate() ? 'private ' : ($rm->isProtected() ? 'protected ' : ''); + throw new MemberAccessException("Call to {$visibility}method {$class}::{$method}() from " . ($context ? "scope {$context}." : 'global scope.')); + } else { + $hint = self::getSuggestion(\array_merge(\get_class_methods($class), self::parseFullDoc(new \ReflectionClass($class), '~^[ \\t*]*@method[ \\t]+(?:static[ \\t]+)?(?:\\S+[ \\t]+)??(\\w+)\\(~m'), $additionalMethods), $method); + throw new MemberAccessException("Call to undefined method {$class}::{$method}()" . ($hint ? ", did you mean {$hint}()?" : '.')); + } + } + /** + * @return never + * @throws MemberAccessException + */ + public static function strictStaticCall(string $class, string $method) : void + { + $trace = \debug_backtrace(0, 3); + // suppose this method is called from __callStatic() + $context = ($trace[1]['function'] ?? null) === '__callStatic' ? $trace[2]['class'] ?? null : null; + if ($context && \is_a($class, $context, \true) && \method_exists($context, $method)) { + // called parent::$method() + $class = \get_parent_class($context); + } + if (\method_exists($class, $method)) { + // insufficient visibility + $rm = new \ReflectionMethod($class, $method); + $visibility = $rm->isPrivate() ? 'private ' : ($rm->isProtected() ? 'protected ' : ''); + throw new MemberAccessException("Call to {$visibility}method {$class}::{$method}() from " . ($context ? "scope {$context}." : 'global scope.')); + } else { + $hint = self::getSuggestion(\array_filter((new \ReflectionClass($class))->getMethods(\ReflectionMethod::IS_PUBLIC), function ($m) { + return $m->isStatic(); + }), $method); + throw new MemberAccessException("Call to undefined static method {$class}::{$method}()" . ($hint ? ", did you mean {$hint}()?" : '.')); + } + } + /** + * Returns array of magic properties defined by annotation @property. + * @return array of [name => bit mask] + * @internal + */ + public static function getMagicProperties(string $class) : array + { + static $cache; + $props =& $cache[$class]; + if ($props !== null) { + return $props; + } + $rc = new \ReflectionClass($class); + \preg_match_all('~^ [ \\t*]* @property(|-read|-write|-deprecated) [ \\t]+ [^\\s$]+ [ \\t]+ \\$ (\\w+) ()~mx', (string) $rc->getDocComment(), $matches, \PREG_SET_ORDER); + $props = []; + foreach ($matches as [, $type, $name]) { + $uname = \ucfirst($name); + $write = $type !== '-read' && $rc->hasMethod($nm = 'set' . $uname) && ($rm = $rc->getMethod($nm))->name === $nm && !$rm->isPrivate() && !$rm->isStatic(); + $read = $type !== '-write' && ($rc->hasMethod($nm = 'get' . $uname) || $rc->hasMethod($nm = 'is' . $uname)) && ($rm = $rc->getMethod($nm))->name === $nm && !$rm->isPrivate() && !$rm->isStatic(); + if ($read || $write) { + $props[$name] = $read << 0 | ($nm[0] === 'g') << 1 | $rm->returnsReference() << 2 | $write << 3 | ($type === '-deprecated') << 4; + } + } + foreach ($rc->getTraits() as $trait) { + $props += self::getMagicProperties($trait->name); + } + if ($parent = \get_parent_class($class)) { + $props += self::getMagicProperties($parent); + } + return $props; + } + /** + * Finds the best suggestion (for 8-bit encoding). + * @param (\ReflectionFunctionAbstract|\ReflectionParameter|\ReflectionClass|\ReflectionProperty|string)[] $possibilities + * @internal + */ + public static function getSuggestion(array $possibilities, string $value) : ?string + { + $norm = \preg_replace($re = '#^(get|set|has|is|add)(?=[A-Z])#', '+', $value); + $best = null; + $min = (\strlen($value) / 4 + 1) * 10 + 0.1; + foreach (\array_unique($possibilities, \SORT_REGULAR) as $item) { + $item = $item instanceof \Reflector ? $item->name : $item; + if ($item !== $value && (($len = \levenshtein($item, $value, 10, 11, 10)) < $min || ($len = \levenshtein(\preg_replace($re, '*', $item), $norm, 10, 11, 10)) < $min)) { + $min = $len; + $best = $item; + } + } + return $best; + } + private static function parseFullDoc(\ReflectionClass $rc, string $pattern) : array + { + do { + $doc[] = $rc->getDocComment(); + $traits = $rc->getTraits(); + while ($trait = \array_pop($traits)) { + $doc[] = $trait->getDocComment(); + $traits += $trait->getTraits(); + } + } while ($rc = $rc->getParentClass()); + return \preg_match_all($pattern, \implode($doc), $m) ? $m[1] : []; + } + /** + * Checks if the public non-static property exists. + * @return bool|string returns 'event' if the property exists and has event like name + * @internal + */ + public static function hasProperty(string $class, string $name) + { + static $cache; + $prop =& $cache[$class][$name]; + if ($prop === null) { + $prop = \false; + try { + $rp = new \ReflectionProperty($class, $name); + $rp->setAccessible(\true); + if ($rp->isPublic() && !$rp->isStatic()) { + $prop = $name >= 'onA' && $name < 'on_' ? 'event' : \true; + } + } catch (\ReflectionException $e) { + } + } + return $prop; + } +} diff --git a/vendor/nette/utils/src/Utils/ObjectMixin.php b/vendor/nette/utils/src/Utils/ObjectMixin.php new file mode 100644 index 0000000000..b8cb1626e9 --- /dev/null +++ b/vendor/nette/utils/src/Utils/ObjectMixin.php @@ -0,0 +1,32 @@ + $firstItemOnPage + * @property-read int<0,max> $lastItemOnPage + * @property int $base + * @property-read bool $first + * @property-read bool $last + * @property-read int<0,max>|null $pageCount + * @property positive-int $itemsPerPage + * @property int<0,max>|null $itemCount + * @property-read int<0,max> $offset + * @property-read int<0,max>|null $countdownOffset + * @property-read int<0,max> $length + */ +class Paginator +{ + use Nette\SmartObject; + /** @var int */ + private $base = 1; + /** @var int */ + private $itemsPerPage = 1; + /** @var int */ + private $page = 1; + /** @var int|null */ + private $itemCount; + /** + * Sets current page number. + * @return static + */ + public function setPage(int $page) + { + $this->page = $page; + return $this; + } + /** + * Returns current page number. + */ + public function getPage() : int + { + return $this->base + $this->getPageIndex(); + } + /** + * Returns first page number. + */ + public function getFirstPage() : int + { + return $this->base; + } + /** + * Returns last page number. + */ + public function getLastPage() : ?int + { + return $this->itemCount === null ? null : $this->base + \max(0, $this->getPageCount() - 1); + } + /** + * Returns the sequence number of the first element on the page + * @return int<0, max> + */ + public function getFirstItemOnPage() : int + { + return $this->itemCount !== 0 ? $this->offset + 1 : 0; + } + /** + * Returns the sequence number of the last element on the page + * @return int<0, max> + */ + public function getLastItemOnPage() : int + { + return $this->offset + $this->length; + } + /** + * Sets first page (base) number. + * @return static + */ + public function setBase(int $base) + { + $this->base = $base; + return $this; + } + /** + * Returns first page (base) number. + */ + public function getBase() : int + { + return $this->base; + } + /** + * Returns zero-based page number. + * @return int<0, max> + */ + protected function getPageIndex() : int + { + $index = \max(0, $this->page - $this->base); + return $this->itemCount === null ? $index : \min($index, \max(0, $this->getPageCount() - 1)); + } + /** + * Is the current page the first one? + */ + public function isFirst() : bool + { + return $this->getPageIndex() === 0; + } + /** + * Is the current page the last one? + */ + public function isLast() : bool + { + return $this->itemCount === null ? \false : $this->getPageIndex() >= $this->getPageCount() - 1; + } + /** + * Returns the total number of pages. + * @return int<0, max>|null + */ + public function getPageCount() : ?int + { + return $this->itemCount === null ? null : (int) \ceil($this->itemCount / $this->itemsPerPage); + } + /** + * Sets the number of items to display on a single page. + * @return static + */ + public function setItemsPerPage(int $itemsPerPage) + { + $this->itemsPerPage = \max(1, $itemsPerPage); + return $this; + } + /** + * Returns the number of items to display on a single page. + * @return positive-int + */ + public function getItemsPerPage() : int + { + return $this->itemsPerPage; + } + /** + * Sets the total number of items. + * @return static + */ + public function setItemCount(?int $itemCount = null) + { + $this->itemCount = $itemCount === null ? null : \max(0, $itemCount); + return $this; + } + /** + * Returns the total number of items. + * @return int<0, max>|null + */ + public function getItemCount() : ?int + { + return $this->itemCount; + } + /** + * Returns the absolute index of the first item on current page. + * @return int<0, max> + */ + public function getOffset() : int + { + return $this->getPageIndex() * $this->itemsPerPage; + } + /** + * Returns the absolute index of the first item on current page in countdown paging. + * @return int<0, max>|null + */ + public function getCountdownOffset() : ?int + { + return $this->itemCount === null ? null : \max(0, $this->itemCount - ($this->getPageIndex() + 1) * $this->itemsPerPage); + } + /** + * Returns the number of items on current page. + * @return int<0, max> + */ + public function getLength() : int + { + return $this->itemCount === null ? $this->itemsPerPage : \min($this->itemsPerPage, $this->itemCount - $this->getPageIndex() * $this->itemsPerPage); + } +} diff --git a/vendor/nette/utils/src/Utils/Random.php b/vendor/nette/utils/src/Utils/Random.php new file mode 100644 index 0000000000..0263a11d2f --- /dev/null +++ b/vendor/nette/utils/src/Utils/Random.php @@ -0,0 +1,38 @@ +getReturnType() ?? (\PHP_VERSION_ID >= 80100 && $func instanceof \ReflectionMethod ? $func->getTentativeReturnType() : null); + return self::getType($func, $type); + } + /** + * @deprecated + */ + public static function getReturnTypes(\ReflectionFunctionAbstract $func) : array + { + $type = Type::fromReflection($func); + return $type ? $type->getNames() : []; + } + /** + * Returns the type of given parameter and normalizes `self` and `parent` to the actual class names. + * If the parameter does not have a type, it returns null. + * If the parameter has union or intersection type, it throws Nette\InvalidStateException. + * @deprecated use Nette\Utils\Type::fromReflection() + */ + public static function getParameterType(\ReflectionParameter $param) : ?string + { + return self::getType($param, $param->getType()); + } + /** + * @deprecated + */ + public static function getParameterTypes(\ReflectionParameter $param) : array + { + $type = Type::fromReflection($param); + return $type ? $type->getNames() : []; + } + /** + * Returns the type of given property and normalizes `self` and `parent` to the actual class names. + * If the property does not have a type, it returns null. + * If the property has union or intersection type, it throws Nette\InvalidStateException. + * @deprecated use Nette\Utils\Type::fromReflection() + */ + public static function getPropertyType(\ReflectionProperty $prop) : ?string + { + return self::getType($prop, \PHP_VERSION_ID >= 70400 ? \method_exists($prop, 'getType') ? $prop->getType() : null : null); + } + /** + * @deprecated + */ + public static function getPropertyTypes(\ReflectionProperty $prop) : array + { + $type = Type::fromReflection($prop); + return $type ? $type->getNames() : []; + } + /** + * @param \ReflectionFunction|\ReflectionMethod|\ReflectionParameter|\ReflectionProperty $reflection + */ + private static function getType($reflection, ?\ReflectionType $type) : ?string + { + if ($type === null) { + return null; + } elseif ($type instanceof \ReflectionNamedType) { + return Type::resolve($type->getName(), $reflection); + } elseif ($type instanceof \ReflectionUnionType || $type instanceof \ReflectionIntersectionType) { + throw new Nette\InvalidStateException('The ' . self::toString($reflection) . ' is not expected to have a union or intersection type.'); + } else { + throw new Nette\InvalidStateException('Unexpected type of ' . self::toString($reflection)); + } + } + /** + * Returns the default value of parameter. If it is a constant, it returns its value. + * @return mixed + * @throws \ReflectionException If the parameter does not have a default value or the constant cannot be resolved + */ + public static function getParameterDefaultValue(\ReflectionParameter $param) + { + if ($param->isDefaultValueConstant()) { + $const = $orig = $param->getDefaultValueConstantName(); + $pair = \explode('::', $const); + if (isset($pair[1])) { + $pair[0] = Type::resolve($pair[0], $param); + try { + $rcc = new \ReflectionClassConstant($pair[0], $pair[1]); + } catch (\ReflectionException $e) { + $name = self::toString($param); + throw new \ReflectionException("Unable to resolve constant {$orig} used as default value of {$name}.", 0, $e); + } + return $rcc->getValue(); + } elseif (!\defined($const)) { + $const = \substr((string) \strrchr($const, '\\'), 1); + if (!\defined($const)) { + $name = self::toString($param); + throw new \ReflectionException("Unable to resolve constant {$orig} used as default value of {$name}."); + } + } + return \constant($const); + } + return $param->getDefaultValue(); + } + /** + * Returns a reflection of a class or trait that contains a declaration of given property. Property can also be declared in the trait. + */ + public static function getPropertyDeclaringClass(\ReflectionProperty $prop) : \ReflectionClass + { + foreach ($prop->getDeclaringClass()->getTraits() as $trait) { + if ($trait->hasProperty($prop->name) && $trait->getProperty($prop->name)->getDocComment() === $prop->getDocComment()) { + return self::getPropertyDeclaringClass($trait->getProperty($prop->name)); + } + } + return $prop->getDeclaringClass(); + } + /** + * Returns a reflection of a method that contains a declaration of $method. + * Usually, each method is its own declaration, but the body of the method can also be in the trait and under a different name. + */ + public static function getMethodDeclaringMethod(\ReflectionMethod $method) : \ReflectionMethod + { + // file & line guessing as workaround for insufficient PHP reflection + $decl = $method->getDeclaringClass(); + if ($decl->getFileName() === $method->getFileName() && $decl->getStartLine() <= $method->getStartLine() && $decl->getEndLine() >= $method->getEndLine()) { + return $method; + } + $hash = [$method->getFileName(), $method->getStartLine(), $method->getEndLine()]; + if (($alias = $decl->getTraitAliases()[$method->name] ?? null) && ($m = new \ReflectionMethod($alias)) && $hash === [$m->getFileName(), $m->getStartLine(), $m->getEndLine()]) { + return self::getMethodDeclaringMethod($m); + } + foreach ($decl->getTraits() as $trait) { + if ($trait->hasMethod($method->name) && ($m = $trait->getMethod($method->name)) && $hash === [$m->getFileName(), $m->getStartLine(), $m->getEndLine()]) { + return self::getMethodDeclaringMethod($m); + } + } + return $method; + } + /** + * Finds out if reflection has access to PHPdoc comments. Comments may not be available due to the opcode cache. + */ + public static function areCommentsAvailable() : bool + { + static $res; + return $res ?? ($res = (bool) (new \ReflectionMethod(__METHOD__))->getDocComment()); + } + public static function toString(\Reflector $ref) : string + { + if ($ref instanceof \ReflectionClass) { + return $ref->name; + } elseif ($ref instanceof \ReflectionMethod) { + return $ref->getDeclaringClass()->name . '::' . $ref->name . '()'; + } elseif ($ref instanceof \ReflectionFunction) { + return $ref->name . '()'; + } elseif ($ref instanceof \ReflectionProperty) { + return self::getPropertyDeclaringClass($ref)->name . '::$' . $ref->name; + } elseif ($ref instanceof \ReflectionParameter) { + return '$' . $ref->name . ' in ' . self::toString($ref->getDeclaringFunction()); + } else { + throw new Nette\InvalidArgumentException(); + } + } + /** + * Expands the name of the class to full name in the given context of given class. + * Thus, it returns how the PHP parser would understand $name if it were written in the body of the class $context. + * @throws Nette\InvalidArgumentException + */ + public static function expandClassName(string $name, \ReflectionClass $context) : string + { + $lower = \strtolower($name); + if (empty($name)) { + throw new Nette\InvalidArgumentException('Class name must not be empty.'); + } elseif (Validators::isBuiltinType($lower)) { + return $lower; + } elseif ($lower === 'self' || $lower === 'static') { + return $context->name; + } elseif ($lower === 'parent') { + return $context->getParentClass() ? $context->getParentClass()->name : 'parent'; + } elseif ($name[0] === '\\') { + // fully qualified name + return \ltrim($name, '\\'); + } + $uses = self::getUseStatements($context); + $parts = \explode('\\', $name, 2); + if (isset($uses[$parts[0]])) { + $parts[0] = $uses[$parts[0]]; + return \implode('\\', $parts); + } elseif ($context->inNamespace()) { + return $context->getNamespaceName() . '\\' . $name; + } else { + return $name; + } + } + /** @return array of [alias => class] */ + public static function getUseStatements(\ReflectionClass $class) : array + { + if ($class->isAnonymous()) { + throw new Nette\NotImplementedException('Anonymous classes are not supported.'); + } + static $cache = []; + if (!isset($cache[$name = $class->name])) { + if ($class->isInternal()) { + $cache[$name] = []; + } else { + $code = \file_get_contents($class->getFileName()); + $cache = self::parseUseStatements($code, $name) + $cache; + } + } + return $cache[$name]; + } + /** + * Parses PHP code to [class => [alias => class, ...]] + */ + private static function parseUseStatements(string $code, ?string $forClass = null) : array + { + try { + $tokens = \token_get_all($code, \TOKEN_PARSE); + } catch (\ParseError $e) { + \trigger_error($e->getMessage(), \E_USER_NOTICE); + $tokens = []; + } + $namespace = $class = null; + $classLevel = $level = 0; + $res = $uses = []; + $nameTokens = \PHP_VERSION_ID < 80000 ? [\T_STRING, \T_NS_SEPARATOR] : [\T_STRING, \T_NS_SEPARATOR, \T_NAME_QUALIFIED, \T_NAME_FULLY_QUALIFIED]; + while ($token = \current($tokens)) { + \next($tokens); + switch (\is_array($token) ? $token[0] : $token) { + case \T_NAMESPACE: + $namespace = \ltrim(self::fetch($tokens, $nameTokens) . '\\', '\\'); + $uses = []; + break; + case \T_CLASS: + case \T_INTERFACE: + case \T_TRAIT: + case \PHP_VERSION_ID < 80100 ? \T_CLASS : \T_ENUM: + if ($name = self::fetch($tokens, \T_STRING)) { + $class = $namespace . $name; + $classLevel = $level + 1; + $res[$class] = $uses; + if ($class === $forClass) { + return $res; + } + } + break; + case \T_USE: + while (!$class && ($name = self::fetch($tokens, $nameTokens))) { + $name = \ltrim($name, '\\'); + if (self::fetch($tokens, '{')) { + while ($suffix = self::fetch($tokens, $nameTokens)) { + if (self::fetch($tokens, \T_AS)) { + $uses[self::fetch($tokens, \T_STRING)] = $name . $suffix; + } else { + $tmp = \explode('\\', $suffix); + $uses[\end($tmp)] = $name . $suffix; + } + if (!self::fetch($tokens, ',')) { + break; + } + } + } elseif (self::fetch($tokens, \T_AS)) { + $uses[self::fetch($tokens, \T_STRING)] = $name; + } else { + $tmp = \explode('\\', $name); + $uses[\end($tmp)] = $name; + } + if (!self::fetch($tokens, ',')) { + break; + } + } + break; + case \T_CURLY_OPEN: + case \T_DOLLAR_OPEN_CURLY_BRACES: + case '{': + $level++; + break; + case '}': + if ($level === $classLevel) { + $class = $classLevel = 0; + } + $level--; + } + } + return $res; + } + private static function fetch(array &$tokens, $take) : ?string + { + $res = null; + while ($token = \current($tokens)) { + [$token, $s] = \is_array($token) ? $token : [$token, $token]; + if (\in_array($token, (array) $take, \true)) { + $res .= $s; + } elseif (!\in_array($token, [\T_DOC_COMMENT, \T_WHITESPACE, \T_COMMENT], \true)) { + break; + } + \next($tokens); + } + return $res; + } +} diff --git a/vendor/nette/utils/src/Utils/Strings.php b/vendor/nette/utils/src/Utils/Strings.php new file mode 100644 index 0000000000..1c2fe5dfdb --- /dev/null +++ b/vendor/nette/utils/src/Utils/Strings.php @@ -0,0 +1,488 @@ += 0xd800 && $code <= 0xdfff || $code > 0x10ffff) { + throw new Nette\InvalidArgumentException('Code point must be in range 0x0 to 0xD7FF or 0xE000 to 0x10FFFF.'); + } elseif (!\extension_loaded('iconv')) { + throw new Nette\NotSupportedException(__METHOD__ . '() requires ICONV extension that is not loaded.'); + } + return \iconv('UTF-32BE', 'UTF-8//IGNORE', \pack('N', $code)); + } + /** + * Starts the $haystack string with the prefix $needle? + */ + public static function startsWith(string $haystack, string $needle) : bool + { + return \strncmp($haystack, $needle, strlen($needle)) === 0; + } + /** + * Ends the $haystack string with the suffix $needle? + */ + public static function endsWith(string $haystack, string $needle) : bool + { + return $needle === '' || \substr($haystack, -strlen($needle)) === $needle; + } + /** + * Does $haystack contain $needle? + */ + public static function contains(string $haystack, string $needle) : bool + { + return \strpos($haystack, $needle) !== \false; + } + /** + * Returns a part of UTF-8 string specified by starting position and length. If start is negative, + * the returned string will start at the start'th character from the end of string. + */ + public static function substring(string $s, int $start, ?int $length = null) : string + { + if (\function_exists('mb_substr')) { + return \mb_substr($s, $start, $length, 'UTF-8'); + // MB is much faster + } elseif (!\extension_loaded('iconv')) { + throw new Nette\NotSupportedException(__METHOD__ . '() requires extension ICONV or MBSTRING, neither is loaded.'); + } elseif ($length === null) { + $length = self::length($s); + } elseif ($start < 0 && $length < 0) { + $start += self::length($s); + // unifies iconv_substr behavior with mb_substr + } + return \iconv_substr($s, $start, $length, 'UTF-8'); + } + /** + * Removes control characters, normalizes line breaks to `\n`, removes leading and trailing blank lines, + * trims end spaces on lines, normalizes UTF-8 to the normal form of NFC. + */ + public static function normalize(string $s) : string + { + // convert to compressed normal form (NFC) + if (\class_exists('Normalizer', \false) && ($n = \Normalizer::normalize($s, \Normalizer::FORM_C)) !== \false) { + $s = $n; + } + $s = self::normalizeNewLines($s); + // remove control characters; leave \t + \n + $s = self::pcre('preg_replace', ['#[\\x00-\\x08\\x0B-\\x1F\\x7F-\\x9F]+#u', '', $s]); + // right trim + $s = self::pcre('preg_replace', ['#[\\t ]+$#m', '', $s]); + // leading and trailing blank lines + $s = \trim($s, "\n"); + return $s; + } + /** + * Standardize line endings to unix-like. + */ + public static function normalizeNewLines(string $s) : string + { + return \str_replace(["\r\n", "\r"], "\n", $s); + } + /** + * Converts UTF-8 string to ASCII, ie removes diacritics etc. + */ + public static function toAscii(string $s) : string + { + $iconv = \defined('ICONV_IMPL') ? \trim(\ICONV_IMPL, '"\'') : null; + static $transliterator = null; + if ($transliterator === null) { + if (\class_exists('Transliterator', \false)) { + $transliterator = \Transliterator::create('Any-Latin; Latin-ASCII'); + } else { + \trigger_error(__METHOD__ . "(): it is recommended to enable PHP extensions 'intl'.", \E_USER_NOTICE); + $transliterator = \false; + } + } + // remove control characters and check UTF-8 validity + $s = self::pcre('preg_replace', ['#[^\\x09\\x0A\\x0D\\x20-\\x7E\\xA0-\\x{2FF}\\x{370}-\\x{10FFFF}]#u', '', $s]); + // transliteration (by Transliterator and iconv) is not optimal, replace some characters directly + $s = \strtr($s, ["„" => '"', "“" => '"', "”" => '"', "‚" => "'", "‘" => "'", "’" => "'", "°" => '^', "Я" => 'Ya', "я" => 'ya', "Ю" => 'Yu', "ю" => 'yu', "Ä" => 'Ae', "Ö" => 'Oe', "Ü" => 'Ue', "ẞ" => 'Ss', "ä" => 'ae', "ö" => 'oe', "ü" => 'ue', "ß" => 'ss']); + // „ “ ” ‚ ‘ ’ ° Я я Ю ю Ä Ö Ü ẞ ä ö ü ß + if ($iconv !== 'libiconv') { + $s = \strtr($s, ["®" => '(R)', "©" => '(c)', "…" => '...', "«" => '<<', "»" => '>>', "£" => 'lb', "¥" => 'yen', "²" => '^2', "³" => '^3', "µ" => 'u', "¹" => '^1', "º" => 'o', "¿" => '?', "ˊ" => "'", "ˍ" => '_', "˝" => '"', "`" => '', "€" => 'EUR', "™" => 'TM', "℮" => 'e', "←" => '<-', "↑" => '^', "→" => '->', "↓" => 'V', "↔" => '<->']); + // ® © … « » £ ¥ ² ³ µ ¹ º ¿ ˊ ˍ ˝ ` € ™ ℮ ← ↑ → ↓ ↔ + } + if ($transliterator) { + $s = $transliterator->transliterate($s); + // use iconv because The transliterator leaves some characters out of ASCII, eg → ʾ + if ($iconv === 'glibc') { + $s = \strtr($s, '?', "\x01"); + // temporarily hide ? to distinguish them from the garbage that iconv creates + $s = \iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $s); + $s = \str_replace(['?', "\x01"], ['', '?'], $s); + // remove garbage and restore ? characters + } elseif ($iconv === 'libiconv') { + $s = \iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $s); + } else { + // null or 'unknown' (#216) + $s = self::pcre('preg_replace', ['#[^\\x00-\\x7F]++#', '', $s]); + // remove non-ascii chars + } + } elseif ($iconv === 'glibc' || $iconv === 'libiconv') { + // temporarily hide these characters to distinguish them from the garbage that iconv creates + $s = \strtr($s, '`\'"^~?', "\x01\x02\x03\x04\x05\x06"); + if ($iconv === 'glibc') { + // glibc implementation is very limited. transliterate into Windows-1250 and then into ASCII, so most Eastern European characters are preserved + $s = \iconv('UTF-8', 'WINDOWS-1250//TRANSLIT//IGNORE', $s); + $s = \strtr($s, "\xa5\xa3\xbc\x8c\xa7\x8a\xaa\x8d\x8f\x8e\xaf\xb9\xb3\xbe\x9c\x9a\xba\x9d\x9f\x9e\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf8\xf9\xfa\xfb\xfc\xfd\xfe\x96\xa0\x8b\x97\x9b\xa6\xad\xb7", 'ALLSSSSTZZZallssstzzzRAAAALCCCEEEEIIDDNNOOOOxRUUUUYTsraaaalccceeeeiiddnnooooruuuuyt- <->|-.'); + $s = self::pcre('preg_replace', ['#[^\\x00-\\x7F]++#', '', $s]); + } else { + $s = \iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $s); + } + // remove garbage that iconv creates during transliteration (eg Ý -> Y') + $s = \str_replace(['`', "'", '"', '^', '~', '?'], '', $s); + // restore temporarily hidden characters + $s = \strtr($s, "\x01\x02\x03\x04\x05\x06", '`\'"^~?'); + } else { + $s = self::pcre('preg_replace', ['#[^\\x00-\\x7F]++#', '', $s]); + // remove non-ascii chars + } + return $s; + } + /** + * Modifies the UTF-8 string to the form used in the URL, ie removes diacritics and replaces all characters + * except letters of the English alphabet and numbers with a hyphens. + */ + public static function webalize(string $s, ?string $charlist = null, bool $lower = \true) : string + { + $s = self::toAscii($s); + if ($lower) { + $s = \strtolower($s); + } + $s = self::pcre('preg_replace', ['#[^a-z0-9' . ($charlist !== null ? \preg_quote($charlist, '#') : '') . ']+#i', '-', $s]); + $s = \trim($s, '-'); + return $s; + } + /** + * Truncates a UTF-8 string to given maximal length, while trying not to split whole words. Only if the string is truncated, + * an ellipsis (or something else set with third argument) is appended to the string. + */ + public static function truncate(string $s, int $maxLen, string $append = "…") : string + { + if (self::length($s) > $maxLen) { + $maxLen -= self::length($append); + if ($maxLen < 1) { + return $append; + } elseif ($matches = self::match($s, '#^.{1,' . $maxLen . '}(?=[\\s\\x00-/:-@\\[-`{-~])#us')) { + return $matches[0] . $append; + } else { + return self::substring($s, 0, $maxLen) . $append; + } + } + return $s; + } + /** + * Indents a multiline text from the left. Second argument sets how many indentation chars should be used, + * while the indent itself is the third argument (*tab* by default). + */ + public static function indent(string $s, int $level = 1, string $chars = "\t") : string + { + if ($level > 0) { + $s = self::replace($s, '#(?:^|[\\r\\n]+)(?=[^\\r\\n])#', '$0' . \str_repeat($chars, $level)); + } + return $s; + } + /** + * Converts all characters of UTF-8 string to lower case. + */ + public static function lower(string $s) : string + { + return \mb_strtolower($s, 'UTF-8'); + } + /** + * Converts the first character of a UTF-8 string to lower case and leaves the other characters unchanged. + */ + public static function firstLower(string $s) : string + { + return self::lower(self::substring($s, 0, 1)) . self::substring($s, 1); + } + /** + * Converts all characters of a UTF-8 string to upper case. + */ + public static function upper(string $s) : string + { + return \mb_strtoupper($s, 'UTF-8'); + } + /** + * Converts the first character of a UTF-8 string to upper case and leaves the other characters unchanged. + */ + public static function firstUpper(string $s) : string + { + return self::upper(self::substring($s, 0, 1)) . self::substring($s, 1); + } + /** + * Converts the first character of every word of a UTF-8 string to upper case and the others to lower case. + */ + public static function capitalize(string $s) : string + { + return \mb_convert_case($s, \MB_CASE_TITLE, 'UTF-8'); + } + /** + * Compares two UTF-8 strings or their parts, without taking character case into account. If length is null, whole strings are compared, + * if it is negative, the corresponding number of characters from the end of the strings is compared, + * otherwise the appropriate number of characters from the beginning is compared. + */ + public static function compare(string $left, string $right, ?int $length = null) : bool + { + if (\class_exists('Normalizer', \false)) { + $left = \Normalizer::normalize($left, \Normalizer::FORM_D); + // form NFD is faster + $right = \Normalizer::normalize($right, \Normalizer::FORM_D); + // form NFD is faster + } + if ($length < 0) { + $left = self::substring($left, $length, -$length); + $right = self::substring($right, $length, -$length); + } elseif ($length !== null) { + $left = self::substring($left, 0, $length); + $right = self::substring($right, 0, $length); + } + return self::lower($left) === self::lower($right); + } + /** + * Finds the common prefix of strings or returns empty string if the prefix was not found. + * @param string[] $strings + */ + public static function findPrefix(array $strings) : string + { + $first = \array_shift($strings); + for ($i = 0; $i < strlen($first); $i++) { + foreach ($strings as $s) { + if (!isset($s[$i]) || $first[$i] !== $s[$i]) { + while ($i && $first[$i - 1] >= "\x80" && $first[$i] >= "\x80" && $first[$i] < "\xc0") { + $i--; + } + return \substr($first, 0, $i); + } + } + } + return $first; + } + /** + * Returns number of characters (not bytes) in UTF-8 string. + * That is the number of Unicode code points which may differ from the number of graphemes. + */ + public static function length(string $s) : int + { + return \function_exists('mb_strlen') ? \mb_strlen($s, 'UTF-8') : strlen(\utf8_decode($s)); + } + /** + * Removes all left and right side spaces (or the characters passed as second argument) from a UTF-8 encoded string. + */ + public static function trim(string $s, string $charlist = self::TRIM_CHARACTERS) : string + { + $charlist = \preg_quote($charlist, '#'); + return self::replace($s, '#^[' . $charlist . ']+|[' . $charlist . ']+$#Du', ''); + } + /** + * Pads a UTF-8 string to given length by prepending the $pad string to the beginning. + * @param non-empty-string $pad + */ + public static function padLeft(string $s, int $length, string $pad = ' ') : string + { + $length = \max(0, $length - self::length($s)); + $padLen = self::length($pad); + return \str_repeat($pad, (int) ($length / $padLen)) . self::substring($pad, 0, $length % $padLen) . $s; + } + /** + * Pads UTF-8 string to given length by appending the $pad string to the end. + * @param non-empty-string $pad + */ + public static function padRight(string $s, int $length, string $pad = ' ') : string + { + $length = \max(0, $length - self::length($s)); + $padLen = self::length($pad); + return $s . \str_repeat($pad, (int) ($length / $padLen)) . self::substring($pad, 0, $length % $padLen); + } + /** + * Reverses UTF-8 string. + */ + public static function reverse(string $s) : string + { + if (!\extension_loaded('iconv')) { + throw new Nette\NotSupportedException(__METHOD__ . '() requires ICONV extension that is not loaded.'); + } + return \iconv('UTF-32LE', 'UTF-8', \strrev(\iconv('UTF-8', 'UTF-32BE', $s))); + } + /** + * Returns part of $haystack before $nth occurence of $needle or returns null if the needle was not found. + * Negative value means searching from the end. + */ + public static function before(string $haystack, string $needle, int $nth = 1) : ?string + { + $pos = self::pos($haystack, $needle, $nth); + return $pos === null ? null : \substr($haystack, 0, $pos); + } + /** + * Returns part of $haystack after $nth occurence of $needle or returns null if the needle was not found. + * Negative value means searching from the end. + */ + public static function after(string $haystack, string $needle, int $nth = 1) : ?string + { + $pos = self::pos($haystack, $needle, $nth); + return $pos === null ? null : \substr($haystack, $pos + strlen($needle)); + } + /** + * Returns position in characters of $nth occurence of $needle in $haystack or null if the $needle was not found. + * Negative value of `$nth` means searching from the end. + */ + public static function indexOf(string $haystack, string $needle, int $nth = 1) : ?int + { + $pos = self::pos($haystack, $needle, $nth); + return $pos === null ? null : self::length(\substr($haystack, 0, $pos)); + } + /** + * Returns position in characters of $nth occurence of $needle in $haystack or null if the needle was not found. + */ + private static function pos(string $haystack, string $needle, int $nth = 1) : ?int + { + if (!$nth) { + return null; + } elseif ($nth > 0) { + if ($needle === '') { + return 0; + } + $pos = 0; + while (($pos = \strpos($haystack, $needle, $pos)) !== \false && --$nth) { + $pos++; + } + } else { + $len = strlen($haystack); + if ($needle === '') { + return $len; + } elseif ($len === 0) { + return null; + } + $pos = $len - 1; + while (($pos = \strrpos($haystack, $needle, $pos - $len)) !== \false && ++$nth) { + $pos--; + } + } + return Helpers::falseToNull($pos); + } + /** + * Splits a string into array by the regular expression. Parenthesized expression in the delimiter are captured. + * Parameter $flags can be any combination of PREG_SPLIT_NO_EMPTY and PREG_OFFSET_CAPTURE flags. + */ + public static function split( + string $subject, + /** + * @language + */ + string $pattern, + int $flags = 0 + ) : array + { + return self::pcre('preg_split', [$pattern, $subject, -1, $flags | \PREG_SPLIT_DELIM_CAPTURE]); + } + /** + * Checks if given string matches a regular expression pattern and returns an array with first found match and each subpattern. + * Parameter $flags can be any combination of PREG_OFFSET_CAPTURE and PREG_UNMATCHED_AS_NULL flags. + */ + public static function match( + string $subject, + /** + * @language + */ + string $pattern, + int $flags = 0, + int $offset = 0 + ) : ?array + { + if ($offset > strlen($subject)) { + return null; + } + return self::pcre('preg_match', [$pattern, $subject, &$m, $flags, $offset]) ? $m : null; + } + /** + * Finds all occurrences matching regular expression pattern and returns a two-dimensional array. Result is array of matches (ie uses by default PREG_SET_ORDER). + * Parameter $flags can be any combination of PREG_OFFSET_CAPTURE, PREG_UNMATCHED_AS_NULL and PREG_PATTERN_ORDER flags. + */ + public static function matchAll( + string $subject, + /** + * @language + */ + string $pattern, + int $flags = 0, + int $offset = 0 + ) : array + { + if ($offset > strlen($subject)) { + return []; + } + self::pcre('preg_match_all', [$pattern, $subject, &$m, $flags & \PREG_PATTERN_ORDER ? $flags : $flags | \PREG_SET_ORDER, $offset]); + return $m; + } + /** + * Replaces all occurrences matching regular expression $pattern which can be string or array in the form `pattern => replacement`. + * @param string|array $pattern + * @param string|callable $replacement + */ + public static function replace( + string $subject, + /** + * @language + */ + $pattern, + $replacement = '', + int $limit = -1 + ) : string + { + if (is_object($replacement) || is_array($replacement)) { + if (!\is_callable($replacement, \false, $textual)) { + throw new Nette\InvalidStateException("Callback '{$textual}' is not callable."); + } + return self::pcre('preg_replace_callback', [$pattern, $replacement, $subject, $limit]); + } elseif (is_array($pattern) && \is_string(\key($pattern))) { + $replacement = \array_values($pattern); + $pattern = \array_keys($pattern); + } + return self::pcre('preg_replace', [$pattern, $replacement, $subject, $limit]); + } + /** @internal */ + public static function pcre(string $func, array $args) + { + $res = Callback::invokeSafe($func, $args, function (string $message) use($args) : void { + // compile-time error, not detectable by preg_last_error + throw new RegexpException($message . ' in pattern: ' . \implode(' or ', (array) $args[0])); + }); + if (($code = \preg_last_error()) && ($res === null || !\in_array($func, ['preg_filter', 'preg_replace_callback', 'preg_replace'], \true))) { + throw new RegexpException((RegexpException::MESSAGES[$code] ?? 'Unknown error') . ' (pattern: ' . \implode(' or ', (array) $args[0]) . ')', $code); + } + return $res; + } +} diff --git a/vendor/nette/utils/src/Utils/Type.php b/vendor/nette/utils/src/Utils/Type.php new file mode 100644 index 0000000000..5bd8948018 --- /dev/null +++ b/vendor/nette/utils/src/Utils/Type.php @@ -0,0 +1,212 @@ + */ + private $types; + /** @var bool */ + private $simple; + /** @var string |, & */ + private $kind; + /** + * Creates a Type object based on reflection. Resolves self, static and parent to the actual class name. + * If the subject has no type, it returns null. + * @param \ReflectionFunctionAbstract|\ReflectionParameter|\ReflectionProperty $reflection + */ + public static function fromReflection($reflection) : ?self + { + if ($reflection instanceof \ReflectionProperty && \PHP_VERSION_ID < 70400) { + return null; + } elseif ($reflection instanceof \ReflectionMethod) { + $type = $reflection->getReturnType() ?? (\PHP_VERSION_ID >= 80100 ? $reflection->getTentativeReturnType() : null); + } else { + $type = $reflection instanceof \ReflectionFunctionAbstract ? $reflection->getReturnType() : $reflection->getType(); + } + return $type ? self::fromReflectionType($type, $reflection, \true) : null; + } + private static function fromReflectionType(\ReflectionType $type, $of, bool $asObject) + { + if ($type instanceof \ReflectionNamedType) { + $name = self::resolve($type->getName(), $of); + return $asObject ? new self($type->allowsNull() && $name !== 'mixed' ? [$name, 'null'] : [$name]) : $name; + } elseif ($type instanceof \ReflectionUnionType || $type instanceof \ReflectionIntersectionType) { + return new self(\array_map(function ($t) use($of) { + return self::fromReflectionType($t, $of, \false); + }, $type->getTypes()), $type instanceof \ReflectionUnionType ? '|' : '&'); + } else { + throw new Nette\InvalidStateException('Unexpected type of ' . Reflection::toString($of)); + } + } + /** + * Creates the Type object according to the text notation. + */ + public static function fromString(string $type) : self + { + if (!Validators::isTypeDeclaration($type)) { + throw new Nette\InvalidArgumentException("Invalid type '{$type}'."); + } + if ($type[0] === '?') { + return new self([\substr($type, 1), 'null']); + } + $unions = []; + foreach (\explode('|', $type) as $part) { + $part = \explode('&', \trim($part, '()')); + $unions[] = \count($part) === 1 ? $part[0] : new self($part, '&'); + } + return \count($unions) === 1 && $unions[0] instanceof self ? $unions[0] : new self($unions); + } + /** + * Resolves 'self', 'static' and 'parent' to the actual class name. + * @param \ReflectionFunctionAbstract|\ReflectionParameter|\ReflectionProperty $of + */ + public static function resolve(string $type, $of) : string + { + $lower = \strtolower($type); + if ($of instanceof \ReflectionFunction) { + return $type; + } elseif ($lower === 'self' || $lower === 'static') { + return $of->getDeclaringClass()->name; + } elseif ($lower === 'parent' && $of->getDeclaringClass()->getParentClass()) { + return $of->getDeclaringClass()->getParentClass()->name; + } else { + return $type; + } + } + private function __construct(array $types, string $kind = '|') + { + $o = \array_search('null', $types, \true); + if ($o !== \false) { + // null as last + \array_splice($types, $o, 1); + $types[] = 'null'; + } + $this->types = $types; + $this->simple = \is_string($types[0]) && ($types[1] ?? 'null') === 'null'; + $this->kind = \count($types) > 1 ? $kind : ''; + } + public function __toString() : string + { + $multi = \count($this->types) > 1; + if ($this->simple) { + return ($multi ? '?' : '') . $this->types[0]; + } + $res = []; + foreach ($this->types as $type) { + $res[] = $type instanceof self && $multi ? "({$type})" : $type; + } + return \implode($this->kind, $res); + } + /** + * Returns the array of subtypes that make up the compound type as strings. + * @return array + */ + public function getNames() : array + { + return \array_map(function ($t) { + return $t instanceof self ? $t->getNames() : $t; + }, $this->types); + } + /** + * Returns the array of subtypes that make up the compound type as Type objects: + * @return self[] + */ + public function getTypes() : array + { + return \array_map(function ($t) { + return $t instanceof self ? $t : new self([$t]); + }, $this->types); + } + /** + * Returns the type name for simple types, otherwise null. + */ + public function getSingleName() : ?string + { + return $this->simple ? $this->types[0] : null; + } + /** + * Returns true whether it is a union type. + */ + public function isUnion() : bool + { + return $this->kind === '|'; + } + /** + * Returns true whether it is an intersection type. + */ + public function isIntersection() : bool + { + return $this->kind === '&'; + } + /** + * Returns true whether it is a simple type. Single nullable types are also considered to be simple types. + */ + public function isSimple() : bool + { + return $this->simple; + } + /** @deprecated use isSimple() */ + public function isSingle() : bool + { + return $this->simple; + } + /** + * Returns true whether the type is both a simple and a PHP built-in type. + */ + public function isBuiltin() : bool + { + return $this->simple && Validators::isBuiltinType($this->types[0]); + } + /** + * Returns true whether the type is both a simple and a class name. + */ + public function isClass() : bool + { + return $this->simple && !Validators::isBuiltinType($this->types[0]); + } + /** + * Determines if type is special class name self/parent/static. + */ + public function isClassKeyword() : bool + { + return $this->simple && Validators::isClassKeyword($this->types[0]); + } + /** + * Verifies type compatibility. For example, it checks if a value of a certain type could be passed as a parameter. + */ + public function allows(string $subtype) : bool + { + if ($this->types === ['mixed']) { + return \true; + } + $subtype = self::fromString($subtype); + return $subtype->isUnion() ? Arrays::every($subtype->types, function ($t) { + return $this->allows2($t instanceof self ? $t->types : [$t]); + }) : $this->allows2($subtype->types); + } + private function allows2(array $subtypes) : bool + { + return $this->isUnion() ? Arrays::some($this->types, function ($t) use($subtypes) { + return $this->allows3($t instanceof self ? $t->types : [$t], $subtypes); + }) : $this->allows3($this->types, $subtypes); + } + private function allows3(array $types, array $subtypes) : bool + { + return Arrays::every($types, function ($type) use($subtypes) { + $builtin = Validators::isBuiltinType($type); + return Arrays::some($subtypes, function ($subtype) use($type, $builtin) { + return $builtin ? \strcasecmp($type, $subtype) === 0 : \is_a($subtype, $type, \true); + }); + }); + } +} diff --git a/vendor/nette/utils/src/Utils/Validators.php b/vendor/nette/utils/src/Utils/Validators.php new file mode 100644 index 0000000000..083086974f --- /dev/null +++ b/vendor/nette/utils/src/Utils/Validators.php @@ -0,0 +1,341 @@ + 1, 'int' => 1, 'float' => 1, 'bool' => 1, 'array' => 1, 'object' => 1, 'callable' => 1, 'iterable' => 1, 'void' => 1, 'null' => 1, 'mixed' => 1, 'false' => 1, 'never' => 1, 'true' => 1]; + /** @var array */ + protected static $validators = [ + // PHP types + 'array' => 'is_array', + 'bool' => 'is_bool', + 'boolean' => 'is_bool', + 'float' => 'is_float', + 'int' => 'is_int', + 'integer' => 'is_int', + 'null' => 'is_null', + 'object' => 'is_object', + 'resource' => 'is_resource', + 'scalar' => 'is_scalar', + 'string' => 'is_string', + // pseudo-types + 'callable' => [self::class, 'isCallable'], + 'iterable' => 'is_iterable', + 'list' => [Arrays::class, 'isList'], + 'mixed' => [self::class, 'isMixed'], + 'none' => [self::class, 'isNone'], + 'number' => [self::class, 'isNumber'], + 'numeric' => [self::class, 'isNumeric'], + 'numericint' => [self::class, 'isNumericInt'], + // string patterns + 'alnum' => 'ctype_alnum', + 'alpha' => 'ctype_alpha', + 'digit' => 'ctype_digit', + 'lower' => 'ctype_lower', + 'pattern' => null, + 'space' => 'ctype_space', + 'unicode' => [self::class, 'isUnicode'], + 'upper' => 'ctype_upper', + 'xdigit' => 'ctype_xdigit', + // syntax validation + 'email' => [self::class, 'isEmail'], + 'identifier' => [self::class, 'isPhpIdentifier'], + 'uri' => [self::class, 'isUri'], + 'url' => [self::class, 'isUrl'], + // environment validation + 'class' => 'class_exists', + 'interface' => 'interface_exists', + 'directory' => 'is_dir', + 'file' => 'is_file', + 'type' => [self::class, 'isType'], + ]; + /** @var array */ + protected static $counters = ['string' => 'strlen', 'unicode' => [Strings::class, 'length'], 'array' => 'count', 'list' => 'count', 'alnum' => 'strlen', 'alpha' => 'strlen', 'digit' => 'strlen', 'lower' => 'strlen', 'space' => 'strlen', 'upper' => 'strlen', 'xdigit' => 'strlen']; + /** + * Verifies that the value is of expected types separated by pipe. + * @param mixed $value + * @throws AssertionException + */ + public static function assert($value, string $expected, string $label = 'variable') : void + { + if (!static::is($value, $expected)) { + $expected = \str_replace(['|', ':'], [' or ', ' in range '], $expected); + $translate = ['boolean' => 'bool', 'integer' => 'int', 'double' => 'float', 'NULL' => 'null']; + $type = $translate[\gettype($value)] ?? \gettype($value); + if (\is_int($value) || \is_float($value) || \is_string($value) && \strlen($value) < 40) { + $type .= ' ' . \var_export($value, \true); + } elseif (\is_object($value)) { + $type .= ' ' . \get_class($value); + } + throw new AssertionException("The {$label} expects to be {$expected}, {$type} given."); + } + } + /** + * Verifies that element $key in array is of expected types separated by pipe. + * @param mixed[] $array + * @param int|string $key + * @throws AssertionException + */ + public static function assertField(array $array, $key, ?string $expected = null, string $label = "item '%' in array") : void + { + if (!\array_key_exists($key, $array)) { + throw new AssertionException('Missing ' . \str_replace('%', $key, $label) . '.'); + } elseif ($expected) { + static::assert($array[$key], $expected, \str_replace('%', $key, $label)); + } + } + /** + * Verifies that the value is of expected types separated by pipe. + * @param mixed $value + */ + public static function is($value, string $expected) : bool + { + foreach (\explode('|', $expected) as $item) { + if (\substr($item, -2) === '[]') { + if (\is_iterable($value) && self::everyIs($value, \substr($item, 0, -2))) { + return \true; + } + continue; + } elseif (\substr($item, 0, 1) === '?') { + $item = \substr($item, 1); + if ($value === null) { + return \true; + } + } + [$type] = $item = \explode(':', $item, 2); + if (isset(static::$validators[$type])) { + try { + if (!static::$validators[$type]($value)) { + continue; + } + } catch (\TypeError $e) { + continue; + } + } elseif ($type === 'pattern') { + if (Strings::match($value, '|^' . ($item[1] ?? '') . '$|D')) { + return \true; + } + continue; + } elseif (!$value instanceof $type) { + continue; + } + if (isset($item[1])) { + $length = $value; + if (isset(static::$counters[$type])) { + $length = static::$counters[$type]($value); + } + $range = \explode('..', $item[1]); + if (!isset($range[1])) { + $range[1] = $range[0]; + } + if ($range[0] !== '' && $length < $range[0] || $range[1] !== '' && $length > $range[1]) { + continue; + } + } + return \true; + } + return \false; + } + /** + * Finds whether all values are of expected types separated by pipe. + * @param mixed[] $values + */ + public static function everyIs(iterable $values, string $expected) : bool + { + foreach ($values as $value) { + if (!static::is($value, $expected)) { + return \false; + } + } + return \true; + } + /** + * Checks if the value is an integer or a float. + * @param mixed $value + */ + public static function isNumber($value) : bool + { + return \is_int($value) || \is_float($value); + } + /** + * Checks if the value is an integer or a integer written in a string. + * @param mixed $value + */ + public static function isNumericInt($value) : bool + { + return \is_int($value) || \is_string($value) && \preg_match('#^[+-]?[0-9]+$#D', $value); + } + /** + * Checks if the value is a number or a number written in a string. + * @param mixed $value + */ + public static function isNumeric($value) : bool + { + return \is_float($value) || \is_int($value) || \is_string($value) && \preg_match('#^[+-]?([0-9]++\\.?[0-9]*|\\.[0-9]+)$#D', $value); + } + /** + * Checks if the value is a syntactically correct callback. + * @param mixed $value + */ + public static function isCallable($value) : bool + { + return $value && \is_callable($value, \true); + } + /** + * Checks if the value is a valid UTF-8 string. + * @param mixed $value + */ + public static function isUnicode($value) : bool + { + return \is_string($value) && \preg_match('##u', $value); + } + /** + * Checks if the value is 0, '', false or null. + * @param mixed $value + */ + public static function isNone($value) : bool + { + return $value == null; + // intentionally == + } + /** @internal */ + public static function isMixed() : bool + { + return \true; + } + /** + * Checks if a variable is a zero-based integer indexed array. + * @param mixed $value + * @deprecated use Nette\Utils\Arrays::isList + * @return ($value is list ? true : false) + */ + public static function isList($value) : bool + { + return Arrays::isList($value); + } + /** + * Checks if the value is in the given range [min, max], where the upper or lower limit can be omitted (null). + * Numbers, strings and DateTime objects can be compared. + * @param mixed $value + */ + public static function isInRange($value, array $range) : bool + { + if ($value === null || !(isset($range[0]) || isset($range[1]))) { + return \false; + } + $limit = $range[0] ?? $range[1]; + if (\is_string($limit)) { + $value = (string) $value; + } elseif ($limit instanceof \DateTimeInterface) { + if (!$value instanceof \DateTimeInterface) { + return \false; + } + } elseif (\is_numeric($value)) { + $value *= 1; + } else { + return \false; + } + return (!isset($range[0]) || $value >= $range[0]) && (!isset($range[1]) || $value <= $range[1]); + } + /** + * Checks if the value is a valid email address. It does not verify that the domain actually exists, only the syntax is verified. + */ + public static function isEmail(string $value) : bool + { + $atom = "[-a-z0-9!#\$%&'*+/=?^_`{|}~]"; + // RFC 5322 unquoted characters in local-part + $alpha = "a-z\x80-\xff"; + // superset of IDN + return (bool) \preg_match(<< \\? (? [a-zA-Z_\x7f-\xff][\w\x7f-\xff]*) (\\ (?&name))* ) | + (? (?&type) (& (?&type))+ ) | + (? (?&type) | \( (?&intersection) \) ) (\| (?&upart))+ + )$~xAD +XX +, $type); + } +} diff --git a/vendor/nette/utils/src/Utils/exceptions.php b/vendor/nette/utils/src/Utils/exceptions.php new file mode 100644 index 0000000000..6c2080ae5e --- /dev/null +++ b/vendor/nette/utils/src/Utils/exceptions.php @@ -0,0 +1,40 @@ + 'Internal error', \PREG_BACKTRACK_LIMIT_ERROR => 'Backtrack limit was exhausted', \PREG_RECURSION_LIMIT_ERROR => 'Recursion limit was exhausted', \PREG_BAD_UTF8_ERROR => 'Malformed UTF-8 data', \PREG_BAD_UTF8_OFFSET_ERROR => 'Offset didn\'t correspond to the begin of a valid UTF-8 code point', 6 => 'Failed due to limited JIT stack space']; +} +/** + * The exception that indicates assertion error. + */ +class AssertionException extends \Exception +{ +} diff --git a/vendor/nette/utils/src/compatibility.php b/vendor/nette/utils/src/compatibility.php new file mode 100644 index 0000000000..caa0f5ef65 --- /dev/null +++ b/vendor/nette/utils/src/compatibility.php @@ -0,0 +1,28 @@ += 7.1; for parsing PHP 5.2 to PHP 8.2). + +[Documentation for version 3.x][doc_3_x] (unsupported; for running on PHP >= 5.5; for parsing PHP 5.2 to PHP 7.2). + +Features +-------- + +The main features provided by this library are: + + * Parsing PHP 5, PHP 7, and PHP 8 code into an abstract syntax tree (AST). + * Invalid code can be parsed into a partial AST. + * The AST contains accurate location information. + * Dumping the AST in human-readable form. + * Converting an AST back to PHP code. + * Experimental: Formatting can be preserved for partially changed ASTs. + * Infrastructure to traverse and modify ASTs. + * Resolution of namespaced names. + * Evaluation of constant expressions. + * Builders to simplify AST construction for code generation. + * Converting an AST into JSON and back. + +Quick Start +----------- + +Install the library using [composer](https://getcomposer.org): + + php composer.phar require nikic/php-parser + +Parse some PHP code into an AST and dump the result in human-readable form: + +```php +create(ParserFactory::PREFER_PHP7); +try { + $ast = $parser->parse($code); +} catch (Error $error) { + echo "Parse error: {$error->getMessage()}\n"; + return; +} + +$dumper = new NodeDumper; +echo $dumper->dump($ast) . "\n"; +``` + +This dumps an AST looking something like this: + +``` +array( + 0: Stmt_Function( + byRef: false + name: Identifier( + name: test + ) + params: array( + 0: Param( + type: null + byRef: false + variadic: false + var: Expr_Variable( + name: foo + ) + default: null + ) + ) + returnType: null + stmts: array( + 0: Stmt_Expression( + expr: Expr_FuncCall( + name: Name( + parts: array( + 0: var_dump + ) + ) + args: array( + 0: Arg( + value: Expr_Variable( + name: foo + ) + byRef: false + unpack: false + ) + ) + ) + ) + ) + ) +) +``` + +Let's traverse the AST and perform some kind of modification. For example, drop all function bodies: + +```php +use PhpParser\Node; +use PhpParser\Node\Stmt\Function_; +use PhpParser\NodeTraverser; +use PhpParser\NodeVisitorAbstract; + +$traverser = new NodeTraverser(); +$traverser->addVisitor(new class extends NodeVisitorAbstract { + public function enterNode(Node $node) { + if ($node instanceof Function_) { + // Clean out the function body + $node->stmts = []; + } + } +}); + +$ast = $traverser->traverse($ast); +echo $dumper->dump($ast) . "\n"; +``` + +This gives us an AST where the `Function_::$stmts` are empty: + +``` +array( + 0: Stmt_Function( + byRef: false + name: Identifier( + name: test + ) + params: array( + 0: Param( + type: null + byRef: false + variadic: false + var: Expr_Variable( + name: foo + ) + default: null + ) + ) + returnType: null + stmts: array( + ) + ) +) +``` + +Finally, we can convert the new AST back to PHP code: + +```php +use PhpParser\PrettyPrinter; + +$prettyPrinter = new PrettyPrinter\Standard; +echo $prettyPrinter->prettyPrintFile($ast); +``` + +This gives us our original code, minus the `var_dump()` call inside the function: + +```php + ['startLine', 'endLine', 'startFilePos', 'endFilePos', 'comments']]); +$parser = (new PhpParser\ParserFactory())->create(PhpParser\ParserFactory::PREFER_PHP7, $lexer); +$dumper = new PhpParser\NodeDumper(['dumpComments' => \true, 'dumpPositions' => $attributes['with-positions']]); +$prettyPrinter = new PhpParser\PrettyPrinter\Standard(); +$traverser = new PhpParser\NodeTraverser(); +$traverser->addVisitor(new PhpParser\NodeVisitor\NameResolver()); +foreach ($files as $file) { + if (\strpos($file, ' Code {$code}\n"); + } else { + if (!\file_exists($file)) { + \fwrite(\STDERR, "File {$file} does not exist.\n"); + exit(1); + } + $code = \file_get_contents($file); + \fwrite(\STDERR, "====> File {$file}:\n"); + } + if ($attributes['with-recovery']) { + $errorHandler = new PhpParser\ErrorHandler\Collecting(); + $stmts = $parser->parse($code, $errorHandler); + foreach ($errorHandler->getErrors() as $error) { + $message = formatErrorMessage($error, $code, $attributes['with-column-info']); + \fwrite(\STDERR, $message . "\n"); + } + if (null === $stmts) { + continue; + } + } else { + try { + $stmts = $parser->parse($code); + } catch (PhpParser\Error $error) { + $message = formatErrorMessage($error, $code, $attributes['with-column-info']); + \fwrite(\STDERR, $message . "\n"); + exit(1); + } + } + foreach ($operations as $operation) { + if ('dump' === $operation) { + \fwrite(\STDERR, "==> Node dump:\n"); + echo $dumper->dump($stmts, $code), "\n"; + } elseif ('pretty-print' === $operation) { + \fwrite(\STDERR, "==> Pretty print:\n"); + echo $prettyPrinter->prettyPrintFile($stmts), "\n"; + } elseif ('json-dump' === $operation) { + \fwrite(\STDERR, "==> JSON dump:\n"); + echo \json_encode($stmts, \JSON_PRETTY_PRINT), "\n"; + } elseif ('var-dump' === $operation) { + \fwrite(\STDERR, "==> var_dump():\n"); + \var_dump($stmts); + } elseif ('resolve-names' === $operation) { + \fwrite(\STDERR, "==> Resolved names.\n"); + $stmts = $traverser->traverse($stmts); + } + } +} +function formatErrorMessage(PhpParser\Error $e, $code, $withColumnInfo) +{ + if ($withColumnInfo && $e->hasColumnInfo()) { + return $e->getMessageWithColumnInfo($code); + } else { + return $e->getMessage(); + } +} +function showHelp($error = '') +{ + if ($error) { + \fwrite(\STDERR, $error . "\n\n"); + } + \fwrite($error ? \STDERR : \STDOUT, << \false, 'with-positions' => \false, 'with-recovery' => \false]; + \array_shift($args); + $parseOptions = \true; + foreach ($args as $arg) { + if (!$parseOptions) { + $files[] = $arg; + continue; + } + switch ($arg) { + case '--dump': + case '-d': + $operations[] = 'dump'; + break; + case '--pretty-print': + case '-p': + $operations[] = 'pretty-print'; + break; + case '--json-dump': + case '-j': + $operations[] = 'json-dump'; + break; + case '--var-dump': + $operations[] = 'var-dump'; + break; + case '--resolve-names': + case '-N': + $operations[] = 'resolve-names'; + break; + case '--with-column-info': + case '-c': + $attributes['with-column-info'] = \true; + break; + case '--with-positions': + case '-P': + $attributes['with-positions'] = \true; + break; + case '--with-recovery': + case '-r': + $attributes['with-recovery'] = \true; + break; + case '--help': + case '-h': + showHelp(); + break; + case '--': + $parseOptions = \false; + break; + default: + if ($arg[0] === '-') { + showHelp("Invalid operation {$arg}."); + } else { + $files[] = $arg; + } + } + } + return [$operations, $files, $attributes]; +} diff --git a/vendor/nikic/php-parser/composer.json b/vendor/nikic/php-parser/composer.json new file mode 100644 index 0000000000..f8c1063142 --- /dev/null +++ b/vendor/nikic/php-parser/composer.json @@ -0,0 +1,41 @@ +{ + "name": "nikic\/php-parser", + "type": "library", + "description": "A PHP parser written in PHP", + "keywords": [ + "php", + "parser" + ], + "license": "BSD-3-Clause", + "authors": [ + { + "name": "Nikita Popov" + } + ], + "require": { + "php": ">=7.1", + "ext-tokenizer": "*" + }, + "require-dev": { + "phpunit\/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0", + "ircmaxell\/php-yacc": "^0.0.7" + }, + "extra": { + "branch-alias": { + "dev-master": "4.9-dev" + } + }, + "autoload": { + "psr-4": { + "SwissKnife202405\\PhpParser\\": "lib\/PhpParser" + } + }, + "autoload-dev": { + "psr-4": { + "SwissKnife202405\\PhpParser\\": "test\/PhpParser\/" + } + }, + "bin": [ + "bin\/php-parse" + ] +} \ No newline at end of file diff --git a/vendor/nikic/php-parser/lib/PhpParser/Builder.php b/vendor/nikic/php-parser/lib/PhpParser/Builder.php new file mode 100644 index 0000000000..4d383e510e --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Builder.php @@ -0,0 +1,14 @@ +constants = [new Const_($name, BuilderHelpers::normalizeValue($value))]; + } + /** + * Add another constant to const group + * + * @param string|Identifier $name Name + * @param Node\Expr|bool|null|int|float|string|array $value Value + * + * @return $this The builder instance (for fluid interface) + */ + public function addConst($name, $value) + { + $this->constants[] = new Const_($name, BuilderHelpers::normalizeValue($value)); + return $this; + } + /** + * Makes the constant public. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePublic() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_PUBLIC); + return $this; + } + /** + * Makes the constant protected. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeProtected() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_PROTECTED); + return $this; + } + /** + * Makes the constant private. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePrivate() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_PRIVATE); + return $this; + } + /** + * Makes the constant final. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeFinal() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_FINAL); + return $this; + } + /** + * Sets doc comment for the constant. + * + * @param PhpParser\Comment\Doc|string $docComment Doc comment to set + * + * @return $this The builder instance (for fluid interface) + */ + public function setDocComment($docComment) + { + $this->attributes = ['comments' => [BuilderHelpers::normalizeDocComment($docComment)]]; + return $this; + } + /** + * Adds an attribute group. + * + * @param Node\Attribute|Node\AttributeGroup $attribute + * + * @return $this The builder instance (for fluid interface) + */ + public function addAttribute($attribute) + { + $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); + return $this; + } + /** + * Sets the constant type. + * + * @param string|Node\Name|Identifier|Node\ComplexType $type + * + * @return $this + */ + public function setType($type) + { + $this->type = BuilderHelpers::normalizeType($type); + return $this; + } + /** + * Returns the built class node. + * + * @return Stmt\ClassConst The built constant node + */ + public function getNode() : PhpParser\Node + { + return new Stmt\ClassConst($this->constants, $this->flags, $this->attributes, $this->attributeGroups, $this->type); + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Builder/Class_.php b/vendor/nikic/php-parser/lib/PhpParser/Builder/Class_.php new file mode 100644 index 0000000000..ddcb68c106 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Builder/Class_.php @@ -0,0 +1,122 @@ +name = $name; + } + /** + * Extends a class. + * + * @param Name|string $class Name of class to extend + * + * @return $this The builder instance (for fluid interface) + */ + public function extend($class) + { + $this->extends = BuilderHelpers::normalizeName($class); + return $this; + } + /** + * Implements one or more interfaces. + * + * @param Name|string ...$interfaces Names of interfaces to implement + * + * @return $this The builder instance (for fluid interface) + */ + public function implement(...$interfaces) + { + foreach ($interfaces as $interface) { + $this->implements[] = BuilderHelpers::normalizeName($interface); + } + return $this; + } + /** + * Makes the class abstract. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeAbstract() + { + $this->flags = BuilderHelpers::addClassModifier($this->flags, Stmt\Class_::MODIFIER_ABSTRACT); + return $this; + } + /** + * Makes the class final. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeFinal() + { + $this->flags = BuilderHelpers::addClassModifier($this->flags, Stmt\Class_::MODIFIER_FINAL); + return $this; + } + public function makeReadonly() + { + $this->flags = BuilderHelpers::addClassModifier($this->flags, Stmt\Class_::MODIFIER_READONLY); + return $this; + } + /** + * Adds a statement. + * + * @param Stmt|PhpParser\Builder $stmt The statement to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addStmt($stmt) + { + $stmt = BuilderHelpers::normalizeNode($stmt); + $targets = [Stmt\TraitUse::class => &$this->uses, Stmt\ClassConst::class => &$this->constants, Stmt\Property::class => &$this->properties, Stmt\ClassMethod::class => &$this->methods]; + $class = \get_class($stmt); + if (!isset($targets[$class])) { + throw new \LogicException(\sprintf('Unexpected node of type "%s"', $stmt->getType())); + } + $targets[$class][] = $stmt; + return $this; + } + /** + * Adds an attribute group. + * + * @param Node\Attribute|Node\AttributeGroup $attribute + * + * @return $this The builder instance (for fluid interface) + */ + public function addAttribute($attribute) + { + $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); + return $this; + } + /** + * Returns the built class node. + * + * @return Stmt\Class_ The built class node + */ + public function getNode() : PhpParser\Node + { + return new Stmt\Class_($this->name, ['flags' => $this->flags, 'extends' => $this->extends, 'implements' => $this->implements, 'stmts' => \array_merge($this->uses, $this->constants, $this->properties, $this->methods), 'attrGroups' => $this->attributeGroups], $this->attributes); + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Builder/Declaration.php b/vendor/nikic/php-parser/lib/PhpParser/Builder/Declaration.php new file mode 100644 index 0000000000..801f66bdf0 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Builder/Declaration.php @@ -0,0 +1,38 @@ +addStmt($stmt); + } + return $this; + } + /** + * Sets doc comment for the declaration. + * + * @param PhpParser\Comment\Doc|string $docComment Doc comment to set + * + * @return $this The builder instance (for fluid interface) + */ + public function setDocComment($docComment) + { + $this->attributes['comments'] = [BuilderHelpers::normalizeDocComment($docComment)]; + return $this; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Builder/EnumCase.php b/vendor/nikic/php-parser/lib/PhpParser/Builder/EnumCase.php new file mode 100644 index 0000000000..2281bd8dbc --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Builder/EnumCase.php @@ -0,0 +1,72 @@ +name = $name; + } + /** + * Sets the value. + * + * @param Node\Expr|string|int $value + * + * @return $this + */ + public function setValue($value) + { + $this->value = BuilderHelpers::normalizeValue($value); + return $this; + } + /** + * Sets doc comment for the constant. + * + * @param PhpParser\Comment\Doc|string $docComment Doc comment to set + * + * @return $this The builder instance (for fluid interface) + */ + public function setDocComment($docComment) + { + $this->attributes = ['comments' => [BuilderHelpers::normalizeDocComment($docComment)]]; + return $this; + } + /** + * Adds an attribute group. + * + * @param Node\Attribute|Node\AttributeGroup $attribute + * + * @return $this The builder instance (for fluid interface) + */ + public function addAttribute($attribute) + { + $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); + return $this; + } + /** + * Returns the built enum case node. + * + * @return Stmt\EnumCase The built constant node + */ + public function getNode() : PhpParser\Node + { + return new Stmt\EnumCase($this->name, $this->value, $this->attributeGroups, $this->attributes); + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Builder/Enum_.php b/vendor/nikic/php-parser/lib/PhpParser/Builder/Enum_.php new file mode 100644 index 0000000000..53f8cd2a32 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Builder/Enum_.php @@ -0,0 +1,97 @@ +name = $name; + } + /** + * Sets the scalar type. + * + * @param string|Identifier $type + * + * @return $this + */ + public function setScalarType($scalarType) + { + $this->scalarType = BuilderHelpers::normalizeType($scalarType); + return $this; + } + /** + * Implements one or more interfaces. + * + * @param Name|string ...$interfaces Names of interfaces to implement + * + * @return $this The builder instance (for fluid interface) + */ + public function implement(...$interfaces) + { + foreach ($interfaces as $interface) { + $this->implements[] = BuilderHelpers::normalizeName($interface); + } + return $this; + } + /** + * Adds a statement. + * + * @param Stmt|PhpParser\Builder $stmt The statement to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addStmt($stmt) + { + $stmt = BuilderHelpers::normalizeNode($stmt); + $targets = [Stmt\TraitUse::class => &$this->uses, Stmt\EnumCase::class => &$this->enumCases, Stmt\ClassConst::class => &$this->constants, Stmt\ClassMethod::class => &$this->methods]; + $class = \get_class($stmt); + if (!isset($targets[$class])) { + throw new \LogicException(\sprintf('Unexpected node of type "%s"', $stmt->getType())); + } + $targets[$class][] = $stmt; + return $this; + } + /** + * Adds an attribute group. + * + * @param Node\Attribute|Node\AttributeGroup $attribute + * + * @return $this The builder instance (for fluid interface) + */ + public function addAttribute($attribute) + { + $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); + return $this; + } + /** + * Returns the built class node. + * + * @return Stmt\Enum_ The built enum node + */ + public function getNode() : PhpParser\Node + { + return new Stmt\Enum_($this->name, ['scalarType' => $this->scalarType, 'implements' => $this->implements, 'stmts' => \array_merge($this->uses, $this->enumCases, $this->constants, $this->methods), 'attrGroups' => $this->attributeGroups], $this->attributes); + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Builder/FunctionLike.php b/vendor/nikic/php-parser/lib/PhpParser/Builder/FunctionLike.php new file mode 100644 index 0000000000..b902ce3811 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Builder/FunctionLike.php @@ -0,0 +1,66 @@ +returnByRef = \true; + return $this; + } + /** + * Adds a parameter. + * + * @param Node\Param|Param $param The parameter to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addParam($param) + { + $param = BuilderHelpers::normalizeNode($param); + if (!$param instanceof Node\Param) { + throw new \LogicException(\sprintf('Expected parameter node, got "%s"', $param->getType())); + } + $this->params[] = $param; + return $this; + } + /** + * Adds multiple parameters. + * + * @param array $params The parameters to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addParams(array $params) + { + foreach ($params as $param) { + $this->addParam($param); + } + return $this; + } + /** + * Sets the return type for PHP 7. + * + * @param string|Node\Name|Node\Identifier|Node\ComplexType $type + * + * @return $this The builder instance (for fluid interface) + */ + public function setReturnType($type) + { + $this->returnType = BuilderHelpers::normalizeType($type); + return $this; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Builder/Function_.php b/vendor/nikic/php-parser/lib/PhpParser/Builder/Function_.php new file mode 100644 index 0000000000..d0b082c380 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Builder/Function_.php @@ -0,0 +1,58 @@ +name = $name; + } + /** + * Adds a statement. + * + * @param Node|PhpParser\Builder $stmt The statement to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addStmt($stmt) + { + $this->stmts[] = BuilderHelpers::normalizeStmt($stmt); + return $this; + } + /** + * Adds an attribute group. + * + * @param Node\Attribute|Node\AttributeGroup $attribute + * + * @return $this The builder instance (for fluid interface) + */ + public function addAttribute($attribute) + { + $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); + return $this; + } + /** + * Returns the built function node. + * + * @return Stmt\Function_ The built function node + */ + public function getNode() : Node + { + return new Stmt\Function_($this->name, ['byRef' => $this->returnByRef, 'params' => $this->params, 'returnType' => $this->returnType, 'stmts' => $this->stmts, 'attrGroups' => $this->attributeGroups], $this->attributes); + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Builder/Interface_.php b/vendor/nikic/php-parser/lib/PhpParser/Builder/Interface_.php new file mode 100644 index 0000000000..14c7dba7a6 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Builder/Interface_.php @@ -0,0 +1,84 @@ +name = $name; + } + /** + * Extends one or more interfaces. + * + * @param Name|string ...$interfaces Names of interfaces to extend + * + * @return $this The builder instance (for fluid interface) + */ + public function extend(...$interfaces) + { + foreach ($interfaces as $interface) { + $this->extends[] = BuilderHelpers::normalizeName($interface); + } + return $this; + } + /** + * Adds a statement. + * + * @param Stmt|PhpParser\Builder $stmt The statement to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addStmt($stmt) + { + $stmt = BuilderHelpers::normalizeNode($stmt); + if ($stmt instanceof Stmt\ClassConst) { + $this->constants[] = $stmt; + } elseif ($stmt instanceof Stmt\ClassMethod) { + // we erase all statements in the body of an interface method + $stmt->stmts = null; + $this->methods[] = $stmt; + } else { + throw new \LogicException(\sprintf('Unexpected node of type "%s"', $stmt->getType())); + } + return $this; + } + /** + * Adds an attribute group. + * + * @param Node\Attribute|Node\AttributeGroup $attribute + * + * @return $this The builder instance (for fluid interface) + */ + public function addAttribute($attribute) + { + $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); + return $this; + } + /** + * Returns the built interface node. + * + * @return Stmt\Interface_ The built interface node + */ + public function getNode() : PhpParser\Node + { + return new Stmt\Interface_($this->name, ['extends' => $this->extends, 'stmts' => \array_merge($this->constants, $this->methods), 'attrGroups' => $this->attributeGroups], $this->attributes); + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Builder/Method.php b/vendor/nikic/php-parser/lib/PhpParser/Builder/Method.php new file mode 100644 index 0000000000..89f98fadda --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Builder/Method.php @@ -0,0 +1,128 @@ +name = $name; + } + /** + * Makes the method public. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePublic() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_PUBLIC); + return $this; + } + /** + * Makes the method protected. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeProtected() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_PROTECTED); + return $this; + } + /** + * Makes the method private. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePrivate() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_PRIVATE); + return $this; + } + /** + * Makes the method static. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeStatic() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_STATIC); + return $this; + } + /** + * Makes the method abstract. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeAbstract() + { + if (!empty($this->stmts)) { + throw new \LogicException('Cannot make method with statements abstract'); + } + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_ABSTRACT); + $this->stmts = null; + // abstract methods don't have statements + return $this; + } + /** + * Makes the method final. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeFinal() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_FINAL); + return $this; + } + /** + * Adds a statement. + * + * @param Node|PhpParser\Builder $stmt The statement to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addStmt($stmt) + { + if (null === $this->stmts) { + throw new \LogicException('Cannot add statements to an abstract method'); + } + $this->stmts[] = BuilderHelpers::normalizeStmt($stmt); + return $this; + } + /** + * Adds an attribute group. + * + * @param Node\Attribute|Node\AttributeGroup $attribute + * + * @return $this The builder instance (for fluid interface) + */ + public function addAttribute($attribute) + { + $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); + return $this; + } + /** + * Returns the built method node. + * + * @return Stmt\ClassMethod The built method node + */ + public function getNode() : Node + { + return new Stmt\ClassMethod($this->name, ['flags' => $this->flags, 'byRef' => $this->returnByRef, 'params' => $this->params, 'returnType' => $this->returnType, 'stmts' => $this->stmts, 'attrGroups' => $this->attributeGroups], $this->attributes); + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Builder/Namespace_.php b/vendor/nikic/php-parser/lib/PhpParser/Builder/Namespace_.php new file mode 100644 index 0000000000..6256d9f928 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Builder/Namespace_.php @@ -0,0 +1,44 @@ +name = null !== $name ? BuilderHelpers::normalizeName($name) : null; + } + /** + * Adds a statement. + * + * @param Node|PhpParser\Builder $stmt The statement to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addStmt($stmt) + { + $this->stmts[] = BuilderHelpers::normalizeStmt($stmt); + return $this; + } + /** + * Returns the built node. + * + * @return Stmt\Namespace_ The built node + */ + public function getNode() : Node + { + return new Stmt\Namespace_($this->name, $this->stmts, $this->attributes); + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Builder/Param.php b/vendor/nikic/php-parser/lib/PhpParser/Builder/Param.php new file mode 100644 index 0000000000..7c711a049e --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Builder/Param.php @@ -0,0 +1,150 @@ +name = $name; + } + /** + * Sets default value for the parameter. + * + * @param mixed $value Default value to use + * + * @return $this The builder instance (for fluid interface) + */ + public function setDefault($value) + { + $this->default = BuilderHelpers::normalizeValue($value); + return $this; + } + /** + * Sets type for the parameter. + * + * @param string|Node\Name|Node\Identifier|Node\ComplexType $type Parameter type + * + * @return $this The builder instance (for fluid interface) + */ + public function setType($type) + { + $this->type = BuilderHelpers::normalizeType($type); + if ($this->type == 'void') { + throw new \LogicException('Parameter type cannot be void'); + } + return $this; + } + /** + * Sets type for the parameter. + * + * @param string|Node\Name|Node\Identifier|Node\ComplexType $type Parameter type + * + * @return $this The builder instance (for fluid interface) + * + * @deprecated Use setType() instead + */ + public function setTypeHint($type) + { + return $this->setType($type); + } + /** + * Make the parameter accept the value by reference. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeByRef() + { + $this->byRef = \true; + return $this; + } + /** + * Make the parameter variadic + * + * @return $this The builder instance (for fluid interface) + */ + public function makeVariadic() + { + $this->variadic = \true; + return $this; + } + /** + * Makes the (promoted) parameter public. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePublic() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Node\Stmt\Class_::MODIFIER_PUBLIC); + return $this; + } + /** + * Makes the (promoted) parameter protected. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeProtected() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Node\Stmt\Class_::MODIFIER_PROTECTED); + return $this; + } + /** + * Makes the (promoted) parameter private. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePrivate() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Node\Stmt\Class_::MODIFIER_PRIVATE); + return $this; + } + /** + * Makes the (promoted) parameter readonly. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeReadonly() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Node\Stmt\Class_::MODIFIER_READONLY); + return $this; + } + /** + * Adds an attribute group. + * + * @param Node\Attribute|Node\AttributeGroup $attribute + * + * @return $this The builder instance (for fluid interface) + */ + public function addAttribute($attribute) + { + $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); + return $this; + } + /** + * Returns the built parameter node. + * + * @return Node\Param The built parameter node + */ + public function getNode() : Node + { + return new Node\Param(new Node\Expr\Variable($this->name), $this->default, $this->type, $this->byRef, $this->variadic, [], $this->flags, $this->attributeGroups); + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Builder/Property.php b/vendor/nikic/php-parser/lib/PhpParser/Builder/Property.php new file mode 100644 index 0000000000..4b7b1471a1 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Builder/Property.php @@ -0,0 +1,139 @@ +name = $name; + } + /** + * Makes the property public. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePublic() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_PUBLIC); + return $this; + } + /** + * Makes the property protected. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeProtected() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_PROTECTED); + return $this; + } + /** + * Makes the property private. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePrivate() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_PRIVATE); + return $this; + } + /** + * Makes the property static. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeStatic() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_STATIC); + return $this; + } + /** + * Makes the property readonly. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeReadonly() + { + $this->flags = BuilderHelpers::addModifier($this->flags, Stmt\Class_::MODIFIER_READONLY); + return $this; + } + /** + * Sets default value for the property. + * + * @param mixed $value Default value to use + * + * @return $this The builder instance (for fluid interface) + */ + public function setDefault($value) + { + $this->default = BuilderHelpers::normalizeValue($value); + return $this; + } + /** + * Sets doc comment for the property. + * + * @param PhpParser\Comment\Doc|string $docComment Doc comment to set + * + * @return $this The builder instance (for fluid interface) + */ + public function setDocComment($docComment) + { + $this->attributes = ['comments' => [BuilderHelpers::normalizeDocComment($docComment)]]; + return $this; + } + /** + * Sets the property type for PHP 7.4+. + * + * @param string|Name|Identifier|ComplexType $type + * + * @return $this + */ + public function setType($type) + { + $this->type = BuilderHelpers::normalizeType($type); + return $this; + } + /** + * Adds an attribute group. + * + * @param Node\Attribute|Node\AttributeGroup $attribute + * + * @return $this The builder instance (for fluid interface) + */ + public function addAttribute($attribute) + { + $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); + return $this; + } + /** + * Returns the built class node. + * + * @return Stmt\Property The built property node + */ + public function getNode() : PhpParser\Node + { + return new Stmt\Property($this->flags !== 0 ? $this->flags : Stmt\Class_::MODIFIER_PUBLIC, [new Stmt\PropertyProperty($this->name, $this->default)], $this->attributes, $this->type, $this->attributeGroups); + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Builder/TraitUse.php b/vendor/nikic/php-parser/lib/PhpParser/Builder/TraitUse.php new file mode 100644 index 0000000000..605d4e00c6 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Builder/TraitUse.php @@ -0,0 +1,62 @@ +and($trait); + } + } + /** + * Adds used trait. + * + * @param Node\Name|string $trait Trait name + * + * @return $this The builder instance (for fluid interface) + */ + public function and($trait) + { + $this->traits[] = BuilderHelpers::normalizeName($trait); + return $this; + } + /** + * Adds trait adaptation. + * + * @param Stmt\TraitUseAdaptation|Builder\TraitUseAdaptation $adaptation Trait adaptation + * + * @return $this The builder instance (for fluid interface) + */ + public function with($adaptation) + { + $adaptation = BuilderHelpers::normalizeNode($adaptation); + if (!$adaptation instanceof Stmt\TraitUseAdaptation) { + throw new \LogicException('Adaptation must have type TraitUseAdaptation'); + } + $this->adaptations[] = $adaptation; + return $this; + } + /** + * Returns the built node. + * + * @return Node The built node + */ + public function getNode() : Node + { + return new Stmt\TraitUse($this->traits, $this->adaptations); + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Builder/TraitUseAdaptation.php b/vendor/nikic/php-parser/lib/PhpParser/Builder/TraitUseAdaptation.php new file mode 100644 index 0000000000..0f0d58c683 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Builder/TraitUseAdaptation.php @@ -0,0 +1,135 @@ +type = self::TYPE_UNDEFINED; + $this->trait = \is_null($trait) ? null : BuilderHelpers::normalizeName($trait); + $this->method = BuilderHelpers::normalizeIdentifier($method); + } + /** + * Sets alias of method. + * + * @param Node\Identifier|string $alias Alias for adaptated method + * + * @return $this The builder instance (for fluid interface) + */ + public function as($alias) + { + if ($this->type === self::TYPE_UNDEFINED) { + $this->type = self::TYPE_ALIAS; + } + if ($this->type !== self::TYPE_ALIAS) { + throw new \LogicException('Cannot set alias for not alias adaptation buider'); + } + $this->alias = $alias; + return $this; + } + /** + * Sets adaptated method public. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePublic() + { + $this->setModifier(Stmt\Class_::MODIFIER_PUBLIC); + return $this; + } + /** + * Sets adaptated method protected. + * + * @return $this The builder instance (for fluid interface) + */ + public function makeProtected() + { + $this->setModifier(Stmt\Class_::MODIFIER_PROTECTED); + return $this; + } + /** + * Sets adaptated method private. + * + * @return $this The builder instance (for fluid interface) + */ + public function makePrivate() + { + $this->setModifier(Stmt\Class_::MODIFIER_PRIVATE); + return $this; + } + /** + * Adds overwritten traits. + * + * @param Node\Name|string ...$traits Traits for overwrite + * + * @return $this The builder instance (for fluid interface) + */ + public function insteadof(...$traits) + { + if ($this->type === self::TYPE_UNDEFINED) { + if (\is_null($this->trait)) { + throw new \LogicException('Precedence adaptation must have trait'); + } + $this->type = self::TYPE_PRECEDENCE; + } + if ($this->type !== self::TYPE_PRECEDENCE) { + throw new \LogicException('Cannot add overwritten traits for not precedence adaptation buider'); + } + foreach ($traits as $trait) { + $this->insteadof[] = BuilderHelpers::normalizeName($trait); + } + return $this; + } + protected function setModifier(int $modifier) + { + if ($this->type === self::TYPE_UNDEFINED) { + $this->type = self::TYPE_ALIAS; + } + if ($this->type !== self::TYPE_ALIAS) { + throw new \LogicException('Cannot set access modifier for not alias adaptation buider'); + } + if (\is_null($this->modifier)) { + $this->modifier = $modifier; + } else { + throw new \LogicException('Multiple access type modifiers are not allowed'); + } + } + /** + * Returns the built node. + * + * @return Node The built node + */ + public function getNode() : Node + { + switch ($this->type) { + case self::TYPE_ALIAS: + return new Stmt\TraitUseAdaptation\Alias($this->trait, $this->method, $this->modifier, $this->alias); + case self::TYPE_PRECEDENCE: + return new Stmt\TraitUseAdaptation\Precedence($this->trait, $this->method, $this->insteadof); + default: + throw new \LogicException('Type of adaptation is not defined'); + } + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Builder/Trait_.php b/vendor/nikic/php-parser/lib/PhpParser/Builder/Trait_.php new file mode 100644 index 0000000000..e99499f9a0 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Builder/Trait_.php @@ -0,0 +1,69 @@ +name = $name; + } + /** + * Adds a statement. + * + * @param Stmt|PhpParser\Builder $stmt The statement to add + * + * @return $this The builder instance (for fluid interface) + */ + public function addStmt($stmt) + { + $stmt = BuilderHelpers::normalizeNode($stmt); + if ($stmt instanceof Stmt\Property) { + $this->properties[] = $stmt; + } elseif ($stmt instanceof Stmt\ClassMethod) { + $this->methods[] = $stmt; + } elseif ($stmt instanceof Stmt\TraitUse) { + $this->uses[] = $stmt; + } else { + throw new \LogicException(\sprintf('Unexpected node of type "%s"', $stmt->getType())); + } + return $this; + } + /** + * Adds an attribute group. + * + * @param Node\Attribute|Node\AttributeGroup $attribute + * + * @return $this The builder instance (for fluid interface) + */ + public function addAttribute($attribute) + { + $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute); + return $this; + } + /** + * Returns the built trait node. + * + * @return Stmt\Trait_ The built interface node + */ + public function getNode() : PhpParser\Node + { + return new Stmt\Trait_($this->name, ['stmts' => \array_merge($this->uses, $this->properties, $this->methods), 'attrGroups' => $this->attributeGroups], $this->attributes); + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Builder/Use_.php b/vendor/nikic/php-parser/lib/PhpParser/Builder/Use_.php new file mode 100644 index 0000000000..e88e594cf3 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Builder/Use_.php @@ -0,0 +1,47 @@ +name = BuilderHelpers::normalizeName($name); + $this->type = $type; + } + /** + * Sets alias for used name. + * + * @param string $alias Alias to use (last component of full name by default) + * + * @return $this The builder instance (for fluid interface) + */ + public function as(string $alias) + { + $this->alias = $alias; + return $this; + } + /** + * Returns the built node. + * + * @return Stmt\Use_ The built node + */ + public function getNode() : Node + { + return new Stmt\Use_([new Stmt\UseUse($this->name, $this->alias)], $this->type); + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/BuilderFactory.php b/vendor/nikic/php-parser/lib/PhpParser/BuilderFactory.php new file mode 100644 index 0000000000..57d47d8933 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/BuilderFactory.php @@ -0,0 +1,375 @@ +args($args)); + } + /** + * Creates a namespace builder. + * + * @param null|string|Node\Name $name Name of the namespace + * + * @return Builder\Namespace_ The created namespace builder + */ + public function namespace($name) : Builder\Namespace_ + { + return new Builder\Namespace_($name); + } + /** + * Creates a class builder. + * + * @param string $name Name of the class + * + * @return Builder\Class_ The created class builder + */ + public function class(string $name) : Builder\Class_ + { + return new Builder\Class_($name); + } + /** + * Creates an interface builder. + * + * @param string $name Name of the interface + * + * @return Builder\Interface_ The created interface builder + */ + public function interface(string $name) : Builder\Interface_ + { + return new Builder\Interface_($name); + } + /** + * Creates a trait builder. + * + * @param string $name Name of the trait + * + * @return Builder\Trait_ The created trait builder + */ + public function trait(string $name) : Builder\Trait_ + { + return new Builder\Trait_($name); + } + /** + * Creates an enum builder. + * + * @param string $name Name of the enum + * + * @return Builder\Enum_ The created enum builder + */ + public function enum(string $name) : Builder\Enum_ + { + return new Builder\Enum_($name); + } + /** + * Creates a trait use builder. + * + * @param Node\Name|string ...$traits Trait names + * + * @return Builder\TraitUse The create trait use builder + */ + public function useTrait(...$traits) : Builder\TraitUse + { + return new Builder\TraitUse(...$traits); + } + /** + * Creates a trait use adaptation builder. + * + * @param Node\Name|string|null $trait Trait name + * @param Node\Identifier|string $method Method name + * + * @return Builder\TraitUseAdaptation The create trait use adaptation builder + */ + public function traitUseAdaptation($trait, $method = null) : Builder\TraitUseAdaptation + { + if ($method === null) { + $method = $trait; + $trait = null; + } + return new Builder\TraitUseAdaptation($trait, $method); + } + /** + * Creates a method builder. + * + * @param string $name Name of the method + * + * @return Builder\Method The created method builder + */ + public function method(string $name) : Builder\Method + { + return new Builder\Method($name); + } + /** + * Creates a parameter builder. + * + * @param string $name Name of the parameter + * + * @return Builder\Param The created parameter builder + */ + public function param(string $name) : Builder\Param + { + return new Builder\Param($name); + } + /** + * Creates a property builder. + * + * @param string $name Name of the property + * + * @return Builder\Property The created property builder + */ + public function property(string $name) : Builder\Property + { + return new Builder\Property($name); + } + /** + * Creates a function builder. + * + * @param string $name Name of the function + * + * @return Builder\Function_ The created function builder + */ + public function function(string $name) : Builder\Function_ + { + return new Builder\Function_($name); + } + /** + * Creates a namespace/class use builder. + * + * @param Node\Name|string $name Name of the entity (namespace or class) to alias + * + * @return Builder\Use_ The created use builder + */ + public function use($name) : Builder\Use_ + { + return new Builder\Use_($name, Use_::TYPE_NORMAL); + } + /** + * Creates a function use builder. + * + * @param Node\Name|string $name Name of the function to alias + * + * @return Builder\Use_ The created use function builder + */ + public function useFunction($name) : Builder\Use_ + { + return new Builder\Use_($name, Use_::TYPE_FUNCTION); + } + /** + * Creates a constant use builder. + * + * @param Node\Name|string $name Name of the const to alias + * + * @return Builder\Use_ The created use const builder + */ + public function useConst($name) : Builder\Use_ + { + return new Builder\Use_($name, Use_::TYPE_CONSTANT); + } + /** + * Creates a class constant builder. + * + * @param string|Identifier $name Name + * @param Node\Expr|bool|null|int|float|string|array $value Value + * + * @return Builder\ClassConst The created use const builder + */ + public function classConst($name, $value) : Builder\ClassConst + { + return new Builder\ClassConst($name, $value); + } + /** + * Creates an enum case builder. + * + * @param string|Identifier $name Name + * + * @return Builder\EnumCase The created use const builder + */ + public function enumCase($name) : Builder\EnumCase + { + return new Builder\EnumCase($name); + } + /** + * Creates node a for a literal value. + * + * @param Expr|bool|null|int|float|string|array $value $value + * + * @return Expr + */ + public function val($value) : Expr + { + return BuilderHelpers::normalizeValue($value); + } + /** + * Creates variable node. + * + * @param string|Expr $name Name + * + * @return Expr\Variable + */ + public function var($name) : Expr\Variable + { + if (!\is_string($name) && !$name instanceof Expr) { + throw new \LogicException('Variable name must be string or Expr'); + } + return new Expr\Variable($name); + } + /** + * Normalizes an argument list. + * + * Creates Arg nodes for all arguments and converts literal values to expressions. + * + * @param array $args List of arguments to normalize + * + * @return Arg[] + */ + public function args(array $args) : array + { + $normalizedArgs = []; + foreach ($args as $key => $arg) { + if (!$arg instanceof Arg) { + $arg = new Arg(BuilderHelpers::normalizeValue($arg)); + } + if (\is_string($key)) { + $arg->name = BuilderHelpers::normalizeIdentifier($key); + } + $normalizedArgs[] = $arg; + } + return $normalizedArgs; + } + /** + * Creates a function call node. + * + * @param string|Name|Expr $name Function name + * @param array $args Function arguments + * + * @return Expr\FuncCall + */ + public function funcCall($name, array $args = []) : Expr\FuncCall + { + return new Expr\FuncCall(BuilderHelpers::normalizeNameOrExpr($name), $this->args($args)); + } + /** + * Creates a method call node. + * + * @param Expr $var Variable the method is called on + * @param string|Identifier|Expr $name Method name + * @param array $args Method arguments + * + * @return Expr\MethodCall + */ + public function methodCall(Expr $var, $name, array $args = []) : Expr\MethodCall + { + return new Expr\MethodCall($var, BuilderHelpers::normalizeIdentifierOrExpr($name), $this->args($args)); + } + /** + * Creates a static method call node. + * + * @param string|Name|Expr $class Class name + * @param string|Identifier|Expr $name Method name + * @param array $args Method arguments + * + * @return Expr\StaticCall + */ + public function staticCall($class, $name, array $args = []) : Expr\StaticCall + { + return new Expr\StaticCall(BuilderHelpers::normalizeNameOrExpr($class), BuilderHelpers::normalizeIdentifierOrExpr($name), $this->args($args)); + } + /** + * Creates an object creation node. + * + * @param string|Name|Expr $class Class name + * @param array $args Constructor arguments + * + * @return Expr\New_ + */ + public function new($class, array $args = []) : Expr\New_ + { + return new Expr\New_(BuilderHelpers::normalizeNameOrExpr($class), $this->args($args)); + } + /** + * Creates a constant fetch node. + * + * @param string|Name $name Constant name + * + * @return Expr\ConstFetch + */ + public function constFetch($name) : Expr\ConstFetch + { + return new Expr\ConstFetch(BuilderHelpers::normalizeName($name)); + } + /** + * Creates a property fetch node. + * + * @param Expr $var Variable holding object + * @param string|Identifier|Expr $name Property name + * + * @return Expr\PropertyFetch + */ + public function propertyFetch(Expr $var, $name) : Expr\PropertyFetch + { + return new Expr\PropertyFetch($var, BuilderHelpers::normalizeIdentifierOrExpr($name)); + } + /** + * Creates a class constant fetch node. + * + * @param string|Name|Expr $class Class name + * @param string|Identifier|Expr $name Constant name + * + * @return Expr\ClassConstFetch + */ + public function classConstFetch($class, $name) : Expr\ClassConstFetch + { + return new Expr\ClassConstFetch(BuilderHelpers::normalizeNameOrExpr($class), BuilderHelpers::normalizeIdentifierOrExpr($name)); + } + /** + * Creates nested Concat nodes from a list of expressions. + * + * @param Expr|string ...$exprs Expressions or literal strings + * + * @return Concat + */ + public function concat(...$exprs) : Concat + { + $numExprs = \count($exprs); + if ($numExprs < 2) { + throw new \LogicException('Expected at least two expressions'); + } + $lastConcat = $this->normalizeStringExpr($exprs[0]); + for ($i = 1; $i < $numExprs; $i++) { + $lastConcat = new Concat($lastConcat, $this->normalizeStringExpr($exprs[$i])); + } + return $lastConcat; + } + /** + * @param string|Expr $expr + * @return Expr + */ + private function normalizeStringExpr($expr) : Expr + { + if ($expr instanceof Expr) { + return $expr; + } + if (\is_string($expr)) { + return new String_($expr); + } + throw new \LogicException('Expected string or Expr'); + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/BuilderHelpers.php b/vendor/nikic/php-parser/lib/PhpParser/BuilderHelpers.php new file mode 100644 index 0000000000..4f483ff9e1 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/BuilderHelpers.php @@ -0,0 +1,270 @@ +getNode(); + } + if ($node instanceof Node) { + return $node; + } + throw new \LogicException('Expected node or builder object'); + } + /** + * Normalizes a node to a statement. + * + * Expressions are wrapped in a Stmt\Expression node. + * + * @param Node|Builder $node The node to normalize + * + * @return Stmt The normalized statement node + */ + public static function normalizeStmt($node) : Stmt + { + $node = self::normalizeNode($node); + if ($node instanceof Stmt) { + return $node; + } + if ($node instanceof Expr) { + return new Stmt\Expression($node); + } + throw new \LogicException('Expected statement or expression node'); + } + /** + * Normalizes strings to Identifier. + * + * @param string|Identifier $name The identifier to normalize + * + * @return Identifier The normalized identifier + */ + public static function normalizeIdentifier($name) : Identifier + { + if ($name instanceof Identifier) { + return $name; + } + if (\is_string($name)) { + return new Identifier($name); + } + throw new \LogicException('Expected string or instance of Node\\Identifier'); + } + /** + * Normalizes strings to Identifier, also allowing expressions. + * + * @param string|Identifier|Expr $name The identifier to normalize + * + * @return Identifier|Expr The normalized identifier or expression + */ + public static function normalizeIdentifierOrExpr($name) + { + if ($name instanceof Identifier || $name instanceof Expr) { + return $name; + } + if (\is_string($name)) { + return new Identifier($name); + } + throw new \LogicException('Expected string or instance of Node\\Identifier or Node\\Expr'); + } + /** + * Normalizes a name: Converts string names to Name nodes. + * + * @param Name|string $name The name to normalize + * + * @return Name The normalized name + */ + public static function normalizeName($name) : Name + { + if ($name instanceof Name) { + return $name; + } + if (\is_string($name)) { + if (!$name) { + throw new \LogicException('Name cannot be empty'); + } + if ($name[0] === '\\') { + return new Name\FullyQualified(\substr($name, 1)); + } + if (0 === \strpos($name, 'namespace\\')) { + return new Name\Relative(\substr($name, \strlen('namespace\\'))); + } + return new Name($name); + } + throw new \LogicException('Name must be a string or an instance of Node\\Name'); + } + /** + * Normalizes a name: Converts string names to Name nodes, while also allowing expressions. + * + * @param Expr|Name|string $name The name to normalize + * + * @return Name|Expr The normalized name or expression + */ + public static function normalizeNameOrExpr($name) + { + if ($name instanceof Expr) { + return $name; + } + if (!\is_string($name) && !$name instanceof Name) { + throw new \LogicException('Name must be a string or an instance of Node\\Name or Node\\Expr'); + } + return self::normalizeName($name); + } + /** + * Normalizes a type: Converts plain-text type names into proper AST representation. + * + * In particular, builtin types become Identifiers, custom types become Names and nullables + * are wrapped in NullableType nodes. + * + * @param string|Name|Identifier|ComplexType $type The type to normalize + * + * @return Name|Identifier|ComplexType The normalized type + */ + public static function normalizeType($type) + { + if (!\is_string($type)) { + if (!$type instanceof Name && !$type instanceof Identifier && !$type instanceof ComplexType) { + throw new \LogicException('Type must be a string, or an instance of Name, Identifier or ComplexType'); + } + return $type; + } + $nullable = \false; + if (\strlen($type) > 0 && $type[0] === '?') { + $nullable = \true; + $type = \substr($type, 1); + } + $builtinTypes = ['array', 'callable', 'bool', 'int', 'float', 'string', 'iterable', 'void', 'object', 'null', 'false', 'mixed', 'never', 'true']; + $lowerType = \strtolower($type); + if (\in_array($lowerType, $builtinTypes)) { + $type = new Identifier($lowerType); + } else { + $type = self::normalizeName($type); + } + $notNullableTypes = ['void', 'mixed', 'never']; + if ($nullable && \in_array((string) $type, $notNullableTypes)) { + throw new \LogicException(\sprintf('%s type cannot be nullable', $type)); + } + return $nullable ? new NullableType($type) : $type; + } + /** + * Normalizes a value: Converts nulls, booleans, integers, + * floats, strings and arrays into their respective nodes + * + * @param Node\Expr|bool|null|int|float|string|array $value The value to normalize + * + * @return Expr The normalized value + */ + public static function normalizeValue($value) : Expr + { + if ($value instanceof Node\Expr) { + return $value; + } + if (\is_null($value)) { + return new Expr\ConstFetch(new Name('null')); + } + if (\is_bool($value)) { + return new Expr\ConstFetch(new Name($value ? 'true' : 'false')); + } + if (\is_int($value)) { + return new Scalar\LNumber($value); + } + if (\is_float($value)) { + return new Scalar\DNumber($value); + } + if (\is_string($value)) { + return new Scalar\String_($value); + } + if (\is_array($value)) { + $items = []; + $lastKey = -1; + foreach ($value as $itemKey => $itemValue) { + // for consecutive, numeric keys don't generate keys + if (null !== $lastKey && ++$lastKey === $itemKey) { + $items[] = new Expr\ArrayItem(self::normalizeValue($itemValue)); + } else { + $lastKey = null; + $items[] = new Expr\ArrayItem(self::normalizeValue($itemValue), self::normalizeValue($itemKey)); + } + } + return new Expr\Array_($items); + } + throw new \LogicException('Invalid value'); + } + /** + * Normalizes a doc comment: Converts plain strings to PhpParser\Comment\Doc. + * + * @param Comment\Doc|string $docComment The doc comment to normalize + * + * @return Comment\Doc The normalized doc comment + */ + public static function normalizeDocComment($docComment) : Comment\Doc + { + if ($docComment instanceof Comment\Doc) { + return $docComment; + } + if (\is_string($docComment)) { + return new Comment\Doc($docComment); + } + throw new \LogicException('Doc comment must be a string or an instance of PhpParser\\Comment\\Doc'); + } + /** + * Normalizes a attribute: Converts attribute to the Attribute Group if needed. + * + * @param Node\Attribute|Node\AttributeGroup $attribute + * + * @return Node\AttributeGroup The Attribute Group + */ + public static function normalizeAttribute($attribute) : Node\AttributeGroup + { + if ($attribute instanceof Node\AttributeGroup) { + return $attribute; + } + if (!$attribute instanceof Node\Attribute) { + throw new \LogicException('Attribute must be an instance of PhpParser\\Node\\Attribute or PhpParser\\Node\\AttributeGroup'); + } + return new Node\AttributeGroup([$attribute]); + } + /** + * Adds a modifier and returns new modifier bitmask. + * + * @param int $modifiers Existing modifiers + * @param int $modifier Modifier to set + * + * @return int New modifiers + */ + public static function addModifier(int $modifiers, int $modifier) : int + { + Stmt\Class_::verifyModifier($modifiers, $modifier); + return $modifiers | $modifier; + } + /** + * Adds a modifier and returns new modifier bitmask. + * @return int New modifiers + */ + public static function addClassModifier(int $existingModifiers, int $modifierToSet) : int + { + Stmt\Class_::verifyClassModifier($existingModifiers, $modifierToSet); + return $existingModifiers | $modifierToSet; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Comment.php b/vendor/nikic/php-parser/lib/PhpParser/Comment.php new file mode 100644 index 0000000000..d083e22260 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Comment.php @@ -0,0 +1,235 @@ +text = $text; + $this->startLine = $startLine; + $this->startFilePos = $startFilePos; + $this->startTokenPos = $startTokenPos; + $this->endLine = $endLine; + $this->endFilePos = $endFilePos; + $this->endTokenPos = $endTokenPos; + } + /** + * Gets the comment text. + * + * @return string The comment text (including comment delimiters like /*) + */ + public function getText() : string + { + return $this->text; + } + /** + * Gets the line number the comment started on. + * + * @return int Line number (or -1 if not available) + */ + public function getStartLine() : int + { + return $this->startLine; + } + /** + * Gets the file offset the comment started on. + * + * @return int File offset (or -1 if not available) + */ + public function getStartFilePos() : int + { + return $this->startFilePos; + } + /** + * Gets the token offset the comment started on. + * + * @return int Token offset (or -1 if not available) + */ + public function getStartTokenPos() : int + { + return $this->startTokenPos; + } + /** + * Gets the line number the comment ends on. + * + * @return int Line number (or -1 if not available) + */ + public function getEndLine() : int + { + return $this->endLine; + } + /** + * Gets the file offset the comment ends on. + * + * @return int File offset (or -1 if not available) + */ + public function getEndFilePos() : int + { + return $this->endFilePos; + } + /** + * Gets the token offset the comment ends on. + * + * @return int Token offset (or -1 if not available) + */ + public function getEndTokenPos() : int + { + return $this->endTokenPos; + } + /** + * Gets the line number the comment started on. + * + * @deprecated Use getStartLine() instead + * + * @return int Line number + */ + public function getLine() : int + { + return $this->startLine; + } + /** + * Gets the file offset the comment started on. + * + * @deprecated Use getStartFilePos() instead + * + * @return int File offset + */ + public function getFilePos() : int + { + return $this->startFilePos; + } + /** + * Gets the token offset the comment started on. + * + * @deprecated Use getStartTokenPos() instead + * + * @return int Token offset + */ + public function getTokenPos() : int + { + return $this->startTokenPos; + } + /** + * Gets the comment text. + * + * @return string The comment text (including comment delimiters like /*) + */ + public function __toString() : string + { + return $this->text; + } + /** + * Gets the reformatted comment text. + * + * "Reformatted" here means that we try to clean up the whitespace at the + * starts of the lines. This is necessary because we receive the comments + * without trailing whitespace on the first line, but with trailing whitespace + * on all subsequent lines. + * + * @return mixed|string + */ + public function getReformattedText() + { + $text = \trim($this->text); + $newlinePos = \strpos($text, "\n"); + if (\false === $newlinePos) { + // Single line comments don't need further processing + return $text; + } elseif (\preg_match('((*BSR_ANYCRLF)(*ANYCRLF)^.*(?:\\R\\s+\\*.*)+$)', $text)) { + // Multi line comment of the type + // + // /* + // * Some text. + // * Some more text. + // */ + // + // is handled by replacing the whitespace sequences before the * by a single space + return \preg_replace('(^\\s+\\*)m', ' *', $this->text); + } elseif (\preg_match('(^/\\*\\*?\\s*[\\r\\n])', $text) && \preg_match('(\\n(\\s*)\\*/$)', $text, $matches)) { + // Multi line comment of the type + // + // /* + // Some text. + // Some more text. + // */ + // + // is handled by removing the whitespace sequence on the line before the closing + // */ on all lines. So if the last line is " */", then " " is removed at the + // start of all lines. + return \preg_replace('(^' . \preg_quote($matches[1]) . ')m', '', $text); + } elseif (\preg_match('(^/\\*\\*?\\s*(?!\\s))', $text, $matches)) { + // Multi line comment of the type + // + // /* Some text. + // Some more text. + // Indented text. + // Even more text. */ + // + // is handled by removing the difference between the shortest whitespace prefix on all + // lines and the length of the "/* " opening sequence. + $prefixLen = $this->getShortestWhitespacePrefixLen(\substr($text, $newlinePos + 1)); + $removeLen = $prefixLen - \strlen($matches[0]); + return \preg_replace('(^\\s{' . $removeLen . '})m', '', $text); + } + // No idea how to format this comment, so simply return as is + return $text; + } + /** + * Get length of shortest whitespace prefix (at the start of a line). + * + * If there is a line with no prefix whitespace, 0 is a valid return value. + * + * @param string $str String to check + * @return int Length in characters. Tabs count as single characters. + */ + private function getShortestWhitespacePrefixLen(string $str) : int + { + $lines = \explode("\n", $str); + $shortestPrefixLen = \INF; + foreach ($lines as $line) { + \preg_match('(^\\s*)', $line, $matches); + $prefixLen = \strlen($matches[0]); + if ($prefixLen < $shortestPrefixLen) { + $shortestPrefixLen = $prefixLen; + } + } + return $shortestPrefixLen; + } + /** + * @return array + * @psalm-return array{nodeType:string, text:mixed, line:mixed, filePos:mixed} + */ + public function jsonSerialize() : array + { + // Technically not a node, but we make it look like one anyway + $type = $this instanceof Comment\Doc ? 'Comment_Doc' : 'Comment'; + return [ + 'nodeType' => $type, + 'text' => $this->text, + // TODO: Rename these to include "start". + 'line' => $this->startLine, + 'filePos' => $this->startFilePos, + 'tokenPos' => $this->startTokenPos, + 'endLine' => $this->endLine, + 'endFilePos' => $this->endFilePos, + 'endTokenPos' => $this->endTokenPos, + ]; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Comment/Doc.php b/vendor/nikic/php-parser/lib/PhpParser/Comment/Doc.php new file mode 100644 index 0000000000..077082166b --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Comment/Doc.php @@ -0,0 +1,8 @@ +fallbackEvaluator = $fallbackEvaluator ?? function (Expr $expr) { + throw new ConstExprEvaluationException("Expression of type {$expr->getType()} cannot be evaluated"); + }; + } + /** + * Silently evaluates a constant expression into a PHP value. + * + * Thrown Errors, warnings or notices will be converted into a ConstExprEvaluationException. + * The original source of the exception is available through getPrevious(). + * + * If some part of the expression cannot be evaluated, the fallback evaluator passed to the + * constructor will be invoked. By default, if no fallback is provided, an exception of type + * ConstExprEvaluationException is thrown. + * + * See class doc comment for caveats and limitations. + * + * @param Expr $expr Constant expression to evaluate + * @return mixed Result of evaluation + * + * @throws ConstExprEvaluationException if the expression cannot be evaluated or an error occurred + */ + public function evaluateSilently(Expr $expr) + { + \set_error_handler(function ($num, $str, $file, $line) { + throw new \ErrorException($str, 0, $num, $file, $line); + }); + try { + return $this->evaluate($expr); + } catch (\Throwable $e) { + if (!$e instanceof ConstExprEvaluationException) { + $e = new ConstExprEvaluationException("An error occurred during constant expression evaluation", 0, $e); + } + throw $e; + } finally { + \restore_error_handler(); + } + } + /** + * Directly evaluates a constant expression into a PHP value. + * + * May generate Error exceptions, warnings or notices. Use evaluateSilently() to convert these + * into a ConstExprEvaluationException. + * + * If some part of the expression cannot be evaluated, the fallback evaluator passed to the + * constructor will be invoked. By default, if no fallback is provided, an exception of type + * ConstExprEvaluationException is thrown. + * + * See class doc comment for caveats and limitations. + * + * @param Expr $expr Constant expression to evaluate + * @return mixed Result of evaluation + * + * @throws ConstExprEvaluationException if the expression cannot be evaluated + */ + public function evaluateDirectly(Expr $expr) + { + return $this->evaluate($expr); + } + private function evaluate(Expr $expr) + { + if ($expr instanceof Scalar\LNumber || $expr instanceof Scalar\DNumber || $expr instanceof Scalar\String_) { + return $expr->value; + } + if ($expr instanceof Expr\Array_) { + return $this->evaluateArray($expr); + } + // Unary operators + if ($expr instanceof Expr\UnaryPlus) { + return +$this->evaluate($expr->expr); + } + if ($expr instanceof Expr\UnaryMinus) { + return -$this->evaluate($expr->expr); + } + if ($expr instanceof Expr\BooleanNot) { + return !$this->evaluate($expr->expr); + } + if ($expr instanceof Expr\BitwiseNot) { + return ~$this->evaluate($expr->expr); + } + if ($expr instanceof Expr\BinaryOp) { + return $this->evaluateBinaryOp($expr); + } + if ($expr instanceof Expr\Ternary) { + return $this->evaluateTernary($expr); + } + if ($expr instanceof Expr\ArrayDimFetch && null !== $expr->dim) { + return $this->evaluate($expr->var)[$this->evaluate($expr->dim)]; + } + if ($expr instanceof Expr\ConstFetch) { + return $this->evaluateConstFetch($expr); + } + return ($this->fallbackEvaluator)($expr); + } + private function evaluateArray(Expr\Array_ $expr) + { + $array = []; + foreach ($expr->items as $item) { + if (null !== $item->key) { + $array[$this->evaluate($item->key)] = $this->evaluate($item->value); + } elseif ($item->unpack) { + $array = array_merge($array, $this->evaluate($item->value)); + } else { + $array[] = $this->evaluate($item->value); + } + } + return $array; + } + private function evaluateTernary(Expr\Ternary $expr) + { + if (null === $expr->if) { + return $this->evaluate($expr->cond) ?: $this->evaluate($expr->else); + } + return $this->evaluate($expr->cond) ? $this->evaluate($expr->if) : $this->evaluate($expr->else); + } + private function evaluateBinaryOp(Expr\BinaryOp $expr) + { + if ($expr instanceof Expr\BinaryOp\Coalesce && $expr->left instanceof Expr\ArrayDimFetch) { + // This needs to be special cased to respect BP_VAR_IS fetch semantics + return $this->evaluate($expr->left->var)[$this->evaluate($expr->left->dim)] ?? $this->evaluate($expr->right); + } + // The evaluate() calls are repeated in each branch, because some of the operators are + // short-circuiting and evaluating the RHS in advance may be illegal in that case + $l = $expr->left; + $r = $expr->right; + switch ($expr->getOperatorSigil()) { + case '&': + return $this->evaluate($l) & $this->evaluate($r); + case '|': + return $this->evaluate($l) | $this->evaluate($r); + case '^': + return $this->evaluate($l) ^ $this->evaluate($r); + case '&&': + return $this->evaluate($l) && $this->evaluate($r); + case '||': + return $this->evaluate($l) || $this->evaluate($r); + case '??': + return $this->evaluate($l) ?? $this->evaluate($r); + case '.': + return $this->evaluate($l) . $this->evaluate($r); + case '/': + return $this->evaluate($l) / $this->evaluate($r); + case '==': + return $this->evaluate($l) == $this->evaluate($r); + case '>': + return $this->evaluate($l) > $this->evaluate($r); + case '>=': + return $this->evaluate($l) >= $this->evaluate($r); + case '===': + return $this->evaluate($l) === $this->evaluate($r); + case 'and': + return $this->evaluate($l) and $this->evaluate($r); + case 'or': + return $this->evaluate($l) or $this->evaluate($r); + case 'xor': + return $this->evaluate($l) xor $this->evaluate($r); + case '-': + return $this->evaluate($l) - $this->evaluate($r); + case '%': + return $this->evaluate($l) % $this->evaluate($r); + case '*': + return $this->evaluate($l) * $this->evaluate($r); + case '!=': + return $this->evaluate($l) != $this->evaluate($r); + case '!==': + return $this->evaluate($l) !== $this->evaluate($r); + case '+': + return $this->evaluate($l) + $this->evaluate($r); + case '**': + return $this->evaluate($l) ** $this->evaluate($r); + case '<<': + return $this->evaluate($l) << $this->evaluate($r); + case '>>': + return $this->evaluate($l) >> $this->evaluate($r); + case '<': + return $this->evaluate($l) < $this->evaluate($r); + case '<=': + return $this->evaluate($l) <= $this->evaluate($r); + case '<=>': + return $this->evaluate($l) <=> $this->evaluate($r); + } + throw new \Exception('Should not happen'); + } + private function evaluateConstFetch(Expr\ConstFetch $expr) + { + $name = $expr->name->toLowerString(); + switch ($name) { + case 'null': + return null; + case 'false': + return \false; + case 'true': + return \true; + } + return ($this->fallbackEvaluator)($expr); + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Error.php b/vendor/nikic/php-parser/lib/PhpParser/Error.php new file mode 100644 index 0000000000..716ba369e7 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Error.php @@ -0,0 +1,172 @@ +rawMessage = $message; + if (\is_array($attributes)) { + $this->attributes = $attributes; + } else { + $this->attributes = ['startLine' => $attributes]; + } + $this->updateMessage(); + } + /** + * Gets the error message + * + * @return string Error message + */ + public function getRawMessage() : string + { + return $this->rawMessage; + } + /** + * Gets the line the error starts in. + * + * @return int Error start line + */ + public function getStartLine() : int + { + return $this->attributes['startLine'] ?? -1; + } + /** + * Gets the line the error ends in. + * + * @return int Error end line + */ + public function getEndLine() : int + { + return $this->attributes['endLine'] ?? -1; + } + /** + * Gets the attributes of the node/token the error occurred at. + * + * @return array + */ + public function getAttributes() : array + { + return $this->attributes; + } + /** + * Sets the attributes of the node/token the error occurred at. + * + * @param array $attributes + */ + public function setAttributes(array $attributes) + { + $this->attributes = $attributes; + $this->updateMessage(); + } + /** + * Sets the line of the PHP file the error occurred in. + * + * @param string $message Error message + */ + public function setRawMessage(string $message) + { + $this->rawMessage = $message; + $this->updateMessage(); + } + /** + * Sets the line the error starts in. + * + * @param int $line Error start line + */ + public function setStartLine(int $line) + { + $this->attributes['startLine'] = $line; + $this->updateMessage(); + } + /** + * Returns whether the error has start and end column information. + * + * For column information enable the startFilePos and endFilePos in the lexer options. + * + * @return bool + */ + public function hasColumnInfo() : bool + { + return isset($this->attributes['startFilePos'], $this->attributes['endFilePos']); + } + /** + * Gets the start column (1-based) into the line where the error started. + * + * @param string $code Source code of the file + * @return int + */ + public function getStartColumn(string $code) : int + { + if (!$this->hasColumnInfo()) { + throw new \RuntimeException('Error does not have column information'); + } + return $this->toColumn($code, $this->attributes['startFilePos']); + } + /** + * Gets the end column (1-based) into the line where the error ended. + * + * @param string $code Source code of the file + * @return int + */ + public function getEndColumn(string $code) : int + { + if (!$this->hasColumnInfo()) { + throw new \RuntimeException('Error does not have column information'); + } + return $this->toColumn($code, $this->attributes['endFilePos']); + } + /** + * Formats message including line and column information. + * + * @param string $code Source code associated with the error, for calculation of the columns + * + * @return string Formatted message + */ + public function getMessageWithColumnInfo(string $code) : string + { + return \sprintf('%s from %d:%d to %d:%d', $this->getRawMessage(), $this->getStartLine(), $this->getStartColumn($code), $this->getEndLine(), $this->getEndColumn($code)); + } + /** + * Converts a file offset into a column. + * + * @param string $code Source code that $pos indexes into + * @param int $pos 0-based position in $code + * + * @return int 1-based column (relative to start of line) + */ + private function toColumn(string $code, int $pos) : int + { + if ($pos > \strlen($code)) { + throw new \RuntimeException('Invalid position information'); + } + $lineStartPos = \strrpos($code, "\n", $pos - \strlen($code)); + if (\false === $lineStartPos) { + $lineStartPos = -1; + } + return $pos - $lineStartPos; + } + /** + * Updates the exception message after a change to rawMessage or rawLine. + */ + protected function updateMessage() + { + $this->message = $this->rawMessage; + if (-1 === $this->getStartLine()) { + $this->message .= ' on unknown line'; + } else { + $this->message .= ' on line ' . $this->getStartLine(); + } + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/ErrorHandler.php b/vendor/nikic/php-parser/lib/PhpParser/ErrorHandler.php new file mode 100644 index 0000000000..13a9902e47 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/ErrorHandler.php @@ -0,0 +1,14 @@ +errors[] = $error; + } + /** + * Get collected errors. + * + * @return Error[] + */ + public function getErrors() : array + { + return $this->errors; + } + /** + * Check whether there are any errors. + * + * @return bool + */ + public function hasErrors() : bool + { + return !empty($this->errors); + } + /** + * Reset/clear collected errors. + */ + public function clearErrors() + { + $this->errors = []; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/ErrorHandler/Throwing.php b/vendor/nikic/php-parser/lib/PhpParser/ErrorHandler/Throwing.php new file mode 100644 index 0000000000..4a5a712126 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/ErrorHandler/Throwing.php @@ -0,0 +1,19 @@ +type = $type; + $this->old = $old; + $this->new = $new; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Internal/Differ.php b/vendor/nikic/php-parser/lib/PhpParser/Internal/Differ.php new file mode 100644 index 0000000000..cf054b14fe --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Internal/Differ.php @@ -0,0 +1,152 @@ +isEqual = $isEqual; + } + /** + * Calculate diff (edit script) from $old to $new. + * + * @param array $old Original array + * @param array $new New array + * + * @return DiffElem[] Diff (edit script) + */ + public function diff(array $old, array $new) + { + list($trace, $x, $y) = $this->calculateTrace($old, $new); + return $this->extractDiff($trace, $x, $y, $old, $new); + } + /** + * Calculate diff, including "replace" operations. + * + * If a sequence of remove operations is followed by the same number of add operations, these + * will be coalesced into replace operations. + * + * @param array $old Original array + * @param array $new New array + * + * @return DiffElem[] Diff (edit script), including replace operations + */ + public function diffWithReplacements(array $old, array $new) + { + return $this->coalesceReplacements($this->diff($old, $new)); + } + private function calculateTrace(array $a, array $b) + { + $n = \count($a); + $m = \count($b); + $max = $n + $m; + $v = [1 => 0]; + $trace = []; + for ($d = 0; $d <= $max; $d++) { + $trace[] = $v; + for ($k = -$d; $k <= $d; $k += 2) { + if ($k === -$d || $k !== $d && $v[$k - 1] < $v[$k + 1]) { + $x = $v[$k + 1]; + } else { + $x = $v[$k - 1] + 1; + } + $y = $x - $k; + while ($x < $n && $y < $m && ($this->isEqual)($a[$x], $b[$y])) { + $x++; + $y++; + } + $v[$k] = $x; + if ($x >= $n && $y >= $m) { + return [$trace, $x, $y]; + } + } + } + throw new \Exception('Should not happen'); + } + private function extractDiff(array $trace, int $x, int $y, array $a, array $b) + { + $result = []; + for ($d = \count($trace) - 1; $d >= 0; $d--) { + $v = $trace[$d]; + $k = $x - $y; + if ($k === -$d || $k !== $d && $v[$k - 1] < $v[$k + 1]) { + $prevK = $k + 1; + } else { + $prevK = $k - 1; + } + $prevX = $v[$prevK]; + $prevY = $prevX - $prevK; + while ($x > $prevX && $y > $prevY) { + $result[] = new DiffElem(DiffElem::TYPE_KEEP, $a[$x - 1], $b[$y - 1]); + $x--; + $y--; + } + if ($d === 0) { + break; + } + while ($x > $prevX) { + $result[] = new DiffElem(DiffElem::TYPE_REMOVE, $a[$x - 1], null); + $x--; + } + while ($y > $prevY) { + $result[] = new DiffElem(DiffElem::TYPE_ADD, null, $b[$y - 1]); + $y--; + } + } + return \array_reverse($result); + } + /** + * Coalesce equal-length sequences of remove+add into a replace operation. + * + * @param DiffElem[] $diff + * @return DiffElem[] + */ + private function coalesceReplacements(array $diff) + { + $newDiff = []; + $c = \count($diff); + for ($i = 0; $i < $c; $i++) { + $diffType = $diff[$i]->type; + if ($diffType !== DiffElem::TYPE_REMOVE) { + $newDiff[] = $diff[$i]; + continue; + } + $j = $i; + while ($j < $c && $diff[$j]->type === DiffElem::TYPE_REMOVE) { + $j++; + } + $k = $j; + while ($k < $c && $diff[$k]->type === DiffElem::TYPE_ADD) { + $k++; + } + if ($j - $i === $k - $j) { + $len = $j - $i; + for ($n = 0; $n < $len; $n++) { + $newDiff[] = new DiffElem(DiffElem::TYPE_REPLACE, $diff[$i + $n]->old, $diff[$j + $n]->new); + } + } else { + for (; $i < $k; $i++) { + $newDiff[] = $diff[$i]; + } + } + $i = $k - 1; + } + return $newDiff; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Internal/PrintableNewAnonClassNode.php b/vendor/nikic/php-parser/lib/PhpParser/Internal/PrintableNewAnonClassNode.php new file mode 100644 index 0000000000..986ebf7efc --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Internal/PrintableNewAnonClassNode.php @@ -0,0 +1,58 @@ +attrGroups = $attrGroups; + $this->flags = $flags; + $this->args = $args; + $this->extends = $extends; + $this->implements = $implements; + $this->stmts = $stmts; + } + public static function fromNewNode(Expr\New_ $newNode) + { + $class = $newNode->class; + \assert($class instanceof Node\Stmt\Class_); + // We don't assert that $class->name is null here, to allow consumers to assign unique names + // to anonymous classes for their own purposes. We simplify ignore the name here. + return new self($class->attrGroups, $class->flags, $newNode->args, $class->extends, $class->implements, $class->stmts, $newNode->getAttributes()); + } + public function getType() : string + { + return 'Expr_PrintableNewAnonClass'; + } + public function getSubNodeNames() : array + { + return ['attrGroups', 'flags', 'args', 'extends', 'implements', 'stmts']; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Internal/TokenStream.php b/vendor/nikic/php-parser/lib/PhpParser/Internal/TokenStream.php new file mode 100644 index 0000000000..d64268a256 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Internal/TokenStream.php @@ -0,0 +1,270 @@ +tokens = $tokens; + $this->indentMap = $this->calcIndentMap(); + } + /** + * Whether the given position is immediately surrounded by parenthesis. + * + * @param int $startPos Start position + * @param int $endPos End position + * + * @return bool + */ + public function haveParens(int $startPos, int $endPos) : bool + { + return $this->haveTokenImmediatelyBefore($startPos, '(') && $this->haveTokenImmediatelyAfter($endPos, ')'); + } + /** + * Whether the given position is immediately surrounded by braces. + * + * @param int $startPos Start position + * @param int $endPos End position + * + * @return bool + */ + public function haveBraces(int $startPos, int $endPos) : bool + { + return ($this->haveTokenImmediatelyBefore($startPos, '{') || $this->haveTokenImmediatelyBefore($startPos, \T_CURLY_OPEN)) && $this->haveTokenImmediatelyAfter($endPos, '}'); + } + /** + * Check whether the position is directly preceded by a certain token type. + * + * During this check whitespace and comments are skipped. + * + * @param int $pos Position before which the token should occur + * @param int|string $expectedTokenType Token to check for + * + * @return bool Whether the expected token was found + */ + public function haveTokenImmediatelyBefore(int $pos, $expectedTokenType) : bool + { + $tokens = $this->tokens; + $pos--; + for (; $pos >= 0; $pos--) { + $tokenType = $tokens[$pos][0]; + if ($tokenType === $expectedTokenType) { + return \true; + } + if ($tokenType !== \T_WHITESPACE && $tokenType !== \T_COMMENT && $tokenType !== \T_DOC_COMMENT) { + break; + } + } + return \false; + } + /** + * Check whether the position is directly followed by a certain token type. + * + * During this check whitespace and comments are skipped. + * + * @param int $pos Position after which the token should occur + * @param int|string $expectedTokenType Token to check for + * + * @return bool Whether the expected token was found + */ + public function haveTokenImmediatelyAfter(int $pos, $expectedTokenType) : bool + { + $tokens = $this->tokens; + $pos++; + for (; $pos < \count($tokens); $pos++) { + $tokenType = $tokens[$pos][0]; + if ($tokenType === $expectedTokenType) { + return \true; + } + if ($tokenType !== \T_WHITESPACE && $tokenType !== \T_COMMENT && $tokenType !== \T_DOC_COMMENT) { + break; + } + } + return \false; + } + public function skipLeft(int $pos, $skipTokenType) + { + $tokens = $this->tokens; + $pos = $this->skipLeftWhitespace($pos); + if ($skipTokenType === \T_WHITESPACE) { + return $pos; + } + if ($tokens[$pos][0] !== $skipTokenType) { + // Shouldn't happen. The skip token MUST be there + throw new \Exception('Encountered unexpected token'); + } + $pos--; + return $this->skipLeftWhitespace($pos); + } + public function skipRight(int $pos, $skipTokenType) + { + $tokens = $this->tokens; + $pos = $this->skipRightWhitespace($pos); + if ($skipTokenType === \T_WHITESPACE) { + return $pos; + } + if ($tokens[$pos][0] !== $skipTokenType) { + // Shouldn't happen. The skip token MUST be there + throw new \Exception('Encountered unexpected token'); + } + $pos++; + return $this->skipRightWhitespace($pos); + } + /** + * Return first non-whitespace token position smaller or equal to passed position. + * + * @param int $pos Token position + * @return int Non-whitespace token position + */ + public function skipLeftWhitespace(int $pos) + { + $tokens = $this->tokens; + for (; $pos >= 0; $pos--) { + $type = $tokens[$pos][0]; + if ($type !== \T_WHITESPACE && $type !== \T_COMMENT && $type !== \T_DOC_COMMENT) { + break; + } + } + return $pos; + } + /** + * Return first non-whitespace position greater or equal to passed position. + * + * @param int $pos Token position + * @return int Non-whitespace token position + */ + public function skipRightWhitespace(int $pos) + { + $tokens = $this->tokens; + for ($count = \count($tokens); $pos < $count; $pos++) { + $type = $tokens[$pos][0]; + if ($type !== \T_WHITESPACE && $type !== \T_COMMENT && $type !== \T_DOC_COMMENT) { + break; + } + } + return $pos; + } + public function findRight(int $pos, $findTokenType) + { + $tokens = $this->tokens; + for ($count = \count($tokens); $pos < $count; $pos++) { + $type = $tokens[$pos][0]; + if ($type === $findTokenType) { + return $pos; + } + } + return -1; + } + /** + * Whether the given position range contains a certain token type. + * + * @param int $startPos Starting position (inclusive) + * @param int $endPos Ending position (exclusive) + * @param int|string $tokenType Token type to look for + * @return bool Whether the token occurs in the given range + */ + public function haveTokenInRange(int $startPos, int $endPos, $tokenType) + { + $tokens = $this->tokens; + for ($pos = $startPos; $pos < $endPos; $pos++) { + if ($tokens[$pos][0] === $tokenType) { + return \true; + } + } + return \false; + } + public function haveBracesInRange(int $startPos, int $endPos) + { + return $this->haveTokenInRange($startPos, $endPos, '{') || $this->haveTokenInRange($startPos, $endPos, \T_CURLY_OPEN) || $this->haveTokenInRange($startPos, $endPos, '}'); + } + public function haveTagInRange(int $startPos, int $endPos) : bool + { + return $this->haveTokenInRange($startPos, $endPos, \T_OPEN_TAG) || $this->haveTokenInRange($startPos, $endPos, \T_CLOSE_TAG); + } + /** + * Get indentation before token position. + * + * @param int $pos Token position + * + * @return int Indentation depth (in spaces) + */ + public function getIndentationBefore(int $pos) : int + { + return $this->indentMap[$pos]; + } + /** + * Get the code corresponding to a token offset range, optionally adjusted for indentation. + * + * @param int $from Token start position (inclusive) + * @param int $to Token end position (exclusive) + * @param int $indent By how much the code should be indented (can be negative as well) + * + * @return string Code corresponding to token range, adjusted for indentation + */ + public function getTokenCode(int $from, int $to, int $indent) : string + { + $tokens = $this->tokens; + $result = ''; + for ($pos = $from; $pos < $to; $pos++) { + $token = $tokens[$pos]; + if (\is_array($token)) { + $type = $token[0]; + $content = $token[1]; + if ($type === \T_CONSTANT_ENCAPSED_STRING || $type === \T_ENCAPSED_AND_WHITESPACE) { + $result .= $content; + } else { + // TODO Handle non-space indentation + if ($indent < 0) { + $result .= \str_replace("\n" . \str_repeat(" ", -$indent), "\n", $content); + } elseif ($indent > 0) { + $result .= \str_replace("\n", "\n" . \str_repeat(" ", $indent), $content); + } else { + $result .= $content; + } + } + } else { + $result .= $token; + } + } + return $result; + } + /** + * Precalculate the indentation at every token position. + * + * @return int[] Token position to indentation map + */ + private function calcIndentMap() + { + $indentMap = []; + $indent = 0; + foreach ($this->tokens as $token) { + $indentMap[] = $indent; + if ($token[0] === \T_WHITESPACE) { + $content = $token[1]; + $newlinePos = \strrpos($content, "\n"); + if (\false !== $newlinePos) { + $indent = \strlen($content) - $newlinePos - 1; + } + } + } + // Add a sentinel for one past end of the file + $indentMap[] = $indent; + return $indentMap; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/JsonDecoder.php b/vendor/nikic/php-parser/lib/PhpParser/JsonDecoder.php new file mode 100644 index 0000000000..9221494a43 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/JsonDecoder.php @@ -0,0 +1,90 @@ +decodeRecursive($value); + } + private function decodeRecursive($value) + { + if (\is_array($value)) { + if (isset($value['nodeType'])) { + if ($value['nodeType'] === 'Comment' || $value['nodeType'] === 'Comment_Doc') { + return $this->decodeComment($value); + } + return $this->decodeNode($value); + } + return $this->decodeArray($value); + } + return $value; + } + private function decodeArray(array $array) : array + { + $decodedArray = []; + foreach ($array as $key => $value) { + $decodedArray[$key] = $this->decodeRecursive($value); + } + return $decodedArray; + } + private function decodeNode(array $value) : Node + { + $nodeType = $value['nodeType']; + if (!\is_string($nodeType)) { + throw new \RuntimeException('Node type must be a string'); + } + $reflectionClass = $this->reflectionClassFromNodeType($nodeType); + /** @var Node $node */ + $node = $reflectionClass->newInstanceWithoutConstructor(); + if (isset($value['attributes'])) { + if (!\is_array($value['attributes'])) { + throw new \RuntimeException('Attributes must be an array'); + } + $node->setAttributes($this->decodeArray($value['attributes'])); + } + foreach ($value as $name => $subNode) { + if ($name === 'nodeType' || $name === 'attributes') { + continue; + } + $node->{$name} = $this->decodeRecursive($subNode); + } + return $node; + } + private function decodeComment(array $value) : Comment + { + $className = $value['nodeType'] === 'Comment' ? Comment::class : Comment\Doc::class; + if (!isset($value['text'])) { + throw new \RuntimeException('Comment must have text'); + } + return new $className($value['text'], $value['line'] ?? -1, $value['filePos'] ?? -1, $value['tokenPos'] ?? -1, $value['endLine'] ?? -1, $value['endFilePos'] ?? -1, $value['endTokenPos'] ?? -1); + } + private function reflectionClassFromNodeType(string $nodeType) : \ReflectionClass + { + if (!isset($this->reflectionClassCache[$nodeType])) { + $className = $this->classNameFromNodeType($nodeType); + $this->reflectionClassCache[$nodeType] = new \ReflectionClass($className); + } + return $this->reflectionClassCache[$nodeType]; + } + private function classNameFromNodeType(string $nodeType) : string + { + $className = 'PhpParser\\Node\\' . \strtr($nodeType, '_', '\\'); + if (\class_exists($className)) { + return $className; + } + $className .= '_'; + if (\class_exists($className)) { + return $className; + } + throw new \RuntimeException("Unknown node type \"{$nodeType}\""); + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Lexer.php b/vendor/nikic/php-parser/lib/PhpParser/Lexer.php new file mode 100644 index 0000000000..a33e14dd16 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Lexer.php @@ -0,0 +1,465 @@ +defineCompatibilityTokens(); + $this->tokenMap = $this->createTokenMap(); + $this->identifierTokens = $this->createIdentifierTokenMap(); + // map of tokens to drop while lexing (the map is only used for isset lookup, + // that's why the value is simply set to 1; the value is never actually used.) + $this->dropTokens = \array_fill_keys([\T_WHITESPACE, \T_OPEN_TAG, \T_COMMENT, \T_DOC_COMMENT, \T_BAD_CHARACTER], 1); + $defaultAttributes = ['comments', 'startLine', 'endLine']; + $usedAttributes = \array_fill_keys($options['usedAttributes'] ?? $defaultAttributes, \true); + // Create individual boolean properties to make these checks faster. + $this->attributeStartLineUsed = isset($usedAttributes['startLine']); + $this->attributeEndLineUsed = isset($usedAttributes['endLine']); + $this->attributeStartTokenPosUsed = isset($usedAttributes['startTokenPos']); + $this->attributeEndTokenPosUsed = isset($usedAttributes['endTokenPos']); + $this->attributeStartFilePosUsed = isset($usedAttributes['startFilePos']); + $this->attributeEndFilePosUsed = isset($usedAttributes['endFilePos']); + $this->attributeCommentsUsed = isset($usedAttributes['comments']); + } + /** + * Initializes the lexer for lexing the provided source code. + * + * This function does not throw if lexing errors occur. Instead, errors may be retrieved using + * the getErrors() method. + * + * @param string $code The source code to lex + * @param ErrorHandler|null $errorHandler Error handler to use for lexing errors. Defaults to + * ErrorHandler\Throwing + */ + public function startLexing(string $code, ?ErrorHandler $errorHandler = null) + { + if (null === $errorHandler) { + $errorHandler = new ErrorHandler\Throwing(); + } + $this->code = $code; + // keep the code around for __halt_compiler() handling + $this->pos = -1; + $this->line = 1; + $this->filePos = 0; + // If inline HTML occurs without preceding code, treat it as if it had a leading newline. + // This ensures proper composability, because having a newline is the "safe" assumption. + $this->prevCloseTagHasNewline = \true; + $scream = \ini_set('xdebug.scream', '0'); + $this->tokens = @\token_get_all($code); + $this->postprocessTokens($errorHandler); + if (\false !== $scream) { + \ini_set('xdebug.scream', $scream); + } + } + private function handleInvalidCharacterRange($start, $end, $line, ErrorHandler $errorHandler) + { + $tokens = []; + for ($i = $start; $i < $end; $i++) { + $chr = $this->code[$i]; + if ($chr === "\x00") { + // PHP cuts error message after null byte, so need special case + $errorMsg = 'Unexpected null byte'; + } else { + $errorMsg = \sprintf('Unexpected character "%s" (ASCII %d)', $chr, \ord($chr)); + } + $tokens[] = [\T_BAD_CHARACTER, $chr, $line]; + $errorHandler->handleError(new Error($errorMsg, ['startLine' => $line, 'endLine' => $line, 'startFilePos' => $i, 'endFilePos' => $i])); + } + return $tokens; + } + /** + * Check whether comment token is unterminated. + * + * @return bool + */ + private function isUnterminatedComment($token) : bool + { + return ($token[0] === \T_COMMENT || $token[0] === \T_DOC_COMMENT) && \substr($token[1], 0, 2) === '/*' && \substr($token[1], -2) !== '*/'; + } + protected function postprocessTokens(ErrorHandler $errorHandler) + { + // PHP's error handling for token_get_all() is rather bad, so if we want detailed + // error information we need to compute it ourselves. Invalid character errors are + // detected by finding "gaps" in the token array. Unterminated comments are detected + // by checking if a trailing comment has a "*/" at the end. + // + // Additionally, we perform a number of canonicalizations here: + // * Use the PHP 8.0 comment format, which does not include trailing whitespace anymore. + // * Use PHP 8.0 T_NAME_* tokens. + // * Use PHP 8.1 T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG and + // T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG tokens used to disambiguate intersection types. + $filePos = 0; + $line = 1; + $numTokens = \count($this->tokens); + for ($i = 0; $i < $numTokens; $i++) { + $token = $this->tokens[$i]; + // Since PHP 7.4 invalid characters are represented by a T_BAD_CHARACTER token. + // In this case we only need to emit an error. + if ($token[0] === \T_BAD_CHARACTER) { + $this->handleInvalidCharacterRange($filePos, $filePos + 1, $line, $errorHandler); + } + if ($token[0] === \T_COMMENT && \substr($token[1], 0, 2) !== '/*' && \preg_match('/(\\r\\n|\\n|\\r)$/D', $token[1], $matches)) { + $trailingNewline = $matches[0]; + $token[1] = \substr($token[1], 0, -\strlen($trailingNewline)); + $this->tokens[$i] = $token; + if (isset($this->tokens[$i + 1]) && $this->tokens[$i + 1][0] === \T_WHITESPACE) { + // Move trailing newline into following T_WHITESPACE token, if it already exists. + $this->tokens[$i + 1][1] = $trailingNewline . $this->tokens[$i + 1][1]; + $this->tokens[$i + 1][2]--; + } else { + // Otherwise, we need to create a new T_WHITESPACE token. + \array_splice($this->tokens, $i + 1, 0, [[\T_WHITESPACE, $trailingNewline, $line]]); + $numTokens++; + } + } + // Emulate PHP 8 T_NAME_* tokens, by combining sequences of T_NS_SEPARATOR and T_STRING + // into a single token. + if (\is_array($token) && ($token[0] === \T_NS_SEPARATOR || isset($this->identifierTokens[$token[0]]))) { + $lastWasSeparator = $token[0] === \T_NS_SEPARATOR; + $text = $token[1]; + for ($j = $i + 1; isset($this->tokens[$j]); $j++) { + if ($lastWasSeparator) { + if (!isset($this->identifierTokens[$this->tokens[$j][0]])) { + break; + } + $lastWasSeparator = \false; + } else { + if ($this->tokens[$j][0] !== \T_NS_SEPARATOR) { + break; + } + $lastWasSeparator = \true; + } + $text .= $this->tokens[$j][1]; + } + if ($lastWasSeparator) { + // Trailing separator is not part of the name. + $j--; + $text = \substr($text, 0, -1); + } + if ($j > $i + 1) { + if ($token[0] === \T_NS_SEPARATOR) { + $type = \T_NAME_FULLY_QUALIFIED; + } else { + if ($token[0] === \T_NAMESPACE) { + $type = \T_NAME_RELATIVE; + } else { + $type = \T_NAME_QUALIFIED; + } + } + $token = [$type, $text, $line]; + \array_splice($this->tokens, $i, $j - $i, [$token]); + $numTokens -= $j - $i - 1; + } + } + if ($token === '&') { + $next = $i + 1; + while (isset($this->tokens[$next]) && $this->tokens[$next][0] === \T_WHITESPACE) { + $next++; + } + $followedByVarOrVarArg = isset($this->tokens[$next]) && ($this->tokens[$next][0] === \T_VARIABLE || $this->tokens[$next][0] === \T_ELLIPSIS); + $this->tokens[$i] = $token = [$followedByVarOrVarArg ? \T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG : \T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, '&', $line]; + } + $tokenValue = \is_string($token) ? $token : $token[1]; + $tokenLen = \strlen($tokenValue); + if (\substr($this->code, $filePos, $tokenLen) !== $tokenValue) { + // Something is missing, must be an invalid character + $nextFilePos = \strpos($this->code, $tokenValue, $filePos); + $badCharTokens = $this->handleInvalidCharacterRange($filePos, $nextFilePos, $line, $errorHandler); + $filePos = (int) $nextFilePos; + \array_splice($this->tokens, $i, 0, $badCharTokens); + $numTokens += \count($badCharTokens); + $i += \count($badCharTokens); + } + $filePos += $tokenLen; + $line += \substr_count($tokenValue, "\n"); + } + if ($filePos !== \strlen($this->code)) { + if (\substr($this->code, $filePos, 2) === '/*') { + // Unlike PHP, HHVM will drop unterminated comments entirely + $comment = \substr($this->code, $filePos); + $errorHandler->handleError(new Error('Unterminated comment', ['startLine' => $line, 'endLine' => $line + \substr_count($comment, "\n"), 'startFilePos' => $filePos, 'endFilePos' => $filePos + \strlen($comment)])); + // Emulate the PHP behavior + $isDocComment = isset($comment[3]) && $comment[3] === '*'; + $this->tokens[] = [$isDocComment ? \T_DOC_COMMENT : \T_COMMENT, $comment, $line]; + } else { + // Invalid characters at the end of the input + $badCharTokens = $this->handleInvalidCharacterRange($filePos, \strlen($this->code), $line, $errorHandler); + $this->tokens = \array_merge($this->tokens, $badCharTokens); + } + return; + } + if (\count($this->tokens) > 0) { + // Check for unterminated comment + $lastToken = $this->tokens[\count($this->tokens) - 1]; + if ($this->isUnterminatedComment($lastToken)) { + $errorHandler->handleError(new Error('Unterminated comment', ['startLine' => $line - \substr_count($lastToken[1], "\n"), 'endLine' => $line, 'startFilePos' => $filePos - \strlen($lastToken[1]), 'endFilePos' => $filePos])); + } + } + } + /** + * Fetches the next token. + * + * The available attributes are determined by the 'usedAttributes' option, which can + * be specified in the constructor. The following attributes are supported: + * + * * 'comments' => Array of PhpParser\Comment or PhpParser\Comment\Doc instances, + * representing all comments that occurred between the previous + * non-discarded token and the current one. + * * 'startLine' => Line in which the node starts. + * * 'endLine' => Line in which the node ends. + * * 'startTokenPos' => Offset into the token array of the first token in the node. + * * 'endTokenPos' => Offset into the token array of the last token in the node. + * * 'startFilePos' => Offset into the code string of the first character that is part of the node. + * * 'endFilePos' => Offset into the code string of the last character that is part of the node. + * + * @param mixed $value Variable to store token content in + * @param mixed $startAttributes Variable to store start attributes in + * @param mixed $endAttributes Variable to store end attributes in + * + * @return int Token id + */ + public function getNextToken(&$value = null, &$startAttributes = null, &$endAttributes = null) : int + { + $startAttributes = []; + $endAttributes = []; + while (1) { + if (isset($this->tokens[++$this->pos])) { + $token = $this->tokens[$this->pos]; + } else { + // EOF token with ID 0 + $token = "\x00"; + } + if ($this->attributeStartLineUsed) { + $startAttributes['startLine'] = $this->line; + } + if ($this->attributeStartTokenPosUsed) { + $startAttributes['startTokenPos'] = $this->pos; + } + if ($this->attributeStartFilePosUsed) { + $startAttributes['startFilePos'] = $this->filePos; + } + if (\is_string($token)) { + $value = $token; + if (isset($token[1])) { + // bug in token_get_all + $this->filePos += 2; + $id = \ord('"'); + } else { + $this->filePos += 1; + $id = \ord($token); + } + } elseif (!isset($this->dropTokens[$token[0]])) { + $value = $token[1]; + $id = $this->tokenMap[$token[0]]; + if (\T_CLOSE_TAG === $token[0]) { + $this->prevCloseTagHasNewline = \false !== \strpos($token[1], "\n") || \false !== \strpos($token[1], "\r"); + } elseif (\T_INLINE_HTML === $token[0]) { + $startAttributes['hasLeadingNewline'] = $this->prevCloseTagHasNewline; + } + $this->line += \substr_count($value, "\n"); + $this->filePos += \strlen($value); + } else { + $origLine = $this->line; + $origFilePos = $this->filePos; + $this->line += \substr_count($token[1], "\n"); + $this->filePos += \strlen($token[1]); + if (\T_COMMENT === $token[0] || \T_DOC_COMMENT === $token[0]) { + if ($this->attributeCommentsUsed) { + $comment = \T_DOC_COMMENT === $token[0] ? new Comment\Doc($token[1], $origLine, $origFilePos, $this->pos, $this->line, $this->filePos - 1, $this->pos) : new Comment($token[1], $origLine, $origFilePos, $this->pos, $this->line, $this->filePos - 1, $this->pos); + $startAttributes['comments'][] = $comment; + } + } + continue; + } + if ($this->attributeEndLineUsed) { + $endAttributes['endLine'] = $this->line; + } + if ($this->attributeEndTokenPosUsed) { + $endAttributes['endTokenPos'] = $this->pos; + } + if ($this->attributeEndFilePosUsed) { + $endAttributes['endFilePos'] = $this->filePos - 1; + } + return $id; + } + throw new \RuntimeException('Reached end of lexer loop'); + } + /** + * Returns the token array for current code. + * + * The token array is in the same format as provided by the + * token_get_all() function and does not discard tokens (i.e. + * whitespace and comments are included). The token position + * attributes are against this token array. + * + * @return array Array of tokens in token_get_all() format + */ + public function getTokens() : array + { + return $this->tokens; + } + /** + * Handles __halt_compiler() by returning the text after it. + * + * @return string Remaining text + */ + public function handleHaltCompiler() : string + { + // text after T_HALT_COMPILER, still including (); + $textAfter = \substr($this->code, $this->filePos); + // ensure that it is followed by (); + // this simplifies the situation, by not allowing any comments + // in between of the tokens. + if (!\preg_match('~^\\s*\\(\\s*\\)\\s*(?:;|\\?>\\r?\\n?)~', $textAfter, $matches)) { + throw new Error('__HALT_COMPILER must be followed by "();"'); + } + // prevent the lexer from returning any further tokens + $this->pos = \count($this->tokens); + // return with (); removed + return \substr($textAfter, \strlen($matches[0])); + } + private function defineCompatibilityTokens() + { + static $compatTokensDefined = \false; + if ($compatTokensDefined) { + return; + } + $compatTokens = [ + // PHP 7.4 + 'T_BAD_CHARACTER', + 'T_FN', + 'T_COALESCE_EQUAL', + // PHP 8.0 + 'T_NAME_QUALIFIED', + 'T_NAME_FULLY_QUALIFIED', + 'T_NAME_RELATIVE', + 'T_MATCH', + 'T_NULLSAFE_OBJECT_OPERATOR', + 'T_ATTRIBUTE', + // PHP 8.1 + 'T_ENUM', + 'T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG', + 'T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG', + 'T_READONLY', + ]; + // PHP-Parser might be used together with another library that also emulates some or all + // of these tokens. Perform a sanity-check that all already defined tokens have been + // assigned a unique ID. + $usedTokenIds = []; + foreach ($compatTokens as $token) { + if (\defined($token)) { + $tokenId = \constant($token); + $clashingToken = $usedTokenIds[$tokenId] ?? null; + if ($clashingToken !== null) { + throw new \Error(\sprintf('Token %s has same ID as token %s, ' . 'you may be using a library with broken token emulation', $token, $clashingToken)); + } + $usedTokenIds[$tokenId] = $token; + } + } + // Now define any tokens that have not yet been emulated. Try to assign IDs from -1 + // downwards, but skip any IDs that may already be in use. + $newTokenId = -1; + foreach ($compatTokens as $token) { + if (!\defined($token)) { + while (isset($usedTokenIds[$newTokenId])) { + $newTokenId--; + } + \define($token, $newTokenId); + $newTokenId--; + } + } + $compatTokensDefined = \true; + } + /** + * Creates the token map. + * + * The token map maps the PHP internal token identifiers + * to the identifiers used by the Parser. Additionally it + * maps T_OPEN_TAG_WITH_ECHO to T_ECHO and T_CLOSE_TAG to ';'. + * + * @return array The token map + */ + protected function createTokenMap() : array + { + $tokenMap = []; + // 256 is the minimum possible token number, as everything below + // it is an ASCII value + for ($i = 256; $i < 1000; ++$i) { + if (\T_DOUBLE_COLON === $i) { + // T_DOUBLE_COLON is equivalent to T_PAAMAYIM_NEKUDOTAYIM + $tokenMap[$i] = Tokens::T_PAAMAYIM_NEKUDOTAYIM; + } elseif (\T_OPEN_TAG_WITH_ECHO === $i) { + // T_OPEN_TAG_WITH_ECHO with dropped T_OPEN_TAG results in T_ECHO + $tokenMap[$i] = Tokens::T_ECHO; + } elseif (\T_CLOSE_TAG === $i) { + // T_CLOSE_TAG is equivalent to ';' + $tokenMap[$i] = \ord(';'); + } elseif ('UNKNOWN' !== ($name = \token_name($i))) { + if ('T_HASHBANG' === $name) { + // HHVM uses a special token for #! hashbang lines + $tokenMap[$i] = Tokens::T_INLINE_HTML; + } elseif (\defined($name = Tokens::class . '::' . $name)) { + // Other tokens can be mapped directly + $tokenMap[$i] = \constant($name); + } + } + } + // HHVM uses a special token for numbers that overflow to double + if (\defined('T_ONUMBER')) { + $tokenMap[\T_ONUMBER] = Tokens::T_DNUMBER; + } + // HHVM also has a separate token for the __COMPILER_HALT_OFFSET__ constant + if (\defined('T_COMPILER_HALT_OFFSET')) { + $tokenMap[\T_COMPILER_HALT_OFFSET] = Tokens::T_STRING; + } + // Assign tokens for which we define compatibility constants, as token_name() does not know them. + $tokenMap[\T_FN] = Tokens::T_FN; + $tokenMap[\T_COALESCE_EQUAL] = Tokens::T_COALESCE_EQUAL; + $tokenMap[\T_NAME_QUALIFIED] = Tokens::T_NAME_QUALIFIED; + $tokenMap[\T_NAME_FULLY_QUALIFIED] = Tokens::T_NAME_FULLY_QUALIFIED; + $tokenMap[\T_NAME_RELATIVE] = Tokens::T_NAME_RELATIVE; + $tokenMap[\T_MATCH] = Tokens::T_MATCH; + $tokenMap[\T_NULLSAFE_OBJECT_OPERATOR] = Tokens::T_NULLSAFE_OBJECT_OPERATOR; + $tokenMap[\T_ATTRIBUTE] = Tokens::T_ATTRIBUTE; + $tokenMap[\T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG] = Tokens::T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG; + $tokenMap[\T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG] = Tokens::T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG; + $tokenMap[\T_ENUM] = Tokens::T_ENUM; + $tokenMap[\T_READONLY] = Tokens::T_READONLY; + return $tokenMap; + } + private function createIdentifierTokenMap() : array + { + // Based on semi_reserved production. + return \array_fill_keys([\T_STRING, \T_STATIC, \T_ABSTRACT, \T_FINAL, \T_PRIVATE, \T_PROTECTED, \T_PUBLIC, \T_READONLY, \T_INCLUDE, \T_INCLUDE_ONCE, \T_EVAL, \T_REQUIRE, \T_REQUIRE_ONCE, \T_LOGICAL_OR, \T_LOGICAL_XOR, \T_LOGICAL_AND, \T_INSTANCEOF, \T_NEW, \T_CLONE, \T_EXIT, \T_IF, \T_ELSEIF, \T_ELSE, \T_ENDIF, \T_ECHO, \T_DO, \T_WHILE, \T_ENDWHILE, \T_FOR, \T_ENDFOR, \T_FOREACH, \T_ENDFOREACH, \T_DECLARE, \T_ENDDECLARE, \T_AS, \T_TRY, \T_CATCH, \T_FINALLY, \T_THROW, \T_USE, \T_INSTEADOF, \T_GLOBAL, \T_VAR, \T_UNSET, \T_ISSET, \T_EMPTY, \T_CONTINUE, \T_GOTO, \T_FUNCTION, \T_CONST, \T_RETURN, \T_PRINT, \T_YIELD, \T_LIST, \T_SWITCH, \T_ENDSWITCH, \T_CASE, \T_DEFAULT, \T_BREAK, \T_ARRAY, \T_CALLABLE, \T_EXTENDS, \T_IMPLEMENTS, \T_NAMESPACE, \T_TRAIT, \T_INTERFACE, \T_CLASS, \T_CLASS_C, \T_TRAIT_C, \T_FUNC_C, \T_METHOD_C, \T_LINE, \T_FILE, \T_DIR, \T_NS_C, \T_HALT_COMPILER, \T_FN, \T_MATCH], \true); + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Lexer/Emulative.php b/vendor/nikic/php-parser/lib/PhpParser/Lexer/Emulative.php new file mode 100644 index 0000000000..8394d1f371 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Lexer/Emulative.php @@ -0,0 +1,209 @@ +targetPhpVersion = $options['phpVersion'] ?? Emulative::PHP_8_2; + unset($options['phpVersion']); + parent::__construct($options); + $emulators = [new FlexibleDocStringEmulator(), new FnTokenEmulator(), new MatchTokenEmulator(), new CoaleseEqualTokenEmulator(), new NumericLiteralSeparatorEmulator(), new NullsafeTokenEmulator(), new AttributeEmulator(), new EnumTokenEmulator(), new ReadonlyTokenEmulator(), new ExplicitOctalEmulator(), new ReadonlyFunctionTokenEmulator()]; + // Collect emulators that are relevant for the PHP version we're running + // and the PHP version we're targeting for emulation. + foreach ($emulators as $emulator) { + $emulatorPhpVersion = $emulator->getPhpVersion(); + if ($this->isForwardEmulationNeeded($emulatorPhpVersion)) { + $this->emulators[] = $emulator; + } else { + if ($this->isReverseEmulationNeeded($emulatorPhpVersion)) { + $this->emulators[] = new ReverseEmulator($emulator); + } + } + } + } + public function startLexing(string $code, ?ErrorHandler $errorHandler = null) + { + $emulators = \array_filter($this->emulators, function ($emulator) use($code) { + return $emulator->isEmulationNeeded($code); + }); + if (empty($emulators)) { + // Nothing to emulate, yay + parent::startLexing($code, $errorHandler); + return; + } + $this->patches = []; + foreach ($emulators as $emulator) { + $code = $emulator->preprocessCode($code, $this->patches); + } + $collector = new ErrorHandler\Collecting(); + parent::startLexing($code, $collector); + $this->sortPatches(); + $this->fixupTokens(); + $errors = $collector->getErrors(); + if (!empty($errors)) { + $this->fixupErrors($errors); + foreach ($errors as $error) { + $errorHandler->handleError($error); + } + } + foreach ($emulators as $emulator) { + $this->tokens = $emulator->emulate($code, $this->tokens); + } + } + private function isForwardEmulationNeeded(string $emulatorPhpVersion) : bool + { + return \version_compare(\PHP_VERSION, $emulatorPhpVersion, '<') && \version_compare($this->targetPhpVersion, $emulatorPhpVersion, '>='); + } + private function isReverseEmulationNeeded(string $emulatorPhpVersion) : bool + { + return \version_compare(\PHP_VERSION, $emulatorPhpVersion, '>=') && \version_compare($this->targetPhpVersion, $emulatorPhpVersion, '<'); + } + private function sortPatches() + { + // Patches may be contributed by different emulators. + // Make sure they are sorted by increasing patch position. + \usort($this->patches, function ($p1, $p2) { + return $p1[0] <=> $p2[0]; + }); + } + private function fixupTokens() + { + if (\count($this->patches) === 0) { + return; + } + // Load first patch + $patchIdx = 0; + list($patchPos, $patchType, $patchText) = $this->patches[$patchIdx]; + // We use a manual loop over the tokens, because we modify the array on the fly + $pos = 0; + for ($i = 0, $c = \count($this->tokens); $i < $c; $i++) { + $token = $this->tokens[$i]; + if (\is_string($token)) { + if ($patchPos === $pos) { + // Only support replacement for string tokens. + \assert($patchType === 'replace'); + $this->tokens[$i] = $patchText; + // Fetch the next patch + $patchIdx++; + if ($patchIdx >= \count($this->patches)) { + // No more patches, we're done + return; + } + list($patchPos, $patchType, $patchText) = $this->patches[$patchIdx]; + } + $pos += \strlen($token); + continue; + } + $len = \strlen($token[1]); + $posDelta = 0; + while ($patchPos >= $pos && $patchPos < $pos + $len) { + $patchTextLen = \strlen($patchText); + if ($patchType === 'remove') { + if ($patchPos === $pos && $patchTextLen === $len) { + // Remove token entirely + \array_splice($this->tokens, $i, 1, []); + $i--; + $c--; + } else { + // Remove from token string + $this->tokens[$i][1] = \substr_replace($token[1], '', $patchPos - $pos + $posDelta, $patchTextLen); + $posDelta -= $patchTextLen; + } + } elseif ($patchType === 'add') { + // Insert into the token string + $this->tokens[$i][1] = \substr_replace($token[1], $patchText, $patchPos - $pos + $posDelta, 0); + $posDelta += $patchTextLen; + } else { + if ($patchType === 'replace') { + // Replace inside the token string + $this->tokens[$i][1] = \substr_replace($token[1], $patchText, $patchPos - $pos + $posDelta, $patchTextLen); + } else { + \assert(\false); + } + } + // Fetch the next patch + $patchIdx++; + if ($patchIdx >= \count($this->patches)) { + // No more patches, we're done + return; + } + list($patchPos, $patchType, $patchText) = $this->patches[$patchIdx]; + // Multiple patches may apply to the same token. Reload the current one to check + // If the new patch applies + $token = $this->tokens[$i]; + } + $pos += $len; + } + // A patch did not apply + \assert(\false); + } + /** + * Fixup line and position information in errors. + * + * @param Error[] $errors + */ + private function fixupErrors(array $errors) + { + foreach ($errors as $error) { + $attrs = $error->getAttributes(); + $posDelta = 0; + $lineDelta = 0; + foreach ($this->patches as $patch) { + list($patchPos, $patchType, $patchText) = $patch; + if ($patchPos >= $attrs['startFilePos']) { + // No longer relevant + break; + } + if ($patchType === 'add') { + $posDelta += \strlen($patchText); + $lineDelta += \substr_count($patchText, "\n"); + } else { + if ($patchType === 'remove') { + $posDelta -= \strlen($patchText); + $lineDelta -= \substr_count($patchText, "\n"); + } + } + } + $attrs['startFilePos'] += $posDelta; + $attrs['endFilePos'] += $posDelta; + $attrs['startLine'] += $lineDelta; + $attrs['endLine'] += $lineDelta; + $error->setAttributes($attrs); + } + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/AttributeEmulator.php b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/AttributeEmulator.php new file mode 100644 index 0000000000..fce7a644d1 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/AttributeEmulator.php @@ -0,0 +1,50 @@ +resolveIntegerOrFloatToken($tokens[$i + 1][1]); + \array_splice($tokens, $i, 2, [[$tokenKind, '0' . $tokens[$i + 1][1], $tokens[$i][2]]]); + $c--; + } + } + return $tokens; + } + private function resolveIntegerOrFloatToken(string $str) : int + { + $str = \substr($str, 1); + $str = \str_replace('_', '', $str); + $num = \octdec($str); + return \is_float($num) ? \T_DNUMBER : \T_LNUMBER; + } + public function reverseEmulate(string $code, array $tokens) : array + { + // Explicit octals were not legal code previously, don't bother. + return $tokens; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/FlexibleDocStringEmulator.php b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/FlexibleDocStringEmulator.php new file mode 100644 index 0000000000..a91a344fa1 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/FlexibleDocStringEmulator.php @@ -0,0 +1,66 @@ +\h*)\2(?![a-zA-Z0-9_\x80-\xff])(?(?:;?[\r\n])?)/x +REGEX; + public function getPhpVersion() : string + { + return Emulative::PHP_7_3; + } + public function isEmulationNeeded(string $code) : bool + { + return \strpos($code, '<<<') !== \false; + } + public function emulate(string $code, array $tokens) : array + { + // Handled by preprocessing + fixup. + return $tokens; + } + public function reverseEmulate(string $code, array $tokens) : array + { + // Not supported. + return $tokens; + } + public function preprocessCode(string $code, array &$patches) : string + { + if (!\preg_match_all(self::FLEXIBLE_DOC_STRING_REGEX, $code, $matches, \PREG_SET_ORDER | \PREG_OFFSET_CAPTURE)) { + // No heredoc/nowdoc found + return $code; + } + // Keep track of how much we need to adjust string offsets due to the modifications we + // already made + $posDelta = 0; + foreach ($matches as $match) { + $indentation = $match['indentation'][0]; + $indentationStart = $match['indentation'][1]; + $separator = $match['separator'][0]; + $separatorStart = $match['separator'][1]; + if ($indentation === '' && $separator !== '') { + // Ordinary heredoc/nowdoc + continue; + } + if ($indentation !== '') { + // Remove indentation + $indentationLen = \strlen($indentation); + $code = \substr_replace($code, '', $indentationStart + $posDelta, $indentationLen); + $patches[] = [$indentationStart + $posDelta, 'add', $indentation]; + $posDelta -= $indentationLen; + } + if ($separator === '') { + // Insert newline as separator + $code = \substr_replace($code, "\n", $separatorStart + $posDelta, 0); + $patches[] = [$separatorStart + $posDelta, 'remove', "\n"]; + $posDelta += 1; + } + } + return $code; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/FnTokenEmulator.php b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/FnTokenEmulator.php new file mode 100644 index 0000000000..3bb002cc51 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/FnTokenEmulator.php @@ -0,0 +1,21 @@ +getKeywordString()) !== \false; + } + protected function isKeywordContext(array $tokens, int $pos) : bool + { + $previousNonSpaceToken = $this->getPreviousNonSpaceToken($tokens, $pos); + return $previousNonSpaceToken === null || $previousNonSpaceToken[0] !== \T_OBJECT_OPERATOR; + } + public function emulate(string $code, array $tokens) : array + { + $keywordString = $this->getKeywordString(); + foreach ($tokens as $i => $token) { + if ($token[0] === \T_STRING && \strtolower($token[1]) === $keywordString && $this->isKeywordContext($tokens, $i)) { + $tokens[$i][0] = $this->getKeywordToken(); + } + } + return $tokens; + } + /** + * @param mixed[] $tokens + * @return array|string|null + */ + private function getPreviousNonSpaceToken(array $tokens, int $start) + { + for ($i = $start - 1; $i >= 0; --$i) { + if ($tokens[$i][0] === \T_WHITESPACE) { + continue; + } + return $tokens[$i]; + } + return null; + } + public function reverseEmulate(string $code, array $tokens) : array + { + $keywordToken = $this->getKeywordToken(); + foreach ($tokens as $i => $token) { + if ($token[0] === $keywordToken) { + $tokens[$i][0] = \T_STRING; + } + } + return $tokens; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/MatchTokenEmulator.php b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/MatchTokenEmulator.php new file mode 100644 index 0000000000..674b7b3513 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/MatchTokenEmulator.php @@ -0,0 +1,21 @@ +') !== \false; + } + public function emulate(string $code, array $tokens) : array + { + // We need to manually iterate and manage a count because we'll change + // the tokens array on the way + $line = 1; + for ($i = 0, $c = \count($tokens); $i < $c; ++$i) { + if ($tokens[$i] === '?' && isset($tokens[$i + 1]) && $tokens[$i + 1][0] === \T_OBJECT_OPERATOR) { + \array_splice($tokens, $i, 2, [[\T_NULLSAFE_OBJECT_OPERATOR, '?->', $line]]); + $c--; + continue; + } + // Handle ?-> inside encapsed string. + if ($tokens[$i][0] === \T_ENCAPSED_AND_WHITESPACE && isset($tokens[$i - 1]) && $tokens[$i - 1][0] === \T_VARIABLE && \preg_match('/^\\?->([a-zA-Z_\\x80-\\xff][a-zA-Z0-9_\\x80-\\xff]*)/', $tokens[$i][1], $matches)) { + $replacement = [[\T_NULLSAFE_OBJECT_OPERATOR, '?->', $line], [\T_STRING, $matches[1], $line]]; + if (\strlen($matches[0]) !== \strlen($tokens[$i][1])) { + $replacement[] = [\T_ENCAPSED_AND_WHITESPACE, \substr($tokens[$i][1], \strlen($matches[0])), $line]; + } + \array_splice($tokens, $i, 1, $replacement); + $c += \count($replacement) - 1; + continue; + } + if (\is_array($tokens[$i])) { + $line += \substr_count($tokens[$i][1], "\n"); + } + } + return $tokens; + } + public function reverseEmulate(string $code, array $tokens) : array + { + // ?-> was not valid code previously, don't bother. + return $tokens; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/NumericLiteralSeparatorEmulator.php b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/NumericLiteralSeparatorEmulator.php new file mode 100644 index 0000000000..6523b889ec --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/NumericLiteralSeparatorEmulator.php @@ -0,0 +1,88 @@ +resolveIntegerOrFloatToken($match); + $newTokens = [[$tokenKind, $match, $token[2]]]; + $numTokens = 1; + $len = $tokenLen; + while ($matchLen > $len) { + $nextToken = $tokens[$i + $numTokens]; + $nextTokenText = \is_array($nextToken) ? $nextToken[1] : $nextToken; + $nextTokenLen = \strlen($nextTokenText); + $numTokens++; + if ($matchLen < $len + $nextTokenLen) { + // Split trailing characters into a partial token. + \assert(\is_array($nextToken), "Partial token should be an array token"); + $partialText = \substr($nextTokenText, $matchLen - $len); + $newTokens[] = [$nextToken[0], $partialText, $nextToken[2]]; + break; + } + $len += $nextTokenLen; + } + \array_splice($tokens, $i, $numTokens, $newTokens); + $c -= $numTokens - \count($newTokens); + $codeOffset += $matchLen; + } + return $tokens; + } + private function resolveIntegerOrFloatToken(string $str) : int + { + $str = \str_replace('_', '', $str); + if (\stripos($str, '0b') === 0) { + $num = \bindec($str); + } elseif (\stripos($str, '0x') === 0) { + $num = \hexdec($str); + } elseif (\stripos($str, '0') === 0 && \ctype_digit($str)) { + $num = \octdec($str); + } else { + $num = +$str; + } + return \is_float($num) ? \T_DNUMBER : \T_LNUMBER; + } + public function reverseEmulate(string $code, array $tokens) : array + { + // Numeric separators were not legal code previously, don't bother. + return $tokens; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReadonlyFunctionTokenEmulator.php b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReadonlyFunctionTokenEmulator.php new file mode 100644 index 0000000000..fd459ad11e --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReadonlyFunctionTokenEmulator.php @@ -0,0 +1,33 @@ +emulator = $emulator; + } + public function getPhpVersion() : string + { + return $this->emulator->getPhpVersion(); + } + public function isEmulationNeeded(string $code) : bool + { + return $this->emulator->isEmulationNeeded($code); + } + public function emulate(string $code, array $tokens) : array + { + return $this->emulator->reverseEmulate($code, $tokens); + } + public function reverseEmulate(string $code, array $tokens) : array + { + return $this->emulator->emulate($code, $tokens); + } + public function preprocessCode(string $code, array &$patches) : string + { + return $code; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/TokenEmulator.php b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/TokenEmulator.php new file mode 100644 index 0000000000..9b42871002 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/TokenEmulator.php @@ -0,0 +1,23 @@ + [aliasName => originalName]] */ + protected $aliases = []; + /** @var Name[][] Same as $aliases but preserving original case */ + protected $origAliases = []; + /** @var ErrorHandler Error handler */ + protected $errorHandler; + /** + * Create a name context. + * + * @param ErrorHandler $errorHandler Error handling used to report errors + */ + public function __construct(ErrorHandler $errorHandler) + { + $this->errorHandler = $errorHandler; + } + /** + * Start a new namespace. + * + * This also resets the alias table. + * + * @param Name|null $namespace Null is the global namespace + */ + public function startNamespace(?Name $namespace = null) + { + $this->namespace = $namespace; + $this->origAliases = $this->aliases = [Stmt\Use_::TYPE_NORMAL => [], Stmt\Use_::TYPE_FUNCTION => [], Stmt\Use_::TYPE_CONSTANT => []]; + } + /** + * Add an alias / import. + * + * @param Name $name Original name + * @param string $aliasName Aliased name + * @param int $type One of Stmt\Use_::TYPE_* + * @param array $errorAttrs Attributes to use to report an error + */ + public function addAlias(Name $name, string $aliasName, int $type, array $errorAttrs = []) + { + // Constant names are case sensitive, everything else case insensitive + if ($type === Stmt\Use_::TYPE_CONSTANT) { + $aliasLookupName = $aliasName; + } else { + $aliasLookupName = \strtolower($aliasName); + } + if (isset($this->aliases[$type][$aliasLookupName])) { + $typeStringMap = [Stmt\Use_::TYPE_NORMAL => '', Stmt\Use_::TYPE_FUNCTION => 'function ', Stmt\Use_::TYPE_CONSTANT => 'const ']; + $this->errorHandler->handleError(new Error(\sprintf('Cannot use %s%s as %s because the name is already in use', $typeStringMap[$type], $name, $aliasName), $errorAttrs)); + return; + } + $this->aliases[$type][$aliasLookupName] = $name; + $this->origAliases[$type][$aliasName] = $name; + } + /** + * Get current namespace. + * + * @return null|Name Namespace (or null if global namespace) + */ + public function getNamespace() + { + return $this->namespace; + } + /** + * Get resolved name. + * + * @param Name $name Name to resolve + * @param int $type One of Stmt\Use_::TYPE_{FUNCTION|CONSTANT} + * + * @return null|Name Resolved name, or null if static resolution is not possible + */ + public function getResolvedName(Name $name, int $type) + { + // don't resolve special class names + if ($type === Stmt\Use_::TYPE_NORMAL && $name->isSpecialClassName()) { + if (!$name->isUnqualified()) { + $this->errorHandler->handleError(new Error(\sprintf("'\\%s' is an invalid class name", $name->toString()), $name->getAttributes())); + } + return $name; + } + // fully qualified names are already resolved + if ($name->isFullyQualified()) { + return $name; + } + // Try to resolve aliases + if (null !== ($resolvedName = $this->resolveAlias($name, $type))) { + return $resolvedName; + } + if ($type !== Stmt\Use_::TYPE_NORMAL && $name->isUnqualified()) { + if (null === $this->namespace) { + // outside of a namespace unaliased unqualified is same as fully qualified + return new FullyQualified($name, $name->getAttributes()); + } + // Cannot resolve statically + return null; + } + // if no alias exists prepend current namespace + return FullyQualified::concat($this->namespace, $name, $name->getAttributes()); + } + /** + * Get resolved class name. + * + * @param Name $name Class ame to resolve + * + * @return Name Resolved name + */ + public function getResolvedClassName(Name $name) : Name + { + return $this->getResolvedName($name, Stmt\Use_::TYPE_NORMAL); + } + /** + * Get possible ways of writing a fully qualified name (e.g., by making use of aliases). + * + * @param string $name Fully-qualified name (without leading namespace separator) + * @param int $type One of Stmt\Use_::TYPE_* + * + * @return Name[] Possible representations of the name + */ + public function getPossibleNames(string $name, int $type) : array + { + $lcName = \strtolower($name); + if ($type === Stmt\Use_::TYPE_NORMAL) { + // self, parent and static must always be unqualified + if ($lcName === "self" || $lcName === "parent" || $lcName === "static") { + return [new Name($name)]; + } + } + // Collect possible ways to write this name, starting with the fully-qualified name + $possibleNames = [new FullyQualified($name)]; + if (null !== ($nsRelativeName = $this->getNamespaceRelativeName($name, $lcName, $type))) { + // Make sure there is no alias that makes the normally namespace-relative name + // into something else + if (null === $this->resolveAlias($nsRelativeName, $type)) { + $possibleNames[] = $nsRelativeName; + } + } + // Check for relevant namespace use statements + foreach ($this->origAliases[Stmt\Use_::TYPE_NORMAL] as $alias => $orig) { + $lcOrig = $orig->toLowerString(); + if (0 === \strpos($lcName, $lcOrig . '\\')) { + $possibleNames[] = new Name($alias . \substr($name, \strlen($lcOrig))); + } + } + // Check for relevant type-specific use statements + foreach ($this->origAliases[$type] as $alias => $orig) { + if ($type === Stmt\Use_::TYPE_CONSTANT) { + // Constants are are complicated-sensitive + $normalizedOrig = $this->normalizeConstName($orig->toString()); + if ($normalizedOrig === $this->normalizeConstName($name)) { + $possibleNames[] = new Name($alias); + } + } else { + // Everything else is case-insensitive + if ($orig->toLowerString() === $lcName) { + $possibleNames[] = new Name($alias); + } + } + } + return $possibleNames; + } + /** + * Get shortest representation of this fully-qualified name. + * + * @param string $name Fully-qualified name (without leading namespace separator) + * @param int $type One of Stmt\Use_::TYPE_* + * + * @return Name Shortest representation + */ + public function getShortName(string $name, int $type) : Name + { + $possibleNames = $this->getPossibleNames($name, $type); + // Find shortest name + $shortestName = null; + $shortestLength = \INF; + foreach ($possibleNames as $possibleName) { + $length = \strlen($possibleName->toCodeString()); + if ($length < $shortestLength) { + $shortestName = $possibleName; + $shortestLength = $length; + } + } + return $shortestName; + } + private function resolveAlias(Name $name, $type) + { + $firstPart = $name->getFirst(); + if ($name->isQualified()) { + // resolve aliases for qualified names, always against class alias table + $checkName = \strtolower($firstPart); + if (isset($this->aliases[Stmt\Use_::TYPE_NORMAL][$checkName])) { + $alias = $this->aliases[Stmt\Use_::TYPE_NORMAL][$checkName]; + return FullyQualified::concat($alias, $name->slice(1), $name->getAttributes()); + } + } elseif ($name->isUnqualified()) { + // constant aliases are case-sensitive, function aliases case-insensitive + $checkName = $type === Stmt\Use_::TYPE_CONSTANT ? $firstPart : \strtolower($firstPart); + if (isset($this->aliases[$type][$checkName])) { + // resolve unqualified aliases + return new FullyQualified($this->aliases[$type][$checkName], $name->getAttributes()); + } + } + // No applicable aliases + return null; + } + private function getNamespaceRelativeName(string $name, string $lcName, int $type) + { + if (null === $this->namespace) { + return new Name($name); + } + if ($type === Stmt\Use_::TYPE_CONSTANT) { + // The constants true/false/null always resolve to the global symbols, even inside a + // namespace, so they may be used without qualification + if ($lcName === "true" || $lcName === "false" || $lcName === "null") { + return new Name($name); + } + } + $namespacePrefix = \strtolower($this->namespace . '\\'); + if (0 === \strpos($lcName, $namespacePrefix)) { + return new Name(\substr($name, \strlen($namespacePrefix))); + } + return null; + } + private function normalizeConstName(string $name) + { + $nsSep = \strrpos($name, '\\'); + if (\false === $nsSep) { + return $name; + } + // Constants have case-insensitive namespace and case-sensitive short-name + $ns = \substr($name, 0, $nsSep); + $shortName = \substr($name, $nsSep + 1); + return \strtolower($ns) . '\\' . $shortName; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node.php b/vendor/nikic/php-parser/lib/PhpParser/Node.php new file mode 100644 index 0000000000..7b99feeef8 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node.php @@ -0,0 +1,136 @@ +attributes = $attributes; + $this->name = $name; + $this->value = $value; + $this->byRef = $byRef; + $this->unpack = $unpack; + } + public function getSubNodeNames() : array + { + return ['name', 'value', 'byRef', 'unpack']; + } + public function getType() : string + { + return 'Arg'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Attribute.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Attribute.php new file mode 100644 index 0000000000..5867015121 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Attribute.php @@ -0,0 +1,33 @@ +attributes = $attributes; + $this->name = $name; + $this->args = $args; + } + public function getSubNodeNames() : array + { + return ['name', 'args']; + } + public function getType() : string + { + return 'Attribute'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/AttributeGroup.php b/vendor/nikic/php-parser/lib/PhpParser/Node/AttributeGroup.php new file mode 100644 index 0000000000..255b74c8a8 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/AttributeGroup.php @@ -0,0 +1,29 @@ +attributes = $attributes; + $this->attrs = $attrs; + } + public function getSubNodeNames() : array + { + return ['attrs']; + } + public function getType() : string + { + return 'AttributeGroup'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/ComplexType.php b/vendor/nikic/php-parser/lib/PhpParser/Node/ComplexType.php new file mode 100644 index 0000000000..301d160342 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/ComplexType.php @@ -0,0 +1,14 @@ +attributes = $attributes; + $this->name = \is_string($name) ? new Identifier($name) : $name; + $this->value = $value; + } + public function getSubNodeNames() : array + { + return ['name', 'value']; + } + public function getType() : string + { + return 'Const'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr.php new file mode 100644 index 0000000000..f5dcde4abf --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr.php @@ -0,0 +1,9 @@ +attributes = $attributes; + $this->var = $var; + $this->dim = $dim; + } + public function getSubNodeNames() : array + { + return ['var', 'dim']; + } + public function getType() : string + { + return 'Expr_ArrayDimFetch'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayItem.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayItem.php new file mode 100644 index 0000000000..9360e8a0fd --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayItem.php @@ -0,0 +1,41 @@ +attributes = $attributes; + $this->key = $key; + $this->value = $value; + $this->byRef = $byRef; + $this->unpack = $unpack; + } + public function getSubNodeNames() : array + { + return ['key', 'value', 'byRef', 'unpack']; + } + public function getType() : string + { + return 'Expr_ArrayItem'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Array_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Array_.php new file mode 100644 index 0000000000..722a31d610 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Array_.php @@ -0,0 +1,35 @@ +attributes = $attributes; + $this->items = $items; + } + public function getSubNodeNames() : array + { + return ['items']; + } + public function getType() : string + { + return 'Expr_Array'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ArrowFunction.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ArrowFunction.php new file mode 100644 index 0000000000..92e62d1fab --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ArrowFunction.php @@ -0,0 +1,75 @@ + false : Whether the closure is static + * 'byRef' => false : Whether to return by reference + * 'params' => array() : Parameters + * 'returnType' => null : Return type + * 'expr' => Expr : Expression body + * 'attrGroups' => array() : PHP attribute groups + * @param array $attributes Additional attributes + */ + public function __construct(array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->static = $subNodes['static'] ?? \false; + $this->byRef = $subNodes['byRef'] ?? \false; + $this->params = $subNodes['params'] ?? []; + $returnType = $subNodes['returnType'] ?? null; + $this->returnType = \is_string($returnType) ? new Node\Identifier($returnType) : $returnType; + $this->expr = $subNodes['expr']; + $this->attrGroups = $subNodes['attrGroups'] ?? []; + } + public function getSubNodeNames() : array + { + return ['attrGroups', 'static', 'byRef', 'params', 'returnType', 'expr']; + } + public function returnsByRef() : bool + { + return $this->byRef; + } + public function getParams() : array + { + return $this->params; + } + public function getReturnType() + { + return $this->returnType; + } + public function getAttrGroups() : array + { + return $this->attrGroups; + } + /** + * @return Node\Stmt\Return_[] + */ + public function getStmts() : array + { + return [new Node\Stmt\Return_($this->expr)]; + } + public function getType() : string + { + return 'Expr_ArrowFunction'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Assign.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Assign.php new file mode 100644 index 0000000000..5894971875 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Assign.php @@ -0,0 +1,34 @@ +attributes = $attributes; + $this->var = $var; + $this->expr = $expr; + } + public function getSubNodeNames() : array + { + return ['var', 'expr']; + } + public function getType() : string + { + return 'Expr_Assign'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp.php new file mode 100644 index 0000000000..da95d2943f --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->var = $var; + $this->expr = $expr; + } + public function getSubNodeNames() : array + { + return ['var', 'expr']; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php new file mode 100644 index 0000000000..4aef6f1dfc --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php @@ -0,0 +1,13 @@ +attributes = $attributes; + $this->var = $var; + $this->expr = $expr; + } + public function getSubNodeNames() : array + { + return ['var', 'expr']; + } + public function getType() : string + { + return 'Expr_AssignRef'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp.php new file mode 100644 index 0000000000..a40f04f9eb --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp.php @@ -0,0 +1,39 @@ +attributes = $attributes; + $this->left = $left; + $this->right = $right; + } + public function getSubNodeNames() : array + { + return ['left', 'right']; + } + /** + * Get the operator sigil for this binary operation. + * + * In the case there are multiple possible sigils for an operator, this method does not + * necessarily return the one used in the parsed code. + * + * @return string + */ + public abstract function getOperatorSigil() : string; +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php new file mode 100644 index 0000000000..f380e7a3f2 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php @@ -0,0 +1,17 @@ +'; + } + public function getType() : string + { + return 'Expr_BinaryOp_Greater'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php new file mode 100644 index 0000000000..2bad64617d --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php @@ -0,0 +1,17 @@ +='; + } + public function getType() : string + { + return 'Expr_BinaryOp_GreaterOrEqual'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Identical.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Identical.php new file mode 100644 index 0000000000..ba9935b7aa --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Identical.php @@ -0,0 +1,17 @@ +>'; + } + public function getType() : string + { + return 'Expr_BinaryOp_ShiftRight'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Smaller.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Smaller.php new file mode 100644 index 0000000000..84461daea8 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Smaller.php @@ -0,0 +1,17 @@ +'; + } + public function getType() : string + { + return 'Expr_BinaryOp_Spaceship'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BitwiseNot.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BitwiseNot.php new file mode 100644 index 0000000000..dc1fa8ffb1 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BitwiseNot.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() : array + { + return ['expr']; + } + public function getType() : string + { + return 'Expr_BitwiseNot'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BooleanNot.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BooleanNot.php new file mode 100644 index 0000000000..2b1ee8ffdf --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BooleanNot.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() : array + { + return ['expr']; + } + public function getType() : string + { + return 'Expr_BooleanNot'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/CallLike.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/CallLike.php new file mode 100644 index 0000000000..ce3b754059 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/CallLike.php @@ -0,0 +1,40 @@ + + */ + public abstract function getRawArgs() : array; + /** + * Returns whether this call expression is actually a first class callable. + */ + public function isFirstClassCallable() : bool + { + foreach ($this->getRawArgs() as $arg) { + if ($arg instanceof VariadicPlaceholder) { + return \true; + } + } + return \false; + } + /** + * Assert that this is not a first-class callable and return only ordinary Args. + * + * @return Arg[] + */ + public function getArgs() : array + { + \assert(!$this->isFirstClassCallable()); + return $this->getRawArgs(); + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Cast.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Cast.php new file mode 100644 index 0000000000..8c8779b19f --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Cast.php @@ -0,0 +1,26 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() : array + { + return ['expr']; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Array_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Array_.php new file mode 100644 index 0000000000..717b4f3c86 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Array_.php @@ -0,0 +1,13 @@ +attributes = $attributes; + $this->class = $class; + $this->name = \is_string($name) ? new Identifier($name) : $name; + } + public function getSubNodeNames() : array + { + return ['class', 'name']; + } + public function getType() : string + { + return 'Expr_ClassConstFetch'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Clone_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Clone_.php new file mode 100644 index 0000000000..8b8a3f4f5d --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Clone_.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() : array + { + return ['expr']; + } + public function getType() : string + { + return 'Expr_Clone'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Closure.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Closure.php new file mode 100644 index 0000000000..8706256d7c --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Closure.php @@ -0,0 +1,79 @@ + false : Whether the closure is static + * 'byRef' => false : Whether to return by reference + * 'params' => array(): Parameters + * 'uses' => array(): use()s + * 'returnType' => null : Return type + * 'stmts' => array(): Statements + * 'attrGroups' => array(): PHP attributes groups + * @param array $attributes Additional attributes + */ + public function __construct(array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->static = $subNodes['static'] ?? \false; + $this->byRef = $subNodes['byRef'] ?? \false; + $this->params = $subNodes['params'] ?? []; + $this->uses = $subNodes['uses'] ?? []; + $returnType = $subNodes['returnType'] ?? null; + $this->returnType = \is_string($returnType) ? new Node\Identifier($returnType) : $returnType; + $this->stmts = $subNodes['stmts'] ?? []; + $this->attrGroups = $subNodes['attrGroups'] ?? []; + } + public function getSubNodeNames() : array + { + return ['attrGroups', 'static', 'byRef', 'params', 'uses', 'returnType', 'stmts']; + } + public function returnsByRef() : bool + { + return $this->byRef; + } + public function getParams() : array + { + return $this->params; + } + public function getReturnType() + { + return $this->returnType; + } + /** @return Node\Stmt[] */ + public function getStmts() : array + { + return $this->stmts; + } + public function getAttrGroups() : array + { + return $this->attrGroups; + } + public function getType() : string + { + return 'Expr_Closure'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ClosureUse.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ClosureUse.php new file mode 100644 index 0000000000..a9d2197a93 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ClosureUse.php @@ -0,0 +1,34 @@ +attributes = $attributes; + $this->var = $var; + $this->byRef = $byRef; + } + public function getSubNodeNames() : array + { + return ['var', 'byRef']; + } + public function getType() : string + { + return 'Expr_ClosureUse'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ConstFetch.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ConstFetch.php new file mode 100644 index 0000000000..616db2f114 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ConstFetch.php @@ -0,0 +1,31 @@ +attributes = $attributes; + $this->name = $name; + } + public function getSubNodeNames() : array + { + return ['name']; + } + public function getType() : string + { + return 'Expr_ConstFetch'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Empty_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Empty_.php new file mode 100644 index 0000000000..4a10939399 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Empty_.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() : array + { + return ['expr']; + } + public function getType() : string + { + return 'Expr_Empty'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Error.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Error.php new file mode 100644 index 0000000000..e3a2d5423a --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Error.php @@ -0,0 +1,32 @@ +attributes = $attributes; + } + public function getSubNodeNames() : array + { + return []; + } + public function getType() : string + { + return 'Expr_Error'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ErrorSuppress.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ErrorSuppress.php new file mode 100644 index 0000000000..09d24484ab --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ErrorSuppress.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() : array + { + return ['expr']; + } + public function getType() : string + { + return 'Expr_ErrorSuppress'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Eval_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Eval_.php new file mode 100644 index 0000000000..bfc50ff9b9 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Eval_.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() : array + { + return ['expr']; + } + public function getType() : string + { + return 'Expr_Eval'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Exit_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Exit_.php new file mode 100644 index 0000000000..47abbb07ff --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Exit_.php @@ -0,0 +1,33 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() : array + { + return ['expr']; + } + public function getType() : string + { + return 'Expr_Exit'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/FuncCall.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/FuncCall.php new file mode 100644 index 0000000000..831951be72 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/FuncCall.php @@ -0,0 +1,39 @@ + Arguments */ + public $args; + /** + * Constructs a function call node. + * + * @param Node\Name|Expr $name Function name + * @param array $args Arguments + * @param array $attributes Additional attributes + */ + public function __construct($name, array $args = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->name = $name; + $this->args = $args; + } + public function getSubNodeNames() : array + { + return ['name', 'args']; + } + public function getType() : string + { + return 'Expr_FuncCall'; + } + public function getRawArgs() : array + { + return $this->args; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Include_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Include_.php new file mode 100644 index 0000000000..7f78c63b09 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Include_.php @@ -0,0 +1,38 @@ +attributes = $attributes; + $this->expr = $expr; + $this->type = $type; + } + public function getSubNodeNames() : array + { + return ['expr', 'type']; + } + public function getType() : string + { + return 'Expr_Include'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Instanceof_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Instanceof_.php new file mode 100644 index 0000000000..4e9d0fb389 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Instanceof_.php @@ -0,0 +1,35 @@ +attributes = $attributes; + $this->expr = $expr; + $this->class = $class; + } + public function getSubNodeNames() : array + { + return ['expr', 'class']; + } + public function getType() : string + { + return 'Expr_Instanceof'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Isset_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Isset_.php new file mode 100644 index 0000000000..392832f503 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Isset_.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->vars = $vars; + } + public function getSubNodeNames() : array + { + return ['vars']; + } + public function getType() : string + { + return 'Expr_Isset'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/List_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/List_.php new file mode 100644 index 0000000000..6dd61c0e08 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/List_.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->items = $items; + } + public function getSubNodeNames() : array + { + return ['items']; + } + public function getType() : string + { + return 'Expr_List'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Match_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Match_.php new file mode 100644 index 0000000000..ed4cc5bcb7 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Match_.php @@ -0,0 +1,31 @@ +attributes = $attributes; + $this->cond = $cond; + $this->arms = $arms; + } + public function getSubNodeNames() : array + { + return ['cond', 'arms']; + } + public function getType() : string + { + return 'Expr_Match'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/MethodCall.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/MethodCall.php new file mode 100644 index 0000000000..3b914410cc --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/MethodCall.php @@ -0,0 +1,45 @@ + Arguments */ + public $args; + /** + * Constructs a function call node. + * + * @param Expr $var Variable holding object + * @param string|Identifier|Expr $name Method name + * @param array $args Arguments + * @param array $attributes Additional attributes + */ + public function __construct(Expr $var, $name, array $args = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->var = $var; + $this->name = \is_string($name) ? new Identifier($name) : $name; + $this->args = $args; + } + public function getSubNodeNames() : array + { + return ['var', 'name', 'args']; + } + public function getType() : string + { + return 'Expr_MethodCall'; + } + public function getRawArgs() : array + { + return $this->args; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/New_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/New_.php new file mode 100644 index 0000000000..579b8dfe17 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/New_.php @@ -0,0 +1,41 @@ + Arguments */ + public $args; + /** + * Constructs a function call node. + * + * @param Node\Name|Expr|Node\Stmt\Class_ $class Class name (or class node for anonymous classes) + * @param array $args Arguments + * @param array $attributes Additional attributes + */ + public function __construct($class, array $args = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->class = $class; + $this->args = $args; + } + public function getSubNodeNames() : array + { + return ['class', 'args']; + } + public function getType() : string + { + return 'Expr_New'; + } + public function getRawArgs() : array + { + return $this->args; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/NullsafeMethodCall.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/NullsafeMethodCall.php new file mode 100644 index 0000000000..0243331dc8 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/NullsafeMethodCall.php @@ -0,0 +1,45 @@ + Arguments */ + public $args; + /** + * Constructs a nullsafe method call node. + * + * @param Expr $var Variable holding object + * @param string|Identifier|Expr $name Method name + * @param array $args Arguments + * @param array $attributes Additional attributes + */ + public function __construct(Expr $var, $name, array $args = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->var = $var; + $this->name = \is_string($name) ? new Identifier($name) : $name; + $this->args = $args; + } + public function getSubNodeNames() : array + { + return ['var', 'name', 'args']; + } + public function getType() : string + { + return 'Expr_NullsafeMethodCall'; + } + public function getRawArgs() : array + { + return $this->args; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/NullsafePropertyFetch.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/NullsafePropertyFetch.php new file mode 100644 index 0000000000..b9dfe84157 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/NullsafePropertyFetch.php @@ -0,0 +1,35 @@ +attributes = $attributes; + $this->var = $var; + $this->name = \is_string($name) ? new Identifier($name) : $name; + } + public function getSubNodeNames() : array + { + return ['var', 'name']; + } + public function getType() : string + { + return 'Expr_NullsafePropertyFetch'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/PostDec.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/PostDec.php new file mode 100644 index 0000000000..025593b6d2 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/PostDec.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->var = $var; + } + public function getSubNodeNames() : array + { + return ['var']; + } + public function getType() : string + { + return 'Expr_PostDec'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/PostInc.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/PostInc.php new file mode 100644 index 0000000000..f3c0023428 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/PostInc.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->var = $var; + } + public function getSubNodeNames() : array + { + return ['var']; + } + public function getType() : string + { + return 'Expr_PostInc'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/PreDec.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/PreDec.php new file mode 100644 index 0000000000..b2dbd65494 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/PreDec.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->var = $var; + } + public function getSubNodeNames() : array + { + return ['var']; + } + public function getType() : string + { + return 'Expr_PreDec'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/PreInc.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/PreInc.php new file mode 100644 index 0000000000..fa1d1ea9a1 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/PreInc.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->var = $var; + } + public function getSubNodeNames() : array + { + return ['var']; + } + public function getType() : string + { + return 'Expr_PreInc'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Print_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Print_.php new file mode 100644 index 0000000000..66ab2351aa --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Print_.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() : array + { + return ['expr']; + } + public function getType() : string + { + return 'Expr_Print'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/PropertyFetch.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/PropertyFetch.php new file mode 100644 index 0000000000..db0fc9e5c1 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/PropertyFetch.php @@ -0,0 +1,35 @@ +attributes = $attributes; + $this->var = $var; + $this->name = \is_string($name) ? new Identifier($name) : $name; + } + public function getSubNodeNames() : array + { + return ['var', 'name']; + } + public function getType() : string + { + return 'Expr_PropertyFetch'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ShellExec.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ShellExec.php new file mode 100644 index 0000000000..b8c6648c82 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ShellExec.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->parts = $parts; + } + public function getSubNodeNames() : array + { + return ['parts']; + } + public function getType() : string + { + return 'Expr_ShellExec'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/StaticCall.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/StaticCall.php new file mode 100644 index 0000000000..696eaed08f --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/StaticCall.php @@ -0,0 +1,46 @@ + Arguments */ + public $args; + /** + * Constructs a static method call node. + * + * @param Node\Name|Expr $class Class name + * @param string|Identifier|Expr $name Method name + * @param array $args Arguments + * @param array $attributes Additional attributes + */ + public function __construct($class, $name, array $args = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->class = $class; + $this->name = \is_string($name) ? new Identifier($name) : $name; + $this->args = $args; + } + public function getSubNodeNames() : array + { + return ['class', 'name', 'args']; + } + public function getType() : string + { + return 'Expr_StaticCall'; + } + public function getRawArgs() : array + { + return $this->args; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/StaticPropertyFetch.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/StaticPropertyFetch.php new file mode 100644 index 0000000000..8d7f3d12e7 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/StaticPropertyFetch.php @@ -0,0 +1,36 @@ +attributes = $attributes; + $this->class = $class; + $this->name = \is_string($name) ? new VarLikeIdentifier($name) : $name; + } + public function getSubNodeNames() : array + { + return ['class', 'name']; + } + public function getType() : string + { + return 'Expr_StaticPropertyFetch'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Ternary.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Ternary.php new file mode 100644 index 0000000000..3e5b295148 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Ternary.php @@ -0,0 +1,38 @@ +attributes = $attributes; + $this->cond = $cond; + $this->if = $if; + $this->else = $else; + } + public function getSubNodeNames() : array + { + return ['cond', 'if', 'else']; + } + public function getType() : string + { + return 'Expr_Ternary'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Throw_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Throw_.php new file mode 100644 index 0000000000..6cb05b5faa --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Throw_.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() : array + { + return ['expr']; + } + public function getType() : string + { + return 'Expr_Throw'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/UnaryMinus.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/UnaryMinus.php new file mode 100644 index 0000000000..3abb152630 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/UnaryMinus.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() : array + { + return ['expr']; + } + public function getType() : string + { + return 'Expr_UnaryMinus'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/UnaryPlus.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/UnaryPlus.php new file mode 100644 index 0000000000..129325b8d3 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/UnaryPlus.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() : array + { + return ['expr']; + } + public function getType() : string + { + return 'Expr_UnaryPlus'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Variable.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Variable.php new file mode 100644 index 0000000000..7eb4549837 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Variable.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->name = $name; + } + public function getSubNodeNames() : array + { + return ['name']; + } + public function getType() : string + { + return 'Expr_Variable'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/YieldFrom.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/YieldFrom.php new file mode 100644 index 0000000000..c64130fc9c --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/YieldFrom.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() : array + { + return ['expr']; + } + public function getType() : string + { + return 'Expr_YieldFrom'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Yield_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Yield_.php new file mode 100644 index 0000000000..c2681d4132 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Yield_.php @@ -0,0 +1,34 @@ +attributes = $attributes; + $this->key = $key; + $this->value = $value; + } + public function getSubNodeNames() : array + { + return ['key', 'value']; + } + public function getType() : string + { + return 'Expr_Yield'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/FunctionLike.php b/vendor/nikic/php-parser/lib/PhpParser/Node/FunctionLike.php new file mode 100644 index 0000000000..d25c740273 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/FunctionLike.php @@ -0,0 +1,39 @@ + \true, 'parent' => \true, 'static' => \true]; + /** + * Constructs an identifier node. + * + * @param string $name Identifier as string + * @param array $attributes Additional attributes + */ + public function __construct(string $name, array $attributes = []) + { + $this->attributes = $attributes; + $this->name = $name; + } + public function getSubNodeNames() : array + { + return ['name']; + } + /** + * Get identifier as string. + * + * @return string Identifier as string. + */ + public function toString() : string + { + return $this->name; + } + /** + * Get lowercased identifier as string. + * + * @return string Lowercased identifier as string + */ + public function toLowerString() : string + { + return \strtolower($this->name); + } + /** + * Checks whether the identifier is a special class name (self, parent or static). + * + * @return bool Whether identifier is a special class name + */ + public function isSpecialClassName() : bool + { + return isset(self::$specialClassNames[\strtolower($this->name)]); + } + /** + * Get identifier as string. + * + * @return string Identifier as string + */ + public function __toString() : string + { + return $this->name; + } + public function getType() : string + { + return 'Identifier'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/IntersectionType.php b/vendor/nikic/php-parser/lib/PhpParser/Node/IntersectionType.php new file mode 100644 index 0000000000..c3102ef7cf --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/IntersectionType.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->types = $types; + } + public function getSubNodeNames() : array + { + return ['types']; + } + public function getType() : string + { + return 'IntersectionType'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/MatchArm.php b/vendor/nikic/php-parser/lib/PhpParser/Node/MatchArm.php new file mode 100644 index 0000000000..605a6b9080 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/MatchArm.php @@ -0,0 +1,31 @@ +conds = $conds; + $this->body = $body; + $this->attributes = $attributes; + } + public function getSubNodeNames() : array + { + return ['conds', 'body']; + } + public function getType() : string + { + return 'MatchArm'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Name.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Name.php new file mode 100644 index 0000000000..269b580450 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Name.php @@ -0,0 +1,237 @@ + \true, 'parent' => \true, 'static' => \true]; + /** + * Constructs a name node. + * + * @param string|string[]|self $name Name as string, part array or Name instance (copy ctor) + * @param array $attributes Additional attributes + */ + public function __construct($name, array $attributes = []) + { + $this->attributes = $attributes; + $this->parts = self::prepareName($name); + } + public function getSubNodeNames() : array + { + return ['parts']; + } + /** + * Get parts of name (split by the namespace separator). + * + * @return string[] Parts of name + */ + public function getParts() : array + { + return $this->parts; + } + /** + * Gets the first part of the name, i.e. everything before the first namespace separator. + * + * @return string First part of the name + */ + public function getFirst() : string + { + return $this->parts[0]; + } + /** + * Gets the last part of the name, i.e. everything after the last namespace separator. + * + * @return string Last part of the name + */ + public function getLast() : string + { + return $this->parts[\count($this->parts) - 1]; + } + /** + * Checks whether the name is unqualified. (E.g. Name) + * + * @return bool Whether the name is unqualified + */ + public function isUnqualified() : bool + { + return 1 === \count($this->parts); + } + /** + * Checks whether the name is qualified. (E.g. Name\Name) + * + * @return bool Whether the name is qualified + */ + public function isQualified() : bool + { + return 1 < \count($this->parts); + } + /** + * Checks whether the name is fully qualified. (E.g. \Name) + * + * @return bool Whether the name is fully qualified + */ + public function isFullyQualified() : bool + { + return \false; + } + /** + * Checks whether the name is explicitly relative to the current namespace. (E.g. namespace\Name) + * + * @return bool Whether the name is relative + */ + public function isRelative() : bool + { + return \false; + } + /** + * Returns a string representation of the name itself, without taking the name type into + * account (e.g., not including a leading backslash for fully qualified names). + * + * @return string String representation + */ + public function toString() : string + { + return \implode('\\', $this->parts); + } + /** + * Returns a string representation of the name as it would occur in code (e.g., including + * leading backslash for fully qualified names. + * + * @return string String representation + */ + public function toCodeString() : string + { + return $this->toString(); + } + /** + * Returns lowercased string representation of the name, without taking the name type into + * account (e.g., no leading backslash for fully qualified names). + * + * @return string Lowercased string representation + */ + public function toLowerString() : string + { + return \strtolower(\implode('\\', $this->parts)); + } + /** + * Checks whether the identifier is a special class name (self, parent or static). + * + * @return bool Whether identifier is a special class name + */ + public function isSpecialClassName() : bool + { + return \count($this->parts) === 1 && isset(self::$specialClassNames[\strtolower($this->parts[0])]); + } + /** + * Returns a string representation of the name by imploding the namespace parts with the + * namespace separator. + * + * @return string String representation + */ + public function __toString() : string + { + return \implode('\\', $this->parts); + } + /** + * Gets a slice of a name (similar to array_slice). + * + * This method returns a new instance of the same type as the original and with the same + * attributes. + * + * If the slice is empty, null is returned. The null value will be correctly handled in + * concatenations using concat(). + * + * Offset and length have the same meaning as in array_slice(). + * + * @param int $offset Offset to start the slice at (may be negative) + * @param int|null $length Length of the slice (may be negative) + * + * @return static|null Sliced name + */ + public function slice(int $offset, ?int $length = null) + { + $numParts = \count($this->parts); + $realOffset = $offset < 0 ? $offset + $numParts : $offset; + if ($realOffset < 0 || $realOffset > $numParts) { + throw new \OutOfBoundsException(\sprintf('Offset %d is out of bounds', $offset)); + } + if (null === $length) { + $realLength = $numParts - $realOffset; + } else { + $realLength = $length < 0 ? $length + $numParts - $realOffset : $length; + if ($realLength < 0 || $realLength > $numParts - $realOffset) { + throw new \OutOfBoundsException(\sprintf('Length %d is out of bounds', $length)); + } + } + if ($realLength === 0) { + // Empty slice is represented as null + return null; + } + return new static(\array_slice($this->parts, $realOffset, $realLength), $this->attributes); + } + /** + * Concatenate two names, yielding a new Name instance. + * + * The type of the generated instance depends on which class this method is called on, for + * example Name\FullyQualified::concat() will yield a Name\FullyQualified instance. + * + * If one of the arguments is null, a new instance of the other name will be returned. If both + * arguments are null, null will be returned. As such, writing + * Name::concat($namespace, $shortName) + * where $namespace is a Name node or null will work as expected. + * + * @param string|string[]|self|null $name1 The first name + * @param string|string[]|self|null $name2 The second name + * @param array $attributes Attributes to assign to concatenated name + * + * @return static|null Concatenated name + */ + public static function concat($name1, $name2, array $attributes = []) + { + if (null === $name1 && null === $name2) { + return null; + } elseif (null === $name1) { + return new static(self::prepareName($name2), $attributes); + } elseif (null === $name2) { + return new static(self::prepareName($name1), $attributes); + } else { + return new static(\array_merge(self::prepareName($name1), self::prepareName($name2)), $attributes); + } + } + /** + * Prepares a (string, array or Name node) name for use in name changing methods by converting + * it to an array. + * + * @param string|string[]|self $name Name to prepare + * + * @return string[] Prepared name + */ + private static function prepareName($name) : array + { + if (\is_string($name)) { + if ('' === $name) { + throw new \InvalidArgumentException('Name cannot be empty'); + } + return \explode('\\', $name); + } elseif (\is_array($name)) { + if (empty($name)) { + throw new \InvalidArgumentException('Name cannot be empty'); + } + return $name; + } elseif ($name instanceof self) { + return $name->parts; + } + throw new \InvalidArgumentException('Expected string, array of parts or Name instance'); + } + public function getType() : string + { + return 'Name'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Name/FullyQualified.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Name/FullyQualified.php new file mode 100644 index 0000000000..680a0e53eb --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Name/FullyQualified.php @@ -0,0 +1,52 @@ +toString(); + } + public function getType() : string + { + return 'Name_FullyQualified'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Name/Relative.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Name/Relative.php new file mode 100644 index 0000000000..1498f8f65a --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Name/Relative.php @@ -0,0 +1,52 @@ +toString(); + } + public function getType() : string + { + return 'Name_Relative'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/NullableType.php b/vendor/nikic/php-parser/lib/PhpParser/Node/NullableType.php new file mode 100644 index 0000000000..b1b6f702a8 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/NullableType.php @@ -0,0 +1,29 @@ +attributes = $attributes; + $this->type = \is_string($type) ? new Identifier($type) : $type; + } + public function getSubNodeNames() : array + { + return ['type']; + } + public function getType() : string + { + return 'NullableType'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Param.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Param.php new file mode 100644 index 0000000000..e1aedd80c4 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Param.php @@ -0,0 +1,54 @@ +attributes = $attributes; + $this->type = \is_string($type) ? new Identifier($type) : $type; + $this->byRef = $byRef; + $this->variadic = $variadic; + $this->var = $var; + $this->default = $default; + $this->flags = $flags; + $this->attrGroups = $attrGroups; + } + public function getSubNodeNames() : array + { + return ['attrGroups', 'flags', 'type', 'byRef', 'variadic', 'var', 'default']; + } + public function getType() : string + { + return 'Param'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar.php new file mode 100644 index 0000000000..7093227b78 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar.php @@ -0,0 +1,8 @@ +attributes = $attributes; + $this->value = $value; + } + public function getSubNodeNames() : array + { + return ['value']; + } + /** + * @param mixed[] $attributes + */ + public static function fromString(string $str, array $attributes = []) : DNumber + { + $attributes['rawValue'] = $str; + $float = self::parse($str); + return new DNumber($float, $attributes); + } + /** + * @internal + * + * Parses a DNUMBER token like PHP would. + * + * @param string $str A string number + * + * @return float The parsed number + */ + public static function parse(string $str) : float + { + $str = \str_replace('_', '', $str); + // Check whether this is one of the special integer notations. + if ('0' === $str[0]) { + // hex + if ('x' === $str[1] || 'X' === $str[1]) { + return \hexdec($str); + } + // bin + if ('b' === $str[1] || 'B' === $str[1]) { + return \bindec($str); + } + // oct, but only if the string does not contain any of '.eE'. + if (\false === \strpbrk($str, '.eE')) { + // substr($str, 0, strcspn($str, '89')) cuts the string at the first invalid digit + // (8 or 9) so that only the digits before that are used. + return \octdec(\substr($str, 0, \strcspn($str, '89'))); + } + } + // dec + return (float) $str; + } + public function getType() : string + { + return 'Scalar_DNumber'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/Encapsed.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/Encapsed.php new file mode 100644 index 0000000000..78b4bb73d9 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/Encapsed.php @@ -0,0 +1,31 @@ +attributes = $attributes; + $this->parts = $parts; + } + public function getSubNodeNames() : array + { + return ['parts']; + } + public function getType() : string + { + return 'Scalar_Encapsed'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/EncapsedStringPart.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/EncapsedStringPart.php new file mode 100644 index 0000000000..89b83d13b0 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/EncapsedStringPart.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->value = $value; + } + public function getSubNodeNames() : array + { + return ['value']; + } + public function getType() : string + { + return 'Scalar_EncapsedStringPart'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/LNumber.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/LNumber.php new file mode 100644 index 0000000000..5c971f85d4 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/LNumber.php @@ -0,0 +1,72 @@ +attributes = $attributes; + $this->value = $value; + } + public function getSubNodeNames() : array + { + return ['value']; + } + /** + * Constructs an LNumber node from a string number literal. + * + * @param string $str String number literal (decimal, octal, hex or binary) + * @param array $attributes Additional attributes + * @param bool $allowInvalidOctal Whether to allow invalid octal numbers (PHP 5) + * + * @return LNumber The constructed LNumber, including kind attribute + */ + public static function fromString(string $str, array $attributes = [], bool $allowInvalidOctal = \false) : LNumber + { + $attributes['rawValue'] = $str; + $str = \str_replace('_', '', $str); + if ('0' !== $str[0] || '0' === $str) { + $attributes['kind'] = LNumber::KIND_DEC; + return new LNumber((int) $str, $attributes); + } + if ('x' === $str[1] || 'X' === $str[1]) { + $attributes['kind'] = LNumber::KIND_HEX; + return new LNumber(\hexdec($str), $attributes); + } + if ('b' === $str[1] || 'B' === $str[1]) { + $attributes['kind'] = LNumber::KIND_BIN; + return new LNumber(\bindec($str), $attributes); + } + if (!$allowInvalidOctal && \strpbrk($str, '89')) { + throw new Error('Invalid numeric literal', $attributes); + } + // Strip optional explicit octal prefix. + if ('o' === $str[1] || 'O' === $str[1]) { + $str = \substr($str, 2); + } + // use intval instead of octdec to get proper cutting behavior with malformed numbers + $attributes['kind'] = LNumber::KIND_OCT; + return new LNumber(\intval($str, 8), $attributes); + } + public function getType() : string + { + return 'Scalar_LNumber'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst.php new file mode 100644 index 0000000000..8327806366 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst.php @@ -0,0 +1,28 @@ +attributes = $attributes; + } + public function getSubNodeNames() : array + { + return []; + } + /** + * Get name of magic constant. + * + * @return string Name of magic constant + */ + public abstract function getName() : string; +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Class_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Class_.php new file mode 100644 index 0000000000..1f0474b0b1 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Class_.php @@ -0,0 +1,17 @@ + '\\', '$' => '$', 'n' => "\n", 'r' => "\r", 't' => "\t", 'f' => "\f", 'v' => "\v", 'e' => "\x1b"]; + /** + * Constructs a string scalar node. + * + * @param string $value Value of the string + * @param array $attributes Additional attributes + */ + public function __construct(string $value, array $attributes = []) + { + $this->attributes = $attributes; + $this->value = $value; + } + public function getSubNodeNames() : array + { + return ['value']; + } + /** + * @param bool $parseUnicodeEscape Whether to parse PHP 7 \u escapes + */ + public static function fromString(string $str, array $attributes = [], bool $parseUnicodeEscape = \true) : self + { + $attributes['kind'] = $str[0] === "'" || $str[1] === "'" && ($str[0] === 'b' || $str[0] === 'B') ? Scalar\String_::KIND_SINGLE_QUOTED : Scalar\String_::KIND_DOUBLE_QUOTED; + $attributes['rawValue'] = $str; + $string = self::parse($str, $parseUnicodeEscape); + return new self($string, $attributes); + } + /** + * @internal + * + * Parses a string token. + * + * @param string $str String token content + * @param bool $parseUnicodeEscape Whether to parse PHP 7 \u escapes + * + * @return string The parsed string + */ + public static function parse(string $str, bool $parseUnicodeEscape = \true) : string + { + $bLength = 0; + if ('b' === $str[0] || 'B' === $str[0]) { + $bLength = 1; + } + if ('\'' === $str[$bLength]) { + return \str_replace(['\\\\', '\\\''], ['\\', '\''], \substr($str, $bLength + 1, -1)); + } else { + return self::parseEscapeSequences(\substr($str, $bLength + 1, -1), '"', $parseUnicodeEscape); + } + } + /** + * @internal + * + * Parses escape sequences in strings (all string types apart from single quoted). + * + * @param string $str String without quotes + * @param null|string $quote Quote type + * @param bool $parseUnicodeEscape Whether to parse PHP 7 \u escapes + * + * @return string String with escape sequences parsed + */ + public static function parseEscapeSequences(string $str, $quote, bool $parseUnicodeEscape = \true) : string + { + if (null !== $quote) { + $str = \str_replace('\\' . $quote, $quote, $str); + } + $extra = ''; + if ($parseUnicodeEscape) { + $extra = '|u\\{([0-9a-fA-F]+)\\}'; + } + return \preg_replace_callback('~\\\\([\\\\$nrtfve]|[xX][0-9a-fA-F]{1,2}|[0-7]{1,3}' . $extra . ')~', function ($matches) { + $str = $matches[1]; + if (isset(self::$replacements[$str])) { + return self::$replacements[$str]; + } elseif ('x' === $str[0] || 'X' === $str[0]) { + return \chr(\hexdec(\substr($str, 1))); + } elseif ('u' === $str[0]) { + return self::codePointToUtf8(\hexdec($matches[2])); + } else { + return \chr(\octdec($str)); + } + }, $str); + } + /** + * Converts a Unicode code point to its UTF-8 encoded representation. + * + * @param int $num Code point + * + * @return string UTF-8 representation of code point + */ + private static function codePointToUtf8(int $num) : string + { + if ($num <= 0x7f) { + return \chr($num); + } + if ($num <= 0x7ff) { + return \chr(($num >> 6) + 0xc0) . \chr(($num & 0x3f) + 0x80); + } + if ($num <= 0xffff) { + return \chr(($num >> 12) + 0xe0) . \chr(($num >> 6 & 0x3f) + 0x80) . \chr(($num & 0x3f) + 0x80); + } + if ($num <= 0x1fffff) { + return \chr(($num >> 18) + 0xf0) . \chr(($num >> 12 & 0x3f) + 0x80) . \chr(($num >> 6 & 0x3f) + 0x80) . \chr(($num & 0x3f) + 0x80); + } + throw new Error('Invalid UTF-8 codepoint escape sequence: Codepoint too large'); + } + public function getType() : string + { + return 'Scalar_String'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt.php new file mode 100644 index 0000000000..02787de177 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt.php @@ -0,0 +1,9 @@ +attributes = $attributes; + $this->num = $num; + } + public function getSubNodeNames() : array + { + return ['num']; + } + public function getType() : string + { + return 'Stmt_Break'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Case_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Case_.php new file mode 100644 index 0000000000..0d5daad371 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Case_.php @@ -0,0 +1,34 @@ +attributes = $attributes; + $this->cond = $cond; + $this->stmts = $stmts; + } + public function getSubNodeNames() : array + { + return ['cond', 'stmts']; + } + public function getType() : string + { + return 'Stmt_Case'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Catch_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Catch_.php new file mode 100644 index 0000000000..931b1481d7 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Catch_.php @@ -0,0 +1,39 @@ +attributes = $attributes; + $this->types = $types; + $this->var = $var; + $this->stmts = $stmts; + } + public function getSubNodeNames() : array + { + return ['types', 'var', 'stmts']; + } + public function getType() : string + { + return 'Stmt_Catch'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassConst.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassConst.php new file mode 100644 index 0000000000..a07e58d91d --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassConst.php @@ -0,0 +1,78 @@ +attributes = $attributes; + $this->flags = $flags; + $this->consts = $consts; + $this->attrGroups = $attrGroups; + $this->type = \is_string($type) ? new Node\Identifier($type) : $type; + } + public function getSubNodeNames() : array + { + return ['attrGroups', 'flags', 'type', 'consts']; + } + /** + * Whether constant is explicitly or implicitly public. + * + * @return bool + */ + public function isPublic() : bool + { + return ($this->flags & Class_::MODIFIER_PUBLIC) !== 0 || ($this->flags & Class_::VISIBILITY_MODIFIER_MASK) === 0; + } + /** + * Whether constant is protected. + * + * @return bool + */ + public function isProtected() : bool + { + return (bool) ($this->flags & Class_::MODIFIER_PROTECTED); + } + /** + * Whether constant is private. + * + * @return bool + */ + public function isPrivate() : bool + { + return (bool) ($this->flags & Class_::MODIFIER_PRIVATE); + } + /** + * Whether constant is final. + * + * @return bool + */ + public function isFinal() : bool + { + return (bool) ($this->flags & Class_::MODIFIER_FINAL); + } + public function getType() : string + { + return 'Stmt_ClassConst'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassLike.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassLike.php new file mode 100644 index 0000000000..def3f98e80 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassLike.php @@ -0,0 +1,108 @@ +stmts as $stmt) { + if ($stmt instanceof TraitUse) { + $traitUses[] = $stmt; + } + } + return $traitUses; + } + /** + * @return ClassConst[] + */ + public function getConstants() : array + { + $constants = []; + foreach ($this->stmts as $stmt) { + if ($stmt instanceof ClassConst) { + $constants[] = $stmt; + } + } + return $constants; + } + /** + * @return Property[] + */ + public function getProperties() : array + { + $properties = []; + foreach ($this->stmts as $stmt) { + if ($stmt instanceof Property) { + $properties[] = $stmt; + } + } + return $properties; + } + /** + * Gets property with the given name defined directly in this class/interface/trait. + * + * @param string $name Name of the property + * + * @return Property|null Property node or null if the property does not exist + */ + public function getProperty(string $name) + { + foreach ($this->stmts as $stmt) { + if ($stmt instanceof Property) { + foreach ($stmt->props as $prop) { + if ($prop instanceof PropertyProperty && $name === $prop->name->toString()) { + return $stmt; + } + } + } + } + return null; + } + /** + * Gets all methods defined directly in this class/interface/trait + * + * @return ClassMethod[] + */ + public function getMethods() : array + { + $methods = []; + foreach ($this->stmts as $stmt) { + if ($stmt instanceof ClassMethod) { + $methods[] = $stmt; + } + } + return $methods; + } + /** + * Gets method with the given name defined directly in this class/interface/trait. + * + * @param string $name Name of the method (compared case-insensitively) + * + * @return ClassMethod|null Method node or null if the method does not exist + */ + public function getMethod(string $name) + { + $lowerName = \strtolower($name); + foreach ($this->stmts as $stmt) { + if ($stmt instanceof ClassMethod && $lowerName === $stmt->name->toLowerString()) { + return $stmt; + } + } + return null; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassMethod.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassMethod.php new file mode 100644 index 0000000000..7db59e7dcc --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassMethod.php @@ -0,0 +1,141 @@ + \true, '__destruct' => \true, '__call' => \true, '__callstatic' => \true, '__get' => \true, '__set' => \true, '__isset' => \true, '__unset' => \true, '__sleep' => \true, '__wakeup' => \true, '__tostring' => \true, '__set_state' => \true, '__clone' => \true, '__invoke' => \true, '__debuginfo' => \true, '__serialize' => \true, '__unserialize' => \true]; + /** + * Constructs a class method node. + * + * @param string|Node\Identifier $name Name + * @param array $subNodes Array of the following optional subnodes: + * 'flags => MODIFIER_PUBLIC: Flags + * 'byRef' => false : Whether to return by reference + * 'params' => array() : Parameters + * 'returnType' => null : Return type + * 'stmts' => array() : Statements + * 'attrGroups' => array() : PHP attribute groups + * @param array $attributes Additional attributes + */ + public function __construct($name, array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->flags = $subNodes['flags'] ?? $subNodes['type'] ?? 0; + $this->byRef = $subNodes['byRef'] ?? \false; + $this->name = \is_string($name) ? new Node\Identifier($name) : $name; + $this->params = $subNodes['params'] ?? []; + $returnType = $subNodes['returnType'] ?? null; + $this->returnType = \is_string($returnType) ? new Node\Identifier($returnType) : $returnType; + $this->stmts = \array_key_exists('stmts', $subNodes) ? $subNodes['stmts'] : []; + $this->attrGroups = $subNodes['attrGroups'] ?? []; + } + public function getSubNodeNames() : array + { + return ['attrGroups', 'flags', 'byRef', 'name', 'params', 'returnType', 'stmts']; + } + public function returnsByRef() : bool + { + return $this->byRef; + } + public function getParams() : array + { + return $this->params; + } + public function getReturnType() + { + return $this->returnType; + } + public function getStmts() + { + return $this->stmts; + } + public function getAttrGroups() : array + { + return $this->attrGroups; + } + /** + * Whether the method is explicitly or implicitly public. + * + * @return bool + */ + public function isPublic() : bool + { + return ($this->flags & Class_::MODIFIER_PUBLIC) !== 0 || ($this->flags & Class_::VISIBILITY_MODIFIER_MASK) === 0; + } + /** + * Whether the method is protected. + * + * @return bool + */ + public function isProtected() : bool + { + return (bool) ($this->flags & Class_::MODIFIER_PROTECTED); + } + /** + * Whether the method is private. + * + * @return bool + */ + public function isPrivate() : bool + { + return (bool) ($this->flags & Class_::MODIFIER_PRIVATE); + } + /** + * Whether the method is abstract. + * + * @return bool + */ + public function isAbstract() : bool + { + return (bool) ($this->flags & Class_::MODIFIER_ABSTRACT); + } + /** + * Whether the method is final. + * + * @return bool + */ + public function isFinal() : bool + { + return (bool) ($this->flags & Class_::MODIFIER_FINAL); + } + /** + * Whether the method is static. + * + * @return bool + */ + public function isStatic() : bool + { + return (bool) ($this->flags & Class_::MODIFIER_STATIC); + } + /** + * Whether the method is magic. + * + * @return bool + */ + public function isMagic() : bool + { + return isset(self::$magicNames[$this->name->toLowerString()]); + } + public function getType() : string + { + return 'Stmt_ClassMethod'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Class_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Class_.php new file mode 100644 index 0000000000..edfc5c1ccf --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Class_.php @@ -0,0 +1,128 @@ + 0 : Flags + * 'extends' => null : Name of extended class + * 'implements' => array(): Names of implemented interfaces + * 'stmts' => array(): Statements + * 'attrGroups' => array(): PHP attribute groups + * @param array $attributes Additional attributes + */ + public function __construct($name, array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->flags = $subNodes['flags'] ?? $subNodes['type'] ?? 0; + $this->name = \is_string($name) ? new Node\Identifier($name) : $name; + $this->extends = $subNodes['extends'] ?? null; + $this->implements = $subNodes['implements'] ?? []; + $this->stmts = $subNodes['stmts'] ?? []; + $this->attrGroups = $subNodes['attrGroups'] ?? []; + } + public function getSubNodeNames() : array + { + return ['attrGroups', 'flags', 'name', 'extends', 'implements', 'stmts']; + } + /** + * Whether the class is explicitly abstract. + * + * @return bool + */ + public function isAbstract() : bool + { + return (bool) ($this->flags & self::MODIFIER_ABSTRACT); + } + /** + * Whether the class is final. + * + * @return bool + */ + public function isFinal() : bool + { + return (bool) ($this->flags & self::MODIFIER_FINAL); + } + public function isReadonly() : bool + { + return (bool) ($this->flags & self::MODIFIER_READONLY); + } + /** + * Whether the class is anonymous. + * + * @return bool + */ + public function isAnonymous() : bool + { + return null === $this->name; + } + /** + * @internal + */ + public static function verifyClassModifier($a, $b) + { + if ($a & self::MODIFIER_ABSTRACT && $b & self::MODIFIER_ABSTRACT) { + throw new Error('Multiple abstract modifiers are not allowed'); + } + if ($a & self::MODIFIER_FINAL && $b & self::MODIFIER_FINAL) { + throw new Error('Multiple final modifiers are not allowed'); + } + if ($a & self::MODIFIER_READONLY && $b & self::MODIFIER_READONLY) { + throw new Error('Multiple readonly modifiers are not allowed'); + } + if ($a & 48 && $b & 48) { + throw new Error('Cannot use the final modifier on an abstract class'); + } + } + /** + * @internal + */ + public static function verifyModifier($a, $b) + { + if ($a & self::VISIBILITY_MODIFIER_MASK && $b & self::VISIBILITY_MODIFIER_MASK) { + throw new Error('Multiple access type modifiers are not allowed'); + } + if ($a & self::MODIFIER_ABSTRACT && $b & self::MODIFIER_ABSTRACT) { + throw new Error('Multiple abstract modifiers are not allowed'); + } + if ($a & self::MODIFIER_STATIC && $b & self::MODIFIER_STATIC) { + throw new Error('Multiple static modifiers are not allowed'); + } + if ($a & self::MODIFIER_FINAL && $b & self::MODIFIER_FINAL) { + throw new Error('Multiple final modifiers are not allowed'); + } + if ($a & self::MODIFIER_READONLY && $b & self::MODIFIER_READONLY) { + throw new Error('Multiple readonly modifiers are not allowed'); + } + if ($a & 48 && $b & 48) { + throw new Error('Cannot use the final modifier on an abstract class member'); + } + } + public function getType() : string + { + return 'Stmt_Class'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Const_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Const_.php new file mode 100644 index 0000000000..65043f4d4a --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Const_.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->consts = $consts; + } + public function getSubNodeNames() : array + { + return ['consts']; + } + public function getType() : string + { + return 'Stmt_Const'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Continue_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Continue_.php new file mode 100644 index 0000000000..aed952d5ab --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Continue_.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->num = $num; + } + public function getSubNodeNames() : array + { + return ['num']; + } + public function getType() : string + { + return 'Stmt_Continue'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/DeclareDeclare.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/DeclareDeclare.php new file mode 100644 index 0000000000..abffb6e86f --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/DeclareDeclare.php @@ -0,0 +1,34 @@ +value pair node. + * + * @param string|Node\Identifier $key Key + * @param Node\Expr $value Value + * @param array $attributes Additional attributes + */ + public function __construct($key, Node\Expr $value, array $attributes = []) + { + $this->attributes = $attributes; + $this->key = \is_string($key) ? new Node\Identifier($key) : $key; + $this->value = $value; + } + public function getSubNodeNames() : array + { + return ['key', 'value']; + } + public function getType() : string + { + return 'Stmt_DeclareDeclare'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Declare_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Declare_.php new file mode 100644 index 0000000000..a0e99c1817 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Declare_.php @@ -0,0 +1,34 @@ +attributes = $attributes; + $this->declares = $declares; + $this->stmts = $stmts; + } + public function getSubNodeNames() : array + { + return ['declares', 'stmts']; + } + public function getType() : string + { + return 'Stmt_Declare'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Do_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Do_.php new file mode 100644 index 0000000000..90ab28c554 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Do_.php @@ -0,0 +1,34 @@ +attributes = $attributes; + $this->cond = $cond; + $this->stmts = $stmts; + } + public function getSubNodeNames() : array + { + return ['stmts', 'cond']; + } + public function getType() : string + { + return 'Stmt_Do'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Echo_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Echo_.php new file mode 100644 index 0000000000..5cae63e1d2 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Echo_.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->exprs = $exprs; + } + public function getSubNodeNames() : array + { + return ['exprs']; + } + public function getType() : string + { + return 'Stmt_Echo'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/ElseIf_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/ElseIf_.php new file mode 100644 index 0000000000..fe952c79d4 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/ElseIf_.php @@ -0,0 +1,34 @@ +attributes = $attributes; + $this->cond = $cond; + $this->stmts = $stmts; + } + public function getSubNodeNames() : array + { + return ['cond', 'stmts']; + } + public function getType() : string + { + return 'Stmt_ElseIf'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Else_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Else_.php new file mode 100644 index 0000000000..10ec986565 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Else_.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->stmts = $stmts; + } + public function getSubNodeNames() : array + { + return ['stmts']; + } + public function getType() : string + { + return 'Stmt_Else'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/EnumCase.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/EnumCase.php new file mode 100644 index 0000000000..acd62ea4f5 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/EnumCase.php @@ -0,0 +1,37 @@ +name = \is_string($name) ? new Node\Identifier($name) : $name; + $this->expr = $expr; + $this->attrGroups = $attrGroups; + } + public function getSubNodeNames() : array + { + return ['attrGroups', 'name', 'expr']; + } + public function getType() : string + { + return 'Stmt_EnumCase'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Enum_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Enum_.php new file mode 100644 index 0000000000..31c7737c39 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Enum_.php @@ -0,0 +1,39 @@ + null : Scalar type + * 'implements' => array() : Names of implemented interfaces + * 'stmts' => array() : Statements + * 'attrGroups' => array() : PHP attribute groups + * @param array $attributes Additional attributes + */ + public function __construct($name, array $subNodes = [], array $attributes = []) + { + $this->name = \is_string($name) ? new Node\Identifier($name) : $name; + $this->scalarType = $subNodes['scalarType'] ?? null; + $this->implements = $subNodes['implements'] ?? []; + $this->stmts = $subNodes['stmts'] ?? []; + $this->attrGroups = $subNodes['attrGroups'] ?? []; + parent::__construct($attributes); + } + public function getSubNodeNames() : array + { + return ['attrGroups', 'name', 'scalarType', 'implements', 'stmts']; + } + public function getType() : string + { + return 'Stmt_Enum'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Expression.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Expression.php new file mode 100644 index 0000000000..3c63d6d9a1 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Expression.php @@ -0,0 +1,33 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() : array + { + return ['expr']; + } + public function getType() : string + { + return 'Stmt_Expression'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Finally_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Finally_.php new file mode 100644 index 0000000000..3accf6b124 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Finally_.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->stmts = $stmts; + } + public function getSubNodeNames() : array + { + return ['stmts']; + } + public function getType() : string + { + return 'Stmt_Finally'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/For_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/For_.php new file mode 100644 index 0000000000..1572646ade --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/For_.php @@ -0,0 +1,43 @@ + array(): Init expressions + * 'cond' => array(): Loop conditions + * 'loop' => array(): Loop expressions + * 'stmts' => array(): Statements + * @param array $attributes Additional attributes + */ + public function __construct(array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->init = $subNodes['init'] ?? []; + $this->cond = $subNodes['cond'] ?? []; + $this->loop = $subNodes['loop'] ?? []; + $this->stmts = $subNodes['stmts'] ?? []; + } + public function getSubNodeNames() : array + { + return ['init', 'cond', 'loop', 'stmts']; + } + public function getType() : string + { + return 'Stmt_For'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Foreach_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Foreach_.php new file mode 100644 index 0000000000..68f9b41d61 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Foreach_.php @@ -0,0 +1,47 @@ + null : Variable to assign key to + * 'byRef' => false : Whether to assign value by reference + * 'stmts' => array(): Statements + * @param array $attributes Additional attributes + */ + public function __construct(Node\Expr $expr, Node\Expr $valueVar, array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->expr = $expr; + $this->keyVar = $subNodes['keyVar'] ?? null; + $this->byRef = $subNodes['byRef'] ?? \false; + $this->valueVar = $valueVar; + $this->stmts = $subNodes['stmts'] ?? []; + } + public function getSubNodeNames() : array + { + return ['expr', 'keyVar', 'byRef', 'valueVar', 'stmts']; + } + public function getType() : string + { + return 'Stmt_Foreach'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Function_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Function_.php new file mode 100644 index 0000000000..5b581c4f13 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Function_.php @@ -0,0 +1,76 @@ + false : Whether to return by reference + * 'params' => array(): Parameters + * 'returnType' => null : Return type + * 'stmts' => array(): Statements + * 'attrGroups' => array(): PHP attribute groups + * @param array $attributes Additional attributes + */ + public function __construct($name, array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->byRef = $subNodes['byRef'] ?? \false; + $this->name = \is_string($name) ? new Node\Identifier($name) : $name; + $this->params = $subNodes['params'] ?? []; + $returnType = $subNodes['returnType'] ?? null; + $this->returnType = \is_string($returnType) ? new Node\Identifier($returnType) : $returnType; + $this->stmts = $subNodes['stmts'] ?? []; + $this->attrGroups = $subNodes['attrGroups'] ?? []; + } + public function getSubNodeNames() : array + { + return ['attrGroups', 'byRef', 'name', 'params', 'returnType', 'stmts']; + } + public function returnsByRef() : bool + { + return $this->byRef; + } + public function getParams() : array + { + return $this->params; + } + public function getReturnType() + { + return $this->returnType; + } + public function getAttrGroups() : array + { + return $this->attrGroups; + } + /** @return Node\Stmt[] */ + public function getStmts() : array + { + return $this->stmts; + } + public function getType() : string + { + return 'Stmt_Function'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Global_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Global_.php new file mode 100644 index 0000000000..f39625eb8a --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Global_.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->vars = $vars; + } + public function getSubNodeNames() : array + { + return ['vars']; + } + public function getType() : string + { + return 'Stmt_Global'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Goto_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Goto_.php new file mode 100644 index 0000000000..b2bf318e64 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Goto_.php @@ -0,0 +1,31 @@ +attributes = $attributes; + $this->name = \is_string($name) ? new Identifier($name) : $name; + } + public function getSubNodeNames() : array + { + return ['name']; + } + public function getType() : string + { + return 'Stmt_Goto'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/GroupUse.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/GroupUse.php new file mode 100644 index 0000000000..54b3510615 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/GroupUse.php @@ -0,0 +1,39 @@ +attributes = $attributes; + $this->type = $type; + $this->prefix = $prefix; + $this->uses = $uses; + } + public function getSubNodeNames() : array + { + return ['type', 'prefix', 'uses']; + } + public function getType() : string + { + return 'Stmt_GroupUse'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/HaltCompiler.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/HaltCompiler.php new file mode 100644 index 0000000000..7357e30429 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/HaltCompiler.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->remaining = $remaining; + } + public function getSubNodeNames() : array + { + return ['remaining']; + } + public function getType() : string + { + return 'Stmt_HaltCompiler'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/If_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/If_.php new file mode 100644 index 0000000000..e4c22a7a5f --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/If_.php @@ -0,0 +1,43 @@ + array(): Statements + * 'elseifs' => array(): Elseif clauses + * 'else' => null : Else clause + * @param array $attributes Additional attributes + */ + public function __construct(Node\Expr $cond, array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->cond = $cond; + $this->stmts = $subNodes['stmts'] ?? []; + $this->elseifs = $subNodes['elseifs'] ?? []; + $this->else = $subNodes['else'] ?? null; + } + public function getSubNodeNames() : array + { + return ['cond', 'stmts', 'elseifs', 'else']; + } + public function getType() : string + { + return 'Stmt_If'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/InlineHTML.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/InlineHTML.php new file mode 100644 index 0000000000..6750044564 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/InlineHTML.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->value = $value; + } + public function getSubNodeNames() : array + { + return ['value']; + } + public function getType() : string + { + return 'Stmt_InlineHTML'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Interface_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Interface_.php new file mode 100644 index 0000000000..660fc6f31a --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Interface_.php @@ -0,0 +1,37 @@ + array(): Name of extended interfaces + * 'stmts' => array(): Statements + * 'attrGroups' => array(): PHP attribute groups + * @param array $attributes Additional attributes + */ + public function __construct($name, array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->name = \is_string($name) ? new Node\Identifier($name) : $name; + $this->extends = $subNodes['extends'] ?? []; + $this->stmts = $subNodes['stmts'] ?? []; + $this->attrGroups = $subNodes['attrGroups'] ?? []; + } + public function getSubNodeNames() : array + { + return ['attrGroups', 'name', 'extends', 'stmts']; + } + public function getType() : string + { + return 'Stmt_Interface'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Label.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Label.php new file mode 100644 index 0000000000..884ba875bf --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Label.php @@ -0,0 +1,31 @@ +attributes = $attributes; + $this->name = \is_string($name) ? new Identifier($name) : $name; + } + public function getSubNodeNames() : array + { + return ['name']; + } + public function getType() : string + { + return 'Stmt_Label'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Namespace_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Namespace_.php new file mode 100644 index 0000000000..95273a53b9 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Namespace_.php @@ -0,0 +1,37 @@ +attributes = $attributes; + $this->name = $name; + $this->stmts = $stmts; + } + public function getSubNodeNames() : array + { + return ['name', 'stmts']; + } + public function getType() : string + { + return 'Stmt_Namespace'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Nop.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Nop.php new file mode 100644 index 0000000000..c0763b3add --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Nop.php @@ -0,0 +1,18 @@ +attributes = $attributes; + $this->flags = $flags; + $this->props = $props; + $this->type = \is_string($type) ? new Identifier($type) : $type; + $this->attrGroups = $attrGroups; + } + public function getSubNodeNames() : array + { + return ['attrGroups', 'flags', 'type', 'props']; + } + /** + * Whether the property is explicitly or implicitly public. + * + * @return bool + */ + public function isPublic() : bool + { + return ($this->flags & Class_::MODIFIER_PUBLIC) !== 0 || ($this->flags & Class_::VISIBILITY_MODIFIER_MASK) === 0; + } + /** + * Whether the property is protected. + * + * @return bool + */ + public function isProtected() : bool + { + return (bool) ($this->flags & Class_::MODIFIER_PROTECTED); + } + /** + * Whether the property is private. + * + * @return bool + */ + public function isPrivate() : bool + { + return (bool) ($this->flags & Class_::MODIFIER_PRIVATE); + } + /** + * Whether the property is static. + * + * @return bool + */ + public function isStatic() : bool + { + return (bool) ($this->flags & Class_::MODIFIER_STATIC); + } + /** + * Whether the property is readonly. + * + * @return bool + */ + public function isReadonly() : bool + { + return (bool) ($this->flags & Class_::MODIFIER_READONLY); + } + public function getType() : string + { + return 'Stmt_Property'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/PropertyProperty.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/PropertyProperty.php new file mode 100644 index 0000000000..57715d6f0c --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/PropertyProperty.php @@ -0,0 +1,34 @@ +attributes = $attributes; + $this->name = \is_string($name) ? new Node\VarLikeIdentifier($name) : $name; + $this->default = $default; + } + public function getSubNodeNames() : array + { + return ['name', 'default']; + } + public function getType() : string + { + return 'Stmt_PropertyProperty'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Return_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Return_.php new file mode 100644 index 0000000000..60d41cff88 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Return_.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() : array + { + return ['expr']; + } + public function getType() : string + { + return 'Stmt_Return'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/StaticVar.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/StaticVar.php new file mode 100644 index 0000000000..0bbf934cf6 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/StaticVar.php @@ -0,0 +1,35 @@ +attributes = $attributes; + $this->var = $var; + $this->default = $default; + } + public function getSubNodeNames() : array + { + return ['var', 'default']; + } + public function getType() : string + { + return 'Stmt_StaticVar'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Static_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Static_.php new file mode 100644 index 0000000000..c839e03863 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Static_.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->vars = $vars; + } + public function getSubNodeNames() : array + { + return ['vars']; + } + public function getType() : string + { + return 'Stmt_Static'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Switch_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Switch_.php new file mode 100644 index 0000000000..9d22aca9b9 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Switch_.php @@ -0,0 +1,34 @@ +attributes = $attributes; + $this->cond = $cond; + $this->cases = $cases; + } + public function getSubNodeNames() : array + { + return ['cond', 'cases']; + } + public function getType() : string + { + return 'Stmt_Switch'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Throw_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Throw_.php new file mode 100644 index 0000000000..4b77f6616b --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Throw_.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->expr = $expr; + } + public function getSubNodeNames() : array + { + return ['expr']; + } + public function getType() : string + { + return 'Stmt_Throw'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUse.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUse.php new file mode 100644 index 0000000000..44bf0c149a --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUse.php @@ -0,0 +1,34 @@ +attributes = $attributes; + $this->traits = $traits; + $this->adaptations = $adaptations; + } + public function getSubNodeNames() : array + { + return ['traits', 'adaptations']; + } + public function getType() : string + { + return 'Stmt_TraitUse'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation.php new file mode 100644 index 0000000000..8c3bba51e1 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation.php @@ -0,0 +1,13 @@ +attributes = $attributes; + $this->trait = $trait; + $this->method = \is_string($method) ? new Node\Identifier($method) : $method; + $this->newModifier = $newModifier; + $this->newName = \is_string($newName) ? new Node\Identifier($newName) : $newName; + } + public function getSubNodeNames() : array + { + return ['trait', 'method', 'newModifier', 'newName']; + } + public function getType() : string + { + return 'Stmt_TraitUseAdaptation_Alias'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php new file mode 100644 index 0000000000..7d1f78527a --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php @@ -0,0 +1,34 @@ +attributes = $attributes; + $this->trait = $trait; + $this->method = \is_string($method) ? new Node\Identifier($method) : $method; + $this->insteadof = $insteadof; + } + public function getSubNodeNames() : array + { + return ['trait', 'method', 'insteadof']; + } + public function getType() : string + { + return 'Stmt_TraitUseAdaptation_Precedence'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Trait_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Trait_.php new file mode 100644 index 0000000000..fcde95a630 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Trait_.php @@ -0,0 +1,33 @@ + array(): Statements + * 'attrGroups' => array(): PHP attribute groups + * @param array $attributes Additional attributes + */ + public function __construct($name, array $subNodes = [], array $attributes = []) + { + $this->attributes = $attributes; + $this->name = \is_string($name) ? new Node\Identifier($name) : $name; + $this->stmts = $subNodes['stmts'] ?? []; + $this->attrGroups = $subNodes['attrGroups'] ?? []; + } + public function getSubNodeNames() : array + { + return ['attrGroups', 'name', 'stmts']; + } + public function getType() : string + { + return 'Stmt_Trait'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TryCatch.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TryCatch.php new file mode 100644 index 0000000000..cb051d0367 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TryCatch.php @@ -0,0 +1,38 @@ +attributes = $attributes; + $this->stmts = $stmts; + $this->catches = $catches; + $this->finally = $finally; + } + public function getSubNodeNames() : array + { + return ['stmts', 'catches', 'finally']; + } + public function getType() : string + { + return 'Stmt_TryCatch'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Unset_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Unset_.php new file mode 100644 index 0000000000..4e3404364b --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Unset_.php @@ -0,0 +1,30 @@ +attributes = $attributes; + $this->vars = $vars; + } + public function getSubNodeNames() : array + { + return ['vars']; + } + public function getType() : string + { + return 'Stmt_Unset'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/UseUse.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/UseUse.php new file mode 100644 index 0000000000..9fff33a138 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/UseUse.php @@ -0,0 +1,51 @@ +attributes = $attributes; + $this->type = $type; + $this->name = $name; + $this->alias = \is_string($alias) ? new Identifier($alias) : $alias; + } + public function getSubNodeNames() : array + { + return ['type', 'name', 'alias']; + } + /** + * Get alias. If not explicitly given this is the last component of the used name. + * + * @return Identifier + */ + public function getAlias() : Identifier + { + if (null !== $this->alias) { + return $this->alias; + } + return new Identifier($this->name->getLast()); + } + public function getType() : string + { + return 'Stmt_UseUse'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Use_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Use_.php new file mode 100644 index 0000000000..a000e3ea43 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Use_.php @@ -0,0 +1,46 @@ +attributes = $attributes; + $this->type = $type; + $this->uses = $uses; + } + public function getSubNodeNames() : array + { + return ['type', 'uses']; + } + public function getType() : string + { + return 'Stmt_Use'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/While_.php b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/While_.php new file mode 100644 index 0000000000..c002dc34ff --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/While_.php @@ -0,0 +1,34 @@ +attributes = $attributes; + $this->cond = $cond; + $this->stmts = $stmts; + } + public function getSubNodeNames() : array + { + return ['cond', 'stmts']; + } + public function getType() : string + { + return 'Stmt_While'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/UnionType.php b/vendor/nikic/php-parser/lib/PhpParser/Node/UnionType.php new file mode 100644 index 0000000000..bba9cb17b9 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/UnionType.php @@ -0,0 +1,29 @@ +attributes = $attributes; + $this->types = $types; + } + public function getSubNodeNames() : array + { + return ['types']; + } + public function getType() : string + { + return 'UnionType'; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Node/VarLikeIdentifier.php b/vendor/nikic/php-parser/lib/PhpParser/Node/VarLikeIdentifier.php new file mode 100644 index 0000000000..0f81a30266 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Node/VarLikeIdentifier.php @@ -0,0 +1,19 @@ +attributes = $attributes; + } + public function getType() : string + { + return 'VariadicPlaceholder'; + } + public function getSubNodeNames() : array + { + return []; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/NodeAbstract.php b/vendor/nikic/php-parser/lib/PhpParser/NodeAbstract.php new file mode 100644 index 0000000000..5777865a6d --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/NodeAbstract.php @@ -0,0 +1,176 @@ +attributes = $attributes; + } + /** + * Gets line the node started in (alias of getStartLine). + * + * @return int Start line (or -1 if not available) + */ + public function getLine() : int + { + return $this->attributes['startLine'] ?? -1; + } + /** + * Gets line the node started in. + * + * Requires the 'startLine' attribute to be enabled in the lexer (enabled by default). + * + * @return int Start line (or -1 if not available) + */ + public function getStartLine() : int + { + return $this->attributes['startLine'] ?? -1; + } + /** + * Gets the line the node ended in. + * + * Requires the 'endLine' attribute to be enabled in the lexer (enabled by default). + * + * @return int End line (or -1 if not available) + */ + public function getEndLine() : int + { + return $this->attributes['endLine'] ?? -1; + } + /** + * Gets the token offset of the first token that is part of this node. + * + * The offset is an index into the array returned by Lexer::getTokens(). + * + * Requires the 'startTokenPos' attribute to be enabled in the lexer (DISABLED by default). + * + * @return int Token start position (or -1 if not available) + */ + public function getStartTokenPos() : int + { + return $this->attributes['startTokenPos'] ?? -1; + } + /** + * Gets the token offset of the last token that is part of this node. + * + * The offset is an index into the array returned by Lexer::getTokens(). + * + * Requires the 'endTokenPos' attribute to be enabled in the lexer (DISABLED by default). + * + * @return int Token end position (or -1 if not available) + */ + public function getEndTokenPos() : int + { + return $this->attributes['endTokenPos'] ?? -1; + } + /** + * Gets the file offset of the first character that is part of this node. + * + * Requires the 'startFilePos' attribute to be enabled in the lexer (DISABLED by default). + * + * @return int File start position (or -1 if not available) + */ + public function getStartFilePos() : int + { + return $this->attributes['startFilePos'] ?? -1; + } + /** + * Gets the file offset of the last character that is part of this node. + * + * Requires the 'endFilePos' attribute to be enabled in the lexer (DISABLED by default). + * + * @return int File end position (or -1 if not available) + */ + public function getEndFilePos() : int + { + return $this->attributes['endFilePos'] ?? -1; + } + /** + * Gets all comments directly preceding this node. + * + * The comments are also available through the "comments" attribute. + * + * @return Comment[] + */ + public function getComments() : array + { + return $this->attributes['comments'] ?? []; + } + /** + * Gets the doc comment of the node. + * + * @return null|Comment\Doc Doc comment object or null + */ + public function getDocComment() + { + $comments = $this->getComments(); + for ($i = \count($comments) - 1; $i >= 0; $i--) { + $comment = $comments[$i]; + if ($comment instanceof Comment\Doc) { + return $comment; + } + } + return null; + } + /** + * Sets the doc comment of the node. + * + * This will either replace an existing doc comment or add it to the comments array. + * + * @param Comment\Doc $docComment Doc comment to set + */ + public function setDocComment(Comment\Doc $docComment) + { + $comments = $this->getComments(); + for ($i = \count($comments) - 1; $i >= 0; $i--) { + if ($comments[$i] instanceof Comment\Doc) { + // Replace existing doc comment. + $comments[$i] = $docComment; + $this->setAttribute('comments', $comments); + return; + } + } + // Append new doc comment. + $comments[] = $docComment; + $this->setAttribute('comments', $comments); + } + public function setAttribute(string $key, $value) + { + $this->attributes[$key] = $value; + } + public function hasAttribute(string $key) : bool + { + return \array_key_exists($key, $this->attributes); + } + public function getAttribute(string $key, $default = null) + { + if (\array_key_exists($key, $this->attributes)) { + return $this->attributes[$key]; + } + return $default; + } + public function getAttributes() : array + { + return $this->attributes; + } + public function setAttributes(array $attributes) + { + $this->attributes = $attributes; + } + /** + * @return array + */ + public function jsonSerialize() : array + { + return ['nodeType' => $this->getType()] + \get_object_vars($this); + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/NodeDumper.php b/vendor/nikic/php-parser/lib/PhpParser/NodeDumper.php new file mode 100644 index 0000000000..b61daecd7e --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/NodeDumper.php @@ -0,0 +1,181 @@ +dumpComments = !empty($options['dumpComments']); + $this->dumpPositions = !empty($options['dumpPositions']); + } + /** + * Dumps a node or array. + * + * @param array|Node $node Node or array to dump + * @param string|null $code Code corresponding to dumped AST. This only needs to be passed if + * the dumpPositions option is enabled and the dumping of node offsets + * is desired. + * + * @return string Dumped value + */ + public function dump($node, ?string $code = null) : string + { + $this->code = $code; + return $this->dumpRecursive($node); + } + protected function dumpRecursive($node) + { + if ($node instanceof Node) { + $r = $node->getType(); + if ($this->dumpPositions && null !== ($p = $this->dumpPosition($node))) { + $r .= $p; + } + $r .= '('; + foreach ($node->getSubNodeNames() as $key) { + $r .= "\n " . $key . ': '; + $value = $node->{$key}; + if (null === $value) { + $r .= 'null'; + } elseif (\false === $value) { + $r .= 'false'; + } elseif (\true === $value) { + $r .= 'true'; + } elseif (\is_scalar($value)) { + if ('flags' === $key || 'newModifier' === $key) { + $r .= $this->dumpFlags($value); + } elseif ('type' === $key && $node instanceof Include_) { + $r .= $this->dumpIncludeType($value); + } elseif ('type' === $key && ($node instanceof Use_ || $node instanceof UseUse || $node instanceof GroupUse)) { + $r .= $this->dumpUseType($value); + } else { + $r .= $value; + } + } else { + $r .= \str_replace("\n", "\n ", $this->dumpRecursive($value)); + } + } + if ($this->dumpComments && ($comments = $node->getComments())) { + $r .= "\n comments: " . \str_replace("\n", "\n ", $this->dumpRecursive($comments)); + } + } elseif (\is_array($node)) { + $r = 'array('; + foreach ($node as $key => $value) { + $r .= "\n " . $key . ': '; + if (null === $value) { + $r .= 'null'; + } elseif (\false === $value) { + $r .= 'false'; + } elseif (\true === $value) { + $r .= 'true'; + } elseif (\is_scalar($value)) { + $r .= $value; + } else { + $r .= \str_replace("\n", "\n ", $this->dumpRecursive($value)); + } + } + } elseif ($node instanceof Comment) { + return $node->getReformattedText(); + } else { + throw new \InvalidArgumentException('Can only dump nodes and arrays.'); + } + return $r . "\n)"; + } + protected function dumpFlags($flags) + { + $strs = []; + if ($flags & Class_::MODIFIER_PUBLIC) { + $strs[] = 'MODIFIER_PUBLIC'; + } + if ($flags & Class_::MODIFIER_PROTECTED) { + $strs[] = 'MODIFIER_PROTECTED'; + } + if ($flags & Class_::MODIFIER_PRIVATE) { + $strs[] = 'MODIFIER_PRIVATE'; + } + if ($flags & Class_::MODIFIER_ABSTRACT) { + $strs[] = 'MODIFIER_ABSTRACT'; + } + if ($flags & Class_::MODIFIER_STATIC) { + $strs[] = 'MODIFIER_STATIC'; + } + if ($flags & Class_::MODIFIER_FINAL) { + $strs[] = 'MODIFIER_FINAL'; + } + if ($flags & Class_::MODIFIER_READONLY) { + $strs[] = 'MODIFIER_READONLY'; + } + if ($strs) { + return \implode(' | ', $strs) . ' (' . $flags . ')'; + } else { + return $flags; + } + } + protected function dumpIncludeType($type) + { + $map = [Include_::TYPE_INCLUDE => 'TYPE_INCLUDE', Include_::TYPE_INCLUDE_ONCE => 'TYPE_INCLUDE_ONCE', Include_::TYPE_REQUIRE => 'TYPE_REQUIRE', Include_::TYPE_REQUIRE_ONCE => 'TYPE_REQUIRE_ONCE']; + if (!isset($map[$type])) { + return $type; + } + return $map[$type] . ' (' . $type . ')'; + } + protected function dumpUseType($type) + { + $map = [Use_::TYPE_UNKNOWN => 'TYPE_UNKNOWN', Use_::TYPE_NORMAL => 'TYPE_NORMAL', Use_::TYPE_FUNCTION => 'TYPE_FUNCTION', Use_::TYPE_CONSTANT => 'TYPE_CONSTANT']; + if (!isset($map[$type])) { + return $type; + } + return $map[$type] . ' (' . $type . ')'; + } + /** + * Dump node position, if possible. + * + * @param Node $node Node for which to dump position + * + * @return string|null Dump of position, or null if position information not available + */ + protected function dumpPosition(Node $node) + { + if (!$node->hasAttribute('startLine') || !$node->hasAttribute('endLine')) { + return null; + } + $start = $node->getStartLine(); + $end = $node->getEndLine(); + if ($node->hasAttribute('startFilePos') && $node->hasAttribute('endFilePos') && null !== $this->code) { + $start .= ':' . $this->toColumn($this->code, $node->getStartFilePos()); + $end .= ':' . $this->toColumn($this->code, $node->getEndFilePos()); + } + return "[{$start} - {$end}]"; + } + // Copied from Error class + private function toColumn($code, $pos) + { + if ($pos > \strlen($code)) { + throw new \RuntimeException('Invalid position information'); + } + $lineStartPos = \strrpos($code, "\n", $pos - \strlen($code)); + if (\false === $lineStartPos) { + $lineStartPos = -1; + } + return $pos - $lineStartPos; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/NodeFinder.php b/vendor/nikic/php-parser/lib/PhpParser/NodeFinder.php new file mode 100644 index 0000000000..f8d091c3b9 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/NodeFinder.php @@ -0,0 +1,76 @@ +addVisitor($visitor); + $traverser->traverse($nodes); + return $visitor->getFoundNodes(); + } + /** + * Find all nodes that are instances of a certain class. + * + * @param Node|Node[] $nodes Single node or array of nodes to search in + * @param string $class Class name + * + * @return Node[] Found nodes (all instances of $class) + */ + public function findInstanceOf($nodes, string $class) : array + { + return $this->find($nodes, function ($node) use($class) { + return $node instanceof $class; + }); + } + /** + * Find first node satisfying a filter callback. + * + * @param Node|Node[] $nodes Single node or array of nodes to search in + * @param callable $filter Filter callback: function(Node $node) : bool + * + * @return null|Node Found node (or null if none found) + */ + public function findFirst($nodes, callable $filter) + { + if (!\is_array($nodes)) { + $nodes = [$nodes]; + } + $visitor = new FirstFindingVisitor($filter); + $traverser = new NodeTraverser(); + $traverser->addVisitor($visitor); + $traverser->traverse($nodes); + return $visitor->getFoundNode(); + } + /** + * Find first node that is an instance of a certain class. + * + * @param Node|Node[] $nodes Single node or array of nodes to search in + * @param string $class Class name + * + * @return null|Node Found node, which is an instance of $class (or null if none found) + */ + public function findFirstInstanceOf($nodes, string $class) + { + return $this->findFirst($nodes, function ($node) use($class) { + return $node instanceof $class; + }); + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php b/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php new file mode 100644 index 0000000000..9306ff0217 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php @@ -0,0 +1,246 @@ +visitors[] = $visitor; + } + /** + * Removes an added visitor. + * + * @param NodeVisitor $visitor + */ + public function removeVisitor(NodeVisitor $visitor) + { + foreach ($this->visitors as $index => $storedVisitor) { + if ($storedVisitor === $visitor) { + unset($this->visitors[$index]); + break; + } + } + } + /** + * Traverses an array of nodes using the registered visitors. + * + * @param Node[] $nodes Array of nodes + * + * @return Node[] Traversed array of nodes + */ + public function traverse(array $nodes) : array + { + $this->stopTraversal = \false; + foreach ($this->visitors as $visitor) { + if (null !== ($return = $visitor->beforeTraverse($nodes))) { + $nodes = $return; + } + } + $nodes = $this->traverseArray($nodes); + foreach ($this->visitors as $visitor) { + if (null !== ($return = $visitor->afterTraverse($nodes))) { + $nodes = $return; + } + } + return $nodes; + } + /** + * Recursively traverse a node. + * + * @param Node $node Node to traverse. + * + * @return Node Result of traversal (may be original node or new one) + */ + protected function traverseNode(Node $node) : Node + { + foreach ($node->getSubNodeNames() as $name) { + $subNode =& $node->{$name}; + if (\is_array($subNode)) { + $subNode = $this->traverseArray($subNode); + if ($this->stopTraversal) { + break; + } + } elseif ($subNode instanceof Node) { + $traverseChildren = \true; + $breakVisitorIndex = null; + foreach ($this->visitors as $visitorIndex => $visitor) { + $return = $visitor->enterNode($subNode); + if (null !== $return) { + if ($return instanceof Node) { + $this->ensureReplacementReasonable($subNode, $return); + $subNode = $return; + } elseif (self::DONT_TRAVERSE_CHILDREN === $return) { + $traverseChildren = \false; + } elseif (self::DONT_TRAVERSE_CURRENT_AND_CHILDREN === $return) { + $traverseChildren = \false; + $breakVisitorIndex = $visitorIndex; + break; + } elseif (self::STOP_TRAVERSAL === $return) { + $this->stopTraversal = \true; + break 2; + } else { + throw new \LogicException('enterNode() returned invalid value of type ' . \gettype($return)); + } + } + } + if ($traverseChildren) { + $subNode = $this->traverseNode($subNode); + if ($this->stopTraversal) { + break; + } + } + foreach ($this->visitors as $visitorIndex => $visitor) { + $return = $visitor->leaveNode($subNode); + if (null !== $return) { + if ($return instanceof Node) { + $this->ensureReplacementReasonable($subNode, $return); + $subNode = $return; + } elseif (self::STOP_TRAVERSAL === $return) { + $this->stopTraversal = \true; + break 2; + } elseif (\is_array($return)) { + throw new \LogicException('leaveNode() may only return an array ' . 'if the parent structure is an array'); + } else { + throw new \LogicException('leaveNode() returned invalid value of type ' . \gettype($return)); + } + } + if ($breakVisitorIndex === $visitorIndex) { + break; + } + } + } + } + return $node; + } + /** + * Recursively traverse array (usually of nodes). + * + * @param array $nodes Array to traverse + * + * @return array Result of traversal (may be original array or changed one) + */ + protected function traverseArray(array $nodes) : array + { + $doNodes = []; + foreach ($nodes as $i => &$node) { + if ($node instanceof Node) { + $traverseChildren = \true; + $breakVisitorIndex = null; + foreach ($this->visitors as $visitorIndex => $visitor) { + $return = $visitor->enterNode($node); + if (null !== $return) { + if ($return instanceof Node) { + $this->ensureReplacementReasonable($node, $return); + $node = $return; + } elseif (self::DONT_TRAVERSE_CHILDREN === $return) { + $traverseChildren = \false; + } elseif (self::DONT_TRAVERSE_CURRENT_AND_CHILDREN === $return) { + $traverseChildren = \false; + $breakVisitorIndex = $visitorIndex; + break; + } elseif (self::STOP_TRAVERSAL === $return) { + $this->stopTraversal = \true; + break 2; + } else { + throw new \LogicException('enterNode() returned invalid value of type ' . \gettype($return)); + } + } + } + if ($traverseChildren) { + $node = $this->traverseNode($node); + if ($this->stopTraversal) { + break; + } + } + foreach ($this->visitors as $visitorIndex => $visitor) { + $return = $visitor->leaveNode($node); + if (null !== $return) { + if ($return instanceof Node) { + $this->ensureReplacementReasonable($node, $return); + $node = $return; + } elseif (\is_array($return)) { + $doNodes[] = [$i, $return]; + break; + } elseif (self::REMOVE_NODE === $return) { + $doNodes[] = [$i, []]; + break; + } elseif (self::STOP_TRAVERSAL === $return) { + $this->stopTraversal = \true; + break 2; + } elseif (\false === $return) { + throw new \LogicException('bool(false) return from leaveNode() no longer supported. ' . 'Return NodeTraverser::REMOVE_NODE instead'); + } else { + throw new \LogicException('leaveNode() returned invalid value of type ' . \gettype($return)); + } + } + if ($breakVisitorIndex === $visitorIndex) { + break; + } + } + } elseif (\is_array($node)) { + throw new \LogicException('Invalid node structure: Contains nested arrays'); + } + } + if (!empty($doNodes)) { + while (list($i, $replace) = \array_pop($doNodes)) { + \array_splice($nodes, $i, 1, $replace); + } + } + return $nodes; + } + private function ensureReplacementReasonable($old, $new) + { + if ($old instanceof Node\Stmt && $new instanceof Node\Expr) { + throw new \LogicException("Trying to replace statement ({$old->getType()}) " . "with expression ({$new->getType()}). Are you missing a " . "Stmt_Expression wrapper?"); + } + if ($old instanceof Node\Expr && $new instanceof Node\Stmt) { + throw new \LogicException("Trying to replace expression ({$old->getType()}) " . "with statement ({$new->getType()})"); + } + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/NodeTraverserInterface.php b/vendor/nikic/php-parser/lib/PhpParser/NodeTraverserInterface.php new file mode 100644 index 0000000000..6e5c27f9d8 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/NodeTraverserInterface.php @@ -0,0 +1,28 @@ + $node stays as-is + * * NodeTraverser::DONT_TRAVERSE_CHILDREN + * => Children of $node are not traversed. $node stays as-is + * * NodeTraverser::STOP_TRAVERSAL + * => Traversal is aborted. $node stays as-is + * * otherwise + * => $node is set to the return value + * + * @param Node $node Node + * + * @return null|int|Node Replacement node (or special return value) + */ + public function enterNode(Node $node); + /** + * Called when leaving a node. + * + * Return value semantics: + * * null + * => $node stays as-is + * * NodeTraverser::REMOVE_NODE + * => $node is removed from the parent array + * * NodeTraverser::STOP_TRAVERSAL + * => Traversal is aborted. $node stays as-is + * * array (of Nodes) + * => The return value is merged into the parent array (at the position of the $node) + * * otherwise + * => $node is set to the return value + * + * @param Node $node Node + * + * @return null|int|Node|Node[] Replacement node (or special return value) + */ + public function leaveNode(Node $node); + /** + * Called once after traversal. + * + * Return value semantics: + * * null: $nodes stays as-is + * * otherwise: $nodes is set to the return value + * + * @param Node[] $nodes Array of nodes + * + * @return null|Node[] Array of nodes + */ + public function afterTraverse(array $nodes); +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/CloningVisitor.php b/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/CloningVisitor.php new file mode 100644 index 0000000000..850bdaf5fa --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/CloningVisitor.php @@ -0,0 +1,21 @@ +setAttribute('origNode', $origNode); + return $node; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/FindingVisitor.php b/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/FindingVisitor.php new file mode 100644 index 0000000000..ac97da459a --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/FindingVisitor.php @@ -0,0 +1,46 @@ +filterCallback = $filterCallback; + } + /** + * Get found nodes satisfying the filter callback. + * + * Nodes are returned in pre-order. + * + * @return Node[] Found nodes + */ + public function getFoundNodes() : array + { + return $this->foundNodes; + } + public function beforeTraverse(array $nodes) + { + $this->foundNodes = []; + return null; + } + public function enterNode(Node $node) + { + $filterCallback = $this->filterCallback; + if ($filterCallback($node)) { + $this->foundNodes[] = $node; + } + return null; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/FirstFindingVisitor.php b/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/FirstFindingVisitor.php new file mode 100644 index 0000000000..7014c5e6b3 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/FirstFindingVisitor.php @@ -0,0 +1,48 @@ +filterCallback = $filterCallback; + } + /** + * Get found node satisfying the filter callback. + * + * Returns null if no node satisfies the filter callback. + * + * @return null|Node Found node (or null if not found) + */ + public function getFoundNode() + { + return $this->foundNode; + } + public function beforeTraverse(array $nodes) + { + $this->foundNode = null; + return null; + } + public function enterNode(Node $node) + { + $filterCallback = $this->filterCallback; + if ($filterCallback($node)) { + $this->foundNode = $node; + return NodeTraverser::STOP_TRAVERSAL; + } + return null; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/NameResolver.php b/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/NameResolver.php new file mode 100644 index 0000000000..a627eda731 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/NameResolver.php @@ -0,0 +1,237 @@ +nameContext = new NameContext($errorHandler ?? new ErrorHandler\Throwing()); + $this->preserveOriginalNames = $options['preserveOriginalNames'] ?? \false; + $this->replaceNodes = $options['replaceNodes'] ?? \true; + } + /** + * Get name resolution context. + * + * @return NameContext + */ + public function getNameContext() : NameContext + { + return $this->nameContext; + } + public function beforeTraverse(array $nodes) + { + $this->nameContext->startNamespace(); + return null; + } + public function enterNode(Node $node) + { + if ($node instanceof Stmt\Namespace_) { + $this->nameContext->startNamespace($node->name); + } elseif ($node instanceof Stmt\Use_) { + foreach ($node->uses as $use) { + $this->addAlias($use, $node->type, null); + } + } elseif ($node instanceof Stmt\GroupUse) { + foreach ($node->uses as $use) { + $this->addAlias($use, $node->type, $node->prefix); + } + } elseif ($node instanceof Stmt\Class_) { + if (null !== $node->extends) { + $node->extends = $this->resolveClassName($node->extends); + } + foreach ($node->implements as &$interface) { + $interface = $this->resolveClassName($interface); + } + $this->resolveAttrGroups($node); + if (null !== $node->name) { + $this->addNamespacedName($node); + } + } elseif ($node instanceof Stmt\Interface_) { + foreach ($node->extends as &$interface) { + $interface = $this->resolveClassName($interface); + } + $this->resolveAttrGroups($node); + $this->addNamespacedName($node); + } elseif ($node instanceof Stmt\Enum_) { + foreach ($node->implements as &$interface) { + $interface = $this->resolveClassName($interface); + } + $this->resolveAttrGroups($node); + if (null !== $node->name) { + $this->addNamespacedName($node); + } + } elseif ($node instanceof Stmt\Trait_) { + $this->resolveAttrGroups($node); + $this->addNamespacedName($node); + } elseif ($node instanceof Stmt\Function_) { + $this->resolveSignature($node); + $this->resolveAttrGroups($node); + $this->addNamespacedName($node); + } elseif ($node instanceof Stmt\ClassMethod || $node instanceof Expr\Closure || $node instanceof Expr\ArrowFunction) { + $this->resolveSignature($node); + $this->resolveAttrGroups($node); + } elseif ($node instanceof Stmt\Property) { + if (null !== $node->type) { + $node->type = $this->resolveType($node->type); + } + $this->resolveAttrGroups($node); + } elseif ($node instanceof Stmt\Const_) { + foreach ($node->consts as $const) { + $this->addNamespacedName($const); + } + } else { + if ($node instanceof Stmt\ClassConst) { + if (null !== $node->type) { + $node->type = $this->resolveType($node->type); + } + $this->resolveAttrGroups($node); + } else { + if ($node instanceof Stmt\EnumCase) { + $this->resolveAttrGroups($node); + } elseif ($node instanceof Expr\StaticCall || $node instanceof Expr\StaticPropertyFetch || $node instanceof Expr\ClassConstFetch || $node instanceof Expr\New_ || $node instanceof Expr\Instanceof_) { + if ($node->class instanceof Name) { + $node->class = $this->resolveClassName($node->class); + } + } elseif ($node instanceof Stmt\Catch_) { + foreach ($node->types as &$type) { + $type = $this->resolveClassName($type); + } + } elseif ($node instanceof Expr\FuncCall) { + if ($node->name instanceof Name) { + $node->name = $this->resolveName($node->name, Stmt\Use_::TYPE_FUNCTION); + } + } elseif ($node instanceof Expr\ConstFetch) { + $node->name = $this->resolveName($node->name, Stmt\Use_::TYPE_CONSTANT); + } elseif ($node instanceof Stmt\TraitUse) { + foreach ($node->traits as &$trait) { + $trait = $this->resolveClassName($trait); + } + foreach ($node->adaptations as $adaptation) { + if (null !== $adaptation->trait) { + $adaptation->trait = $this->resolveClassName($adaptation->trait); + } + if ($adaptation instanceof Stmt\TraitUseAdaptation\Precedence) { + foreach ($adaptation->insteadof as &$insteadof) { + $insteadof = $this->resolveClassName($insteadof); + } + } + } + } + } + } + return null; + } + private function addAlias(Stmt\UseUse $use, int $type, ?Name $prefix = null) + { + // Add prefix for group uses + $name = $prefix ? Name::concat($prefix, $use->name) : $use->name; + // Type is determined either by individual element or whole use declaration + $type |= $use->type; + $this->nameContext->addAlias($name, (string) $use->getAlias(), $type, $use->getAttributes()); + } + /** @param Stmt\Function_|Stmt\ClassMethod|Expr\Closure $node */ + private function resolveSignature($node) + { + foreach ($node->params as $param) { + $param->type = $this->resolveType($param->type); + $this->resolveAttrGroups($param); + } + $node->returnType = $this->resolveType($node->returnType); + } + private function resolveType($node) + { + if ($node instanceof Name) { + return $this->resolveClassName($node); + } + if ($node instanceof Node\NullableType) { + $node->type = $this->resolveType($node->type); + return $node; + } + if ($node instanceof Node\UnionType || $node instanceof Node\IntersectionType) { + foreach ($node->types as &$type) { + $type = $this->resolveType($type); + } + return $node; + } + return $node; + } + /** + * Resolve name, according to name resolver options. + * + * @param Name $name Function or constant name to resolve + * @param int $type One of Stmt\Use_::TYPE_* + * + * @return Name Resolved name, or original name with attribute + */ + protected function resolveName(Name $name, int $type) : Name + { + if (!$this->replaceNodes) { + $resolvedName = $this->nameContext->getResolvedName($name, $type); + if (null !== $resolvedName) { + $name->setAttribute('resolvedName', $resolvedName); + } else { + $name->setAttribute('namespacedName', FullyQualified::concat($this->nameContext->getNamespace(), $name, $name->getAttributes())); + } + return $name; + } + if ($this->preserveOriginalNames) { + // Save the original name + $originalName = $name; + $name = clone $originalName; + $name->setAttribute('originalName', $originalName); + } + $resolvedName = $this->nameContext->getResolvedName($name, $type); + if (null !== $resolvedName) { + return $resolvedName; + } + // unqualified names inside a namespace cannot be resolved at compile-time + // add the namespaced version of the name as an attribute + $name->setAttribute('namespacedName', FullyQualified::concat($this->nameContext->getNamespace(), $name, $name->getAttributes())); + return $name; + } + protected function resolveClassName(Name $name) + { + return $this->resolveName($name, Stmt\Use_::TYPE_NORMAL); + } + protected function addNamespacedName(Node $node) + { + $node->namespacedName = Name::concat($this->nameContext->getNamespace(), (string) $node->name); + } + protected function resolveAttrGroups(Node $node) + { + foreach ($node->attrGroups as $attrGroup) { + foreach ($attrGroup->attrs as $attr) { + $attr->name = $this->resolveClassName($attr->name); + } + } + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/NodeConnectingVisitor.php b/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/NodeConnectingVisitor.php new file mode 100644 index 0000000000..168055c406 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/NodeConnectingVisitor.php @@ -0,0 +1,48 @@ +$node->getAttribute('parent'), the previous + * node can be accessed through $node->getAttribute('previous'), + * and the next node can be accessed through $node->getAttribute('next'). + */ +final class NodeConnectingVisitor extends NodeVisitorAbstract +{ + /** + * @var Node[] + */ + private $stack = []; + /** + * @var ?Node + */ + private $previous; + public function beforeTraverse(array $nodes) + { + $this->stack = []; + $this->previous = null; + } + public function enterNode(Node $node) + { + if (!empty($this->stack)) { + $node->setAttribute('parent', $this->stack[\count($this->stack) - 1]); + } + if ($this->previous !== null && $this->previous->getAttribute('parent') === $node->getAttribute('parent')) { + $node->setAttribute('previous', $this->previous); + $this->previous->setAttribute('next', $node); + } + $this->stack[] = $node; + } + public function leaveNode(Node $node) + { + $this->previous = $node; + \array_pop($this->stack); + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/ParentConnectingVisitor.php b/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/ParentConnectingVisitor.php new file mode 100644 index 0000000000..f4f69070d3 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/ParentConnectingVisitor.php @@ -0,0 +1,37 @@ +$node->getAttribute('parent'). + */ +final class ParentConnectingVisitor extends NodeVisitorAbstract +{ + /** + * @var Node[] + */ + private $stack = []; + public function beforeTraverse(array $nodes) + { + $this->stack = []; + } + public function enterNode(Node $node) + { + if (!empty($this->stack)) { + $node->setAttribute('parent', $this->stack[count($this->stack) - 1]); + } + $this->stack[] = $node; + } + public function leaveNode(Node $node) + { + array_pop($this->stack); + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/NodeVisitorAbstract.php b/vendor/nikic/php-parser/lib/PhpParser/NodeVisitorAbstract.php new file mode 100644 index 0000000000..552018f8c7 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/NodeVisitorAbstract.php @@ -0,0 +1,27 @@ +parsers = $parsers; + } + public function parse(string $code, ?ErrorHandler $errorHandler = null) + { + if (null === $errorHandler) { + $errorHandler = new ErrorHandler\Throwing(); + } + list($firstStmts, $firstError) = $this->tryParse($this->parsers[0], $errorHandler, $code); + if ($firstError === null) { + return $firstStmts; + } + for ($i = 1, $c = \count($this->parsers); $i < $c; ++$i) { + list($stmts, $error) = $this->tryParse($this->parsers[$i], $errorHandler, $code); + if ($error === null) { + return $stmts; + } + } + throw $firstError; + } + private function tryParse(Parser $parser, ErrorHandler $errorHandler, $code) + { + $stmts = null; + $error = null; + try { + $stmts = $parser->parse($code, $errorHandler); + } catch (Error $error) { + } + return [$stmts, $error]; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Parser/Php5.php b/vendor/nikic/php-parser/lib/PhpParser/Parser/Php5.php new file mode 100644 index 0000000000..63dc8b3acd --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Parser/Php5.php @@ -0,0 +1,1320 @@ +'", "T_IS_GREATER_OR_EQUAL", "T_SL", "T_SR", "'+'", "'-'", "'.'", "'*'", "'/'", "'%'", "'!'", "T_INSTANCEOF", "'~'", "T_INC", "T_DEC", "T_INT_CAST", "T_DOUBLE_CAST", "T_STRING_CAST", "T_ARRAY_CAST", "T_OBJECT_CAST", "T_BOOL_CAST", "T_UNSET_CAST", "'@'", "T_POW", "'['", "T_NEW", "T_CLONE", "T_EXIT", "T_IF", "T_ELSEIF", "T_ELSE", "T_ENDIF", "T_LNUMBER", "T_DNUMBER", "T_STRING", "T_STRING_VARNAME", "T_VARIABLE", "T_NUM_STRING", "T_INLINE_HTML", "T_ENCAPSED_AND_WHITESPACE", "T_CONSTANT_ENCAPSED_STRING", "T_ECHO", "T_DO", "T_WHILE", "T_ENDWHILE", "T_FOR", "T_ENDFOR", "T_FOREACH", "T_ENDFOREACH", "T_DECLARE", "T_ENDDECLARE", "T_AS", "T_SWITCH", "T_MATCH", "T_ENDSWITCH", "T_CASE", "T_DEFAULT", "T_BREAK", "T_CONTINUE", "T_GOTO", "T_FUNCTION", "T_FN", "T_CONST", "T_RETURN", "T_TRY", "T_CATCH", "T_FINALLY", "T_USE", "T_INSTEADOF", "T_GLOBAL", "T_STATIC", "T_ABSTRACT", "T_FINAL", "T_PRIVATE", "T_PROTECTED", "T_PUBLIC", "T_READONLY", "T_VAR", "T_UNSET", "T_ISSET", "T_EMPTY", "T_HALT_COMPILER", "T_CLASS", "T_TRAIT", "T_INTERFACE", "T_EXTENDS", "T_IMPLEMENTS", "T_OBJECT_OPERATOR", "T_LIST", "T_ARRAY", "T_CALLABLE", "T_CLASS_C", "T_TRAIT_C", "T_METHOD_C", "T_FUNC_C", "T_LINE", "T_FILE", "T_START_HEREDOC", "T_END_HEREDOC", "T_DOLLAR_OPEN_CURLY_BRACES", "T_CURLY_OPEN", "T_PAAMAYIM_NEKUDOTAYIM", "T_NAMESPACE", "T_NS_C", "T_DIR", "T_NS_SEPARATOR", "T_ELLIPSIS", "T_NAME_FULLY_QUALIFIED", "T_NAME_QUALIFIED", "T_NAME_RELATIVE", "';'", "'{'", "'}'", "'('", "')'", "'\$'", "'`'", "']'", "'\"'", "T_ENUM", "T_NULLSAFE_OBJECT_OPERATOR", "T_ATTRIBUTE"); + protected $tokenToSymbol = array(0, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 56, 164, 168, 161, 55, 168, 168, 159, 160, 53, 50, 8, 51, 52, 54, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 31, 156, 44, 16, 46, 30, 68, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 70, 168, 163, 36, 168, 162, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 157, 35, 158, 58, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43, 45, 47, 48, 49, 57, 59, 60, 61, 62, 63, 64, 65, 66, 67, 69, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 165, 131, 132, 133, 166, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 167); + protected $action = array(700, 670, 671, 672, 673, 674, 286, 675, 676, 677, 713, 714, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 0, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32767, -32767, -32767, -32767, 245, 246, 242, 243, 244, -32766, -32766, 678, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, 1229, 245, 246, 1230, 679, 680, 681, 682, 683, 684, 685, 899, 900, 747, -32766, -32766, -32766, -32766, -32766, -32766, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 716, 739, 717, 718, 719, 720, 708, 709, 710, 738, 711, 712, 697, 698, 699, 701, 702, 703, 741, 742, 743, 744, 745, 746, 875, 704, 705, 706, 707, 737, 728, 726, 727, 723, 724, 1046, 715, 721, 722, 729, 730, 732, 731, 733, 734, 55, 56, 425, 57, 58, 725, 736, 735, 755, 59, 60, -226, 61, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, 337, -32767, -32767, -32767, -32767, 29, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 620, -32766, -32766, -32766, -32766, 62, 63, 1046, -32766, -32766, -32766, 64, 419, 65, 294, 295, 66, 67, 68, 69, 70, 71, 72, 73, 823, 25, 302, 74, 418, 984, 986, 669, 668, 1100, 1101, 1078, 755, 755, 767, 1220, 768, 470, -32766, -32766, -32766, 341, 749, 824, 54, -32767, -32767, -32767, -32767, 98, 99, 100, 101, 102, 220, 221, 222, 362, 876, -32766, 27, -32766, -32766, -32766, -32766, -32766, 1046, 493, 126, 1080, 1079, 1081, 370, 1068, 930, 207, 478, 479, 952, 953, 954, 951, 950, 949, 128, 480, 481, 803, 1106, 1107, 1108, 1109, 1103, 1104, 319, 32, 297, 10, 211, -515, 1110, 1105, 669, 668, 1080, 1079, 1081, 220, 221, 222, 41, 364, 341, 334, 421, 336, 426, -128, -128, -128, 313, 1046, 469, -4, 824, 54, 812, 770, 207, 40, 21, 427, -128, 471, -128, 472, -128, 473, -128, 1046, 428, 220, 221, 222, -32766, 33, 34, 429, 361, 327, 52, 35, 474, -32766, -32766, -32766, 342, 357, 358, 475, 476, 48, 207, 249, 669, 668, 477, 443, 300, 795, 846, 430, 431, 28, -32766, 814, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32767, -32767, -32767, -32767, -32767, 952, 953, 954, 951, 950, 949, 422, 755, 424, 426, 826, 634, -128, -32766, -32766, 469, 824, 54, 288, 812, 1151, 755, 40, 21, 427, 317, 471, 345, 472, 129, 473, 9, 1186, 428, 769, 360, 324, 905, 33, 34, 429, 361, 1046, 415, 35, 474, 944, 1068, 315, 125, 357, 358, 475, 476, -32766, -32766, -32766, 926, 302, 477, 121, 1068, 759, 846, 430, 431, 669, 668, 423, 755, 1152, 809, 1046, 480, 766, -32766, 805, -32766, -32766, -32766, -32766, -261, 127, 347, 436, 841, 341, 1078, 1200, 426, 446, 826, 634, -4, 807, 469, 824, 54, 436, 812, 341, 755, 40, 21, 427, 444, 471, 130, 472, 1068, 473, 346, 767, 428, 768, -211, -211, -211, 33, 34, 429, 361, 308, 1076, 35, 474, -32766, -32766, -32766, 1046, 357, 358, 475, 476, -32766, -32766, -32766, 906, 120, 477, 539, 1068, 795, 846, 430, 431, 436, -32766, 341, -32766, -32766, -32766, 1046, 480, 810, -32766, 925, -32766, -32766, 754, 1080, 1079, 1081, 49, -32766, -32766, -32766, 749, 751, 426, 1201, 826, 634, -211, 30, 469, 669, 668, 436, 812, 341, 75, 40, 21, 427, -32766, 471, 1064, 472, 124, 473, 669, 668, 428, 212, -210, -210, -210, 33, 34, 429, 361, 51, 1186, 35, 474, 755, -32766, -32766, -32766, 357, 358, 475, 476, 213, 824, 54, 221, 222, 477, 20, 581, 795, 846, 430, 431, 220, 221, 222, 755, 222, 247, 78, 79, 80, 81, 341, 207, 517, 103, 104, 105, 752, 307, 131, 637, 1068, 207, 341, 207, 122, 826, 634, -210, 36, 106, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 1112, 307, 346, 436, 214, 341, 824, 54, 426, 123, 250, 129, 134, 106, 469, -32766, 572, 1112, 812, 245, 246, 40, 21, 427, 251, 471, 252, 472, 341, 473, 453, 22, 428, 207, 899, 900, 638, 33, 34, 429, 824, 54, -86, 35, 474, 220, 221, 222, 314, 357, 358, 100, 101, 102, 239, 240, 241, 645, 477, -230, 458, 589, 135, 374, 596, 597, 207, 760, 640, 648, 642, 941, 654, 929, 662, 822, 133, 307, 837, 426, -32766, 106, 749, 43, 44, 469, 45, 442, 46, 812, 826, 634, 40, 21, 427, 47, 471, 50, 472, 53, 473, 132, 608, 428, 302, 604, -280, -32766, 33, 34, 429, 824, 54, 426, 35, 474, 755, 957, -84, 469, 357, 358, 521, 812, 628, 363, 40, 21, 427, 477, 471, 575, 472, -515, 473, 847, 616, 428, -423, -32766, 11, 646, 33, 34, 429, 824, 54, 445, 35, 474, 462, 285, 578, 1111, 357, 358, 593, 369, 848, 594, 290, 826, 634, 477, 0, 0, 532, 0, 0, 325, 0, 0, 0, 0, 0, 651, 0, 0, 0, 322, 326, 0, 0, 0, 426, 0, 0, 0, 0, 323, 469, 316, 318, -516, 812, 862, 634, 40, 21, 427, 0, 471, 0, 472, 0, 473, 1158, 0, 428, 0, -414, 6, 7, 33, 34, 429, 824, 54, 426, 35, 474, 12, 14, 373, 469, 357, 358, -424, 812, 563, 754, 40, 21, 427, 477, 471, 248, 472, 839, 473, 38, 39, 428, 657, 658, 765, 813, 33, 34, 429, 821, 800, 815, 35, 474, 215, 216, 878, 869, 357, 358, 217, 870, 218, 798, 863, 826, 634, 477, 860, 858, 936, 937, 934, 820, 209, 804, 806, 808, 811, 933, 763, 764, 1100, 1101, 935, 659, 78, 335, 426, 359, 1102, 635, 639, 641, 469, 643, 644, 647, 812, 826, 634, 40, 21, 427, 649, 471, 650, 472, 652, 473, 653, 636, 428, 796, 1226, 1228, 762, 33, 34, 429, 215, 216, 845, 35, 474, 761, 217, 844, 218, 357, 358, 1227, 843, 1060, 831, 1048, 842, 1049, 477, 559, 209, 1106, 1107, 1108, 1109, 1103, 1104, 398, 1100, 1101, 829, 942, 867, 1110, 1105, 868, 1102, 457, 1225, 1194, 1192, 1177, 1157, 219, 1190, 1091, 917, 1198, 1188, 0, 826, 634, 24, -433, 26, 31, 37, 42, 76, 77, 210, 287, 292, 293, 308, 309, 310, 311, 339, 356, 416, 0, -227, -226, 16, 17, 18, 393, 454, 461, 463, 467, 553, 625, 1051, 559, 1054, 1106, 1107, 1108, 1109, 1103, 1104, 398, 907, 1116, 1050, 1026, 564, 1110, 1105, 1025, 1093, 1055, 0, 1044, 0, 1057, 1056, 219, 1059, 1058, 1075, 0, 1191, 1176, 1172, 1189, 1090, 1223, 1117, 1171, 600); + protected $actionCheck = array(2, 3, 4, 5, 6, 7, 14, 9, 10, 11, 12, 13, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 0, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 9, 10, 11, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 69, 70, 53, 54, 55, 9, 10, 57, 30, 116, 32, 33, 34, 35, 36, 37, 38, 80, 69, 70, 83, 71, 72, 73, 74, 75, 76, 77, 135, 136, 80, 33, 34, 35, 36, 37, 38, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 31, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 13, 134, 135, 136, 137, 138, 139, 140, 141, 142, 3, 4, 5, 6, 7, 148, 149, 150, 82, 12, 13, 160, 15, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 8, 44, 45, 46, 47, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 80, 33, 34, 35, 36, 50, 51, 13, 9, 10, 11, 56, 128, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 1, 70, 71, 72, 73, 59, 60, 37, 38, 78, 79, 80, 82, 82, 106, 85, 108, 86, 9, 10, 11, 161, 80, 1, 2, 44, 45, 46, 47, 48, 49, 50, 51, 52, 9, 10, 11, 106, 156, 30, 8, 32, 33, 34, 35, 36, 13, 116, 8, 153, 154, 155, 8, 122, 158, 30, 125, 126, 116, 117, 118, 119, 120, 121, 31, 134, 135, 156, 137, 138, 139, 140, 141, 142, 143, 145, 146, 8, 8, 133, 149, 150, 37, 38, 153, 154, 155, 9, 10, 11, 159, 8, 161, 162, 8, 164, 74, 75, 76, 77, 8, 13, 80, 0, 1, 2, 84, 158, 30, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 13, 98, 9, 10, 11, 9, 103, 104, 105, 106, 8, 70, 109, 110, 9, 10, 11, 8, 115, 116, 117, 118, 70, 30, 31, 37, 38, 124, 31, 8, 127, 128, 129, 130, 8, 30, 156, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 116, 117, 118, 119, 120, 121, 8, 82, 8, 74, 156, 157, 158, 33, 34, 80, 1, 2, 8, 84, 163, 82, 87, 88, 89, 133, 91, 70, 93, 152, 95, 108, 82, 98, 158, 8, 113, 160, 103, 104, 105, 106, 13, 108, 109, 110, 123, 122, 113, 157, 115, 116, 117, 118, 9, 10, 11, 156, 71, 124, 157, 122, 127, 128, 129, 130, 37, 38, 8, 82, 160, 156, 13, 134, 156, 30, 156, 32, 33, 34, 35, 158, 157, 148, 159, 122, 161, 80, 1, 74, 133, 156, 157, 158, 156, 80, 1, 2, 159, 84, 161, 82, 87, 88, 89, 157, 91, 157, 93, 122, 95, 161, 106, 98, 108, 100, 101, 102, 103, 104, 105, 106, 159, 116, 109, 110, 9, 10, 11, 13, 115, 116, 117, 118, 9, 10, 11, 160, 16, 124, 81, 122, 127, 128, 129, 130, 159, 30, 161, 32, 33, 34, 13, 134, 156, 30, 156, 32, 33, 153, 153, 154, 155, 70, 9, 10, 11, 80, 80, 74, 160, 156, 157, 158, 14, 80, 37, 38, 159, 84, 161, 152, 87, 88, 89, 30, 91, 160, 93, 14, 95, 37, 38, 98, 16, 100, 101, 102, 103, 104, 105, 106, 70, 82, 109, 110, 82, 33, 34, 35, 115, 116, 117, 118, 16, 1, 2, 10, 11, 124, 160, 85, 127, 128, 129, 130, 9, 10, 11, 82, 11, 14, 157, 9, 10, 11, 161, 30, 85, 53, 54, 55, 154, 57, 157, 31, 122, 30, 161, 30, 157, 156, 157, 158, 30, 69, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 144, 57, 161, 159, 16, 161, 1, 2, 74, 157, 16, 152, 157, 69, 80, 116, 161, 144, 84, 69, 70, 87, 88, 89, 16, 91, 16, 93, 161, 95, 75, 76, 98, 30, 135, 136, 31, 103, 104, 105, 1, 2, 31, 109, 110, 9, 10, 11, 31, 115, 116, 50, 51, 52, 50, 51, 52, 31, 124, 160, 75, 76, 101, 102, 111, 112, 30, 156, 157, 31, 31, 156, 157, 156, 157, 31, 31, 57, 38, 74, 33, 69, 80, 70, 70, 80, 70, 89, 70, 84, 156, 157, 87, 88, 89, 70, 91, 70, 93, 70, 95, 70, 96, 98, 71, 77, 82, 85, 103, 104, 105, 1, 2, 74, 109, 110, 82, 82, 97, 80, 115, 116, 85, 84, 92, 106, 87, 88, 89, 124, 91, 90, 93, 133, 95, 128, 94, 98, 147, 116, 97, 31, 103, 104, 105, 1, 2, 97, 109, 110, 97, 97, 100, 144, 115, 116, 100, 106, 128, 113, 161, 156, 157, 124, -1, -1, 151, -1, -1, 114, -1, -1, -1, -1, -1, 31, -1, -1, -1, 131, 131, -1, -1, -1, 74, -1, -1, -1, -1, 132, 80, 133, 133, 133, 84, 156, 157, 87, 88, 89, -1, 91, -1, 93, -1, 95, 144, -1, 98, -1, 147, 147, 147, 103, 104, 105, 1, 2, 74, 109, 110, 147, 147, 147, 80, 115, 116, 147, 84, 151, 153, 87, 88, 89, 124, 91, 31, 93, 152, 95, 156, 156, 98, 156, 156, 156, 156, 103, 104, 105, 156, 156, 156, 109, 110, 50, 51, 156, 156, 115, 116, 56, 156, 58, 156, 156, 156, 157, 124, 156, 156, 156, 156, 156, 156, 70, 156, 156, 156, 156, 156, 156, 156, 78, 79, 156, 158, 157, 157, 74, 157, 86, 157, 157, 157, 80, 157, 157, 157, 84, 156, 157, 87, 88, 89, 157, 91, 157, 93, 157, 95, 157, 157, 98, 158, 158, 158, 158, 103, 104, 105, 50, 51, 158, 109, 110, 158, 56, 158, 58, 115, 116, 158, 158, 158, 158, 158, 158, 158, 124, 135, 70, 137, 138, 139, 140, 141, 142, 143, 78, 79, 158, 158, 158, 149, 150, 158, 86, 158, 158, 158, 158, 158, 164, 159, 158, 158, 158, 158, 158, -1, 156, 157, 159, 162, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, -1, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 135, 160, 137, 138, 139, 140, 141, 142, 143, 160, 160, 160, 160, 160, 149, 150, 160, 160, 163, -1, 162, -1, 163, 163, 159, 163, 163, 163, -1, 163, 163, 163, 163, 163, 163, 163, 163, 163); + protected $actionBase = array(0, 229, 310, 390, 470, 103, 325, 325, 784, -2, -2, 149, -2, -2, -2, 660, 765, 799, 765, 589, 694, 870, 870, 870, 252, 404, 404, 404, 514, 177, 177, 918, 434, 118, 295, 313, 240, 491, 491, 491, 491, 138, 138, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 491, 89, 206, 773, 550, 535, 775, 776, 777, 912, 709, 913, 856, 857, 700, 858, 859, 862, 863, 864, 855, 865, 935, 866, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 322, 592, 285, 319, 232, 44, 691, 691, 691, 691, 691, 691, 691, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 582, 530, 530, 530, 594, 860, 658, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 926, 500, -21, -21, 492, 702, 420, 355, 216, 549, 151, 26, 26, 331, 331, 331, 331, 331, 46, 46, 5, 5, 5, 5, 153, 188, 188, 188, 188, 121, 121, 121, 121, 314, 314, 394, 394, 362, 300, 298, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 67, 656, 656, 659, 659, 522, 554, 554, 554, 554, 679, -59, -59, 381, 462, 462, 462, 528, 717, 854, 382, 382, 382, 382, 382, 382, 561, 561, 561, -3, -3, -3, 692, 115, 137, 115, 137, 678, 732, 450, 732, 338, 677, -15, 510, 810, 468, 707, 850, 711, 853, 572, 735, 267, 529, 654, 674, 463, 529, 529, 529, 529, 654, 610, 640, 608, 463, 529, 463, 718, 323, 496, 89, 570, 507, 675, 778, 293, 670, 780, 290, 373, 332, 566, 278, 435, 733, 781, 914, 917, 385, 715, 675, 675, 675, 352, 511, 278, -8, 605, 605, 605, 605, 156, 605, 605, 605, 605, 251, 276, 375, 402, 779, 657, 657, 690, 872, 869, 869, 657, 689, 657, 690, 874, 874, 874, 874, 657, 657, 657, 657, 869, 869, 869, 688, 869, 239, 703, 704, 704, 874, 742, 743, 657, 657, 712, 869, 869, 869, 712, 695, 874, 701, 741, 277, 869, 874, 672, 689, 672, 657, 701, 672, 689, 689, 672, 22, 666, 668, 873, 875, 887, 790, 662, 685, 879, 880, 876, 878, 871, 699, 744, 745, 497, 669, 671, 673, 680, 719, 682, 713, 674, 667, 667, 667, 655, 720, 655, 667, 667, 667, 667, 667, 667, 667, 667, 916, 646, 731, 714, 653, 749, 553, 573, 791, 664, 811, 900, 893, 867, 919, 881, 898, 655, 920, 739, 247, 643, 882, 783, 786, 655, 883, 655, 792, 655, 902, 812, 686, 813, 814, 667, 910, 921, 923, 924, 925, 927, 928, 929, 930, 684, 931, 750, 696, 894, 299, 877, 718, 729, 705, 788, 751, 820, 328, 932, 823, 655, 655, 794, 785, 655, 795, 756, 740, 890, 757, 895, 933, 664, 708, 896, 655, 706, 825, 934, 328, 681, 683, 888, 661, 761, 886, 911, 885, 796, 649, 663, 829, 830, 831, 693, 763, 891, 892, 889, 764, 803, 665, 805, 697, 832, 807, 884, 768, 833, 834, 899, 676, 730, 710, 698, 687, 809, 835, 897, 769, 770, 771, 848, 772, 849, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, 138, 138, 138, -2, -2, -2, -2, 0, 0, -2, 0, 0, 0, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 0, 0, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 599, -21, -21, -21, -21, 599, -21, -21, -21, -21, -21, -21, -21, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, -21, 599, 599, 599, -21, 382, -21, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 599, 0, 0, 599, -21, 599, -21, 599, -21, -21, 599, 599, 599, 599, 599, 599, 599, -21, -21, -21, -21, -21, -21, 0, 561, 561, 561, 561, -21, -21, -21, -21, 382, 382, 382, 382, 382, 382, 259, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 561, 561, -3, -3, 382, 382, 382, 382, 382, 259, 382, 382, 463, 689, 689, 689, 137, 137, 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 137, 463, 0, 463, 0, 382, 463, 689, 463, 657, 137, 689, 689, 463, 869, 616, 616, 616, 616, 328, 278, 0, 0, 689, 689, 0, 0, 0, 0, 0, 689, 0, 0, 0, 0, 0, 0, 869, 0, 0, 0, 0, 0, 667, 247, 0, 705, 335, 0, 0, 0, 0, 0, 0, 705, 335, 347, 347, 0, 684, 667, 667, 667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 328); + protected $actionDefault = array(3, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 544, 544, 499, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 299, 299, 299, 32767, 32767, 32767, 532, 532, 532, 532, 532, 532, 532, 532, 532, 532, 532, 32767, 32767, 32767, 32767, 32767, 32767, 383, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 389, 549, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 364, 365, 367, 368, 298, 552, 533, 247, 390, 548, 297, 249, 327, 503, 32767, 32767, 32767, 329, 122, 258, 203, 502, 125, 296, 234, 382, 384, 328, 303, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 302, 458, 361, 360, 359, 460, 32767, 459, 496, 496, 499, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 325, 487, 486, 326, 456, 330, 457, 333, 461, 464, 331, 332, 349, 350, 347, 348, 351, 462, 463, 480, 481, 478, 479, 301, 352, 353, 354, 355, 482, 483, 484, 485, 32767, 32767, 543, 543, 32767, 32767, 282, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 340, 341, 471, 472, 32767, 238, 238, 238, 238, 283, 238, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 335, 336, 334, 466, 467, 465, 432, 32767, 32767, 32767, 434, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 504, 32767, 32767, 32767, 32767, 32767, 517, 421, 171, 32767, 413, 32767, 171, 171, 171, 171, 32767, 222, 224, 167, 32767, 171, 32767, 490, 32767, 32767, 32767, 32767, 522, 345, 32767, 32767, 116, 32767, 32767, 32767, 559, 32767, 517, 32767, 116, 32767, 32767, 32767, 32767, 358, 337, 338, 339, 32767, 32767, 521, 515, 474, 475, 476, 477, 32767, 468, 469, 470, 473, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 429, 435, 435, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 520, 519, 32767, 414, 498, 188, 186, 186, 32767, 208, 208, 32767, 32767, 190, 491, 510, 32767, 190, 173, 32767, 400, 175, 498, 32767, 32767, 240, 32767, 240, 32767, 400, 240, 32767, 32767, 240, 32767, 415, 439, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 379, 380, 493, 506, 32767, 507, 32767, 413, 343, 344, 346, 322, 32767, 324, 369, 370, 371, 372, 373, 374, 375, 377, 32767, 419, 32767, 422, 32767, 32767, 32767, 257, 32767, 557, 32767, 32767, 306, 557, 32767, 32767, 32767, 551, 32767, 32767, 300, 32767, 32767, 32767, 32767, 253, 32767, 169, 32767, 541, 32767, 558, 32767, 515, 32767, 342, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 516, 32767, 32767, 32767, 32767, 229, 32767, 452, 32767, 116, 32767, 32767, 32767, 189, 32767, 32767, 304, 248, 32767, 32767, 550, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 114, 32767, 170, 32767, 32767, 32767, 191, 32767, 32767, 515, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 295, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 515, 32767, 32767, 233, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 415, 32767, 276, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 127, 127, 3, 127, 127, 260, 3, 260, 127, 260, 260, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 216, 219, 208, 208, 164, 127, 127, 268); + protected $goto = array(166, 140, 140, 140, 166, 187, 168, 144, 147, 141, 142, 143, 149, 163, 163, 163, 163, 144, 144, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 138, 159, 160, 161, 162, 184, 139, 185, 494, 495, 377, 496, 500, 501, 502, 503, 504, 505, 506, 507, 970, 164, 145, 146, 148, 171, 176, 186, 203, 253, 256, 258, 260, 263, 264, 265, 266, 267, 268, 269, 277, 278, 279, 280, 303, 304, 328, 329, 330, 394, 395, 396, 543, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 150, 151, 152, 167, 153, 169, 154, 204, 170, 155, 156, 157, 205, 158, 136, 621, 561, 757, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 1113, 629, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 758, 520, 531, 509, 656, 556, 1183, 750, 509, 592, 786, 1183, 888, 612, 613, 884, 617, 618, 624, 626, 631, 633, 817, 855, 855, 855, 855, 850, 856, 174, 891, 891, 1205, 1205, 177, 178, 179, 401, 402, 403, 404, 173, 202, 206, 208, 257, 259, 261, 262, 270, 271, 272, 273, 274, 275, 281, 282, 283, 284, 305, 306, 331, 332, 333, 406, 407, 408, 409, 175, 180, 254, 255, 181, 182, 183, 498, 498, 498, 498, 498, 498, 861, 498, 498, 498, 498, 498, 498, 498, 498, 498, 498, 510, 586, 538, 601, 602, 510, 545, 546, 547, 548, 549, 550, 551, 552, 554, 587, 1209, 560, 350, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 560, 400, 607, 537, 537, 569, 533, 909, 535, 535, 497, 499, 525, 541, 570, 573, 584, 591, 298, 296, 296, 296, 298, 289, 299, 611, 378, 511, 614, 595, 947, 375, 511, 437, 437, 437, 437, 437, 437, 1163, 437, 437, 437, 437, 437, 437, 437, 437, 437, 437, 1077, 948, 338, 1175, 321, 1077, 898, 898, 898, 898, 606, 898, 898, 1217, 1217, 1202, 753, 576, 605, 756, 1077, 1077, 1077, 1077, 1077, 1077, 1069, 384, 384, 384, 391, 1217, 877, 859, 857, 859, 655, 466, 512, 886, 881, 753, 384, 753, 384, 968, 384, 895, 385, 588, 353, 414, 384, 1231, 1019, 542, 1197, 1197, 1197, 568, 1094, 386, 386, 386, 904, 915, 515, 1029, 19, 15, 372, 389, 915, 940, 448, 450, 632, 340, 1216, 1216, 1114, 615, 938, 840, 555, 775, 386, 913, 1070, 1073, 1074, 399, 1069, 1182, 660, 23, 1216, 773, 1182, 544, 603, 1066, 1219, 1071, 1174, 1071, 519, 1199, 1199, 1199, 1089, 1088, 1072, 343, 523, 534, 519, 519, 772, 351, 352, 13, 579, 583, 627, 1061, 388, 782, 562, 771, 515, 783, 1181, 3, 4, 918, 956, 865, 451, 574, 1160, 464, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 514, 529, 0, 0, 0, 0, 514, 0, 529, 0, 0, 0, 0, 610, 513, 516, 439, 440, 1067, 619, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 780, 1224, 0, 0, 0, 0, 0, 524, 0, 0, 0, 0, 0, 0, 0, 0, 0, 778, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 301, 301); + protected $gotoCheck = array(43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 57, 69, 15, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 128, 9, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 16, 102, 32, 69, 32, 32, 120, 6, 69, 32, 29, 120, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 50, 69, 69, 69, 69, 69, 69, 27, 77, 77, 77, 77, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 119, 119, 119, 119, 119, 119, 33, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 67, 110, 67, 67, 119, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 142, 57, 72, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 51, 51, 51, 51, 51, 51, 84, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 5, 5, 5, 5, 5, 5, 5, 63, 46, 124, 63, 129, 98, 63, 124, 57, 57, 57, 57, 57, 57, 133, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 98, 127, 82, 127, 57, 57, 57, 57, 57, 49, 57, 57, 144, 144, 140, 11, 40, 40, 14, 57, 57, 57, 57, 57, 57, 82, 13, 13, 13, 48, 144, 14, 14, 14, 14, 14, 57, 14, 14, 14, 11, 13, 11, 13, 102, 13, 79, 11, 70, 70, 70, 13, 13, 103, 2, 9, 9, 9, 2, 34, 125, 125, 125, 81, 13, 13, 34, 34, 34, 34, 17, 13, 8, 8, 8, 8, 18, 143, 143, 8, 8, 8, 9, 34, 25, 125, 85, 82, 82, 82, 125, 82, 121, 74, 34, 143, 24, 121, 47, 34, 116, 143, 82, 82, 82, 47, 121, 121, 121, 126, 126, 82, 58, 58, 58, 47, 47, 23, 72, 72, 58, 62, 62, 62, 114, 12, 23, 12, 23, 13, 26, 121, 30, 30, 86, 100, 71, 65, 66, 132, 109, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 9, 9, -1, -1, -1, -1, 9, -1, 9, -1, -1, -1, -1, 13, 9, 9, 9, 9, 13, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 9, 9, -1, -1, -1, -1, -1, 102, -1, -1, -1, -1, -1, -1, -1, -1, -1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 5); + protected $gotoBase = array(0, 0, -172, 0, 0, 353, 201, 0, 477, 149, 0, 110, 195, 117, 426, 112, 203, 140, 171, 0, 0, 0, 0, 168, 164, 157, 119, 27, 0, 205, -118, 0, -428, 266, 51, 0, 0, 0, 0, 0, 388, 0, 0, -24, 0, 0, 345, 484, 146, 133, 209, 75, 0, 0, 0, 0, 0, 107, 161, 0, 0, 0, 222, -77, 0, 106, 97, -343, 0, -94, 135, 123, -129, 0, 129, 0, 0, -50, 0, 143, 0, 159, 64, 0, 338, 132, 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, 0, 121, 0, 165, 156, 0, 0, 0, 0, 0, 87, 273, 259, 0, 0, 114, 0, 150, 0, 0, -5, -91, 200, 0, 0, 84, 154, 202, 77, -48, 178, 0, 0, 93, 187, 0, 0, 0, 0, 0, 0, 136, 0, 286, 167, 102, 0, 0); + protected $gotoDefault = array(-32768, 468, 664, 2, 665, 835, 740, 748, 598, 482, 630, 582, 380, 1193, 792, 793, 794, 381, 368, 483, 379, 410, 405, 781, 774, 776, 784, 172, 411, 787, 1, 789, 518, 825, 1020, 365, 797, 366, 590, 799, 527, 801, 802, 137, 382, 383, 528, 484, 390, 577, 816, 276, 387, 818, 367, 819, 828, 371, 465, 455, 460, 530, 557, 609, 432, 447, 571, 565, 536, 1086, 566, 864, 349, 872, 661, 880, 883, 485, 558, 894, 452, 902, 1099, 397, 908, 914, 919, 291, 922, 417, 412, 585, 927, 928, 5, 932, 622, 623, 8, 312, 955, 599, 969, 420, 1039, 1041, 486, 487, 522, 459, 508, 526, 488, 1062, 441, 413, 1065, 433, 489, 490, 434, 435, 1083, 355, 1168, 354, 449, 320, 1155, 580, 1118, 456, 1208, 1164, 348, 491, 492, 376, 1187, 392, 1203, 438, 1210, 1218, 344, 540, 567); + protected $ruleToNonTerminal = array(0, 1, 3, 3, 2, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 9, 10, 11, 11, 12, 12, 13, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 18, 18, 19, 19, 21, 21, 17, 17, 22, 22, 23, 23, 24, 24, 25, 25, 20, 20, 26, 28, 28, 29, 30, 30, 32, 31, 31, 31, 31, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 14, 14, 54, 54, 56, 55, 55, 48, 48, 58, 58, 59, 59, 60, 60, 61, 61, 15, 16, 16, 16, 64, 64, 64, 65, 65, 68, 68, 66, 66, 70, 70, 41, 41, 50, 50, 53, 53, 53, 52, 52, 71, 42, 42, 42, 42, 72, 72, 73, 73, 74, 74, 39, 39, 35, 35, 75, 37, 37, 76, 36, 36, 38, 38, 49, 49, 49, 62, 62, 78, 78, 79, 79, 81, 81, 81, 80, 80, 63, 63, 82, 82, 82, 83, 83, 84, 84, 84, 44, 44, 85, 85, 85, 45, 45, 86, 86, 87, 87, 67, 88, 88, 88, 88, 93, 93, 94, 94, 95, 95, 95, 95, 95, 96, 97, 97, 92, 92, 89, 89, 91, 91, 99, 99, 98, 98, 98, 98, 98, 98, 90, 90, 101, 100, 100, 46, 46, 40, 40, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 34, 34, 47, 47, 106, 106, 107, 107, 107, 107, 113, 102, 102, 109, 109, 115, 115, 116, 117, 118, 118, 118, 118, 118, 118, 118, 69, 69, 57, 57, 57, 57, 103, 103, 122, 122, 119, 119, 123, 123, 123, 123, 104, 104, 104, 108, 108, 108, 114, 114, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 27, 27, 27, 27, 27, 27, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 112, 112, 105, 105, 105, 105, 129, 129, 132, 132, 131, 131, 133, 133, 51, 51, 51, 51, 135, 135, 134, 134, 134, 134, 134, 136, 136, 121, 121, 124, 124, 120, 120, 138, 137, 137, 137, 137, 125, 125, 125, 125, 111, 111, 126, 126, 126, 126, 77, 139, 139, 140, 140, 140, 110, 110, 141, 141, 142, 142, 142, 142, 142, 127, 127, 127, 127, 144, 145, 143, 143, 143, 143, 143, 143, 143, 146, 146, 146); + protected $ruleToLength = array(1, 1, 2, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 5, 4, 3, 4, 2, 3, 1, 1, 7, 6, 3, 1, 3, 1, 3, 1, 1, 3, 1, 3, 1, 2, 3, 1, 3, 3, 1, 3, 2, 0, 1, 1, 1, 1, 1, 3, 5, 8, 3, 5, 9, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 1, 2, 2, 5, 7, 9, 5, 6, 3, 3, 2, 2, 1, 1, 1, 0, 2, 8, 0, 4, 1, 3, 0, 1, 0, 1, 0, 1, 1, 1, 10, 7, 6, 5, 1, 2, 2, 0, 2, 0, 2, 0, 2, 1, 3, 1, 4, 1, 4, 1, 1, 4, 1, 3, 3, 3, 4, 4, 5, 0, 2, 4, 3, 1, 1, 1, 4, 0, 2, 3, 0, 2, 4, 0, 2, 0, 3, 1, 2, 1, 1, 0, 1, 3, 4, 6, 1, 1, 1, 0, 1, 0, 2, 2, 3, 3, 1, 3, 1, 2, 2, 3, 1, 1, 2, 4, 3, 1, 1, 3, 2, 0, 1, 3, 3, 9, 3, 1, 3, 0, 2, 4, 5, 4, 4, 4, 3, 1, 1, 1, 3, 1, 1, 0, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 3, 3, 1, 0, 1, 1, 3, 3, 4, 4, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 5, 4, 3, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 2, 1, 2, 10, 11, 3, 3, 2, 4, 4, 3, 4, 4, 4, 4, 7, 3, 2, 0, 4, 1, 3, 2, 1, 2, 2, 4, 6, 2, 2, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 4, 4, 0, 2, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 1, 3, 1, 4, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 5, 4, 4, 3, 1, 3, 1, 1, 3, 3, 0, 2, 0, 1, 3, 1, 3, 1, 1, 1, 1, 1, 6, 4, 3, 4, 2, 4, 4, 1, 3, 1, 2, 1, 1, 4, 1, 1, 3, 6, 4, 4, 4, 4, 1, 4, 0, 1, 1, 3, 1, 1, 4, 3, 1, 1, 1, 0, 0, 2, 3, 1, 3, 1, 4, 2, 2, 2, 2, 1, 2, 1, 1, 1, 4, 3, 3, 3, 6, 3, 1, 1, 1); + protected function initReduceCallbacks() + { + $this->reduceCallbacks = [0 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 1 => function ($stackPos) { + $this->semValue = $this->handleNamespaces($this->semStack[$stackPos - (1 - 1)]); + }, 2 => function ($stackPos) { + if (\is_array($this->semStack[$stackPos - (2 - 2)])) { + $this->semValue = \array_merge($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)]); + } else { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + } + }, 3 => function ($stackPos) { + $this->semValue = array(); + }, 4 => function ($stackPos) { + $startAttributes = $this->lookaheadStartAttributes; + if (isset($startAttributes['comments'])) { + $nop = new Stmt\Nop($this->createCommentNopAttributes($startAttributes['comments'])); + } else { + $nop = null; + } + if ($nop !== null) { + $this->semStack[$stackPos - (1 - 1)][] = $nop; + } + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 5 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 6 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 7 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 8 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 9 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 10 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 11 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 12 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 13 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 14 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 15 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 16 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 17 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 18 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 19 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 20 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 21 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 22 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 23 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 24 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 25 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 26 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 27 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 28 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 29 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 30 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 31 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 32 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 33 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 34 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 35 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 36 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 37 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 38 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 39 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 40 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 41 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 42 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 43 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 44 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 45 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 46 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 47 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 48 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 49 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 50 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 51 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 52 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 53 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 54 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 55 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 56 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 57 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 58 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 59 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 60 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 61 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 62 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 63 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 64 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 65 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 66 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 67 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 68 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 69 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 70 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 71 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 72 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 73 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 74 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 75 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 76 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 77 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 78 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 79 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 80 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 81 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 82 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 83 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 84 => function ($stackPos) { + $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 85 => function ($stackPos) { + $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 86 => function ($stackPos) { + $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 87 => function ($stackPos) { + $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 88 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 89 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 90 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 91 => function ($stackPos) { + $this->semValue = new Name(\substr($this->semStack[$stackPos - (1 - 1)], 1), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 92 => function ($stackPos) { + $this->semValue = new Expr\Variable(\substr($this->semStack[$stackPos - (1 - 1)], 1), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 93 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 94 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 95 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 96 => function ($stackPos) { + $this->semValue = new Stmt\HaltCompiler($this->lexer->handleHaltCompiler(), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 97 => function ($stackPos) { + $this->semValue = new Stmt\Namespace_($this->semStack[$stackPos - (3 - 2)], null, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + $this->semValue->setAttribute('kind', Stmt\Namespace_::KIND_SEMICOLON); + $this->checkNamespace($this->semValue); + }, 98 => function ($stackPos) { + $this->semValue = new Stmt\Namespace_($this->semStack[$stackPos - (5 - 2)], $this->semStack[$stackPos - (5 - 4)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + $this->semValue->setAttribute('kind', Stmt\Namespace_::KIND_BRACED); + $this->checkNamespace($this->semValue); + }, 99 => function ($stackPos) { + $this->semValue = new Stmt\Namespace_(null, $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + $this->semValue->setAttribute('kind', Stmt\Namespace_::KIND_BRACED); + $this->checkNamespace($this->semValue); + }, 100 => function ($stackPos) { + $this->semValue = new Stmt\Use_($this->semStack[$stackPos - (3 - 2)], Stmt\Use_::TYPE_NORMAL, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 101 => function ($stackPos) { + $this->semValue = new Stmt\Use_($this->semStack[$stackPos - (4 - 3)], $this->semStack[$stackPos - (4 - 2)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 102 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 103 => function ($stackPos) { + $this->semValue = new Stmt\Const_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 104 => function ($stackPos) { + $this->semValue = Stmt\Use_::TYPE_FUNCTION; + }, 105 => function ($stackPos) { + $this->semValue = Stmt\Use_::TYPE_CONSTANT; + }, 106 => function ($stackPos) { + $this->semValue = new Stmt\GroupUse($this->semStack[$stackPos - (7 - 3)], $this->semStack[$stackPos - (7 - 6)], $this->semStack[$stackPos - (7 - 2)], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); + }, 107 => function ($stackPos) { + $this->semValue = new Stmt\GroupUse($this->semStack[$stackPos - (6 - 2)], $this->semStack[$stackPos - (6 - 5)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + }, 108 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 109 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 110 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 111 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 112 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 113 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 114 => function ($stackPos) { + $this->semValue = new Stmt\UseUse($this->semStack[$stackPos - (1 - 1)], null, Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + $this->checkUseUse($this->semValue, $stackPos - (1 - 1)); + }, 115 => function ($stackPos) { + $this->semValue = new Stmt\UseUse($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + $this->checkUseUse($this->semValue, $stackPos - (3 - 3)); + }, 116 => function ($stackPos) { + $this->semValue = new Stmt\UseUse($this->semStack[$stackPos - (1 - 1)], null, Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + $this->checkUseUse($this->semValue, $stackPos - (1 - 1)); + }, 117 => function ($stackPos) { + $this->semValue = new Stmt\UseUse($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + $this->checkUseUse($this->semValue, $stackPos - (3 - 3)); + }, 118 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + $this->semValue->type = Stmt\Use_::TYPE_NORMAL; + }, 119 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue->type = $this->semStack[$stackPos - (2 - 1)]; + }, 120 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 121 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 122 => function ($stackPos) { + $this->semValue = new Node\Const_($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 123 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 124 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 125 => function ($stackPos) { + $this->semValue = new Node\Const_($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 126 => function ($stackPos) { + if (\is_array($this->semStack[$stackPos - (2 - 2)])) { + $this->semValue = \array_merge($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)]); + } else { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + } + }, 127 => function ($stackPos) { + $this->semValue = array(); + }, 128 => function ($stackPos) { + $startAttributes = $this->lookaheadStartAttributes; + if (isset($startAttributes['comments'])) { + $nop = new Stmt\Nop($this->createCommentNopAttributes($startAttributes['comments'])); + } else { + $nop = null; + } + if ($nop !== null) { + $this->semStack[$stackPos - (1 - 1)][] = $nop; + } + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 129 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 130 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 131 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 132 => function ($stackPos) { + throw new Error('__HALT_COMPILER() can only be used from the outermost scope', $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 133 => function ($stackPos) { + if ($this->semStack[$stackPos - (3 - 2)]) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + $attrs = $this->startAttributeStack[$stackPos - (3 - 1)]; + $stmts = $this->semValue; + if (!empty($attrs['comments'])) { + $stmts[0]->setAttribute('comments', \array_merge($attrs['comments'], $stmts[0]->getAttribute('comments', []))); + } + } else { + $startAttributes = $this->startAttributeStack[$stackPos - (3 - 1)]; + if (isset($startAttributes['comments'])) { + $this->semValue = new Stmt\Nop($startAttributes + $this->endAttributes); + } else { + $this->semValue = null; + } + if (null === $this->semValue) { + $this->semValue = array(); + } + } + }, 134 => function ($stackPos) { + $this->semValue = new Stmt\If_($this->semStack[$stackPos - (5 - 2)], ['stmts' => \is_array($this->semStack[$stackPos - (5 - 3)]) ? $this->semStack[$stackPos - (5 - 3)] : array($this->semStack[$stackPos - (5 - 3)]), 'elseifs' => $this->semStack[$stackPos - (5 - 4)], 'else' => $this->semStack[$stackPos - (5 - 5)]], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 135 => function ($stackPos) { + $this->semValue = new Stmt\If_($this->semStack[$stackPos - (8 - 2)], ['stmts' => $this->semStack[$stackPos - (8 - 4)], 'elseifs' => $this->semStack[$stackPos - (8 - 5)], 'else' => $this->semStack[$stackPos - (8 - 6)]], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes); + }, 136 => function ($stackPos) { + $this->semValue = new Stmt\While_($this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 137 => function ($stackPos) { + $this->semValue = new Stmt\Do_($this->semStack[$stackPos - (5 - 4)], \is_array($this->semStack[$stackPos - (5 - 2)]) ? $this->semStack[$stackPos - (5 - 2)] : array($this->semStack[$stackPos - (5 - 2)]), $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 138 => function ($stackPos) { + $this->semValue = new Stmt\For_(['init' => $this->semStack[$stackPos - (9 - 3)], 'cond' => $this->semStack[$stackPos - (9 - 5)], 'loop' => $this->semStack[$stackPos - (9 - 7)], 'stmts' => $this->semStack[$stackPos - (9 - 9)]], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); + }, 139 => function ($stackPos) { + $this->semValue = new Stmt\Switch_($this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 140 => function ($stackPos) { + $this->semValue = new Stmt\Break_(null, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 141 => function ($stackPos) { + $this->semValue = new Stmt\Break_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 142 => function ($stackPos) { + $this->semValue = new Stmt\Continue_(null, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 143 => function ($stackPos) { + $this->semValue = new Stmt\Continue_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 144 => function ($stackPos) { + $this->semValue = new Stmt\Return_(null, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 145 => function ($stackPos) { + $this->semValue = new Stmt\Return_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 146 => function ($stackPos) { + $this->semValue = new Stmt\Global_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 147 => function ($stackPos) { + $this->semValue = new Stmt\Static_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 148 => function ($stackPos) { + $this->semValue = new Stmt\Echo_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 149 => function ($stackPos) { + $this->semValue = new Stmt\InlineHTML($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 150 => function ($stackPos) { + $this->semValue = new Stmt\Expression($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 151 => function ($stackPos) { + $this->semValue = new Stmt\Expression($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 152 => function ($stackPos) { + $this->semValue = new Stmt\Unset_($this->semStack[$stackPos - (5 - 3)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 153 => function ($stackPos) { + $this->semValue = new Stmt\Foreach_($this->semStack[$stackPos - (7 - 3)], $this->semStack[$stackPos - (7 - 5)][0], ['keyVar' => null, 'byRef' => $this->semStack[$stackPos - (7 - 5)][1], 'stmts' => $this->semStack[$stackPos - (7 - 7)]], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); + }, 154 => function ($stackPos) { + $this->semValue = new Stmt\Foreach_($this->semStack[$stackPos - (9 - 3)], $this->semStack[$stackPos - (9 - 7)][0], ['keyVar' => $this->semStack[$stackPos - (9 - 5)], 'byRef' => $this->semStack[$stackPos - (9 - 7)][1], 'stmts' => $this->semStack[$stackPos - (9 - 9)]], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); + }, 155 => function ($stackPos) { + $this->semValue = new Stmt\Declare_($this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 5)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 156 => function ($stackPos) { + $this->semValue = new Stmt\TryCatch($this->semStack[$stackPos - (6 - 3)], $this->semStack[$stackPos - (6 - 5)], $this->semStack[$stackPos - (6 - 6)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + $this->checkTryCatch($this->semValue); + }, 157 => function ($stackPos) { + $this->semValue = new Stmt\Throw_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 158 => function ($stackPos) { + $this->semValue = new Stmt\Goto_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 159 => function ($stackPos) { + $this->semValue = new Stmt\Label($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 160 => function ($stackPos) { + $this->semValue = new Stmt\Expression($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 161 => function ($stackPos) { + $this->semValue = array(); + /* means: no statement */ + }, 162 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 163 => function ($stackPos) { + $startAttributes = $this->startAttributeStack[$stackPos - (1 - 1)]; + if (isset($startAttributes['comments'])) { + $this->semValue = new Stmt\Nop($startAttributes + $this->endAttributes); + } else { + $this->semValue = null; + } + if ($this->semValue === null) { + $this->semValue = array(); + } + /* means: no statement */ + }, 164 => function ($stackPos) { + $this->semValue = array(); + }, 165 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 166 => function ($stackPos) { + $this->semValue = new Stmt\Catch_(array($this->semStack[$stackPos - (8 - 3)]), $this->semStack[$stackPos - (8 - 4)], $this->semStack[$stackPos - (8 - 7)], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes); + }, 167 => function ($stackPos) { + $this->semValue = null; + }, 168 => function ($stackPos) { + $this->semValue = new Stmt\Finally_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 169 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 170 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 171 => function ($stackPos) { + $this->semValue = \false; + }, 172 => function ($stackPos) { + $this->semValue = \true; + }, 173 => function ($stackPos) { + $this->semValue = \false; + }, 174 => function ($stackPos) { + $this->semValue = \true; + }, 175 => function ($stackPos) { + $this->semValue = \false; + }, 176 => function ($stackPos) { + $this->semValue = \true; + }, 177 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 178 => function ($stackPos) { + $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 179 => function ($stackPos) { + $this->semValue = new Stmt\Function_($this->semStack[$stackPos - (10 - 3)], ['byRef' => $this->semStack[$stackPos - (10 - 2)], 'params' => $this->semStack[$stackPos - (10 - 5)], 'returnType' => $this->semStack[$stackPos - (10 - 7)], 'stmts' => $this->semStack[$stackPos - (10 - 9)]], $this->startAttributeStack[$stackPos - (10 - 1)] + $this->endAttributes); + }, 180 => function ($stackPos) { + $this->semValue = new Stmt\Class_($this->semStack[$stackPos - (7 - 2)], ['type' => $this->semStack[$stackPos - (7 - 1)], 'extends' => $this->semStack[$stackPos - (7 - 3)], 'implements' => $this->semStack[$stackPos - (7 - 4)], 'stmts' => $this->semStack[$stackPos - (7 - 6)]], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); + $this->checkClass($this->semValue, $stackPos - (7 - 2)); + }, 181 => function ($stackPos) { + $this->semValue = new Stmt\Interface_($this->semStack[$stackPos - (6 - 2)], ['extends' => $this->semStack[$stackPos - (6 - 3)], 'stmts' => $this->semStack[$stackPos - (6 - 5)]], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + $this->checkInterface($this->semValue, $stackPos - (6 - 2)); + }, 182 => function ($stackPos) { + $this->semValue = new Stmt\Trait_($this->semStack[$stackPos - (5 - 2)], ['stmts' => $this->semStack[$stackPos - (5 - 4)]], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 183 => function ($stackPos) { + $this->semValue = 0; + }, 184 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_ABSTRACT; + }, 185 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_FINAL; + }, 186 => function ($stackPos) { + $this->semValue = null; + }, 187 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 2)]; + }, 188 => function ($stackPos) { + $this->semValue = array(); + }, 189 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 2)]; + }, 190 => function ($stackPos) { + $this->semValue = array(); + }, 191 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 2)]; + }, 192 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 193 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 194 => function ($stackPos) { + $this->semValue = \is_array($this->semStack[$stackPos - (1 - 1)]) ? $this->semStack[$stackPos - (1 - 1)] : array($this->semStack[$stackPos - (1 - 1)]); + }, 195 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 2)]; + }, 196 => function ($stackPos) { + $this->semValue = \is_array($this->semStack[$stackPos - (1 - 1)]) ? $this->semStack[$stackPos - (1 - 1)] : array($this->semStack[$stackPos - (1 - 1)]); + }, 197 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 2)]; + }, 198 => function ($stackPos) { + $this->semValue = \is_array($this->semStack[$stackPos - (1 - 1)]) ? $this->semStack[$stackPos - (1 - 1)] : array($this->semStack[$stackPos - (1 - 1)]); + }, 199 => function ($stackPos) { + $this->semValue = null; + }, 200 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 2)]; + }, 201 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 202 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 203 => function ($stackPos) { + $this->semValue = new Stmt\DeclareDeclare($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 204 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 205 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 3)]; + }, 206 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 2)]; + }, 207 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (5 - 3)]; + }, 208 => function ($stackPos) { + $this->semValue = array(); + }, 209 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 210 => function ($stackPos) { + $this->semValue = new Stmt\Case_($this->semStack[$stackPos - (4 - 2)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 211 => function ($stackPos) { + $this->semValue = new Stmt\Case_(null, $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 212 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 213 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 214 => function ($stackPos) { + $this->semValue = \is_array($this->semStack[$stackPos - (1 - 1)]) ? $this->semStack[$stackPos - (1 - 1)] : array($this->semStack[$stackPos - (1 - 1)]); + }, 215 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 2)]; + }, 216 => function ($stackPos) { + $this->semValue = array(); + }, 217 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 218 => function ($stackPos) { + $this->semValue = new Stmt\ElseIf_($this->semStack[$stackPos - (3 - 2)], \is_array($this->semStack[$stackPos - (3 - 3)]) ? $this->semStack[$stackPos - (3 - 3)] : array($this->semStack[$stackPos - (3 - 3)]), $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 219 => function ($stackPos) { + $this->semValue = array(); + }, 220 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 221 => function ($stackPos) { + $this->semValue = new Stmt\ElseIf_($this->semStack[$stackPos - (4 - 2)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 222 => function ($stackPos) { + $this->semValue = null; + }, 223 => function ($stackPos) { + $this->semValue = new Stmt\Else_(\is_array($this->semStack[$stackPos - (2 - 2)]) ? $this->semStack[$stackPos - (2 - 2)] : array($this->semStack[$stackPos - (2 - 2)]), $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 224 => function ($stackPos) { + $this->semValue = null; + }, 225 => function ($stackPos) { + $this->semValue = new Stmt\Else_($this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 226 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)], \false); + }, 227 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (2 - 2)], \true); + }, 228 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)], \false); + }, 229 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 230 => function ($stackPos) { + $this->semValue = array(); + }, 231 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 232 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 233 => function ($stackPos) { + $this->semValue = new Node\Param($this->semStack[$stackPos - (4 - 4)], null, $this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 2)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + $this->checkParam($this->semValue); + }, 234 => function ($stackPos) { + $this->semValue = new Node\Param($this->semStack[$stackPos - (6 - 4)], $this->semStack[$stackPos - (6 - 6)], $this->semStack[$stackPos - (6 - 1)], $this->semStack[$stackPos - (6 - 2)], $this->semStack[$stackPos - (6 - 3)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + $this->checkParam($this->semValue); + }, 235 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 236 => function ($stackPos) { + $this->semValue = new Node\Identifier('array', $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 237 => function ($stackPos) { + $this->semValue = new Node\Identifier('callable', $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 238 => function ($stackPos) { + $this->semValue = null; + }, 239 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 240 => function ($stackPos) { + $this->semValue = null; + }, 241 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 2)]; + }, 242 => function ($stackPos) { + $this->semValue = array(); + }, 243 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 244 => function ($stackPos) { + $this->semValue = array(new Node\Arg($this->semStack[$stackPos - (3 - 2)], \false, \false, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes)); + }, 245 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 246 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 247 => function ($stackPos) { + $this->semValue = new Node\Arg($this->semStack[$stackPos - (1 - 1)], \false, \false, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 248 => function ($stackPos) { + $this->semValue = new Node\Arg($this->semStack[$stackPos - (2 - 2)], \true, \false, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 249 => function ($stackPos) { + $this->semValue = new Node\Arg($this->semStack[$stackPos - (2 - 2)], \false, \true, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 250 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 251 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 252 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 253 => function ($stackPos) { + $this->semValue = new Expr\Variable($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 254 => function ($stackPos) { + $this->semValue = new Expr\Variable($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 255 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 256 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 257 => function ($stackPos) { + $this->semValue = new Stmt\StaticVar($this->semStack[$stackPos - (1 - 1)], null, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 258 => function ($stackPos) { + $this->semValue = new Stmt\StaticVar($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 259 => function ($stackPos) { + if ($this->semStack[$stackPos - (2 - 2)] !== null) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + } else { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + } + }, 260 => function ($stackPos) { + $this->semValue = array(); + }, 261 => function ($stackPos) { + $startAttributes = $this->lookaheadStartAttributes; + if (isset($startAttributes['comments'])) { + $nop = new Stmt\Nop($this->createCommentNopAttributes($startAttributes['comments'])); + } else { + $nop = null; + } + if ($nop !== null) { + $this->semStack[$stackPos - (1 - 1)][] = $nop; + } + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 262 => function ($stackPos) { + $this->semValue = new Stmt\Property($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + $this->checkProperty($this->semValue, $stackPos - (3 - 1)); + }, 263 => function ($stackPos) { + $this->semValue = new Stmt\ClassConst($this->semStack[$stackPos - (3 - 2)], 0, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 264 => function ($stackPos) { + $this->semValue = new Stmt\ClassMethod($this->semStack[$stackPos - (9 - 4)], ['type' => $this->semStack[$stackPos - (9 - 1)], 'byRef' => $this->semStack[$stackPos - (9 - 3)], 'params' => $this->semStack[$stackPos - (9 - 6)], 'returnType' => $this->semStack[$stackPos - (9 - 8)], 'stmts' => $this->semStack[$stackPos - (9 - 9)]], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); + $this->checkClassMethod($this->semValue, $stackPos - (9 - 1)); + }, 265 => function ($stackPos) { + $this->semValue = new Stmt\TraitUse($this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 266 => function ($stackPos) { + $this->semValue = array(); + }, 267 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 268 => function ($stackPos) { + $this->semValue = array(); + }, 269 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 270 => function ($stackPos) { + $this->semValue = new Stmt\TraitUseAdaptation\Precedence($this->semStack[$stackPos - (4 - 1)][0], $this->semStack[$stackPos - (4 - 1)][1], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 271 => function ($stackPos) { + $this->semValue = new Stmt\TraitUseAdaptation\Alias($this->semStack[$stackPos - (5 - 1)][0], $this->semStack[$stackPos - (5 - 1)][1], $this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 4)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 272 => function ($stackPos) { + $this->semValue = new Stmt\TraitUseAdaptation\Alias($this->semStack[$stackPos - (4 - 1)][0], $this->semStack[$stackPos - (4 - 1)][1], $this->semStack[$stackPos - (4 - 3)], null, $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 273 => function ($stackPos) { + $this->semValue = new Stmt\TraitUseAdaptation\Alias($this->semStack[$stackPos - (4 - 1)][0], $this->semStack[$stackPos - (4 - 1)][1], null, $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 274 => function ($stackPos) { + $this->semValue = new Stmt\TraitUseAdaptation\Alias($this->semStack[$stackPos - (4 - 1)][0], $this->semStack[$stackPos - (4 - 1)][1], null, $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 275 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)]); + }, 276 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 277 => function ($stackPos) { + $this->semValue = array(null, $this->semStack[$stackPos - (1 - 1)]); + }, 278 => function ($stackPos) { + $this->semValue = null; + }, 279 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 280 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 281 => function ($stackPos) { + $this->semValue = 0; + }, 282 => function ($stackPos) { + $this->semValue = 0; + }, 283 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 284 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 285 => function ($stackPos) { + $this->checkModifier($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $stackPos - (2 - 2)); + $this->semValue = $this->semStack[$stackPos - (2 - 1)] | $this->semStack[$stackPos - (2 - 2)]; + }, 286 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_PUBLIC; + }, 287 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_PROTECTED; + }, 288 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_PRIVATE; + }, 289 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_STATIC; + }, 290 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_ABSTRACT; + }, 291 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_FINAL; + }, 292 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 293 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 294 => function ($stackPos) { + $this->semValue = new Node\VarLikeIdentifier(\substr($this->semStack[$stackPos - (1 - 1)], 1), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 295 => function ($stackPos) { + $this->semValue = new Stmt\PropertyProperty($this->semStack[$stackPos - (1 - 1)], null, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 296 => function ($stackPos) { + $this->semValue = new Stmt\PropertyProperty($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 297 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 298 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 299 => function ($stackPos) { + $this->semValue = array(); + }, 300 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 301 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 302 => function ($stackPos) { + $this->semValue = new Expr\Assign($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 303 => function ($stackPos) { + $this->semValue = new Expr\Assign($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 304 => function ($stackPos) { + $this->semValue = new Expr\AssignRef($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 305 => function ($stackPos) { + $this->semValue = new Expr\AssignRef($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 306 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 307 => function ($stackPos) { + $this->semValue = new Expr\Clone_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 308 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Plus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 309 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Minus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 310 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Mul($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 311 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Div($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 312 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Concat($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 313 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Mod($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 314 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\BitwiseAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 315 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\BitwiseOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 316 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\BitwiseXor($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 317 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\ShiftLeft($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 318 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\ShiftRight($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 319 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Pow($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 320 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Coalesce($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 321 => function ($stackPos) { + $this->semValue = new Expr\PostInc($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 322 => function ($stackPos) { + $this->semValue = new Expr\PreInc($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 323 => function ($stackPos) { + $this->semValue = new Expr\PostDec($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 324 => function ($stackPos) { + $this->semValue = new Expr\PreDec($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 325 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BooleanOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 326 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BooleanAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 327 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\LogicalOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 328 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\LogicalAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 329 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\LogicalXor($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 330 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BitwiseOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 331 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BitwiseAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 332 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BitwiseAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 333 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BitwiseXor($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 334 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Concat($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 335 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Plus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 336 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Minus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 337 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Mul($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 338 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Div($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 339 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Mod($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 340 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\ShiftLeft($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 341 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\ShiftRight($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 342 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Pow($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 343 => function ($stackPos) { + $this->semValue = new Expr\UnaryPlus($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 344 => function ($stackPos) { + $this->semValue = new Expr\UnaryMinus($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 345 => function ($stackPos) { + $this->semValue = new Expr\BooleanNot($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 346 => function ($stackPos) { + $this->semValue = new Expr\BitwiseNot($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 347 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Identical($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 348 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\NotIdentical($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 349 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Equal($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 350 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\NotEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 351 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Spaceship($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 352 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Smaller($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 353 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\SmallerOrEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 354 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Greater($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 355 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\GreaterOrEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 356 => function ($stackPos) { + $this->semValue = new Expr\Instanceof_($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 357 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 358 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 359 => function ($stackPos) { + $this->semValue = new Expr\Ternary($this->semStack[$stackPos - (5 - 1)], $this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 5)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 360 => function ($stackPos) { + $this->semValue = new Expr\Ternary($this->semStack[$stackPos - (4 - 1)], null, $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 361 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Coalesce($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 362 => function ($stackPos) { + $this->semValue = new Expr\Isset_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 363 => function ($stackPos) { + $this->semValue = new Expr\Empty_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 364 => function ($stackPos) { + $this->semValue = new Expr\Include_($this->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_INCLUDE, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 365 => function ($stackPos) { + $this->semValue = new Expr\Include_($this->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_INCLUDE_ONCE, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 366 => function ($stackPos) { + $this->semValue = new Expr\Eval_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 367 => function ($stackPos) { + $this->semValue = new Expr\Include_($this->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_REQUIRE, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 368 => function ($stackPos) { + $this->semValue = new Expr\Include_($this->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_REQUIRE_ONCE, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 369 => function ($stackPos) { + $this->semValue = new Expr\Cast\Int_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 370 => function ($stackPos) { + $attrs = $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes; + $attrs['kind'] = $this->getFloatCastKind($this->semStack[$stackPos - (2 - 1)]); + $this->semValue = new Expr\Cast\Double($this->semStack[$stackPos - (2 - 2)], $attrs); + }, 371 => function ($stackPos) { + $this->semValue = new Expr\Cast\String_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 372 => function ($stackPos) { + $this->semValue = new Expr\Cast\Array_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 373 => function ($stackPos) { + $this->semValue = new Expr\Cast\Object_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 374 => function ($stackPos) { + $this->semValue = new Expr\Cast\Bool_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 375 => function ($stackPos) { + $this->semValue = new Expr\Cast\Unset_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 376 => function ($stackPos) { + $attrs = $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes; + $attrs['kind'] = \strtolower($this->semStack[$stackPos - (2 - 1)]) === 'exit' ? Expr\Exit_::KIND_EXIT : Expr\Exit_::KIND_DIE; + $this->semValue = new Expr\Exit_($this->semStack[$stackPos - (2 - 2)], $attrs); + }, 377 => function ($stackPos) { + $this->semValue = new Expr\ErrorSuppress($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 378 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 379 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 380 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 381 => function ($stackPos) { + $this->semValue = new Expr\ShellExec($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 382 => function ($stackPos) { + $this->semValue = new Expr\Print_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 383 => function ($stackPos) { + $this->semValue = new Expr\Yield_(null, null, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 384 => function ($stackPos) { + $this->semValue = new Expr\YieldFrom($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 385 => function ($stackPos) { + $this->semValue = new Expr\Closure(['static' => \false, 'byRef' => $this->semStack[$stackPos - (10 - 2)], 'params' => $this->semStack[$stackPos - (10 - 4)], 'uses' => $this->semStack[$stackPos - (10 - 6)], 'returnType' => $this->semStack[$stackPos - (10 - 7)], 'stmts' => $this->semStack[$stackPos - (10 - 9)]], $this->startAttributeStack[$stackPos - (10 - 1)] + $this->endAttributes); + }, 386 => function ($stackPos) { + $this->semValue = new Expr\Closure(['static' => \true, 'byRef' => $this->semStack[$stackPos - (11 - 3)], 'params' => $this->semStack[$stackPos - (11 - 5)], 'uses' => $this->semStack[$stackPos - (11 - 7)], 'returnType' => $this->semStack[$stackPos - (11 - 8)], 'stmts' => $this->semStack[$stackPos - (11 - 10)]], $this->startAttributeStack[$stackPos - (11 - 1)] + $this->endAttributes); + }, 387 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 388 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 389 => function ($stackPos) { + $this->semValue = new Expr\Yield_($this->semStack[$stackPos - (2 - 2)], null, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 390 => function ($stackPos) { + $this->semValue = new Expr\Yield_($this->semStack[$stackPos - (4 - 4)], $this->semStack[$stackPos - (4 - 2)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 391 => function ($stackPos) { + $attrs = $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes; + $attrs['kind'] = Expr\Array_::KIND_LONG; + $this->semValue = new Expr\Array_($this->semStack[$stackPos - (4 - 3)], $attrs); + }, 392 => function ($stackPos) { + $attrs = $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes; + $attrs['kind'] = Expr\Array_::KIND_SHORT; + $this->semValue = new Expr\Array_($this->semStack[$stackPos - (3 - 2)], $attrs); + }, 393 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 394 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch(Scalar\String_::fromString($this->semStack[$stackPos - (4 - 1)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes), $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 395 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 396 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 397 => function ($stackPos) { + $this->semValue = array(new Stmt\Class_(null, ['type' => 0, 'extends' => $this->semStack[$stackPos - (7 - 3)], 'implements' => $this->semStack[$stackPos - (7 - 4)], 'stmts' => $this->semStack[$stackPos - (7 - 6)]], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes), $this->semStack[$stackPos - (7 - 2)]); + $this->checkClass($this->semValue[0], -1); + }, 398 => function ($stackPos) { + $this->semValue = new Expr\New_($this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 399 => function ($stackPos) { + list($class, $ctorArgs) = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = new Expr\New_($class, $ctorArgs, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 400 => function ($stackPos) { + $this->semValue = array(); + }, 401 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 3)]; + }, 402 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 403 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 404 => function ($stackPos) { + $this->semValue = new Expr\ClosureUse($this->semStack[$stackPos - (2 - 2)], $this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 405 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 406 => function ($stackPos) { + $this->semValue = new Expr\FuncCall($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 407 => function ($stackPos) { + $this->semValue = new Expr\FuncCall($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 408 => function ($stackPos) { + $this->semValue = new Expr\StaticCall($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 409 => function ($stackPos) { + $this->semValue = new Expr\StaticCall($this->semStack[$stackPos - (6 - 1)], $this->semStack[$stackPos - (6 - 4)], $this->semStack[$stackPos - (6 - 6)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + }, 410 => function ($stackPos) { + $this->semValue = $this->fixupPhp5StaticPropCall($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 411 => function ($stackPos) { + $this->semValue = new Expr\FuncCall($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 412 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 413 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 414 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 415 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 416 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 417 => function ($stackPos) { + $this->semValue = new Name\FullyQualified(\substr($this->semStack[$stackPos - (1 - 1)], 1), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 418 => function ($stackPos) { + $this->semValue = new Name\Relative(\substr($this->semStack[$stackPos - (1 - 1)], 10), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 419 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 420 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 421 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 422 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 423 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 424 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 425 => function ($stackPos) { + $this->semValue = new Expr\PropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 426 => function ($stackPos) { + $this->semValue = new Expr\PropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 427 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 428 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 429 => function ($stackPos) { + $this->semValue = null; + }, 430 => function ($stackPos) { + $this->semValue = null; + }, 431 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 432 => function ($stackPos) { + $this->semValue = array(); + }, 433 => function ($stackPos) { + $this->semValue = array(new Scalar\EncapsedStringPart(Scalar\String_::parseEscapeSequences($this->semStack[$stackPos - (1 - 1)], '`', \false), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes)); + }, 434 => function ($stackPos) { + foreach ($this->semStack[$stackPos - (1 - 1)] as $s) { + if ($s instanceof Node\Scalar\EncapsedStringPart) { + $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, '`', \false); + } + } + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 435 => function ($stackPos) { + $this->semValue = array(); + }, 436 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 437 => function ($stackPos) { + $this->semValue = $this->parseLNumber($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes, \true); + }, 438 => function ($stackPos) { + $this->semValue = Scalar\DNumber::fromString($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 439 => function ($stackPos) { + $this->semValue = Scalar\String_::fromString($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes, \false); + }, 440 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Line($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 441 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\File($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 442 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Dir($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 443 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Class_($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 444 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Trait_($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 445 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Method($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 446 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Function_($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 447 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Namespace_($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 448 => function ($stackPos) { + $this->semValue = $this->parseDocString($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes, $this->startAttributeStack[$stackPos - (3 - 3)] + $this->endAttributeStack[$stackPos - (3 - 3)], \false); + }, 449 => function ($stackPos) { + $this->semValue = $this->parseDocString($this->semStack[$stackPos - (2 - 1)], '', $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes, $this->startAttributeStack[$stackPos - (2 - 2)] + $this->endAttributeStack[$stackPos - (2 - 2)], \false); + }, 450 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 451 => function ($stackPos) { + $this->semValue = new Expr\ClassConstFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 452 => function ($stackPos) { + $this->semValue = new Expr\ConstFetch($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 453 => function ($stackPos) { + $this->semValue = new Expr\Array_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 454 => function ($stackPos) { + $this->semValue = new Expr\Array_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 455 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 456 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BooleanOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 457 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BooleanAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 458 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\LogicalOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 459 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\LogicalAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 460 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\LogicalXor($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 461 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BitwiseOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 462 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BitwiseAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 463 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BitwiseAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 464 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BitwiseXor($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 465 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Concat($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 466 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Plus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 467 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Minus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 468 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Mul($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 469 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Div($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 470 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Mod($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 471 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\ShiftLeft($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 472 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\ShiftRight($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 473 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Pow($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 474 => function ($stackPos) { + $this->semValue = new Expr\UnaryPlus($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 475 => function ($stackPos) { + $this->semValue = new Expr\UnaryMinus($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 476 => function ($stackPos) { + $this->semValue = new Expr\BooleanNot($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 477 => function ($stackPos) { + $this->semValue = new Expr\BitwiseNot($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 478 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Identical($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 479 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\NotIdentical($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 480 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Equal($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 481 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\NotEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 482 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Smaller($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 483 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\SmallerOrEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 484 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Greater($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 485 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\GreaterOrEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 486 => function ($stackPos) { + $this->semValue = new Expr\Ternary($this->semStack[$stackPos - (5 - 1)], $this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 5)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 487 => function ($stackPos) { + $this->semValue = new Expr\Ternary($this->semStack[$stackPos - (4 - 1)], null, $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 488 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 489 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 490 => function ($stackPos) { + $this->semValue = new Expr\ConstFetch($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 491 => function ($stackPos) { + $this->semValue = new Expr\ClassConstFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 492 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 493 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 494 => function ($stackPos) { + $attrs = $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes; + $attrs['kind'] = Scalar\String_::KIND_DOUBLE_QUOTED; + foreach ($this->semStack[$stackPos - (3 - 2)] as $s) { + if ($s instanceof Node\Scalar\EncapsedStringPart) { + $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, '"', \true); + } + } + $this->semValue = new Scalar\Encapsed($this->semStack[$stackPos - (3 - 2)], $attrs); + }, 495 => function ($stackPos) { + $this->semValue = $this->parseDocString($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes, $this->startAttributeStack[$stackPos - (3 - 3)] + $this->endAttributeStack[$stackPos - (3 - 3)], \true); + }, 496 => function ($stackPos) { + $this->semValue = array(); + }, 497 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 498 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 499 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 500 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 501 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 502 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (3 - 3)], $this->semStack[$stackPos - (3 - 1)], \false, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 503 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (1 - 1)], null, \false, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 504 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 505 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 506 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 507 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 508 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (6 - 2)], $this->semStack[$stackPos - (6 - 5)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + }, 509 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 510 => function ($stackPos) { + $this->semValue = new Expr\PropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 511 => function ($stackPos) { + $this->semValue = new Expr\MethodCall($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 512 => function ($stackPos) { + $this->semValue = new Expr\FuncCall($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 513 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 514 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 515 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 516 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 517 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 518 => function ($stackPos) { + $this->semValue = new Expr\Variable($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 519 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 520 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 521 => function ($stackPos) { + $this->semValue = new Expr\StaticPropertyFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 522 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 523 => function ($stackPos) { + $var = \substr($this->semStack[$stackPos - (1 - 1)], 1); + $this->semValue = \is_string($var) ? new Node\VarLikeIdentifier($var, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes) : $var; + }, 524 => function ($stackPos) { + $this->semValue = new Expr\StaticPropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 525 => function ($stackPos) { + $this->semValue = new Expr\StaticPropertyFetch($this->semStack[$stackPos - (6 - 1)], $this->semStack[$stackPos - (6 - 5)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + }, 526 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 527 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 528 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 529 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 530 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 531 => function ($stackPos) { + $this->semValue = new Expr\Variable($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 532 => function ($stackPos) { + $this->semValue = null; + }, 533 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 534 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 535 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 536 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 537 => function ($stackPos) { + $this->semValue = new Expr\Error($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + $this->errorState = 2; + }, 538 => function ($stackPos) { + $this->semValue = new Expr\List_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 539 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 540 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 541 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (1 - 1)], null, \false, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 542 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (1 - 1)], null, \false, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 543 => function ($stackPos) { + $this->semValue = null; + }, 544 => function ($stackPos) { + $this->semValue = array(); + }, 545 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 546 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 547 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 548 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (3 - 3)], $this->semStack[$stackPos - (3 - 1)], \false, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 549 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (1 - 1)], null, \false, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 550 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (4 - 4)], $this->semStack[$stackPos - (4 - 1)], \true, $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 551 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (2 - 2)], null, \true, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 552 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (2 - 2)], null, \false, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes, \true); + }, 553 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 554 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 555 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 556 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)]); + }, 557 => function ($stackPos) { + $this->semValue = new Scalar\EncapsedStringPart($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 558 => function ($stackPos) { + $this->semValue = new Expr\Variable($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 559 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 560 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 561 => function ($stackPos) { + $this->semValue = new Expr\PropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 562 => function ($stackPos) { + $this->semValue = new Expr\Variable($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 563 => function ($stackPos) { + $this->semValue = new Expr\Variable($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 564 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (6 - 2)], $this->semStack[$stackPos - (6 - 4)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + }, 565 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 566 => function ($stackPos) { + $this->semValue = new Scalar\String_($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 567 => function ($stackPos) { + $this->semValue = $this->parseNumString($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 568 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }]; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Parser/Php7.php b/vendor/nikic/php-parser/lib/PhpParser/Parser/Php7.php new file mode 100644 index 0000000000..2802b3c937 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Parser/Php7.php @@ -0,0 +1,1441 @@ +'", "T_IS_GREATER_OR_EQUAL", "T_SL", "T_SR", "'+'", "'-'", "'.'", "'*'", "'/'", "'%'", "'!'", "T_INSTANCEOF", "'~'", "T_INC", "T_DEC", "T_INT_CAST", "T_DOUBLE_CAST", "T_STRING_CAST", "T_ARRAY_CAST", "T_OBJECT_CAST", "T_BOOL_CAST", "T_UNSET_CAST", "'@'", "T_POW", "'['", "T_NEW", "T_CLONE", "T_EXIT", "T_IF", "T_ELSEIF", "T_ELSE", "T_ENDIF", "T_LNUMBER", "T_DNUMBER", "T_STRING", "T_STRING_VARNAME", "T_VARIABLE", "T_NUM_STRING", "T_INLINE_HTML", "T_ENCAPSED_AND_WHITESPACE", "T_CONSTANT_ENCAPSED_STRING", "T_ECHO", "T_DO", "T_WHILE", "T_ENDWHILE", "T_FOR", "T_ENDFOR", "T_FOREACH", "T_ENDFOREACH", "T_DECLARE", "T_ENDDECLARE", "T_AS", "T_SWITCH", "T_MATCH", "T_ENDSWITCH", "T_CASE", "T_DEFAULT", "T_BREAK", "T_CONTINUE", "T_GOTO", "T_FUNCTION", "T_FN", "T_CONST", "T_RETURN", "T_TRY", "T_CATCH", "T_FINALLY", "T_USE", "T_INSTEADOF", "T_GLOBAL", "T_STATIC", "T_ABSTRACT", "T_FINAL", "T_PRIVATE", "T_PROTECTED", "T_PUBLIC", "T_READONLY", "T_VAR", "T_UNSET", "T_ISSET", "T_EMPTY", "T_HALT_COMPILER", "T_CLASS", "T_TRAIT", "T_INTERFACE", "T_ENUM", "T_EXTENDS", "T_IMPLEMENTS", "T_OBJECT_OPERATOR", "T_NULLSAFE_OBJECT_OPERATOR", "T_LIST", "T_ARRAY", "T_CALLABLE", "T_CLASS_C", "T_TRAIT_C", "T_METHOD_C", "T_FUNC_C", "T_LINE", "T_FILE", "T_START_HEREDOC", "T_END_HEREDOC", "T_DOLLAR_OPEN_CURLY_BRACES", "T_CURLY_OPEN", "T_PAAMAYIM_NEKUDOTAYIM", "T_NAMESPACE", "T_NS_C", "T_DIR", "T_NS_SEPARATOR", "T_ELLIPSIS", "T_NAME_FULLY_QUALIFIED", "T_NAME_QUALIFIED", "T_NAME_RELATIVE", "T_ATTRIBUTE", "';'", "']'", "'{'", "'}'", "'('", "')'", "'`'", "'\"'", "'\$'"); + protected $tokenToSymbol = array(0, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 56, 166, 168, 167, 55, 168, 168, 163, 164, 53, 50, 8, 51, 52, 54, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 31, 159, 44, 16, 46, 30, 68, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 70, 168, 160, 36, 168, 165, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 161, 35, 162, 58, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43, 45, 47, 48, 49, 57, 59, 60, 61, 62, 63, 64, 65, 66, 67, 69, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158); + protected $action = array(133, 134, 135, 579, 136, 137, 0, 748, 749, 750, 138, 38, 327, -32766, -32766, -32766, -32766, -32766, -32766, -32767, -32767, -32767, -32767, 102, 103, 104, 105, 106, 1109, 1110, 1111, 1108, 1107, 1106, 1112, 742, 741, -32766, 1232, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32767, -32767, -32767, -32767, -32767, 2, 107, 108, 109, 751, 274, 381, 380, -32766, -32766, -32766, -32766, 104, 105, 106, 1024, 422, 110, 265, 139, 403, 755, 756, 757, 758, 466, 467, 428, 938, 291, -32766, 287, -32766, -32766, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 789, 580, 790, 791, 792, 793, 781, 782, 344, 345, 784, 785, 770, 771, 772, 774, 775, 776, 355, 816, 817, 818, 819, 820, 581, 777, 778, 582, 583, 810, 801, 799, 800, 813, 796, 797, 687, -545, 584, 585, 795, 586, 587, 588, 589, 590, 591, -328, -593, -367, 1234, -367, 798, 592, 593, -593, 140, -32766, -32766, -32766, 133, 134, 135, 579, 136, 137, 1057, 748, 749, 750, 138, 38, 688, 1020, 1019, 1018, 1021, 390, -32766, 7, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, -32766, 379, 380, 1033, 689, 690, 742, 741, -32766, -32766, -32766, 422, -545, -545, -590, -32766, -32766, -32766, 1032, -32766, 127, -590, 1236, 1235, 1237, 1318, 751, -545, 290, -32766, 283, -32766, -32766, -32766, -32766, -32766, 1236, 1235, 1237, -545, 265, 139, 403, 755, 756, 757, 758, 16, 481, 428, 458, 459, 460, 298, 722, 35, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 789, 580, 790, 791, 792, 793, 781, 782, 344, 345, 784, 785, 770, 771, 772, 774, 775, 776, 355, 816, 817, 818, 819, 820, 581, 777, 778, 582, 583, 810, 801, 799, 800, 813, 796, 797, 129, 824, 584, 585, 795, 586, 587, 588, 589, 590, 591, -328, 83, 84, 85, -593, 798, 592, 593, -593, 149, 773, 743, 744, 745, 746, 747, 824, 748, 749, 750, 786, 787, 37, 145, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 291, 274, 835, 254, 1109, 1110, 1111, 1108, 1107, 1106, 1112, -590, 860, 110, 861, -590, 482, 751, -32766, -32766, -32766, -32766, -32766, 142, 603, 1085, 742, 741, 1262, 326, 987, 752, 753, 754, 755, 756, 757, 758, 309, -32766, 822, -32766, -32766, -32766, -32766, 242, 553, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 789, 812, 790, 791, 792, 793, 781, 782, 783, 811, 784, 785, 770, 771, 772, 774, 775, 776, 815, 816, 817, 818, 819, 820, 821, 777, 778, 779, 780, 810, 801, 799, 800, 813, 796, 797, 311, 940, 788, 794, 795, 802, 803, 805, 804, 806, 807, 323, 609, 1274, 1033, 833, 798, 809, 808, 50, 51, 52, 512, 53, 54, 860, 241, 861, 918, 55, 56, -111, 57, -32766, -32766, -32766, -111, 826, -111, 290, 1302, 1347, 356, 305, 1348, 339, -111, -111, -111, -111, -111, -111, -111, -111, -32766, -194, -32766, -32766, -32766, -193, 956, 957, 829, -86, 988, 958, 834, 58, 59, 340, 428, 952, -544, 60, 832, 61, 247, 248, 62, 63, 64, 65, 66, 67, 68, 69, 1241, 28, 267, 70, 444, 513, -342, -32766, 141, 1268, 1269, 514, 918, 833, 326, -272, 918, 1266, 42, 25, 515, 940, 516, 14, 517, 908, 518, 828, 369, 519, 520, 373, 709, 1033, 44, 45, 445, 376, 375, 388, 46, 521, 712, -86, 440, 1101, 367, 338, -543, 441, -544, -544, 830, 1227, 442, 523, 524, 525, 290, 1236, 1235, 1237, 361, 1030, 443, -544, 1087, 526, 527, 839, 1255, 1256, 1257, 1258, 1252, 1253, 297, -544, 151, -550, -584, 833, 1259, 1254, -584, 1033, 1236, 1235, 1237, 298, -154, -154, -154, 152, 71, 908, 321, 322, 326, 908, 920, 1030, 707, 833, 154, -154, 1337, -154, 155, -154, 283, -154, -543, -543, 82, 1232, 1086, 1322, 734, 156, 326, 374, 158, 1033, 1321, -194, -79, -543, -88, -193, 742, 741, 956, 957, 653, 26, -32766, 522, -51, -543, 33, -549, 894, 952, -111, -111, -111, 32, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, -59, 75, 28, 672, 673, 326, -58, 36, 250, 920, 124, 707, 125, 920, 833, 707, -154, 130, 1266, 131, -32766, -547, 144, -542, 150, 406, 1234, 377, 378, 1146, 1148, 382, 383, -32766, -32766, -32766, -85, -32766, 1056, -32766, -542, -32766, 644, 645, -32766, 159, 160, 161, 1232, -32766, -32766, -32766, 162, -79, 1227, -32766, -32766, 742, 741, 163, -302, -32766, 419, -75, -4, 918, -73, 287, 526, 527, -32766, 1255, 1256, 1257, 1258, 1252, 1253, -72, -71, -70, -69, -68, -67, 1259, 1254, -547, -547, -542, -542, 742, 741, -66, -47, -18, -32766, 73, 148, 918, 322, 326, 1234, 273, -542, 284, -542, -542, 723, -32766, -32766, -32766, 726, -32766, -547, -32766, -542, -32766, 917, 147, -32766, -542, 288, 289, -298, -32766, -32766, -32766, -32766, 713, 279, -32766, -32766, -542, 1234, 280, 285, -32766, 419, 48, 286, -32766, -32766, -32766, 332, -32766, -32766, -32766, 292, -32766, 908, 293, -32766, 934, 274, 1030, 918, -32766, -32766, -32766, 110, 682, 132, -32766, -32766, 833, 146, -32766, 559, -32766, 419, 659, 374, 824, 435, 1349, 74, 1033, -32766, 296, 654, 1116, 908, 956, 957, 306, 714, 698, 522, 555, 303, 13, 310, 852, 952, -111, -111, -111, 700, 463, 492, 953, 283, 299, 300, -32766, 49, 675, 918, 304, 660, 1234, 676, 936, 1273, -32766, 10, 1263, -32766, -32766, -32766, 642, -32766, 918, -32766, 920, -32766, 707, -4, -32766, 126, 34, 918, 565, -32766, -32766, -32766, -32766, 0, 908, -32766, -32766, 0, 1234, 918, 0, -32766, 419, 0, 0, -32766, -32766, -32766, 717, -32766, -32766, -32766, 920, -32766, 707, 1033, -32766, 724, 1275, 0, 487, -32766, -32766, -32766, -32766, 301, 302, -32766, -32766, -507, 1234, 571, -497, -32766, 419, 607, 8, -32766, -32766, -32766, 372, -32766, -32766, -32766, 17, -32766, 908, 371, -32766, 832, 298, 320, 128, -32766, -32766, -32766, 40, 370, 41, -32766, -32766, 908, -250, -250, -250, -32766, 419, 731, 374, 973, 908, 707, 732, 899, -32766, 997, 974, 728, 981, 956, 957, 971, 908, 982, 522, 897, 969, 1090, 1093, 894, 952, -111, -111, -111, 28, 1094, 1091, 1092, -249, -249, -249, 1241, 1098, 708, 374, 844, 833, 1288, 1306, 1340, 1266, 647, 1267, 711, 715, 956, 957, 716, 1241, 718, 522, 920, 719, 707, -250, 894, 952, -111, -111, -111, 720, -16, 721, 725, 710, -511, 920, 895, 707, -578, 1232, 1344, 1346, 855, 854, 920, 1227, 707, -577, 863, 946, 989, 862, 1345, 945, 943, 944, 920, 947, 707, -249, 527, 1218, 1255, 1256, 1257, 1258, 1252, 1253, 927, 937, 925, 979, 980, 631, 1259, 1254, 1343, 1300, -32766, 1289, 1307, 833, 1316, -275, 1234, -576, 73, -550, -549, 322, 326, -32766, -32766, -32766, -548, -32766, -491, -32766, 833, -32766, 1, 29, -32766, 30, 39, 43, 47, -32766, -32766, -32766, 72, 76, 77, -32766, -32766, 1232, -111, -111, 78, -32766, 419, -111, 79, 80, 81, 143, 153, -111, -32766, 157, 246, 328, 1232, -111, -111, 356, -32766, 357, -111, 358, 359, 360, 361, 362, -111, 363, 364, 365, 366, 368, 436, 0, -273, -32766, -272, 19, 20, 298, 21, 22, 24, 405, 75, 1203, 483, 484, 326, 491, 0, 494, 495, 496, 497, 501, 298, 502, 503, 510, 693, 75, 0, 1245, 1186, 326, 1264, 1059, 1058, 1039, 1222, 1035, -277, -103, 18, 23, 27, 295, 404, 600, 604, 633, 699, 1190, 1240, 1187, 1319, 0, 0, 0, 326); + protected $actionCheck = array(2, 3, 4, 5, 6, 7, 0, 9, 10, 11, 12, 13, 70, 9, 10, 11, 9, 10, 11, 44, 45, 46, 47, 48, 49, 50, 51, 52, 116, 117, 118, 119, 120, 121, 122, 37, 38, 30, 116, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 8, 53, 54, 55, 57, 57, 106, 107, 137, 9, 10, 11, 50, 51, 52, 1, 116, 69, 71, 72, 73, 74, 75, 76, 77, 134, 135, 80, 1, 30, 30, 30, 32, 33, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 80, 70, 136, 137, 138, 139, 140, 141, 142, 143, 144, 8, 1, 106, 80, 108, 150, 151, 152, 8, 154, 9, 10, 11, 2, 3, 4, 5, 6, 7, 164, 9, 10, 11, 12, 13, 116, 119, 120, 121, 122, 106, 30, 108, 32, 33, 34, 35, 36, 37, 38, 9, 10, 11, 106, 107, 138, 137, 138, 37, 38, 9, 10, 11, 116, 134, 135, 1, 9, 10, 11, 137, 30, 14, 8, 155, 156, 157, 1, 57, 149, 163, 30, 163, 32, 33, 34, 35, 36, 155, 156, 157, 161, 71, 72, 73, 74, 75, 76, 77, 8, 31, 80, 129, 130, 131, 158, 161, 8, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 8, 80, 136, 137, 138, 139, 140, 141, 142, 143, 144, 164, 9, 10, 11, 160, 150, 151, 152, 164, 154, 2, 3, 4, 5, 6, 7, 80, 9, 10, 11, 12, 13, 30, 8, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 30, 57, 1, 8, 116, 117, 118, 119, 120, 121, 122, 160, 106, 69, 108, 164, 161, 57, 9, 10, 11, 9, 10, 161, 1, 1, 37, 38, 1, 167, 31, 71, 72, 73, 74, 75, 76, 77, 8, 30, 80, 32, 33, 34, 35, 14, 85, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 8, 122, 136, 137, 138, 139, 140, 141, 142, 143, 144, 8, 51, 146, 138, 82, 150, 151, 152, 2, 3, 4, 5, 6, 7, 106, 97, 108, 1, 12, 13, 101, 15, 9, 10, 11, 106, 80, 108, 163, 1, 80, 163, 113, 83, 8, 116, 117, 118, 119, 120, 121, 122, 123, 30, 8, 32, 33, 34, 8, 117, 118, 80, 31, 159, 122, 159, 50, 51, 8, 80, 128, 70, 56, 155, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 1, 70, 71, 72, 73, 74, 162, 9, 161, 78, 79, 80, 1, 82, 167, 164, 1, 86, 87, 88, 89, 122, 91, 101, 93, 84, 95, 156, 8, 98, 99, 8, 161, 138, 103, 104, 105, 106, 107, 8, 109, 110, 31, 97, 8, 123, 115, 116, 70, 8, 134, 135, 156, 122, 8, 124, 125, 126, 163, 155, 156, 157, 163, 116, 8, 149, 162, 136, 137, 8, 139, 140, 141, 142, 143, 144, 145, 161, 14, 163, 160, 82, 151, 152, 164, 138, 155, 156, 157, 158, 75, 76, 77, 14, 163, 84, 165, 166, 167, 84, 159, 116, 161, 82, 14, 90, 85, 92, 14, 94, 163, 96, 134, 135, 161, 116, 159, 1, 161, 14, 167, 106, 14, 138, 8, 164, 16, 149, 31, 164, 37, 38, 117, 118, 75, 76, 137, 122, 31, 161, 14, 163, 127, 128, 129, 130, 131, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 16, 163, 70, 75, 76, 167, 16, 147, 148, 159, 16, 161, 16, 159, 82, 161, 162, 16, 86, 16, 74, 70, 16, 70, 101, 102, 80, 106, 107, 59, 60, 106, 107, 87, 88, 89, 31, 91, 1, 93, 70, 95, 111, 112, 98, 16, 16, 16, 116, 103, 104, 105, 16, 31, 122, 109, 110, 37, 38, 16, 35, 115, 116, 31, 0, 1, 31, 30, 136, 137, 124, 139, 140, 141, 142, 143, 144, 31, 31, 31, 31, 31, 31, 151, 152, 134, 135, 134, 135, 37, 38, 31, 31, 31, 74, 163, 31, 1, 166, 167, 80, 31, 149, 31, 134, 135, 31, 87, 88, 89, 31, 91, 161, 93, 161, 95, 31, 31, 98, 149, 37, 37, 35, 103, 104, 105, 74, 31, 35, 109, 110, 161, 80, 35, 35, 115, 116, 70, 35, 87, 88, 89, 35, 91, 124, 93, 37, 95, 84, 37, 98, 38, 57, 116, 1, 103, 104, 105, 69, 77, 31, 109, 110, 82, 70, 85, 89, 115, 116, 96, 106, 80, 108, 83, 154, 138, 124, 113, 90, 82, 84, 117, 118, 114, 31, 80, 122, 85, 132, 97, 132, 127, 128, 129, 130, 131, 92, 97, 97, 128, 163, 134, 135, 74, 70, 94, 1, 133, 100, 80, 100, 154, 146, 137, 150, 160, 87, 88, 89, 113, 91, 1, 93, 159, 95, 161, 162, 98, 161, 161, 1, 153, 103, 104, 105, 74, -1, 84, 109, 110, -1, 80, 1, -1, 115, 116, -1, -1, 87, 88, 89, 31, 91, 124, 93, 159, 95, 161, 138, 98, 31, 146, -1, 102, 103, 104, 105, 74, 134, 135, 109, 110, 149, 80, 81, 149, 115, 116, 153, 149, 87, 88, 89, 149, 91, 124, 93, 149, 95, 84, 149, 98, 155, 158, 161, 161, 103, 104, 105, 159, 161, 159, 109, 110, 84, 100, 101, 102, 115, 116, 159, 106, 159, 84, 161, 159, 159, 124, 159, 159, 162, 159, 117, 118, 159, 84, 159, 122, 159, 159, 159, 159, 127, 128, 129, 130, 131, 70, 159, 159, 159, 100, 101, 102, 1, 159, 161, 106, 160, 82, 160, 160, 160, 86, 160, 166, 161, 161, 117, 118, 161, 1, 161, 122, 159, 161, 161, 162, 127, 128, 129, 130, 131, 161, 31, 161, 161, 161, 165, 159, 162, 161, 163, 116, 162, 162, 162, 162, 159, 122, 161, 163, 162, 162, 162, 162, 162, 162, 162, 162, 159, 162, 161, 162, 137, 162, 139, 140, 141, 142, 143, 144, 162, 162, 162, 162, 162, 162, 151, 152, 162, 162, 74, 162, 162, 82, 162, 164, 80, 163, 163, 163, 163, 166, 167, 87, 88, 89, 163, 91, 163, 93, 82, 95, 163, 163, 98, 163, 163, 163, 163, 103, 104, 105, 163, 163, 163, 109, 110, 116, 117, 118, 163, 115, 116, 122, 163, 163, 163, 163, 163, 128, 124, 163, 163, 163, 116, 117, 118, 163, 137, 163, 122, 163, 163, 163, 163, 163, 128, 163, 163, 163, 163, 163, 163, -1, 164, 137, 164, 164, 164, 158, 164, 164, 164, 164, 163, 165, 164, 164, 167, 164, -1, 164, 164, 164, 164, 164, 158, 164, 164, 164, 164, 163, -1, 164, 164, 167, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, -1, -1, -1, 167); + protected $actionBase = array(0, -2, 154, 542, 752, 893, 929, 52, 374, 431, 398, 869, 793, 235, 307, 307, 793, 307, 784, 908, 908, 917, 908, 538, 841, 468, 468, 468, 708, 708, 708, 708, 740, 740, 849, 849, 881, 817, 634, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 1036, 348, 346, 370, 653, 1063, 1069, 1065, 1070, 1061, 1060, 1064, 1066, 1071, 946, 947, 774, 949, 950, 943, 952, 1067, 882, 1062, 1068, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 525, 191, 359, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 174, 174, 174, 620, 620, 51, 465, 356, 955, 955, 955, 955, 955, 955, 955, 955, 955, 955, 658, 184, 144, 144, 7, 7, 7, 7, 7, 1031, 371, 1048, -25, -25, -25, -25, 50, 725, 526, 449, 39, 317, 80, 474, 474, 13, 13, 512, 512, 422, 422, 512, 512, 512, 808, 808, 808, 808, 443, 505, 360, 308, -78, 209, 209, 209, 209, -78, -78, -78, -78, 803, 877, -78, -78, -78, 63, 641, 641, 822, -1, -1, -1, 641, 253, 790, 548, 253, 384, 548, 480, 402, 764, 759, -49, 447, 764, 639, 755, 198, 143, 825, 609, 825, 1059, 320, 768, 426, 749, 720, 874, 904, 1072, 796, 941, 798, 942, 106, -58, 710, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1058, 1073, 336, 1059, 423, 1073, 1073, 1073, 336, 336, 336, 336, 336, 336, 336, 336, 336, 336, 619, 423, 586, 616, 423, 795, 336, 348, 814, 348, 348, 348, 348, 348, 348, 348, 348, 348, 348, 750, 202, 348, 346, 78, 78, 484, 65, 78, 78, 78, 78, 348, 348, 348, 348, 609, 783, 766, 613, 813, 492, 783, 783, 783, 473, 135, 378, 488, 713, 775, 67, 779, 779, 785, 969, 969, 779, 769, 779, 785, 975, 779, 779, 969, 969, 823, 280, 563, 478, 550, 568, 969, 377, 779, 779, 779, 779, 746, 573, 779, 342, 314, 779, 779, 746, 744, 760, 43, 762, 969, 969, 969, 746, 547, 762, 762, 762, 839, 844, 794, 758, 444, 433, 588, 232, 801, 758, 758, 779, 558, 794, 758, 794, 758, 745, 758, 758, 758, 794, 758, 769, 502, 758, 717, 583, 224, 758, 6, 979, 980, 624, 981, 973, 987, 1019, 991, 992, 873, 965, 999, 974, 993, 972, 970, 773, 682, 684, 818, 811, 963, 777, 777, 777, 956, 777, 777, 777, 777, 777, 777, 777, 777, 682, 743, 829, 765, 1006, 689, 691, 754, 906, 901, 1030, 1004, 1049, 994, 828, 694, 1028, 1008, 846, 821, 1009, 1010, 1029, 1050, 1052, 910, 782, 911, 912, 876, 1012, 883, 777, 979, 992, 693, 974, 993, 972, 970, 748, 739, 737, 738, 736, 735, 723, 734, 753, 1053, 954, 907, 878, 1011, 957, 682, 879, 1023, 756, 1032, 1033, 827, 788, 778, 880, 913, 1014, 1015, 1016, 884, 1054, 887, 830, 1024, 951, 1035, 789, 918, 1037, 1038, 1039, 1040, 889, 919, 892, 916, 900, 845, 776, 1020, 761, 920, 591, 787, 791, 800, 1018, 606, 1000, 902, 921, 922, 1041, 1043, 1044, 923, 924, 995, 847, 1026, 799, 1027, 1022, 848, 850, 617, 797, 1055, 781, 786, 772, 621, 632, 925, 927, 931, 998, 763, 770, 853, 855, 1056, 771, 1057, 938, 635, 857, 718, 939, 1046, 719, 724, 637, 678, 672, 731, 792, 903, 826, 757, 780, 1017, 724, 767, 858, 940, 859, 860, 867, 1045, 868, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 458, 458, 458, 458, 458, 458, 307, 307, 307, 307, 307, 307, 307, 0, 0, 307, 0, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 458, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 291, 66, 66, 291, 291, 291, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 0, 291, 291, 291, 291, 291, 291, 291, 291, 66, 823, 66, -1, -1, -1, -1, 66, 66, 66, -88, -88, 66, 384, 66, 66, -1, -1, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 0, 0, 423, 548, 66, 769, 769, 769, 769, 66, 66, 66, 66, 548, 548, 66, 66, 66, 0, 0, 0, 0, 0, 0, 0, 0, 423, 548, 0, 423, 0, 0, 769, 769, 66, 384, 823, 643, 66, 0, 0, 0, 0, 423, 769, 423, 336, 779, 548, 779, 336, 336, 78, 348, 643, 611, 611, 611, 611, 0, 0, 609, 823, 823, 823, 823, 823, 823, 823, 823, 823, 823, 823, 769, 0, 823, 0, 769, 769, 769, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 769, 0, 0, 969, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 975, 0, 0, 0, 0, 0, 0, 769, 0, 0, 0, 0, 0, 0, 0, 0, 0, 777, 788, 0, 788, 0, 777, 777, 777, 0, 0, 0, 0, 797, 771); + protected $actionDefault = array(3, 32767, 103, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 101, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 596, 596, 596, 596, 32767, 32767, 254, 103, 32767, 32767, 469, 387, 387, 387, 32767, 32767, 540, 540, 540, 540, 540, 540, 32767, 32767, 32767, 32767, 32767, 32767, 469, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 101, 32767, 32767, 32767, 37, 7, 8, 10, 11, 50, 17, 324, 32767, 32767, 32767, 32767, 103, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 589, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 473, 452, 453, 455, 456, 386, 541, 595, 327, 592, 385, 146, 339, 329, 242, 330, 258, 474, 259, 475, 478, 479, 215, 287, 382, 150, 151, 416, 470, 418, 468, 472, 417, 392, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 390, 391, 471, 449, 448, 447, 32767, 32767, 414, 415, 419, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 103, 32767, 389, 422, 420, 421, 438, 439, 436, 437, 440, 32767, 32767, 32767, 441, 442, 443, 444, 316, 32767, 32767, 366, 364, 316, 112, 32767, 32767, 429, 430, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 534, 446, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 103, 32767, 101, 536, 411, 413, 503, 424, 425, 423, 393, 32767, 510, 32767, 103, 32767, 512, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 535, 32767, 542, 542, 32767, 496, 101, 195, 32767, 32767, 32767, 195, 195, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 603, 496, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 32767, 195, 111, 32767, 32767, 32767, 101, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 190, 32767, 268, 270, 103, 557, 195, 32767, 515, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 508, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 496, 434, 139, 32767, 139, 542, 426, 427, 428, 498, 542, 542, 542, 312, 289, 32767, 32767, 32767, 32767, 513, 513, 101, 101, 101, 101, 508, 32767, 32767, 32767, 32767, 112, 100, 100, 100, 100, 100, 104, 102, 32767, 32767, 32767, 32767, 223, 100, 32767, 102, 102, 32767, 32767, 223, 225, 212, 102, 227, 32767, 561, 562, 223, 102, 227, 227, 227, 247, 247, 485, 318, 102, 100, 102, 102, 197, 318, 318, 32767, 102, 485, 318, 485, 318, 199, 318, 318, 318, 485, 318, 32767, 102, 318, 214, 100, 100, 318, 32767, 32767, 32767, 498, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 222, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 529, 32767, 546, 559, 432, 433, 435, 544, 457, 458, 459, 460, 461, 462, 463, 465, 591, 32767, 502, 32767, 32767, 32767, 338, 601, 32767, 601, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 602, 32767, 542, 32767, 32767, 32767, 32767, 431, 9, 76, 491, 43, 44, 52, 58, 519, 520, 521, 522, 516, 517, 523, 518, 32767, 32767, 524, 567, 32767, 32767, 543, 594, 32767, 32767, 32767, 32767, 32767, 32767, 139, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 529, 32767, 137, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 525, 32767, 32767, 32767, 542, 32767, 32767, 32767, 32767, 314, 311, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 542, 32767, 32767, 32767, 32767, 32767, 291, 32767, 308, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 286, 32767, 32767, 381, 498, 294, 296, 297, 32767, 32767, 32767, 32767, 360, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, 153, 153, 3, 3, 341, 153, 153, 153, 341, 341, 153, 341, 341, 341, 153, 153, 153, 153, 153, 153, 280, 185, 262, 265, 247, 247, 153, 352, 153); + protected $goto = array(196, 196, 1031, 703, 694, 430, 658, 1062, 1334, 1334, 424, 313, 314, 335, 573, 319, 429, 336, 431, 635, 651, 652, 850, 669, 670, 671, 1334, 167, 167, 167, 167, 221, 197, 193, 193, 177, 179, 216, 193, 193, 193, 193, 193, 194, 194, 194, 194, 194, 194, 188, 189, 190, 191, 192, 218, 216, 219, 534, 535, 420, 536, 538, 539, 540, 541, 542, 543, 544, 545, 1132, 168, 169, 170, 195, 171, 172, 173, 166, 174, 175, 176, 178, 215, 217, 220, 238, 243, 244, 245, 257, 258, 259, 260, 261, 262, 263, 264, 268, 269, 270, 271, 281, 282, 316, 317, 318, 425, 426, 427, 578, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 180, 237, 181, 198, 199, 200, 239, 188, 189, 190, 191, 192, 218, 1132, 201, 182, 183, 184, 202, 198, 185, 240, 203, 201, 165, 204, 205, 186, 206, 207, 208, 187, 209, 210, 211, 212, 213, 214, 853, 851, 278, 278, 278, 278, 418, 620, 620, 350, 570, 597, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1265, 1283, 1283, 831, 618, 655, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 353, 353, 353, 353, 866, 557, 550, 858, 825, 907, 902, 903, 916, 859, 904, 856, 905, 906, 857, 878, 457, 910, 865, 884, 546, 546, 546, 546, 831, 601, 831, 1084, 1079, 1080, 1081, 341, 550, 557, 566, 567, 343, 576, 599, 613, 614, 407, 408, 972, 465, 465, 667, 15, 668, 1323, 411, 412, 413, 465, 681, 348, 1233, 414, 1233, 478, 569, 346, 439, 1031, 1031, 1233, 993, 480, 1031, 393, 1031, 1031, 1104, 1105, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1315, 1315, 1315, 1315, 1233, 657, 1333, 1333, 1055, 1233, 1233, 1233, 1233, 1037, 1036, 1233, 1233, 1233, 1034, 1034, 1181, 354, 678, 949, 1333, 437, 1026, 1042, 1043, 337, 691, 354, 354, 827, 923, 691, 1040, 1041, 924, 691, 663, 1336, 939, 871, 939, 354, 354, 1281, 1281, 354, 679, 1350, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 552, 537, 537, 911, 354, 912, 537, 537, 537, 537, 537, 537, 537, 537, 537, 537, 548, 564, 548, 574, 611, 730, 634, 636, 849, 548, 656, 475, 1308, 1309, 680, 684, 1007, 692, 701, 1003, 252, 252, 996, 970, 970, 968, 970, 729, 843, 549, 1005, 1000, 423, 455, 608, 1294, 846, 955, 966, 966, 966, 966, 325, 308, 455, 960, 967, 249, 249, 249, 249, 251, 253, 402, 351, 352, 683, 868, 551, 561, 449, 449, 449, 551, 1305, 561, 1305, 612, 396, 461, 1010, 1010, 1224, 1305, 395, 398, 558, 598, 602, 1015, 468, 577, 469, 470, 1310, 1311, 876, 552, 846, 1341, 1342, 964, 409, 702, 733, 324, 275, 324, 1317, 1317, 1317, 1317, 606, 621, 624, 625, 626, 627, 648, 649, 650, 705, 1068, 596, 1097, 874, 706, 476, 1228, 507, 697, 880, 1095, 1115, 432, 1301, 628, 630, 632, 432, 879, 867, 1067, 1071, 5, 1072, 6, 1038, 1038, 977, 0, 975, 662, 1049, 1045, 1046, 0, 0, 0, 0, 1226, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, 928, 1120, 449, 965, 1070, 0, 0, 616, 1303, 1303, 1070, 1229, 1230, 1012, 499, 0, 500, 0, 0, 841, 0, 870, 506, 661, 991, 1113, 883, 1212, 941, 864, 0, 1213, 1216, 942, 1217, 0, 0, 1231, 1291, 1292, 0, 1223, 0, 0, 0, 846, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255); + protected $gotoCheck = array(42, 42, 72, 9, 72, 65, 65, 126, 181, 181, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 85, 85, 26, 85, 85, 85, 181, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 15, 27, 23, 23, 23, 23, 43, 107, 107, 96, 170, 129, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 168, 168, 12, 55, 55, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 24, 24, 24, 24, 35, 75, 75, 15, 6, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 35, 82, 15, 35, 45, 106, 106, 106, 106, 12, 106, 12, 15, 15, 15, 15, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 81, 81, 49, 148, 148, 81, 75, 81, 179, 81, 81, 81, 148, 81, 177, 72, 81, 72, 83, 103, 81, 82, 72, 72, 72, 102, 83, 72, 61, 72, 72, 143, 143, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 9, 9, 9, 9, 72, 63, 180, 180, 113, 72, 72, 72, 72, 117, 117, 72, 72, 72, 88, 88, 150, 14, 88, 88, 180, 112, 88, 88, 88, 29, 7, 14, 14, 7, 72, 7, 118, 118, 72, 7, 119, 180, 9, 39, 9, 14, 14, 169, 169, 14, 115, 14, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 14, 171, 171, 64, 14, 64, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 19, 48, 19, 2, 2, 48, 48, 48, 25, 19, 48, 174, 174, 174, 48, 48, 48, 48, 48, 48, 5, 5, 25, 25, 25, 25, 25, 25, 18, 25, 25, 25, 13, 19, 13, 14, 22, 91, 19, 19, 19, 19, 167, 167, 19, 19, 19, 5, 5, 5, 5, 5, 5, 28, 96, 96, 14, 37, 9, 9, 23, 23, 23, 9, 129, 9, 129, 79, 9, 9, 106, 106, 159, 129, 58, 58, 58, 58, 58, 109, 9, 9, 9, 9, 176, 176, 9, 14, 22, 9, 9, 92, 92, 92, 98, 24, 24, 24, 129, 129, 129, 129, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 128, 8, 8, 9, 8, 156, 20, 8, 8, 41, 8, 146, 116, 129, 84, 84, 84, 116, 16, 16, 16, 16, 46, 131, 46, 116, 116, 95, -1, 16, 116, 116, 116, 116, -1, -1, -1, -1, 14, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 17, 17, 23, 16, 129, -1, -1, 17, 129, 129, 129, 20, 20, 17, 154, -1, 154, -1, -1, 20, -1, 17, 154, 17, 17, 16, 16, 78, 78, 17, -1, 78, 78, 78, 78, -1, -1, 20, 20, 20, -1, 17, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 5); + protected $gotoBase = array(0, 0, -339, 0, 0, 386, 195, 312, 472, -10, 0, 0, -109, 62, 13, -184, 46, 65, 86, 102, 93, 0, 125, 162, 197, 371, 18, 160, 83, 22, 0, 0, 0, 0, 0, -166, 0, 85, 0, 9, 0, 48, -1, 157, 0, 207, -232, 0, -340, 223, 0, 0, 0, 0, 0, 148, 0, 0, 396, 0, 0, 231, 0, 52, 334, -236, 0, 0, 0, 0, 0, 0, -5, 0, 0, -139, 0, 0, 149, 91, 112, -245, -58, -205, 15, -695, 0, 0, 28, 0, 0, 75, 154, 0, 0, 64, -310, 0, 55, 0, 0, 0, 235, 221, 0, 0, 196, -71, 0, 77, 0, 0, 37, 24, 0, 56, 219, 23, 40, 39, 0, 0, 0, 0, 0, 0, 5, 0, 106, 166, 0, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 47, 0, 214, 0, 35, 0, 0, 0, 49, 0, 45, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 88, -56, 95, 144, 111, 0, 0, 78, 0, 80, 229, 0, 222, -12, -299, 0, 0); + protected $gotoDefault = array(-32768, 511, 737, 4, 738, 932, 814, 823, 594, 528, 704, 347, 622, 421, 1299, 909, 1119, 575, 842, 1242, 1250, 456, 845, 330, 727, 891, 892, 893, 399, 385, 391, 397, 646, 623, 493, 877, 452, 869, 485, 872, 451, 881, 164, 417, 509, 885, 3, 888, 554, 919, 386, 896, 387, 674, 898, 560, 900, 901, 394, 400, 401, 1124, 568, 619, 913, 256, 562, 914, 384, 915, 922, 389, 392, 685, 464, 504, 498, 410, 1099, 563, 605, 643, 446, 472, 617, 629, 615, 479, 433, 415, 329, 954, 962, 486, 462, 976, 349, 984, 735, 1131, 637, 488, 992, 638, 999, 1002, 529, 530, 477, 1014, 272, 1017, 489, 12, 664, 1028, 1029, 665, 639, 1051, 640, 666, 641, 1053, 471, 595, 1061, 453, 1069, 1287, 454, 1073, 266, 1076, 277, 416, 434, 1082, 1083, 9, 1089, 695, 696, 11, 276, 508, 1114, 686, 450, 1130, 438, 1200, 1202, 556, 490, 1220, 1219, 677, 505, 1225, 447, 1290, 448, 531, 473, 315, 532, 307, 333, 312, 547, 294, 334, 533, 474, 1296, 1304, 331, 31, 1324, 1335, 342, 572, 610); + protected $ruleToNonTerminal = array(0, 1, 3, 3, 2, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 9, 10, 11, 11, 11, 12, 12, 13, 13, 14, 15, 15, 16, 16, 17, 17, 18, 18, 21, 21, 22, 23, 23, 24, 24, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 29, 29, 30, 30, 32, 34, 34, 28, 36, 36, 33, 38, 38, 35, 35, 37, 37, 39, 39, 31, 40, 40, 41, 43, 44, 44, 45, 45, 46, 46, 48, 47, 47, 47, 47, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 25, 25, 68, 68, 71, 71, 70, 69, 69, 62, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 26, 26, 27, 27, 27, 27, 27, 87, 87, 89, 89, 82, 82, 90, 90, 91, 91, 91, 83, 83, 86, 86, 84, 84, 92, 93, 93, 56, 56, 64, 64, 67, 67, 67, 66, 94, 94, 95, 57, 57, 57, 57, 96, 96, 97, 97, 98, 98, 99, 100, 100, 101, 101, 102, 102, 54, 54, 50, 50, 104, 52, 52, 105, 51, 51, 53, 53, 63, 63, 63, 63, 80, 80, 108, 108, 110, 110, 111, 111, 111, 111, 109, 109, 109, 113, 113, 113, 113, 88, 88, 116, 116, 116, 117, 117, 114, 114, 118, 118, 120, 120, 121, 121, 115, 122, 122, 119, 123, 123, 123, 123, 112, 112, 81, 81, 81, 20, 20, 20, 125, 124, 124, 126, 126, 126, 126, 59, 127, 127, 128, 60, 130, 130, 131, 131, 132, 132, 85, 133, 133, 133, 133, 133, 133, 133, 138, 138, 139, 139, 140, 140, 140, 140, 140, 141, 142, 142, 137, 137, 134, 134, 136, 136, 144, 144, 143, 143, 143, 143, 143, 143, 143, 135, 145, 145, 147, 146, 146, 61, 103, 148, 148, 55, 55, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 155, 149, 149, 154, 154, 157, 158, 158, 159, 160, 161, 161, 161, 161, 19, 19, 72, 72, 72, 72, 150, 150, 150, 150, 163, 163, 151, 151, 153, 153, 153, 156, 156, 168, 168, 168, 168, 168, 168, 168, 168, 168, 169, 169, 169, 107, 171, 171, 171, 171, 152, 152, 152, 152, 152, 152, 152, 152, 58, 58, 166, 166, 166, 166, 172, 172, 162, 162, 162, 173, 173, 173, 173, 173, 173, 73, 73, 65, 65, 65, 65, 129, 129, 129, 129, 176, 175, 165, 165, 165, 165, 165, 165, 165, 164, 164, 164, 174, 174, 174, 174, 106, 170, 178, 178, 177, 177, 179, 179, 179, 179, 179, 179, 179, 179, 167, 167, 167, 167, 181, 182, 180, 180, 180, 180, 180, 180, 180, 180, 183, 183, 183, 183); + protected $ruleToLength = array(1, 1, 2, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 2, 1, 3, 4, 1, 2, 0, 1, 1, 1, 1, 1, 3, 5, 4, 3, 4, 2, 3, 1, 1, 7, 6, 2, 3, 1, 2, 3, 1, 2, 3, 1, 1, 3, 1, 3, 1, 2, 2, 3, 1, 3, 2, 3, 1, 3, 3, 2, 0, 1, 1, 1, 1, 1, 3, 7, 10, 5, 7, 9, 5, 3, 3, 3, 3, 3, 3, 1, 2, 5, 7, 9, 6, 5, 6, 3, 2, 1, 1, 1, 0, 2, 1, 3, 8, 0, 4, 2, 1, 3, 0, 1, 0, 1, 0, 1, 3, 1, 1, 1, 8, 9, 7, 8, 7, 6, 8, 0, 2, 0, 2, 1, 2, 1, 2, 1, 1, 1, 0, 2, 0, 2, 0, 2, 2, 1, 3, 1, 4, 1, 4, 1, 1, 4, 2, 1, 3, 3, 3, 4, 4, 5, 0, 2, 4, 3, 1, 1, 7, 0, 2, 1, 3, 3, 4, 1, 4, 0, 2, 5, 0, 2, 6, 0, 2, 0, 3, 1, 2, 1, 1, 2, 0, 1, 3, 0, 2, 1, 1, 1, 1, 6, 8, 6, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 1, 3, 3, 3, 3, 3, 1, 3, 3, 1, 1, 2, 1, 1, 0, 1, 0, 2, 2, 2, 4, 3, 1, 1, 3, 1, 2, 2, 3, 2, 3, 1, 1, 2, 3, 1, 1, 3, 2, 0, 1, 5, 5, 6, 10, 3, 5, 1, 1, 3, 0, 2, 4, 5, 4, 4, 4, 3, 1, 1, 1, 1, 1, 1, 0, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 3, 1, 1, 3, 2, 2, 3, 1, 0, 1, 1, 3, 3, 3, 4, 1, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 4, 3, 4, 4, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 3, 2, 1, 2, 4, 2, 2, 8, 9, 8, 9, 9, 10, 9, 10, 8, 3, 2, 0, 4, 2, 1, 3, 2, 1, 2, 2, 2, 4, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 0, 3, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 5, 3, 3, 4, 1, 1, 3, 1, 1, 1, 1, 1, 3, 2, 3, 0, 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, 1, 4, 4, 1, 4, 4, 0, 1, 1, 1, 3, 3, 1, 4, 2, 2, 1, 3, 1, 4, 4, 3, 3, 3, 3, 1, 3, 1, 1, 3, 1, 1, 4, 1, 1, 1, 3, 1, 1, 2, 1, 3, 4, 3, 2, 0, 2, 2, 1, 2, 1, 1, 1, 4, 3, 3, 3, 3, 6, 3, 1, 1, 2, 1); + protected function initReduceCallbacks() + { + $this->reduceCallbacks = [0 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 1 => function ($stackPos) { + $this->semValue = $this->handleNamespaces($this->semStack[$stackPos - (1 - 1)]); + }, 2 => function ($stackPos) { + if (\is_array($this->semStack[$stackPos - (2 - 2)])) { + $this->semValue = \array_merge($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)]); + } else { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + } + }, 3 => function ($stackPos) { + $this->semValue = array(); + }, 4 => function ($stackPos) { + $startAttributes = $this->lookaheadStartAttributes; + if (isset($startAttributes['comments'])) { + $nop = new Stmt\Nop($this->createCommentNopAttributes($startAttributes['comments'])); + } else { + $nop = null; + } + if ($nop !== null) { + $this->semStack[$stackPos - (1 - 1)][] = $nop; + } + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 5 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 6 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 7 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 8 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 9 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 10 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 11 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 12 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 13 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 14 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 15 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 16 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 17 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 18 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 19 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 20 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 21 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 22 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 23 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 24 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 25 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 26 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 27 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 28 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 29 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 30 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 31 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 32 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 33 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 34 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 35 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 36 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 37 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 38 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 39 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 40 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 41 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 42 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 43 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 44 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 45 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 46 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 47 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 48 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 49 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 50 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 51 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 52 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 53 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 54 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 55 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 56 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 57 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 58 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 59 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 60 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 61 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 62 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 63 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 64 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 65 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 66 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 67 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 68 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 69 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 70 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 71 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 72 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 73 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 74 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 75 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 76 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 77 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 78 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 79 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 80 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 81 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 82 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 83 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 84 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 85 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 86 => function ($stackPos) { + $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 87 => function ($stackPos) { + $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 88 => function ($stackPos) { + $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 89 => function ($stackPos) { + $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 90 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 91 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 92 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 93 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 94 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 95 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 96 => function ($stackPos) { + $this->semValue = new Name(\substr($this->semStack[$stackPos - (1 - 1)], 1), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 97 => function ($stackPos) { + $this->semValue = new Expr\Variable(\substr($this->semStack[$stackPos - (1 - 1)], 1), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 98 => function ($stackPos) { + /* nothing */ + }, 99 => function ($stackPos) { + /* nothing */ + }, 100 => function ($stackPos) { + /* nothing */ + }, 101 => function ($stackPos) { + $this->emitError(new Error('A trailing comma is not allowed here', $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes)); + }, 102 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 103 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 104 => function ($stackPos) { + $this->semValue = new Node\Attribute($this->semStack[$stackPos - (1 - 1)], [], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 105 => function ($stackPos) { + $this->semValue = new Node\Attribute($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 106 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 107 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 108 => function ($stackPos) { + $this->semValue = new Node\AttributeGroup($this->semStack[$stackPos - (4 - 2)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 109 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 110 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 111 => function ($stackPos) { + $this->semValue = []; + }, 112 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 113 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 114 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 115 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 116 => function ($stackPos) { + $this->semValue = new Stmt\HaltCompiler($this->lexer->handleHaltCompiler(), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 117 => function ($stackPos) { + $this->semValue = new Stmt\Namespace_($this->semStack[$stackPos - (3 - 2)], null, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + $this->semValue->setAttribute('kind', Stmt\Namespace_::KIND_SEMICOLON); + $this->checkNamespace($this->semValue); + }, 118 => function ($stackPos) { + $this->semValue = new Stmt\Namespace_($this->semStack[$stackPos - (5 - 2)], $this->semStack[$stackPos - (5 - 4)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + $this->semValue->setAttribute('kind', Stmt\Namespace_::KIND_BRACED); + $this->checkNamespace($this->semValue); + }, 119 => function ($stackPos) { + $this->semValue = new Stmt\Namespace_(null, $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + $this->semValue->setAttribute('kind', Stmt\Namespace_::KIND_BRACED); + $this->checkNamespace($this->semValue); + }, 120 => function ($stackPos) { + $this->semValue = new Stmt\Use_($this->semStack[$stackPos - (3 - 2)], Stmt\Use_::TYPE_NORMAL, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 121 => function ($stackPos) { + $this->semValue = new Stmt\Use_($this->semStack[$stackPos - (4 - 3)], $this->semStack[$stackPos - (4 - 2)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 122 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 123 => function ($stackPos) { + $this->semValue = new Stmt\Const_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 124 => function ($stackPos) { + $this->semValue = Stmt\Use_::TYPE_FUNCTION; + }, 125 => function ($stackPos) { + $this->semValue = Stmt\Use_::TYPE_CONSTANT; + }, 126 => function ($stackPos) { + $this->semValue = new Stmt\GroupUse($this->semStack[$stackPos - (7 - 3)], $this->semStack[$stackPos - (7 - 6)], $this->semStack[$stackPos - (7 - 2)], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); + }, 127 => function ($stackPos) { + $this->semValue = new Stmt\GroupUse($this->semStack[$stackPos - (6 - 2)], $this->semStack[$stackPos - (6 - 5)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + }, 128 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 129 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 130 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 131 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 132 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 133 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 134 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 135 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 136 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 137 => function ($stackPos) { + $this->semValue = new Stmt\UseUse($this->semStack[$stackPos - (1 - 1)], null, Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + $this->checkUseUse($this->semValue, $stackPos - (1 - 1)); + }, 138 => function ($stackPos) { + $this->semValue = new Stmt\UseUse($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + $this->checkUseUse($this->semValue, $stackPos - (3 - 3)); + }, 139 => function ($stackPos) { + $this->semValue = new Stmt\UseUse($this->semStack[$stackPos - (1 - 1)], null, Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + $this->checkUseUse($this->semValue, $stackPos - (1 - 1)); + }, 140 => function ($stackPos) { + $this->semValue = new Stmt\UseUse($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + $this->checkUseUse($this->semValue, $stackPos - (3 - 3)); + }, 141 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + $this->semValue->type = Stmt\Use_::TYPE_NORMAL; + }, 142 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue->type = $this->semStack[$stackPos - (2 - 1)]; + }, 143 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 144 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 145 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 146 => function ($stackPos) { + $this->semValue = new Node\Const_($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 147 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 148 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 149 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 150 => function ($stackPos) { + $this->semValue = new Node\Const_(new Node\Identifier($this->semStack[$stackPos - (3 - 1)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributeStack[$stackPos - (3 - 1)]), $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 151 => function ($stackPos) { + $this->semValue = new Node\Const_(new Node\Identifier($this->semStack[$stackPos - (3 - 1)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributeStack[$stackPos - (3 - 1)]), $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 152 => function ($stackPos) { + if (\is_array($this->semStack[$stackPos - (2 - 2)])) { + $this->semValue = \array_merge($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)]); + } else { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + } + }, 153 => function ($stackPos) { + $this->semValue = array(); + }, 154 => function ($stackPos) { + $startAttributes = $this->lookaheadStartAttributes; + if (isset($startAttributes['comments'])) { + $nop = new Stmt\Nop($this->createCommentNopAttributes($startAttributes['comments'])); + } else { + $nop = null; + } + if ($nop !== null) { + $this->semStack[$stackPos - (1 - 1)][] = $nop; + } + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 155 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 156 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 157 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 158 => function ($stackPos) { + throw new Error('__HALT_COMPILER() can only be used from the outermost scope', $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 159 => function ($stackPos) { + if ($this->semStack[$stackPos - (3 - 2)]) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + $attrs = $this->startAttributeStack[$stackPos - (3 - 1)]; + $stmts = $this->semValue; + if (!empty($attrs['comments'])) { + $stmts[0]->setAttribute('comments', \array_merge($attrs['comments'], $stmts[0]->getAttribute('comments', []))); + } + } else { + $startAttributes = $this->startAttributeStack[$stackPos - (3 - 1)]; + if (isset($startAttributes['comments'])) { + $this->semValue = new Stmt\Nop($startAttributes + $this->endAttributes); + } else { + $this->semValue = null; + } + if (null === $this->semValue) { + $this->semValue = array(); + } + } + }, 160 => function ($stackPos) { + $this->semValue = new Stmt\If_($this->semStack[$stackPos - (7 - 3)], ['stmts' => \is_array($this->semStack[$stackPos - (7 - 5)]) ? $this->semStack[$stackPos - (7 - 5)] : array($this->semStack[$stackPos - (7 - 5)]), 'elseifs' => $this->semStack[$stackPos - (7 - 6)], 'else' => $this->semStack[$stackPos - (7 - 7)]], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); + }, 161 => function ($stackPos) { + $this->semValue = new Stmt\If_($this->semStack[$stackPos - (10 - 3)], ['stmts' => $this->semStack[$stackPos - (10 - 6)], 'elseifs' => $this->semStack[$stackPos - (10 - 7)], 'else' => $this->semStack[$stackPos - (10 - 8)]], $this->startAttributeStack[$stackPos - (10 - 1)] + $this->endAttributes); + }, 162 => function ($stackPos) { + $this->semValue = new Stmt\While_($this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 5)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 163 => function ($stackPos) { + $this->semValue = new Stmt\Do_($this->semStack[$stackPos - (7 - 5)], \is_array($this->semStack[$stackPos - (7 - 2)]) ? $this->semStack[$stackPos - (7 - 2)] : array($this->semStack[$stackPos - (7 - 2)]), $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); + }, 164 => function ($stackPos) { + $this->semValue = new Stmt\For_(['init' => $this->semStack[$stackPos - (9 - 3)], 'cond' => $this->semStack[$stackPos - (9 - 5)], 'loop' => $this->semStack[$stackPos - (9 - 7)], 'stmts' => $this->semStack[$stackPos - (9 - 9)]], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); + }, 165 => function ($stackPos) { + $this->semValue = new Stmt\Switch_($this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 5)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 166 => function ($stackPos) { + $this->semValue = new Stmt\Break_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 167 => function ($stackPos) { + $this->semValue = new Stmt\Continue_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 168 => function ($stackPos) { + $this->semValue = new Stmt\Return_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 169 => function ($stackPos) { + $this->semValue = new Stmt\Global_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 170 => function ($stackPos) { + $this->semValue = new Stmt\Static_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 171 => function ($stackPos) { + $this->semValue = new Stmt\Echo_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 172 => function ($stackPos) { + $this->semValue = new Stmt\InlineHTML($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 173 => function ($stackPos) { + $e = $this->semStack[$stackPos - (2 - 1)]; + if ($e instanceof Expr\Throw_) { + // For backwards-compatibility reasons, convert throw in statement position into + // Stmt\Throw_ rather than Stmt\Expression(Expr\Throw_). + $this->semValue = new Stmt\Throw_($e->expr, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + } else { + $this->semValue = new Stmt\Expression($e, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + } + }, 174 => function ($stackPos) { + $this->semValue = new Stmt\Unset_($this->semStack[$stackPos - (5 - 3)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 175 => function ($stackPos) { + $this->semValue = new Stmt\Foreach_($this->semStack[$stackPos - (7 - 3)], $this->semStack[$stackPos - (7 - 5)][0], ['keyVar' => null, 'byRef' => $this->semStack[$stackPos - (7 - 5)][1], 'stmts' => $this->semStack[$stackPos - (7 - 7)]], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); + }, 176 => function ($stackPos) { + $this->semValue = new Stmt\Foreach_($this->semStack[$stackPos - (9 - 3)], $this->semStack[$stackPos - (9 - 7)][0], ['keyVar' => $this->semStack[$stackPos - (9 - 5)], 'byRef' => $this->semStack[$stackPos - (9 - 7)][1], 'stmts' => $this->semStack[$stackPos - (9 - 9)]], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); + }, 177 => function ($stackPos) { + $this->semValue = new Stmt\Foreach_($this->semStack[$stackPos - (6 - 3)], new Expr\Error($this->startAttributeStack[$stackPos - (6 - 4)] + $this->endAttributeStack[$stackPos - (6 - 4)]), ['stmts' => $this->semStack[$stackPos - (6 - 6)]], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + }, 178 => function ($stackPos) { + $this->semValue = new Stmt\Declare_($this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 5)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 179 => function ($stackPos) { + $this->semValue = new Stmt\TryCatch($this->semStack[$stackPos - (6 - 3)], $this->semStack[$stackPos - (6 - 5)], $this->semStack[$stackPos - (6 - 6)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + $this->checkTryCatch($this->semValue); + }, 180 => function ($stackPos) { + $this->semValue = new Stmt\Goto_($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 181 => function ($stackPos) { + $this->semValue = new Stmt\Label($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 182 => function ($stackPos) { + $this->semValue = array(); + /* means: no statement */ + }, 183 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 184 => function ($stackPos) { + $startAttributes = $this->startAttributeStack[$stackPos - (1 - 1)]; + if (isset($startAttributes['comments'])) { + $this->semValue = new Stmt\Nop($startAttributes + $this->endAttributes); + } else { + $this->semValue = null; + } + if ($this->semValue === null) { + $this->semValue = array(); + } + /* means: no statement */ + }, 185 => function ($stackPos) { + $this->semValue = array(); + }, 186 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 187 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 188 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 189 => function ($stackPos) { + $this->semValue = new Stmt\Catch_($this->semStack[$stackPos - (8 - 3)], $this->semStack[$stackPos - (8 - 4)], $this->semStack[$stackPos - (8 - 7)], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes); + }, 190 => function ($stackPos) { + $this->semValue = null; + }, 191 => function ($stackPos) { + $this->semValue = new Stmt\Finally_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 192 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 193 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 194 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 195 => function ($stackPos) { + $this->semValue = \false; + }, 196 => function ($stackPos) { + $this->semValue = \true; + }, 197 => function ($stackPos) { + $this->semValue = \false; + }, 198 => function ($stackPos) { + $this->semValue = \true; + }, 199 => function ($stackPos) { + $this->semValue = \false; + }, 200 => function ($stackPos) { + $this->semValue = \true; + }, 201 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 202 => function ($stackPos) { + $this->semValue = []; + }, 203 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 204 => function ($stackPos) { + $this->semValue = new Node\Identifier($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 205 => function ($stackPos) { + $this->semValue = new Stmt\Function_($this->semStack[$stackPos - (8 - 3)], ['byRef' => $this->semStack[$stackPos - (8 - 2)], 'params' => $this->semStack[$stackPos - (8 - 5)], 'returnType' => $this->semStack[$stackPos - (8 - 7)], 'stmts' => $this->semStack[$stackPos - (8 - 8)], 'attrGroups' => []], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes); + }, 206 => function ($stackPos) { + $this->semValue = new Stmt\Function_($this->semStack[$stackPos - (9 - 4)], ['byRef' => $this->semStack[$stackPos - (9 - 3)], 'params' => $this->semStack[$stackPos - (9 - 6)], 'returnType' => $this->semStack[$stackPos - (9 - 8)], 'stmts' => $this->semStack[$stackPos - (9 - 9)], 'attrGroups' => $this->semStack[$stackPos - (9 - 1)]], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); + }, 207 => function ($stackPos) { + $this->semValue = new Stmt\Class_($this->semStack[$stackPos - (7 - 2)], ['type' => $this->semStack[$stackPos - (7 - 1)], 'extends' => $this->semStack[$stackPos - (7 - 3)], 'implements' => $this->semStack[$stackPos - (7 - 4)], 'stmts' => $this->semStack[$stackPos - (7 - 6)], 'attrGroups' => []], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); + $this->checkClass($this->semValue, $stackPos - (7 - 2)); + }, 208 => function ($stackPos) { + $this->semValue = new Stmt\Class_($this->semStack[$stackPos - (8 - 3)], ['type' => $this->semStack[$stackPos - (8 - 2)], 'extends' => $this->semStack[$stackPos - (8 - 4)], 'implements' => $this->semStack[$stackPos - (8 - 5)], 'stmts' => $this->semStack[$stackPos - (8 - 7)], 'attrGroups' => $this->semStack[$stackPos - (8 - 1)]], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes); + $this->checkClass($this->semValue, $stackPos - (8 - 3)); + }, 209 => function ($stackPos) { + $this->semValue = new Stmt\Interface_($this->semStack[$stackPos - (7 - 3)], ['extends' => $this->semStack[$stackPos - (7 - 4)], 'stmts' => $this->semStack[$stackPos - (7 - 6)], 'attrGroups' => $this->semStack[$stackPos - (7 - 1)]], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); + $this->checkInterface($this->semValue, $stackPos - (7 - 3)); + }, 210 => function ($stackPos) { + $this->semValue = new Stmt\Trait_($this->semStack[$stackPos - (6 - 3)], ['stmts' => $this->semStack[$stackPos - (6 - 5)], 'attrGroups' => $this->semStack[$stackPos - (6 - 1)]], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + }, 211 => function ($stackPos) { + $this->semValue = new Stmt\Enum_($this->semStack[$stackPos - (8 - 3)], ['scalarType' => $this->semStack[$stackPos - (8 - 4)], 'implements' => $this->semStack[$stackPos - (8 - 5)], 'stmts' => $this->semStack[$stackPos - (8 - 7)], 'attrGroups' => $this->semStack[$stackPos - (8 - 1)]], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes); + $this->checkEnum($this->semValue, $stackPos - (8 - 3)); + }, 212 => function ($stackPos) { + $this->semValue = null; + }, 213 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 2)]; + }, 214 => function ($stackPos) { + $this->semValue = null; + }, 215 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 2)]; + }, 216 => function ($stackPos) { + $this->semValue = 0; + }, 217 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 218 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 219 => function ($stackPos) { + $this->checkClassModifier($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $stackPos - (2 - 2)); + $this->semValue = $this->semStack[$stackPos - (2 - 1)] | $this->semStack[$stackPos - (2 - 2)]; + }, 220 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_ABSTRACT; + }, 221 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_FINAL; + }, 222 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_READONLY; + }, 223 => function ($stackPos) { + $this->semValue = null; + }, 224 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 2)]; + }, 225 => function ($stackPos) { + $this->semValue = array(); + }, 226 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 2)]; + }, 227 => function ($stackPos) { + $this->semValue = array(); + }, 228 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 2)]; + }, 229 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 230 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 231 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 232 => function ($stackPos) { + $this->semValue = \is_array($this->semStack[$stackPos - (1 - 1)]) ? $this->semStack[$stackPos - (1 - 1)] : array($this->semStack[$stackPos - (1 - 1)]); + }, 233 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 2)]; + }, 234 => function ($stackPos) { + $this->semValue = \is_array($this->semStack[$stackPos - (1 - 1)]) ? $this->semStack[$stackPos - (1 - 1)] : array($this->semStack[$stackPos - (1 - 1)]); + }, 235 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 2)]; + }, 236 => function ($stackPos) { + $this->semValue = \is_array($this->semStack[$stackPos - (1 - 1)]) ? $this->semStack[$stackPos - (1 - 1)] : array($this->semStack[$stackPos - (1 - 1)]); + }, 237 => function ($stackPos) { + $this->semValue = null; + }, 238 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 2)]; + }, 239 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 240 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 241 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 242 => function ($stackPos) { + $this->semValue = new Stmt\DeclareDeclare($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 243 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 244 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 3)]; + }, 245 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 2)]; + }, 246 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (5 - 3)]; + }, 247 => function ($stackPos) { + $this->semValue = array(); + }, 248 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 249 => function ($stackPos) { + $this->semValue = new Stmt\Case_($this->semStack[$stackPos - (4 - 2)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 250 => function ($stackPos) { + $this->semValue = new Stmt\Case_(null, $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 251 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 252 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 253 => function ($stackPos) { + $this->semValue = new Expr\Match_($this->semStack[$stackPos - (7 - 3)], $this->semStack[$stackPos - (7 - 6)], $this->startAttributeStack[$stackPos - (7 - 1)] + $this->endAttributes); + }, 254 => function ($stackPos) { + $this->semValue = []; + }, 255 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 256 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 257 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 258 => function ($stackPos) { + $this->semValue = new Node\MatchArm($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 259 => function ($stackPos) { + $this->semValue = new Node\MatchArm(null, $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 260 => function ($stackPos) { + $this->semValue = \is_array($this->semStack[$stackPos - (1 - 1)]) ? $this->semStack[$stackPos - (1 - 1)] : array($this->semStack[$stackPos - (1 - 1)]); + }, 261 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 2)]; + }, 262 => function ($stackPos) { + $this->semValue = array(); + }, 263 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 264 => function ($stackPos) { + $this->semValue = new Stmt\ElseIf_($this->semStack[$stackPos - (5 - 3)], \is_array($this->semStack[$stackPos - (5 - 5)]) ? $this->semStack[$stackPos - (5 - 5)] : array($this->semStack[$stackPos - (5 - 5)]), $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 265 => function ($stackPos) { + $this->semValue = array(); + }, 266 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 267 => function ($stackPos) { + $this->semValue = new Stmt\ElseIf_($this->semStack[$stackPos - (6 - 3)], $this->semStack[$stackPos - (6 - 6)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + $this->fixupAlternativeElse($this->semValue); + }, 268 => function ($stackPos) { + $this->semValue = null; + }, 269 => function ($stackPos) { + $this->semValue = new Stmt\Else_(\is_array($this->semStack[$stackPos - (2 - 2)]) ? $this->semStack[$stackPos - (2 - 2)] : array($this->semStack[$stackPos - (2 - 2)]), $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 270 => function ($stackPos) { + $this->semValue = null; + }, 271 => function ($stackPos) { + $this->semValue = new Stmt\Else_($this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + $this->fixupAlternativeElse($this->semValue); + }, 272 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)], \false); + }, 273 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (2 - 2)], \true); + }, 274 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)], \false); + }, 275 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)], \false); + }, 276 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 277 => function ($stackPos) { + $this->semValue = array(); + }, 278 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 279 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 280 => function ($stackPos) { + $this->semValue = 0; + }, 281 => function ($stackPos) { + $this->checkModifier($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $stackPos - (2 - 2)); + $this->semValue = $this->semStack[$stackPos - (2 - 1)] | $this->semStack[$stackPos - (2 - 2)]; + }, 282 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_PUBLIC; + }, 283 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_PROTECTED; + }, 284 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_PRIVATE; + }, 285 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_READONLY; + }, 286 => function ($stackPos) { + $this->semValue = new Node\Param($this->semStack[$stackPos - (6 - 6)], null, $this->semStack[$stackPos - (6 - 3)], $this->semStack[$stackPos - (6 - 4)], $this->semStack[$stackPos - (6 - 5)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes, $this->semStack[$stackPos - (6 - 2)], $this->semStack[$stackPos - (6 - 1)]); + $this->checkParam($this->semValue); + }, 287 => function ($stackPos) { + $this->semValue = new Node\Param($this->semStack[$stackPos - (8 - 6)], $this->semStack[$stackPos - (8 - 8)], $this->semStack[$stackPos - (8 - 3)], $this->semStack[$stackPos - (8 - 4)], $this->semStack[$stackPos - (8 - 5)], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes, $this->semStack[$stackPos - (8 - 2)], $this->semStack[$stackPos - (8 - 1)]); + $this->checkParam($this->semValue); + }, 288 => function ($stackPos) { + $this->semValue = new Node\Param(new Expr\Error($this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes), null, $this->semStack[$stackPos - (6 - 3)], $this->semStack[$stackPos - (6 - 4)], $this->semStack[$stackPos - (6 - 5)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes, $this->semStack[$stackPos - (6 - 2)], $this->semStack[$stackPos - (6 - 1)]); + }, 289 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 290 => function ($stackPos) { + $this->semValue = new Node\NullableType($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 291 => function ($stackPos) { + $this->semValue = new Node\UnionType($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 292 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 293 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 294 => function ($stackPos) { + $this->semValue = new Node\Name('static', $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 295 => function ($stackPos) { + $this->semValue = $this->handleBuiltinTypes($this->semStack[$stackPos - (1 - 1)]); + }, 296 => function ($stackPos) { + $this->semValue = new Node\Identifier('array', $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 297 => function ($stackPos) { + $this->semValue = new Node\Identifier('callable', $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 298 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 299 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 300 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)]); + }, 301 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 302 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 303 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 304 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)]); + }, 305 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 306 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)]); + }, 307 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 308 => function ($stackPos) { + $this->semValue = new Node\IntersectionType($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 309 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)]); + }, 310 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 311 => function ($stackPos) { + $this->semValue = new Node\IntersectionType($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 312 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 313 => function ($stackPos) { + $this->semValue = new Node\NullableType($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 314 => function ($stackPos) { + $this->semValue = new Node\UnionType($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 315 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 316 => function ($stackPos) { + $this->semValue = null; + }, 317 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 318 => function ($stackPos) { + $this->semValue = null; + }, 319 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 2)]; + }, 320 => function ($stackPos) { + $this->semValue = null; + }, 321 => function ($stackPos) { + $this->semValue = array(); + }, 322 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 2)]; + }, 323 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (3 - 2)]); + }, 324 => function ($stackPos) { + $this->semValue = new Node\VariadicPlaceholder($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 325 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 326 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 327 => function ($stackPos) { + $this->semValue = new Node\Arg($this->semStack[$stackPos - (1 - 1)], \false, \false, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 328 => function ($stackPos) { + $this->semValue = new Node\Arg($this->semStack[$stackPos - (2 - 2)], \true, \false, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 329 => function ($stackPos) { + $this->semValue = new Node\Arg($this->semStack[$stackPos - (2 - 2)], \false, \true, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 330 => function ($stackPos) { + $this->semValue = new Node\Arg($this->semStack[$stackPos - (3 - 3)], \false, \false, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes, $this->semStack[$stackPos - (3 - 1)]); + }, 331 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 332 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 333 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 334 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 335 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 336 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 337 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 338 => function ($stackPos) { + $this->semValue = new Stmt\StaticVar($this->semStack[$stackPos - (1 - 1)], null, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 339 => function ($stackPos) { + $this->semValue = new Stmt\StaticVar($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 340 => function ($stackPos) { + if ($this->semStack[$stackPos - (2 - 2)] !== null) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + } else { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + } + }, 341 => function ($stackPos) { + $this->semValue = array(); + }, 342 => function ($stackPos) { + $startAttributes = $this->lookaheadStartAttributes; + if (isset($startAttributes['comments'])) { + $nop = new Stmt\Nop($this->createCommentNopAttributes($startAttributes['comments'])); + } else { + $nop = null; + } + if ($nop !== null) { + $this->semStack[$stackPos - (1 - 1)][] = $nop; + } + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 343 => function ($stackPos) { + $this->semValue = new Stmt\Property($this->semStack[$stackPos - (5 - 2)], $this->semStack[$stackPos - (5 - 4)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes, $this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 1)]); + $this->checkProperty($this->semValue, $stackPos - (5 - 2)); + }, 344 => function ($stackPos) { + $this->semValue = new Stmt\ClassConst($this->semStack[$stackPos - (5 - 4)], $this->semStack[$stackPos - (5 - 2)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes, $this->semStack[$stackPos - (5 - 1)]); + $this->checkClassConst($this->semValue, $stackPos - (5 - 2)); + }, 345 => function ($stackPos) { + $this->semValue = new Stmt\ClassConst($this->semStack[$stackPos - (6 - 5)], $this->semStack[$stackPos - (6 - 2)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes, $this->semStack[$stackPos - (6 - 1)], $this->semStack[$stackPos - (6 - 4)]); + $this->checkClassConst($this->semValue, $stackPos - (6 - 2)); + }, 346 => function ($stackPos) { + $this->semValue = new Stmt\ClassMethod($this->semStack[$stackPos - (10 - 5)], ['type' => $this->semStack[$stackPos - (10 - 2)], 'byRef' => $this->semStack[$stackPos - (10 - 4)], 'params' => $this->semStack[$stackPos - (10 - 7)], 'returnType' => $this->semStack[$stackPos - (10 - 9)], 'stmts' => $this->semStack[$stackPos - (10 - 10)], 'attrGroups' => $this->semStack[$stackPos - (10 - 1)]], $this->startAttributeStack[$stackPos - (10 - 1)] + $this->endAttributes); + $this->checkClassMethod($this->semValue, $stackPos - (10 - 2)); + }, 347 => function ($stackPos) { + $this->semValue = new Stmt\TraitUse($this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 348 => function ($stackPos) { + $this->semValue = new Stmt\EnumCase($this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 4)], $this->semStack[$stackPos - (5 - 1)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 349 => function ($stackPos) { + $this->semValue = null; + /* will be skipped */ + }, 350 => function ($stackPos) { + $this->semValue = array(); + }, 351 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 352 => function ($stackPos) { + $this->semValue = array(); + }, 353 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 354 => function ($stackPos) { + $this->semValue = new Stmt\TraitUseAdaptation\Precedence($this->semStack[$stackPos - (4 - 1)][0], $this->semStack[$stackPos - (4 - 1)][1], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 355 => function ($stackPos) { + $this->semValue = new Stmt\TraitUseAdaptation\Alias($this->semStack[$stackPos - (5 - 1)][0], $this->semStack[$stackPos - (5 - 1)][1], $this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 4)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 356 => function ($stackPos) { + $this->semValue = new Stmt\TraitUseAdaptation\Alias($this->semStack[$stackPos - (4 - 1)][0], $this->semStack[$stackPos - (4 - 1)][1], $this->semStack[$stackPos - (4 - 3)], null, $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 357 => function ($stackPos) { + $this->semValue = new Stmt\TraitUseAdaptation\Alias($this->semStack[$stackPos - (4 - 1)][0], $this->semStack[$stackPos - (4 - 1)][1], null, $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 358 => function ($stackPos) { + $this->semValue = new Stmt\TraitUseAdaptation\Alias($this->semStack[$stackPos - (4 - 1)][0], $this->semStack[$stackPos - (4 - 1)][1], null, $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 359 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)]); + }, 360 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 361 => function ($stackPos) { + $this->semValue = array(null, $this->semStack[$stackPos - (1 - 1)]); + }, 362 => function ($stackPos) { + $this->semValue = null; + }, 363 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 364 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 365 => function ($stackPos) { + $this->semValue = 0; + }, 366 => function ($stackPos) { + $this->semValue = 0; + }, 367 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 368 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 369 => function ($stackPos) { + $this->checkModifier($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $stackPos - (2 - 2)); + $this->semValue = $this->semStack[$stackPos - (2 - 1)] | $this->semStack[$stackPos - (2 - 2)]; + }, 370 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_PUBLIC; + }, 371 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_PROTECTED; + }, 372 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_PRIVATE; + }, 373 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_STATIC; + }, 374 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_ABSTRACT; + }, 375 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_FINAL; + }, 376 => function ($stackPos) { + $this->semValue = Stmt\Class_::MODIFIER_READONLY; + }, 377 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 378 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 379 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 380 => function ($stackPos) { + $this->semValue = new Node\VarLikeIdentifier(\substr($this->semStack[$stackPos - (1 - 1)], 1), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 381 => function ($stackPos) { + $this->semValue = new Stmt\PropertyProperty($this->semStack[$stackPos - (1 - 1)], null, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 382 => function ($stackPos) { + $this->semValue = new Stmt\PropertyProperty($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 383 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 384 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 385 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 386 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 387 => function ($stackPos) { + $this->semValue = array(); + }, 388 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 389 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 390 => function ($stackPos) { + $this->semValue = new Expr\Assign($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 391 => function ($stackPos) { + $this->semValue = new Expr\Assign($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 392 => function ($stackPos) { + $this->semValue = new Expr\Assign($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 393 => function ($stackPos) { + $this->semValue = new Expr\AssignRef($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 394 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 395 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 396 => function ($stackPos) { + $this->semValue = new Expr\Clone_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 397 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Plus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 398 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Minus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 399 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Mul($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 400 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Div($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 401 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Concat($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 402 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Mod($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 403 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\BitwiseAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 404 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\BitwiseOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 405 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\BitwiseXor($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 406 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\ShiftLeft($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 407 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\ShiftRight($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 408 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Pow($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 409 => function ($stackPos) { + $this->semValue = new Expr\AssignOp\Coalesce($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 410 => function ($stackPos) { + $this->semValue = new Expr\PostInc($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 411 => function ($stackPos) { + $this->semValue = new Expr\PreInc($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 412 => function ($stackPos) { + $this->semValue = new Expr\PostDec($this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 413 => function ($stackPos) { + $this->semValue = new Expr\PreDec($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 414 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BooleanOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 415 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BooleanAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 416 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\LogicalOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 417 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\LogicalAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 418 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\LogicalXor($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 419 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BitwiseOr($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 420 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BitwiseAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 421 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BitwiseAnd($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 422 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\BitwiseXor($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 423 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Concat($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 424 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Plus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 425 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Minus($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 426 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Mul($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 427 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Div($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 428 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Mod($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 429 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\ShiftLeft($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 430 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\ShiftRight($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 431 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Pow($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 432 => function ($stackPos) { + $this->semValue = new Expr\UnaryPlus($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 433 => function ($stackPos) { + $this->semValue = new Expr\UnaryMinus($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 434 => function ($stackPos) { + $this->semValue = new Expr\BooleanNot($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 435 => function ($stackPos) { + $this->semValue = new Expr\BitwiseNot($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 436 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Identical($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 437 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\NotIdentical($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 438 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Equal($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 439 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\NotEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 440 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Spaceship($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 441 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Smaller($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 442 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\SmallerOrEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 443 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Greater($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 444 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\GreaterOrEqual($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 445 => function ($stackPos) { + $this->semValue = new Expr\Instanceof_($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 446 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 447 => function ($stackPos) { + $this->semValue = new Expr\Ternary($this->semStack[$stackPos - (5 - 1)], $this->semStack[$stackPos - (5 - 3)], $this->semStack[$stackPos - (5 - 5)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 448 => function ($stackPos) { + $this->semValue = new Expr\Ternary($this->semStack[$stackPos - (4 - 1)], null, $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 449 => function ($stackPos) { + $this->semValue = new Expr\BinaryOp\Coalesce($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 450 => function ($stackPos) { + $this->semValue = new Expr\Isset_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 451 => function ($stackPos) { + $this->semValue = new Expr\Empty_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 452 => function ($stackPos) { + $this->semValue = new Expr\Include_($this->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_INCLUDE, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 453 => function ($stackPos) { + $this->semValue = new Expr\Include_($this->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_INCLUDE_ONCE, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 454 => function ($stackPos) { + $this->semValue = new Expr\Eval_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 455 => function ($stackPos) { + $this->semValue = new Expr\Include_($this->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_REQUIRE, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 456 => function ($stackPos) { + $this->semValue = new Expr\Include_($this->semStack[$stackPos - (2 - 2)], Expr\Include_::TYPE_REQUIRE_ONCE, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 457 => function ($stackPos) { + $this->semValue = new Expr\Cast\Int_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 458 => function ($stackPos) { + $attrs = $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes; + $attrs['kind'] = $this->getFloatCastKind($this->semStack[$stackPos - (2 - 1)]); + $this->semValue = new Expr\Cast\Double($this->semStack[$stackPos - (2 - 2)], $attrs); + }, 459 => function ($stackPos) { + $this->semValue = new Expr\Cast\String_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 460 => function ($stackPos) { + $this->semValue = new Expr\Cast\Array_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 461 => function ($stackPos) { + $this->semValue = new Expr\Cast\Object_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 462 => function ($stackPos) { + $this->semValue = new Expr\Cast\Bool_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 463 => function ($stackPos) { + $this->semValue = new Expr\Cast\Unset_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 464 => function ($stackPos) { + $attrs = $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes; + $attrs['kind'] = \strtolower($this->semStack[$stackPos - (2 - 1)]) === 'exit' ? Expr\Exit_::KIND_EXIT : Expr\Exit_::KIND_DIE; + $this->semValue = new Expr\Exit_($this->semStack[$stackPos - (2 - 2)], $attrs); + }, 465 => function ($stackPos) { + $this->semValue = new Expr\ErrorSuppress($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 466 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 467 => function ($stackPos) { + $this->semValue = new Expr\ShellExec($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 468 => function ($stackPos) { + $this->semValue = new Expr\Print_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 469 => function ($stackPos) { + $this->semValue = new Expr\Yield_(null, null, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 470 => function ($stackPos) { + $this->semValue = new Expr\Yield_($this->semStack[$stackPos - (2 - 2)], null, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 471 => function ($stackPos) { + $this->semValue = new Expr\Yield_($this->semStack[$stackPos - (4 - 4)], $this->semStack[$stackPos - (4 - 2)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 472 => function ($stackPos) { + $this->semValue = new Expr\YieldFrom($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 473 => function ($stackPos) { + $this->semValue = new Expr\Throw_($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 474 => function ($stackPos) { + $this->semValue = new Expr\ArrowFunction(['static' => \false, 'byRef' => $this->semStack[$stackPos - (8 - 2)], 'params' => $this->semStack[$stackPos - (8 - 4)], 'returnType' => $this->semStack[$stackPos - (8 - 6)], 'expr' => $this->semStack[$stackPos - (8 - 8)], 'attrGroups' => []], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes); + }, 475 => function ($stackPos) { + $this->semValue = new Expr\ArrowFunction(['static' => \true, 'byRef' => $this->semStack[$stackPos - (9 - 3)], 'params' => $this->semStack[$stackPos - (9 - 5)], 'returnType' => $this->semStack[$stackPos - (9 - 7)], 'expr' => $this->semStack[$stackPos - (9 - 9)], 'attrGroups' => []], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); + }, 476 => function ($stackPos) { + $this->semValue = new Expr\Closure(['static' => \false, 'byRef' => $this->semStack[$stackPos - (8 - 2)], 'params' => $this->semStack[$stackPos - (8 - 4)], 'uses' => $this->semStack[$stackPos - (8 - 6)], 'returnType' => $this->semStack[$stackPos - (8 - 7)], 'stmts' => $this->semStack[$stackPos - (8 - 8)], 'attrGroups' => []], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes); + }, 477 => function ($stackPos) { + $this->semValue = new Expr\Closure(['static' => \true, 'byRef' => $this->semStack[$stackPos - (9 - 3)], 'params' => $this->semStack[$stackPos - (9 - 5)], 'uses' => $this->semStack[$stackPos - (9 - 7)], 'returnType' => $this->semStack[$stackPos - (9 - 8)], 'stmts' => $this->semStack[$stackPos - (9 - 9)], 'attrGroups' => []], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); + }, 478 => function ($stackPos) { + $this->semValue = new Expr\ArrowFunction(['static' => \false, 'byRef' => $this->semStack[$stackPos - (9 - 3)], 'params' => $this->semStack[$stackPos - (9 - 5)], 'returnType' => $this->semStack[$stackPos - (9 - 7)], 'expr' => $this->semStack[$stackPos - (9 - 9)], 'attrGroups' => $this->semStack[$stackPos - (9 - 1)]], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); + }, 479 => function ($stackPos) { + $this->semValue = new Expr\ArrowFunction(['static' => \true, 'byRef' => $this->semStack[$stackPos - (10 - 4)], 'params' => $this->semStack[$stackPos - (10 - 6)], 'returnType' => $this->semStack[$stackPos - (10 - 8)], 'expr' => $this->semStack[$stackPos - (10 - 10)], 'attrGroups' => $this->semStack[$stackPos - (10 - 1)]], $this->startAttributeStack[$stackPos - (10 - 1)] + $this->endAttributes); + }, 480 => function ($stackPos) { + $this->semValue = new Expr\Closure(['static' => \false, 'byRef' => $this->semStack[$stackPos - (9 - 3)], 'params' => $this->semStack[$stackPos - (9 - 5)], 'uses' => $this->semStack[$stackPos - (9 - 7)], 'returnType' => $this->semStack[$stackPos - (9 - 8)], 'stmts' => $this->semStack[$stackPos - (9 - 9)], 'attrGroups' => $this->semStack[$stackPos - (9 - 1)]], $this->startAttributeStack[$stackPos - (9 - 1)] + $this->endAttributes); + }, 481 => function ($stackPos) { + $this->semValue = new Expr\Closure(['static' => \true, 'byRef' => $this->semStack[$stackPos - (10 - 4)], 'params' => $this->semStack[$stackPos - (10 - 6)], 'uses' => $this->semStack[$stackPos - (10 - 8)], 'returnType' => $this->semStack[$stackPos - (10 - 9)], 'stmts' => $this->semStack[$stackPos - (10 - 10)], 'attrGroups' => $this->semStack[$stackPos - (10 - 1)]], $this->startAttributeStack[$stackPos - (10 - 1)] + $this->endAttributes); + }, 482 => function ($stackPos) { + $this->semValue = array(new Stmt\Class_(null, ['type' => $this->semStack[$stackPos - (8 - 2)], 'extends' => $this->semStack[$stackPos - (8 - 4)], 'implements' => $this->semStack[$stackPos - (8 - 5)], 'stmts' => $this->semStack[$stackPos - (8 - 7)], 'attrGroups' => $this->semStack[$stackPos - (8 - 1)]], $this->startAttributeStack[$stackPos - (8 - 1)] + $this->endAttributes), $this->semStack[$stackPos - (8 - 3)]); + $this->checkClass($this->semValue[0], -1); + }, 483 => function ($stackPos) { + $this->semValue = new Expr\New_($this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 484 => function ($stackPos) { + list($class, $ctorArgs) = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = new Expr\New_($class, $ctorArgs, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 485 => function ($stackPos) { + $this->semValue = array(); + }, 486 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (4 - 3)]; + }, 487 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 488 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 489 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 490 => function ($stackPos) { + $this->semValue = new Expr\ClosureUse($this->semStack[$stackPos - (2 - 2)], $this->semStack[$stackPos - (2 - 1)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 491 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 492 => function ($stackPos) { + $this->semValue = new Expr\FuncCall($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 493 => function ($stackPos) { + $this->semValue = new Expr\FuncCall($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 494 => function ($stackPos) { + $this->semValue = new Expr\FuncCall($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 495 => function ($stackPos) { + $this->semValue = new Expr\StaticCall($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 496 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 497 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 498 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 499 => function ($stackPos) { + $this->semValue = new Name($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 500 => function ($stackPos) { + $this->semValue = new Name\FullyQualified(\substr($this->semStack[$stackPos - (1 - 1)], 1), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 501 => function ($stackPos) { + $this->semValue = new Name\Relative(\substr($this->semStack[$stackPos - (1 - 1)], 10), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 502 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 503 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 504 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 505 => function ($stackPos) { + $this->semValue = new Expr\Error($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + $this->errorState = 2; + }, 506 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 507 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 508 => function ($stackPos) { + $this->semValue = null; + }, 509 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 510 => function ($stackPos) { + $this->semValue = array(); + }, 511 => function ($stackPos) { + $this->semValue = array(new Scalar\EncapsedStringPart(Scalar\String_::parseEscapeSequences($this->semStack[$stackPos - (1 - 1)], '`'), $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes)); + }, 512 => function ($stackPos) { + foreach ($this->semStack[$stackPos - (1 - 1)] as $s) { + if ($s instanceof Node\Scalar\EncapsedStringPart) { + $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, '`', \true); + } + } + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 513 => function ($stackPos) { + $this->semValue = array(); + }, 514 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 515 => function ($stackPos) { + $this->semValue = new Expr\ConstFetch($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 516 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Line($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 517 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\File($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 518 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Dir($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 519 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Class_($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 520 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Trait_($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 521 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Method($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 522 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Function_($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 523 => function ($stackPos) { + $this->semValue = new Scalar\MagicConst\Namespace_($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 524 => function ($stackPos) { + $this->semValue = new Expr\ClassConstFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 525 => function ($stackPos) { + $this->semValue = new Expr\ClassConstFetch($this->semStack[$stackPos - (5 - 1)], $this->semStack[$stackPos - (5 - 4)], $this->startAttributeStack[$stackPos - (5 - 1)] + $this->endAttributes); + }, 526 => function ($stackPos) { + $this->semValue = new Expr\ClassConstFetch($this->semStack[$stackPos - (3 - 1)], new Expr\Error($this->startAttributeStack[$stackPos - (3 - 3)] + $this->endAttributeStack[$stackPos - (3 - 3)]), $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + $this->errorState = 2; + }, 527 => function ($stackPos) { + $attrs = $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes; + $attrs['kind'] = Expr\Array_::KIND_SHORT; + $this->semValue = new Expr\Array_($this->semStack[$stackPos - (3 - 2)], $attrs); + }, 528 => function ($stackPos) { + $attrs = $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes; + $attrs['kind'] = Expr\Array_::KIND_LONG; + $this->semValue = new Expr\Array_($this->semStack[$stackPos - (4 - 3)], $attrs); + }, 529 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 530 => function ($stackPos) { + $this->semValue = Scalar\String_::fromString($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 531 => function ($stackPos) { + $attrs = $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes; + $attrs['kind'] = Scalar\String_::KIND_DOUBLE_QUOTED; + foreach ($this->semStack[$stackPos - (3 - 2)] as $s) { + if ($s instanceof Node\Scalar\EncapsedStringPart) { + $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, '"', \true); + } + } + $this->semValue = new Scalar\Encapsed($this->semStack[$stackPos - (3 - 2)], $attrs); + }, 532 => function ($stackPos) { + $this->semValue = $this->parseLNumber($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 533 => function ($stackPos) { + $this->semValue = Scalar\DNumber::fromString($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 534 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 535 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 536 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 537 => function ($stackPos) { + $this->semValue = $this->parseDocString($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes, $this->startAttributeStack[$stackPos - (3 - 3)] + $this->endAttributeStack[$stackPos - (3 - 3)], \true); + }, 538 => function ($stackPos) { + $this->semValue = $this->parseDocString($this->semStack[$stackPos - (2 - 1)], '', $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes, $this->startAttributeStack[$stackPos - (2 - 2)] + $this->endAttributeStack[$stackPos - (2 - 2)], \true); + }, 539 => function ($stackPos) { + $this->semValue = $this->parseDocString($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 2)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes, $this->startAttributeStack[$stackPos - (3 - 3)] + $this->endAttributeStack[$stackPos - (3 - 3)], \true); + }, 540 => function ($stackPos) { + $this->semValue = null; + }, 541 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 542 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 543 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 544 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 545 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 546 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 547 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 548 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 549 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 550 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 551 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 552 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 553 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 554 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 555 => function ($stackPos) { + $this->semValue = new Expr\MethodCall($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 556 => function ($stackPos) { + $this->semValue = new Expr\NullsafeMethodCall($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->semStack[$stackPos - (4 - 4)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 557 => function ($stackPos) { + $this->semValue = null; + }, 558 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 559 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 560 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 561 => function ($stackPos) { + $this->semValue = new Expr\PropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 562 => function ($stackPos) { + $this->semValue = new Expr\NullsafePropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 563 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 564 => function ($stackPos) { + $this->semValue = new Expr\Variable($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 565 => function ($stackPos) { + $this->semValue = new Expr\Variable($this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 566 => function ($stackPos) { + $this->semValue = new Expr\Variable(new Expr\Error($this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes), $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + $this->errorState = 2; + }, 567 => function ($stackPos) { + $var = $this->semStack[$stackPos - (1 - 1)]->name; + $this->semValue = \is_string($var) ? new Node\VarLikeIdentifier($var, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes) : $var; + }, 568 => function ($stackPos) { + $this->semValue = new Expr\StaticPropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 569 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 570 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 571 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 572 => function ($stackPos) { + $this->semValue = new Expr\PropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 573 => function ($stackPos) { + $this->semValue = new Expr\NullsafePropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 574 => function ($stackPos) { + $this->semValue = new Expr\StaticPropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 575 => function ($stackPos) { + $this->semValue = new Expr\StaticPropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 576 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 577 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 578 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 579 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 580 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 581 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 582 => function ($stackPos) { + $this->semValue = new Expr\Error($this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + $this->errorState = 2; + }, 583 => function ($stackPos) { + $this->semValue = new Expr\List_($this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 584 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + $end = \count($this->semValue) - 1; + if ($this->semValue[$end] === null) { + \array_pop($this->semValue); + } + }, 585 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos]; + }, 586 => function ($stackPos) { + /* do nothing -- prevent default action of $$=$this->semStack[$1]. See $551. */ + }, 587 => function ($stackPos) { + $this->semStack[$stackPos - (3 - 1)][] = $this->semStack[$stackPos - (3 - 3)]; + $this->semValue = $this->semStack[$stackPos - (3 - 1)]; + }, 588 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 589 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (1 - 1)], null, \false, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 590 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (2 - 2)], null, \true, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 591 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (1 - 1)], null, \false, $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 592 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (3 - 3)], $this->semStack[$stackPos - (3 - 1)], \false, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 593 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (4 - 4)], $this->semStack[$stackPos - (4 - 1)], \true, $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 594 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (3 - 3)], $this->semStack[$stackPos - (3 - 1)], \false, $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 595 => function ($stackPos) { + $this->semValue = new Expr\ArrayItem($this->semStack[$stackPos - (2 - 2)], null, \false, $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes, \true); + }, 596 => function ($stackPos) { + $this->semValue = null; + }, 597 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 598 => function ($stackPos) { + $this->semStack[$stackPos - (2 - 1)][] = $this->semStack[$stackPos - (2 - 2)]; + $this->semValue = $this->semStack[$stackPos - (2 - 1)]; + }, 599 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (1 - 1)]); + }, 600 => function ($stackPos) { + $this->semValue = array($this->semStack[$stackPos - (2 - 1)], $this->semStack[$stackPos - (2 - 2)]); + }, 601 => function ($stackPos) { + $this->semValue = new Scalar\EncapsedStringPart($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 602 => function ($stackPos) { + $this->semValue = new Expr\Variable($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 603 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }, 604 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (4 - 1)], $this->semStack[$stackPos - (4 - 3)], $this->startAttributeStack[$stackPos - (4 - 1)] + $this->endAttributes); + }, 605 => function ($stackPos) { + $this->semValue = new Expr\PropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 606 => function ($stackPos) { + $this->semValue = new Expr\NullsafePropertyFetch($this->semStack[$stackPos - (3 - 1)], $this->semStack[$stackPos - (3 - 3)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 607 => function ($stackPos) { + $this->semValue = new Expr\Variable($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 608 => function ($stackPos) { + $this->semValue = new Expr\Variable($this->semStack[$stackPos - (3 - 2)], $this->startAttributeStack[$stackPos - (3 - 1)] + $this->endAttributes); + }, 609 => function ($stackPos) { + $this->semValue = new Expr\ArrayDimFetch($this->semStack[$stackPos - (6 - 2)], $this->semStack[$stackPos - (6 - 4)], $this->startAttributeStack[$stackPos - (6 - 1)] + $this->endAttributes); + }, 610 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (3 - 2)]; + }, 611 => function ($stackPos) { + $this->semValue = new Scalar\String_($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 612 => function ($stackPos) { + $this->semValue = $this->parseNumString($this->semStack[$stackPos - (1 - 1)], $this->startAttributeStack[$stackPos - (1 - 1)] + $this->endAttributes); + }, 613 => function ($stackPos) { + $this->semValue = $this->parseNumString('-' . $this->semStack[$stackPos - (2 - 2)], $this->startAttributeStack[$stackPos - (2 - 1)] + $this->endAttributes); + }, 614 => function ($stackPos) { + $this->semValue = $this->semStack[$stackPos - (1 - 1)]; + }]; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/Parser/Tokens.php b/vendor/nikic/php-parser/lib/PhpParser/Parser/Tokens.php new file mode 100644 index 0000000000..bfe4bbad7b --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/Parser/Tokens.php @@ -0,0 +1,148 @@ +lexer = $lexer; + if (isset($options['throwOnError'])) { + throw new \LogicException('"throwOnError" is no longer supported, use "errorHandler" instead'); + } + $this->initReduceCallbacks(); + } + /** + * Parses PHP code into a node tree. + * + * If a non-throwing error handler is used, the parser will continue parsing after an error + * occurred and attempt to build a partial AST. + * + * @param string $code The source code to parse + * @param ErrorHandler|null $errorHandler Error handler to use for lexer/parser errors, defaults + * to ErrorHandler\Throwing. + * + * @return Node\Stmt[]|null Array of statements (or null non-throwing error handler is used and + * the parser was unable to recover from an error). + */ + public function parse(string $code, ?ErrorHandler $errorHandler = null) + { + $this->errorHandler = $errorHandler ?: new ErrorHandler\Throwing(); + $this->lexer->startLexing($code, $this->errorHandler); + $result = $this->doParse(); + // Clear out some of the interior state, so we don't hold onto unnecessary + // memory between uses of the parser + $this->startAttributeStack = []; + $this->endAttributeStack = []; + $this->semStack = []; + $this->semValue = null; + return $result; + } + protected function doParse() + { + // We start off with no lookahead-token + $symbol = self::SYMBOL_NONE; + // The attributes for a node are taken from the first and last token of the node. + // From the first token only the startAttributes are taken and from the last only + // the endAttributes. Both are merged using the array union operator (+). + $startAttributes = []; + $endAttributes = []; + $this->endAttributes = $endAttributes; + // Keep stack of start and end attributes + $this->startAttributeStack = []; + $this->endAttributeStack = [$endAttributes]; + // Start off in the initial state and keep a stack of previous states + $state = 0; + $stateStack = [$state]; + // Semantic value stack (contains values of tokens and semantic action results) + $this->semStack = []; + // Current position in the stack(s) + $stackPos = 0; + $this->errorState = 0; + for (;;) { + //$this->traceNewState($state, $symbol); + if ($this->actionBase[$state] === 0) { + $rule = $this->actionDefault[$state]; + } else { + if ($symbol === self::SYMBOL_NONE) { + // Fetch the next token id from the lexer and fetch additional info by-ref. + // The end attributes are fetched into a temporary variable and only set once the token is really + // shifted (not during read). Otherwise you would sometimes get off-by-one errors, when a rule is + // reduced after a token was read but not yet shifted. + $tokenId = $this->lexer->getNextToken($tokenValue, $startAttributes, $endAttributes); + // map the lexer token id to the internally used symbols + $symbol = $tokenId >= 0 && $tokenId < $this->tokenToSymbolMapSize ? $this->tokenToSymbol[$tokenId] : $this->invalidSymbol; + if ($symbol === $this->invalidSymbol) { + throw new \RangeException(\sprintf('The lexer returned an invalid token (id=%d, value=%s)', $tokenId, $tokenValue)); + } + // Allow productions to access the start attributes of the lookahead token. + $this->lookaheadStartAttributes = $startAttributes; + //$this->traceRead($symbol); + } + $idx = $this->actionBase[$state] + $symbol; + if (($idx >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $symbol || $state < $this->YY2TBLSTATE && ($idx = $this->actionBase[$state + $this->numNonLeafStates] + $symbol) >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $symbol) && ($action = $this->action[$idx]) !== $this->defaultAction) { + /* + * >= numNonLeafStates: shift and reduce + * > 0: shift + * = 0: accept + * < 0: reduce + * = -YYUNEXPECTED: error + */ + if ($action > 0) { + /* shift */ + //$this->traceShift($symbol); + ++$stackPos; + $stateStack[$stackPos] = $state = $action; + $this->semStack[$stackPos] = $tokenValue; + $this->startAttributeStack[$stackPos] = $startAttributes; + $this->endAttributeStack[$stackPos] = $endAttributes; + $this->endAttributes = $endAttributes; + $symbol = self::SYMBOL_NONE; + if ($this->errorState) { + --$this->errorState; + } + if ($action < $this->numNonLeafStates) { + continue; + } + /* $yyn >= numNonLeafStates means shift-and-reduce */ + $rule = $action - $this->numNonLeafStates; + } else { + $rule = -$action; + } + } else { + $rule = $this->actionDefault[$state]; + } + } + for (;;) { + if ($rule === 0) { + /* accept */ + //$this->traceAccept(); + return $this->semValue; + } elseif ($rule !== $this->unexpectedTokenRule) { + /* reduce */ + //$this->traceReduce($rule); + try { + $this->reduceCallbacks[$rule]($stackPos); + } catch (Error $e) { + if (-1 === $e->getStartLine() && isset($startAttributes['startLine'])) { + $e->setStartLine($startAttributes['startLine']); + } + $this->emitError($e); + // Can't recover from this type of error + return null; + } + /* Goto - shift nonterminal */ + $lastEndAttributes = $this->endAttributeStack[$stackPos]; + $ruleLength = $this->ruleToLength[$rule]; + $stackPos -= $ruleLength; + $nonTerminal = $this->ruleToNonTerminal[$rule]; + $idx = $this->gotoBase[$nonTerminal] + $stateStack[$stackPos]; + if ($idx >= 0 && $idx < $this->gotoTableSize && $this->gotoCheck[$idx] === $nonTerminal) { + $state = $this->goto[$idx]; + } else { + $state = $this->gotoDefault[$nonTerminal]; + } + ++$stackPos; + $stateStack[$stackPos] = $state; + $this->semStack[$stackPos] = $this->semValue; + $this->endAttributeStack[$stackPos] = $lastEndAttributes; + if ($ruleLength === 0) { + // Empty productions use the start attributes of the lookahead token. + $this->startAttributeStack[$stackPos] = $this->lookaheadStartAttributes; + } + } else { + /* error */ + switch ($this->errorState) { + case 0: + $msg = $this->getErrorMessage($symbol, $state); + $this->emitError(new Error($msg, $startAttributes + $endAttributes)); + // Break missing intentionally + case 1: + case 2: + $this->errorState = 3; + // Pop until error-expecting state uncovered + while (!(($idx = $this->actionBase[$state] + $this->errorSymbol) >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $this->errorSymbol || $state < $this->YY2TBLSTATE && ($idx = $this->actionBase[$state + $this->numNonLeafStates] + $this->errorSymbol) >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $this->errorSymbol) || ($action = $this->action[$idx]) === $this->defaultAction) { + // Not totally sure about this + if ($stackPos <= 0) { + // Could not recover from error + return null; + } + $state = $stateStack[--$stackPos]; + //$this->tracePop($state); + } + //$this->traceShift($this->errorSymbol); + ++$stackPos; + $stateStack[$stackPos] = $state = $action; + // We treat the error symbol as being empty, so we reset the end attributes + // to the end attributes of the last non-error symbol + $this->startAttributeStack[$stackPos] = $this->lookaheadStartAttributes; + $this->endAttributeStack[$stackPos] = $this->endAttributeStack[$stackPos - 1]; + $this->endAttributes = $this->endAttributeStack[$stackPos - 1]; + break; + case 3: + if ($symbol === 0) { + // Reached EOF without recovering from error + return null; + } + //$this->traceDiscard($symbol); + $symbol = self::SYMBOL_NONE; + break 2; + } + } + if ($state < $this->numNonLeafStates) { + break; + } + /* >= numNonLeafStates means shift-and-reduce */ + $rule = $state - $this->numNonLeafStates; + } + } + throw new \RuntimeException('Reached end of parser loop'); + } + protected function emitError(Error $error) + { + $this->errorHandler->handleError($error); + } + /** + * Format error message including expected tokens. + * + * @param int $symbol Unexpected symbol + * @param int $state State at time of error + * + * @return string Formatted error message + */ + protected function getErrorMessage(int $symbol, int $state) : string + { + $expectedString = ''; + if ($expected = $this->getExpectedTokens($state)) { + $expectedString = ', expecting ' . \implode(' or ', $expected); + } + return 'Syntax error, unexpected ' . $this->symbolToName[$symbol] . $expectedString; + } + /** + * Get limited number of expected tokens in given state. + * + * @param int $state State + * + * @return string[] Expected tokens. If too many, an empty array is returned. + */ + protected function getExpectedTokens(int $state) : array + { + $expected = []; + $base = $this->actionBase[$state]; + foreach ($this->symbolToName as $symbol => $name) { + $idx = $base + $symbol; + if ($idx >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $symbol || $state < $this->YY2TBLSTATE && ($idx = $this->actionBase[$state + $this->numNonLeafStates] + $symbol) >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $symbol) { + if ($this->action[$idx] !== $this->unexpectedTokenRule && $this->action[$idx] !== $this->defaultAction && $symbol !== $this->errorSymbol) { + if (\count($expected) === 4) { + /* Too many expected tokens */ + return []; + } + $expected[] = $name; + } + } + } + return $expected; + } + /* + * Tracing functions used for debugging the parser. + */ + /* + protected function traceNewState($state, $symbol) { + echo '% State ' . $state + . ', Lookahead ' . ($symbol == self::SYMBOL_NONE ? '--none--' : $this->symbolToName[$symbol]) . "\n"; + } + + protected function traceRead($symbol) { + echo '% Reading ' . $this->symbolToName[$symbol] . "\n"; + } + + protected function traceShift($symbol) { + echo '% Shift ' . $this->symbolToName[$symbol] . "\n"; + } + + protected function traceAccept() { + echo "% Accepted.\n"; + } + + protected function traceReduce($n) { + echo '% Reduce by (' . $n . ') ' . $this->productions[$n] . "\n"; + } + + protected function tracePop($state) { + echo '% Recovering, uncovered state ' . $state . "\n"; + } + + protected function traceDiscard($symbol) { + echo '% Discard ' . $this->symbolToName[$symbol] . "\n"; + } + */ + /* + * Helper functions invoked by semantic actions + */ + /** + * Moves statements of semicolon-style namespaces into $ns->stmts and checks various error conditions. + * + * @param Node\Stmt[] $stmts + * @return Node\Stmt[] + */ + protected function handleNamespaces(array $stmts) : array + { + $hasErrored = \false; + $style = $this->getNamespacingStyle($stmts); + if (null === $style) { + // not namespaced, nothing to do + return $stmts; + } elseif ('brace' === $style) { + // For braced namespaces we only have to check that there are no invalid statements between the namespaces + $afterFirstNamespace = \false; + foreach ($stmts as $stmt) { + if ($stmt instanceof Node\Stmt\Namespace_) { + $afterFirstNamespace = \true; + } elseif (!$stmt instanceof Node\Stmt\HaltCompiler && !$stmt instanceof Node\Stmt\Nop && $afterFirstNamespace && !$hasErrored) { + $this->emitError(new Error('No code may exist outside of namespace {}', $stmt->getAttributes())); + $hasErrored = \true; + // Avoid one error for every statement + } + } + return $stmts; + } else { + // For semicolon namespaces we have to move the statements after a namespace declaration into ->stmts + $resultStmts = []; + $targetStmts =& $resultStmts; + $lastNs = null; + foreach ($stmts as $stmt) { + if ($stmt instanceof Node\Stmt\Namespace_) { + if ($lastNs !== null) { + $this->fixupNamespaceAttributes($lastNs); + } + if ($stmt->stmts === null) { + $stmt->stmts = []; + $targetStmts =& $stmt->stmts; + $resultStmts[] = $stmt; + } else { + // This handles the invalid case of mixed style namespaces + $resultStmts[] = $stmt; + $targetStmts =& $resultStmts; + } + $lastNs = $stmt; + } elseif ($stmt instanceof Node\Stmt\HaltCompiler) { + // __halt_compiler() is not moved into the namespace + $resultStmts[] = $stmt; + } else { + $targetStmts[] = $stmt; + } + } + if ($lastNs !== null) { + $this->fixupNamespaceAttributes($lastNs); + } + return $resultStmts; + } + } + private function fixupNamespaceAttributes(Node\Stmt\Namespace_ $stmt) + { + // We moved the statements into the namespace node, as such the end of the namespace node + // needs to be extended to the end of the statements. + if (empty($stmt->stmts)) { + return; + } + // We only move the builtin end attributes here. This is the best we can do with the + // knowledge we have. + $endAttributes = ['endLine', 'endFilePos', 'endTokenPos']; + $lastStmt = $stmt->stmts[\count($stmt->stmts) - 1]; + foreach ($endAttributes as $endAttribute) { + if ($lastStmt->hasAttribute($endAttribute)) { + $stmt->setAttribute($endAttribute, $lastStmt->getAttribute($endAttribute)); + } + } + } + /** + * Determine namespacing style (semicolon or brace) + * + * @param Node[] $stmts Top-level statements. + * + * @return null|string One of "semicolon", "brace" or null (no namespaces) + */ + private function getNamespacingStyle(array $stmts) + { + $style = null; + $hasNotAllowedStmts = \false; + foreach ($stmts as $i => $stmt) { + if ($stmt instanceof Node\Stmt\Namespace_) { + $currentStyle = null === $stmt->stmts ? 'semicolon' : 'brace'; + if (null === $style) { + $style = $currentStyle; + if ($hasNotAllowedStmts) { + $this->emitError(new Error('Namespace declaration statement has to be the very first statement in the script', $stmt->getLine())); + } + } elseif ($style !== $currentStyle) { + $this->emitError(new Error('Cannot mix bracketed namespace declarations with unbracketed namespace declarations', $stmt->getLine())); + // Treat like semicolon style for namespace normalization + return 'semicolon'; + } + continue; + } + /* declare(), __halt_compiler() and nops can be used before a namespace declaration */ + if ($stmt instanceof Node\Stmt\Declare_ || $stmt instanceof Node\Stmt\HaltCompiler || $stmt instanceof Node\Stmt\Nop) { + continue; + } + /* There may be a hashbang line at the very start of the file */ + if ($i === 0 && $stmt instanceof Node\Stmt\InlineHTML && \preg_match('/\\A#!.*\\r?\\n\\z/', $stmt->value)) { + continue; + } + /* Everything else if forbidden before namespace declarations */ + $hasNotAllowedStmts = \true; + } + return $style; + } + /** + * Fix up parsing of static property calls in PHP 5. + * + * In PHP 5 A::$b[c][d] and A::$b[c][d]() have very different interpretation. The former is + * interpreted as (A::$b)[c][d], while the latter is the same as A::{$b[c][d]}(). We parse the + * latter as the former initially and this method fixes the AST into the correct form when we + * encounter the "()". + * + * @param Node\Expr\StaticPropertyFetch|Node\Expr\ArrayDimFetch $prop + * @param Node\Arg[] $args + * @param array $attributes + * + * @return Expr\StaticCall + */ + protected function fixupPhp5StaticPropCall($prop, array $args, array $attributes) : Expr\StaticCall + { + if ($prop instanceof Node\Expr\StaticPropertyFetch) { + $name = $prop->name instanceof VarLikeIdentifier ? $prop->name->toString() : $prop->name; + $var = new Expr\Variable($name, $prop->name->getAttributes()); + return new Expr\StaticCall($prop->class, $var, $args, $attributes); + } elseif ($prop instanceof Node\Expr\ArrayDimFetch) { + $tmp = $prop; + while ($tmp->var instanceof Node\Expr\ArrayDimFetch) { + $tmp = $tmp->var; + } + /** @var Expr\StaticPropertyFetch $staticProp */ + $staticProp = $tmp->var; + // Set start attributes to attributes of innermost node + $tmp = $prop; + $this->fixupStartAttributes($tmp, $staticProp->name); + while ($tmp->var instanceof Node\Expr\ArrayDimFetch) { + $tmp = $tmp->var; + $this->fixupStartAttributes($tmp, $staticProp->name); + } + $name = $staticProp->name instanceof VarLikeIdentifier ? $staticProp->name->toString() : $staticProp->name; + $tmp->var = new Expr\Variable($name, $staticProp->name->getAttributes()); + return new Expr\StaticCall($staticProp->class, $prop, $args, $attributes); + } else { + throw new \Exception(); + } + } + protected function fixupStartAttributes(Node $to, Node $from) + { + $startAttributes = ['startLine', 'startFilePos', 'startTokenPos']; + foreach ($startAttributes as $startAttribute) { + if ($from->hasAttribute($startAttribute)) { + $to->setAttribute($startAttribute, $from->getAttribute($startAttribute)); + } + } + } + protected function handleBuiltinTypes(Name $name) + { + $builtinTypes = ['bool' => \true, 'int' => \true, 'float' => \true, 'string' => \true, 'iterable' => \true, 'void' => \true, 'object' => \true, 'null' => \true, 'false' => \true, 'mixed' => \true, 'never' => \true, 'true' => \true]; + if (!$name->isUnqualified()) { + return $name; + } + $lowerName = $name->toLowerString(); + if (!isset($builtinTypes[$lowerName])) { + return $name; + } + return new Node\Identifier($lowerName, $name->getAttributes()); + } + /** + * Get combined start and end attributes at a stack location + * + * @param int $pos Stack location + * + * @return array Combined start and end attributes + */ + protected function getAttributesAt(int $pos) : array + { + return $this->startAttributeStack[$pos] + $this->endAttributeStack[$pos]; + } + protected function getFloatCastKind(string $cast) : int + { + $cast = \strtolower($cast); + if (\strpos($cast, 'float') !== \false) { + return Double::KIND_FLOAT; + } + if (\strpos($cast, 'real') !== \false) { + return Double::KIND_REAL; + } + return Double::KIND_DOUBLE; + } + protected function parseLNumber($str, $attributes, $allowInvalidOctal = \false) + { + try { + return LNumber::fromString($str, $attributes, $allowInvalidOctal); + } catch (Error $error) { + $this->emitError($error); + // Use dummy value + return new LNumber(0, $attributes); + } + } + /** + * Parse a T_NUM_STRING token into either an integer or string node. + * + * @param string $str Number string + * @param array $attributes Attributes + * + * @return LNumber|String_ Integer or string node. + */ + protected function parseNumString(string $str, array $attributes) + { + if (!\preg_match('/^(?:0|-?[1-9][0-9]*)$/', $str)) { + return new String_($str, $attributes); + } + $num = +$str; + if (!\is_int($num)) { + return new String_($str, $attributes); + } + return new LNumber($num, $attributes); + } + protected function stripIndentation(string $string, int $indentLen, string $indentChar, bool $newlineAtStart, bool $newlineAtEnd, array $attributes) + { + if ($indentLen === 0) { + return $string; + } + $start = $newlineAtStart ? '(?:(?<=\\n)|\\A)' : '(?<=\\n)'; + $end = $newlineAtEnd ? '(?:(?=[\\r\\n])|\\z)' : '(?=[\\r\\n])'; + $regex = '/' . $start . '([ \\t]*)(' . $end . ')?/'; + return \preg_replace_callback($regex, function ($matches) use($indentLen, $indentChar, $attributes) { + $prefix = \substr($matches[1], 0, $indentLen); + if (\false !== \strpos($prefix, $indentChar === " " ? "\t" : " ")) { + $this->emitError(new Error('Invalid indentation - tabs and spaces cannot be mixed', $attributes)); + } elseif (\strlen($prefix) < $indentLen && !isset($matches[2])) { + $this->emitError(new Error('Invalid body indentation level ' . '(expecting an indentation level of at least ' . $indentLen . ')', $attributes)); + } + return \substr($matches[0], \strlen($prefix)); + }, $string); + } + protected function parseDocString(string $startToken, $contents, string $endToken, array $attributes, array $endTokenAttributes, bool $parseUnicodeEscape) + { + $kind = \strpos($startToken, "'") === \false ? String_::KIND_HEREDOC : String_::KIND_NOWDOC; + $regex = '/\\A[bB]?<<<[ \\t]*[\'"]?([a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*)[\'"]?(?:\\r\\n|\\n|\\r)\\z/'; + $result = \preg_match($regex, $startToken, $matches); + \assert($result === 1); + $label = $matches[1]; + $result = \preg_match('/\\A[ \\t]*/', $endToken, $matches); + \assert($result === 1); + $indentation = $matches[0]; + $attributes['kind'] = $kind; + $attributes['docLabel'] = $label; + $attributes['docIndentation'] = $indentation; + $indentHasSpaces = \false !== \strpos($indentation, " "); + $indentHasTabs = \false !== \strpos($indentation, "\t"); + if ($indentHasSpaces && $indentHasTabs) { + $this->emitError(new Error('Invalid indentation - tabs and spaces cannot be mixed', $endTokenAttributes)); + // Proceed processing as if this doc string is not indented + $indentation = ''; + } + $indentLen = \strlen($indentation); + $indentChar = $indentHasSpaces ? " " : "\t"; + if (\is_string($contents)) { + if ($contents === '') { + return new String_('', $attributes); + } + $contents = $this->stripIndentation($contents, $indentLen, $indentChar, \true, \true, $attributes); + $contents = \preg_replace('~(\\r\\n|\\n|\\r)\\z~', '', $contents); + if ($kind === String_::KIND_HEREDOC) { + $contents = String_::parseEscapeSequences($contents, null, $parseUnicodeEscape); + } + return new String_($contents, $attributes); + } else { + \assert(\count($contents) > 0); + if (!$contents[0] instanceof Node\Scalar\EncapsedStringPart) { + // If there is no leading encapsed string part, pretend there is an empty one + $this->stripIndentation('', $indentLen, $indentChar, \true, \false, $contents[0]->getAttributes()); + } + $newContents = []; + foreach ($contents as $i => $part) { + if ($part instanceof Node\Scalar\EncapsedStringPart) { + $isLast = $i === \count($contents) - 1; + $part->value = $this->stripIndentation($part->value, $indentLen, $indentChar, $i === 0, $isLast, $part->getAttributes()); + $part->value = String_::parseEscapeSequences($part->value, null, $parseUnicodeEscape); + if ($isLast) { + $part->value = \preg_replace('~(\\r\\n|\\n|\\r)\\z~', '', $part->value); + } + if ('' === $part->value) { + continue; + } + } + $newContents[] = $part; + } + return new Encapsed($newContents, $attributes); + } + } + /** + * Create attributes for a zero-length common-capturing nop. + * + * @param Comment[] $comments + * @return array + */ + protected function createCommentNopAttributes(array $comments) + { + $comment = $comments[\count($comments) - 1]; + $commentEndLine = $comment->getEndLine(); + $commentEndFilePos = $comment->getEndFilePos(); + $commentEndTokenPos = $comment->getEndTokenPos(); + $attributes = ['comments' => $comments]; + if (-1 !== $commentEndLine) { + $attributes['startLine'] = $commentEndLine; + $attributes['endLine'] = $commentEndLine; + } + if (-1 !== $commentEndFilePos) { + $attributes['startFilePos'] = $commentEndFilePos + 1; + $attributes['endFilePos'] = $commentEndFilePos; + } + if (-1 !== $commentEndTokenPos) { + $attributes['startTokenPos'] = $commentEndTokenPos + 1; + $attributes['endTokenPos'] = $commentEndTokenPos; + } + return $attributes; + } + /** @param ElseIf_|Else_ $node */ + protected function fixupAlternativeElse($node) + { + // Make sure a trailing nop statement carrying comments is part of the node. + $numStmts = \count($node->stmts); + if ($numStmts !== 0 && $node->stmts[$numStmts - 1] instanceof Nop) { + $nopAttrs = $node->stmts[$numStmts - 1]->getAttributes(); + if (isset($nopAttrs['endLine'])) { + $node->setAttribute('endLine', $nopAttrs['endLine']); + } + if (isset($nopAttrs['endFilePos'])) { + $node->setAttribute('endFilePos', $nopAttrs['endFilePos']); + } + if (isset($nopAttrs['endTokenPos'])) { + $node->setAttribute('endTokenPos', $nopAttrs['endTokenPos']); + } + } + } + protected function checkClassModifier($a, $b, $modifierPos) + { + try { + Class_::verifyClassModifier($a, $b); + } catch (Error $error) { + $error->setAttributes($this->getAttributesAt($modifierPos)); + $this->emitError($error); + } + } + protected function checkModifier($a, $b, $modifierPos) + { + // Jumping through some hoops here because verifyModifier() is also used elsewhere + try { + Class_::verifyModifier($a, $b); + } catch (Error $error) { + $error->setAttributes($this->getAttributesAt($modifierPos)); + $this->emitError($error); + } + } + protected function checkParam(Param $node) + { + if ($node->variadic && null !== $node->default) { + $this->emitError(new Error('Variadic parameter cannot have a default value', $node->default->getAttributes())); + } + } + protected function checkTryCatch(TryCatch $node) + { + if (empty($node->catches) && null === $node->finally) { + $this->emitError(new Error('Cannot use try without catch or finally', $node->getAttributes())); + } + } + protected function checkNamespace(Namespace_ $node) + { + if (null !== $node->stmts) { + foreach ($node->stmts as $stmt) { + if ($stmt instanceof Namespace_) { + $this->emitError(new Error('Namespace declarations cannot be nested', $stmt->getAttributes())); + } + } + } + } + private function checkClassName($name, $namePos) + { + if (null !== $name && $name->isSpecialClassName()) { + $this->emitError(new Error(\sprintf('Cannot use \'%s\' as class name as it is reserved', $name), $this->getAttributesAt($namePos))); + } + } + private function checkImplementedInterfaces(array $interfaces) + { + foreach ($interfaces as $interface) { + if ($interface->isSpecialClassName()) { + $this->emitError(new Error(\sprintf('Cannot use \'%s\' as interface name as it is reserved', $interface), $interface->getAttributes())); + } + } + } + protected function checkClass(Class_ $node, $namePos) + { + $this->checkClassName($node->name, $namePos); + if ($node->extends && $node->extends->isSpecialClassName()) { + $this->emitError(new Error(\sprintf('Cannot use \'%s\' as class name as it is reserved', $node->extends), $node->extends->getAttributes())); + } + $this->checkImplementedInterfaces($node->implements); + } + protected function checkInterface(Interface_ $node, $namePos) + { + $this->checkClassName($node->name, $namePos); + $this->checkImplementedInterfaces($node->extends); + } + protected function checkEnum(Enum_ $node, $namePos) + { + $this->checkClassName($node->name, $namePos); + $this->checkImplementedInterfaces($node->implements); + } + protected function checkClassMethod(ClassMethod $node, $modifierPos) + { + if ($node->flags & Class_::MODIFIER_STATIC) { + switch ($node->name->toLowerString()) { + case '__construct': + $this->emitError(new Error(\sprintf('Constructor %s() cannot be static', $node->name), $this->getAttributesAt($modifierPos))); + break; + case '__destruct': + $this->emitError(new Error(\sprintf('Destructor %s() cannot be static', $node->name), $this->getAttributesAt($modifierPos))); + break; + case '__clone': + $this->emitError(new Error(\sprintf('Clone method %s() cannot be static', $node->name), $this->getAttributesAt($modifierPos))); + break; + } + } + if ($node->flags & Class_::MODIFIER_READONLY) { + $this->emitError(new Error(\sprintf('Method %s() cannot be readonly', $node->name), $this->getAttributesAt($modifierPos))); + } + } + protected function checkClassConst(ClassConst $node, $modifierPos) + { + if ($node->flags & Class_::MODIFIER_STATIC) { + $this->emitError(new Error("Cannot use 'static' as constant modifier", $this->getAttributesAt($modifierPos))); + } + if ($node->flags & Class_::MODIFIER_ABSTRACT) { + $this->emitError(new Error("Cannot use 'abstract' as constant modifier", $this->getAttributesAt($modifierPos))); + } + if ($node->flags & Class_::MODIFIER_READONLY) { + $this->emitError(new Error("Cannot use 'readonly' as constant modifier", $this->getAttributesAt($modifierPos))); + } + } + protected function checkProperty(Property $node, $modifierPos) + { + if ($node->flags & Class_::MODIFIER_ABSTRACT) { + $this->emitError(new Error('Properties cannot be declared abstract', $this->getAttributesAt($modifierPos))); + } + if ($node->flags & Class_::MODIFIER_FINAL) { + $this->emitError(new Error('Properties cannot be declared final', $this->getAttributesAt($modifierPos))); + } + } + protected function checkUseUse(UseUse $node, $namePos) + { + if ($node->alias && $node->alias->isSpecialClassName()) { + $this->emitError(new Error(\sprintf('Cannot use %s as %s because \'%2$s\' is a special class name', $node->name, $node->alias), $this->getAttributesAt($namePos))); + } + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/ParserFactory.php b/vendor/nikic/php-parser/lib/PhpParser/ParserFactory.php new file mode 100644 index 0000000000..c094359632 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/ParserFactory.php @@ -0,0 +1,68 @@ +getLexerOptions())); + } + /** + * Create a parser targeting the host PHP version, that is the PHP version we're currently + * running on. This parser will not use any token emulation. + * + * All supported lexer attributes (comments, startLine, endLine, startTokenPos, endTokenPos, + * startFilePos, endFilePos) will be enabled. + */ + public function createForHostVersion() : Parser + { + return new Php7(new Lexer($this->getLexerOptions())); + } + private function getLexerOptions() : array + { + return ['usedAttributes' => ['comments', 'startLine', 'endLine', 'startTokenPos', 'endTokenPos', 'startFilePos', 'endFilePos']]; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/PrettyPrinter/Standard.php b/vendor/nikic/php-parser/lib/PhpParser/PrettyPrinter/Standard.php new file mode 100644 index 0000000000..2ac24caa87 --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/PrettyPrinter/Standard.php @@ -0,0 +1,968 @@ +pAttrGroups($node->attrGroups, \true) . $this->pModifiers($node->flags) . ($node->type ? $this->p($node->type) . ' ' : '') . ($node->byRef ? '&' : '') . ($node->variadic ? '...' : '') . $this->p($node->var) . ($node->default ? ' = ' . $this->p($node->default) : ''); + } + protected function pArg(Node\Arg $node) + { + return ($node->name ? $node->name->toString() . ': ' : '') . ($node->byRef ? '&' : '') . ($node->unpack ? '...' : '') . $this->p($node->value); + } + protected function pVariadicPlaceholder(Node\VariadicPlaceholder $node) + { + return '...'; + } + protected function pConst(Node\Const_ $node) + { + return $node->name . ' = ' . $this->p($node->value); + } + protected function pNullableType(Node\NullableType $node) + { + return '?' . $this->p($node->type); + } + protected function pUnionType(Node\UnionType $node) + { + $types = []; + foreach ($node->types as $typeNode) { + if ($typeNode instanceof Node\IntersectionType) { + $types[] = '(' . $this->p($typeNode) . ')'; + continue; + } + $types[] = $this->p($typeNode); + } + return \implode('|', $types); + } + protected function pIntersectionType(Node\IntersectionType $node) + { + return $this->pImplode($node->types, '&'); + } + protected function pIdentifier(Node\Identifier $node) + { + return $node->name; + } + protected function pVarLikeIdentifier(Node\VarLikeIdentifier $node) + { + return '$' . $node->name; + } + protected function pAttribute(Node\Attribute $node) + { + return $this->p($node->name) . ($node->args ? '(' . $this->pCommaSeparated($node->args) . ')' : ''); + } + protected function pAttributeGroup(Node\AttributeGroup $node) + { + return '#[' . $this->pCommaSeparated($node->attrs) . ']'; + } + // Names + protected function pName(Name $node) + { + return \implode('\\', $node->parts); + } + protected function pName_FullyQualified(Name\FullyQualified $node) + { + return '\\' . \implode('\\', $node->parts); + } + protected function pName_Relative(Name\Relative $node) + { + return 'namespace\\' . \implode('\\', $node->parts); + } + // Magic Constants + protected function pScalar_MagicConst_Class(MagicConst\Class_ $node) + { + return '__CLASS__'; + } + protected function pScalar_MagicConst_Dir(MagicConst\Dir $node) + { + return '__DIR__'; + } + protected function pScalar_MagicConst_File(MagicConst\File $node) + { + return '__FILE__'; + } + protected function pScalar_MagicConst_Function(MagicConst\Function_ $node) + { + return '__FUNCTION__'; + } + protected function pScalar_MagicConst_Line(MagicConst\Line $node) + { + return '__LINE__'; + } + protected function pScalar_MagicConst_Method(MagicConst\Method $node) + { + return '__METHOD__'; + } + protected function pScalar_MagicConst_Namespace(MagicConst\Namespace_ $node) + { + return '__NAMESPACE__'; + } + protected function pScalar_MagicConst_Trait(MagicConst\Trait_ $node) + { + return '__TRAIT__'; + } + // Scalars + protected function pScalar_String(Scalar\String_ $node) + { + $kind = $node->getAttribute('kind', Scalar\String_::KIND_SINGLE_QUOTED); + switch ($kind) { + case Scalar\String_::KIND_NOWDOC: + $label = $node->getAttribute('docLabel'); + if ($label && !$this->containsEndLabel($node->value, $label)) { + if ($node->value === '') { + return "<<<'{$label}'\n{$label}" . $this->docStringEndToken; + } + return "<<<'{$label}'\n{$node->value}\n{$label}" . $this->docStringEndToken; + } + /* break missing intentionally */ + case Scalar\String_::KIND_SINGLE_QUOTED: + return $this->pSingleQuotedString($node->value); + case Scalar\String_::KIND_HEREDOC: + $label = $node->getAttribute('docLabel'); + if ($label && !$this->containsEndLabel($node->value, $label)) { + if ($node->value === '') { + return "<<<{$label}\n{$label}" . $this->docStringEndToken; + } + $escaped = $this->escapeString($node->value, null); + return "<<<{$label}\n" . $escaped . "\n{$label}" . $this->docStringEndToken; + } + /* break missing intentionally */ + case Scalar\String_::KIND_DOUBLE_QUOTED: + return '"' . $this->escapeString($node->value, '"') . '"'; + } + throw new \Exception('Invalid string kind'); + } + protected function pScalar_Encapsed(Scalar\Encapsed $node) + { + if ($node->getAttribute('kind') === Scalar\String_::KIND_HEREDOC) { + $label = $node->getAttribute('docLabel'); + if ($label && !$this->encapsedContainsEndLabel($node->parts, $label)) { + if (\count($node->parts) === 1 && $node->parts[0] instanceof Scalar\EncapsedStringPart && $node->parts[0]->value === '') { + return "<<<{$label}\n{$label}" . $this->docStringEndToken; + } + return "<<<{$label}\n" . $this->pEncapsList($node->parts, null) . "\n{$label}" . $this->docStringEndToken; + } + } + return '"' . $this->pEncapsList($node->parts, '"') . '"'; + } + protected function pScalar_LNumber(Scalar\LNumber $node) + { + if ($node->value === -\PHP_INT_MAX - 1) { + // PHP_INT_MIN cannot be represented as a literal, + // because the sign is not part of the literal + return '(-' . \PHP_INT_MAX . '-1)'; + } + $kind = $node->getAttribute('kind', Scalar\LNumber::KIND_DEC); + if (Scalar\LNumber::KIND_DEC === $kind) { + return (string) $node->value; + } + if ($node->value < 0) { + $sign = '-'; + $str = (string) -$node->value; + } else { + $sign = ''; + $str = (string) $node->value; + } + switch ($kind) { + case Scalar\LNumber::KIND_BIN: + return $sign . '0b' . \base_convert($str, 10, 2); + case Scalar\LNumber::KIND_OCT: + return $sign . '0' . \base_convert($str, 10, 8); + case Scalar\LNumber::KIND_HEX: + return $sign . '0x' . \base_convert($str, 10, 16); + } + throw new \Exception('Invalid number kind'); + } + protected function pScalar_DNumber(Scalar\DNumber $node) + { + if (!\is_finite($node->value)) { + if ($node->value === \INF) { + return '\\INF'; + } elseif ($node->value === -\INF) { + return '-\\INF'; + } else { + return '\\NAN'; + } + } + // Try to find a short full-precision representation + $stringValue = \sprintf('%.16G', $node->value); + if ($node->value !== (double) $stringValue) { + $stringValue = \sprintf('%.17G', $node->value); + } + // %G is locale dependent and there exists no locale-independent alternative. We don't want + // mess with switching locales here, so let's assume that a comma is the only non-standard + // decimal separator we may encounter... + $stringValue = \str_replace(',', '.', $stringValue); + // ensure that number is really printed as float + return \preg_match('/^-?[0-9]+$/', $stringValue) ? $stringValue . '.0' : $stringValue; + } + protected function pScalar_EncapsedStringPart(Scalar\EncapsedStringPart $node) + { + throw new \LogicException('Cannot directly print EncapsedStringPart'); + } + // Assignments + protected function pExpr_Assign(Expr\Assign $node) + { + return $this->pInfixOp(Expr\Assign::class, $node->var, ' = ', $node->expr); + } + protected function pExpr_AssignRef(Expr\AssignRef $node) + { + return $this->pInfixOp(Expr\AssignRef::class, $node->var, ' =& ', $node->expr); + } + protected function pExpr_AssignOp_Plus(AssignOp\Plus $node) + { + return $this->pInfixOp(AssignOp\Plus::class, $node->var, ' += ', $node->expr); + } + protected function pExpr_AssignOp_Minus(AssignOp\Minus $node) + { + return $this->pInfixOp(AssignOp\Minus::class, $node->var, ' -= ', $node->expr); + } + protected function pExpr_AssignOp_Mul(AssignOp\Mul $node) + { + return $this->pInfixOp(AssignOp\Mul::class, $node->var, ' *= ', $node->expr); + } + protected function pExpr_AssignOp_Div(AssignOp\Div $node) + { + return $this->pInfixOp(AssignOp\Div::class, $node->var, ' /= ', $node->expr); + } + protected function pExpr_AssignOp_Concat(AssignOp\Concat $node) + { + return $this->pInfixOp(AssignOp\Concat::class, $node->var, ' .= ', $node->expr); + } + protected function pExpr_AssignOp_Mod(AssignOp\Mod $node) + { + return $this->pInfixOp(AssignOp\Mod::class, $node->var, ' %= ', $node->expr); + } + protected function pExpr_AssignOp_BitwiseAnd(AssignOp\BitwiseAnd $node) + { + return $this->pInfixOp(AssignOp\BitwiseAnd::class, $node->var, ' &= ', $node->expr); + } + protected function pExpr_AssignOp_BitwiseOr(AssignOp\BitwiseOr $node) + { + return $this->pInfixOp(AssignOp\BitwiseOr::class, $node->var, ' |= ', $node->expr); + } + protected function pExpr_AssignOp_BitwiseXor(AssignOp\BitwiseXor $node) + { + return $this->pInfixOp(AssignOp\BitwiseXor::class, $node->var, ' ^= ', $node->expr); + } + protected function pExpr_AssignOp_ShiftLeft(AssignOp\ShiftLeft $node) + { + return $this->pInfixOp(AssignOp\ShiftLeft::class, $node->var, ' <<= ', $node->expr); + } + protected function pExpr_AssignOp_ShiftRight(AssignOp\ShiftRight $node) + { + return $this->pInfixOp(AssignOp\ShiftRight::class, $node->var, ' >>= ', $node->expr); + } + protected function pExpr_AssignOp_Pow(AssignOp\Pow $node) + { + return $this->pInfixOp(AssignOp\Pow::class, $node->var, ' **= ', $node->expr); + } + protected function pExpr_AssignOp_Coalesce(AssignOp\Coalesce $node) + { + return $this->pInfixOp(AssignOp\Coalesce::class, $node->var, ' ??= ', $node->expr); + } + // Binary expressions + protected function pExpr_BinaryOp_Plus(BinaryOp\Plus $node) + { + return $this->pInfixOp(BinaryOp\Plus::class, $node->left, ' + ', $node->right); + } + protected function pExpr_BinaryOp_Minus(BinaryOp\Minus $node) + { + return $this->pInfixOp(BinaryOp\Minus::class, $node->left, ' - ', $node->right); + } + protected function pExpr_BinaryOp_Mul(BinaryOp\Mul $node) + { + return $this->pInfixOp(BinaryOp\Mul::class, $node->left, ' * ', $node->right); + } + protected function pExpr_BinaryOp_Div(BinaryOp\Div $node) + { + return $this->pInfixOp(BinaryOp\Div::class, $node->left, ' / ', $node->right); + } + protected function pExpr_BinaryOp_Concat(BinaryOp\Concat $node) + { + return $this->pInfixOp(BinaryOp\Concat::class, $node->left, ' . ', $node->right); + } + protected function pExpr_BinaryOp_Mod(BinaryOp\Mod $node) + { + return $this->pInfixOp(BinaryOp\Mod::class, $node->left, ' % ', $node->right); + } + protected function pExpr_BinaryOp_BooleanAnd(BinaryOp\BooleanAnd $node) + { + return $this->pInfixOp(BinaryOp\BooleanAnd::class, $node->left, ' && ', $node->right); + } + protected function pExpr_BinaryOp_BooleanOr(BinaryOp\BooleanOr $node) + { + return $this->pInfixOp(BinaryOp\BooleanOr::class, $node->left, ' || ', $node->right); + } + protected function pExpr_BinaryOp_BitwiseAnd(BinaryOp\BitwiseAnd $node) + { + return $this->pInfixOp(BinaryOp\BitwiseAnd::class, $node->left, ' & ', $node->right); + } + protected function pExpr_BinaryOp_BitwiseOr(BinaryOp\BitwiseOr $node) + { + return $this->pInfixOp(BinaryOp\BitwiseOr::class, $node->left, ' | ', $node->right); + } + protected function pExpr_BinaryOp_BitwiseXor(BinaryOp\BitwiseXor $node) + { + return $this->pInfixOp(BinaryOp\BitwiseXor::class, $node->left, ' ^ ', $node->right); + } + protected function pExpr_BinaryOp_ShiftLeft(BinaryOp\ShiftLeft $node) + { + return $this->pInfixOp(BinaryOp\ShiftLeft::class, $node->left, ' << ', $node->right); + } + protected function pExpr_BinaryOp_ShiftRight(BinaryOp\ShiftRight $node) + { + return $this->pInfixOp(BinaryOp\ShiftRight::class, $node->left, ' >> ', $node->right); + } + protected function pExpr_BinaryOp_Pow(BinaryOp\Pow $node) + { + return $this->pInfixOp(BinaryOp\Pow::class, $node->left, ' ** ', $node->right); + } + protected function pExpr_BinaryOp_LogicalAnd(BinaryOp\LogicalAnd $node) + { + return $this->pInfixOp(BinaryOp\LogicalAnd::class, $node->left, ' and ', $node->right); + } + protected function pExpr_BinaryOp_LogicalOr(BinaryOp\LogicalOr $node) + { + return $this->pInfixOp(BinaryOp\LogicalOr::class, $node->left, ' or ', $node->right); + } + protected function pExpr_BinaryOp_LogicalXor(BinaryOp\LogicalXor $node) + { + return $this->pInfixOp(BinaryOp\LogicalXor::class, $node->left, ' xor ', $node->right); + } + protected function pExpr_BinaryOp_Equal(BinaryOp\Equal $node) + { + return $this->pInfixOp(BinaryOp\Equal::class, $node->left, ' == ', $node->right); + } + protected function pExpr_BinaryOp_NotEqual(BinaryOp\NotEqual $node) + { + return $this->pInfixOp(BinaryOp\NotEqual::class, $node->left, ' != ', $node->right); + } + protected function pExpr_BinaryOp_Identical(BinaryOp\Identical $node) + { + return $this->pInfixOp(BinaryOp\Identical::class, $node->left, ' === ', $node->right); + } + protected function pExpr_BinaryOp_NotIdentical(BinaryOp\NotIdentical $node) + { + return $this->pInfixOp(BinaryOp\NotIdentical::class, $node->left, ' !== ', $node->right); + } + protected function pExpr_BinaryOp_Spaceship(BinaryOp\Spaceship $node) + { + return $this->pInfixOp(BinaryOp\Spaceship::class, $node->left, ' <=> ', $node->right); + } + protected function pExpr_BinaryOp_Greater(BinaryOp\Greater $node) + { + return $this->pInfixOp(BinaryOp\Greater::class, $node->left, ' > ', $node->right); + } + protected function pExpr_BinaryOp_GreaterOrEqual(BinaryOp\GreaterOrEqual $node) + { + return $this->pInfixOp(BinaryOp\GreaterOrEqual::class, $node->left, ' >= ', $node->right); + } + protected function pExpr_BinaryOp_Smaller(BinaryOp\Smaller $node) + { + return $this->pInfixOp(BinaryOp\Smaller::class, $node->left, ' < ', $node->right); + } + protected function pExpr_BinaryOp_SmallerOrEqual(BinaryOp\SmallerOrEqual $node) + { + return $this->pInfixOp(BinaryOp\SmallerOrEqual::class, $node->left, ' <= ', $node->right); + } + protected function pExpr_BinaryOp_Coalesce(BinaryOp\Coalesce $node) + { + return $this->pInfixOp(BinaryOp\Coalesce::class, $node->left, ' ?? ', $node->right); + } + protected function pExpr_Instanceof(Expr\Instanceof_ $node) + { + list($precedence, $associativity) = $this->precedenceMap[Expr\Instanceof_::class]; + return $this->pPrec($node->expr, $precedence, $associativity, -1) . ' instanceof ' . $this->pNewVariable($node->class); + } + // Unary expressions + protected function pExpr_BooleanNot(Expr\BooleanNot $node) + { + return $this->pPrefixOp(Expr\BooleanNot::class, '!', $node->expr); + } + protected function pExpr_BitwiseNot(Expr\BitwiseNot $node) + { + return $this->pPrefixOp(Expr\BitwiseNot::class, '~', $node->expr); + } + protected function pExpr_UnaryMinus(Expr\UnaryMinus $node) + { + if ($node->expr instanceof Expr\UnaryMinus || $node->expr instanceof Expr\PreDec) { + // Enforce -(-$expr) instead of --$expr + return '-(' . $this->p($node->expr) . ')'; + } + return $this->pPrefixOp(Expr\UnaryMinus::class, '-', $node->expr); + } + protected function pExpr_UnaryPlus(Expr\UnaryPlus $node) + { + if ($node->expr instanceof Expr\UnaryPlus || $node->expr instanceof Expr\PreInc) { + // Enforce +(+$expr) instead of ++$expr + return '+(' . $this->p($node->expr) . ')'; + } + return $this->pPrefixOp(Expr\UnaryPlus::class, '+', $node->expr); + } + protected function pExpr_PreInc(Expr\PreInc $node) + { + return $this->pPrefixOp(Expr\PreInc::class, '++', $node->var); + } + protected function pExpr_PreDec(Expr\PreDec $node) + { + return $this->pPrefixOp(Expr\PreDec::class, '--', $node->var); + } + protected function pExpr_PostInc(Expr\PostInc $node) + { + return $this->pPostfixOp(Expr\PostInc::class, $node->var, '++'); + } + protected function pExpr_PostDec(Expr\PostDec $node) + { + return $this->pPostfixOp(Expr\PostDec::class, $node->var, '--'); + } + protected function pExpr_ErrorSuppress(Expr\ErrorSuppress $node) + { + return $this->pPrefixOp(Expr\ErrorSuppress::class, '@', $node->expr); + } + protected function pExpr_YieldFrom(Expr\YieldFrom $node) + { + return $this->pPrefixOp(Expr\YieldFrom::class, 'yield from ', $node->expr); + } + protected function pExpr_Print(Expr\Print_ $node) + { + return $this->pPrefixOp(Expr\Print_::class, 'print ', $node->expr); + } + // Casts + protected function pExpr_Cast_Int(Cast\Int_ $node) + { + return $this->pPrefixOp(Cast\Int_::class, '(int) ', $node->expr); + } + protected function pExpr_Cast_Double(Cast\Double $node) + { + $kind = $node->getAttribute('kind', Cast\Double::KIND_DOUBLE); + if ($kind === Cast\Double::KIND_DOUBLE) { + $cast = '(double)'; + } elseif ($kind === Cast\Double::KIND_FLOAT) { + $cast = '(float)'; + } elseif ($kind === Cast\Double::KIND_REAL) { + $cast = '(real)'; + } + return $this->pPrefixOp(Cast\Double::class, $cast . ' ', $node->expr); + } + protected function pExpr_Cast_String(Cast\String_ $node) + { + return $this->pPrefixOp(Cast\String_::class, '(string) ', $node->expr); + } + protected function pExpr_Cast_Array(Cast\Array_ $node) + { + return $this->pPrefixOp(Cast\Array_::class, '(array) ', $node->expr); + } + protected function pExpr_Cast_Object(Cast\Object_ $node) + { + return $this->pPrefixOp(Cast\Object_::class, '(object) ', $node->expr); + } + protected function pExpr_Cast_Bool(Cast\Bool_ $node) + { + return $this->pPrefixOp(Cast\Bool_::class, '(bool) ', $node->expr); + } + protected function pExpr_Cast_Unset(Cast\Unset_ $node) + { + return $this->pPrefixOp(Cast\Unset_::class, '(unset) ', $node->expr); + } + // Function calls and similar constructs + protected function pExpr_FuncCall(Expr\FuncCall $node) + { + return $this->pCallLhs($node->name) . '(' . $this->pMaybeMultiline($node->args) . ')'; + } + protected function pExpr_MethodCall(Expr\MethodCall $node) + { + return $this->pDereferenceLhs($node->var) . '->' . $this->pObjectProperty($node->name) . '(' . $this->pMaybeMultiline($node->args) . ')'; + } + protected function pExpr_NullsafeMethodCall(Expr\NullsafeMethodCall $node) + { + return $this->pDereferenceLhs($node->var) . '?->' . $this->pObjectProperty($node->name) . '(' . $this->pMaybeMultiline($node->args) . ')'; + } + protected function pExpr_StaticCall(Expr\StaticCall $node) + { + return $this->pStaticDereferenceLhs($node->class) . '::' . ($node->name instanceof Expr ? $node->name instanceof Expr\Variable ? $this->p($node->name) : '{' . $this->p($node->name) . '}' : $node->name) . '(' . $this->pMaybeMultiline($node->args) . ')'; + } + protected function pExpr_Empty(Expr\Empty_ $node) + { + return 'empty(' . $this->p($node->expr) . ')'; + } + protected function pExpr_Isset(Expr\Isset_ $node) + { + return 'isset(' . $this->pCommaSeparated($node->vars) . ')'; + } + protected function pExpr_Eval(Expr\Eval_ $node) + { + return 'eval(' . $this->p($node->expr) . ')'; + } + protected function pExpr_Include(Expr\Include_ $node) + { + static $map = [Expr\Include_::TYPE_INCLUDE => 'include', Expr\Include_::TYPE_INCLUDE_ONCE => 'include_once', Expr\Include_::TYPE_REQUIRE => 'require', Expr\Include_::TYPE_REQUIRE_ONCE => 'require_once']; + return $map[$node->type] . ' ' . $this->p($node->expr); + } + protected function pExpr_List(Expr\List_ $node) + { + return 'list(' . $this->pCommaSeparated($node->items) . ')'; + } + // Other + protected function pExpr_Error(Expr\Error $node) + { + throw new \LogicException('Cannot pretty-print AST with Error nodes'); + } + protected function pExpr_Variable(Expr\Variable $node) + { + if ($node->name instanceof Expr) { + return '${' . $this->p($node->name) . '}'; + } else { + return '$' . $node->name; + } + } + protected function pExpr_Array(Expr\Array_ $node) + { + $syntax = $node->getAttribute('kind', $this->options['shortArraySyntax'] ? Expr\Array_::KIND_SHORT : Expr\Array_::KIND_LONG); + if ($syntax === Expr\Array_::KIND_SHORT) { + return '[' . $this->pMaybeMultiline($node->items, \true) . ']'; + } else { + return 'array(' . $this->pMaybeMultiline($node->items, \true) . ')'; + } + } + protected function pExpr_ArrayItem(Expr\ArrayItem $node) + { + return (null !== $node->key ? $this->p($node->key) . ' => ' : '') . ($node->byRef ? '&' : '') . ($node->unpack ? '...' : '') . $this->p($node->value); + } + protected function pExpr_ArrayDimFetch(Expr\ArrayDimFetch $node) + { + return $this->pDereferenceLhs($node->var) . '[' . (null !== $node->dim ? $this->p($node->dim) : '') . ']'; + } + protected function pExpr_ConstFetch(Expr\ConstFetch $node) + { + return $this->p($node->name); + } + protected function pExpr_ClassConstFetch(Expr\ClassConstFetch $node) + { + return $this->pStaticDereferenceLhs($node->class) . '::' . $this->pObjectProperty($node->name); + } + protected function pExpr_PropertyFetch(Expr\PropertyFetch $node) + { + return $this->pDereferenceLhs($node->var) . '->' . $this->pObjectProperty($node->name); + } + protected function pExpr_NullsafePropertyFetch(Expr\NullsafePropertyFetch $node) + { + return $this->pDereferenceLhs($node->var) . '?->' . $this->pObjectProperty($node->name); + } + protected function pExpr_StaticPropertyFetch(Expr\StaticPropertyFetch $node) + { + return $this->pStaticDereferenceLhs($node->class) . '::$' . $this->pObjectProperty($node->name); + } + protected function pExpr_ShellExec(Expr\ShellExec $node) + { + return '`' . $this->pEncapsList($node->parts, '`') . '`'; + } + protected function pExpr_Closure(Expr\Closure $node) + { + return $this->pAttrGroups($node->attrGroups, \true) . ($node->static ? 'static ' : '') . 'function ' . ($node->byRef ? '&' : '') . '(' . $this->pCommaSeparated($node->params) . ')' . (!empty($node->uses) ? ' use(' . $this->pCommaSeparated($node->uses) . ')' : '') . (null !== $node->returnType ? ' : ' . $this->p($node->returnType) : '') . ' {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pExpr_Match(Expr\Match_ $node) + { + return 'match (' . $this->p($node->cond) . ') {' . $this->pCommaSeparatedMultiline($node->arms, \true) . $this->nl . '}'; + } + protected function pMatchArm(Node\MatchArm $node) + { + return ($node->conds ? $this->pCommaSeparated($node->conds) : 'default') . ' => ' . $this->p($node->body); + } + protected function pExpr_ArrowFunction(Expr\ArrowFunction $node) + { + return $this->pAttrGroups($node->attrGroups, \true) . ($node->static ? 'static ' : '') . 'fn' . ($node->byRef ? '&' : '') . '(' . $this->pCommaSeparated($node->params) . ')' . (null !== $node->returnType ? ': ' . $this->p($node->returnType) : '') . ' => ' . $this->p($node->expr); + } + protected function pExpr_ClosureUse(Expr\ClosureUse $node) + { + return ($node->byRef ? '&' : '') . $this->p($node->var); + } + protected function pExpr_New(Expr\New_ $node) + { + if ($node->class instanceof Stmt\Class_) { + $args = $node->args ? '(' . $this->pMaybeMultiline($node->args) . ')' : ''; + return 'new ' . $this->pClassCommon($node->class, $args); + } + return 'new ' . $this->pNewVariable($node->class) . '(' . $this->pMaybeMultiline($node->args) . ')'; + } + protected function pExpr_Clone(Expr\Clone_ $node) + { + return 'clone ' . $this->p($node->expr); + } + protected function pExpr_Ternary(Expr\Ternary $node) + { + // a bit of cheating: we treat the ternary as a binary op where the ?...: part is the operator. + // this is okay because the part between ? and : never needs parentheses. + return $this->pInfixOp(Expr\Ternary::class, $node->cond, ' ?' . (null !== $node->if ? ' ' . $this->p($node->if) . ' ' : '') . ': ', $node->else); + } + protected function pExpr_Exit(Expr\Exit_ $node) + { + $kind = $node->getAttribute('kind', Expr\Exit_::KIND_DIE); + return ($kind === Expr\Exit_::KIND_EXIT ? 'exit' : 'die') . (null !== $node->expr ? '(' . $this->p($node->expr) . ')' : ''); + } + protected function pExpr_Throw(Expr\Throw_ $node) + { + return 'throw ' . $this->p($node->expr); + } + protected function pExpr_Yield(Expr\Yield_ $node) + { + if ($node->value === null) { + return 'yield'; + } else { + // this is a bit ugly, but currently there is no way to detect whether the parentheses are necessary + return '(yield ' . ($node->key !== null ? $this->p($node->key) . ' => ' : '') . $this->p($node->value) . ')'; + } + } + // Declarations + protected function pStmt_Namespace(Stmt\Namespace_ $node) + { + if ($this->canUseSemicolonNamespaces) { + return 'namespace ' . $this->p($node->name) . ';' . $this->nl . $this->pStmts($node->stmts, \false); + } else { + return 'namespace' . (null !== $node->name ? ' ' . $this->p($node->name) : '') . ' {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + } + protected function pStmt_Use(Stmt\Use_ $node) + { + return 'use ' . $this->pUseType($node->type) . $this->pCommaSeparated($node->uses) . ';'; + } + protected function pStmt_GroupUse(Stmt\GroupUse $node) + { + return 'use ' . $this->pUseType($node->type) . $this->pName($node->prefix) . '\\{' . $this->pCommaSeparated($node->uses) . '};'; + } + protected function pStmt_UseUse(Stmt\UseUse $node) + { + return $this->pUseType($node->type) . $this->p($node->name) . (null !== $node->alias ? ' as ' . $node->alias : ''); + } + protected function pUseType($type) + { + return $type === Stmt\Use_::TYPE_FUNCTION ? 'function ' : ($type === Stmt\Use_::TYPE_CONSTANT ? 'const ' : ''); + } + protected function pStmt_Interface(Stmt\Interface_ $node) + { + return $this->pAttrGroups($node->attrGroups) . 'interface ' . $node->name . (!empty($node->extends) ? ' extends ' . $this->pCommaSeparated($node->extends) : '') . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_Enum(Stmt\Enum_ $node) + { + return $this->pAttrGroups($node->attrGroups) . 'enum ' . $node->name . ($node->scalarType ? " : {$node->scalarType}" : '') . (!empty($node->implements) ? ' implements ' . $this->pCommaSeparated($node->implements) : '') . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_Class(Stmt\Class_ $node) + { + return $this->pClassCommon($node, ' ' . $node->name); + } + protected function pStmt_Trait(Stmt\Trait_ $node) + { + return $this->pAttrGroups($node->attrGroups) . 'trait ' . $node->name . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_EnumCase(Stmt\EnumCase $node) + { + return $this->pAttrGroups($node->attrGroups) . 'case ' . $node->name . ($node->expr ? ' = ' . $this->p($node->expr) : '') . ';'; + } + protected function pStmt_TraitUse(Stmt\TraitUse $node) + { + return 'use ' . $this->pCommaSeparated($node->traits) . (empty($node->adaptations) ? ';' : ' {' . $this->pStmts($node->adaptations) . $this->nl . '}'); + } + protected function pStmt_TraitUseAdaptation_Precedence(Stmt\TraitUseAdaptation\Precedence $node) + { + return $this->p($node->trait) . '::' . $node->method . ' insteadof ' . $this->pCommaSeparated($node->insteadof) . ';'; + } + protected function pStmt_TraitUseAdaptation_Alias(Stmt\TraitUseAdaptation\Alias $node) + { + return (null !== $node->trait ? $this->p($node->trait) . '::' : '') . $node->method . ' as' . (null !== $node->newModifier ? ' ' . \rtrim($this->pModifiers($node->newModifier), ' ') : '') . (null !== $node->newName ? ' ' . $node->newName : '') . ';'; + } + protected function pStmt_Property(Stmt\Property $node) + { + return $this->pAttrGroups($node->attrGroups) . (0 === $node->flags ? 'var ' : $this->pModifiers($node->flags)) . ($node->type ? $this->p($node->type) . ' ' : '') . $this->pCommaSeparated($node->props) . ';'; + } + protected function pStmt_PropertyProperty(Stmt\PropertyProperty $node) + { + return '$' . $node->name . (null !== $node->default ? ' = ' . $this->p($node->default) : ''); + } + protected function pStmt_ClassMethod(Stmt\ClassMethod $node) + { + return $this->pAttrGroups($node->attrGroups) . $this->pModifiers($node->flags) . 'function ' . ($node->byRef ? '&' : '') . $node->name . '(' . $this->pMaybeMultiline($node->params) . ')' . (null !== $node->returnType ? ' : ' . $this->p($node->returnType) : '') . (null !== $node->stmts ? $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}' : ';'); + } + protected function pStmt_ClassConst(Stmt\ClassConst $node) + { + return $this->pAttrGroups($node->attrGroups) . $this->pModifiers($node->flags) . 'const ' . (null !== $node->type ? $this->p($node->type) . ' ' : '') . $this->pCommaSeparated($node->consts) . ';'; + } + protected function pStmt_Function(Stmt\Function_ $node) + { + return $this->pAttrGroups($node->attrGroups) . 'function ' . ($node->byRef ? '&' : '') . $node->name . '(' . $this->pCommaSeparated($node->params) . ')' . (null !== $node->returnType ? ' : ' . $this->p($node->returnType) : '') . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_Const(Stmt\Const_ $node) + { + return 'const ' . $this->pCommaSeparated($node->consts) . ';'; + } + protected function pStmt_Declare(Stmt\Declare_ $node) + { + return 'declare (' . $this->pCommaSeparated($node->declares) . ')' . (null !== $node->stmts ? ' {' . $this->pStmts($node->stmts) . $this->nl . '}' : ';'); + } + protected function pStmt_DeclareDeclare(Stmt\DeclareDeclare $node) + { + return $node->key . '=' . $this->p($node->value); + } + // Control flow + protected function pStmt_If(Stmt\If_ $node) + { + return 'if (' . $this->p($node->cond) . ') {' . $this->pStmts($node->stmts) . $this->nl . '}' . ($node->elseifs ? ' ' . $this->pImplode($node->elseifs, ' ') : '') . (null !== $node->else ? ' ' . $this->p($node->else) : ''); + } + protected function pStmt_ElseIf(Stmt\ElseIf_ $node) + { + return 'elseif (' . $this->p($node->cond) . ') {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_Else(Stmt\Else_ $node) + { + return 'else {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_For(Stmt\For_ $node) + { + return 'for (' . $this->pCommaSeparated($node->init) . ';' . (!empty($node->cond) ? ' ' : '') . $this->pCommaSeparated($node->cond) . ';' . (!empty($node->loop) ? ' ' : '') . $this->pCommaSeparated($node->loop) . ') {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_Foreach(Stmt\Foreach_ $node) + { + return 'foreach (' . $this->p($node->expr) . ' as ' . (null !== $node->keyVar ? $this->p($node->keyVar) . ' => ' : '') . ($node->byRef ? '&' : '') . $this->p($node->valueVar) . ') {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_While(Stmt\While_ $node) + { + return 'while (' . $this->p($node->cond) . ') {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_Do(Stmt\Do_ $node) + { + return 'do {' . $this->pStmts($node->stmts) . $this->nl . '} while (' . $this->p($node->cond) . ');'; + } + protected function pStmt_Switch(Stmt\Switch_ $node) + { + return 'switch (' . $this->p($node->cond) . ') {' . $this->pStmts($node->cases) . $this->nl . '}'; + } + protected function pStmt_Case(Stmt\Case_ $node) + { + return (null !== $node->cond ? 'case ' . $this->p($node->cond) : 'default') . ':' . $this->pStmts($node->stmts); + } + protected function pStmt_TryCatch(Stmt\TryCatch $node) + { + return 'try {' . $this->pStmts($node->stmts) . $this->nl . '}' . ($node->catches ? ' ' . $this->pImplode($node->catches, ' ') : '') . ($node->finally !== null ? ' ' . $this->p($node->finally) : ''); + } + protected function pStmt_Catch(Stmt\Catch_ $node) + { + return 'catch (' . $this->pImplode($node->types, '|') . ($node->var !== null ? ' ' . $this->p($node->var) : '') . ') {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_Finally(Stmt\Finally_ $node) + { + return 'finally {' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pStmt_Break(Stmt\Break_ $node) + { + return 'break' . ($node->num !== null ? ' ' . $this->p($node->num) : '') . ';'; + } + protected function pStmt_Continue(Stmt\Continue_ $node) + { + return 'continue' . ($node->num !== null ? ' ' . $this->p($node->num) : '') . ';'; + } + protected function pStmt_Return(Stmt\Return_ $node) + { + return 'return' . (null !== $node->expr ? ' ' . $this->p($node->expr) : '') . ';'; + } + protected function pStmt_Throw(Stmt\Throw_ $node) + { + return 'throw ' . $this->p($node->expr) . ';'; + } + protected function pStmt_Label(Stmt\Label $node) + { + return $node->name . ':'; + } + protected function pStmt_Goto(Stmt\Goto_ $node) + { + return 'goto ' . $node->name . ';'; + } + // Other + protected function pStmt_Expression(Stmt\Expression $node) + { + return $this->p($node->expr) . ';'; + } + protected function pStmt_Echo(Stmt\Echo_ $node) + { + return 'echo ' . $this->pCommaSeparated($node->exprs) . ';'; + } + protected function pStmt_Static(Stmt\Static_ $node) + { + return 'static ' . $this->pCommaSeparated($node->vars) . ';'; + } + protected function pStmt_Global(Stmt\Global_ $node) + { + return 'global ' . $this->pCommaSeparated($node->vars) . ';'; + } + protected function pStmt_StaticVar(Stmt\StaticVar $node) + { + return $this->p($node->var) . (null !== $node->default ? ' = ' . $this->p($node->default) : ''); + } + protected function pStmt_Unset(Stmt\Unset_ $node) + { + return 'unset(' . $this->pCommaSeparated($node->vars) . ');'; + } + protected function pStmt_InlineHTML(Stmt\InlineHTML $node) + { + $newline = $node->getAttribute('hasLeadingNewline', \true) ? "\n" : ''; + return '?>' . $newline . $node->value . 'remaining; + } + protected function pStmt_Nop(Stmt\Nop $node) + { + return ''; + } + // Helpers + protected function pClassCommon(Stmt\Class_ $node, $afterClassToken) + { + return $this->pAttrGroups($node->attrGroups, $node->name === null) . $this->pModifiers($node->flags) . 'class' . $afterClassToken . (null !== $node->extends ? ' extends ' . $this->p($node->extends) : '') . (!empty($node->implements) ? ' implements ' . $this->pCommaSeparated($node->implements) : '') . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'; + } + protected function pObjectProperty($node) + { + if ($node instanceof Expr) { + return '{' . $this->p($node) . '}'; + } else { + return $node; + } + } + protected function pEncapsList(array $encapsList, $quote) + { + $return = ''; + foreach ($encapsList as $element) { + if ($element instanceof Scalar\EncapsedStringPart) { + $return .= $this->escapeString($element->value, $quote); + } else { + $return .= '{' . $this->p($element) . '}'; + } + } + return $return; + } + protected function pSingleQuotedString(string $string) + { + return '\'' . \addcslashes($string, '\'\\') . '\''; + } + protected function escapeString($string, $quote) + { + if (null === $quote) { + // For doc strings, don't escape newlines + $escaped = \addcslashes($string, "\t\f\v\$\\"); + } else { + $escaped = \addcslashes($string, "\n\r\t\f\v\$" . $quote . "\\"); + } + // Escape control characters and non-UTF-8 characters. + // Regex based on https://stackoverflow.com/a/11709412/385378. + $regex = '/( + [\\x00-\\x08\\x0E-\\x1F] # Control characters + | [\\xC0-\\xC1] # Invalid UTF-8 Bytes + | [\\xF5-\\xFF] # Invalid UTF-8 Bytes + | \\xE0(?=[\\x80-\\x9F]) # Overlong encoding of prior code point + | \\xF0(?=[\\x80-\\x8F]) # Overlong encoding of prior code point + | [\\xC2-\\xDF](?![\\x80-\\xBF]) # Invalid UTF-8 Sequence Start + | [\\xE0-\\xEF](?![\\x80-\\xBF]{2}) # Invalid UTF-8 Sequence Start + | [\\xF0-\\xF4](?![\\x80-\\xBF]{3}) # Invalid UTF-8 Sequence Start + | (?<=[\\x00-\\x7F\\xF5-\\xFF])[\\x80-\\xBF] # Invalid UTF-8 Sequence Middle + | (? $part) { + $atStart = $i === 0; + $atEnd = $i === \count($parts) - 1; + if ($part instanceof Scalar\EncapsedStringPart && $this->containsEndLabel($part->value, $label, $atStart, $atEnd)) { + return \true; + } + } + return \false; + } + protected function pDereferenceLhs(Node $node) + { + if (!$this->dereferenceLhsRequiresParens($node)) { + return $this->p($node); + } else { + return '(' . $this->p($node) . ')'; + } + } + protected function pStaticDereferenceLhs(Node $node) + { + if (!$this->staticDereferenceLhsRequiresParens($node)) { + return $this->p($node); + } else { + return '(' . $this->p($node) . ')'; + } + } + protected function pCallLhs(Node $node) + { + if (!$this->callLhsRequiresParens($node)) { + return $this->p($node); + } else { + return '(' . $this->p($node) . ')'; + } + } + protected function pNewVariable(Node $node) : string + { + if (!$this->newOperandRequiresParens($node)) { + return $this->p($node); + } else { + return '(' . $this->p($node) . ')'; + } + } + /** + * @param Node[] $nodes + * @return bool + */ + protected function hasNodeWithComments(array $nodes) + { + foreach ($nodes as $node) { + if ($node && $node->getComments()) { + return \true; + } + } + return \false; + } + protected function pMaybeMultiline(array $nodes, bool $trailingComma = \false) + { + if (!$this->hasNodeWithComments($nodes)) { + return $this->pCommaSeparated($nodes); + } else { + return $this->pCommaSeparatedMultiline($nodes, $trailingComma) . $this->nl; + } + } + protected function pAttrGroups(array $nodes, bool $inline = \false) : string + { + $result = ''; + $sep = $inline ? ' ' : $this->nl; + foreach ($nodes as $node) { + $result .= $this->p($node) . $sep; + } + return $result; + } +} diff --git a/vendor/nikic/php-parser/lib/PhpParser/PrettyPrinterAbstract.php b/vendor/nikic/php-parser/lib/PhpParser/PrettyPrinterAbstract.php new file mode 100644 index 0000000000..891e9a52cf --- /dev/null +++ b/vendor/nikic/php-parser/lib/PhpParser/PrettyPrinterAbstract.php @@ -0,0 +1,1254 @@ + [0, 1], + Expr\BitwiseNot::class => [10, 1], + Expr\PreInc::class => [10, 1], + Expr\PreDec::class => [10, 1], + Expr\PostInc::class => [10, -1], + Expr\PostDec::class => [10, -1], + Expr\UnaryPlus::class => [10, 1], + Expr\UnaryMinus::class => [10, 1], + Cast\Int_::class => [10, 1], + Cast\Double::class => [10, 1], + Cast\String_::class => [10, 1], + Cast\Array_::class => [10, 1], + Cast\Object_::class => [10, 1], + Cast\Bool_::class => [10, 1], + Cast\Unset_::class => [10, 1], + Expr\ErrorSuppress::class => [10, 1], + Expr\Instanceof_::class => [20, 0], + Expr\BooleanNot::class => [30, 1], + BinaryOp\Mul::class => [40, -1], + BinaryOp\Div::class => [40, -1], + BinaryOp\Mod::class => [40, -1], + BinaryOp\Plus::class => [50, -1], + BinaryOp\Minus::class => [50, -1], + BinaryOp\Concat::class => [50, -1], + BinaryOp\ShiftLeft::class => [60, -1], + BinaryOp\ShiftRight::class => [60, -1], + BinaryOp\Smaller::class => [70, 0], + BinaryOp\SmallerOrEqual::class => [70, 0], + BinaryOp\Greater::class => [70, 0], + BinaryOp\GreaterOrEqual::class => [70, 0], + BinaryOp\Equal::class => [80, 0], + BinaryOp\NotEqual::class => [80, 0], + BinaryOp\Identical::class => [80, 0], + BinaryOp\NotIdentical::class => [80, 0], + BinaryOp\Spaceship::class => [80, 0], + BinaryOp\BitwiseAnd::class => [90, -1], + BinaryOp\BitwiseXor::class => [100, -1], + BinaryOp\BitwiseOr::class => [110, -1], + BinaryOp\BooleanAnd::class => [120, -1], + BinaryOp\BooleanOr::class => [130, -1], + BinaryOp\Coalesce::class => [140, 1], + Expr\Ternary::class => [150, 0], + // parser uses %left for assignments, but they really behave as %right + Expr\Assign::class => [160, 1], + Expr\AssignRef::class => [160, 1], + AssignOp\Plus::class => [160, 1], + AssignOp\Minus::class => [160, 1], + AssignOp\Mul::class => [160, 1], + AssignOp\Div::class => [160, 1], + AssignOp\Concat::class => [160, 1], + AssignOp\Mod::class => [160, 1], + AssignOp\BitwiseAnd::class => [160, 1], + AssignOp\BitwiseOr::class => [160, 1], + AssignOp\BitwiseXor::class => [160, 1], + AssignOp\ShiftLeft::class => [160, 1], + AssignOp\ShiftRight::class => [160, 1], + AssignOp\Pow::class => [160, 1], + AssignOp\Coalesce::class => [160, 1], + Expr\YieldFrom::class => [165, 1], + Expr\Print_::class => [168, 1], + BinaryOp\LogicalAnd::class => [170, -1], + BinaryOp\LogicalXor::class => [180, -1], + BinaryOp\LogicalOr::class => [190, -1], + Expr\Include_::class => [200, -1], + ]; + /** @var int Current indentation level. */ + protected $indentLevel; + /** @var string Newline including current indentation. */ + protected $nl; + /** @var string Token placed at end of doc string to ensure it is followed by a newline. */ + protected $docStringEndToken; + /** @var bool Whether semicolon namespaces can be used (i.e. no global namespace is used) */ + protected $canUseSemicolonNamespaces; + /** @var array Pretty printer options */ + protected $options; + /** @var TokenStream Original tokens for use in format-preserving pretty print */ + protected $origTokens; + /** @var Internal\Differ Differ for node lists */ + protected $nodeListDiffer; + /** @var bool[] Map determining whether a certain character is a label character */ + protected $labelCharMap; + /** + * @var int[][] Map from token classes and subnode names to FIXUP_* constants. This is used + * during format-preserving prints to place additional parens/braces if necessary. + */ + protected $fixupMap; + /** + * @var int[][] Map from "{$node->getType()}->{$subNode}" to ['left' => $l, 'right' => $r], + * where $l and $r specify the token type that needs to be stripped when removing + * this node. + */ + protected $removalMap; + /** + * @var mixed[] Map from "{$node->getType()}->{$subNode}" to [$find, $beforeToken, $extraLeft, $extraRight]. + * $find is an optional token after which the insertion occurs. $extraLeft/Right + * are optionally added before/after the main insertions. + */ + protected $insertionMap; + /** + * @var string[] Map From "{$node->getType()}->{$subNode}" to string that should be inserted + * between elements of this list subnode. + */ + protected $listInsertionMap; + protected $emptyListInsertionMap; + /** @var int[] Map from "{$node->getType()}->{$subNode}" to token before which the modifiers + * should be reprinted. */ + protected $modifierChangeMap; + /** + * Creates a pretty printer instance using the given options. + * + * Supported options: + * * bool $shortArraySyntax = false: Whether to use [] instead of array() as the default array + * syntax, if the node does not specify a format. + * + * @param array $options Dictionary of formatting options + */ + public function __construct(array $options = []) + { + $this->docStringEndToken = '_DOC_STRING_END_' . \mt_rand(); + $defaultOptions = ['shortArraySyntax' => \false]; + $this->options = $options + $defaultOptions; + } + /** + * Reset pretty printing state. + */ + protected function resetState() + { + $this->indentLevel = 0; + $this->nl = "\n"; + $this->origTokens = null; + } + /** + * Set indentation level + * + * @param int $level Level in number of spaces + */ + protected function setIndentLevel(int $level) + { + $this->indentLevel = $level; + $this->nl = "\n" . \str_repeat(' ', $level); + } + /** + * Increase indentation level. + */ + protected function indent() + { + $this->indentLevel += 4; + $this->nl .= ' '; + } + /** + * Decrease indentation level. + */ + protected function outdent() + { + \assert($this->indentLevel >= 4); + $this->indentLevel -= 4; + $this->nl = "\n" . \str_repeat(' ', $this->indentLevel); + } + /** + * Pretty prints an array of statements. + * + * @param Node[] $stmts Array of statements + * + * @return string Pretty printed statements + */ + public function prettyPrint(array $stmts) : string + { + $this->resetState(); + $this->preprocessNodes($stmts); + return \ltrim($this->handleMagicTokens($this->pStmts($stmts, \false))); + } + /** + * Pretty prints an expression. + * + * @param Expr $node Expression node + * + * @return string Pretty printed node + */ + public function prettyPrintExpr(Expr $node) : string + { + $this->resetState(); + return $this->handleMagicTokens($this->p($node)); + } + /** + * Pretty prints a file of statements (includes the opening prettyPrint($stmts); + if ($stmts[0] instanceof Stmt\InlineHTML) { + $p = \preg_replace('/^<\\?php\\s+\\?>\\n?/', '', $p); + } + if ($stmts[\count($stmts) - 1] instanceof Stmt\InlineHTML) { + $p = \preg_replace('/<\\?php$/', '', \rtrim($p)); + } + return $p; + } + /** + * Preprocesses the top-level nodes to initialize pretty printer state. + * + * @param Node[] $nodes Array of nodes + */ + protected function preprocessNodes(array $nodes) + { + /* We can use semicolon-namespaces unless there is a global namespace declaration */ + $this->canUseSemicolonNamespaces = \true; + foreach ($nodes as $node) { + if ($node instanceof Stmt\Namespace_ && null === $node->name) { + $this->canUseSemicolonNamespaces = \false; + break; + } + } + } + /** + * Handles (and removes) no-indent and doc-string-end tokens. + * + * @param string $str + * @return string + */ + protected function handleMagicTokens(string $str) : string + { + // Replace doc-string-end tokens with nothing or a newline + $str = \str_replace($this->docStringEndToken . ";\n", ";\n", $str); + $str = \str_replace($this->docStringEndToken, "\n", $str); + return $str; + } + /** + * Pretty prints an array of nodes (statements) and indents them optionally. + * + * @param Node[] $nodes Array of nodes + * @param bool $indent Whether to indent the printed nodes + * + * @return string Pretty printed statements + */ + protected function pStmts(array $nodes, bool $indent = \true) : string + { + if ($indent) { + $this->indent(); + } + $result = ''; + foreach ($nodes as $node) { + $comments = $node->getComments(); + if ($comments) { + $result .= $this->nl . $this->pComments($comments); + if ($node instanceof Stmt\Nop) { + continue; + } + } + $result .= $this->nl . $this->p($node); + } + if ($indent) { + $this->outdent(); + } + return $result; + } + /** + * Pretty-print an infix operation while taking precedence into account. + * + * @param string $class Node class of operator + * @param Node $leftNode Left-hand side node + * @param string $operatorString String representation of the operator + * @param Node $rightNode Right-hand side node + * + * @return string Pretty printed infix operation + */ + protected function pInfixOp(string $class, Node $leftNode, string $operatorString, Node $rightNode) : string + { + list($precedence, $associativity) = $this->precedenceMap[$class]; + return $this->pPrec($leftNode, $precedence, $associativity, -1) . $operatorString . $this->pPrec($rightNode, $precedence, $associativity, 1); + } + /** + * Pretty-print a prefix operation while taking precedence into account. + * + * @param string $class Node class of operator + * @param string $operatorString String representation of the operator + * @param Node $node Node + * + * @return string Pretty printed prefix operation + */ + protected function pPrefixOp(string $class, string $operatorString, Node $node) : string + { + list($precedence, $associativity) = $this->precedenceMap[$class]; + return $operatorString . $this->pPrec($node, $precedence, $associativity, 1); + } + /** + * Pretty-print a postfix operation while taking precedence into account. + * + * @param string $class Node class of operator + * @param string $operatorString String representation of the operator + * @param Node $node Node + * + * @return string Pretty printed postfix operation + */ + protected function pPostfixOp(string $class, Node $node, string $operatorString) : string + { + list($precedence, $associativity) = $this->precedenceMap[$class]; + return $this->pPrec($node, $precedence, $associativity, -1) . $operatorString; + } + /** + * Prints an expression node with the least amount of parentheses necessary to preserve the meaning. + * + * @param Node $node Node to pretty print + * @param int $parentPrecedence Precedence of the parent operator + * @param int $parentAssociativity Associativity of parent operator + * (-1 is left, 0 is nonassoc, 1 is right) + * @param int $childPosition Position of the node relative to the operator + * (-1 is left, 1 is right) + * + * @return string The pretty printed node + */ + protected function pPrec(Node $node, int $parentPrecedence, int $parentAssociativity, int $childPosition) : string + { + $class = \get_class($node); + if (isset($this->precedenceMap[$class])) { + $childPrecedence = $this->precedenceMap[$class][0]; + if ($childPrecedence > $parentPrecedence || $parentPrecedence === $childPrecedence && $parentAssociativity !== $childPosition) { + return '(' . $this->p($node) . ')'; + } + } + return $this->p($node); + } + /** + * Pretty prints an array of nodes and implodes the printed values. + * + * @param Node[] $nodes Array of Nodes to be printed + * @param string $glue Character to implode with + * + * @return string Imploded pretty printed nodes + */ + protected function pImplode(array $nodes, string $glue = '') : string + { + $pNodes = []; + foreach ($nodes as $node) { + if (null === $node) { + $pNodes[] = ''; + } else { + $pNodes[] = $this->p($node); + } + } + return \implode($glue, $pNodes); + } + /** + * Pretty prints an array of nodes and implodes the printed values with commas. + * + * @param Node[] $nodes Array of Nodes to be printed + * + * @return string Comma separated pretty printed nodes + */ + protected function pCommaSeparated(array $nodes) : string + { + return $this->pImplode($nodes, ', '); + } + /** + * Pretty prints a comma-separated list of nodes in multiline style, including comments. + * + * The result includes a leading newline and one level of indentation (same as pStmts). + * + * @param Node[] $nodes Array of Nodes to be printed + * @param bool $trailingComma Whether to use a trailing comma + * + * @return string Comma separated pretty printed nodes in multiline style + */ + protected function pCommaSeparatedMultiline(array $nodes, bool $trailingComma) : string + { + $this->indent(); + $result = ''; + $lastIdx = \count($nodes) - 1; + foreach ($nodes as $idx => $node) { + if ($node !== null) { + $comments = $node->getComments(); + if ($comments) { + $result .= $this->nl . $this->pComments($comments); + } + $result .= $this->nl . $this->p($node); + } else { + $result .= $this->nl; + } + if ($trailingComma || $idx !== $lastIdx) { + $result .= ','; + } + } + $this->outdent(); + return $result; + } + /** + * Prints reformatted text of the passed comments. + * + * @param Comment[] $comments List of comments + * + * @return string Reformatted text of comments + */ + protected function pComments(array $comments) : string + { + $formattedComments = []; + foreach ($comments as $comment) { + $formattedComments[] = \str_replace("\n", $this->nl, $comment->getReformattedText()); + } + return \implode($this->nl, $formattedComments); + } + /** + * Perform a format-preserving pretty print of an AST. + * + * The format preservation is best effort. For some changes to the AST the formatting will not + * be preserved (at least not locally). + * + * In order to use this method a number of prerequisites must be satisfied: + * * The startTokenPos and endTokenPos attributes in the lexer must be enabled. + * * The CloningVisitor must be run on the AST prior to modification. + * * The original tokens must be provided, using the getTokens() method on the lexer. + * + * @param Node[] $stmts Modified AST with links to original AST + * @param Node[] $origStmts Original AST with token offset information + * @param array $origTokens Tokens of the original code + * + * @return string + */ + public function printFormatPreserving(array $stmts, array $origStmts, array $origTokens) : string + { + $this->initializeNodeListDiffer(); + $this->initializeLabelCharMap(); + $this->initializeFixupMap(); + $this->initializeRemovalMap(); + $this->initializeInsertionMap(); + $this->initializeListInsertionMap(); + $this->initializeEmptyListInsertionMap(); + $this->initializeModifierChangeMap(); + $this->resetState(); + $this->origTokens = new TokenStream($origTokens); + $this->preprocessNodes($stmts); + $pos = 0; + $result = $this->pArray($stmts, $origStmts, $pos, 0, 'File', 'stmts', null); + if (null !== $result) { + $result .= $this->origTokens->getTokenCode($pos, \count($origTokens), 0); + } else { + // Fallback + // TODO Add pStmts($stmts, \false); + } + return \ltrim($this->handleMagicTokens($result)); + } + protected function pFallback(Node $node) + { + return $this->{'p' . $node->getType()}($node); + } + /** + * Pretty prints a node. + * + * This method also handles formatting preservation for nodes. + * + * @param Node $node Node to be pretty printed + * @param bool $parentFormatPreserved Whether parent node has preserved formatting + * + * @return string Pretty printed node + */ + protected function p(Node $node, $parentFormatPreserved = \false) : string + { + // No orig tokens means this is a normal pretty print without preservation of formatting + if (!$this->origTokens) { + return $this->{'p' . $node->getType()}($node); + } + /** @var Node $origNode */ + $origNode = $node->getAttribute('origNode'); + if (null === $origNode) { + return $this->pFallback($node); + } + $class = \get_class($node); + \assert($class === \get_class($origNode)); + $startPos = $origNode->getStartTokenPos(); + $endPos = $origNode->getEndTokenPos(); + \assert($startPos >= 0 && $endPos >= 0); + $fallbackNode = $node; + if ($node instanceof Expr\New_ && $node->class instanceof Stmt\Class_) { + // Normalize node structure of anonymous classes + $node = PrintableNewAnonClassNode::fromNewNode($node); + $origNode = PrintableNewAnonClassNode::fromNewNode($origNode); + } + // InlineHTML node does not contain closing and opening PHP tags. If the parent formatting + // is not preserved, then we need to use the fallback code to make sure the tags are + // printed. + if ($node instanceof Stmt\InlineHTML && !$parentFormatPreserved) { + return $this->pFallback($fallbackNode); + } + $indentAdjustment = $this->indentLevel - $this->origTokens->getIndentationBefore($startPos); + $type = $node->getType(); + $fixupInfo = $this->fixupMap[$class] ?? null; + $result = ''; + $pos = $startPos; + foreach ($node->getSubNodeNames() as $subNodeName) { + $subNode = $node->{$subNodeName}; + $origSubNode = $origNode->{$subNodeName}; + if (!$subNode instanceof Node && $subNode !== null || !$origSubNode instanceof Node && $origSubNode !== null) { + if ($subNode === $origSubNode) { + // Unchanged, can reuse old code + continue; + } + if (\is_array($subNode) && \is_array($origSubNode)) { + // Array subnode changed, we might be able to reconstruct it + $listResult = $this->pArray($subNode, $origSubNode, $pos, $indentAdjustment, $type, $subNodeName, $fixupInfo[$subNodeName] ?? null); + if (null === $listResult) { + return $this->pFallback($fallbackNode); + } + $result .= $listResult; + continue; + } + if (\is_int($subNode) && \is_int($origSubNode)) { + // Check if this is a modifier change + $key = $type . '->' . $subNodeName; + if (!isset($this->modifierChangeMap[$key])) { + return $this->pFallback($fallbackNode); + } + $findToken = $this->modifierChangeMap[$key]; + $result .= $this->pModifiers($subNode); + $pos = $this->origTokens->findRight($pos, $findToken); + continue; + } + // If a non-node, non-array subnode changed, we don't be able to do a partial + // reconstructions, as we don't have enough offset information. Pretty print the + // whole node instead. + return $this->pFallback($fallbackNode); + } + $extraLeft = ''; + $extraRight = ''; + if ($origSubNode !== null) { + $subStartPos = $origSubNode->getStartTokenPos(); + $subEndPos = $origSubNode->getEndTokenPos(); + \assert($subStartPos >= 0 && $subEndPos >= 0); + } else { + if ($subNode === null) { + // Both null, nothing to do + continue; + } + // A node has been inserted, check if we have insertion information for it + $key = $type . '->' . $subNodeName; + if (!isset($this->insertionMap[$key])) { + return $this->pFallback($fallbackNode); + } + list($findToken, $beforeToken, $extraLeft, $extraRight) = $this->insertionMap[$key]; + if (null !== $findToken) { + $subStartPos = $this->origTokens->findRight($pos, $findToken) + (int) (!$beforeToken); + } else { + $subStartPos = $pos; + } + if (null === $extraLeft && null !== $extraRight) { + // If inserting on the right only, skipping whitespace looks better + $subStartPos = $this->origTokens->skipRightWhitespace($subStartPos); + } + $subEndPos = $subStartPos - 1; + } + if (null === $subNode) { + // A node has been removed, check if we have removal information for it + $key = $type . '->' . $subNodeName; + if (!isset($this->removalMap[$key])) { + return $this->pFallback($fallbackNode); + } + // Adjust positions to account for additional tokens that must be skipped + $removalInfo = $this->removalMap[$key]; + if (isset($removalInfo['left'])) { + $subStartPos = $this->origTokens->skipLeft($subStartPos - 1, $removalInfo['left']) + 1; + } + if (isset($removalInfo['right'])) { + $subEndPos = $this->origTokens->skipRight($subEndPos + 1, $removalInfo['right']) - 1; + } + } + $result .= $this->origTokens->getTokenCode($pos, $subStartPos, $indentAdjustment); + if (null !== $subNode) { + $result .= $extraLeft; + $origIndentLevel = $this->indentLevel; + $this->setIndentLevel($this->origTokens->getIndentationBefore($subStartPos) + $indentAdjustment); + // If it's the same node that was previously in this position, it certainly doesn't + // need fixup. It's important to check this here, because our fixup checks are more + // conservative than strictly necessary. + if (isset($fixupInfo[$subNodeName]) && $subNode->getAttribute('origNode') !== $origSubNode) { + $fixup = $fixupInfo[$subNodeName]; + $res = $this->pFixup($fixup, $subNode, $class, $subStartPos, $subEndPos); + } else { + $res = $this->p($subNode, \true); + } + $this->safeAppend($result, $res); + $this->setIndentLevel($origIndentLevel); + $result .= $extraRight; + } + $pos = $subEndPos + 1; + } + $result .= $this->origTokens->getTokenCode($pos, $endPos + 1, $indentAdjustment); + return $result; + } + /** + * Perform a format-preserving pretty print of an array. + * + * @param array $nodes New nodes + * @param array $origNodes Original nodes + * @param int $pos Current token position (updated by reference) + * @param int $indentAdjustment Adjustment for indentation + * @param string $parentNodeType Type of the containing node. + * @param string $subNodeName Name of array subnode. + * @param null|int $fixup Fixup information for array item nodes + * + * @return null|string Result of pretty print or null if cannot preserve formatting + */ + protected function pArray(array $nodes, array $origNodes, int &$pos, int $indentAdjustment, string $parentNodeType, string $subNodeName, $fixup) + { + $diff = $this->nodeListDiffer->diffWithReplacements($origNodes, $nodes); + $mapKey = $parentNodeType . '->' . $subNodeName; + $insertStr = $this->listInsertionMap[$mapKey] ?? null; + $isStmtList = $subNodeName === 'stmts'; + $beforeFirstKeepOrReplace = \true; + $skipRemovedNode = \false; + $delayedAdd = []; + $lastElemIndentLevel = $this->indentLevel; + $insertNewline = \false; + if ($insertStr === "\n") { + $insertStr = ''; + $insertNewline = \true; + } + if ($isStmtList && \count($origNodes) === 1 && \count($nodes) !== 1) { + $startPos = $origNodes[0]->getStartTokenPos(); + $endPos = $origNodes[0]->getEndTokenPos(); + \assert($startPos >= 0 && $endPos >= 0); + if (!$this->origTokens->haveBraces($startPos, $endPos)) { + // This was a single statement without braces, but either additional statements + // have been added, or the single statement has been removed. This requires the + // addition of braces. For now fall back. + // TODO: Try to preserve formatting + return null; + } + } + $result = ''; + foreach ($diff as $i => $diffElem) { + $diffType = $diffElem->type; + /** @var Node|null $arrItem */ + $arrItem = $diffElem->new; + /** @var Node|null $origArrItem */ + $origArrItem = $diffElem->old; + if ($diffType === DiffElem::TYPE_KEEP || $diffType === DiffElem::TYPE_REPLACE) { + $beforeFirstKeepOrReplace = \false; + if ($origArrItem === null || $arrItem === null) { + // We can only handle the case where both are null + if ($origArrItem === $arrItem) { + continue; + } + return null; + } + if (!$arrItem instanceof Node || !$origArrItem instanceof Node) { + // We can only deal with nodes. This can occur for Names, which use string arrays. + return null; + } + $itemStartPos = $origArrItem->getStartTokenPos(); + $itemEndPos = $origArrItem->getEndTokenPos(); + \assert($itemStartPos >= 0 && $itemEndPos >= 0 && $itemStartPos >= $pos); + $origIndentLevel = $this->indentLevel; + $lastElemIndentLevel = $this->origTokens->getIndentationBefore($itemStartPos) + $indentAdjustment; + $this->setIndentLevel($lastElemIndentLevel); + $comments = $arrItem->getComments(); + $origComments = $origArrItem->getComments(); + $commentStartPos = $origComments ? $origComments[0]->getStartTokenPos() : $itemStartPos; + \assert($commentStartPos >= 0); + if ($commentStartPos < $pos) { + // Comments may be assigned to multiple nodes if they start at the same position. + // Make sure we don't try to print them multiple times. + $commentStartPos = $itemStartPos; + } + if ($skipRemovedNode) { + if ($isStmtList && ($this->origTokens->haveBracesInRange($pos, $itemStartPos) || $this->origTokens->haveTagInRange($pos, $itemStartPos))) { + // We'd remove the brace of a code block. + // TODO: Preserve formatting. + $this->setIndentLevel($origIndentLevel); + return null; + } + } else { + $result .= $this->origTokens->getTokenCode($pos, $commentStartPos, $indentAdjustment); + } + if (!empty($delayedAdd)) { + /** @var Node $delayedAddNode */ + foreach ($delayedAdd as $delayedAddNode) { + if ($insertNewline) { + $delayedAddComments = $delayedAddNode->getComments(); + if ($delayedAddComments) { + $result .= $this->pComments($delayedAddComments) . $this->nl; + } + } + $this->safeAppend($result, $this->p($delayedAddNode, \true)); + if ($insertNewline) { + $result .= $insertStr . $this->nl; + } else { + $result .= $insertStr; + } + } + $delayedAdd = []; + } + if ($comments !== $origComments) { + if ($comments) { + $result .= $this->pComments($comments) . $this->nl; + } + } else { + $result .= $this->origTokens->getTokenCode($commentStartPos, $itemStartPos, $indentAdjustment); + } + // If we had to remove anything, we have done so now. + $skipRemovedNode = \false; + } elseif ($diffType === DiffElem::TYPE_ADD) { + if (null === $insertStr) { + // We don't have insertion information for this list type + return null; + } + // We go multiline if the original code was multiline, + // or if it's an array item with a comment above it. + if ($insertStr === ', ' && ($this->isMultiline($origNodes) || $arrItem->getComments())) { + $insertStr = ','; + $insertNewline = \true; + } + if ($beforeFirstKeepOrReplace) { + // Will be inserted at the next "replace" or "keep" element + $delayedAdd[] = $arrItem; + continue; + } + $itemStartPos = $pos; + $itemEndPos = $pos - 1; + $origIndentLevel = $this->indentLevel; + $this->setIndentLevel($lastElemIndentLevel); + if ($insertNewline) { + $result .= $insertStr . $this->nl; + $comments = $arrItem->getComments(); + if ($comments) { + $result .= $this->pComments($comments) . $this->nl; + } + } else { + $result .= $insertStr; + } + } elseif ($diffType === DiffElem::TYPE_REMOVE) { + if (!$origArrItem instanceof Node) { + // We only support removal for nodes + return null; + } + $itemStartPos = $origArrItem->getStartTokenPos(); + $itemEndPos = $origArrItem->getEndTokenPos(); + \assert($itemStartPos >= 0 && $itemEndPos >= 0); + // Consider comments part of the node. + $origComments = $origArrItem->getComments(); + if ($origComments) { + $itemStartPos = $origComments[0]->getStartTokenPos(); + } + if ($i === 0) { + // If we're removing from the start, keep the tokens before the node and drop those after it, + // instead of the other way around. + $result .= $this->origTokens->getTokenCode($pos, $itemStartPos, $indentAdjustment); + $skipRemovedNode = \true; + } else { + if ($isStmtList && ($this->origTokens->haveBracesInRange($pos, $itemStartPos) || $this->origTokens->haveTagInRange($pos, $itemStartPos))) { + // We'd remove the brace of a code block. + // TODO: Preserve formatting. + return null; + } + } + $pos = $itemEndPos + 1; + continue; + } else { + throw new \Exception("Shouldn't happen"); + } + if (null !== $fixup && $arrItem->getAttribute('origNode') !== $origArrItem) { + $res = $this->pFixup($fixup, $arrItem, null, $itemStartPos, $itemEndPos); + } else { + $res = $this->p($arrItem, \true); + } + $this->safeAppend($result, $res); + $this->setIndentLevel($origIndentLevel); + $pos = $itemEndPos + 1; + } + if ($skipRemovedNode) { + // TODO: Support removing single node. + return null; + } + if (!empty($delayedAdd)) { + if (!isset($this->emptyListInsertionMap[$mapKey])) { + return null; + } + list($findToken, $extraLeft, $extraRight) = $this->emptyListInsertionMap[$mapKey]; + if (null !== $findToken) { + $insertPos = $this->origTokens->findRight($pos, $findToken) + 1; + $result .= $this->origTokens->getTokenCode($pos, $insertPos, $indentAdjustment); + $pos = $insertPos; + } + $first = \true; + $result .= $extraLeft; + foreach ($delayedAdd as $delayedAddNode) { + if (!$first) { + $result .= $insertStr; + if ($insertNewline) { + $result .= $this->nl; + } + } + $result .= $this->p($delayedAddNode, \true); + $first = \false; + } + $result .= $extraRight === "\n" ? $this->nl : $extraRight; + } + return $result; + } + /** + * Print node with fixups. + * + * Fixups here refer to the addition of extra parentheses, braces or other characters, that + * are required to preserve program semantics in a certain context (e.g. to maintain precedence + * or because only certain expressions are allowed in certain places). + * + * @param int $fixup Fixup type + * @param Node $subNode Subnode to print + * @param string|null $parentClass Class of parent node + * @param int $subStartPos Original start pos of subnode + * @param int $subEndPos Original end pos of subnode + * + * @return string Result of fixed-up print of subnode + */ + protected function pFixup(int $fixup, Node $subNode, $parentClass, int $subStartPos, int $subEndPos) : string + { + switch ($fixup) { + case self::FIXUP_PREC_LEFT: + case self::FIXUP_PREC_RIGHT: + if (!$this->origTokens->haveParens($subStartPos, $subEndPos)) { + list($precedence, $associativity) = $this->precedenceMap[$parentClass]; + return $this->pPrec($subNode, $precedence, $associativity, $fixup === self::FIXUP_PREC_LEFT ? -1 : 1); + } + break; + case self::FIXUP_CALL_LHS: + if ($this->callLhsRequiresParens($subNode) && !$this->origTokens->haveParens($subStartPos, $subEndPos)) { + return '(' . $this->p($subNode) . ')'; + } + break; + case self::FIXUP_DEREF_LHS: + if ($this->dereferenceLhsRequiresParens($subNode) && !$this->origTokens->haveParens($subStartPos, $subEndPos)) { + return '(' . $this->p($subNode) . ')'; + } + break; + case self::FIXUP_STATIC_DEREF_LHS: + if ($this->staticDereferenceLhsRequiresParens($subNode) && !$this->origTokens->haveParens($subStartPos, $subEndPos)) { + return '(' . $this->p($subNode) . ')'; + } + break; + case self::FIXUP_NEW: + if ($this->newOperandRequiresParens($subNode) && !$this->origTokens->haveParens($subStartPos, $subEndPos)) { + return '(' . $this->p($subNode) . ')'; + } + break; + case self::FIXUP_BRACED_NAME: + case self::FIXUP_VAR_BRACED_NAME: + if ($subNode instanceof Expr && !$this->origTokens->haveBraces($subStartPos, $subEndPos)) { + return ($fixup === self::FIXUP_VAR_BRACED_NAME ? '$' : '') . '{' . $this->p($subNode) . '}'; + } + break; + case self::FIXUP_ENCAPSED: + if (!$subNode instanceof Scalar\EncapsedStringPart && !$this->origTokens->haveBraces($subStartPos, $subEndPos)) { + return '{' . $this->p($subNode) . '}'; + } + break; + default: + throw new \Exception('Cannot happen'); + } + // Nothing special to do + return $this->p($subNode); + } + /** + * Appends to a string, ensuring whitespace between label characters. + * + * Example: "echo" and "$x" result in "echo$x", but "echo" and "x" result in "echo x". + * Without safeAppend the result would be "echox", which does not preserve semantics. + * + * @param string $str + * @param string $append + */ + protected function safeAppend(string &$str, string $append) + { + if ($str === "") { + $str = $append; + return; + } + if ($append === "") { + return; + } + if (!$this->labelCharMap[$append[0]] || !$this->labelCharMap[$str[\strlen($str) - 1]]) { + $str .= $append; + } else { + $str .= " " . $append; + } + } + /** + * Determines whether the LHS of a call must be wrapped in parenthesis. + * + * @param Node $node LHS of a call + * + * @return bool Whether parentheses are required + */ + protected function callLhsRequiresParens(Node $node) : bool + { + return !($node instanceof Node\Name || $node instanceof Expr\Variable || $node instanceof Expr\ArrayDimFetch || $node instanceof Expr\FuncCall || $node instanceof Expr\MethodCall || $node instanceof Expr\NullsafeMethodCall || $node instanceof Expr\StaticCall || $node instanceof Expr\Array_); + } + /** + * Determines whether the LHS of an array/object operation must be wrapped in parentheses. + * + * @param Node $node LHS of dereferencing operation + * + * @return bool Whether parentheses are required + */ + protected function dereferenceLhsRequiresParens(Node $node) : bool + { + // A constant can occur on the LHS of an array/object deref, but not a static deref. + return $this->staticDereferenceLhsRequiresParens($node) && !$node instanceof Expr\ConstFetch; + } + /** + * Determines whether the LHS of a static operation must be wrapped in parentheses. + * + * @param Node $node LHS of dereferencing operation + * + * @return bool Whether parentheses are required + */ + protected function staticDereferenceLhsRequiresParens(Node $node) : bool + { + return !($node instanceof Expr\Variable || $node instanceof Node\Name || $node instanceof Expr\ArrayDimFetch || $node instanceof Expr\PropertyFetch || $node instanceof Expr\NullsafePropertyFetch || $node instanceof Expr\StaticPropertyFetch || $node instanceof Expr\FuncCall || $node instanceof Expr\MethodCall || $node instanceof Expr\NullsafeMethodCall || $node instanceof Expr\StaticCall || $node instanceof Expr\Array_ || $node instanceof Scalar\String_ || $node instanceof Expr\ClassConstFetch); + } + /** + * Determines whether an expression used in "new" or "instanceof" requires parentheses. + * + * @param Node $node New or instanceof operand + * + * @return bool Whether parentheses are required + */ + protected function newOperandRequiresParens(Node $node) : bool + { + if ($node instanceof Node\Name || $node instanceof Expr\Variable) { + return \false; + } + if ($node instanceof Expr\ArrayDimFetch || $node instanceof Expr\PropertyFetch || $node instanceof Expr\NullsafePropertyFetch) { + return $this->newOperandRequiresParens($node->var); + } + if ($node instanceof Expr\StaticPropertyFetch) { + return $this->newOperandRequiresParens($node->class); + } + return \true; + } + /** + * Print modifiers, including trailing whitespace. + * + * @param int $modifiers Modifier mask to print + * + * @return string Printed modifiers + */ + protected function pModifiers(int $modifiers) + { + return ($modifiers & Stmt\Class_::MODIFIER_PUBLIC ? 'public ' : '') . ($modifiers & Stmt\Class_::MODIFIER_PROTECTED ? 'protected ' : '') . ($modifiers & Stmt\Class_::MODIFIER_PRIVATE ? 'private ' : '') . ($modifiers & Stmt\Class_::MODIFIER_STATIC ? 'static ' : '') . ($modifiers & Stmt\Class_::MODIFIER_ABSTRACT ? 'abstract ' : '') . ($modifiers & Stmt\Class_::MODIFIER_FINAL ? 'final ' : '') . ($modifiers & Stmt\Class_::MODIFIER_READONLY ? 'readonly ' : ''); + } + /** + * Determine whether a list of nodes uses multiline formatting. + * + * @param (Node|null)[] $nodes Node list + * + * @return bool Whether multiline formatting is used + */ + protected function isMultiline(array $nodes) : bool + { + if (\count($nodes) < 2) { + return \false; + } + $pos = -1; + foreach ($nodes as $node) { + if (null === $node) { + continue; + } + $endPos = $node->getEndTokenPos() + 1; + if ($pos >= 0) { + $text = $this->origTokens->getTokenCode($pos, $endPos, 0); + if (\false === \strpos($text, "\n")) { + // We require that a newline is present between *every* item. If the formatting + // is inconsistent, with only some items having newlines, we don't consider it + // as multiline + return \false; + } + } + $pos = $endPos; + } + return \true; + } + /** + * Lazily initializes label char map. + * + * The label char map determines whether a certain character may occur in a label. + */ + protected function initializeLabelCharMap() + { + if ($this->labelCharMap) { + return; + } + $this->labelCharMap = []; + for ($i = 0; $i < 256; $i++) { + // Since PHP 7.1 The lower range is 0x80. However, we also want to support code for + // older versions. + $chr = \chr($i); + $this->labelCharMap[$chr] = $i >= 0x7f || \ctype_alnum($chr); + } + } + /** + * Lazily initializes node list differ. + * + * The node list differ is used to determine differences between two array subnodes. + */ + protected function initializeNodeListDiffer() + { + if ($this->nodeListDiffer) { + return; + } + $this->nodeListDiffer = new Internal\Differ(function ($a, $b) { + if ($a instanceof Node && $b instanceof Node) { + return $a === $b->getAttribute('origNode'); + } + // Can happen for array destructuring + return $a === null && $b === null; + }); + } + /** + * Lazily initializes fixup map. + * + * The fixup map is used to determine whether a certain subnode of a certain node may require + * some kind of "fixup" operation, e.g. the addition of parenthesis or braces. + */ + protected function initializeFixupMap() + { + if ($this->fixupMap) { + return; + } + $this->fixupMap = [Expr\PreInc::class => ['var' => self::FIXUP_PREC_RIGHT], Expr\PreDec::class => ['var' => self::FIXUP_PREC_RIGHT], Expr\PostInc::class => ['var' => self::FIXUP_PREC_LEFT], Expr\PostDec::class => ['var' => self::FIXUP_PREC_LEFT], Expr\Instanceof_::class => ['expr' => self::FIXUP_PREC_LEFT, 'class' => self::FIXUP_NEW], Expr\Ternary::class => ['cond' => self::FIXUP_PREC_LEFT, 'else' => self::FIXUP_PREC_RIGHT], Expr\FuncCall::class => ['name' => self::FIXUP_CALL_LHS], Expr\StaticCall::class => ['class' => self::FIXUP_STATIC_DEREF_LHS], Expr\ArrayDimFetch::class => ['var' => self::FIXUP_DEREF_LHS], Expr\ClassConstFetch::class => ['class' => self::FIXUP_STATIC_DEREF_LHS, 'name' => self::FIXUP_BRACED_NAME], Expr\New_::class => ['class' => self::FIXUP_NEW], Expr\MethodCall::class => ['var' => self::FIXUP_DEREF_LHS, 'name' => self::FIXUP_BRACED_NAME], Expr\NullsafeMethodCall::class => ['var' => self::FIXUP_DEREF_LHS, 'name' => self::FIXUP_BRACED_NAME], Expr\StaticPropertyFetch::class => ['class' => self::FIXUP_STATIC_DEREF_LHS, 'name' => self::FIXUP_VAR_BRACED_NAME], Expr\PropertyFetch::class => ['var' => self::FIXUP_DEREF_LHS, 'name' => self::FIXUP_BRACED_NAME], Expr\NullsafePropertyFetch::class => ['var' => self::FIXUP_DEREF_LHS, 'name' => self::FIXUP_BRACED_NAME], Scalar\Encapsed::class => ['parts' => self::FIXUP_ENCAPSED]]; + $binaryOps = [BinaryOp\Pow::class, BinaryOp\Mul::class, BinaryOp\Div::class, BinaryOp\Mod::class, BinaryOp\Plus::class, BinaryOp\Minus::class, BinaryOp\Concat::class, BinaryOp\ShiftLeft::class, BinaryOp\ShiftRight::class, BinaryOp\Smaller::class, BinaryOp\SmallerOrEqual::class, BinaryOp\Greater::class, BinaryOp\GreaterOrEqual::class, BinaryOp\Equal::class, BinaryOp\NotEqual::class, BinaryOp\Identical::class, BinaryOp\NotIdentical::class, BinaryOp\Spaceship::class, BinaryOp\BitwiseAnd::class, BinaryOp\BitwiseXor::class, BinaryOp\BitwiseOr::class, BinaryOp\BooleanAnd::class, BinaryOp\BooleanOr::class, BinaryOp\Coalesce::class, BinaryOp\LogicalAnd::class, BinaryOp\LogicalXor::class, BinaryOp\LogicalOr::class]; + foreach ($binaryOps as $binaryOp) { + $this->fixupMap[$binaryOp] = ['left' => self::FIXUP_PREC_LEFT, 'right' => self::FIXUP_PREC_RIGHT]; + } + $assignOps = [Expr\Assign::class, Expr\AssignRef::class, AssignOp\Plus::class, AssignOp\Minus::class, AssignOp\Mul::class, AssignOp\Div::class, AssignOp\Concat::class, AssignOp\Mod::class, AssignOp\BitwiseAnd::class, AssignOp\BitwiseOr::class, AssignOp\BitwiseXor::class, AssignOp\ShiftLeft::class, AssignOp\ShiftRight::class, AssignOp\Pow::class, AssignOp\Coalesce::class]; + foreach ($assignOps as $assignOp) { + $this->fixupMap[$assignOp] = ['var' => self::FIXUP_PREC_LEFT, 'expr' => self::FIXUP_PREC_RIGHT]; + } + $prefixOps = [Expr\BitwiseNot::class, Expr\BooleanNot::class, Expr\UnaryPlus::class, Expr\UnaryMinus::class, Cast\Int_::class, Cast\Double::class, Cast\String_::class, Cast\Array_::class, Cast\Object_::class, Cast\Bool_::class, Cast\Unset_::class, Expr\ErrorSuppress::class, Expr\YieldFrom::class, Expr\Print_::class, Expr\Include_::class]; + foreach ($prefixOps as $prefixOp) { + $this->fixupMap[$prefixOp] = ['expr' => self::FIXUP_PREC_RIGHT]; + } + } + /** + * Lazily initializes the removal map. + * + * The removal map is used to determine which additional tokens should be removed when a + * certain node is replaced by null. + */ + protected function initializeRemovalMap() + { + if ($this->removalMap) { + return; + } + $stripBoth = ['left' => \T_WHITESPACE, 'right' => \T_WHITESPACE]; + $stripLeft = ['left' => \T_WHITESPACE]; + $stripRight = ['right' => \T_WHITESPACE]; + $stripDoubleArrow = ['right' => \T_DOUBLE_ARROW]; + $stripColon = ['left' => ':']; + $stripEquals = ['left' => '=']; + $this->removalMap = ['Expr_ArrayDimFetch->dim' => $stripBoth, 'Expr_ArrayItem->key' => $stripDoubleArrow, 'Expr_ArrowFunction->returnType' => $stripColon, 'Expr_Closure->returnType' => $stripColon, 'Expr_Exit->expr' => $stripBoth, 'Expr_Ternary->if' => $stripBoth, 'Expr_Yield->key' => $stripDoubleArrow, 'Expr_Yield->value' => $stripBoth, 'Param->type' => $stripRight, 'Param->default' => $stripEquals, 'Stmt_Break->num' => $stripBoth, 'Stmt_Catch->var' => $stripLeft, 'Stmt_ClassConst->type' => $stripRight, 'Stmt_ClassMethod->returnType' => $stripColon, 'Stmt_Class->extends' => ['left' => \T_EXTENDS], 'Stmt_Enum->scalarType' => $stripColon, 'Stmt_EnumCase->expr' => $stripEquals, 'Expr_PrintableNewAnonClass->extends' => ['left' => \T_EXTENDS], 'Stmt_Continue->num' => $stripBoth, 'Stmt_Foreach->keyVar' => $stripDoubleArrow, 'Stmt_Function->returnType' => $stripColon, 'Stmt_If->else' => $stripLeft, 'Stmt_Namespace->name' => $stripLeft, 'Stmt_Property->type' => $stripRight, 'Stmt_PropertyProperty->default' => $stripEquals, 'Stmt_Return->expr' => $stripBoth, 'Stmt_StaticVar->default' => $stripEquals, 'Stmt_TraitUseAdaptation_Alias->newName' => $stripLeft, 'Stmt_TryCatch->finally' => $stripLeft]; + } + protected function initializeInsertionMap() + { + if ($this->insertionMap) { + return; + } + // TODO: "yield" where both key and value are inserted doesn't work + // [$find, $beforeToken, $extraLeft, $extraRight] + $this->insertionMap = [ + 'Expr_ArrayDimFetch->dim' => ['[', \false, null, null], + 'Expr_ArrayItem->key' => [null, \false, null, ' => '], + 'Expr_ArrowFunction->returnType' => [')', \false, ' : ', null], + 'Expr_Closure->returnType' => [')', \false, ' : ', null], + 'Expr_Ternary->if' => ['?', \false, ' ', ' '], + 'Expr_Yield->key' => [\T_YIELD, \false, null, ' => '], + 'Expr_Yield->value' => [\T_YIELD, \false, ' ', null], + 'Param->type' => [null, \false, null, ' '], + 'Param->default' => [null, \false, ' = ', null], + 'Stmt_Break->num' => [\T_BREAK, \false, ' ', null], + 'Stmt_Catch->var' => [null, \false, ' ', null], + 'Stmt_ClassMethod->returnType' => [')', \false, ' : ', null], + 'Stmt_ClassConst->type' => [\T_CONST, \false, ' ', null], + 'Stmt_Class->extends' => [null, \false, ' extends ', null], + 'Stmt_Enum->scalarType' => [null, \false, ' : ', null], + 'Stmt_EnumCase->expr' => [null, \false, ' = ', null], + 'Expr_PrintableNewAnonClass->extends' => [null, ' extends ', null], + 'Stmt_Continue->num' => [\T_CONTINUE, \false, ' ', null], + 'Stmt_Foreach->keyVar' => [\T_AS, \false, null, ' => '], + 'Stmt_Function->returnType' => [')', \false, ' : ', null], + 'Stmt_If->else' => [null, \false, ' ', null], + 'Stmt_Namespace->name' => [\T_NAMESPACE, \false, ' ', null], + 'Stmt_Property->type' => [\T_VARIABLE, \true, null, ' '], + 'Stmt_PropertyProperty->default' => [null, \false, ' = ', null], + 'Stmt_Return->expr' => [\T_RETURN, \false, ' ', null], + 'Stmt_StaticVar->default' => [null, \false, ' = ', null], + //'Stmt_TraitUseAdaptation_Alias->newName' => [T_AS, false, ' ', null], // TODO + 'Stmt_TryCatch->finally' => [null, \false, ' ', null], + ]; + } + protected function initializeListInsertionMap() + { + if ($this->listInsertionMap) { + return; + } + $this->listInsertionMap = [ + // special + //'Expr_ShellExec->parts' => '', // TODO These need to be treated more carefully + //'Scalar_Encapsed->parts' => '', + 'Stmt_Catch->types' => '|', + 'UnionType->types' => '|', + 'IntersectionType->types' => '&', + 'Stmt_If->elseifs' => ' ', + 'Stmt_TryCatch->catches' => ' ', + // comma-separated lists + 'Expr_Array->items' => ', ', + 'Expr_ArrowFunction->params' => ', ', + 'Expr_Closure->params' => ', ', + 'Expr_Closure->uses' => ', ', + 'Expr_FuncCall->args' => ', ', + 'Expr_Isset->vars' => ', ', + 'Expr_List->items' => ', ', + 'Expr_MethodCall->args' => ', ', + 'Expr_NullsafeMethodCall->args' => ', ', + 'Expr_New->args' => ', ', + 'Expr_PrintableNewAnonClass->args' => ', ', + 'Expr_StaticCall->args' => ', ', + 'Stmt_ClassConst->consts' => ', ', + 'Stmt_ClassMethod->params' => ', ', + 'Stmt_Class->implements' => ', ', + 'Stmt_Enum->implements' => ', ', + 'Expr_PrintableNewAnonClass->implements' => ', ', + 'Stmt_Const->consts' => ', ', + 'Stmt_Declare->declares' => ', ', + 'Stmt_Echo->exprs' => ', ', + 'Stmt_For->init' => ', ', + 'Stmt_For->cond' => ', ', + 'Stmt_For->loop' => ', ', + 'Stmt_Function->params' => ', ', + 'Stmt_Global->vars' => ', ', + 'Stmt_GroupUse->uses' => ', ', + 'Stmt_Interface->extends' => ', ', + 'Stmt_Match->arms' => ', ', + 'Stmt_Property->props' => ', ', + 'Stmt_StaticVar->vars' => ', ', + 'Stmt_TraitUse->traits' => ', ', + 'Stmt_TraitUseAdaptation_Precedence->insteadof' => ', ', + 'Stmt_Unset->vars' => ', ', + 'Stmt_Use->uses' => ', ', + 'MatchArm->conds' => ', ', + 'AttributeGroup->attrs' => ', ', + // statement lists + 'Expr_Closure->stmts' => "\n", + 'Stmt_Case->stmts' => "\n", + 'Stmt_Catch->stmts' => "\n", + 'Stmt_Class->stmts' => "\n", + 'Stmt_Enum->stmts' => "\n", + 'Expr_PrintableNewAnonClass->stmts' => "\n", + 'Stmt_Interface->stmts' => "\n", + 'Stmt_Trait->stmts' => "\n", + 'Stmt_ClassMethod->stmts' => "\n", + 'Stmt_Declare->stmts' => "\n", + 'Stmt_Do->stmts' => "\n", + 'Stmt_ElseIf->stmts' => "\n", + 'Stmt_Else->stmts' => "\n", + 'Stmt_Finally->stmts' => "\n", + 'Stmt_Foreach->stmts' => "\n", + 'Stmt_For->stmts' => "\n", + 'Stmt_Function->stmts' => "\n", + 'Stmt_If->stmts' => "\n", + 'Stmt_Namespace->stmts' => "\n", + 'Stmt_Class->attrGroups' => "\n", + 'Stmt_Enum->attrGroups' => "\n", + 'Stmt_EnumCase->attrGroups' => "\n", + 'Stmt_Interface->attrGroups' => "\n", + 'Stmt_Trait->attrGroups' => "\n", + 'Stmt_Function->attrGroups' => "\n", + 'Stmt_ClassMethod->attrGroups' => "\n", + 'Stmt_ClassConst->attrGroups' => "\n", + 'Stmt_Property->attrGroups' => "\n", + 'Expr_PrintableNewAnonClass->attrGroups' => ' ', + 'Expr_Closure->attrGroups' => ' ', + 'Expr_ArrowFunction->attrGroups' => ' ', + 'Param->attrGroups' => ' ', + 'Stmt_Switch->cases' => "\n", + 'Stmt_TraitUse->adaptations' => "\n", + 'Stmt_TryCatch->stmts' => "\n", + 'Stmt_While->stmts' => "\n", + // dummy for top-level context + 'File->stmts' => "\n", + ]; + } + protected function initializeEmptyListInsertionMap() + { + if ($this->emptyListInsertionMap) { + return; + } + // TODO Insertion into empty statement lists. + // [$find, $extraLeft, $extraRight] + $this->emptyListInsertionMap = ['Expr_ArrowFunction->params' => ['(', '', ''], 'Expr_Closure->uses' => [')', ' use(', ')'], 'Expr_Closure->params' => ['(', '', ''], 'Expr_FuncCall->args' => ['(', '', ''], 'Expr_MethodCall->args' => ['(', '', ''], 'Expr_NullsafeMethodCall->args' => ['(', '', ''], 'Expr_New->args' => ['(', '', ''], 'Expr_PrintableNewAnonClass->args' => ['(', '', ''], 'Expr_PrintableNewAnonClass->implements' => [null, ' implements ', ''], 'Expr_StaticCall->args' => ['(', '', ''], 'Stmt_Class->implements' => [null, ' implements ', ''], 'Stmt_Enum->implements' => [null, ' implements ', ''], 'Stmt_ClassMethod->params' => ['(', '', ''], 'Stmt_Interface->extends' => [null, ' extends ', ''], 'Stmt_Function->params' => ['(', '', ''], 'Stmt_Interface->attrGroups' => [null, '', "\n"], 'Stmt_Class->attrGroups' => [null, '', "\n"], 'Stmt_ClassConst->attrGroups' => [null, '', "\n"], 'Stmt_ClassMethod->attrGroups' => [null, '', "\n"], 'Stmt_Function->attrGroups' => [null, '', "\n"], 'Stmt_Property->attrGroups' => [null, '', "\n"], 'Stmt_Trait->attrGroups' => [null, '', "\n"], 'Expr_ArrowFunction->attrGroups' => [null, '', ' '], 'Expr_Closure->attrGroups' => [null, '', ' '], 'Expr_PrintableNewAnonClass->attrGroups' => [\T_NEW, ' ', '']]; + } + protected function initializeModifierChangeMap() + { + if ($this->modifierChangeMap) { + return; + } + $this->modifierChangeMap = ['Stmt_ClassConst->flags' => \T_CONST, 'Stmt_ClassMethod->flags' => \T_FUNCTION, 'Stmt_Class->flags' => \T_CLASS, 'Stmt_Property->flags' => \T_VARIABLE, 'Expr_PrintableNewAnonClass->flags' => \T_CLASS, 'Param->flags' => \T_VARIABLE]; + // List of integer subnodes that are not modifiers: + // Expr_Include->type + // Stmt_GroupUse->type + // Stmt_Use->type + // Stmt_UseUse->type + } +} diff --git a/vendor/psr/container/LICENSE b/vendor/psr/container/LICENSE new file mode 100644 index 0000000000..2877a4894e --- /dev/null +++ b/vendor/psr/container/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013-2016 container-interop +Copyright (c) 2016 PHP Framework Interoperability Group + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/psr/container/README.md b/vendor/psr/container/README.md new file mode 100644 index 0000000000..1b9d9e5708 --- /dev/null +++ b/vendor/psr/container/README.md @@ -0,0 +1,13 @@ +Container interface +============== + +This repository holds all interfaces related to [PSR-11 (Container Interface)][psr-url]. + +Note that this is not a Container implementation of its own. It is merely abstractions that describe the components of a Dependency Injection Container. + +The installable [package][package-url] and [implementations][implementation-url] are listed on Packagist. + +[psr-url]: https://www.php-fig.org/psr/psr-11/ +[package-url]: https://packagist.org/packages/psr/container +[implementation-url]: https://packagist.org/providers/psr/container-implementation + diff --git a/vendor/psr/container/composer.json b/vendor/psr/container/composer.json new file mode 100644 index 0000000000..37bc45613f --- /dev/null +++ b/vendor/psr/container/composer.json @@ -0,0 +1,33 @@ +{ + "name": "psr\/container", + "type": "library", + "description": "Common Container Interface (PHP FIG PSR-11)", + "keywords": [ + "psr", + "psr-11", + "container", + "container-interop", + "container-interface" + ], + "homepage": "https:\/\/github.com\/php-fig\/container", + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https:\/\/www.php-fig.org\/" + } + ], + "require": { + "php": ">=7.4.0" + }, + "autoload": { + "psr-4": { + "SwissKnife202405\\Psr\\Container\\": "src\/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + } +} \ No newline at end of file diff --git a/vendor/psr/container/src/ContainerExceptionInterface.php b/vendor/psr/container/src/ContainerExceptionInterface.php new file mode 100644 index 0000000000..cb1c7ec7c4 --- /dev/null +++ b/vendor/psr/container/src/ContainerExceptionInterface.php @@ -0,0 +1,11 @@ + Permission is hereby granted, free of charge, to any person obtaining a copy +> of this software and associated documentation files (the "Software"), to deal +> in the Software without restriction, including without limitation the rights +> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +> copies of the Software, and to permit persons to whom the Software is +> furnished to do so, subject to the following conditions: +> +> The above copyright notice and this permission notice shall be included in +> all copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +> THE SOFTWARE. diff --git a/vendor/psr/simple-cache/README.md b/vendor/psr/simple-cache/README.md new file mode 100644 index 0000000000..43641d175c --- /dev/null +++ b/vendor/psr/simple-cache/README.md @@ -0,0 +1,8 @@ +PHP FIG Simple Cache PSR +======================== + +This repository holds all interfaces related to PSR-16. + +Note that this is not a cache implementation of its own. It is merely an interface that describes a cache implementation. See [the specification](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-16-simple-cache.md) for more details. + +You can find implementations of the specification by looking for packages providing the [psr/simple-cache-implementation](https://packagist.org/providers/psr/simple-cache-implementation) virtual package. diff --git a/vendor/psr/simple-cache/composer.json b/vendor/psr/simple-cache/composer.json new file mode 100644 index 0000000000..dea9c5b1a9 --- /dev/null +++ b/vendor/psr/simple-cache/composer.json @@ -0,0 +1,31 @@ +{ + "name": "psr\/simple-cache", + "description": "Common interfaces for simple caching", + "keywords": [ + "psr", + "psr-16", + "cache", + "simple-cache", + "caching" + ], + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https:\/\/www.php-fig.org\/" + } + ], + "require": { + "php": ">=8.0.0" + }, + "autoload": { + "psr-4": { + "SwissKnife202405\\Psr\\SimpleCache\\": "src\/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + } +} \ No newline at end of file diff --git a/vendor/psr/simple-cache/src/CacheException.php b/vendor/psr/simple-cache/src/CacheException.php new file mode 100644 index 0000000000..8562c6d7a5 --- /dev/null +++ b/vendor/psr/simple-cache/src/CacheException.php @@ -0,0 +1,10 @@ + $keys A list of keys that can be obtained in a single operation. + * @param mixed $default Default value to return for keys that do not exist. + * + * @return iterable A list of key => value pairs. Cache keys that do not exist or are stale will have $default as value. + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if $keys is neither an array nor a Traversable, + * or if any of the $keys are not a legal value. + */ + public function getMultiple(iterable $keys, $default = null) : iterable; + /** + * Persists a set of key => value pairs in the cache, with an optional TTL. + * + * @param iterable $values A list of key => value pairs for a multiple-set operation. + * @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and + * the driver supports TTL then the library may set a default value + * for it or let the driver take care of that. + * + * @return bool True on success and false on failure. + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if $values is neither an array nor a Traversable, + * or if any of the $values are not a legal value. + */ + public function setMultiple(iterable $values, $ttl = null) : bool; + /** + * Deletes multiple cache items in a single operation. + * + * @param iterable $keys A list of string-based keys to be deleted. + * + * @return bool True if the items were successfully removed. False if there was an error. + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if $keys is neither an array nor a Traversable, + * or if any of the $keys are not a legal value. + */ + public function deleteMultiple(iterable $keys) : bool; + /** + * Determines whether an item is present in the cache. + * + * NOTE: It is recommended that has() is only to be used for cache warming type purposes + * and not to be used within your live applications operations for get/set, as this method + * is subject to a race condition where your has() will return true and immediately after, + * another script can remove it making the state of your app out of date. + * + * @param string $key The cache item key. + * + * @return bool + * + * @throws \Psr\SimpleCache\InvalidArgumentException + * MUST be thrown if the $key string is not a legal value. + */ + public function has(string $key) : bool; +} diff --git a/vendor/psr/simple-cache/src/InvalidArgumentException.php b/vendor/psr/simple-cache/src/InvalidArgumentException.php new file mode 100644 index 0000000000..4a1dec1fad --- /dev/null +++ b/vendor/psr/simple-cache/src/InvalidArgumentException.php @@ -0,0 +1,13 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console; + +use SwissKnife202405\Symfony\Component\Console\Command\Command; +use SwissKnife202405\Symfony\Component\Console\Command\CompleteCommand; +use SwissKnife202405\Symfony\Component\Console\Command\DumpCompletionCommand; +use SwissKnife202405\Symfony\Component\Console\Command\HelpCommand; +use SwissKnife202405\Symfony\Component\Console\Command\LazyCommand; +use SwissKnife202405\Symfony\Component\Console\Command\ListCommand; +use SwissKnife202405\Symfony\Component\Console\Command\SignalableCommandInterface; +use SwissKnife202405\Symfony\Component\Console\CommandLoader\CommandLoaderInterface; +use SwissKnife202405\Symfony\Component\Console\Completion\CompletionInput; +use SwissKnife202405\Symfony\Component\Console\Completion\CompletionSuggestions; +use SwissKnife202405\Symfony\Component\Console\Completion\Suggestion; +use SwissKnife202405\Symfony\Component\Console\Event\ConsoleCommandEvent; +use SwissKnife202405\Symfony\Component\Console\Event\ConsoleErrorEvent; +use SwissKnife202405\Symfony\Component\Console\Event\ConsoleSignalEvent; +use SwissKnife202405\Symfony\Component\Console\Event\ConsoleTerminateEvent; +use SwissKnife202405\Symfony\Component\Console\Exception\CommandNotFoundException; +use SwissKnife202405\Symfony\Component\Console\Exception\ExceptionInterface; +use SwissKnife202405\Symfony\Component\Console\Exception\LogicException; +use SwissKnife202405\Symfony\Component\Console\Exception\NamespaceNotFoundException; +use SwissKnife202405\Symfony\Component\Console\Exception\RuntimeException; +use SwissKnife202405\Symfony\Component\Console\Formatter\OutputFormatter; +use SwissKnife202405\Symfony\Component\Console\Helper\DebugFormatterHelper; +use SwissKnife202405\Symfony\Component\Console\Helper\DescriptorHelper; +use SwissKnife202405\Symfony\Component\Console\Helper\FormatterHelper; +use SwissKnife202405\Symfony\Component\Console\Helper\Helper; +use SwissKnife202405\Symfony\Component\Console\Helper\HelperSet; +use SwissKnife202405\Symfony\Component\Console\Helper\ProcessHelper; +use SwissKnife202405\Symfony\Component\Console\Helper\QuestionHelper; +use SwissKnife202405\Symfony\Component\Console\Input\ArgvInput; +use SwissKnife202405\Symfony\Component\Console\Input\ArrayInput; +use SwissKnife202405\Symfony\Component\Console\Input\InputArgument; +use SwissKnife202405\Symfony\Component\Console\Input\InputAwareInterface; +use SwissKnife202405\Symfony\Component\Console\Input\InputDefinition; +use SwissKnife202405\Symfony\Component\Console\Input\InputInterface; +use SwissKnife202405\Symfony\Component\Console\Input\InputOption; +use SwissKnife202405\Symfony\Component\Console\Output\ConsoleOutput; +use SwissKnife202405\Symfony\Component\Console\Output\ConsoleOutputInterface; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +use SwissKnife202405\Symfony\Component\Console\SignalRegistry\SignalRegistry; +use SwissKnife202405\Symfony\Component\Console\Style\SymfonyStyle; +use SwissKnife202405\Symfony\Component\ErrorHandler\ErrorHandler; +use SwissKnife202405\Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use SwissKnife202405\Symfony\Contracts\Service\ResetInterface; +/** + * An Application is the container for a collection of commands. + * + * It is the main entry point of a Console application. + * + * This class is optimized for a standard CLI environment. + * + * Usage: + * + * $app = new Application('myapp', '1.0 (stable)'); + * $app->add(new SimpleCommand()); + * $app->run(); + * + * @author Fabien Potencier + */ +class Application implements ResetInterface +{ + /** + * @var mixed[] + */ + private $commands = []; + /** + * @var bool + */ + private $wantHelps = \false; + /** + * @var \Symfony\Component\Console\Command\Command|null + */ + private $runningCommand; + /** + * @var string + */ + private $name; + /** + * @var string + */ + private $version; + /** + * @var \Symfony\Component\Console\CommandLoader\CommandLoaderInterface|null + */ + private $commandLoader; + /** + * @var bool + */ + private $catchExceptions = \true; + /** + * @var bool + */ + private $catchErrors = \false; + /** + * @var bool + */ + private $autoExit = \true; + /** + * @var \Symfony\Component\Console\Input\InputDefinition + */ + private $definition; + /** + * @var \Symfony\Component\Console\Helper\HelperSet + */ + private $helperSet; + /** + * @var \Symfony\Contracts\EventDispatcher\EventDispatcherInterface|null + */ + private $dispatcher; + /** + * @var \Symfony\Component\Console\Terminal + */ + private $terminal; + /** + * @var string + */ + private $defaultCommand; + /** + * @var bool + */ + private $singleCommand = \false; + /** + * @var bool + */ + private $initialized = \false; + /** + * @var \Symfony\Component\Console\SignalRegistry\SignalRegistry|null + */ + private $signalRegistry; + /** + * @var mixed[] + */ + private $signalsToDispatchEvent = []; + public function __construct(string $name = 'UNKNOWN', string $version = 'UNKNOWN') + { + $this->name = $name; + $this->version = $version; + $this->terminal = new Terminal(); + $this->defaultCommand = 'list'; + if (\defined('SIGINT') && SignalRegistry::isSupported()) { + $this->signalRegistry = new SignalRegistry(); + $this->signalsToDispatchEvent = [\SIGINT, \SIGTERM, \SIGUSR1, \SIGUSR2]; + } + } + /** + * @final + */ + public function setDispatcher(EventDispatcherInterface $dispatcher) : void + { + $this->dispatcher = $dispatcher; + } + /** + * @return void + */ + public function setCommandLoader(CommandLoaderInterface $commandLoader) + { + $this->commandLoader = $commandLoader; + } + public function getSignalRegistry() : SignalRegistry + { + if (!$this->signalRegistry) { + throw new RuntimeException('Signals are not supported. Make sure that the "pcntl" extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.'); + } + return $this->signalRegistry; + } + /** + * @return void + */ + public function setSignalsToDispatchEvent(int ...$signalsToDispatchEvent) + { + $this->signalsToDispatchEvent = $signalsToDispatchEvent; + } + /** + * Runs the current application. + * + * @return int 0 if everything went fine, or an error code + * + * @throws \Exception When running fails. Bypass this when {@link setCatchExceptions()}. + */ + public function run(?InputInterface $input = null, ?OutputInterface $output = null) : int + { + if (\function_exists('putenv')) { + @\putenv('LINES=' . $this->terminal->getHeight()); + @\putenv('COLUMNS=' . $this->terminal->getWidth()); + } + $input = $input ?? new ArgvInput(); + $output = $output ?? new ConsoleOutput(); + $renderException = function (\Throwable $e) use($output) { + if ($output instanceof ConsoleOutputInterface) { + $this->renderThrowable($e, $output->getErrorOutput()); + } else { + $this->renderThrowable($e, $output); + } + }; + if ($phpHandler = \set_exception_handler($renderException)) { + \restore_exception_handler(); + if (!\is_array($phpHandler) || !$phpHandler[0] instanceof ErrorHandler) { + $errorHandler = \true; + } elseif ($errorHandler = $phpHandler[0]->setExceptionHandler($renderException)) { + $phpHandler[0]->setExceptionHandler($errorHandler); + } + } + $this->configureIO($input, $output); + try { + $exitCode = $this->doRun($input, $output); + } catch (\Throwable $e) { + if ($e instanceof \Exception && !$this->catchExceptions) { + throw $e; + } + if (!$e instanceof \Exception && !$this->catchErrors) { + throw $e; + } + $renderException($e); + $exitCode = $e->getCode(); + if (\is_numeric($exitCode)) { + $exitCode = (int) $exitCode; + if ($exitCode <= 0) { + $exitCode = 1; + } + } else { + $exitCode = 1; + } + } finally { + // if the exception handler changed, keep it + // otherwise, unregister $renderException + if (!$phpHandler) { + if (\set_exception_handler($renderException) === $renderException) { + \restore_exception_handler(); + } + \restore_exception_handler(); + } elseif (!$errorHandler) { + $finalHandler = $phpHandler[0]->setExceptionHandler(null); + if ($finalHandler !== $renderException) { + $phpHandler[0]->setExceptionHandler($finalHandler); + } + } + } + if ($this->autoExit) { + if ($exitCode > 255) { + $exitCode = 255; + } + exit($exitCode); + } + return $exitCode; + } + /** + * Runs the current application. + * + * @return int 0 if everything went fine, or an error code + */ + public function doRun(InputInterface $input, OutputInterface $output) + { + if (\true === $input->hasParameterOption(['--version', '-V'], \true)) { + $output->writeln($this->getLongVersion()); + return 0; + } + try { + // Makes ArgvInput::getFirstArgument() able to distinguish an option from an argument. + $input->bind($this->getDefinition()); + } catch (ExceptionInterface $exception) { + // Errors must be ignored, full binding/validation happens later when the command is known. + } + $name = $this->getCommandName($input); + if (\true === $input->hasParameterOption(['--help', '-h'], \true)) { + if (!$name) { + $name = 'help'; + $input = new ArrayInput(['command_name' => $this->defaultCommand]); + } else { + $this->wantHelps = \true; + } + } + if (!$name) { + $name = $this->defaultCommand; + $definition = $this->getDefinition(); + $definition->setArguments(\array_merge($definition->getArguments(), ['command' => new InputArgument('command', InputArgument::OPTIONAL, $definition->getArgument('command')->getDescription(), $name)])); + } + try { + $this->runningCommand = null; + // the command name MUST be the first element of the input + $command = $this->find($name); + } catch (\Throwable $e) { + if ($e instanceof CommandNotFoundException && !$e instanceof NamespaceNotFoundException && 1 === \count($alternatives = $e->getAlternatives()) && $input->isInteractive()) { + $alternative = $alternatives[0]; + $style = new SymfonyStyle($input, $output); + $output->writeln(''); + $formattedBlock = (new FormatterHelper())->formatBlock(\sprintf('Command "%s" is not defined.', $name), 'error', \true); + $output->writeln($formattedBlock); + if (!$style->confirm(\sprintf('Do you want to run "%s" instead? ', $alternative), \false)) { + if (null !== $this->dispatcher) { + $event = new ConsoleErrorEvent($input, $output, $e); + $this->dispatcher->dispatch($event, ConsoleEvents::ERROR); + return $event->getExitCode(); + } + return 1; + } + $command = $this->find($alternative); + } else { + if (null !== $this->dispatcher) { + $event = new ConsoleErrorEvent($input, $output, $e); + $this->dispatcher->dispatch($event, ConsoleEvents::ERROR); + if (0 === $event->getExitCode()) { + return 0; + } + $e = $event->getError(); + } + try { + if ($e instanceof CommandNotFoundException && ($namespace = $this->findNamespace($name))) { + $helper = new DescriptorHelper(); + $helper->describe($output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output, $this, ['format' => 'txt', 'raw_text' => \false, 'namespace' => $namespace, 'short' => \false]); + return isset($event) ? $event->getExitCode() : 1; + } + throw $e; + } catch (NamespaceNotFoundException $exception) { + throw $e; + } + } + } + if ($command instanceof LazyCommand) { + $command = $command->getCommand(); + } + $this->runningCommand = $command; + $exitCode = $this->doRunCommand($command, $input, $output); + $this->runningCommand = null; + return $exitCode; + } + /** + * @return void + */ + public function reset() + { + } + /** + * @return void + */ + public function setHelperSet(HelperSet $helperSet) + { + $this->helperSet = $helperSet; + } + /** + * Get the helper set associated with the command. + */ + public function getHelperSet() : HelperSet + { + return $this->helperSet = $this->helperSet ?? $this->getDefaultHelperSet(); + } + /** + * @return void + */ + public function setDefinition(InputDefinition $definition) + { + $this->definition = $definition; + } + /** + * Gets the InputDefinition related to this Application. + */ + public function getDefinition() : InputDefinition + { + $this->definition = $this->definition ?? $this->getDefaultInputDefinition(); + if ($this->singleCommand) { + $inputDefinition = $this->definition; + $inputDefinition->setArguments(); + return $inputDefinition; + } + return $this->definition; + } + /** + * Adds suggestions to $suggestions for the current completion input (e.g. option or argument). + */ + public function complete(CompletionInput $input, CompletionSuggestions $suggestions) : void + { + if (CompletionInput::TYPE_ARGUMENT_VALUE === $input->getCompletionType() && 'command' === $input->getCompletionName()) { + foreach ($this->all() as $name => $command) { + // skip hidden commands and aliased commands as they already get added below + if ($command->isHidden() || $command->getName() !== $name) { + continue; + } + $suggestions->suggestValue(new Suggestion($command->getName(), $command->getDescription())); + foreach ($command->getAliases() as $name) { + $suggestions->suggestValue(new Suggestion($name, $command->getDescription())); + } + } + return; + } + if (CompletionInput::TYPE_OPTION_NAME === $input->getCompletionType()) { + $suggestions->suggestOptions($this->getDefinition()->getOptions()); + return; + } + } + /** + * Gets the help message. + */ + public function getHelp() : string + { + return $this->getLongVersion(); + } + /** + * Gets whether to catch exceptions or not during commands execution. + */ + public function areExceptionsCaught() : bool + { + return $this->catchExceptions; + } + /** + * Sets whether to catch exceptions or not during commands execution. + * + * @return void + */ + public function setCatchExceptions(bool $boolean) + { + $this->catchExceptions = $boolean; + } + /** + * Sets whether to catch errors or not during commands execution. + */ + public function setCatchErrors(bool $catchErrors = \true) : void + { + $this->catchErrors = $catchErrors; + } + /** + * Gets whether to automatically exit after a command execution or not. + */ + public function isAutoExitEnabled() : bool + { + return $this->autoExit; + } + /** + * Sets whether to automatically exit after a command execution or not. + * + * @return void + */ + public function setAutoExit(bool $boolean) + { + $this->autoExit = $boolean; + } + /** + * Gets the name of the application. + */ + public function getName() : string + { + return $this->name; + } + /** + * Sets the application name. + * + * @return void + */ + public function setName(string $name) + { + $this->name = $name; + } + /** + * Gets the application version. + */ + public function getVersion() : string + { + return $this->version; + } + /** + * Sets the application version. + * + * @return void + */ + public function setVersion(string $version) + { + $this->version = $version; + } + /** + * Returns the long version of the application. + * + * @return string + */ + public function getLongVersion() + { + if ('UNKNOWN' !== $this->getName()) { + if ('UNKNOWN' !== $this->getVersion()) { + return \sprintf('%s %s', $this->getName(), $this->getVersion()); + } + return $this->getName(); + } + return 'Console Tool'; + } + /** + * Registers a new command. + */ + public function register(string $name) : Command + { + return $this->add(new Command($name)); + } + /** + * Adds an array of command objects. + * + * If a Command is not enabled it will not be added. + * + * @param Command[] $commands An array of commands + * + * @return void + */ + public function addCommands(array $commands) + { + foreach ($commands as $command) { + $this->add($command); + } + } + /** + * Adds a command object. + * + * If a command with the same name already exists, it will be overridden. + * If the command is not enabled it will not be added. + * + * @return Command|null + */ + public function add(Command $command) + { + $this->init(); + $command->setApplication($this); + if (!$command->isEnabled()) { + $command->setApplication(null); + return null; + } + if (!$command instanceof LazyCommand) { + // Will throw if the command is not correctly initialized. + $command->getDefinition(); + } + if (!$command->getName()) { + throw new LogicException(\sprintf('The command defined in "%s" cannot have an empty name.', \get_debug_type($command))); + } + $this->commands[$command->getName()] = $command; + foreach ($command->getAliases() as $alias) { + $this->commands[$alias] = $command; + } + return $command; + } + /** + * Returns a registered command by name or alias. + * + * @return Command + * + * @throws CommandNotFoundException When given command name does not exist + */ + public function get(string $name) + { + $this->init(); + if (!$this->has($name)) { + throw new CommandNotFoundException(\sprintf('The command "%s" does not exist.', $name)); + } + // When the command has a different name than the one used at the command loader level + if (!isset($this->commands[$name])) { + throw new CommandNotFoundException(\sprintf('The "%s" command cannot be found because it is registered under multiple names. Make sure you don\'t set a different name via constructor or "setName()".', $name)); + } + $command = $this->commands[$name]; + if ($this->wantHelps) { + $this->wantHelps = \false; + $helpCommand = $this->get('help'); + $helpCommand->setCommand($command); + return $helpCommand; + } + return $command; + } + /** + * Returns true if the command exists, false otherwise. + */ + public function has(string $name) : bool + { + $this->init(); + return isset($this->commands[$name]) || (($nullsafeVariable1 = $this->commandLoader) ? $nullsafeVariable1->has($name) : null) && $this->add($this->commandLoader->get($name)); + } + /** + * Returns an array of all unique namespaces used by currently registered commands. + * + * It does not return the global namespace which always exists. + * + * @return string[] + */ + public function getNamespaces() : array + { + $namespaces = []; + foreach ($this->all() as $command) { + if ($command->isHidden()) { + continue; + } + $namespaces[] = $this->extractAllNamespaces($command->getName()); + foreach ($command->getAliases() as $alias) { + $namespaces[] = $this->extractAllNamespaces($alias); + } + } + return \array_values(\array_unique(\array_filter(\array_merge([], ...$namespaces)))); + } + /** + * Finds a registered namespace by a name or an abbreviation. + * + * @throws NamespaceNotFoundException When namespace is incorrect or ambiguous + */ + public function findNamespace(string $namespace) : string + { + $allNamespaces = $this->getNamespaces(); + $expr = \implode('[^:]*:', \array_map('preg_quote', \explode(':', $namespace))) . '[^:]*'; + $namespaces = \preg_grep('{^' . $expr . '}', $allNamespaces); + if (empty($namespaces)) { + $message = \sprintf('There are no commands defined in the "%s" namespace.', $namespace); + if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) { + if (1 == \count($alternatives)) { + $message .= "\n\nDid you mean this?\n "; + } else { + $message .= "\n\nDid you mean one of these?\n "; + } + $message .= \implode("\n ", $alternatives); + } + throw new NamespaceNotFoundException($message, $alternatives); + } + $exact = \in_array($namespace, $namespaces, \true); + if (\count($namespaces) > 1 && !$exact) { + throw new NamespaceNotFoundException(\sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $namespace, $this->getAbbreviationSuggestions(\array_values($namespaces))), \array_values($namespaces)); + } + return $exact ? $namespace : \reset($namespaces); + } + /** + * Finds a command by name or alias. + * + * Contrary to get, this command tries to find the best + * match if you give it an abbreviation of a name or alias. + * + * @return Command + * + * @throws CommandNotFoundException When command name is incorrect or ambiguous + */ + public function find(string $name) + { + $this->init(); + $aliases = []; + foreach ($this->commands as $command) { + foreach ($command->getAliases() as $alias) { + if (!$this->has($alias)) { + $this->commands[$alias] = $command; + } + } + } + if ($this->has($name)) { + return $this->get($name); + } + $allCommands = $this->commandLoader ? \array_merge($this->commandLoader->getNames(), \array_keys($this->commands)) : \array_keys($this->commands); + $expr = \implode('[^:]*:', \array_map('preg_quote', \explode(':', $name))) . '[^:]*'; + $commands = \preg_grep('{^' . $expr . '}', $allCommands); + if (empty($commands)) { + $commands = \preg_grep('{^' . $expr . '}i', $allCommands); + } + // if no commands matched or we just matched namespaces + if (empty($commands) || \count(\preg_grep('{^' . $expr . '$}i', $commands)) < 1) { + if (\false !== ($pos = \strrpos($name, ':'))) { + // check if a namespace exists and contains commands + $this->findNamespace(\substr($name, 0, $pos)); + } + $message = \sprintf('Command "%s" is not defined.', $name); + if ($alternatives = $this->findAlternatives($name, $allCommands)) { + // remove hidden commands + $alternatives = \array_filter($alternatives, function ($name) { + return !$this->get($name)->isHidden(); + }); + if (1 == \count($alternatives)) { + $message .= "\n\nDid you mean this?\n "; + } else { + $message .= "\n\nDid you mean one of these?\n "; + } + $message .= \implode("\n ", $alternatives); + } + throw new CommandNotFoundException($message, \array_values($alternatives)); + } + // filter out aliases for commands which are already on the list + if (\count($commands) > 1) { + $commandList = $this->commandLoader ? \array_merge(\array_flip($this->commandLoader->getNames()), $this->commands) : $this->commands; + $commands = \array_unique(\array_filter($commands, function ($nameOrAlias) use(&$commandList, $commands, &$aliases) { + if (!$commandList[$nameOrAlias] instanceof Command) { + $commandList[$nameOrAlias] = $this->commandLoader->get($nameOrAlias); + } + $commandName = $commandList[$nameOrAlias]->getName(); + $aliases[$nameOrAlias] = $commandName; + return $commandName === $nameOrAlias || !\in_array($commandName, $commands); + })); + } + if (\count($commands) > 1) { + $usableWidth = $this->terminal->getWidth() - 10; + $abbrevs = \array_values($commands); + $maxLen = 0; + foreach ($abbrevs as $abbrev) { + $maxLen = \max(Helper::width($abbrev), $maxLen); + } + $abbrevs = \array_map(function ($cmd) use($commandList, $usableWidth, $maxLen, &$commands) { + if ($commandList[$cmd]->isHidden()) { + unset($commands[\array_search($cmd, $commands)]); + return \false; + } + $abbrev = \str_pad($cmd, $maxLen, ' ') . ' ' . $commandList[$cmd]->getDescription(); + return Helper::width($abbrev) > $usableWidth ? Helper::substr($abbrev, 0, $usableWidth - 3) . '...' : $abbrev; + }, \array_values($commands)); + if (\count($commands) > 1) { + $suggestions = $this->getAbbreviationSuggestions(\array_filter($abbrevs)); + throw new CommandNotFoundException(\sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $name, $suggestions), \array_values($commands)); + } + } + $command = $this->get(\reset($commands)); + if ($command->isHidden()) { + throw new CommandNotFoundException(\sprintf('The command "%s" does not exist.', $name)); + } + return $command; + } + /** + * Gets the commands (registered in the given namespace if provided). + * + * The array keys are the full names and the values the command instances. + * + * @return Command[] + */ + public function all(?string $namespace = null) + { + $this->init(); + if (null === $namespace) { + if (!$this->commandLoader) { + return $this->commands; + } + $commands = $this->commands; + foreach ($this->commandLoader->getNames() as $name) { + if (!isset($commands[$name]) && $this->has($name)) { + $commands[$name] = $this->get($name); + } + } + return $commands; + } + $commands = []; + foreach ($this->commands as $name => $command) { + if ($namespace === $this->extractNamespace($name, \substr_count($namespace, ':') + 1)) { + $commands[$name] = $command; + } + } + if ($this->commandLoader) { + foreach ($this->commandLoader->getNames() as $name) { + if (!isset($commands[$name]) && $namespace === $this->extractNamespace($name, \substr_count($namespace, ':') + 1) && $this->has($name)) { + $commands[$name] = $this->get($name); + } + } + } + return $commands; + } + /** + * Returns an array of possible abbreviations given a set of names. + * + * @return string[][] + */ + public static function getAbbreviations(array $names) : array + { + $abbrevs = []; + foreach ($names as $name) { + for ($len = \strlen($name); $len > 0; --$len) { + $abbrev = \substr($name, 0, $len); + $abbrevs[$abbrev][] = $name; + } + } + return $abbrevs; + } + public function renderThrowable(\Throwable $e, OutputInterface $output) : void + { + $output->writeln('', OutputInterface::VERBOSITY_QUIET); + $this->doRenderThrowable($e, $output); + if (null !== $this->runningCommand) { + $output->writeln(\sprintf('%s', OutputFormatter::escape(\sprintf($this->runningCommand->getSynopsis(), $this->getName()))), OutputInterface::VERBOSITY_QUIET); + $output->writeln('', OutputInterface::VERBOSITY_QUIET); + } + } + protected function doRenderThrowable(\Throwable $e, OutputInterface $output) : void + { + do { + $message = \trim($e->getMessage()); + if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { + $class = \get_debug_type($e); + $title = \sprintf(' [%s%s] ', $class, 0 !== ($code = $e->getCode()) ? ' (' . $code . ')' : ''); + $len = Helper::width($title); + } else { + $len = 0; + } + if (\strpos($message, "@anonymous\x00") !== \false) { + $message = \preg_replace_callback('/[a-zA-Z_\\x7f-\\xff][\\\\a-zA-Z0-9_\\x7f-\\xff]*+@anonymous\\x00.*?\\.php(?:0x?|:[0-9]++\\$)[0-9a-fA-F]++/', function ($m) { + return \class_exists($m[0], \false) ? ((\get_parent_class($m[0]) ?: \key(\class_implements($m[0]))) ?: 'class') . '@anonymous' : $m[0]; + }, $message); + } + $width = $this->terminal->getWidth() ? $this->terminal->getWidth() - 1 : \PHP_INT_MAX; + $lines = []; + foreach ('' !== $message ? \preg_split('/\\r?\\n/', $message) : [] as $line) { + foreach ($this->splitStringByWidth($line, $width - 4) as $line) { + // pre-format lines to get the right string length + $lineLength = Helper::width($line) + 4; + $lines[] = [$line, $lineLength]; + $len = \max($lineLength, $len); + } + } + $messages = []; + if (!$e instanceof ExceptionInterface || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { + $messages[] = \sprintf('%s', OutputFormatter::escape(\sprintf('In %s line %s:', \basename($e->getFile()) ?: 'n/a', $e->getLine() ?: 'n/a'))); + } + $messages[] = $emptyLine = \sprintf('%s', \str_repeat(' ', $len)); + if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { + $messages[] = \sprintf('%s%s', $title, \str_repeat(' ', \max(0, $len - Helper::width($title)))); + } + foreach ($lines as $line) { + $messages[] = \sprintf(' %s %s', OutputFormatter::escape($line[0]), \str_repeat(' ', $len - $line[1])); + } + $messages[] = $emptyLine; + $messages[] = ''; + $output->writeln($messages, OutputInterface::VERBOSITY_QUIET); + if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { + $output->writeln('Exception trace:', OutputInterface::VERBOSITY_QUIET); + // exception related properties + $trace = $e->getTrace(); + \array_unshift($trace, ['function' => '', 'file' => $e->getFile() ?: 'n/a', 'line' => $e->getLine() ?: 'n/a', 'args' => []]); + for ($i = 0, $count = \count($trace); $i < $count; ++$i) { + $class = $trace[$i]['class'] ?? ''; + $type = $trace[$i]['type'] ?? ''; + $function = $trace[$i]['function'] ?? ''; + $file = $trace[$i]['file'] ?? 'n/a'; + $line = $trace[$i]['line'] ?? 'n/a'; + $output->writeln(\sprintf(' %s%s at %s:%s', $class, $function ? $type . $function . '()' : '', $file, $line), OutputInterface::VERBOSITY_QUIET); + } + $output->writeln('', OutputInterface::VERBOSITY_QUIET); + } + } while ($e = $e->getPrevious()); + } + /** + * Configures the input and output instances based on the user arguments and options. + * + * @return void + */ + protected function configureIO(InputInterface $input, OutputInterface $output) + { + if (\true === $input->hasParameterOption(['--ansi'], \true)) { + $output->setDecorated(\true); + } elseif (\true === $input->hasParameterOption(['--no-ansi'], \true)) { + $output->setDecorated(\false); + } + if (\true === $input->hasParameterOption(['--no-interaction', '-n'], \true)) { + $input->setInteractive(\false); + } + switch ($shellVerbosity = (int) \getenv('SHELL_VERBOSITY')) { + case -1: + $output->setVerbosity(OutputInterface::VERBOSITY_QUIET); + break; + case 1: + $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); + break; + case 2: + $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE); + break; + case 3: + $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG); + break; + default: + $shellVerbosity = 0; + break; + } + if (\true === $input->hasParameterOption(['--quiet', '-q'], \true)) { + $output->setVerbosity(OutputInterface::VERBOSITY_QUIET); + $shellVerbosity = -1; + } else { + if ($input->hasParameterOption('-vvv', \true) || $input->hasParameterOption('--verbose=3', \true) || 3 === $input->getParameterOption('--verbose', \false, \true)) { + $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG); + $shellVerbosity = 3; + } elseif ($input->hasParameterOption('-vv', \true) || $input->hasParameterOption('--verbose=2', \true) || 2 === $input->getParameterOption('--verbose', \false, \true)) { + $output->setVerbosity(OutputInterface::VERBOSITY_VERY_VERBOSE); + $shellVerbosity = 2; + } elseif ($input->hasParameterOption('-v', \true) || $input->hasParameterOption('--verbose=1', \true) || $input->hasParameterOption('--verbose', \true) || $input->getParameterOption('--verbose', \false, \true)) { + $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE); + $shellVerbosity = 1; + } + } + if (-1 === $shellVerbosity) { + $input->setInteractive(\false); + } + if (\function_exists('putenv')) { + @\putenv('SHELL_VERBOSITY=' . $shellVerbosity); + } + $_ENV['SHELL_VERBOSITY'] = $shellVerbosity; + $_SERVER['SHELL_VERBOSITY'] = $shellVerbosity; + } + /** + * Runs the current command. + * + * If an event dispatcher has been attached to the application, + * events are also dispatched during the life-cycle of the command. + * + * @return int 0 if everything went fine, or an error code + */ + protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output) + { + foreach ($command->getHelperSet() as $helper) { + if ($helper instanceof InputAwareInterface) { + $helper->setInput($input); + } + } + $commandSignals = $command instanceof SignalableCommandInterface ? $command->getSubscribedSignals() : []; + if ($commandSignals || $this->dispatcher && $this->signalsToDispatchEvent) { + if (!$this->signalRegistry) { + throw new RuntimeException('Unable to subscribe to signal events. Make sure that the "pcntl" extension is installed and that "pcntl_*" functions are not disabled by your php.ini\'s "disable_functions" directive.'); + } + if (Terminal::hasSttyAvailable()) { + $sttyMode = \shell_exec('stty -g'); + foreach ([\SIGINT, \SIGTERM] as $signal) { + $this->signalRegistry->register($signal, static function () use($sttyMode) { + return \shell_exec('stty ' . $sttyMode); + }); + } + } + if ($this->dispatcher) { + // We register application signals, so that we can dispatch the event + foreach ($this->signalsToDispatchEvent as $signal) { + $event = new ConsoleSignalEvent($command, $input, $output, $signal); + $this->signalRegistry->register($signal, function ($signal) use($event, $command, $commandSignals) { + $this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL); + $exitCode = $event->getExitCode(); + // If the command is signalable, we call the handleSignal() method + if (\in_array($signal, $commandSignals, \true)) { + $exitCode = $command->handleSignal($signal, $exitCode); + // BC layer for Symfony <= 5 + if (null === $exitCode) { + trigger_deprecation('symfony/console', '6.3', 'Not returning an exit code from "%s::handleSignal()" is deprecated, return "false" to keep the command running or "0" to exit successfully.', \get_debug_type($command)); + $exitCode = 0; + } + } + if (\false !== $exitCode) { + $event = new ConsoleTerminateEvent($command, $event->getInput(), $event->getOutput(), $exitCode, $signal); + $this->dispatcher->dispatch($event, ConsoleEvents::TERMINATE); + exit($event->getExitCode()); + } + }); + } + // then we register command signals, but not if already handled after the dispatcher + $commandSignals = \array_diff($commandSignals, $this->signalsToDispatchEvent); + } + foreach ($commandSignals as $signal) { + $this->signalRegistry->register($signal, function (int $signal) use($command) : void { + $exitCode = $command->handleSignal($signal); + // BC layer for Symfony <= 5 + if (null === $exitCode) { + trigger_deprecation('symfony/console', '6.3', 'Not returning an exit code from "%s::handleSignal()" is deprecated, return "false" to keep the command running or "0" to exit successfully.', \get_debug_type($command)); + $exitCode = 0; + } + if (\false !== $exitCode) { + exit($exitCode); + } + }); + } + } + if (null === $this->dispatcher) { + return $command->run($input, $output); + } + // bind before the console.command event, so the listeners have access to input options/arguments + try { + $command->mergeApplicationDefinition(); + $input->bind($command->getDefinition()); + } catch (ExceptionInterface $exception) { + // ignore invalid options/arguments for now, to allow the event listeners to customize the InputDefinition + } + $event = new ConsoleCommandEvent($command, $input, $output); + $e = null; + try { + $this->dispatcher->dispatch($event, ConsoleEvents::COMMAND); + if ($event->commandShouldRun()) { + $exitCode = $command->run($input, $output); + } else { + $exitCode = ConsoleCommandEvent::RETURN_CODE_DISABLED; + } + } catch (\Throwable $e) { + $event = new ConsoleErrorEvent($input, $output, $e, $command); + $this->dispatcher->dispatch($event, ConsoleEvents::ERROR); + $e = $event->getError(); + if (0 === ($exitCode = $event->getExitCode())) { + $e = null; + } + } + $event = new ConsoleTerminateEvent($command, $input, $output, $exitCode); + $this->dispatcher->dispatch($event, ConsoleEvents::TERMINATE); + if (null !== $e) { + throw $e; + } + return $event->getExitCode(); + } + /** + * Gets the name of the command based on input. + */ + protected function getCommandName(InputInterface $input) : ?string + { + return $this->singleCommand ? $this->defaultCommand : $input->getFirstArgument(); + } + /** + * Gets the default input definition. + */ + protected function getDefaultInputDefinition() : InputDefinition + { + return new InputDefinition([new InputArgument('command', InputArgument::REQUIRED, 'The command to execute'), new InputOption('--help', '-h', InputOption::VALUE_NONE, 'Display help for the given command. When no command is given display help for the ' . $this->defaultCommand . ' command'), new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'), new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'), new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version'), new InputOption('--ansi', '', InputOption::VALUE_NEGATABLE, 'Force (or disable --no-ansi) ANSI output', null), new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question')]); + } + /** + * Gets the default commands that should always be available. + * + * @return Command[] + */ + protected function getDefaultCommands() : array + { + return [new HelpCommand(), new ListCommand(), new CompleteCommand(), new DumpCompletionCommand()]; + } + /** + * Gets the default helper set with the helpers that should always be available. + */ + protected function getDefaultHelperSet() : HelperSet + { + return new HelperSet([new FormatterHelper(), new DebugFormatterHelper(), new ProcessHelper(), new QuestionHelper()]); + } + /** + * Returns abbreviated suggestions in string format. + */ + private function getAbbreviationSuggestions(array $abbrevs) : string + { + return ' ' . \implode("\n ", $abbrevs); + } + /** + * Returns the namespace part of the command name. + * + * This method is not part of public API and should not be used directly. + */ + public function extractNamespace(string $name, ?int $limit = null) : string + { + $parts = \explode(':', $name, -1); + return \implode(':', null === $limit ? $parts : \array_slice($parts, 0, $limit)); + } + /** + * Finds alternative of $name among $collection, + * if nothing is found in $collection, try in $abbrevs. + * + * @return string[] + */ + private function findAlternatives(string $name, iterable $collection) : array + { + $threshold = 1000.0; + $alternatives = []; + $collectionParts = []; + foreach ($collection as $item) { + $collectionParts[$item] = \explode(':', $item); + } + foreach (\explode(':', $name) as $i => $subname) { + foreach ($collectionParts as $collectionName => $parts) { + $exists = isset($alternatives[$collectionName]); + if (!isset($parts[$i]) && $exists) { + $alternatives[$collectionName] += $threshold; + continue; + } elseif (!isset($parts[$i])) { + continue; + } + $lev = \levenshtein($subname, $parts[$i]); + if ($lev <= \strlen($subname) / 3 || '' !== $subname && \strpos($parts[$i], $subname) !== \false) { + $alternatives[$collectionName] = $exists ? $alternatives[$collectionName] + $lev : $lev; + } elseif ($exists) { + $alternatives[$collectionName] += $threshold; + } + } + } + foreach ($collection as $item) { + $lev = \levenshtein($name, $item); + if ($lev <= \strlen($name) / 3 || \strpos($item, $name) !== \false) { + $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev; + } + } + $alternatives = \array_filter($alternatives, function ($lev) use($threshold) { + return $lev < 2 * $threshold; + }); + \ksort($alternatives, \SORT_NATURAL | \SORT_FLAG_CASE); + return \array_keys($alternatives); + } + /** + * Sets the default Command name. + * + * @return $this + */ + public function setDefaultCommand(string $commandName, bool $isSingleCommand = \false) + { + $this->defaultCommand = \explode('|', \ltrim($commandName, '|'))[0]; + if ($isSingleCommand) { + // Ensure the command exist + $this->find($commandName); + $this->singleCommand = \true; + } + return $this; + } + /** + * @internal + */ + public function isSingleCommand() : bool + { + return $this->singleCommand; + } + private function splitStringByWidth(string $string, int $width) : array + { + // str_split is not suitable for multi-byte characters, we should use preg_split to get char array properly. + // additionally, array_slice() is not enough as some character has doubled width. + // we need a function to split string not by character count but by string width + if (\false === ($encoding = \mb_detect_encoding($string, null, \true))) { + return \str_split($string, $width); + } + $utf8String = \mb_convert_encoding($string, 'utf8', $encoding); + $lines = []; + $line = ''; + $offset = 0; + while (\preg_match('/.{1,10000}/u', $utf8String, $m, 0, $offset)) { + $offset += \strlen($m[0]); + foreach (\preg_split('//u', $m[0]) as $char) { + // test if $char could be appended to current line + if (\mb_strwidth($line . $char, 'utf8') <= $width) { + $line .= $char; + continue; + } + // if not, push current line to array and make new line + $lines[] = \str_pad($line, $width); + $line = $char; + } + } + $lines[] = \count($lines) ? \str_pad($line, $width) : $line; + \mb_convert_variables($encoding, 'utf8', $lines); + return $lines; + } + /** + * Returns all namespaces of the command name. + * + * @return string[] + */ + private function extractAllNamespaces(string $name) : array + { + // -1 as third argument is needed to skip the command short name when exploding + $parts = \explode(':', $name, -1); + $namespaces = []; + foreach ($parts as $part) { + if (\count($namespaces)) { + $namespaces[] = \end($namespaces) . ':' . $part; + } else { + $namespaces[] = $part; + } + } + return $namespaces; + } + private function init() : void + { + if ($this->initialized) { + return; + } + $this->initialized = \true; + foreach ($this->getDefaultCommands() as $command) { + $this->add($command); + } + } +} diff --git a/vendor/symfony/console/Attribute/AsCommand.php b/vendor/symfony/console/Attribute/AsCommand.php new file mode 100644 index 0000000000..13aae05953 --- /dev/null +++ b/vendor/symfony/console/Attribute/AsCommand.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Attribute; + +/** + * Service tag to autoconfigure commands. + */ +#[\Attribute(\Attribute::TARGET_CLASS)] +class AsCommand +{ + /** + * @var string + */ + public $name; + /** + * @var string|null + */ + public $description; + public function __construct(string $name, ?string $description = null, array $aliases = [], bool $hidden = \false) + { + $this->name = $name; + $this->description = $description; + if (!$hidden && !$aliases) { + return; + } + $name = \explode('|', $name); + $name = \array_merge($name, $aliases); + if ($hidden && '' !== $name[0]) { + \array_unshift($name, ''); + } + $this->name = \implode('|', $name); + } +} diff --git a/vendor/symfony/console/CHANGELOG.md b/vendor/symfony/console/CHANGELOG.md new file mode 100644 index 0000000000..9ccb41d945 --- /dev/null +++ b/vendor/symfony/console/CHANGELOG.md @@ -0,0 +1,261 @@ +CHANGELOG +========= + +6.4 +--- + + * Add `SignalMap` to map signal value to its name + * Multi-line text in vertical tables is aligned properly + * The application can also catch errors with `Application::setCatchErrors(true)` + * Add `RunCommandMessage` and `RunCommandMessageHandler` + * Dispatch `ConsoleTerminateEvent` after an exit on signal handling and add `ConsoleTerminateEvent::getInterruptingSignal()` + +6.3 +--- + + * Add support for choosing exit code while handling signal, or to not exit at all + * Add `ProgressBar::setPlaceholderFormatter` to set a placeholder attached to a instance, instead of being global. + * Add `ReStructuredTextDescriptor` + +6.2 +--- + + * Improve truecolor terminal detection in some cases + * Add support for 256 color terminals (conversion from Ansi24 to Ansi8 if terminal is capable of it) + * Deprecate calling `*Command::setApplication()`, `*FormatterStyle::setForeground/setBackground()`, `Helper::setHelpSet()`, `Input*::setDefault()`, `Question::setAutocompleterCallback/setValidator()`without any arguments + * Change the signature of `OutputFormatterStyleInterface::setForeground/setBackground()` to `setForeground/setBackground(?string)` + * Change the signature of `HelperInterface::setHelperSet()` to `setHelperSet(?HelperSet)` + +6.1 +--- + + * Add support to display table vertically when calling setVertical() + * Add method `__toString()` to `InputInterface` + * Added `OutputWrapper` to prevent truncated URL in `SymfonyStyle::createBlock`. + * Deprecate `Command::$defaultName` and `Command::$defaultDescription`, use the `AsCommand` attribute instead + * Add suggested values for arguments and options in input definition, for input completion + * Add `$resumeAt` parameter to `ProgressBar#start()`, so that one can easily 'resume' progress on longer tasks, and still get accurate `getEstimate()` and `getRemaining()` results. + +6.0 +--- + + * `Command::setHidden()` has a default value (`true`) for `$hidden` parameter and is final + * Remove `Helper::strlen()`, use `Helper::width()` instead + * Remove `Helper::strlenWithoutDecoration()`, use `Helper::removeDecoration()` instead + * `AddConsoleCommandPass` can not be configured anymore + * Remove `HelperSet::setCommand()` and `getCommand()` without replacement + +5.4 +--- + + * Add `TesterTrait::assertCommandIsSuccessful()` to test command + * Deprecate `HelperSet::setCommand()` and `getCommand()` without replacement + +5.3 +--- + + * Add `GithubActionReporter` to render annotations in a Github Action + * Add `InputOption::VALUE_NEGATABLE` flag to handle `--foo`/`--no-foo` options + * Add the `Command::$defaultDescription` static property and the `description` attribute + on the `console.command` tag to allow the `list` command to instantiate commands lazily + * Add option `--short` to the `list` command + * Add support for bright colors + * Add `#[AsCommand]` attribute for declaring commands on PHP 8 + * Add `Helper::width()` and `Helper::length()` + * The `--ansi` and `--no-ansi` options now default to `null`. + +5.2.0 +----- + + * Added `SingleCommandApplication::setAutoExit()` to allow testing via `CommandTester` + * added support for multiline responses to questions through `Question::setMultiline()` + and `Question::isMultiline()` + * Added `SignalRegistry` class to stack signals handlers + * Added support for signals: + * Added `Application::getSignalRegistry()` and `Application::setSignalsToDispatchEvent()` methods + * Added `SignalableCommandInterface` interface + * Added `TableCellStyle` class to customize table cell + * Removed `php ` prefix invocation from help messages. + +5.1.0 +----- + + * `Command::setHidden()` is final since Symfony 5.1 + * Add `SingleCommandApplication` + * Add `Cursor` class + +5.0.0 +----- + + * removed support for finding hidden commands using an abbreviation, use the full name instead + * removed `TableStyle::setCrossingChar()` method in favor of `TableStyle::setDefaultCrossingChar()` + * removed `TableStyle::setHorizontalBorderChar()` method in favor of `TableStyle::setDefaultCrossingChars()` + * removed `TableStyle::getHorizontalBorderChar()` method in favor of `TableStyle::getBorderChars()` + * removed `TableStyle::setVerticalBorderChar()` method in favor of `TableStyle::setVerticalBorderChars()` + * removed `TableStyle::getVerticalBorderChar()` method in favor of `TableStyle::getBorderChars()` + * removed support for returning `null` from `Command::execute()`, return `0` instead + * `ProcessHelper::run()` accepts only `array|Symfony\Component\Process\Process` for its `command` argument + * `Application::setDispatcher` accepts only `Symfony\Contracts\EventDispatcher\EventDispatcherInterface` + for its `dispatcher` argument + * renamed `Application::renderException()` and `Application::doRenderException()` + to `renderThrowable()` and `doRenderThrowable()` respectively. + +4.4.0 +----- + + * deprecated finding hidden commands using an abbreviation, use the full name instead + * added `Question::setTrimmable` default to true to allow the answer to be trimmed + * added method `minSecondsBetweenRedraws()` and `maxSecondsBetweenRedraws()` on `ProgressBar` + * `Application` implements `ResetInterface` + * marked all dispatched event classes as `@final` + * added support for displaying table horizontally + * deprecated returning `null` from `Command::execute()`, return `0` instead + * Deprecated the `Application::renderException()` and `Application::doRenderException()` methods, + use `renderThrowable()` and `doRenderThrowable()` instead. + * added support for the `NO_COLOR` env var (https://no-color.org/) + +4.3.0 +----- + + * added support for hyperlinks + * added `ProgressBar::iterate()` method that simplify updating the progress bar when iterating + * added `Question::setAutocompleterCallback()` to provide a callback function + that dynamically generates suggestions as the user types + +4.2.0 +----- + + * allowed passing commands as `[$process, 'ENV_VAR' => 'value']` to + `ProcessHelper::run()` to pass environment variables + * deprecated passing a command as a string to `ProcessHelper::run()`, + pass it the command as an array of its arguments instead + * made the `ProcessHelper` class final + * added `WrappableOutputFormatterInterface::formatAndWrap()` (implemented in `OutputFormatter`) + * added `capture_stderr_separately` option to `CommandTester::execute()` + +4.1.0 +----- + + * added option to run suggested command if command is not found and only 1 alternative is available + * added option to modify console output and print multiple modifiable sections + * added support for iterable messages in output `write` and `writeln` methods + +4.0.0 +----- + + * `OutputFormatter` throws an exception when unknown options are used + * removed `QuestionHelper::setInputStream()/getInputStream()` + * removed `Application::getTerminalWidth()/getTerminalHeight()` and + `Application::setTerminalDimensions()/getTerminalDimensions()` + * removed `ConsoleExceptionEvent` + * removed `ConsoleEvents::EXCEPTION` + +3.4.0 +----- + + * added `SHELL_VERBOSITY` env var to control verbosity + * added `CommandLoaderInterface`, `FactoryCommandLoader` and PSR-11 + `ContainerCommandLoader` for commands lazy-loading + * added a case-insensitive command name matching fallback + * added static `Command::$defaultName/getDefaultName()`, allowing for + commands to be registered at compile time in the application command loader. + Setting the `$defaultName` property avoids the need for filling the `command` + attribute on the `console.command` tag when using `AddConsoleCommandPass`. + +3.3.0 +----- + + * added `ExceptionListener` + * added `AddConsoleCommandPass` (originally in FrameworkBundle) + * [BC BREAK] `Input::getOption()` no longer returns the default value for options + with value optional explicitly passed empty + * added console.error event to catch exceptions thrown by other listeners + * deprecated console.exception event in favor of console.error + * added ability to handle `CommandNotFoundException` through the + `console.error` event + * deprecated default validation in `SymfonyQuestionHelper::ask` + +3.2.0 +------ + + * added `setInputs()` method to CommandTester for ease testing of commands expecting inputs + * added `setStream()` and `getStream()` methods to Input (implement StreamableInputInterface) + * added StreamableInputInterface + * added LockableTrait + +3.1.0 +----- + + * added truncate method to FormatterHelper + * added setColumnWidth(s) method to Table + +2.8.3 +----- + + * remove readline support from the question helper as it caused issues + +2.8.0 +----- + + * use readline for user input in the question helper when available to allow + the use of arrow keys + +2.6.0 +----- + + * added a Process helper + * added a DebugFormatter helper + +2.5.0 +----- + + * deprecated the dialog helper (use the question helper instead) + * deprecated TableHelper in favor of Table + * deprecated ProgressHelper in favor of ProgressBar + * added ConsoleLogger + * added a question helper + * added a way to set the process name of a command + * added a way to set a default command instead of `ListCommand` + +2.4.0 +----- + + * added a way to force terminal dimensions + * added a convenient method to detect verbosity level + * [BC BREAK] made descriptors use output instead of returning a string + +2.3.0 +----- + + * added multiselect support to the select dialog helper + * added Table Helper for tabular data rendering + * added support for events in `Application` + * added a way to normalize EOLs in `ApplicationTester::getDisplay()` and `CommandTester::getDisplay()` + * added a way to set the progress bar progress via the `setCurrent` method + * added support for multiple InputOption shortcuts, written as `'-a|-b|-c'` + * added two additional verbosity levels, VERBOSITY_VERY_VERBOSE and VERBOSITY_DEBUG + +2.2.0 +----- + + * added support for colorization on Windows via ConEmu + * add a method to Dialog Helper to ask for a question and hide the response + * added support for interactive selections in console (DialogHelper::select()) + * added support for autocompletion as you type in Dialog Helper + +2.1.0 +----- + + * added ConsoleOutputInterface + * added the possibility to disable a command (Command::isEnabled()) + * added suggestions when a command does not exist + * added a --raw option to the list command + * added support for STDERR in the console output class (errors are now sent + to STDERR) + * made the defaults (helper set, commands, input definition) in Application + more easily customizable + * added support for the shell even if readline is not available + * added support for process isolation in Symfony shell via + `--process-isolation` switch + * added support for `--`, which disables options parsing after that point + (tokens will be parsed as arguments) diff --git a/vendor/symfony/console/CI/GithubActionReporter.php b/vendor/symfony/console/CI/GithubActionReporter.php new file mode 100644 index 0000000000..c4e116e257 --- /dev/null +++ b/vendor/symfony/console/CI/GithubActionReporter.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\CI; + +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +/** + * Utility class for Github actions. + * + * @author Maxime Steinhausser + */ +class GithubActionReporter +{ + /** + * @var \Symfony\Component\Console\Output\OutputInterface + */ + private $output; + /** + * @see https://github.com/actions/toolkit/blob/5e5e1b7aacba68a53836a34db4a288c3c1c1585b/packages/core/src/command.ts#L80-L85 + */ + private const ESCAPED_DATA = ['%' => '%25', "\r" => '%0D', "\n" => '%0A']; + /** + * @see https://github.com/actions/toolkit/blob/5e5e1b7aacba68a53836a34db4a288c3c1c1585b/packages/core/src/command.ts#L87-L94 + */ + private const ESCAPED_PROPERTIES = ['%' => '%25', "\r" => '%0D', "\n" => '%0A', ':' => '%3A', ',' => '%2C']; + public function __construct(OutputInterface $output) + { + $this->output = $output; + } + public static function isGithubActionEnvironment() : bool + { + return \false !== \getenv('GITHUB_ACTIONS'); + } + /** + * Output an error using the Github annotations format. + * + * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-an-error-message + */ + public function error(string $message, ?string $file = null, ?int $line = null, ?int $col = null) : void + { + $this->log('error', $message, $file, $line, $col); + } + /** + * Output a warning using the Github annotations format. + * + * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-a-warning-message + */ + public function warning(string $message, ?string $file = null, ?int $line = null, ?int $col = null) : void + { + $this->log('warning', $message, $file, $line, $col); + } + /** + * Output a debug log using the Github annotations format. + * + * @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-a-debug-message + */ + public function debug(string $message, ?string $file = null, ?int $line = null, ?int $col = null) : void + { + $this->log('debug', $message, $file, $line, $col); + } + private function log(string $type, string $message, ?string $file = null, ?int $line = null, ?int $col = null) : void + { + // Some values must be encoded. + $message = \strtr($message, self::ESCAPED_DATA); + if (!$file) { + // No file provided, output the message solely: + $this->output->writeln(\sprintf('::%s::%s', $type, $message)); + return; + } + $this->output->writeln(\sprintf('::%s file=%s,line=%s,col=%s::%s', $type, \strtr($file, self::ESCAPED_PROPERTIES), \strtr($line ?? 1, self::ESCAPED_PROPERTIES), \strtr($col ?? 0, self::ESCAPED_PROPERTIES), $message)); + } +} diff --git a/vendor/symfony/console/Color.php b/vendor/symfony/console/Color.php new file mode 100644 index 0000000000..b463fe8271 --- /dev/null +++ b/vendor/symfony/console/Color.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console; + +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +/** + * @author Fabien Potencier + */ +final class Color +{ + private const COLORS = ['black' => 0, 'red' => 1, 'green' => 2, 'yellow' => 3, 'blue' => 4, 'magenta' => 5, 'cyan' => 6, 'white' => 7, 'default' => 9]; + private const BRIGHT_COLORS = ['gray' => 0, 'bright-red' => 1, 'bright-green' => 2, 'bright-yellow' => 3, 'bright-blue' => 4, 'bright-magenta' => 5, 'bright-cyan' => 6, 'bright-white' => 7]; + private const AVAILABLE_OPTIONS = ['bold' => ['set' => 1, 'unset' => 22], 'underscore' => ['set' => 4, 'unset' => 24], 'blink' => ['set' => 5, 'unset' => 25], 'reverse' => ['set' => 7, 'unset' => 27], 'conceal' => ['set' => 8, 'unset' => 28]]; + /** + * @var string + */ + private $foreground; + /** + * @var string + */ + private $background; + /** + * @var mixed[] + */ + private $options = []; + public function __construct(string $foreground = '', string $background = '', array $options = []) + { + $this->foreground = $this->parseColor($foreground); + $this->background = $this->parseColor($background, \true); + foreach ($options as $option) { + if (!isset(self::AVAILABLE_OPTIONS[$option])) { + throw new InvalidArgumentException(\sprintf('Invalid option specified: "%s". Expected one of (%s).', $option, \implode(', ', \array_keys(self::AVAILABLE_OPTIONS)))); + } + $this->options[$option] = self::AVAILABLE_OPTIONS[$option]; + } + } + public function apply(string $text) : string + { + return $this->set() . $text . $this->unset(); + } + public function set() : string + { + $setCodes = []; + if ('' !== $this->foreground) { + $setCodes[] = $this->foreground; + } + if ('' !== $this->background) { + $setCodes[] = $this->background; + } + foreach ($this->options as $option) { + $setCodes[] = $option['set']; + } + if (0 === \count($setCodes)) { + return ''; + } + return \sprintf("\x1b[%sm", \implode(';', $setCodes)); + } + public function unset() : string + { + $unsetCodes = []; + if ('' !== $this->foreground) { + $unsetCodes[] = 39; + } + if ('' !== $this->background) { + $unsetCodes[] = 49; + } + foreach ($this->options as $option) { + $unsetCodes[] = $option['unset']; + } + if (0 === \count($unsetCodes)) { + return ''; + } + return \sprintf("\x1b[%sm", \implode(';', $unsetCodes)); + } + private function parseColor(string $color, bool $background = \false) : string + { + if ('' === $color) { + return ''; + } + if ('#' === $color[0]) { + return ($background ? '4' : '3') . Terminal::getColorMode()->convertFromHexToAnsiColorCode($color); + } + if (isset(self::COLORS[$color])) { + return ($background ? '4' : '3') . self::COLORS[$color]; + } + if (isset(self::BRIGHT_COLORS[$color])) { + return ($background ? '10' : '9') . self::BRIGHT_COLORS[$color]; + } + throw new InvalidArgumentException(\sprintf('Invalid "%s" color; expected one of (%s).', $color, \implode(', ', \array_merge(\array_keys(self::COLORS), \array_keys(self::BRIGHT_COLORS))))); + } +} diff --git a/vendor/symfony/console/Command/Command.php b/vendor/symfony/console/Command/Command.php new file mode 100644 index 0000000000..f09f1fcb5d --- /dev/null +++ b/vendor/symfony/console/Command/Command.php @@ -0,0 +1,677 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Command; + +use SwissKnife202405\Symfony\Component\Console\Application; +use SwissKnife202405\Symfony\Component\Console\Attribute\AsCommand; +use SwissKnife202405\Symfony\Component\Console\Completion\CompletionInput; +use SwissKnife202405\Symfony\Component\Console\Completion\CompletionSuggestions; +use SwissKnife202405\Symfony\Component\Console\Completion\Suggestion; +use SwissKnife202405\Symfony\Component\Console\Exception\ExceptionInterface; +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +use SwissKnife202405\Symfony\Component\Console\Exception\LogicException; +use SwissKnife202405\Symfony\Component\Console\Helper\HelperInterface; +use SwissKnife202405\Symfony\Component\Console\Helper\HelperSet; +use SwissKnife202405\Symfony\Component\Console\Input\InputArgument; +use SwissKnife202405\Symfony\Component\Console\Input\InputDefinition; +use SwissKnife202405\Symfony\Component\Console\Input\InputInterface; +use SwissKnife202405\Symfony\Component\Console\Input\InputOption; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +/** + * Base class for all commands. + * + * @author Fabien Potencier + */ +class Command +{ + // see https://tldp.org/LDP/abs/html/exitcodes.html + public const SUCCESS = 0; + public const FAILURE = 1; + public const INVALID = 2; + /** + * @var string|null The default command name + * + * @deprecated since Symfony 6.1, use the AsCommand attribute instead + */ + protected static $defaultName; + /** + * @var string|null The default command description + * + * @deprecated since Symfony 6.1, use the AsCommand attribute instead + */ + protected static $defaultDescription; + /** + * @var \Symfony\Component\Console\Application|null + */ + private $application; + /** + * @var string|null + */ + private $name; + /** + * @var string|null + */ + private $processTitle; + /** + * @var mixed[] + */ + private $aliases = []; + /** + * @var \Symfony\Component\Console\Input\InputDefinition + */ + private $definition; + /** + * @var bool + */ + private $hidden = \false; + /** + * @var string + */ + private $help = ''; + /** + * @var string + */ + private $description = ''; + /** + * @var \Symfony\Component\Console\Input\InputDefinition|null + */ + private $fullDefinition; + /** + * @var bool + */ + private $ignoreValidationErrors = \false; + /** + * @var \Closure|null + */ + private $code; + /** + * @var mixed[] + */ + private $synopsis = []; + /** + * @var mixed[] + */ + private $usages = []; + /** + * @var \Symfony\Component\Console\Helper\HelperSet|null + */ + private $helperSet; + public static function getDefaultName() : ?string + { + $class = static::class; + if ($attribute = \method_exists(new \ReflectionClass($class), 'getAttributes') ? (new \ReflectionClass($class))->getAttributes(AsCommand::class) : []) { + return $attribute[0]->newInstance()->name; + } + $r = new \ReflectionProperty($class, 'defaultName'); + $r->setAccessible(\true); + if ($class !== $r->class || null === static::$defaultName) { + return null; + } + trigger_deprecation('symfony/console', '6.1', 'Relying on the static property "$defaultName" for setting a command name is deprecated. Add the "%s" attribute to the "%s" class instead.', AsCommand::class, static::class); + return static::$defaultName; + } + public static function getDefaultDescription() : ?string + { + $class = static::class; + if ($attribute = \method_exists(new \ReflectionClass($class), 'getAttributes') ? (new \ReflectionClass($class))->getAttributes(AsCommand::class) : []) { + return $attribute[0]->newInstance()->description; + } + $r = new \ReflectionProperty($class, 'defaultDescription'); + $r->setAccessible(\true); + if ($class !== $r->class || null === static::$defaultDescription) { + return null; + } + trigger_deprecation('symfony/console', '6.1', 'Relying on the static property "$defaultDescription" for setting a command description is deprecated. Add the "%s" attribute to the "%s" class instead.', AsCommand::class, static::class); + return static::$defaultDescription; + } + /** + * @param string|null $name The name of the command; passing null means it must be set in configure() + * + * @throws LogicException When the command name is empty + */ + public function __construct(?string $name = null) + { + $this->definition = new InputDefinition(); + if (null === $name && null !== ($name = static::getDefaultName())) { + $aliases = \explode('|', $name); + if ('' === ($name = \array_shift($aliases))) { + $this->setHidden(\true); + $name = \array_shift($aliases); + } + $this->setAliases($aliases); + } + if (null !== $name) { + $this->setName($name); + } + if ('' === $this->description) { + $this->setDescription(static::getDefaultDescription() ?? ''); + } + $this->configure(); + } + /** + * Ignores validation errors. + * + * This is mainly useful for the help command. + * + * @return void + */ + public function ignoreValidationErrors() + { + $this->ignoreValidationErrors = \true; + } + /** + * @return void + */ + public function setApplication(?Application $application = null) + { + if (1 > \func_num_args()) { + trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); + } + $this->application = $application; + if ($application) { + $this->setHelperSet($application->getHelperSet()); + } else { + $this->helperSet = null; + } + $this->fullDefinition = null; + } + /** + * @return void + */ + public function setHelperSet(HelperSet $helperSet) + { + $this->helperSet = $helperSet; + } + /** + * Gets the helper set. + */ + public function getHelperSet() : ?HelperSet + { + return $this->helperSet; + } + /** + * Gets the application instance for this command. + */ + public function getApplication() : ?Application + { + return $this->application; + } + /** + * Checks whether the command is enabled or not in the current environment. + * + * Override this to check for x or y and return false if the command cannot + * run properly under the current conditions. + * + * @return bool + */ + public function isEnabled() + { + return \true; + } + /** + * Configures the current command. + * + * @return void + */ + protected function configure() + { + } + /** + * Executes the current command. + * + * This method is not abstract because you can use this class + * as a concrete class. In this case, instead of defining the + * execute() method, you set the code to execute by passing + * a Closure to the setCode() method. + * + * @return int 0 if everything went fine, or an exit code + * + * @throws LogicException When this abstract method is not implemented + * + * @see setCode() + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + throw new LogicException('You must override the execute() method in the concrete command class.'); + } + /** + * Interacts with the user. + * + * This method is executed before the InputDefinition is validated. + * This means that this is the only place where the command can + * interactively ask for values of missing required arguments. + * + * @return void + */ + protected function interact(InputInterface $input, OutputInterface $output) + { + } + /** + * Initializes the command after the input has been bound and before the input + * is validated. + * + * This is mainly useful when a lot of commands extends one main command + * where some things need to be initialized based on the input arguments and options. + * + * @see InputInterface::bind() + * @see InputInterface::validate() + * + * @return void + */ + protected function initialize(InputInterface $input, OutputInterface $output) + { + } + /** + * Runs the command. + * + * The code to execute is either defined directly with the + * setCode() method or by overriding the execute() method + * in a sub-class. + * + * @return int The command exit code + * + * @throws ExceptionInterface When input binding fails. Bypass this by calling {@link ignoreValidationErrors()}. + * + * @see setCode() + * @see execute() + */ + public function run(InputInterface $input, OutputInterface $output) : int + { + // add the application arguments and options + $this->mergeApplicationDefinition(); + // bind the input against the command specific arguments/options + try { + $input->bind($this->getDefinition()); + } catch (ExceptionInterface $e) { + if (!$this->ignoreValidationErrors) { + throw $e; + } + } + $this->initialize($input, $output); + if (null !== $this->processTitle) { + if (\function_exists('cli_set_process_title')) { + if (!@\cli_set_process_title($this->processTitle)) { + if ('Darwin' === \PHP_OS) { + $output->writeln('Running "cli_set_process_title" as an unprivileged user is not supported on MacOS.', OutputInterface::VERBOSITY_VERY_VERBOSE); + } else { + \cli_set_process_title($this->processTitle); + } + } + } elseif (\function_exists('setproctitle')) { + \setproctitle($this->processTitle); + } elseif (OutputInterface::VERBOSITY_VERY_VERBOSE === $output->getVerbosity()) { + $output->writeln('Install the proctitle PECL to be able to change the process title.'); + } + } + if ($input->isInteractive()) { + $this->interact($input, $output); + } + // The command name argument is often omitted when a command is executed directly with its run() method. + // It would fail the validation if we didn't make sure the command argument is present, + // since it's required by the application. + if ($input->hasArgument('command') && null === $input->getArgument('command')) { + $input->setArgument('command', $this->getName()); + } + $input->validate(); + if ($this->code) { + $statusCode = ($this->code)($input, $output); + } else { + $statusCode = $this->execute($input, $output); + if (!\is_int($statusCode)) { + throw new \TypeError(\sprintf('Return value of "%s::execute()" must be of the type int, "%s" returned.', static::class, \get_debug_type($statusCode))); + } + } + return \is_numeric($statusCode) ? (int) $statusCode : 0; + } + /** + * Adds suggestions to $suggestions for the current completion input (e.g. option or argument). + */ + public function complete(CompletionInput $input, CompletionSuggestions $suggestions) : void + { + $definition = $this->getDefinition(); + if (CompletionInput::TYPE_OPTION_VALUE === $input->getCompletionType() && $definition->hasOption($input->getCompletionName())) { + $definition->getOption($input->getCompletionName())->complete($input, $suggestions); + } elseif (CompletionInput::TYPE_ARGUMENT_VALUE === $input->getCompletionType() && $definition->hasArgument($input->getCompletionName())) { + $definition->getArgument($input->getCompletionName())->complete($input, $suggestions); + } + } + /** + * Sets the code to execute when running this command. + * + * If this method is used, it overrides the code defined + * in the execute() method. + * + * @param callable $code A callable(InputInterface $input, OutputInterface $output) + * + * @return $this + * + * @throws InvalidArgumentException + * + * @see execute() + */ + public function setCode(callable $code) + { + if ($code instanceof \Closure) { + $r = new \ReflectionFunction($code); + if (null === $r->getClosureThis()) { + \set_error_handler(static function () { + }); + try { + if ($c = \Closure::bind($code, $this)) { + $code = $c; + } + } finally { + \restore_error_handler(); + } + } + } else { + $code = \Closure::fromCallable($code); + } + $this->code = $code; + return $this; + } + /** + * Merges the application definition with the command definition. + * + * This method is not part of public API and should not be used directly. + * + * @param bool $mergeArgs Whether to merge or not the Application definition arguments to Command definition arguments + * + * @internal + */ + public function mergeApplicationDefinition(bool $mergeArgs = \true) : void + { + if (null === $this->application) { + return; + } + $this->fullDefinition = new InputDefinition(); + $this->fullDefinition->setOptions($this->definition->getOptions()); + $this->fullDefinition->addOptions($this->application->getDefinition()->getOptions()); + if ($mergeArgs) { + $this->fullDefinition->setArguments($this->application->getDefinition()->getArguments()); + $this->fullDefinition->addArguments($this->definition->getArguments()); + } else { + $this->fullDefinition->setArguments($this->definition->getArguments()); + } + } + /** + * Sets an array of argument and option instances. + * + * @return $this + * @param mixed[]|\Symfony\Component\Console\Input\InputDefinition $definition + */ + public function setDefinition($definition) + { + if ($definition instanceof InputDefinition) { + $this->definition = $definition; + } else { + $this->definition->setDefinition($definition); + } + $this->fullDefinition = null; + return $this; + } + /** + * Gets the InputDefinition attached to this Command. + */ + public function getDefinition() : InputDefinition + { + return $this->fullDefinition ?? $this->getNativeDefinition(); + } + /** + * Gets the InputDefinition to be used to create representations of this Command. + * + * Can be overridden to provide the original command representation when it would otherwise + * be changed by merging with the application InputDefinition. + * + * This method is not part of public API and should not be used directly. + */ + public function getNativeDefinition() : InputDefinition + { + if (!isset($this->definition)) { + throw new LogicException(\sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', static::class)); + } + return $this->definition; + } + /** + * Adds an argument. + * + * @param $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL + * @param $default The default value (for InputArgument::OPTIONAL mode only) + * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion + * + * @return $this + * + * @throws InvalidArgumentException When argument mode is not valid + * @param mixed $default + */ + public function addArgument(string $name, ?int $mode = null, string $description = '', $default = null) + { + $suggestedValues = 5 <= \func_num_args() ? \func_get_arg(4) : []; + if (!\is_array($suggestedValues) && !$suggestedValues instanceof \Closure) { + throw new \TypeError(\sprintf('Argument 5 passed to "%s()" must be array or \\Closure, "%s" given.', __METHOD__, \get_debug_type($suggestedValues))); + } + $this->definition->addArgument(new InputArgument($name, $mode, $description, $default, $suggestedValues)); + ($nullsafeVariable1 = $this->fullDefinition) ? $nullsafeVariable1->addArgument(new InputArgument($name, $mode, $description, $default, $suggestedValues)) : null; + return $this; + } + /** + * Adds an option. + * + * @param $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts + * @param $mode The option mode: One of the InputOption::VALUE_* constants + * @param $default The default value (must be null for InputOption::VALUE_NONE) + * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion + * + * @return $this + * + * @throws InvalidArgumentException If option mode is invalid or incompatible + * @param string|mixed[]|null $shortcut + * @param mixed $default + */ + public function addOption(string $name, $shortcut = null, ?int $mode = null, string $description = '', $default = null) + { + $suggestedValues = 6 <= \func_num_args() ? \func_get_arg(5) : []; + if (!\is_array($suggestedValues) && !$suggestedValues instanceof \Closure) { + throw new \TypeError(\sprintf('Argument 5 passed to "%s()" must be array or \\Closure, "%s" given.', __METHOD__, \get_debug_type($suggestedValues))); + } + $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default, $suggestedValues)); + ($nullsafeVariable2 = $this->fullDefinition) ? $nullsafeVariable2->addOption(new InputOption($name, $shortcut, $mode, $description, $default, $suggestedValues)) : null; + return $this; + } + /** + * Sets the name of the command. + * + * This method can set both the namespace and the name if + * you separate them by a colon (:) + * + * $command->setName('foo:bar'); + * + * @return $this + * + * @throws InvalidArgumentException When the name is invalid + */ + public function setName(string $name) + { + $this->validateName($name); + $this->name = $name; + return $this; + } + /** + * Sets the process title of the command. + * + * This feature should be used only when creating a long process command, + * like a daemon. + * + * @return $this + */ + public function setProcessTitle(string $title) + { + $this->processTitle = $title; + return $this; + } + /** + * Returns the command name. + */ + public function getName() : ?string + { + return $this->name; + } + /** + * @param bool $hidden Whether or not the command should be hidden from the list of commands + * + * @return $this + */ + public function setHidden(bool $hidden = \true) + { + $this->hidden = $hidden; + return $this; + } + /** + * @return bool whether the command should be publicly shown or not + */ + public function isHidden() : bool + { + return $this->hidden; + } + /** + * Sets the description for the command. + * + * @return $this + */ + public function setDescription(string $description) + { + $this->description = $description; + return $this; + } + /** + * Returns the description for the command. + */ + public function getDescription() : string + { + return $this->description; + } + /** + * Sets the help for the command. + * + * @return $this + */ + public function setHelp(string $help) + { + $this->help = $help; + return $this; + } + /** + * Returns the help for the command. + */ + public function getHelp() : string + { + return $this->help; + } + /** + * Returns the processed help for the command replacing the %command.name% and + * %command.full_name% patterns with the real values dynamically. + */ + public function getProcessedHelp() : string + { + $name = $this->name; + $isSingleCommand = ($nullsafeVariable3 = $this->application) ? $nullsafeVariable3->isSingleCommand() : null; + $placeholders = ['%command.name%', '%command.full_name%']; + $replacements = [$name, $isSingleCommand ? $_SERVER['PHP_SELF'] : $_SERVER['PHP_SELF'] . ' ' . $name]; + return \str_replace($placeholders, $replacements, $this->getHelp() ?: $this->getDescription()); + } + /** + * Sets the aliases for the command. + * + * @param string[] $aliases An array of aliases for the command + * + * @return $this + * + * @throws InvalidArgumentException When an alias is invalid + */ + public function setAliases(iterable $aliases) + { + $list = []; + foreach ($aliases as $alias) { + $this->validateName($alias); + $list[] = $alias; + } + $this->aliases = \is_array($aliases) ? $aliases : $list; + return $this; + } + /** + * Returns the aliases for the command. + */ + public function getAliases() : array + { + return $this->aliases; + } + /** + * Returns the synopsis for the command. + * + * @param bool $short Whether to show the short version of the synopsis (with options folded) or not + */ + public function getSynopsis(bool $short = \false) : string + { + $key = $short ? 'short' : 'long'; + if (!isset($this->synopsis[$key])) { + $this->synopsis[$key] = \trim(\sprintf('%s %s', $this->name, $this->definition->getSynopsis($short))); + } + return $this->synopsis[$key]; + } + /** + * Add a command usage example, it'll be prefixed with the command name. + * + * @return $this + */ + public function addUsage(string $usage) + { + if (\strncmp($usage, $this->name, \strlen($this->name)) !== 0) { + $usage = \sprintf('%s %s', $this->name, $usage); + } + $this->usages[] = $usage; + return $this; + } + /** + * Returns alternative usages of the command. + */ + public function getUsages() : array + { + return $this->usages; + } + /** + * Gets a helper instance by name. + * + * @return HelperInterface + * + * @throws LogicException if no HelperSet is defined + * @throws InvalidArgumentException if the helper is not defined + */ + public function getHelper(string $name) + { + if (null === $this->helperSet) { + throw new LogicException(\sprintf('Cannot retrieve helper "%s" because there is no HelperSet defined. Did you forget to add your command to the application or to set the application on the command using the setApplication() method? You can also set the HelperSet directly using the setHelperSet() method.', $name)); + } + return $this->helperSet->get($name); + } + /** + * Validates a command name. + * + * It must be non-empty and parts can optionally be separated by ":". + * + * @throws InvalidArgumentException When the name is invalid + */ + private function validateName(string $name) : void + { + if (!\preg_match('/^[^\\:]++(\\:[^\\:]++)*$/', $name)) { + throw new InvalidArgumentException(\sprintf('Command name "%s" is invalid.', $name)); + } + } +} diff --git a/vendor/symfony/console/Command/CompleteCommand.php b/vendor/symfony/console/Command/CompleteCommand.php new file mode 100644 index 0000000000..79c39bddc0 --- /dev/null +++ b/vendor/symfony/console/Command/CompleteCommand.php @@ -0,0 +1,164 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Command; + +use SwissKnife202405\Symfony\Component\Console\Attribute\AsCommand; +use SwissKnife202405\Symfony\Component\Console\Completion\CompletionInput; +use SwissKnife202405\Symfony\Component\Console\Completion\CompletionSuggestions; +use SwissKnife202405\Symfony\Component\Console\Completion\Output\BashCompletionOutput; +use SwissKnife202405\Symfony\Component\Console\Completion\Output\CompletionOutputInterface; +use SwissKnife202405\Symfony\Component\Console\Completion\Output\FishCompletionOutput; +use SwissKnife202405\Symfony\Component\Console\Completion\Output\ZshCompletionOutput; +use SwissKnife202405\Symfony\Component\Console\Exception\CommandNotFoundException; +use SwissKnife202405\Symfony\Component\Console\Exception\ExceptionInterface; +use SwissKnife202405\Symfony\Component\Console\Input\InputInterface; +use SwissKnife202405\Symfony\Component\Console\Input\InputOption; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +/** + * Responsible for providing the values to the shell completion. + * + * @author Wouter de Jong + */ +final class CompleteCommand extends Command +{ + public const COMPLETION_API_VERSION = '1'; + /** + * @deprecated since Symfony 6.1 + */ + protected static $defaultName = '|_complete'; + /** + * @deprecated since Symfony 6.1 + */ + protected static $defaultDescription = 'Internal command to provide shell completion suggestions'; + /** + * @var mixed[] + */ + private $completionOutputs; + /** + * @var bool + */ + private $isDebug = \false; + /** + * @param array> $completionOutputs A list of additional completion outputs, with shell name as key and FQCN as value + */ + public function __construct(array $completionOutputs = []) + { + // must be set before the parent constructor, as the property value is used in configure() + $this->completionOutputs = $completionOutputs + ['bash' => BashCompletionOutput::class, 'fish' => FishCompletionOutput::class, 'zsh' => ZshCompletionOutput::class]; + parent::__construct(); + } + protected function configure() : void + { + $this->addOption('shell', 's', InputOption::VALUE_REQUIRED, 'The shell type ("' . \implode('", "', \array_keys($this->completionOutputs)) . '")')->addOption('input', 'i', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'An array of input tokens (e.g. COMP_WORDS or argv)')->addOption('current', 'c', InputOption::VALUE_REQUIRED, 'The index of the "input" array that the cursor is in (e.g. COMP_CWORD)')->addOption('api-version', 'a', InputOption::VALUE_REQUIRED, 'The API version of the completion script')->addOption('symfony', 'S', InputOption::VALUE_REQUIRED, 'deprecated'); + } + protected function initialize(InputInterface $input, OutputInterface $output) : void + { + $this->isDebug = \filter_var(\getenv('SYMFONY_COMPLETION_DEBUG'), \FILTER_VALIDATE_BOOL); + } + protected function execute(InputInterface $input, OutputInterface $output) : int + { + try { + // "symfony" must be kept for compat with the shell scripts generated by Symfony Console 5.4 - 6.1 + $version = $input->getOption('symfony') ? '1' : $input->getOption('api-version'); + if ($version && \version_compare($version, self::COMPLETION_API_VERSION, '<')) { + $message = \sprintf('Completion script version is not supported ("%s" given, ">=%s" required).', $version, self::COMPLETION_API_VERSION); + $this->log($message); + $output->writeln($message . ' Install the Symfony completion script again by using the "completion" command.'); + return 126; + } + $shell = $input->getOption('shell'); + if (!$shell) { + throw new \RuntimeException('The "--shell" option must be set.'); + } + if (!($completionOutput = $this->completionOutputs[$shell] ?? \false)) { + throw new \RuntimeException(\sprintf('Shell completion is not supported for your shell: "%s" (supported: "%s").', $shell, \implode('", "', \array_keys($this->completionOutputs)))); + } + $completionInput = $this->createCompletionInput($input); + $suggestions = new CompletionSuggestions(); + $this->log(['', '' . \date('Y-m-d H:i:s') . '', 'Input: ("|" indicates the cursor position)', ' ' . (string) $completionInput, 'Command:', ' ' . (string) \implode(' ', $_SERVER['argv']), 'Messages:']); + $command = $this->findCommand($completionInput, $output); + if (null === $command) { + $this->log(' No command found, completing using the Application class.'); + $this->getApplication()->complete($completionInput, $suggestions); + } elseif ($completionInput->mustSuggestArgumentValuesFor('command') && $command->getName() !== $completionInput->getCompletionValue() && !\in_array($completionInput->getCompletionValue(), $command->getAliases(), \true)) { + $this->log(' No command found, completing using the Application class.'); + // expand shortcut names ("cache:cl") into their full name ("cache:clear") + $suggestions->suggestValues(\array_filter(\array_merge([$command->getName()], $command->getAliases()))); + } else { + $command->mergeApplicationDefinition(); + $completionInput->bind($command->getDefinition()); + if (CompletionInput::TYPE_OPTION_NAME === $completionInput->getCompletionType()) { + $this->log(' Completing option names for the ' . \get_class($command instanceof LazyCommand ? $command->getCommand() : $command) . ' command.'); + $suggestions->suggestOptions($command->getDefinition()->getOptions()); + } else { + $this->log([' Completing using the ' . \get_class($command instanceof LazyCommand ? $command->getCommand() : $command) . ' class.', ' Completing ' . $completionInput->getCompletionType() . ' for ' . $completionInput->getCompletionName() . '']); + if (null !== ($compval = $completionInput->getCompletionValue())) { + $this->log(' Current value: ' . $compval . ''); + } + $command->complete($completionInput, $suggestions); + } + } + /** @var CompletionOutputInterface $completionOutput */ + $completionOutput = new $completionOutput(); + $this->log('Suggestions:'); + if ($options = $suggestions->getOptionSuggestions()) { + $this->log(' --' . \implode(' --', \array_map(function ($o) { + return $o->getName(); + }, $options))); + } elseif ($values = $suggestions->getValueSuggestions()) { + $this->log(' ' . \implode(' ', $values)); + } else { + $this->log(' No suggestions were provided'); + } + $completionOutput->write($suggestions, $output); + } catch (\Throwable $e) { + $this->log(['Error!', (string) $e]); + if ($output->isDebug()) { + throw $e; + } + return 2; + } + return 0; + } + private function createCompletionInput(InputInterface $input) : CompletionInput + { + $currentIndex = $input->getOption('current'); + if (!$currentIndex || !\ctype_digit($currentIndex)) { + throw new \RuntimeException('The "--current" option must be set and it must be an integer.'); + } + $completionInput = CompletionInput::fromTokens($input->getOption('input'), (int) $currentIndex); + try { + $completionInput->bind($this->getApplication()->getDefinition()); + } catch (ExceptionInterface $exception) { + } + return $completionInput; + } + private function findCommand(CompletionInput $completionInput, OutputInterface $output) : ?Command + { + try { + $inputName = $completionInput->getFirstArgument(); + if (null === $inputName) { + return null; + } + return $this->getApplication()->find($inputName); + } catch (CommandNotFoundException $exception) { + } + return null; + } + private function log($messages) : void + { + if (!$this->isDebug) { + return; + } + $commandName = \basename($_SERVER['argv'][0]); + \file_put_contents(\sys_get_temp_dir() . '/sf_' . $commandName . '.log', \implode(\PHP_EOL, (array) $messages) . \PHP_EOL, \FILE_APPEND); + } +} diff --git a/vendor/symfony/console/Command/DumpCompletionCommand.php b/vendor/symfony/console/Command/DumpCompletionCommand.php new file mode 100644 index 0000000000..af6046b720 --- /dev/null +++ b/vendor/symfony/console/Command/DumpCompletionCommand.php @@ -0,0 +1,143 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Command; + +use SwissKnife202405\Symfony\Component\Console\Attribute\AsCommand; +use SwissKnife202405\Symfony\Component\Console\Input\InputArgument; +use SwissKnife202405\Symfony\Component\Console\Input\InputInterface; +use SwissKnife202405\Symfony\Component\Console\Input\InputOption; +use SwissKnife202405\Symfony\Component\Console\Output\ConsoleOutputInterface; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +use SwissKnife202405\Symfony\Component\Process\Process; +/** + * Dumps the completion script for the current shell. + * + * @author Wouter de Jong + */ +final class DumpCompletionCommand extends Command +{ + /** + * @deprecated since Symfony 6.1 + */ + protected static $defaultName = 'completion'; + /** + * @deprecated since Symfony 6.1 + */ + protected static $defaultDescription = 'Dump the shell completion script'; + /** + * @var mixed[] + */ + private $supportedShells; + protected function configure() : void + { + $fullCommand = $_SERVER['PHP_SELF']; + $commandName = \basename($fullCommand); + $fullCommand = @\realpath($fullCommand) ?: $fullCommand; + $shell = $this->guessShell(); + switch ($shell) { + case 'fish': + [$rcFile, $completionFile] = ['~/.config/fish/config.fish', "/etc/fish/completions/{$commandName}.fish"]; + break; + case 'zsh': + [$rcFile, $completionFile] = ['~/.zshrc', '$fpath[1]/_' . $commandName]; + break; + default: + [$rcFile, $completionFile] = ['~/.bashrc', "/etc/bash_completion.d/{$commandName}"]; + break; + } + $supportedShells = \implode(', ', $this->getSupportedShells()); + $this->setHelp(<<%command.name% command dumps the shell completion script required +to use shell autocompletion (currently, {$supportedShells} completion are supported). + +Static installation +------------------- + +Dump the script to a global completion file and restart your shell: + + %command.full_name% {$shell} | sudo tee {$completionFile} + +Or dump the script to a local file and source it: + + %command.full_name% {$shell} > completion.sh + + # source the file whenever you use the project + source completion.sh + + # or add this line at the end of your "{$rcFile}" file: + source /path/to/completion.sh + +Dynamic installation +-------------------- + +Add this to the end of your shell configuration file (e.g. "{$rcFile}"): + + eval "\$({$fullCommand} completion {$shell})" +EOH +)->addArgument('shell', InputArgument::OPTIONAL, 'The shell type (e.g. "bash"), the value of the "$SHELL" env var will be used if this is not given', null, \Closure::fromCallable([$this, 'getSupportedShells']))->addOption('debug', null, InputOption::VALUE_NONE, 'Tail the completion debug log'); + } + protected function execute(InputInterface $input, OutputInterface $output) : int + { + $commandName = \basename($_SERVER['argv'][0]); + if ($input->getOption('debug')) { + $this->tailDebugLog($commandName, $output); + return 0; + } + $shell = $input->getArgument('shell') ?? self::guessShell(); + $completionFile = __DIR__ . '/../Resources/completion.' . $shell; + if (!\file_exists($completionFile)) { + $supportedShells = $this->getSupportedShells(); + if ($output instanceof ConsoleOutputInterface) { + $output = $output->getErrorOutput(); + } + if ($shell) { + $output->writeln(\sprintf('Detected shell "%s", which is not supported by Symfony shell completion (supported shells: "%s").', $shell, \implode('", "', $supportedShells))); + } else { + $output->writeln(\sprintf('Shell not detected, Symfony shell completion only supports "%s").', \implode('", "', $supportedShells))); + } + return 2; + } + $output->write(\str_replace(['{{ COMMAND_NAME }}', '{{ VERSION }}'], [$commandName, CompleteCommand::COMPLETION_API_VERSION], \file_get_contents($completionFile))); + return 0; + } + private static function guessShell() : string + { + return \basename($_SERVER['SHELL'] ?? ''); + } + private function tailDebugLog(string $commandName, OutputInterface $output) : void + { + $debugFile = \sys_get_temp_dir() . '/sf_' . $commandName . '.log'; + if (!\file_exists($debugFile)) { + \touch($debugFile); + } + $process = new Process(['tail', '-f', $debugFile], null, null, null, 0); + $process->run(function (string $type, string $line) use($output) : void { + $output->write($line); + }); + } + /** + * @return string[] + */ + private function getSupportedShells() : array + { + if (isset($this->supportedShells)) { + return $this->supportedShells; + } + $shells = []; + foreach (new \DirectoryIterator(__DIR__ . '/../Resources/') as $file) { + if (\strncmp($file->getBasename(), 'completion.', \strlen('completion.')) === 0 && $file->isFile()) { + $shells[] = $file->getExtension(); + } + } + \sort($shells); + return $this->supportedShells = $shells; + } +} diff --git a/vendor/symfony/console/Command/HelpCommand.php b/vendor/symfony/console/Command/HelpCommand.php new file mode 100644 index 0000000000..23e96f33cb --- /dev/null +++ b/vendor/symfony/console/Command/HelpCommand.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Command; + +use SwissKnife202405\Symfony\Component\Console\Descriptor\ApplicationDescription; +use SwissKnife202405\Symfony\Component\Console\Helper\DescriptorHelper; +use SwissKnife202405\Symfony\Component\Console\Input\InputArgument; +use SwissKnife202405\Symfony\Component\Console\Input\InputInterface; +use SwissKnife202405\Symfony\Component\Console\Input\InputOption; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +/** + * HelpCommand displays the help for a given command. + * + * @author Fabien Potencier + */ +class HelpCommand extends Command +{ + /** + * @var \Symfony\Component\Console\Command\Command + */ + private $command; + /** + * @return void + */ + protected function configure() + { + $this->ignoreValidationErrors(); + $this->setName('help')->setDefinition([new InputArgument('command_name', InputArgument::OPTIONAL, 'The command name', 'help', function () { + return \array_keys((new ApplicationDescription($this->getApplication()))->getCommands()); + }), new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt', function () { + return (new DescriptorHelper())->getFormats(); + }), new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command help')])->setDescription('Display help for a command')->setHelp(<<<'EOF' +The %command.name% command displays help for a given command: + + %command.full_name% list + +You can also output the help in other formats by using the --format option: + + %command.full_name% --format=xml list + +To display the list of available commands, please use the list command. +EOF +); + } + /** + * @return void + */ + public function setCommand(Command $command) + { + $this->command = $command; + } + protected function execute(InputInterface $input, OutputInterface $output) : int + { + $this->command = $this->command ?? $this->getApplication()->find($input->getArgument('command_name')); + $helper = new DescriptorHelper(); + $helper->describe($output, $this->command, ['format' => $input->getOption('format'), 'raw_text' => $input->getOption('raw')]); + unset($this->command); + return 0; + } +} diff --git a/vendor/symfony/console/Command/LazyCommand.php b/vendor/symfony/console/Command/LazyCommand.php new file mode 100644 index 0000000000..b1c5a6841a --- /dev/null +++ b/vendor/symfony/console/Command/LazyCommand.php @@ -0,0 +1,188 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Command; + +use SwissKnife202405\Symfony\Component\Console\Application; +use SwissKnife202405\Symfony\Component\Console\Completion\CompletionInput; +use SwissKnife202405\Symfony\Component\Console\Completion\CompletionSuggestions; +use SwissKnife202405\Symfony\Component\Console\Completion\Suggestion; +use SwissKnife202405\Symfony\Component\Console\Helper\HelperInterface; +use SwissKnife202405\Symfony\Component\Console\Helper\HelperSet; +use SwissKnife202405\Symfony\Component\Console\Input\InputDefinition; +use SwissKnife202405\Symfony\Component\Console\Input\InputInterface; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +/** + * @author Nicolas Grekas + */ +final class LazyCommand extends Command +{ + /** + * @var \Closure|\Symfony\Component\Console\Command\Command + */ + private $command; + /** + * @var bool|null + */ + private $isEnabled; + public function __construct(string $name, array $aliases, string $description, bool $isHidden, \Closure $commandFactory, ?bool $isEnabled = \true) + { + $this->setName($name)->setAliases($aliases)->setHidden($isHidden)->setDescription($description); + $this->command = $commandFactory; + $this->isEnabled = $isEnabled; + } + public function ignoreValidationErrors() : void + { + $this->getCommand()->ignoreValidationErrors(); + } + public function setApplication(?Application $application = null) : void + { + if (1 > \func_num_args()) { + trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); + } + if ($this->command instanceof parent) { + $this->command->setApplication($application); + } + parent::setApplication($application); + } + public function setHelperSet(HelperSet $helperSet) : void + { + if ($this->command instanceof parent) { + $this->command->setHelperSet($helperSet); + } + parent::setHelperSet($helperSet); + } + public function isEnabled() : bool + { + return $this->isEnabled ?? $this->getCommand()->isEnabled(); + } + public function run(InputInterface $input, OutputInterface $output) : int + { + return $this->getCommand()->run($input, $output); + } + public function complete(CompletionInput $input, CompletionSuggestions $suggestions) : void + { + $this->getCommand()->complete($input, $suggestions); + } + /** + * @return static + */ + public function setCode(callable $code) + { + $this->getCommand()->setCode($code); + return $this; + } + /** + * @internal + */ + public function mergeApplicationDefinition(bool $mergeArgs = \true) : void + { + $this->getCommand()->mergeApplicationDefinition($mergeArgs); + } + /** + * @param mixed[]|\Symfony\Component\Console\Input\InputDefinition $definition + * @return static + */ + public function setDefinition($definition) + { + $this->getCommand()->setDefinition($definition); + return $this; + } + public function getDefinition() : InputDefinition + { + return $this->getCommand()->getDefinition(); + } + public function getNativeDefinition() : InputDefinition + { + return $this->getCommand()->getNativeDefinition(); + } + /** + * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion + * @param mixed $default + * @return static + */ + public function addArgument(string $name, ?int $mode = null, string $description = '', $default = null) + { + $suggestedValues = 5 <= \func_num_args() ? \func_get_arg(4) : []; + $this->getCommand()->addArgument($name, $mode, $description, $default, $suggestedValues); + return $this; + } + /** + * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion + * @param string|mixed[]|null $shortcut + * @param mixed $default + * @return static + */ + public function addOption(string $name, $shortcut = null, ?int $mode = null, string $description = '', $default = null) + { + $suggestedValues = 6 <= \func_num_args() ? \func_get_arg(5) : []; + $this->getCommand()->addOption($name, $shortcut, $mode, $description, $default, $suggestedValues); + return $this; + } + /** + * @return static + */ + public function setProcessTitle(string $title) + { + $this->getCommand()->setProcessTitle($title); + return $this; + } + /** + * @return static + */ + public function setHelp(string $help) + { + $this->getCommand()->setHelp($help); + return $this; + } + public function getHelp() : string + { + return $this->getCommand()->getHelp(); + } + public function getProcessedHelp() : string + { + return $this->getCommand()->getProcessedHelp(); + } + public function getSynopsis(bool $short = \false) : string + { + return $this->getCommand()->getSynopsis($short); + } + /** + * @return static + */ + public function addUsage(string $usage) + { + $this->getCommand()->addUsage($usage); + return $this; + } + public function getUsages() : array + { + return $this->getCommand()->getUsages(); + } + public function getHelper(string $name) : HelperInterface + { + return $this->getCommand()->getHelper($name); + } + public function getCommand() : parent + { + if (!$this->command instanceof \Closure) { + return $this->command; + } + $command = $this->command = ($this->command)(); + $command->setApplication($this->getApplication()); + if (null !== $this->getHelperSet()) { + $command->setHelperSet($this->getHelperSet()); + } + $command->setName($this->getName())->setAliases($this->getAliases())->setHidden($this->isHidden())->setDescription($this->getDescription()); + // Will throw if the command is not correctly initialized. + $command->getDefinition(); + return $command; + } +} diff --git a/vendor/symfony/console/Command/ListCommand.php b/vendor/symfony/console/Command/ListCommand.php new file mode 100644 index 0000000000..024ff932b3 --- /dev/null +++ b/vendor/symfony/console/Command/ListCommand.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Command; + +use SwissKnife202405\Symfony\Component\Console\Descriptor\ApplicationDescription; +use SwissKnife202405\Symfony\Component\Console\Helper\DescriptorHelper; +use SwissKnife202405\Symfony\Component\Console\Input\InputArgument; +use SwissKnife202405\Symfony\Component\Console\Input\InputInterface; +use SwissKnife202405\Symfony\Component\Console\Input\InputOption; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +/** + * ListCommand displays the list of all available commands for the application. + * + * @author Fabien Potencier + */ +class ListCommand extends Command +{ + /** + * @return void + */ + protected function configure() + { + $this->setName('list')->setDefinition([new InputArgument('namespace', InputArgument::OPTIONAL, 'The namespace name', null, function () { + return \array_keys((new ApplicationDescription($this->getApplication()))->getNamespaces()); + }), new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw command list'), new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt', function () { + return (new DescriptorHelper())->getFormats(); + }), new InputOption('short', null, InputOption::VALUE_NONE, 'To skip describing commands\' arguments')])->setDescription('List commands')->setHelp(<<<'EOF' +The %command.name% command lists all commands: + + %command.full_name% + +You can also display the commands for a specific namespace: + + %command.full_name% test + +You can also output the information in other formats by using the --format option: + + %command.full_name% --format=xml + +It's also possible to get raw list of commands (useful for embedding command runner): + + %command.full_name% --raw +EOF +); + } + protected function execute(InputInterface $input, OutputInterface $output) : int + { + $helper = new DescriptorHelper(); + $helper->describe($output, $this->getApplication(), ['format' => $input->getOption('format'), 'raw_text' => $input->getOption('raw'), 'namespace' => $input->getArgument('namespace'), 'short' => $input->getOption('short')]); + return 0; + } +} diff --git a/vendor/symfony/console/Command/LockableTrait.php b/vendor/symfony/console/Command/LockableTrait.php new file mode 100644 index 0000000000..d0915f03b9 --- /dev/null +++ b/vendor/symfony/console/Command/LockableTrait.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Command; + +use SwissKnife202405\Symfony\Component\Console\Exception\LogicException; +use SwissKnife202405\Symfony\Component\Lock\LockFactory; +use SwissKnife202405\Symfony\Component\Lock\LockInterface; +use SwissKnife202405\Symfony\Component\Lock\Store\FlockStore; +use SwissKnife202405\Symfony\Component\Lock\Store\SemaphoreStore; +/** + * Basic lock feature for commands. + * + * @author Geoffrey Brier + */ +trait LockableTrait +{ + /** + * @var \Symfony\Component\Lock\LockInterface|null + */ + private $lock; + /** + * Locks a command. + */ + private function lock(?string $name = null, bool $blocking = \false) : bool + { + if (!\class_exists(SemaphoreStore::class)) { + throw new LogicException('To enable the locking feature you must install the symfony/lock component. Try running "composer require symfony/lock".'); + } + if (null !== $this->lock) { + throw new LogicException('A lock is already in place.'); + } + if (SemaphoreStore::isSupported()) { + $store = new SemaphoreStore(); + } else { + $store = new FlockStore(); + } + $this->lock = (new LockFactory($store))->createLock($name ?: $this->getName()); + if (!$this->lock->acquire($blocking)) { + $this->lock = null; + return \false; + } + return \true; + } + /** + * Releases the command lock if there is one. + */ + private function release() : void + { + if ($this->lock) { + $this->lock->release(); + $this->lock = null; + } + } +} diff --git a/vendor/symfony/console/Command/SignalableCommandInterface.php b/vendor/symfony/console/Command/SignalableCommandInterface.php new file mode 100644 index 0000000000..a8f45e723d --- /dev/null +++ b/vendor/symfony/console/Command/SignalableCommandInterface.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Command; + +/** + * Interface for command reacting to signal. + * + * @author Grégoire Pineau + */ +interface SignalableCommandInterface +{ + /** + * Returns the list of signals to subscribe. + */ + public function getSubscribedSignals() : array; + /** + * The method will be called when the application is signaled. + * + * @param int|false $previousExitCode + * + * @return int|false The exit code to return or false to continue the normal execution + */ + public function handleSignal(int $signal); +} diff --git a/vendor/symfony/console/Command/TraceableCommand.php b/vendor/symfony/console/Command/TraceableCommand.php new file mode 100644 index 0000000000..3b7b286924 --- /dev/null +++ b/vendor/symfony/console/Command/TraceableCommand.php @@ -0,0 +1,340 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Command; + +use SwissKnife202405\Symfony\Component\Console\Application; +use SwissKnife202405\Symfony\Component\Console\Completion\CompletionInput; +use SwissKnife202405\Symfony\Component\Console\Completion\CompletionSuggestions; +use SwissKnife202405\Symfony\Component\Console\Helper\HelperInterface; +use SwissKnife202405\Symfony\Component\Console\Helper\HelperSet; +use SwissKnife202405\Symfony\Component\Console\Input\InputDefinition; +use SwissKnife202405\Symfony\Component\Console\Input\InputInterface; +use SwissKnife202405\Symfony\Component\Console\Output\ConsoleOutputInterface; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +use SwissKnife202405\Symfony\Component\Stopwatch\Stopwatch; +/** + * @internal + * + * @author Jules Pietri + */ +final class TraceableCommand extends Command implements SignalableCommandInterface +{ + /** + * @readonly + * @var \Symfony\Component\Stopwatch\Stopwatch + */ + private $stopwatch; + /** + * @readonly + * @var \Symfony\Component\Console\Command\Command + */ + public $command; + /** + * @var int + */ + public $exitCode; + /** + * @var int|null + */ + public $interruptedBySignal; + /** + * @var bool + */ + public $ignoreValidation; + /** + * @var bool + */ + public $isInteractive = \false; + /** + * @var string + */ + public $duration = 'n/a'; + /** + * @var string + */ + public $maxMemoryUsage = 'n/a'; + /** + * @var \Symfony\Component\Console\Input\InputInterface + */ + public $input; + /** + * @var \Symfony\Component\Console\Output\OutputInterface + */ + public $output; + /** @var array */ + public $arguments; + /** @var array */ + public $options; + /** @var array */ + public $interactiveInputs = []; + /** + * @var mixed[] + */ + public $handledSignals = []; + public function __construct(Command $command, Stopwatch $stopwatch) + { + $this->stopwatch = $stopwatch; + if ($command instanceof LazyCommand) { + $command = $command->getCommand(); + } + $this->command = $command; + // prevent call to self::getDefaultDescription() + $this->setDescription($command->getDescription()); + parent::__construct($command->getName()); + // init below enables calling {@see parent::run()} + [$code, $processTitle, $ignoreValidationErrors] = \Closure::bind(function () { + return [$this->code, $this->processTitle, $this->ignoreValidationErrors]; + }, $command, Command::class)(); + if (\is_callable($code)) { + $this->setCode($code); + } + if ($processTitle) { + parent::setProcessTitle($processTitle); + } + if ($ignoreValidationErrors) { + parent::ignoreValidationErrors(); + } + $this->ignoreValidation = $ignoreValidationErrors; + } + /** + * @return mixed + */ + public function __call(string $name, array $arguments) + { + return $this->command->{$name}(...$arguments); + } + public function getSubscribedSignals() : array + { + return $this->command instanceof SignalableCommandInterface ? $this->command->getSubscribedSignals() : []; + } + /** + * @param int|false $previousExitCode + * @return int|false + */ + public function handleSignal(int $signal, $previousExitCode = 0) + { + if (!$this->command instanceof SignalableCommandInterface) { + return \false; + } + $event = $this->stopwatch->start($this->getName() . '.handle_signal'); + $exit = $this->command->handleSignal($signal, $previousExitCode); + $event->stop(); + if (!isset($this->handledSignals[$signal])) { + $this->handledSignals[$signal] = ['handled' => 0, 'duration' => 0, 'memory' => 0]; + } + ++$this->handledSignals[$signal]['handled']; + $this->handledSignals[$signal]['duration'] += $event->getDuration(); + $this->handledSignals[$signal]['memory'] = \max($this->handledSignals[$signal]['memory'], $event->getMemory() >> 20); + return $exit; + } + /** + * {@inheritdoc} + * + * Calling parent method is required to be used in {@see parent::run()}. + */ + public function ignoreValidationErrors() : void + { + $this->ignoreValidation = \true; + $this->command->ignoreValidationErrors(); + parent::ignoreValidationErrors(); + } + public function setApplication(?Application $application = null) : void + { + $this->command->setApplication($application); + } + public function getApplication() : ?Application + { + return $this->command->getApplication(); + } + public function setHelperSet(HelperSet $helperSet) : void + { + $this->command->setHelperSet($helperSet); + } + public function getHelperSet() : ?HelperSet + { + return $this->command->getHelperSet(); + } + public function isEnabled() : bool + { + return $this->command->isEnabled(); + } + public function complete(CompletionInput $input, CompletionSuggestions $suggestions) : void + { + $this->command->complete($input, $suggestions); + } + /** + * {@inheritdoc} + * + * Calling parent method is required to be used in {@see parent::run()}. + * @return static + */ + public function setCode(callable $code) + { + $this->command->setCode($code); + return parent::setCode(function (InputInterface $input, OutputInterface $output) use($code) : int { + $event = $this->stopwatch->start($this->getName() . '.code'); + $this->exitCode = $code($input, $output); + $event->stop(); + return $this->exitCode; + }); + } + /** + * @internal + */ + public function mergeApplicationDefinition(bool $mergeArgs = \true) : void + { + $this->command->mergeApplicationDefinition($mergeArgs); + } + /** + * @param mixed[]|\Symfony\Component\Console\Input\InputDefinition $definition + * @return static + */ + public function setDefinition($definition) + { + $this->command->setDefinition($definition); + return $this; + } + public function getDefinition() : InputDefinition + { + return $this->command->getDefinition(); + } + public function getNativeDefinition() : InputDefinition + { + return $this->command->getNativeDefinition(); + } + /** + * @param mixed[]|\Closure $suggestedValues + * @param mixed $default + * @return static + */ + public function addArgument(string $name, ?int $mode = null, string $description = '', $default = null, $suggestedValues = []) + { + $this->command->addArgument($name, $mode, $description, $default, $suggestedValues); + return $this; + } + /** + * @param string|mixed[]|null $shortcut + * @param mixed[]|\Closure $suggestedValues + * @param mixed $default + * @return static + */ + public function addOption(string $name, $shortcut = null, ?int $mode = null, string $description = '', $default = null, $suggestedValues = []) + { + $this->command->addOption($name, $shortcut, $mode, $description, $default, $suggestedValues); + return $this; + } + /** + * {@inheritdoc} + * + * Calling parent method is required to be used in {@see parent::run()}. + * @return static + */ + public function setProcessTitle(string $title) + { + $this->command->setProcessTitle($title); + return parent::setProcessTitle($title); + } + /** + * @return static + */ + public function setHelp(string $help) + { + $this->command->setHelp($help); + return $this; + } + public function getHelp() : string + { + return $this->command->getHelp(); + } + public function getProcessedHelp() : string + { + return $this->command->getProcessedHelp(); + } + public function getSynopsis(bool $short = \false) : string + { + return $this->command->getSynopsis($short); + } + /** + * @return static + */ + public function addUsage(string $usage) + { + $this->command->addUsage($usage); + return $this; + } + public function getUsages() : array + { + return $this->command->getUsages(); + } + public function getHelper(string $name) : HelperInterface + { + return $this->command->getHelper($name); + } + public function run(InputInterface $input, OutputInterface $output) : int + { + $this->input = $input; + $this->output = $output; + $this->arguments = $input->getArguments(); + $this->options = $input->getOptions(); + $event = $this->stopwatch->start($this->getName(), 'command'); + try { + $this->exitCode = parent::run($input, $output); + } finally { + $event->stop(); + if ($output instanceof ConsoleOutputInterface && $output->isDebug()) { + $output->getErrorOutput()->writeln((string) $event); + } + $this->duration = $event->getDuration() . ' ms'; + $this->maxMemoryUsage = ($event->getMemory() >> 20) . ' MiB'; + if ($this->isInteractive) { + $this->extractInteractiveInputs($input->getArguments(), $input->getOptions()); + } + } + return $this->exitCode; + } + protected function initialize(InputInterface $input, OutputInterface $output) : void + { + $event = $this->stopwatch->start($this->getName() . '.init', 'command'); + $this->command->initialize($input, $output); + $event->stop(); + } + protected function interact(InputInterface $input, OutputInterface $output) : void + { + if (!($this->isInteractive = Command::class !== (new \ReflectionMethod($this->command, 'interact'))->getDeclaringClass()->getName())) { + return; + } + $event = $this->stopwatch->start($this->getName() . '.interact', 'command'); + $this->command->interact($input, $output); + $event->stop(); + } + protected function execute(InputInterface $input, OutputInterface $output) : int + { + $event = $this->stopwatch->start($this->getName() . '.execute', 'command'); + $exitCode = $this->command->execute($input, $output); + $event->stop(); + return $exitCode; + } + private function extractInteractiveInputs(array $arguments, array $options) : void + { + foreach ($arguments as $argName => $argValue) { + if (\array_key_exists($argName, $this->arguments) && $this->arguments[$argName] === $argValue) { + continue; + } + $this->interactiveInputs[$argName] = $argValue; + } + foreach ($options as $optName => $optValue) { + if (\array_key_exists($optName, $this->options) && $this->options[$optName] === $optValue) { + continue; + } + $this->interactiveInputs['--' . $optName] = $optValue; + } + } +} diff --git a/vendor/symfony/console/CommandLoader/CommandLoaderInterface.php b/vendor/symfony/console/CommandLoader/CommandLoaderInterface.php new file mode 100644 index 0000000000..b71fd7e3bf --- /dev/null +++ b/vendor/symfony/console/CommandLoader/CommandLoaderInterface.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\CommandLoader; + +use SwissKnife202405\Symfony\Component\Console\Command\Command; +use SwissKnife202405\Symfony\Component\Console\Exception\CommandNotFoundException; +/** + * @author Robin Chalas + */ +interface CommandLoaderInterface +{ + /** + * Loads a command. + * + * @throws CommandNotFoundException + */ + public function get(string $name) : Command; + /** + * Checks if a command exists. + */ + public function has(string $name) : bool; + /** + * @return string[] + */ + public function getNames() : array; +} diff --git a/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php b/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php new file mode 100644 index 0000000000..9d8536489a --- /dev/null +++ b/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\CommandLoader; + +use SwissKnife202405\Psr\Container\ContainerInterface; +use SwissKnife202405\Symfony\Component\Console\Command\Command; +use SwissKnife202405\Symfony\Component\Console\Exception\CommandNotFoundException; +/** + * Loads commands from a PSR-11 container. + * + * @author Robin Chalas + */ +class ContainerCommandLoader implements CommandLoaderInterface +{ + /** + * @var \Psr\Container\ContainerInterface + */ + private $container; + /** + * @var mixed[] + */ + private $commandMap; + /** + * @param array $commandMap An array with command names as keys and service ids as values + */ + public function __construct(ContainerInterface $container, array $commandMap) + { + $this->container = $container; + $this->commandMap = $commandMap; + } + public function get(string $name) : Command + { + if (!$this->has($name)) { + throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name)); + } + return $this->container->get($this->commandMap[$name]); + } + public function has(string $name) : bool + { + return isset($this->commandMap[$name]) && $this->container->has($this->commandMap[$name]); + } + public function getNames() : array + { + return \array_keys($this->commandMap); + } +} diff --git a/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php b/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php new file mode 100644 index 0000000000..98769f14b7 --- /dev/null +++ b/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\CommandLoader; + +use SwissKnife202405\Symfony\Component\Console\Command\Command; +use SwissKnife202405\Symfony\Component\Console\Exception\CommandNotFoundException; +/** + * A simple command loader using factories to instantiate commands lazily. + * + * @author Maxime Steinhausser + */ +class FactoryCommandLoader implements CommandLoaderInterface +{ + /** + * @var mixed[] + */ + private $factories; + /** + * @param callable[] $factories Indexed by command names + */ + public function __construct(array $factories) + { + $this->factories = $factories; + } + public function has(string $name) : bool + { + return isset($this->factories[$name]); + } + public function get(string $name) : Command + { + if (!isset($this->factories[$name])) { + throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name)); + } + $factory = $this->factories[$name]; + return $factory(); + } + public function getNames() : array + { + return \array_keys($this->factories); + } +} diff --git a/vendor/symfony/console/Completion/CompletionInput.php b/vendor/symfony/console/Completion/CompletionInput.php new file mode 100644 index 0000000000..1491236fbd --- /dev/null +++ b/vendor/symfony/console/Completion/CompletionInput.php @@ -0,0 +1,228 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Completion; + +use SwissKnife202405\Symfony\Component\Console\Exception\RuntimeException; +use SwissKnife202405\Symfony\Component\Console\Input\ArgvInput; +use SwissKnife202405\Symfony\Component\Console\Input\InputDefinition; +use SwissKnife202405\Symfony\Component\Console\Input\InputOption; +/** + * An input specialized for shell completion. + * + * This input allows unfinished option names or values and exposes what kind of + * completion is expected. + * + * @author Wouter de Jong + */ +final class CompletionInput extends ArgvInput +{ + public const TYPE_ARGUMENT_VALUE = 'argument_value'; + public const TYPE_OPTION_VALUE = 'option_value'; + public const TYPE_OPTION_NAME = 'option_name'; + public const TYPE_NONE = 'none'; + /** + * @var mixed[] + */ + private $tokens; + /** + * @var int + */ + private $currentIndex; + /** + * @var string + */ + private $completionType; + /** + * @var string|null + */ + private $completionName; + /** + * @var string + */ + private $completionValue = ''; + /** + * Converts a terminal string into tokens. + * + * This is required for shell completions without COMP_WORDS support. + */ + public static function fromString(string $inputStr, int $currentIndex) : self + { + \preg_match_all('/(?<=^|\\s)([\'"]?)(.+?)(?tokens = $tokens; + $input->currentIndex = $currentIndex; + return $input; + } + public function bind(InputDefinition $definition) : void + { + parent::bind($definition); + $relevantToken = $this->getRelevantToken(); + if ('-' === $relevantToken[0]) { + // the current token is an input option: complete either option name or option value + [$optionToken, $optionValue] = \explode('=', $relevantToken, 2) + ['', '']; + $option = $this->getOptionFromToken($optionToken); + if (null === $option && !$this->isCursorFree()) { + $this->completionType = self::TYPE_OPTION_NAME; + $this->completionValue = $relevantToken; + return; + } + if (($nullsafeVariable1 = $option) ? $nullsafeVariable1->acceptValue() : null) { + $this->completionType = self::TYPE_OPTION_VALUE; + $this->completionName = $option->getName(); + $this->completionValue = $optionValue ?: (\strncmp($optionToken, '--', \strlen('--')) !== 0 ? \substr($optionToken, 2) : ''); + return; + } + } + $previousToken = $this->tokens[$this->currentIndex - 1]; + if ('-' === $previousToken[0] && '' !== \trim($previousToken, '-')) { + // check if previous option accepted a value + $previousOption = $this->getOptionFromToken($previousToken); + if (($nullsafeVariable2 = $previousOption) ? $nullsafeVariable2->acceptValue() : null) { + $this->completionType = self::TYPE_OPTION_VALUE; + $this->completionName = $previousOption->getName(); + $this->completionValue = $relevantToken; + return; + } + } + // complete argument value + $this->completionType = self::TYPE_ARGUMENT_VALUE; + foreach ($this->definition->getArguments() as $argumentName => $argument) { + if (!isset($this->arguments[$argumentName])) { + break; + } + $argumentValue = $this->arguments[$argumentName]; + $this->completionName = $argumentName; + if (\is_array($argumentValue)) { + \end($argumentValue); + $this->completionValue = $argumentValue ? $argumentValue[\key($argumentValue)] : null; + \reset($argumentValue); + } else { + $this->completionValue = $argumentValue; + } + } + if ($this->currentIndex >= \count($this->tokens)) { + if (!isset($this->arguments[$argumentName]) || $this->definition->getArgument($argumentName)->isArray()) { + $this->completionName = $argumentName; + $this->completionValue = ''; + } else { + // we've reached the end + $this->completionType = self::TYPE_NONE; + $this->completionName = null; + $this->completionValue = ''; + } + } + } + /** + * Returns the type of completion required. + * + * TYPE_ARGUMENT_VALUE when completing the value of an input argument + * TYPE_OPTION_VALUE when completing the value of an input option + * TYPE_OPTION_NAME when completing the name of an input option + * TYPE_NONE when nothing should be completed + * + * TYPE_OPTION_NAME and TYPE_NONE are already implemented by the Console component. + * + * @return self::TYPE_* + */ + public function getCompletionType() : string + { + return $this->completionType; + } + /** + * The name of the input option or argument when completing a value. + * + * @return string|null returns null when completing an option name + */ + public function getCompletionName() : ?string + { + return $this->completionName; + } + /** + * The value already typed by the user (or empty string). + */ + public function getCompletionValue() : string + { + return $this->completionValue; + } + public function mustSuggestOptionValuesFor(string $optionName) : bool + { + return self::TYPE_OPTION_VALUE === $this->getCompletionType() && $optionName === $this->getCompletionName(); + } + public function mustSuggestArgumentValuesFor(string $argumentName) : bool + { + return self::TYPE_ARGUMENT_VALUE === $this->getCompletionType() && $argumentName === $this->getCompletionName(); + } + protected function parseToken(string $token, bool $parseOptions) : bool + { + try { + return parent::parseToken($token, $parseOptions); + } catch (RuntimeException $exception) { + // suppress errors, completed input is almost never valid + } + return $parseOptions; + } + private function getOptionFromToken(string $optionToken) : ?InputOption + { + $optionName = \ltrim($optionToken, '-'); + if (!$optionName) { + return null; + } + if ('-' === ($optionToken[1] ?? ' ')) { + // long option name + return $this->definition->hasOption($optionName) ? $this->definition->getOption($optionName) : null; + } + // short option name + return $this->definition->hasShortcut($optionName[0]) ? $this->definition->getOptionForShortcut($optionName[0]) : null; + } + /** + * The token of the cursor, or the last token if the cursor is at the end of the input. + */ + private function getRelevantToken() : string + { + return $this->tokens[$this->isCursorFree() ? $this->currentIndex - 1 : $this->currentIndex]; + } + /** + * Whether the cursor is "free" (i.e. at the end of the input preceded by a space). + */ + private function isCursorFree() : bool + { + $nrOfTokens = \count($this->tokens); + if ($this->currentIndex > $nrOfTokens) { + throw new \LogicException('Current index is invalid, it must be the number of input tokens or one more.'); + } + return $this->currentIndex >= $nrOfTokens; + } + public function __toString() : string + { + $str = ''; + foreach ($this->tokens as $i => $token) { + $str .= $token; + if ($this->currentIndex === $i) { + $str .= '|'; + } + $str .= ' '; + } + if ($this->currentIndex > $i) { + $str .= '|'; + } + return \rtrim($str); + } +} diff --git a/vendor/symfony/console/Completion/CompletionSuggestions.php b/vendor/symfony/console/Completion/CompletionSuggestions.php new file mode 100644 index 0000000000..86a0b9caea --- /dev/null +++ b/vendor/symfony/console/Completion/CompletionSuggestions.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Completion; + +use SwissKnife202405\Symfony\Component\Console\Input\InputOption; +/** + * Stores all completion suggestions for the current input. + * + * @author Wouter de Jong + */ +final class CompletionSuggestions +{ + /** + * @var mixed[] + */ + private $valueSuggestions = []; + /** + * @var mixed[] + */ + private $optionSuggestions = []; + /** + * Add a suggested value for an input option or argument. + * + * @return $this + * @param string|\Symfony\Component\Console\Completion\Suggestion $value + */ + public function suggestValue($value) + { + $this->valueSuggestions[] = !$value instanceof Suggestion ? new Suggestion($value) : $value; + return $this; + } + /** + * Add multiple suggested values at once for an input option or argument. + * + * @param list $values + * + * @return $this + */ + public function suggestValues(array $values) + { + foreach ($values as $value) { + $this->suggestValue($value); + } + return $this; + } + /** + * Add a suggestion for an input option name. + * + * @return $this + */ + public function suggestOption(InputOption $option) + { + $this->optionSuggestions[] = $option; + return $this; + } + /** + * Add multiple suggestions for input option names at once. + * + * @param InputOption[] $options + * + * @return $this + */ + public function suggestOptions(array $options) + { + foreach ($options as $option) { + $this->suggestOption($option); + } + return $this; + } + /** + * @return InputOption[] + */ + public function getOptionSuggestions() : array + { + return $this->optionSuggestions; + } + /** + * @return Suggestion[] + */ + public function getValueSuggestions() : array + { + return $this->valueSuggestions; + } +} diff --git a/vendor/symfony/console/Completion/Output/BashCompletionOutput.php b/vendor/symfony/console/Completion/Output/BashCompletionOutput.php new file mode 100644 index 0000000000..0c586e715d --- /dev/null +++ b/vendor/symfony/console/Completion/Output/BashCompletionOutput.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Completion\Output; + +use SwissKnife202405\Symfony\Component\Console\Completion\CompletionSuggestions; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +/** + * @author Wouter de Jong + */ +class BashCompletionOutput implements CompletionOutputInterface +{ + public function write(CompletionSuggestions $suggestions, OutputInterface $output) : void + { + $values = $suggestions->getValueSuggestions(); + foreach ($suggestions->getOptionSuggestions() as $option) { + $values[] = '--' . $option->getName(); + if ($option->isNegatable()) { + $values[] = '--no-' . $option->getName(); + } + } + $output->writeln(\implode("\n", $values)); + } +} diff --git a/vendor/symfony/console/Completion/Output/CompletionOutputInterface.php b/vendor/symfony/console/Completion/Output/CompletionOutputInterface.php new file mode 100644 index 0000000000..1d553aff0e --- /dev/null +++ b/vendor/symfony/console/Completion/Output/CompletionOutputInterface.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Completion\Output; + +use SwissKnife202405\Symfony\Component\Console\Completion\CompletionSuggestions; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +/** + * Transforms the {@see CompletionSuggestions} object into output readable by the shell completion. + * + * @author Wouter de Jong + */ +interface CompletionOutputInterface +{ + public function write(CompletionSuggestions $suggestions, OutputInterface $output) : void; +} diff --git a/vendor/symfony/console/Completion/Output/FishCompletionOutput.php b/vendor/symfony/console/Completion/Output/FishCompletionOutput.php new file mode 100644 index 0000000000..7d232156f1 --- /dev/null +++ b/vendor/symfony/console/Completion/Output/FishCompletionOutput.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Completion\Output; + +use SwissKnife202405\Symfony\Component\Console\Completion\CompletionSuggestions; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +/** + * @author Guillaume Aveline + */ +class FishCompletionOutput implements CompletionOutputInterface +{ + public function write(CompletionSuggestions $suggestions, OutputInterface $output) : void + { + $values = $suggestions->getValueSuggestions(); + foreach ($suggestions->getOptionSuggestions() as $option) { + $values[] = '--' . $option->getName(); + if ($option->isNegatable()) { + $values[] = '--no-' . $option->getName(); + } + } + $output->write(\implode("\n", $values)); + } +} diff --git a/vendor/symfony/console/Completion/Output/ZshCompletionOutput.php b/vendor/symfony/console/Completion/Output/ZshCompletionOutput.php new file mode 100644 index 0000000000..0a45fd150d --- /dev/null +++ b/vendor/symfony/console/Completion/Output/ZshCompletionOutput.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Completion\Output; + +use SwissKnife202405\Symfony\Component\Console\Completion\CompletionSuggestions; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +/** + * @author Jitendra A + */ +class ZshCompletionOutput implements CompletionOutputInterface +{ + public function write(CompletionSuggestions $suggestions, OutputInterface $output) : void + { + $values = []; + foreach ($suggestions->getValueSuggestions() as $value) { + $values[] = $value->getValue() . ($value->getDescription() ? "\t" . $value->getDescription() : ''); + } + foreach ($suggestions->getOptionSuggestions() as $option) { + $values[] = '--' . $option->getName() . ($option->getDescription() ? "\t" . $option->getDescription() : ''); + if ($option->isNegatable()) { + $values[] = '--no-' . $option->getName() . ($option->getDescription() ? "\t" . $option->getDescription() : ''); + } + } + $output->write(\implode("\n", $values) . "\n"); + } +} diff --git a/vendor/symfony/console/Completion/Suggestion.php b/vendor/symfony/console/Completion/Suggestion.php new file mode 100644 index 0000000000..7040009a54 --- /dev/null +++ b/vendor/symfony/console/Completion/Suggestion.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Completion; + +/** + * Represents a single suggested value. + * + * @author Wouter de Jong + */ +class Suggestion +{ + /** + * @readonly + * @var string + */ + private $value; + /** + * @readonly + * @var string + */ + private $description = ''; + public function __construct(string $value, string $description = '') + { + $this->value = $value; + $this->description = $description; + } + public function getValue() : string + { + return $this->value; + } + public function getDescription() : string + { + return $this->description; + } + public function __toString() : string + { + return $this->getValue(); + } +} diff --git a/vendor/symfony/console/ConsoleEvents.php b/vendor/symfony/console/ConsoleEvents.php new file mode 100644 index 0000000000..ec742e5a16 --- /dev/null +++ b/vendor/symfony/console/ConsoleEvents.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console; + +use SwissKnife202405\Symfony\Component\Console\Event\ConsoleCommandEvent; +use SwissKnife202405\Symfony\Component\Console\Event\ConsoleErrorEvent; +use SwissKnife202405\Symfony\Component\Console\Event\ConsoleSignalEvent; +use SwissKnife202405\Symfony\Component\Console\Event\ConsoleTerminateEvent; +/** + * Contains all events dispatched by an Application. + * + * @author Francesco Levorato + */ +final class ConsoleEvents +{ + /** + * The COMMAND event allows you to attach listeners before any command is + * executed by the console. It also allows you to modify the command, input and output + * before they are handed to the command. + * + * @Event("Symfony\Component\Console\Event\ConsoleCommandEvent") + */ + public const COMMAND = 'console.command'; + /** + * The SIGNAL event allows you to perform some actions + * after the command execution was interrupted. + * + * @Event("Symfony\Component\Console\Event\ConsoleSignalEvent") + */ + public const SIGNAL = 'console.signal'; + /** + * The TERMINATE event allows you to attach listeners after a command is + * executed by the console. + * + * @Event("Symfony\Component\Console\Event\ConsoleTerminateEvent") + */ + public const TERMINATE = 'console.terminate'; + /** + * The ERROR event occurs when an uncaught exception or error appears. + * + * This event allows you to deal with the exception/error or + * to modify the thrown exception. + * + * @Event("Symfony\Component\Console\Event\ConsoleErrorEvent") + */ + public const ERROR = 'console.error'; + /** + * Event aliases. + * + * These aliases can be consumed by RegisterListenersPass. + */ + public const ALIASES = [ConsoleCommandEvent::class => self::COMMAND, ConsoleErrorEvent::class => self::ERROR, ConsoleSignalEvent::class => self::SIGNAL, ConsoleTerminateEvent::class => self::TERMINATE]; +} diff --git a/vendor/symfony/console/Cursor.php b/vendor/symfony/console/Cursor.php new file mode 100644 index 0000000000..5fc1c89de2 --- /dev/null +++ b/vendor/symfony/console/Cursor.php @@ -0,0 +1,168 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console; + +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +/** + * @author Pierre du Plessis + */ +final class Cursor +{ + /** + * @var \Symfony\Component\Console\Output\OutputInterface + */ + private $output; + /** @var resource */ + private $input; + /** + * @param resource|null $input + */ + public function __construct(OutputInterface $output, $input = null) + { + $this->output = $output; + $this->input = $input ?? (\defined('STDIN') ? \STDIN : \fopen('php://input', 'r+')); + } + /** + * @return $this + */ + public function moveUp(int $lines = 1) + { + $this->output->write(\sprintf("\x1b[%dA", $lines)); + return $this; + } + /** + * @return $this + */ + public function moveDown(int $lines = 1) + { + $this->output->write(\sprintf("\x1b[%dB", $lines)); + return $this; + } + /** + * @return $this + */ + public function moveRight(int $columns = 1) + { + $this->output->write(\sprintf("\x1b[%dC", $columns)); + return $this; + } + /** + * @return $this + */ + public function moveLeft(int $columns = 1) + { + $this->output->write(\sprintf("\x1b[%dD", $columns)); + return $this; + } + /** + * @return $this + */ + public function moveToColumn(int $column) + { + $this->output->write(\sprintf("\x1b[%dG", $column)); + return $this; + } + /** + * @return $this + */ + public function moveToPosition(int $column, int $row) + { + $this->output->write(\sprintf("\x1b[%d;%dH", $row + 1, $column)); + return $this; + } + /** + * @return $this + */ + public function savePosition() + { + $this->output->write("\x1b7"); + return $this; + } + /** + * @return $this + */ + public function restorePosition() + { + $this->output->write("\x1b8"); + return $this; + } + /** + * @return $this + */ + public function hide() + { + $this->output->write("\x1b[?25l"); + return $this; + } + /** + * @return $this + */ + public function show() + { + $this->output->write("\x1b[?25h\x1b[?0c"); + return $this; + } + /** + * Clears all the output from the current line. + * + * @return $this + */ + public function clearLine() + { + $this->output->write("\x1b[2K"); + return $this; + } + /** + * Clears all the output from the current line after the current position. + */ + public function clearLineAfter() : self + { + $this->output->write("\x1b[K"); + return $this; + } + /** + * Clears all the output from the cursors' current position to the end of the screen. + * + * @return $this + */ + public function clearOutput() + { + $this->output->write("\x1b[0J"); + return $this; + } + /** + * Clears the entire screen. + * + * @return $this + */ + public function clearScreen() + { + $this->output->write("\x1b[2J"); + return $this; + } + /** + * Returns the current cursor position as x,y coordinates. + */ + public function getCurrentPosition() : array + { + static $isTtySupported; + if (!($isTtySupported = $isTtySupported ?? '/' === \DIRECTORY_SEPARATOR && \stream_isatty(\STDOUT))) { + return [1, 1]; + } + $sttyMode = \shell_exec('stty -g'); + \shell_exec('stty -icanon -echo'); + @\fwrite($this->input, "\x1b[6n"); + $code = \trim(\fread($this->input, 1024)); + \shell_exec(\sprintf('stty %s', $sttyMode)); + \sscanf($code, "\x1b[%d;%dR", $row, $col); + return [$col, $row]; + } +} diff --git a/vendor/symfony/console/DataCollector/CommandDataCollector.php b/vendor/symfony/console/DataCollector/CommandDataCollector.php new file mode 100644 index 0000000000..807044ca28 --- /dev/null +++ b/vendor/symfony/console/DataCollector/CommandDataCollector.php @@ -0,0 +1,182 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\DataCollector; + +use SwissKnife202405\Symfony\Component\Console\Command\Command; +use SwissKnife202405\Symfony\Component\Console\Debug\CliRequest; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +use SwissKnife202405\Symfony\Component\Console\SignalRegistry\SignalMap; +use SwissKnife202405\Symfony\Component\HttpFoundation\Request; +use SwissKnife202405\Symfony\Component\HttpFoundation\Response; +use SwissKnife202405\Symfony\Component\HttpKernel\DataCollector\DataCollector; +use SwissKnife202405\Symfony\Component\VarDumper\Cloner\Data; +/** + * @internal + * + * @author Jules Pietri + */ +final class CommandDataCollector extends DataCollector +{ + public function collect(Request $request, Response $response, ?\Throwable $exception = null) : void + { + if (!$request instanceof CliRequest) { + return; + } + $command = $request->command; + $application = $command->getApplication(); + $this->data = ['command' => $this->cloneVar($command->command), 'exit_code' => $command->exitCode, 'interrupted_by_signal' => $command->interruptedBySignal, 'duration' => $command->duration, 'max_memory_usage' => $command->maxMemoryUsage, 'verbosity_level' => (function () use($command) { + switch ($command->output->getVerbosity()) { + case OutputInterface::VERBOSITY_QUIET: + return 'quiet'; + case OutputInterface::VERBOSITY_NORMAL: + return 'normal'; + case OutputInterface::VERBOSITY_VERBOSE: + return 'verbose'; + case OutputInterface::VERBOSITY_VERY_VERBOSE: + return 'very verbose'; + case OutputInterface::VERBOSITY_DEBUG: + return 'debug'; + } + })(), 'interactive' => $command->isInteractive, 'validate_input' => !$command->ignoreValidation, 'enabled' => $command->isEnabled(), 'visible' => !$command->isHidden(), 'input' => $this->cloneVar($command->input), 'output' => $this->cloneVar($command->output), 'interactive_inputs' => \array_map(\Closure::fromCallable([$this, 'cloneVar']), $command->interactiveInputs), 'signalable' => $command->getSubscribedSignals(), 'handled_signals' => $command->handledSignals, 'helper_set' => \array_map(\Closure::fromCallable([$this, 'cloneVar']), \iterator_to_array($command->getHelperSet()))]; + $baseDefinition = $application->getDefinition(); + foreach ($command->arguments as $argName => $argValue) { + if ($baseDefinition->hasArgument($argName)) { + $this->data['application_inputs'][$argName] = $this->cloneVar($argValue); + } else { + $this->data['arguments'][$argName] = $this->cloneVar($argValue); + } + } + foreach ($command->options as $optName => $optValue) { + if ($baseDefinition->hasOption($optName)) { + $this->data['application_inputs']['--' . $optName] = $this->cloneVar($optValue); + } else { + $this->data['options'][$optName] = $this->cloneVar($optValue); + } + } + } + public function getName() : string + { + return 'command'; + } + /** + * @return array{ + * class?: class-string, + * executor?: string, + * file: string, + * line: int, + * } + */ + public function getCommand() : array + { + $class = $this->data['command']->getType(); + $r = new \ReflectionMethod($class, 'execute'); + if (Command::class !== $r->getDeclaringClass()) { + return ['executor' => $class . '::' . $r->name, 'file' => $r->getFileName(), 'line' => $r->getStartLine()]; + } + $r = new \ReflectionClass($class); + return ['class' => $class, 'file' => $r->getFileName(), 'line' => $r->getStartLine()]; + } + public function getInterruptedBySignal() : ?string + { + if (isset($this->data['interrupted_by_signal'])) { + return \sprintf('%s (%d)', SignalMap::getSignalName($this->data['interrupted_by_signal']), $this->data['interrupted_by_signal']); + } + return null; + } + public function getDuration() : string + { + return $this->data['duration']; + } + public function getMaxMemoryUsage() : string + { + return $this->data['max_memory_usage']; + } + public function getVerbosityLevel() : string + { + return $this->data['verbosity_level']; + } + public function getInteractive() : bool + { + return $this->data['interactive']; + } + public function getValidateInput() : bool + { + return $this->data['validate_input']; + } + public function getEnabled() : bool + { + return $this->data['enabled']; + } + public function getVisible() : bool + { + return $this->data['visible']; + } + public function getInput() : Data + { + return $this->data['input']; + } + public function getOutput() : Data + { + return $this->data['output']; + } + /** + * @return Data[] + */ + public function getArguments() : array + { + return $this->data['arguments'] ?? []; + } + /** + * @return Data[] + */ + public function getOptions() : array + { + return $this->data['options'] ?? []; + } + /** + * @return Data[] + */ + public function getApplicationInputs() : array + { + return $this->data['application_inputs'] ?? []; + } + /** + * @return Data[] + */ + public function getInteractiveInputs() : array + { + return $this->data['interactive_inputs'] ?? []; + } + public function getSignalable() : array + { + return \array_map(static function (int $signal) : string { + return \sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal); + }, $this->data['signalable']); + } + public function getHandledSignals() : array + { + $keys = \array_map(static function (int $signal) : string { + return \sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal); + }, \array_keys($this->data['handled_signals'])); + return \array_combine($keys, \array_values($this->data['handled_signals'])); + } + /** + * @return Data[] + */ + public function getHelperSet() : array + { + return $this->data['helper_set'] ?? []; + } + public function reset() : void + { + $this->data = []; + } +} diff --git a/vendor/symfony/console/Debug/CliRequest.php b/vendor/symfony/console/Debug/CliRequest.php new file mode 100644 index 0000000000..2ffc28f9c6 --- /dev/null +++ b/vendor/symfony/console/Debug/CliRequest.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Debug; + +use SwissKnife202405\Symfony\Component\Console\Command\TraceableCommand; +use SwissKnife202405\Symfony\Component\HttpFoundation\Request; +use SwissKnife202405\Symfony\Component\HttpFoundation\Response; +/** + * @internal + */ +final class CliRequest extends Request +{ + /** + * @readonly + * @var \Symfony\Component\Console\Command\TraceableCommand + */ + public $command; + public function __construct(TraceableCommand $command) + { + $this->command = $command; + parent::__construct(attributes: ['_controller' => \get_class($command->command), '_virtual_type' => 'command'], server: $_SERVER); + } + // Methods below allow to populate a profile, thus enable search and filtering + public function getUri() : string + { + if ($this->server->has('SYMFONY_CLI_BINARY_NAME')) { + $binary = $this->server->get('SYMFONY_CLI_BINARY_NAME') . ' console'; + } else { + $binary = $this->server->get('argv')[0]; + } + return $binary . ' ' . $this->command->input; + } + public function getMethod() : string + { + return $this->command->isInteractive ? 'INTERACTIVE' : 'BATCH'; + } + public function getResponse() : Response + { + return new class($this->command->exitCode) extends Response + { + /** + * @readonly + * @var int + */ + private $exitCode; + public function __construct(int $exitCode) + { + $this->exitCode = $exitCode; + parent::__construct(); + } + public function getStatusCode() : int + { + return $this->exitCode; + } + }; + } + public function getClientIp() : string + { + $application = $this->command->getApplication(); + return $application->getName() . ' ' . $application->getVersion(); + } +} diff --git a/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php b/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php new file mode 100644 index 0000000000..577c040381 --- /dev/null +++ b/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php @@ -0,0 +1,107 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\DependencyInjection; + +use SwissKnife202405\Symfony\Component\Console\Command\Command; +use SwissKnife202405\Symfony\Component\Console\Command\LazyCommand; +use SwissKnife202405\Symfony\Component\Console\CommandLoader\ContainerCommandLoader; +use SwissKnife202405\Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; +use SwissKnife202405\Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use SwissKnife202405\Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; +use SwissKnife202405\Symfony\Component\DependencyInjection\ContainerBuilder; +use SwissKnife202405\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use SwissKnife202405\Symfony\Component\DependencyInjection\Reference; +use SwissKnife202405\Symfony\Component\DependencyInjection\TypedReference; +/** + * Registers console commands. + * + * @author Grégoire Pineau + */ +class AddConsoleCommandPass implements CompilerPassInterface +{ + /** + * @return void + */ + public function process(ContainerBuilder $container) + { + $commandServices = $container->findTaggedServiceIds('console.command', \true); + $lazyCommandMap = []; + $lazyCommandRefs = []; + $serviceIds = []; + foreach ($commandServices as $id => $tags) { + $definition = $container->getDefinition($id); + $definition->addTag('container.no_preload'); + $class = $container->getParameterBag()->resolveValue($definition->getClass()); + if (isset($tags[0]['command'])) { + $aliases = $tags[0]['command']; + } else { + if (!($r = $container->getReflectionClass($class))) { + throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); + } + if (!$r->isSubclassOf(Command::class)) { + throw new InvalidArgumentException(\sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, 'console.command', Command::class)); + } + $aliases = \str_replace('%', '%%', $class::getDefaultName() ?? ''); + } + $aliases = \explode('|', $aliases ?? ''); + $commandName = \array_shift($aliases); + if ($isHidden = '' === $commandName) { + $commandName = \array_shift($aliases); + } + if (null === $commandName) { + if (!$definition->isPublic() || $definition->isPrivate() || $definition->hasTag('container.private')) { + $commandId = 'console.command.public_alias.' . $id; + $container->setAlias($commandId, $id)->setPublic(\true); + $id = $commandId; + } + $serviceIds[] = $id; + continue; + } + $description = $tags[0]['description'] ?? null; + unset($tags[0]); + $lazyCommandMap[$commandName] = $id; + $lazyCommandRefs[$id] = new TypedReference($id, $class); + foreach ($aliases as $alias) { + $lazyCommandMap[$alias] = $id; + } + foreach ($tags as $tag) { + if (isset($tag['command'])) { + $aliases[] = $tag['command']; + $lazyCommandMap[$tag['command']] = $id; + } + $description = $description ?? $tag['description'] ?? null; + } + $definition->addMethodCall('setName', [$commandName]); + if ($aliases) { + $definition->addMethodCall('setAliases', [$aliases]); + } + if ($isHidden) { + $definition->addMethodCall('setHidden', [\true]); + } + if (!$description) { + if (!($r = $container->getReflectionClass($class))) { + throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); + } + if (!$r->isSubclassOf(Command::class)) { + throw new InvalidArgumentException(\sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, 'console.command', Command::class)); + } + $description = \str_replace('%', '%%', $class::getDefaultDescription() ?? ''); + } + if ($description) { + $definition->addMethodCall('setDescription', [$description]); + $container->register('.' . $id . '.lazy', LazyCommand::class)->setArguments([$commandName, $aliases, $description, $isHidden, new ServiceClosureArgument($lazyCommandRefs[$id])]); + $lazyCommandRefs[$id] = new Reference('.' . $id . '.lazy'); + } + } + $container->register('console.command_loader', ContainerCommandLoader::class)->setPublic(\true)->addTag('container.no_preload')->setArguments([ServiceLocatorTagPass::register($container, $lazyCommandRefs), $lazyCommandMap]); + $container->setParameter('console.command.ids', $serviceIds); + } +} diff --git a/vendor/symfony/console/Descriptor/ApplicationDescription.php b/vendor/symfony/console/Descriptor/ApplicationDescription.php new file mode 100644 index 0000000000..559cecd7ff --- /dev/null +++ b/vendor/symfony/console/Descriptor/ApplicationDescription.php @@ -0,0 +1,129 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Descriptor; + +use SwissKnife202405\Symfony\Component\Console\Application; +use SwissKnife202405\Symfony\Component\Console\Command\Command; +use SwissKnife202405\Symfony\Component\Console\Exception\CommandNotFoundException; +/** + * @author Jean-François Simon + * + * @internal + */ +class ApplicationDescription +{ + public const GLOBAL_NAMESPACE = '_global'; + /** + * @var \Symfony\Component\Console\Application + */ + private $application; + /** + * @var string|null + */ + private $namespace; + /** + * @var bool + */ + private $showHidden; + /** + * @var mixed[] + */ + private $namespaces; + /** + * @var array + */ + private $commands; + /** + * @var array + */ + private $aliases = []; + public function __construct(Application $application, ?string $namespace = null, bool $showHidden = \false) + { + $this->application = $application; + $this->namespace = $namespace; + $this->showHidden = $showHidden; + } + public function getNamespaces() : array + { + if (!isset($this->namespaces)) { + $this->inspectApplication(); + } + return $this->namespaces; + } + /** + * @return Command[] + */ + public function getCommands() : array + { + if (!isset($this->commands)) { + $this->inspectApplication(); + } + return $this->commands; + } + /** + * @throws CommandNotFoundException + */ + public function getCommand(string $name) : Command + { + if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) { + throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name)); + } + return $this->commands[$name] ?? $this->aliases[$name]; + } + private function inspectApplication() : void + { + $this->commands = []; + $this->namespaces = []; + $all = $this->application->all($this->namespace ? $this->application->findNamespace($this->namespace) : null); + foreach ($this->sortCommands($all) as $namespace => $commands) { + $names = []; + /** @var Command $command */ + foreach ($commands as $name => $command) { + if (!$command->getName() || !$this->showHidden && $command->isHidden()) { + continue; + } + if ($command->getName() === $name) { + $this->commands[$name] = $command; + } else { + $this->aliases[$name] = $command; + } + $names[] = $name; + } + $this->namespaces[$namespace] = ['id' => $namespace, 'commands' => $names]; + } + } + private function sortCommands(array $commands) : array + { + $namespacedCommands = []; + $globalCommands = []; + $sortedCommands = []; + foreach ($commands as $name => $command) { + $key = $this->application->extractNamespace($name, 1); + if (\in_array($key, ['', self::GLOBAL_NAMESPACE], \true)) { + $globalCommands[$name] = $command; + } else { + $namespacedCommands[$key][$name] = $command; + } + } + if ($globalCommands) { + \ksort($globalCommands); + $sortedCommands[self::GLOBAL_NAMESPACE] = $globalCommands; + } + if ($namespacedCommands) { + \ksort($namespacedCommands, \SORT_STRING); + foreach ($namespacedCommands as $key => $commandsSet) { + \ksort($commandsSet); + $sortedCommands[$key] = $commandsSet; + } + } + return $sortedCommands; + } +} diff --git a/vendor/symfony/console/Descriptor/Descriptor.php b/vendor/symfony/console/Descriptor/Descriptor.php new file mode 100644 index 0000000000..35c4014816 --- /dev/null +++ b/vendor/symfony/console/Descriptor/Descriptor.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Descriptor; + +use SwissKnife202405\Symfony\Component\Console\Application; +use SwissKnife202405\Symfony\Component\Console\Command\Command; +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +use SwissKnife202405\Symfony\Component\Console\Input\InputArgument; +use SwissKnife202405\Symfony\Component\Console\Input\InputDefinition; +use SwissKnife202405\Symfony\Component\Console\Input\InputOption; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +/** + * @author Jean-François Simon + * + * @internal + */ +abstract class Descriptor implements DescriptorInterface +{ + /** + * @var \Symfony\Component\Console\Output\OutputInterface + */ + protected $output; + public function describe(OutputInterface $output, object $object, array $options = []) : void + { + $this->output = $output; + switch (\true) { + case $object instanceof InputArgument: + $this->describeInputArgument($object, $options); + break; + case $object instanceof InputOption: + $this->describeInputOption($object, $options); + break; + case $object instanceof InputDefinition: + $this->describeInputDefinition($object, $options); + break; + case $object instanceof Command: + $this->describeCommand($object, $options); + break; + case $object instanceof Application: + $this->describeApplication($object, $options); + break; + default: + throw new InvalidArgumentException(\sprintf('Object of type "%s" is not describable.', \get_debug_type($object))); + } + } + protected function write(string $content, bool $decorated = \false) : void + { + $this->output->write($content, \false, $decorated ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW); + } + /** + * Describes an InputArgument instance. + */ + protected abstract function describeInputArgument(InputArgument $argument, array $options = []) : void; + /** + * Describes an InputOption instance. + */ + protected abstract function describeInputOption(InputOption $option, array $options = []) : void; + /** + * Describes an InputDefinition instance. + */ + protected abstract function describeInputDefinition(InputDefinition $definition, array $options = []) : void; + /** + * Describes a Command instance. + */ + protected abstract function describeCommand(Command $command, array $options = []) : void; + /** + * Describes an Application instance. + */ + protected abstract function describeApplication(Application $application, array $options = []) : void; +} diff --git a/vendor/symfony/console/Descriptor/DescriptorInterface.php b/vendor/symfony/console/Descriptor/DescriptorInterface.php new file mode 100644 index 0000000000..f84fcad89c --- /dev/null +++ b/vendor/symfony/console/Descriptor/DescriptorInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Descriptor; + +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +/** + * Descriptor interface. + * + * @author Jean-François Simon + */ +interface DescriptorInterface +{ + /** + * @return void + */ + public function describe(OutputInterface $output, object $object, array $options = []); +} diff --git a/vendor/symfony/console/Descriptor/JsonDescriptor.php b/vendor/symfony/console/Descriptor/JsonDescriptor.php new file mode 100644 index 0000000000..f7b7c16126 --- /dev/null +++ b/vendor/symfony/console/Descriptor/JsonDescriptor.php @@ -0,0 +1,112 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Descriptor; + +use SwissKnife202405\Symfony\Component\Console\Application; +use SwissKnife202405\Symfony\Component\Console\Command\Command; +use SwissKnife202405\Symfony\Component\Console\Input\InputArgument; +use SwissKnife202405\Symfony\Component\Console\Input\InputDefinition; +use SwissKnife202405\Symfony\Component\Console\Input\InputOption; +/** + * JSON descriptor. + * + * @author Jean-François Simon + * + * @internal + */ +class JsonDescriptor extends Descriptor +{ + protected function describeInputArgument(InputArgument $argument, array $options = []) : void + { + $this->writeData($this->getInputArgumentData($argument), $options); + } + protected function describeInputOption(InputOption $option, array $options = []) : void + { + $this->writeData($this->getInputOptionData($option), $options); + if ($option->isNegatable()) { + $this->writeData($this->getInputOptionData($option, \true), $options); + } + } + protected function describeInputDefinition(InputDefinition $definition, array $options = []) : void + { + $this->writeData($this->getInputDefinitionData($definition), $options); + } + protected function describeCommand(Command $command, array $options = []) : void + { + $this->writeData($this->getCommandData($command, $options['short'] ?? \false), $options); + } + protected function describeApplication(Application $application, array $options = []) : void + { + $describedNamespace = $options['namespace'] ?? null; + $description = new ApplicationDescription($application, $describedNamespace, \true); + $commands = []; + foreach ($description->getCommands() as $command) { + $commands[] = $this->getCommandData($command, $options['short'] ?? \false); + } + $data = []; + if ('UNKNOWN' !== $application->getName()) { + $data['application']['name'] = $application->getName(); + if ('UNKNOWN' !== $application->getVersion()) { + $data['application']['version'] = $application->getVersion(); + } + } + $data['commands'] = $commands; + if ($describedNamespace) { + $data['namespace'] = $describedNamespace; + } else { + $data['namespaces'] = \array_values($description->getNamespaces()); + } + $this->writeData($data, $options); + } + /** + * Writes data as json. + */ + private function writeData(array $data, array $options) : void + { + $flags = $options['json_encoding'] ?? 0; + $this->write(\json_encode($data, $flags)); + } + private function getInputArgumentData(InputArgument $argument) : array + { + return ['name' => $argument->getName(), 'is_required' => $argument->isRequired(), 'is_array' => $argument->isArray(), 'description' => \preg_replace('/\\s*[\\r\\n]\\s*/', ' ', $argument->getDescription()), 'default' => \INF === $argument->getDefault() ? 'INF' : $argument->getDefault()]; + } + private function getInputOptionData(InputOption $option, bool $negated = \false) : array + { + return $negated ? ['name' => '--no-' . $option->getName(), 'shortcut' => '', 'accept_value' => \false, 'is_value_required' => \false, 'is_multiple' => \false, 'description' => 'Negate the "--' . $option->getName() . '" option', 'default' => \false] : ['name' => '--' . $option->getName(), 'shortcut' => $option->getShortcut() ? '-' . \str_replace('|', '|-', $option->getShortcut()) : '', 'accept_value' => $option->acceptValue(), 'is_value_required' => $option->isValueRequired(), 'is_multiple' => $option->isArray(), 'description' => \preg_replace('/\\s*[\\r\\n]\\s*/', ' ', $option->getDescription()), 'default' => \INF === $option->getDefault() ? 'INF' : $option->getDefault()]; + } + private function getInputDefinitionData(InputDefinition $definition) : array + { + $inputArguments = []; + foreach ($definition->getArguments() as $name => $argument) { + $inputArguments[$name] = $this->getInputArgumentData($argument); + } + $inputOptions = []; + foreach ($definition->getOptions() as $name => $option) { + $inputOptions[$name] = $this->getInputOptionData($option); + if ($option->isNegatable()) { + $inputOptions['no-' . $name] = $this->getInputOptionData($option, \true); + } + } + return ['arguments' => $inputArguments, 'options' => $inputOptions]; + } + private function getCommandData(Command $command, bool $short = \false) : array + { + $data = ['name' => $command->getName(), 'description' => $command->getDescription()]; + if ($short) { + $data += ['usage' => $command->getAliases()]; + } else { + $command->mergeApplicationDefinition(\false); + $data += ['usage' => \array_merge([$command->getSynopsis()], $command->getUsages(), $command->getAliases()), 'help' => $command->getProcessedHelp(), 'definition' => $this->getInputDefinitionData($command->getDefinition())]; + } + $data['hidden'] = $command->isHidden(); + return $data; + } +} diff --git a/vendor/symfony/console/Descriptor/MarkdownDescriptor.php b/vendor/symfony/console/Descriptor/MarkdownDescriptor.php new file mode 100644 index 0000000000..a666ffe738 --- /dev/null +++ b/vendor/symfony/console/Descriptor/MarkdownDescriptor.php @@ -0,0 +1,128 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Descriptor; + +use SwissKnife202405\Symfony\Component\Console\Application; +use SwissKnife202405\Symfony\Component\Console\Command\Command; +use SwissKnife202405\Symfony\Component\Console\Helper\Helper; +use SwissKnife202405\Symfony\Component\Console\Input\InputArgument; +use SwissKnife202405\Symfony\Component\Console\Input\InputDefinition; +use SwissKnife202405\Symfony\Component\Console\Input\InputOption; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +/** + * Markdown descriptor. + * + * @author Jean-François Simon + * + * @internal + */ +class MarkdownDescriptor extends Descriptor +{ + public function describe(OutputInterface $output, object $object, array $options = []) : void + { + $decorated = $output->isDecorated(); + $output->setDecorated(\false); + parent::describe($output, $object, $options); + $output->setDecorated($decorated); + } + protected function write(string $content, bool $decorated = \true) : void + { + parent::write($content, $decorated); + } + protected function describeInputArgument(InputArgument $argument, array $options = []) : void + { + $this->write('#### `' . ($argument->getName() ?: '') . "`\n\n" . ($argument->getDescription() ? \preg_replace('/\\s*[\\r\\n]\\s*/', "\n", $argument->getDescription()) . "\n\n" : '') . '* Is required: ' . ($argument->isRequired() ? 'yes' : 'no') . "\n" . '* Is array: ' . ($argument->isArray() ? 'yes' : 'no') . "\n" . '* Default: `' . \str_replace("\n", '', \var_export($argument->getDefault(), \true)) . '`'); + } + protected function describeInputOption(InputOption $option, array $options = []) : void + { + $name = '--' . $option->getName(); + if ($option->isNegatable()) { + $name .= '|--no-' . $option->getName(); + } + if ($option->getShortcut()) { + $name .= '|-' . \str_replace('|', '|-', $option->getShortcut()) . ''; + } + $this->write('#### `' . $name . '`' . "\n\n" . ($option->getDescription() ? \preg_replace('/\\s*[\\r\\n]\\s*/', "\n", $option->getDescription()) . "\n\n" : '') . '* Accept value: ' . ($option->acceptValue() ? 'yes' : 'no') . "\n" . '* Is value required: ' . ($option->isValueRequired() ? 'yes' : 'no') . "\n" . '* Is multiple: ' . ($option->isArray() ? 'yes' : 'no') . "\n" . '* Is negatable: ' . ($option->isNegatable() ? 'yes' : 'no') . "\n" . '* Default: `' . \str_replace("\n", '', \var_export($option->getDefault(), \true)) . '`'); + } + protected function describeInputDefinition(InputDefinition $definition, array $options = []) : void + { + if ($showArguments = \count($definition->getArguments()) > 0) { + $this->write('### Arguments'); + foreach ($definition->getArguments() as $argument) { + $this->write("\n\n"); + $this->describeInputArgument($argument); + } + } + if (\count($definition->getOptions()) > 0) { + if ($showArguments) { + $this->write("\n\n"); + } + $this->write('### Options'); + foreach ($definition->getOptions() as $option) { + $this->write("\n\n"); + $this->describeInputOption($option); + } + } + } + protected function describeCommand(Command $command, array $options = []) : void + { + if ($options['short'] ?? \false) { + $this->write('`' . $command->getName() . "`\n" . \str_repeat('-', Helper::width($command->getName()) + 2) . "\n\n" . ($command->getDescription() ? $command->getDescription() . "\n\n" : '') . '### Usage' . "\n\n" . \array_reduce($command->getAliases(), function ($carry, $usage) { + return $carry . '* `' . $usage . '`' . "\n"; + })); + return; + } + $command->mergeApplicationDefinition(\false); + $this->write('`' . $command->getName() . "`\n" . \str_repeat('-', Helper::width($command->getName()) + 2) . "\n\n" . ($command->getDescription() ? $command->getDescription() . "\n\n" : '') . '### Usage' . "\n\n" . \array_reduce(\array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), function ($carry, $usage) { + return $carry . '* `' . $usage . '`' . "\n"; + })); + if ($help = $command->getProcessedHelp()) { + $this->write("\n"); + $this->write($help); + } + $definition = $command->getDefinition(); + if ($definition->getOptions() || $definition->getArguments()) { + $this->write("\n\n"); + $this->describeInputDefinition($definition); + } + } + protected function describeApplication(Application $application, array $options = []) : void + { + $describedNamespace = $options['namespace'] ?? null; + $description = new ApplicationDescription($application, $describedNamespace); + $title = $this->getApplicationTitle($application); + $this->write($title . "\n" . \str_repeat('=', Helper::width($title))); + foreach ($description->getNamespaces() as $namespace) { + if (ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) { + $this->write("\n\n"); + $this->write('**' . $namespace['id'] . ':**'); + } + $this->write("\n\n"); + $this->write(\implode("\n", \array_map(function ($commandName) use($description) { + return \sprintf('* [`%s`](#%s)', $commandName, \str_replace(':', '', $description->getCommand($commandName)->getName())); + }, $namespace['commands']))); + } + foreach ($description->getCommands() as $command) { + $this->write("\n\n"); + $this->describeCommand($command, $options); + } + } + private function getApplicationTitle(Application $application) : string + { + if ('UNKNOWN' !== $application->getName()) { + if ('UNKNOWN' !== $application->getVersion()) { + return \sprintf('%s %s', $application->getName(), $application->getVersion()); + } + return $application->getName(); + } + return 'Console Tool'; + } +} diff --git a/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php b/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php new file mode 100644 index 0000000000..3528daa7fe --- /dev/null +++ b/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php @@ -0,0 +1,234 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Descriptor; + +use SwissKnife202405\Symfony\Component\Console\Application; +use SwissKnife202405\Symfony\Component\Console\Command\Command; +use SwissKnife202405\Symfony\Component\Console\Helper\Helper; +use SwissKnife202405\Symfony\Component\Console\Input\InputArgument; +use SwissKnife202405\Symfony\Component\Console\Input\InputDefinition; +use SwissKnife202405\Symfony\Component\Console\Input\InputOption; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +use SwissKnife202405\Symfony\Component\String\UnicodeString; +class ReStructuredTextDescriptor extends Descriptor +{ + //

+ /** + * @var string + */ + private $partChar = '='; + //

+ /** + * @var string + */ + private $chapterChar = '-'; + //

+ /** + * @var string + */ + private $sectionChar = '~'; + //

+ /** + * @var string + */ + private $subsectionChar = '.'; + //

+ /** + * @var string + */ + private $subsubsectionChar = '^'; + //
+ /** + * @var string + */ + private $paragraphsChar = '"'; + /** + * @var mixed[] + */ + private $visibleNamespaces = []; + public function describe(OutputInterface $output, object $object, array $options = []) : void + { + $decorated = $output->isDecorated(); + $output->setDecorated(\false); + parent::describe($output, $object, $options); + $output->setDecorated($decorated); + } + /** + * Override parent method to set $decorated = true. + */ + protected function write(string $content, bool $decorated = \true) : void + { + parent::write($content, $decorated); + } + protected function describeInputArgument(InputArgument $argument, array $options = []) : void + { + $this->write($argument->getName() ?: '' . "\n" . \str_repeat($this->paragraphsChar, Helper::width($argument->getName())) . "\n\n" . ($argument->getDescription() ? \preg_replace('/\\s*[\\r\\n]\\s*/', "\n", $argument->getDescription()) . "\n\n" : '') . '- **Is required**: ' . ($argument->isRequired() ? 'yes' : 'no') . "\n" . '- **Is array**: ' . ($argument->isArray() ? 'yes' : 'no') . "\n" . '- **Default**: ``' . \str_replace("\n", '', \var_export($argument->getDefault(), \true)) . '``'); + } + protected function describeInputOption(InputOption $option, array $options = []) : void + { + $name = '\\-\\-' . $option->getName(); + if ($option->isNegatable()) { + $name .= '|\\-\\-no-' . $option->getName(); + } + if ($option->getShortcut()) { + $name .= '|-' . \str_replace('|', '|-', $option->getShortcut()); + } + $optionDescription = $option->getDescription() ? \preg_replace('/\\s*[\\r\\n]\\s*/', "\n\n", $option->getDescription()) . "\n\n" : ''; + $optionDescription = (new UnicodeString($optionDescription))->ascii(); + $this->write($name . "\n" . \str_repeat($this->paragraphsChar, Helper::width($name)) . "\n\n" . $optionDescription . '- **Accept value**: ' . ($option->acceptValue() ? 'yes' : 'no') . "\n" . '- **Is value required**: ' . ($option->isValueRequired() ? 'yes' : 'no') . "\n" . '- **Is multiple**: ' . ($option->isArray() ? 'yes' : 'no') . "\n" . '- **Is negatable**: ' . ($option->isNegatable() ? 'yes' : 'no') . "\n" . '- **Default**: ``' . \str_replace("\n", '', \var_export($option->getDefault(), \true)) . '``' . "\n"); + } + protected function describeInputDefinition(InputDefinition $definition, array $options = []) : void + { + if ($showArguments = (bool) $definition->getArguments()) { + $this->write("Arguments\n" . \str_repeat($this->subsubsectionChar, 9)) . "\n\n"; + foreach ($definition->getArguments() as $argument) { + $this->write("\n\n"); + $this->describeInputArgument($argument); + } + } + if ($nonDefaultOptions = $this->getNonDefaultOptions($definition)) { + if ($showArguments) { + $this->write("\n\n"); + } + $this->write("Options\n" . \str_repeat($this->subsubsectionChar, 7) . "\n\n"); + foreach ($nonDefaultOptions as $option) { + $this->describeInputOption($option); + $this->write("\n"); + } + } + } + protected function describeCommand(Command $command, array $options = []) : void + { + if ($options['short'] ?? \false) { + $this->write('``' . $command->getName() . "``\n" . \str_repeat($this->subsectionChar, Helper::width($command->getName())) . "\n\n" . ($command->getDescription() ? $command->getDescription() . "\n\n" : '') . "Usage\n" . \str_repeat($this->paragraphsChar, 5) . "\n\n" . \array_reduce($command->getAliases(), static function ($carry, $usage) { + return $carry . '- ``' . $usage . '``' . "\n"; + })); + return; + } + $command->mergeApplicationDefinition(\false); + foreach ($command->getAliases() as $alias) { + $this->write('.. _' . $alias . ":\n\n"); + } + $this->write($command->getName() . "\n" . \str_repeat($this->subsectionChar, Helper::width($command->getName())) . "\n\n" . ($command->getDescription() ? $command->getDescription() . "\n\n" : '') . "Usage\n" . \str_repeat($this->subsubsectionChar, 5) . "\n\n" . \array_reduce(\array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()), static function ($carry, $usage) { + return $carry . '- ``' . $usage . '``' . "\n"; + })); + if ($help = $command->getProcessedHelp()) { + $this->write("\n"); + $this->write($help); + } + $definition = $command->getDefinition(); + if ($definition->getOptions() || $definition->getArguments()) { + $this->write("\n\n"); + $this->describeInputDefinition($definition); + } + } + protected function describeApplication(Application $application, array $options = []) : void + { + $description = new ApplicationDescription($application, $options['namespace'] ?? null); + $title = $this->getApplicationTitle($application); + $this->write($title . "\n" . \str_repeat($this->partChar, Helper::width($title))); + $this->createTableOfContents($description, $application); + $this->describeCommands($application, $options); + } + private function getApplicationTitle(Application $application) : string + { + if ('UNKNOWN' === $application->getName()) { + return 'Console Tool'; + } + if ('UNKNOWN' !== $application->getVersion()) { + return \sprintf('%s %s', $application->getName(), $application->getVersion()); + } + return $application->getName(); + } + private function describeCommands($application, array $options) : void + { + $title = 'Commands'; + $this->write("\n\n{$title}\n" . \str_repeat($this->chapterChar, Helper::width($title)) . "\n\n"); + foreach ($this->visibleNamespaces as $namespace) { + if ('_global' === $namespace) { + $commands = $application->all(''); + $this->write('Global' . "\n" . \str_repeat($this->sectionChar, Helper::width('Global')) . "\n\n"); + } else { + $commands = $application->all($namespace); + $this->write($namespace . "\n" . \str_repeat($this->sectionChar, Helper::width($namespace)) . "\n\n"); + } + foreach ($this->removeAliasesAndHiddenCommands($commands) as $command) { + $this->describeCommand($command, $options); + $this->write("\n\n"); + } + } + } + private function createTableOfContents(ApplicationDescription $description, Application $application) : void + { + $this->setVisibleNamespaces($description); + $chapterTitle = 'Table of Contents'; + $this->write("\n\n{$chapterTitle}\n" . \str_repeat($this->chapterChar, Helper::width($chapterTitle)) . "\n\n"); + foreach ($this->visibleNamespaces as $namespace) { + if ('_global' === $namespace) { + $commands = $application->all(''); + } else { + $commands = $application->all($namespace); + $this->write("\n\n"); + $this->write($namespace . "\n" . \str_repeat($this->sectionChar, Helper::width($namespace)) . "\n\n"); + } + $commands = $this->removeAliasesAndHiddenCommands($commands); + $this->write("\n\n"); + $this->write(\implode("\n", \array_map(static function ($commandName) { + return \sprintf('- `%s`_', $commandName); + }, \array_keys($commands)))); + } + } + private function getNonDefaultOptions(InputDefinition $definition) : array + { + $globalOptions = ['help', 'quiet', 'verbose', 'version', 'ansi', 'no-interaction']; + $nonDefaultOptions = []; + foreach ($definition->getOptions() as $option) { + // Skip global options. + if (!\in_array($option->getName(), $globalOptions)) { + $nonDefaultOptions[] = $option; + } + } + return $nonDefaultOptions; + } + private function setVisibleNamespaces(ApplicationDescription $description) : void + { + $commands = $description->getCommands(); + foreach ($description->getNamespaces() as $namespace) { + try { + $namespaceCommands = $namespace['commands']; + foreach ($namespaceCommands as $key => $commandName) { + if (!\array_key_exists($commandName, $commands)) { + // If the array key does not exist, then this is an alias. + unset($namespaceCommands[$key]); + } elseif ($commands[$commandName]->isHidden()) { + unset($namespaceCommands[$key]); + } + } + if (!$namespaceCommands) { + // If the namespace contained only aliases or hidden commands, skip the namespace. + continue; + } + } catch (\Exception $exception) { + } + $this->visibleNamespaces[] = $namespace['id']; + } + } + private function removeAliasesAndHiddenCommands(array $commands) : array + { + foreach ($commands as $key => $command) { + if ($command->isHidden() || \in_array($key, $command->getAliases(), \true)) { + unset($commands[$key]); + } + } + unset($commands['completion']); + return $commands; + } +} diff --git a/vendor/symfony/console/Descriptor/TextDescriptor.php b/vendor/symfony/console/Descriptor/TextDescriptor.php new file mode 100644 index 0000000000..4f0d4f8984 --- /dev/null +++ b/vendor/symfony/console/Descriptor/TextDescriptor.php @@ -0,0 +1,274 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Descriptor; + +use SwissKnife202405\Symfony\Component\Console\Application; +use SwissKnife202405\Symfony\Component\Console\Command\Command; +use SwissKnife202405\Symfony\Component\Console\Formatter\OutputFormatter; +use SwissKnife202405\Symfony\Component\Console\Helper\Helper; +use SwissKnife202405\Symfony\Component\Console\Input\InputArgument; +use SwissKnife202405\Symfony\Component\Console\Input\InputDefinition; +use SwissKnife202405\Symfony\Component\Console\Input\InputOption; +/** + * Text descriptor. + * + * @author Jean-François Simon + * + * @internal + */ +class TextDescriptor extends Descriptor +{ + protected function describeInputArgument(InputArgument $argument, array $options = []) : void + { + if (null !== $argument->getDefault() && (!\is_array($argument->getDefault()) || \count($argument->getDefault()))) { + $default = \sprintf(' [default: %s]', $this->formatDefaultValue($argument->getDefault())); + } else { + $default = ''; + } + $totalWidth = $options['total_width'] ?? Helper::width($argument->getName()); + $spacingWidth = $totalWidth - \strlen($argument->getName()); + $this->writeText(\sprintf( + ' %s %s%s%s', + $argument->getName(), + \str_repeat(' ', $spacingWidth), + // + 4 = 2 spaces before , 2 spaces after + \preg_replace('/\\s*[\\r\\n]\\s*/', "\n" . \str_repeat(' ', $totalWidth + 4), $argument->getDescription()), + $default + ), $options); + } + protected function describeInputOption(InputOption $option, array $options = []) : void + { + if ($option->acceptValue() && null !== $option->getDefault() && (!\is_array($option->getDefault()) || \count($option->getDefault()))) { + $default = \sprintf(' [default: %s]', $this->formatDefaultValue($option->getDefault())); + } else { + $default = ''; + } + $value = ''; + if ($option->acceptValue()) { + $value = '=' . \strtoupper($option->getName()); + if ($option->isValueOptional()) { + $value = '[' . $value . ']'; + } + } + $totalWidth = $options['total_width'] ?? $this->calculateTotalWidthForOptions([$option]); + $synopsis = \sprintf('%s%s', $option->getShortcut() ? \sprintf('-%s, ', $option->getShortcut()) : ' ', \sprintf($option->isNegatable() ? '--%1$s|--no-%1$s' : '--%1$s%2$s', $option->getName(), $value)); + $spacingWidth = $totalWidth - Helper::width($synopsis); + $this->writeText(\sprintf( + ' %s %s%s%s%s', + $synopsis, + \str_repeat(' ', $spacingWidth), + // + 4 = 2 spaces before , 2 spaces after + \preg_replace('/\\s*[\\r\\n]\\s*/', "\n" . \str_repeat(' ', $totalWidth + 4), $option->getDescription()), + $default, + $option->isArray() ? ' (multiple values allowed)' : '' + ), $options); + } + protected function describeInputDefinition(InputDefinition $definition, array $options = []) : void + { + $totalWidth = $this->calculateTotalWidthForOptions($definition->getOptions()); + foreach ($definition->getArguments() as $argument) { + $totalWidth = \max($totalWidth, Helper::width($argument->getName())); + } + if ($definition->getArguments()) { + $this->writeText('Arguments:', $options); + $this->writeText("\n"); + foreach ($definition->getArguments() as $argument) { + $this->describeInputArgument($argument, \array_merge($options, ['total_width' => $totalWidth])); + $this->writeText("\n"); + } + } + if ($definition->getArguments() && $definition->getOptions()) { + $this->writeText("\n"); + } + if ($definition->getOptions()) { + $laterOptions = []; + $this->writeText('Options:', $options); + foreach ($definition->getOptions() as $option) { + if (\strlen($option->getShortcut() ?? '') > 1) { + $laterOptions[] = $option; + continue; + } + $this->writeText("\n"); + $this->describeInputOption($option, \array_merge($options, ['total_width' => $totalWidth])); + } + foreach ($laterOptions as $option) { + $this->writeText("\n"); + $this->describeInputOption($option, \array_merge($options, ['total_width' => $totalWidth])); + } + } + } + protected function describeCommand(Command $command, array $options = []) : void + { + $command->mergeApplicationDefinition(\false); + if ($description = $command->getDescription()) { + $this->writeText('Description:', $options); + $this->writeText("\n"); + $this->writeText(' ' . $description); + $this->writeText("\n\n"); + } + $this->writeText('Usage:', $options); + foreach (\array_merge([$command->getSynopsis(\true)], $command->getAliases(), $command->getUsages()) as $usage) { + $this->writeText("\n"); + $this->writeText(' ' . OutputFormatter::escape($usage), $options); + } + $this->writeText("\n"); + $definition = $command->getDefinition(); + if ($definition->getOptions() || $definition->getArguments()) { + $this->writeText("\n"); + $this->describeInputDefinition($definition, $options); + $this->writeText("\n"); + } + $help = $command->getProcessedHelp(); + if ($help && $help !== $description) { + $this->writeText("\n"); + $this->writeText('Help:', $options); + $this->writeText("\n"); + $this->writeText(' ' . \str_replace("\n", "\n ", $help), $options); + $this->writeText("\n"); + } + } + protected function describeApplication(Application $application, array $options = []) : void + { + $describedNamespace = $options['namespace'] ?? null; + $description = new ApplicationDescription($application, $describedNamespace); + if (isset($options['raw_text']) && $options['raw_text']) { + $width = $this->getColumnWidth($description->getCommands()); + foreach ($description->getCommands() as $command) { + $this->writeText(\sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options); + $this->writeText("\n"); + } + } else { + if ('' != ($help = $application->getHelp())) { + $this->writeText("{$help}\n\n", $options); + } + $this->writeText("Usage:\n", $options); + $this->writeText(" command [options] [arguments]\n\n", $options); + $this->describeInputDefinition(new InputDefinition($application->getDefinition()->getOptions()), $options); + $this->writeText("\n"); + $this->writeText("\n"); + $commands = $description->getCommands(); + $namespaces = $description->getNamespaces(); + if ($describedNamespace && $namespaces) { + // make sure all alias commands are included when describing a specific namespace + $describedNamespaceInfo = \reset($namespaces); + foreach ($describedNamespaceInfo['commands'] as $name) { + $commands[$name] = $description->getCommand($name); + } + } + // calculate max. width based on available commands per namespace + $width = $this->getColumnWidth(\array_merge(...\array_values(\array_map(function ($namespace) use($commands) { + return \array_intersect($namespace['commands'], \array_keys($commands)); + }, \array_values($namespaces))))); + if ($describedNamespace) { + $this->writeText(\sprintf('Available commands for the "%s" namespace:', $describedNamespace), $options); + } else { + $this->writeText('Available commands:', $options); + } + foreach ($namespaces as $namespace) { + $namespace['commands'] = \array_filter($namespace['commands'], function ($name) use($commands) { + return isset($commands[$name]); + }); + if (!$namespace['commands']) { + continue; + } + if (!$describedNamespace && ApplicationDescription::GLOBAL_NAMESPACE !== $namespace['id']) { + $this->writeText("\n"); + $this->writeText(' ' . $namespace['id'] . '', $options); + } + foreach ($namespace['commands'] as $name) { + $this->writeText("\n"); + $spacingWidth = $width - Helper::width($name); + $command = $commands[$name]; + $commandAliases = $name === $command->getName() ? $this->getCommandAliasesText($command) : ''; + $this->writeText(\sprintf(' %s%s%s', $name, \str_repeat(' ', $spacingWidth), $commandAliases . $command->getDescription()), $options); + } + } + $this->writeText("\n"); + } + } + private function writeText(string $content, array $options = []) : void + { + $this->write(isset($options['raw_text']) && $options['raw_text'] ? \strip_tags($content) : $content, isset($options['raw_output']) ? !$options['raw_output'] : \true); + } + /** + * Formats command aliases to show them in the command description. + */ + private function getCommandAliasesText(Command $command) : string + { + $text = ''; + $aliases = $command->getAliases(); + if ($aliases) { + $text = '[' . \implode('|', $aliases) . '] '; + } + return $text; + } + /** + * Formats input option/argument default value. + * @param mixed $default + */ + private function formatDefaultValue($default) : string + { + if (\INF === $default) { + return 'INF'; + } + if (\is_string($default)) { + $default = OutputFormatter::escape($default); + } elseif (\is_array($default)) { + foreach ($default as $key => $value) { + if (\is_string($value)) { + $default[$key] = OutputFormatter::escape($value); + } + } + } + return \str_replace('\\\\', '\\', \json_encode($default, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE)); + } + /** + * @param array $commands + */ + private function getColumnWidth(array $commands) : int + { + $widths = []; + foreach ($commands as $command) { + if ($command instanceof Command) { + $widths[] = Helper::width($command->getName()); + foreach ($command->getAliases() as $alias) { + $widths[] = Helper::width($alias); + } + } else { + $widths[] = Helper::width($command); + } + } + return $widths ? \max($widths) + 2 : 0; + } + /** + * @param InputOption[] $options + */ + private function calculateTotalWidthForOptions(array $options) : int + { + $totalWidth = 0; + foreach ($options as $option) { + // "-" + shortcut + ", --" + name + $nameLength = 1 + \max(Helper::width($option->getShortcut()), 1) + 4 + Helper::width($option->getName()); + if ($option->isNegatable()) { + $nameLength += 6 + Helper::width($option->getName()); + // |--no- + name + } elseif ($option->acceptValue()) { + $valueLength = 1 + Helper::width($option->getName()); + // = + value + $valueLength += $option->isValueOptional() ? 2 : 0; + // [ + ] + $nameLength += $valueLength; + } + $totalWidth = \max($totalWidth, $nameLength); + } + return $totalWidth; + } +} diff --git a/vendor/symfony/console/Descriptor/XmlDescriptor.php b/vendor/symfony/console/Descriptor/XmlDescriptor.php new file mode 100644 index 0000000000..d26c14fa26 --- /dev/null +++ b/vendor/symfony/console/Descriptor/XmlDescriptor.php @@ -0,0 +1,191 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Descriptor; + +use SwissKnife202405\Symfony\Component\Console\Application; +use SwissKnife202405\Symfony\Component\Console\Command\Command; +use SwissKnife202405\Symfony\Component\Console\Input\InputArgument; +use SwissKnife202405\Symfony\Component\Console\Input\InputDefinition; +use SwissKnife202405\Symfony\Component\Console\Input\InputOption; +/** + * XML descriptor. + * + * @author Jean-François Simon + * + * @internal + */ +class XmlDescriptor extends Descriptor +{ + public function getInputDefinitionDocument(InputDefinition $definition) : \DOMDocument + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->appendChild($definitionXML = $dom->createElement('definition')); + $definitionXML->appendChild($argumentsXML = $dom->createElement('arguments')); + foreach ($definition->getArguments() as $argument) { + $this->appendDocument($argumentsXML, $this->getInputArgumentDocument($argument)); + } + $definitionXML->appendChild($optionsXML = $dom->createElement('options')); + foreach ($definition->getOptions() as $option) { + $this->appendDocument($optionsXML, $this->getInputOptionDocument($option)); + } + return $dom; + } + public function getCommandDocument(Command $command, bool $short = \false) : \DOMDocument + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->appendChild($commandXML = $dom->createElement('command')); + $commandXML->setAttribute('id', $command->getName()); + $commandXML->setAttribute('name', $command->getName()); + $commandXML->setAttribute('hidden', $command->isHidden() ? 1 : 0); + $commandXML->appendChild($usagesXML = $dom->createElement('usages')); + $commandXML->appendChild($descriptionXML = $dom->createElement('description')); + $descriptionXML->appendChild($dom->createTextNode(\str_replace("\n", "\n ", $command->getDescription()))); + if ($short) { + foreach ($command->getAliases() as $usage) { + $usagesXML->appendChild($dom->createElement('usage', $usage)); + } + } else { + $command->mergeApplicationDefinition(\false); + foreach (\array_merge([$command->getSynopsis()], $command->getAliases(), $command->getUsages()) as $usage) { + $usagesXML->appendChild($dom->createElement('usage', $usage)); + } + $commandXML->appendChild($helpXML = $dom->createElement('help')); + $helpXML->appendChild($dom->createTextNode(\str_replace("\n", "\n ", $command->getProcessedHelp()))); + $definitionXML = $this->getInputDefinitionDocument($command->getDefinition()); + $this->appendDocument($commandXML, $definitionXML->getElementsByTagName('definition')->item(0)); + } + return $dom; + } + public function getApplicationDocument(Application $application, ?string $namespace = null, bool $short = \false) : \DOMDocument + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->appendChild($rootXml = $dom->createElement('symfony')); + if ('UNKNOWN' !== $application->getName()) { + $rootXml->setAttribute('name', $application->getName()); + if ('UNKNOWN' !== $application->getVersion()) { + $rootXml->setAttribute('version', $application->getVersion()); + } + } + $rootXml->appendChild($commandsXML = $dom->createElement('commands')); + $description = new ApplicationDescription($application, $namespace, \true); + if ($namespace) { + $commandsXML->setAttribute('namespace', $namespace); + } + foreach ($description->getCommands() as $command) { + $this->appendDocument($commandsXML, $this->getCommandDocument($command, $short)); + } + if (!$namespace) { + $rootXml->appendChild($namespacesXML = $dom->createElement('namespaces')); + foreach ($description->getNamespaces() as $namespaceDescription) { + $namespacesXML->appendChild($namespaceArrayXML = $dom->createElement('namespace')); + $namespaceArrayXML->setAttribute('id', $namespaceDescription['id']); + foreach ($namespaceDescription['commands'] as $name) { + $namespaceArrayXML->appendChild($commandXML = $dom->createElement('command')); + $commandXML->appendChild($dom->createTextNode($name)); + } + } + } + return $dom; + } + protected function describeInputArgument(InputArgument $argument, array $options = []) : void + { + $this->writeDocument($this->getInputArgumentDocument($argument)); + } + protected function describeInputOption(InputOption $option, array $options = []) : void + { + $this->writeDocument($this->getInputOptionDocument($option)); + } + protected function describeInputDefinition(InputDefinition $definition, array $options = []) : void + { + $this->writeDocument($this->getInputDefinitionDocument($definition)); + } + protected function describeCommand(Command $command, array $options = []) : void + { + $this->writeDocument($this->getCommandDocument($command, $options['short'] ?? \false)); + } + protected function describeApplication(Application $application, array $options = []) : void + { + $this->writeDocument($this->getApplicationDocument($application, $options['namespace'] ?? null, $options['short'] ?? \false)); + } + /** + * Appends document children to parent node. + */ + private function appendDocument(\DOMNode $parentNode, \DOMNode $importedParent) : void + { + foreach ($importedParent->childNodes as $childNode) { + $parentNode->appendChild($parentNode->ownerDocument->importNode($childNode, \true)); + } + } + /** + * Writes DOM document. + */ + private function writeDocument(\DOMDocument $dom) : void + { + $dom->formatOutput = \true; + $this->write($dom->saveXML()); + } + private function getInputArgumentDocument(InputArgument $argument) : \DOMDocument + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->appendChild($objectXML = $dom->createElement('argument')); + $objectXML->setAttribute('name', $argument->getName()); + $objectXML->setAttribute('is_required', $argument->isRequired() ? 1 : 0); + $objectXML->setAttribute('is_array', $argument->isArray() ? 1 : 0); + $objectXML->appendChild($descriptionXML = $dom->createElement('description')); + $descriptionXML->appendChild($dom->createTextNode($argument->getDescription())); + $objectXML->appendChild($defaultsXML = $dom->createElement('defaults')); + $defaults = \is_array($argument->getDefault()) ? $argument->getDefault() : (\is_bool($argument->getDefault()) ? [\var_export($argument->getDefault(), \true)] : ($argument->getDefault() ? [$argument->getDefault()] : [])); + foreach ($defaults as $default) { + $defaultsXML->appendChild($defaultXML = $dom->createElement('default')); + $defaultXML->appendChild($dom->createTextNode($default)); + } + return $dom; + } + private function getInputOptionDocument(InputOption $option) : \DOMDocument + { + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->appendChild($objectXML = $dom->createElement('option')); + $objectXML->setAttribute('name', '--' . $option->getName()); + $pos = \strpos($option->getShortcut() ?? '', '|'); + if (\false !== $pos) { + $objectXML->setAttribute('shortcut', '-' . \substr($option->getShortcut(), 0, $pos)); + $objectXML->setAttribute('shortcuts', '-' . \str_replace('|', '|-', $option->getShortcut())); + } else { + $objectXML->setAttribute('shortcut', $option->getShortcut() ? '-' . $option->getShortcut() : ''); + } + $objectXML->setAttribute('accept_value', $option->acceptValue() ? 1 : 0); + $objectXML->setAttribute('is_value_required', $option->isValueRequired() ? 1 : 0); + $objectXML->setAttribute('is_multiple', $option->isArray() ? 1 : 0); + $objectXML->appendChild($descriptionXML = $dom->createElement('description')); + $descriptionXML->appendChild($dom->createTextNode($option->getDescription())); + if ($option->acceptValue()) { + $defaults = \is_array($option->getDefault()) ? $option->getDefault() : (\is_bool($option->getDefault()) ? [\var_export($option->getDefault(), \true)] : ($option->getDefault() ? [$option->getDefault()] : [])); + $objectXML->appendChild($defaultsXML = $dom->createElement('defaults')); + if (!empty($defaults)) { + foreach ($defaults as $default) { + $defaultsXML->appendChild($defaultXML = $dom->createElement('default')); + $defaultXML->appendChild($dom->createTextNode($default)); + } + } + } + if ($option->isNegatable()) { + $dom->appendChild($objectXML = $dom->createElement('option')); + $objectXML->setAttribute('name', '--no-' . $option->getName()); + $objectXML->setAttribute('shortcut', ''); + $objectXML->setAttribute('accept_value', 0); + $objectXML->setAttribute('is_value_required', 0); + $objectXML->setAttribute('is_multiple', 0); + $objectXML->appendChild($descriptionXML = $dom->createElement('description')); + $descriptionXML->appendChild($dom->createTextNode('Negate the "--' . $option->getName() . '" option')); + } + return $dom; + } +} diff --git a/vendor/symfony/console/Event/ConsoleCommandEvent.php b/vendor/symfony/console/Event/ConsoleCommandEvent.php new file mode 100644 index 0000000000..024ab6eacf --- /dev/null +++ b/vendor/symfony/console/Event/ConsoleCommandEvent.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Event; + +/** + * Allows to do things before the command is executed, like skipping the command or executing code before the command is + * going to be executed. + * + * Changing the input arguments will have no effect. + * + * @author Fabien Potencier + */ +final class ConsoleCommandEvent extends ConsoleEvent +{ + /** + * The return code for skipped commands, this will also be passed into the terminate event. + */ + public const RETURN_CODE_DISABLED = 113; + /** + * Indicates if the command should be run or skipped. + * @var bool + */ + private $commandShouldRun = \true; + /** + * Disables the command, so it won't be run. + */ + public function disableCommand() : bool + { + return $this->commandShouldRun = \false; + } + public function enableCommand() : bool + { + return $this->commandShouldRun = \true; + } + /** + * Returns true if the command is runnable, false otherwise. + */ + public function commandShouldRun() : bool + { + return $this->commandShouldRun; + } +} diff --git a/vendor/symfony/console/Event/ConsoleErrorEvent.php b/vendor/symfony/console/Event/ConsoleErrorEvent.php new file mode 100644 index 0000000000..4154ccaa29 --- /dev/null +++ b/vendor/symfony/console/Event/ConsoleErrorEvent.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Event; + +use SwissKnife202405\Symfony\Component\Console\Command\Command; +use SwissKnife202405\Symfony\Component\Console\Input\InputInterface; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +/** + * Allows to handle throwables thrown while running a command. + * + * @author Wouter de Jong + */ +final class ConsoleErrorEvent extends ConsoleEvent +{ + /** + * @var \Throwable + */ + private $error; + /** + * @var int + */ + private $exitCode; + public function __construct(InputInterface $input, OutputInterface $output, \Throwable $error, ?Command $command = null) + { + parent::__construct($command, $input, $output); + $this->error = $error; + } + public function getError() : \Throwable + { + return $this->error; + } + public function setError(\Throwable $error) : void + { + $this->error = $error; + } + public function setExitCode(int $exitCode) : void + { + $this->exitCode = $exitCode; + $r = new \ReflectionProperty($this->error, 'code'); + $r->setAccessible(\true); + $r->setValue($this->error, $this->exitCode); + } + public function getExitCode() : int + { + return $this->exitCode ?? (\is_int($this->error->getCode()) && 0 !== $this->error->getCode() ? $this->error->getCode() : 1); + } +} diff --git a/vendor/symfony/console/Event/ConsoleEvent.php b/vendor/symfony/console/Event/ConsoleEvent.php new file mode 100644 index 0000000000..adf868d8a4 --- /dev/null +++ b/vendor/symfony/console/Event/ConsoleEvent.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Event; + +use SwissKnife202405\Symfony\Component\Console\Command\Command; +use SwissKnife202405\Symfony\Component\Console\Input\InputInterface; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +use SwissKnife202405\Symfony\Contracts\EventDispatcher\Event; +/** + * Allows to inspect input and output of a command. + * + * @author Francesco Levorato + */ +class ConsoleEvent extends Event +{ + protected $command; + /** + * @var \Symfony\Component\Console\Input\InputInterface + */ + private $input; + /** + * @var \Symfony\Component\Console\Output\OutputInterface + */ + private $output; + public function __construct(?Command $command, InputInterface $input, OutputInterface $output) + { + $this->command = $command; + $this->input = $input; + $this->output = $output; + } + /** + * Gets the command that is executed. + */ + public function getCommand() : ?Command + { + return $this->command; + } + /** + * Gets the input instance. + */ + public function getInput() : InputInterface + { + return $this->input; + } + /** + * Gets the output instance. + */ + public function getOutput() : OutputInterface + { + return $this->output; + } +} diff --git a/vendor/symfony/console/Event/ConsoleSignalEvent.php b/vendor/symfony/console/Event/ConsoleSignalEvent.php new file mode 100644 index 0000000000..606fe2d693 --- /dev/null +++ b/vendor/symfony/console/Event/ConsoleSignalEvent.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Event; + +use SwissKnife202405\Symfony\Component\Console\Command\Command; +use SwissKnife202405\Symfony\Component\Console\Input\InputInterface; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +/** + * @author marie + */ +final class ConsoleSignalEvent extends ConsoleEvent +{ + /** + * @var int + */ + private $handlingSignal; + /** + * @var int|false + */ + private $exitCode; + /** + * @param int|false $exitCode + */ + public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $handlingSignal, $exitCode = 0) + { + parent::__construct($command, $input, $output); + $this->handlingSignal = $handlingSignal; + $this->exitCode = $exitCode; + } + public function getHandlingSignal() : int + { + return $this->handlingSignal; + } + public function setExitCode(int $exitCode) : void + { + if ($exitCode < 0 || $exitCode > 255) { + throw new \InvalidArgumentException('Exit code must be between 0 and 255.'); + } + $this->exitCode = $exitCode; + } + public function abortExit() : void + { + $this->exitCode = \false; + } + /** + * @return int|false + */ + public function getExitCode() + { + return $this->exitCode; + } +} diff --git a/vendor/symfony/console/Event/ConsoleTerminateEvent.php b/vendor/symfony/console/Event/ConsoleTerminateEvent.php new file mode 100644 index 0000000000..0c8621bd4c --- /dev/null +++ b/vendor/symfony/console/Event/ConsoleTerminateEvent.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Event; + +use SwissKnife202405\Symfony\Component\Console\Command\Command; +use SwissKnife202405\Symfony\Component\Console\Input\InputInterface; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +/** + * Allows to manipulate the exit code of a command after its execution. + * + * @author Francesco Levorato + * @author Jules Pietri + */ +final class ConsoleTerminateEvent extends ConsoleEvent +{ + /** + * @var int + */ + private $exitCode; + /** + * @readonly + * @var int|null + */ + private $interruptingSignal; + public function __construct(Command $command, InputInterface $input, OutputInterface $output, int $exitCode, ?int $interruptingSignal = null) + { + $this->exitCode = $exitCode; + $this->interruptingSignal = $interruptingSignal; + parent::__construct($command, $input, $output); + } + public function setExitCode(int $exitCode) : void + { + $this->exitCode = $exitCode; + } + public function getExitCode() : int + { + return $this->exitCode; + } + public function getInterruptingSignal() : ?int + { + return $this->interruptingSignal; + } +} diff --git a/vendor/symfony/console/EventListener/ErrorListener.php b/vendor/symfony/console/EventListener/ErrorListener.php new file mode 100644 index 0000000000..3836bd2843 --- /dev/null +++ b/vendor/symfony/console/EventListener/ErrorListener.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\EventListener; + +use SwissKnife202405\Psr\Log\LoggerInterface; +use SwissKnife202405\Symfony\Component\Console\ConsoleEvents; +use SwissKnife202405\Symfony\Component\Console\Event\ConsoleErrorEvent; +use SwissKnife202405\Symfony\Component\Console\Event\ConsoleEvent; +use SwissKnife202405\Symfony\Component\Console\Event\ConsoleTerminateEvent; +use SwissKnife202405\Symfony\Component\EventDispatcher\EventSubscriberInterface; +/** + * @author James Halsall + * @author Robin Chalas + */ +class ErrorListener implements EventSubscriberInterface +{ + /** + * @var \Psr\Log\LoggerInterface|null + */ + private $logger; + public function __construct(?LoggerInterface $logger = null) + { + $this->logger = $logger; + } + /** + * @return void + */ + public function onConsoleError(ConsoleErrorEvent $event) + { + if (null === $this->logger) { + return; + } + $error = $event->getError(); + if (!($inputString = $this->getInputString($event))) { + $this->logger->critical('An error occurred while using the console. Message: "{message}"', ['exception' => $error, 'message' => $error->getMessage()]); + return; + } + $this->logger->critical('Error thrown while running command "{command}". Message: "{message}"', ['exception' => $error, 'command' => $inputString, 'message' => $error->getMessage()]); + } + /** + * @return void + */ + public function onConsoleTerminate(ConsoleTerminateEvent $event) + { + if (null === $this->logger) { + return; + } + $exitCode = $event->getExitCode(); + if (0 === $exitCode) { + return; + } + if (!($inputString = $this->getInputString($event))) { + $this->logger->debug('The console exited with code "{code}"', ['code' => $exitCode]); + return; + } + $this->logger->debug('Command "{command}" exited with code "{code}"', ['command' => $inputString, 'code' => $exitCode]); + } + public static function getSubscribedEvents() : array + { + return [ConsoleEvents::ERROR => ['onConsoleError', -128], ConsoleEvents::TERMINATE => ['onConsoleTerminate', -128]]; + } + private static function getInputString(ConsoleEvent $event) : ?string + { + $commandName = ($nullsafeVariable1 = $event->getCommand()) ? $nullsafeVariable1->getName() : null; + $input = $event->getInput(); + if ($input instanceof \Stringable) { + if ($commandName) { + return \str_replace(["'{$commandName}'", "\"{$commandName}\""], $commandName, (string) $input); + } + return (string) $input; + } + return $commandName; + } +} diff --git a/vendor/symfony/console/Exception/CommandNotFoundException.php b/vendor/symfony/console/Exception/CommandNotFoundException.php new file mode 100644 index 0000000000..6c819841dd --- /dev/null +++ b/vendor/symfony/console/Exception/CommandNotFoundException.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Exception; + +/** + * Represents an incorrect command name typed in the console. + * + * @author Jérôme Tamarelle + */ +class CommandNotFoundException extends \InvalidArgumentException implements ExceptionInterface +{ + /** + * @var mixed[] + */ + private $alternatives; + /** + * @param string $message Exception message to throw + * @param string[] $alternatives List of similar defined names + * @param int $code Exception code + * @param \Throwable|null $previous Previous exception used for the exception chaining + */ + public function __construct(string $message, array $alternatives = [], int $code = 0, ?\Throwable $previous = null) + { + parent::__construct($message, $code, $previous); + $this->alternatives = $alternatives; + } + /** + * @return string[] + */ + public function getAlternatives() : array + { + return $this->alternatives; + } +} diff --git a/vendor/symfony/console/Exception/ExceptionInterface.php b/vendor/symfony/console/Exception/ExceptionInterface.php new file mode 100644 index 0000000000..a8e018cbf2 --- /dev/null +++ b/vendor/symfony/console/Exception/ExceptionInterface.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Exception; + +/** + * ExceptionInterface. + * + * @author Jérôme Tamarelle + */ +interface ExceptionInterface extends \Throwable +{ +} diff --git a/vendor/symfony/console/Exception/InvalidArgumentException.php b/vendor/symfony/console/Exception/InvalidArgumentException.php new file mode 100644 index 0000000000..521d715d9a --- /dev/null +++ b/vendor/symfony/console/Exception/InvalidArgumentException.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Exception; + +/** + * @author Jérôme Tamarelle + */ +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/console/Exception/InvalidOptionException.php b/vendor/symfony/console/Exception/InvalidOptionException.php new file mode 100644 index 0000000000..43048a6edd --- /dev/null +++ b/vendor/symfony/console/Exception/InvalidOptionException.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Exception; + +/** + * Represents an incorrect option name or value typed in the console. + * + * @author Jérôme Tamarelle + */ +class InvalidOptionException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/console/Exception/LogicException.php b/vendor/symfony/console/Exception/LogicException.php new file mode 100644 index 0000000000..2b18385187 --- /dev/null +++ b/vendor/symfony/console/Exception/LogicException.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Exception; + +/** + * @author Jérôme Tamarelle + */ +class LogicException extends \LogicException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/console/Exception/MissingInputException.php b/vendor/symfony/console/Exception/MissingInputException.php new file mode 100644 index 0000000000..01501a4c46 --- /dev/null +++ b/vendor/symfony/console/Exception/MissingInputException.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Exception; + +/** + * Represents failure to read input from stdin. + * + * @author Gabriel Ostrolucký + */ +class MissingInputException extends RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/console/Exception/NamespaceNotFoundException.php b/vendor/symfony/console/Exception/NamespaceNotFoundException.php new file mode 100644 index 0000000000..0dbd49bd29 --- /dev/null +++ b/vendor/symfony/console/Exception/NamespaceNotFoundException.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Exception; + +/** + * Represents an incorrect namespace typed in the console. + * + * @author Pierre du Plessis + */ +class NamespaceNotFoundException extends CommandNotFoundException +{ +} diff --git a/vendor/symfony/console/Exception/RunCommandFailedException.php b/vendor/symfony/console/Exception/RunCommandFailedException.php new file mode 100644 index 0000000000..8d3cd8687b --- /dev/null +++ b/vendor/symfony/console/Exception/RunCommandFailedException.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Exception; + +use SwissKnife202405\Symfony\Component\Console\Messenger\RunCommandContext; +/** + * @author Kevin Bond + */ +final class RunCommandFailedException extends RuntimeException +{ + /** + * @readonly + * @var \Symfony\Component\Console\Messenger\RunCommandContext + */ + public $context; + /** + * @param \Throwable|string $exception + */ + public function __construct($exception, RunCommandContext $context) + { + $this->context = $context; + parent::__construct($exception instanceof \Throwable ? $exception->getMessage() : $exception, $exception instanceof \Throwable ? $exception->getCode() : 0, $exception instanceof \Throwable ? $exception : null); + } +} diff --git a/vendor/symfony/console/Exception/RuntimeException.php b/vendor/symfony/console/Exception/RuntimeException.php new file mode 100644 index 0000000000..b7afbeef50 --- /dev/null +++ b/vendor/symfony/console/Exception/RuntimeException.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Exception; + +/** + * @author Jérôme Tamarelle + */ +class RuntimeException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/console/Formatter/NullOutputFormatter.php b/vendor/symfony/console/Formatter/NullOutputFormatter.php new file mode 100644 index 0000000000..f3018f079b --- /dev/null +++ b/vendor/symfony/console/Formatter/NullOutputFormatter.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Formatter; + +/** + * @author Tien Xuan Vo + */ +final class NullOutputFormatter implements OutputFormatterInterface +{ + /** + * @var \Symfony\Component\Console\Formatter\NullOutputFormatterStyle + */ + private $style; + public function format(?string $message) : ?string + { + return null; + } + public function getStyle(string $name) : OutputFormatterStyleInterface + { + // to comply with the interface we must return a OutputFormatterStyleInterface + return $this->style = $this->style ?? new NullOutputFormatterStyle(); + } + public function hasStyle(string $name) : bool + { + return \false; + } + public function isDecorated() : bool + { + return \false; + } + public function setDecorated(bool $decorated) : void + { + // do nothing + } + public function setStyle(string $name, OutputFormatterStyleInterface $style) : void + { + // do nothing + } +} diff --git a/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php b/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php new file mode 100644 index 0000000000..bab08b207a --- /dev/null +++ b/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Formatter; + +/** + * @author Tien Xuan Vo + */ +final class NullOutputFormatterStyle implements OutputFormatterStyleInterface +{ + public function apply(string $text) : string + { + return $text; + } + public function setBackground(?string $color = null) : void + { + if (1 > \func_num_args()) { + trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); + } + // do nothing + } + public function setForeground(?string $color = null) : void + { + if (1 > \func_num_args()) { + trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); + } + // do nothing + } + public function setOption(string $option) : void + { + // do nothing + } + public function setOptions(array $options) : void + { + // do nothing + } + public function unsetOption(string $option) : void + { + // do nothing + } +} diff --git a/vendor/symfony/console/Formatter/OutputFormatter.php b/vendor/symfony/console/Formatter/OutputFormatter.php new file mode 100644 index 0000000000..a8a6ec3bd8 --- /dev/null +++ b/vendor/symfony/console/Formatter/OutputFormatter.php @@ -0,0 +1,241 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Formatter; + +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +use function SwissKnife202405\Symfony\Component\String\b; +/** + * Formatter class for console output. + * + * @author Konstantin Kudryashov + * @author Roland Franssen + */ +class OutputFormatter implements WrappableOutputFormatterInterface +{ + /** + * @var bool + */ + private $decorated; + /** + * @var mixed[] + */ + private $styles = []; + /** + * @var \Symfony\Component\Console\Formatter\OutputFormatterStyleStack + */ + private $styleStack; + public function __clone() + { + $this->styleStack = clone $this->styleStack; + foreach ($this->styles as $key => $value) { + $this->styles[$key] = clone $value; + } + } + /** + * Escapes "<" and ">" special chars in given text. + */ + public static function escape(string $text) : string + { + $text = \preg_replace('/([^\\\\]|^)([<>])/', '$1\\\\$2', $text); + return self::escapeTrailingBackslash($text); + } + /** + * Escapes trailing "\" in given text. + * + * @internal + */ + public static function escapeTrailingBackslash(string $text) : string + { + if (\substr_compare($text, '\\', -\strlen('\\')) === 0) { + $len = \strlen($text); + $text = \rtrim($text, '\\'); + $text = \str_replace("\x00", '', $text); + $text .= \str_repeat("\x00", $len - \strlen($text)); + } + return $text; + } + /** + * Initializes console output formatter. + * + * @param OutputFormatterStyleInterface[] $styles Array of "name => FormatterStyle" instances + */ + public function __construct(bool $decorated = \false, array $styles = []) + { + $this->decorated = $decorated; + $this->setStyle('error', new OutputFormatterStyle('white', 'red')); + $this->setStyle('info', new OutputFormatterStyle('green')); + $this->setStyle('comment', new OutputFormatterStyle('yellow')); + $this->setStyle('question', new OutputFormatterStyle('black', 'cyan')); + foreach ($styles as $name => $style) { + $this->setStyle($name, $style); + } + $this->styleStack = new OutputFormatterStyleStack(); + } + /** + * @return void + */ + public function setDecorated(bool $decorated) + { + $this->decorated = $decorated; + } + public function isDecorated() : bool + { + return $this->decorated; + } + /** + * @return void + */ + public function setStyle(string $name, OutputFormatterStyleInterface $style) + { + $this->styles[\strtolower($name)] = $style; + } + public function hasStyle(string $name) : bool + { + return isset($this->styles[\strtolower($name)]); + } + public function getStyle(string $name) : OutputFormatterStyleInterface + { + if (!$this->hasStyle($name)) { + throw new InvalidArgumentException(\sprintf('Undefined style: "%s".', $name)); + } + return $this->styles[\strtolower($name)]; + } + public function format(?string $message) : ?string + { + return $this->formatAndWrap($message, 0); + } + /** + * @return string + */ + public function formatAndWrap(?string $message, int $width) + { + if (null === $message) { + return ''; + } + $offset = 0; + $output = ''; + $openTagRegex = '[a-z](?:[^\\\\<>]*+ | \\\\.)*'; + $closeTagRegex = '[a-z][^<>]*+'; + $currentLineLength = 0; + \preg_match_all("#<(({$openTagRegex}) | /({$closeTagRegex})?)>#ix", $message, $matches, \PREG_OFFSET_CAPTURE); + foreach ($matches[0] as $i => $match) { + $pos = $match[1]; + $text = $match[0]; + if (0 != $pos && '\\' == $message[$pos - 1]) { + continue; + } + // add the text up to the next tag + $output .= $this->applyCurrentStyle(\substr($message, $offset, $pos - $offset), $output, $width, $currentLineLength); + $offset = $pos + \strlen($text); + // opening tag? + if ($open = '/' !== $text[1]) { + $tag = $matches[1][$i][0]; + } else { + $tag = $matches[3][$i][0] ?? ''; + } + if (!$open && !$tag) { + // + $this->styleStack->pop(); + } elseif (null === ($style = $this->createStyleFromString($tag))) { + $output .= $this->applyCurrentStyle($text, $output, $width, $currentLineLength); + } elseif ($open) { + $this->styleStack->push($style); + } else { + $this->styleStack->pop($style); + } + } + $output .= $this->applyCurrentStyle(\substr($message, $offset), $output, $width, $currentLineLength); + return \strtr($output, ["\x00" => '\\', '\\<' => '<', '\\>' => '>']); + } + public function getStyleStack() : OutputFormatterStyleStack + { + return $this->styleStack; + } + /** + * Tries to create new style instance from string. + */ + private function createStyleFromString(string $string) : ?OutputFormatterStyleInterface + { + if (isset($this->styles[$string])) { + return $this->styles[$string]; + } + if (!\preg_match_all('/([^=]+)=([^;]+)(;|$)/', $string, $matches, \PREG_SET_ORDER)) { + return null; + } + $style = new OutputFormatterStyle(); + foreach ($matches as $match) { + \array_shift($match); + $match[0] = \strtolower($match[0]); + if ('fg' == $match[0]) { + $style->setForeground(\strtolower($match[1])); + } elseif ('bg' == $match[0]) { + $style->setBackground(\strtolower($match[1])); + } elseif ('href' === $match[0]) { + $url = \preg_replace('{\\\\([<>])}', '$1', $match[1]); + $style->setHref($url); + } elseif ('options' === $match[0]) { + \preg_match_all('([^,;]+)', \strtolower($match[1]), $options); + $options = \array_shift($options); + foreach ($options as $option) { + $style->setOption($option); + } + } else { + return null; + } + } + return $style; + } + /** + * Applies current style from stack to text, if must be applied. + */ + private function applyCurrentStyle(string $text, string $current, int $width, int &$currentLineLength) : string + { + if ('' === $text) { + return ''; + } + if (!$width) { + return $this->isDecorated() ? $this->styleStack->getCurrent()->apply($text) : $text; + } + if (!$currentLineLength && '' !== $current) { + $text = \ltrim($text); + } + if ($currentLineLength) { + $prefix = \substr($text, 0, $i = $width - $currentLineLength) . "\n"; + $text = \substr($text, $i); + } else { + $prefix = ''; + } + \preg_match('~(\\n)$~', $text, $matches); + $text = $prefix . $this->addLineBreaks($text, $width); + $text = \rtrim($text, "\n") . ($matches[1] ?? ''); + if (!$currentLineLength && '' !== $current && \substr_compare($current, "\n", -\strlen("\n")) !== 0) { + $text = "\n" . $text; + } + $lines = \explode("\n", $text); + foreach ($lines as $line) { + $currentLineLength += \strlen($line); + if ($width <= $currentLineLength) { + $currentLineLength = 0; + } + } + if ($this->isDecorated()) { + foreach ($lines as $i => $line) { + $lines[$i] = $this->styleStack->getCurrent()->apply($line); + } + } + return \implode("\n", $lines); + } + private function addLineBreaks(string $text, int $width) : string + { + $encoding = \mb_detect_encoding($text, null, \true) ?: 'UTF-8'; + return b($text)->toCodePointString($encoding)->wordwrap($width, "\n", \true)->toByteString($encoding); + } +} diff --git a/vendor/symfony/console/Formatter/OutputFormatterInterface.php b/vendor/symfony/console/Formatter/OutputFormatterInterface.php new file mode 100644 index 0000000000..754d721633 --- /dev/null +++ b/vendor/symfony/console/Formatter/OutputFormatterInterface.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Formatter; + +/** + * Formatter interface for console output. + * + * @author Konstantin Kudryashov + */ +interface OutputFormatterInterface +{ + /** + * Sets the decorated flag. + * + * @return void + */ + public function setDecorated(bool $decorated); + /** + * Whether the output will decorate messages. + */ + public function isDecorated() : bool; + /** + * Sets a new style. + * + * @return void + */ + public function setStyle(string $name, OutputFormatterStyleInterface $style); + /** + * Checks if output formatter has style with specified name. + */ + public function hasStyle(string $name) : bool; + /** + * Gets style options from style with specified name. + * + * @throws \InvalidArgumentException When style isn't defined + */ + public function getStyle(string $name) : OutputFormatterStyleInterface; + /** + * Formats a message according to the given styles. + */ + public function format(?string $message) : ?string; +} diff --git a/vendor/symfony/console/Formatter/OutputFormatterStyle.php b/vendor/symfony/console/Formatter/OutputFormatterStyle.php new file mode 100644 index 0000000000..66ea9f12e2 --- /dev/null +++ b/vendor/symfony/console/Formatter/OutputFormatterStyle.php @@ -0,0 +1,113 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Formatter; + +use SwissKnife202405\Symfony\Component\Console\Color; +/** + * Formatter style class for defining styles. + * + * @author Konstantin Kudryashov + */ +class OutputFormatterStyle implements OutputFormatterStyleInterface +{ + /** + * @var \Symfony\Component\Console\Color + */ + private $color; + /** + * @var string + */ + private $foreground; + /** + * @var string + */ + private $background; + /** + * @var mixed[] + */ + private $options; + /** + * @var string|null + */ + private $href; + /** + * @var bool + */ + private $handlesHrefGracefully; + /** + * Initializes output formatter style. + * + * @param string|null $foreground The style foreground color name + * @param string|null $background The style background color name + */ + public function __construct(?string $foreground = null, ?string $background = null, array $options = []) + { + $this->color = new Color($this->foreground = $foreground ?: '', $this->background = $background ?: '', $this->options = $options); + } + /** + * @return void + */ + public function setForeground(?string $color = null) + { + if (1 > \func_num_args()) { + trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); + } + $this->color = new Color($this->foreground = $color ?: '', $this->background, $this->options); + } + /** + * @return void + */ + public function setBackground(?string $color = null) + { + if (1 > \func_num_args()) { + trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); + } + $this->color = new Color($this->foreground, $this->background = $color ?: '', $this->options); + } + public function setHref(string $url) : void + { + $this->href = $url; + } + /** + * @return void + */ + public function setOption(string $option) + { + $this->options[] = $option; + $this->color = new Color($this->foreground, $this->background, $this->options); + } + /** + * @return void + */ + public function unsetOption(string $option) + { + $pos = \array_search($option, $this->options); + if (\false !== $pos) { + unset($this->options[$pos]); + } + $this->color = new Color($this->foreground, $this->background, $this->options); + } + /** + * @return void + */ + public function setOptions(array $options) + { + $this->color = new Color($this->foreground, $this->background, $this->options = $options); + } + public function apply(string $text) : string + { + $this->handlesHrefGracefully = $this->handlesHrefGracefully ?? 'JetBrains-JediTerm' !== \getenv('TERMINAL_EMULATOR') && (!\getenv('KONSOLE_VERSION') || (int) \getenv('KONSOLE_VERSION') > 201100) && !isset($_SERVER['IDEA_INITIAL_DIRECTORY']); + if (null !== $this->href && $this->handlesHrefGracefully) { + $text = "\x1b]8;;{$this->href}\x1b\\{$text}\x1b]8;;\x1b\\"; + } + return $this->color->apply($text); + } +} diff --git a/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php b/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php new file mode 100644 index 0000000000..f9035c9c47 --- /dev/null +++ b/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Formatter; + +/** + * Formatter style interface for defining styles. + * + * @author Konstantin Kudryashov + */ +interface OutputFormatterStyleInterface +{ + /** + * Sets style foreground color. + * + * @return void + */ + public function setForeground(?string $color); + /** + * Sets style background color. + * + * @return void + */ + public function setBackground(?string $color); + /** + * Sets some specific style option. + * + * @return void + */ + public function setOption(string $option); + /** + * Unsets some specific style option. + * + * @return void + */ + public function unsetOption(string $option); + /** + * Sets multiple style options at once. + * + * @return void + */ + public function setOptions(array $options); + /** + * Applies the style to a given text. + */ + public function apply(string $text) : string; +} diff --git a/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php b/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php new file mode 100644 index 0000000000..1ae84ffa68 --- /dev/null +++ b/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Formatter; + +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +use SwissKnife202405\Symfony\Contracts\Service\ResetInterface; +/** + * @author Jean-François Simon + */ +class OutputFormatterStyleStack implements ResetInterface +{ + /** + * @var OutputFormatterStyleInterface[] + */ + private $styles = []; + /** + * @var \Symfony\Component\Console\Formatter\OutputFormatterStyleInterface + */ + private $emptyStyle; + public function __construct(?OutputFormatterStyleInterface $emptyStyle = null) + { + $this->emptyStyle = $emptyStyle ?? new OutputFormatterStyle(); + $this->reset(); + } + /** + * Resets stack (ie. empty internal arrays). + * + * @return void + */ + public function reset() + { + $this->styles = []; + } + /** + * Pushes a style in the stack. + * + * @return void + */ + public function push(OutputFormatterStyleInterface $style) + { + $this->styles[] = $style; + } + /** + * Pops a style from the stack. + * + * @throws InvalidArgumentException When style tags incorrectly nested + */ + public function pop(?OutputFormatterStyleInterface $style = null) : OutputFormatterStyleInterface + { + if (!$this->styles) { + return $this->emptyStyle; + } + if (null === $style) { + return \array_pop($this->styles); + } + foreach (\array_reverse($this->styles, \true) as $index => $stackedStyle) { + if ($style->apply('') === $stackedStyle->apply('')) { + $this->styles = \array_slice($this->styles, 0, $index); + return $stackedStyle; + } + } + throw new InvalidArgumentException('Incorrectly nested style tag found.'); + } + /** + * Computes current style with stacks top codes. + */ + public function getCurrent() : OutputFormatterStyleInterface + { + if (!$this->styles) { + return $this->emptyStyle; + } + return $this->styles[\count($this->styles) - 1]; + } + /** + * @return $this + */ + public function setEmptyStyle(OutputFormatterStyleInterface $emptyStyle) + { + $this->emptyStyle = $emptyStyle; + return $this; + } + public function getEmptyStyle() : OutputFormatterStyleInterface + { + return $this->emptyStyle; + } +} diff --git a/vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php b/vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php new file mode 100644 index 0000000000..e6aa2a7268 --- /dev/null +++ b/vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Formatter; + +/** + * Formatter interface for console output that supports word wrapping. + * + * @author Roland Franssen + */ +interface WrappableOutputFormatterInterface extends OutputFormatterInterface +{ + /** + * Formats a message according to the given styles, wrapping at `$width` (0 means no wrapping). + * + * @return string + */ + public function formatAndWrap(?string $message, int $width); +} diff --git a/vendor/symfony/console/Helper/DebugFormatterHelper.php b/vendor/symfony/console/Helper/DebugFormatterHelper.php new file mode 100644 index 0000000000..36baa240c6 --- /dev/null +++ b/vendor/symfony/console/Helper/DebugFormatterHelper.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Helper; + +/** + * Helps outputting debug information when running an external program from a command. + * + * An external program can be a Process, an HTTP request, or anything else. + * + * @author Fabien Potencier + */ +class DebugFormatterHelper extends Helper +{ + private const COLORS = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'default']; + /** + * @var mixed[] + */ + private $started = []; + /** + * @var int + */ + private $count = -1; + /** + * Starts a debug formatting session. + */ + public function start(string $id, string $message, string $prefix = 'RUN') : string + { + $this->started[$id] = ['border' => ++$this->count % \count(self::COLORS)]; + return \sprintf("%s %s %s\n", $this->getBorder($id), $prefix, $message); + } + /** + * Adds progress to a formatting session. + */ + public function progress(string $id, string $buffer, bool $error = \false, string $prefix = 'OUT', string $errorPrefix = 'ERR') : string + { + $message = ''; + if ($error) { + if (isset($this->started[$id]['out'])) { + $message .= "\n"; + unset($this->started[$id]['out']); + } + if (!isset($this->started[$id]['err'])) { + $message .= \sprintf('%s %s ', $this->getBorder($id), $errorPrefix); + $this->started[$id]['err'] = \true; + } + $message .= \str_replace("\n", \sprintf("\n%s %s ", $this->getBorder($id), $errorPrefix), $buffer); + } else { + if (isset($this->started[$id]['err'])) { + $message .= "\n"; + unset($this->started[$id]['err']); + } + if (!isset($this->started[$id]['out'])) { + $message .= \sprintf('%s %s ', $this->getBorder($id), $prefix); + $this->started[$id]['out'] = \true; + } + $message .= \str_replace("\n", \sprintf("\n%s %s ", $this->getBorder($id), $prefix), $buffer); + } + return $message; + } + /** + * Stops a formatting session. + */ + public function stop(string $id, string $message, bool $successful, string $prefix = 'RES') : string + { + $trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? "\n" : ''; + if ($successful) { + return \sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); + } + $message = \sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); + unset($this->started[$id]['out'], $this->started[$id]['err']); + return $message; + } + private function getBorder(string $id) : string + { + return \sprintf(' ', self::COLORS[$this->started[$id]['border']]); + } + public function getName() : string + { + return 'debug_formatter'; + } +} diff --git a/vendor/symfony/console/Helper/DescriptorHelper.php b/vendor/symfony/console/Helper/DescriptorHelper.php new file mode 100644 index 0000000000..a899494202 --- /dev/null +++ b/vendor/symfony/console/Helper/DescriptorHelper.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Helper; + +use SwissKnife202405\Symfony\Component\Console\Descriptor\DescriptorInterface; +use SwissKnife202405\Symfony\Component\Console\Descriptor\JsonDescriptor; +use SwissKnife202405\Symfony\Component\Console\Descriptor\MarkdownDescriptor; +use SwissKnife202405\Symfony\Component\Console\Descriptor\ReStructuredTextDescriptor; +use SwissKnife202405\Symfony\Component\Console\Descriptor\TextDescriptor; +use SwissKnife202405\Symfony\Component\Console\Descriptor\XmlDescriptor; +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +/** + * This class adds helper method to describe objects in various formats. + * + * @author Jean-François Simon + */ +class DescriptorHelper extends Helper +{ + /** + * @var DescriptorInterface[] + */ + private $descriptors = []; + public function __construct() + { + $this->register('txt', new TextDescriptor())->register('xml', new XmlDescriptor())->register('json', new JsonDescriptor())->register('md', new MarkdownDescriptor())->register('rst', new ReStructuredTextDescriptor()); + } + /** + * Describes an object if supported. + * + * Available options are: + * * format: string, the output format name + * * raw_text: boolean, sets output type as raw + * + * @return void + * + * @throws InvalidArgumentException when the given format is not supported + */ + public function describe(OutputInterface $output, ?object $object, array $options = []) + { + $options = \array_merge(['raw_text' => \false, 'format' => 'txt'], $options); + if (!isset($this->descriptors[$options['format']])) { + throw new InvalidArgumentException(\sprintf('Unsupported format "%s".', $options['format'])); + } + $descriptor = $this->descriptors[$options['format']]; + $descriptor->describe($output, $object, $options); + } + /** + * Registers a descriptor. + * + * @return $this + */ + public function register(string $format, DescriptorInterface $descriptor) + { + $this->descriptors[$format] = $descriptor; + return $this; + } + public function getName() : string + { + return 'descriptor'; + } + public function getFormats() : array + { + return \array_keys($this->descriptors); + } +} diff --git a/vendor/symfony/console/Helper/Dumper.php b/vendor/symfony/console/Helper/Dumper.php new file mode 100644 index 0000000000..75eac70ec6 --- /dev/null +++ b/vendor/symfony/console/Helper/Dumper.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Helper; + +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +use SwissKnife202405\Symfony\Component\VarDumper\Cloner\ClonerInterface; +use SwissKnife202405\Symfony\Component\VarDumper\Cloner\VarCloner; +use SwissKnife202405\Symfony\Component\VarDumper\Dumper\CliDumper; +/** + * @author Roland Franssen + */ +final class Dumper +{ + /** + * @var \Symfony\Component\Console\Output\OutputInterface + */ + private $output; + /** + * @var \Symfony\Component\VarDumper\Dumper\CliDumper|null + */ + private $dumper; + /** + * @var \Symfony\Component\VarDumper\Cloner\ClonerInterface|null + */ + private $cloner; + /** + * @var \Closure + */ + private $handler; + public function __construct(OutputInterface $output, ?CliDumper $dumper = null, ?ClonerInterface $cloner = null) + { + $this->output = $output; + $this->dumper = $dumper; + $this->cloner = $cloner; + if (\class_exists(CliDumper::class)) { + $this->handler = function ($var) : string { + $dumper = $this->dumper = $this->dumper ?? new CliDumper(null, null, CliDumper::DUMP_LIGHT_ARRAY | CliDumper::DUMP_COMMA_SEPARATOR); + $dumper->setColors($this->output->isDecorated()); + return \rtrim($dumper->dump(($this->cloner = $this->cloner ?? new VarCloner())->cloneVar($var)->withRefHandles(\false), \true)); + }; + } else { + $this->handler = function ($var) : string { + switch (\true) { + case null === $var: + return 'null'; + case \true === $var: + return 'true'; + case \false === $var: + return 'false'; + case \is_string($var): + return '"' . $var . '"'; + default: + return \rtrim(\print_r($var, \true)); + } + }; + } + } + /** + * @param mixed $var + */ + public function __invoke($var) : string + { + return ($this->handler)($var); + } +} diff --git a/vendor/symfony/console/Helper/FormatterHelper.php b/vendor/symfony/console/Helper/FormatterHelper.php new file mode 100644 index 0000000000..27242a5e21 --- /dev/null +++ b/vendor/symfony/console/Helper/FormatterHelper.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Helper; + +use SwissKnife202405\Symfony\Component\Console\Formatter\OutputFormatter; +/** + * The Formatter class provides helpers to format messages. + * + * @author Fabien Potencier + */ +class FormatterHelper extends Helper +{ + /** + * Formats a message within a section. + */ + public function formatSection(string $section, string $message, string $style = 'info') : string + { + return \sprintf('<%s>[%s] %s', $style, $section, $style, $message); + } + /** + * Formats a message as a block of text. + * @param string|mixed[] $messages + */ + public function formatBlock($messages, string $style, bool $large = \false) : string + { + if (!\is_array($messages)) { + $messages = [$messages]; + } + $len = 0; + $lines = []; + foreach ($messages as $message) { + $message = OutputFormatter::escape($message); + $lines[] = \sprintf($large ? ' %s ' : ' %s ', $message); + $len = \max(self::width($message) + ($large ? 4 : 2), $len); + } + $messages = $large ? [\str_repeat(' ', $len)] : []; + for ($i = 0; isset($lines[$i]); ++$i) { + $messages[] = $lines[$i] . \str_repeat(' ', $len - self::width($lines[$i])); + } + if ($large) { + $messages[] = \str_repeat(' ', $len); + } + for ($i = 0; isset($messages[$i]); ++$i) { + $messages[$i] = \sprintf('<%s>%s', $style, $messages[$i], $style); + } + return \implode("\n", $messages); + } + /** + * Truncates a message to the given length. + */ + public function truncate(string $message, int $length, string $suffix = '...') : string + { + $computedLength = $length - self::width($suffix); + if ($computedLength > self::width($message)) { + return $message; + } + return self::substr($message, 0, $length) . $suffix; + } + public function getName() : string + { + return 'formatter'; + } +} diff --git a/vendor/symfony/console/Helper/Helper.php b/vendor/symfony/console/Helper/Helper.php new file mode 100644 index 0000000000..982d2f03c7 --- /dev/null +++ b/vendor/symfony/console/Helper/Helper.php @@ -0,0 +1,139 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Helper; + +use SwissKnife202405\Symfony\Component\Console\Formatter\OutputFormatterInterface; +use SwissKnife202405\Symfony\Component\String\UnicodeString; +/** + * Helper is the base class for all helper classes. + * + * @author Fabien Potencier + */ +abstract class Helper implements HelperInterface +{ + protected $helperSet; + /** + * @return void + */ + public function setHelperSet(?HelperSet $helperSet = null) + { + if (1 > \func_num_args()) { + trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); + } + $this->helperSet = $helperSet; + } + public function getHelperSet() : ?HelperSet + { + return $this->helperSet; + } + /** + * Returns the width of a string, using mb_strwidth if it is available. + * The width is how many characters positions the string will use. + */ + public static function width(?string $string) : int + { + $string = $string ?? ''; + if (\preg_match('//u', $string)) { + return (new UnicodeString($string))->width(\false); + } + if (\false === ($encoding = \mb_detect_encoding($string, null, \true))) { + return \strlen($string); + } + return \mb_strwidth($string, $encoding); + } + /** + * Returns the length of a string, using mb_strlen if it is available. + * The length is related to how many bytes the string will use. + */ + public static function length(?string $string) : int + { + $string = $string ?? ''; + if (\preg_match('//u', $string)) { + return (new UnicodeString($string))->length(); + } + if (\false === ($encoding = \mb_detect_encoding($string, null, \true))) { + return \strlen($string); + } + return \mb_strlen($string, $encoding); + } + /** + * Returns the subset of a string, using mb_substr if it is available. + */ + public static function substr(?string $string, int $from, ?int $length = null) : string + { + $string = $string ?? ''; + if (\false === ($encoding = \mb_detect_encoding($string, null, \true))) { + return \substr($string, $from, $length); + } + return \mb_substr($string, $from, $length, $encoding); + } + /** + * @return string + * @param int|float $secs + */ + public static function formatTime($secs, int $precision = 1) + { + $secs = (int) \floor($secs); + if (0 === $secs) { + return '< 1 sec'; + } + static $timeFormats = [[1, '1 sec', 'secs'], [60, '1 min', 'mins'], [3600, '1 hr', 'hrs'], [86400, '1 day', 'days']]; + $times = []; + foreach ($timeFormats as $index => $format) { + $seconds = isset($timeFormats[$index + 1]) ? $secs % $timeFormats[$index + 1][0] : $secs; + if (isset($times[$index - $precision])) { + unset($times[$index - $precision]); + } + if (0 === $seconds) { + continue; + } + $unitCount = $seconds / $format[0]; + $times[$index] = 1 === $unitCount ? $format[1] : $unitCount . ' ' . $format[2]; + if ($secs === $seconds) { + break; + } + $secs -= $seconds; + } + return \implode(', ', \array_reverse($times)); + } + /** + * @return string + */ + public static function formatMemory(int $memory) + { + if ($memory >= 1024 * 1024 * 1024) { + return \sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024); + } + if ($memory >= 1024 * 1024) { + return \sprintf('%.1f MiB', $memory / 1024 / 1024); + } + if ($memory >= 1024) { + return \sprintf('%d KiB', $memory / 1024); + } + return \sprintf('%d B', $memory); + } + /** + * @return string + */ + public static function removeDecoration(OutputFormatterInterface $formatter, ?string $string) + { + $isDecorated = $formatter->isDecorated(); + $formatter->setDecorated(\false); + // remove <...> formatting + $string = $formatter->format($string ?? ''); + // remove already formatted characters + $string = \preg_replace("/\x1b\\[[^m]*m/", '', $string ?? ''); + // remove terminal hyperlinks + $string = \preg_replace('/\\033]8;[^;]*;[^\\033]*\\033\\\\/', '', $string ?? ''); + $formatter->setDecorated($isDecorated); + return $string; + } +} diff --git a/vendor/symfony/console/Helper/HelperInterface.php b/vendor/symfony/console/Helper/HelperInterface.php new file mode 100644 index 0000000000..acd05e2f4a --- /dev/null +++ b/vendor/symfony/console/Helper/HelperInterface.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Helper; + +/** + * HelperInterface is the interface all helpers must implement. + * + * @author Fabien Potencier + */ +interface HelperInterface +{ + /** + * Sets the helper set associated with this helper. + * + * @return void + */ + public function setHelperSet(?HelperSet $helperSet); + /** + * Gets the helper set associated with this helper. + */ + public function getHelperSet() : ?HelperSet; + /** + * Returns the canonical name of this helper. + * + * @return string + */ + public function getName(); +} diff --git a/vendor/symfony/console/Helper/HelperSet.php b/vendor/symfony/console/Helper/HelperSet.php new file mode 100644 index 0000000000..6220898250 --- /dev/null +++ b/vendor/symfony/console/Helper/HelperSet.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Helper; + +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +/** + * HelperSet represents a set of helpers to be used with a command. + * + * @author Fabien Potencier + * + * @implements \IteratorAggregate + */ +class HelperSet implements \IteratorAggregate +{ + /** @var array */ + private $helpers = []; + /** + * @param HelperInterface[] $helpers + */ + public function __construct(array $helpers = []) + { + foreach ($helpers as $alias => $helper) { + $this->set($helper, \is_int($alias) ? null : $alias); + } + } + /** + * @return void + */ + public function set(HelperInterface $helper, ?string $alias = null) + { + $this->helpers[$helper->getName()] = $helper; + if (null !== $alias) { + $this->helpers[$alias] = $helper; + } + $helper->setHelperSet($this); + } + /** + * Returns true if the helper if defined. + */ + public function has(string $name) : bool + { + return isset($this->helpers[$name]); + } + /** + * Gets a helper value. + * + * @throws InvalidArgumentException if the helper is not defined + */ + public function get(string $name) : HelperInterface + { + if (!$this->has($name)) { + throw new InvalidArgumentException(\sprintf('The helper "%s" is not defined.', $name)); + } + return $this->helpers[$name]; + } + public function getIterator() : \Traversable + { + return new \ArrayIterator($this->helpers); + } +} diff --git a/vendor/symfony/console/Helper/InputAwareHelper.php b/vendor/symfony/console/Helper/InputAwareHelper.php new file mode 100644 index 0000000000..41d464b4f9 --- /dev/null +++ b/vendor/symfony/console/Helper/InputAwareHelper.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Helper; + +use SwissKnife202405\Symfony\Component\Console\Input\InputAwareInterface; +use SwissKnife202405\Symfony\Component\Console\Input\InputInterface; +/** + * An implementation of InputAwareInterface for Helpers. + * + * @author Wouter J + */ +abstract class InputAwareHelper extends Helper implements InputAwareInterface +{ + protected $input; + /** + * @return void + */ + public function setInput(InputInterface $input) + { + $this->input = $input; + } +} diff --git a/vendor/symfony/console/Helper/OutputWrapper.php b/vendor/symfony/console/Helper/OutputWrapper.php new file mode 100644 index 0000000000..07844b2cec --- /dev/null +++ b/vendor/symfony/console/Helper/OutputWrapper.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Helper; + +/** + * Simple output wrapper for "tagged outputs" instead of wordwrap(). This solution is based on a StackOverflow + * answer: https://stackoverflow.com/a/20434776/1476819 from user557597 (alias SLN). + * + * (?: + * # -- Words/Characters + * ( # (1 start) + * (?> # Atomic Group - Match words with valid breaks + * .{1,16} # 1-N characters + * # Followed by one of 4 prioritized, non-linebreak whitespace + * (?: # break types: + * (?<= [^\S\r\n] ) # 1. - Behind a non-linebreak whitespace + * [^\S\r\n]? # ( optionally accept an extra non-linebreak whitespace ) + * | (?= \r? \n ) # 2. - Ahead a linebreak + * | $ # 3. - EOS + * | [^\S\r\n] # 4. - Accept an extra non-linebreak whitespace + * ) + * ) # End atomic group + * | + * .{1,16} # No valid word breaks, just break on the N'th character + * ) # (1 end) + * (?: \r? \n )? # Optional linebreak after Words/Characters + * | + * # -- Or, Linebreak + * (?: \r? \n | $ ) # Stand alone linebreak or at EOS + * ) + * + * @author Krisztián Ferenczi + * + * @see https://stackoverflow.com/a/20434776/1476819 + */ +final class OutputWrapper +{ + /** + * @var bool + */ + private $allowCutUrls = \false; + private const TAG_OPEN_REGEX_SEGMENT = '[a-z](?:[^\\\\<>]*+ | \\\\.)*'; + private const TAG_CLOSE_REGEX_SEGMENT = '[a-z][^<>]*+'; + private const URL_PATTERN = 'https?://\\S+'; + public function __construct(bool $allowCutUrls = \false) + { + $this->allowCutUrls = $allowCutUrls; + } + public function wrap(string $text, int $width, string $break = "\n") : string + { + if (!$width) { + return $text; + } + $tagPattern = \sprintf('<(?:(?:%s)|/(?:%s)?)>', self::TAG_OPEN_REGEX_SEGMENT, self::TAG_CLOSE_REGEX_SEGMENT); + $limitPattern = "{1,{$width}}"; + $patternBlocks = [$tagPattern]; + if (!$this->allowCutUrls) { + $patternBlocks[] = self::URL_PATTERN; + } + $patternBlocks[] = '.'; + $blocks = \implode('|', $patternBlocks); + $rowPattern = "(?:{$blocks}){$limitPattern}"; + $pattern = \sprintf('#(?:((?>(%1$s)((?<=[^\\S\\r\\n])[^\\S\\r\\n]?|(?=\\r?\\n)|$|[^\\S\\r\\n]))|(%1$s))(?:\\r?\\n)?|(?:\\r?\\n|$))#imux', $rowPattern); + $output = \rtrim(\preg_replace($pattern, '\\1' . $break, $text), $break); + return \str_replace(' ' . $break, $break, $output); + } +} diff --git a/vendor/symfony/console/Helper/ProcessHelper.php b/vendor/symfony/console/Helper/ProcessHelper.php new file mode 100644 index 0000000000..e1d93cf79b --- /dev/null +++ b/vendor/symfony/console/Helper/ProcessHelper.php @@ -0,0 +1,116 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Helper; + +use SwissKnife202405\Symfony\Component\Console\Output\ConsoleOutputInterface; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +use SwissKnife202405\Symfony\Component\Process\Exception\ProcessFailedException; +use SwissKnife202405\Symfony\Component\Process\Process; +/** + * The ProcessHelper class provides helpers to run external processes. + * + * @author Fabien Potencier + * + * @final + */ +class ProcessHelper extends Helper +{ + /** + * Runs an external process. + * + * @param array|Process $cmd An instance of Process or an array of the command and arguments + * @param callable|null $callback A PHP callback to run whenever there is some + * output available on STDOUT or STDERR + */ + public function run(OutputInterface $output, $cmd, ?string $error = null, ?callable $callback = null, int $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE) : Process + { + if (!\class_exists(Process::class)) { + throw new \LogicException('The ProcessHelper cannot be run as the Process component is not installed. Try running "compose require symfony/process".'); + } + if ($output instanceof ConsoleOutputInterface) { + $output = $output->getErrorOutput(); + } + $formatter = $this->getHelperSet()->get('debug_formatter'); + if ($cmd instanceof Process) { + $cmd = [$cmd]; + } + if (\is_string($cmd[0] ?? null)) { + $process = new Process($cmd); + $cmd = []; + } elseif (($cmd[0] ?? null) instanceof Process) { + $process = $cmd[0]; + unset($cmd[0]); + } else { + throw new \InvalidArgumentException(\sprintf('Invalid command provided to "%s()": the command should be an array whose first element is either the path to the binary to run or a "Process" object.', __METHOD__)); + } + if ($verbosity <= $output->getVerbosity()) { + $output->write($formatter->start(\spl_object_hash($process), $this->escapeString($process->getCommandLine()))); + } + if ($output->isDebug()) { + $callback = $this->wrapCallback($output, $process, $callback); + } + $process->run($callback, $cmd); + if ($verbosity <= $output->getVerbosity()) { + $message = $process->isSuccessful() ? 'Command ran successfully' : \sprintf('%s Command did not run successfully', $process->getExitCode()); + $output->write($formatter->stop(\spl_object_hash($process), $message, $process->isSuccessful())); + } + if (!$process->isSuccessful() && null !== $error) { + $output->writeln(\sprintf('%s', $this->escapeString($error))); + } + return $process; + } + /** + * Runs the process. + * + * This is identical to run() except that an exception is thrown if the process + * exits with a non-zero exit code. + * + * @param array|Process $cmd An instance of Process or a command to run + * @param callable|null $callback A PHP callback to run whenever there is some + * output available on STDOUT or STDERR + * + * @throws ProcessFailedException + * + * @see run() + */ + public function mustRun(OutputInterface $output, $cmd, ?string $error = null, ?callable $callback = null) : Process + { + $process = $this->run($output, $cmd, $error, $callback); + if (!$process->isSuccessful()) { + throw new ProcessFailedException($process); + } + return $process; + } + /** + * Wraps a Process callback to add debugging output. + */ + public function wrapCallback(OutputInterface $output, Process $process, ?callable $callback = null) : callable + { + if ($output instanceof ConsoleOutputInterface) { + $output = $output->getErrorOutput(); + } + $formatter = $this->getHelperSet()->get('debug_formatter'); + return function ($type, $buffer) use($output, $process, $callback, $formatter) { + $output->write($formatter->progress(\spl_object_hash($process), $this->escapeString($buffer), Process::ERR === $type)); + if (null !== $callback) { + $callback($type, $buffer); + } + }; + } + private function escapeString(string $str) : string + { + return \str_replace('<', '\\<', $str); + } + public function getName() : string + { + return 'process'; + } +} diff --git a/vendor/symfony/console/Helper/ProgressBar.php b/vendor/symfony/console/Helper/ProgressBar.php new file mode 100644 index 0000000000..78663f95a5 --- /dev/null +++ b/vendor/symfony/console/Helper/ProgressBar.php @@ -0,0 +1,597 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Helper; + +use SwissKnife202405\Symfony\Component\Console\Cursor; +use SwissKnife202405\Symfony\Component\Console\Exception\LogicException; +use SwissKnife202405\Symfony\Component\Console\Output\ConsoleOutputInterface; +use SwissKnife202405\Symfony\Component\Console\Output\ConsoleSectionOutput; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +use SwissKnife202405\Symfony\Component\Console\Terminal; +/** + * The ProgressBar provides helpers to display progress output. + * + * @author Fabien Potencier + * @author Chris Jones + */ +final class ProgressBar +{ + public const FORMAT_VERBOSE = 'verbose'; + public const FORMAT_VERY_VERBOSE = 'very_verbose'; + public const FORMAT_DEBUG = 'debug'; + public const FORMAT_NORMAL = 'normal'; + private const FORMAT_VERBOSE_NOMAX = 'verbose_nomax'; + private const FORMAT_VERY_VERBOSE_NOMAX = 'very_verbose_nomax'; + private const FORMAT_DEBUG_NOMAX = 'debug_nomax'; + private const FORMAT_NORMAL_NOMAX = 'normal_nomax'; + /** + * @var int + */ + private $barWidth = 28; + /** + * @var string + */ + private $barChar; + /** + * @var string + */ + private $emptyBarChar = '-'; + /** + * @var string + */ + private $progressChar = '>'; + /** + * @var string|null + */ + private $format; + /** + * @var string|null + */ + private $internalFormat; + /** + * @var int|null + */ + private $redrawFreq = 1; + /** + * @var int + */ + private $writeCount = 0; + /** + * @var float + */ + private $lastWriteTime = 0; + /** + * @var float + */ + private $minSecondsBetweenRedraws = 0; + /** + * @var float + */ + private $maxSecondsBetweenRedraws = 1; + /** + * @var \Symfony\Component\Console\Output\OutputInterface + */ + private $output; + /** + * @var int + */ + private $step = 0; + /** + * @var int + */ + private $startingStep = 0; + /** + * @var int|null + */ + private $max; + /** + * @var int + */ + private $startTime; + /** + * @var int + */ + private $stepWidth; + /** + * @var float + */ + private $percent = 0.0; + /** + * @var mixed[] + */ + private $messages = []; + /** + * @var bool + */ + private $overwrite = \true; + /** + * @var \Symfony\Component\Console\Terminal + */ + private $terminal; + /** + * @var string|null + */ + private $previousMessage; + /** + * @var \Symfony\Component\Console\Cursor + */ + private $cursor; + /** + * @var mixed[] + */ + private $placeholders = []; + /** + * @var mixed[] + */ + private static $formatters; + /** + * @var mixed[] + */ + private static $formats; + /** + * @param int $max Maximum steps (0 if unknown) + */ + public function __construct(OutputInterface $output, int $max = 0, float $minSecondsBetweenRedraws = 1 / 25) + { + if ($output instanceof ConsoleOutputInterface) { + $output = $output->getErrorOutput(); + } + $this->output = $output; + $this->setMaxSteps($max); + $this->terminal = new Terminal(); + if (0 < $minSecondsBetweenRedraws) { + $this->redrawFreq = null; + $this->minSecondsBetweenRedraws = $minSecondsBetweenRedraws; + } + if (!$this->output->isDecorated()) { + // disable overwrite when output does not support ANSI codes. + $this->overwrite = \false; + // set a reasonable redraw frequency so output isn't flooded + $this->redrawFreq = null; + } + $this->startTime = \time(); + $this->cursor = new Cursor($output); + } + /** + * Sets a placeholder formatter for a given name, globally for all instances of ProgressBar. + * + * This method also allow you to override an existing placeholder. + * + * @param string $name The placeholder name (including the delimiter char like %) + * @param callable(ProgressBar):string $callable A PHP callable + */ + public static function setPlaceholderFormatterDefinition(string $name, callable $callable) : void + { + self::$formatters = self::$formatters ?? self::initPlaceholderFormatters(); + self::$formatters[$name] = $callable; + } + /** + * Gets the placeholder formatter for a given name. + * + * @param string $name The placeholder name (including the delimiter char like %) + */ + public static function getPlaceholderFormatterDefinition(string $name) : ?callable + { + self::$formatters = self::$formatters ?? self::initPlaceholderFormatters(); + return self::$formatters[$name] ?? null; + } + /** + * Sets a placeholder formatter for a given name, for this instance only. + * + * @param callable(ProgressBar):string $callable A PHP callable + */ + public function setPlaceholderFormatter(string $name, callable $callable) : void + { + $this->placeholders[$name] = $callable; + } + /** + * Gets the placeholder formatter for a given name. + * + * @param string $name The placeholder name (including the delimiter char like %) + */ + public function getPlaceholderFormatter(string $name) : ?callable + { + return $this->placeholders[$name] ?? $this::getPlaceholderFormatterDefinition($name); + } + /** + * Sets a format for a given name. + * + * This method also allow you to override an existing format. + * + * @param string $name The format name + * @param string $format A format string + */ + public static function setFormatDefinition(string $name, string $format) : void + { + self::$formats = self::$formats ?? self::initFormats(); + self::$formats[$name] = $format; + } + /** + * Gets the format for a given name. + * + * @param string $name The format name + */ + public static function getFormatDefinition(string $name) : ?string + { + self::$formats = self::$formats ?? self::initFormats(); + return self::$formats[$name] ?? null; + } + /** + * Associates a text with a named placeholder. + * + * The text is displayed when the progress bar is rendered but only + * when the corresponding placeholder is part of the custom format line + * (by wrapping the name with %). + * + * @param string $message The text to associate with the placeholder + * @param string $name The name of the placeholder + */ + public function setMessage(string $message, string $name = 'message') : void + { + $this->messages[$name] = $message; + } + public function getMessage(string $name = 'message') : ?string + { + return $this->messages[$name] ?? null; + } + public function getStartTime() : int + { + return $this->startTime; + } + public function getMaxSteps() : int + { + return $this->max; + } + public function getProgress() : int + { + return $this->step; + } + private function getStepWidth() : int + { + return $this->stepWidth; + } + public function getProgressPercent() : float + { + return $this->percent; + } + public function getBarOffset() : float + { + return \floor($this->max ? $this->percent * $this->barWidth : (null === $this->redrawFreq ? (int) (\min(5, $this->barWidth / 15) * $this->writeCount) : $this->step) % $this->barWidth); + } + public function getEstimated() : float + { + if (0 === $this->step || $this->step === $this->startingStep) { + return 0; + } + return \round((\time() - $this->startTime) / ($this->step - $this->startingStep) * $this->max); + } + public function getRemaining() : float + { + if (!$this->step) { + return 0; + } + return \round((\time() - $this->startTime) / ($this->step - $this->startingStep) * ($this->max - $this->step)); + } + public function setBarWidth(int $size) : void + { + $this->barWidth = \max(1, $size); + } + public function getBarWidth() : int + { + return $this->barWidth; + } + public function setBarCharacter(string $char) : void + { + $this->barChar = $char; + } + public function getBarCharacter() : string + { + return $this->barChar ?? ($this->max ? '=' : $this->emptyBarChar); + } + public function setEmptyBarCharacter(string $char) : void + { + $this->emptyBarChar = $char; + } + public function getEmptyBarCharacter() : string + { + return $this->emptyBarChar; + } + public function setProgressCharacter(string $char) : void + { + $this->progressChar = $char; + } + public function getProgressCharacter() : string + { + return $this->progressChar; + } + public function setFormat(string $format) : void + { + $this->format = null; + $this->internalFormat = $format; + } + /** + * Sets the redraw frequency. + * + * @param int|null $freq The frequency in steps + */ + public function setRedrawFrequency(?int $freq) : void + { + $this->redrawFreq = null !== $freq ? \max(1, $freq) : null; + } + public function minSecondsBetweenRedraws(float $seconds) : void + { + $this->minSecondsBetweenRedraws = $seconds; + } + public function maxSecondsBetweenRedraws(float $seconds) : void + { + $this->maxSecondsBetweenRedraws = $seconds; + } + /** + * Returns an iterator that will automatically update the progress bar when iterated. + * + * @template TKey + * @template TValue + * + * @param iterable $iterable + * @param int|null $max Number of steps to complete the bar (0 if indeterminate), if null it will be inferred from $iterable + * + * @return iterable + */ + public function iterate(iterable $iterable, ?int $max = null) : iterable + { + $this->start($max ?? (\is_array($iterable) || $iterable instanceof \Countable ? \count($iterable) : 0)); + foreach ($iterable as $key => $value) { + (yield $key => $value); + $this->advance(); + } + $this->finish(); + } + /** + * Starts the progress output. + * + * @param int|null $max Number of steps to complete the bar (0 if indeterminate), null to leave unchanged + * @param int $startAt The starting point of the bar (useful e.g. when resuming a previously started bar) + */ + public function start(?int $max = null, int $startAt = 0) : void + { + $this->startTime = \time(); + $this->step = $startAt; + $this->startingStep = $startAt; + $startAt > 0 ? $this->setProgress($startAt) : ($this->percent = 0.0); + if (null !== $max) { + $this->setMaxSteps($max); + } + $this->display(); + } + /** + * Advances the progress output X steps. + * + * @param int $step Number of steps to advance + */ + public function advance(int $step = 1) : void + { + $this->setProgress($this->step + $step); + } + /** + * Sets whether to overwrite the progressbar, false for new line. + */ + public function setOverwrite(bool $overwrite) : void + { + $this->overwrite = $overwrite; + } + public function setProgress(int $step) : void + { + if ($this->max && $step > $this->max) { + $this->max = $step; + } elseif ($step < 0) { + $step = 0; + } + $redrawFreq = $this->redrawFreq ?? ($this->max ?: 10) / 10; + $prevPeriod = (int) ($this->step / $redrawFreq); + $currPeriod = (int) ($step / $redrawFreq); + $this->step = $step; + $this->percent = $this->max ? (float) $this->step / $this->max : 0; + $timeInterval = \microtime(\true) - $this->lastWriteTime; + // Draw regardless of other limits + if ($this->max === $step) { + $this->display(); + return; + } + // Throttling + if ($timeInterval < $this->minSecondsBetweenRedraws) { + return; + } + // Draw each step period, but not too late + if ($prevPeriod !== $currPeriod || $timeInterval >= $this->maxSecondsBetweenRedraws) { + $this->display(); + } + } + public function setMaxSteps(int $max) : void + { + $this->format = null; + $this->max = \max(0, $max); + $this->stepWidth = $this->max ? Helper::width((string) $this->max) : 4; + } + /** + * Finishes the progress output. + */ + public function finish() : void + { + if (!$this->max) { + $this->max = $this->step; + } + if ($this->step === $this->max && !$this->overwrite) { + // prevent double 100% output + return; + } + $this->setProgress($this->max); + } + /** + * Outputs the current progress string. + */ + public function display() : void + { + if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) { + return; + } + if (null === $this->format) { + $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat()); + } + $this->overwrite($this->buildLine()); + } + /** + * Removes the progress bar from the current line. + * + * This is useful if you wish to write some output + * while a progress bar is running. + * Call display() to show the progress bar again. + */ + public function clear() : void + { + if (!$this->overwrite) { + return; + } + if (null === $this->format) { + $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat()); + } + $this->overwrite(''); + } + private function setRealFormat(string $format) : void + { + // try to use the _nomax variant if available + if (!$this->max && null !== self::getFormatDefinition($format . '_nomax')) { + $this->format = self::getFormatDefinition($format . '_nomax'); + } elseif (null !== self::getFormatDefinition($format)) { + $this->format = self::getFormatDefinition($format); + } else { + $this->format = $format; + } + } + /** + * Overwrites a previous message to the output. + */ + private function overwrite(string $message) : void + { + if ($this->previousMessage === $message) { + return; + } + $originalMessage = $message; + if ($this->overwrite) { + if (null !== $this->previousMessage) { + if ($this->output instanceof ConsoleSectionOutput) { + $messageLines = \explode("\n", $this->previousMessage); + $lineCount = \count($messageLines); + foreach ($messageLines as $messageLine) { + $messageLineLength = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $messageLine)); + if ($messageLineLength > $this->terminal->getWidth()) { + $lineCount += \floor($messageLineLength / $this->terminal->getWidth()); + } + } + $this->output->clear($lineCount); + } else { + $lineCount = \substr_count($this->previousMessage, "\n"); + for ($i = 0; $i < $lineCount; ++$i) { + $this->cursor->moveToColumn(1); + $this->cursor->clearLine(); + $this->cursor->moveUp(); + } + $this->cursor->moveToColumn(1); + $this->cursor->clearLine(); + } + } + } elseif ($this->step > 0) { + $message = \PHP_EOL . $message; + } + $this->previousMessage = $originalMessage; + $this->lastWriteTime = \microtime(\true); + $this->output->write($message); + ++$this->writeCount; + } + private function determineBestFormat() : string + { + switch ($this->output->getVerbosity()) { + case OutputInterface::VERBOSITY_VERBOSE: + return $this->max ? self::FORMAT_VERBOSE : self::FORMAT_VERBOSE_NOMAX; + case OutputInterface::VERBOSITY_VERY_VERBOSE: + return $this->max ? self::FORMAT_VERY_VERBOSE : self::FORMAT_VERY_VERBOSE_NOMAX; + case OutputInterface::VERBOSITY_DEBUG: + return $this->max ? self::FORMAT_DEBUG : self::FORMAT_DEBUG_NOMAX; + default: + return $this->max ? self::FORMAT_NORMAL : self::FORMAT_NORMAL_NOMAX; + } + } + private static function initPlaceholderFormatters() : array + { + return ['bar' => function (self $bar, OutputInterface $output) { + $completeBars = $bar->getBarOffset(); + $display = \str_repeat($bar->getBarCharacter(), $completeBars); + if ($completeBars < $bar->getBarWidth()) { + $emptyBars = $bar->getBarWidth() - $completeBars - Helper::length(Helper::removeDecoration($output->getFormatter(), $bar->getProgressCharacter())); + $display .= $bar->getProgressCharacter() . \str_repeat($bar->getEmptyBarCharacter(), $emptyBars); + } + return $display; + }, 'elapsed' => function (self $bar) { + return Helper::formatTime(\time() - $bar->getStartTime(), 2); + }, 'remaining' => function (self $bar) { + if (!$bar->getMaxSteps()) { + throw new LogicException('Unable to display the remaining time if the maximum number of steps is not set.'); + } + return Helper::formatTime($bar->getRemaining(), 2); + }, 'estimated' => function (self $bar) { + if (!$bar->getMaxSteps()) { + throw new LogicException('Unable to display the estimated time if the maximum number of steps is not set.'); + } + return Helper::formatTime($bar->getEstimated(), 2); + }, 'memory' => function (self $bar) { + return Helper::formatMemory(\memory_get_usage(\true)); + }, 'current' => function (self $bar) { + return \str_pad($bar->getProgress(), $bar->getStepWidth(), ' ', \STR_PAD_LEFT); + }, 'max' => function (self $bar) { + return $bar->getMaxSteps(); + }, 'percent' => function (self $bar) { + return \floor($bar->getProgressPercent() * 100); + }]; + } + private static function initFormats() : array + { + return [self::FORMAT_NORMAL => ' %current%/%max% [%bar%] %percent:3s%%', self::FORMAT_NORMAL_NOMAX => ' %current% [%bar%]', self::FORMAT_VERBOSE => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%', self::FORMAT_VERBOSE_NOMAX => ' %current% [%bar%] %elapsed:6s%', self::FORMAT_VERY_VERBOSE => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s%', self::FORMAT_VERY_VERBOSE_NOMAX => ' %current% [%bar%] %elapsed:6s%', self::FORMAT_DEBUG => ' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %memory:6s%', self::FORMAT_DEBUG_NOMAX => ' %current% [%bar%] %elapsed:6s% %memory:6s%']; + } + private function buildLine() : string + { + \assert(null !== $this->format); + $regex = "{%([a-z\\-_]+)(?:\\:([^%]+))?%}i"; + $callback = function ($matches) { + if ($formatter = $this->getPlaceholderFormatter($matches[1])) { + $text = $formatter($this, $this->output); + } elseif (isset($this->messages[$matches[1]])) { + $text = $this->messages[$matches[1]]; + } else { + return $matches[0]; + } + if (isset($matches[2])) { + $text = \sprintf('%' . $matches[2], $text); + } + return $text; + }; + $line = \preg_replace_callback($regex, $callback, $this->format); + // gets string length for each sub line with multiline format + $linesLength = \array_map(function ($subLine) { + return Helper::width(Helper::removeDecoration($this->output->getFormatter(), \rtrim($subLine, "\r"))); + }, \explode("\n", $line)); + $linesWidth = \max($linesLength); + $terminalWidth = $this->terminal->getWidth(); + if ($linesWidth <= $terminalWidth) { + return $line; + } + $this->setBarWidth($this->barWidth - $linesWidth + $terminalWidth); + return \preg_replace_callback($regex, $callback, $this->format); + } +} diff --git a/vendor/symfony/console/Helper/ProgressIndicator.php b/vendor/symfony/console/Helper/ProgressIndicator.php new file mode 100644 index 0000000000..f669f3c2bc --- /dev/null +++ b/vendor/symfony/console/Helper/ProgressIndicator.php @@ -0,0 +1,225 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Helper; + +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +use SwissKnife202405\Symfony\Component\Console\Exception\LogicException; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +/** + * @author Kevin Bond + */ +class ProgressIndicator +{ + private const FORMATS = ['normal' => ' %indicator% %message%', 'normal_no_ansi' => ' %message%', 'verbose' => ' %indicator% %message% (%elapsed:6s%)', 'verbose_no_ansi' => ' %message% (%elapsed:6s%)', 'very_verbose' => ' %indicator% %message% (%elapsed:6s%, %memory:6s%)', 'very_verbose_no_ansi' => ' %message% (%elapsed:6s%, %memory:6s%)']; + /** + * @var \Symfony\Component\Console\Output\OutputInterface + */ + private $output; + /** + * @var int + */ + private $startTime; + /** + * @var string|null + */ + private $format; + /** + * @var string|null + */ + private $message; + /** + * @var mixed[] + */ + private $indicatorValues; + /** + * @var int + */ + private $indicatorCurrent; + /** + * @var int + */ + private $indicatorChangeInterval; + /** + * @var float + */ + private $indicatorUpdateTime; + /** + * @var bool + */ + private $started = \false; + /** + * @var array + */ + private static $formatters; + /** + * @param int $indicatorChangeInterval Change interval in milliseconds + * @param array|null $indicatorValues Animated indicator characters + */ + public function __construct(OutputInterface $output, ?string $format = null, int $indicatorChangeInterval = 100, ?array $indicatorValues = null) + { + $this->output = $output; + $format = $format ?? $this->determineBestFormat(); + $indicatorValues = $indicatorValues ?? ['-', '\\', '|', '/']; + $indicatorValues = \array_values($indicatorValues); + if (2 > \count($indicatorValues)) { + throw new InvalidArgumentException('Must have at least 2 indicator value characters.'); + } + $this->format = self::getFormatDefinition($format); + $this->indicatorChangeInterval = $indicatorChangeInterval; + $this->indicatorValues = $indicatorValues; + $this->startTime = \time(); + } + /** + * Sets the current indicator message. + * + * @return void + */ + public function setMessage(?string $message) + { + $this->message = $message; + $this->display(); + } + /** + * Starts the indicator output. + * + * @return void + */ + public function start(string $message) + { + if ($this->started) { + throw new LogicException('Progress indicator already started.'); + } + $this->message = $message; + $this->started = \true; + $this->startTime = \time(); + $this->indicatorUpdateTime = $this->getCurrentTimeInMilliseconds() + $this->indicatorChangeInterval; + $this->indicatorCurrent = 0; + $this->display(); + } + /** + * Advances the indicator. + * + * @return void + */ + public function advance() + { + if (!$this->started) { + throw new LogicException('Progress indicator has not yet been started.'); + } + if (!$this->output->isDecorated()) { + return; + } + $currentTime = $this->getCurrentTimeInMilliseconds(); + if ($currentTime < $this->indicatorUpdateTime) { + return; + } + $this->indicatorUpdateTime = $currentTime + $this->indicatorChangeInterval; + ++$this->indicatorCurrent; + $this->display(); + } + /** + * Finish the indicator with message. + * + * @return void + */ + public function finish(string $message) + { + if (!$this->started) { + throw new LogicException('Progress indicator has not yet been started.'); + } + $this->message = $message; + $this->display(); + $this->output->writeln(''); + $this->started = \false; + } + /** + * Gets the format for a given name. + */ + public static function getFormatDefinition(string $name) : ?string + { + return self::FORMATS[$name] ?? null; + } + /** + * Sets a placeholder formatter for a given name. + * + * This method also allow you to override an existing placeholder. + * + * @return void + */ + public static function setPlaceholderFormatterDefinition(string $name, callable $callable) + { + self::$formatters = self::$formatters ?? self::initPlaceholderFormatters(); + self::$formatters[$name] = $callable; + } + /** + * Gets the placeholder formatter for a given name (including the delimiter char like %). + */ + public static function getPlaceholderFormatterDefinition(string $name) : ?callable + { + self::$formatters = self::$formatters ?? self::initPlaceholderFormatters(); + return self::$formatters[$name] ?? null; + } + private function display() : void + { + if (OutputInterface::VERBOSITY_QUIET === $this->output->getVerbosity()) { + return; + } + $this->overwrite(\preg_replace_callback("{%([a-z\\-_]+)(?:\\:([^%]+))?%}i", function ($matches) { + if ($formatter = self::getPlaceholderFormatterDefinition($matches[1])) { + return $formatter($this); + } + return $matches[0]; + }, $this->format ?? '')); + } + private function determineBestFormat() : string + { + switch ($this->output->getVerbosity()) { + case OutputInterface::VERBOSITY_VERBOSE: + return $this->output->isDecorated() ? 'verbose' : 'verbose_no_ansi'; + case OutputInterface::VERBOSITY_VERY_VERBOSE: + case OutputInterface::VERBOSITY_DEBUG: + return $this->output->isDecorated() ? 'very_verbose' : 'very_verbose_no_ansi'; + default: + return $this->output->isDecorated() ? 'normal' : 'normal_no_ansi'; + } + } + /** + * Overwrites a previous message to the output. + */ + private function overwrite(string $message) : void + { + if ($this->output->isDecorated()) { + $this->output->write("\r\x1b[2K"); + $this->output->write($message); + } else { + $this->output->writeln($message); + } + } + private function getCurrentTimeInMilliseconds() : float + { + return \round(\microtime(\true) * 1000); + } + /** + * @return array + */ + private static function initPlaceholderFormatters() : array + { + return ['indicator' => function (self $indicator) { + return $indicator->indicatorValues[$indicator->indicatorCurrent % \count($indicator->indicatorValues)]; + }, 'message' => function (self $indicator) { + return $indicator->message; + }, 'elapsed' => function (self $indicator) { + return Helper::formatTime(\time() - $indicator->startTime, 2); + }, 'memory' => function () { + return Helper::formatMemory(\memory_get_usage(\true)); + }]; + } +} diff --git a/vendor/symfony/console/Helper/QuestionHelper.php b/vendor/symfony/console/Helper/QuestionHelper.php new file mode 100644 index 0000000000..ba700943f2 --- /dev/null +++ b/vendor/symfony/console/Helper/QuestionHelper.php @@ -0,0 +1,508 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Helper; + +use SwissKnife202405\Symfony\Component\Console\Cursor; +use SwissKnife202405\Symfony\Component\Console\Exception\MissingInputException; +use SwissKnife202405\Symfony\Component\Console\Exception\RuntimeException; +use SwissKnife202405\Symfony\Component\Console\Formatter\OutputFormatter; +use SwissKnife202405\Symfony\Component\Console\Formatter\OutputFormatterStyle; +use SwissKnife202405\Symfony\Component\Console\Input\InputInterface; +use SwissKnife202405\Symfony\Component\Console\Input\StreamableInputInterface; +use SwissKnife202405\Symfony\Component\Console\Output\ConsoleOutputInterface; +use SwissKnife202405\Symfony\Component\Console\Output\ConsoleSectionOutput; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +use SwissKnife202405\Symfony\Component\Console\Question\ChoiceQuestion; +use SwissKnife202405\Symfony\Component\Console\Question\Question; +use SwissKnife202405\Symfony\Component\Console\Terminal; +use function SwissKnife202405\Symfony\Component\String\s; +/** + * The QuestionHelper class provides helpers to interact with the user. + * + * @author Fabien Potencier + */ +class QuestionHelper extends Helper +{ + /** + * @var resource|null + */ + private $inputStream; + /** + * @var bool + */ + private static $stty = \true; + /** + * @var bool + */ + private static $stdinIsInteractive; + /** + * Asks a question to the user. + * + * @return mixed The user answer + * + * @throws RuntimeException If there is no data to read in the input stream + */ + public function ask(InputInterface $input, OutputInterface $output, Question $question) + { + if ($output instanceof ConsoleOutputInterface) { + $output = $output->getErrorOutput(); + } + if (!$input->isInteractive()) { + return $this->getDefaultAnswer($question); + } + if ($input instanceof StreamableInputInterface && ($stream = $input->getStream())) { + $this->inputStream = $stream; + } + try { + if (!$question->getValidator()) { + return $this->doAsk($output, $question); + } + $interviewer = function () use($output, $question) { + return $this->doAsk($output, $question); + }; + return $this->validateAttempts($interviewer, $output, $question); + } catch (MissingInputException $exception) { + $input->setInteractive(\false); + if (null === ($fallbackOutput = $this->getDefaultAnswer($question))) { + throw $exception; + } + return $fallbackOutput; + } + } + public function getName() : string + { + return 'question'; + } + /** + * Prevents usage of stty. + * + * @return void + */ + public static function disableStty() + { + self::$stty = \false; + } + /** + * Asks the question to the user. + * + * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden + * @return mixed + */ + private function doAsk(OutputInterface $output, Question $question) + { + $this->writePrompt($output, $question); + $inputStream = $this->inputStream ?: \STDIN; + $autocomplete = $question->getAutocompleterCallback(); + if (null === $autocomplete || !self::$stty || !Terminal::hasSttyAvailable()) { + $ret = \false; + if ($question->isHidden()) { + try { + $hiddenResponse = $this->getHiddenResponse($output, $inputStream, $question->isTrimmable()); + $ret = $question->isTrimmable() ? \trim($hiddenResponse) : $hiddenResponse; + } catch (RuntimeException $e) { + if (!$question->isHiddenFallback()) { + throw $e; + } + } + } + if (\false === $ret) { + $isBlocked = \stream_get_meta_data($inputStream)['blocked'] ?? \true; + if (!$isBlocked) { + \stream_set_blocking($inputStream, \true); + } + $ret = $this->readInput($inputStream, $question); + if (!$isBlocked) { + \stream_set_blocking($inputStream, \false); + } + if (\false === $ret) { + throw new MissingInputException('Aborted.'); + } + if ($question->isTrimmable()) { + $ret = \trim($ret); + } + } + } else { + $autocomplete = $this->autocomplete($output, $question, $inputStream, $autocomplete); + $ret = $question->isTrimmable() ? \trim($autocomplete) : $autocomplete; + } + if ($output instanceof ConsoleSectionOutput) { + $output->addContent(''); + // add EOL to the question + $output->addContent($ret); + } + $ret = \strlen($ret) > 0 ? $ret : $question->getDefault(); + if ($normalizer = $question->getNormalizer()) { + return $normalizer($ret); + } + return $ret; + } + /** + * @return mixed + */ + private function getDefaultAnswer(Question $question) + { + $default = $question->getDefault(); + if (null === $default) { + return $default; + } + if ($validator = $question->getValidator()) { + return \call_user_func($validator, $default); + } elseif ($question instanceof ChoiceQuestion) { + $choices = $question->getChoices(); + if (!$question->isMultiselect()) { + return $choices[$default] ?? $default; + } + $default = \explode(',', $default); + foreach ($default as $k => $v) { + $v = $question->isTrimmable() ? \trim($v) : $v; + $default[$k] = $choices[$v] ?? $v; + } + } + return $default; + } + /** + * Outputs the question prompt. + * + * @return void + */ + protected function writePrompt(OutputInterface $output, Question $question) + { + $message = $question->getQuestion(); + if ($question instanceof ChoiceQuestion) { + $output->writeln(\array_merge([$question->getQuestion()], $this->formatChoiceQuestionChoices($question, 'info'))); + $message = $question->getPrompt(); + } + $output->write($message); + } + /** + * @return string[] + */ + protected function formatChoiceQuestionChoices(ChoiceQuestion $question, string $tag) : array + { + $messages = []; + $maxWidth = \max(\array_map([__CLASS__, 'width'], \array_keys($choices = $question->getChoices()))); + foreach ($choices as $key => $value) { + $padding = \str_repeat(' ', $maxWidth - self::width($key)); + $messages[] = \sprintf(" [<{$tag}>%s{$padding}] %s", $key, $value); + } + return $messages; + } + /** + * Outputs an error message. + * + * @return void + */ + protected function writeError(OutputInterface $output, \Exception $error) + { + if (null !== $this->getHelperSet() && $this->getHelperSet()->has('formatter')) { + $message = $this->getHelperSet()->get('formatter')->formatBlock($error->getMessage(), 'error'); + } else { + $message = '' . $error->getMessage() . ''; + } + $output->writeln($message); + } + /** + * Autocompletes a question. + * + * @param resource $inputStream + */ + private function autocomplete(OutputInterface $output, Question $question, $inputStream, callable $autocomplete) : string + { + $cursor = new Cursor($output, $inputStream); + $fullChoice = ''; + $ret = ''; + $i = 0; + $ofs = -1; + $matches = $autocomplete($ret); + $numMatches = \count($matches); + $sttyMode = \shell_exec('stty -g'); + $isStdin = 'php://stdin' === (\stream_get_meta_data($inputStream)['uri'] ?? null); + $r = [$inputStream]; + $w = []; + // Disable icanon (so we can fread each keypress) and echo (we'll do echoing here instead) + \shell_exec('stty -icanon -echo'); + // Add highlighted text style + $output->getFormatter()->setStyle('hl', new OutputFormatterStyle('black', 'white')); + // Read a keypress + while (!\feof($inputStream)) { + while ($isStdin && 0 === @\stream_select($r, $w, $w, 0, 100)) { + // Give signal handlers a chance to run + $r = [$inputStream]; + } + $c = \fread($inputStream, 1); + // as opposed to fgets(), fread() returns an empty string when the stream content is empty, not false. + if (\false === $c || '' === $ret && '' === $c && null === $question->getDefault()) { + \shell_exec('stty ' . $sttyMode); + throw new MissingInputException('Aborted.'); + } elseif ("" === $c) { + // Backspace Character + if (0 === $numMatches && 0 !== $i) { + --$i; + $cursor->moveLeft(s($fullChoice)->slice(-1)->width(\false)); + $fullChoice = self::substr($fullChoice, 0, $i); + } + if (0 === $i) { + $ofs = -1; + $matches = $autocomplete($ret); + $numMatches = \count($matches); + } else { + $numMatches = 0; + } + // Pop the last character off the end of our string + $ret = self::substr($ret, 0, $i); + } elseif ("\x1b" === $c) { + // Did we read an escape sequence? + $c .= \fread($inputStream, 2); + // A = Up Arrow. B = Down Arrow + if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) { + if ('A' === $c[2] && -1 === $ofs) { + $ofs = 0; + } + if (0 === $numMatches) { + continue; + } + $ofs += 'A' === $c[2] ? -1 : 1; + $ofs = ($numMatches + $ofs) % $numMatches; + } + } elseif (\ord($c) < 32) { + if ("\t" === $c || "\n" === $c) { + if ($numMatches > 0 && -1 !== $ofs) { + $ret = (string) $matches[$ofs]; + // Echo out remaining chars for current match + $remainingCharacters = \substr($ret, \strlen(\trim($this->mostRecentlyEnteredValue($fullChoice)))); + $output->write($remainingCharacters); + $fullChoice .= $remainingCharacters; + $i = \false === ($encoding = \mb_detect_encoding($fullChoice, null, \true)) ? \strlen($fullChoice) : \mb_strlen($fullChoice, $encoding); + $matches = \array_filter($autocomplete($ret), function ($match) use($ret) { + return '' === $ret || \strncmp($match, $ret, \strlen($ret)) === 0; + }); + $numMatches = \count($matches); + $ofs = -1; + } + if ("\n" === $c) { + $output->write($c); + break; + } + $numMatches = 0; + } + continue; + } else { + if ("\x80" <= $c) { + $c .= \fread($inputStream, ["\xc0" => 1, "\xd0" => 1, "\xe0" => 2, "\xf0" => 3][$c & "\xf0"]); + } + $output->write($c); + $ret .= $c; + $fullChoice .= $c; + ++$i; + $tempRet = $ret; + if ($question instanceof ChoiceQuestion && $question->isMultiselect()) { + $tempRet = $this->mostRecentlyEnteredValue($fullChoice); + } + $numMatches = 0; + $ofs = 0; + foreach ($autocomplete($ret) as $value) { + // If typed characters match the beginning chunk of value (e.g. [AcmeDe]moBundle) + if (\strncmp($value, $tempRet, \strlen($tempRet)) === 0) { + $matches[$numMatches++] = $value; + } + } + } + $cursor->clearLineAfter(); + if ($numMatches > 0 && -1 !== $ofs) { + $cursor->savePosition(); + // Write highlighted text, complete the partially entered response + $charactersEntered = \strlen(\trim($this->mostRecentlyEnteredValue($fullChoice))); + $output->write('' . OutputFormatter::escapeTrailingBackslash(\substr($matches[$ofs], $charactersEntered)) . ''); + $cursor->restorePosition(); + } + } + // Reset stty so it behaves normally again + \shell_exec('stty ' . $sttyMode); + return $fullChoice; + } + private function mostRecentlyEnteredValue(string $entered) : string + { + // Determine the most recent value that the user entered + if (\strpos($entered, ',') === \false) { + return $entered; + } + $choices = \explode(',', $entered); + if ('' !== ($lastChoice = \trim($choices[\count($choices) - 1]))) { + return $lastChoice; + } + return $entered; + } + /** + * Gets a hidden response from user. + * + * @param resource $inputStream The handler resource + * @param bool $trimmable Is the answer trimmable + * + * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden + */ + private function getHiddenResponse(OutputInterface $output, $inputStream, bool $trimmable = \true) : string + { + if ('\\' === \DIRECTORY_SEPARATOR) { + $exe = __DIR__ . '/../Resources/bin/hiddeninput.exe'; + // handle code running from a phar + if (\strncmp(__FILE__, 'phar:', \strlen('phar:')) === 0) { + $tmpExe = \sys_get_temp_dir() . '/hiddeninput.exe'; + \copy($exe, $tmpExe); + $exe = $tmpExe; + } + $sExec = \shell_exec('"' . $exe . '"'); + $value = $trimmable ? \rtrim($sExec) : $sExec; + $output->writeln(''); + if (isset($tmpExe)) { + \unlink($tmpExe); + } + return $value; + } + if (self::$stty && Terminal::hasSttyAvailable()) { + $sttyMode = \shell_exec('stty -g'); + \shell_exec('stty -echo'); + } elseif ($this->isInteractiveInput($inputStream)) { + throw new RuntimeException('Unable to hide the response.'); + } + $value = \fgets($inputStream, 4096); + if (4095 === \strlen($value)) { + $errOutput = $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output; + $errOutput->warning('The value was possibly truncated by your shell or terminal emulator'); + } + if (self::$stty && Terminal::hasSttyAvailable()) { + \shell_exec('stty ' . $sttyMode); + } + if (\false === $value) { + throw new MissingInputException('Aborted.'); + } + if ($trimmable) { + $value = \trim($value); + } + $output->writeln(''); + return $value; + } + /** + * Validates an attempt. + * + * @param callable $interviewer A callable that will ask for a question and return the result + * + * @throws \Exception In case the max number of attempts has been reached and no valid response has been given + * @return mixed + */ + private function validateAttempts(callable $interviewer, OutputInterface $output, Question $question) + { + $error = null; + $attempts = $question->getMaxAttempts(); + while (null === $attempts || $attempts--) { + if (null !== $error) { + $this->writeError($output, $error); + } + try { + return $question->getValidator()($interviewer()); + } catch (RuntimeException $e) { + throw $e; + } catch (\Exception $error) { + } + } + throw $error; + } + private function isInteractiveInput($inputStream) : bool + { + if ('php://stdin' !== (\stream_get_meta_data($inputStream)['uri'] ?? null)) { + return \false; + } + if (isset(self::$stdinIsInteractive)) { + return self::$stdinIsInteractive; + } + return self::$stdinIsInteractive = @\stream_isatty(\fopen('php://stdin', 'r')); + } + /** + * Reads one or more lines of input and returns what is read. + * + * @param resource $inputStream The handler resource + * @param Question $question The question being asked + * @return string|false + */ + private function readInput($inputStream, Question $question) + { + if (!$question->isMultiline()) { + $cp = $this->setIOCodepage(); + $ret = \fgets($inputStream, 4096); + return $this->resetIOCodepage($cp, $ret); + } + $multiLineStreamReader = $this->cloneInputStream($inputStream); + if (null === $multiLineStreamReader) { + return \false; + } + $ret = ''; + $cp = $this->setIOCodepage(); + while (\false !== ($char = \fgetc($multiLineStreamReader))) { + if (\PHP_EOL === "{$ret}{$char}") { + break; + } + $ret .= $char; + } + return $this->resetIOCodepage($cp, $ret); + } + private function setIOCodepage() : int + { + if (\function_exists('sapi_windows_cp_set')) { + $cp = \sapi_windows_cp_get(); + \sapi_windows_cp_set(\sapi_windows_cp_get('oem')); + return $cp; + } + return 0; + } + /** + * Sets console I/O to the specified code page and converts the user input. + * @param string|false $input + * @return string|false + */ + private function resetIOCodepage(int $cp, $input) + { + if (0 !== $cp) { + \sapi_windows_cp_set($cp); + if (\false !== $input && '' !== $input) { + $input = \sapi_windows_cp_conv(\sapi_windows_cp_get('oem'), $cp, $input); + } + } + return $input; + } + /** + * Clones an input stream in order to act on one instance of the same + * stream without affecting the other instance. + * + * @param resource $inputStream The handler resource + * + * @return resource|null The cloned resource, null in case it could not be cloned + */ + private function cloneInputStream($inputStream) + { + $streamMetaData = \stream_get_meta_data($inputStream); + $seekable = $streamMetaData['seekable'] ?? \false; + $mode = $streamMetaData['mode'] ?? 'rb'; + $uri = $streamMetaData['uri'] ?? null; + if (null === $uri) { + return null; + } + $cloneStream = \fopen($uri, $mode); + // For seekable and writable streams, add all the same data to the + // cloned stream and then seek to the same offset. + if (\true === $seekable && !\in_array($mode, ['r', 'rb', 'rt'])) { + $offset = \ftell($inputStream); + \rewind($inputStream); + \stream_copy_to_stream($inputStream, $cloneStream); + \fseek($inputStream, $offset); + \fseek($cloneStream, $offset); + } + return $cloneStream; + } +} diff --git a/vendor/symfony/console/Helper/SymfonyQuestionHelper.php b/vendor/symfony/console/Helper/SymfonyQuestionHelper.php new file mode 100644 index 0000000000..d2ac9f6f8c --- /dev/null +++ b/vendor/symfony/console/Helper/SymfonyQuestionHelper.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Helper; + +use SwissKnife202405\Symfony\Component\Console\Formatter\OutputFormatter; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +use SwissKnife202405\Symfony\Component\Console\Question\ChoiceQuestion; +use SwissKnife202405\Symfony\Component\Console\Question\ConfirmationQuestion; +use SwissKnife202405\Symfony\Component\Console\Question\Question; +use SwissKnife202405\Symfony\Component\Console\Style\SymfonyStyle; +/** + * Symfony Style Guide compliant question helper. + * + * @author Kevin Bond + */ +class SymfonyQuestionHelper extends QuestionHelper +{ + /** + * @return void + */ + protected function writePrompt(OutputInterface $output, Question $question) + { + $text = OutputFormatter::escapeTrailingBackslash($question->getQuestion()); + $default = $question->getDefault(); + if ($question->isMultiline()) { + $text .= \sprintf(' (press %s to continue)', $this->getEofShortcut()); + } + switch (\true) { + case null === $default: + $text = \sprintf(' %s:', $text); + break; + case $question instanceof ConfirmationQuestion: + $text = \sprintf(' %s (yes/no) [%s]:', $text, $default ? 'yes' : 'no'); + break; + case $question instanceof ChoiceQuestion && $question->isMultiselect(): + $choices = $question->getChoices(); + $default = \explode(',', $default); + foreach ($default as $key => $value) { + $default[$key] = $choices[\trim($value)]; + } + $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape(\implode(', ', $default))); + break; + case $question instanceof ChoiceQuestion: + $choices = $question->getChoices(); + $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape($choices[$default] ?? $default)); + break; + default: + $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape($default)); + } + $output->writeln($text); + $prompt = ' > '; + if ($question instanceof ChoiceQuestion) { + $output->writeln($this->formatChoiceQuestionChoices($question, 'comment')); + $prompt = $question->getPrompt(); + } + $output->write($prompt); + } + /** + * @return void + */ + protected function writeError(OutputInterface $output, \Exception $error) + { + if ($output instanceof SymfonyStyle) { + $output->newLine(); + $output->error($error->getMessage()); + return; + } + parent::writeError($output, $error); + } + private function getEofShortcut() : string + { + if ('Windows' === \PHP_OS_FAMILY) { + return 'Ctrl+Z then Enter'; + } + return 'Ctrl+D'; + } +} diff --git a/vendor/symfony/console/Helper/Table.php b/vendor/symfony/console/Helper/Table.php new file mode 100644 index 0000000000..f7bba9fb60 --- /dev/null +++ b/vendor/symfony/console/Helper/Table.php @@ -0,0 +1,811 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Helper; + +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +use SwissKnife202405\Symfony\Component\Console\Exception\RuntimeException; +use SwissKnife202405\Symfony\Component\Console\Formatter\OutputFormatter; +use SwissKnife202405\Symfony\Component\Console\Formatter\WrappableOutputFormatterInterface; +use SwissKnife202405\Symfony\Component\Console\Output\ConsoleSectionOutput; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +/** + * Provides helpers to display a table. + * + * @author Fabien Potencier + * @author Саша Стаменковић + * @author Abdellatif Ait boudad + * @author Max Grigorian + * @author Dany Maillard + */ +class Table +{ + private const SEPARATOR_TOP = 0; + private const SEPARATOR_TOP_BOTTOM = 1; + private const SEPARATOR_MID = 2; + private const SEPARATOR_BOTTOM = 3; + private const BORDER_OUTSIDE = 0; + private const BORDER_INSIDE = 1; + private const DISPLAY_ORIENTATION_DEFAULT = 'default'; + private const DISPLAY_ORIENTATION_HORIZONTAL = 'horizontal'; + private const DISPLAY_ORIENTATION_VERTICAL = 'vertical'; + /** + * @var string|null + */ + private $headerTitle; + /** + * @var string|null + */ + private $footerTitle; + /** + * @var mixed[] + */ + private $headers = []; + /** + * @var mixed[] + */ + private $rows = []; + /** + * @var mixed[] + */ + private $effectiveColumnWidths = []; + /** + * @var int + */ + private $numberOfColumns; + /** + * @var \Symfony\Component\Console\Output\OutputInterface + */ + private $output; + /** + * @var \Symfony\Component\Console\Helper\TableStyle + */ + private $style; + /** + * @var mixed[] + */ + private $columnStyles = []; + /** + * @var mixed[] + */ + private $columnWidths = []; + /** + * @var mixed[] + */ + private $columnMaxWidths = []; + /** + * @var bool + */ + private $rendered = \false; + /** + * @var string + */ + private $displayOrientation = self::DISPLAY_ORIENTATION_DEFAULT; + /** + * @var mixed[] + */ + private static $styles; + public function __construct(OutputInterface $output) + { + $this->output = $output; + self::$styles = self::$styles ?? self::initStyles(); + $this->setStyle('default'); + } + /** + * Sets a style definition. + * + * @return void + */ + public static function setStyleDefinition(string $name, TableStyle $style) + { + self::$styles = self::$styles ?? self::initStyles(); + self::$styles[$name] = $style; + } + /** + * Gets a style definition by name. + */ + public static function getStyleDefinition(string $name) : TableStyle + { + self::$styles = self::$styles ?? self::initStyles(); + if (!isset(self::$styles[$name])) { + throw new InvalidArgumentException(\sprintf('Style "%s" is not defined.', $name)); + } + return self::$styles[$name]; + } + /** + * Sets table style. + * + * @return $this + * @param \Symfony\Component\Console\Helper\TableStyle|string $name + */ + public function setStyle($name) + { + $this->style = $this->resolveStyle($name); + return $this; + } + /** + * Gets the current table style. + */ + public function getStyle() : TableStyle + { + return $this->style; + } + /** + * Sets table column style. + * + * @param TableStyle|string $name The style name or a TableStyle instance + * + * @return $this + */ + public function setColumnStyle(int $columnIndex, $name) + { + $this->columnStyles[$columnIndex] = $this->resolveStyle($name); + return $this; + } + /** + * Gets the current style for a column. + * + * If style was not set, it returns the global table style. + */ + public function getColumnStyle(int $columnIndex) : TableStyle + { + return $this->columnStyles[$columnIndex] ?? $this->getStyle(); + } + /** + * Sets the minimum width of a column. + * + * @return $this + */ + public function setColumnWidth(int $columnIndex, int $width) + { + $this->columnWidths[$columnIndex] = $width; + return $this; + } + /** + * Sets the minimum width of all columns. + * + * @return $this + */ + public function setColumnWidths(array $widths) + { + $this->columnWidths = []; + foreach ($widths as $index => $width) { + $this->setColumnWidth($index, $width); + } + return $this; + } + /** + * Sets the maximum width of a column. + * + * Any cell within this column which contents exceeds the specified width will be wrapped into multiple lines, while + * formatted strings are preserved. + * + * @return $this + */ + public function setColumnMaxWidth(int $columnIndex, int $width) + { + if (!$this->output->getFormatter() instanceof WrappableOutputFormatterInterface) { + throw new \LogicException(\sprintf('Setting a maximum column width is only supported when using a "%s" formatter, got "%s".', WrappableOutputFormatterInterface::class, \get_debug_type($this->output->getFormatter()))); + } + $this->columnMaxWidths[$columnIndex] = $width; + return $this; + } + /** + * @return $this + */ + public function setHeaders(array $headers) + { + $headers = \array_values($headers); + if ($headers && !\is_array($headers[0])) { + $headers = [$headers]; + } + $this->headers = $headers; + return $this; + } + /** + * @return $this + */ + public function setRows(array $rows) + { + $this->rows = []; + return $this->addRows($rows); + } + /** + * @return $this + */ + public function addRows(array $rows) + { + foreach ($rows as $row) { + $this->addRow($row); + } + return $this; + } + /** + * @return $this + * @param \Symfony\Component\Console\Helper\TableSeparator|mixed[] $row + */ + public function addRow($row) + { + if ($row instanceof TableSeparator) { + $this->rows[] = $row; + return $this; + } + $this->rows[] = \array_values($row); + return $this; + } + /** + * Adds a row to the table, and re-renders the table. + * + * @return $this + * @param \Symfony\Component\Console\Helper\TableSeparator|mixed[] $row + */ + public function appendRow($row) + { + if (!$this->output instanceof ConsoleSectionOutput) { + throw new RuntimeException(\sprintf('Output should be an instance of "%s" when calling "%s".', ConsoleSectionOutput::class, __METHOD__)); + } + if ($this->rendered) { + $this->output->clear($this->calculateRowCount()); + } + $this->addRow($row); + $this->render(); + return $this; + } + /** + * @return $this + * @param int|string $column + */ + public function setRow($column, array $row) + { + $this->rows[$column] = $row; + return $this; + } + /** + * @return $this + */ + public function setHeaderTitle(?string $title) + { + $this->headerTitle = $title; + return $this; + } + /** + * @return $this + */ + public function setFooterTitle(?string $title) + { + $this->footerTitle = $title; + return $this; + } + /** + * @return $this + */ + public function setHorizontal(bool $horizontal = \true) + { + $this->displayOrientation = $horizontal ? self::DISPLAY_ORIENTATION_HORIZONTAL : self::DISPLAY_ORIENTATION_DEFAULT; + return $this; + } + /** + * @return $this + */ + public function setVertical(bool $vertical = \true) + { + $this->displayOrientation = $vertical ? self::DISPLAY_ORIENTATION_VERTICAL : self::DISPLAY_ORIENTATION_DEFAULT; + return $this; + } + /** + * Renders table to output. + * + * Example: + * + * +---------------+-----------------------+------------------+ + * | ISBN | Title | Author | + * +---------------+-----------------------+------------------+ + * | 99921-58-10-7 | Divine Comedy | Dante Alighieri | + * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | + * | 960-425-059-0 | The Lord of the Rings | J. R. R. Tolkien | + * +---------------+-----------------------+------------------+ + * + * @return void + */ + public function render() + { + $divider = new TableSeparator(); + $isCellWithColspan = static function ($cell) { + return $cell instanceof TableCell && $cell->getColspan() >= 2; + }; + $horizontal = self::DISPLAY_ORIENTATION_HORIZONTAL === $this->displayOrientation; + $vertical = self::DISPLAY_ORIENTATION_VERTICAL === $this->displayOrientation; + $rows = []; + if ($horizontal) { + foreach ($this->headers[0] ?? [] as $i => $header) { + $rows[$i] = [$header]; + foreach ($this->rows as $row) { + if ($row instanceof TableSeparator) { + continue; + } + if (isset($row[$i])) { + $rows[$i][] = $row[$i]; + } elseif ($isCellWithColspan($rows[$i][0])) { + // Noop, there is a "title" + } else { + $rows[$i][] = null; + } + } + } + } elseif ($vertical) { + $formatter = $this->output->getFormatter(); + $maxHeaderLength = \array_reduce($this->headers[0] ?? [], static function ($max, $header) use($formatter) { + return \max($max, Helper::width(Helper::removeDecoration($formatter, $header))); + }, 0); + foreach ($this->rows as $row) { + if ($row instanceof TableSeparator) { + continue; + } + if ($rows) { + $rows[] = [$divider]; + } + $containsColspan = \false; + foreach ($row as $cell) { + if ($containsColspan = $isCellWithColspan($cell)) { + break; + } + } + $headers = $this->headers[0] ?? []; + $maxRows = \max(\count($headers), \count($row)); + for ($i = 0; $i < $maxRows; ++$i) { + $cell = (string) ($row[$i] ?? ''); + $eol = \strpos($cell, "\r\n") !== \false ? "\r\n" : "\n"; + $parts = \explode($eol, $cell); + foreach ($parts as $idx => $part) { + if ($headers && !$containsColspan) { + if (0 === $idx) { + $rows[] = [\sprintf('%s%s: %s', \str_repeat(' ', $maxHeaderLength - Helper::width(Helper::removeDecoration($formatter, $headers[$i] ?? ''))), $headers[$i] ?? '', $part)]; + } else { + $rows[] = [\sprintf('%s %s', \str_pad('', $maxHeaderLength, ' ', \STR_PAD_LEFT), $part)]; + } + } elseif ('' !== $cell) { + $rows[] = [$part]; + } + } + } + } + } else { + $rows = \array_merge($this->headers, [$divider], $this->rows); + } + $this->calculateNumberOfColumns($rows); + $rowGroups = $this->buildTableRows($rows); + $this->calculateColumnsWidth($rowGroups); + $isHeader = !$horizontal; + $isFirstRow = $horizontal; + $hasTitle = (bool) $this->headerTitle; + foreach ($rowGroups as $rowGroup) { + $isHeaderSeparatorRendered = \false; + foreach ($rowGroup as $row) { + if ($divider === $row) { + $isHeader = \false; + $isFirstRow = \true; + continue; + } + if ($row instanceof TableSeparator) { + $this->renderRowSeparator(); + continue; + } + if (!$row) { + continue; + } + if ($isHeader && !$isHeaderSeparatorRendered) { + $this->renderRowSeparator(self::SEPARATOR_TOP, $hasTitle ? $this->headerTitle : null, $hasTitle ? $this->style->getHeaderTitleFormat() : null); + $hasTitle = \false; + $isHeaderSeparatorRendered = \true; + } + if ($isFirstRow) { + $this->renderRowSeparator($horizontal ? self::SEPARATOR_TOP : self::SEPARATOR_TOP_BOTTOM, $hasTitle ? $this->headerTitle : null, $hasTitle ? $this->style->getHeaderTitleFormat() : null); + $isFirstRow = \false; + $hasTitle = \false; + } + if ($vertical) { + $isHeader = \false; + $isFirstRow = \false; + } + if ($horizontal) { + $this->renderRow($row, $this->style->getCellRowFormat(), $this->style->getCellHeaderFormat()); + } else { + $this->renderRow($row, $isHeader ? $this->style->getCellHeaderFormat() : $this->style->getCellRowFormat()); + } + } + } + $this->renderRowSeparator(self::SEPARATOR_BOTTOM, $this->footerTitle, $this->style->getFooterTitleFormat()); + $this->cleanup(); + $this->rendered = \true; + } + /** + * Renders horizontal header separator. + * + * Example: + * + * +-----+-----------+-------+ + */ + private function renderRowSeparator(int $type = self::SEPARATOR_MID, ?string $title = null, ?string $titleFormat = null) : void + { + if (!($count = $this->numberOfColumns)) { + return; + } + $borders = $this->style->getBorderChars(); + if (!$borders[0] && !$borders[2] && !$this->style->getCrossingChar()) { + return; + } + $crossings = $this->style->getCrossingChars(); + if (self::SEPARATOR_MID === $type) { + [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[2], $crossings[8], $crossings[0], $crossings[4]]; + } elseif (self::SEPARATOR_TOP === $type) { + [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[1], $crossings[2], $crossings[3]]; + } elseif (self::SEPARATOR_TOP_BOTTOM === $type) { + [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[9], $crossings[10], $crossings[11]]; + } else { + [$horizontal, $leftChar, $midChar, $rightChar] = [$borders[0], $crossings[7], $crossings[6], $crossings[5]]; + } + $markup = $leftChar; + for ($column = 0; $column < $count; ++$column) { + $markup .= \str_repeat($horizontal, $this->effectiveColumnWidths[$column]); + $markup .= $column === $count - 1 ? $rightChar : $midChar; + } + if (null !== $title) { + $titleLength = Helper::width(Helper::removeDecoration($formatter = $this->output->getFormatter(), $formattedTitle = \sprintf($titleFormat, $title))); + $markupLength = Helper::width($markup); + if ($titleLength > ($limit = $markupLength - 4)) { + $titleLength = $limit; + $formatLength = Helper::width(Helper::removeDecoration($formatter, \sprintf($titleFormat, ''))); + $formattedTitle = \sprintf($titleFormat, Helper::substr($title, 0, $limit - $formatLength - 3) . '...'); + } + $titleStart = \intdiv($markupLength - $titleLength, 2); + if (\false === \mb_detect_encoding($markup, null, \true)) { + $markup = \substr_replace($markup, $formattedTitle, $titleStart, $titleLength); + } else { + $markup = \mb_substr($markup, 0, $titleStart) . $formattedTitle . \mb_substr($markup, $titleStart + $titleLength); + } + } + $this->output->writeln(\sprintf($this->style->getBorderFormat(), $markup)); + } + /** + * Renders vertical column separator. + */ + private function renderColumnSeparator(int $type = self::BORDER_OUTSIDE) : string + { + $borders = $this->style->getBorderChars(); + return \sprintf($this->style->getBorderFormat(), self::BORDER_OUTSIDE === $type ? $borders[1] : $borders[3]); + } + /** + * Renders table row. + * + * Example: + * + * | 9971-5-0210-0 | A Tale of Two Cities | Charles Dickens | + */ + private function renderRow(array $row, string $cellFormat, ?string $firstCellFormat = null) : void + { + $rowContent = $this->renderColumnSeparator(self::BORDER_OUTSIDE); + $columns = $this->getRowColumns($row); + $last = \count($columns) - 1; + foreach ($columns as $i => $column) { + if ($firstCellFormat && 0 === $i) { + $rowContent .= $this->renderCell($row, $column, $firstCellFormat); + } else { + $rowContent .= $this->renderCell($row, $column, $cellFormat); + } + $rowContent .= $this->renderColumnSeparator($last === $i ? self::BORDER_OUTSIDE : self::BORDER_INSIDE); + } + $this->output->writeln($rowContent); + } + /** + * Renders table cell with padding. + */ + private function renderCell(array $row, int $column, string $cellFormat) : string + { + $cell = $row[$column] ?? ''; + $width = $this->effectiveColumnWidths[$column]; + if ($cell instanceof TableCell && $cell->getColspan() > 1) { + // add the width of the following columns(numbers of colspan). + foreach (\range($column + 1, $column + $cell->getColspan() - 1) as $nextColumn) { + $width += $this->getColumnSeparatorWidth() + $this->effectiveColumnWidths[$nextColumn]; + } + } + // str_pad won't work properly with multi-byte strings, we need to fix the padding + if (\false !== ($encoding = \mb_detect_encoding($cell, null, \true))) { + $width += \strlen($cell) - \mb_strwidth($cell, $encoding); + } + $style = $this->getColumnStyle($column); + if ($cell instanceof TableSeparator) { + return \sprintf($style->getBorderFormat(), \str_repeat($style->getBorderChars()[2], $width)); + } + $width += Helper::length($cell) - Helper::length(Helper::removeDecoration($this->output->getFormatter(), $cell)); + $content = \sprintf($style->getCellRowContentFormat(), $cell); + $padType = $style->getPadType(); + if ($cell instanceof TableCell && $cell->getStyle() instanceof TableCellStyle) { + $isNotStyledByTag = !\preg_match('/^<(\\w+|(\\w+=[\\w,]+;?)*)>.+<\\/(\\w+|(\\w+=\\w+;?)*)?>$/', $cell); + if ($isNotStyledByTag) { + $cellFormat = $cell->getStyle()->getCellFormat(); + if (!\is_string($cellFormat)) { + $tag = \http_build_query($cell->getStyle()->getTagOptions(), '', ';'); + $cellFormat = '<' . $tag . '>%s'; + } + if (\strpos($content, '') !== \false) { + $content = \str_replace('', '', $content); + $width -= 3; + } + if (\strpos($content, '') !== \false) { + $content = \str_replace('', '', $content); + $width -= \strlen(''); + } + } + $padType = $cell->getStyle()->getPadByAlign(); + } + return \sprintf($cellFormat, \str_pad($content, $width, $style->getPaddingChar(), $padType)); + } + /** + * Calculate number of columns for this table. + */ + private function calculateNumberOfColumns(array $rows) : void + { + $columns = [0]; + foreach ($rows as $row) { + if ($row instanceof TableSeparator) { + continue; + } + $columns[] = $this->getNumberOfColumns($row); + } + $this->numberOfColumns = \max($columns); + } + private function buildTableRows(array $rows) : TableRows + { + /** @var WrappableOutputFormatterInterface $formatter */ + $formatter = $this->output->getFormatter(); + $unmergedRows = []; + for ($rowKey = 0; $rowKey < \count($rows); ++$rowKey) { + $rows = $this->fillNextRows($rows, $rowKey); + // Remove any new line breaks and replace it with a new line + foreach ($rows[$rowKey] as $column => $cell) { + $colspan = $cell instanceof TableCell ? $cell->getColspan() : 1; + if (isset($this->columnMaxWidths[$column]) && Helper::width(Helper::removeDecoration($formatter, $cell)) > $this->columnMaxWidths[$column]) { + $cell = $formatter->formatAndWrap($cell, $this->columnMaxWidths[$column] * $colspan); + } + if (\strpos($cell ?? '', "\n") === \false) { + continue; + } + $eol = \strpos($cell ?? '', "\r\n") !== \false ? "\r\n" : "\n"; + $escaped = \implode($eol, \array_map(\Closure::fromCallable([OutputFormatter::class, 'escapeTrailingBackslash']), \explode($eol, $cell))); + $cell = $cell instanceof TableCell ? new TableCell($escaped, ['colspan' => $cell->getColspan()]) : $escaped; + $lines = \explode($eol, \str_replace($eol, '' . $eol, $cell)); + foreach ($lines as $lineKey => $line) { + if ($colspan > 1) { + $line = new TableCell($line, ['colspan' => $colspan]); + } + if (0 === $lineKey) { + $rows[$rowKey][$column] = $line; + } else { + if (!\array_key_exists($rowKey, $unmergedRows) || !\array_key_exists($lineKey, $unmergedRows[$rowKey])) { + $unmergedRows[$rowKey][$lineKey] = $this->copyRow($rows, $rowKey); + } + $unmergedRows[$rowKey][$lineKey][$column] = $line; + } + } + } + } + return new TableRows(function () use($rows, $unmergedRows) : \Traversable { + foreach ($rows as $rowKey => $row) { + $rowGroup = [$row instanceof TableSeparator ? $row : $this->fillCells($row)]; + if (isset($unmergedRows[$rowKey])) { + foreach ($unmergedRows[$rowKey] as $row) { + $rowGroup[] = $row instanceof TableSeparator ? $row : $this->fillCells($row); + } + } + (yield $rowGroup); + } + }); + } + private function calculateRowCount() : int + { + $numberOfRows = \count(\iterator_to_array($this->buildTableRows(\array_merge($this->headers, [new TableSeparator()], $this->rows)))); + if ($this->headers) { + ++$numberOfRows; + // Add row for header separator + } + if ($this->rows) { + ++$numberOfRows; + // Add row for footer separator + } + return $numberOfRows; + } + /** + * fill rows that contains rowspan > 1. + * + * @throws InvalidArgumentException + */ + private function fillNextRows(array $rows, int $line) : array + { + $unmergedRows = []; + foreach ($rows[$line] as $column => $cell) { + if (null !== $cell && !$cell instanceof TableCell && !\is_scalar($cell) && !$cell instanceof \Stringable) { + throw new InvalidArgumentException(\sprintf('A cell must be a TableCell, a scalar or an object implementing "__toString()", "%s" given.', \get_debug_type($cell))); + } + if ($cell instanceof TableCell && $cell->getRowspan() > 1) { + $nbLines = $cell->getRowspan() - 1; + $lines = [$cell]; + if (\strpos($cell, "\n") !== \false) { + $eol = \strpos($cell, "\r\n") !== \false ? "\r\n" : "\n"; + $lines = \explode($eol, \str_replace($eol, '' . $eol . '', $cell)); + $nbLines = \count($lines) > $nbLines ? \substr_count($cell, $eol) : $nbLines; + $rows[$line][$column] = new TableCell($lines[0], ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]); + unset($lines[0]); + } + // create a two dimensional array (rowspan x colspan) + $unmergedRows = \array_replace_recursive(\array_fill($line + 1, $nbLines, []), $unmergedRows); + foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) { + $value = $lines[$unmergedRowKey - $line] ?? ''; + $unmergedRows[$unmergedRowKey][$column] = new TableCell($value, ['colspan' => $cell->getColspan(), 'style' => $cell->getStyle()]); + if ($nbLines === $unmergedRowKey - $line) { + break; + } + } + } + } + foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) { + // we need to know if $unmergedRow will be merged or inserted into $rows + if (isset($rows[$unmergedRowKey]) && \is_array($rows[$unmergedRowKey]) && $this->getNumberOfColumns($rows[$unmergedRowKey]) + $this->getNumberOfColumns($unmergedRows[$unmergedRowKey]) <= $this->numberOfColumns) { + foreach ($unmergedRow as $cellKey => $cell) { + // insert cell into row at cellKey position + \array_splice($rows[$unmergedRowKey], $cellKey, 0, [$cell]); + } + } else { + $row = $this->copyRow($rows, $unmergedRowKey - 1); + foreach ($unmergedRow as $column => $cell) { + if (!empty($cell)) { + $row[$column] = $unmergedRow[$column]; + } + } + \array_splice($rows, $unmergedRowKey, 0, [$row]); + } + } + return $rows; + } + /** + * fill cells for a row that contains colspan > 1. + */ + private function fillCells(iterable $row) : iterable + { + $newRow = []; + foreach ($row as $column => $cell) { + $newRow[] = $cell; + if ($cell instanceof TableCell && $cell->getColspan() > 1) { + foreach (\range($column + 1, $column + $cell->getColspan() - 1) as $position) { + // insert empty value at column position + $newRow[] = ''; + } + } + } + return $newRow ?: $row; + } + private function copyRow(array $rows, int $line) : array + { + $row = $rows[$line]; + foreach ($row as $cellKey => $cellValue) { + $row[$cellKey] = ''; + if ($cellValue instanceof TableCell) { + $row[$cellKey] = new TableCell('', ['colspan' => $cellValue->getColspan()]); + } + } + return $row; + } + /** + * Gets number of columns by row. + */ + private function getNumberOfColumns(array $row) : int + { + $columns = \count($row); + foreach ($row as $column) { + $columns += $column instanceof TableCell ? $column->getColspan() - 1 : 0; + } + return $columns; + } + /** + * Gets list of columns for the given row. + */ + private function getRowColumns(array $row) : array + { + $columns = \range(0, $this->numberOfColumns - 1); + foreach ($row as $cellKey => $cell) { + if ($cell instanceof TableCell && $cell->getColspan() > 1) { + // exclude grouped columns. + $columns = \array_diff($columns, \range($cellKey + 1, $cellKey + $cell->getColspan() - 1)); + } + } + return $columns; + } + /** + * Calculates columns widths. + */ + private function calculateColumnsWidth(iterable $groups) : void + { + for ($column = 0; $column < $this->numberOfColumns; ++$column) { + $lengths = []; + foreach ($groups as $group) { + foreach ($group as $row) { + if ($row instanceof TableSeparator) { + continue; + } + foreach ($row as $i => $cell) { + if ($cell instanceof TableCell) { + $textContent = Helper::removeDecoration($this->output->getFormatter(), $cell); + $textLength = Helper::width($textContent); + if ($textLength > 0) { + $contentColumns = \mb_str_split($textContent, \ceil($textLength / $cell->getColspan())); + foreach ($contentColumns as $position => $content) { + $row[$i + $position] = $content; + } + } + } + } + $lengths[] = $this->getCellWidth($row, $column); + } + } + $this->effectiveColumnWidths[$column] = \max($lengths) + Helper::width($this->style->getCellRowContentFormat()) - 2; + } + } + private function getColumnSeparatorWidth() : int + { + return Helper::width(\sprintf($this->style->getBorderFormat(), $this->style->getBorderChars()[3])); + } + private function getCellWidth(array $row, int $column) : int + { + $cellWidth = 0; + if (isset($row[$column])) { + $cell = $row[$column]; + $cellWidth = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $cell)); + } + $columnWidth = $this->columnWidths[$column] ?? 0; + $cellWidth = \max($cellWidth, $columnWidth); + return isset($this->columnMaxWidths[$column]) ? \min($this->columnMaxWidths[$column], $cellWidth) : $cellWidth; + } + /** + * Called after rendering to cleanup cache data. + */ + private function cleanup() : void + { + $this->effectiveColumnWidths = []; + unset($this->numberOfColumns); + } + /** + * @return array + */ + private static function initStyles() : array + { + $borderless = new TableStyle(); + $borderless->setHorizontalBorderChars('=')->setVerticalBorderChars(' ')->setDefaultCrossingChar(' '); + $compact = new TableStyle(); + $compact->setHorizontalBorderChars('')->setVerticalBorderChars('')->setDefaultCrossingChar('')->setCellRowContentFormat('%s '); + $styleGuide = new TableStyle(); + $styleGuide->setHorizontalBorderChars('-')->setVerticalBorderChars(' ')->setDefaultCrossingChar(' ')->setCellHeaderFormat('%s'); + $box = (new TableStyle())->setHorizontalBorderChars('─')->setVerticalBorderChars('│')->setCrossingChars('┼', '┌', '┬', '┐', '┤', '┘', '┴', '└', '├'); + $boxDouble = (new TableStyle())->setHorizontalBorderChars('═', '─')->setVerticalBorderChars('║', '│')->setCrossingChars('┼', '╔', '╤', '╗', '╢', '╝', '╧', '╚', '╟', '╠', '╪', '╣'); + return ['default' => new TableStyle(), 'borderless' => $borderless, 'compact' => $compact, 'symfony-style-guide' => $styleGuide, 'box' => $box, 'box-double' => $boxDouble]; + } + /** + * @param \Symfony\Component\Console\Helper\TableStyle|string $name + */ + private function resolveStyle($name) : TableStyle + { + if ($name instanceof TableStyle) { + return $name; + } + if (!isset(self::$styles[$name])) { + throw new InvalidArgumentException(\sprintf('Style "%s" is not defined.', $name)); + } + return self::$styles[$name]; + } +} diff --git a/vendor/symfony/console/Helper/TableCell.php b/vendor/symfony/console/Helper/TableCell.php new file mode 100644 index 0000000000..c50cf460b0 --- /dev/null +++ b/vendor/symfony/console/Helper/TableCell.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Helper; + +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +/** + * @author Abdellatif Ait boudad + */ +class TableCell +{ + /** + * @var string + */ + private $value; + /** + * @var mixed[] + */ + private $options = ['rowspan' => 1, 'colspan' => 1, 'style' => null]; + public function __construct(string $value = '', array $options = []) + { + $this->value = $value; + // check option names + if ($diff = \array_diff(\array_keys($options), \array_keys($this->options))) { + throw new InvalidArgumentException(\sprintf('The TableCell does not support the following options: \'%s\'.', \implode('\', \'', $diff))); + } + if (isset($options['style']) && !$options['style'] instanceof TableCellStyle) { + throw new InvalidArgumentException('The style option must be an instance of "TableCellStyle".'); + } + $this->options = \array_merge($this->options, $options); + } + /** + * Returns the cell value. + */ + public function __toString() : string + { + return $this->value; + } + /** + * Gets number of colspan. + */ + public function getColspan() : int + { + return (int) $this->options['colspan']; + } + /** + * Gets number of rowspan. + */ + public function getRowspan() : int + { + return (int) $this->options['rowspan']; + } + public function getStyle() : ?TableCellStyle + { + return $this->options['style']; + } +} diff --git a/vendor/symfony/console/Helper/TableCellStyle.php b/vendor/symfony/console/Helper/TableCellStyle.php new file mode 100644 index 0000000000..fed9cebbd5 --- /dev/null +++ b/vendor/symfony/console/Helper/TableCellStyle.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Helper; + +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +/** + * @author Yewhen Khoptynskyi + */ +class TableCellStyle +{ + public const DEFAULT_ALIGN = 'left'; + private const TAG_OPTIONS = ['fg', 'bg', 'options']; + private const ALIGN_MAP = ['left' => \STR_PAD_RIGHT, 'center' => \STR_PAD_BOTH, 'right' => \STR_PAD_LEFT]; + /** + * @var mixed[] + */ + private $options = ['fg' => 'default', 'bg' => 'default', 'options' => null, 'align' => self::DEFAULT_ALIGN, 'cellFormat' => null]; + public function __construct(array $options = []) + { + if ($diff = \array_diff(\array_keys($options), \array_keys($this->options))) { + throw new InvalidArgumentException(\sprintf('The TableCellStyle does not support the following options: \'%s\'.', \implode('\', \'', $diff))); + } + if (isset($options['align']) && !\array_key_exists($options['align'], self::ALIGN_MAP)) { + throw new InvalidArgumentException(\sprintf('Wrong align value. Value must be following: \'%s\'.', \implode('\', \'', \array_keys(self::ALIGN_MAP)))); + } + $this->options = \array_merge($this->options, $options); + } + public function getOptions() : array + { + return $this->options; + } + /** + * Gets options we need for tag for example fg, bg. + * + * @return string[] + */ + public function getTagOptions() : array + { + return \array_filter($this->getOptions(), function ($key) { + return \in_array($key, self::TAG_OPTIONS) && isset($this->options[$key]); + }, \ARRAY_FILTER_USE_KEY); + } + public function getPadByAlign() : int + { + return self::ALIGN_MAP[$this->getOptions()['align']]; + } + public function getCellFormat() : ?string + { + return $this->getOptions()['cellFormat']; + } +} diff --git a/vendor/symfony/console/Helper/TableRows.php b/vendor/symfony/console/Helper/TableRows.php new file mode 100644 index 0000000000..983ebcdd18 --- /dev/null +++ b/vendor/symfony/console/Helper/TableRows.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Helper; + +/** + * @internal + */ +class TableRows implements \IteratorAggregate +{ + /** + * @var \Closure + */ + private $generator; + public function __construct(\Closure $generator) + { + $this->generator = $generator; + } + public function getIterator() : \Traversable + { + return ($this->generator)(); + } +} diff --git a/vendor/symfony/console/Helper/TableSeparator.php b/vendor/symfony/console/Helper/TableSeparator.php new file mode 100644 index 0000000000..aec8b89eb6 --- /dev/null +++ b/vendor/symfony/console/Helper/TableSeparator.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Helper; + +/** + * Marks a row as being a separator. + * + * @author Fabien Potencier + */ +class TableSeparator extends TableCell +{ + public function __construct(array $options = []) + { + parent::__construct('', $options); + } +} diff --git a/vendor/symfony/console/Helper/TableStyle.php b/vendor/symfony/console/Helper/TableStyle.php new file mode 100644 index 0000000000..f227f7016d --- /dev/null +++ b/vendor/symfony/console/Helper/TableStyle.php @@ -0,0 +1,378 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Helper; + +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +use SwissKnife202405\Symfony\Component\Console\Exception\LogicException; +/** + * Defines the styles for a Table. + * + * @author Fabien Potencier + * @author Саша Стаменковић + * @author Dany Maillard + */ +class TableStyle +{ + /** + * @var string + */ + private $paddingChar = ' '; + /** + * @var string + */ + private $horizontalOutsideBorderChar = '-'; + /** + * @var string + */ + private $horizontalInsideBorderChar = '-'; + /** + * @var string + */ + private $verticalOutsideBorderChar = '|'; + /** + * @var string + */ + private $verticalInsideBorderChar = '|'; + /** + * @var string + */ + private $crossingChar = '+'; + /** + * @var string + */ + private $crossingTopRightChar = '+'; + /** + * @var string + */ + private $crossingTopMidChar = '+'; + /** + * @var string + */ + private $crossingTopLeftChar = '+'; + /** + * @var string + */ + private $crossingMidRightChar = '+'; + /** + * @var string + */ + private $crossingBottomRightChar = '+'; + /** + * @var string + */ + private $crossingBottomMidChar = '+'; + /** + * @var string + */ + private $crossingBottomLeftChar = '+'; + /** + * @var string + */ + private $crossingMidLeftChar = '+'; + /** + * @var string + */ + private $crossingTopLeftBottomChar = '+'; + /** + * @var string + */ + private $crossingTopMidBottomChar = '+'; + /** + * @var string + */ + private $crossingTopRightBottomChar = '+'; + /** + * @var string + */ + private $headerTitleFormat = ' %s '; + /** + * @var string + */ + private $footerTitleFormat = ' %s '; + /** + * @var string + */ + private $cellHeaderFormat = '%s'; + /** + * @var string + */ + private $cellRowFormat = '%s'; + /** + * @var string + */ + private $cellRowContentFormat = ' %s '; + /** + * @var string + */ + private $borderFormat = '%s'; + /** + * @var int + */ + private $padType = \STR_PAD_RIGHT; + /** + * Sets padding character, used for cell padding. + * + * @return $this + */ + public function setPaddingChar(string $paddingChar) + { + if (!$paddingChar) { + throw new LogicException('The padding char must not be empty.'); + } + $this->paddingChar = $paddingChar; + return $this; + } + /** + * Gets padding character, used for cell padding. + */ + public function getPaddingChar() : string + { + return $this->paddingChar; + } + /** + * Sets horizontal border characters. + * + * + * ╔═══════════════╤══════════════════════════╤══════════════════╗ + * 1 ISBN 2 Title │ Author ║ + * ╠═══════════════╪══════════════════════════╪══════════════════╣ + * ║ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri ║ + * ║ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens ║ + * ║ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien ║ + * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║ + * ╚═══════════════╧══════════════════════════╧══════════════════╝ + * + * + * @return $this + */ + public function setHorizontalBorderChars(string $outside, ?string $inside = null) + { + $this->horizontalOutsideBorderChar = $outside; + $this->horizontalInsideBorderChar = $inside ?? $outside; + return $this; + } + /** + * Sets vertical border characters. + * + * + * ╔═══════════════╤══════════════════════════╤══════════════════╗ + * ║ ISBN │ Title │ Author ║ + * ╠═══════1═══════╪══════════════════════════╪══════════════════╣ + * ║ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri ║ + * ║ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens ║ + * ╟───────2───────┼──────────────────────────┼──────────────────╢ + * ║ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien ║ + * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║ + * ╚═══════════════╧══════════════════════════╧══════════════════╝ + * + * + * @return $this + */ + public function setVerticalBorderChars(string $outside, ?string $inside = null) + { + $this->verticalOutsideBorderChar = $outside; + $this->verticalInsideBorderChar = $inside ?? $outside; + return $this; + } + /** + * Gets border characters. + * + * @internal + */ + public function getBorderChars() : array + { + return [$this->horizontalOutsideBorderChar, $this->verticalOutsideBorderChar, $this->horizontalInsideBorderChar, $this->verticalInsideBorderChar]; + } + /** + * Sets crossing characters. + * + * Example: + * + * 1═══════════════2══════════════════════════2══════════════════3 + * ║ ISBN │ Title │ Author ║ + * 8'══════════════0'═════════════════════════0'═════════════════4' + * ║ 99921-58-10-7 │ Divine Comedy │ Dante Alighieri ║ + * ║ 9971-5-0210-0 │ A Tale of Two Cities │ Charles Dickens ║ + * 8───────────────0──────────────────────────0──────────────────4 + * ║ 960-425-059-0 │ The Lord of the Rings │ J. R. R. Tolkien ║ + * ║ 80-902734-1-6 │ And Then There Were None │ Agatha Christie ║ + * 7═══════════════6══════════════════════════6══════════════════5 + * + * + * @param string $cross Crossing char (see #0 of example) + * @param string $topLeft Top left char (see #1 of example) + * @param string $topMid Top mid char (see #2 of example) + * @param string $topRight Top right char (see #3 of example) + * @param string $midRight Mid right char (see #4 of example) + * @param string $bottomRight Bottom right char (see #5 of example) + * @param string $bottomMid Bottom mid char (see #6 of example) + * @param string $bottomLeft Bottom left char (see #7 of example) + * @param string $midLeft Mid left char (see #8 of example) + * @param string|null $topLeftBottom Top left bottom char (see #8' of example), equals to $midLeft if null + * @param string|null $topMidBottom Top mid bottom char (see #0' of example), equals to $cross if null + * @param string|null $topRightBottom Top right bottom char (see #4' of example), equals to $midRight if null + * + * @return $this + */ + public function setCrossingChars(string $cross, string $topLeft, string $topMid, string $topRight, string $midRight, string $bottomRight, string $bottomMid, string $bottomLeft, string $midLeft, ?string $topLeftBottom = null, ?string $topMidBottom = null, ?string $topRightBottom = null) + { + $this->crossingChar = $cross; + $this->crossingTopLeftChar = $topLeft; + $this->crossingTopMidChar = $topMid; + $this->crossingTopRightChar = $topRight; + $this->crossingMidRightChar = $midRight; + $this->crossingBottomRightChar = $bottomRight; + $this->crossingBottomMidChar = $bottomMid; + $this->crossingBottomLeftChar = $bottomLeft; + $this->crossingMidLeftChar = $midLeft; + $this->crossingTopLeftBottomChar = $topLeftBottom ?? $midLeft; + $this->crossingTopMidBottomChar = $topMidBottom ?? $cross; + $this->crossingTopRightBottomChar = $topRightBottom ?? $midRight; + return $this; + } + /** + * Sets default crossing character used for each cross. + * + * @see {@link setCrossingChars()} for setting each crossing individually. + */ + public function setDefaultCrossingChar(string $char) : self + { + return $this->setCrossingChars($char, $char, $char, $char, $char, $char, $char, $char, $char); + } + /** + * Gets crossing character. + */ + public function getCrossingChar() : string + { + return $this->crossingChar; + } + /** + * Gets crossing characters. + * + * @internal + */ + public function getCrossingChars() : array + { + return [$this->crossingChar, $this->crossingTopLeftChar, $this->crossingTopMidChar, $this->crossingTopRightChar, $this->crossingMidRightChar, $this->crossingBottomRightChar, $this->crossingBottomMidChar, $this->crossingBottomLeftChar, $this->crossingMidLeftChar, $this->crossingTopLeftBottomChar, $this->crossingTopMidBottomChar, $this->crossingTopRightBottomChar]; + } + /** + * Sets header cell format. + * + * @return $this + */ + public function setCellHeaderFormat(string $cellHeaderFormat) + { + $this->cellHeaderFormat = $cellHeaderFormat; + return $this; + } + /** + * Gets header cell format. + */ + public function getCellHeaderFormat() : string + { + return $this->cellHeaderFormat; + } + /** + * Sets row cell format. + * + * @return $this + */ + public function setCellRowFormat(string $cellRowFormat) + { + $this->cellRowFormat = $cellRowFormat; + return $this; + } + /** + * Gets row cell format. + */ + public function getCellRowFormat() : string + { + return $this->cellRowFormat; + } + /** + * Sets row cell content format. + * + * @return $this + */ + public function setCellRowContentFormat(string $cellRowContentFormat) + { + $this->cellRowContentFormat = $cellRowContentFormat; + return $this; + } + /** + * Gets row cell content format. + */ + public function getCellRowContentFormat() : string + { + return $this->cellRowContentFormat; + } + /** + * Sets table border format. + * + * @return $this + */ + public function setBorderFormat(string $borderFormat) + { + $this->borderFormat = $borderFormat; + return $this; + } + /** + * Gets table border format. + */ + public function getBorderFormat() : string + { + return $this->borderFormat; + } + /** + * Sets cell padding type. + * + * @return $this + */ + public function setPadType(int $padType) + { + if (!\in_array($padType, [\STR_PAD_LEFT, \STR_PAD_RIGHT, \STR_PAD_BOTH], \true)) { + throw new InvalidArgumentException('Invalid padding type. Expected one of (STR_PAD_LEFT, STR_PAD_RIGHT, STR_PAD_BOTH).'); + } + $this->padType = $padType; + return $this; + } + /** + * Gets cell padding type. + */ + public function getPadType() : int + { + return $this->padType; + } + public function getHeaderTitleFormat() : string + { + return $this->headerTitleFormat; + } + /** + * @return $this + */ + public function setHeaderTitleFormat(string $format) + { + $this->headerTitleFormat = $format; + return $this; + } + public function getFooterTitleFormat() : string + { + return $this->footerTitleFormat; + } + /** + * @return $this + */ + public function setFooterTitleFormat(string $format) + { + $this->footerTitleFormat = $format; + return $this; + } +} diff --git a/vendor/symfony/console/Input/ArgvInput.php b/vendor/symfony/console/Input/ArgvInput.php new file mode 100644 index 0000000000..d573890f9e --- /dev/null +++ b/vendor/symfony/console/Input/ArgvInput.php @@ -0,0 +1,336 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Input; + +use SwissKnife202405\Symfony\Component\Console\Exception\RuntimeException; +/** + * ArgvInput represents an input coming from the CLI arguments. + * + * Usage: + * + * $input = new ArgvInput(); + * + * By default, the `$_SERVER['argv']` array is used for the input values. + * + * This can be overridden by explicitly passing the input values in the constructor: + * + * $input = new ArgvInput($_SERVER['argv']); + * + * If you pass it yourself, don't forget that the first element of the array + * is the name of the running application. + * + * When passing an argument to the constructor, be sure that it respects + * the same rules as the argv one. It's almost always better to use the + * `StringInput` when you want to provide your own input. + * + * @author Fabien Potencier + * + * @see http://www.gnu.org/software/libc/manual/html_node/Argument-Syntax.html + * @see http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html#tag_12_02 + */ +class ArgvInput extends Input +{ + /** + * @var mixed[] + */ + private $tokens; + /** + * @var mixed[] + */ + private $parsed; + public function __construct(?array $argv = null, ?InputDefinition $definition = null) + { + $argv = $argv ?? $_SERVER['argv'] ?? []; + // strip the application name + \array_shift($argv); + $this->tokens = $argv; + parent::__construct($definition); + } + /** + * @return void + */ + protected function setTokens(array $tokens) + { + $this->tokens = $tokens; + } + /** + * @return void + */ + protected function parse() + { + $parseOptions = \true; + $this->parsed = $this->tokens; + while (null !== ($token = \array_shift($this->parsed))) { + $parseOptions = $this->parseToken($token, $parseOptions); + } + } + protected function parseToken(string $token, bool $parseOptions) : bool + { + if ($parseOptions && '' == $token) { + $this->parseArgument($token); + } elseif ($parseOptions && '--' == $token) { + return \false; + } elseif ($parseOptions && \strncmp($token, '--', \strlen('--')) === 0) { + $this->parseLongOption($token); + } elseif ($parseOptions && '-' === $token[0] && '-' !== $token) { + $this->parseShortOption($token); + } else { + $this->parseArgument($token); + } + return $parseOptions; + } + /** + * Parses a short option. + */ + private function parseShortOption(string $token) : void + { + $name = \substr($token, 1); + if (\strlen($name) > 1) { + if ($this->definition->hasShortcut($name[0]) && $this->definition->getOptionForShortcut($name[0])->acceptValue()) { + // an option with a value (with no space) + $this->addShortOption($name[0], \substr($name, 1)); + } else { + $this->parseShortOptionSet($name); + } + } else { + $this->addShortOption($name, null); + } + } + /** + * Parses a short option set. + * + * @throws RuntimeException When option given doesn't exist + */ + private function parseShortOptionSet(string $name) : void + { + $len = \strlen($name); + for ($i = 0; $i < $len; ++$i) { + if (!$this->definition->hasShortcut($name[$i])) { + $encoding = \mb_detect_encoding($name, null, \true); + throw new RuntimeException(\sprintf('The "-%s" option does not exist.', \false === $encoding ? $name[$i] : \mb_substr($name, $i, 1, $encoding))); + } + $option = $this->definition->getOptionForShortcut($name[$i]); + if ($option->acceptValue()) { + $this->addLongOption($option->getName(), $i === $len - 1 ? null : \substr($name, $i + 1)); + break; + } else { + $this->addLongOption($option->getName(), null); + } + } + } + /** + * Parses a long option. + */ + private function parseLongOption(string $token) : void + { + $name = \substr($token, 2); + if (\false !== ($pos = \strpos($name, '='))) { + if ('' === ($value = \substr($name, $pos + 1))) { + \array_unshift($this->parsed, $value); + } + $this->addLongOption(\substr($name, 0, $pos), $value); + } else { + $this->addLongOption($name, null); + } + } + /** + * Parses an argument. + * + * @throws RuntimeException When too many arguments are given + */ + private function parseArgument(string $token) : void + { + $c = \count($this->arguments); + // if input is expecting another argument, add it + if ($this->definition->hasArgument($c)) { + $arg = $this->definition->getArgument($c); + $this->arguments[$arg->getName()] = $arg->isArray() ? [$token] : $token; + // if last argument isArray(), append token to last argument + } elseif ($this->definition->hasArgument($c - 1) && $this->definition->getArgument($c - 1)->isArray()) { + $arg = $this->definition->getArgument($c - 1); + $this->arguments[$arg->getName()][] = $token; + // unexpected argument + } else { + $all = $this->definition->getArguments(); + $symfonyCommandName = null; + \reset($all); + if (($inputArgument = $all[$key = \key($all)] ?? null) && 'command' === $inputArgument->getName()) { + $symfonyCommandName = $this->arguments['command'] ?? null; + unset($all[$key]); + } + if (\count($all)) { + if ($symfonyCommandName) { + $message = \sprintf('Too many arguments to "%s" command, expected arguments "%s".', $symfonyCommandName, \implode('" "', \array_keys($all))); + } else { + $message = \sprintf('Too many arguments, expected arguments "%s".', \implode('" "', \array_keys($all))); + } + } elseif ($symfonyCommandName) { + $message = \sprintf('No arguments expected for "%s" command, got "%s".', $symfonyCommandName, $token); + } else { + $message = \sprintf('No arguments expected, got "%s".', $token); + } + throw new RuntimeException($message); + } + } + /** + * Adds a short option value. + * + * @throws RuntimeException When option given doesn't exist + * @param mixed $value + */ + private function addShortOption(string $shortcut, $value) : void + { + if (!$this->definition->hasShortcut($shortcut)) { + throw new RuntimeException(\sprintf('The "-%s" option does not exist.', $shortcut)); + } + $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value); + } + /** + * Adds a long option value. + * + * @throws RuntimeException When option given doesn't exist + * @param mixed $value + */ + private function addLongOption(string $name, $value) : void + { + if (!$this->definition->hasOption($name)) { + if (!$this->definition->hasNegation($name)) { + throw new RuntimeException(\sprintf('The "--%s" option does not exist.', $name)); + } + $optionName = $this->definition->negationToName($name); + if (null !== $value) { + throw new RuntimeException(\sprintf('The "--%s" option does not accept a value.', $name)); + } + $this->options[$optionName] = \false; + return; + } + $option = $this->definition->getOption($name); + if (null !== $value && !$option->acceptValue()) { + throw new RuntimeException(\sprintf('The "--%s" option does not accept a value.', $name)); + } + if (\in_array($value, ['', null], \true) && $option->acceptValue() && \count($this->parsed)) { + // if option accepts an optional or mandatory argument + // let's see if there is one provided + $next = \array_shift($this->parsed); + if (isset($next[0]) && '-' !== $next[0] || \in_array($next, ['', null], \true)) { + $value = $next; + } else { + \array_unshift($this->parsed, $next); + } + } + if (null === $value) { + if ($option->isValueRequired()) { + throw new RuntimeException(\sprintf('The "--%s" option requires a value.', $name)); + } + if (!$option->isArray() && !$option->isValueOptional()) { + $value = \true; + } + } + if ($option->isArray()) { + $this->options[$name][] = $value; + } else { + $this->options[$name] = $value; + } + } + public function getFirstArgument() : ?string + { + $isOption = \false; + foreach ($this->tokens as $i => $token) { + if ($token && '-' === $token[0]) { + if (\strpos($token, '=') !== \false || !isset($this->tokens[$i + 1])) { + continue; + } + // If it's a long option, consider that everything after "--" is the option name. + // Otherwise, use the last char (if it's a short option set, only the last one can take a value with space separator) + $name = '-' === $token[1] ? \substr($token, 2) : \substr($token, -1); + if (!isset($this->options[$name]) && !$this->definition->hasShortcut($name)) { + // noop + } elseif ((isset($this->options[$name]) || isset($this->options[$name = $this->definition->shortcutToName($name)])) && $this->tokens[$i + 1] === $this->options[$name]) { + $isOption = \true; + } + continue; + } + if ($isOption) { + $isOption = \false; + continue; + } + return $token; + } + return null; + } + /** + * @param string|mixed[] $values + */ + public function hasParameterOption($values, bool $onlyParams = \false) : bool + { + $values = (array) $values; + foreach ($this->tokens as $token) { + if ($onlyParams && '--' === $token) { + return \false; + } + foreach ($values as $value) { + // Options with values: + // For long options, test for '--option=' at beginning + // For short options, test for '-o' at beginning + $leading = \strncmp($value, '--', \strlen('--')) === 0 ? $value . '=' : $value; + if ($token === $value || '' !== $leading && \strncmp($token, $leading, \strlen($leading)) === 0) { + return \true; + } + } + } + return \false; + } + /** + * @param string|mixed[] $values + * @param string|bool|int|float|mixed[]|null $default + * @return mixed + */ + public function getParameterOption($values, $default = \false, bool $onlyParams = \false) + { + $values = (array) $values; + $tokens = $this->tokens; + while (0 < \count($tokens)) { + $token = \array_shift($tokens); + if ($onlyParams && '--' === $token) { + return $default; + } + foreach ($values as $value) { + if ($token === $value) { + return \array_shift($tokens); + } + // Options with values: + // For long options, test for '--option=' at beginning + // For short options, test for '-o' at beginning + $leading = \strncmp($value, '--', \strlen('--')) === 0 ? $value . '=' : $value; + if ('' !== $leading && \strncmp($token, $leading, \strlen($leading)) === 0) { + return \substr($token, \strlen($leading)); + } + } + } + return $default; + } + /** + * Returns a stringified representation of the args passed to the command. + */ + public function __toString() : string + { + $tokens = \array_map(function ($token) { + if (\preg_match('{^(-[^=]+=)(.+)}', $token, $match)) { + return $match[1] . $this->escapeToken($match[2]); + } + if ($token && '-' !== $token[0]) { + return $this->escapeToken($token); + } + return $token; + }, $this->tokens); + return \implode(' ', $tokens); + } +} diff --git a/vendor/symfony/console/Input/ArrayInput.php b/vendor/symfony/console/Input/ArrayInput.php new file mode 100644 index 0000000000..73b38311fd --- /dev/null +++ b/vendor/symfony/console/Input/ArrayInput.php @@ -0,0 +1,181 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Input; + +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidOptionException; +/** + * ArrayInput represents an input provided as an array. + * + * Usage: + * + * $input = new ArrayInput(['command' => 'foo:bar', 'foo' => 'bar', '--bar' => 'foobar']); + * + * @author Fabien Potencier + */ +class ArrayInput extends Input +{ + /** + * @var mixed[] + */ + private $parameters; + public function __construct(array $parameters, ?InputDefinition $definition = null) + { + $this->parameters = $parameters; + parent::__construct($definition); + } + public function getFirstArgument() : ?string + { + foreach ($this->parameters as $param => $value) { + if ($param && \is_string($param) && '-' === $param[0]) { + continue; + } + return $value; + } + return null; + } + /** + * @param string|mixed[] $values + */ + public function hasParameterOption($values, bool $onlyParams = \false) : bool + { + $values = (array) $values; + foreach ($this->parameters as $k => $v) { + if (!\is_int($k)) { + $v = $k; + } + if ($onlyParams && '--' === $v) { + return \false; + } + if (\in_array($v, $values)) { + return \true; + } + } + return \false; + } + /** + * @param string|mixed[] $values + * @param string|bool|int|float|mixed[]|null $default + * @return mixed + */ + public function getParameterOption($values, $default = \false, bool $onlyParams = \false) + { + $values = (array) $values; + foreach ($this->parameters as $k => $v) { + if ($onlyParams && ('--' === $k || \is_int($k) && '--' === $v)) { + return $default; + } + if (\is_int($k)) { + if (\in_array($v, $values)) { + return \true; + } + } elseif (\in_array($k, $values)) { + return $v; + } + } + return $default; + } + /** + * Returns a stringified representation of the args passed to the command. + */ + public function __toString() : string + { + $params = []; + foreach ($this->parameters as $param => $val) { + if ($param && \is_string($param) && '-' === $param[0]) { + $glue = '-' === $param[1] ? '=' : ' '; + if (\is_array($val)) { + foreach ($val as $v) { + $params[] = $param . ('' != $v ? $glue . $this->escapeToken($v) : ''); + } + } else { + $params[] = $param . ('' != $val ? $glue . $this->escapeToken($val) : ''); + } + } else { + $params[] = \is_array($val) ? \implode(' ', \array_map(\Closure::fromCallable([$this, 'escapeToken']), $val)) : $this->escapeToken($val); + } + } + return \implode(' ', $params); + } + /** + * @return void + */ + protected function parse() + { + foreach ($this->parameters as $key => $value) { + if ('--' === $key) { + return; + } + if (\strncmp($key, '--', \strlen('--')) === 0) { + $this->addLongOption(\substr($key, 2), $value); + } elseif (\strncmp($key, '-', \strlen('-')) === 0) { + $this->addShortOption(\substr($key, 1), $value); + } else { + $this->addArgument($key, $value); + } + } + } + /** + * Adds a short option value. + * + * @throws InvalidOptionException When option given doesn't exist + * @param mixed $value + */ + private function addShortOption(string $shortcut, $value) : void + { + if (!$this->definition->hasShortcut($shortcut)) { + throw new InvalidOptionException(\sprintf('The "-%s" option does not exist.', $shortcut)); + } + $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value); + } + /** + * Adds a long option value. + * + * @throws InvalidOptionException When option given doesn't exist + * @throws InvalidOptionException When a required value is missing + * @param mixed $value + */ + private function addLongOption(string $name, $value) : void + { + if (!$this->definition->hasOption($name)) { + if (!$this->definition->hasNegation($name)) { + throw new InvalidOptionException(\sprintf('The "--%s" option does not exist.', $name)); + } + $optionName = $this->definition->negationToName($name); + $this->options[$optionName] = \false; + return; + } + $option = $this->definition->getOption($name); + if (null === $value) { + if ($option->isValueRequired()) { + throw new InvalidOptionException(\sprintf('The "--%s" option requires a value.', $name)); + } + if (!$option->isValueOptional()) { + $value = \true; + } + } + $this->options[$name] = $value; + } + /** + * Adds an argument value. + * + * @throws InvalidArgumentException When argument given doesn't exist + * @param string|int $name + * @param mixed $value + */ + private function addArgument($name, $value) : void + { + if (!$this->definition->hasArgument($name)) { + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); + } + $this->arguments[$name] = $value; + } +} diff --git a/vendor/symfony/console/Input/Input.php b/vendor/symfony/console/Input/Input.php new file mode 100644 index 0000000000..2deabb2b60 --- /dev/null +++ b/vendor/symfony/console/Input/Input.php @@ -0,0 +1,174 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Input; + +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +use SwissKnife202405\Symfony\Component\Console\Exception\RuntimeException; +/** + * Input is the base class for all concrete Input classes. + * + * Three concrete classes are provided by default: + * + * * `ArgvInput`: The input comes from the CLI arguments (argv) + * * `StringInput`: The input is provided as a string + * * `ArrayInput`: The input is provided as an array + * + * @author Fabien Potencier + */ +abstract class Input implements InputInterface, StreamableInputInterface +{ + protected $definition; + /** @var resource */ + protected $stream; + protected $options = []; + protected $arguments = []; + protected $interactive = \true; + public function __construct(?InputDefinition $definition = null) + { + if (null === $definition) { + $this->definition = new InputDefinition(); + } else { + $this->bind($definition); + $this->validate(); + } + } + /** + * @return void + */ + public function bind(InputDefinition $definition) + { + $this->arguments = []; + $this->options = []; + $this->definition = $definition; + $this->parse(); + } + /** + * Processes command line arguments. + * + * @return void + */ + protected abstract function parse(); + /** + * @return void + */ + public function validate() + { + $definition = $this->definition; + $givenArguments = $this->arguments; + $missingArguments = \array_filter(\array_keys($definition->getArguments()), function ($argument) use($givenArguments, $definition) { + return !\array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired(); + }); + if (\count($missingArguments) > 0) { + throw new RuntimeException(\sprintf('Not enough arguments (missing: "%s").', \implode(', ', $missingArguments))); + } + } + public function isInteractive() : bool + { + return $this->interactive; + } + /** + * @return void + */ + public function setInteractive(bool $interactive) + { + $this->interactive = $interactive; + } + public function getArguments() : array + { + return \array_merge($this->definition->getArgumentDefaults(), $this->arguments); + } + /** + * @return mixed + */ + public function getArgument(string $name) + { + if (!$this->definition->hasArgument($name)) { + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); + } + return $this->arguments[$name] ?? $this->definition->getArgument($name)->getDefault(); + } + /** + * @return void + * @param mixed $value + */ + public function setArgument(string $name, $value) + { + if (!$this->definition->hasArgument($name)) { + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); + } + $this->arguments[$name] = $value; + } + public function hasArgument(string $name) : bool + { + return $this->definition->hasArgument($name); + } + public function getOptions() : array + { + return \array_merge($this->definition->getOptionDefaults(), $this->options); + } + /** + * @return mixed + */ + public function getOption(string $name) + { + if ($this->definition->hasNegation($name)) { + if (null === ($value = $this->getOption($this->definition->negationToName($name)))) { + return $value; + } + return !$value; + } + if (!$this->definition->hasOption($name)) { + throw new InvalidArgumentException(\sprintf('The "%s" option does not exist.', $name)); + } + return \array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault(); + } + /** + * @return void + * @param mixed $value + */ + public function setOption(string $name, $value) + { + if ($this->definition->hasNegation($name)) { + $this->options[$this->definition->negationToName($name)] = !$value; + return; + } elseif (!$this->definition->hasOption($name)) { + throw new InvalidArgumentException(\sprintf('The "%s" option does not exist.', $name)); + } + $this->options[$name] = $value; + } + public function hasOption(string $name) : bool + { + return $this->definition->hasOption($name) || $this->definition->hasNegation($name); + } + /** + * Escapes a token through escapeshellarg if it contains unsafe chars. + */ + public function escapeToken(string $token) : string + { + return \preg_match('{^[\\w-]+$}', $token) ? $token : \escapeshellarg($token); + } + /** + * @param resource $stream + * + * @return void + */ + public function setStream($stream) + { + $this->stream = $stream; + } + /** + * @return resource + */ + public function getStream() + { + return $this->stream; + } +} diff --git a/vendor/symfony/console/Input/InputArgument.php b/vendor/symfony/console/Input/InputArgument.php new file mode 100644 index 0000000000..269d5c0840 --- /dev/null +++ b/vendor/symfony/console/Input/InputArgument.php @@ -0,0 +1,155 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Input; + +use SwissKnife202405\Symfony\Component\Console\Command\Command; +use SwissKnife202405\Symfony\Component\Console\Completion\CompletionInput; +use SwissKnife202405\Symfony\Component\Console\Completion\CompletionSuggestions; +use SwissKnife202405\Symfony\Component\Console\Completion\Suggestion; +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +use SwissKnife202405\Symfony\Component\Console\Exception\LogicException; +/** + * Represents a command line argument. + * + * @author Fabien Potencier + */ +class InputArgument +{ + public const REQUIRED = 1; + public const OPTIONAL = 2; + public const IS_ARRAY = 4; + /** + * @var string + */ + private $name; + /** + * @var int + */ + private $mode; + /** + * @var mixed[]|bool|float|int|string|null + */ + private $default; + /** + * @var mixed[]|\Closure + */ + private $suggestedValues; + /** + * @var string + */ + private $description; + /** + * @param string $name The argument name + * @param int|null $mode The argument mode: a bit mask of self::REQUIRED, self::OPTIONAL and self::IS_ARRAY + * @param string $description A description text + * @param string|bool|int|float|array|null $default The default value (for self::OPTIONAL mode only) + * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion + * + * @throws InvalidArgumentException When argument mode is not valid + */ + public function __construct(string $name, ?int $mode = null, string $description = '', $default = null, $suggestedValues = []) + { + if (null === $mode) { + $mode = self::OPTIONAL; + } elseif ($mode > 7 || $mode < 1) { + throw new InvalidArgumentException(\sprintf('Argument mode "%s" is not valid.', $mode)); + } + $this->name = $name; + $this->mode = $mode; + $this->description = $description; + $this->suggestedValues = $suggestedValues; + $this->setDefault($default); + } + /** + * Returns the argument name. + */ + public function getName() : string + { + return $this->name; + } + /** + * Returns true if the argument is required. + * + * @return bool true if parameter mode is self::REQUIRED, false otherwise + */ + public function isRequired() : bool + { + return self::REQUIRED === (self::REQUIRED & $this->mode); + } + /** + * Returns true if the argument can take multiple values. + * + * @return bool true if mode is self::IS_ARRAY, false otherwise + */ + public function isArray() : bool + { + return self::IS_ARRAY === (self::IS_ARRAY & $this->mode); + } + /** + * Sets the default value. + * + * @return void + * + * @throws LogicException When incorrect default value is given + * @param string|bool|int|float|mixed[]|null $default + */ + public function setDefault($default = null) + { + if (1 > \func_num_args()) { + trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); + } + if ($this->isRequired() && null !== $default) { + throw new LogicException('Cannot set a default value except for InputArgument::OPTIONAL mode.'); + } + if ($this->isArray()) { + if (null === $default) { + $default = []; + } elseif (!\is_array($default)) { + throw new LogicException('A default value for an array argument must be an array.'); + } + } + $this->default = $default; + } + /** + * Returns the default value. + * @return mixed[]|bool|float|int|string|null + */ + public function getDefault() + { + return $this->default; + } + public function hasCompletion() : bool + { + return [] !== $this->suggestedValues; + } + /** + * Adds suggestions to $suggestions for the current completion input. + * + * @see Command::complete() + */ + public function complete(CompletionInput $input, CompletionSuggestions $suggestions) : void + { + $values = $this->suggestedValues; + if ($values instanceof \Closure && !\is_array($values = $values($input))) { + throw new LogicException(\sprintf('Closure for argument "%s" must return an array. Got "%s".', $this->name, \get_debug_type($values))); + } + if ($values) { + $suggestions->suggestValues($values); + } + } + /** + * Returns the description text. + */ + public function getDescription() : string + { + return $this->description; + } +} diff --git a/vendor/symfony/console/Input/InputAwareInterface.php b/vendor/symfony/console/Input/InputAwareInterface.php new file mode 100644 index 0000000000..35ecd59fe0 --- /dev/null +++ b/vendor/symfony/console/Input/InputAwareInterface.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Input; + +/** + * InputAwareInterface should be implemented by classes that depends on the + * Console Input. + * + * @author Wouter J + */ +interface InputAwareInterface +{ + /** + * Sets the Console Input. + * + * @return void + */ + public function setInput(InputInterface $input); +} diff --git a/vendor/symfony/console/Input/InputDefinition.php b/vendor/symfony/console/Input/InputDefinition.php new file mode 100644 index 0000000000..6fcf2d987a --- /dev/null +++ b/vendor/symfony/console/Input/InputDefinition.php @@ -0,0 +1,384 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Input; + +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +use SwissKnife202405\Symfony\Component\Console\Exception\LogicException; +/** + * A InputDefinition represents a set of valid command line arguments and options. + * + * Usage: + * + * $definition = new InputDefinition([ + * new InputArgument('name', InputArgument::REQUIRED), + * new InputOption('foo', 'f', InputOption::VALUE_REQUIRED), + * ]); + * + * @author Fabien Potencier + */ +class InputDefinition +{ + /** + * @var mixed[] + */ + private $arguments = []; + /** + * @var int + */ + private $requiredCount = 0; + /** + * @var \Symfony\Component\Console\Input\InputArgument|null + */ + private $lastArrayArgument; + /** + * @var \Symfony\Component\Console\Input\InputArgument|null + */ + private $lastOptionalArgument; + /** + * @var mixed[] + */ + private $options = []; + /** + * @var mixed[] + */ + private $negations = []; + /** + * @var mixed[] + */ + private $shortcuts = []; + /** + * @param array $definition An array of InputArgument and InputOption instance + */ + public function __construct(array $definition = []) + { + $this->setDefinition($definition); + } + /** + * Sets the definition of the input. + * + * @return void + */ + public function setDefinition(array $definition) + { + $arguments = []; + $options = []; + foreach ($definition as $item) { + if ($item instanceof InputOption) { + $options[] = $item; + } else { + $arguments[] = $item; + } + } + $this->setArguments($arguments); + $this->setOptions($options); + } + /** + * Sets the InputArgument objects. + * + * @param InputArgument[] $arguments An array of InputArgument objects + * + * @return void + */ + public function setArguments(array $arguments = []) + { + $this->arguments = []; + $this->requiredCount = 0; + $this->lastOptionalArgument = null; + $this->lastArrayArgument = null; + $this->addArguments($arguments); + } + /** + * Adds an array of InputArgument objects. + * + * @param InputArgument[] $arguments An array of InputArgument objects + * + * @return void + */ + public function addArguments(?array $arguments = []) + { + if (null !== $arguments) { + foreach ($arguments as $argument) { + $this->addArgument($argument); + } + } + } + /** + * @return void + * + * @throws LogicException When incorrect argument is given + */ + public function addArgument(InputArgument $argument) + { + if (isset($this->arguments[$argument->getName()])) { + throw new LogicException(\sprintf('An argument with name "%s" already exists.', $argument->getName())); + } + if (null !== $this->lastArrayArgument) { + throw new LogicException(\sprintf('Cannot add a required argument "%s" after an array argument "%s".', $argument->getName(), $this->lastArrayArgument->getName())); + } + if ($argument->isRequired() && null !== $this->lastOptionalArgument) { + throw new LogicException(\sprintf('Cannot add a required argument "%s" after an optional one "%s".', $argument->getName(), $this->lastOptionalArgument->getName())); + } + if ($argument->isArray()) { + $this->lastArrayArgument = $argument; + } + if ($argument->isRequired()) { + ++$this->requiredCount; + } else { + $this->lastOptionalArgument = $argument; + } + $this->arguments[$argument->getName()] = $argument; + } + /** + * Returns an InputArgument by name or by position. + * + * @throws InvalidArgumentException When argument given doesn't exist + * @param string|int $name + */ + public function getArgument($name) : InputArgument + { + if (!$this->hasArgument($name)) { + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); + } + $arguments = \is_int($name) ? \array_values($this->arguments) : $this->arguments; + return $arguments[$name]; + } + /** + * Returns true if an InputArgument object exists by name or position. + * @param string|int $name + */ + public function hasArgument($name) : bool + { + $arguments = \is_int($name) ? \array_values($this->arguments) : $this->arguments; + return isset($arguments[$name]); + } + /** + * Gets the array of InputArgument objects. + * + * @return InputArgument[] + */ + public function getArguments() : array + { + return $this->arguments; + } + /** + * Returns the number of InputArguments. + */ + public function getArgumentCount() : int + { + return null !== $this->lastArrayArgument ? \PHP_INT_MAX : \count($this->arguments); + } + /** + * Returns the number of required InputArguments. + */ + public function getArgumentRequiredCount() : int + { + return $this->requiredCount; + } + /** + * @return array + */ + public function getArgumentDefaults() : array + { + $values = []; + foreach ($this->arguments as $argument) { + $values[$argument->getName()] = $argument->getDefault(); + } + return $values; + } + /** + * Sets the InputOption objects. + * + * @param InputOption[] $options An array of InputOption objects + * + * @return void + */ + public function setOptions(array $options = []) + { + $this->options = []; + $this->shortcuts = []; + $this->negations = []; + $this->addOptions($options); + } + /** + * Adds an array of InputOption objects. + * + * @param InputOption[] $options An array of InputOption objects + * + * @return void + */ + public function addOptions(array $options = []) + { + foreach ($options as $option) { + $this->addOption($option); + } + } + /** + * @return void + * + * @throws LogicException When option given already exist + */ + public function addOption(InputOption $option) + { + if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) { + throw new LogicException(\sprintf('An option named "%s" already exists.', $option->getName())); + } + if (isset($this->negations[$option->getName()])) { + throw new LogicException(\sprintf('An option named "%s" already exists.', $option->getName())); + } + if ($option->getShortcut()) { + foreach (\explode('|', $option->getShortcut()) as $shortcut) { + if (isset($this->shortcuts[$shortcut]) && !$option->equals($this->options[$this->shortcuts[$shortcut]])) { + throw new LogicException(\sprintf('An option with shortcut "%s" already exists.', $shortcut)); + } + } + } + $this->options[$option->getName()] = $option; + if ($option->getShortcut()) { + foreach (\explode('|', $option->getShortcut()) as $shortcut) { + $this->shortcuts[$shortcut] = $option->getName(); + } + } + if ($option->isNegatable()) { + $negatedName = 'no-' . $option->getName(); + if (isset($this->options[$negatedName])) { + throw new LogicException(\sprintf('An option named "%s" already exists.', $negatedName)); + } + $this->negations[$negatedName] = $option->getName(); + } + } + /** + * Returns an InputOption by name. + * + * @throws InvalidArgumentException When option given doesn't exist + */ + public function getOption(string $name) : InputOption + { + if (!$this->hasOption($name)) { + throw new InvalidArgumentException(\sprintf('The "--%s" option does not exist.', $name)); + } + return $this->options[$name]; + } + /** + * Returns true if an InputOption object exists by name. + * + * This method can't be used to check if the user included the option when + * executing the command (use getOption() instead). + */ + public function hasOption(string $name) : bool + { + return isset($this->options[$name]); + } + /** + * Gets the array of InputOption objects. + * + * @return InputOption[] + */ + public function getOptions() : array + { + return $this->options; + } + /** + * Returns true if an InputOption object exists by shortcut. + */ + public function hasShortcut(string $name) : bool + { + return isset($this->shortcuts[$name]); + } + /** + * Returns true if an InputOption object exists by negated name. + */ + public function hasNegation(string $name) : bool + { + return isset($this->negations[$name]); + } + /** + * Gets an InputOption by shortcut. + */ + public function getOptionForShortcut(string $shortcut) : InputOption + { + return $this->getOption($this->shortcutToName($shortcut)); + } + /** + * @return array + */ + public function getOptionDefaults() : array + { + $values = []; + foreach ($this->options as $option) { + $values[$option->getName()] = $option->getDefault(); + } + return $values; + } + /** + * Returns the InputOption name given a shortcut. + * + * @throws InvalidArgumentException When option given does not exist + * + * @internal + */ + public function shortcutToName(string $shortcut) : string + { + if (!isset($this->shortcuts[$shortcut])) { + throw new InvalidArgumentException(\sprintf('The "-%s" option does not exist.', $shortcut)); + } + return $this->shortcuts[$shortcut]; + } + /** + * Returns the InputOption name given a negation. + * + * @throws InvalidArgumentException When option given does not exist + * + * @internal + */ + public function negationToName(string $negation) : string + { + if (!isset($this->negations[$negation])) { + throw new InvalidArgumentException(\sprintf('The "--%s" option does not exist.', $negation)); + } + return $this->negations[$negation]; + } + /** + * Gets the synopsis. + */ + public function getSynopsis(bool $short = \false) : string + { + $elements = []; + if ($short && $this->getOptions()) { + $elements[] = '[options]'; + } elseif (!$short) { + foreach ($this->getOptions() as $option) { + $value = ''; + if ($option->acceptValue()) { + $value = \sprintf(' %s%s%s', $option->isValueOptional() ? '[' : '', \strtoupper($option->getName()), $option->isValueOptional() ? ']' : ''); + } + $shortcut = $option->getShortcut() ? \sprintf('-%s|', $option->getShortcut()) : ''; + $negation = $option->isNegatable() ? \sprintf('|--no-%s', $option->getName()) : ''; + $elements[] = \sprintf('[%s--%s%s%s]', $shortcut, $option->getName(), $value, $negation); + } + } + if (\count($elements) && $this->getArguments()) { + $elements[] = '[--]'; + } + $tail = ''; + foreach ($this->getArguments() as $argument) { + $element = '<' . $argument->getName() . '>'; + if ($argument->isArray()) { + $element .= '...'; + } + if (!$argument->isRequired()) { + $element = '[' . $element; + $tail .= ']'; + } + $elements[] = $element; + } + return \implode(' ', $elements) . $tail; + } +} diff --git a/vendor/symfony/console/Input/InputInterface.php b/vendor/symfony/console/Input/InputInterface.php new file mode 100644 index 0000000000..1aff520958 --- /dev/null +++ b/vendor/symfony/console/Input/InputInterface.php @@ -0,0 +1,136 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Input; + +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +use SwissKnife202405\Symfony\Component\Console\Exception\RuntimeException; +/** + * InputInterface is the interface implemented by all input classes. + * + * @author Fabien Potencier + * + * @method string __toString() Returns a stringified representation of the args passed to the command. + * InputArguments MUST be escaped as well as the InputOption values passed to the command. + */ +interface InputInterface +{ + /** + * Returns the first argument from the raw parameters (not parsed). + */ + public function getFirstArgument() : ?string; + /** + * Returns true if the raw parameters (not parsed) contain a value. + * + * This method is to be used to introspect the input parameters + * before they have been validated. It must be used carefully. + * Does not necessarily return the correct result for short options + * when multiple flags are combined in the same option. + * + * @param string|array $values The values to look for in the raw parameters (can be an array) + * @param bool $onlyParams Only check real parameters, skip those following an end of options (--) signal + */ + public function hasParameterOption($values, bool $onlyParams = \false) : bool; + /** + * Returns the value of a raw option (not parsed). + * + * This method is to be used to introspect the input parameters + * before they have been validated. It must be used carefully. + * Does not necessarily return the correct result for short options + * when multiple flags are combined in the same option. + * + * @param string|array $values The value(s) to look for in the raw parameters (can be an array) + * @param string|bool|int|float|array|null $default The default value to return if no result is found + * @param bool $onlyParams Only check real parameters, skip those following an end of options (--) signal + * + * @return mixed + */ + public function getParameterOption($values, $default = \false, bool $onlyParams = \false); + /** + * Binds the current Input instance with the given arguments and options. + * + * @return void + * + * @throws RuntimeException + */ + public function bind(InputDefinition $definition); + /** + * Validates the input. + * + * @return void + * + * @throws RuntimeException When not enough arguments are given + */ + public function validate(); + /** + * Returns all the given arguments merged with the default values. + * + * @return array + */ + public function getArguments() : array; + /** + * Returns the argument value for a given argument name. + * + * @return mixed + * + * @throws InvalidArgumentException When argument given doesn't exist + */ + public function getArgument(string $name); + /** + * Sets an argument value by name. + * + * @return void + * + * @throws InvalidArgumentException When argument given doesn't exist + * @param mixed $value + */ + public function setArgument(string $name, $value); + /** + * Returns true if an InputArgument object exists by name or position. + */ + public function hasArgument(string $name) : bool; + /** + * Returns all the given options merged with the default values. + * + * @return array + */ + public function getOptions() : array; + /** + * Returns the option value for a given option name. + * + * @return mixed + * + * @throws InvalidArgumentException When option given doesn't exist + */ + public function getOption(string $name); + /** + * Sets an option value by name. + * + * @return void + * + * @throws InvalidArgumentException When option given doesn't exist + * @param mixed $value + */ + public function setOption(string $name, $value); + /** + * Returns true if an InputOption object exists by name. + */ + public function hasOption(string $name) : bool; + /** + * Is this input means interactive? + */ + public function isInteractive() : bool; + /** + * Sets the input interactivity. + * + * @return void + */ + public function setInteractive(bool $interactive); +} diff --git a/vendor/symfony/console/Input/InputOption.php b/vendor/symfony/console/Input/InputOption.php new file mode 100644 index 0000000000..0b61185113 --- /dev/null +++ b/vendor/symfony/console/Input/InputOption.php @@ -0,0 +1,237 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Input; + +use SwissKnife202405\Symfony\Component\Console\Command\Command; +use SwissKnife202405\Symfony\Component\Console\Completion\CompletionInput; +use SwissKnife202405\Symfony\Component\Console\Completion\CompletionSuggestions; +use SwissKnife202405\Symfony\Component\Console\Completion\Suggestion; +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +use SwissKnife202405\Symfony\Component\Console\Exception\LogicException; +/** + * Represents a command line option. + * + * @author Fabien Potencier + */ +class InputOption +{ + /** + * Do not accept input for the option (e.g. --yell). This is the default behavior of options. + */ + public const VALUE_NONE = 1; + /** + * A value must be passed when the option is used (e.g. --iterations=5 or -i5). + */ + public const VALUE_REQUIRED = 2; + /** + * The option may or may not have a value (e.g. --yell or --yell=loud). + */ + public const VALUE_OPTIONAL = 4; + /** + * The option accepts multiple values (e.g. --dir=/foo --dir=/bar). + */ + public const VALUE_IS_ARRAY = 8; + /** + * The option may have either positive or negative value (e.g. --ansi or --no-ansi). + */ + public const VALUE_NEGATABLE = 16; + /** + * @var string + */ + private $name; + /** + * @var mixed[]|string|null + */ + private $shortcut; + /** + * @var int + */ + private $mode; + /** + * @var mixed[]|bool|float|int|string|null + */ + private $default; + /** + * @var mixed[]|\Closure + */ + private $suggestedValues; + /** + * @var string + */ + private $description; + /** + * @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts + * @param int|null $mode The option mode: One of the VALUE_* constants + * @param string|bool|int|float|array|null $default The default value (must be null for self::VALUE_NONE) + * @param array|\Closure(CompletionInput,CompletionSuggestions):list $suggestedValues The values used for input completion + * + * @throws InvalidArgumentException If option mode is invalid or incompatible + */ + public function __construct(string $name, $shortcut = null, ?int $mode = null, string $description = '', $default = null, $suggestedValues = []) + { + if (\strncmp($name, '--', \strlen('--')) === 0) { + $name = \substr($name, 2); + } + if (empty($name)) { + throw new InvalidArgumentException('An option name cannot be empty.'); + } + if ('' === $shortcut || [] === $shortcut || \false === $shortcut) { + $shortcut = null; + } + if (null !== $shortcut) { + if (\is_array($shortcut)) { + $shortcut = \implode('|', $shortcut); + } + $shortcuts = \preg_split('{(\\|)-?}', \ltrim($shortcut, '-')); + $shortcuts = \array_filter($shortcuts, 'strlen'); + $shortcut = \implode('|', $shortcuts); + if ('' === $shortcut) { + throw new InvalidArgumentException('An option shortcut cannot be empty.'); + } + } + if (null === $mode) { + $mode = self::VALUE_NONE; + } elseif ($mode >= self::VALUE_NEGATABLE << 1 || $mode < 1) { + throw new InvalidArgumentException(\sprintf('Option mode "%s" is not valid.', $mode)); + } + $this->name = $name; + $this->shortcut = $shortcut; + $this->mode = $mode; + $this->description = $description; + $this->suggestedValues = $suggestedValues; + if ($suggestedValues && !$this->acceptValue()) { + throw new LogicException('Cannot set suggested values if the option does not accept a value.'); + } + if ($this->isArray() && !$this->acceptValue()) { + throw new InvalidArgumentException('Impossible to have an option mode VALUE_IS_ARRAY if the option does not accept a value.'); + } + if ($this->isNegatable() && $this->acceptValue()) { + throw new InvalidArgumentException('Impossible to have an option mode VALUE_NEGATABLE if the option also accepts a value.'); + } + $this->setDefault($default); + } + /** + * Returns the option shortcut. + */ + public function getShortcut() : ?string + { + return $this->shortcut; + } + /** + * Returns the option name. + */ + public function getName() : string + { + return $this->name; + } + /** + * Returns true if the option accepts a value. + * + * @return bool true if value mode is not self::VALUE_NONE, false otherwise + */ + public function acceptValue() : bool + { + return $this->isValueRequired() || $this->isValueOptional(); + } + /** + * Returns true if the option requires a value. + * + * @return bool true if value mode is self::VALUE_REQUIRED, false otherwise + */ + public function isValueRequired() : bool + { + return self::VALUE_REQUIRED === (self::VALUE_REQUIRED & $this->mode); + } + /** + * Returns true if the option takes an optional value. + * + * @return bool true if value mode is self::VALUE_OPTIONAL, false otherwise + */ + public function isValueOptional() : bool + { + return self::VALUE_OPTIONAL === (self::VALUE_OPTIONAL & $this->mode); + } + /** + * Returns true if the option can take multiple values. + * + * @return bool true if mode is self::VALUE_IS_ARRAY, false otherwise + */ + public function isArray() : bool + { + return self::VALUE_IS_ARRAY === (self::VALUE_IS_ARRAY & $this->mode); + } + public function isNegatable() : bool + { + return self::VALUE_NEGATABLE === (self::VALUE_NEGATABLE & $this->mode); + } + /** + * @return void + * @param string|bool|int|float|mixed[]|null $default + */ + public function setDefault($default = null) + { + if (1 > \func_num_args()) { + trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); + } + if (self::VALUE_NONE === (self::VALUE_NONE & $this->mode) && null !== $default) { + throw new LogicException('Cannot set a default value when using InputOption::VALUE_NONE mode.'); + } + if ($this->isArray()) { + if (null === $default) { + $default = []; + } elseif (!\is_array($default)) { + throw new LogicException('A default value for an array option must be an array.'); + } + } + $this->default = $this->acceptValue() || $this->isNegatable() ? $default : \false; + } + /** + * Returns the default value. + * @return mixed[]|bool|float|int|string|null + */ + public function getDefault() + { + return $this->default; + } + /** + * Returns the description text. + */ + public function getDescription() : string + { + return $this->description; + } + public function hasCompletion() : bool + { + return [] !== $this->suggestedValues; + } + /** + * Adds suggestions to $suggestions for the current completion input. + * + * @see Command::complete() + */ + public function complete(CompletionInput $input, CompletionSuggestions $suggestions) : void + { + $values = $this->suggestedValues; + if ($values instanceof \Closure && !\is_array($values = $values($input))) { + throw new LogicException(\sprintf('Closure for option "%s" must return an array. Got "%s".', $this->name, \get_debug_type($values))); + } + if ($values) { + $suggestions->suggestValues($values); + } + } + /** + * Checks whether the given option equals this one. + */ + public function equals(self $option) : bool + { + return $option->getName() === $this->getName() && $option->getShortcut() === $this->getShortcut() && $option->getDefault() === $this->getDefault() && $option->isNegatable() === $this->isNegatable() && $option->isArray() === $this->isArray() && $option->isValueRequired() === $this->isValueRequired() && $option->isValueOptional() === $this->isValueOptional(); + } +} diff --git a/vendor/symfony/console/Input/StreamableInputInterface.php b/vendor/symfony/console/Input/StreamableInputInterface.php new file mode 100644 index 0000000000..76391bbbca --- /dev/null +++ b/vendor/symfony/console/Input/StreamableInputInterface.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Input; + +/** + * StreamableInputInterface is the interface implemented by all input classes + * that have an input stream. + * + * @author Robin Chalas + */ +interface StreamableInputInterface extends InputInterface +{ + /** + * Sets the input stream to read from when interacting with the user. + * + * This is mainly useful for testing purpose. + * + * @param resource $stream The input stream + * + * @return void + */ + public function setStream($stream); + /** + * Returns the input stream. + * + * @return resource|null + */ + public function getStream(); +} diff --git a/vendor/symfony/console/Input/StringInput.php b/vendor/symfony/console/Input/StringInput.php new file mode 100644 index 0000000000..13607b112f --- /dev/null +++ b/vendor/symfony/console/Input/StringInput.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Input; + +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +/** + * StringInput represents an input provided as a string. + * + * Usage: + * + * $input = new StringInput('foo --bar="foobar"'); + * + * @author Fabien Potencier + */ +class StringInput extends ArgvInput +{ + /** + * @deprecated since Symfony 6.1 + */ + public const REGEX_STRING = '([^\\s]+?)(?:\\s|(?setTokens($this->tokenize($input)); + } + /** + * Tokenizes a string. + * + * @throws InvalidArgumentException When unable to parse input (should never happen) + */ + private function tokenize(string $input) : array + { + $tokens = []; + $length = \strlen($input); + $cursor = 0; + $token = null; + while ($cursor < $length) { + if ('\\' === $input[$cursor]) { + $token .= $input[++$cursor] ?? ''; + ++$cursor; + continue; + } + if (\preg_match('/\\s+/A', $input, $match, 0, $cursor)) { + if (null !== $token) { + $tokens[] = $token; + $token = null; + } + } elseif (\preg_match('/([^="\'\\s]+?)(=?)(' . self::REGEX_QUOTED_STRING . '+)/A', $input, $match, 0, $cursor)) { + $token .= $match[1] . $match[2] . \stripcslashes(\str_replace(['"\'', '\'"', '\'\'', '""'], '', \substr($match[3], 1, -1))); + } elseif (\preg_match('/' . self::REGEX_QUOTED_STRING . '/A', $input, $match, 0, $cursor)) { + $token .= \stripcslashes(\substr($match[0], 1, -1)); + } elseif (\preg_match('/' . self::REGEX_UNQUOTED_STRING . '/A', $input, $match, 0, $cursor)) { + $token .= $match[1]; + } else { + // should never happen + throw new InvalidArgumentException(\sprintf('Unable to parse input near "... %s ...".', \substr($input, $cursor, 10))); + } + $cursor += \strlen($match[0]); + } + if (null !== $token) { + $tokens[] = $token; + } + return $tokens; + } +} diff --git a/vendor/symfony/console/LICENSE b/vendor/symfony/console/LICENSE new file mode 100644 index 0000000000..0138f8f071 --- /dev/null +++ b/vendor/symfony/console/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-present Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/console/Logger/ConsoleLogger.php b/vendor/symfony/console/Logger/ConsoleLogger.php new file mode 100644 index 0000000000..045b182def --- /dev/null +++ b/vendor/symfony/console/Logger/ConsoleLogger.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Logger; + +use SwissKnife202405\Psr\Log\AbstractLogger; +use SwissKnife202405\Psr\Log\InvalidArgumentException; +use SwissKnife202405\Psr\Log\LogLevel; +use SwissKnife202405\Symfony\Component\Console\Output\ConsoleOutputInterface; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +/** + * PSR-3 compliant console logger. + * + * @author Kévin Dunglas + * + * @see https://www.php-fig.org/psr/psr-3/ + */ +class ConsoleLogger extends AbstractLogger +{ + public const INFO = 'info'; + public const ERROR = 'error'; + /** + * @var \Symfony\Component\Console\Output\OutputInterface + */ + private $output; + /** + * @var mixed[] + */ + private $verbosityLevelMap = [LogLevel::EMERGENCY => OutputInterface::VERBOSITY_NORMAL, LogLevel::ALERT => OutputInterface::VERBOSITY_NORMAL, LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL, LogLevel::ERROR => OutputInterface::VERBOSITY_NORMAL, LogLevel::WARNING => OutputInterface::VERBOSITY_NORMAL, LogLevel::NOTICE => OutputInterface::VERBOSITY_VERBOSE, LogLevel::INFO => OutputInterface::VERBOSITY_VERY_VERBOSE, LogLevel::DEBUG => OutputInterface::VERBOSITY_DEBUG]; + /** + * @var mixed[] + */ + private $formatLevelMap = [LogLevel::EMERGENCY => self::ERROR, LogLevel::ALERT => self::ERROR, LogLevel::CRITICAL => self::ERROR, LogLevel::ERROR => self::ERROR, LogLevel::WARNING => self::INFO, LogLevel::NOTICE => self::INFO, LogLevel::INFO => self::INFO, LogLevel::DEBUG => self::INFO]; + /** + * @var bool + */ + private $errored = \false; + public function __construct(OutputInterface $output, array $verbosityLevelMap = [], array $formatLevelMap = []) + { + $this->output = $output; + $this->verbosityLevelMap = $verbosityLevelMap + $this->verbosityLevelMap; + $this->formatLevelMap = $formatLevelMap + $this->formatLevelMap; + } + public function log($level, $message, array $context = []) : void + { + if (!isset($this->verbosityLevelMap[$level])) { + throw new InvalidArgumentException(\sprintf('The log level "%s" does not exist.', $level)); + } + $output = $this->output; + // Write to the error output if necessary and available + if (self::ERROR === $this->formatLevelMap[$level]) { + if ($this->output instanceof ConsoleOutputInterface) { + $output = $output->getErrorOutput(); + } + $this->errored = \true; + } + // the if condition check isn't necessary -- it's the same one that $output will do internally anyway. + // We only do it for efficiency here as the message formatting is relatively expensive. + if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) { + $output->writeln(\sprintf('<%1$s>[%2$s] %3$s', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)), $this->verbosityLevelMap[$level]); + } + } + /** + * Returns true when any messages have been logged at error levels. + */ + public function hasErrored() : bool + { + return $this->errored; + } + /** + * Interpolates context values into the message placeholders. + * + * @author PHP Framework Interoperability Group + */ + private function interpolate(string $message, array $context) : string + { + if (\strpos($message, '{') === \false) { + return $message; + } + $replacements = []; + foreach ($context as $key => $val) { + if (null === $val || \is_scalar($val) || $val instanceof \Stringable) { + $replacements["{{$key}}"] = $val; + } elseif ($val instanceof \DateTimeInterface) { + $replacements["{{$key}}"] = $val->format(\DateTimeInterface::RFC3339); + } elseif (\is_object($val)) { + $replacements["{{$key}}"] = '[object ' . \get_class($val) . ']'; + } else { + $replacements["{{$key}}"] = '[' . \gettype($val) . ']'; + } + } + return \strtr($message, $replacements); + } +} diff --git a/vendor/symfony/console/Messenger/RunCommandContext.php b/vendor/symfony/console/Messenger/RunCommandContext.php new file mode 100644 index 0000000000..cb9b489a23 --- /dev/null +++ b/vendor/symfony/console/Messenger/RunCommandContext.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Messenger; + +/** + * @author Kevin Bond + */ +final class RunCommandContext +{ + /** + * @readonly + * @var \Symfony\Component\Console\Messenger\RunCommandMessage + */ + public $message; + /** + * @readonly + * @var int + */ + public $exitCode; + /** + * @readonly + * @var string + */ + public $output; + public function __construct(RunCommandMessage $message, int $exitCode, string $output) + { + $this->message = $message; + $this->exitCode = $exitCode; + $this->output = $output; + } +} diff --git a/vendor/symfony/console/Messenger/RunCommandMessage.php b/vendor/symfony/console/Messenger/RunCommandMessage.php new file mode 100644 index 0000000000..a0efb65d9b --- /dev/null +++ b/vendor/symfony/console/Messenger/RunCommandMessage.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Messenger; + +use SwissKnife202405\Symfony\Component\Console\Exception\RunCommandFailedException; +/** + * @author Kevin Bond + */ +class RunCommandMessage +{ + /** + * @readonly + * @var string + */ + public $input; + /** + * @var bool + * @readonly + */ + public $throwOnFailure = \true; + /** + * @var bool + * @readonly + */ + public $catchExceptions = \false; + /** + * @param bool $throwOnFailure If the command has a non-zero exit code, throw {@see RunCommandFailedException} + * @param bool $catchExceptions @see Application::setCatchExceptions() + */ + public function __construct(string $input, bool $throwOnFailure = \true, bool $catchExceptions = \false) + { + $this->input = $input; + $this->throwOnFailure = $throwOnFailure; + $this->catchExceptions = $catchExceptions; + } + public function __toString() : string + { + return $this->input; + } +} diff --git a/vendor/symfony/console/Messenger/RunCommandMessageHandler.php b/vendor/symfony/console/Messenger/RunCommandMessageHandler.php new file mode 100644 index 0000000000..35408418e4 --- /dev/null +++ b/vendor/symfony/console/Messenger/RunCommandMessageHandler.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Messenger; + +use SwissKnife202405\Symfony\Component\Console\Application; +use SwissKnife202405\Symfony\Component\Console\Command\Command; +use SwissKnife202405\Symfony\Component\Console\Exception\RunCommandFailedException; +use SwissKnife202405\Symfony\Component\Console\Input\StringInput; +use SwissKnife202405\Symfony\Component\Console\Output\BufferedOutput; +/** + * @author Kevin Bond + */ +final class RunCommandMessageHandler +{ + /** + * @readonly + * @var \Symfony\Component\Console\Application + */ + private $application; + public function __construct(Application $application) + { + $this->application = $application; + } + public function __invoke(RunCommandMessage $message) : RunCommandContext + { + $input = new StringInput($message->input); + $output = new BufferedOutput(); + $this->application->setCatchExceptions($message->catchExceptions); + try { + $exitCode = $this->application->run($input, $output); + } catch (\Throwable $e) { + throw new RunCommandFailedException($e, new RunCommandContext($message, Command::FAILURE, $output->fetch())); + } + if ($message->throwOnFailure && Command::SUCCESS !== $exitCode) { + throw new RunCommandFailedException(\sprintf('Command "%s" exited with code "%s".', $message->input, $exitCode), new RunCommandContext($message, $exitCode, $output->fetch())); + } + return new RunCommandContext($message, $exitCode, $output->fetch()); + } +} diff --git a/vendor/symfony/console/Output/AnsiColorMode.php b/vendor/symfony/console/Output/AnsiColorMode.php new file mode 100644 index 0000000000..828d6e6dce --- /dev/null +++ b/vendor/symfony/console/Output/AnsiColorMode.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Output; + +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +class AnsiColorMode +{ + public const Ansi4 = 'ansi4'; + public const Ansi8 = 'ansi8'; + public const Ansi24 = 'ansi24'; + /** + * Converts an RGB hexadecimal color to the corresponding Ansi code. + */ + public function convertFromHexToAnsiColorCode(string $hexColor) : string + { + $hexColor = \str_replace('#', '', $hexColor); + if (3 === \strlen($hexColor)) { + $hexColor = $hexColor[0] . $hexColor[0] . $hexColor[1] . $hexColor[1] . $hexColor[2] . $hexColor[2]; + } + if (6 !== \strlen($hexColor)) { + throw new InvalidArgumentException(\sprintf('Invalid "#%s" color.', $hexColor)); + } + $color = \hexdec($hexColor); + $r = $color >> 16 & 255; + $g = $color >> 8 & 255; + $b = $color & 255; + switch ($this) { + case self::Ansi4: + return (string) $this->convertFromRGB($r, $g, $b); + case self::Ansi8: + return '8;5;' . (string) $this->convertFromRGB($r, $g, $b); + case self::Ansi24: + return \sprintf('8;2;%d;%d;%d', $r, $g, $b); + } + } + private function convertFromRGB(int $r, int $g, int $b) : int + { + switch ($this) { + case self::Ansi4: + return $this->degradeHexColorToAnsi4($r, $g, $b); + case self::Ansi8: + return $this->degradeHexColorToAnsi8($r, $g, $b); + default: + throw new InvalidArgumentException("RGB cannot be converted to {$this->name}."); + } + } + private function degradeHexColorToAnsi4(int $r, int $g, int $b) : int + { + return \round($b / 255) << 2 | \round($g / 255) << 1 | \round($r / 255); + } + /** + * Inspired from https://github.com/ajalt/colormath/blob/e464e0da1b014976736cf97250063248fc77b8e7/colormath/src/commonMain/kotlin/com/github/ajalt/colormath/model/Ansi256.kt code (MIT license). + */ + private function degradeHexColorToAnsi8(int $r, int $g, int $b) : int + { + if ($r === $g && $g === $b) { + if ($r < 8) { + return 16; + } + if ($r > 248) { + return 231; + } + return (int) \round(($r - 8) / 247 * 24) + 232; + } else { + return 16 + 36 * (int) \round($r / 255 * 5) + 6 * (int) \round($g / 255 * 5) + (int) \round($b / 255 * 5); + } + } +} diff --git a/vendor/symfony/console/Output/BufferedOutput.php b/vendor/symfony/console/Output/BufferedOutput.php new file mode 100644 index 0000000000..cf819c15cc --- /dev/null +++ b/vendor/symfony/console/Output/BufferedOutput.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Output; + +/** + * @author Jean-François Simon + */ +class BufferedOutput extends Output +{ + /** + * @var string + */ + private $buffer = ''; + /** + * Empties buffer and returns its content. + */ + public function fetch() : string + { + $content = $this->buffer; + $this->buffer = ''; + return $content; + } + /** + * @return void + */ + protected function doWrite(string $message, bool $newline) + { + $this->buffer .= $message; + if ($newline) { + $this->buffer .= \PHP_EOL; + } + } +} diff --git a/vendor/symfony/console/Output/ConsoleOutput.php b/vendor/symfony/console/Output/ConsoleOutput.php new file mode 100644 index 0000000000..fa15e11600 --- /dev/null +++ b/vendor/symfony/console/Output/ConsoleOutput.php @@ -0,0 +1,146 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Output; + +use SwissKnife202405\Symfony\Component\Console\Formatter\OutputFormatterInterface; +/** + * ConsoleOutput is the default class for all CLI output. It uses STDOUT and STDERR. + * + * This class is a convenient wrapper around `StreamOutput` for both STDOUT and STDERR. + * + * $output = new ConsoleOutput(); + * + * This is equivalent to: + * + * $output = new StreamOutput(fopen('php://stdout', 'w')); + * $stdErr = new StreamOutput(fopen('php://stderr', 'w')); + * + * @author Fabien Potencier + */ +class ConsoleOutput extends StreamOutput implements ConsoleOutputInterface +{ + /** + * @var \Symfony\Component\Console\Output\OutputInterface + */ + private $stderr; + /** + * @var mixed[] + */ + private $consoleSectionOutputs = []; + /** + * @param int $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface) + * @param bool|null $decorated Whether to decorate messages (null for auto-guessing) + * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter) + */ + public function __construct(int $verbosity = self::VERBOSITY_NORMAL, ?bool $decorated = null, ?OutputFormatterInterface $formatter = null) + { + parent::__construct($this->openOutputStream(), $verbosity, $decorated, $formatter); + if (null === $formatter) { + // for BC reasons, stdErr has it own Formatter only when user don't inject a specific formatter. + $this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated); + return; + } + $actualDecorated = $this->isDecorated(); + $this->stderr = new StreamOutput($this->openErrorStream(), $verbosity, $decorated, $this->getFormatter()); + if (null === $decorated) { + $this->setDecorated($actualDecorated && $this->stderr->isDecorated()); + } + } + /** + * Creates a new output section. + */ + public function section() : ConsoleSectionOutput + { + return new ConsoleSectionOutput($this->getStream(), $this->consoleSectionOutputs, $this->getVerbosity(), $this->isDecorated(), $this->getFormatter()); + } + /** + * @return void + */ + public function setDecorated(bool $decorated) + { + parent::setDecorated($decorated); + $this->stderr->setDecorated($decorated); + } + /** + * @return void + */ + public function setFormatter(OutputFormatterInterface $formatter) + { + parent::setFormatter($formatter); + $this->stderr->setFormatter($formatter); + } + /** + * @return void + */ + public function setVerbosity(int $level) + { + parent::setVerbosity($level); + $this->stderr->setVerbosity($level); + } + public function getErrorOutput() : OutputInterface + { + return $this->stderr; + } + /** + * @return void + */ + public function setErrorOutput(OutputInterface $error) + { + $this->stderr = $error; + } + /** + * Returns true if current environment supports writing console output to + * STDOUT. + */ + protected function hasStdoutSupport() : bool + { + return \false === $this->isRunningOS400(); + } + /** + * Returns true if current environment supports writing console output to + * STDERR. + */ + protected function hasStderrSupport() : bool + { + return \false === $this->isRunningOS400(); + } + /** + * Checks if current executing environment is IBM iSeries (OS400), which + * doesn't properly convert character-encodings between ASCII to EBCDIC. + */ + private function isRunningOS400() : bool + { + $checks = [\function_exists('php_uname') ? \php_uname('s') : '', \getenv('OSTYPE'), \PHP_OS]; + return \false !== \stripos(\implode(';', $checks), 'OS400'); + } + /** + * @return resource + */ + private function openOutputStream() + { + if (!$this->hasStdoutSupport()) { + return \fopen('php://output', 'w'); + } + // Use STDOUT when possible to prevent from opening too many file descriptors + return \defined('STDOUT') ? \STDOUT : (@\fopen('php://stdout', 'w') ?: \fopen('php://output', 'w')); + } + /** + * @return resource + */ + private function openErrorStream() + { + if (!$this->hasStderrSupport()) { + return \fopen('php://output', 'w'); + } + // Use STDERR when possible to prevent from opening too many file descriptors + return \defined('STDERR') ? \STDERR : (@\fopen('php://stderr', 'w') ?: \fopen('php://output', 'w')); + } +} diff --git a/vendor/symfony/console/Output/ConsoleOutputInterface.php b/vendor/symfony/console/Output/ConsoleOutputInterface.php new file mode 100644 index 0000000000..0e5e309a02 --- /dev/null +++ b/vendor/symfony/console/Output/ConsoleOutputInterface.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Output; + +/** + * ConsoleOutputInterface is the interface implemented by ConsoleOutput class. + * This adds information about stderr and section output stream. + * + * @author Dariusz Górecki + */ +interface ConsoleOutputInterface extends OutputInterface +{ + /** + * Gets the OutputInterface for errors. + */ + public function getErrorOutput() : OutputInterface; + /** + * @return void + */ + public function setErrorOutput(OutputInterface $error); + public function section() : ConsoleSectionOutput; +} diff --git a/vendor/symfony/console/Output/ConsoleSectionOutput.php b/vendor/symfony/console/Output/ConsoleSectionOutput.php new file mode 100644 index 0000000000..3715bb1343 --- /dev/null +++ b/vendor/symfony/console/Output/ConsoleSectionOutput.php @@ -0,0 +1,222 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Output; + +use SwissKnife202405\Symfony\Component\Console\Formatter\OutputFormatterInterface; +use SwissKnife202405\Symfony\Component\Console\Helper\Helper; +use SwissKnife202405\Symfony\Component\Console\Terminal; +/** + * @author Pierre du Plessis + * @author Gabriel Ostrolucký + */ +class ConsoleSectionOutput extends StreamOutput +{ + /** + * @var mixed[] + */ + private $content = []; + /** + * @var int + */ + private $lines = 0; + /** + * @var mixed[] + */ + private $sections; + /** + * @var \Symfony\Component\Console\Terminal + */ + private $terminal; + /** + * @var int + */ + private $maxHeight = 0; + /** + * @param resource $stream + * @param ConsoleSectionOutput[] $sections + */ + public function __construct($stream, array &$sections, int $verbosity, bool $decorated, OutputFormatterInterface $formatter) + { + parent::__construct($stream, $verbosity, $decorated, $formatter); + \array_unshift($sections, $this); + $this->sections =& $sections; + $this->terminal = new Terminal(); + } + /** + * Defines a maximum number of lines for this section. + * + * When more lines are added, the section will automatically scroll to the + * end (i.e. remove the first lines to comply with the max height). + */ + public function setMaxHeight(int $maxHeight) : void + { + // when changing max height, clear output of current section and redraw again with the new height + $previousMaxHeight = $this->maxHeight; + $this->maxHeight = $maxHeight; + $existingContent = $this->popStreamContentUntilCurrentSection($previousMaxHeight ? \min($previousMaxHeight, $this->lines) : $this->lines); + parent::doWrite($this->getVisibleContent(), \false); + parent::doWrite($existingContent, \false); + } + /** + * Clears previous output for this section. + * + * @param int $lines Number of lines to clear. If null, then the entire output of this section is cleared + * + * @return void + */ + public function clear(?int $lines = null) + { + if (empty($this->content) || !$this->isDecorated()) { + return; + } + if ($lines) { + \array_splice($this->content, -$lines); + } else { + $lines = $this->lines; + $this->content = []; + } + $this->lines -= $lines; + parent::doWrite($this->popStreamContentUntilCurrentSection($this->maxHeight ? \min($this->maxHeight, $lines) : $lines), \false); + } + /** + * Overwrites the previous output with a new message. + * + * @return void + * @param string|iterable $message + */ + public function overwrite($message) + { + $this->clear(); + $this->writeln($message); + } + public function getContent() : string + { + return \implode('', $this->content); + } + public function getVisibleContent() : string + { + if (0 === $this->maxHeight) { + return $this->getContent(); + } + return \implode('', \array_slice($this->content, -$this->maxHeight)); + } + /** + * @internal + */ + public function addContent(string $input, bool $newline = \true) : int + { + $width = $this->terminal->getWidth(); + $lines = \explode(\PHP_EOL, $input); + $linesAdded = 0; + $count = \count($lines) - 1; + foreach ($lines as $i => $lineContent) { + // re-add the line break (that has been removed in the above `explode()` for + // - every line that is not the last line + // - if $newline is required, also add it to the last line + if ($i < $count || $newline) { + $lineContent .= \PHP_EOL; + } + // skip line if there is no text (or newline for that matter) + if ('' === $lineContent) { + continue; + } + // For the first line, check if the previous line (last entry of `$this->content`) + // needs to be continued (i.e. does not end with a line break). + if (0 === $i && \false !== ($lastLine = \end($this->content)) && \substr_compare($lastLine, \PHP_EOL, -\strlen(\PHP_EOL)) !== 0) { + // deduct the line count of the previous line + $this->lines -= (int) \ceil($this->getDisplayLength($lastLine) / $width) ?: 1; + // concatenate previous and new line + $lineContent = $lastLine . $lineContent; + // replace last entry of `$this->content` with the new expanded line + \array_splice($this->content, -1, 1, $lineContent); + } else { + // otherwise just add the new content + $this->content[] = $lineContent; + } + $linesAdded += (int) \ceil($this->getDisplayLength($lineContent) / $width) ?: 1; + } + $this->lines += $linesAdded; + return $linesAdded; + } + /** + * @internal + */ + public function addNewLineOfInputSubmit() : void + { + $this->content[] = \PHP_EOL; + ++$this->lines; + } + /** + * @return void + */ + protected function doWrite(string $message, bool $newline) + { + // Simulate newline behavior for consistent output formatting, avoiding extra logic + if (!$newline && \substr_compare($message, \PHP_EOL, -\strlen(\PHP_EOL)) === 0) { + $message = \substr($message, 0, -\strlen(\PHP_EOL)); + $newline = \true; + } + if (!$this->isDecorated()) { + parent::doWrite($message, $newline); + return; + } + // Check if the previous line (last entry of `$this->content`) needs to be continued + // (i.e. does not end with a line break). In which case, it needs to be erased first. + $linesToClear = $deleteLastLine = ($lastLine = \end($this->content) ?: '') && \substr_compare($lastLine, \PHP_EOL, -\strlen(\PHP_EOL)) !== 0 ? 1 : 0; + $linesAdded = $this->addContent($message, $newline); + if ($lineOverflow = $this->maxHeight > 0 && $this->lines > $this->maxHeight) { + // on overflow, clear the whole section and redraw again (to remove the first lines) + $linesToClear = $this->maxHeight; + } + $erasedContent = $this->popStreamContentUntilCurrentSection($linesToClear); + if ($lineOverflow) { + // redraw existing lines of the section + $previousLinesOfSection = \array_slice($this->content, $this->lines - $this->maxHeight, $this->maxHeight - $linesAdded); + parent::doWrite(\implode('', $previousLinesOfSection), \false); + } + // if the last line was removed, re-print its content together with the new content. + // otherwise, just print the new content. + parent::doWrite($deleteLastLine ? $lastLine . $message : $message, \true); + parent::doWrite($erasedContent, \false); + } + /** + * At initial stage, cursor is at the end of stream output. This method makes cursor crawl upwards until it hits + * current section. Then it erases content it crawled through. Optionally, it erases part of current section too. + */ + private function popStreamContentUntilCurrentSection(int $numberOfLinesToClearFromCurrentSection = 0) : string + { + $numberOfLinesToClear = $numberOfLinesToClearFromCurrentSection; + $erasedContent = []; + foreach ($this->sections as $section) { + if ($section === $this) { + break; + } + $numberOfLinesToClear += $section->maxHeight ? \min($section->lines, $section->maxHeight) : $section->lines; + if ('' !== ($sectionContent = $section->getVisibleContent())) { + if (\substr_compare($sectionContent, \PHP_EOL, -\strlen(\PHP_EOL)) !== 0) { + $sectionContent .= \PHP_EOL; + } + $erasedContent[] = $sectionContent; + } + } + if ($numberOfLinesToClear > 0) { + // move cursor up n lines + parent::doWrite(\sprintf("\x1b[%dA", $numberOfLinesToClear), \false); + // erase to end of screen + parent::doWrite("\x1b[0J", \false); + } + return \implode('', \array_reverse($erasedContent)); + } + private function getDisplayLength(string $text) : int + { + return Helper::width(Helper::removeDecoration($this->getFormatter(), \str_replace("\t", ' ', $text))); + } +} diff --git a/vendor/symfony/console/Output/NullOutput.php b/vendor/symfony/console/Output/NullOutput.php new file mode 100644 index 0000000000..5487ceab34 --- /dev/null +++ b/vendor/symfony/console/Output/NullOutput.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Output; + +use SwissKnife202405\Symfony\Component\Console\Formatter\NullOutputFormatter; +use SwissKnife202405\Symfony\Component\Console\Formatter\OutputFormatterInterface; +/** + * NullOutput suppresses all output. + * + * $output = new NullOutput(); + * + * @author Fabien Potencier + * @author Tobias Schultze + */ +class NullOutput implements OutputInterface +{ + /** + * @var \Symfony\Component\Console\Formatter\NullOutputFormatter + */ + private $formatter; + /** + * @return void + */ + public function setFormatter(OutputFormatterInterface $formatter) + { + // do nothing + } + public function getFormatter() : OutputFormatterInterface + { + // to comply with the interface we must return a OutputFormatterInterface + return $this->formatter = $this->formatter ?? new NullOutputFormatter(); + } + /** + * @return void + */ + public function setDecorated(bool $decorated) + { + // do nothing + } + public function isDecorated() : bool + { + return \false; + } + /** + * @return void + */ + public function setVerbosity(int $level) + { + // do nothing + } + public function getVerbosity() : int + { + return self::VERBOSITY_QUIET; + } + public function isQuiet() : bool + { + return \true; + } + public function isVerbose() : bool + { + return \false; + } + public function isVeryVerbose() : bool + { + return \false; + } + public function isDebug() : bool + { + return \false; + } + /** + * @return void + * @param string|iterable $messages + */ + public function writeln($messages, int $options = self::OUTPUT_NORMAL) + { + // do nothing + } + /** + * @return void + * @param string|iterable $messages + */ + public function write($messages, bool $newline = \false, int $options = self::OUTPUT_NORMAL) + { + // do nothing + } +} diff --git a/vendor/symfony/console/Output/Output.php b/vendor/symfony/console/Output/Output.php new file mode 100644 index 0000000000..f88d5c0961 --- /dev/null +++ b/vendor/symfony/console/Output/Output.php @@ -0,0 +1,142 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Output; + +use SwissKnife202405\Symfony\Component\Console\Formatter\OutputFormatter; +use SwissKnife202405\Symfony\Component\Console\Formatter\OutputFormatterInterface; +/** + * Base class for output classes. + * + * There are five levels of verbosity: + * + * * normal: no option passed (normal output) + * * verbose: -v (more output) + * * very verbose: -vv (highly extended output) + * * debug: -vvv (all debug output) + * * quiet: -q (no output) + * + * @author Fabien Potencier + */ +abstract class Output implements OutputInterface +{ + /** + * @var int + */ + private $verbosity; + /** + * @var \Symfony\Component\Console\Formatter\OutputFormatterInterface + */ + private $formatter; + /** + * @param int|null $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface) + * @param bool $decorated Whether to decorate messages + * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter) + */ + public function __construct(?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = \false, ?OutputFormatterInterface $formatter = null) + { + $this->verbosity = $verbosity ?? self::VERBOSITY_NORMAL; + $this->formatter = $formatter ?? new OutputFormatter(); + $this->formatter->setDecorated($decorated); + } + /** + * @return void + */ + public function setFormatter(OutputFormatterInterface $formatter) + { + $this->formatter = $formatter; + } + public function getFormatter() : OutputFormatterInterface + { + return $this->formatter; + } + /** + * @return void + */ + public function setDecorated(bool $decorated) + { + $this->formatter->setDecorated($decorated); + } + public function isDecorated() : bool + { + return $this->formatter->isDecorated(); + } + /** + * @return void + */ + public function setVerbosity(int $level) + { + $this->verbosity = $level; + } + public function getVerbosity() : int + { + return $this->verbosity; + } + public function isQuiet() : bool + { + return self::VERBOSITY_QUIET === $this->verbosity; + } + public function isVerbose() : bool + { + return self::VERBOSITY_VERBOSE <= $this->verbosity; + } + public function isVeryVerbose() : bool + { + return self::VERBOSITY_VERY_VERBOSE <= $this->verbosity; + } + public function isDebug() : bool + { + return self::VERBOSITY_DEBUG <= $this->verbosity; + } + /** + * @return void + * @param string|iterable $messages + */ + public function writeln($messages, int $options = self::OUTPUT_NORMAL) + { + $this->write($messages, \true, $options); + } + /** + * @return void + * @param string|iterable $messages + */ + public function write($messages, bool $newline = \false, int $options = self::OUTPUT_NORMAL) + { + if (!\is_iterable($messages)) { + $messages = [$messages]; + } + $types = self::OUTPUT_NORMAL | self::OUTPUT_RAW | self::OUTPUT_PLAIN; + $type = $types & $options ?: self::OUTPUT_NORMAL; + $verbosities = self::VERBOSITY_QUIET | self::VERBOSITY_NORMAL | self::VERBOSITY_VERBOSE | self::VERBOSITY_VERY_VERBOSE | self::VERBOSITY_DEBUG; + $verbosity = $verbosities & $options ?: self::VERBOSITY_NORMAL; + if ($verbosity > $this->getVerbosity()) { + return; + } + foreach ($messages as $message) { + switch ($type) { + case OutputInterface::OUTPUT_NORMAL: + $message = $this->formatter->format($message); + break; + case OutputInterface::OUTPUT_RAW: + break; + case OutputInterface::OUTPUT_PLAIN: + $message = \strip_tags($this->formatter->format($message)); + break; + } + $this->doWrite($message ?? '', $newline); + } + } + /** + * Writes a message to the output. + * + * @return void + */ + protected abstract function doWrite(string $message, bool $newline); +} diff --git a/vendor/symfony/console/Output/OutputInterface.php b/vendor/symfony/console/Output/OutputInterface.php new file mode 100644 index 0000000000..d53c131c0e --- /dev/null +++ b/vendor/symfony/console/Output/OutputInterface.php @@ -0,0 +1,98 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Output; + +use SwissKnife202405\Symfony\Component\Console\Formatter\OutputFormatterInterface; +/** + * OutputInterface is the interface implemented by all Output classes. + * + * @author Fabien Potencier + */ +interface OutputInterface +{ + public const VERBOSITY_QUIET = 16; + public const VERBOSITY_NORMAL = 32; + public const VERBOSITY_VERBOSE = 64; + public const VERBOSITY_VERY_VERBOSE = 128; + public const VERBOSITY_DEBUG = 256; + public const OUTPUT_NORMAL = 1; + public const OUTPUT_RAW = 2; + public const OUTPUT_PLAIN = 4; + /** + * Writes a message to the output. + * + * @param bool $newline Whether to add a newline + * @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), + * 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL + * + * @return void + * @param string|iterable $messages + */ + public function write($messages, bool $newline = \false, int $options = 0); + /** + * Writes a message to the output and adds a newline at the end. + * + * @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), + * 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL + * + * @return void + * @param string|iterable $messages + */ + public function writeln($messages, int $options = 0); + /** + * Sets the verbosity of the output. + * + * @param self::VERBOSITY_* $level + * + * @return void + */ + public function setVerbosity(int $level); + /** + * Gets the current verbosity of the output. + * + * @return self::VERBOSITY_* + */ + public function getVerbosity() : int; + /** + * Returns whether verbosity is quiet (-q). + */ + public function isQuiet() : bool; + /** + * Returns whether verbosity is verbose (-v). + */ + public function isVerbose() : bool; + /** + * Returns whether verbosity is very verbose (-vv). + */ + public function isVeryVerbose() : bool; + /** + * Returns whether verbosity is debug (-vvv). + */ + public function isDebug() : bool; + /** + * Sets the decorated flag. + * + * @return void + */ + public function setDecorated(bool $decorated); + /** + * Gets the decorated flag. + */ + public function isDecorated() : bool; + /** + * @return void + */ + public function setFormatter(OutputFormatterInterface $formatter); + /** + * Returns current output formatter instance. + */ + public function getFormatter() : OutputFormatterInterface; +} diff --git a/vendor/symfony/console/Output/StreamOutput.php b/vendor/symfony/console/Output/StreamOutput.php new file mode 100644 index 0000000000..01410ccd46 --- /dev/null +++ b/vendor/symfony/console/Output/StreamOutput.php @@ -0,0 +1,105 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Output; + +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +use SwissKnife202405\Symfony\Component\Console\Formatter\OutputFormatterInterface; +/** + * StreamOutput writes the output to a given stream. + * + * Usage: + * + * $output = new StreamOutput(fopen('php://stdout', 'w')); + * + * As `StreamOutput` can use any stream, you can also use a file: + * + * $output = new StreamOutput(fopen('/path/to/output.log', 'a', false)); + * + * @author Fabien Potencier + */ +class StreamOutput extends Output +{ + /** @var resource */ + private $stream; + /** + * @param resource $stream A stream resource + * @param int $verbosity The verbosity level (one of the VERBOSITY constants in OutputInterface) + * @param bool|null $decorated Whether to decorate messages (null for auto-guessing) + * @param OutputFormatterInterface|null $formatter Output formatter instance (null to use default OutputFormatter) + * + * @throws InvalidArgumentException When first argument is not a real stream + */ + public function __construct($stream, int $verbosity = self::VERBOSITY_NORMAL, ?bool $decorated = null, ?OutputFormatterInterface $formatter = null) + { + if (!\is_resource($stream) || 'stream' !== \get_resource_type($stream)) { + throw new InvalidArgumentException('The StreamOutput class needs a stream as its first argument.'); + } + $this->stream = $stream; + $decorated = $decorated ?? $this->hasColorSupport(); + parent::__construct($verbosity, $decorated, $formatter); + } + /** + * Gets the stream attached to this StreamOutput instance. + * + * @return resource + */ + public function getStream() + { + return $this->stream; + } + /** + * @return void + */ + protected function doWrite(string $message, bool $newline) + { + if ($newline) { + $message .= \PHP_EOL; + } + @\fwrite($this->stream, $message); + \fflush($this->stream); + } + /** + * Returns true if the stream supports colorization. + * + * Colorization is disabled if not supported by the stream: + * + * This is tricky on Windows, because Cygwin, Msys2 etc emulate pseudo + * terminals via named pipes, so we can only check the environment. + * + * Reference: Composer\XdebugHandler\Process::supportsColor + * https://github.com/composer/xdebug-handler + * + * @return bool true if the stream supports colorization, false otherwise + */ + protected function hasColorSupport() : bool + { + // Follow https://no-color.org/ + if (isset($_SERVER['NO_COLOR']) || \false !== \getenv('NO_COLOR')) { + return \false; + } + // Detect msysgit/mingw and assume this is a tty because detection + // does not work correctly, see https://github.com/composer/composer/issues/9690 + if (!@\stream_isatty($this->stream) && !\in_array(\strtoupper((string) \getenv('MSYSTEM')), ['MINGW32', 'MINGW64'], \true)) { + return \false; + } + if ('\\' === \DIRECTORY_SEPARATOR && @\sapi_windows_vt100_support($this->stream)) { + return \true; + } + if ('Hyper' === \getenv('TERM_PROGRAM') || \false !== \getenv('COLORTERM') || \false !== \getenv('ANSICON') || 'ON' === \getenv('ConEmuANSI')) { + return \true; + } + if ('dumb' === ($term = (string) \getenv('TERM'))) { + return \false; + } + // See https://github.com/chalk/supports-color/blob/d4f413efaf8da045c5ab440ed418ef02dbb28bf1/index.js#L157 + return \preg_match('/^((screen|xterm|vt100|vt220|putty|rxvt|ansi|cygwin|linux).*)|(.*-256(color)?(-bce)?)$/', $term); + } +} diff --git a/vendor/symfony/console/Output/TrimmedBufferOutput.php b/vendor/symfony/console/Output/TrimmedBufferOutput.php new file mode 100644 index 0000000000..ca7ff6aff2 --- /dev/null +++ b/vendor/symfony/console/Output/TrimmedBufferOutput.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Output; + +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +use SwissKnife202405\Symfony\Component\Console\Formatter\OutputFormatterInterface; +/** + * A BufferedOutput that keeps only the last N chars. + * + * @author Jérémy Derussé + */ +class TrimmedBufferOutput extends Output +{ + /** + * @var int + */ + private $maxLength; + /** + * @var string + */ + private $buffer = ''; + public function __construct(int $maxLength, ?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = \false, ?OutputFormatterInterface $formatter = null) + { + if ($maxLength <= 0) { + throw new InvalidArgumentException(\sprintf('"%s()" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength)); + } + parent::__construct($verbosity, $decorated, $formatter); + $this->maxLength = $maxLength; + } + /** + * Empties buffer and returns its content. + */ + public function fetch() : string + { + $content = $this->buffer; + $this->buffer = ''; + return $content; + } + /** + * @return void + */ + protected function doWrite(string $message, bool $newline) + { + $this->buffer .= $message; + if ($newline) { + $this->buffer .= \PHP_EOL; + } + $this->buffer = \substr($this->buffer, 0 - $this->maxLength); + } +} diff --git a/vendor/symfony/console/Question/ChoiceQuestion.php b/vendor/symfony/console/Question/ChoiceQuestion.php new file mode 100644 index 0000000000..80e458ba4d --- /dev/null +++ b/vendor/symfony/console/Question/ChoiceQuestion.php @@ -0,0 +1,163 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Question; + +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +/** + * Represents a choice question. + * + * @author Fabien Potencier + */ +class ChoiceQuestion extends Question +{ + /** + * @var mixed[] + */ + private $choices; + /** + * @var bool + */ + private $multiselect = \false; + /** + * @var string + */ + private $prompt = ' > '; + /** + * @var string + */ + private $errorMessage = 'Value "%s" is invalid'; + /** + * @param string $question The question to ask to the user + * @param array $choices The list of available choices + * @param mixed $default The default answer to return + */ + public function __construct(string $question, array $choices, $default = null) + { + if (!$choices) { + throw new \LogicException('Choice question must have at least 1 choice available.'); + } + parent::__construct($question, $default); + $this->choices = $choices; + $this->setValidator($this->getDefaultValidator()); + $this->setAutocompleterValues($choices); + } + /** + * Returns available choices. + */ + public function getChoices() : array + { + return $this->choices; + } + /** + * Sets multiselect option. + * + * When multiselect is set to true, multiple choices can be answered. + * + * @return $this + */ + public function setMultiselect(bool $multiselect) + { + $this->multiselect = $multiselect; + $this->setValidator($this->getDefaultValidator()); + return $this; + } + /** + * Returns whether the choices are multiselect. + */ + public function isMultiselect() : bool + { + return $this->multiselect; + } + /** + * Gets the prompt for choices. + */ + public function getPrompt() : string + { + return $this->prompt; + } + /** + * Sets the prompt for choices. + * + * @return $this + */ + public function setPrompt(string $prompt) + { + $this->prompt = $prompt; + return $this; + } + /** + * Sets the error message for invalid values. + * + * The error message has a string placeholder (%s) for the invalid value. + * + * @return $this + */ + public function setErrorMessage(string $errorMessage) + { + $this->errorMessage = $errorMessage; + $this->setValidator($this->getDefaultValidator()); + return $this; + } + private function getDefaultValidator() : callable + { + $choices = $this->choices; + $errorMessage = $this->errorMessage; + $multiselect = $this->multiselect; + $isAssoc = $this->isAssoc($choices); + return function ($selected) use($choices, $errorMessage, $multiselect, $isAssoc) { + if ($multiselect) { + // Check for a separated comma values + if (!\preg_match('/^[^,]+(?:,[^,]+)*$/', (string) $selected, $matches)) { + throw new InvalidArgumentException(\sprintf($errorMessage, $selected)); + } + $selectedChoices = \explode(',', (string) $selected); + } else { + $selectedChoices = [$selected]; + } + if ($this->isTrimmable()) { + foreach ($selectedChoices as $k => $v) { + $selectedChoices[$k] = \trim((string) $v); + } + } + $multiselectChoices = []; + foreach ($selectedChoices as $value) { + $results = []; + foreach ($choices as $key => $choice) { + if ($choice === $value) { + $results[] = $key; + } + } + if (\count($results) > 1) { + throw new InvalidArgumentException(\sprintf('The provided answer is ambiguous. Value should be one of "%s".', \implode('" or "', $results))); + } + $result = \array_search($value, $choices); + if (!$isAssoc) { + if (\false !== $result) { + $result = $choices[$result]; + } elseif (isset($choices[$value])) { + $result = $choices[$value]; + } + } elseif (\false === $result && isset($choices[$value])) { + $result = $value; + } + if (\false === $result) { + throw new InvalidArgumentException(\sprintf($errorMessage, $value)); + } + // For associative choices, consistently return the key as string: + $multiselectChoices[] = $isAssoc ? (string) $result : $result; + } + if ($multiselect) { + return $multiselectChoices; + } + return \current($multiselectChoices); + }; + } +} diff --git a/vendor/symfony/console/Question/ConfirmationQuestion.php b/vendor/symfony/console/Question/ConfirmationQuestion.php new file mode 100644 index 0000000000..d524b057c4 --- /dev/null +++ b/vendor/symfony/console/Question/ConfirmationQuestion.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Question; + +/** + * Represents a yes/no question. + * + * @author Fabien Potencier + */ +class ConfirmationQuestion extends Question +{ + /** + * @var string + */ + private $trueAnswerRegex; + /** + * @param string $question The question to ask to the user + * @param bool $default The default answer to return, true or false + * @param string $trueAnswerRegex A regex to match the "yes" answer + */ + public function __construct(string $question, bool $default = \true, string $trueAnswerRegex = '/^y/i') + { + parent::__construct($question, $default); + $this->trueAnswerRegex = $trueAnswerRegex; + $this->setNormalizer($this->getDefaultNormalizer()); + } + /** + * Returns the default answer normalizer. + */ + private function getDefaultNormalizer() : callable + { + $default = $this->getDefault(); + $regex = $this->trueAnswerRegex; + return function ($answer) use($default, $regex) { + if (\is_bool($answer)) { + return $answer; + } + $answerIsTrue = (bool) \preg_match($regex, $answer); + if (\false === $default) { + return $answer && $answerIsTrue; + } + return '' === $answer || $answerIsTrue; + }; + } +} diff --git a/vendor/symfony/console/Question/Question.php b/vendor/symfony/console/Question/Question.php new file mode 100644 index 0000000000..a53899b459 --- /dev/null +++ b/vendor/symfony/console/Question/Question.php @@ -0,0 +1,285 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Question; + +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +use SwissKnife202405\Symfony\Component\Console\Exception\LogicException; +/** + * Represents a Question. + * + * @author Fabien Potencier + */ +class Question +{ + /** + * @var string + */ + private $question; + /** + * @var int|null + */ + private $attempts; + /** + * @var bool + */ + private $hidden = \false; + /** + * @var bool + */ + private $hiddenFallback = \true; + /** + * @var \Closure|null + */ + private $autocompleterCallback; + /** + * @var \Closure|null + */ + private $validator; + /** + * @var bool|float|int|string|null + */ + private $default; + /** + * @var \Closure|null + */ + private $normalizer; + /** + * @var bool + */ + private $trimmable = \true; + /** + * @var bool + */ + private $multiline = \false; + /** + * @param string $question The question to ask to the user + * @param string|bool|int|float|null $default The default answer to return if the user enters nothing + */ + public function __construct(string $question, $default = null) + { + $this->question = $question; + $this->default = $default; + } + /** + * Returns the question. + */ + public function getQuestion() : string + { + return $this->question; + } + /** + * Returns the default answer. + * @return bool|float|int|string|null + */ + public function getDefault() + { + return $this->default; + } + /** + * Returns whether the user response accepts newline characters. + */ + public function isMultiline() : bool + { + return $this->multiline; + } + /** + * Sets whether the user response should accept newline characters. + * + * @return $this + */ + public function setMultiline(bool $multiline) + { + $this->multiline = $multiline; + return $this; + } + /** + * Returns whether the user response must be hidden. + */ + public function isHidden() : bool + { + return $this->hidden; + } + /** + * Sets whether the user response must be hidden or not. + * + * @return $this + * + * @throws LogicException In case the autocompleter is also used + */ + public function setHidden(bool $hidden) + { + if ($this->autocompleterCallback) { + throw new LogicException('A hidden question cannot use the autocompleter.'); + } + $this->hidden = $hidden; + return $this; + } + /** + * In case the response cannot be hidden, whether to fallback on non-hidden question or not. + */ + public function isHiddenFallback() : bool + { + return $this->hiddenFallback; + } + /** + * Sets whether to fallback on non-hidden question if the response cannot be hidden. + * + * @return $this + */ + public function setHiddenFallback(bool $fallback) + { + $this->hiddenFallback = $fallback; + return $this; + } + /** + * Gets values for the autocompleter. + */ + public function getAutocompleterValues() : ?iterable + { + $callback = $this->getAutocompleterCallback(); + return $callback ? $callback('') : null; + } + /** + * Sets values for the autocompleter. + * + * @return $this + * + * @throws LogicException + */ + public function setAutocompleterValues(?iterable $values) + { + if (\is_array($values)) { + $values = $this->isAssoc($values) ? \array_merge(\array_keys($values), \array_values($values)) : \array_values($values); + $callback = static function () use($values) { + return $values; + }; + } elseif ($values instanceof \Traversable) { + $callback = static function () use($values) { + static $valueCache; + return $valueCache = $valueCache ?? \iterator_to_array($values, \false); + }; + } else { + $callback = null; + } + return $this->setAutocompleterCallback($callback); + } + /** + * Gets the callback function used for the autocompleter. + */ + public function getAutocompleterCallback() : ?callable + { + return $this->autocompleterCallback; + } + /** + * Sets the callback function used for the autocompleter. + * + * The callback is passed the user input as argument and should return an iterable of corresponding suggestions. + * + * @return $this + */ + public function setAutocompleterCallback(?callable $callback = null) + { + if (1 > \func_num_args()) { + trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); + } + if ($this->hidden && null !== $callback) { + throw new LogicException('A hidden question cannot use the autocompleter.'); + } + $this->autocompleterCallback = null === $callback ? null : \Closure::fromCallable($callback); + return $this; + } + /** + * Sets a validator for the question. + * + * @return $this + */ + public function setValidator(?callable $validator = null) + { + if (1 > \func_num_args()) { + trigger_deprecation('symfony/console', '6.2', 'Calling "%s()" without any arguments is deprecated, pass null explicitly instead.', __METHOD__); + } + $this->validator = null === $validator ? null : \Closure::fromCallable($validator); + return $this; + } + /** + * Gets the validator for the question. + */ + public function getValidator() : ?callable + { + return $this->validator; + } + /** + * Sets the maximum number of attempts. + * + * Null means an unlimited number of attempts. + * + * @return $this + * + * @throws InvalidArgumentException in case the number of attempts is invalid + */ + public function setMaxAttempts(?int $attempts) + { + if (null !== $attempts && $attempts < 1) { + throw new InvalidArgumentException('Maximum number of attempts must be a positive value.'); + } + $this->attempts = $attempts; + return $this; + } + /** + * Gets the maximum number of attempts. + * + * Null means an unlimited number of attempts. + */ + public function getMaxAttempts() : ?int + { + return $this->attempts; + } + /** + * Sets a normalizer for the response. + * + * The normalizer can be a callable (a string), a closure or a class implementing __invoke. + * + * @return $this + */ + public function setNormalizer(callable $normalizer) + { + $this->normalizer = \Closure::fromCallable($normalizer); + return $this; + } + /** + * Gets the normalizer for the response. + * + * The normalizer can ba a callable (a string), a closure or a class implementing __invoke. + */ + public function getNormalizer() : ?callable + { + return $this->normalizer; + } + /** + * @return bool + */ + protected function isAssoc(array $array) + { + return (bool) \count(\array_filter(\array_keys($array), 'is_string')); + } + public function isTrimmable() : bool + { + return $this->trimmable; + } + /** + * @return $this + */ + public function setTrimmable(bool $trimmable) + { + $this->trimmable = $trimmable; + return $this; + } +} diff --git a/vendor/symfony/console/README.md b/vendor/symfony/console/README.md new file mode 100644 index 0000000000..e9013182a3 --- /dev/null +++ b/vendor/symfony/console/README.md @@ -0,0 +1,36 @@ +Console Component +================= + +The Console component eases the creation of beautiful and testable command line +interfaces. + +Sponsor +------- + +The Console component for Symfony 6.4 is [backed][1] by [Les-Tilleuls.coop][2]. + +Les-Tilleuls.coop is a team of 70+ Symfony experts who can help you design, develop and +fix your projects. They provide a wide range of professional services including development, +consulting, coaching, training and audits. They also are highly skilled in JS, Go and DevOps. +They are a worker cooperative! + +Help Symfony by [sponsoring][3] its development! + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/console.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) + +Credits +------- + +`Resources/bin/hiddeninput.exe` is a third party binary provided within this +component. Find sources and license at https://github.com/Seldaek/hidden-input. + +[1]: https://symfony.com/backers +[2]: https://les-tilleuls.coop +[3]: https://symfony.com/sponsor diff --git a/vendor/symfony/console/Resources/bin/hiddeninput.exe b/vendor/symfony/console/Resources/bin/hiddeninput.exe new file mode 100644 index 0000000000..c8cf65e8d8 Binary files /dev/null and b/vendor/symfony/console/Resources/bin/hiddeninput.exe differ diff --git a/vendor/symfony/console/Resources/completion.bash b/vendor/symfony/console/Resources/completion.bash new file mode 100644 index 0000000000..0d76eacc3b --- /dev/null +++ b/vendor/symfony/console/Resources/completion.bash @@ -0,0 +1,94 @@ +# This file is part of the Symfony package. +# +# (c) Fabien Potencier +# +# For the full copyright and license information, please view +# https://symfony.com/doc/current/contributing/code/license.html + +_sf_{{ COMMAND_NAME }}() { + + # Use the default completion for shell redirect operators. + for w in '>' '>>' '&>' '<'; do + if [[ $w = "${COMP_WORDS[COMP_CWORD-1]}" ]]; then + compopt -o filenames + COMPREPLY=($(compgen -f -- "${COMP_WORDS[COMP_CWORD]}")) + return 0 + fi + done + + # Use newline as only separator to allow space in completion values + IFS=$'\n' + local sf_cmd="${COMP_WORDS[0]}" + + # for an alias, get the real script behind it + sf_cmd_type=$(type -t $sf_cmd) + if [[ $sf_cmd_type == "alias" ]]; then + sf_cmd=$(alias $sf_cmd | sed -E "s/alias $sf_cmd='(.*)'/\1/") + elif [[ $sf_cmd_type == "file" ]]; then + sf_cmd=$(type -p $sf_cmd) + fi + + if [[ $sf_cmd_type != "function" && ! -x $sf_cmd ]]; then + return 1 + fi + + local cur prev words cword + _get_comp_words_by_ref -n := cur prev words cword + + local completecmd=("$sf_cmd" "_complete" "--no-interaction" "-sbash" "-c$cword" "-a{{ VERSION }}") + for w in ${words[@]}; do + w=$(printf -- '%b' "$w") + # remove quotes from typed values + quote="${w:0:1}" + if [ "$quote" == \' ]; then + w="${w%\'}" + w="${w#\'}" + elif [ "$quote" == \" ]; then + w="${w%\"}" + w="${w#\"}" + fi + # empty values are ignored + if [ ! -z "$w" ]; then + completecmd+=("-i$w") + fi + done + + local sfcomplete + if sfcomplete=$(${completecmd[@]} 2>&1); then + local quote suggestions + quote=${cur:0:1} + + # Use single quotes by default if suggestions contains backslash (FQCN) + if [ "$quote" == '' ] && [[ "$sfcomplete" =~ \\ ]]; then + quote=\' + fi + + if [ "$quote" == \' ]; then + # single quotes: no additional escaping (does not accept ' in values) + suggestions=$(for s in $sfcomplete; do printf $'%q%q%q\n' "$quote" "$s" "$quote"; done) + elif [ "$quote" == \" ]; then + # double quotes: double escaping for \ $ ` " + suggestions=$(for s in $sfcomplete; do + s=${s//\\/\\\\} + s=${s//\$/\\\$} + s=${s//\`/\\\`} + s=${s//\"/\\\"} + printf $'%q%q%q\n' "$quote" "$s" "$quote"; + done) + else + # no quotes: double escaping + suggestions=$(for s in $sfcomplete; do printf $'%q\n' $(printf '%q' "$s"); done) + fi + COMPREPLY=($(IFS=$'\n' compgen -W "$suggestions" -- $(printf -- "%q" "$cur"))) + __ltrim_colon_completions "$cur" + else + if [[ "$sfcomplete" != *"Command \"_complete\" is not defined."* ]]; then + >&2 echo + >&2 echo $sfcomplete + fi + + return 1 + fi +} + +complete -F _sf_{{ COMMAND_NAME }} {{ COMMAND_NAME }} diff --git a/vendor/symfony/console/Resources/completion.fish b/vendor/symfony/console/Resources/completion.fish new file mode 100644 index 0000000000..1c34292aee --- /dev/null +++ b/vendor/symfony/console/Resources/completion.fish @@ -0,0 +1,29 @@ +# This file is part of the Symfony package. +# +# (c) Fabien Potencier +# +# For the full copyright and license information, please view +# https://symfony.com/doc/current/contributing/code/license.html + +function _sf_{{ COMMAND_NAME }} + set sf_cmd (commandline -o) + set c (count (commandline -oc)) + + set completecmd "$sf_cmd[1]" "_complete" "--no-interaction" "-sfish" "-a{{ VERSION }}" + + for i in $sf_cmd + if [ $i != "" ] + set completecmd $completecmd "-i$i" + end + end + + set completecmd $completecmd "-c$c" + + set sfcomplete ($completecmd) + + for i in $sfcomplete + echo $i + end +end + +complete -c '{{ COMMAND_NAME }}' -a '(_sf_{{ COMMAND_NAME }})' -f diff --git a/vendor/symfony/console/Resources/completion.zsh b/vendor/symfony/console/Resources/completion.zsh new file mode 100644 index 0000000000..ff76fe5fa9 --- /dev/null +++ b/vendor/symfony/console/Resources/completion.zsh @@ -0,0 +1,82 @@ +#compdef {{ COMMAND_NAME }} + +# This file is part of the Symfony package. +# +# (c) Fabien Potencier +# +# For the full copyright and license information, please view +# https://symfony.com/doc/current/contributing/code/license.html + +# +# zsh completions for {{ COMMAND_NAME }} +# +# References: +# - https://github.com/spf13/cobra/blob/master/zsh_completions.go +# - https://github.com/symfony/symfony/blob/5.4/src/Symfony/Component/Console/Resources/completion.bash +# +_sf_{{ COMMAND_NAME }}() { + local lastParam flagPrefix requestComp out comp + local -a completions + + # The user could have moved the cursor backwards on the command-line. + # We need to trigger completion from the $CURRENT location, so we need + # to truncate the command-line ($words) up to the $CURRENT location. + # (We cannot use $CURSOR as its value does not work when a command is an alias.) + words=("${=words[1,CURRENT]}") lastParam=${words[-1]} + + # For zsh, when completing a flag with an = (e.g., {{ COMMAND_NAME }} -n=) + # completions must be prefixed with the flag + setopt local_options BASH_REMATCH + if [[ "${lastParam}" =~ '-.*=' ]]; then + # We are dealing with a flag with an = + flagPrefix="-P ${BASH_REMATCH}" + fi + + # Prepare the command to obtain completions + requestComp="${words[0]} ${words[1]} _complete --no-interaction -szsh -a{{ VERSION }} -c$((CURRENT-1))" i="" + for w in ${words[@]}; do + w=$(printf -- '%b' "$w") + # remove quotes from typed values + quote="${w:0:1}" + if [ "$quote" = \' ]; then + w="${w%\'}" + w="${w#\'}" + elif [ "$quote" = \" ]; then + w="${w%\"}" + w="${w#\"}" + fi + # empty values are ignored + if [ ! -z "$w" ]; then + i="${i}-i${w} " + fi + done + + # Ensure at least 1 input + if [ "${i}" = "" ]; then + requestComp="${requestComp} -i\" \"" + else + requestComp="${requestComp} ${i}" + fi + + # Use eval to handle any environment variables and such + out=$(eval ${requestComp} 2>/dev/null) + + while IFS='\n' read -r comp; do + if [ -n "$comp" ]; then + # If requested, completions are returned with a description. + # The description is preceded by a TAB character. + # For zsh's _describe, we need to use a : instead of a TAB. + # We first need to escape any : as part of the completion itself. + comp=${comp//:/\\:} + local tab=$(printf '\t') + comp=${comp//$tab/:} + completions+=${comp} + fi + done < <(printf "%s\n" "${out[@]}") + + # Let inbuilt _describe handle completions + eval _describe "completions" completions $flagPrefix + return $? +} + +compdef _sf_{{ COMMAND_NAME }} {{ COMMAND_NAME }} diff --git a/vendor/symfony/console/SignalRegistry/SignalMap.php b/vendor/symfony/console/SignalRegistry/SignalMap.php new file mode 100644 index 0000000000..2ca108bc88 --- /dev/null +++ b/vendor/symfony/console/SignalRegistry/SignalMap.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\SignalRegistry; + +/** + * @author Grégoire Pineau + */ +class SignalMap +{ + /** + * @var mixed[] + */ + private static $map; + public static function getSignalName(int $signal) : ?string + { + if (!\extension_loaded('pcntl')) { + return null; + } + if (!isset(self::$map)) { + $r = new \ReflectionExtension('pcntl'); + $c = $r->getConstants(); + $map = \array_filter($c, function ($k) { + return \strncmp($k, 'SIG', \strlen('SIG')) === 0 && \strncmp($k, 'SIG_', \strlen('SIG_')) !== 0; + }, \ARRAY_FILTER_USE_KEY); + self::$map = \array_flip($map); + } + return self::$map[$signal] ?? null; + } +} diff --git a/vendor/symfony/console/SignalRegistry/SignalRegistry.php b/vendor/symfony/console/SignalRegistry/SignalRegistry.php new file mode 100644 index 0000000000..aaedb76bc7 --- /dev/null +++ b/vendor/symfony/console/SignalRegistry/SignalRegistry.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\SignalRegistry; + +final class SignalRegistry +{ + /** + * @var mixed[] + */ + private $signalHandlers = []; + public function __construct() + { + if (\function_exists('pcntl_async_signals')) { + \pcntl_async_signals(\true); + } + } + public function register(int $signal, callable $signalHandler) : void + { + if (!isset($this->signalHandlers[$signal])) { + $previousCallback = \pcntl_signal_get_handler($signal); + if (\is_callable($previousCallback)) { + $this->signalHandlers[$signal][] = $previousCallback; + } + } + $this->signalHandlers[$signal][] = $signalHandler; + \pcntl_signal($signal, \Closure::fromCallable([$this, 'handle'])); + } + public static function isSupported() : bool + { + return \function_exists('pcntl_signal'); + } + /** + * @internal + */ + public function handle(int $signal) : void + { + $count = \count($this->signalHandlers[$signal]); + foreach ($this->signalHandlers[$signal] as $i => $signalHandler) { + $hasNext = $i !== $count - 1; + $signalHandler($signal, $hasNext); + } + } +} diff --git a/vendor/symfony/console/SingleCommandApplication.php b/vendor/symfony/console/SingleCommandApplication.php new file mode 100644 index 0000000000..a840ec21d6 --- /dev/null +++ b/vendor/symfony/console/SingleCommandApplication.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console; + +use SwissKnife202405\Symfony\Component\Console\Command\Command; +use SwissKnife202405\Symfony\Component\Console\Input\InputInterface; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +/** + * @author Grégoire Pineau + */ +class SingleCommandApplication extends Command +{ + /** + * @var string + */ + private $version = 'UNKNOWN'; + /** + * @var bool + */ + private $autoExit = \true; + /** + * @var bool + */ + private $running = \false; + /** + * @return $this + */ + public function setVersion(string $version) + { + $this->version = $version; + return $this; + } + /** + * @final + * + * @return $this + */ + public function setAutoExit(bool $autoExit) + { + $this->autoExit = $autoExit; + return $this; + } + public function run(?InputInterface $input = null, ?OutputInterface $output = null) : int + { + if ($this->running) { + return parent::run($input, $output); + } + // We use the command name as the application name + $application = new Application($this->getName() ?: 'UNKNOWN', $this->version); + $application->setAutoExit($this->autoExit); + // Fix the usage of the command displayed with "--help" + $this->setName($_SERVER['argv'][0]); + $application->add($this); + $application->setDefaultCommand($this->getName(), \true); + $this->running = \true; + try { + $ret = $application->run($input, $output); + } finally { + $this->running = \false; + } + return $ret ?? 1; + } +} diff --git a/vendor/symfony/console/Style/OutputStyle.php b/vendor/symfony/console/Style/OutputStyle.php new file mode 100644 index 0000000000..c69acf2889 --- /dev/null +++ b/vendor/symfony/console/Style/OutputStyle.php @@ -0,0 +1,118 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Style; + +use SwissKnife202405\Symfony\Component\Console\Formatter\OutputFormatterInterface; +use SwissKnife202405\Symfony\Component\Console\Helper\ProgressBar; +use SwissKnife202405\Symfony\Component\Console\Output\ConsoleOutputInterface; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +/** + * Decorates output to add console style guide helpers. + * + * @author Kevin Bond + */ +abstract class OutputStyle implements OutputInterface, StyleInterface +{ + /** + * @var \Symfony\Component\Console\Output\OutputInterface + */ + private $output; + public function __construct(OutputInterface $output) + { + $this->output = $output; + } + /** + * @return void + */ + public function newLine(int $count = 1) + { + $this->output->write(\str_repeat(\PHP_EOL, $count)); + } + public function createProgressBar(int $max = 0) : ProgressBar + { + return new ProgressBar($this->output, $max); + } + /** + * @return void + * @param string|iterable $messages + */ + public function write($messages, bool $newline = \false, int $type = self::OUTPUT_NORMAL) + { + $this->output->write($messages, $newline, $type); + } + /** + * @return void + * @param string|iterable $messages + */ + public function writeln($messages, int $type = self::OUTPUT_NORMAL) + { + $this->output->writeln($messages, $type); + } + /** + * @return void + */ + public function setVerbosity(int $level) + { + $this->output->setVerbosity($level); + } + public function getVerbosity() : int + { + return $this->output->getVerbosity(); + } + /** + * @return void + */ + public function setDecorated(bool $decorated) + { + $this->output->setDecorated($decorated); + } + public function isDecorated() : bool + { + return $this->output->isDecorated(); + } + /** + * @return void + */ + public function setFormatter(OutputFormatterInterface $formatter) + { + $this->output->setFormatter($formatter); + } + public function getFormatter() : OutputFormatterInterface + { + return $this->output->getFormatter(); + } + public function isQuiet() : bool + { + return $this->output->isQuiet(); + } + public function isVerbose() : bool + { + return $this->output->isVerbose(); + } + public function isVeryVerbose() : bool + { + return $this->output->isVeryVerbose(); + } + public function isDebug() : bool + { + return $this->output->isDebug(); + } + /** + * @return OutputInterface + */ + protected function getErrorOutput() + { + if (!$this->output instanceof ConsoleOutputInterface) { + return $this->output; + } + return $this->output->getErrorOutput(); + } +} diff --git a/vendor/symfony/console/Style/StyleInterface.php b/vendor/symfony/console/Style/StyleInterface.php new file mode 100644 index 0000000000..482c70cb0f --- /dev/null +++ b/vendor/symfony/console/Style/StyleInterface.php @@ -0,0 +1,130 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Style; + +/** + * Output style helpers. + * + * @author Kevin Bond + */ +interface StyleInterface +{ + /** + * Formats a command title. + * + * @return void + */ + public function title(string $message); + /** + * Formats a section title. + * + * @return void + */ + public function section(string $message); + /** + * Formats a list. + * + * @return void + */ + public function listing(array $elements); + /** + * Formats informational text. + * + * @return void + * @param string|mixed[] $message + */ + public function text($message); + /** + * Formats a success result bar. + * + * @return void + * @param string|mixed[] $message + */ + public function success($message); + /** + * Formats an error result bar. + * + * @return void + * @param string|mixed[] $message + */ + public function error($message); + /** + * Formats an warning result bar. + * + * @return void + * @param string|mixed[] $message + */ + public function warning($message); + /** + * Formats a note admonition. + * + * @return void + * @param string|mixed[] $message + */ + public function note($message); + /** + * Formats a caution admonition. + * + * @return void + * @param string|mixed[] $message + */ + public function caution($message); + /** + * Formats a table. + * + * @return void + */ + public function table(array $headers, array $rows); + /** + * Asks a question. + * @return mixed + */ + public function ask(string $question, ?string $default = null, ?callable $validator = null); + /** + * Asks a question with the user input hidden. + * @return mixed + */ + public function askHidden(string $question, ?callable $validator = null); + /** + * Asks for confirmation. + */ + public function confirm(string $question, bool $default = \true) : bool; + /** + * Asks a choice question. + * @param mixed $default + * @return mixed + */ + public function choice(string $question, array $choices, $default = null); + /** + * Add newline(s). + * + * @return void + */ + public function newLine(int $count = 1); + /** + * Starts the progress output. + * + * @return void + */ + public function progressStart(int $max = 0); + /** + * Advances the progress output X steps. + * + * @return void + */ + public function progressAdvance(int $step = 1); + /** + * Finishes the progress output. + * + * @return void + */ + public function progressFinish(); +} diff --git a/vendor/symfony/console/Style/SymfonyStyle.php b/vendor/symfony/console/Style/SymfonyStyle.php new file mode 100644 index 0000000000..8defee237f --- /dev/null +++ b/vendor/symfony/console/Style/SymfonyStyle.php @@ -0,0 +1,470 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Style; + +use SwissKnife202405\Symfony\Component\Console\Exception\InvalidArgumentException; +use SwissKnife202405\Symfony\Component\Console\Exception\RuntimeException; +use SwissKnife202405\Symfony\Component\Console\Formatter\OutputFormatter; +use SwissKnife202405\Symfony\Component\Console\Helper\Helper; +use SwissKnife202405\Symfony\Component\Console\Helper\OutputWrapper; +use SwissKnife202405\Symfony\Component\Console\Helper\ProgressBar; +use SwissKnife202405\Symfony\Component\Console\Helper\SymfonyQuestionHelper; +use SwissKnife202405\Symfony\Component\Console\Helper\Table; +use SwissKnife202405\Symfony\Component\Console\Helper\TableCell; +use SwissKnife202405\Symfony\Component\Console\Helper\TableSeparator; +use SwissKnife202405\Symfony\Component\Console\Input\InputInterface; +use SwissKnife202405\Symfony\Component\Console\Output\ConsoleOutputInterface; +use SwissKnife202405\Symfony\Component\Console\Output\ConsoleSectionOutput; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +use SwissKnife202405\Symfony\Component\Console\Output\TrimmedBufferOutput; +use SwissKnife202405\Symfony\Component\Console\Question\ChoiceQuestion; +use SwissKnife202405\Symfony\Component\Console\Question\ConfirmationQuestion; +use SwissKnife202405\Symfony\Component\Console\Question\Question; +use SwissKnife202405\Symfony\Component\Console\Terminal; +/** + * Output decorator helpers for the Symfony Style Guide. + * + * @author Kevin Bond + */ +class SymfonyStyle extends OutputStyle +{ + public const MAX_LINE_LENGTH = 120; + /** + * @var \Symfony\Component\Console\Input\InputInterface + */ + private $input; + /** + * @var \Symfony\Component\Console\Output\OutputInterface + */ + private $output; + /** + * @var \Symfony\Component\Console\Helper\SymfonyQuestionHelper + */ + private $questionHelper; + /** + * @var \Symfony\Component\Console\Helper\ProgressBar + */ + private $progressBar; + /** + * @var int + */ + private $lineLength; + /** + * @var \Symfony\Component\Console\Output\TrimmedBufferOutput + */ + private $bufferedOutput; + public function __construct(InputInterface $input, OutputInterface $output) + { + $this->input = $input; + $this->bufferedOutput = new TrimmedBufferOutput(\DIRECTORY_SEPARATOR === '\\' ? 4 : 2, $output->getVerbosity(), \false, clone $output->getFormatter()); + // Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not. + $width = (new Terminal())->getWidth() ?: self::MAX_LINE_LENGTH; + $this->lineLength = \min($width - (int) (\DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH); + parent::__construct($this->output = $output); + } + /** + * Formats a message as a block of text. + * + * @return void + * @param string|mixed[] $messages + */ + public function block($messages, ?string $type = null, ?string $style = null, string $prefix = ' ', bool $padding = \false, bool $escape = \true) + { + $messages = \is_array($messages) ? \array_values($messages) : [$messages]; + $this->autoPrependBlock(); + $this->writeln($this->createBlock($messages, $type, $style, $prefix, $padding, $escape)); + $this->newLine(); + } + /** + * @return void + */ + public function title(string $message) + { + $this->autoPrependBlock(); + $this->writeln([\sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), \sprintf('%s', \str_repeat('=', Helper::width(Helper::removeDecoration($this->getFormatter(), $message))))]); + $this->newLine(); + } + /** + * @return void + */ + public function section(string $message) + { + $this->autoPrependBlock(); + $this->writeln([\sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), \sprintf('%s', \str_repeat('-', Helper::width(Helper::removeDecoration($this->getFormatter(), $message))))]); + $this->newLine(); + } + /** + * @return void + */ + public function listing(array $elements) + { + $this->autoPrependText(); + $elements = \array_map(function ($element) { + return \sprintf(' * %s', $element); + }, $elements); + $this->writeln($elements); + $this->newLine(); + } + /** + * @return void + * @param string|mixed[] $message + */ + public function text($message) + { + $this->autoPrependText(); + $messages = \is_array($message) ? \array_values($message) : [$message]; + foreach ($messages as $message) { + $this->writeln(\sprintf(' %s', $message)); + } + } + /** + * Formats a command comment. + * + * @return void + * @param string|mixed[] $message + */ + public function comment($message) + { + $this->block($message, null, null, ' // ', \false, \false); + } + /** + * @return void + * @param string|mixed[] $message + */ + public function success($message) + { + $this->block($message, 'OK', 'fg=black;bg=green', ' ', \true); + } + /** + * @return void + * @param string|mixed[] $message + */ + public function error($message) + { + $this->block($message, 'ERROR', 'fg=white;bg=red', ' ', \true); + } + /** + * @return void + * @param string|mixed[] $message + */ + public function warning($message) + { + $this->block($message, 'WARNING', 'fg=black;bg=yellow', ' ', \true); + } + /** + * @return void + * @param string|mixed[] $message + */ + public function note($message) + { + $this->block($message, 'NOTE', 'fg=yellow', ' ! '); + } + /** + * Formats an info message. + * + * @return void + * @param string|mixed[] $message + */ + public function info($message) + { + $this->block($message, 'INFO', 'fg=green', ' ', \true); + } + /** + * @return void + * @param string|mixed[] $message + */ + public function caution($message) + { + $this->block($message, 'CAUTION', 'fg=white;bg=red', ' ! ', \true); + } + /** + * @return void + */ + public function table(array $headers, array $rows) + { + $this->createTable()->setHeaders($headers)->setRows($rows)->render(); + $this->newLine(); + } + /** + * Formats a horizontal table. + * + * @return void + */ + public function horizontalTable(array $headers, array $rows) + { + $this->createTable()->setHorizontal(\true)->setHeaders($headers)->setRows($rows)->render(); + $this->newLine(); + } + /** + * Formats a list of key/value horizontally. + * + * Each row can be one of: + * * 'A title' + * * ['key' => 'value'] + * * new TableSeparator() + * + * @return void + * @param string|mixed[]|\Symfony\Component\Console\Helper\TableSeparator ...$list + */ + public function definitionList(...$list) + { + $headers = []; + $row = []; + foreach ($list as $value) { + if ($value instanceof TableSeparator) { + $headers[] = $value; + $row[] = $value; + continue; + } + if (\is_string($value)) { + $headers[] = new TableCell($value, ['colspan' => 2]); + $row[] = null; + continue; + } + if (!\is_array($value)) { + throw new InvalidArgumentException('Value should be an array, string, or an instance of TableSeparator.'); + } + $headers[] = \key($value); + $row[] = \current($value); + } + $this->horizontalTable($headers, [$row]); + } + /** + * @return mixed + */ + public function ask(string $question, ?string $default = null, ?callable $validator = null) + { + $question = new Question($question, $default); + $question->setValidator($validator); + return $this->askQuestion($question); + } + /** + * @return mixed + */ + public function askHidden(string $question, ?callable $validator = null) + { + $question = new Question($question); + $question->setHidden(\true); + $question->setValidator($validator); + return $this->askQuestion($question); + } + public function confirm(string $question, bool $default = \true) : bool + { + return $this->askQuestion(new ConfirmationQuestion($question, $default)); + } + /** + * @param mixed $default + * @return mixed + */ + public function choice(string $question, array $choices, $default = null, bool $multiSelect = \false) + { + if (null !== $default) { + $values = \array_flip($choices); + $default = $values[$default] ?? $default; + } + $questionChoice = new ChoiceQuestion($question, $choices, $default); + $questionChoice->setMultiselect($multiSelect); + return $this->askQuestion($questionChoice); + } + /** + * @return void + */ + public function progressStart(int $max = 0) + { + $this->progressBar = $this->createProgressBar($max); + $this->progressBar->start(); + } + /** + * @return void + */ + public function progressAdvance(int $step = 1) + { + $this->getProgressBar()->advance($step); + } + /** + * @return void + */ + public function progressFinish() + { + $this->getProgressBar()->finish(); + $this->newLine(2); + unset($this->progressBar); + } + public function createProgressBar(int $max = 0) : ProgressBar + { + $progressBar = parent::createProgressBar($max); + if ('\\' !== \DIRECTORY_SEPARATOR || 'Hyper' === \getenv('TERM_PROGRAM')) { + $progressBar->setEmptyBarCharacter('░'); + // light shade character \u2591 + $progressBar->setProgressCharacter(''); + $progressBar->setBarCharacter('▓'); + // dark shade character \u2593 + } + return $progressBar; + } + /** + * @see ProgressBar::iterate() + * + * @template TKey + * @template TValue + * + * @param iterable $iterable + * @param int|null $max Number of steps to complete the bar (0 if indeterminate), if null it will be inferred from $iterable + * + * @return iterable + */ + public function progressIterate(iterable $iterable, ?int $max = null) : iterable + { + yield from $this->createProgressBar()->iterate($iterable, $max); + $this->newLine(2); + } + /** + * @return mixed + */ + public function askQuestion(Question $question) + { + if ($this->input->isInteractive()) { + $this->autoPrependBlock(); + } + $this->questionHelper = $this->questionHelper ?? new SymfonyQuestionHelper(); + $answer = $this->questionHelper->ask($this->input, $this, $question); + if ($this->input->isInteractive()) { + if ($this->output instanceof ConsoleSectionOutput) { + // add the new line of the `return` to submit the input to ConsoleSectionOutput, because ConsoleSectionOutput is holding all it's lines. + // this is relevant when a `ConsoleSectionOutput::clear` is called. + $this->output->addNewLineOfInputSubmit(); + } + $this->newLine(); + $this->bufferedOutput->write("\n"); + } + return $answer; + } + /** + * @return void + * @param string|iterable $messages + */ + public function writeln($messages, int $type = self::OUTPUT_NORMAL) + { + if (!\is_iterable($messages)) { + $messages = [$messages]; + } + foreach ($messages as $message) { + parent::writeln($message, $type); + $this->writeBuffer($message, \true, $type); + } + } + /** + * @return void + * @param string|iterable $messages + */ + public function write($messages, bool $newline = \false, int $type = self::OUTPUT_NORMAL) + { + if (!\is_iterable($messages)) { + $messages = [$messages]; + } + foreach ($messages as $message) { + parent::write($message, $newline, $type); + $this->writeBuffer($message, $newline, $type); + } + } + /** + * @return void + */ + public function newLine(int $count = 1) + { + parent::newLine($count); + $this->bufferedOutput->write(\str_repeat("\n", $count)); + } + /** + * Returns a new instance which makes use of stderr if available. + */ + public function getErrorStyle() : self + { + return new self($this->input, $this->getErrorOutput()); + } + public function createTable() : Table + { + $output = $this->output instanceof ConsoleOutputInterface ? $this->output->section() : $this->output; + $style = clone Table::getStyleDefinition('symfony-style-guide'); + $style->setCellHeaderFormat('%s'); + return (new Table($output))->setStyle($style); + } + private function getProgressBar() : ProgressBar + { + if (!isset($this->progressBar)) { + throw new RuntimeException('The ProgressBar is not started.'); + } + return $this->progressBar; + } + private function autoPrependBlock() : void + { + $chars = \substr(\str_replace(\PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2); + if (!isset($chars[0])) { + $this->newLine(); + // empty history, so we should start with a new line. + return; + } + // Prepend new line for each non LF chars (This means no blank line was output before) + $this->newLine(2 - \substr_count($chars, "\n")); + } + private function autoPrependText() : void + { + $fetched = $this->bufferedOutput->fetch(); + // Prepend new line if last char isn't EOL: + if ($fetched && \substr_compare($fetched, "\n", -\strlen("\n")) !== 0) { + $this->newLine(); + } + } + private function writeBuffer(string $message, bool $newLine, int $type) : void + { + // We need to know if the last chars are PHP_EOL + $this->bufferedOutput->write($message, $newLine, $type); + } + private function createBlock(iterable $messages, ?string $type = null, ?string $style = null, string $prefix = ' ', bool $padding = \false, bool $escape = \false) : array + { + $indentLength = 0; + $prefixLength = Helper::width(Helper::removeDecoration($this->getFormatter(), $prefix)); + $lines = []; + if (null !== $type) { + $type = \sprintf('[%s] ', $type); + $indentLength = Helper::width($type); + $lineIndentation = \str_repeat(' ', $indentLength); + } + // wrap and add newlines for each element + $outputWrapper = new OutputWrapper(); + foreach ($messages as $key => $message) { + if ($escape) { + $message = OutputFormatter::escape($message); + } + $lines = \array_merge($lines, \explode(\PHP_EOL, $outputWrapper->wrap($message, $this->lineLength - $prefixLength - $indentLength, \PHP_EOL))); + if (\count($messages) > 1 && $key < \count($messages) - 1) { + $lines[] = ''; + } + } + $firstLineIndex = 0; + if ($padding && $this->isDecorated()) { + $firstLineIndex = 1; + \array_unshift($lines, ''); + $lines[] = ''; + } + foreach ($lines as $i => &$line) { + if (null !== $type) { + $line = $firstLineIndex === $i ? $type . $line : $lineIndentation . $line; + } + $line = $prefix . $line; + $line .= \str_repeat(' ', \max($this->lineLength - Helper::width(Helper::removeDecoration($this->getFormatter(), $line)), 0)); + if ($style) { + $line = \sprintf('<%s>%s', $style, $line); + } + } + return $lines; + } +} diff --git a/vendor/symfony/console/Terminal.php b/vendor/symfony/console/Terminal.php new file mode 100644 index 0000000000..2843300042 --- /dev/null +++ b/vendor/symfony/console/Terminal.php @@ -0,0 +1,208 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console; + +use SwissKnife202405\Symfony\Component\Console\Output\AnsiColorMode; +class Terminal +{ + public const DEFAULT_COLOR_MODE = AnsiColorMode::Ansi4; + /** + * @var \Symfony\Component\Console\Output\AnsiColorMode|null + */ + private static $colorMode; + /** + * @var int|null + */ + private static $width; + /** + * @var int|null + */ + private static $height; + /** + * @var bool|null + */ + private static $stty; + /** + * About Ansi color types: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors + * For more information about true color support with terminals https://github.com/termstandard/colors/. + */ + public static function getColorMode() : AnsiColorMode + { + // Use Cache from previous run (or user forced mode) + if (null !== self::$colorMode) { + return self::$colorMode; + } + // Try with $COLORTERM first + if (\is_string($colorterm = \getenv('COLORTERM'))) { + $colorterm = \strtolower($colorterm); + if (\strpos($colorterm, 'truecolor') !== \false) { + self::setColorMode(AnsiColorMode::Ansi24); + return self::$colorMode; + } + if (\strpos($colorterm, '256color') !== \false) { + self::setColorMode(AnsiColorMode::Ansi8); + return self::$colorMode; + } + } + // Try with $TERM + if (\is_string($term = \getenv('TERM'))) { + $term = \strtolower($term); + if (\strpos($term, 'truecolor') !== \false) { + self::setColorMode(AnsiColorMode::Ansi24); + return self::$colorMode; + } + if (\strpos($term, '256color') !== \false) { + self::setColorMode(AnsiColorMode::Ansi8); + return self::$colorMode; + } + } + self::setColorMode(self::DEFAULT_COLOR_MODE); + return self::$colorMode; + } + /** + * Force a terminal color mode rendering. + */ + public static function setColorMode(?AnsiColorMode $colorMode) : void + { + self::$colorMode = $colorMode; + } + /** + * Gets the terminal width. + */ + public function getWidth() : int + { + $width = \getenv('COLUMNS'); + if (\false !== $width) { + return (int) \trim($width); + } + if (null === self::$width) { + self::initDimensions(); + } + return self::$width ?: 80; + } + /** + * Gets the terminal height. + */ + public function getHeight() : int + { + $height = \getenv('LINES'); + if (\false !== $height) { + return (int) \trim($height); + } + if (null === self::$height) { + self::initDimensions(); + } + return self::$height ?: 50; + } + /** + * @internal + */ + public static function hasSttyAvailable() : bool + { + if (null !== self::$stty) { + return self::$stty; + } + // skip check if shell_exec function is disabled + if (!\function_exists('shell_exec')) { + return \false; + } + return self::$stty = (bool) \shell_exec('stty 2> ' . ('\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null')); + } + private static function initDimensions() : void + { + if ('\\' === \DIRECTORY_SEPARATOR) { + $ansicon = \getenv('ANSICON'); + if (\false !== $ansicon && \preg_match('/^(\\d+)x(\\d+)(?: \\((\\d+)x(\\d+)\\))?$/', \trim($ansicon), $matches)) { + // extract [w, H] from "wxh (WxH)" + // or [w, h] from "wxh" + self::$width = (int) $matches[1]; + self::$height = isset($matches[4]) ? (int) $matches[4] : (int) $matches[2]; + } elseif (!self::hasVt100Support() && self::hasSttyAvailable()) { + // only use stty on Windows if the terminal does not support vt100 (e.g. Windows 7 + git-bash) + // testing for stty in a Windows 10 vt100-enabled console will implicitly disable vt100 support on STDOUT + self::initDimensionsUsingStty(); + } elseif (null !== ($dimensions = self::getConsoleMode())) { + // extract [w, h] from "wxh" + self::$width = (int) $dimensions[0]; + self::$height = (int) $dimensions[1]; + } + } else { + self::initDimensionsUsingStty(); + } + } + /** + * Returns whether STDOUT has vt100 support (some Windows 10+ configurations). + */ + private static function hasVt100Support() : bool + { + return \function_exists('sapi_windows_vt100_support') && \sapi_windows_vt100_support(\fopen('php://stdout', 'w')); + } + /** + * Initializes dimensions using the output of an stty columns line. + */ + private static function initDimensionsUsingStty() : void + { + if ($sttyString = self::getSttyColumns()) { + if (\preg_match('/rows.(\\d+);.columns.(\\d+);/is', $sttyString, $matches)) { + // extract [w, h] from "rows h; columns w;" + self::$width = (int) $matches[2]; + self::$height = (int) $matches[1]; + } elseif (\preg_match('/;.(\\d+).rows;.(\\d+).columns/is', $sttyString, $matches)) { + // extract [w, h] from "; h rows; w columns" + self::$width = (int) $matches[2]; + self::$height = (int) $matches[1]; + } + } + } + /** + * Runs and parses mode CON if it's available, suppressing any error output. + * + * @return int[]|null An array composed of the width and the height or null if it could not be parsed + */ + private static function getConsoleMode() : ?array + { + $info = self::readFromProcess('mode CON'); + if (null === $info || !\preg_match('/--------+\\r?\\n.+?(\\d+)\\r?\\n.+?(\\d+)\\r?\\n/', $info, $matches)) { + return null; + } + return [(int) $matches[2], (int) $matches[1]]; + } + /** + * Runs and parses stty -a if it's available, suppressing any error output. + */ + private static function getSttyColumns() : ?string + { + return self::readFromProcess(['stty', '-a']); + } + /** + * @param string|mixed[] $command + */ + private static function readFromProcess($command) : ?string + { + if (!\function_exists('proc_open')) { + return null; + } + $descriptorspec = [1 => ['pipe', 'w'], 2 => ['pipe', 'w']]; + $cp = \function_exists('sapi_windows_cp_set') ? \sapi_windows_cp_get() : 0; + $process = \proc_open(\is_array($command) ? \implode(' ', \array_map('escapeshellarg', $command)) : $command, $descriptorspec, $pipes, null, null, ['suppress_errors' => \true]); + if (!\is_resource($process)) { + return null; + } + $info = \stream_get_contents($pipes[1]); + \fclose($pipes[1]); + \fclose($pipes[2]); + \proc_close($process); + if ($cp) { + \sapi_windows_cp_set($cp); + } + return $info; + } +} diff --git a/vendor/symfony/console/Tester/ApplicationTester.php b/vendor/symfony/console/Tester/ApplicationTester.php new file mode 100644 index 0000000000..d7017f4bf7 --- /dev/null +++ b/vendor/symfony/console/Tester/ApplicationTester.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Tester; + +use SwissKnife202405\Symfony\Component\Console\Application; +use SwissKnife202405\Symfony\Component\Console\Input\ArrayInput; +/** + * Eases the testing of console applications. + * + * When testing an application, don't forget to disable the auto exit flag: + * + * $application = new Application(); + * $application->setAutoExit(false); + * + * @author Fabien Potencier + */ +class ApplicationTester +{ + use TesterTrait; + /** + * @var \Symfony\Component\Console\Application + */ + private $application; + public function __construct(Application $application) + { + $this->application = $application; + } + /** + * Executes the application. + * + * Available options: + * + * * interactive: Sets the input interactive flag + * * decorated: Sets the output decorated flag + * * verbosity: Sets the output verbosity flag + * * capture_stderr_separately: Make output of stdOut and stdErr separately available + * + * @return int The command exit code + */ + public function run(array $input, array $options = []) : int + { + $prevShellVerbosity = \getenv('SHELL_VERBOSITY'); + try { + $this->input = new ArrayInput($input); + if (isset($options['interactive'])) { + $this->input->setInteractive($options['interactive']); + } + if ($this->inputs) { + $this->input->setStream(self::createStream($this->inputs)); + } + $this->initOutput($options); + return $this->statusCode = $this->application->run($this->input, $this->output); + } finally { + // SHELL_VERBOSITY is set by Application::configureIO so we need to unset/reset it + // to its previous value to avoid one test's verbosity to spread to the following tests + if (\false === $prevShellVerbosity) { + if (\function_exists('putenv')) { + @\putenv('SHELL_VERBOSITY'); + } + unset($_ENV['SHELL_VERBOSITY']); + unset($_SERVER['SHELL_VERBOSITY']); + } else { + if (\function_exists('putenv')) { + @\putenv('SHELL_VERBOSITY=' . $prevShellVerbosity); + } + $_ENV['SHELL_VERBOSITY'] = $prevShellVerbosity; + $_SERVER['SHELL_VERBOSITY'] = $prevShellVerbosity; + } + } + } +} diff --git a/vendor/symfony/console/Tester/CommandCompletionTester.php b/vendor/symfony/console/Tester/CommandCompletionTester.php new file mode 100644 index 0000000000..0c2d760242 --- /dev/null +++ b/vendor/symfony/console/Tester/CommandCompletionTester.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Tester; + +use SwissKnife202405\Symfony\Component\Console\Command\Command; +use SwissKnife202405\Symfony\Component\Console\Completion\CompletionInput; +use SwissKnife202405\Symfony\Component\Console\Completion\CompletionSuggestions; +/** + * Eases the testing of command completion. + * + * @author Jérôme Tamarelle + */ +class CommandCompletionTester +{ + /** + * @var \Symfony\Component\Console\Command\Command + */ + private $command; + public function __construct(Command $command) + { + $this->command = $command; + } + /** + * Create completion suggestions from input tokens. + */ + public function complete(array $input) : array + { + $currentIndex = \count($input); + if ('' === \end($input)) { + \array_pop($input); + } + \array_unshift($input, $this->command->getName()); + $completionInput = CompletionInput::fromTokens($input, $currentIndex); + $completionInput->bind($this->command->getDefinition()); + $suggestions = new CompletionSuggestions(); + $this->command->complete($completionInput, $suggestions); + $options = []; + foreach ($suggestions->getOptionSuggestions() as $option) { + $options[] = '--' . $option->getName(); + } + return \array_map('strval', \array_merge($options, $suggestions->getValueSuggestions())); + } +} diff --git a/vendor/symfony/console/Tester/CommandTester.php b/vendor/symfony/console/Tester/CommandTester.php new file mode 100644 index 0000000000..0d12d6e71d --- /dev/null +++ b/vendor/symfony/console/Tester/CommandTester.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Tester; + +use SwissKnife202405\Symfony\Component\Console\Command\Command; +use SwissKnife202405\Symfony\Component\Console\Input\ArrayInput; +/** + * Eases the testing of console commands. + * + * @author Fabien Potencier + * @author Robin Chalas + */ +class CommandTester +{ + use TesterTrait; + /** + * @var \Symfony\Component\Console\Command\Command + */ + private $command; + public function __construct(Command $command) + { + $this->command = $command; + } + /** + * Executes the command. + * + * Available execution options: + * + * * interactive: Sets the input interactive flag + * * decorated: Sets the output decorated flag + * * verbosity: Sets the output verbosity flag + * * capture_stderr_separately: Make output of stdOut and stdErr separately available + * + * @param array $input An array of command arguments and options + * @param array $options An array of execution options + * + * @return int The command exit code + */ + public function execute(array $input, array $options = []) : int + { + // set the command name automatically if the application requires + // this argument and no command name was passed + if (!isset($input['command']) && null !== ($application = $this->command->getApplication()) && $application->getDefinition()->hasArgument('command')) { + $input = \array_merge(['command' => $this->command->getName()], $input); + } + $this->input = new ArrayInput($input); + // Use an in-memory input stream even if no inputs are set so that QuestionHelper::ask() does not rely on the blocking STDIN. + $this->input->setStream(self::createStream($this->inputs)); + if (isset($options['interactive'])) { + $this->input->setInteractive($options['interactive']); + } + if (!isset($options['decorated'])) { + $options['decorated'] = \false; + } + $this->initOutput($options); + return $this->statusCode = $this->command->run($this->input, $this->output); + } +} diff --git a/vendor/symfony/console/Tester/Constraint/CommandIsSuccessful.php b/vendor/symfony/console/Tester/Constraint/CommandIsSuccessful.php new file mode 100644 index 0000000000..d355c6661f --- /dev/null +++ b/vendor/symfony/console/Tester/Constraint/CommandIsSuccessful.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Tester\Constraint; + +use SwissKnife202405\PHPUnit\Framework\Constraint\Constraint; +use SwissKnife202405\Symfony\Component\Console\Command\Command; +final class CommandIsSuccessful extends Constraint +{ + public function toString() : string + { + return 'is successful'; + } + protected function matches($other) : bool + { + return Command::SUCCESS === $other; + } + protected function failureDescription($other) : string + { + return 'the command ' . $this->toString(); + } + protected function additionalFailureDescription($other) : string + { + $mapping = [Command::FAILURE => 'Command failed.', Command::INVALID => 'Command was invalid.']; + return $mapping[$other] ?? \sprintf('Command returned exit status %d.', $other); + } +} diff --git a/vendor/symfony/console/Tester/TesterTrait.php b/vendor/symfony/console/Tester/TesterTrait.php new file mode 100644 index 0000000000..d921beb27c --- /dev/null +++ b/vendor/symfony/console/Tester/TesterTrait.php @@ -0,0 +1,167 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Console\Tester; + +use SwissKnife202405\PHPUnit\Framework\Assert; +use SwissKnife202405\Symfony\Component\Console\Input\InputInterface; +use SwissKnife202405\Symfony\Component\Console\Output\ConsoleOutput; +use SwissKnife202405\Symfony\Component\Console\Output\OutputInterface; +use SwissKnife202405\Symfony\Component\Console\Output\StreamOutput; +use SwissKnife202405\Symfony\Component\Console\Tester\Constraint\CommandIsSuccessful; +/** + * @author Amrouche Hamza + */ +trait TesterTrait +{ + /** + * @var \Symfony\Component\Console\Output\StreamOutput + */ + private $output; + /** + * @var mixed[] + */ + private $inputs = []; + /** + * @var bool + */ + private $captureStreamsIndependently = \false; + /** + * @var \Symfony\Component\Console\Input\InputInterface + */ + private $input; + /** + * @var int + */ + private $statusCode; + /** + * Gets the display returned by the last execution of the command or application. + * + * @throws \RuntimeException If it's called before the execute method + */ + public function getDisplay(bool $normalize = \false) : string + { + if (!isset($this->output)) { + throw new \RuntimeException('Output not initialized, did you execute the command before requesting the display?'); + } + \rewind($this->output->getStream()); + $display = \stream_get_contents($this->output->getStream()); + if ($normalize) { + $display = \str_replace(\PHP_EOL, "\n", $display); + } + return $display; + } + /** + * Gets the output written to STDERR by the application. + * + * @param bool $normalize Whether to normalize end of lines to \n or not + */ + public function getErrorOutput(bool $normalize = \false) : string + { + if (!$this->captureStreamsIndependently) { + throw new \LogicException('The error output is not available when the tester is run without "capture_stderr_separately" option set.'); + } + \rewind($this->output->getErrorOutput()->getStream()); + $display = \stream_get_contents($this->output->getErrorOutput()->getStream()); + if ($normalize) { + $display = \str_replace(\PHP_EOL, "\n", $display); + } + return $display; + } + /** + * Gets the input instance used by the last execution of the command or application. + */ + public function getInput() : InputInterface + { + return $this->input; + } + /** + * Gets the output instance used by the last execution of the command or application. + */ + public function getOutput() : OutputInterface + { + return $this->output; + } + /** + * Gets the status code returned by the last execution of the command or application. + * + * @throws \RuntimeException If it's called before the execute method + */ + public function getStatusCode() : int + { + if (!isset($this->statusCode)) { + throw new \RuntimeException('Status code not initialized, did you execute the command before requesting the status code?'); + } + return $this->statusCode; + } + public function assertCommandIsSuccessful(string $message = '') : void + { + Assert::assertThat($this->statusCode, new CommandIsSuccessful(), $message); + } + /** + * Sets the user inputs. + * + * @param array $inputs An array of strings representing each input + * passed to the command input stream + * + * @return $this + */ + public function setInputs(array $inputs) + { + $this->inputs = $inputs; + return $this; + } + /** + * Initializes the output property. + * + * Available options: + * + * * decorated: Sets the output decorated flag + * * verbosity: Sets the output verbosity flag + * * capture_stderr_separately: Make output of stdOut and stdErr separately available + */ + private function initOutput(array $options) : void + { + $this->captureStreamsIndependently = $options['capture_stderr_separately'] ?? \false; + if (!$this->captureStreamsIndependently) { + $this->output = new StreamOutput(\fopen('php://memory', 'w', \false)); + if (isset($options['decorated'])) { + $this->output->setDecorated($options['decorated']); + } + if (isset($options['verbosity'])) { + $this->output->setVerbosity($options['verbosity']); + } + } else { + $this->output = new ConsoleOutput($options['verbosity'] ?? ConsoleOutput::VERBOSITY_NORMAL, $options['decorated'] ?? null); + $errorOutput = new StreamOutput(\fopen('php://memory', 'w', \false)); + $errorOutput->setFormatter($this->output->getFormatter()); + $errorOutput->setVerbosity($this->output->getVerbosity()); + $errorOutput->setDecorated($this->output->isDecorated()); + $reflectedOutput = new \ReflectionObject($this->output); + $strErrProperty = $reflectedOutput->getProperty('stderr'); + $strErrProperty->setValue($this->output, $errorOutput); + $reflectedParent = $reflectedOutput->getParentClass(); + $streamProperty = $reflectedParent->getProperty('stream'); + $streamProperty->setValue($this->output, \fopen('php://memory', 'w', \false)); + } + } + /** + * @return resource + */ + private static function createStream(array $inputs) + { + $stream = \fopen('php://memory', 'r+', \false); + foreach ($inputs as $input) { + \fwrite($stream, $input . \PHP_EOL); + } + \rewind($stream); + return $stream; + } +} diff --git a/vendor/symfony/console/composer.json b/vendor/symfony/console/composer.json new file mode 100644 index 0000000000..77fb3980bc --- /dev/null +++ b/vendor/symfony/console/composer.json @@ -0,0 +1,62 @@ +{ + "name": "symfony\/console", + "type": "library", + "description": "Eases the creation of beautiful and testable command line interfaces", + "keywords": [ + "console", + "cli", + "command-line", + "terminal" + ], + "homepage": "https:\/\/symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https:\/\/symfony.com\/contributors" + } + ], + "require": { + "php": ">=8.1", + "symfony\/deprecation-contracts": "^2.5|^3", + "symfony\/polyfill-mbstring": "~1.0", + "symfony\/service-contracts": "^2.5|^3", + "symfony\/string": "^5.4|^6.0|^7.0" + }, + "require-dev": { + "symfony\/config": "^5.4|^6.0|^7.0", + "symfony\/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony\/dependency-injection": "^5.4|^6.0|^7.0", + "symfony\/http-foundation": "^6.4|^7.0", + "symfony\/http-kernel": "^6.4|^7.0", + "symfony\/lock": "^5.4|^6.0|^7.0", + "symfony\/messenger": "^5.4|^6.0|^7.0", + "symfony\/process": "^5.4|^6.0|^7.0", + "symfony\/stopwatch": "^5.4|^6.0|^7.0", + "symfony\/var-dumper": "^5.4|^6.0|^7.0", + "psr\/log": "^1|^2|^3" + }, + "provide": { + "psr\/log-implementation": "1.0|2.0|3.0" + }, + "conflict": { + "symfony\/dependency-injection": "<5.4", + "symfony\/dotenv": "<5.4", + "symfony\/event-dispatcher": "<5.4", + "symfony\/lock": "<5.4", + "symfony\/process": "<5.4" + }, + "autoload": { + "psr-4": { + "SwissKnife202405\\Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "\/Tests\/" + ] + }, + "minimum-stability": "dev" +} \ No newline at end of file diff --git a/vendor/symfony/deprecation-contracts/CHANGELOG.md b/vendor/symfony/deprecation-contracts/CHANGELOG.md new file mode 100644 index 0000000000..7932e26132 --- /dev/null +++ b/vendor/symfony/deprecation-contracts/CHANGELOG.md @@ -0,0 +1,5 @@ +CHANGELOG +========= + +The changelog is maintained for all Symfony contracts at the following URL: +https://github.com/symfony/contracts/blob/main/CHANGELOG.md diff --git a/vendor/symfony/deprecation-contracts/LICENSE b/vendor/symfony/deprecation-contracts/LICENSE new file mode 100644 index 0000000000..0ed3a24655 --- /dev/null +++ b/vendor/symfony/deprecation-contracts/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2020-present Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/deprecation-contracts/README.md b/vendor/symfony/deprecation-contracts/README.md new file mode 100644 index 0000000000..9814864c03 --- /dev/null +++ b/vendor/symfony/deprecation-contracts/README.md @@ -0,0 +1,26 @@ +Symfony Deprecation Contracts +============================= + +A generic function and convention to trigger deprecation notices. + +This package provides a single global function named `trigger_deprecation()` that triggers silenced deprecation notices. + +By using a custom PHP error handler such as the one provided by the Symfony ErrorHandler component, +the triggered deprecations can be caught and logged for later discovery, both on dev and prod environments. + +The function requires at least 3 arguments: + - the name of the Composer package that is triggering the deprecation + - the version of the package that introduced the deprecation + - the message of the deprecation + - more arguments can be provided: they will be inserted in the message using `printf()` formatting + +Example: +```php +trigger_deprecation('symfony/blockchain', '8.9', 'Using "%s" is deprecated, use "%s" instead.', 'bitcoin', 'fabcoin'); +``` + +This will generate the following message: +`Since symfony/blockchain 8.9: Using "bitcoin" is deprecated, use "fabcoin" instead.` + +While not recommended, the deprecation notices can be completely ignored by declaring an empty +`function trigger_deprecation() {}` in your application. diff --git a/vendor/symfony/deprecation-contracts/composer.json b/vendor/symfony/deprecation-contracts/composer.json new file mode 100644 index 0000000000..696f5a7f29 --- /dev/null +++ b/vendor/symfony/deprecation-contracts/composer.json @@ -0,0 +1,35 @@ +{ + "name": "symfony\/deprecation-contracts", + "type": "library", + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https:\/\/symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https:\/\/symfony.com\/contributors" + } + ], + "require": { + "php": ">=8.1" + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony\/contracts", + "url": "https:\/\/github.com\/symfony\/contracts" + } + } +} \ No newline at end of file diff --git a/vendor/symfony/deprecation-contracts/function.php b/vendor/symfony/deprecation-contracts/function.php new file mode 100644 index 0000000000..d4371504a0 --- /dev/null +++ b/vendor/symfony/deprecation-contracts/function.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (!function_exists('trigger_deprecation')) { + /** + * Triggers a silenced deprecation notice. + * + * @param string $package The name of the Composer package that is triggering the deprecation + * @param string $version The version of the package that introduced the deprecation + * @param string $message The message of the deprecation + * @param mixed ...$args Values to insert in the message using printf() formatting + * + * @author Nicolas Grekas + */ + function trigger_deprecation(string $package, string $version, string $message, ...$args): void + { + @trigger_error(($package || $version ? "Since $package $version: " : '').($args ? vsprintf($message, $args) : $message), \E_USER_DEPRECATED); + } +} diff --git a/vendor/symfony/finder/CHANGELOG.md b/vendor/symfony/finder/CHANGELOG.md new file mode 100644 index 0000000000..e838302477 --- /dev/null +++ b/vendor/symfony/finder/CHANGELOG.md @@ -0,0 +1,103 @@ +CHANGELOG +========= + +6.4 +--- + + * Add early directory pruning to `Finder::filter()` + +6.2 +--- + + * Add `Finder::sortByExtension()` and `Finder::sortBySize()` + * Add `Finder::sortByCaseInsensitiveName()` to sort by name with case insensitive sorting methods + +6.0 +--- + + * Remove `Comparator::setTarget()` and `Comparator::setOperator()` + +5.4.0 +----- + + * Deprecate `Comparator::setTarget()` and `Comparator::setOperator()` + * Add a constructor to `Comparator` that allows setting target and operator + * Finder's iterator has now `Symfony\Component\Finder\SplFileInfo` inner type specified + * Add recursive .gitignore files support + +5.0.0 +----- + + * added `$useNaturalSort` argument to `Finder::sortByName()` + +4.3.0 +----- + + * added Finder::ignoreVCSIgnored() to ignore files based on rules listed in .gitignore + +4.2.0 +----- + + * added $useNaturalSort option to Finder::sortByName() method + * the `Finder::sortByName()` method will have a new `$useNaturalSort` + argument in version 5.0, not defining it is deprecated + * added `Finder::reverseSorting()` to reverse the sorting + +4.0.0 +----- + + * removed `ExceptionInterface` + * removed `Symfony\Component\Finder\Iterator\FilterIterator` + +3.4.0 +----- + + * deprecated `Symfony\Component\Finder\Iterator\FilterIterator` + * added Finder::hasResults() method to check if any results were found + +3.3.0 +----- + + * added double-star matching to Glob::toRegex() + +3.0.0 +----- + + * removed deprecated classes + +2.8.0 +----- + + * deprecated adapters and related classes + +2.5.0 +----- + * added support for GLOB_BRACE in the paths passed to Finder::in() + +2.3.0 +----- + + * added a way to ignore unreadable directories (via Finder::ignoreUnreadableDirs()) + * unified the way subfolders that are not executable are handled by always throwing an AccessDeniedException exception + +2.2.0 +----- + + * added Finder::path() and Finder::notPath() methods + * added finder adapters to improve performance on specific platforms + * added support for wildcard characters (glob patterns) in the paths passed + to Finder::in() + +2.1.0 +----- + + * added Finder::sortByAccessedTime(), Finder::sortByChangedTime(), and + Finder::sortByModifiedTime() + * added Countable to Finder + * added support for an array of directories as an argument to + Finder::exclude() + * added searching based on the file content via Finder::contains() and + Finder::notContains() + * added support for the != operator in the Comparator + * [BC BREAK] filter expressions (used for file name and content) are no more + considered as regexps but glob patterns when they are enclosed in '*' or '?' diff --git a/vendor/symfony/finder/Comparator/Comparator.php b/vendor/symfony/finder/Comparator/Comparator.php new file mode 100644 index 0000000000..8f7402dcf0 --- /dev/null +++ b/vendor/symfony/finder/Comparator/Comparator.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Finder\Comparator; + +/** + * @author Fabien Potencier + */ +class Comparator +{ + /** + * @var string + */ + private $target; + /** + * @var string + */ + private $operator; + public function __construct(string $target, string $operator = '==') + { + if (!\in_array($operator, ['>', '<', '>=', '<=', '==', '!='])) { + throw new \InvalidArgumentException(\sprintf('Invalid operator "%s".', $operator)); + } + $this->target = $target; + $this->operator = $operator; + } + /** + * Gets the target value. + */ + public function getTarget() : string + { + return $this->target; + } + /** + * Gets the comparison operator. + */ + public function getOperator() : string + { + return $this->operator; + } + /** + * Tests against the target. + * @param mixed $test + */ + public function test($test) : bool + { + switch ($this->operator) { + case '>': + return $test > $this->target; + case '>=': + return $test >= $this->target; + case '<': + return $test < $this->target; + case '<=': + return $test <= $this->target; + case '!=': + return $test != $this->target; + default: + return $test == $this->target; + } + } +} diff --git a/vendor/symfony/finder/Comparator/DateComparator.php b/vendor/symfony/finder/Comparator/DateComparator.php new file mode 100644 index 0000000000..9dc34b9750 --- /dev/null +++ b/vendor/symfony/finder/Comparator/DateComparator.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Finder\Comparator; + +/** + * DateCompare compiles date comparisons. + * + * @author Fabien Potencier + */ +class DateComparator extends Comparator +{ + /** + * @param string $test A comparison string + * + * @throws \InvalidArgumentException If the test is not understood + */ + public function __construct(string $test) + { + if (!\preg_match('#^\\s*(==|!=|[<>]=?|after|since|before|until)?\\s*(.+?)\\s*$#i', $test, $matches)) { + throw new \InvalidArgumentException(\sprintf('Don\'t understand "%s" as a date test.', $test)); + } + try { + $date = new \DateTimeImmutable($matches[2]); + $target = $date->format('U'); + } catch (\Exception $exception) { + throw new \InvalidArgumentException(\sprintf('"%s" is not a valid date.', $matches[2])); + } + $operator = $matches[1] ?? '=='; + if ('since' === $operator || 'after' === $operator) { + $operator = '>'; + } + if ('until' === $operator || 'before' === $operator) { + $operator = '<'; + } + parent::__construct($target, $operator); + } +} diff --git a/vendor/symfony/finder/Comparator/NumberComparator.php b/vendor/symfony/finder/Comparator/NumberComparator.php new file mode 100644 index 0000000000..7ba26f8d62 --- /dev/null +++ b/vendor/symfony/finder/Comparator/NumberComparator.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Finder\Comparator; + +/** + * NumberComparator compiles a simple comparison to an anonymous + * subroutine, which you can call with a value to be tested again. + * + * Now this would be very pointless, if NumberCompare didn't understand + * magnitudes. + * + * The target value may use magnitudes of kilobytes (k, ki), + * megabytes (m, mi), or gigabytes (g, gi). Those suffixed + * with an i use the appropriate 2**n version in accordance with the + * IEC standard: http://physics.nist.gov/cuu/Units/binary.html + * + * Based on the Perl Number::Compare module. + * + * @author Fabien Potencier PHP port + * @author Richard Clamp Perl version + * @copyright 2004-2005 Fabien Potencier + * @copyright 2002 Richard Clamp + * + * @see http://physics.nist.gov/cuu/Units/binary.html + */ +class NumberComparator extends Comparator +{ + /** + * @param string|null $test A comparison string or null + * + * @throws \InvalidArgumentException If the test is not understood + */ + public function __construct(?string $test) + { + if (null === $test || !\preg_match('#^\\s*(==|!=|[<>]=?)?\\s*([0-9\\.]+)\\s*([kmg]i?)?\\s*$#i', $test, $matches)) { + throw new \InvalidArgumentException(\sprintf('Don\'t understand "%s" as a number test.', $test ?? 'null')); + } + $target = $matches[2]; + if (!\is_numeric($target)) { + throw new \InvalidArgumentException(\sprintf('Invalid number "%s".', $target)); + } + if (isset($matches[3])) { + // magnitude + switch (\strtolower($matches[3])) { + case 'k': + $target *= 1000; + break; + case 'ki': + $target *= 1024; + break; + case 'm': + $target *= 1000000; + break; + case 'mi': + $target *= 1024 * 1024; + break; + case 'g': + $target *= 1000000000; + break; + case 'gi': + $target *= 1024 * 1024 * 1024; + break; + } + } + parent::__construct($target, $matches[1] ?: '=='); + } +} diff --git a/vendor/symfony/finder/Exception/AccessDeniedException.php b/vendor/symfony/finder/Exception/AccessDeniedException.php new file mode 100644 index 0000000000..b7dd3dc203 --- /dev/null +++ b/vendor/symfony/finder/Exception/AccessDeniedException.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Finder\Exception; + +/** + * @author Jean-François Simon + */ +class AccessDeniedException extends \UnexpectedValueException +{ +} diff --git a/vendor/symfony/finder/Exception/DirectoryNotFoundException.php b/vendor/symfony/finder/Exception/DirectoryNotFoundException.php new file mode 100644 index 0000000000..370ac19941 --- /dev/null +++ b/vendor/symfony/finder/Exception/DirectoryNotFoundException.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Finder\Exception; + +/** + * @author Andreas Erhard + */ +class DirectoryNotFoundException extends \InvalidArgumentException +{ +} diff --git a/vendor/symfony/finder/Finder.php b/vendor/symfony/finder/Finder.php new file mode 100644 index 0000000000..220c2c97bd --- /dev/null +++ b/vendor/symfony/finder/Finder.php @@ -0,0 +1,818 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Finder; + +use SwissKnife202405\Symfony\Component\Finder\Comparator\DateComparator; +use SwissKnife202405\Symfony\Component\Finder\Comparator\NumberComparator; +use SwissKnife202405\Symfony\Component\Finder\Exception\DirectoryNotFoundException; +use SwissKnife202405\Symfony\Component\Finder\Iterator\CustomFilterIterator; +use SwissKnife202405\Symfony\Component\Finder\Iterator\DateRangeFilterIterator; +use SwissKnife202405\Symfony\Component\Finder\Iterator\DepthRangeFilterIterator; +use SwissKnife202405\Symfony\Component\Finder\Iterator\ExcludeDirectoryFilterIterator; +use SwissKnife202405\Symfony\Component\Finder\Iterator\FilecontentFilterIterator; +use SwissKnife202405\Symfony\Component\Finder\Iterator\FilenameFilterIterator; +use SwissKnife202405\Symfony\Component\Finder\Iterator\LazyIterator; +use SwissKnife202405\Symfony\Component\Finder\Iterator\SizeRangeFilterIterator; +use SwissKnife202405\Symfony\Component\Finder\Iterator\SortableIterator; +/** + * Finder allows to build rules to find files and directories. + * + * It is a thin wrapper around several specialized iterator classes. + * + * All rules may be invoked several times. + * + * All methods return the current Finder object to allow chaining: + * + * $finder = Finder::create()->files()->name('*.php')->in(__DIR__); + * + * @author Fabien Potencier + * + * @implements \IteratorAggregate + */ +class Finder implements \IteratorAggregate, \Countable +{ + public const IGNORE_VCS_FILES = 1; + public const IGNORE_DOT_FILES = 2; + public const IGNORE_VCS_IGNORED_FILES = 4; + /** + * @var int + */ + private $mode = 0; + /** + * @var mixed[] + */ + private $names = []; + /** + * @var mixed[] + */ + private $notNames = []; + /** + * @var mixed[] + */ + private $exclude = []; + /** + * @var mixed[] + */ + private $filters = []; + /** + * @var mixed[] + */ + private $pruneFilters = []; + /** + * @var mixed[] + */ + private $depths = []; + /** + * @var mixed[] + */ + private $sizes = []; + /** + * @var bool + */ + private $followLinks = \false; + /** + * @var bool + */ + private $reverseSorting = \false; + /** + * @var \Closure|int|false + */ + private $sort = \false; + /** + * @var int + */ + private $ignore = 0; + /** + * @var mixed[] + */ + private $dirs = []; + /** + * @var mixed[] + */ + private $dates = []; + /** + * @var mixed[] + */ + private $iterators = []; + /** + * @var mixed[] + */ + private $contains = []; + /** + * @var mixed[] + */ + private $notContains = []; + /** + * @var mixed[] + */ + private $paths = []; + /** + * @var mixed[] + */ + private $notPaths = []; + /** + * @var bool + */ + private $ignoreUnreadableDirs = \false; + /** + * @var mixed[] + */ + private static $vcsPatterns = ['.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg']; + public function __construct() + { + $this->ignore = static::IGNORE_VCS_FILES | static::IGNORE_DOT_FILES; + } + /** + * Creates a new Finder. + * @return static + */ + public static function create() + { + return new static(); + } + /** + * Restricts the matching to directories only. + * + * @return $this + */ + public function directories() + { + $this->mode = Iterator\FileTypeFilterIterator::ONLY_DIRECTORIES; + return $this; + } + /** + * Restricts the matching to files only. + * + * @return $this + */ + public function files() + { + $this->mode = Iterator\FileTypeFilterIterator::ONLY_FILES; + return $this; + } + /** + * Adds tests for the directory depth. + * + * Usage: + * + * $finder->depth('> 1') // the Finder will start matching at level 1. + * $finder->depth('< 3') // the Finder will descend at most 3 levels of directories below the starting point. + * $finder->depth(['>= 1', '< 3']) + * + * @param string|int|string[]|int[] $levels The depth level expression or an array of depth levels + * + * @return $this + * + * @see DepthRangeFilterIterator + * @see NumberComparator + */ + public function depth($levels) + { + foreach ((array) $levels as $level) { + $this->depths[] = new Comparator\NumberComparator($level); + } + return $this; + } + /** + * Adds tests for file dates (last modified). + * + * The date must be something that strtotime() is able to parse: + * + * $finder->date('since yesterday'); + * $finder->date('until 2 days ago'); + * $finder->date('> now - 2 hours'); + * $finder->date('>= 2005-10-15'); + * $finder->date(['>= 2005-10-15', '<= 2006-05-27']); + * + * @param string|string[] $dates A date range string or an array of date ranges + * + * @return $this + * + * @see strtotime + * @see DateRangeFilterIterator + * @see DateComparator + */ + public function date($dates) + { + foreach ((array) $dates as $date) { + $this->dates[] = new Comparator\DateComparator($date); + } + return $this; + } + /** + * Adds rules that files must match. + * + * You can use patterns (delimited with / sign), globs or simple strings. + * + * $finder->name('/\.php$/') + * $finder->name('*.php') // same as above, without dot files + * $finder->name('test.php') + * $finder->name(['test.py', 'test.php']) + * + * @param string|string[] $patterns A pattern (a regexp, a glob, or a string) or an array of patterns + * + * @return $this + * + * @see FilenameFilterIterator + */ + public function name($patterns) + { + $this->names = \array_merge($this->names, (array) $patterns); + return $this; + } + /** + * Adds rules that files must not match. + * + * @param string|string[] $patterns A pattern (a regexp, a glob, or a string) or an array of patterns + * + * @return $this + * + * @see FilenameFilterIterator + */ + public function notName($patterns) + { + $this->notNames = \array_merge($this->notNames, (array) $patterns); + return $this; + } + /** + * Adds tests that file contents must match. + * + * Strings or PCRE patterns can be used: + * + * $finder->contains('Lorem ipsum') + * $finder->contains('/Lorem ipsum/i') + * $finder->contains(['dolor', '/ipsum/i']) + * + * @param string|string[] $patterns A pattern (string or regexp) or an array of patterns + * + * @return $this + * + * @see FilecontentFilterIterator + */ + public function contains($patterns) + { + $this->contains = \array_merge($this->contains, (array) $patterns); + return $this; + } + /** + * Adds tests that file contents must not match. + * + * Strings or PCRE patterns can be used: + * + * $finder->notContains('Lorem ipsum') + * $finder->notContains('/Lorem ipsum/i') + * $finder->notContains(['lorem', '/dolor/i']) + * + * @param string|string[] $patterns A pattern (string or regexp) or an array of patterns + * + * @return $this + * + * @see FilecontentFilterIterator + */ + public function notContains($patterns) + { + $this->notContains = \array_merge($this->notContains, (array) $patterns); + return $this; + } + /** + * Adds rules that filenames must match. + * + * You can use patterns (delimited with / sign) or simple strings. + * + * $finder->path('some/special/dir') + * $finder->path('/some\/special\/dir/') // same as above + * $finder->path(['some dir', 'another/dir']) + * + * Use only / as dirname separator. + * + * @param string|string[] $patterns A pattern (a regexp or a string) or an array of patterns + * + * @return $this + * + * @see FilenameFilterIterator + */ + public function path($patterns) + { + $this->paths = \array_merge($this->paths, (array) $patterns); + return $this; + } + /** + * Adds rules that filenames must not match. + * + * You can use patterns (delimited with / sign) or simple strings. + * + * $finder->notPath('some/special/dir') + * $finder->notPath('/some\/special\/dir/') // same as above + * $finder->notPath(['some/file.txt', 'another/file.log']) + * + * Use only / as dirname separator. + * + * @param string|string[] $patterns A pattern (a regexp or a string) or an array of patterns + * + * @return $this + * + * @see FilenameFilterIterator + */ + public function notPath($patterns) + { + $this->notPaths = \array_merge($this->notPaths, (array) $patterns); + return $this; + } + /** + * Adds tests for file sizes. + * + * $finder->size('> 10K'); + * $finder->size('<= 1Ki'); + * $finder->size(4); + * $finder->size(['> 10K', '< 20K']) + * + * @param string|int|string[]|int[] $sizes A size range string or an integer or an array of size ranges + * + * @return $this + * + * @see SizeRangeFilterIterator + * @see NumberComparator + */ + public function size($sizes) + { + foreach ((array) $sizes as $size) { + $this->sizes[] = new Comparator\NumberComparator($size); + } + return $this; + } + /** + * Excludes directories. + * + * Directories passed as argument must be relative to the ones defined with the `in()` method. For example: + * + * $finder->in(__DIR__)->exclude('ruby'); + * + * @param string|array $dirs A directory path or an array of directories + * + * @return $this + * + * @see ExcludeDirectoryFilterIterator + */ + public function exclude($dirs) + { + $this->exclude = \array_merge($this->exclude, (array) $dirs); + return $this; + } + /** + * Excludes "hidden" directories and files (starting with a dot). + * + * This option is enabled by default. + * + * @return $this + * + * @see ExcludeDirectoryFilterIterator + */ + public function ignoreDotFiles(bool $ignoreDotFiles) + { + if ($ignoreDotFiles) { + $this->ignore |= static::IGNORE_DOT_FILES; + } else { + $this->ignore &= ~static::IGNORE_DOT_FILES; + } + return $this; + } + /** + * Forces the finder to ignore version control directories. + * + * This option is enabled by default. + * + * @return $this + * + * @see ExcludeDirectoryFilterIterator + */ + public function ignoreVCS(bool $ignoreVCS) + { + if ($ignoreVCS) { + $this->ignore |= static::IGNORE_VCS_FILES; + } else { + $this->ignore &= ~static::IGNORE_VCS_FILES; + } + return $this; + } + /** + * Forces Finder to obey .gitignore and ignore files based on rules listed there. + * + * This option is disabled by default. + * + * @return $this + */ + public function ignoreVCSIgnored(bool $ignoreVCSIgnored) + { + if ($ignoreVCSIgnored) { + $this->ignore |= static::IGNORE_VCS_IGNORED_FILES; + } else { + $this->ignore &= ~static::IGNORE_VCS_IGNORED_FILES; + } + return $this; + } + /** + * Adds VCS patterns. + * + * @see ignoreVCS() + * + * @param string|string[] $pattern VCS patterns to ignore + * + * @return void + */ + public static function addVCSPattern($pattern) + { + foreach ((array) $pattern as $p) { + self::$vcsPatterns[] = $p; + } + self::$vcsPatterns = \array_unique(self::$vcsPatterns); + } + /** + * Sorts files and directories by an anonymous function. + * + * The anonymous function receives two \SplFileInfo instances to compare. + * + * This can be slow as all the matching files and directories must be retrieved for comparison. + * + * @return $this + * + * @see SortableIterator + */ + public function sort(\Closure $closure) + { + $this->sort = $closure; + return $this; + } + /** + * Sorts files and directories by extension. + * + * This can be slow as all the matching files and directories must be retrieved for comparison. + * + * @return $this + * + * @see SortableIterator + */ + public function sortByExtension() + { + $this->sort = Iterator\SortableIterator::SORT_BY_EXTENSION; + return $this; + } + /** + * Sorts files and directories by name. + * + * This can be slow as all the matching files and directories must be retrieved for comparison. + * + * @return $this + * + * @see SortableIterator + */ + public function sortByName(bool $useNaturalSort = \false) + { + $this->sort = $useNaturalSort ? Iterator\SortableIterator::SORT_BY_NAME_NATURAL : Iterator\SortableIterator::SORT_BY_NAME; + return $this; + } + /** + * Sorts files and directories by name case insensitive. + * + * This can be slow as all the matching files and directories must be retrieved for comparison. + * + * @return $this + * + * @see SortableIterator + */ + public function sortByCaseInsensitiveName(bool $useNaturalSort = \false) + { + $this->sort = $useNaturalSort ? Iterator\SortableIterator::SORT_BY_NAME_NATURAL_CASE_INSENSITIVE : Iterator\SortableIterator::SORT_BY_NAME_CASE_INSENSITIVE; + return $this; + } + /** + * Sorts files and directories by size. + * + * This can be slow as all the matching files and directories must be retrieved for comparison. + * + * @return $this + * + * @see SortableIterator + */ + public function sortBySize() + { + $this->sort = Iterator\SortableIterator::SORT_BY_SIZE; + return $this; + } + /** + * Sorts files and directories by type (directories before files), then by name. + * + * This can be slow as all the matching files and directories must be retrieved for comparison. + * + * @return $this + * + * @see SortableIterator + */ + public function sortByType() + { + $this->sort = Iterator\SortableIterator::SORT_BY_TYPE; + return $this; + } + /** + * Sorts files and directories by the last accessed time. + * + * This is the time that the file was last accessed, read or written to. + * + * This can be slow as all the matching files and directories must be retrieved for comparison. + * + * @return $this + * + * @see SortableIterator + */ + public function sortByAccessedTime() + { + $this->sort = Iterator\SortableIterator::SORT_BY_ACCESSED_TIME; + return $this; + } + /** + * Reverses the sorting. + * + * @return $this + */ + public function reverseSorting() + { + $this->reverseSorting = \true; + return $this; + } + /** + * Sorts files and directories by the last inode changed time. + * + * This is the time that the inode information was last modified (permissions, owner, group or other metadata). + * + * On Windows, since inode is not available, changed time is actually the file creation time. + * + * This can be slow as all the matching files and directories must be retrieved for comparison. + * + * @return $this + * + * @see SortableIterator + */ + public function sortByChangedTime() + { + $this->sort = Iterator\SortableIterator::SORT_BY_CHANGED_TIME; + return $this; + } + /** + * Sorts files and directories by the last modified time. + * + * This is the last time the actual contents of the file were last modified. + * + * This can be slow as all the matching files and directories must be retrieved for comparison. + * + * @return $this + * + * @see SortableIterator + */ + public function sortByModifiedTime() + { + $this->sort = Iterator\SortableIterator::SORT_BY_MODIFIED_TIME; + return $this; + } + /** + * Filters the iterator with an anonymous function. + * + * The anonymous function receives a \SplFileInfo and must return false + * to remove files. + * + * @param \Closure(SplFileInfo): bool $closure + * @param bool $prune Whether to skip traversing directories further + * + * @return $this + * + * @see CustomFilterIterator + */ + public function filter(\Closure $closure) + { + $prune = 1 < \func_num_args() ? \func_get_arg(1) : \false; + $this->filters[] = $closure; + if ($prune) { + $this->pruneFilters[] = $closure; + } + return $this; + } + /** + * Forces the following of symlinks. + * + * @return $this + */ + public function followLinks() + { + $this->followLinks = \true; + return $this; + } + /** + * Tells finder to ignore unreadable directories. + * + * By default, scanning unreadable directories content throws an AccessDeniedException. + * + * @return $this + */ + public function ignoreUnreadableDirs(bool $ignore = \true) + { + $this->ignoreUnreadableDirs = $ignore; + return $this; + } + /** + * Searches files and directories which match defined rules. + * + * @param string|string[] $dirs A directory path or an array of directories + * + * @return $this + * + * @throws DirectoryNotFoundException if one of the directories does not exist + */ + public function in($dirs) + { + $resolvedDirs = []; + foreach ((array) $dirs as $dir) { + if (\is_dir($dir)) { + $resolvedDirs[] = [$this->normalizeDir($dir)]; + } elseif ($glob = \glob($dir, (\defined('GLOB_BRACE') ? \GLOB_BRACE : 0) | \GLOB_ONLYDIR | \GLOB_NOSORT)) { + \sort($glob); + $resolvedDirs[] = \array_map(\Closure::fromCallable([$this, 'normalizeDir']), $glob); + } else { + throw new DirectoryNotFoundException(\sprintf('The "%s" directory does not exist.', $dir)); + } + } + $this->dirs = \array_merge($this->dirs, ...$resolvedDirs); + return $this; + } + /** + * Returns an Iterator for the current Finder configuration. + * + * This method implements the IteratorAggregate interface. + * + * @return \Iterator + * + * @throws \LogicException if the in() method has not been called + */ + public function getIterator() : \Iterator + { + if (0 === \count($this->dirs) && 0 === \count($this->iterators)) { + throw new \LogicException('You must call one of in() or append() methods before iterating over a Finder.'); + } + if (1 === \count($this->dirs) && 0 === \count($this->iterators)) { + $iterator = $this->searchInDirectory($this->dirs[0]); + if ($this->sort || $this->reverseSorting) { + $iterator = (new Iterator\SortableIterator($iterator, $this->sort, $this->reverseSorting))->getIterator(); + } + return $iterator; + } + $iterator = new \AppendIterator(); + foreach ($this->dirs as $dir) { + $iterator->append(new \IteratorIterator(new LazyIterator(function () use($dir) { + return $this->searchInDirectory($dir); + }))); + } + foreach ($this->iterators as $it) { + $iterator->append($it); + } + if ($this->sort || $this->reverseSorting) { + $iterator = (new Iterator\SortableIterator($iterator, $this->sort, $this->reverseSorting))->getIterator(); + } + return $iterator; + } + /** + * Appends an existing set of files/directories to the finder. + * + * The set can be another Finder, an Iterator, an IteratorAggregate, or even a plain array. + * + * @return $this + * + * @throws \InvalidArgumentException when the given argument is not iterable + */ + public function append(iterable $iterator) + { + if ($iterator instanceof \IteratorAggregate) { + $this->iterators[] = $iterator->getIterator(); + } elseif ($iterator instanceof \Iterator) { + $this->iterators[] = $iterator; + } elseif (\is_iterable($iterator)) { + $it = new \ArrayIterator(); + foreach ($iterator as $file) { + $file = $file instanceof \SplFileInfo ? $file : new \SplFileInfo($file); + $it[$file->getPathname()] = $file; + } + $this->iterators[] = $it; + } else { + throw new \InvalidArgumentException('Finder::append() method wrong argument type.'); + } + return $this; + } + /** + * Check if any results were found. + */ + public function hasResults() : bool + { + foreach ($this->getIterator() as $_) { + return \true; + } + return \false; + } + /** + * Counts all the results collected by the iterators. + */ + public function count() : int + { + return \iterator_count($this->getIterator()); + } + private function searchInDirectory(string $dir) : \Iterator + { + $exclude = $this->exclude; + $notPaths = $this->notPaths; + if ($this->pruneFilters) { + $exclude = \array_merge($exclude, $this->pruneFilters); + } + if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) { + $exclude = \array_merge($exclude, self::$vcsPatterns); + } + if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) { + $notPaths[] = '#(^|/)\\..+(/|$)#'; + } + $minDepth = 0; + $maxDepth = \PHP_INT_MAX; + foreach ($this->depths as $comparator) { + switch ($comparator->getOperator()) { + case '>': + $minDepth = $comparator->getTarget() + 1; + break; + case '>=': + $minDepth = $comparator->getTarget(); + break; + case '<': + $maxDepth = $comparator->getTarget() - 1; + break; + case '<=': + $maxDepth = $comparator->getTarget(); + break; + default: + $minDepth = $maxDepth = $comparator->getTarget(); + } + } + $flags = \RecursiveDirectoryIterator::SKIP_DOTS; + if ($this->followLinks) { + $flags |= \RecursiveDirectoryIterator::FOLLOW_SYMLINKS; + } + $iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs); + if ($exclude) { + $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $exclude); + } + $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST); + if ($minDepth > 0 || $maxDepth < \PHP_INT_MAX) { + $iterator = new Iterator\DepthRangeFilterIterator($iterator, $minDepth, $maxDepth); + } + if ($this->mode) { + $iterator = new Iterator\FileTypeFilterIterator($iterator, $this->mode); + } + if ($this->names || $this->notNames) { + $iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames); + } + if ($this->contains || $this->notContains) { + $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains); + } + if ($this->sizes) { + $iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes); + } + if ($this->dates) { + $iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates); + } + if ($this->filters) { + $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters); + } + if ($this->paths || $notPaths) { + $iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $notPaths); + } + if (static::IGNORE_VCS_IGNORED_FILES === (static::IGNORE_VCS_IGNORED_FILES & $this->ignore)) { + $iterator = new Iterator\VcsIgnoredFilterIterator($iterator, $dir); + } + return $iterator; + } + /** + * Normalizes given directory names by removing trailing slashes. + * + * Excluding: (s)ftp:// or ssh2.(s)ftp:// wrapper + */ + private function normalizeDir(string $dir) : string + { + if ('/' === $dir) { + return $dir; + } + $dir = \rtrim($dir, '/' . \DIRECTORY_SEPARATOR); + if (\preg_match('#^(ssh2\\.)?s?ftp://#', $dir)) { + $dir .= '/'; + } + return $dir; + } +} diff --git a/vendor/symfony/finder/Gitignore.php b/vendor/symfony/finder/Gitignore.php new file mode 100644 index 0000000000..be6414d925 --- /dev/null +++ b/vendor/symfony/finder/Gitignore.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Finder; + +/** + * Gitignore matches against text. + * + * @author Michael Voříšek + * @author Ahmed Abdou + */ +class Gitignore +{ + /** + * Returns a regexp which is the equivalent of the gitignore pattern. + * + * Format specification: https://git-scm.com/docs/gitignore#_pattern_format + */ + public static function toRegex(string $gitignoreFileContent) : string + { + return self::buildRegex($gitignoreFileContent, \false); + } + public static function toRegexMatchingNegatedPatterns(string $gitignoreFileContent) : string + { + return self::buildRegex($gitignoreFileContent, \true); + } + private static function buildRegex(string $gitignoreFileContent, bool $inverted) : string + { + $gitignoreFileContent = \preg_replace('~(? + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Finder; + +/** + * Glob matches globbing patterns against text. + * + * if match_glob("foo.*", "foo.bar") echo "matched\n"; + * + * // prints foo.bar and foo.baz + * $regex = glob_to_regex("foo.*"); + * for (['foo.bar', 'foo.baz', 'foo', 'bar'] as $t) + * { + * if (/$regex/) echo "matched: $car\n"; + * } + * + * Glob implements glob(3) style matching that can be used to match + * against text, rather than fetching names from a filesystem. + * + * Based on the Perl Text::Glob module. + * + * @author Fabien Potencier PHP port + * @author Richard Clamp Perl version + * @copyright 2004-2005 Fabien Potencier + * @copyright 2002 Richard Clamp + */ +class Glob +{ + /** + * Returns a regexp which is the equivalent of the glob pattern. + */ + public static function toRegex(string $glob, bool $strictLeadingDot = \true, bool $strictWildcardSlash = \true, string $delimiter = '#') : string + { + $firstByte = \true; + $escaping = \false; + $inCurlies = 0; + $regex = ''; + $sizeGlob = \strlen($glob); + for ($i = 0; $i < $sizeGlob; ++$i) { + $car = $glob[$i]; + if ($firstByte && $strictLeadingDot && '.' !== $car) { + $regex .= '(?=[^\\.])'; + } + $firstByte = '/' === $car; + if ($firstByte && $strictWildcardSlash && isset($glob[$i + 2]) && '**' === $glob[$i + 1] . $glob[$i + 2] && (!isset($glob[$i + 3]) || '/' === $glob[$i + 3])) { + $car = '[^/]++/'; + if (!isset($glob[$i + 3])) { + $car .= '?'; + } + if ($strictLeadingDot) { + $car = '(?=[^\\.])' . $car; + } + $car = '/(?:' . $car . ')*'; + $i += 2 + isset($glob[$i + 3]); + if ('/' === $delimiter) { + $car = \str_replace('/', '\\/', $car); + } + } + if ($delimiter === $car || '.' === $car || '(' === $car || ')' === $car || '|' === $car || '+' === $car || '^' === $car || '$' === $car) { + $regex .= "\\{$car}"; + } elseif ('*' === $car) { + $regex .= $escaping ? '\\*' : ($strictWildcardSlash ? '[^/]*' : '.*'); + } elseif ('?' === $car) { + $regex .= $escaping ? '\\?' : ($strictWildcardSlash ? '[^/]' : '.'); + } elseif ('{' === $car) { + $regex .= $escaping ? '\\{' : '('; + if (!$escaping) { + ++$inCurlies; + } + } elseif ('}' === $car && $inCurlies) { + $regex .= $escaping ? '}' : ')'; + if (!$escaping) { + --$inCurlies; + } + } elseif (',' === $car && $inCurlies) { + $regex .= $escaping ? ',' : '|'; + } elseif ('\\' === $car) { + if ($escaping) { + $regex .= '\\\\'; + $escaping = \false; + } else { + $escaping = \true; + } + continue; + } else { + $regex .= $car; + } + $escaping = \false; + } + return $delimiter . '^' . $regex . '$' . $delimiter; + } +} diff --git a/vendor/symfony/finder/Iterator/CustomFilterIterator.php b/vendor/symfony/finder/Iterator/CustomFilterIterator.php new file mode 100644 index 0000000000..1f2b9450a0 --- /dev/null +++ b/vendor/symfony/finder/Iterator/CustomFilterIterator.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Finder\Iterator; + +/** + * CustomFilterIterator filters files by applying anonymous functions. + * + * The anonymous function receives a \SplFileInfo and must return false + * to remove files. + * + * @author Fabien Potencier + * + * @extends \FilterIterator + */ +class CustomFilterIterator extends \FilterIterator +{ + /** + * @var mixed[] + */ + private $filters = []; + /** + * @param \Iterator $iterator The Iterator to filter + * @param callable[] $filters An array of PHP callbacks + * + * @throws \InvalidArgumentException + */ + public function __construct(\Iterator $iterator, array $filters) + { + foreach ($filters as $filter) { + if (!\is_callable($filter)) { + throw new \InvalidArgumentException('Invalid PHP callback.'); + } + } + $this->filters = $filters; + parent::__construct($iterator); + } + /** + * Filters the iterator values. + */ + public function accept() : bool + { + $fileinfo = $this->current(); + foreach ($this->filters as $filter) { + if (\false === $filter($fileinfo)) { + return \false; + } + } + return \true; + } +} diff --git a/vendor/symfony/finder/Iterator/DateRangeFilterIterator.php b/vendor/symfony/finder/Iterator/DateRangeFilterIterator.php new file mode 100644 index 0000000000..fe96e93a66 --- /dev/null +++ b/vendor/symfony/finder/Iterator/DateRangeFilterIterator.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Finder\Iterator; + +use SwissKnife202405\Symfony\Component\Finder\Comparator\DateComparator; +/** + * DateRangeFilterIterator filters out files that are not in the given date range (last modified dates). + * + * @author Fabien Potencier + * + * @extends \FilterIterator + */ +class DateRangeFilterIterator extends \FilterIterator +{ + /** + * @var mixed[] + */ + private $comparators = []; + /** + * @param \Iterator $iterator + * @param DateComparator[] $comparators + */ + public function __construct(\Iterator $iterator, array $comparators) + { + $this->comparators = $comparators; + parent::__construct($iterator); + } + /** + * Filters the iterator values. + */ + public function accept() : bool + { + $fileinfo = $this->current(); + if (!\file_exists($fileinfo->getPathname())) { + return \false; + } + $filedate = $fileinfo->getMTime(); + foreach ($this->comparators as $compare) { + if (!$compare->test($filedate)) { + return \false; + } + } + return \true; + } +} diff --git a/vendor/symfony/finder/Iterator/DepthRangeFilterIterator.php b/vendor/symfony/finder/Iterator/DepthRangeFilterIterator.php new file mode 100644 index 0000000000..a4ff679ae4 --- /dev/null +++ b/vendor/symfony/finder/Iterator/DepthRangeFilterIterator.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Finder\Iterator; + +/** + * DepthRangeFilterIterator limits the directory depth. + * + * @author Fabien Potencier + * + * @template-covariant TKey + * @template-covariant TValue + * + * @extends \FilterIterator + */ +class DepthRangeFilterIterator extends \FilterIterator +{ + /** + * @var int + */ + private $minDepth = 0; + /** + * @param \RecursiveIteratorIterator<\RecursiveIterator> $iterator The Iterator to filter + * @param int $minDepth The min depth + * @param int $maxDepth The max depth + */ + public function __construct(\RecursiveIteratorIterator $iterator, int $minDepth = 0, int $maxDepth = \PHP_INT_MAX) + { + $this->minDepth = $minDepth; + $iterator->setMaxDepth(\PHP_INT_MAX === $maxDepth ? -1 : $maxDepth); + parent::__construct($iterator); + } + /** + * Filters the iterator values. + */ + public function accept() : bool + { + return $this->getInnerIterator()->getDepth() >= $this->minDepth; + } +} diff --git a/vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php b/vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php new file mode 100644 index 0000000000..e2be00a9c7 --- /dev/null +++ b/vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Finder\Iterator; + +use SwissKnife202405\Symfony\Component\Finder\SplFileInfo; +/** + * ExcludeDirectoryFilterIterator filters out directories. + * + * @author Fabien Potencier + * + * @extends \FilterIterator + * + * @implements \RecursiveIterator + */ +class ExcludeDirectoryFilterIterator extends \FilterIterator implements \RecursiveIterator +{ + /** @var \Iterator */ + private $iterator; + /** + * @var bool + */ + private $isRecursive; + /** @var array */ + private $excludedDirs = []; + /** + * @var string|null + */ + private $excludedPattern; + /** @var list */ + private $pruneFilters = []; + /** + * @param \Iterator $iterator The Iterator to filter + * @param list $directories An array of directories to exclude + */ + public function __construct(\Iterator $iterator, array $directories) + { + $this->iterator = $iterator; + $this->isRecursive = $iterator instanceof \RecursiveIterator; + $patterns = []; + foreach ($directories as $directory) { + if (!\is_string($directory)) { + if (!\is_callable($directory)) { + throw new \InvalidArgumentException('Invalid PHP callback.'); + } + $this->pruneFilters[] = $directory; + continue; + } + $directory = \rtrim($directory, '/'); + if (!$this->isRecursive || \strpos($directory, '/') !== \false) { + $patterns[] = \preg_quote($directory, '#'); + } else { + $this->excludedDirs[$directory] = \true; + } + } + if ($patterns) { + $this->excludedPattern = '#(?:^|/)(?:' . \implode('|', $patterns) . ')(?:/|$)#'; + } + parent::__construct($iterator); + } + /** + * Filters the iterator values. + */ + public function accept() : bool + { + if ($this->isRecursive && isset($this->excludedDirs[$this->getFilename()]) && $this->isDir()) { + return \false; + } + if ($this->excludedPattern) { + $path = $this->isDir() ? $this->current()->getRelativePathname() : $this->current()->getRelativePath(); + $path = \str_replace('\\', '/', $path); + return !\preg_match($this->excludedPattern, $path); + } + if ($this->pruneFilters && $this->hasChildren()) { + foreach ($this->pruneFilters as $pruneFilter) { + if (!$pruneFilter($this->current())) { + return \false; + } + } + } + return \true; + } + public function hasChildren() : bool + { + return $this->isRecursive && $this->iterator->hasChildren(); + } + public function getChildren() : self + { + $children = new self($this->iterator->getChildren(), []); + $children->excludedDirs = $this->excludedDirs; + $children->excludedPattern = $this->excludedPattern; + return $children; + } +} diff --git a/vendor/symfony/finder/Iterator/FileTypeFilterIterator.php b/vendor/symfony/finder/Iterator/FileTypeFilterIterator.php new file mode 100644 index 0000000000..a727a33412 --- /dev/null +++ b/vendor/symfony/finder/Iterator/FileTypeFilterIterator.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Finder\Iterator; + +/** + * FileTypeFilterIterator only keeps files, directories, or both. + * + * @author Fabien Potencier + * + * @extends \FilterIterator + */ +class FileTypeFilterIterator extends \FilterIterator +{ + public const ONLY_FILES = 1; + public const ONLY_DIRECTORIES = 2; + /** + * @var int + */ + private $mode; + /** + * @param \Iterator $iterator The Iterator to filter + * @param int $mode The mode (self::ONLY_FILES or self::ONLY_DIRECTORIES) + */ + public function __construct(\Iterator $iterator, int $mode) + { + $this->mode = $mode; + parent::__construct($iterator); + } + /** + * Filters the iterator values. + */ + public function accept() : bool + { + $fileinfo = $this->current(); + if (self::ONLY_DIRECTORIES === (self::ONLY_DIRECTORIES & $this->mode) && $fileinfo->isFile()) { + return \false; + } elseif (self::ONLY_FILES === (self::ONLY_FILES & $this->mode) && $fileinfo->isDir()) { + return \false; + } + return \true; + } +} diff --git a/vendor/symfony/finder/Iterator/FilecontentFilterIterator.php b/vendor/symfony/finder/Iterator/FilecontentFilterIterator.php new file mode 100644 index 0000000000..631956528d --- /dev/null +++ b/vendor/symfony/finder/Iterator/FilecontentFilterIterator.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Finder\Iterator; + +use SwissKnife202405\Symfony\Component\Finder\SplFileInfo; +/** + * FilecontentFilterIterator filters files by their contents using patterns (regexps or strings). + * + * @author Fabien Potencier + * @author Włodzimierz Gajda + * + * @extends MultiplePcreFilterIterator + */ +class FilecontentFilterIterator extends MultiplePcreFilterIterator +{ + /** + * Filters the iterator values. + */ + public function accept() : bool + { + if (!$this->matchRegexps && !$this->noMatchRegexps) { + return \true; + } + $fileinfo = $this->current(); + if ($fileinfo->isDir() || !$fileinfo->isReadable()) { + return \false; + } + $content = $fileinfo->getContents(); + if (!$content) { + return \false; + } + return $this->isAccepted($content); + } + /** + * Converts string to regexp if necessary. + * + * @param string $str Pattern: string or regexp + */ + protected function toRegex(string $str) : string + { + return $this->isRegex($str) ? $str : '/' . \preg_quote($str, '/') . '/'; + } +} diff --git a/vendor/symfony/finder/Iterator/FilenameFilterIterator.php b/vendor/symfony/finder/Iterator/FilenameFilterIterator.php new file mode 100644 index 0000000000..9f6f852a98 --- /dev/null +++ b/vendor/symfony/finder/Iterator/FilenameFilterIterator.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Finder\Iterator; + +use SwissKnife202405\Symfony\Component\Finder\Glob; +/** + * FilenameFilterIterator filters files by patterns (a regexp, a glob, or a string). + * + * @author Fabien Potencier + * + * @extends MultiplePcreFilterIterator + */ +class FilenameFilterIterator extends MultiplePcreFilterIterator +{ + /** + * Filters the iterator values. + */ + public function accept() : bool + { + return $this->isAccepted($this->current()->getFilename()); + } + /** + * Converts glob to regexp. + * + * PCRE patterns are left unchanged. + * Glob strings are transformed with Glob::toRegex(). + * + * @param string $str Pattern: glob or regexp + */ + protected function toRegex(string $str) : string + { + return $this->isRegex($str) ? $str : Glob::toRegex($str); + } +} diff --git a/vendor/symfony/finder/Iterator/LazyIterator.php b/vendor/symfony/finder/Iterator/LazyIterator.php new file mode 100644 index 0000000000..7e92a92533 --- /dev/null +++ b/vendor/symfony/finder/Iterator/LazyIterator.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Finder\Iterator; + +/** + * @author Jérémy Derussé + * + * @internal + */ +class LazyIterator implements \IteratorAggregate +{ + /** + * @var \Closure + */ + private $iteratorFactory; + public function __construct(callable $iteratorFactory) + { + $this->iteratorFactory = \Closure::fromCallable($iteratorFactory); + } + public function getIterator() : \Traversable + { + yield from ($this->iteratorFactory)(); + } +} diff --git a/vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php b/vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php new file mode 100644 index 0000000000..af8e40ffc7 --- /dev/null +++ b/vendor/symfony/finder/Iterator/MultiplePcreFilterIterator.php @@ -0,0 +1,96 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Finder\Iterator; + +/** + * MultiplePcreFilterIterator filters files using patterns (regexps, globs or strings). + * + * @author Fabien Potencier + * + * @template-covariant TKey + * @template-covariant TValue + * + * @extends \FilterIterator + */ +abstract class MultiplePcreFilterIterator extends \FilterIterator +{ + protected $matchRegexps = []; + protected $noMatchRegexps = []; + /** + * @param \Iterator $iterator The Iterator to filter + * @param string[] $matchPatterns An array of patterns that need to match + * @param string[] $noMatchPatterns An array of patterns that need to not match + */ + public function __construct(\Iterator $iterator, array $matchPatterns, array $noMatchPatterns) + { + foreach ($matchPatterns as $pattern) { + $this->matchRegexps[] = $this->toRegex($pattern); + } + foreach ($noMatchPatterns as $pattern) { + $this->noMatchRegexps[] = $this->toRegex($pattern); + } + parent::__construct($iterator); + } + /** + * Checks whether the string is accepted by the regex filters. + * + * If there is no regexps defined in the class, this method will accept the string. + * Such case can be handled by child classes before calling the method if they want to + * apply a different behavior. + */ + protected function isAccepted(string $string) : bool + { + // should at least not match one rule to exclude + foreach ($this->noMatchRegexps as $regex) { + if (\preg_match($regex, $string)) { + return \false; + } + } + // should at least match one rule + if ($this->matchRegexps) { + foreach ($this->matchRegexps as $regex) { + if (\preg_match($regex, $string)) { + return \true; + } + } + return \false; + } + // If there is no match rules, the file is accepted + return \true; + } + /** + * Checks whether the string is a regex. + */ + protected function isRegex(string $str) : bool + { + $availableModifiers = 'imsxuADU'; + if (\PHP_VERSION_ID >= 80200) { + $availableModifiers .= 'n'; + } + if (\preg_match('/^(.{3,}?)[' . $availableModifiers . ']*$/', $str, $m)) { + $start = \substr($m[1], 0, 1); + $end = \substr($m[1], -1); + if ($start === $end) { + return !\preg_match('/[*?[:alnum:] \\\\]/', $start); + } + foreach ([['{', '}'], ['(', ')'], ['[', ']'], ['<', '>']] as $delimiters) { + if ($start === $delimiters[0] && $end === $delimiters[1]) { + return \true; + } + } + } + return \false; + } + /** + * Converts string into regexp. + */ + protected abstract function toRegex(string $str) : string; +} diff --git a/vendor/symfony/finder/Iterator/PathFilterIterator.php b/vendor/symfony/finder/Iterator/PathFilterIterator.php new file mode 100644 index 0000000000..11882ff72b --- /dev/null +++ b/vendor/symfony/finder/Iterator/PathFilterIterator.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Finder\Iterator; + +use SwissKnife202405\Symfony\Component\Finder\SplFileInfo; +/** + * PathFilterIterator filters files by path patterns (e.g. some/special/dir). + * + * @author Fabien Potencier + * @author Włodzimierz Gajda + * + * @extends MultiplePcreFilterIterator + */ +class PathFilterIterator extends MultiplePcreFilterIterator +{ + /** + * Filters the iterator values. + */ + public function accept() : bool + { + $filename = $this->current()->getRelativePathname(); + if ('\\' === \DIRECTORY_SEPARATOR) { + $filename = \str_replace('\\', '/', $filename); + } + return $this->isAccepted($filename); + } + /** + * Converts strings to regexp. + * + * PCRE patterns are left unchanged. + * + * Default conversion: + * 'lorem/ipsum/dolor' ==> 'lorem\/ipsum\/dolor/' + * + * Use only / as directory separator (on Windows also). + * + * @param string $str Pattern: regexp or dirname + */ + protected function toRegex(string $str) : string + { + return $this->isRegex($str) ? $str : '/' . \preg_quote($str, '/') . '/'; + } +} diff --git a/vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php b/vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php new file mode 100644 index 0000000000..8965d2ed2a --- /dev/null +++ b/vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php @@ -0,0 +1,126 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Finder\Iterator; + +use SwissKnife202405\Symfony\Component\Finder\Exception\AccessDeniedException; +use SwissKnife202405\Symfony\Component\Finder\SplFileInfo; +/** + * Extends the \RecursiveDirectoryIterator to support relative paths. + * + * @author Victor Berchet + * + * @extends \RecursiveDirectoryIterator + */ +class RecursiveDirectoryIterator extends \RecursiveDirectoryIterator +{ + /** + * @var bool + */ + private $ignoreUnreadableDirs; + /** + * @var bool + */ + private $ignoreFirstRewind = \true; + // these 3 properties take part of the performance optimization to avoid redoing the same work in all iterations + /** + * @var string + */ + private $rootPath; + /** + * @var string + */ + private $subPath; + /** + * @var string + */ + private $directorySeparator = '/'; + /** + * @throws \RuntimeException + */ + public function __construct(string $path, int $flags, bool $ignoreUnreadableDirs = \false) + { + if ($flags & (self::CURRENT_AS_PATHNAME | self::CURRENT_AS_SELF)) { + throw new \RuntimeException('This iterator only support returning current as fileinfo.'); + } + parent::__construct($path, $flags); + $this->ignoreUnreadableDirs = $ignoreUnreadableDirs; + $this->rootPath = $path; + if ('/' !== \DIRECTORY_SEPARATOR && !($flags & self::UNIX_PATHS)) { + $this->directorySeparator = \DIRECTORY_SEPARATOR; + } + } + /** + * Return an instance of SplFileInfo with support for relative paths. + */ + public function current() : SplFileInfo + { + // the logic here avoids redoing the same work in all iterations + if (!isset($this->subPath)) { + $this->subPath = $this->getSubPath(); + } + $subPathname = $this->subPath; + if ('' !== $subPathname) { + $subPathname .= $this->directorySeparator; + } + $subPathname .= $this->getFilename(); + if ('/' !== ($basePath = $this->rootPath)) { + $basePath .= $this->directorySeparator; + } + return new SplFileInfo($basePath . $subPathname, $this->subPath, $subPathname); + } + public function hasChildren($allowLinks = \false) : bool + { + $hasChildren = parent::hasChildren($allowLinks); + if (!$hasChildren || !$this->ignoreUnreadableDirs) { + return $hasChildren; + } + try { + parent::getChildren(); + return \true; + } catch (\UnexpectedValueException $exception) { + // If directory is unreadable and finder is set to ignore it, skip children + return \false; + } + } + /** + * @throws AccessDeniedException + */ + public function getChildren() : \RecursiveDirectoryIterator + { + try { + $children = parent::getChildren(); + if ($children instanceof self) { + // parent method will call the constructor with default arguments, so unreadable dirs won't be ignored anymore + $children->ignoreUnreadableDirs = $this->ignoreUnreadableDirs; + // performance optimization to avoid redoing the same work in all children + $children->rootPath = $this->rootPath; + } + return $children; + } catch (\UnexpectedValueException $e) { + throw new AccessDeniedException($e->getMessage(), $e->getCode(), $e); + } + } + public function next() : void + { + $this->ignoreFirstRewind = \false; + parent::next(); + } + public function rewind() : void + { + // some streams like FTP are not rewindable, ignore the first rewind after creation, + // as newly created DirectoryIterator does not need to be rewound + if ($this->ignoreFirstRewind) { + $this->ignoreFirstRewind = \false; + return; + } + parent::rewind(); + } +} diff --git a/vendor/symfony/finder/Iterator/SizeRangeFilterIterator.php b/vendor/symfony/finder/Iterator/SizeRangeFilterIterator.php new file mode 100644 index 0000000000..4bacc85dba --- /dev/null +++ b/vendor/symfony/finder/Iterator/SizeRangeFilterIterator.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Finder\Iterator; + +use SwissKnife202405\Symfony\Component\Finder\Comparator\NumberComparator; +/** + * SizeRangeFilterIterator filters out files that are not in the given size range. + * + * @author Fabien Potencier + * + * @extends \FilterIterator + */ +class SizeRangeFilterIterator extends \FilterIterator +{ + /** + * @var mixed[] + */ + private $comparators = []; + /** + * @param \Iterator $iterator + * @param NumberComparator[] $comparators + */ + public function __construct(\Iterator $iterator, array $comparators) + { + $this->comparators = $comparators; + parent::__construct($iterator); + } + /** + * Filters the iterator values. + */ + public function accept() : bool + { + $fileinfo = $this->current(); + if (!$fileinfo->isFile()) { + return \true; + } + $filesize = $fileinfo->getSize(); + foreach ($this->comparators as $compare) { + if (!$compare->test($filesize)) { + return \false; + } + } + return \true; + } +} diff --git a/vendor/symfony/finder/Iterator/SortableIterator.php b/vendor/symfony/finder/Iterator/SortableIterator.php new file mode 100644 index 0000000000..29608dddc9 --- /dev/null +++ b/vendor/symfony/finder/Iterator/SortableIterator.php @@ -0,0 +1,117 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Finder\Iterator; + +/** + * SortableIterator applies a sort on a given Iterator. + * + * @author Fabien Potencier + * + * @implements \IteratorAggregate + */ +class SortableIterator implements \IteratorAggregate +{ + public const SORT_BY_NONE = 0; + public const SORT_BY_NAME = 1; + public const SORT_BY_TYPE = 2; + public const SORT_BY_ACCESSED_TIME = 3; + public const SORT_BY_CHANGED_TIME = 4; + public const SORT_BY_MODIFIED_TIME = 5; + public const SORT_BY_NAME_NATURAL = 6; + public const SORT_BY_NAME_CASE_INSENSITIVE = 7; + public const SORT_BY_NAME_NATURAL_CASE_INSENSITIVE = 8; + public const SORT_BY_EXTENSION = 9; + public const SORT_BY_SIZE = 10; + /** @var \Traversable */ + private $iterator; + /** + * @var \Closure|int + */ + private $sort; + /** + * @param \Traversable $iterator + * @param int|callable $sort The sort type (SORT_BY_NAME, SORT_BY_TYPE, or a PHP callback) + * + * @throws \InvalidArgumentException + */ + public function __construct(\Traversable $iterator, $sort, bool $reverseOrder = \false) + { + $this->iterator = $iterator; + $order = $reverseOrder ? -1 : 1; + if (self::SORT_BY_NAME === $sort) { + $this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use($order) { + return $order * \strcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname()); + }; + } elseif (self::SORT_BY_NAME_NATURAL === $sort) { + $this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use($order) { + return $order * \strnatcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname()); + }; + } elseif (self::SORT_BY_NAME_CASE_INSENSITIVE === $sort) { + $this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use($order) { + return $order * \strcasecmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname()); + }; + } elseif (self::SORT_BY_NAME_NATURAL_CASE_INSENSITIVE === $sort) { + $this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use($order) { + return $order * \strnatcasecmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname()); + }; + } elseif (self::SORT_BY_TYPE === $sort) { + $this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use($order) { + if ($a->isDir() && $b->isFile()) { + return -$order; + } elseif ($a->isFile() && $b->isDir()) { + return $order; + } + return $order * \strcmp($a->getRealPath() ?: $a->getPathname(), $b->getRealPath() ?: $b->getPathname()); + }; + } elseif (self::SORT_BY_ACCESSED_TIME === $sort) { + $this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use($order) { + return $order * ($a->getATime() - $b->getATime()); + }; + } elseif (self::SORT_BY_CHANGED_TIME === $sort) { + $this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use($order) { + return $order * ($a->getCTime() - $b->getCTime()); + }; + } elseif (self::SORT_BY_MODIFIED_TIME === $sort) { + $this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use($order) { + return $order * ($a->getMTime() - $b->getMTime()); + }; + } elseif (self::SORT_BY_EXTENSION === $sort) { + $this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use($order) { + return $order * \strnatcmp($a->getExtension(), $b->getExtension()); + }; + } elseif (self::SORT_BY_SIZE === $sort) { + $this->sort = static function (\SplFileInfo $a, \SplFileInfo $b) use($order) { + return $order * ($a->getSize() - $b->getSize()); + }; + } elseif (self::SORT_BY_NONE === $sort) { + $this->sort = $order; + } elseif (\is_callable($sort)) { + $this->sort = $reverseOrder ? static function (\SplFileInfo $a, \SplFileInfo $b) use($sort) { + return -$sort($a, $b); + } : \Closure::fromCallable($sort); + } else { + throw new \InvalidArgumentException('The SortableIterator takes a PHP callable or a valid built-in sort algorithm as an argument.'); + } + } + public function getIterator() : \Traversable + { + if (1 === $this->sort) { + return $this->iterator; + } + $array = \iterator_to_array($this->iterator, \true); + if (-1 === $this->sort) { + $array = \array_reverse($array); + } else { + \uasort($array, $this->sort); + } + return new \ArrayIterator($array); + } +} diff --git a/vendor/symfony/finder/Iterator/VcsIgnoredFilterIterator.php b/vendor/symfony/finder/Iterator/VcsIgnoredFilterIterator.php new file mode 100644 index 0000000000..9eaf910d97 --- /dev/null +++ b/vendor/symfony/finder/Iterator/VcsIgnoredFilterIterator.php @@ -0,0 +1,134 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Finder\Iterator; + +use SwissKnife202405\Symfony\Component\Finder\Gitignore; +/** + * @extends \FilterIterator + */ +final class VcsIgnoredFilterIterator extends \FilterIterator +{ + /** + * @var string + */ + private $baseDir; + /** + * @var array + */ + private $gitignoreFilesCache = []; + /** + * @var array + */ + private $ignoredPathsCache = []; + /** + * @param \Iterator $iterator + */ + public function __construct(\Iterator $iterator, string $baseDir) + { + $this->baseDir = $this->normalizePath($baseDir); + foreach (\array_merge([$this->baseDir], $this->parentDirectoriesUpwards($this->baseDir)) as $directory) { + if (@\is_dir("{$directory}/.git")) { + $this->baseDir = $directory; + break; + } + } + parent::__construct($iterator); + } + public function accept() : bool + { + $file = $this->current(); + $fileRealPath = $this->normalizePath($file->getRealPath()); + return !$this->isIgnored($fileRealPath); + } + private function isIgnored(string $fileRealPath) : bool + { + if (\is_dir($fileRealPath) && \substr_compare($fileRealPath, '/', -\strlen('/')) !== 0) { + $fileRealPath .= '/'; + } + if (isset($this->ignoredPathsCache[$fileRealPath])) { + return $this->ignoredPathsCache[$fileRealPath]; + } + $ignored = \false; + foreach ($this->parentDirectoriesDownwards($fileRealPath) as $parentDirectory) { + if ($this->isIgnored($parentDirectory)) { + // rules in ignored directories are ignored, no need to check further. + break; + } + $fileRelativePath = \substr($fileRealPath, \strlen($parentDirectory) + 1); + if (null === ($regexps = $this->readGitignoreFile("{$parentDirectory}/.gitignore"))) { + continue; + } + [$exclusionRegex, $inclusionRegex] = $regexps; + if (\preg_match($exclusionRegex, $fileRelativePath)) { + $ignored = \true; + continue; + } + if (\preg_match($inclusionRegex, $fileRelativePath)) { + $ignored = \false; + } + } + return $this->ignoredPathsCache[$fileRealPath] = $ignored; + } + /** + * @return list + */ + private function parentDirectoriesUpwards(string $from) : array + { + $parentDirectories = []; + $parentDirectory = $from; + while (\true) { + $newParentDirectory = \dirname($parentDirectory); + // dirname('/') = '/' + if ($newParentDirectory === $parentDirectory) { + break; + } + $parentDirectories[] = $parentDirectory = $newParentDirectory; + } + return $parentDirectories; + } + private function parentDirectoriesUpTo(string $from, string $upTo) : array + { + return \array_filter($this->parentDirectoriesUpwards($from), static function (string $directory) use($upTo) : bool { + return \strncmp($directory, $upTo, \strlen($upTo)) === 0; + }); + } + /** + * @return list + */ + private function parentDirectoriesDownwards(string $fileRealPath) : array + { + return \array_reverse($this->parentDirectoriesUpTo($fileRealPath, $this->baseDir)); + } + /** + * @return array{0: string, 1: string}|null + */ + private function readGitignoreFile(string $path) : ?array + { + if (\array_key_exists($path, $this->gitignoreFilesCache)) { + return $this->gitignoreFilesCache[$path]; + } + if (!\file_exists($path)) { + return $this->gitignoreFilesCache[$path] = null; + } + if (!\is_file($path) || !\is_readable($path)) { + throw new \RuntimeException("The \"ignoreVCSIgnored\" option cannot be used by the Finder as the \"{$path}\" file is not readable."); + } + $gitignoreFileContent = \file_get_contents($path); + return $this->gitignoreFilesCache[$path] = [Gitignore::toRegex($gitignoreFileContent), Gitignore::toRegexMatchingNegatedPatterns($gitignoreFileContent)]; + } + private function normalizePath(string $path) : string + { + if ('\\' === \DIRECTORY_SEPARATOR) { + return \str_replace('\\', '/', $path); + } + return $path; + } +} diff --git a/vendor/symfony/finder/LICENSE b/vendor/symfony/finder/LICENSE new file mode 100644 index 0000000000..0138f8f071 --- /dev/null +++ b/vendor/symfony/finder/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-present Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/finder/README.md b/vendor/symfony/finder/README.md new file mode 100644 index 0000000000..22bdeb9bcf --- /dev/null +++ b/vendor/symfony/finder/README.md @@ -0,0 +1,14 @@ +Finder Component +================ + +The Finder component finds files and directories via an intuitive fluent +interface. + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/finder.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/vendor/symfony/finder/SplFileInfo.php b/vendor/symfony/finder/SplFileInfo.php new file mode 100644 index 0000000000..04901986cf --- /dev/null +++ b/vendor/symfony/finder/SplFileInfo.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Finder; + +/** + * Extends \SplFileInfo to support relative paths. + * + * @author Fabien Potencier + */ +class SplFileInfo extends \SplFileInfo +{ + /** + * @var string + */ + private $relativePath; + /** + * @var string + */ + private $relativePathname; + /** + * @param string $file The file name + * @param string $relativePath The relative path + * @param string $relativePathname The relative path name + */ + public function __construct(string $file, string $relativePath, string $relativePathname) + { + parent::__construct($file); + $this->relativePath = $relativePath; + $this->relativePathname = $relativePathname; + } + /** + * Returns the relative path. + * + * This path does not contain the file name. + */ + public function getRelativePath() : string + { + return $this->relativePath; + } + /** + * Returns the relative path name. + * + * This path contains the file name. + */ + public function getRelativePathname() : string + { + return $this->relativePathname; + } + public function getFilenameWithoutExtension() : string + { + $filename = $this->getFilename(); + return \pathinfo($filename, \PATHINFO_FILENAME); + } + /** + * Returns the contents of the file. + * + * @throws \RuntimeException + */ + public function getContents() : string + { + \set_error_handler(function ($type, $msg) use(&$error) { + $error = $msg; + }); + try { + $content = \file_get_contents($this->getPathname()); + } finally { + \restore_error_handler(); + } + if (\false === $content) { + throw new \RuntimeException($error); + } + return $content; + } +} diff --git a/vendor/symfony/finder/composer.json b/vendor/symfony/finder/composer.json new file mode 100644 index 0000000000..62ba338659 --- /dev/null +++ b/vendor/symfony/finder/composer.json @@ -0,0 +1,33 @@ +{ + "name": "symfony\/finder", + "type": "library", + "description": "Finds files and directories via an intuitive fluent interface", + "keywords": [], + "homepage": "https:\/\/symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https:\/\/symfony.com\/contributors" + } + ], + "require": { + "php": ">=8.1" + }, + "require-dev": { + "symfony\/filesystem": "^6.0|^7.0" + }, + "autoload": { + "psr-4": { + "SwissKnife202405\\Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "\/Tests\/" + ] + }, + "minimum-stability": "dev" +} \ No newline at end of file diff --git a/vendor/symfony/polyfill-intl-grapheme/Grapheme.php b/vendor/symfony/polyfill-intl-grapheme/Grapheme.php new file mode 100644 index 0000000000..87f475a74f --- /dev/null +++ b/vendor/symfony/polyfill-intl-grapheme/Grapheme.php @@ -0,0 +1,210 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Symfony\Polyfill\Intl\Grapheme; + +\define('SYMFONY_GRAPHEME_CLUSTER_RX', ((float) \PCRE_VERSION < 10 ? (float) \PCRE_VERSION >= 8.32 : (float) \PCRE_VERSION >= 10.39) ? '\\X' : \Symfony\Polyfill\Intl\Grapheme\Grapheme::GRAPHEME_CLUSTER_RX); +/** + * Partial intl implementation in pure PHP. + * + * Implemented: + * - grapheme_extract - Extract a sequence of grapheme clusters from a text buffer, which must be encoded in UTF-8 + * - grapheme_stripos - Find position (in grapheme units) of first occurrence of a case-insensitive string + * - grapheme_stristr - Returns part of haystack string from the first occurrence of case-insensitive needle to the end of haystack + * - grapheme_strlen - Get string length in grapheme units + * - grapheme_strpos - Find position (in grapheme units) of first occurrence of a string + * - grapheme_strripos - Find position (in grapheme units) of last occurrence of a case-insensitive string + * - grapheme_strrpos - Find position (in grapheme units) of last occurrence of a string + * - grapheme_strstr - Returns part of haystack string from the first occurrence of needle to the end of haystack + * - grapheme_substr - Return part of a string + * + * @author Nicolas Grekas + * + * @internal + */ +final class Grapheme +{ + // (CRLF|([ZWNJ-ZWJ]|T+|L*(LV?V+|LV|LVT)T*|L+|[^Control])[Extend]*|[Control]) + // This regular expression is a work around for http://bugs.exim.org/1279 + public const GRAPHEME_CLUSTER_RX = '(?:\\r\\n|(?:[ -~\\x{200C}\\x{200D}]|[ᆨ-ᇹ]+|[ᄀ-ᅟ]*(?:[가개갸걔거게겨계고과괘괴교구궈궤귀규그긔기까깨꺄꺠꺼께껴꼐꼬꽈꽤꾀꾜꾸꿔꿰뀌뀨끄끠끼나내냐냬너네녀녜노놔놰뇌뇨누눠눼뉘뉴느늬니다대댜댸더데뎌뎨도돠돼되됴두둬뒈뒤듀드듸디따때땨떄떠떼뗘뗴또똬뙈뙤뚀뚜뚸뛔뛰뜌뜨띄띠라래랴럐러레려례로롸뢔뢰료루뤄뤠뤼류르릐리마매먀먜머메며몌모뫄뫠뫼묘무뭐뭬뮈뮤므믜미바배뱌뱨버베벼볘보봐봬뵈뵤부붜붸뷔뷰브븨비빠빼뺘뺴뻐뻬뼈뼤뽀뽜뽸뾔뾰뿌뿨쀄쀠쀼쁘쁴삐사새샤섀서세셔셰소솨쇄쇠쇼수숴쉐쉬슈스싀시싸쌔쌰썌써쎄쎠쎼쏘쏴쐐쐬쑈쑤쒀쒜쒸쓔쓰씌씨아애야얘어에여예오와왜외요우워웨위유으의이자재쟈쟤저제져졔조좌좨죄죠주줘줴쥐쥬즈즤지짜째쨔쨰쩌쩨쪄쪠쪼쫘쫴쬐쬬쭈쭤쮀쮜쮸쯔쯰찌차채챠챼처체쳐쳬초촤쵀최쵸추춰췌취츄츠츼치카캐캬컈커케켜켸코콰쾌쾨쿄쿠쿼퀘퀴큐크킈키타태탸턔터테텨톄토톼퇘퇴툐투퉈퉤튀튜트틔티파패퍄퍠퍼페펴폐포퐈퐤푀표푸풔풰퓌퓨프픠피하해햐햬허헤혀혜호화홰회효후훠훼휘휴흐희히]?[ᅠ-ᆢ]+|[가-힣])[ᆨ-ᇹ]*|[ᄀ-ᅟ]+|[^\\p{Cc}\\p{Cf}\\p{Zl}\\p{Zp}])[\\p{Mn}\\p{Me}\\x{09BE}\\x{09D7}\\x{0B3E}\\x{0B57}\\x{0BBE}\\x{0BD7}\\x{0CC2}\\x{0CD5}\\x{0CD6}\\x{0D3E}\\x{0D57}\\x{0DCF}\\x{0DDF}\\x{200C}\\x{200D}\\x{1D165}\\x{1D16E}-\\x{1D172}]*|[\\p{Cc}\\p{Cf}\\p{Zl}\\p{Zp}])'; + private const CASE_FOLD = [['µ', 'ſ', "ͅ", 'ς', "ϐ", "ϑ", "ϕ", "ϖ", "ϰ", "ϱ", "ϵ", "ẛ", "ι"], ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "ṡ", 'ι']]; + public static function grapheme_extract($s, $size, $type = \GRAPHEME_EXTR_COUNT, $start = 0, &$next = 0) + { + if (0 > $start) { + $start = \strlen($s) + $start; + } + if (!\is_scalar($s)) { + $hasError = \false; + \set_error_handler(function () use(&$hasError) { + $hasError = \true; + }); + $next = \substr($s, $start); + \restore_error_handler(); + if ($hasError) { + \substr($s, $start); + $s = ''; + } else { + $s = $next; + } + } else { + $s = \substr($s, $start); + } + $size = (int) $size; + $type = (int) $type; + $start = (int) $start; + if (\GRAPHEME_EXTR_COUNT !== $type && \GRAPHEME_EXTR_MAXBYTES !== $type && \GRAPHEME_EXTR_MAXCHARS !== $type) { + if (80000 > \PHP_VERSION_ID) { + return \false; + } + throw new \ValueError('grapheme_extract(): Argument #3 ($type) must be one of GRAPHEME_EXTR_COUNT, GRAPHEME_EXTR_MAXBYTES, or GRAPHEME_EXTR_MAXCHARS'); + } + if (!isset($s[0]) || 0 > $size || 0 > $start) { + return \false; + } + if (0 === $size) { + return ''; + } + $next = $start; + $s = \preg_split('/(' . SYMFONY_GRAPHEME_CLUSTER_RX . ')/u', "\r\n" . $s, $size + 1, \PREG_SPLIT_NO_EMPTY | \PREG_SPLIT_DELIM_CAPTURE); + if (!isset($s[1])) { + return \false; + } + $i = 1; + $ret = ''; + do { + if (\GRAPHEME_EXTR_COUNT === $type) { + --$size; + } elseif (\GRAPHEME_EXTR_MAXBYTES === $type) { + $size -= \strlen($s[$i]); + } else { + $size -= \iconv_strlen($s[$i], 'UTF-8//IGNORE'); + } + if ($size >= 0) { + $ret .= $s[$i]; + } + } while (isset($s[++$i]) && $size > 0); + $next += \strlen($ret); + return $ret; + } + public static function grapheme_strlen($s) + { + \preg_replace('/' . SYMFONY_GRAPHEME_CLUSTER_RX . '/u', '', $s, -1, $len); + return 0 === $len && '' !== $s ? null : $len; + } + public static function grapheme_substr($s, $start, $len = null) + { + if (null === $len) { + $len = 2147483647; + } + \preg_match_all('/' . SYMFONY_GRAPHEME_CLUSTER_RX . '/u', $s, $s); + $slen = \count($s[0]); + $start = (int) $start; + if (0 > $start) { + $start += $slen; + } + if (0 > $start) { + if (\PHP_VERSION_ID < 80000) { + return \false; + } + $start = 0; + } + if ($start >= $slen) { + return \PHP_VERSION_ID >= 80000 ? '' : \false; + } + $rem = $slen - $start; + if (0 > $len) { + $len += $rem; + } + if (0 === $len) { + return ''; + } + if (0 > $len) { + return \PHP_VERSION_ID >= 80000 ? '' : \false; + } + if ($len > $rem) { + $len = $rem; + } + return \implode('', \array_slice($s[0], $start, $len)); + } + public static function grapheme_strpos($s, $needle, $offset = 0) + { + return self::grapheme_position($s, $needle, $offset, 0); + } + public static function grapheme_stripos($s, $needle, $offset = 0) + { + return self::grapheme_position($s, $needle, $offset, 1); + } + public static function grapheme_strrpos($s, $needle, $offset = 0) + { + return self::grapheme_position($s, $needle, $offset, 2); + } + public static function grapheme_strripos($s, $needle, $offset = 0) + { + return self::grapheme_position($s, $needle, $offset, 3); + } + public static function grapheme_stristr($s, $needle, $beforeNeedle = \false) + { + return \mb_stristr($s, $needle, $beforeNeedle, 'UTF-8'); + } + public static function grapheme_strstr($s, $needle, $beforeNeedle = \false) + { + return \mb_strstr($s, $needle, $beforeNeedle, 'UTF-8'); + } + private static function grapheme_position($s, $needle, $offset, $mode) + { + $needle = (string) $needle; + if (80000 > \PHP_VERSION_ID && !\preg_match('/./us', $needle)) { + return \false; + } + $s = (string) $s; + if (!\preg_match('/./us', $s)) { + return \false; + } + if ($offset > 0) { + $s = self::grapheme_substr($s, $offset); + } elseif ($offset < 0) { + if (2 > $mode) { + $offset += self::grapheme_strlen($s); + $s = self::grapheme_substr($s, $offset); + if (0 > $offset) { + $offset = 0; + } + } elseif (0 > ($offset += self::grapheme_strlen($needle))) { + $s = self::grapheme_substr($s, 0, $offset); + $offset = 0; + } else { + $offset = 0; + } + } + // As UTF-8 is self-synchronizing, and we have ensured the strings are valid UTF-8, + // we can use normal binary string functions here. For case-insensitive searches, + // case fold the strings first. + $caseInsensitive = $mode & 1; + $reverse = $mode & 2; + if ($caseInsensitive) { + // Use the same case folding mode as mbstring does for mb_stripos(). + // Stick to SIMPLE case folding to avoid changing the length of the string, which + // might result in offsets being shifted. + $mode = \defined('MB_CASE_FOLD_SIMPLE') ? \MB_CASE_FOLD_SIMPLE : \MB_CASE_LOWER; + $s = \mb_convert_case($s, $mode, 'UTF-8'); + $needle = \mb_convert_case($needle, $mode, 'UTF-8'); + if (!\defined('MB_CASE_FOLD_SIMPLE')) { + $s = \str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $s); + $needle = \str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $needle); + } + } + if ($reverse) { + $needlePos = \strrpos($s, $needle); + } else { + $needlePos = \strpos($s, $needle); + } + return \false !== $needlePos ? self::grapheme_strlen(\substr($s, 0, $needlePos)) + $offset : \false; + } +} diff --git a/vendor/symfony/polyfill-intl-grapheme/LICENSE b/vendor/symfony/polyfill-intl-grapheme/LICENSE new file mode 100644 index 0000000000..6e3afce692 --- /dev/null +++ b/vendor/symfony/polyfill-intl-grapheme/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015-present Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/polyfill-intl-grapheme/README.md b/vendor/symfony/polyfill-intl-grapheme/README.md new file mode 100644 index 0000000000..f55d92c5c3 --- /dev/null +++ b/vendor/symfony/polyfill-intl-grapheme/README.md @@ -0,0 +1,31 @@ +Symfony Polyfill / Intl: Grapheme +================================= + +This component provides a partial, native PHP implementation of the +[Grapheme functions](https://php.net/intl.grapheme) from the +[Intl](https://php.net/intl) extension. + +- [`grapheme_extract`](https://php.net/grapheme_extract): Extract a sequence of grapheme + clusters from a text buffer, which must be encoded in UTF-8 +- [`grapheme_stripos`](https://php.net/grapheme_stripos): Find position (in grapheme units) + of first occurrence of a case-insensitive string +- [`grapheme_stristr`](https://php.net/grapheme_stristr): Returns part of haystack string + from the first occurrence of case-insensitive needle to the end of haystack +- [`grapheme_strlen`](https://php.net/grapheme_strlen): Get string length in grapheme units +- [`grapheme_strpos`](https://php.net/grapheme_strpos): Find position (in grapheme units) + of first occurrence of a string +- [`grapheme_strripos`](https://php.net/grapheme_strripos): Find position (in grapheme units) + of last occurrence of a case-insensitive string +- [`grapheme_strrpos`](https://php.net/grapheme_strrpos): Find position (in grapheme units) + of last occurrence of a string +- [`grapheme_strstr`](https://php.net/grapheme_strstr): Returns part of haystack string from + the first occurrence of needle to the end of haystack +- [`grapheme_substr`](https://php.net/grapheme_substr): Return part of a string + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/vendor/symfony/polyfill-intl-grapheme/bootstrap.php b/vendor/symfony/polyfill-intl-grapheme/bootstrap.php new file mode 100644 index 0000000000..fb999a7e65 --- /dev/null +++ b/vendor/symfony/polyfill-intl-grapheme/bootstrap.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +use Symfony\Polyfill\Intl\Grapheme as p; +if (\extension_loaded('intl')) { + return; +} +if (\PHP_VERSION_ID >= 80000) { + return require __DIR__ . '/bootstrap80.php'; +} +if (!\defined('GRAPHEME_EXTR_COUNT')) { + \define('GRAPHEME_EXTR_COUNT', 0); +} +if (!\defined('GRAPHEME_EXTR_MAXBYTES')) { + \define('GRAPHEME_EXTR_MAXBYTES', 1); +} +if (!\defined('GRAPHEME_EXTR_MAXCHARS')) { + \define('GRAPHEME_EXTR_MAXCHARS', 2); +} +if (!\function_exists('grapheme_extract')) { + function grapheme_extract($haystack, $size, $type = 0, $start = 0, &$next = 0) + { + return p\Grapheme::grapheme_extract($haystack, $size, $type, $start, $next); + } +} +if (!\function_exists('grapheme_stripos')) { + function grapheme_stripos($haystack, $needle, $offset = 0) + { + return p\Grapheme::grapheme_stripos($haystack, $needle, $offset); + } +} +if (!\function_exists('grapheme_stristr')) { + function grapheme_stristr($haystack, $needle, $beforeNeedle = \false) + { + return p\Grapheme::grapheme_stristr($haystack, $needle, $beforeNeedle); + } +} +if (!\function_exists('grapheme_strlen')) { + function grapheme_strlen($input) + { + return p\Grapheme::grapheme_strlen($input); + } +} +if (!\function_exists('grapheme_strpos')) { + function grapheme_strpos($haystack, $needle, $offset = 0) + { + return p\Grapheme::grapheme_strpos($haystack, $needle, $offset); + } +} +if (!\function_exists('grapheme_strripos')) { + function grapheme_strripos($haystack, $needle, $offset = 0) + { + return p\Grapheme::grapheme_strripos($haystack, $needle, $offset); + } +} +if (!\function_exists('grapheme_strrpos')) { + function grapheme_strrpos($haystack, $needle, $offset = 0) + { + return p\Grapheme::grapheme_strrpos($haystack, $needle, $offset); + } +} +if (!\function_exists('grapheme_strstr')) { + function grapheme_strstr($haystack, $needle, $beforeNeedle = \false) + { + return p\Grapheme::grapheme_strstr($haystack, $needle, $beforeNeedle); + } +} +if (!\function_exists('grapheme_substr')) { + function grapheme_substr($string, $offset, $length = null) + { + return p\Grapheme::grapheme_substr($string, $offset, $length); + } +} diff --git a/vendor/symfony/polyfill-intl-grapheme/bootstrap80.php b/vendor/symfony/polyfill-intl-grapheme/bootstrap80.php new file mode 100644 index 0000000000..c5ac94a9ea --- /dev/null +++ b/vendor/symfony/polyfill-intl-grapheme/bootstrap80.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +use Symfony\Polyfill\Intl\Grapheme as p; +if (!\defined('GRAPHEME_EXTR_COUNT')) { + \define('GRAPHEME_EXTR_COUNT', 0); +} +if (!\defined('GRAPHEME_EXTR_MAXBYTES')) { + \define('GRAPHEME_EXTR_MAXBYTES', 1); +} +if (!\defined('GRAPHEME_EXTR_MAXCHARS')) { + \define('GRAPHEME_EXTR_MAXCHARS', 2); +} +if (!\function_exists('grapheme_extract')) { + /** + * @return string|false + */ + function grapheme_extract(?string $haystack, ?int $size, ?int $type = \GRAPHEME_EXTR_COUNT, ?int $offset = 0, &$next = null) + { + return p\Grapheme::grapheme_extract((string) $haystack, (int) $size, (int) $type, (int) $offset, $next); + } +} +if (!\function_exists('grapheme_stripos')) { + /** + * @return int|false + */ + function grapheme_stripos(?string $haystack, ?string $needle, ?int $offset = 0) + { + return p\Grapheme::grapheme_stripos((string) $haystack, (string) $needle, (int) $offset); + } +} +if (!\function_exists('grapheme_stristr')) { + /** + * @return string|false + */ + function grapheme_stristr(?string $haystack, ?string $needle, ?bool $beforeNeedle = \false) + { + return p\Grapheme::grapheme_stristr((string) $haystack, (string) $needle, (bool) $beforeNeedle); + } +} +if (!\function_exists('grapheme_strlen')) { + /** + * @return int|false|null + */ + function grapheme_strlen(?string $string) + { + return p\Grapheme::grapheme_strlen((string) $string); + } +} +if (!\function_exists('grapheme_strpos')) { + /** + * @return int|false + */ + function grapheme_strpos(?string $haystack, ?string $needle, ?int $offset = 0) + { + return p\Grapheme::grapheme_strpos((string) $haystack, (string) $needle, (int) $offset); + } +} +if (!\function_exists('grapheme_strripos')) { + /** + * @return int|false + */ + function grapheme_strripos(?string $haystack, ?string $needle, ?int $offset = 0) + { + return p\Grapheme::grapheme_strripos((string) $haystack, (string) $needle, (int) $offset); + } +} +if (!\function_exists('grapheme_strrpos')) { + /** + * @return int|false + */ + function grapheme_strrpos(?string $haystack, ?string $needle, ?int $offset = 0) + { + return p\Grapheme::grapheme_strrpos((string) $haystack, (string) $needle, (int) $offset); + } +} +if (!\function_exists('grapheme_strstr')) { + /** + * @return string|false + */ + function grapheme_strstr(?string $haystack, ?string $needle, ?bool $beforeNeedle = \false) + { + return p\Grapheme::grapheme_strstr((string) $haystack, (string) $needle, (bool) $beforeNeedle); + } +} +if (!\function_exists('grapheme_substr')) { + /** + * @return string|false + */ + function grapheme_substr(?string $string, ?int $offset, ?int $length = null) + { + return p\Grapheme::grapheme_substr((string) $string, (int) $offset, $length); + } +} diff --git a/vendor/symfony/polyfill-intl-grapheme/composer.json b/vendor/symfony/polyfill-intl-grapheme/composer.json new file mode 100644 index 0000000000..c2fca99a51 --- /dev/null +++ b/vendor/symfony/polyfill-intl-grapheme/composer.json @@ -0,0 +1,46 @@ +{ + "name": "symfony\/polyfill-intl-grapheme", + "type": "library", + "description": "Symfony polyfill for intl's grapheme_* functions", + "keywords": [ + "polyfill", + "shim", + "compatibility", + "portable", + "intl", + "grapheme" + ], + "homepage": "https:\/\/symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https:\/\/symfony.com\/contributors" + } + ], + "require": { + "php": ">=7.1" + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "suggest": { + "ext-intl": "For best performance" + }, + "minimum-stability": "dev", + "extra": { + "thanks": { + "name": "symfony\/polyfill", + "url": "https:\/\/github.com\/symfony\/polyfill" + } + } +} \ No newline at end of file diff --git a/vendor/symfony/process/CHANGELOG.md b/vendor/symfony/process/CHANGELOG.md new file mode 100644 index 0000000000..e26819b5bc --- /dev/null +++ b/vendor/symfony/process/CHANGELOG.md @@ -0,0 +1,124 @@ +CHANGELOG +========= + +6.4 +--- + + * Add `PhpSubprocess` to handle PHP subprocesses that take over the + configuration from their parent + * Add `RunProcessMessage` and `RunProcessMessageHandler` + * Support using `Process::findExecutable()` independently of `open_basedir` + +5.2.0 +----- + + * added `Process::setOptions()` to set `Process` specific options + * added option `create_new_console` to allow a subprocess to continue + to run after the main script exited, both on Linux and on Windows + +5.1.0 +----- + + * added `Process::getStartTime()` to retrieve the start time of the process as float + +5.0.0 +----- + + * removed `Process::inheritEnvironmentVariables()` + * removed `PhpProcess::setPhpBinary()` + * `Process` must be instantiated with a command array, use `Process::fromShellCommandline()` when the command should be parsed by the shell + * removed `Process::setCommandLine()` + +4.4.0 +----- + + * deprecated `Process::inheritEnvironmentVariables()`: env variables are always inherited. + * added `Process::getLastOutputTime()` method + +4.2.0 +----- + + * added the `Process::fromShellCommandline()` to run commands in a shell wrapper + * deprecated passing a command as string when creating a `Process` instance + * deprecated the `Process::setCommandline()` and the `PhpProcess::setPhpBinary()` methods + * added the `Process::waitUntil()` method to wait for the process only for a + specific output, then continue the normal execution of your application + +4.1.0 +----- + + * added the `Process::isTtySupported()` method that allows to check for TTY support + * made `PhpExecutableFinder` look for the `PHP_BINARY` env var when searching the php binary + * added the `ProcessSignaledException` class to properly catch signaled process errors + +4.0.0 +----- + + * environment variables will always be inherited + * added a second `array $env = []` argument to the `start()`, `run()`, + `mustRun()`, and `restart()` methods of the `Process` class + * added a second `array $env = []` argument to the `start()` method of the + `PhpProcess` class + * the `ProcessUtils::escapeArgument()` method has been removed + * the `areEnvironmentVariablesInherited()`, `getOptions()`, and `setOptions()` + methods of the `Process` class have been removed + * support for passing `proc_open()` options has been removed + * removed the `ProcessBuilder` class, use the `Process` class instead + * removed the `getEnhanceWindowsCompatibility()` and `setEnhanceWindowsCompatibility()` methods of the `Process` class + * passing a not existing working directory to the constructor of the `Symfony\Component\Process\Process` class is not + supported anymore + +3.4.0 +----- + + * deprecated the ProcessBuilder class + * deprecated calling `Process::start()` without setting a valid working directory beforehand (via `setWorkingDirectory()` or constructor) + +3.3.0 +----- + + * added command line arrays in the `Process` class + * added `$env` argument to `Process::start()`, `run()`, `mustRun()` and `restart()` methods + * deprecated the `ProcessUtils::escapeArgument()` method + * deprecated not inheriting environment variables + * deprecated configuring `proc_open()` options + * deprecated configuring enhanced Windows compatibility + * deprecated configuring enhanced sigchild compatibility + +2.5.0 +----- + + * added support for PTY mode + * added the convenience method "mustRun" + * deprecation: Process::setStdin() is deprecated in favor of Process::setInput() + * deprecation: Process::getStdin() is deprecated in favor of Process::getInput() + * deprecation: Process::setInput() and ProcessBuilder::setInput() do not accept non-scalar types + +2.4.0 +----- + + * added the ability to define an idle timeout + +2.3.0 +----- + + * added ProcessUtils::escapeArgument() to fix the bug in escapeshellarg() function on Windows + * added Process::signal() + * added Process::getPid() + * added support for a TTY mode + +2.2.0 +----- + + * added ProcessBuilder::setArguments() to reset the arguments on a builder + * added a way to retrieve the standard and error output incrementally + * added Process:restart() + +2.1.0 +----- + + * added support for non-blocking processes (start(), wait(), isRunning(), stop()) + * enhanced Windows compatibility + * added Process::getExitCodeText() that returns a string representation for + the exit code returned by the process + * added ProcessBuilder diff --git a/vendor/symfony/process/Exception/ExceptionInterface.php b/vendor/symfony/process/Exception/ExceptionInterface.php new file mode 100644 index 0000000000..b85ad4f75c --- /dev/null +++ b/vendor/symfony/process/Exception/ExceptionInterface.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Process\Exception; + +/** + * Marker Interface for the Process Component. + * + * @author Johannes M. Schmitt + */ +interface ExceptionInterface extends \Throwable +{ +} diff --git a/vendor/symfony/process/Exception/InvalidArgumentException.php b/vendor/symfony/process/Exception/InvalidArgumentException.php new file mode 100644 index 0000000000..9e2699594a --- /dev/null +++ b/vendor/symfony/process/Exception/InvalidArgumentException.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Process\Exception; + +/** + * InvalidArgumentException for the Process Component. + * + * @author Romain Neutron + */ +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/process/Exception/LogicException.php b/vendor/symfony/process/Exception/LogicException.php new file mode 100644 index 0000000000..c7ced56333 --- /dev/null +++ b/vendor/symfony/process/Exception/LogicException.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Process\Exception; + +/** + * LogicException for the Process Component. + * + * @author Romain Neutron + */ +class LogicException extends \LogicException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/process/Exception/ProcessFailedException.php b/vendor/symfony/process/Exception/ProcessFailedException.php new file mode 100644 index 0000000000..469a54d414 --- /dev/null +++ b/vendor/symfony/process/Exception/ProcessFailedException.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Process\Exception; + +use SwissKnife202405\Symfony\Component\Process\Process; +/** + * Exception for failed processes. + * + * @author Johannes M. Schmitt + */ +class ProcessFailedException extends RuntimeException +{ + /** + * @var \Symfony\Component\Process\Process + */ + private $process; + public function __construct(Process $process) + { + if ($process->isSuccessful()) { + throw new InvalidArgumentException('Expected a failed process, but the given process was successful.'); + } + $error = \sprintf('The command "%s" failed.' . "\n\nExit Code: %s(%s)\n\nWorking directory: %s", $process->getCommandLine(), $process->getExitCode(), $process->getExitCodeText(), $process->getWorkingDirectory()); + if (!$process->isOutputDisabled()) { + $error .= \sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s", $process->getOutput(), $process->getErrorOutput()); + } + parent::__construct($error); + $this->process = $process; + } + /** + * @return Process + */ + public function getProcess() + { + return $this->process; + } +} diff --git a/vendor/symfony/process/Exception/ProcessSignaledException.php b/vendor/symfony/process/Exception/ProcessSignaledException.php new file mode 100644 index 0000000000..af2ddc5e3e --- /dev/null +++ b/vendor/symfony/process/Exception/ProcessSignaledException.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Process\Exception; + +use SwissKnife202405\Symfony\Component\Process\Process; +/** + * Exception that is thrown when a process has been signaled. + * + * @author Sullivan Senechal + */ +final class ProcessSignaledException extends RuntimeException +{ + /** + * @var \Symfony\Component\Process\Process + */ + private $process; + public function __construct(Process $process) + { + $this->process = $process; + parent::__construct(\sprintf('The process has been signaled with signal "%s".', $process->getTermSignal())); + } + public function getProcess() : Process + { + return $this->process; + } + public function getSignal() : int + { + return $this->getProcess()->getTermSignal(); + } +} diff --git a/vendor/symfony/process/Exception/ProcessTimedOutException.php b/vendor/symfony/process/Exception/ProcessTimedOutException.php new file mode 100644 index 0000000000..b8b2c7391e --- /dev/null +++ b/vendor/symfony/process/Exception/ProcessTimedOutException.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Process\Exception; + +use SwissKnife202405\Symfony\Component\Process\Process; +/** + * Exception that is thrown when a process times out. + * + * @author Johannes M. Schmitt + */ +class ProcessTimedOutException extends RuntimeException +{ + public const TYPE_GENERAL = 1; + public const TYPE_IDLE = 2; + /** + * @var \Symfony\Component\Process\Process + */ + private $process; + /** + * @var int + */ + private $timeoutType; + public function __construct(Process $process, int $timeoutType) + { + $this->process = $process; + $this->timeoutType = $timeoutType; + parent::__construct(\sprintf('The process "%s" exceeded the timeout of %s seconds.', $process->getCommandLine(), $this->getExceededTimeout())); + } + /** + * @return Process + */ + public function getProcess() + { + return $this->process; + } + /** + * @return bool + */ + public function isGeneralTimeout() + { + return self::TYPE_GENERAL === $this->timeoutType; + } + /** + * @return bool + */ + public function isIdleTimeout() + { + return self::TYPE_IDLE === $this->timeoutType; + } + public function getExceededTimeout() : ?float + { + switch ($this->timeoutType) { + case self::TYPE_GENERAL: + return $this->process->getTimeout(); + case self::TYPE_IDLE: + return $this->process->getIdleTimeout(); + default: + throw new \LogicException(\sprintf('Unknown timeout type "%d".', $this->timeoutType)); + } + } +} diff --git a/vendor/symfony/process/Exception/RunProcessFailedException.php b/vendor/symfony/process/Exception/RunProcessFailedException.php new file mode 100644 index 0000000000..cbafe04c17 --- /dev/null +++ b/vendor/symfony/process/Exception/RunProcessFailedException.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Process\Exception; + +use SwissKnife202405\Symfony\Component\Process\Messenger\RunProcessContext; +/** + * @author Kevin Bond + */ +final class RunProcessFailedException extends RuntimeException +{ + /** + * @readonly + * @var \Symfony\Component\Process\Messenger\RunProcessContext + */ + public $context; + public function __construct(ProcessFailedException $exception, RunProcessContext $context) + { + $this->context = $context; + parent::__construct($exception->getMessage(), $exception->getCode()); + } +} diff --git a/vendor/symfony/process/Exception/RuntimeException.php b/vendor/symfony/process/Exception/RuntimeException.php new file mode 100644 index 0000000000..d4b3c48673 --- /dev/null +++ b/vendor/symfony/process/Exception/RuntimeException.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Process\Exception; + +/** + * RuntimeException for the Process Component. + * + * @author Johannes M. Schmitt + */ +class RuntimeException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/process/ExecutableFinder.php b/vendor/symfony/process/ExecutableFinder.php new file mode 100644 index 0000000000..9991d1a321 --- /dev/null +++ b/vendor/symfony/process/ExecutableFinder.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Process; + +/** + * Generic executable finder. + * + * @author Fabien Potencier + * @author Johannes M. Schmitt + */ +class ExecutableFinder +{ + /** + * @var mixed[] + */ + private $suffixes = ['.exe', '.bat', '.cmd', '.com']; + /** + * Replaces default suffixes of executable. + * + * @return void + */ + public function setSuffixes(array $suffixes) + { + $this->suffixes = $suffixes; + } + /** + * Adds new possible suffix to check for executable. + * + * @return void + */ + public function addSuffix(string $suffix) + { + $this->suffixes[] = $suffix; + } + /** + * Finds an executable by name. + * + * @param string $name The executable name (without the extension) + * @param string|null $default The default to return if no executable is found + * @param array $extraDirs Additional dirs to check into + */ + public function find(string $name, ?string $default = null, array $extraDirs = []) : ?string + { + $dirs = \array_merge(\explode(\PATH_SEPARATOR, \getenv('PATH') ?: \getenv('Path')), $extraDirs); + $suffixes = ['']; + if ('\\' === \DIRECTORY_SEPARATOR) { + $pathExt = \getenv('PATHEXT'); + $suffixes = \array_merge($pathExt ? \explode(\PATH_SEPARATOR, $pathExt) : $this->suffixes, $suffixes); + } + foreach ($suffixes as $suffix) { + foreach ($dirs as $dir) { + if (@\is_file($file = $dir . \DIRECTORY_SEPARATOR . $name . $suffix) && ('\\' === \DIRECTORY_SEPARATOR || @\is_executable($file))) { + return $file; + } + if (!@\is_dir($dir) && \basename($dir) === $name . $suffix && @\is_executable($dir)) { + return $dir; + } + } + } + $command = '\\' === \DIRECTORY_SEPARATOR ? 'where' : 'command -v --'; + if (\function_exists('exec') && ($executablePath = \strtok(@\exec($command . ' ' . \escapeshellarg($name)), \PHP_EOL)) && @\is_executable($executablePath)) { + return $executablePath; + } + return $default; + } +} diff --git a/vendor/symfony/process/InputStream.php b/vendor/symfony/process/InputStream.php new file mode 100644 index 0000000000..406fd261aa --- /dev/null +++ b/vendor/symfony/process/InputStream.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Process; + +use SwissKnife202405\Symfony\Component\Process\Exception\RuntimeException; +/** + * Provides a way to continuously write to the input of a Process until the InputStream is closed. + * + * @author Nicolas Grekas + * + * @implements \IteratorAggregate + */ +class InputStream implements \IteratorAggregate +{ + /** + * @var \Closure|null + */ + private $onEmpty; + /** + * @var mixed[] + */ + private $input = []; + /** + * @var bool + */ + private $open = \true; + /** + * Sets a callback that is called when the write buffer becomes empty. + * + * @return void + */ + public function onEmpty(?callable $onEmpty = null) + { + $this->onEmpty = null !== $onEmpty ? \Closure::fromCallable($onEmpty) : null; + } + /** + * Appends an input to the write buffer. + * + * @param mixed $input The input to append as scalar, + * stream resource or \Traversable + * + * @return void + */ + public function write($input) + { + if (null === $input) { + return; + } + if ($this->isClosed()) { + throw new RuntimeException(\sprintf('"%s" is closed.', static::class)); + } + $this->input[] = ProcessUtils::validateInput(__METHOD__, $input); + } + /** + * Closes the write buffer. + * + * @return void + */ + public function close() + { + $this->open = \false; + } + /** + * Tells whether the write buffer is closed or not. + * + * @return bool + */ + public function isClosed() + { + return !$this->open; + } + public function getIterator() : \Traversable + { + $this->open = \true; + while ($this->open || $this->input) { + if (!$this->input) { + (yield ''); + continue; + } + $current = \array_shift($this->input); + if ($current instanceof \Iterator) { + yield from $current; + } else { + (yield $current); + } + if (!$this->input && $this->open && null !== ($onEmpty = $this->onEmpty)) { + $this->write($onEmpty($this)); + } + } + } +} diff --git a/vendor/symfony/process/LICENSE b/vendor/symfony/process/LICENSE new file mode 100644 index 0000000000..0138f8f071 --- /dev/null +++ b/vendor/symfony/process/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-present Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/process/Messenger/RunProcessContext.php b/vendor/symfony/process/Messenger/RunProcessContext.php new file mode 100644 index 0000000000..7c84368945 --- /dev/null +++ b/vendor/symfony/process/Messenger/RunProcessContext.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Process\Messenger; + +use SwissKnife202405\Symfony\Component\Process\Process; +/** + * @author Kevin Bond + */ +final class RunProcessContext +{ + /** + * @readonly + * @var \Symfony\Component\Process\Messenger\RunProcessMessage + */ + public $message; + /** + * @readonly + * @var int|null + */ + public $exitCode; + /** + * @readonly + * @var string|null + */ + public $output; + /** + * @readonly + * @var string|null + */ + public $errorOutput; + public function __construct(RunProcessMessage $message, Process $process) + { + $this->message = $message; + $this->exitCode = $process->getExitCode(); + $this->output = $process->isOutputDisabled() ? null : $process->getOutput(); + $this->errorOutput = $process->isOutputDisabled() ? null : $process->getErrorOutput(); + } +} diff --git a/vendor/symfony/process/Messenger/RunProcessMessage.php b/vendor/symfony/process/Messenger/RunProcessMessage.php new file mode 100644 index 0000000000..ef5c4a37b0 --- /dev/null +++ b/vendor/symfony/process/Messenger/RunProcessMessage.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Process\Messenger; + +/** + * @author Kevin Bond + */ +class RunProcessMessage +{ + /** + * @readonly + * @var mixed[] + */ + public $command; + /** + * @readonly + * @var string|null + */ + public $cwd; + /** + * @readonly + * @var mixed[]|null + */ + public $env; + /** + * @readonly + * @var mixed + */ + public $input = null; + /** + * @readonly + * @var float|null + */ + public $timeout = 60.0; + /** + * @param mixed $input + */ + public function __construct(array $command, ?string $cwd = null, ?array $env = null, $input = null, ?float $timeout = 60.0) + { + $this->command = $command; + $this->cwd = $cwd; + $this->env = $env; + $this->input = $input; + $this->timeout = $timeout; + } + public function __toString() : string + { + return \implode(' ', $this->command); + } +} diff --git a/vendor/symfony/process/Messenger/RunProcessMessageHandler.php b/vendor/symfony/process/Messenger/RunProcessMessageHandler.php new file mode 100644 index 0000000000..4400baf723 --- /dev/null +++ b/vendor/symfony/process/Messenger/RunProcessMessageHandler.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Process\Messenger; + +use SwissKnife202405\Symfony\Component\Process\Exception\ProcessFailedException; +use SwissKnife202405\Symfony\Component\Process\Exception\RunProcessFailedException; +use SwissKnife202405\Symfony\Component\Process\Process; +/** + * @author Kevin Bond + */ +final class RunProcessMessageHandler +{ + public function __invoke(RunProcessMessage $message) : RunProcessContext + { + $process = new Process($message->command, $message->cwd, $message->env, $message->input, $message->timeout); + try { + return new RunProcessContext($message, $process->mustRun()); + } catch (ProcessFailedException $e) { + throw new RunProcessFailedException($e, new RunProcessContext($message, $e->getProcess())); + } + } +} diff --git a/vendor/symfony/process/PhpExecutableFinder.php b/vendor/symfony/process/PhpExecutableFinder.php new file mode 100644 index 0000000000..8743c2aed1 --- /dev/null +++ b/vendor/symfony/process/PhpExecutableFinder.php @@ -0,0 +1,88 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Process; + +/** + * An executable finder specifically designed for the PHP executable. + * + * @author Fabien Potencier + * @author Johannes M. Schmitt + */ +class PhpExecutableFinder +{ + /** + * @var \Symfony\Component\Process\ExecutableFinder + */ + private $executableFinder; + public function __construct() + { + $this->executableFinder = new ExecutableFinder(); + } + /** + * Finds The PHP executable. + * @return string|false + */ + public function find(bool $includeArgs = \true) + { + if ($php = \getenv('PHP_BINARY')) { + if (!\is_executable($php)) { + $command = '\\' === \DIRECTORY_SEPARATOR ? 'where' : 'command -v --'; + if (\function_exists('exec') && ($php = \strtok(\exec($command . ' ' . \escapeshellarg($php)), \PHP_EOL))) { + if (!\is_executable($php)) { + return \false; + } + } else { + return \false; + } + } + if (@\is_dir($php)) { + return \false; + } + return $php; + } + $args = $this->findArguments(); + $args = $includeArgs && $args ? ' ' . \implode(' ', $args) : ''; + // PHP_BINARY return the current sapi executable + if (\PHP_BINARY && \in_array(\PHP_SAPI, ['cli', 'cli-server', 'phpdbg'], \true)) { + return \PHP_BINARY . $args; + } + if ($php = \getenv('PHP_PATH')) { + if (!@\is_executable($php) || @\is_dir($php)) { + return \false; + } + return $php; + } + if ($php = \getenv('PHP_PEAR_PHP_BIN')) { + if (@\is_executable($php) && !@\is_dir($php)) { + return $php; + } + } + if (@\is_executable($php = \PHP_BINDIR . ('\\' === \DIRECTORY_SEPARATOR ? '\\php.exe' : '/php')) && !@\is_dir($php)) { + return $php; + } + $dirs = [\PHP_BINDIR]; + if ('\\' === \DIRECTORY_SEPARATOR) { + $dirs[] = 'C:\\xampp\\php\\'; + } + return $this->executableFinder->find('php', \false, $dirs); + } + /** + * Finds the PHP executable arguments. + */ + public function findArguments() : array + { + $arguments = []; + if ('phpdbg' === \PHP_SAPI) { + $arguments[] = '-qrr'; + } + return $arguments; + } +} diff --git a/vendor/symfony/process/PhpProcess.php b/vendor/symfony/process/PhpProcess.php new file mode 100644 index 0000000000..cbc49eed35 --- /dev/null +++ b/vendor/symfony/process/PhpProcess.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Process; + +use SwissKnife202405\Symfony\Component\Process\Exception\LogicException; +use SwissKnife202405\Symfony\Component\Process\Exception\RuntimeException; +/** + * PhpProcess runs a PHP script in an independent process. + * + * $p = new PhpProcess(''); + * $p->run(); + * print $p->getOutput()."\n"; + * + * @author Fabien Potencier + */ +class PhpProcess extends Process +{ + /** + * @param string $script The PHP script to run (as a string) + * @param string|null $cwd The working directory or null to use the working dir of the current PHP process + * @param array|null $env The environment variables or null to use the same environment as the current PHP process + * @param int $timeout The timeout in seconds + * @param array|null $php Path to the PHP binary to use with any additional arguments + */ + public function __construct(string $script, ?string $cwd = null, ?array $env = null, int $timeout = 60, ?array $php = null) + { + if (null === $php) { + $executableFinder = new PhpExecutableFinder(); + $php = $executableFinder->find(\false); + $php = \false === $php ? null : \array_merge([$php], $executableFinder->findArguments()); + } + if ('phpdbg' === \PHP_SAPI) { + $file = \tempnam(\sys_get_temp_dir(), 'dbg'); + \file_put_contents($file, $script); + \register_shutdown_function('unlink', $file); + $php[] = $file; + $script = null; + } + parent::__construct($php, $cwd, $env, $script, $timeout); + } + /** + * @param mixed $input + * @return static + */ + public static function fromShellCommandline(string $command, ?string $cwd = null, ?array $env = null, $input = null, ?float $timeout = 60) + { + throw new LogicException(\sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class)); + } + /** + * @return void + */ + public function start(?callable $callback = null, array $env = []) + { + if (null === $this->getCommandLine()) { + throw new RuntimeException('Unable to find the PHP executable.'); + } + parent::start($callback, $env); + } +} diff --git a/vendor/symfony/process/PhpSubprocess.php b/vendor/symfony/process/PhpSubprocess.php new file mode 100644 index 0000000000..2f312ef0aa --- /dev/null +++ b/vendor/symfony/process/PhpSubprocess.php @@ -0,0 +1,140 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Process; + +use SwissKnife202405\Symfony\Component\Process\Exception\LogicException; +use SwissKnife202405\Symfony\Component\Process\Exception\RuntimeException; +/** + * PhpSubprocess runs a PHP command as a subprocess while keeping the original php.ini settings. + * + * For this, it generates a temporary php.ini file taking over all the current settings and disables + * loading additional .ini files. Basically, your command gets prefixed using "php -n -c /tmp/temp.ini". + * + * Given your php.ini contains "memory_limit=-1" and you have a "MemoryTest.php" with the following content: + * + * run(); + * print $p->getOutput()."\n"; + * + * This will output "string(2) "-1", because the process is started with the default php.ini settings. + * + * $p = new PhpSubprocess(['MemoryTest.php'], null, null, 60, ['php', '-d', 'memory_limit=256M']); + * $p->run(); + * print $p->getOutput()."\n"; + * + * This will output "string(4) "256M"", because the process is started with the temporarily created php.ini settings. + * + * @author Yanick Witschi + * @author Partially copied and heavily inspired from composer/xdebug-handler by John Stevenson + */ +class PhpSubprocess extends Process +{ + /** + * @param array $command The command to run and its arguments listed as separate entries. They will automatically + * get prefixed with the PHP binary + * @param string|null $cwd The working directory or null to use the working dir of the current PHP process + * @param array|null $env The environment variables or null to use the same environment as the current PHP process + * @param int $timeout The timeout in seconds + * @param array|null $php Path to the PHP binary to use with any additional arguments + */ + public function __construct(array $command, ?string $cwd = null, ?array $env = null, int $timeout = 60, ?array $php = null) + { + if (null === $php) { + $executableFinder = new PhpExecutableFinder(); + $php = $executableFinder->find(\false); + $php = \false === $php ? null : \array_merge([$php], $executableFinder->findArguments()); + } + if (null === $php) { + throw new RuntimeException('Unable to find PHP binary.'); + } + $tmpIni = $this->writeTmpIni($this->getAllIniFiles(), \sys_get_temp_dir()); + $php = \array_merge($php, ['-n', '-c', $tmpIni]); + \register_shutdown_function('unlink', $tmpIni); + $command = \array_merge($php, $command); + parent::__construct($command, $cwd, $env, null, $timeout); + } + /** + * @param mixed $input + * @return static + */ + public static function fromShellCommandline(string $command, ?string $cwd = null, ?array $env = null, $input = null, ?float $timeout = 60) + { + throw new LogicException(\sprintf('The "%s()" method cannot be called when using "%s".', __METHOD__, self::class)); + } + public function start(?callable $callback = null, array $env = []) : void + { + if (null === $this->getCommandLine()) { + throw new RuntimeException('Unable to find the PHP executable.'); + } + parent::start($callback, $env); + } + private function writeTmpIni(array $iniFiles, string $tmpDir) : string + { + if (\false === ($tmpfile = @\tempnam($tmpDir, ''))) { + throw new RuntimeException('Unable to create temporary ini file.'); + } + // $iniFiles has at least one item and it may be empty + if ('' === $iniFiles[0]) { + \array_shift($iniFiles); + } + $content = ''; + foreach ($iniFiles as $file) { + // Check for inaccessible ini files + if (($data = @\file_get_contents($file)) === \false) { + throw new RuntimeException('Unable to read ini: ' . $file); + } + // Check and remove directives after HOST and PATH sections + if (\preg_match('/^\\s*\\[(?:PATH|HOST)\\s*=/mi', $data, $matches)) { + $data = \substr($data, 0, $matches[0][1]); + } + $content .= $data . "\n"; + } + // Merge loaded settings into our ini content, if it is valid + $config = \parse_ini_string($content); + $loaded = \ini_get_all(null, \false); + if (\false === $config || \false === $loaded) { + throw new RuntimeException('Unable to parse ini data.'); + } + $content .= $this->mergeLoadedConfig($loaded, $config); + // Work-around for https://bugs.php.net/bug.php?id=75932 + $content .= "opcache.enable_cli=0\n"; + if (\false === @\file_put_contents($tmpfile, $content)) { + throw new RuntimeException('Unable to write temporary ini file.'); + } + return $tmpfile; + } + private function mergeLoadedConfig(array $loadedConfig, array $iniConfig) : string + { + $content = ''; + foreach ($loadedConfig as $name => $value) { + if (!\is_string($value)) { + continue; + } + if (!isset($iniConfig[$name]) || $iniConfig[$name] !== $value) { + // Double-quote escape each value + $content .= $name . '="' . \addcslashes($value, '\\"') . "\"\n"; + } + } + return $content; + } + private function getAllIniFiles() : array + { + $paths = [(string) \php_ini_loaded_file()]; + if (\false !== ($scanned = \php_ini_scanned_files())) { + $paths = \array_merge($paths, \array_map('trim', \explode(',', $scanned))); + } + return $paths; + } +} diff --git a/vendor/symfony/process/Pipes/AbstractPipes.php b/vendor/symfony/process/Pipes/AbstractPipes.php new file mode 100644 index 0000000000..34c0fd1bc9 --- /dev/null +++ b/vendor/symfony/process/Pipes/AbstractPipes.php @@ -0,0 +1,168 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Process\Pipes; + +use SwissKnife202405\Symfony\Component\Process\Exception\InvalidArgumentException; +/** + * @author Romain Neutron + * + * @internal + */ +abstract class AbstractPipes implements PipesInterface +{ + /** + * @var mixed[] + */ + public $pipes = []; + /** + * @var string + */ + private $inputBuffer = ''; + /** @var resource|string|\Iterator */ + private $input; + /** + * @var bool + */ + private $blocked = \true; + /** + * @var string|null + */ + private $lastError; + /** + * @param resource|string|\Iterator $input + */ + public function __construct($input) + { + if (\is_resource($input) || $input instanceof \Iterator) { + $this->input = $input; + } else { + $this->inputBuffer = (string) $input; + } + } + public function close() : void + { + foreach ($this->pipes as $pipe) { + if (\is_resource($pipe)) { + \fclose($pipe); + } + } + $this->pipes = []; + } + /** + * Returns true if a system call has been interrupted. + */ + protected function hasSystemCallBeenInterrupted() : bool + { + $lastError = $this->lastError; + $this->lastError = null; + // stream_select returns false when the `select` system call is interrupted by an incoming signal + return null !== $lastError && \false !== \stripos($lastError, 'interrupted system call'); + } + /** + * Unblocks streams. + */ + protected function unblock() : void + { + if (!$this->blocked) { + return; + } + foreach ($this->pipes as $pipe) { + \stream_set_blocking($pipe, 0); + } + if (\is_resource($this->input)) { + \stream_set_blocking($this->input, 0); + } + $this->blocked = \false; + } + /** + * Writes input to stdin. + * + * @throws InvalidArgumentException When an input iterator yields a non supported value + */ + protected function write() : ?array + { + if (!isset($this->pipes[0])) { + return null; + } + $input = $this->input; + if ($input instanceof \Iterator) { + if (!$input->valid()) { + $input = null; + } elseif (\is_resource($input = $input->current())) { + \stream_set_blocking($input, 0); + } elseif (!isset($this->inputBuffer[0])) { + if (!\is_string($input)) { + if (!\is_scalar($input)) { + throw new InvalidArgumentException(\sprintf('"%s" yielded a value of type "%s", but only scalars and stream resources are supported.', \get_debug_type($this->input), \get_debug_type($input))); + } + $input = (string) $input; + } + $this->inputBuffer = $input; + $this->input->next(); + $input = null; + } else { + $input = null; + } + } + $r = $e = []; + $w = [$this->pipes[0]]; + // let's have a look if something changed in streams + if (\false === @\stream_select($r, $w, $e, 0, 0)) { + return null; + } + foreach ($w as $stdin) { + if (isset($this->inputBuffer[0])) { + $written = \fwrite($stdin, $this->inputBuffer); + $this->inputBuffer = \substr($this->inputBuffer, $written); + if (isset($this->inputBuffer[0])) { + return [$this->pipes[0]]; + } + } + if ($input) { + while (\true) { + $data = \fread($input, self::CHUNK_SIZE); + if (!isset($data[0])) { + break; + } + $written = \fwrite($stdin, $data); + $data = \substr($data, $written); + if (isset($data[0])) { + $this->inputBuffer = $data; + return [$this->pipes[0]]; + } + } + if (\feof($input)) { + if ($this->input instanceof \Iterator) { + $this->input->next(); + } else { + $this->input = null; + } + } + } + } + // no input to read on resource, buffer is empty + if (!isset($this->inputBuffer[0]) && !($this->input instanceof \Iterator ? $this->input->valid() : $this->input)) { + $this->input = null; + \fclose($this->pipes[0]); + unset($this->pipes[0]); + } elseif (!$w) { + return [$this->pipes[0]]; + } + return null; + } + /** + * @internal + */ + public function handleError(int $type, string $msg) : void + { + $this->lastError = $msg; + } +} diff --git a/vendor/symfony/process/Pipes/PipesInterface.php b/vendor/symfony/process/Pipes/PipesInterface.php new file mode 100644 index 0000000000..b7f2b2b9ac --- /dev/null +++ b/vendor/symfony/process/Pipes/PipesInterface.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Process\Pipes; + +/** + * PipesInterface manages descriptors and pipes for the use of proc_open. + * + * @author Romain Neutron + * + * @internal + */ +interface PipesInterface +{ + public const CHUNK_SIZE = 16384; + /** + * Returns an array of descriptors for the use of proc_open. + */ + public function getDescriptors() : array; + /** + * Returns an array of filenames indexed by their related stream in case these pipes use temporary files. + * + * @return string[] + */ + public function getFiles() : array; + /** + * Reads data in file handles and pipes. + * + * @param bool $blocking Whether to use blocking calls or not + * @param bool $close Whether to close pipes if they've reached EOF + * + * @return string[] An array of read data indexed by their fd + */ + public function readAndWrite(bool $blocking, bool $close = \false) : array; + /** + * Returns if the current state has open file handles or pipes. + */ + public function areOpen() : bool; + /** + * Returns if pipes are able to read output. + */ + public function haveReadSupport() : bool; + /** + * Closes file handles and pipes. + */ + public function close() : void; +} diff --git a/vendor/symfony/process/Pipes/UnixPipes.php b/vendor/symfony/process/Pipes/UnixPipes.php new file mode 100644 index 0000000000..2e9cd33136 --- /dev/null +++ b/vendor/symfony/process/Pipes/UnixPipes.php @@ -0,0 +1,125 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Process\Pipes; + +use SwissKnife202405\Symfony\Component\Process\Process; +/** + * UnixPipes implementation uses unix pipes as handles. + * + * @author Romain Neutron + * + * @internal + */ +class UnixPipes extends AbstractPipes +{ + /** + * @var bool|null + */ + private $ttyMode; + /** + * @var bool + */ + private $ptyMode; + /** + * @var bool + */ + private $haveReadSupport; + /** + * @param mixed $input + */ + public function __construct(?bool $ttyMode, bool $ptyMode, $input, bool $haveReadSupport) + { + $this->ttyMode = $ttyMode; + $this->ptyMode = $ptyMode; + $this->haveReadSupport = $haveReadSupport; + parent::__construct($input); + } + public function __sleep() : array + { + throw new \BadMethodCallException('Cannot serialize ' . __CLASS__); + } + public function __wakeup() : void + { + throw new \BadMethodCallException('Cannot unserialize ' . __CLASS__); + } + public function __destruct() + { + $this->close(); + } + public function getDescriptors() : array + { + if (!$this->haveReadSupport) { + $nullstream = \fopen('/dev/null', 'c'); + return [['pipe', 'r'], $nullstream, $nullstream]; + } + if ($this->ttyMode) { + return [['file', '/dev/tty', 'r'], ['file', '/dev/tty', 'w'], ['file', '/dev/tty', 'w']]; + } + if ($this->ptyMode && Process::isPtySupported()) { + return [['pty'], ['pty'], ['pty']]; + } + return [ + ['pipe', 'r'], + ['pipe', 'w'], + // stdout + ['pipe', 'w'], + ]; + } + public function getFiles() : array + { + return []; + } + public function readAndWrite(bool $blocking, bool $close = \false) : array + { + $this->unblock(); + $w = $this->write(); + $read = $e = []; + $r = $this->pipes; + unset($r[0]); + // let's have a look if something changed in streams + \set_error_handler(\Closure::fromCallable([$this, 'handleError'])); + if (($r || $w) && \false === \stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1000000.0 : 0)) { + \restore_error_handler(); + // if a system call has been interrupted, forget about it, let's try again + // otherwise, an error occurred, let's reset pipes + if (!$this->hasSystemCallBeenInterrupted()) { + $this->pipes = []; + } + return $read; + } + \restore_error_handler(); + foreach ($r as $pipe) { + // prior PHP 5.4 the array passed to stream_select is modified and + // lose key association, we have to find back the key + $read[$type = \array_search($pipe, $this->pipes, \true)] = ''; + do { + $data = @\fread($pipe, self::CHUNK_SIZE); + $read[$type] .= $data; + } while (isset($data[0]) && ($close || isset($data[self::CHUNK_SIZE - 1]))); + if (!isset($read[$type][0])) { + unset($read[$type]); + } + if ($close && \feof($pipe)) { + \fclose($pipe); + unset($this->pipes[$type]); + } + } + return $read; + } + public function haveReadSupport() : bool + { + return $this->haveReadSupport; + } + public function areOpen() : bool + { + return (bool) $this->pipes; + } +} diff --git a/vendor/symfony/process/Pipes/WindowsPipes.php b/vendor/symfony/process/Pipes/WindowsPipes.php new file mode 100644 index 0000000000..5eaf9a6fe2 --- /dev/null +++ b/vendor/symfony/process/Pipes/WindowsPipes.php @@ -0,0 +1,171 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Process\Pipes; + +use SwissKnife202405\Symfony\Component\Process\Exception\RuntimeException; +use SwissKnife202405\Symfony\Component\Process\Process; +/** + * WindowsPipes implementation uses temporary files as handles. + * + * @see https://bugs.php.net/51800 + * @see https://bugs.php.net/65650 + * + * @author Romain Neutron + * + * @internal + */ +class WindowsPipes extends AbstractPipes +{ + /** + * @var mixed[] + */ + private $files = []; + /** + * @var mixed[] + */ + private $fileHandles = []; + /** + * @var mixed[] + */ + private $lockHandles = []; + /** + * @var mixed[] + */ + private $readBytes = [Process::STDOUT => 0, Process::STDERR => 0]; + /** + * @var bool + */ + private $haveReadSupport; + /** + * @param mixed $input + */ + public function __construct($input, bool $haveReadSupport) + { + $this->haveReadSupport = $haveReadSupport; + if ($this->haveReadSupport) { + // Fix for PHP bug #51800: reading from STDOUT pipe hangs forever on Windows if the output is too big. + // Workaround for this problem is to use temporary files instead of pipes on Windows platform. + // + // @see https://bugs.php.net/51800 + $pipes = [Process::STDOUT => Process::OUT, Process::STDERR => Process::ERR]; + $tmpDir = \sys_get_temp_dir(); + $lastError = 'unknown reason'; + \set_error_handler(function ($type, $msg) use(&$lastError) { + $lastError = $msg; + }); + for ($i = 0;; ++$i) { + foreach ($pipes as $pipe => $name) { + $file = \sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name); + if (!($h = \fopen($file . '.lock', 'w'))) { + if (\file_exists($file . '.lock')) { + continue 2; + } + \restore_error_handler(); + throw new RuntimeException('A temporary file could not be opened to write the process output: ' . $lastError); + } + if (!\flock($h, \LOCK_EX | \LOCK_NB)) { + continue 2; + } + if (isset($this->lockHandles[$pipe])) { + \flock($this->lockHandles[$pipe], \LOCK_UN); + \fclose($this->lockHandles[$pipe]); + } + $this->lockHandles[$pipe] = $h; + if (!($h = \fopen($file, 'w')) || !\fclose($h) || !($h = \fopen($file, 'r'))) { + \flock($this->lockHandles[$pipe], \LOCK_UN); + \fclose($this->lockHandles[$pipe]); + unset($this->lockHandles[$pipe]); + continue 2; + } + $this->fileHandles[$pipe] = $h; + $this->files[$pipe] = $file; + } + break; + } + \restore_error_handler(); + } + parent::__construct($input); + } + public function __sleep() : array + { + throw new \BadMethodCallException('Cannot serialize ' . __CLASS__); + } + public function __wakeup() : void + { + throw new \BadMethodCallException('Cannot unserialize ' . __CLASS__); + } + public function __destruct() + { + $this->close(); + } + public function getDescriptors() : array + { + if (!$this->haveReadSupport) { + $nullstream = \fopen('NUL', 'c'); + return [['pipe', 'r'], $nullstream, $nullstream]; + } + // We're not using pipe on Windows platform as it hangs (https://bugs.php.net/51800) + // We're not using file handles as it can produce corrupted output https://bugs.php.net/65650 + // So we redirect output within the commandline and pass the nul device to the process + return [['pipe', 'r'], ['file', 'NUL', 'w'], ['file', 'NUL', 'w']]; + } + public function getFiles() : array + { + return $this->files; + } + public function readAndWrite(bool $blocking, bool $close = \false) : array + { + $this->unblock(); + $w = $this->write(); + $read = $r = $e = []; + if ($blocking) { + if ($w) { + @\stream_select($r, $w, $e, 0, Process::TIMEOUT_PRECISION * 1000000.0); + } elseif ($this->fileHandles) { + \usleep((int) (Process::TIMEOUT_PRECISION * 1000000.0)); + } + } + foreach ($this->fileHandles as $type => $fileHandle) { + $data = \stream_get_contents($fileHandle, -1, $this->readBytes[$type]); + if (isset($data[0])) { + $this->readBytes[$type] += \strlen($data); + $read[$type] = $data; + } + if ($close) { + \ftruncate($fileHandle, 0); + \fclose($fileHandle); + \flock($this->lockHandles[$type], \LOCK_UN); + \fclose($this->lockHandles[$type]); + unset($this->fileHandles[$type], $this->lockHandles[$type]); + } + } + return $read; + } + public function haveReadSupport() : bool + { + return $this->haveReadSupport; + } + public function areOpen() : bool + { + return $this->pipes && $this->fileHandles; + } + public function close() : void + { + parent::close(); + foreach ($this->fileHandles as $type => $handle) { + \ftruncate($handle, 0); + \fclose($handle); + \flock($this->lockHandles[$type], \LOCK_UN); + \fclose($this->lockHandles[$type]); + } + $this->fileHandles = $this->lockHandles = []; + } +} diff --git a/vendor/symfony/process/Process.php b/vendor/symfony/process/Process.php new file mode 100644 index 0000000000..21eb24e269 --- /dev/null +++ b/vendor/symfony/process/Process.php @@ -0,0 +1,1459 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Process; + +use SwissKnife202405\Symfony\Component\Process\Exception\InvalidArgumentException; +use SwissKnife202405\Symfony\Component\Process\Exception\LogicException; +use SwissKnife202405\Symfony\Component\Process\Exception\ProcessFailedException; +use SwissKnife202405\Symfony\Component\Process\Exception\ProcessSignaledException; +use SwissKnife202405\Symfony\Component\Process\Exception\ProcessTimedOutException; +use SwissKnife202405\Symfony\Component\Process\Exception\RuntimeException; +use SwissKnife202405\Symfony\Component\Process\Pipes\UnixPipes; +use SwissKnife202405\Symfony\Component\Process\Pipes\WindowsPipes; +/** + * Process is a thin wrapper around proc_* functions to easily + * start independent PHP processes. + * + * @author Fabien Potencier + * @author Romain Neutron + * + * @implements \IteratorAggregate + */ +class Process implements \IteratorAggregate +{ + public const ERR = 'err'; + public const OUT = 'out'; + public const STATUS_READY = 'ready'; + public const STATUS_STARTED = 'started'; + public const STATUS_TERMINATED = 'terminated'; + public const STDIN = 0; + public const STDOUT = 1; + public const STDERR = 2; + // Timeout Precision in seconds. + public const TIMEOUT_PRECISION = 0.2; + public const ITER_NON_BLOCKING = 1; + // By default, iterating over outputs is a blocking call, use this flag to make it non-blocking + public const ITER_KEEP_OUTPUT = 2; + // By default, outputs are cleared while iterating, use this flag to keep them in memory + public const ITER_SKIP_OUT = 4; + // Use this flag to skip STDOUT while iterating + public const ITER_SKIP_ERR = 8; + // Use this flag to skip STDERR while iterating + /** + * @var \Closure|null + */ + private $callback; + /** + * @var mixed[]|string + */ + private $commandline; + /** + * @var string|null + */ + private $cwd; + /** + * @var mixed[] + */ + private $env = []; + /** @var resource|string|\Iterator|null */ + private $input; + /** + * @var float|null + */ + private $starttime; + /** + * @var float|null + */ + private $lastOutputTime; + /** + * @var float|null + */ + private $timeout; + /** + * @var float|null + */ + private $idleTimeout; + /** + * @var int|null + */ + private $exitcode; + /** + * @var mixed[] + */ + private $fallbackStatus = []; + /** + * @var mixed[] + */ + private $processInformation; + /** + * @var bool + */ + private $outputDisabled = \false; + /** @var resource */ + private $stdout; + /** @var resource */ + private $stderr; + /** @var resource|null */ + private $process; + /** + * @var string + */ + private $status = self::STATUS_READY; + /** + * @var int + */ + private $incrementalOutputOffset = 0; + /** + * @var int + */ + private $incrementalErrorOutputOffset = 0; + /** + * @var bool + */ + private $tty = \false; + /** + * @var bool + */ + private $pty; + /** + * @var mixed[] + */ + private $options = ['suppress_errors' => \true, 'bypass_shell' => \true]; + /** + * @var \Symfony\Component\Process\Pipes\WindowsPipes|\Symfony\Component\Process\Pipes\UnixPipes + */ + private $processPipes; + /** + * @var int|null + */ + private $latestSignal; + /** + * @var int|null + */ + private $cachedExitCode; + /** + * @var bool|null + */ + private static $sigchild; + /** + * Exit codes translation table. + * + * User-defined errors must use exit codes in the 64-113 range. + */ + public static $exitCodes = [ + 0 => 'OK', + 1 => 'General error', + 2 => 'Misuse of shell builtins', + 126 => 'Invoked command cannot execute', + 127 => 'Command not found', + 128 => 'Invalid exit argument', + // signals + 129 => 'Hangup', + 130 => 'Interrupt', + 131 => 'Quit and dump core', + 132 => 'Illegal instruction', + 133 => 'Trace/breakpoint trap', + 134 => 'Process aborted', + 135 => 'Bus error: "access to undefined portion of memory object"', + 136 => 'Floating point exception: "erroneous arithmetic operation"', + 137 => 'Kill (terminate immediately)', + 138 => 'User-defined 1', + 139 => 'Segmentation violation', + 140 => 'User-defined 2', + 141 => 'Write to pipe with no one reading', + 142 => 'Signal raised by alarm', + 143 => 'Termination (request to terminate)', + // 144 - not defined + 145 => 'Child process terminated, stopped (or continued*)', + 146 => 'Continue if stopped', + 147 => 'Stop executing temporarily', + 148 => 'Terminal stop signal', + 149 => 'Background process attempting to read from tty ("in")', + 150 => 'Background process attempting to write to tty ("out")', + 151 => 'Urgent data available on socket', + 152 => 'CPU time limit exceeded', + 153 => 'File size limit exceeded', + 154 => 'Signal raised by timer counting virtual time: "virtual timer expired"', + 155 => 'Profiling timer expired', + // 156 - not defined + 157 => 'Pollable event', + // 158 - not defined + 159 => 'Bad syscall', + ]; + /** + * @param array $command The command to run and its arguments listed as separate entries + * @param string|null $cwd The working directory or null to use the working dir of the current PHP process + * @param array|null $env The environment variables or null to use the same environment as the current PHP process + * @param mixed $input The input as stream resource, scalar or \Traversable, or null for no input + * @param int|float|null $timeout The timeout in seconds or null to disable + * + * @throws LogicException When proc_open is not installed + */ + public function __construct(array $command, ?string $cwd = null, ?array $env = null, $input = null, ?float $timeout = 60) + { + if (!\function_exists('proc_open')) { + throw new LogicException('The Process class relies on proc_open, which is not available on your PHP installation.'); + } + $this->commandline = $command; + $this->cwd = $cwd; + // on Windows, if the cwd changed via chdir(), proc_open defaults to the dir where PHP was started + // on Gnu/Linux, PHP builds with --enable-maintainer-zts are also affected + // @see : https://bugs.php.net/51800 + // @see : https://bugs.php.net/50524 + if (null === $this->cwd && (\defined('ZEND_THREAD_SAFE') || '\\' === \DIRECTORY_SEPARATOR)) { + $this->cwd = \getcwd(); + } + if (null !== $env) { + $this->setEnv($env); + } + $this->setInput($input); + $this->setTimeout($timeout); + $this->pty = \false; + } + /** + * Creates a Process instance as a command-line to be run in a shell wrapper. + * + * Command-lines are parsed by the shell of your OS (/bin/sh on Unix-like, cmd.exe on Windows.) + * This allows using e.g. pipes or conditional execution. In this mode, signals are sent to the + * shell wrapper and not to your commands. + * + * In order to inject dynamic values into command-lines, we strongly recommend using placeholders. + * This will save escaping values, which is not portable nor secure anyway: + * + * $process = Process::fromShellCommandline('my_command "${:MY_VAR}"'); + * $process->run(null, ['MY_VAR' => $theValue]); + * + * @param string $command The command line to pass to the shell of the OS + * @param string|null $cwd The working directory or null to use the working dir of the current PHP process + * @param array|null $env The environment variables or null to use the same environment as the current PHP process + * @param mixed $input The input as stream resource, scalar or \Traversable, or null for no input + * @param int|float|null $timeout The timeout in seconds or null to disable + * + * @throws LogicException When proc_open is not installed + * @return static + */ + public static function fromShellCommandline(string $command, ?string $cwd = null, ?array $env = null, $input = null, ?float $timeout = 60) + { + $process = new static([], $cwd, $env, $input, $timeout); + $process->commandline = $command; + return $process; + } + public function __sleep() : array + { + throw new \BadMethodCallException('Cannot serialize ' . __CLASS__); + } + /** + * @return void + */ + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize ' . __CLASS__); + } + public function __destruct() + { + if ($this->options['create_new_console'] ?? \false) { + $this->processPipes->close(); + } else { + $this->stop(0); + } + } + public function __clone() + { + $this->resetProcessData(); + } + /** + * Runs the process. + * + * The callback receives the type of output (out or err) and + * some bytes from the output in real-time. It allows to have feedback + * from the independent process during execution. + * + * The STDOUT and STDERR are also available after the process is finished + * via the getOutput() and getErrorOutput() methods. + * + * @param callable|null $callback A PHP callback to run whenever there is some + * output available on STDOUT or STDERR + * + * @return int The exit status code + * + * @throws RuntimeException When process can't be launched + * @throws RuntimeException When process is already running + * @throws ProcessTimedOutException When process timed out + * @throws ProcessSignaledException When process stopped after receiving signal + * @throws LogicException In case a callback is provided and output has been disabled + * + * @final + */ + public function run(?callable $callback = null, array $env = []) : int + { + $this->start($callback, $env); + return $this->wait(); + } + /** + * Runs the process. + * + * This is identical to run() except that an exception is thrown if the process + * exits with a non-zero exit code. + * + * @return $this + * + * @throws ProcessFailedException if the process didn't terminate successfully + * + * @final + */ + public function mustRun(?callable $callback = null, array $env = []) + { + if (0 !== $this->run($callback, $env)) { + throw new ProcessFailedException($this); + } + return $this; + } + /** + * Starts the process and returns after writing the input to STDIN. + * + * This method blocks until all STDIN data is sent to the process then it + * returns while the process runs in the background. + * + * The termination of the process can be awaited with wait(). + * + * The callback receives the type of output (out or err) and some bytes from + * the output in real-time while writing the standard input to the process. + * It allows to have feedback from the independent process during execution. + * + * @param callable|null $callback A PHP callback to run whenever there is some + * output available on STDOUT or STDERR + * + * @return void + * + * @throws RuntimeException When process can't be launched + * @throws RuntimeException When process is already running + * @throws LogicException In case a callback is provided and output has been disabled + */ + public function start(?callable $callback = null, array $env = []) + { + if ($this->isRunning()) { + throw new RuntimeException('Process is already running.'); + } + $this->resetProcessData(); + $this->starttime = $this->lastOutputTime = \microtime(\true); + $this->callback = $this->buildCallback($callback); + $descriptors = $this->getDescriptors(null !== $callback); + if ($this->env) { + $env += '\\' === \DIRECTORY_SEPARATOR ? \array_diff_ukey($this->env, $env, 'strcasecmp') : $this->env; + } + $env += '\\' === \DIRECTORY_SEPARATOR ? \array_diff_ukey($this->getDefaultEnv(), $env, 'strcasecmp') : $this->getDefaultEnv(); + if (\is_array($commandline = $this->commandline)) { + $commandline = \implode(' ', \array_map(\Closure::fromCallable([$this, 'escapeArgument']), $commandline)); + if ('\\' !== \DIRECTORY_SEPARATOR) { + // exec is mandatory to deal with sending a signal to the process + $commandline = 'exec ' . $commandline; + } + } else { + $commandline = $this->replacePlaceholders($commandline, $env); + } + if ('\\' === \DIRECTORY_SEPARATOR) { + $commandline = $this->prepareWindowsCommandLine($commandline, $env); + } elseif ($this->isSigchildEnabled()) { + // last exit code is output on the fourth pipe and caught to work around --enable-sigchild + $descriptors[3] = ['pipe', 'w']; + // See https://unix.stackexchange.com/questions/71205/background-process-pipe-input + $commandline = '{ (' . $commandline . ') <&3 3<&- 3>/dev/null & } 3<&0;'; + $commandline .= 'pid=$!; echo $pid >&3; wait $pid 2>/dev/null; code=$?; echo $code >&3; exit $code'; + } + $envPairs = []; + foreach ($env as $k => $v) { + if (\false !== $v && \false === \in_array($k, ['argc', 'argv', 'ARGC', 'ARGV'], \true)) { + $envPairs[] = $k . '=' . $v; + } + } + if (!\is_dir($this->cwd)) { + throw new RuntimeException(\sprintf('The provided cwd "%s" does not exist.', $this->cwd)); + } + $process = @\proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $this->options); + if (!\is_resource($process)) { + throw new RuntimeException('Unable to launch a new process.'); + } + $this->process = $process; + $this->status = self::STATUS_STARTED; + if (isset($descriptors[3])) { + $this->fallbackStatus['pid'] = (int) \fgets($this->processPipes->pipes[3]); + } + if ($this->tty) { + return; + } + $this->updateStatus(\false); + $this->checkTimeout(); + } + /** + * Restarts the process. + * + * Be warned that the process is cloned before being started. + * + * @param callable|null $callback A PHP callback to run whenever there is some + * output available on STDOUT or STDERR + * + * @throws RuntimeException When process can't be launched + * @throws RuntimeException When process is already running + * + * @see start() + * + * @final + * @return static + */ + public function restart(?callable $callback = null, array $env = []) + { + if ($this->isRunning()) { + throw new RuntimeException('Process is already running.'); + } + $process = clone $this; + $process->start($callback, $env); + return $process; + } + /** + * Waits for the process to terminate. + * + * The callback receives the type of output (out or err) and some bytes + * from the output in real-time while writing the standard input to the process. + * It allows to have feedback from the independent process during execution. + * + * @param callable|null $callback A valid PHP callback + * + * @return int The exitcode of the process + * + * @throws ProcessTimedOutException When process timed out + * @throws ProcessSignaledException When process stopped after receiving signal + * @throws LogicException When process is not yet started + */ + public function wait(?callable $callback = null) : int + { + $this->requireProcessIsStarted(__FUNCTION__); + $this->updateStatus(\false); + if (null !== $callback) { + if (!$this->processPipes->haveReadSupport()) { + $this->stop(0); + throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::wait".'); + } + $this->callback = $this->buildCallback($callback); + } + do { + $this->checkTimeout(); + $running = $this->isRunning() && ('\\' === \DIRECTORY_SEPARATOR || $this->processPipes->areOpen()); + $this->readPipes($running, '\\' !== \DIRECTORY_SEPARATOR || !$running); + } while ($running); + while ($this->isRunning()) { + $this->checkTimeout(); + \usleep(1000); + } + if ($this->processInformation['signaled'] && $this->processInformation['termsig'] !== $this->latestSignal) { + throw new ProcessSignaledException($this); + } + return $this->exitcode; + } + /** + * Waits until the callback returns true. + * + * The callback receives the type of output (out or err) and some bytes + * from the output in real-time while writing the standard input to the process. + * It allows to have feedback from the independent process during execution. + * + * @throws RuntimeException When process timed out + * @throws LogicException When process is not yet started + * @throws ProcessTimedOutException In case the timeout was reached + */ + public function waitUntil(callable $callback) : bool + { + $this->requireProcessIsStarted(__FUNCTION__); + $this->updateStatus(\false); + if (!$this->processPipes->haveReadSupport()) { + $this->stop(0); + throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::waitUntil".'); + } + $callback = $this->buildCallback($callback); + $ready = \false; + while (\true) { + $this->checkTimeout(); + $running = '\\' === \DIRECTORY_SEPARATOR ? $this->isRunning() : $this->processPipes->areOpen(); + $output = $this->processPipes->readAndWrite($running, '\\' !== \DIRECTORY_SEPARATOR || !$running); + foreach ($output as $type => $data) { + if (3 !== $type) { + $ready = $callback(self::STDOUT === $type ? self::OUT : self::ERR, $data) || $ready; + } elseif (!isset($this->fallbackStatus['signaled'])) { + $this->fallbackStatus['exitcode'] = (int) $data; + } + } + if ($ready) { + return \true; + } + if (!$running) { + return \false; + } + \usleep(1000); + } + } + /** + * Returns the Pid (process identifier), if applicable. + * + * @return int|null The process id if running, null otherwise + */ + public function getPid() : ?int + { + return $this->isRunning() ? $this->processInformation['pid'] : null; + } + /** + * Sends a POSIX signal to the process. + * + * @param int $signal A valid POSIX signal (see https://php.net/pcntl.constants) + * + * @return $this + * + * @throws LogicException In case the process is not running + * @throws RuntimeException In case --enable-sigchild is activated and the process can't be killed + * @throws RuntimeException In case of failure + */ + public function signal(int $signal) + { + $this->doSignal($signal, \true); + return $this; + } + /** + * Disables fetching output and error output from the underlying process. + * + * @return $this + * + * @throws RuntimeException In case the process is already running + * @throws LogicException if an idle timeout is set + */ + public function disableOutput() + { + if ($this->isRunning()) { + throw new RuntimeException('Disabling output while the process is running is not possible.'); + } + if (null !== $this->idleTimeout) { + throw new LogicException('Output cannot be disabled while an idle timeout is set.'); + } + $this->outputDisabled = \true; + return $this; + } + /** + * Enables fetching output and error output from the underlying process. + * + * @return $this + * + * @throws RuntimeException In case the process is already running + */ + public function enableOutput() + { + if ($this->isRunning()) { + throw new RuntimeException('Enabling output while the process is running is not possible.'); + } + $this->outputDisabled = \false; + return $this; + } + /** + * Returns true in case the output is disabled, false otherwise. + */ + public function isOutputDisabled() : bool + { + return $this->outputDisabled; + } + /** + * Returns the current output of the process (STDOUT). + * + * @throws LogicException in case the output has been disabled + * @throws LogicException In case the process is not started + */ + public function getOutput() : string + { + $this->readPipesForOutput(__FUNCTION__); + if (\false === ($ret = \stream_get_contents($this->stdout, -1, 0))) { + return ''; + } + return $ret; + } + /** + * Returns the output incrementally. + * + * In comparison with the getOutput method which always return the whole + * output, this one returns the new output since the last call. + * + * @throws LogicException in case the output has been disabled + * @throws LogicException In case the process is not started + */ + public function getIncrementalOutput() : string + { + $this->readPipesForOutput(__FUNCTION__); + $latest = \stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset); + $this->incrementalOutputOffset = \ftell($this->stdout); + if (\false === $latest) { + return ''; + } + return $latest; + } + /** + * Returns an iterator to the output of the process, with the output type as keys (Process::OUT/ERR). + * + * @param int $flags A bit field of Process::ITER_* flags + * + * @return \Generator + * + * @throws LogicException in case the output has been disabled + * @throws LogicException In case the process is not started + */ + public function getIterator(int $flags = 0) : \Generator + { + $this->readPipesForOutput(__FUNCTION__, \false); + $clearOutput = !(self::ITER_KEEP_OUTPUT & $flags); + $blocking = !(self::ITER_NON_BLOCKING & $flags); + $yieldOut = !(self::ITER_SKIP_OUT & $flags); + $yieldErr = !(self::ITER_SKIP_ERR & $flags); + while (null !== $this->callback || $yieldOut && !\feof($this->stdout) || $yieldErr && !\feof($this->stderr)) { + if ($yieldOut) { + $out = \stream_get_contents($this->stdout, -1, $this->incrementalOutputOffset); + if (isset($out[0])) { + if ($clearOutput) { + $this->clearOutput(); + } else { + $this->incrementalOutputOffset = \ftell($this->stdout); + } + (yield self::OUT => $out); + } + } + if ($yieldErr) { + $err = \stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset); + if (isset($err[0])) { + if ($clearOutput) { + $this->clearErrorOutput(); + } else { + $this->incrementalErrorOutputOffset = \ftell($this->stderr); + } + (yield self::ERR => $err); + } + } + if (!$blocking && !isset($out[0]) && !isset($err[0])) { + (yield self::OUT => ''); + } + $this->checkTimeout(); + $this->readPipesForOutput(__FUNCTION__, $blocking); + } + } + /** + * Clears the process output. + * + * @return $this + */ + public function clearOutput() + { + \ftruncate($this->stdout, 0); + \fseek($this->stdout, 0); + $this->incrementalOutputOffset = 0; + return $this; + } + /** + * Returns the current error output of the process (STDERR). + * + * @throws LogicException in case the output has been disabled + * @throws LogicException In case the process is not started + */ + public function getErrorOutput() : string + { + $this->readPipesForOutput(__FUNCTION__); + if (\false === ($ret = \stream_get_contents($this->stderr, -1, 0))) { + return ''; + } + return $ret; + } + /** + * Returns the errorOutput incrementally. + * + * In comparison with the getErrorOutput method which always return the + * whole error output, this one returns the new error output since the last + * call. + * + * @throws LogicException in case the output has been disabled + * @throws LogicException In case the process is not started + */ + public function getIncrementalErrorOutput() : string + { + $this->readPipesForOutput(__FUNCTION__); + $latest = \stream_get_contents($this->stderr, -1, $this->incrementalErrorOutputOffset); + $this->incrementalErrorOutputOffset = \ftell($this->stderr); + if (\false === $latest) { + return ''; + } + return $latest; + } + /** + * Clears the process output. + * + * @return $this + */ + public function clearErrorOutput() + { + \ftruncate($this->stderr, 0); + \fseek($this->stderr, 0); + $this->incrementalErrorOutputOffset = 0; + return $this; + } + /** + * Returns the exit code returned by the process. + * + * @return int|null The exit status code, null if the Process is not terminated + */ + public function getExitCode() : ?int + { + $this->updateStatus(\false); + return $this->exitcode; + } + /** + * Returns a string representation for the exit code returned by the process. + * + * This method relies on the Unix exit code status standardization + * and might not be relevant for other operating systems. + * + * @return string|null A string representation for the exit status code, null if the Process is not terminated + * + * @see http://tldp.org/LDP/abs/html/exitcodes.html + * @see http://en.wikipedia.org/wiki/Unix_signal + */ + public function getExitCodeText() : ?string + { + if (null === ($exitcode = $this->getExitCode())) { + return null; + } + return self::$exitCodes[$exitcode] ?? 'Unknown error'; + } + /** + * Checks if the process ended successfully. + */ + public function isSuccessful() : bool + { + return 0 === $this->getExitCode(); + } + /** + * Returns true if the child process has been terminated by an uncaught signal. + * + * It always returns false on Windows. + * + * @throws LogicException In case the process is not terminated + */ + public function hasBeenSignaled() : bool + { + $this->requireProcessIsTerminated(__FUNCTION__); + return $this->processInformation['signaled']; + } + /** + * Returns the number of the signal that caused the child process to terminate its execution. + * + * It is only meaningful if hasBeenSignaled() returns true. + * + * @throws RuntimeException In case --enable-sigchild is activated + * @throws LogicException In case the process is not terminated + */ + public function getTermSignal() : int + { + $this->requireProcessIsTerminated(__FUNCTION__); + if ($this->isSigchildEnabled() && -1 === $this->processInformation['termsig']) { + throw new RuntimeException('This PHP has been compiled with --enable-sigchild. Term signal cannot be retrieved.'); + } + return $this->processInformation['termsig']; + } + /** + * Returns true if the child process has been stopped by a signal. + * + * It always returns false on Windows. + * + * @throws LogicException In case the process is not terminated + */ + public function hasBeenStopped() : bool + { + $this->requireProcessIsTerminated(__FUNCTION__); + return $this->processInformation['stopped']; + } + /** + * Returns the number of the signal that caused the child process to stop its execution. + * + * It is only meaningful if hasBeenStopped() returns true. + * + * @throws LogicException In case the process is not terminated + */ + public function getStopSignal() : int + { + $this->requireProcessIsTerminated(__FUNCTION__); + return $this->processInformation['stopsig']; + } + /** + * Checks if the process is currently running. + */ + public function isRunning() : bool + { + if (self::STATUS_STARTED !== $this->status) { + return \false; + } + $this->updateStatus(\false); + return $this->processInformation['running']; + } + /** + * Checks if the process has been started with no regard to the current state. + */ + public function isStarted() : bool + { + return self::STATUS_READY != $this->status; + } + /** + * Checks if the process is terminated. + */ + public function isTerminated() : bool + { + $this->updateStatus(\false); + return self::STATUS_TERMINATED == $this->status; + } + /** + * Gets the process status. + * + * The status is one of: ready, started, terminated. + */ + public function getStatus() : string + { + $this->updateStatus(\false); + return $this->status; + } + /** + * Stops the process. + * + * @param int|float $timeout The timeout in seconds + * @param int|null $signal A POSIX signal to send in case the process has not stop at timeout, default is SIGKILL (9) + * + * @return int|null The exit-code of the process or null if it's not running + */ + public function stop(float $timeout = 10, ?int $signal = null) : ?int + { + $timeoutMicro = \microtime(\true) + $timeout; + if ($this->isRunning()) { + // given SIGTERM may not be defined and that "proc_terminate" uses the constant value and not the constant itself, we use the same here + $this->doSignal(15, \false); + do { + \usleep(1000); + } while ($this->isRunning() && \microtime(\true) < $timeoutMicro); + if ($this->isRunning()) { + // Avoid exception here: process is supposed to be running, but it might have stopped just + // after this line. In any case, let's silently discard the error, we cannot do anything. + $this->doSignal($signal ?: 9, \false); + } + } + if ($this->isRunning()) { + if (isset($this->fallbackStatus['pid'])) { + unset($this->fallbackStatus['pid']); + return $this->stop(0, $signal); + } + $this->close(); + } + return $this->exitcode; + } + /** + * Adds a line to the STDOUT stream. + * + * @internal + */ + public function addOutput(string $line) : void + { + $this->lastOutputTime = \microtime(\true); + \fseek($this->stdout, 0, \SEEK_END); + \fwrite($this->stdout, $line); + \fseek($this->stdout, $this->incrementalOutputOffset); + } + /** + * Adds a line to the STDERR stream. + * + * @internal + */ + public function addErrorOutput(string $line) : void + { + $this->lastOutputTime = \microtime(\true); + \fseek($this->stderr, 0, \SEEK_END); + \fwrite($this->stderr, $line); + \fseek($this->stderr, $this->incrementalErrorOutputOffset); + } + /** + * Gets the last output time in seconds. + */ + public function getLastOutputTime() : ?float + { + return $this->lastOutputTime; + } + /** + * Gets the command line to be executed. + */ + public function getCommandLine() : string + { + return \is_array($this->commandline) ? \implode(' ', \array_map(\Closure::fromCallable([$this, 'escapeArgument']), $this->commandline)) : $this->commandline; + } + /** + * Gets the process timeout in seconds (max. runtime). + */ + public function getTimeout() : ?float + { + return $this->timeout; + } + /** + * Gets the process idle timeout in seconds (max. time since last output). + */ + public function getIdleTimeout() : ?float + { + return $this->idleTimeout; + } + /** + * Sets the process timeout (max. runtime) in seconds. + * + * To disable the timeout, set this value to null. + * + * @return $this + * + * @throws InvalidArgumentException if the timeout is negative + */ + public function setTimeout(?float $timeout) + { + $this->timeout = $this->validateTimeout($timeout); + return $this; + } + /** + * Sets the process idle timeout (max. time since last output) in seconds. + * + * To disable the timeout, set this value to null. + * + * @return $this + * + * @throws LogicException if the output is disabled + * @throws InvalidArgumentException if the timeout is negative + */ + public function setIdleTimeout(?float $timeout) + { + if (null !== $timeout && $this->outputDisabled) { + throw new LogicException('Idle timeout cannot be set while the output is disabled.'); + } + $this->idleTimeout = $this->validateTimeout($timeout); + return $this; + } + /** + * Enables or disables the TTY mode. + * + * @return $this + * + * @throws RuntimeException In case the TTY mode is not supported + */ + public function setTty(bool $tty) + { + if ('\\' === \DIRECTORY_SEPARATOR && $tty) { + throw new RuntimeException('TTY mode is not supported on Windows platform.'); + } + if ($tty && !self::isTtySupported()) { + throw new RuntimeException('TTY mode requires /dev/tty to be read/writable.'); + } + $this->tty = $tty; + return $this; + } + /** + * Checks if the TTY mode is enabled. + */ + public function isTty() : bool + { + return $this->tty; + } + /** + * Sets PTY mode. + * + * @return $this + */ + public function setPty(bool $bool) + { + $this->pty = $bool; + return $this; + } + /** + * Returns PTY state. + */ + public function isPty() : bool + { + return $this->pty; + } + /** + * Gets the working directory. + */ + public function getWorkingDirectory() : ?string + { + if (null === $this->cwd) { + // getcwd() will return false if any one of the parent directories does not have + // the readable or search mode set, even if the current directory does + return \getcwd() ?: null; + } + return $this->cwd; + } + /** + * Sets the current working directory. + * + * @return $this + */ + public function setWorkingDirectory(string $cwd) + { + $this->cwd = $cwd; + return $this; + } + /** + * Gets the environment variables. + */ + public function getEnv() : array + { + return $this->env; + } + /** + * Sets the environment variables. + * + * @param array $env The new environment variables + * + * @return $this + */ + public function setEnv(array $env) + { + $this->env = $env; + return $this; + } + /** + * Gets the Process input. + * + * @return resource|string|\Iterator|null + */ + public function getInput() + { + return $this->input; + } + /** + * Sets the input. + * + * This content will be passed to the underlying process standard input. + * + * @param mixed $input The content + * + * @return $this + * + * @throws LogicException In case the process is running + */ + public function setInput($input) + { + if ($this->isRunning()) { + throw new LogicException('Input cannot be set while the process is running.'); + } + $this->input = ProcessUtils::validateInput(__METHOD__, $input); + return $this; + } + /** + * Performs a check between the timeout definition and the time the process started. + * + * In case you run a background process (with the start method), you should + * trigger this method regularly to ensure the process timeout + * + * @return void + * + * @throws ProcessTimedOutException In case the timeout was reached + */ + public function checkTimeout() + { + if (self::STATUS_STARTED !== $this->status) { + return; + } + if (null !== $this->timeout && $this->timeout < \microtime(\true) - $this->starttime) { + $this->stop(0); + throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_GENERAL); + } + if (null !== $this->idleTimeout && $this->idleTimeout < \microtime(\true) - $this->lastOutputTime) { + $this->stop(0); + throw new ProcessTimedOutException($this, ProcessTimedOutException::TYPE_IDLE); + } + } + /** + * @throws LogicException in case process is not started + */ + public function getStartTime() : float + { + if (!$this->isStarted()) { + throw new LogicException('Start time is only available after process start.'); + } + return $this->starttime; + } + /** + * Defines options to pass to the underlying proc_open(). + * + * @see https://php.net/proc_open for the options supported by PHP. + * + * Enabling the "create_new_console" option allows a subprocess to continue + * to run after the main process exited, on both Windows and *nix + * + * @return void + */ + public function setOptions(array $options) + { + if ($this->isRunning()) { + throw new RuntimeException('Setting options while the process is running is not possible.'); + } + $defaultOptions = $this->options; + $existingOptions = ['blocking_pipes', 'create_process_group', 'create_new_console']; + foreach ($options as $key => $value) { + if (!\in_array($key, $existingOptions)) { + $this->options = $defaultOptions; + throw new LogicException(\sprintf('Invalid option "%s" passed to "%s()". Supported options are "%s".', $key, __METHOD__, \implode('", "', $existingOptions))); + } + $this->options[$key] = $value; + } + } + /** + * Returns whether TTY is supported on the current operating system. + */ + public static function isTtySupported() : bool + { + static $isTtySupported; + return $isTtySupported = $isTtySupported ?? '/' === \DIRECTORY_SEPARATOR && \stream_isatty(\STDOUT); + } + /** + * Returns whether PTY is supported on the current operating system. + */ + public static function isPtySupported() : bool + { + static $result; + if (null !== $result) { + return $result; + } + if ('\\' === \DIRECTORY_SEPARATOR) { + return $result = \false; + } + return $result = (bool) @\proc_open('echo 1 >/dev/null', [['pty'], ['pty'], ['pty']], $pipes); + } + /** + * Creates the descriptors needed by the proc_open. + */ + private function getDescriptors(bool $hasCallback) : array + { + if ($this->input instanceof \Iterator) { + $this->input->rewind(); + } + if ('\\' === \DIRECTORY_SEPARATOR) { + $this->processPipes = new WindowsPipes($this->input, !$this->outputDisabled || $hasCallback); + } else { + $this->processPipes = new UnixPipes($this->isTty(), $this->isPty(), $this->input, !$this->outputDisabled || $hasCallback); + } + return $this->processPipes->getDescriptors(); + } + /** + * Builds up the callback used by wait(). + * + * The callbacks adds all occurred output to the specific buffer and calls + * the user callback (if present) with the received output. + * + * @param callable|null $callback The user defined PHP callback + */ + protected function buildCallback(?callable $callback = null) : \Closure + { + if ($this->outputDisabled) { + return function ($type, $data) use($callback) : bool { + return null !== $callback && $callback($type, $data); + }; + } + $out = self::OUT; + return function ($type, $data) use($callback, $out) : bool { + if ($out == $type) { + $this->addOutput($data); + } else { + $this->addErrorOutput($data); + } + return null !== $callback && $callback($type, $data); + }; + } + /** + * Updates the status of the process, reads pipes. + * + * @param bool $blocking Whether to use a blocking read call + * + * @return void + */ + protected function updateStatus(bool $blocking) + { + if (self::STATUS_STARTED !== $this->status) { + return; + } + $this->processInformation = \proc_get_status($this->process); + $running = $this->processInformation['running']; + // In PHP < 8.3, "proc_get_status" only returns the correct exit status on the first call. + // Subsequent calls return -1 as the process is discarded. This workaround caches the first + // retrieved exit status for consistent results in later calls, mimicking PHP 8.3 behavior. + if (\PHP_VERSION_ID < 80300) { + if (!isset($this->cachedExitCode) && !$running && -1 !== $this->processInformation['exitcode']) { + $this->cachedExitCode = $this->processInformation['exitcode']; + } + if (isset($this->cachedExitCode) && !$running && -1 === $this->processInformation['exitcode']) { + $this->processInformation['exitcode'] = $this->cachedExitCode; + } + } + $this->readPipes($running && $blocking, '\\' !== \DIRECTORY_SEPARATOR || !$running); + if ($this->fallbackStatus && $this->isSigchildEnabled()) { + $this->processInformation = $this->fallbackStatus + $this->processInformation; + } + if (!$running) { + $this->close(); + } + } + /** + * Returns whether PHP has been compiled with the '--enable-sigchild' option or not. + */ + protected function isSigchildEnabled() : bool + { + if (null !== self::$sigchild) { + return self::$sigchild; + } + if (!\function_exists('phpinfo')) { + return self::$sigchild = \false; + } + \ob_start(); + \phpinfo(\INFO_GENERAL); + return self::$sigchild = \strpos(\ob_get_clean(), '--enable-sigchild') !== \false; + } + /** + * Reads pipes for the freshest output. + * + * @param string $caller The name of the method that needs fresh outputs + * @param bool $blocking Whether to use blocking calls or not + * + * @throws LogicException in case output has been disabled or process is not started + */ + private function readPipesForOutput(string $caller, bool $blocking = \false) : void + { + if ($this->outputDisabled) { + throw new LogicException('Output has been disabled.'); + } + $this->requireProcessIsStarted($caller); + $this->updateStatus($blocking); + } + /** + * Validates and returns the filtered timeout. + * + * @throws InvalidArgumentException if the given timeout is a negative number + */ + private function validateTimeout(?float $timeout) : ?float + { + $timeout = (float) $timeout; + if (0.0 === $timeout) { + $timeout = null; + } elseif ($timeout < 0) { + throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.'); + } + return $timeout; + } + /** + * Reads pipes, executes callback. + * + * @param bool $blocking Whether to use blocking calls or not + * @param bool $close Whether to close file handles or not + */ + private function readPipes(bool $blocking, bool $close) : void + { + $result = $this->processPipes->readAndWrite($blocking, $close); + $callback = $this->callback; + foreach ($result as $type => $data) { + if (3 !== $type) { + $callback(self::STDOUT === $type ? self::OUT : self::ERR, $data); + } elseif (!isset($this->fallbackStatus['signaled'])) { + $this->fallbackStatus['exitcode'] = (int) $data; + } + } + } + /** + * Closes process resource, closes file handles, sets the exitcode. + * + * @return int The exitcode + */ + private function close() : int + { + $this->processPipes->close(); + if (\is_resource($this->process)) { + \proc_close($this->process); + } + $this->exitcode = $this->processInformation['exitcode']; + $this->status = self::STATUS_TERMINATED; + if (-1 === $this->exitcode) { + if ($this->processInformation['signaled'] && 0 < $this->processInformation['termsig']) { + // if process has been signaled, no exitcode but a valid termsig, apply Unix convention + $this->exitcode = 128 + $this->processInformation['termsig']; + } elseif ($this->isSigchildEnabled()) { + $this->processInformation['signaled'] = \true; + $this->processInformation['termsig'] = -1; + } + } + // Free memory from self-reference callback created by buildCallback + // Doing so in other contexts like __destruct or by garbage collector is ineffective + // Now pipes are closed, so the callback is no longer necessary + $this->callback = null; + return $this->exitcode; + } + /** + * Resets data related to the latest run of the process. + */ + private function resetProcessData() : void + { + $this->starttime = null; + $this->callback = null; + $this->exitcode = null; + $this->fallbackStatus = []; + $this->processInformation = []; + $this->stdout = \fopen('php://temp/maxmemory:' . 1024 * 1024, 'w+'); + $this->stderr = \fopen('php://temp/maxmemory:' . 1024 * 1024, 'w+'); + $this->process = null; + $this->latestSignal = null; + $this->status = self::STATUS_READY; + $this->incrementalOutputOffset = 0; + $this->incrementalErrorOutputOffset = 0; + } + /** + * Sends a POSIX signal to the process. + * + * @param int $signal A valid POSIX signal (see https://php.net/pcntl.constants) + * @param bool $throwException Whether to throw exception in case signal failed + * + * @throws LogicException In case the process is not running + * @throws RuntimeException In case --enable-sigchild is activated and the process can't be killed + * @throws RuntimeException In case of failure + */ + private function doSignal(int $signal, bool $throwException) : bool + { + if (null === ($pid = $this->getPid())) { + if ($throwException) { + throw new LogicException('Cannot send signal on a non running process.'); + } + return \false; + } + if ('\\' === \DIRECTORY_SEPARATOR) { + \exec(\sprintf('taskkill /F /T /PID %d 2>&1', $pid), $output, $exitCode); + if ($exitCode && $this->isRunning()) { + if ($throwException) { + throw new RuntimeException(\sprintf('Unable to kill the process (%s).', \implode(' ', $output))); + } + return \false; + } + } else { + if (!$this->isSigchildEnabled()) { + $ok = @\proc_terminate($this->process, $signal); + } elseif (\function_exists('posix_kill')) { + $ok = @\posix_kill($pid, $signal); + } elseif ($ok = \proc_open(\sprintf('kill -%d %d', $signal, $pid), [2 => ['pipe', 'w']], $pipes)) { + $ok = \false === \fgets($pipes[2]); + } + if (!$ok) { + if ($throwException) { + throw new RuntimeException(\sprintf('Error while sending signal "%s".', $signal)); + } + return \false; + } + } + $this->latestSignal = $signal; + $this->fallbackStatus['signaled'] = \true; + $this->fallbackStatus['exitcode'] = -1; + $this->fallbackStatus['termsig'] = $this->latestSignal; + return \true; + } + private function prepareWindowsCommandLine(string $cmd, array &$env) : string + { + $uid = \uniqid('', \true); + $cmd = \preg_replace_callback('/"(?:( + [^"%!^]*+ + (?: + (?: !LF! | "(?:\\^[%!^])?+" ) + [^"%!^]*+ + )++ + ) | [^"]*+ )"/x', function ($m) use(&$env, $uid) { + static $varCount = 0; + static $varCache = []; + if (!isset($m[1])) { + return $m[0]; + } + if (isset($varCache[$m[0]])) { + return $varCache[$m[0]]; + } + if (\strpos($value = $m[1], "\x00") !== \false) { + $value = \str_replace("\x00", '?', $value); + } + if (\false === \strpbrk($value, "\"%!\n")) { + return '"' . $value . '"'; + } + $value = \str_replace(['!LF!', '"^!"', '"^%"', '"^^"', '""'], ["\n", '!', '%', '^', '"'], $value); + $value = '"' . \preg_replace('/(\\\\*)"/', '$1$1\\"', $value) . '"'; + $var = $uid . ++$varCount; + $env[$var] = $value; + return $varCache[$m[0]] = '!' . $var . '!'; + }, $cmd); + $cmd = 'cmd /V:ON /E:ON /D /C (' . \str_replace("\n", ' ', $cmd) . ')'; + foreach ($this->processPipes->getFiles() as $offset => $filename) { + $cmd .= ' ' . $offset . '>"' . $filename . '"'; + } + return $cmd; + } + /** + * Ensures the process is running or terminated, throws a LogicException if the process has a not started. + * + * @throws LogicException if the process has not run + */ + private function requireProcessIsStarted(string $functionName) : void + { + if (!$this->isStarted()) { + throw new LogicException(\sprintf('Process must be started before calling "%s()".', $functionName)); + } + } + /** + * Ensures the process is terminated, throws a LogicException if the process has a status different than "terminated". + * + * @throws LogicException if the process is not yet terminated + */ + private function requireProcessIsTerminated(string $functionName) : void + { + if (!$this->isTerminated()) { + throw new LogicException(\sprintf('Process must be terminated before calling "%s()".', $functionName)); + } + } + /** + * Escapes a string to be used as a shell argument. + */ + private function escapeArgument(?string $argument) : string + { + if ('' === $argument || null === $argument) { + return '""'; + } + if ('\\' !== \DIRECTORY_SEPARATOR) { + return "'" . \str_replace("'", "'\\''", $argument) . "'"; + } + if (\strpos($argument, "\x00") !== \false) { + $argument = \str_replace("\x00", '?', $argument); + } + if (!\preg_match('/[\\/()%!^"<>&|\\s]/', $argument)) { + return $argument; + } + $argument = \preg_replace('/(\\\\+)$/', '$1$1', $argument); + return '"' . \str_replace(['"', '^', '%', '!', "\n"], ['""', '"^^"', '"^%"', '"^!"', '!LF!'], $argument) . '"'; + } + private function replacePlaceholders(string $commandline, array $env) : string + { + return \preg_replace_callback('/"\\$\\{:([_a-zA-Z]++[_a-zA-Z0-9]*+)\\}"/', function ($matches) use($commandline, $env) { + if (!isset($env[$matches[1]]) || \false === $env[$matches[1]]) { + throw new InvalidArgumentException(\sprintf('Command line is missing a value for parameter "%s": ', $matches[1]) . $commandline); + } + return $this->escapeArgument($env[$matches[1]]); + }, $commandline); + } + private function getDefaultEnv() : array + { + $env = \getenv(); + $env = ('\\' === \DIRECTORY_SEPARATOR ? \array_intersect_ukey($env, $_SERVER, 'strcasecmp') : \array_intersect_key($env, $_SERVER)) ?: $env; + return $_ENV + ('\\' === \DIRECTORY_SEPARATOR ? \array_diff_ukey($env, $_ENV, 'strcasecmp') : $env); + } +} diff --git a/vendor/symfony/process/ProcessUtils.php b/vendor/symfony/process/ProcessUtils.php new file mode 100644 index 0000000000..d8b80957cc --- /dev/null +++ b/vendor/symfony/process/ProcessUtils.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\Process; + +use SwissKnife202405\Symfony\Component\Process\Exception\InvalidArgumentException; +/** + * ProcessUtils is a bunch of utility methods. + * + * This class contains static methods only and is not meant to be instantiated. + * + * @author Martin Hasoň + */ +class ProcessUtils +{ + /** + * This class should not be instantiated. + */ + private function __construct() + { + } + /** + * Validates and normalizes a Process input. + * + * @param string $caller The name of method call that validates the input + * @param mixed $input The input to validate + * + * @throws InvalidArgumentException In case the input is not valid + * @return mixed + */ + public static function validateInput(string $caller, $input) + { + if (null !== $input) { + if (\is_resource($input)) { + return $input; + } + if (\is_scalar($input)) { + return (string) $input; + } + if ($input instanceof Process) { + return $input->getIterator($input::ITER_SKIP_ERR); + } + if ($input instanceof \Iterator) { + return $input; + } + if ($input instanceof \Traversable) { + return new \IteratorIterator($input); + } + throw new InvalidArgumentException(\sprintf('"%s" only accepts strings, Traversable objects or stream resources.', $caller)); + } + return $input; + } +} diff --git a/vendor/symfony/process/README.md b/vendor/symfony/process/README.md new file mode 100644 index 0000000000..afce5e45ee --- /dev/null +++ b/vendor/symfony/process/README.md @@ -0,0 +1,13 @@ +Process Component +================= + +The Process component executes commands in sub-processes. + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/process.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/vendor/symfony/process/composer.json b/vendor/symfony/process/composer.json new file mode 100644 index 0000000000..99367a1f75 --- /dev/null +++ b/vendor/symfony/process/composer.json @@ -0,0 +1,30 @@ +{ + "name": "symfony\/process", + "type": "library", + "description": "Executes commands in sub-processes", + "keywords": [], + "homepage": "https:\/\/symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https:\/\/symfony.com\/contributors" + } + ], + "require": { + "php": ">=8.1" + }, + "autoload": { + "psr-4": { + "SwissKnife202405\\Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "\/Tests\/" + ] + }, + "minimum-stability": "dev" +} \ No newline at end of file diff --git a/vendor/symfony/service-contracts/Attribute/Required.php b/vendor/symfony/service-contracts/Attribute/Required.php new file mode 100644 index 0000000000..d9b5ddc4fd --- /dev/null +++ b/vendor/symfony/service-contracts/Attribute/Required.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Contracts\Service\Attribute; + +/** + * A required dependency. + * + * This attribute indicates that a property holds a required dependency. The annotated property or method should be + * considered during the instantiation process of the containing class. + * + * @author Alexander M. Turek + */ +#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)] +final class Required +{ +} diff --git a/vendor/symfony/service-contracts/Attribute/SubscribedService.php b/vendor/symfony/service-contracts/Attribute/SubscribedService.php new file mode 100644 index 0000000000..f8fc4f3e25 --- /dev/null +++ b/vendor/symfony/service-contracts/Attribute/SubscribedService.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Contracts\Service\Attribute; + +use SwissKnife202405\Symfony\Contracts\Service\ServiceMethodsSubscriberTrait; +use SwissKnife202405\Symfony\Contracts\Service\ServiceSubscriberInterface; +/** + * For use as the return value for {@see ServiceSubscriberInterface}. + * + * @example new SubscribedService('http_client', HttpClientInterface::class, false, new Target('githubApi')) + * + * Use with {@see ServiceMethodsSubscriberTrait} to mark a method's return type + * as a subscribed service. + * + * @author Kevin Bond + */ +#[\Attribute(\Attribute::TARGET_METHOD)] +final class SubscribedService +{ + /** + * @var string|null + */ + public $key; + /** + * @var class-string|null + */ + public $type; + /** + * @var bool + */ + public $nullable = \false; + /** @var object[] */ + public $attributes; + /** + * @param string|null $key The key to use for the service + * @param class-string|null $type The service class + * @param bool $nullable Whether the service is optional + * @param object|object[] $attributes One or more dependency injection attributes to use + */ + public function __construct(?string $key = null, ?string $type = null, bool $nullable = \false, $attributes = []) + { + $this->key = $key; + $this->type = $type; + $this->nullable = $nullable; + $this->attributes = \is_array($attributes) ? $attributes : [$attributes]; + } +} diff --git a/vendor/symfony/service-contracts/CHANGELOG.md b/vendor/symfony/service-contracts/CHANGELOG.md new file mode 100644 index 0000000000..7932e26132 --- /dev/null +++ b/vendor/symfony/service-contracts/CHANGELOG.md @@ -0,0 +1,5 @@ +CHANGELOG +========= + +The changelog is maintained for all Symfony contracts at the following URL: +https://github.com/symfony/contracts/blob/main/CHANGELOG.md diff --git a/vendor/symfony/service-contracts/LICENSE b/vendor/symfony/service-contracts/LICENSE new file mode 100644 index 0000000000..7536caeae8 --- /dev/null +++ b/vendor/symfony/service-contracts/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-present Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/service-contracts/README.md b/vendor/symfony/service-contracts/README.md new file mode 100644 index 0000000000..42841a57d0 --- /dev/null +++ b/vendor/symfony/service-contracts/README.md @@ -0,0 +1,9 @@ +Symfony Service Contracts +========================= + +A set of abstractions extracted out of the Symfony components. + +Can be used to build on semantics that the Symfony components proved useful and +that already have battle tested implementations. + +See https://github.com/symfony/contracts/blob/main/README.md for more information. diff --git a/vendor/symfony/service-contracts/ResetInterface.php b/vendor/symfony/service-contracts/ResetInterface.php new file mode 100644 index 0000000000..a70a5602a9 --- /dev/null +++ b/vendor/symfony/service-contracts/ResetInterface.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Contracts\Service; + +/** + * Provides a way to reset an object to its initial state. + * + * When calling the "reset()" method on an object, it should be put back to its + * initial state. This usually means clearing any internal buffers and forwarding + * the call to internal dependencies. All properties of the object should be put + * back to the same state it had when it was first ready to use. + * + * This method could be called, for example, to recycle objects that are used as + * services, so that they can be used to handle several requests in the same + * process loop (note that we advise making your services stateless instead of + * implementing this interface when possible.) + */ +interface ResetInterface +{ + /** + * @return void + */ + public function reset(); +} diff --git a/vendor/symfony/service-contracts/ServiceCollectionInterface.php b/vendor/symfony/service-contracts/ServiceCollectionInterface.php new file mode 100644 index 0000000000..1326f3d322 --- /dev/null +++ b/vendor/symfony/service-contracts/ServiceCollectionInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Contracts\Service; + +/** + * A ServiceProviderInterface that is also countable and iterable. + * + * @author Kevin Bond + * + * @template-covariant T of mixed + * + * @extends ServiceProviderInterface + * @extends \IteratorAggregate + */ +interface ServiceCollectionInterface extends ServiceProviderInterface, \Countable, \IteratorAggregate +{ +} diff --git a/vendor/symfony/service-contracts/ServiceLocatorTrait.php b/vendor/symfony/service-contracts/ServiceLocatorTrait.php new file mode 100644 index 0000000000..c177d173a5 --- /dev/null +++ b/vendor/symfony/service-contracts/ServiceLocatorTrait.php @@ -0,0 +1,112 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Contracts\Service; + +use SwissKnife202405\Psr\Container\ContainerExceptionInterface; +use SwissKnife202405\Psr\Container\NotFoundExceptionInterface; +// Help opcache.preload discover always-needed symbols +\class_exists(ContainerExceptionInterface::class); +\class_exists(NotFoundExceptionInterface::class); +/** + * A trait to help implement ServiceProviderInterface. + * + * @author Robin Chalas + * @author Nicolas Grekas + */ +trait ServiceLocatorTrait +{ + /** + * @var mixed[] + */ + private $factories; + /** + * @var mixed[] + */ + private $loading = []; + /** + * @var mixed[] + */ + private $providedTypes; + /** + * @param array $factories + */ + public function __construct(array $factories) + { + $this->factories = $factories; + } + public function has(string $id) : bool + { + return isset($this->factories[$id]); + } + /** + * @return mixed + */ + public function get(string $id) + { + if (!isset($this->factories[$id])) { + throw $this->createNotFoundException($id); + } + if (isset($this->loading[$id])) { + $ids = \array_values($this->loading); + $ids = \array_slice($this->loading, \array_search($id, $ids)); + $ids[] = $id; + throw $this->createCircularReferenceException($id, $ids); + } + $this->loading[$id] = $id; + try { + return $this->factories[$id]($this); + } finally { + unset($this->loading[$id]); + } + } + public function getProvidedServices() : array + { + if (!isset($this->providedTypes)) { + $this->providedTypes = []; + foreach ($this->factories as $name => $factory) { + if (!\is_callable($factory)) { + $this->providedTypes[$name] = '?'; + } else { + $type = (new \ReflectionFunction($factory))->getReturnType(); + $this->providedTypes[$name] = $type ? ($type->allowsNull() ? '?' : '') . ($type instanceof \ReflectionNamedType ? $type->getName() : $type) : '?'; + } + } + } + return $this->providedTypes; + } + private function createNotFoundException(string $id) : NotFoundExceptionInterface + { + if (!($alternatives = \array_keys($this->factories))) { + $message = 'is empty...'; + } else { + $last = \array_pop($alternatives); + if ($alternatives) { + $message = \sprintf('only knows about the "%s" and "%s" services.', \implode('", "', $alternatives), $last); + } else { + $message = \sprintf('only knows about the "%s" service.', $last); + } + } + if ($this->loading) { + $message = \sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', \end($this->loading), $id, $message); + } else { + $message = \sprintf('Service "%s" not found: the current service locator %s', $id, $message); + } + return new class($message) extends \InvalidArgumentException implements NotFoundExceptionInterface + { + }; + } + private function createCircularReferenceException(string $id, array $path) : ContainerExceptionInterface + { + return new class(\sprintf('Circular reference detected for service "%s", path: "%s".', $id, \implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface + { + }; + } +} diff --git a/vendor/symfony/service-contracts/ServiceMethodsSubscriberTrait.php b/vendor/symfony/service-contracts/ServiceMethodsSubscriberTrait.php new file mode 100644 index 0000000000..ffc94a3247 --- /dev/null +++ b/vendor/symfony/service-contracts/ServiceMethodsSubscriberTrait.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Contracts\Service; + +use SwissKnife202405\Psr\Container\ContainerInterface; +use SwissKnife202405\Symfony\Contracts\Service\Attribute\Required; +use SwissKnife202405\Symfony\Contracts\Service\Attribute\SubscribedService; +/** + * Implementation of ServiceSubscriberInterface that determines subscribed services + * from methods that have the #[SubscribedService] attribute. + * + * Service ids are available as "ClassName::methodName" so that the implementation + * of subscriber methods can be just `return $this->container->get(__METHOD__);`. + * + * @author Kevin Bond + */ +trait ServiceMethodsSubscriberTrait +{ + /** + * @var \Psr\Container\ContainerInterface + */ + protected $container; + public static function getSubscribedServices() : array + { + $services = \method_exists(\get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : []; + foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { + if (self::class !== $method->getDeclaringClass()->name) { + continue; + } + if (!($attribute = (\method_exists($method, 'getAttributes') ? $method->getAttributes(SubscribedService::class) : [])[0] ?? null)) { + continue; + } + if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { + throw new \LogicException(\sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); + } + if (!($returnType = $method->getReturnType())) { + throw new \LogicException(\sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); + } + /* @var SubscribedService $attribute */ + $attribute = $attribute->newInstance(); + $attribute->key = $attribute->key ?? self::class . '::' . $method->name; + $attribute->type = $attribute->type ?? ($returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType); + $attribute->nullable = $returnType->allowsNull(); + if ($attribute->attributes) { + $services[] = $attribute; + } else { + $services[$attribute->key] = ($attribute->nullable ? '?' : '') . $attribute->type; + } + } + return $services; + } + /** + * @required + */ + public function setContainer(ContainerInterface $container) : ?ContainerInterface + { + $ret = null; + if (\method_exists(\get_parent_class(self::class) ?: '', __FUNCTION__)) { + $ret = parent::setContainer($container); + } + $this->container = $container; + return $ret; + } +} diff --git a/vendor/symfony/service-contracts/ServiceProviderInterface.php b/vendor/symfony/service-contracts/ServiceProviderInterface.php new file mode 100644 index 0000000000..4a68723aad --- /dev/null +++ b/vendor/symfony/service-contracts/ServiceProviderInterface.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Contracts\Service; + +use SwissKnife202405\Psr\Container\ContainerInterface; +/** + * A ServiceProviderInterface exposes the identifiers and the types of services provided by a container. + * + * @author Nicolas Grekas + * @author Mateusz Sip + * + * @template-covariant T of mixed + */ +interface ServiceProviderInterface extends ContainerInterface +{ + /** + * @return T + */ + public function get(string $id); + public function has(string $id) : bool; + /** + * Returns an associative array of service types keyed by the identifiers provided by the current container. + * + * Examples: + * + * * ['logger' => 'Psr\Log\LoggerInterface'] means the object provides a service named "logger" that implements Psr\Log\LoggerInterface + * * ['foo' => '?'] means the container provides service name "foo" of unspecified type + * * ['bar' => '?Bar\Baz'] means the container provides a service "bar" of type Bar\Baz|null + * + * @return array The provided service types, keyed by service names + */ + public function getProvidedServices() : array; +} diff --git a/vendor/symfony/service-contracts/ServiceSubscriberInterface.php b/vendor/symfony/service-contracts/ServiceSubscriberInterface.php new file mode 100644 index 0000000000..c11b692e86 --- /dev/null +++ b/vendor/symfony/service-contracts/ServiceSubscriberInterface.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Contracts\Service; + +use SwissKnife202405\Symfony\Contracts\Service\Attribute\SubscribedService; +/** + * A ServiceSubscriber exposes its dependencies via the static {@link getSubscribedServices} method. + * + * The getSubscribedServices method returns an array of service types required by such instances, + * optionally keyed by the service names used internally. Service types that start with an interrogation + * mark "?" are optional, while the other ones are mandatory service dependencies. + * + * The injected service locators SHOULD NOT allow access to any other services not specified by the method. + * + * It is expected that ServiceSubscriber instances consume PSR-11-based service locators internally. + * This interface does not dictate any injection method for these service locators, although constructor + * injection is recommended. + * + * @author Nicolas Grekas + */ +interface ServiceSubscriberInterface +{ + /** + * Returns an array of service types (or {@see SubscribedService} objects) required + * by such instances, optionally keyed by the service names used internally. + * + * For mandatory dependencies: + * + * * ['logger' => 'Psr\Log\LoggerInterface'] means the objects use the "logger" name + * internally to fetch a service which must implement Psr\Log\LoggerInterface. + * * ['loggers' => 'Psr\Log\LoggerInterface[]'] means the objects use the "loggers" name + * internally to fetch an iterable of Psr\Log\LoggerInterface instances. + * * ['Psr\Log\LoggerInterface'] is a shortcut for + * * ['Psr\Log\LoggerInterface' => 'Psr\Log\LoggerInterface'] + * + * otherwise: + * + * * ['logger' => '?Psr\Log\LoggerInterface'] denotes an optional dependency + * * ['loggers' => '?Psr\Log\LoggerInterface[]'] denotes an optional iterable dependency + * * ['?Psr\Log\LoggerInterface'] is a shortcut for + * * ['Psr\Log\LoggerInterface' => '?Psr\Log\LoggerInterface'] + * + * additionally, an array of {@see SubscribedService}'s can be returned: + * + * * [new SubscribedService('logger', Psr\Log\LoggerInterface::class)] + * * [new SubscribedService(type: Psr\Log\LoggerInterface::class, nullable: true)] + * * [new SubscribedService('http_client', HttpClientInterface::class, attributes: new Target('githubApi'))] + * + * @return string[]|SubscribedService[] The required service types, optionally keyed by service names + */ + public static function getSubscribedServices() : array; +} diff --git a/vendor/symfony/service-contracts/ServiceSubscriberTrait.php b/vendor/symfony/service-contracts/ServiceSubscriberTrait.php new file mode 100644 index 0000000000..685ff663b5 --- /dev/null +++ b/vendor/symfony/service-contracts/ServiceSubscriberTrait.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Contracts\Service; + +use SwissKnife202405\Psr\Container\ContainerInterface; +use SwissKnife202405\Symfony\Contracts\Service\Attribute\Required; +use SwissKnife202405\Symfony\Contracts\Service\Attribute\SubscribedService; +trigger_deprecation('symfony/contracts', 'v3.5', '"%s" is deprecated, use "ServiceMethodsSubscriberTrait" instead.', ServiceSubscriberTrait::class); +/** + * Implementation of ServiceSubscriberInterface that determines subscribed services + * from methods that have the #[SubscribedService] attribute. + * + * Service ids are available as "ClassName::methodName" so that the implementation + * of subscriber methods can be just `return $this->container->get(__METHOD__);`. + * + * @property ContainerInterface $container + * + * @author Kevin Bond + * + * @deprecated since symfony/contracts v3.5, use ServiceMethodsSubscriberTrait instead + */ +trait ServiceSubscriberTrait +{ + public static function getSubscribedServices() : array + { + $services = \method_exists(\get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : []; + foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { + if (self::class !== $method->getDeclaringClass()->name) { + continue; + } + if (!($attribute = (\method_exists($method, 'getAttributes') ? $method->getAttributes(SubscribedService::class) : [])[0] ?? null)) { + continue; + } + if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { + throw new \LogicException(\sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); + } + if (!($returnType = $method->getReturnType())) { + throw new \LogicException(\sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); + } + /* @var SubscribedService $attribute */ + $attribute = $attribute->newInstance(); + $attribute->key = $attribute->key ?? self::class . '::' . $method->name; + $attribute->type = $attribute->type ?? ($returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType); + $attribute->nullable = $returnType->allowsNull(); + if ($attribute->attributes) { + $services[] = $attribute; + } else { + $services[$attribute->key] = ($attribute->nullable ? '?' : '') . $attribute->type; + } + } + return $services; + } + /** + * @required + */ + public function setContainer(ContainerInterface $container) : ?ContainerInterface + { + $ret = null; + if (\method_exists(\get_parent_class(self::class) ?: '', __FUNCTION__)) { + $ret = parent::setContainer($container); + } + $this->container = $container; + return $ret; + } +} diff --git a/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php b/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php new file mode 100644 index 0000000000..c4bc951fe4 --- /dev/null +++ b/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Contracts\Service\Test; + +\class_alias(ServiceLocatorTestCase::class, ServiceLocatorTest::class); +if (\false) { + /** + * @deprecated since PHPUnit 9.6 + */ + class ServiceLocatorTest + { + } +} diff --git a/vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.php b/vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.php new file mode 100644 index 0000000000..102229c33c --- /dev/null +++ b/vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Contracts\Service\Test; + +use SwissKnife202405\PHPUnit\Framework\TestCase; +use SwissKnife202405\Psr\Container\ContainerExceptionInterface; +use SwissKnife202405\Psr\Container\ContainerInterface; +use SwissKnife202405\Psr\Container\NotFoundExceptionInterface; +use SwissKnife202405\Symfony\Contracts\Service\ServiceLocatorTrait; +abstract class ServiceLocatorTestCase extends TestCase +{ + protected function getServiceLocator(array $factories) : ContainerInterface + { + return new class($factories) implements ContainerInterface + { + use ServiceLocatorTrait; + }; + } + public function testHas() + { + $locator = $this->getServiceLocator(['foo' => function () { + return 'bar'; + }, 'bar' => function () { + return 'baz'; + }, function () { + return 'dummy'; + }]); + $this->assertTrue($locator->has('foo')); + $this->assertTrue($locator->has('bar')); + $this->assertFalse($locator->has('dummy')); + } + public function testGet() + { + $locator = $this->getServiceLocator(['foo' => function () { + return 'bar'; + }, 'bar' => function () { + return 'baz'; + }]); + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame('baz', $locator->get('bar')); + } + public function testGetDoesNotMemoize() + { + $i = 0; + $locator = $this->getServiceLocator(['foo' => function () use(&$i) { + ++$i; + return 'bar'; + }]); + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame(2, $i); + } + public function testThrowsOnUndefinedInternalService() + { + $locator = $this->getServiceLocator(['foo' => function () use(&$locator) { + return $locator->get('bar'); + }]); + if (!$this->getExpectedException()) { + $this->expectException(NotFoundExceptionInterface::class); + $this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.'); + } + $locator->get('foo'); + } + public function testThrowsOnCircularReference() + { + $locator = $this->getServiceLocator(['foo' => function () use(&$locator) { + return $locator->get('bar'); + }, 'bar' => function () use(&$locator) { + return $locator->get('baz'); + }, 'baz' => function () use(&$locator) { + return $locator->get('bar'); + }]); + $this->expectException(ContainerExceptionInterface::class); + $this->expectExceptionMessage('Circular reference detected for service "bar", path: "bar -> baz -> bar".'); + $locator->get('foo'); + } +} diff --git a/vendor/symfony/service-contracts/composer.json b/vendor/symfony/service-contracts/composer.json new file mode 100644 index 0000000000..37a84239ac --- /dev/null +++ b/vendor/symfony/service-contracts/composer.json @@ -0,0 +1,51 @@ +{ + "name": "symfony\/service-contracts", + "type": "library", + "description": "Generic abstractions related to writing services", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "homepage": "https:\/\/symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https:\/\/symfony.com\/contributors" + } + ], + "require": { + "php": ">=8.1", + "psr\/container": "^1.1|^2.0", + "symfony\/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "autoload": { + "psr-4": { + "SwissKnife202405\\Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "\/Test\/" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony\/contracts", + "url": "https:\/\/github.com\/symfony\/contracts" + } + } +} \ No newline at end of file diff --git a/vendor/symfony/string/AbstractString.php b/vendor/symfony/string/AbstractString.php new file mode 100644 index 0000000000..0991cfd704 --- /dev/null +++ b/vendor/symfony/string/AbstractString.php @@ -0,0 +1,645 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\String; + +use SwissKnife202405\Symfony\Component\String\Exception\ExceptionInterface; +use SwissKnife202405\Symfony\Component\String\Exception\InvalidArgumentException; +use SwissKnife202405\Symfony\Component\String\Exception\RuntimeException; +/** + * Represents a string of abstract characters. + * + * Unicode defines 3 types of "characters" (bytes, code points and grapheme clusters). + * This class is the abstract type to use as a type-hint when the logic you want to + * implement doesn't care about the exact variant it deals with. + * + * @author Nicolas Grekas + * @author Hugo Hamon + * + * @throws ExceptionInterface + */ +abstract class AbstractString implements \JsonSerializable +{ + public const PREG_PATTERN_ORDER = \PREG_PATTERN_ORDER; + public const PREG_SET_ORDER = \PREG_SET_ORDER; + public const PREG_OFFSET_CAPTURE = \PREG_OFFSET_CAPTURE; + public const PREG_UNMATCHED_AS_NULL = \PREG_UNMATCHED_AS_NULL; + public const PREG_SPLIT = 0; + public const PREG_SPLIT_NO_EMPTY = \PREG_SPLIT_NO_EMPTY; + public const PREG_SPLIT_DELIM_CAPTURE = \PREG_SPLIT_DELIM_CAPTURE; + public const PREG_SPLIT_OFFSET_CAPTURE = \PREG_SPLIT_OFFSET_CAPTURE; + /** + * @var string + */ + protected $string = ''; + /** + * @var bool|null + */ + protected $ignoreCase = \false; + public abstract function __construct(string $string = ''); + /** + * Unwraps instances of AbstractString back to strings. + * + * @return string[]|array + */ + public static function unwrap(array $values) : array + { + foreach ($values as $k => $v) { + if ($v instanceof self) { + $values[$k] = $v->__toString(); + } elseif (\is_array($v) && $values[$k] !== ($v = static::unwrap($v))) { + $values[$k] = $v; + } + } + return $values; + } + /** + * Wraps (and normalizes) strings in instances of AbstractString. + * + * @return static[]|array + */ + public static function wrap(array $values) : array + { + $i = 0; + $keys = null; + foreach ($values as $k => $v) { + if (\is_string($k) && '' !== $k && $k !== ($j = (string) new static($k))) { + $keys = $keys ?? \array_keys($values); + $keys[$i] = $j; + } + if (\is_string($v)) { + $values[$k] = new static($v); + } elseif (\is_array($v) && $values[$k] !== ($v = static::wrap($v))) { + $values[$k] = $v; + } + ++$i; + } + return null !== $keys ? \array_combine($keys, $values) : $values; + } + /** + * @param string|string[] $needle + * @return static + */ + public function after($needle, bool $includeNeedle = \false, int $offset = 0) + { + $str = clone $this; + $i = \PHP_INT_MAX; + if (\is_string($needle)) { + $needle = [$needle]; + } + foreach ($needle as $n) { + $n = (string) $n; + $j = $this->indexOf($n, $offset); + if (null !== $j && $j < $i) { + $i = $j; + $str->string = $n; + } + } + if (\PHP_INT_MAX === $i) { + return $str; + } + if (!$includeNeedle) { + $i += $str->length(); + } + return $this->slice($i); + } + /** + * @param string|string[] $needle + * @return static + */ + public function afterLast($needle, bool $includeNeedle = \false, int $offset = 0) + { + $str = clone $this; + $i = null; + if (\is_string($needle)) { + $needle = [$needle]; + } + foreach ($needle as $n) { + $n = (string) $n; + $j = $this->indexOfLast($n, $offset); + if (null !== $j && $j >= $i) { + $i = $offset = $j; + $str->string = $n; + } + } + if (null === $i) { + return $str; + } + if (!$includeNeedle) { + $i += $str->length(); + } + return $this->slice($i); + } + /** + * @return static + */ + public abstract function append(string ...$suffix); + /** + * @param string|string[] $needle + * @return static + */ + public function before($needle, bool $includeNeedle = \false, int $offset = 0) + { + $str = clone $this; + $i = \PHP_INT_MAX; + if (\is_string($needle)) { + $needle = [$needle]; + } + foreach ($needle as $n) { + $n = (string) $n; + $j = $this->indexOf($n, $offset); + if (null !== $j && $j < $i) { + $i = $j; + $str->string = $n; + } + } + if (\PHP_INT_MAX === $i) { + return $str; + } + if ($includeNeedle) { + $i += $str->length(); + } + return $this->slice(0, $i); + } + /** + * @param string|string[] $needle + * @return static + */ + public function beforeLast($needle, bool $includeNeedle = \false, int $offset = 0) + { + $str = clone $this; + $i = null; + if (\is_string($needle)) { + $needle = [$needle]; + } + foreach ($needle as $n) { + $n = (string) $n; + $j = $this->indexOfLast($n, $offset); + if (null !== $j && $j >= $i) { + $i = $offset = $j; + $str->string = $n; + } + } + if (null === $i) { + return $str; + } + if ($includeNeedle) { + $i += $str->length(); + } + return $this->slice(0, $i); + } + /** + * @return int[] + */ + public function bytesAt(int $offset) : array + { + $str = $this->slice($offset, 1); + return '' === $str->string ? [] : \array_values(\unpack('C*', $str->string)); + } + /** + * @return static + */ + public abstract function camel(); + /** + * @return static[] + */ + public abstract function chunk(int $length = 1) : array; + /** + * @return static + */ + public function collapseWhitespace() + { + $str = clone $this; + $str->string = \trim(\preg_replace("/(?:[ \n\r\t\f]{2,}+|[\n\r\t\f])/", ' ', $str->string), " \n\r\t\f"); + return $str; + } + /** + * @param string|string[] $needle + */ + public function containsAny($needle) : bool + { + return null !== $this->indexOf($needle); + } + /** + * @param string|string[] $suffix + */ + public function endsWith($suffix) : bool + { + if (\is_string($suffix)) { + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + } + foreach ($suffix as $s) { + if ($this->endsWith((string) $s)) { + return \true; + } + } + return \false; + } + /** + * @return static + */ + public function ensureEnd(string $suffix) + { + if (!$this->endsWith($suffix)) { + return $this->append($suffix); + } + $suffix = \preg_quote($suffix); + $regex = '{(' . $suffix . ')(?:' . $suffix . ')++$}D'; + return $this->replaceMatches($regex . ($this->ignoreCase ? 'i' : ''), '$1'); + } + /** + * @return static + */ + public function ensureStart(string $prefix) + { + $prefix = new static($prefix); + if (!$this->startsWith($prefix)) { + return $this->prepend($prefix); + } + $str = clone $this; + $i = $prefixLen = $prefix->length(); + while ($this->indexOf($prefix, $i) === $i) { + $str = $str->slice($prefixLen); + $i += $prefixLen; + } + return $str; + } + /** + * @param string|string[] $string + */ + public function equalsTo($string) : bool + { + if (\is_string($string)) { + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + } + foreach ($string as $s) { + if ($this->equalsTo((string) $s)) { + return \true; + } + } + return \false; + } + /** + * @return static + */ + public abstract function folded(); + /** + * @return static + */ + public function ignoreCase() + { + $str = clone $this; + $str->ignoreCase = \true; + return $str; + } + /** + * @param string|string[] $needle + */ + public function indexOf($needle, int $offset = 0) : ?int + { + if (\is_string($needle)) { + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + } + $i = \PHP_INT_MAX; + foreach ($needle as $n) { + $j = $this->indexOf((string) $n, $offset); + if (null !== $j && $j < $i) { + $i = $j; + } + } + return \PHP_INT_MAX === $i ? null : $i; + } + /** + * @param string|string[] $needle + */ + public function indexOfLast($needle, int $offset = 0) : ?int + { + if (\is_string($needle)) { + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + } + $i = null; + foreach ($needle as $n) { + $j = $this->indexOfLast((string) $n, $offset); + if (null !== $j && $j >= $i) { + $i = $offset = $j; + } + } + return $i; + } + public function isEmpty() : bool + { + return '' === $this->string; + } + /** + * @return static + */ + public abstract function join(array $strings, ?string $lastGlue = null); + public function jsonSerialize() : string + { + return $this->string; + } + public abstract function length() : int; + /** + * @return static + */ + public abstract function lower(); + /** + * Matches the string using a regular expression. + * + * Pass PREG_PATTERN_ORDER or PREG_SET_ORDER as $flags to get all occurrences matching the regular expression. + * + * @return array All matches in a multi-dimensional array ordered according to flags + */ + public abstract function match(string $regexp, int $flags = 0, int $offset = 0) : array; + /** + * @return static + */ + public abstract function padBoth(int $length, string $padStr = ' '); + /** + * @return static + */ + public abstract function padEnd(int $length, string $padStr = ' '); + /** + * @return static + */ + public abstract function padStart(int $length, string $padStr = ' '); + /** + * @return static + */ + public abstract function prepend(string ...$prefix); + /** + * @return static + */ + public function repeat(int $multiplier) + { + if (0 > $multiplier) { + throw new InvalidArgumentException(\sprintf('Multiplier must be positive, %d given.', $multiplier)); + } + $str = clone $this; + $str->string = \str_repeat($str->string, $multiplier); + return $str; + } + /** + * @return static + */ + public abstract function replace(string $from, string $to); + /** + * @param string|callable $to + * @return static + */ + public abstract function replaceMatches(string $fromRegexp, $to); + /** + * @return static + */ + public abstract function reverse(); + /** + * @return static + */ + public abstract function slice(int $start = 0, ?int $length = null); + /** + * @return static + */ + public abstract function snake(); + /** + * @return static + */ + public abstract function splice(string $replacement, int $start = 0, ?int $length = null); + /** + * @return static[] + */ + public function split(string $delimiter, ?int $limit = null, ?int $flags = null) : array + { + if (null === $flags) { + throw new \TypeError('Split behavior when $flags is null must be implemented by child classes.'); + } + if ($this->ignoreCase) { + $delimiter .= 'i'; + } + \set_error_handler(static function ($t, $m) { + throw new InvalidArgumentException($m); + }); + try { + if (\false === ($chunks = \preg_split($delimiter, $this->string, $limit, $flags))) { + throw new RuntimeException('Splitting failed with error: ' . \preg_last_error_msg()); + } + } finally { + \restore_error_handler(); + } + $str = clone $this; + if (self::PREG_SPLIT_OFFSET_CAPTURE & $flags) { + foreach ($chunks as &$chunk) { + $str->string = $chunk[0]; + $chunk[0] = clone $str; + } + } else { + foreach ($chunks as &$chunk) { + $str->string = $chunk; + $chunk = clone $str; + } + } + return $chunks; + } + /** + * @param string|string[] $prefix + */ + public function startsWith($prefix) : bool + { + if (\is_string($prefix)) { + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + } + foreach ($prefix as $prefix) { + if ($this->startsWith((string) $prefix)) { + return \true; + } + } + return \false; + } + /** + * @return static + */ + public abstract function title(bool $allWords = \false); + public function toByteString(?string $toEncoding = null) : ByteString + { + $b = new ByteString(); + $toEncoding = \in_array($toEncoding, ['utf8', 'utf-8', 'UTF8'], \true) ? 'UTF-8' : $toEncoding; + if (null === $toEncoding || $toEncoding === ($fromEncoding = $this instanceof AbstractUnicodeString || \preg_match('//u', $b->string) ? 'UTF-8' : 'Windows-1252')) { + $b->string = $this->string; + return $b; + } + try { + $b->string = \mb_convert_encoding($this->string, $toEncoding, 'UTF-8'); + } catch (\ValueError $e) { + if (!\function_exists('iconv')) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } + $b->string = \iconv('UTF-8', $toEncoding, $this->string); + } + return $b; + } + public function toCodePointString() : CodePointString + { + return new CodePointString($this->string); + } + public function toString() : string + { + return $this->string; + } + public function toUnicodeString() : UnicodeString + { + return new UnicodeString($this->string); + } + /** + * @return static + */ + public abstract function trim(string $chars = " \t\n\r\x00\v\f "); + /** + * @return static + */ + public abstract function trimEnd(string $chars = " \t\n\r\x00\v\f "); + /** + * @param string|string[] $prefix + * @return static + */ + public function trimPrefix($prefix) + { + if (\is_array($prefix) || $prefix instanceof \Traversable) { + // don't use is_iterable(), it's slow + foreach ($prefix as $s) { + $t = $this->trimPrefix($s); + if ($t->string !== $this->string) { + return $t; + } + } + return clone $this; + } + $str = clone $this; + if ($prefix instanceof self) { + $prefix = $prefix->string; + } else { + $prefix = (string) $prefix; + } + if ('' !== $prefix && \strlen($this->string) >= \strlen($prefix) && 0 === \substr_compare($this->string, $prefix, 0, \strlen($prefix), $this->ignoreCase)) { + $str->string = \substr($this->string, \strlen($prefix)); + } + return $str; + } + /** + * @return static + */ + public abstract function trimStart(string $chars = " \t\n\r\x00\v\f "); + /** + * @param string|string[] $suffix + * @return static + */ + public function trimSuffix($suffix) + { + if (\is_array($suffix) || $suffix instanceof \Traversable) { + // don't use is_iterable(), it's slow + foreach ($suffix as $s) { + $t = $this->trimSuffix($s); + if ($t->string !== $this->string) { + return $t; + } + } + return clone $this; + } + $str = clone $this; + if ($suffix instanceof self) { + $suffix = $suffix->string; + } else { + $suffix = (string) $suffix; + } + if ('' !== $suffix && \strlen($this->string) >= \strlen($suffix) && 0 === \substr_compare($this->string, $suffix, -\strlen($suffix), null, $this->ignoreCase)) { + $str->string = \substr($this->string, 0, -\strlen($suffix)); + } + return $str; + } + /** + * @return static + */ + public function truncate(int $length, string $ellipsis = '', bool $cut = \true) + { + $stringLength = $this->length(); + if ($stringLength <= $length) { + return clone $this; + } + $ellipsisLength = '' !== $ellipsis ? (new static($ellipsis))->length() : 0; + if ($length < $ellipsisLength) { + $ellipsisLength = 0; + } + if (!$cut) { + if (null === ($length = $this->indexOf([' ', "\r", "\n", "\t"], ($length ?: 1) - 1))) { + return clone $this; + } + $length += $ellipsisLength; + } + $str = $this->slice(0, $length - $ellipsisLength); + return $ellipsisLength ? $str->trimEnd()->append($ellipsis) : $str; + } + /** + * @return static + */ + public abstract function upper(); + /** + * Returns the printable length on a terminal. + */ + public abstract function width(bool $ignoreAnsiDecoration = \true) : int; + /** + * @return static + */ + public function wordwrap(int $width = 75, string $break = "\n", bool $cut = \false) + { + $lines = '' !== $break ? $this->split($break) : [clone $this]; + $chars = []; + $mask = ''; + if (1 === \count($lines) && '' === $lines[0]->string) { + return $lines[0]; + } + foreach ($lines as $i => $line) { + if ($i) { + $chars[] = $break; + $mask .= '#'; + } + foreach ($line->chunk() as $char) { + $chars[] = $char->string; + $mask .= ' ' === $char->string ? ' ' : '?'; + } + } + $string = ''; + $j = 0; + $b = $i = -1; + $mask = \wordwrap($mask, $width, '#', $cut); + while (\false !== ($b = \strpos($mask, '#', $b + 1))) { + for (++$i; $i < $b; ++$i) { + $string .= $chars[$j]; + unset($chars[$j++]); + } + if ($break === $chars[$j] || ' ' === $chars[$j]) { + unset($chars[$j++]); + } + $string .= $break; + } + $str = clone $this; + $str->string = $string . \implode('', $chars); + return $str; + } + public function __sleep() : array + { + return ['string']; + } + public function __clone() + { + $this->ignoreCase = \false; + } + public function __toString() : string + { + return $this->string; + } +} diff --git a/vendor/symfony/string/AbstractUnicodeString.php b/vendor/symfony/string/AbstractUnicodeString.php new file mode 100644 index 0000000000..bc9fd7396c --- /dev/null +++ b/vendor/symfony/string/AbstractUnicodeString.php @@ -0,0 +1,532 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\String; + +use SwissKnife202405\Symfony\Component\String\Exception\ExceptionInterface; +use SwissKnife202405\Symfony\Component\String\Exception\InvalidArgumentException; +use SwissKnife202405\Symfony\Component\String\Exception\RuntimeException; +/** + * Represents a string of abstract Unicode characters. + * + * Unicode defines 3 types of "characters" (bytes, code points and grapheme clusters). + * This class is the abstract type to use as a type-hint when the logic you want to + * implement is Unicode-aware but doesn't care about code points vs grapheme clusters. + * + * @author Nicolas Grekas + * + * @throws ExceptionInterface + */ +abstract class AbstractUnicodeString extends AbstractString +{ + public const NFC = \Normalizer::NFC; + public const NFD = \Normalizer::NFD; + public const NFKC = \Normalizer::NFKC; + public const NFKD = \Normalizer::NFKD; + // all ASCII letters sorted by typical frequency of occurrence + private const ASCII = " eiasntrolud][cmp'\ng|hv.fb,:=-q10C2*yx)(L9AS/P\"EjMIk3>5T>', '<', '>', '-', '-', '-', '-', '-', '-', '-', '-', '-', '||', '/', '[', ']', '*', ',', '.', '<', '>', '<<', '>>', '[', ']', '[', ']', '[', ']', ',', '.', '[', ']', '<<', '>>', '<', '>', ',', '[', ']', '((', '))', '.', ',', '*', '/', '-', '/', '\\', '|', '||', '<<', '>>', '((', '))']; + /** + * @var mixed[] + */ + private static $transliterators = []; + /** + * @var mixed[] + */ + private static $tableZero; + /** + * @var mixed[] + */ + private static $tableWide; + /** + * @return static + */ + public static function fromCodePoints(int ...$codes) + { + $string = ''; + foreach ($codes as $code) { + if (0x80 > ($code %= 0x200000)) { + $string .= \chr($code); + } elseif (0x800 > $code) { + $string .= \chr(0xc0 | $code >> 6) . \chr(0x80 | $code & 0x3f); + } elseif (0x10000 > $code) { + $string .= \chr(0xe0 | $code >> 12) . \chr(0x80 | $code >> 6 & 0x3f) . \chr(0x80 | $code & 0x3f); + } else { + $string .= \chr(0xf0 | $code >> 18) . \chr(0x80 | $code >> 12 & 0x3f) . \chr(0x80 | $code >> 6 & 0x3f) . \chr(0x80 | $code & 0x3f); + } + } + return new static($string); + } + /** + * Generic UTF-8 to ASCII transliteration. + * + * Install the intl extension for best results. + * + * @param string[]|\Transliterator[]|\Closure[] $rules See "*-Latin" rules from Transliterator::listIDs() + */ + public function ascii(array $rules = []) : self + { + $str = clone $this; + $s = $str->string; + $str->string = ''; + \array_unshift($rules, 'nfd'); + $rules[] = 'latin-ascii'; + if (\function_exists('transliterator_transliterate')) { + $rules[] = 'any-latin/bgn'; + } + $rules[] = 'nfkd'; + $rules[] = '[:nonspacing mark:] remove'; + while (\strlen($s) - 1 > ($i = \strspn($s, self::ASCII))) { + if (0 < --$i) { + $str->string .= \substr($s, 0, $i); + $s = \substr($s, $i); + } + if (!($rule = \array_shift($rules))) { + $rules = []; + // An empty rule interrupts the next ones + } + if ($rule instanceof \Transliterator) { + $s = $rule->transliterate($s); + } elseif ($rule instanceof \Closure) { + $s = $rule($s); + } elseif ($rule) { + if ('nfd' === ($rule = \strtolower($rule))) { + \normalizer_is_normalized($s, self::NFD) ?: ($s = \normalizer_normalize($s, self::NFD)); + } elseif ('nfkd' === $rule) { + \normalizer_is_normalized($s, self::NFKD) ?: ($s = \normalizer_normalize($s, self::NFKD)); + } elseif ('[:nonspacing mark:] remove' === $rule) { + $s = \preg_replace('/\\p{Mn}++/u', '', $s); + } elseif ('latin-ascii' === $rule) { + $s = \str_replace(self::TRANSLIT_FROM, self::TRANSLIT_TO, $s); + } elseif ('de-ascii' === $rule) { + $s = \preg_replace("/([AUO])̈(?=\\p{Ll})/u", '$1e', $s); + $s = \str_replace(["ä", "ö", "ü", "Ä", "Ö", "Ü"], ['ae', 'oe', 'ue', 'AE', 'OE', 'UE'], $s); + } elseif (\function_exists('transliterator_transliterate')) { + if (null === ($transliterator = self::$transliterators[$rule] = self::$transliterators[$rule] ?? \Transliterator::create($rule))) { + if ('any-latin/bgn' === $rule) { + $rule = 'any-latin'; + $transliterator = self::$transliterators[$rule] = self::$transliterators[$rule] ?? \Transliterator::create($rule); + } + if (null === $transliterator) { + throw new InvalidArgumentException(\sprintf('Unknown transliteration rule "%s".', $rule)); + } + self::$transliterators['any-latin/bgn'] = $transliterator; + } + $s = $transliterator->transliterate($s); + } + } elseif (!\function_exists('iconv')) { + $s = \preg_replace('/[^\\x00-\\x7F]/u', '?', $s); + } else { + $s = @\preg_replace_callback('/[^\\x00-\\x7F]/u', static function ($c) { + $c = (string) \iconv('UTF-8', 'ASCII//TRANSLIT', $c[0]); + if ('' === $c && '' === \iconv('UTF-8', 'ASCII//TRANSLIT', '²')) { + throw new \LogicException(\sprintf('"%s" requires a translit-able iconv implementation, try installing "gnu-libiconv" if you\'re using Alpine Linux.', static::class)); + } + return 1 < \strlen($c) ? \ltrim($c, '\'`"^~') : ('' !== $c ? $c : '?'); + }, $s); + } + } + $str->string .= $s; + return $str; + } + /** + * @return static + */ + public function camel() + { + $str = clone $this; + $str->string = \str_replace(' ', '', \preg_replace_callback('/\\b.(?![A-Z]{2,})/u', static function ($m) { + static $i = 0; + return 1 === ++$i ? 'İ' === $m[0] ? 'i̇' : \mb_strtolower($m[0], 'UTF-8') : \mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8'); + }, \preg_replace('/[^\\pL0-9]++/u', ' ', $this->string))); + return $str; + } + /** + * @return int[] + */ + public function codePointsAt(int $offset) : array + { + $str = $this->slice($offset, 1); + if ('' === $str->string) { + return []; + } + $codePoints = []; + foreach (\preg_split('//u', $str->string, -1, \PREG_SPLIT_NO_EMPTY) as $c) { + $codePoints[] = \mb_ord($c, 'UTF-8'); + } + return $codePoints; + } + /** + * @return static + */ + public function folded(bool $compat = \true) + { + $str = clone $this; + if (!$compat || !\defined('Normalizer::NFKC_CF')) { + $str->string = \normalizer_normalize($str->string, $compat ? \Normalizer::NFKC : \Normalizer::NFC); + $str->string = \mb_strtolower(\str_replace(self::FOLD_FROM, self::FOLD_TO, $this->string), 'UTF-8'); + } else { + $str->string = \normalizer_normalize($str->string, \Normalizer::NFKC_CF); + } + return $str; + } + /** + * @return static + */ + public function join(array $strings, ?string $lastGlue = null) + { + $str = clone $this; + $tail = null !== $lastGlue && 1 < \count($strings) ? $lastGlue . \array_pop($strings) : ''; + $str->string = \implode($this->string, $strings) . $tail; + if (!\preg_match('//u', $str->string)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + return $str; + } + /** + * @return static + */ + public function lower() + { + $str = clone $this; + $str->string = \mb_strtolower(\str_replace('İ', 'i̇', $str->string), 'UTF-8'); + return $str; + } + public function match(string $regexp, int $flags = 0, int $offset = 0) : array + { + $match = (\PREG_PATTERN_ORDER | \PREG_SET_ORDER) & $flags ? 'preg_match_all' : 'preg_match'; + if ($this->ignoreCase) { + $regexp .= 'i'; + } + \set_error_handler(static function ($t, $m) { + throw new InvalidArgumentException($m); + }); + try { + if (\false === $match($regexp . 'u', $this->string, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset)) { + throw new RuntimeException('Matching failed with error: ' . \preg_last_error_msg()); + } + } finally { + \restore_error_handler(); + } + return $matches; + } + /** + * @return static + */ + public function normalize(int $form = self::NFC) + { + if (!\in_array($form, [self::NFC, self::NFD, self::NFKC, self::NFKD])) { + throw new InvalidArgumentException('Unsupported normalization form.'); + } + $str = clone $this; + \normalizer_is_normalized($str->string, $form) ?: ($str->string = \normalizer_normalize($str->string, $form)); + return $str; + } + /** + * @return static + */ + public function padBoth(int $length, string $padStr = ' ') + { + if ('' === $padStr || !\preg_match('//u', $padStr)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + $pad = clone $this; + $pad->string = $padStr; + return $this->pad($length, $pad, \STR_PAD_BOTH); + } + /** + * @return static + */ + public function padEnd(int $length, string $padStr = ' ') + { + if ('' === $padStr || !\preg_match('//u', $padStr)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + $pad = clone $this; + $pad->string = $padStr; + return $this->pad($length, $pad, \STR_PAD_RIGHT); + } + /** + * @return static + */ + public function padStart(int $length, string $padStr = ' ') + { + if ('' === $padStr || !\preg_match('//u', $padStr)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + $pad = clone $this; + $pad->string = $padStr; + return $this->pad($length, $pad, \STR_PAD_LEFT); + } + /** + * @param string|callable $to + * @return static + */ + public function replaceMatches(string $fromRegexp, $to) + { + if ($this->ignoreCase) { + $fromRegexp .= 'i'; + } + if (\is_array($to) || $to instanceof \Closure) { + $replace = 'preg_replace_callback'; + $to = static function (array $m) use($to) : string { + $to = $to($m); + if ('' !== $to && (!\is_string($to) || !\preg_match('//u', $to))) { + throw new InvalidArgumentException('Replace callback must return a valid UTF-8 string.'); + } + return $to; + }; + } elseif ('' !== $to && !\preg_match('//u', $to)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } else { + $replace = 'preg_replace'; + } + \set_error_handler(static function ($t, $m) { + throw new InvalidArgumentException($m); + }); + try { + if (null === ($string = $replace($fromRegexp . 'u', $to, $this->string))) { + $lastError = \preg_last_error(); + foreach (\get_defined_constants(\true)['pcre'] as $k => $v) { + if ($lastError === $v && \substr_compare($k, '_ERROR', -\strlen('_ERROR')) === 0) { + throw new RuntimeException('Matching failed with ' . $k . '.'); + } + } + throw new RuntimeException('Matching failed with unknown error code.'); + } + } finally { + \restore_error_handler(); + } + $str = clone $this; + $str->string = $string; + return $str; + } + /** + * @return static + */ + public function reverse() + { + $str = clone $this; + $str->string = \implode('', \array_reverse(\preg_split('/(\\X)/u', $str->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY))); + return $str; + } + /** + * @return static + */ + public function snake() + { + $str = $this->camel(); + $str->string = \mb_strtolower(\preg_replace(['/(\\p{Lu}+)(\\p{Lu}\\p{Ll})/u', '/([\\p{Ll}0-9])(\\p{Lu})/u'], 'SwissKnife202405\\1_\\2', $str->string), 'UTF-8'); + return $str; + } + /** + * @return static + */ + public function title(bool $allWords = \false) + { + $str = clone $this; + $limit = $allWords ? -1 : 1; + $str->string = \preg_replace_callback('/\\b./u', static function (array $m) : string { + return \mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8'); + }, $str->string, $limit); + return $str; + } + /** + * @return static + */ + public function trim(string $chars = " \t\n\r\x00\v\f ") + { + if (" \t\n\r\x00\v\f " !== $chars && !\preg_match('//u', $chars)) { + throw new InvalidArgumentException('Invalid UTF-8 chars.'); + } + $chars = \preg_quote($chars); + $str = clone $this; + $str->string = \preg_replace("{^[{$chars}]++|[{$chars}]++\$}uD", '', $str->string); + return $str; + } + /** + * @return static + */ + public function trimEnd(string $chars = " \t\n\r\x00\v\f ") + { + if (" \t\n\r\x00\v\f " !== $chars && !\preg_match('//u', $chars)) { + throw new InvalidArgumentException('Invalid UTF-8 chars.'); + } + $chars = \preg_quote($chars); + $str = clone $this; + $str->string = \preg_replace("{[{$chars}]++\$}uD", '', $str->string); + return $str; + } + /** + * @return static + */ + public function trimPrefix($prefix) + { + if (!$this->ignoreCase) { + return parent::trimPrefix($prefix); + } + $str = clone $this; + if ($prefix instanceof \Traversable) { + $prefix = \iterator_to_array($prefix, \false); + } elseif ($prefix instanceof parent) { + $prefix = $prefix->string; + } + $prefix = \implode('|', \array_map('preg_quote', (array) $prefix)); + $str->string = \preg_replace("{^(?:{$prefix})}iuD", '', $this->string); + return $str; + } + /** + * @return static + */ + public function trimStart(string $chars = " \t\n\r\x00\v\f ") + { + if (" \t\n\r\x00\v\f " !== $chars && !\preg_match('//u', $chars)) { + throw new InvalidArgumentException('Invalid UTF-8 chars.'); + } + $chars = \preg_quote($chars); + $str = clone $this; + $str->string = \preg_replace("{^[{$chars}]++}uD", '', $str->string); + return $str; + } + /** + * @return static + */ + public function trimSuffix($suffix) + { + if (!$this->ignoreCase) { + return parent::trimSuffix($suffix); + } + $str = clone $this; + if ($suffix instanceof \Traversable) { + $suffix = \iterator_to_array($suffix, \false); + } elseif ($suffix instanceof parent) { + $suffix = $suffix->string; + } + $suffix = \implode('|', \array_map('preg_quote', (array) $suffix)); + $str->string = \preg_replace("{(?:{$suffix})\$}iuD", '', $this->string); + return $str; + } + /** + * @return static + */ + public function upper() + { + $str = clone $this; + $str->string = \mb_strtoupper($str->string, 'UTF-8'); + return $str; + } + public function width(bool $ignoreAnsiDecoration = \true) : int + { + $width = 0; + $s = \str_replace(["\x00", "\x05", "\x07"], '', $this->string); + if (\strpos($s, "\r") !== \false) { + $s = \str_replace(["\r\n", "\r"], "\n", $s); + } + if (!$ignoreAnsiDecoration) { + $s = \preg_replace('/[\\p{Cc}\\x7F]++/u', '', $s); + } + foreach (\explode("\n", $s) as $s) { + if ($ignoreAnsiDecoration) { + $s = \preg_replace('/(?:\\x1B(?: + \\[ [\\x30-\\x3F]*+ [\\x20-\\x2F]*+ [\\x40-\\x7E] + | [P\\]X^_] .*? \\x1B\\\\ + | [\\x41-\\x7E] + )|[\\p{Cc}\\x7F]++)/xu', '', $s); + } + $lineWidth = $this->wcswidth($s); + if ($lineWidth > $width) { + $width = $lineWidth; + } + } + return $width; + } + /** + * @return static + */ + private function pad(int $len, self $pad, int $type) + { + $sLen = $this->length(); + if ($len <= $sLen) { + return clone $this; + } + $padLen = $pad->length(); + $freeLen = $len - $sLen; + $len = $freeLen % $padLen; + switch ($type) { + case \STR_PAD_RIGHT: + return $this->append(\str_repeat($pad->string, \intdiv($freeLen, $padLen)) . ($len ? $pad->slice(0, $len) : '')); + case \STR_PAD_LEFT: + return $this->prepend(\str_repeat($pad->string, \intdiv($freeLen, $padLen)) . ($len ? $pad->slice(0, $len) : '')); + case \STR_PAD_BOTH: + $freeLen /= 2; + $rightLen = \ceil($freeLen); + $len = $rightLen % $padLen; + $str = $this->append(\str_repeat($pad->string, \intdiv($rightLen, $padLen)) . ($len ? $pad->slice(0, $len) : '')); + $leftLen = \floor($freeLen); + $len = $leftLen % $padLen; + return $str->prepend(\str_repeat($pad->string, \intdiv($leftLen, $padLen)) . ($len ? $pad->slice(0, $len) : '')); + default: + throw new InvalidArgumentException('Invalid padding type.'); + } + } + /** + * Based on https://github.com/jquast/wcwidth, a Python implementation of https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c. + */ + private function wcswidth(string $string) : int + { + $width = 0; + foreach (\preg_split('//u', $string, -1, \PREG_SPLIT_NO_EMPTY) as $c) { + $codePoint = \mb_ord($c, 'UTF-8'); + if (0 === $codePoint || 0x34f === $codePoint || 0x200b <= $codePoint && 0x200f >= $codePoint || 0x2028 === $codePoint || 0x2029 === $codePoint || 0x202a <= $codePoint && 0x202e >= $codePoint || 0x2060 <= $codePoint && 0x2063 >= $codePoint) { + continue; + } + // Non printable characters + if (32 > $codePoint || 0x7f <= $codePoint && 0xa0 > $codePoint) { + return -1; + } + self::$tableZero = self::$tableZero ?? (require __DIR__ . '/Resources/data/wcswidth_table_zero.php'); + if ($codePoint >= self::$tableZero[0][0] && $codePoint <= self::$tableZero[$ubound = \count(self::$tableZero) - 1][1]) { + $lbound = 0; + while ($ubound >= $lbound) { + $mid = \floor(($lbound + $ubound) / 2); + if ($codePoint > self::$tableZero[$mid][1]) { + $lbound = $mid + 1; + } elseif ($codePoint < self::$tableZero[$mid][0]) { + $ubound = $mid - 1; + } else { + continue 2; + } + } + } + self::$tableWide = self::$tableWide ?? (require __DIR__ . '/Resources/data/wcswidth_table_wide.php'); + if ($codePoint >= self::$tableWide[0][0] && $codePoint <= self::$tableWide[$ubound = \count(self::$tableWide) - 1][1]) { + $lbound = 0; + while ($ubound >= $lbound) { + $mid = \floor(($lbound + $ubound) / 2); + if ($codePoint > self::$tableWide[$mid][1]) { + $lbound = $mid + 1; + } elseif ($codePoint < self::$tableWide[$mid][0]) { + $ubound = $mid - 1; + } else { + $width += 2; + continue 2; + } + } + } + ++$width; + } + return $width; + } +} diff --git a/vendor/symfony/string/ByteString.php b/vendor/symfony/string/ByteString.php new file mode 100644 index 0000000000..7407430f1b --- /dev/null +++ b/vendor/symfony/string/ByteString.php @@ -0,0 +1,459 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\String; + +use SwissKnife202405\Symfony\Component\String\Exception\ExceptionInterface; +use SwissKnife202405\Symfony\Component\String\Exception\InvalidArgumentException; +use SwissKnife202405\Symfony\Component\String\Exception\RuntimeException; +/** + * Represents a binary-safe string of bytes. + * + * @author Nicolas Grekas + * @author Hugo Hamon + * + * @throws ExceptionInterface + */ +class ByteString extends AbstractString +{ + private const ALPHABET_ALPHANUMERIC = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; + public function __construct(string $string = '') + { + $this->string = $string; + } + /* + * The following method was derived from code of the Hack Standard Library (v4.40 - 2020-05-03) + * + * https://github.com/hhvm/hsl/blob/80a42c02f036f72a42f0415e80d6b847f4bf62d5/src/random/private.php#L16 + * + * Code subject to the MIT license (https://github.com/hhvm/hsl/blob/master/LICENSE). + * + * Copyright (c) 2004-2020, Facebook, Inc. (https://www.facebook.com/) + */ + public static function fromRandom(int $length = 16, ?string $alphabet = null) : self + { + if ($length <= 0) { + throw new InvalidArgumentException(\sprintf('A strictly positive length is expected, "%d" given.', $length)); + } + $alphabet = $alphabet ?? self::ALPHABET_ALPHANUMERIC; + $alphabetSize = \strlen($alphabet); + $bits = (int) \ceil(\log($alphabetSize, 2.0)); + if ($bits <= 0 || $bits > 56) { + throw new InvalidArgumentException('The length of the alphabet must in the [2^1, 2^56] range.'); + } + $ret = ''; + while ($length > 0) { + $urandomLength = (int) \ceil(2 * $length * $bits / 8.0); + $data = \random_bytes($urandomLength); + $unpackedData = 0; + $unpackedBits = 0; + for ($i = 0; $i < $urandomLength && $length > 0; ++$i) { + // Unpack 8 bits + $unpackedData = $unpackedData << 8 | \ord($data[$i]); + $unpackedBits += 8; + // While we have enough bits to select a character from the alphabet, keep + // consuming the random data + for (; $unpackedBits >= $bits && $length > 0; $unpackedBits -= $bits) { + $index = $unpackedData & (1 << $bits) - 1; + $unpackedData >>= $bits; + // Unfortunately, the alphabet size is not necessarily a power of two. + // Worst case, it is 2^k + 1, which means we need (k+1) bits and we + // have around a 50% chance of missing as k gets larger + if ($index < $alphabetSize) { + $ret .= $alphabet[$index]; + --$length; + } + } + } + } + return new static($ret); + } + public function bytesAt(int $offset) : array + { + $str = $this->string[$offset] ?? ''; + return '' === $str ? [] : [\ord($str)]; + } + /** + * @return static + */ + public function append(string ...$suffix) + { + $str = clone $this; + $str->string .= 1 >= \count($suffix) ? $suffix[0] ?? '' : \implode('', $suffix); + return $str; + } + /** + * @return static + */ + public function camel() + { + $str = clone $this; + $parts = \explode(' ', \trim(\ucwords(\preg_replace('/[^a-zA-Z0-9\\x7f-\\xff]++/', ' ', $this->string)))); + $parts[0] = 1 !== \strlen($parts[0]) && \ctype_upper($parts[0]) ? $parts[0] : \lcfirst($parts[0]); + $str->string = \implode('', $parts); + return $str; + } + public function chunk(int $length = 1) : array + { + if (1 > $length) { + throw new InvalidArgumentException('The chunk length must be greater than zero.'); + } + if ('' === $this->string) { + return []; + } + $str = clone $this; + $chunks = []; + foreach (\str_split($this->string, $length) as $chunk) { + $str->string = $chunk; + $chunks[] = clone $str; + } + return $chunks; + } + /** + * @param string|iterable|\Symfony\Component\String\AbstractString $suffix + */ + public function endsWith($suffix) : bool + { + if ($suffix instanceof AbstractString) { + $suffix = $suffix->string; + } elseif (!\is_string($suffix)) { + return parent::endsWith($suffix); + } + return '' !== $suffix && \strlen($this->string) >= \strlen($suffix) && 0 === \substr_compare($this->string, $suffix, -\strlen($suffix), null, $this->ignoreCase); + } + /** + * @param string|iterable|\Symfony\Component\String\AbstractString $string + */ + public function equalsTo($string) : bool + { + if ($string instanceof AbstractString) { + $string = $string->string; + } elseif (!\is_string($string)) { + return parent::equalsTo($string); + } + if ('' !== $string && $this->ignoreCase) { + return 0 === \strcasecmp($string, $this->string); + } + return $string === $this->string; + } + /** + * @return static + */ + public function folded() + { + $str = clone $this; + $str->string = \strtolower($str->string); + return $str; + } + /** + * @param string|iterable|\Symfony\Component\String\AbstractString $needle + */ + public function indexOf($needle, int $offset = 0) : ?int + { + if ($needle instanceof AbstractString) { + $needle = $needle->string; + } elseif (!\is_string($needle)) { + return parent::indexOf($needle, $offset); + } + if ('' === $needle) { + return null; + } + $i = $this->ignoreCase ? \stripos($this->string, $needle, $offset) : \strpos($this->string, $needle, $offset); + return \false === $i ? null : $i; + } + /** + * @param string|iterable|\Symfony\Component\String\AbstractString $needle + */ + public function indexOfLast($needle, int $offset = 0) : ?int + { + if ($needle instanceof AbstractString) { + $needle = $needle->string; + } elseif (!\is_string($needle)) { + return parent::indexOfLast($needle, $offset); + } + if ('' === $needle) { + return null; + } + $i = $this->ignoreCase ? \strripos($this->string, $needle, $offset) : \strrpos($this->string, $needle, $offset); + return \false === $i ? null : $i; + } + public function isUtf8() : bool + { + return '' === $this->string || \preg_match('//u', $this->string); + } + /** + * @return static + */ + public function join(array $strings, ?string $lastGlue = null) + { + $str = clone $this; + $tail = null !== $lastGlue && 1 < \count($strings) ? $lastGlue . \array_pop($strings) : ''; + $str->string = \implode($this->string, $strings) . $tail; + return $str; + } + public function length() : int + { + return \strlen($this->string); + } + /** + * @return static + */ + public function lower() + { + $str = clone $this; + $str->string = \strtolower($str->string); + return $str; + } + public function match(string $regexp, int $flags = 0, int $offset = 0) : array + { + $match = (\PREG_PATTERN_ORDER | \PREG_SET_ORDER) & $flags ? 'preg_match_all' : 'preg_match'; + if ($this->ignoreCase) { + $regexp .= 'i'; + } + \set_error_handler(static function ($t, $m) { + throw new InvalidArgumentException($m); + }); + try { + if (\false === $match($regexp, $this->string, $matches, $flags | \PREG_UNMATCHED_AS_NULL, $offset)) { + throw new RuntimeException('Matching failed with error: ' . \preg_last_error_msg()); + } + } finally { + \restore_error_handler(); + } + return $matches; + } + /** + * @return static + */ + public function padBoth(int $length, string $padStr = ' ') + { + $str = clone $this; + $str->string = \str_pad($this->string, $length, $padStr, \STR_PAD_BOTH); + return $str; + } + /** + * @return static + */ + public function padEnd(int $length, string $padStr = ' ') + { + $str = clone $this; + $str->string = \str_pad($this->string, $length, $padStr, \STR_PAD_RIGHT); + return $str; + } + /** + * @return static + */ + public function padStart(int $length, string $padStr = ' ') + { + $str = clone $this; + $str->string = \str_pad($this->string, $length, $padStr, \STR_PAD_LEFT); + return $str; + } + /** + * @return static + */ + public function prepend(string ...$prefix) + { + $str = clone $this; + $str->string = (1 >= \count($prefix) ? $prefix[0] ?? '' : \implode('', $prefix)) . $str->string; + return $str; + } + /** + * @return static + */ + public function replace(string $from, string $to) + { + $str = clone $this; + if ('' !== $from) { + $str->string = $this->ignoreCase ? \str_ireplace($from, $to, $this->string) : \str_replace($from, $to, $this->string); + } + return $str; + } + /** + * @param string|callable $to + * @return static + */ + public function replaceMatches(string $fromRegexp, $to) + { + if ($this->ignoreCase) { + $fromRegexp .= 'i'; + } + $replace = \is_array($to) || $to instanceof \Closure ? 'preg_replace_callback' : 'preg_replace'; + \set_error_handler(static function ($t, $m) { + throw new InvalidArgumentException($m); + }); + try { + if (null === ($string = $replace($fromRegexp, $to, $this->string))) { + $lastError = \preg_last_error(); + foreach (\get_defined_constants(\true)['pcre'] as $k => $v) { + if ($lastError === $v && \substr_compare($k, '_ERROR', -\strlen('_ERROR')) === 0) { + throw new RuntimeException('Matching failed with ' . $k . '.'); + } + } + throw new RuntimeException('Matching failed with unknown error code.'); + } + } finally { + \restore_error_handler(); + } + $str = clone $this; + $str->string = $string; + return $str; + } + /** + * @return static + */ + public function reverse() + { + $str = clone $this; + $str->string = \strrev($str->string); + return $str; + } + /** + * @return static + */ + public function slice(int $start = 0, ?int $length = null) + { + $str = clone $this; + $str->string = (string) \substr($this->string, $start, $length ?? \PHP_INT_MAX); + return $str; + } + /** + * @return static + */ + public function snake() + { + $str = $this->camel(); + $str->string = \strtolower(\preg_replace(['/([A-Z]+)([A-Z][a-z])/', '/([a-z\\d])([A-Z])/'], 'SwissKnife202405\\1_\\2', $str->string)); + return $str; + } + /** + * @return static + */ + public function splice(string $replacement, int $start = 0, ?int $length = null) + { + $str = clone $this; + $str->string = \substr_replace($this->string, $replacement, $start, $length ?? \PHP_INT_MAX); + return $str; + } + public function split(string $delimiter, ?int $limit = null, ?int $flags = null) : array + { + if (1 > ($limit = $limit ?? \PHP_INT_MAX)) { + throw new InvalidArgumentException('Split limit must be a positive integer.'); + } + if ('' === $delimiter) { + throw new InvalidArgumentException('Split delimiter is empty.'); + } + if (null !== $flags) { + return parent::split($delimiter, $limit, $flags); + } + $str = clone $this; + $chunks = $this->ignoreCase ? \preg_split('{' . \preg_quote($delimiter) . '}iD', $this->string, $limit) : \explode($delimiter, $this->string, $limit); + foreach ($chunks as &$chunk) { + $str->string = $chunk; + $chunk = clone $str; + } + return $chunks; + } + /** + * @param string|iterable|\Symfony\Component\String\AbstractString $prefix + */ + public function startsWith($prefix) : bool + { + if ($prefix instanceof AbstractString) { + $prefix = $prefix->string; + } elseif (!\is_string($prefix)) { + return parent::startsWith($prefix); + } + return '' !== $prefix && 0 === ($this->ignoreCase ? \strncasecmp($this->string, $prefix, \strlen($prefix)) : \strncmp($this->string, $prefix, \strlen($prefix))); + } + /** + * @return static + */ + public function title(bool $allWords = \false) + { + $str = clone $this; + $str->string = $allWords ? \ucwords($str->string) : \ucfirst($str->string); + return $str; + } + public function toUnicodeString(?string $fromEncoding = null) : UnicodeString + { + return new UnicodeString($this->toCodePointString($fromEncoding)->string); + } + public function toCodePointString(?string $fromEncoding = null) : CodePointString + { + $u = new CodePointString(); + if (\in_array($fromEncoding, [null, 'utf8', 'utf-8', 'UTF8', 'UTF-8'], \true) && \preg_match('//u', $this->string)) { + $u->string = $this->string; + return $u; + } + \set_error_handler(static function ($t, $m) { + throw new InvalidArgumentException($m); + }); + try { + try { + $validEncoding = \false !== \mb_detect_encoding($this->string, $fromEncoding ?? 'Windows-1252', \true); + } catch (InvalidArgumentException $e) { + if (!\function_exists('iconv')) { + throw $e; + } + $u->string = \iconv($fromEncoding ?? 'Windows-1252', 'UTF-8', $this->string); + return $u; + } + } finally { + \restore_error_handler(); + } + if (!$validEncoding) { + throw new InvalidArgumentException(\sprintf('Invalid "%s" string.', $fromEncoding ?? 'Windows-1252')); + } + $u->string = \mb_convert_encoding($this->string, 'UTF-8', $fromEncoding ?? 'Windows-1252'); + return $u; + } + /** + * @return static + */ + public function trim(string $chars = " \t\n\r\x00\v\f") + { + $str = clone $this; + $str->string = \trim($str->string, $chars); + return $str; + } + /** + * @return static + */ + public function trimEnd(string $chars = " \t\n\r\x00\v\f") + { + $str = clone $this; + $str->string = \rtrim($str->string, $chars); + return $str; + } + /** + * @return static + */ + public function trimStart(string $chars = " \t\n\r\x00\v\f") + { + $str = clone $this; + $str->string = \ltrim($str->string, $chars); + return $str; + } + /** + * @return static + */ + public function upper() + { + $str = clone $this; + $str->string = \strtoupper($str->string); + return $str; + } + public function width(bool $ignoreAnsiDecoration = \true) : int + { + $string = \preg_match('//u', $this->string) ? $this->string : \preg_replace('/[\\x80-\\xFF]/', '?', $this->string); + return (new CodePointString($string))->width($ignoreAnsiDecoration); + } +} diff --git a/vendor/symfony/string/CHANGELOG.md b/vendor/symfony/string/CHANGELOG.md new file mode 100644 index 0000000000..31a3b54dbf --- /dev/null +++ b/vendor/symfony/string/CHANGELOG.md @@ -0,0 +1,40 @@ +CHANGELOG +========= + +6.2 +--- + + * Add support for emoji in `AsciiSlugger` + +5.4 +--- + + * Add `trimSuffix()` and `trimPrefix()` methods + +5.3 +--- + + * Made `AsciiSlugger` fallback to parent locale's symbolsMap + +5.2.0 +----- + + * added a `FrenchInflector` class + +5.1.0 +----- + + * added the `AbstractString::reverse()` method + * made `AbstractString::width()` follow POSIX.1-2001 + * added `LazyString` which provides memoizing stringable objects + * The component is not marked as `@experimental` anymore + * added the `s()` helper method to get either an `UnicodeString` or `ByteString` instance, + depending of the input string UTF-8 compliancy + * added `$cut` parameter to `Symfony\Component\String\AbstractString::truncate()` + * added `AbstractString::containsAny()` + * allow passing a string of custom characters to `ByteString::fromRandom()` + +5.0.0 +----- + + * added the component as experimental diff --git a/vendor/symfony/string/CodePointString.php b/vendor/symfony/string/CodePointString.php new file mode 100644 index 0000000000..d95f962ea1 --- /dev/null +++ b/vendor/symfony/string/CodePointString.php @@ -0,0 +1,234 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\String; + +use SwissKnife202405\Symfony\Component\String\Exception\ExceptionInterface; +use SwissKnife202405\Symfony\Component\String\Exception\InvalidArgumentException; +/** + * Represents a string of Unicode code points encoded as UTF-8. + * + * @author Nicolas Grekas + * @author Hugo Hamon + * + * @throws ExceptionInterface + */ +class CodePointString extends AbstractUnicodeString +{ + public function __construct(string $string = '') + { + if ('' !== $string && !\preg_match('//u', $string)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + $this->string = $string; + } + /** + * @return static + */ + public function append(string ...$suffix) + { + $str = clone $this; + $str->string .= 1 >= \count($suffix) ? $suffix[0] ?? '' : \implode('', $suffix); + if (!\preg_match('//u', $str->string)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + return $str; + } + public function chunk(int $length = 1) : array + { + if (1 > $length) { + throw new InvalidArgumentException('The chunk length must be greater than zero.'); + } + if ('' === $this->string) { + return []; + } + $rx = '/('; + while (65535 < $length) { + $rx .= '.{65535}'; + $length -= 65535; + } + $rx .= '.{' . $length . '})/us'; + $str = clone $this; + $chunks = []; + foreach (\preg_split($rx, $this->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY) as $chunk) { + $str->string = $chunk; + $chunks[] = clone $str; + } + return $chunks; + } + public function codePointsAt(int $offset) : array + { + $str = $offset ? $this->slice($offset, 1) : $this; + return '' === $str->string ? [] : [\mb_ord($str->string, 'UTF-8')]; + } + /** + * @param string|iterable|\Symfony\Component\String\AbstractString $suffix + */ + public function endsWith($suffix) : bool + { + if ($suffix instanceof AbstractString) { + $suffix = $suffix->string; + } elseif (!\is_string($suffix)) { + return parent::endsWith($suffix); + } + if ('' === $suffix || !\preg_match('//u', $suffix)) { + return \false; + } + if ($this->ignoreCase) { + return \preg_match('{' . \preg_quote($suffix) . '$}iuD', $this->string); + } + return \strlen($this->string) >= \strlen($suffix) && 0 === \substr_compare($this->string, $suffix, -\strlen($suffix)); + } + /** + * @param string|iterable|\Symfony\Component\String\AbstractString $string + */ + public function equalsTo($string) : bool + { + if ($string instanceof AbstractString) { + $string = $string->string; + } elseif (!\is_string($string)) { + return parent::equalsTo($string); + } + if ('' !== $string && $this->ignoreCase) { + return \strlen($string) === \strlen($this->string) && 0 === \mb_stripos($this->string, $string, 0, 'UTF-8'); + } + return $string === $this->string; + } + /** + * @param string|iterable|\Symfony\Component\String\AbstractString $needle + */ + public function indexOf($needle, int $offset = 0) : ?int + { + if ($needle instanceof AbstractString) { + $needle = $needle->string; + } elseif (!\is_string($needle)) { + return parent::indexOf($needle, $offset); + } + if ('' === $needle) { + return null; + } + $i = $this->ignoreCase ? \mb_stripos($this->string, $needle, $offset, 'UTF-8') : \mb_strpos($this->string, $needle, $offset, 'UTF-8'); + return \false === $i ? null : $i; + } + /** + * @param string|iterable|\Symfony\Component\String\AbstractString $needle + */ + public function indexOfLast($needle, int $offset = 0) : ?int + { + if ($needle instanceof AbstractString) { + $needle = $needle->string; + } elseif (!\is_string($needle)) { + return parent::indexOfLast($needle, $offset); + } + if ('' === $needle) { + return null; + } + $i = $this->ignoreCase ? \mb_strripos($this->string, $needle, $offset, 'UTF-8') : \mb_strrpos($this->string, $needle, $offset, 'UTF-8'); + return \false === $i ? null : $i; + } + public function length() : int + { + return \mb_strlen($this->string, 'UTF-8'); + } + /** + * @return static + */ + public function prepend(string ...$prefix) + { + $str = clone $this; + $str->string = (1 >= \count($prefix) ? $prefix[0] ?? '' : \implode('', $prefix)) . $this->string; + if (!\preg_match('//u', $str->string)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + return $str; + } + /** + * @return static + */ + public function replace(string $from, string $to) + { + $str = clone $this; + if ('' === $from || !\preg_match('//u', $from)) { + return $str; + } + if ('' !== $to && !\preg_match('//u', $to)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + if ($this->ignoreCase) { + $str->string = \implode($to, \preg_split('{' . \preg_quote($from) . '}iuD', $this->string)); + } else { + $str->string = \str_replace($from, $to, $this->string); + } + return $str; + } + /** + * @return static + */ + public function slice(int $start = 0, ?int $length = null) + { + $str = clone $this; + $str->string = \mb_substr($this->string, $start, $length, 'UTF-8'); + return $str; + } + /** + * @return static + */ + public function splice(string $replacement, int $start = 0, ?int $length = null) + { + if (!\preg_match('//u', $replacement)) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + $str = clone $this; + $start = $start ? \strlen(\mb_substr($this->string, 0, $start, 'UTF-8')) : 0; + $length = $length ? \strlen(\mb_substr($this->string, $start, $length, 'UTF-8')) : $length; + $str->string = \substr_replace($this->string, $replacement, $start, $length ?? \PHP_INT_MAX); + return $str; + } + public function split(string $delimiter, ?int $limit = null, ?int $flags = null) : array + { + if (1 > ($limit = $limit ?? \PHP_INT_MAX)) { + throw new InvalidArgumentException('Split limit must be a positive integer.'); + } + if ('' === $delimiter) { + throw new InvalidArgumentException('Split delimiter is empty.'); + } + if (null !== $flags) { + return parent::split($delimiter . 'u', $limit, $flags); + } + if (!\preg_match('//u', $delimiter)) { + throw new InvalidArgumentException('Split delimiter is not a valid UTF-8 string.'); + } + $str = clone $this; + $chunks = $this->ignoreCase ? \preg_split('{' . \preg_quote($delimiter) . '}iuD', $this->string, $limit) : \explode($delimiter, $this->string, $limit); + foreach ($chunks as &$chunk) { + $str->string = $chunk; + $chunk = clone $str; + } + return $chunks; + } + /** + * @param string|iterable|\Symfony\Component\String\AbstractString $prefix + */ + public function startsWith($prefix) : bool + { + if ($prefix instanceof AbstractString) { + $prefix = $prefix->string; + } elseif (!\is_string($prefix)) { + return parent::startsWith($prefix); + } + if ('' === $prefix || !\preg_match('//u', $prefix)) { + return \false; + } + if ($this->ignoreCase) { + return 0 === \mb_stripos($this->string, $prefix, 0, 'UTF-8'); + } + return 0 === \strncmp($this->string, $prefix, \strlen($prefix)); + } +} diff --git a/vendor/symfony/string/Exception/ExceptionInterface.php b/vendor/symfony/string/Exception/ExceptionInterface.php new file mode 100644 index 0000000000..5c1def9d1e --- /dev/null +++ b/vendor/symfony/string/Exception/ExceptionInterface.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\String\Exception; + +interface ExceptionInterface extends \Throwable +{ +} diff --git a/vendor/symfony/string/Exception/InvalidArgumentException.php b/vendor/symfony/string/Exception/InvalidArgumentException.php new file mode 100644 index 0000000000..331097d334 --- /dev/null +++ b/vendor/symfony/string/Exception/InvalidArgumentException.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\String\Exception; + +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/string/Exception/RuntimeException.php b/vendor/symfony/string/Exception/RuntimeException.php new file mode 100644 index 0000000000..a281a36a58 --- /dev/null +++ b/vendor/symfony/string/Exception/RuntimeException.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\String\Exception; + +class RuntimeException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/string/Inflector/EnglishInflector.php b/vendor/symfony/string/Inflector/EnglishInflector.php new file mode 100644 index 0000000000..77186a0e83 --- /dev/null +++ b/vendor/symfony/string/Inflector/EnglishInflector.php @@ -0,0 +1,404 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\String\Inflector; + +final class EnglishInflector implements InflectorInterface +{ + /** + * Map English plural to singular suffixes. + * + * @see http://english-zone.com/spelling/plurals.html + */ + private const PLURAL_MAP = [ + // First entry: plural suffix, reversed + // Second entry: length of plural suffix + // Third entry: Whether the suffix may succeed a vowel + // Fourth entry: Whether the suffix may succeed a consonant + // Fifth entry: singular suffix, normal + // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) + ['a', 1, \true, \true, ['on', 'um']], + // nebulae (nebula) + ['ea', 2, \true, \true, 'a'], + // services (service) + ['secivres', 8, \true, \true, 'service'], + // mice (mouse), lice (louse) + ['eci', 3, \false, \true, 'ouse'], + // geese (goose) + ['esee', 4, \false, \true, 'oose'], + // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius) + ['i', 1, \true, \true, 'us'], + // men (man), women (woman) + ['nem', 3, \true, \true, 'man'], + // children (child) + ['nerdlihc', 8, \true, \true, 'child'], + // oxen (ox) + ['nexo', 4, \false, \false, 'ox'], + // indices (index), appendices (appendix), prices (price) + ['seci', 4, \false, \true, ['ex', 'ix', 'ice']], + // codes (code) + ['sedoc', 5, \false, \true, 'code'], + // selfies (selfie) + ['seifles', 7, \true, \true, 'selfie'], + // zombies (zombie) + ['seibmoz', 7, \true, \true, 'zombie'], + // movies (movie) + ['seivom', 6, \true, \true, 'movie'], + // names (name) + ['seman', 5, \true, \false, 'name'], + // conspectuses (conspectus), prospectuses (prospectus) + ['sesutcep', 8, \true, \true, 'pectus'], + // feet (foot) + ['teef', 4, \true, \true, 'foot'], + // geese (goose) + ['eseeg', 5, \true, \true, 'goose'], + // teeth (tooth) + ['hteet', 5, \true, \true, 'tooth'], + // news (news) + ['swen', 4, \true, \true, 'news'], + // series (series) + ['seires', 6, \true, \true, 'series'], + // babies (baby) + ['sei', 3, \false, \true, 'y'], + // accesses (access), addresses (address), kisses (kiss) + ['sess', 4, \true, \false, 'ss'], + // statuses (status) + ['sesutats', 8, \true, \true, 'status'], + // analyses (analysis), ellipses (ellipsis), fungi (fungus), + // neuroses (neurosis), theses (thesis), emphases (emphasis), + // oases (oasis), crises (crisis), houses (house), bases (base), + // atlases (atlas) + ['ses', 3, \true, \true, ['s', 'se', 'sis']], + // objectives (objective), alternative (alternatives) + ['sevit', 5, \true, \true, 'tive'], + // drives (drive) + ['sevird', 6, \false, \true, 'drive'], + // lives (life), wives (wife) + ['sevi', 4, \false, \true, 'ife'], + // moves (move) + ['sevom', 5, \true, \true, 'move'], + // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf), caves (cave), staves (staff) + ['sev', 3, \true, \true, ['f', 've', 'ff']], + // axes (axis), axes (ax), axes (axe) + ['sexa', 4, \false, \false, ['ax', 'axe', 'axis']], + // indexes (index), matrixes (matrix) + ['sex', 3, \true, \false, 'x'], + // quizzes (quiz) + ['sezz', 4, \true, \false, 'z'], + // bureaus (bureau) + ['suae', 4, \false, \true, 'eau'], + // fees (fee), trees (tree), employees (employee) + ['see', 3, \true, \true, 'ee'], + // edges (edge) + ['segd', 4, \true, \true, 'dge'], + // roses (rose), garages (garage), cassettes (cassette), + // waltzes (waltz), heroes (hero), bushes (bush), arches (arch), + // shoes (shoe) + ['se', 2, \true, \true, ['', 'e']], + // status (status) + ['sutats', 6, \true, \true, 'status'], + // tags (tag) + ['s', 1, \true, \true, ''], + // chateaux (chateau) + ['xuae', 4, \false, \true, 'eau'], + // people (person) + ['elpoep', 6, \true, \true, 'person'], + ]; + /** + * Map English singular to plural suffixes. + * + * @see http://english-zone.com/spelling/plurals.html + */ + private const SINGULAR_MAP = [ + // First entry: singular suffix, reversed + // Second entry: length of singular suffix + // Third entry: Whether the suffix may succeed a vowel + // Fourth entry: Whether the suffix may succeed a consonant + // Fifth entry: plural suffix, normal + // axes (axis) + ['sixa', 4, \false, \false, 'axes'], + // criterion (criteria) + ['airetirc', 8, \false, \false, 'criterion'], + // nebulae (nebula) + ['aluben', 6, \false, \false, 'nebulae'], + // children (child) + ['dlihc', 5, \true, \true, 'children'], + // prices (price) + ['eci', 3, \false, \true, 'ices'], + // services (service) + ['ecivres', 7, \true, \true, 'services'], + // lives (life), wives (wife) + ['efi', 3, \false, \true, 'ives'], + // selfies (selfie) + ['eifles', 6, \true, \true, 'selfies'], + // movies (movie) + ['eivom', 5, \true, \true, 'movies'], + // lice (louse) + ['esuol', 5, \false, \true, 'lice'], + // mice (mouse) + ['esuom', 5, \false, \true, 'mice'], + // geese (goose) + ['esoo', 4, \false, \true, 'eese'], + // houses (house), bases (base) + ['es', 2, \true, \true, 'ses'], + // geese (goose) + ['esoog', 5, \true, \true, 'geese'], + // caves (cave) + ['ev', 2, \true, \true, 'ves'], + // drives (drive) + ['evird', 5, \false, \true, 'drives'], + // objectives (objective), alternative (alternatives) + ['evit', 4, \true, \true, 'tives'], + // moves (move) + ['evom', 4, \true, \true, 'moves'], + // staves (staff) + ['ffats', 5, \true, \true, 'staves'], + // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf) + ['ff', 2, \true, \true, 'ffs'], + // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf) + ['f', 1, \true, \true, ['fs', 'ves']], + // arches (arch) + ['hc', 2, \true, \true, 'ches'], + // bushes (bush) + ['hs', 2, \true, \true, 'shes'], + // teeth (tooth) + ['htoot', 5, \true, \true, 'teeth'], + // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) + ['mu', 2, \true, \true, 'a'], + // men (man), women (woman) + ['nam', 3, \true, \true, 'men'], + // people (person) + ['nosrep', 6, \true, \true, ['persons', 'people']], + // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) + ['noi', 3, \true, \true, 'ions'], + // coupon (coupons) + ['nop', 3, \true, \true, 'pons'], + // seasons (season), treasons (treason), poisons (poison), lessons (lesson) + ['nos', 3, \true, \true, 'sons'], + // icons (icon) + ['noc', 3, \true, \true, 'cons'], + // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) + ['no', 2, \true, \true, 'a'], + // echoes (echo) + ['ohce', 4, \true, \true, 'echoes'], + // heroes (hero) + ['oreh', 4, \true, \true, 'heroes'], + // atlases (atlas) + ['salta', 5, \true, \true, 'atlases'], + // irises (iris) + ['siri', 4, \true, \true, 'irises'], + // analyses (analysis), ellipses (ellipsis), neuroses (neurosis) + // theses (thesis), emphases (emphasis), oases (oasis), + // crises (crisis) + ['sis', 3, \true, \true, 'ses'], + // accesses (access), addresses (address), kisses (kiss) + ['ss', 2, \true, \false, 'sses'], + // syllabi (syllabus) + ['suballys', 8, \true, \true, 'syllabi'], + // buses (bus) + ['sub', 3, \true, \true, 'buses'], + // circuses (circus) + ['suc', 3, \true, \true, 'cuses'], + // hippocampi (hippocampus) + ['supmacoppih', 11, \false, \false, 'hippocampi'], + // campuses (campus) + ['sup', 3, \true, \true, 'puses'], + // status (status) + ['sutats', 6, \true, \true, ['status', 'statuses']], + // conspectuses (conspectus), prospectuses (prospectus) + ['sutcep', 6, \true, \true, 'pectuses'], + // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius) + ['su', 2, \true, \true, 'i'], + // news (news) + ['swen', 4, \true, \true, 'news'], + // feet (foot) + ['toof', 4, \true, \true, 'feet'], + // chateaux (chateau), bureaus (bureau) + ['uae', 3, \false, \true, ['eaus', 'eaux']], + // oxen (ox) + ['xo', 2, \false, \false, 'oxen'], + // hoaxes (hoax) + ['xaoh', 4, \true, \false, 'hoaxes'], + // indices (index) + ['xedni', 5, \false, \true, ['indicies', 'indexes']], + // boxes (box) + ['xo', 2, \false, \true, 'oxes'], + // indexes (index), matrixes (matrix) + ['x', 1, \true, \false, ['cies', 'xes']], + // appendices (appendix) + ['xi', 2, \false, \true, 'ices'], + // babies (baby) + ['y', 1, \false, \true, 'ies'], + // quizzes (quiz) + ['ziuq', 4, \true, \false, 'quizzes'], + // waltzes (waltz) + ['z', 1, \true, \true, 'zes'], + ]; + /** + * A list of words which should not be inflected, reversed. + */ + private const UNINFLECTED = [ + '', + // data + 'atad', + // deer + 'reed', + // equipment + 'tnempiuqe', + // feedback + 'kcabdeef', + // fish + 'hsif', + // health + 'htlaeh', + // history + 'yrotsih', + // info + 'ofni', + // information + 'noitamrofni', + // money + 'yenom', + // moose + 'esoom', + // series + 'seires', + // sheep + 'peehs', + // species + 'seiceps', + // traffic + 'ciffart', + // aircraft + 'tfarcria', + ]; + public function singularize(string $plural) : array + { + $pluralRev = \strrev($plural); + $lowerPluralRev = \strtolower($pluralRev); + $pluralLength = \strlen($lowerPluralRev); + // Check if the word is one which is not inflected, return early if so + if (\in_array($lowerPluralRev, self::UNINFLECTED, \true)) { + return [$plural]; + } + // The outer loop iterates over the entries of the plural table + // The inner loop $j iterates over the characters of the plural suffix + // in the plural table to compare them with the characters of the actual + // given plural suffix + foreach (self::PLURAL_MAP as $map) { + $suffix = $map[0]; + $suffixLength = $map[1]; + $j = 0; + // Compare characters in the plural table and of the suffix of the + // given plural one by one + while ($suffix[$j] === $lowerPluralRev[$j]) { + // Let $j point to the next character + ++$j; + // Successfully compared the last character + // Add an entry with the singular suffix to the singular array + if ($j === $suffixLength) { + // Is there any character preceding the suffix in the plural string? + if ($j < $pluralLength) { + $nextIsVowel = \strpos('aeiou', $lowerPluralRev[$j]) !== \false; + if (!$map[2] && $nextIsVowel) { + // suffix may not succeed a vowel but next char is one + break; + } + if (!$map[3] && !$nextIsVowel) { + // suffix may not succeed a consonant but next char is one + break; + } + } + $newBase = \substr($plural, 0, $pluralLength - $suffixLength); + $newSuffix = $map[4]; + // Check whether the first character in the plural suffix + // is uppercased. If yes, uppercase the first character in + // the singular suffix too + $firstUpper = \ctype_upper($pluralRev[$j - 1]); + if (\is_array($newSuffix)) { + $singulars = []; + foreach ($newSuffix as $newSuffixEntry) { + $singulars[] = $newBase . ($firstUpper ? \ucfirst($newSuffixEntry) : $newSuffixEntry); + } + return $singulars; + } + return [$newBase . ($firstUpper ? \ucfirst($newSuffix) : $newSuffix)]; + } + // Suffix is longer than word + if ($j === $pluralLength) { + break; + } + } + } + // Assume that plural and singular is identical + return [$plural]; + } + public function pluralize(string $singular) : array + { + $singularRev = \strrev($singular); + $lowerSingularRev = \strtolower($singularRev); + $singularLength = \strlen($lowerSingularRev); + // Check if the word is one which is not inflected, return early if so + if (\in_array($lowerSingularRev, self::UNINFLECTED, \true)) { + return [$singular]; + } + // The outer loop iterates over the entries of the singular table + // The inner loop $j iterates over the characters of the singular suffix + // in the singular table to compare them with the characters of the actual + // given singular suffix + foreach (self::SINGULAR_MAP as $map) { + $suffix = $map[0]; + $suffixLength = $map[1]; + $j = 0; + // Compare characters in the singular table and of the suffix of the + // given plural one by one + while ($suffix[$j] === $lowerSingularRev[$j]) { + // Let $j point to the next character + ++$j; + // Successfully compared the last character + // Add an entry with the plural suffix to the plural array + if ($j === $suffixLength) { + // Is there any character preceding the suffix in the plural string? + if ($j < $singularLength) { + $nextIsVowel = \strpos('aeiou', $lowerSingularRev[$j]) !== \false; + if (!$map[2] && $nextIsVowel) { + // suffix may not succeed a vowel but next char is one + break; + } + if (!$map[3] && !$nextIsVowel) { + // suffix may not succeed a consonant but next char is one + break; + } + } + $newBase = \substr($singular, 0, $singularLength - $suffixLength); + $newSuffix = $map[4]; + // Check whether the first character in the singular suffix + // is uppercased. If yes, uppercase the first character in + // the singular suffix too + $firstUpper = \ctype_upper($singularRev[$j - 1]); + if (\is_array($newSuffix)) { + $plurals = []; + foreach ($newSuffix as $newSuffixEntry) { + $plurals[] = $newBase . ($firstUpper ? \ucfirst($newSuffixEntry) : $newSuffixEntry); + } + return $plurals; + } + return [$newBase . ($firstUpper ? \ucfirst($newSuffix) : $newSuffix)]; + } + // Suffix is longer than word + if ($j === $singularLength) { + break; + } + } + } + // Assume that plural is singular with a trailing `s` + return [$singular . 's']; + } +} diff --git a/vendor/symfony/string/Inflector/FrenchInflector.php b/vendor/symfony/string/Inflector/FrenchInflector.php new file mode 100644 index 0000000000..570b83026d --- /dev/null +++ b/vendor/symfony/string/Inflector/FrenchInflector.php @@ -0,0 +1,122 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\String\Inflector; + +/** + * French inflector. + * + * This class does only inflect nouns; not adjectives nor composed words like "soixante-dix". + */ +final class FrenchInflector implements InflectorInterface +{ + /** + * A list of all rules for pluralise. + * + * @see https://la-conjugaison.nouvelobs.com/regles/grammaire/le-pluriel-des-noms-121.php + */ + private const PLURALIZE_REGEXP = [ + // First entry: regexp + // Second entry: replacement + // Words finishing with "s", "x" or "z" are invariables + // Les mots finissant par "s", "x" ou "z" sont invariables + ['/(s|x|z)$/i', '\\1'], + // Words finishing with "eau" are pluralized with a "x" + // Les mots finissant par "eau" prennent tous un "x" au pluriel + ['/(eau)$/i', '\\1x'], + // Words finishing with "au" are pluralized with a "x" excepted "landau" + // Les mots finissant par "au" prennent un "x" au pluriel sauf "landau" + ['/^(landau)$/i', '\\1s'], + ['/(au)$/i', '\\1x'], + // Words finishing with "eu" are pluralized with a "x" excepted "pneu", "bleu", "émeu" + // Les mots finissant en "eu" prennent un "x" au pluriel sauf "pneu", "bleu", "émeu" + ['/^(pneu|bleu|émeu)$/i', '\\1s'], + ['/(eu)$/i', '\\1x'], + // Words finishing with "al" are pluralized with a "aux" excepted + // Les mots finissant en "al" se terminent en "aux" sauf + ['/^(bal|carnaval|caracal|chacal|choral|corral|étal|festival|récital|val)$/i', '\\1s'], + ['/al$/i', '\\1aux'], + // Aspirail, bail, corail, émail, fermail, soupirail, travail, vantail et vitrail font leur pluriel en -aux + ['/^(aspir|b|cor|ém|ferm|soupir|trav|vant|vitr)ail$/i', '\\1aux'], + // Bijou, caillou, chou, genou, hibou, joujou et pou qui prennent un x au pluriel + ['/^(bij|caill|ch|gen|hib|jouj|p)ou$/i', '\\1oux'], + // Invariable words + ['/^(cinquante|soixante|mille)$/i', '\\1'], + // French titles + ['/^(mon|ma)(sieur|dame|demoiselle|seigneur)$/', 'SwissKnife202405\\mes\\2s'], + ['/^(Mon|Ma)(sieur|dame|demoiselle|seigneur)$/', 'SwissKnife202405\\Mes\\2s'], + ]; + /** + * A list of all rules for singularize. + */ + private const SINGULARIZE_REGEXP = [ + // First entry: regexp + // Second entry: replacement + // Aspirail, bail, corail, émail, fermail, soupirail, travail, vantail et vitrail font leur pluriel en -aux + ['/((aspir|b|cor|ém|ferm|soupir|trav|vant|vitr))aux$/i', '\\1ail'], + // Words finishing with "eau" are pluralized with a "x" + // Les mots finissant par "eau" prennent tous un "x" au pluriel + ['/(eau)x$/i', '\\1'], + // Words finishing with "al" are pluralized with a "aux" expected + // Les mots finissant en "al" se terminent en "aux" sauf + ['/(amir|anim|arsen|boc|can|capit|capor|chev|crist|génér|hopit|hôpit|idé|journ|littor|loc|m|mét|minér|princip|radic|termin)aux$/i', '\\1al'], + // Words finishing with "au" are pluralized with a "x" excepted "landau" + // Les mots finissant par "au" prennent un "x" au pluriel sauf "landau" + ['/(au)x$/i', '\\1'], + // Words finishing with "eu" are pluralized with a "x" excepted "pneu", "bleu", "émeu" + // Les mots finissant en "eu" prennent un "x" au pluriel sauf "pneu", "bleu", "émeu" + ['/(eu)x$/i', '\\1'], + // Words finishing with "ou" are pluralized with a "s" excepted bijou, caillou, chou, genou, hibou, joujou, pou + // Les mots finissant par "ou" prennent un "s" sauf bijou, caillou, chou, genou, hibou, joujou, pou + ['/(bij|caill|ch|gen|hib|jouj|p)oux$/i', '\\1ou'], + // French titles + ['/^mes(dame|demoiselle)s$/', 'SwissKnife202405\\ma\\1'], + ['/^Mes(dame|demoiselle)s$/', 'SwissKnife202405\\Ma\\1'], + ['/^mes(sieur|seigneur)s$/', 'SwissKnife202405\\mon\\1'], + ['/^Mes(sieur|seigneur)s$/', 'SwissKnife202405\\Mon\\1'], + // Default rule + ['/s$/i', ''], + ]; + /** + * A list of words which should not be inflected. + * This list is only used by singularize. + */ + private const UNINFLECTED = '/^(abcès|accès|abus|albatros|anchois|anglais|autobus|bois|brebis|carquois|cas|chas|colis|concours|corps|cours|cyprès|décès|devis|discours|dos|embarras|engrais|entrelacs|excès|fils|fois|gâchis|gars|glas|héros|intrus|jars|jus|kermès|lacis|legs|lilas|marais|mars|matelas|mépris|mets|mois|mors|obus|os|palais|paradis|parcours|pardessus|pays|plusieurs|poids|pois|pouls|printemps|processus|progrès|puits|pus|rabais|radis|recors|recours|refus|relais|remords|remous|rictus|rhinocéros|repas|rubis|sans|sas|secours|sens|souris|succès|talus|tapis|tas|taudis|temps|tiers|univers|velours|verglas|vernis|virus)$/i'; + public function singularize(string $plural) : array + { + if ($this->isInflectedWord($plural)) { + return [$plural]; + } + foreach (self::SINGULARIZE_REGEXP as $rule) { + [$regexp, $replace] = $rule; + if (1 === \preg_match($regexp, $plural)) { + return [\preg_replace($regexp, $replace, $plural)]; + } + } + return [$plural]; + } + public function pluralize(string $singular) : array + { + if ($this->isInflectedWord($singular)) { + return [$singular]; + } + foreach (self::PLURALIZE_REGEXP as $rule) { + [$regexp, $replace] = $rule; + if (1 === \preg_match($regexp, $singular)) { + return [\preg_replace($regexp, $replace, $singular)]; + } + } + return [$singular . 's']; + } + private function isInflectedWord(string $word) : bool + { + return 1 === \preg_match(self::UNINFLECTED, $word); + } +} diff --git a/vendor/symfony/string/Inflector/InflectorInterface.php b/vendor/symfony/string/Inflector/InflectorInterface.php new file mode 100644 index 0000000000..a3f138f029 --- /dev/null +++ b/vendor/symfony/string/Inflector/InflectorInterface.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\String\Inflector; + +interface InflectorInterface +{ + /** + * Returns the singular forms of a string. + * + * If the method can't determine the form with certainty, several possible singulars are returned. + * + * @return string[] + */ + public function singularize(string $plural) : array; + /** + * Returns the plural forms of a string. + * + * If the method can't determine the form with certainty, several possible plurals are returned. + * + * @return string[] + */ + public function pluralize(string $singular) : array; +} diff --git a/vendor/symfony/string/LICENSE b/vendor/symfony/string/LICENSE new file mode 100644 index 0000000000..f37c76b591 --- /dev/null +++ b/vendor/symfony/string/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2019-present Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/string/LazyString.php b/vendor/symfony/string/LazyString.php new file mode 100644 index 0000000000..8be3078cc5 --- /dev/null +++ b/vendor/symfony/string/LazyString.php @@ -0,0 +1,132 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\String; + +/** + * A string whose value is computed lazily by a callback. + * + * @author Nicolas Grekas + */ +class LazyString implements \JsonSerializable +{ + /** + * @var \Closure|string + */ + private $value; + /** + * @param callable|array $callback A callable or a [Closure, method] lazy-callable + * @param mixed ...$arguments + * @return static + */ + public static function fromCallable($callback, ...$arguments) + { + if (\is_array($callback) && !\is_callable($callback) && !(($callback[0] ?? null) instanceof \Closure || 2 < \count($callback))) { + throw new \TypeError(\sprintf('Argument 1 passed to "%s()" must be a callable or a [Closure, method] lazy-callable, "%s" given.', __METHOD__, '[' . \implode(', ', \array_map('get_debug_type', $callback)) . ']')); + } + $lazyString = new static(); + $lazyString->value = static function () use(&$callback, &$arguments) : string { + static $value; + if (null !== $arguments) { + if (!\is_callable($callback)) { + $callback[0] = $callback[0](); + $callback[1] = $callback[1] ?? '__invoke'; + } + $value = $callback(...$arguments); + $callback = !\is_scalar($value) && !$value instanceof \Stringable ? self::getPrettyName($callback) : 'callable'; + $arguments = null; + } + return $value ?? ''; + }; + return $lazyString; + } + /** + * @param string|int|float|bool|\Stringable $value + * @return static + */ + public static function fromStringable($value) + { + if (\is_object($value)) { + return static::fromCallable(\Closure::fromCallable([$value, '__toString'])); + } + $lazyString = new static(); + $lazyString->value = (string) $value; + return $lazyString; + } + /** + * Tells whether the provided value can be cast to string. + * @param mixed $value + */ + public static final function isStringable($value) : bool + { + return \is_string($value) || $value instanceof \Stringable || \is_scalar($value); + } + /** + * Casts scalars and stringable objects to strings. + * + * @throws \TypeError When the provided value is not stringable + * @param \Stringable|string|int|float|bool $value + */ + public static final function resolve($value) : string + { + return $value; + } + public function __toString() : string + { + if (\is_string($this->value)) { + return $this->value; + } + try { + return $this->value = ($this->value)(); + } catch (\Throwable $e) { + if (\TypeError::class === \get_class($e) && __FILE__ === $e->getFile()) { + $type = \explode(', ', $e->getMessage()); + $type = \substr(\array_pop($type), 0, -\strlen(' returned')); + $r = new \ReflectionFunction($this->value); + $callback = $r->getStaticVariables()['callback']; + $e = new \TypeError(\sprintf('Return value of %s() passed to %s::fromCallable() must be of the type string, %s returned.', $callback, static::class, $type)); + } + throw $e; + } + } + public function __sleep() : array + { + $this->__toString(); + return ['value']; + } + public function jsonSerialize() : string + { + return $this->__toString(); + } + private function __construct() + { + } + private static function getPrettyName(callable $callback) : string + { + if (\is_string($callback)) { + return $callback; + } + if (\is_array($callback)) { + $class = \is_object($callback[0]) ? \get_debug_type($callback[0]) : $callback[0]; + $method = $callback[1]; + } elseif ($callback instanceof \Closure) { + $r = new \ReflectionFunction($callback); + if (\strpos($r->name, '{closure') !== \false || !($class = $r->getClosureCalledClass())) { + return $r->name; + } + $class = $class->name; + $method = $r->name; + } else { + $class = \get_debug_type($callback); + $method = '__invoke'; + } + return $class . '::' . $method; + } +} diff --git a/vendor/symfony/string/README.md b/vendor/symfony/string/README.md new file mode 100644 index 0000000000..9c7e1e190d --- /dev/null +++ b/vendor/symfony/string/README.md @@ -0,0 +1,14 @@ +String Component +================ + +The String component provides an object-oriented API to strings and deals +with bytes, UTF-8 code points and grapheme clusters in a unified way. + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/string.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/vendor/symfony/string/Resources/data/wcswidth_table_wide.php b/vendor/symfony/string/Resources/data/wcswidth_table_wide.php new file mode 100644 index 0000000000..779a2c6c1f --- /dev/null +++ b/vendor/symfony/string/Resources/data/wcswidth_table_wide.php @@ -0,0 +1,11 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\String; + +if (!\function_exists(u::class)) { + function u(?string $string = '') : UnicodeString + { + return new UnicodeString($string ?? ''); + } +} +if (!\function_exists(b::class)) { + function b(?string $string = '') : ByteString + { + return new ByteString($string ?? ''); + } +} +if (!\function_exists(s::class)) { + /** + * @return UnicodeString|ByteString + */ + function s(?string $string = '') : AbstractString + { + $string = $string ?? ''; + return \preg_match('//u', $string) ? new UnicodeString($string) : new ByteString($string); + } +} diff --git a/vendor/symfony/string/Slugger/AsciiSlugger.php b/vendor/symfony/string/Slugger/AsciiSlugger.php new file mode 100644 index 0000000000..559fc34b07 --- /dev/null +++ b/vendor/symfony/string/Slugger/AsciiSlugger.php @@ -0,0 +1,161 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\String\Slugger; + +use SwissKnife202405\Symfony\Component\Intl\Transliterator\EmojiTransliterator; +use SwissKnife202405\Symfony\Component\String\AbstractUnicodeString; +use SwissKnife202405\Symfony\Component\String\UnicodeString; +use SwissKnife202405\Symfony\Contracts\Translation\LocaleAwareInterface; +if (!\interface_exists(LocaleAwareInterface::class)) { + throw new \LogicException('You cannot use the "Symfony\\Component\\String\\Slugger\\AsciiSlugger" as the "symfony/translation-contracts" package is not installed. Try running "composer require symfony/translation-contracts".'); +} +/** + * @author Titouan Galopin + */ +class AsciiSlugger implements SluggerInterface, LocaleAwareInterface +{ + private const LOCALE_TO_TRANSLITERATOR_ID = ['am' => 'Amharic-Latin', 'ar' => 'Arabic-Latin', 'az' => 'Azerbaijani-Latin', 'be' => 'Belarusian-Latin', 'bg' => 'Bulgarian-Latin', 'bn' => 'Bengali-Latin', 'de' => 'de-ASCII', 'el' => 'Greek-Latin', 'fa' => 'Persian-Latin', 'he' => 'Hebrew-Latin', 'hy' => 'Armenian-Latin', 'ka' => 'Georgian-Latin', 'kk' => 'Kazakh-Latin', 'ky' => 'Kirghiz-Latin', 'ko' => 'Korean-Latin', 'mk' => 'Macedonian-Latin', 'mn' => 'Mongolian-Latin', 'or' => 'Oriya-Latin', 'ps' => 'Pashto-Latin', 'ru' => 'Russian-Latin', 'sr' => 'Serbian-Latin', 'sr_Cyrl' => 'Serbian-Latin', 'th' => 'Thai-Latin', 'tk' => 'Turkmen-Latin', 'uk' => 'Ukrainian-Latin', 'uz' => 'Uzbek-Latin', 'zh' => 'Han-Latin']; + /** + * @var string|null + */ + private $defaultLocale; + /** + * @var \Closure|mixed[] + */ + private $symbolsMap = ['en' => ['@' => 'at', '&' => 'and']]; + /** + * @var bool|string + */ + private $emoji = \false; + /** + * Cache of transliterators per locale. + * + * @var \Transliterator[] + */ + private $transliterators = []; + /** + * @param mixed[]|\Closure|null $symbolsMap + */ + public function __construct(?string $defaultLocale = null, $symbolsMap = null) + { + $this->defaultLocale = $defaultLocale; + $this->symbolsMap = $symbolsMap ?? $this->symbolsMap; + } + public function setLocale(string $locale) : void + { + $this->defaultLocale = $locale; + } + public function getLocale() : string + { + return $this->defaultLocale; + } + /** + * @param bool|string $emoji true will use the same locale, + * false will disable emoji, + * and a string to use a specific locale + * @return static + */ + public function withEmoji($emoji = \true) + { + if (\false !== $emoji && !\class_exists(EmojiTransliterator::class)) { + throw new \LogicException(\sprintf('You cannot use the "%s()" method as the "symfony/intl" package is not installed. Try running "composer require symfony/intl".', __METHOD__)); + } + $new = clone $this; + $new->emoji = $emoji; + return $new; + } + public function slug(string $string, string $separator = '-', ?string $locale = null) : AbstractUnicodeString + { + $locale = $locale ?? $this->defaultLocale; + $transliterator = []; + if ($locale && ('de' === $locale || \strncmp($locale, 'de_', \strlen('de_')) === 0)) { + // Use the shortcut for German in UnicodeString::ascii() if possible (faster and no requirement on intl) + $transliterator = ['de-ASCII']; + } elseif (\function_exists('transliterator_transliterate') && $locale) { + $transliterator = (array) $this->createTransliterator($locale); + } + if ($emojiTransliterator = $this->createEmojiTransliterator($locale)) { + $transliterator[] = $emojiTransliterator; + } + if ($this->symbolsMap instanceof \Closure) { + // If the symbols map is passed as a closure, there is no need to fallback to the parent locale + // as the closure can just provide substitutions for all locales of interest. + $symbolsMap = $this->symbolsMap; + \array_unshift($transliterator, static function ($s) use($symbolsMap, $locale) { + return $symbolsMap($s, $locale); + }); + } + $unicodeString = (new UnicodeString($string))->ascii($transliterator); + if (\is_array($this->symbolsMap)) { + $map = null; + if (isset($this->symbolsMap[$locale])) { + $map = $this->symbolsMap[$locale]; + } else { + $parent = self::getParentLocale($locale); + if ($parent && isset($this->symbolsMap[$parent])) { + $map = $this->symbolsMap[$parent]; + } + } + if ($map) { + foreach ($map as $char => $replace) { + $unicodeString = $unicodeString->replace($char, ' ' . $replace . ' '); + } + } + } + return $unicodeString->replaceMatches('/[^A-Za-z0-9]++/', $separator)->trim($separator); + } + private function createTransliterator(string $locale) : ?\Transliterator + { + if (\array_key_exists($locale, $this->transliterators)) { + return $this->transliterators[$locale]; + } + // Exact locale supported, cache and return + if ($id = self::LOCALE_TO_TRANSLITERATOR_ID[$locale] ?? null) { + return $this->transliterators[$locale] = \Transliterator::create($id . '/BGN') ?? \Transliterator::create($id); + } + // Locale not supported and no parent, fallback to any-latin + if (!($parent = self::getParentLocale($locale))) { + return $this->transliterators[$locale] = null; + } + // Try to use the parent locale (ie. try "de" for "de_AT") and cache both locales + if ($id = self::LOCALE_TO_TRANSLITERATOR_ID[$parent] ?? null) { + $transliterator = \Transliterator::create($id . '/BGN') ?? \Transliterator::create($id); + } + return $this->transliterators[$locale] = $this->transliterators[$parent] = $transliterator ?? null; + } + private function createEmojiTransliterator(?string $locale) : ?EmojiTransliterator + { + if (\is_string($this->emoji)) { + $locale = $this->emoji; + } elseif (!$this->emoji) { + return null; + } + while (null !== $locale) { + try { + return EmojiTransliterator::create("emoji-{$locale}"); + } catch (\IntlException $exception) { + $locale = self::getParentLocale($locale); + } + } + return null; + } + private static function getParentLocale(?string $locale) : ?string + { + if (!$locale) { + return null; + } + if (\false === ($str = \strrchr($locale, '_'))) { + // no parent locale + return null; + } + return \substr($locale, 0, -\strlen($str)); + } +} diff --git a/vendor/symfony/string/Slugger/SluggerInterface.php b/vendor/symfony/string/Slugger/SluggerInterface.php new file mode 100644 index 0000000000..274d8cd882 --- /dev/null +++ b/vendor/symfony/string/Slugger/SluggerInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\String\Slugger; + +use SwissKnife202405\Symfony\Component\String\AbstractUnicodeString; +/** + * Creates a URL-friendly slug from a given string. + * + * @author Titouan Galopin + */ +interface SluggerInterface +{ + /** + * Creates a slug for the given string and locale, using appropriate transliteration when needed. + */ + public function slug(string $string, string $separator = '-', ?string $locale = null) : AbstractUnicodeString; +} diff --git a/vendor/symfony/string/UnicodeString.php b/vendor/symfony/string/UnicodeString.php new file mode 100644 index 0000000000..4da902d87a --- /dev/null +++ b/vendor/symfony/string/UnicodeString.php @@ -0,0 +1,338 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Symfony\Component\String; + +use SwissKnife202405\Symfony\Component\String\Exception\ExceptionInterface; +use SwissKnife202405\Symfony\Component\String\Exception\InvalidArgumentException; +/** + * Represents a string of Unicode grapheme clusters encoded as UTF-8. + * + * A letter followed by combining characters (accents typically) form what Unicode defines + * as a grapheme cluster: a character as humans mean it in written texts. This class knows + * about the concept and won't split a letter apart from its combining accents. It also + * ensures all string comparisons happen on their canonically-composed representation, + * ignoring e.g. the order in which accents are listed when a letter has many of them. + * + * @see https://unicode.org/reports/tr15/ + * + * @author Nicolas Grekas + * @author Hugo Hamon + * + * @throws ExceptionInterface + */ +class UnicodeString extends AbstractUnicodeString +{ + public function __construct(string $string = '') + { + if ('' === $string || \normalizer_is_normalized($this->string = $string)) { + return; + } + if (\false === ($string = \normalizer_normalize($string))) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + $this->string = $string; + } + /** + * @return static + */ + public function append(string ...$suffix) + { + $str = clone $this; + $str->string = $this->string . (1 >= \count($suffix) ? $suffix[0] ?? '' : \implode('', $suffix)); + if (\normalizer_is_normalized($str->string)) { + return $str; + } + if (\false === ($string = \normalizer_normalize($str->string))) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + $str->string = $string; + return $str; + } + public function chunk(int $length = 1) : array + { + if (1 > $length) { + throw new InvalidArgumentException('The chunk length must be greater than zero.'); + } + if ('' === $this->string) { + return []; + } + $rx = '/('; + while (65535 < $length) { + $rx .= '\\X{65535}'; + $length -= 65535; + } + $rx .= '\\X{' . $length . '})/u'; + $str = clone $this; + $chunks = []; + foreach (\preg_split($rx, $this->string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY) as $chunk) { + $str->string = $chunk; + $chunks[] = clone $str; + } + return $chunks; + } + /** + * @param string|iterable|\Symfony\Component\String\AbstractString $suffix + */ + public function endsWith($suffix) : bool + { + if ($suffix instanceof AbstractString) { + $suffix = $suffix->string; + } elseif (!\is_string($suffix)) { + return parent::endsWith($suffix); + } + $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; + \normalizer_is_normalized($suffix, $form) ?: ($suffix = \normalizer_normalize($suffix, $form)); + if ('' === $suffix || \false === $suffix) { + return \false; + } + if ($this->ignoreCase) { + return 0 === \mb_stripos(\grapheme_extract($this->string, \strlen($suffix), \GRAPHEME_EXTR_MAXBYTES, \strlen($this->string) - \strlen($suffix)), $suffix, 0, 'UTF-8'); + } + return $suffix === \grapheme_extract($this->string, \strlen($suffix), \GRAPHEME_EXTR_MAXBYTES, \strlen($this->string) - \strlen($suffix)); + } + /** + * @param string|iterable|\Symfony\Component\String\AbstractString $string + */ + public function equalsTo($string) : bool + { + if ($string instanceof AbstractString) { + $string = $string->string; + } elseif (!\is_string($string)) { + return parent::equalsTo($string); + } + $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; + \normalizer_is_normalized($string, $form) ?: ($string = \normalizer_normalize($string, $form)); + if ('' !== $string && \false !== $string && $this->ignoreCase) { + return \strlen($string) === \strlen($this->string) && 0 === \mb_stripos($this->string, $string, 0, 'UTF-8'); + } + return $string === $this->string; + } + /** + * @param string|iterable|\Symfony\Component\String\AbstractString $needle + */ + public function indexOf($needle, int $offset = 0) : ?int + { + if ($needle instanceof AbstractString) { + $needle = $needle->string; + } elseif (!\is_string($needle)) { + return parent::indexOf($needle, $offset); + } + $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; + \normalizer_is_normalized($needle, $form) ?: ($needle = \normalizer_normalize($needle, $form)); + if ('' === $needle || \false === $needle) { + return null; + } + try { + $i = $this->ignoreCase ? \grapheme_stripos($this->string, $needle, $offset) : \grapheme_strpos($this->string, $needle, $offset); + } catch (\ValueError $exception) { + return null; + } + return \false === $i ? null : $i; + } + /** + * @param string|iterable|\Symfony\Component\String\AbstractString $needle + */ + public function indexOfLast($needle, int $offset = 0) : ?int + { + if ($needle instanceof AbstractString) { + $needle = $needle->string; + } elseif (!\is_string($needle)) { + return parent::indexOfLast($needle, $offset); + } + $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; + \normalizer_is_normalized($needle, $form) ?: ($needle = \normalizer_normalize($needle, $form)); + if ('' === $needle || \false === $needle) { + return null; + } + $string = $this->string; + if (0 > $offset) { + // workaround https://bugs.php.net/74264 + if (0 > ($offset += \grapheme_strlen($needle))) { + $string = \grapheme_substr($string, 0, $offset); + } + $offset = 0; + } + $i = $this->ignoreCase ? \grapheme_strripos($string, $needle, $offset) : \grapheme_strrpos($string, $needle, $offset); + return \false === $i ? null : $i; + } + /** + * @return static + */ + public function join(array $strings, ?string $lastGlue = null) + { + $str = parent::join($strings, $lastGlue); + \normalizer_is_normalized($str->string) ?: ($str->string = \normalizer_normalize($str->string)); + return $str; + } + public function length() : int + { + return \grapheme_strlen($this->string); + } + /** + * @return static + */ + public function normalize(int $form = self::NFC) + { + $str = clone $this; + if (\in_array($form, [self::NFC, self::NFKC], \true)) { + \normalizer_is_normalized($str->string, $form) ?: ($str->string = \normalizer_normalize($str->string, $form)); + } elseif (!\in_array($form, [self::NFD, self::NFKD], \true)) { + throw new InvalidArgumentException('Unsupported normalization form.'); + } elseif (!\normalizer_is_normalized($str->string, $form)) { + $str->string = \normalizer_normalize($str->string, $form); + $str->ignoreCase = null; + } + return $str; + } + /** + * @return static + */ + public function prepend(string ...$prefix) + { + $str = clone $this; + $str->string = (1 >= \count($prefix) ? $prefix[0] ?? '' : \implode('', $prefix)) . $this->string; + if (\normalizer_is_normalized($str->string)) { + return $str; + } + if (\false === ($string = \normalizer_normalize($str->string))) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + $str->string = $string; + return $str; + } + /** + * @return static + */ + public function replace(string $from, string $to) + { + $str = clone $this; + \normalizer_is_normalized($from) ?: ($from = \normalizer_normalize($from)); + if ('' !== $from && \false !== $from) { + $tail = $str->string; + $result = ''; + $indexOf = $this->ignoreCase ? 'grapheme_stripos' : 'grapheme_strpos'; + while ('' !== $tail && \false !== ($i = $indexOf($tail, $from))) { + $slice = \grapheme_substr($tail, 0, $i); + $result .= $slice . $to; + $tail = \substr($tail, \strlen($slice) + \strlen($from)); + } + $str->string = $result . $tail; + if (\normalizer_is_normalized($str->string)) { + return $str; + } + if (\false === ($string = \normalizer_normalize($str->string))) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + $str->string = $string; + } + return $str; + } + /** + * @param string|callable $to + * @return static + */ + public function replaceMatches(string $fromRegexp, $to) + { + $str = parent::replaceMatches($fromRegexp, $to); + \normalizer_is_normalized($str->string) ?: ($str->string = \normalizer_normalize($str->string)); + return $str; + } + /** + * @return static + */ + public function slice(int $start = 0, ?int $length = null) + { + $str = clone $this; + $str->string = (string) \grapheme_substr($this->string, $start, $length ?? 2147483647); + return $str; + } + /** + * @return static + */ + public function splice(string $replacement, int $start = 0, ?int $length = null) + { + $str = clone $this; + $start = $start ? \strlen(\grapheme_substr($this->string, 0, $start)) : 0; + $length = $length ? \strlen(\grapheme_substr($this->string, $start, $length ?? 2147483647)) : $length; + $str->string = \substr_replace($this->string, $replacement, $start, $length ?? 2147483647); + if (\normalizer_is_normalized($str->string)) { + return $str; + } + if (\false === ($string = \normalizer_normalize($str->string))) { + throw new InvalidArgumentException('Invalid UTF-8 string.'); + } + $str->string = $string; + return $str; + } + public function split(string $delimiter, ?int $limit = null, ?int $flags = null) : array + { + if (1 > ($limit = $limit ?? 2147483647)) { + throw new InvalidArgumentException('Split limit must be a positive integer.'); + } + if ('' === $delimiter) { + throw new InvalidArgumentException('Split delimiter is empty.'); + } + if (null !== $flags) { + return parent::split($delimiter . 'u', $limit, $flags); + } + \normalizer_is_normalized($delimiter) ?: ($delimiter = \normalizer_normalize($delimiter)); + if (\false === $delimiter) { + throw new InvalidArgumentException('Split delimiter is not a valid UTF-8 string.'); + } + $str = clone $this; + $tail = $this->string; + $chunks = []; + $indexOf = $this->ignoreCase ? 'grapheme_stripos' : 'grapheme_strpos'; + while (1 < $limit && \false !== ($i = $indexOf($tail, $delimiter))) { + $str->string = \grapheme_substr($tail, 0, $i); + $chunks[] = clone $str; + $tail = \substr($tail, \strlen($str->string) + \strlen($delimiter)); + --$limit; + } + $str->string = $tail; + $chunks[] = clone $str; + return $chunks; + } + /** + * @param string|iterable|\Symfony\Component\String\AbstractString $prefix + */ + public function startsWith($prefix) : bool + { + if ($prefix instanceof AbstractString) { + $prefix = $prefix->string; + } elseif (!\is_string($prefix)) { + return parent::startsWith($prefix); + } + $form = null === $this->ignoreCase ? \Normalizer::NFD : \Normalizer::NFC; + \normalizer_is_normalized($prefix, $form) ?: ($prefix = \normalizer_normalize($prefix, $form)); + if ('' === $prefix || \false === $prefix) { + return \false; + } + if ($this->ignoreCase) { + return 0 === \mb_stripos(\grapheme_extract($this->string, \strlen($prefix), \GRAPHEME_EXTR_MAXBYTES), $prefix, 0, 'UTF-8'); + } + return $prefix === \grapheme_extract($this->string, \strlen($prefix), \GRAPHEME_EXTR_MAXBYTES); + } + public function __wakeup() : void + { + if (!\is_string($this->string)) { + throw new \BadMethodCallException('Cannot unserialize ' . __CLASS__); + } + \normalizer_is_normalized($this->string) ?: ($this->string = \normalizer_normalize($this->string)); + } + public function __clone() + { + if (null === $this->ignoreCase) { + \normalizer_is_normalized($this->string) ?: ($this->string = \normalizer_normalize($this->string)); + } + $this->ignoreCase = \false; + } +} diff --git a/vendor/symfony/string/composer.json b/vendor/symfony/string/composer.json new file mode 100644 index 0000000000..eb95e76537 --- /dev/null +++ b/vendor/symfony/string/composer.json @@ -0,0 +1,54 @@ +{ + "name": "symfony\/string", + "type": "library", + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "keywords": [ + "string", + "utf8", + "utf-8", + "grapheme", + "i18n", + "unicode" + ], + "homepage": "https:\/\/symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https:\/\/symfony.com\/contributors" + } + ], + "require": { + "php": ">=8.2", + "symfony\/polyfill-ctype": "~1.8", + "symfony\/polyfill-intl-grapheme": "~1.0", + "symfony\/polyfill-intl-normalizer": "~1.0", + "symfony\/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "symfony\/error-handler": "^6.4|^7.0", + "symfony\/intl": "^6.4|^7.0", + "symfony\/http-client": "^6.4|^7.0", + "symfony\/translation-contracts": "^2.5|^3.0", + "symfony\/var-exporter": "^6.4|^7.0" + }, + "conflict": { + "symfony\/translation-contracts": "<2.5" + }, + "autoload": { + "psr-4": { + "SwissKnife202405\\Symfony\\Component\\String\\": "" + }, + "files": [ + "Resources\/functions.php" + ], + "exclude-from-classmap": [ + "\/Tests\/" + ] + }, + "minimum-stability": "dev" +} \ No newline at end of file diff --git a/vendor/webmozart/assert/CHANGELOG.md b/vendor/webmozart/assert/CHANGELOG.md new file mode 100644 index 0000000000..56c8011dee --- /dev/null +++ b/vendor/webmozart/assert/CHANGELOG.md @@ -0,0 +1,207 @@ +Changelog +========= + +## UNRELEASED + +## 1.11.0 + +### Added + +* Added explicit (non magic) `allNullOr*` methods, with `@psalm-assert` annotations, for better Psalm support. + +### Changed + +* Trait methods will now check the assertion themselves, instead of using `__callStatic` +* `isList` will now deal correctly with (modified) lists that contain `NaN` +* `reportInvalidArgument` now has a return type of `never`. + +### Removed + +* Removed `symfony/polyfill-ctype` as a dependency, and require `ext-cytpe` instead. + * You can still require the `symfony/polyfill-ctype` in your project if you need it, as it provides `ext-ctype` + +## 1.10.0 + +### Added + +* On invalid assertion, we throw a `Webmozart\Assert\InvalidArgumentException` +* Added `Assert::positiveInteger()` + +### Changed + +* Using a trait with real implementations of `all*()` and `nullOr*()` methods to improve psalm compatibility. + +### Removed + +* Support for PHP <7.2 + +## 1.9.1 + +## Fixed + +* provisional support for PHP 8.0 + +## 1.9.0 + +* added better Psalm support for `all*` & `nullOr*` methods +* These methods are now understood by Psalm through a mixin. You may need a newer version of Psalm in order to use this +* added `@psalm-pure` annotation to `Assert::notFalse()` +* added more `@psalm-assert` annotations where appropriate + +## Changed + +* the `all*` & `nullOr*` methods are now declared on an interface, instead of `@method` annotations. +This interface is linked to the `Assert` class with a `@mixin` annotation. Most IDE's have supported this +for a long time, and you should not lose any autocompletion capabilities. PHPStan has supported this since +version `0.12.20`. This package is marked incompatible (with a composer conflict) with phpstan version prior to that. +If you do not use PHPStan than this does not matter. + +## 1.8.0 + +### Added + +* added `Assert::notStartsWith()` +* added `Assert::notEndsWith()` +* added `Assert::inArray()` +* added `@psalm-pure` annotations to pure assertions + +### Fixed + +* Exception messages of comparisons between `DateTime(Immutable)` objects now display their date & time. +* Custom Exception messages for `Assert::count()` now use the values to render the exception message. + +## 1.7.0 (2020-02-14) + +### Added + +* added `Assert::notFalse()` +* added `Assert::isAOf()` +* added `Assert::isAnyOf()` +* added `Assert::isNotA()` + +## 1.6.0 (2019-11-24) + +### Added + +* added `Assert::validArrayKey()` +* added `Assert::isNonEmptyList()` +* added `Assert::isNonEmptyMap()` +* added `@throws InvalidArgumentException` annotations to all methods that throw. +* added `@psalm-assert` for the list type to the `isList` assertion. + +### Fixed + +* `ResourceBundle` & `SimpleXMLElement` now pass the `isCountable` assertions. +They are countable, without implementing the `Countable` interface. +* The doc block of `range` now has the proper variables. +* An empty array will now pass `isList` and `isMap`. As it is a valid form of both. +If a non-empty variant is needed, use `isNonEmptyList` or `isNonEmptyMap`. + +### Changed + +* Removed some `@psalm-assert` annotations, that were 'side effect' assertions See: + * [#144](https://github.com/webmozart/assert/pull/144) + * [#145](https://github.com/webmozart/assert/issues/145) + * [#146](https://github.com/webmozart/assert/pull/146) + * [#150](https://github.com/webmozart/assert/pull/150) +* If you use Psalm, the minimum version needed is `3.6.0`. Which is enforced through a composer conflict. +If you don't use Psalm, then this has no impact. + +## 1.5.0 (2019-08-24) + +### Added + +* added `Assert::uniqueValues()` +* added `Assert::unicodeLetters()` +* added: `Assert::email()` +* added support for [Psalm](https://github.com/vimeo/psalm), by adding `@psalm-assert` annotations where appropriate. + +### Fixed + +* `Assert::endsWith()` would not give the correct result when dealing with a multibyte suffix. +* `Assert::length(), minLength, maxLength, lengthBetween` would not give the correct result when dealing with multibyte characters. + +**NOTE**: These 2 changes may break your assertions if you relied on the fact that multibyte characters didn't behave correctly. + +### Changed + +* The names of some variables have been updated to better reflect what they are. +* All function calls are now in their FQN form, slightly increasing performance. +* Tests are now properly ran against HHVM-3.30 and PHP nightly. + +### Deprecation + +* deprecated `Assert::isTraversable()` in favor of `Assert::isIterable()` + * This was already done in 1.3.0, but it was only done through a silenced `trigger_error`. It is now annotated as well. + +## 1.4.0 (2018-12-25) + +### Added + +* added `Assert::ip()` +* added `Assert::ipv4()` +* added `Assert::ipv6()` +* added `Assert::notRegex()` +* added `Assert::interfaceExists()` +* added `Assert::isList()` +* added `Assert::isMap()` +* added polyfill for ctype + +### Fixed + +* Special case when comparing objects implementing `__toString()` + +## 1.3.0 (2018-01-29) + +### Added + +* added `Assert::minCount()` +* added `Assert::maxCount()` +* added `Assert::countBetween()` +* added `Assert::isCountable()` +* added `Assert::notWhitespaceOnly()` +* added `Assert::natural()` +* added `Assert::notContains()` +* added `Assert::isArrayAccessible()` +* added `Assert::isInstanceOfAny()` +* added `Assert::isIterable()` + +### Fixed + +* `stringNotEmpty` will no longer report "0" is an empty string + +### Deprecation + +* deprecated `Assert::isTraversable()` in favor of `Assert::isIterable()` + +## 1.2.0 (2016-11-23) + + * added `Assert::throws()` + * added `Assert::count()` + * added extension point `Assert::reportInvalidArgument()` for custom subclasses + +## 1.1.0 (2016-08-09) + + * added `Assert::object()` + * added `Assert::propertyExists()` + * added `Assert::propertyNotExists()` + * added `Assert::methodExists()` + * added `Assert::methodNotExists()` + * added `Assert::uuid()` + +## 1.0.2 (2015-08-24) + + * integrated Style CI + * add tests for minimum package dependencies on Travis CI + +## 1.0.1 (2015-05-12) + + * added support for PHP 5.3.3 + +## 1.0.0 (2015-05-12) + + * first stable release + +## 1.0.0-beta (2015-03-19) + + * first beta release diff --git a/vendor/webmozart/assert/LICENSE b/vendor/webmozart/assert/LICENSE new file mode 100644 index 0000000000..9e2e3075eb --- /dev/null +++ b/vendor/webmozart/assert/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2014 Bernhard Schussek + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/webmozart/assert/README.md b/vendor/webmozart/assert/README.md new file mode 100644 index 0000000000..3b2397a1ab --- /dev/null +++ b/vendor/webmozart/assert/README.md @@ -0,0 +1,287 @@ +Webmozart Assert +================ + +[![Latest Stable Version](https://poser.pugx.org/webmozart/assert/v/stable.svg)](https://packagist.org/packages/webmozart/assert) +[![Total Downloads](https://poser.pugx.org/webmozart/assert/downloads.svg)](https://packagist.org/packages/webmozart/assert) + +This library contains efficient assertions to test the input and output of +your methods. With these assertions, you can greatly reduce the amount of coding +needed to write a safe implementation. + +All assertions in the [`Assert`] class throw an `Webmozart\Assert\InvalidArgumentException` if +they fail. + +FAQ +--- + +**What's the difference to [beberlei/assert]?** + +This library is heavily inspired by Benjamin Eberlei's wonderful [assert package], +but fixes a usability issue with error messages that can't be fixed there without +breaking backwards compatibility. + +This package features usable error messages by default. However, you can also +easily write custom error messages: + +``` +Assert::string($path, 'The path is expected to be a string. Got: %s'); +``` + +In [beberlei/assert], the ordering of the `%s` placeholders is different for +every assertion. This package, on the contrary, provides consistent placeholder +ordering for all assertions: + +* `%s`: The tested value as string, e.g. `"/foo/bar"`. +* `%2$s`, `%3$s`, ...: Additional assertion-specific values, e.g. the + minimum/maximum length, allowed values, etc. + +Check the source code of the assertions to find out details about the additional +available placeholders. + +Installation +------------ + +Use [Composer] to install the package: + +```bash +composer require webmozart/assert +``` + +Example +------- + +```php +use Webmozart\Assert\Assert; + +class Employee +{ + public function __construct($id) + { + Assert::integer($id, 'The employee ID must be an integer. Got: %s'); + Assert::greaterThan($id, 0, 'The employee ID must be a positive integer. Got: %s'); + } +} +``` + +If you create an employee with an invalid ID, an exception is thrown: + +```php +new Employee('foobar'); +// => Webmozart\Assert\InvalidArgumentException: +// The employee ID must be an integer. Got: string + +new Employee(-10); +// => Webmozart\Assert\InvalidArgumentException: +// The employee ID must be a positive integer. Got: -10 +``` + +Assertions +---------- + +The [`Assert`] class provides the following assertions: + +### Type Assertions + +Method | Description +-------------------------------------------------------- | -------------------------------------------------- +`string($value, $message = '')` | Check that a value is a string +`stringNotEmpty($value, $message = '')` | Check that a value is a non-empty string +`integer($value, $message = '')` | Check that a value is an integer +`integerish($value, $message = '')` | Check that a value casts to an integer +`positiveInteger($value, $message = '')` | Check that a value is a positive (non-zero) integer +`float($value, $message = '')` | Check that a value is a float +`numeric($value, $message = '')` | Check that a value is numeric +`natural($value, $message= ''')` | Check that a value is a non-negative integer +`boolean($value, $message = '')` | Check that a value is a boolean +`scalar($value, $message = '')` | Check that a value is a scalar +`object($value, $message = '')` | Check that a value is an object +`resource($value, $type = null, $message = '')` | Check that a value is a resource +`isCallable($value, $message = '')` | Check that a value is a callable +`isArray($value, $message = '')` | Check that a value is an array +`isTraversable($value, $message = '')` (deprecated) | Check that a value is an array or a `\Traversable` +`isIterable($value, $message = '')` | Check that a value is an array or a `\Traversable` +`isCountable($value, $message = '')` | Check that a value is an array or a `\Countable` +`isInstanceOf($value, $class, $message = '')` | Check that a value is an `instanceof` a class +`isInstanceOfAny($value, array $classes, $message = '')` | Check that a value is an `instanceof` at least one class on the array of classes +`notInstanceOf($value, $class, $message = '')` | Check that a value is not an `instanceof` a class +`isAOf($value, $class, $message = '')` | Check that a value is of the class or has one of its parents +`isAnyOf($value, array $classes, $message = '')` | Check that a value is of at least one of the classes or has one of its parents +`isNotA($value, $class, $message = '')` | Check that a value is not of the class or has not one of its parents +`isArrayAccessible($value, $message = '')` | Check that a value can be accessed as an array +`uniqueValues($values, $message = '')` | Check that the given array contains unique values + +### Comparison Assertions + +Method | Description +----------------------------------------------- | ------------------------------------------------------------------ +`true($value, $message = '')` | Check that a value is `true` +`false($value, $message = '')` | Check that a value is `false` +`notFalse($value, $message = '')` | Check that a value is not `false` +`null($value, $message = '')` | Check that a value is `null` +`notNull($value, $message = '')` | Check that a value is not `null` +`isEmpty($value, $message = '')` | Check that a value is `empty()` +`notEmpty($value, $message = '')` | Check that a value is not `empty()` +`eq($value, $value2, $message = '')` | Check that a value equals another (`==`) +`notEq($value, $value2, $message = '')` | Check that a value does not equal another (`!=`) +`same($value, $value2, $message = '')` | Check that a value is identical to another (`===`) +`notSame($value, $value2, $message = '')` | Check that a value is not identical to another (`!==`) +`greaterThan($value, $value2, $message = '')` | Check that a value is greater than another +`greaterThanEq($value, $value2, $message = '')` | Check that a value is greater than or equal to another +`lessThan($value, $value2, $message = '')` | Check that a value is less than another +`lessThanEq($value, $value2, $message = '')` | Check that a value is less than or equal to another +`range($value, $min, $max, $message = '')` | Check that a value is within a range +`inArray($value, array $values, $message = '')` | Check that a value is one of a list of values +`oneOf($value, array $values, $message = '')` | Check that a value is one of a list of values (alias of `inArray`) + +### String Assertions + +You should check that a value is a string with `Assert::string()` before making +any of the following assertions. + +Method | Description +--------------------------------------------------- | ----------------------------------------------------------------- +`contains($value, $subString, $message = '')` | Check that a string contains a substring +`notContains($value, $subString, $message = '')` | Check that a string does not contain a substring +`startsWith($value, $prefix, $message = '')` | Check that a string has a prefix +`notStartsWith($value, $prefix, $message = '')` | Check that a string does not have a prefix +`startsWithLetter($value, $message = '')` | Check that a string starts with a letter +`endsWith($value, $suffix, $message = '')` | Check that a string has a suffix +`notEndsWith($value, $suffix, $message = '')` | Check that a string does not have a suffix +`regex($value, $pattern, $message = '')` | Check that a string matches a regular expression +`notRegex($value, $pattern, $message = '')` | Check that a string does not match a regular expression +`unicodeLetters($value, $message = '')` | Check that a string contains Unicode letters only +`alpha($value, $message = '')` | Check that a string contains letters only +`digits($value, $message = '')` | Check that a string contains digits only +`alnum($value, $message = '')` | Check that a string contains letters and digits only +`lower($value, $message = '')` | Check that a string contains lowercase characters only +`upper($value, $message = '')` | Check that a string contains uppercase characters only +`length($value, $length, $message = '')` | Check that a string has a certain number of characters +`minLength($value, $min, $message = '')` | Check that a string has at least a certain number of characters +`maxLength($value, $max, $message = '')` | Check that a string has at most a certain number of characters +`lengthBetween($value, $min, $max, $message = '')` | Check that a string has a length in the given range +`uuid($value, $message = '')` | Check that a string is a valid UUID +`ip($value, $message = '')` | Check that a string is a valid IP (either IPv4 or IPv6) +`ipv4($value, $message = '')` | Check that a string is a valid IPv4 +`ipv6($value, $message = '')` | Check that a string is a valid IPv6 +`email($value, $message = '')` | Check that a string is a valid e-mail address +`notWhitespaceOnly($value, $message = '')` | Check that a string contains at least one non-whitespace character + +### File Assertions + +Method | Description +----------------------------------- | -------------------------------------------------- +`fileExists($value, $message = '')` | Check that a value is an existing path +`file($value, $message = '')` | Check that a value is an existing file +`directory($value, $message = '')` | Check that a value is an existing directory +`readable($value, $message = '')` | Check that a value is a readable path +`writable($value, $message = '')` | Check that a value is a writable path + +### Object Assertions + +Method | Description +----------------------------------------------------- | -------------------------------------------------- +`classExists($value, $message = '')` | Check that a value is an existing class name +`subclassOf($value, $class, $message = '')` | Check that a class is a subclass of another +`interfaceExists($value, $message = '')` | Check that a value is an existing interface name +`implementsInterface($value, $class, $message = '')` | Check that a class implements an interface +`propertyExists($value, $property, $message = '')` | Check that a property exists in a class/object +`propertyNotExists($value, $property, $message = '')` | Check that a property does not exist in a class/object +`methodExists($value, $method, $message = '')` | Check that a method exists in a class/object +`methodNotExists($value, $method, $message = '')` | Check that a method does not exist in a class/object + +### Array Assertions + +Method | Description +-------------------------------------------------- | ------------------------------------------------------------------ +`keyExists($array, $key, $message = '')` | Check that a key exists in an array +`keyNotExists($array, $key, $message = '')` | Check that a key does not exist in an array +`validArrayKey($key, $message = '')` | Check that a value is a valid array key (int or string) +`count($array, $number, $message = '')` | Check that an array contains a specific number of elements +`minCount($array, $min, $message = '')` | Check that an array contains at least a certain number of elements +`maxCount($array, $max, $message = '')` | Check that an array contains at most a certain number of elements +`countBetween($array, $min, $max, $message = '')` | Check that an array has a count in the given range +`isList($array, $message = '')` | Check that an array is a non-associative list +`isNonEmptyList($array, $message = '')` | Check that an array is a non-associative list, and not empty +`isMap($array, $message = '')` | Check that an array is associative and has strings as keys +`isNonEmptyMap($array, $message = '')` | Check that an array is associative and has strings as keys, and is not empty + +### Function Assertions + +Method | Description +------------------------------------------- | ----------------------------------------------------------------------------------------------------- +`throws($closure, $class, $message = '')` | Check that a function throws a certain exception. Subclasses of the exception class will be accepted. + +### Collection Assertions + +All of the above assertions can be prefixed with `all*()` to test the contents +of an array or a `\Traversable`: + +```php +Assert::allIsInstanceOf($employees, 'Acme\Employee'); +``` + +### Nullable Assertions + +All of the above assertions can be prefixed with `nullOr*()` to run the +assertion only if it the value is not `null`: + +```php +Assert::nullOrString($middleName, 'The middle name must be a string or null. Got: %s'); +``` + +### Extending Assert + +The `Assert` class comes with a few methods, which can be overridden to change the class behaviour. You can also extend it to +add your own assertions. + +#### Overriding methods + +Overriding the following methods in your assertion class allows you to change the behaviour of the assertions: + +* `public static function __callStatic($name, $arguments)` + * This method is used to 'create' the `nullOr` and `all` versions of the assertions. +* `protected static function valueToString($value)` + * This method is used for error messages, to convert the value to a string value for displaying. You could use this for representing a value object with a `__toString` method for example. +* `protected static function typeToString($value)` + * This method is used for error messages, to convert the a value to a string representing its type. +* `protected static function strlen($value)` + * This method is used to calculate string length for relevant methods, using the `mb_strlen` if available and useful. +* `protected static function reportInvalidArgument($message)` + * This method is called when an assertion fails, with the specified error message. Here you can throw your own exception, or log something. + +## Static analysis support + +Where applicable, assertion functions are annotated to support Psalm's +[Assertion syntax](https://psalm.dev/docs/annotating_code/assertion_syntax/). +A dedicated [PHPStan Plugin](https://github.com/phpstan/phpstan-webmozart-assert) is +required for proper type support. + +Authors +------- + +* [Bernhard Schussek] a.k.a. [@webmozart] +* [The Community Contributors] + +Contribute +---------- + +Contributions to the package are always welcome! + +* Report any bugs or issues you find on the [issue tracker]. +* You can grab the source code at the package's [Git repository]. + +License +------- + +All contents of this package are licensed under the [MIT license]. + +[beberlei/assert]: https://github.com/beberlei/assert +[assert package]: https://github.com/beberlei/assert +[Composer]: https://getcomposer.org +[Bernhard Schussek]: https://webmozarts.com +[The Community Contributors]: https://github.com/webmozart/assert/graphs/contributors +[issue tracker]: https://github.com/webmozart/assert/issues +[Git repository]: https://github.com/webmozart/assert +[@webmozart]: https://twitter.com/webmozart +[MIT license]: LICENSE +[`Assert`]: src/Assert.php diff --git a/vendor/webmozart/assert/composer.json b/vendor/webmozart/assert/composer.json new file mode 100644 index 0000000000..da937898fc --- /dev/null +++ b/vendor/webmozart/assert/composer.json @@ -0,0 +1,43 @@ +{ + "name": "webmozart\/assert", + "description": "Assertions to validate method input\/output with nice error messages.", + "license": "MIT", + "keywords": [ + "assert", + "check", + "validate" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "require": { + "php": "^7.2 || ^8.0", + "ext-ctype": "*" + }, + "require-dev": { + "phpunit\/phpunit": "^8.5.13" + }, + "conflict": { + "phpstan\/phpstan": "<0.12.20", + "vimeo\/psalm": "<4.6.1 || 4.6.2" + }, + "autoload": { + "psr-4": { + "SwissKnife202405\\Webmozart\\Assert\\": "src\/" + } + }, + "autoload-dev": { + "psr-4": { + "SwissKnife202405\\Webmozart\\Assert\\Tests\\": "tests\/", + "SwissKnife202405\\Webmozart\\Assert\\Bin\\": "bin\/src" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + } +} \ No newline at end of file diff --git a/vendor/webmozart/assert/src/Assert.php b/vendor/webmozart/assert/src/Assert.php new file mode 100644 index 0000000000..6f7972e7d4 --- /dev/null +++ b/vendor/webmozart/assert/src/Assert.php @@ -0,0 +1,1606 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Webmozart\Assert; + +use ArrayAccess; +use BadMethodCallException; +use Closure; +use Countable; +use DateTime; +use DateTimeImmutable; +use Exception; +use ResourceBundle; +use SimpleXMLElement; +use Throwable; +use Traversable; +/** + * Efficient assertions to validate the input/output of your methods. + * + * @since 1.0 + * + * @author Bernhard Schussek + */ +class Assert +{ + use Mixin; + /** + * @psalm-pure + * @psalm-assert string $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function string($value, $message = '') + { + if (!\is_string($value)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a string. Got: %s', static::typeToString($value))); + } + } + /** + * @psalm-pure + * @psalm-assert non-empty-string $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function stringNotEmpty($value, $message = '') + { + static::string($value, $message); + static::notEq($value, '', $message); + } + /** + * @psalm-pure + * @psalm-assert int $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function integer($value, $message = '') + { + if (!\is_int($value)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected an integer. Got: %s', static::typeToString($value))); + } + } + /** + * @psalm-pure + * @psalm-assert numeric $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function integerish($value, $message = '') + { + if (!\is_numeric($value) || $value != (int) $value) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected an integerish value. Got: %s', static::typeToString($value))); + } + } + /** + * @psalm-pure + * @psalm-assert positive-int $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function positiveInteger($value, $message = '') + { + if (!(\is_int($value) && $value > 0)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a positive integer. Got: %s', static::valueToString($value))); + } + } + /** + * @psalm-pure + * @psalm-assert float $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function float($value, $message = '') + { + if (!\is_float($value)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a float. Got: %s', static::typeToString($value))); + } + } + /** + * @psalm-pure + * @psalm-assert numeric $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function numeric($value, $message = '') + { + if (!\is_numeric($value)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a numeric. Got: %s', static::typeToString($value))); + } + } + /** + * @psalm-pure + * @psalm-assert positive-int|0 $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function natural($value, $message = '') + { + if (!\is_int($value) || $value < 0) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a non-negative integer. Got: %s', static::valueToString($value))); + } + } + /** + * @psalm-pure + * @psalm-assert bool $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function boolean($value, $message = '') + { + if (!\is_bool($value)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a boolean. Got: %s', static::typeToString($value))); + } + } + /** + * @psalm-pure + * @psalm-assert scalar $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function scalar($value, $message = '') + { + if (!\is_scalar($value)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a scalar. Got: %s', static::typeToString($value))); + } + } + /** + * @psalm-pure + * @psalm-assert object $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function object($value, $message = '') + { + if (!\is_object($value)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected an object. Got: %s', static::typeToString($value))); + } + } + /** + * @psalm-pure + * @psalm-assert resource $value + * + * @param mixed $value + * @param string|null $type type of resource this should be. @see https://www.php.net/manual/en/function.get-resource-type.php + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function resource($value, $type = null, $message = '') + { + if (!\is_resource($value)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a resource. Got: %s', static::typeToString($value))); + } + if ($type && $type !== \get_resource_type($value)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a resource of type %2$s. Got: %s', static::typeToString($value), $type)); + } + } + /** + * @psalm-pure + * @psalm-assert callable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isCallable($value, $message = '') + { + if (!\is_callable($value)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a callable. Got: %s', static::typeToString($value))); + } + } + /** + * @psalm-pure + * @psalm-assert array $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isArray($value, $message = '') + { + if (!\is_array($value)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected an array. Got: %s', static::typeToString($value))); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @deprecated use "isIterable" or "isInstanceOf" instead + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isTraversable($value, $message = '') + { + @\trigger_error(\sprintf('The "%s" assertion is deprecated. You should stop using it, as it will soon be removed in 2.0 version. Use "isIterable" or "isInstanceOf" instead.', __METHOD__), \E_USER_DEPRECATED); + if (!\is_array($value) && !$value instanceof Traversable) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a traversable. Got: %s', static::typeToString($value))); + } + } + /** + * @psalm-pure + * @psalm-assert array|ArrayAccess $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isArrayAccessible($value, $message = '') + { + if (!\is_array($value) && !$value instanceof ArrayAccess) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected an array accessible. Got: %s', static::typeToString($value))); + } + } + /** + * @psalm-pure + * @psalm-assert countable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isCountable($value, $message = '') + { + if (!\is_array($value) && !$value instanceof Countable && !$value instanceof ResourceBundle && !$value instanceof SimpleXMLElement) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a countable. Got: %s', static::typeToString($value))); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isIterable($value, $message = '') + { + if (!\is_array($value) && !$value instanceof Traversable) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected an iterable. Got: %s', static::typeToString($value))); + } + } + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert ExpectedType $value + * + * @param mixed $value + * @param string|object $class + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isInstanceOf($value, $class, $message = '') + { + if (!$value instanceof $class) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected an instance of %2$s. Got: %s', static::typeToString($value), $class)); + } + } + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert !ExpectedType $value + * + * @param mixed $value + * @param string|object $class + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function notInstanceOf($value, $class, $message = '') + { + if ($value instanceof $class) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected an instance other than %2$s. Got: %s', static::typeToString($value), $class)); + } + } + /** + * @psalm-pure + * @psalm-param array $classes + * + * @param mixed $value + * @param array $classes + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isInstanceOfAny($value, array $classes, $message = '') + { + foreach ($classes as $class) { + if ($value instanceof $class) { + return; + } + } + static::reportInvalidArgument(\sprintf($message ?: 'Expected an instance of any of %2$s. Got: %s', static::typeToString($value), \implode(', ', \array_map(array(static::class, 'valueToString'), $classes)))); + } + /** + * @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 + * + * @throws InvalidArgumentException + */ + public static function isAOf($value, $class, $message = '') + { + static::string($class, 'Expected class as a string. Got: %s'); + if (!\is_a($value, $class, \is_string($value))) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected an instance of this class or to this class among its parents "%2$s". Got: %s', static::valueToString($value), $class)); + } + } + /** + * @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 + * + * @throws InvalidArgumentException + */ + public static function isNotA($value, $class, $message = '') + { + static::string($class, 'Expected class as a string. Got: %s'); + if (\is_a($value, $class, \is_string($value))) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected an instance of this class or to this class among its parents other than "%2$s". Got: %s', static::valueToString($value), $class)); + } + } + /** + * @psalm-pure + * @psalm-param array $classes + * + * @param object|string $value + * @param string[] $classes + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isAnyOf($value, array $classes, $message = '') + { + foreach ($classes as $class) { + static::string($class, 'Expected class as a string. Got: %s'); + if (\is_a($value, $class, \is_string($value))) { + return; + } + } + static::reportInvalidArgument(\sprintf($message ?: 'Expected an instance of any of this classes or any of those classes among their parents "%2$s". Got: %s', static::valueToString($value), \implode(', ', $classes))); + } + /** + * @psalm-pure + * @psalm-assert empty $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isEmpty($value, $message = '') + { + if (!empty($value)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected an empty value. Got: %s', static::valueToString($value))); + } + } + /** + * @psalm-pure + * @psalm-assert !empty $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function notEmpty($value, $message = '') + { + if (empty($value)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a non-empty value. Got: %s', static::valueToString($value))); + } + } + /** + * @psalm-pure + * @psalm-assert null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function null($value, $message = '') + { + if (null !== $value) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected null. Got: %s', static::valueToString($value))); + } + } + /** + * @psalm-pure + * @psalm-assert !null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function notNull($value, $message = '') + { + if (null === $value) { + static::reportInvalidArgument($message ?: 'Expected a value other than null.'); + } + } + /** + * @psalm-pure + * @psalm-assert true $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function true($value, $message = '') + { + if (\true !== $value) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to be true. Got: %s', static::valueToString($value))); + } + } + /** + * @psalm-pure + * @psalm-assert false $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function false($value, $message = '') + { + if (\false !== $value) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to be false. Got: %s', static::valueToString($value))); + } + } + /** + * @psalm-pure + * @psalm-assert !false $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function notFalse($value, $message = '') + { + if (\false === $value) { + static::reportInvalidArgument($message ?: 'Expected a value other than false.'); + } + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function ip($value, $message = '') + { + if (\false === \filter_var($value, \FILTER_VALIDATE_IP)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to be an IP. Got: %s', static::valueToString($value))); + } + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function ipv4($value, $message = '') + { + if (\false === \filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to be an IPv4. Got: %s', static::valueToString($value))); + } + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function ipv6($value, $message = '') + { + if (\false === \filter_var($value, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to be an IPv6. Got: %s', static::valueToString($value))); + } + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function email($value, $message = '') + { + if (\false === \filter_var($value, \FILTER_VALIDATE_EMAIL)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to be a valid e-mail address. Got: %s', static::valueToString($value))); + } + } + /** + * Does non strict comparisons on the items, so ['3', 3] will not pass the assertion. + * + * @param array $values + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function uniqueValues(array $values, $message = '') + { + $allValues = \count($values); + $uniqueValues = \count(\array_unique($values)); + if ($allValues !== $uniqueValues) { + $difference = $allValues - $uniqueValues; + static::reportInvalidArgument(\sprintf($message ?: 'Expected an array of unique values, but %s of them %s duplicated', $difference, 1 === $difference ? 'is' : 'are')); + } + } + /** + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function eq($value, $expect, $message = '') + { + if ($expect != $value) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value equal to %2$s. Got: %s', static::valueToString($value), static::valueToString($expect))); + } + } + /** + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function notEq($value, $expect, $message = '') + { + if ($expect == $value) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a different value than %s.', static::valueToString($expect))); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function same($value, $expect, $message = '') + { + if ($expect !== $value) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value identical to %2$s. Got: %s', static::valueToString($value), static::valueToString($expect))); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function notSame($value, $expect, $message = '') + { + if ($expect === $value) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value not identical to %s.', static::valueToString($expect))); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function greaterThan($value, $limit, $message = '') + { + if ($value <= $limit) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value greater than %2$s. Got: %s', static::valueToString($value), static::valueToString($limit))); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function greaterThanEq($value, $limit, $message = '') + { + if ($value < $limit) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value greater than or equal to %2$s. Got: %s', static::valueToString($value), static::valueToString($limit))); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function lessThan($value, $limit, $message = '') + { + if ($value >= $limit) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value less than %2$s. Got: %s', static::valueToString($value), static::valueToString($limit))); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function lessThanEq($value, $limit, $message = '') + { + if ($value > $limit) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value less than or equal to %2$s. Got: %s', static::valueToString($value), static::valueToString($limit))); + } + } + /** + * Inclusive range, so Assert::(3, 3, 5) passes. + * + * @psalm-pure + * + * @param mixed $value + * @param mixed $min + * @param mixed $max + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function range($value, $min, $max, $message = '') + { + if ($value < $min || $value > $max) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value between %2$s and %3$s. Got: %s', static::valueToString($value), static::valueToString($min), static::valueToString($max))); + } + } + /** + * A more human-readable alias of Assert::inArray(). + * + * @psalm-pure + * + * @param mixed $value + * @param array $values + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function oneOf($value, array $values, $message = '') + { + static::inArray($value, $values, $message); + } + /** + * Does strict comparison, so Assert::inArray(3, ['3']) does not pass the assertion. + * + * @psalm-pure + * + * @param mixed $value + * @param array $values + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function inArray($value, array $values, $message = '') + { + if (!\in_array($value, $values, \true)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected one of: %2$s. Got: %s', static::valueToString($value), \implode(', ', \array_map(array(static::class, 'valueToString'), $values)))); + } + } + /** + * @psalm-pure + * + * @param string $value + * @param string $subString + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function contains($value, $subString, $message = '') + { + if (\false === \strpos($value, $subString)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to contain %2$s. Got: %s', static::valueToString($value), static::valueToString($subString))); + } + } + /** + * @psalm-pure + * + * @param string $value + * @param string $subString + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function notContains($value, $subString, $message = '') + { + if (\false !== \strpos($value, $subString)) { + static::reportInvalidArgument(\sprintf($message ?: '%2$s was not expected to be contained in a value. Got: %s', static::valueToString($value), static::valueToString($subString))); + } + } + /** + * @psalm-pure + * + * @param string $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function notWhitespaceOnly($value, $message = '') + { + if (\preg_match('/^\\s*$/', $value)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a non-whitespace string. Got: %s', static::valueToString($value))); + } + } + /** + * @psalm-pure + * + * @param string $value + * @param string $prefix + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function startsWith($value, $prefix, $message = '') + { + if (0 !== \strpos($value, $prefix)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to start with %2$s. Got: %s', static::valueToString($value), static::valueToString($prefix))); + } + } + /** + * @psalm-pure + * + * @param string $value + * @param string $prefix + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function notStartsWith($value, $prefix, $message = '') + { + if (0 === \strpos($value, $prefix)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value not to start with %2$s. Got: %s', static::valueToString($value), static::valueToString($prefix))); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function startsWithLetter($value, $message = '') + { + static::string($value); + $valid = isset($value[0]); + if ($valid) { + $locale = \setlocale(\LC_CTYPE, 0); + \setlocale(\LC_CTYPE, 'C'); + $valid = \ctype_alpha($value[0]); + \setlocale(\LC_CTYPE, $locale); + } + if (!$valid) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to start with a letter. Got: %s', static::valueToString($value))); + } + } + /** + * @psalm-pure + * + * @param string $value + * @param string $suffix + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function endsWith($value, $suffix, $message = '') + { + if ($suffix !== \substr($value, -\strlen($suffix))) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to end with %2$s. Got: %s', static::valueToString($value), static::valueToString($suffix))); + } + } + /** + * @psalm-pure + * + * @param string $value + * @param string $suffix + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function notEndsWith($value, $suffix, $message = '') + { + if ($suffix === \substr($value, -\strlen($suffix))) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value not to end with %2$s. Got: %s', static::valueToString($value), static::valueToString($suffix))); + } + } + /** + * @psalm-pure + * + * @param string $value + * @param string $pattern + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function regex($value, $pattern, $message = '') + { + if (!\preg_match($pattern, $value)) { + static::reportInvalidArgument(\sprintf($message ?: 'The value %s does not match the expected pattern.', static::valueToString($value))); + } + } + /** + * @psalm-pure + * + * @param string $value + * @param string $pattern + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function notRegex($value, $pattern, $message = '') + { + if (\preg_match($pattern, $value, $matches, \PREG_OFFSET_CAPTURE)) { + static::reportInvalidArgument(\sprintf($message ?: 'The value %s matches the pattern %s (at offset %d).', static::valueToString($value), static::valueToString($pattern), $matches[0][1])); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function unicodeLetters($value, $message = '') + { + static::string($value); + if (!\preg_match('/^\\p{L}+$/u', $value)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to contain only Unicode letters. Got: %s', static::valueToString($value))); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function alpha($value, $message = '') + { + static::string($value); + $locale = \setlocale(\LC_CTYPE, 0); + \setlocale(\LC_CTYPE, 'C'); + $valid = !\ctype_alpha($value); + \setlocale(\LC_CTYPE, $locale); + if ($valid) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to contain only letters. Got: %s', static::valueToString($value))); + } + } + /** + * @psalm-pure + * + * @param string $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function digits($value, $message = '') + { + $locale = \setlocale(\LC_CTYPE, 0); + \setlocale(\LC_CTYPE, 'C'); + $valid = !\ctype_digit($value); + \setlocale(\LC_CTYPE, $locale); + if ($valid) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to contain digits only. Got: %s', static::valueToString($value))); + } + } + /** + * @psalm-pure + * + * @param string $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function alnum($value, $message = '') + { + $locale = \setlocale(\LC_CTYPE, 0); + \setlocale(\LC_CTYPE, 'C'); + $valid = !\ctype_alnum($value); + \setlocale(\LC_CTYPE, $locale); + if ($valid) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to contain letters and digits only. Got: %s', static::valueToString($value))); + } + } + /** + * @psalm-pure + * @psalm-assert lowercase-string $value + * + * @param string $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function lower($value, $message = '') + { + $locale = \setlocale(\LC_CTYPE, 0); + \setlocale(\LC_CTYPE, 'C'); + $valid = !\ctype_lower($value); + \setlocale(\LC_CTYPE, $locale); + if ($valid) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to contain lowercase characters only. Got: %s', static::valueToString($value))); + } + } + /** + * @psalm-pure + * @psalm-assert !lowercase-string $value + * + * @param string $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function upper($value, $message = '') + { + $locale = \setlocale(\LC_CTYPE, 0); + \setlocale(\LC_CTYPE, 'C'); + $valid = !\ctype_upper($value); + \setlocale(\LC_CTYPE, $locale); + if ($valid) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to contain uppercase characters only. Got: %s', static::valueToString($value))); + } + } + /** + * @psalm-pure + * + * @param string $value + * @param int $length + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function length($value, $length, $message = '') + { + if ($length !== static::strlen($value)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to contain %2$s characters. Got: %s', static::valueToString($value), $length)); + } + } + /** + * Inclusive min. + * + * @psalm-pure + * + * @param string $value + * @param int|float $min + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function minLength($value, $min, $message = '') + { + if (static::strlen($value) < $min) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to contain at least %2$s characters. Got: %s', static::valueToString($value), $min)); + } + } + /** + * Inclusive max. + * + * @psalm-pure + * + * @param string $value + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function maxLength($value, $max, $message = '') + { + if (static::strlen($value) > $max) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to contain at most %2$s characters. Got: %s', static::valueToString($value), $max)); + } + } + /** + * Inclusive , so Assert::lengthBetween('asd', 3, 5); passes the assertion. + * + * @psalm-pure + * + * @param string $value + * @param int|float $min + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function lengthBetween($value, $min, $max, $message = '') + { + $length = static::strlen($value); + if ($length < $min || $length > $max) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a value to contain between %2$s and %3$s characters. Got: %s', static::valueToString($value), $min, $max)); + } + } + /** + * Will also pass if $value is a directory, use Assert::file() instead if you need to be sure it is a file. + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function fileExists($value, $message = '') + { + static::string($value); + if (!\file_exists($value)) { + static::reportInvalidArgument(\sprintf($message ?: 'The file %s does not exist.', static::valueToString($value))); + } + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function file($value, $message = '') + { + static::fileExists($value, $message); + if (!\is_file($value)) { + static::reportInvalidArgument(\sprintf($message ?: 'The path %s is not a file.', static::valueToString($value))); + } + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function directory($value, $message = '') + { + static::fileExists($value, $message); + if (!\is_dir($value)) { + static::reportInvalidArgument(\sprintf($message ?: 'The path %s is no directory.', static::valueToString($value))); + } + } + /** + * @param string $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function readable($value, $message = '') + { + if (!\is_readable($value)) { + static::reportInvalidArgument(\sprintf($message ?: 'The path %s is not readable.', static::valueToString($value))); + } + } + /** + * @param string $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function writable($value, $message = '') + { + if (!\is_writable($value)) { + static::reportInvalidArgument(\sprintf($message ?: 'The path %s is not writable.', static::valueToString($value))); + } + } + /** + * @psalm-assert class-string $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function classExists($value, $message = '') + { + if (!\class_exists($value)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected an existing class name. Got: %s', static::valueToString($value))); + } + } + /** + * @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 + * + * @throws InvalidArgumentException + */ + public static function subclassOf($value, $class, $message = '') + { + if (!\is_subclass_of($value, $class)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected a sub-class of %2$s. Got: %s', static::valueToString($value), static::valueToString($class))); + } + } + /** + * @psalm-assert class-string $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function interfaceExists($value, $message = '') + { + if (!\interface_exists($value)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected an existing interface name. got %s', static::valueToString($value))); + } + } + /** + * @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 + * + * @throws InvalidArgumentException + */ + public static function implementsInterface($value, $interface, $message = '') + { + if (!\in_array($interface, \class_implements($value))) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected an implementation of %2$s. Got: %s', static::valueToString($value), static::valueToString($interface))); + } + } + /** + * @psalm-pure + * @psalm-param class-string|object $classOrObject + * + * @param string|object $classOrObject + * @param mixed $property + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function propertyExists($classOrObject, $property, $message = '') + { + if (!\property_exists($classOrObject, $property)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected the property %s to exist.', static::valueToString($property))); + } + } + /** + * @psalm-pure + * @psalm-param class-string|object $classOrObject + * + * @param string|object $classOrObject + * @param mixed $property + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function propertyNotExists($classOrObject, $property, $message = '') + { + if (\property_exists($classOrObject, $property)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected the property %s to not exist.', static::valueToString($property))); + } + } + /** + * @psalm-pure + * @psalm-param class-string|object $classOrObject + * + * @param string|object $classOrObject + * @param mixed $method + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function methodExists($classOrObject, $method, $message = '') + { + if (!(\is_string($classOrObject) || \is_object($classOrObject)) || !\method_exists($classOrObject, $method)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected the method %s to exist.', static::valueToString($method))); + } + } + /** + * @psalm-pure + * @psalm-param class-string|object $classOrObject + * + * @param string|object $classOrObject + * @param mixed $method + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function methodNotExists($classOrObject, $method, $message = '') + { + if ((\is_string($classOrObject) || \is_object($classOrObject)) && \method_exists($classOrObject, $method)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected the method %s to not exist.', static::valueToString($method))); + } + } + /** + * @psalm-pure + * + * @param array $array + * @param string|int $key + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function keyExists($array, $key, $message = '') + { + if (!(isset($array[$key]) || \array_key_exists($key, $array))) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected the key %s to exist.', static::valueToString($key))); + } + } + /** + * @psalm-pure + * + * @param array $array + * @param string|int $key + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function keyNotExists($array, $key, $message = '') + { + if (isset($array[$key]) || \array_key_exists($key, $array)) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected the key %s to not exist.', static::valueToString($key))); + } + } + /** + * Checks if a value is a valid array key (int or string). + * + * @psalm-pure + * @psalm-assert array-key $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function validArrayKey($value, $message = '') + { + if (!(\is_int($value) || \is_string($value))) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected string or integer. Got: %s', static::typeToString($value))); + } + } + /** + * Does not check if $array is countable, this can generate a warning on php versions after 7.2. + * + * @param Countable|array $array + * @param int $number + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function count($array, $number, $message = '') + { + static::eq(\count($array), $number, \sprintf($message ?: 'Expected an array to contain %d elements. Got: %d.', $number, \count($array))); + } + /** + * Does not check if $array is countable, this can generate a warning on php versions after 7.2. + * + * @param Countable|array $array + * @param int|float $min + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function minCount($array, $min, $message = '') + { + if (\count($array) < $min) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected an array to contain at least %2$d elements. Got: %d', \count($array), $min)); + } + } + /** + * Does not check if $array is countable, this can generate a warning on php versions after 7.2. + * + * @param Countable|array $array + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function maxCount($array, $max, $message = '') + { + if (\count($array) > $max) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected an array to contain at most %2$d elements. Got: %d', \count($array), $max)); + } + } + /** + * Does not check if $array is countable, this can generate a warning on php versions after 7.2. + * + * @param Countable|array $array + * @param int|float $min + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function countBetween($array, $min, $max, $message = '') + { + $count = \count($array); + if ($count < $min || $count > $max) { + static::reportInvalidArgument(\sprintf($message ?: 'Expected an array to contain between %2$d and %3$d elements. Got: %d', $count, $min, $max)); + } + } + /** + * @psalm-pure + * @psalm-assert list $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isList($array, $message = '') + { + if (!\is_array($array)) { + static::reportInvalidArgument($message ?: 'Expected list - non-associative array.'); + } + if ($array === \array_values($array)) { + return; + } + $nextKey = -1; + foreach ($array as $k => $v) { + if ($k !== ++$nextKey) { + static::reportInvalidArgument($message ?: 'Expected list - non-associative array.'); + } + } + } + /** + * @psalm-pure + * @psalm-assert non-empty-list $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isNonEmptyList($array, $message = '') + { + static::isList($array, $message); + static::notEmpty($array, $message); + } + /** + * @psalm-pure + * @psalm-template T + * @psalm-param mixed|array $array + * @psalm-assert array $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isMap($array, $message = '') + { + if (!\is_array($array) || \array_keys($array) !== \array_filter(\array_keys($array), '\\is_string')) { + static::reportInvalidArgument($message ?: 'Expected map - associative array with string keys.'); + } + } + /** + * @psalm-pure + * @psalm-template T + * @psalm-param mixed|array $array + * @psalm-assert array $array + * @psalm-assert !empty $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function isNonEmptyMap($array, $message = '') + { + static::isMap($array, $message); + static::notEmpty($array, $message); + } + /** + * @psalm-pure + * + * @param string $value + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function uuid($value, $message = '') + { + $value = \str_replace(array('urn:', 'uuid:', '{', '}'), '', $value); + // The nil UUID is special form of UUID that is specified to have all + // 128 bits set to zero. + if ('00000000-0000-0000-0000-000000000000' === $value) { + return; + } + if (!\preg_match('/^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$/', $value)) { + static::reportInvalidArgument(\sprintf($message ?: 'Value %s is not a valid UUID.', static::valueToString($value))); + } + } + /** + * @psalm-param class-string $class + * + * @param Closure $expression + * @param string $class + * @param string $message + * + * @throws InvalidArgumentException + */ + public static function throws(Closure $expression, $class = 'Exception', $message = '') + { + static::string($class); + $actual = 'none'; + try { + $expression(); + } catch (Exception $e) { + $actual = \get_class($e); + if ($e instanceof $class) { + return; + } + } catch (Throwable $e) { + $actual = \get_class($e); + if ($e instanceof $class) { + return; + } + } + static::reportInvalidArgument($message ?: \sprintf('Expected to throw "%s", got "%s"', $class, $actual)); + } + /** + * @throws BadMethodCallException + */ + public static function __callStatic($name, $arguments) + { + if ('nullOr' === \substr($name, 0, 6)) { + if (null !== $arguments[0]) { + $method = \lcfirst(\substr($name, 6)); + \call_user_func_array(array(static::class, $method), $arguments); + } + return; + } + if ('all' === \substr($name, 0, 3)) { + static::isIterable($arguments[0]); + $method = \lcfirst(\substr($name, 3)); + $args = $arguments; + foreach ($arguments[0] as $entry) { + $args[0] = $entry; + \call_user_func_array(array(static::class, $method), $args); + } + return; + } + throw new BadMethodCallException('No such method: ' . $name); + } + /** + * @param mixed $value + * + * @return string + */ + protected static function valueToString($value) + { + if (null === $value) { + return 'null'; + } + if (\true === $value) { + return 'true'; + } + if (\false === $value) { + return 'false'; + } + if (\is_array($value)) { + return 'array'; + } + if (\is_object($value)) { + if (\method_exists($value, '__toString')) { + return \get_class($value) . ': ' . self::valueToString($value->__toString()); + } + if ($value instanceof DateTime || $value instanceof DateTimeImmutable) { + return \get_class($value) . ': ' . self::valueToString($value->format('c')); + } + return \get_class($value); + } + if (\is_resource($value)) { + return 'resource'; + } + if (\is_string($value)) { + return '"' . $value . '"'; + } + return (string) $value; + } + /** + * @param mixed $value + * + * @return string + */ + protected static function typeToString($value) + { + return \is_object($value) ? \get_class($value) : \gettype($value); + } + protected static function strlen($value) + { + if (!\function_exists('mb_detect_encoding')) { + return \strlen($value); + } + if (\false === ($encoding = \mb_detect_encoding($value))) { + return \strlen($value); + } + return \mb_strlen($value, $encoding); + } + /** + * @param string $message + * + * @throws InvalidArgumentException + * + * @psalm-pure this method is not supposed to perform side-effects + * @psalm-return never + */ + protected static function reportInvalidArgument($message) + { + throw new InvalidArgumentException($message); + } + private function __construct() + { + } +} diff --git a/vendor/webmozart/assert/src/InvalidArgumentException.php b/vendor/webmozart/assert/src/InvalidArgumentException.php new file mode 100644 index 0000000000..4ad638ff75 --- /dev/null +++ b/vendor/webmozart/assert/src/InvalidArgumentException.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace SwissKnife202405\Webmozart\Assert; + +class InvalidArgumentException extends \InvalidArgumentException +{ +} diff --git a/vendor/webmozart/assert/src/Mixin.php b/vendor/webmozart/assert/src/Mixin.php new file mode 100644 index 0000000000..503fa638ed --- /dev/null +++ b/vendor/webmozart/assert/src/Mixin.php @@ -0,0 +1,4630 @@ + $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allString($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::string($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrString($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::string($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert non-empty-string|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrStringNotEmpty($value, $message = '') + { + null === $value || static::stringNotEmpty($value, $message); + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allStringNotEmpty($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::stringNotEmpty($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrStringNotEmpty($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::stringNotEmpty($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert int|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrInteger($value, $message = '') + { + null === $value || static::integer($value, $message); + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allInteger($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::integer($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrInteger($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::integer($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert numeric|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIntegerish($value, $message = '') + { + null === $value || static::integerish($value, $message); + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIntegerish($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::integerish($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIntegerish($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::integerish($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert positive-int|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrPositiveInteger($value, $message = '') + { + null === $value || static::positiveInteger($value, $message); + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allPositiveInteger($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::positiveInteger($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrPositiveInteger($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::positiveInteger($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert float|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrFloat($value, $message = '') + { + null === $value || static::float($value, $message); + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allFloat($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::float($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrFloat($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::float($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert numeric|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrNumeric($value, $message = '') + { + null === $value || static::numeric($value, $message); + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNumeric($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::numeric($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrNumeric($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::numeric($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert positive-int|0|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrNatural($value, $message = '') + { + null === $value || static::natural($value, $message); + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNatural($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::natural($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrNatural($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::natural($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert bool|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrBoolean($value, $message = '') + { + null === $value || static::boolean($value, $message); + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allBoolean($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::boolean($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrBoolean($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::boolean($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert scalar|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrScalar($value, $message = '') + { + null === $value || static::scalar($value, $message); + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allScalar($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::scalar($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrScalar($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::scalar($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert object|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrObject($value, $message = '') + { + null === $value || static::object($value, $message); + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allObject($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::object($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrObject($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::object($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert resource|null $value + * + * @param mixed $value + * @param string|null $type type of resource this should be. @see https://www.php.net/manual/en/function.get-resource-type.php + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrResource($value, $type = null, $message = '') + { + null === $value || static::resource($value, $type, $message); + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string|null $type type of resource this should be. @see https://www.php.net/manual/en/function.get-resource-type.php + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allResource($value, $type = null, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::resource($entry, $type, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string|null $type type of resource this should be. @see https://www.php.net/manual/en/function.get-resource-type.php + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrResource($value, $type = null, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::resource($entry, $type, $message); + } + } + /** + * @psalm-pure + * @psalm-assert callable|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsCallable($value, $message = '') + { + null === $value || static::isCallable($value, $message); + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsCallable($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::isCallable($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsCallable($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::isCallable($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert array|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsArray($value, $message = '') + { + null === $value || static::isArray($value, $message); + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsArray($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::isArray($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsArray($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::isArray($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable|null $value + * + * @deprecated use "isIterable" or "isInstanceOf" instead + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsTraversable($value, $message = '') + { + null === $value || static::isTraversable($value, $message); + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @deprecated use "isIterable" or "isInstanceOf" instead + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsTraversable($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::isTraversable($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @deprecated use "isIterable" or "isInstanceOf" instead + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsTraversable($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::isTraversable($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert array|ArrayAccess|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsArrayAccessible($value, $message = '') + { + null === $value || static::isArrayAccessible($value, $message); + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsArrayAccessible($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::isArrayAccessible($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsArrayAccessible($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::isArrayAccessible($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert countable|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsCountable($value, $message = '') + { + null === $value || static::isCountable($value, $message); + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsCountable($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::isCountable($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsCountable($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::isCountable($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsIterable($value, $message = '') + { + null === $value || static::isIterable($value, $message); + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsIterable($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::isIterable($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsIterable($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::isIterable($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert ExpectedType|null $value + * + * @param mixed $value + * @param string|object $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsInstanceOf($value, $class, $message = '') + { + null === $value || static::isInstanceOf($value, $class, $message); + } + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string|object $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsInstanceOf($value, $class, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::isInstanceOf($entry, $class, $message); + } + } + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string|object $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsInstanceOf($value, $class, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::isInstanceOf($entry, $class, $message); + } + } + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * + * @param mixed $value + * @param string|object $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrNotInstanceOf($value, $class, $message = '') + { + null === $value || static::notInstanceOf($value, $class, $message); + } + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * + * @param mixed $value + * @param string|object $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNotInstanceOf($value, $class, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::notInstanceOf($entry, $class, $message); + } + } + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string|object $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrNotInstanceOf($value, $class, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::notInstanceOf($entry, $class, $message); + } + } + /** + * @psalm-pure + * @psalm-param array $classes + * + * @param mixed $value + * @param array $classes + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsInstanceOfAny($value, $classes, $message = '') + { + null === $value || static::isInstanceOfAny($value, $classes, $message); + } + /** + * @psalm-pure + * @psalm-param array $classes + * + * @param mixed $value + * @param array $classes + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsInstanceOfAny($value, $classes, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::isInstanceOfAny($entry, $classes, $message); + } + } + /** + * @psalm-pure + * @psalm-param array $classes + * + * @param mixed $value + * @param array $classes + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsInstanceOfAny($value, $classes, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::isInstanceOfAny($entry, $classes, $message); + } + } + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert ExpectedType|class-string|null $value + * + * @param object|string|null $value + * @param string $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsAOf($value, $class, $message = '') + { + null === $value || static::isAOf($value, $class, $message); + } + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert iterable> $value + * + * @param iterable $value + * @param string $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsAOf($value, $class, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::isAOf($entry, $class, $message); + } + } + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert iterable|null> $value + * + * @param iterable $value + * @param string $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsAOf($value, $class, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::isAOf($entry, $class, $message); + } + } + /** + * @psalm-pure + * @psalm-template UnexpectedType of object + * @psalm-param class-string $class + * + * @param object|string|null $value + * @param string $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsNotA($value, $class, $message = '') + { + null === $value || static::isNotA($value, $class, $message); + } + /** + * @psalm-pure + * @psalm-template UnexpectedType of object + * @psalm-param class-string $class + * + * @param iterable $value + * @param string $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsNotA($value, $class, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::isNotA($entry, $class, $message); + } + } + /** + * @psalm-pure + * @psalm-template UnexpectedType of object + * @psalm-param class-string $class + * @psalm-assert iterable $value + * @psalm-assert iterable|null> $value + * + * @param iterable $value + * @param string $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsNotA($value, $class, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::isNotA($entry, $class, $message); + } + } + /** + * @psalm-pure + * @psalm-param array $classes + * + * @param object|string|null $value + * @param string[] $classes + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsAnyOf($value, $classes, $message = '') + { + null === $value || static::isAnyOf($value, $classes, $message); + } + /** + * @psalm-pure + * @psalm-param array $classes + * + * @param iterable $value + * @param string[] $classes + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsAnyOf($value, $classes, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::isAnyOf($entry, $classes, $message); + } + } + /** + * @psalm-pure + * @psalm-param array $classes + * + * @param iterable $value + * @param string[] $classes + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsAnyOf($value, $classes, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::isAnyOf($entry, $classes, $message); + } + } + /** + * @psalm-pure + * @psalm-assert empty $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsEmpty($value, $message = '') + { + null === $value || static::isEmpty($value, $message); + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsEmpty($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::isEmpty($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsEmpty($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::isEmpty($entry, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrNotEmpty($value, $message = '') + { + null === $value || static::notEmpty($value, $message); + } + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNotEmpty($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::notEmpty($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrNotEmpty($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::notEmpty($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNull($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::null($entry, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNotNull($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::notNull($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert true|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrTrue($value, $message = '') + { + null === $value || static::true($value, $message); + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allTrue($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::true($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrTrue($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::true($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert false|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrFalse($value, $message = '') + { + null === $value || static::false($value, $message); + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allFalse($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::false($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrFalse($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::false($entry, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrNotFalse($value, $message = '') + { + null === $value || static::notFalse($value, $message); + } + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNotFalse($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::notFalse($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrNotFalse($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::notFalse($entry, $message); + } + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIp($value, $message = '') + { + null === $value || static::ip($value, $message); + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIp($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::ip($entry, $message); + } + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIp($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::ip($entry, $message); + } + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIpv4($value, $message = '') + { + null === $value || static::ipv4($value, $message); + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIpv4($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::ipv4($entry, $message); + } + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIpv4($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::ipv4($entry, $message); + } + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIpv6($value, $message = '') + { + null === $value || static::ipv6($value, $message); + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIpv6($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::ipv6($entry, $message); + } + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIpv6($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::ipv6($entry, $message); + } + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrEmail($value, $message = '') + { + null === $value || static::email($value, $message); + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allEmail($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::email($entry, $message); + } + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrEmail($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::email($entry, $message); + } + } + /** + * @param array|null $values + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrUniqueValues($values, $message = '') + { + null === $values || static::uniqueValues($values, $message); + } + /** + * @param iterable $values + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allUniqueValues($values, $message = '') + { + static::isIterable($values); + foreach ($values as $entry) { + static::uniqueValues($entry, $message); + } + } + /** + * @param iterable $values + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrUniqueValues($values, $message = '') + { + static::isIterable($values); + foreach ($values as $entry) { + null === $entry || static::uniqueValues($entry, $message); + } + } + /** + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrEq($value, $expect, $message = '') + { + null === $value || static::eq($value, $expect, $message); + } + /** + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allEq($value, $expect, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::eq($entry, $expect, $message); + } + } + /** + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrEq($value, $expect, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::eq($entry, $expect, $message); + } + } + /** + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrNotEq($value, $expect, $message = '') + { + null === $value || static::notEq($value, $expect, $message); + } + /** + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNotEq($value, $expect, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::notEq($entry, $expect, $message); + } + } + /** + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrNotEq($value, $expect, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::notEq($entry, $expect, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrSame($value, $expect, $message = '') + { + null === $value || static::same($value, $expect, $message); + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allSame($value, $expect, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::same($entry, $expect, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrSame($value, $expect, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::same($entry, $expect, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrNotSame($value, $expect, $message = '') + { + null === $value || static::notSame($value, $expect, $message); + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNotSame($value, $expect, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::notSame($entry, $expect, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $expect + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrNotSame($value, $expect, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::notSame($entry, $expect, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrGreaterThan($value, $limit, $message = '') + { + null === $value || static::greaterThan($value, $limit, $message); + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allGreaterThan($value, $limit, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::greaterThan($entry, $limit, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrGreaterThan($value, $limit, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::greaterThan($entry, $limit, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrGreaterThanEq($value, $limit, $message = '') + { + null === $value || static::greaterThanEq($value, $limit, $message); + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allGreaterThanEq($value, $limit, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::greaterThanEq($entry, $limit, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrGreaterThanEq($value, $limit, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::greaterThanEq($entry, $limit, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrLessThan($value, $limit, $message = '') + { + null === $value || static::lessThan($value, $limit, $message); + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allLessThan($value, $limit, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::lessThan($entry, $limit, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrLessThan($value, $limit, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::lessThan($entry, $limit, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrLessThanEq($value, $limit, $message = '') + { + null === $value || static::lessThanEq($value, $limit, $message); + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allLessThanEq($value, $limit, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::lessThanEq($entry, $limit, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $limit + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrLessThanEq($value, $limit, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::lessThanEq($entry, $limit, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $min + * @param mixed $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrRange($value, $min, $max, $message = '') + { + null === $value || static::range($value, $min, $max, $message); + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $min + * @param mixed $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allRange($value, $min, $max, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::range($entry, $min, $max, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param mixed $min + * @param mixed $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrRange($value, $min, $max, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::range($entry, $min, $max, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param array $values + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrOneOf($value, $values, $message = '') + { + null === $value || static::oneOf($value, $values, $message); + } + /** + * @psalm-pure + * + * @param mixed $value + * @param array $values + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allOneOf($value, $values, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::oneOf($entry, $values, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param array $values + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrOneOf($value, $values, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::oneOf($entry, $values, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param array $values + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrInArray($value, $values, $message = '') + { + null === $value || static::inArray($value, $values, $message); + } + /** + * @psalm-pure + * + * @param mixed $value + * @param array $values + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allInArray($value, $values, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::inArray($entry, $values, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param array $values + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrInArray($value, $values, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::inArray($entry, $values, $message); + } + } + /** + * @psalm-pure + * + * @param string|null $value + * @param string $subString + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrContains($value, $subString, $message = '') + { + null === $value || static::contains($value, $subString, $message); + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $subString + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allContains($value, $subString, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::contains($entry, $subString, $message); + } + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $subString + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrContains($value, $subString, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::contains($entry, $subString, $message); + } + } + /** + * @psalm-pure + * + * @param string|null $value + * @param string $subString + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrNotContains($value, $subString, $message = '') + { + null === $value || static::notContains($value, $subString, $message); + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $subString + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNotContains($value, $subString, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::notContains($entry, $subString, $message); + } + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $subString + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrNotContains($value, $subString, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::notContains($entry, $subString, $message); + } + } + /** + * @psalm-pure + * + * @param string|null $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrNotWhitespaceOnly($value, $message = '') + { + null === $value || static::notWhitespaceOnly($value, $message); + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNotWhitespaceOnly($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::notWhitespaceOnly($entry, $message); + } + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrNotWhitespaceOnly($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::notWhitespaceOnly($entry, $message); + } + } + /** + * @psalm-pure + * + * @param string|null $value + * @param string $prefix + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrStartsWith($value, $prefix, $message = '') + { + null === $value || static::startsWith($value, $prefix, $message); + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $prefix + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allStartsWith($value, $prefix, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::startsWith($entry, $prefix, $message); + } + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $prefix + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrStartsWith($value, $prefix, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::startsWith($entry, $prefix, $message); + } + } + /** + * @psalm-pure + * + * @param string|null $value + * @param string $prefix + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrNotStartsWith($value, $prefix, $message = '') + { + null === $value || static::notStartsWith($value, $prefix, $message); + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $prefix + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNotStartsWith($value, $prefix, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::notStartsWith($entry, $prefix, $message); + } + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $prefix + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrNotStartsWith($value, $prefix, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::notStartsWith($entry, $prefix, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrStartsWithLetter($value, $message = '') + { + null === $value || static::startsWithLetter($value, $message); + } + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allStartsWithLetter($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::startsWithLetter($entry, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrStartsWithLetter($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::startsWithLetter($entry, $message); + } + } + /** + * @psalm-pure + * + * @param string|null $value + * @param string $suffix + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrEndsWith($value, $suffix, $message = '') + { + null === $value || static::endsWith($value, $suffix, $message); + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $suffix + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allEndsWith($value, $suffix, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::endsWith($entry, $suffix, $message); + } + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $suffix + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrEndsWith($value, $suffix, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::endsWith($entry, $suffix, $message); + } + } + /** + * @psalm-pure + * + * @param string|null $value + * @param string $suffix + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrNotEndsWith($value, $suffix, $message = '') + { + null === $value || static::notEndsWith($value, $suffix, $message); + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $suffix + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNotEndsWith($value, $suffix, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::notEndsWith($entry, $suffix, $message); + } + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $suffix + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrNotEndsWith($value, $suffix, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::notEndsWith($entry, $suffix, $message); + } + } + /** + * @psalm-pure + * + * @param string|null $value + * @param string $pattern + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrRegex($value, $pattern, $message = '') + { + null === $value || static::regex($value, $pattern, $message); + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $pattern + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allRegex($value, $pattern, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::regex($entry, $pattern, $message); + } + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $pattern + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrRegex($value, $pattern, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::regex($entry, $pattern, $message); + } + } + /** + * @psalm-pure + * + * @param string|null $value + * @param string $pattern + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrNotRegex($value, $pattern, $message = '') + { + null === $value || static::notRegex($value, $pattern, $message); + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $pattern + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNotRegex($value, $pattern, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::notRegex($entry, $pattern, $message); + } + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $pattern + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrNotRegex($value, $pattern, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::notRegex($entry, $pattern, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrUnicodeLetters($value, $message = '') + { + null === $value || static::unicodeLetters($value, $message); + } + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allUnicodeLetters($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::unicodeLetters($entry, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrUnicodeLetters($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::unicodeLetters($entry, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrAlpha($value, $message = '') + { + null === $value || static::alpha($value, $message); + } + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allAlpha($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::alpha($entry, $message); + } + } + /** + * @psalm-pure + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrAlpha($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::alpha($entry, $message); + } + } + /** + * @psalm-pure + * + * @param string|null $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrDigits($value, $message = '') + { + null === $value || static::digits($value, $message); + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allDigits($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::digits($entry, $message); + } + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrDigits($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::digits($entry, $message); + } + } + /** + * @psalm-pure + * + * @param string|null $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrAlnum($value, $message = '') + { + null === $value || static::alnum($value, $message); + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allAlnum($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::alnum($entry, $message); + } + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrAlnum($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::alnum($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert lowercase-string|null $value + * + * @param string|null $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrLower($value, $message = '') + { + null === $value || static::lower($value, $message); + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allLower($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::lower($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrLower($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::lower($entry, $message); + } + } + /** + * @psalm-pure + * + * @param string|null $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrUpper($value, $message = '') + { + null === $value || static::upper($value, $message); + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allUpper($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::upper($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrUpper($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::upper($entry, $message); + } + } + /** + * @psalm-pure + * + * @param string|null $value + * @param int $length + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrLength($value, $length, $message = '') + { + null === $value || static::length($value, $length, $message); + } + /** + * @psalm-pure + * + * @param iterable $value + * @param int $length + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allLength($value, $length, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::length($entry, $length, $message); + } + } + /** + * @psalm-pure + * + * @param iterable $value + * @param int $length + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrLength($value, $length, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::length($entry, $length, $message); + } + } + /** + * @psalm-pure + * + * @param string|null $value + * @param int|float $min + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrMinLength($value, $min, $message = '') + { + null === $value || static::minLength($value, $min, $message); + } + /** + * @psalm-pure + * + * @param iterable $value + * @param int|float $min + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allMinLength($value, $min, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::minLength($entry, $min, $message); + } + } + /** + * @psalm-pure + * + * @param iterable $value + * @param int|float $min + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrMinLength($value, $min, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::minLength($entry, $min, $message); + } + } + /** + * @psalm-pure + * + * @param string|null $value + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrMaxLength($value, $max, $message = '') + { + null === $value || static::maxLength($value, $max, $message); + } + /** + * @psalm-pure + * + * @param iterable $value + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allMaxLength($value, $max, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::maxLength($entry, $max, $message); + } + } + /** + * @psalm-pure + * + * @param iterable $value + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrMaxLength($value, $max, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::maxLength($entry, $max, $message); + } + } + /** + * @psalm-pure + * + * @param string|null $value + * @param int|float $min + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrLengthBetween($value, $min, $max, $message = '') + { + null === $value || static::lengthBetween($value, $min, $max, $message); + } + /** + * @psalm-pure + * + * @param iterable $value + * @param int|float $min + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allLengthBetween($value, $min, $max, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::lengthBetween($entry, $min, $max, $message); + } + } + /** + * @psalm-pure + * + * @param iterable $value + * @param int|float $min + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrLengthBetween($value, $min, $max, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::lengthBetween($entry, $min, $max, $message); + } + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrFileExists($value, $message = '') + { + null === $value || static::fileExists($value, $message); + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allFileExists($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::fileExists($entry, $message); + } + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrFileExists($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::fileExists($entry, $message); + } + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrFile($value, $message = '') + { + null === $value || static::file($value, $message); + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allFile($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::file($entry, $message); + } + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrFile($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::file($entry, $message); + } + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrDirectory($value, $message = '') + { + null === $value || static::directory($value, $message); + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allDirectory($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::directory($entry, $message); + } + } + /** + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrDirectory($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::directory($entry, $message); + } + } + /** + * @param string|null $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrReadable($value, $message = '') + { + null === $value || static::readable($value, $message); + } + /** + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allReadable($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::readable($entry, $message); + } + } + /** + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrReadable($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::readable($entry, $message); + } + } + /** + * @param string|null $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrWritable($value, $message = '') + { + null === $value || static::writable($value, $message); + } + /** + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allWritable($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::writable($entry, $message); + } + } + /** + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrWritable($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::writable($entry, $message); + } + } + /** + * @psalm-assert class-string|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrClassExists($value, $message = '') + { + null === $value || static::classExists($value, $message); + } + /** + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allClassExists($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::classExists($entry, $message); + } + } + /** + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrClassExists($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::classExists($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert class-string|ExpectedType|null $value + * + * @param mixed $value + * @param string|object $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrSubclassOf($value, $class, $message = '') + { + null === $value || static::subclassOf($value, $class, $message); + } + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert iterable|ExpectedType> $value + * + * @param mixed $value + * @param string|object $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allSubclassOf($value, $class, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::subclassOf($entry, $class, $message); + } + } + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $class + * @psalm-assert iterable|ExpectedType|null> $value + * + * @param mixed $value + * @param string|object $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrSubclassOf($value, $class, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::subclassOf($entry, $class, $message); + } + } + /** + * @psalm-assert class-string|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrInterfaceExists($value, $message = '') + { + null === $value || static::interfaceExists($value, $message); + } + /** + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allInterfaceExists($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::interfaceExists($entry, $message); + } + } + /** + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrInterfaceExists($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::interfaceExists($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $interface + * @psalm-assert class-string|null $value + * + * @param mixed $value + * @param mixed $interface + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrImplementsInterface($value, $interface, $message = '') + { + null === $value || static::implementsInterface($value, $interface, $message); + } + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $interface + * @psalm-assert iterable> $value + * + * @param mixed $value + * @param mixed $interface + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allImplementsInterface($value, $interface, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::implementsInterface($entry, $interface, $message); + } + } + /** + * @psalm-pure + * @psalm-template ExpectedType of object + * @psalm-param class-string $interface + * @psalm-assert iterable|null> $value + * + * @param mixed $value + * @param mixed $interface + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrImplementsInterface($value, $interface, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::implementsInterface($entry, $interface, $message); + } + } + /** + * @psalm-pure + * @psalm-param class-string|object|null $classOrObject + * + * @param string|object|null $classOrObject + * @param mixed $property + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrPropertyExists($classOrObject, $property, $message = '') + { + null === $classOrObject || static::propertyExists($classOrObject, $property, $message); + } + /** + * @psalm-pure + * @psalm-param iterable $classOrObject + * + * @param iterable $classOrObject + * @param mixed $property + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allPropertyExists($classOrObject, $property, $message = '') + { + static::isIterable($classOrObject); + foreach ($classOrObject as $entry) { + static::propertyExists($entry, $property, $message); + } + } + /** + * @psalm-pure + * @psalm-param iterable $classOrObject + * + * @param iterable $classOrObject + * @param mixed $property + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrPropertyExists($classOrObject, $property, $message = '') + { + static::isIterable($classOrObject); + foreach ($classOrObject as $entry) { + null === $entry || static::propertyExists($entry, $property, $message); + } + } + /** + * @psalm-pure + * @psalm-param class-string|object|null $classOrObject + * + * @param string|object|null $classOrObject + * @param mixed $property + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrPropertyNotExists($classOrObject, $property, $message = '') + { + null === $classOrObject || static::propertyNotExists($classOrObject, $property, $message); + } + /** + * @psalm-pure + * @psalm-param iterable $classOrObject + * + * @param iterable $classOrObject + * @param mixed $property + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allPropertyNotExists($classOrObject, $property, $message = '') + { + static::isIterable($classOrObject); + foreach ($classOrObject as $entry) { + static::propertyNotExists($entry, $property, $message); + } + } + /** + * @psalm-pure + * @psalm-param iterable $classOrObject + * + * @param iterable $classOrObject + * @param mixed $property + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrPropertyNotExists($classOrObject, $property, $message = '') + { + static::isIterable($classOrObject); + foreach ($classOrObject as $entry) { + null === $entry || static::propertyNotExists($entry, $property, $message); + } + } + /** + * @psalm-pure + * @psalm-param class-string|object|null $classOrObject + * + * @param string|object|null $classOrObject + * @param mixed $method + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrMethodExists($classOrObject, $method, $message = '') + { + null === $classOrObject || static::methodExists($classOrObject, $method, $message); + } + /** + * @psalm-pure + * @psalm-param iterable $classOrObject + * + * @param iterable $classOrObject + * @param mixed $method + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allMethodExists($classOrObject, $method, $message = '') + { + static::isIterable($classOrObject); + foreach ($classOrObject as $entry) { + static::methodExists($entry, $method, $message); + } + } + /** + * @psalm-pure + * @psalm-param iterable $classOrObject + * + * @param iterable $classOrObject + * @param mixed $method + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrMethodExists($classOrObject, $method, $message = '') + { + static::isIterable($classOrObject); + foreach ($classOrObject as $entry) { + null === $entry || static::methodExists($entry, $method, $message); + } + } + /** + * @psalm-pure + * @psalm-param class-string|object|null $classOrObject + * + * @param string|object|null $classOrObject + * @param mixed $method + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrMethodNotExists($classOrObject, $method, $message = '') + { + null === $classOrObject || static::methodNotExists($classOrObject, $method, $message); + } + /** + * @psalm-pure + * @psalm-param iterable $classOrObject + * + * @param iterable $classOrObject + * @param mixed $method + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allMethodNotExists($classOrObject, $method, $message = '') + { + static::isIterable($classOrObject); + foreach ($classOrObject as $entry) { + static::methodNotExists($entry, $method, $message); + } + } + /** + * @psalm-pure + * @psalm-param iterable $classOrObject + * + * @param iterable $classOrObject + * @param mixed $method + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrMethodNotExists($classOrObject, $method, $message = '') + { + static::isIterable($classOrObject); + foreach ($classOrObject as $entry) { + null === $entry || static::methodNotExists($entry, $method, $message); + } + } + /** + * @psalm-pure + * + * @param array|null $array + * @param string|int $key + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrKeyExists($array, $key, $message = '') + { + null === $array || static::keyExists($array, $key, $message); + } + /** + * @psalm-pure + * + * @param iterable $array + * @param string|int $key + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allKeyExists($array, $key, $message = '') + { + static::isIterable($array); + foreach ($array as $entry) { + static::keyExists($entry, $key, $message); + } + } + /** + * @psalm-pure + * + * @param iterable $array + * @param string|int $key + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrKeyExists($array, $key, $message = '') + { + static::isIterable($array); + foreach ($array as $entry) { + null === $entry || static::keyExists($entry, $key, $message); + } + } + /** + * @psalm-pure + * + * @param array|null $array + * @param string|int $key + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrKeyNotExists($array, $key, $message = '') + { + null === $array || static::keyNotExists($array, $key, $message); + } + /** + * @psalm-pure + * + * @param iterable $array + * @param string|int $key + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allKeyNotExists($array, $key, $message = '') + { + static::isIterable($array); + foreach ($array as $entry) { + static::keyNotExists($entry, $key, $message); + } + } + /** + * @psalm-pure + * + * @param iterable $array + * @param string|int $key + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrKeyNotExists($array, $key, $message = '') + { + static::isIterable($array); + foreach ($array as $entry) { + null === $entry || static::keyNotExists($entry, $key, $message); + } + } + /** + * @psalm-pure + * @psalm-assert array-key|null $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrValidArrayKey($value, $message = '') + { + null === $value || static::validArrayKey($value, $message); + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allValidArrayKey($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::validArrayKey($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $value + * + * @param mixed $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrValidArrayKey($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::validArrayKey($entry, $message); + } + } + /** + * @param Countable|array|null $array + * @param int $number + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrCount($array, $number, $message = '') + { + null === $array || static::count($array, $number, $message); + } + /** + * @param iterable $array + * @param int $number + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allCount($array, $number, $message = '') + { + static::isIterable($array); + foreach ($array as $entry) { + static::count($entry, $number, $message); + } + } + /** + * @param iterable $array + * @param int $number + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrCount($array, $number, $message = '') + { + static::isIterable($array); + foreach ($array as $entry) { + null === $entry || static::count($entry, $number, $message); + } + } + /** + * @param Countable|array|null $array + * @param int|float $min + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrMinCount($array, $min, $message = '') + { + null === $array || static::minCount($array, $min, $message); + } + /** + * @param iterable $array + * @param int|float $min + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allMinCount($array, $min, $message = '') + { + static::isIterable($array); + foreach ($array as $entry) { + static::minCount($entry, $min, $message); + } + } + /** + * @param iterable $array + * @param int|float $min + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrMinCount($array, $min, $message = '') + { + static::isIterable($array); + foreach ($array as $entry) { + null === $entry || static::minCount($entry, $min, $message); + } + } + /** + * @param Countable|array|null $array + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrMaxCount($array, $max, $message = '') + { + null === $array || static::maxCount($array, $max, $message); + } + /** + * @param iterable $array + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allMaxCount($array, $max, $message = '') + { + static::isIterable($array); + foreach ($array as $entry) { + static::maxCount($entry, $max, $message); + } + } + /** + * @param iterable $array + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrMaxCount($array, $max, $message = '') + { + static::isIterable($array); + foreach ($array as $entry) { + null === $entry || static::maxCount($entry, $max, $message); + } + } + /** + * @param Countable|array|null $array + * @param int|float $min + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrCountBetween($array, $min, $max, $message = '') + { + null === $array || static::countBetween($array, $min, $max, $message); + } + /** + * @param iterable $array + * @param int|float $min + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allCountBetween($array, $min, $max, $message = '') + { + static::isIterable($array); + foreach ($array as $entry) { + static::countBetween($entry, $min, $max, $message); + } + } + /** + * @param iterable $array + * @param int|float $min + * @param int|float $max + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrCountBetween($array, $min, $max, $message = '') + { + static::isIterable($array); + foreach ($array as $entry) { + null === $entry || static::countBetween($entry, $min, $max, $message); + } + } + /** + * @psalm-pure + * @psalm-assert list|null $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsList($array, $message = '') + { + null === $array || static::isList($array, $message); + } + /** + * @psalm-pure + * @psalm-assert iterable $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsList($array, $message = '') + { + static::isIterable($array); + foreach ($array as $entry) { + static::isList($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsList($array, $message = '') + { + static::isIterable($array); + foreach ($array as $entry) { + null === $entry || static::isList($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert non-empty-list|null $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsNonEmptyList($array, $message = '') + { + null === $array || static::isNonEmptyList($array, $message); + } + /** + * @psalm-pure + * @psalm-assert iterable $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsNonEmptyList($array, $message = '') + { + static::isIterable($array); + foreach ($array as $entry) { + static::isNonEmptyList($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-assert iterable $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsNonEmptyList($array, $message = '') + { + static::isIterable($array); + foreach ($array as $entry) { + null === $entry || static::isNonEmptyList($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-template T + * @psalm-param mixed|array|null $array + * @psalm-assert array|null $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsMap($array, $message = '') + { + null === $array || static::isMap($array, $message); + } + /** + * @psalm-pure + * @psalm-template T + * @psalm-param iterable> $array + * @psalm-assert iterable> $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsMap($array, $message = '') + { + static::isIterable($array); + foreach ($array as $entry) { + static::isMap($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-template T + * @psalm-param iterable|null> $array + * @psalm-assert iterable|null> $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsMap($array, $message = '') + { + static::isIterable($array); + foreach ($array as $entry) { + null === $entry || static::isMap($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-template T + * @psalm-param mixed|array|null $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrIsNonEmptyMap($array, $message = '') + { + null === $array || static::isNonEmptyMap($array, $message); + } + /** + * @psalm-pure + * @psalm-template T + * @psalm-param iterable> $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allIsNonEmptyMap($array, $message = '') + { + static::isIterable($array); + foreach ($array as $entry) { + static::isNonEmptyMap($entry, $message); + } + } + /** + * @psalm-pure + * @psalm-template T + * @psalm-param iterable|null> $array + * @psalm-assert iterable|null> $array + * @psalm-assert iterable $array + * + * @param mixed $array + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrIsNonEmptyMap($array, $message = '') + { + static::isIterable($array); + foreach ($array as $entry) { + null === $entry || static::isNonEmptyMap($entry, $message); + } + } + /** + * @psalm-pure + * + * @param string|null $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrUuid($value, $message = '') + { + null === $value || static::uuid($value, $message); + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allUuid($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + static::uuid($entry, $message); + } + } + /** + * @psalm-pure + * + * @param iterable $value + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrUuid($value, $message = '') + { + static::isIterable($value); + foreach ($value as $entry) { + null === $entry || static::uuid($entry, $message); + } + } + /** + * @psalm-param class-string $class + * + * @param Closure|null $expression + * @param string $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function nullOrThrows($expression, $class = 'Exception', $message = '') + { + null === $expression || static::throws($expression, $class, $message); + } + /** + * @psalm-param class-string $class + * + * @param iterable $expression + * @param string $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allThrows($expression, $class = 'Exception', $message = '') + { + static::isIterable($expression); + foreach ($expression as $entry) { + static::throws($entry, $class, $message); + } + } + /** + * @psalm-param class-string $class + * + * @param iterable $expression + * @param string $class + * @param string $message + * + * @throws InvalidArgumentException + * + * @return void + */ + public static function allNullOrThrows($expression, $class = 'Exception', $message = '') + { + static::isIterable($expression); + foreach ($expression as $entry) { + null === $entry || static::throws($entry, $class, $message); + } + } +}