Добавлено исключение папок .idea и vendor
This commit is contained in:
		
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -77,3 +77,5 @@ fabric.properties | ||||
| # Android studio 3.1+ serialized cache file | ||||
| .idea/caches/build_file_checksums.ser | ||||
|  | ||||
| .idea/ | ||||
| vendor/ | ||||
							
								
								
									
										8
									
								
								.idea/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.idea/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,8 +0,0 @@ | ||||
| # Файлы, игнорируемые по умолчанию | ||||
| /shelf/ | ||||
| /workspace.xml | ||||
| # Запросы HTTP-клиента в редакторе | ||||
| /httpRequests/ | ||||
| # Datasource local storage ignored files | ||||
| /dataSources/ | ||||
| /dataSources.local.xml | ||||
							
								
								
									
										39
									
								
								.idea/anb_php_components_pack.iml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										39
									
								
								.idea/anb_php_components_pack.iml
									
									
									
										generated
									
									
									
								
							| @@ -1,39 +0,0 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <module type="WEB_MODULE" version="4"> | ||||
|   <component name="NewModuleRootManager"> | ||||
|     <content url="file://$MODULE_DIR$"> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/sources" isTestSource="false" packagePrefix="goodboyalex\php_components_pack\" /> | ||||
|       <sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" packagePrefix="goodboyalex\php_components_pack\tests\" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/composer" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/myclabs/deep-copy" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/nikic/php-parser" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/phar-io/manifest" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/phar-io/version" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-code-coverage" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-file-iterator" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-invoker" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-text-template" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-timer" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/phpunit" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/cli-parser" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/comparator" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/complexity" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/diff" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/environment" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/exporter" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/global-state" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/lines-of-code" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/object-enumerator" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/object-reflector" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/recursion-context" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/type" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/version" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/staabm/side-effects-detector" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/theseer/tokenizer" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/code-unit" /> | ||||
|       <excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/code-unit-reverse-lookup" /> | ||||
|     </content> | ||||
|     <orderEntry type="inheritedJdk" /> | ||||
|     <orderEntry type="sourceFolder" forTests="false" /> | ||||
|   </component> | ||||
| </module> | ||||
							
								
								
									
										8
									
								
								.idea/modules.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										8
									
								
								.idea/modules.xml
									
									
									
										generated
									
									
									
								
							| @@ -1,8 +0,0 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="ProjectModuleManager"> | ||||
|     <modules> | ||||
|       <module fileurl="file://$PROJECT_DIR$/.idea/anb_php_components_pack.iml" filepath="$PROJECT_DIR$/.idea/anb_php_components_pack.iml" /> | ||||
|     </modules> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										14
									
								
								.idea/php-test-framework.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										14
									
								
								.idea/php-test-framework.xml
									
									
									
										generated
									
									
									
								
							| @@ -1,14 +0,0 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="PhpTestFrameworkVersionCache"> | ||||
|     <tools_cache> | ||||
|       <tool tool_name="PHPUnit"> | ||||
|         <cache> | ||||
|           <versions> | ||||
|             <info id="локальный\vendor/autoload.php" version="12.0" /> | ||||
|           </versions> | ||||
|         </cache> | ||||
|       </tool> | ||||
|     </tools_cache> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										57
									
								
								.idea/php.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										57
									
								
								.idea/php.xml
									
									
									
										generated
									
									
									
								
							| @@ -1,57 +0,0 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="MessDetectorOptionsConfiguration"> | ||||
|     <option name="transferred" value="true" /> | ||||
|   </component> | ||||
|   <component name="PHPCSFixerOptionsConfiguration"> | ||||
|     <option name="transferred" value="true" /> | ||||
|   </component> | ||||
|   <component name="PHPCodeSnifferOptionsConfiguration"> | ||||
|     <option name="highlightLevel" value="WARNING" /> | ||||
|     <option name="transferred" value="true" /> | ||||
|   </component> | ||||
|   <component name="PhpIncludePathManager"> | ||||
|     <include_path> | ||||
|       <path value="$PROJECT_DIR$/vendor/composer" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/theseer/tokenizer" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/sebastian/cli-parser" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/staabm/side-effects-detector" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/sebastian/comparator" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/sebastian/complexity" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/sebastian/diff" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/sebastian/environment" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/sebastian/exporter" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/sebastian/global-state" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/sebastian/lines-of-code" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/sebastian/object-enumerator" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/nikic/php-parser" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/sebastian/object-reflector" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/sebastian/recursion-context" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/sebastian/type" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/sebastian/version" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/phpunit/php-code-coverage" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/phpunit/php-file-iterator" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/phpunit/php-invoker" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/phpunit/php-text-template" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/phpunit/php-timer" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/phpunit/phpunit" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/myclabs/deep-copy" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/phar-io/manifest" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/phar-io/version" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/sebastian/code-unit" /> | ||||
|       <path value="$PROJECT_DIR$/vendor/sebastian/code-unit-reverse-lookup" /> | ||||
|     </include_path> | ||||
|   </component> | ||||
|   <component name="PhpProjectSharedConfiguration" php_language_level="8.4" /> | ||||
|   <component name="PhpStanOptionsConfiguration"> | ||||
|     <option name="transferred" value="true" /> | ||||
|   </component> | ||||
|   <component name="PhpUnit"> | ||||
|     <phpunit_settings> | ||||
|       <PhpUnitSettings custom_loader_path="$PROJECT_DIR$/vendor/autoload.php" phpunit_phar_path="$PROJECT_DIR$/../../Internet/php/tools/phpunit/phpunit_2.phar" /> | ||||
|     </phpunit_settings> | ||||
|   </component> | ||||
|   <component name="PsalmOptionsConfiguration"> | ||||
|     <option name="transferred" value="true" /> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										6
									
								
								.idea/vcs.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								.idea/vcs.xml
									
									
									
										generated
									
									
									
								
							| @@ -1,6 +0,0 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="VcsDirectoryMappings"> | ||||
|     <mapping directory="" vcs="Git" /> | ||||
|   </component> | ||||
| </project> | ||||
							
								
								
									
										25
									
								
								vendor/autoload.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										25
									
								
								vendor/autoload.php
									
									
									
									
										vendored
									
									
								
							| @@ -1,25 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| // autoload.php @generated by Composer | ||||
|  | ||||
| if (PHP_VERSION_ID < 50600) { | ||||
|     if (!headers_sent()) { | ||||
|         header('HTTP/1.1 500 Internal Server Error'); | ||||
|     } | ||||
|     $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL; | ||||
|     if (!ini_get('display_errors')) { | ||||
|         if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { | ||||
|             fwrite(STDERR, $err); | ||||
|         } elseif (!headers_sent()) { | ||||
|             echo $err; | ||||
|         } | ||||
|     } | ||||
|     trigger_error( | ||||
|         $err, | ||||
|         E_USER_ERROR | ||||
|     ); | ||||
| } | ||||
|  | ||||
| require_once __DIR__ . '/composer/autoload_real.php'; | ||||
|  | ||||
| return ComposerAutoloaderInitc00e5b601adae61bbbc3f6be4864ef55::getLoader(); | ||||
							
								
								
									
										119
									
								
								vendor/bin/php-parse
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										119
									
								
								vendor/bin/php-parse
									
									
									
									
										vendored
									
									
								
							| @@ -1,119 +0,0 @@ | ||||
| #!/usr/bin/env php | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * Proxy PHP file generated by Composer | ||||
|  * | ||||
|  * This file includes the referenced bin path (../nikic/php-parser/bin/php-parse) | ||||
|  * using a stream wrapper to prevent the shebang from being output on PHP<8 | ||||
|  * | ||||
|  * @generated | ||||
|  */ | ||||
|  | ||||
| namespace Composer; | ||||
|  | ||||
| $GLOBALS['_composer_bin_dir'] = __DIR__; | ||||
| $GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php'; | ||||
|  | ||||
| if (PHP_VERSION_ID < 80000) { | ||||
|     if (!class_exists('Composer\BinProxyWrapper')) { | ||||
|         /** | ||||
|          * @internal | ||||
|          */ | ||||
|         final class BinProxyWrapper | ||||
|         { | ||||
|             private $handle; | ||||
|             private $position; | ||||
|             private $realpath; | ||||
|  | ||||
|             public function stream_open($path, $mode, $options, &$opened_path) | ||||
|             { | ||||
|                 // get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution | ||||
|                 $opened_path = substr($path, 17); | ||||
|                 $this->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', 'Composer\BinProxyWrapper')) | ||||
|     ) { | ||||
|         return include("phpvfscomposer://" . __DIR__ . '/..'.'/nikic/php-parser/bin/php-parse'); | ||||
|     } | ||||
| } | ||||
|  | ||||
| return include __DIR__ . '/..'.'/nikic/php-parser/bin/php-parse'; | ||||
							
								
								
									
										5
									
								
								vendor/bin/php-parse.bat
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/bin/php-parse.bat
									
									
									
									
										vendored
									
									
								
							| @@ -1,5 +0,0 @@ | ||||
| @ECHO OFF | ||||
| setlocal DISABLEDELAYEDEXPANSION | ||||
| SET BIN_TARGET=%~dp0/php-parse | ||||
| SET COMPOSER_RUNTIME_BIN_DIR=%~dp0 | ||||
| php "%BIN_TARGET%" %* | ||||
							
								
								
									
										122
									
								
								vendor/bin/phpunit
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										122
									
								
								vendor/bin/phpunit
									
									
									
									
										vendored
									
									
								
							| @@ -1,122 +0,0 @@ | ||||
| #!/usr/bin/env php | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * Proxy PHP file generated by Composer | ||||
|  * | ||||
|  * This file includes the referenced bin path (../phpunit/phpunit/phpunit) | ||||
|  * using a stream wrapper to prevent the shebang from being output on PHP<8 | ||||
|  * | ||||
|  * @generated | ||||
|  */ | ||||
|  | ||||
| namespace Composer; | ||||
|  | ||||
| $GLOBALS['_composer_bin_dir'] = __DIR__; | ||||
| $GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php'; | ||||
| $GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST'] = $GLOBALS['__PHPUNIT_ISOLATION_BLACKLIST'] = array(realpath(__DIR__ . '/..'.'/phpunit/phpunit/phpunit')); | ||||
|  | ||||
| if (PHP_VERSION_ID < 80000) { | ||||
|     if (!class_exists('Composer\BinProxyWrapper')) { | ||||
|         /** | ||||
|          * @internal | ||||
|          */ | ||||
|         final class BinProxyWrapper | ||||
|         { | ||||
|             private $handle; | ||||
|             private $position; | ||||
|             private $realpath; | ||||
|  | ||||
|             public function stream_open($path, $mode, $options, &$opened_path) | ||||
|             { | ||||
|                 // get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution | ||||
|                 $opened_path = substr($path, 17); | ||||
|                 $this->realpath = realpath($opened_path) ?: $opened_path; | ||||
|                 $opened_path = 'phpvfscomposer://'.$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); | ||||
|                 } | ||||
|                 $data = str_replace('__DIR__', var_export(dirname($this->realpath), true), $data); | ||||
|                 $data = str_replace('__FILE__', var_export($this->realpath, true), $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', 'Composer\BinProxyWrapper')) | ||||
|     ) { | ||||
|         return include("phpvfscomposer://" . __DIR__ . '/..'.'/phpunit/phpunit/phpunit'); | ||||
|     } | ||||
| } | ||||
|  | ||||
| return include __DIR__ . '/..'.'/phpunit/phpunit/phpunit'; | ||||
							
								
								
									
										5
									
								
								vendor/bin/phpunit.bat
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/bin/phpunit.bat
									
									
									
									
										vendored
									
									
								
							| @@ -1,5 +0,0 @@ | ||||
| @ECHO OFF | ||||
| setlocal DISABLEDELAYEDEXPANSION | ||||
| SET BIN_TARGET=%~dp0/phpunit | ||||
| SET COMPOSER_RUNTIME_BIN_DIR=%~dp0 | ||||
| php "%BIN_TARGET%" %* | ||||
							
								
								
									
										579
									
								
								vendor/composer/ClassLoader.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										579
									
								
								vendor/composer/ClassLoader.php
									
									
									
									
										vendored
									
									
								
							| @@ -1,579 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| /* | ||||
|  * This file is part of Composer. | ||||
|  * | ||||
|  * (c) Nils Adermann <naderman@naderman.de> | ||||
|  *     Jordi Boggiano <j.boggiano@seld.be> | ||||
|  * | ||||
|  * 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 <fabien@symfony.com> | ||||
|  * @author Jordi Boggiano <j.boggiano@seld.be> | ||||
|  * @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<string, array<string, int>> | ||||
|      */ | ||||
|     private $prefixLengthsPsr4 = array(); | ||||
|     /** | ||||
|      * @var array<string, list<string>> | ||||
|      */ | ||||
|     private $prefixDirsPsr4 = array(); | ||||
|     /** | ||||
|      * @var list<string> | ||||
|      */ | ||||
|     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<string, array<string, list<string>>> | ||||
|      */ | ||||
|     private $prefixesPsr0 = array(); | ||||
|     /** | ||||
|      * @var list<string> | ||||
|      */ | ||||
|     private $fallbackDirsPsr0 = array(); | ||||
|  | ||||
|     /** @var bool */ | ||||
|     private $useIncludePath = false; | ||||
|  | ||||
|     /** | ||||
|      * @var array<string, string> | ||||
|      */ | ||||
|     private $classMap = array(); | ||||
|  | ||||
|     /** @var bool */ | ||||
|     private $classMapAuthoritative = false; | ||||
|  | ||||
|     /** | ||||
|      * @var array<string, bool> | ||||
|      */ | ||||
|     private $missingClasses = array(); | ||||
|  | ||||
|     /** @var string|null */ | ||||
|     private $apcuPrefix; | ||||
|  | ||||
|     /** | ||||
|      * @var array<string, self> | ||||
|      */ | ||||
|     private static $registeredLoaders = array(); | ||||
|  | ||||
|     /** | ||||
|      * @param string|null $vendorDir | ||||
|      */ | ||||
|     public function __construct($vendorDir = null) | ||||
|     { | ||||
|         $this->vendorDir = $vendorDir; | ||||
|         self::initializeIncludeClosure(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return array<string, list<string>> | ||||
|      */ | ||||
|     public function getPrefixes() | ||||
|     { | ||||
|         if (!empty($this->prefixesPsr0)) { | ||||
|             return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); | ||||
|         } | ||||
|  | ||||
|         return array(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return array<string, list<string>> | ||||
|      */ | ||||
|     public function getPrefixesPsr4() | ||||
|     { | ||||
|         return $this->prefixDirsPsr4; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return list<string> | ||||
|      */ | ||||
|     public function getFallbackDirs() | ||||
|     { | ||||
|         return $this->fallbackDirsPsr0; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return list<string> | ||||
|      */ | ||||
|     public function getFallbackDirsPsr4() | ||||
|     { | ||||
|         return $this->fallbackDirsPsr4; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return array<string, string> Array of classname => path | ||||
|      */ | ||||
|     public function getClassMap() | ||||
|     { | ||||
|         return $this->classMap; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param array<string, string> $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>|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>|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>|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>|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<string, self> | ||||
|      */ | ||||
|     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); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										378
									
								
								vendor/composer/InstalledVersions.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										378
									
								
								vendor/composer/InstalledVersions.php
									
									
									
									
										vendored
									
									
								
							| @@ -1,378 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| /* | ||||
|  * This file is part of Composer. | ||||
|  * | ||||
|  * (c) Nils Adermann <naderman@naderman.de> | ||||
|  *     Jordi Boggiano <j.boggiano@seld.be> | ||||
|  * | ||||
|  * For the full copyright and license information, please view the LICENSE | ||||
|  * file that was distributed with this source code. | ||||
|  */ | ||||
|  | ||||
| namespace Composer; | ||||
|  | ||||
| use Composer\Autoload\ClassLoader; | ||||
| use 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<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null | ||||
|      */ | ||||
|     private static $installed; | ||||
|  | ||||
|     /** | ||||
|      * @var bool | ||||
|      */ | ||||
|     private static $installedIsLocalDir; | ||||
|  | ||||
|     /** | ||||
|      * @var bool|null | ||||
|      */ | ||||
|     private static $canGetVendors; | ||||
|  | ||||
|     /** | ||||
|      * @var array[] | ||||
|      * @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}> | ||||
|      */ | ||||
|     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<string> | ||||
|      */ | ||||
|     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('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<string> | ||||
|      */ | ||||
|     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<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} | ||||
|      */ | ||||
|     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<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}> | ||||
|      */ | ||||
|     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<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data | ||||
|      */ | ||||
|     public static function reload($data) | ||||
|     { | ||||
|         self::$installed = $data; | ||||
|         self::$installedByVendor = array(); | ||||
|  | ||||
|         // when using reload, we disable the duplicate protection to ensure that self::$installed data is | ||||
|         // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not, | ||||
|         // so we have to assume it does not, and that may result in duplicate data being returned when listing | ||||
|         // all installed packages for example | ||||
|         self::$installedIsLocalDir = false; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return array[] | ||||
|      * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}> | ||||
|      */ | ||||
|     private static function getInstalled() | ||||
|     { | ||||
|         if (null === self::$canGetVendors) { | ||||
|             self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); | ||||
|         } | ||||
|  | ||||
|         $installed = array(); | ||||
|         $copiedLocalDir = false; | ||||
|  | ||||
|         if (self::$canGetVendors) { | ||||
|             $selfDir = strtr(__DIR__, '\\', '/'); | ||||
|             foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { | ||||
|                 $vendorDir = strtr($vendorDir, '\\', '/'); | ||||
|                 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<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */ | ||||
|                     $required = require $vendorDir.'/composer/installed.php'; | ||||
|                     self::$installedByVendor[$vendorDir] = $required; | ||||
|                     $installed[] = $required; | ||||
|                     if (self::$installed === null && $vendorDir.'/composer' === $selfDir) { | ||||
|                         self::$installed = $required; | ||||
|                         self::$installedIsLocalDir = true; | ||||
|                     } | ||||
|                 } | ||||
|                 if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) { | ||||
|                     $copiedLocalDir = true; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         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<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */ | ||||
|                 $required = require __DIR__ . '/installed.php'; | ||||
|                 self::$installed = $required; | ||||
|             } else { | ||||
|                 self::$installed = array(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (self::$installed !== array() && !$copiedLocalDir) { | ||||
|             $installed[] = self::$installed; | ||||
|         } | ||||
|  | ||||
|         return $installed; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										21
									
								
								vendor/composer/LICENSE
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								vendor/composer/LICENSE
									
									
									
									
										vendored
									
									
								
							| @@ -1,21 +0,0 @@ | ||||
|  | ||||
| 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. | ||||
|  | ||||
							
								
								
									
										1230
									
								
								vendor/composer/autoload_classmap.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1230
									
								
								vendor/composer/autoload_classmap.php
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										11
									
								
								vendor/composer/autoload_files.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								vendor/composer/autoload_files.php
									
									
									
									
										vendored
									
									
								
							| @@ -1,11 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| // autoload_files.php @generated by Composer | ||||
|  | ||||
| $vendorDir = dirname(__DIR__); | ||||
| $baseDir = dirname($vendorDir); | ||||
|  | ||||
| return array( | ||||
|     '6124b4c8570aa390c21fafd04a26c69f' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/deep_copy.php', | ||||
|     'ec07570ca5a812141189b1fa81503674' => $vendorDir . '/phpunit/phpunit/src/Framework/Assert/Functions.php', | ||||
| ); | ||||
							
								
								
									
										9
									
								
								vendor/composer/autoload_namespaces.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								vendor/composer/autoload_namespaces.php
									
									
									
									
										vendored
									
									
								
							| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| // autoload_namespaces.php @generated by Composer | ||||
|  | ||||
| $vendorDir = dirname(__DIR__); | ||||
| $baseDir = dirname($vendorDir); | ||||
|  | ||||
| return array( | ||||
| ); | ||||
							
								
								
									
										13
									
								
								vendor/composer/autoload_psr4.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								vendor/composer/autoload_psr4.php
									
									
									
									
										vendored
									
									
								
							| @@ -1,13 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| // autoload_psr4.php @generated by Composer | ||||
|  | ||||
| $vendorDir = dirname(__DIR__); | ||||
| $baseDir = dirname($vendorDir); | ||||
|  | ||||
| return array( | ||||
|     'goodboyalex\\php_components_pack\\tests\\' => array($baseDir . '/tests'), | ||||
|     'goodboyalex\\php_components_pack\\' => array($baseDir . '/sources'), | ||||
|     'PhpParser\\' => array($vendorDir . '/nikic/php-parser/lib/PhpParser'), | ||||
|     'DeepCopy\\' => array($vendorDir . '/myclabs/deep-copy/src/DeepCopy'), | ||||
| ); | ||||
							
								
								
									
										50
									
								
								vendor/composer/autoload_real.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										50
									
								
								vendor/composer/autoload_real.php
									
									
									
									
										vendored
									
									
								
							| @@ -1,50 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| // autoload_real.php @generated by Composer | ||||
|  | ||||
| class ComposerAutoloaderInitc00e5b601adae61bbbc3f6be4864ef55 | ||||
| { | ||||
|     private static $loader; | ||||
|  | ||||
|     public static function loadClassLoader($class) | ||||
|     { | ||||
|         if ('Composer\Autoload\ClassLoader' === $class) { | ||||
|             require __DIR__ . '/ClassLoader.php'; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return \Composer\Autoload\ClassLoader | ||||
|      */ | ||||
|     public static function getLoader() | ||||
|     { | ||||
|         if (null !== self::$loader) { | ||||
|             return self::$loader; | ||||
|         } | ||||
|  | ||||
|         require __DIR__ . '/platform_check.php'; | ||||
|  | ||||
|         spl_autoload_register(array('ComposerAutoloaderInitc00e5b601adae61bbbc3f6be4864ef55', 'loadClassLoader'), true, true); | ||||
|         self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); | ||||
|         spl_autoload_unregister(array('ComposerAutoloaderInitc00e5b601adae61bbbc3f6be4864ef55', 'loadClassLoader')); | ||||
|  | ||||
|         require __DIR__ . '/autoload_static.php'; | ||||
|         call_user_func(\Composer\Autoload\ComposerStaticInitc00e5b601adae61bbbc3f6be4864ef55::getInitializer($loader)); | ||||
|  | ||||
|         $loader->register(true); | ||||
|  | ||||
|         $filesToLoad = \Composer\Autoload\ComposerStaticInitc00e5b601adae61bbbc3f6be4864ef55::$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; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										1282
									
								
								vendor/composer/autoload_static.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1282
									
								
								vendor/composer/autoload_static.php
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1803
									
								
								vendor/composer/installed.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1803
									
								
								vendor/composer/installed.json
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										266
									
								
								vendor/composer/installed.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										266
									
								
								vendor/composer/installed.php
									
									
									
									
										vendored
									
									
								
							| @@ -1,266 +0,0 @@ | ||||
| <?php return array( | ||||
|     'root' => array( | ||||
|         'name' => 'goodboyalex/php_components_pack', | ||||
|         'pretty_version' => 'dev-master', | ||||
|         'version' => 'dev-master', | ||||
|         'reference' => '6ed1df2eda6978ae8b1fac707d7c0b762bfe491d', | ||||
|         'type' => 'library', | ||||
|         'install_path' => __DIR__ . '/../../', | ||||
|         'aliases' => array(), | ||||
|         'dev' => true, | ||||
|     ), | ||||
|     'versions' => array( | ||||
|         'goodboyalex/php_components_pack' => array( | ||||
|             'pretty_version' => 'dev-master', | ||||
|             'version' => 'dev-master', | ||||
|             'reference' => '6ed1df2eda6978ae8b1fac707d7c0b762bfe491d', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../../', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => false, | ||||
|         ), | ||||
|         'myclabs/deep-copy' => array( | ||||
|             'pretty_version' => '1.12.1', | ||||
|             'version' => '1.12.1.0', | ||||
|             'reference' => '123267b2c49fbf30d78a7b2d333f6be754b94845', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../myclabs/deep-copy', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'nikic/php-parser' => array( | ||||
|             'pretty_version' => 'v5.4.0', | ||||
|             'version' => '5.4.0.0', | ||||
|             'reference' => '447a020a1f875a434d62f2a401f53b82a396e494', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../nikic/php-parser', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'phar-io/manifest' => array( | ||||
|             'pretty_version' => '2.0.4', | ||||
|             'version' => '2.0.4.0', | ||||
|             'reference' => '54750ef60c58e43759730615a392c31c80e23176', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../phar-io/manifest', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'phar-io/version' => array( | ||||
|             'pretty_version' => '3.2.1', | ||||
|             'version' => '3.2.1.0', | ||||
|             'reference' => '4f7fd7836c6f332bb2933569e566a0d6c4cbed74', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../phar-io/version', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'phpunit/php-code-coverage' => array( | ||||
|             'pretty_version' => '11.0.8', | ||||
|             'version' => '11.0.8.0', | ||||
|             'reference' => '418c59fd080954f8c4aa5631d9502ecda2387118', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../phpunit/php-code-coverage', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'phpunit/php-file-iterator' => array( | ||||
|             'pretty_version' => '5.1.0', | ||||
|             'version' => '5.1.0.0', | ||||
|             'reference' => '118cfaaa8bc5aef3287bf315b6060b1174754af6', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../phpunit/php-file-iterator', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'phpunit/php-invoker' => array( | ||||
|             'pretty_version' => '5.0.1', | ||||
|             'version' => '5.0.1.0', | ||||
|             'reference' => 'c1ca3814734c07492b3d4c5f794f4b0995333da2', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../phpunit/php-invoker', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'phpunit/php-text-template' => array( | ||||
|             'pretty_version' => '4.0.1', | ||||
|             'version' => '4.0.1.0', | ||||
|             'reference' => '3e0404dc6b300e6bf56415467ebcb3fe4f33e964', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../phpunit/php-text-template', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'phpunit/php-timer' => array( | ||||
|             'pretty_version' => '7.0.1', | ||||
|             'version' => '7.0.1.0', | ||||
|             'reference' => '3b415def83fbcb41f991d9ebf16ae4ad8b7837b3', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../phpunit/php-timer', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'phpunit/phpunit' => array( | ||||
|             'pretty_version' => '11.5.6', | ||||
|             'version' => '11.5.6.0', | ||||
|             'reference' => '3c3ae14c90f244cdda95028c3e469028e8d1c02c', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../phpunit/phpunit', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'sebastian/cli-parser' => array( | ||||
|             'pretty_version' => '3.0.2', | ||||
|             'version' => '3.0.2.0', | ||||
|             'reference' => '15c5dd40dc4f38794d383bb95465193f5e0ae180', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../sebastian/cli-parser', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'sebastian/code-unit' => array( | ||||
|             'pretty_version' => '3.0.2', | ||||
|             'version' => '3.0.2.0', | ||||
|             'reference' => 'ee88b0cdbe74cf8dd3b54940ff17643c0d6543ca', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../sebastian/code-unit', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'sebastian/code-unit-reverse-lookup' => array( | ||||
|             'pretty_version' => '4.0.1', | ||||
|             'version' => '4.0.1.0', | ||||
|             'reference' => '183a9b2632194febd219bb9246eee421dad8d45e', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../sebastian/code-unit-reverse-lookup', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'sebastian/comparator' => array( | ||||
|             'pretty_version' => '6.3.0', | ||||
|             'version' => '6.3.0.0', | ||||
|             'reference' => 'd4e47a769525c4dd38cea90e5dcd435ddbbc7115', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../sebastian/comparator', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'sebastian/complexity' => array( | ||||
|             'pretty_version' => '4.0.1', | ||||
|             'version' => '4.0.1.0', | ||||
|             'reference' => 'ee41d384ab1906c68852636b6de493846e13e5a0', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../sebastian/complexity', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'sebastian/diff' => array( | ||||
|             'pretty_version' => '6.0.2', | ||||
|             'version' => '6.0.2.0', | ||||
|             'reference' => 'b4ccd857127db5d41a5b676f24b51371d76d8544', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../sebastian/diff', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'sebastian/environment' => array( | ||||
|             'pretty_version' => '7.2.0', | ||||
|             'version' => '7.2.0.0', | ||||
|             'reference' => '855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../sebastian/environment', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'sebastian/exporter' => array( | ||||
|             'pretty_version' => '6.3.0', | ||||
|             'version' => '6.3.0.0', | ||||
|             'reference' => '3473f61172093b2da7de1fb5782e1f24cc036dc3', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../sebastian/exporter', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'sebastian/global-state' => array( | ||||
|             'pretty_version' => '7.0.2', | ||||
|             'version' => '7.0.2.0', | ||||
|             'reference' => '3be331570a721f9a4b5917f4209773de17f747d7', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../sebastian/global-state', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'sebastian/lines-of-code' => array( | ||||
|             'pretty_version' => '3.0.1', | ||||
|             'version' => '3.0.1.0', | ||||
|             'reference' => 'd36ad0d782e5756913e42ad87cb2890f4ffe467a', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../sebastian/lines-of-code', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'sebastian/object-enumerator' => array( | ||||
|             'pretty_version' => '6.0.1', | ||||
|             'version' => '6.0.1.0', | ||||
|             'reference' => 'f5b498e631a74204185071eb41f33f38d64608aa', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../sebastian/object-enumerator', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'sebastian/object-reflector' => array( | ||||
|             'pretty_version' => '4.0.1', | ||||
|             'version' => '4.0.1.0', | ||||
|             'reference' => '6e1a43b411b2ad34146dee7524cb13a068bb35f9', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../sebastian/object-reflector', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'sebastian/recursion-context' => array( | ||||
|             'pretty_version' => '6.0.2', | ||||
|             'version' => '6.0.2.0', | ||||
|             'reference' => '694d156164372abbd149a4b85ccda2e4670c0e16', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../sebastian/recursion-context', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'sebastian/type' => array( | ||||
|             'pretty_version' => '5.1.0', | ||||
|             'version' => '5.1.0.0', | ||||
|             'reference' => '461b9c5da241511a2a0e8f240814fb23ce5c0aac', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../sebastian/type', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'sebastian/version' => array( | ||||
|             'pretty_version' => '5.0.2', | ||||
|             'version' => '5.0.2.0', | ||||
|             'reference' => 'c687e3387b99f5b03b6caa64c74b63e2936ff874', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../sebastian/version', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'staabm/side-effects-detector' => array( | ||||
|             'pretty_version' => '1.0.5', | ||||
|             'version' => '1.0.5.0', | ||||
|             'reference' => 'd8334211a140ce329c13726d4a715adbddd0a163', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../staabm/side-effects-detector', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|         'theseer/tokenizer' => array( | ||||
|             'pretty_version' => '1.2.3', | ||||
|             'version' => '1.2.3.0', | ||||
|             'reference' => '737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2', | ||||
|             'type' => 'library', | ||||
|             'install_path' => __DIR__ . '/../theseer/tokenizer', | ||||
|             'aliases' => array(), | ||||
|             'dev_requirement' => true, | ||||
|         ), | ||||
|     ), | ||||
| ); | ||||
							
								
								
									
										26
									
								
								vendor/composer/platform_check.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								vendor/composer/platform_check.php
									
									
									
									
										vendored
									
									
								
							| @@ -1,26 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| // platform_check.php @generated by Composer | ||||
|  | ||||
| $issues = array(); | ||||
|  | ||||
| if (!(PHP_VERSION_ID >= 80400)) { | ||||
|     $issues[] = 'Your Composer dependencies require a PHP version ">= 8.4.0". You are running ' . PHP_VERSION . '.'; | ||||
| } | ||||
|  | ||||
| if ($issues) { | ||||
|     if (!headers_sent()) { | ||||
|         header('HTTP/1.1 500 Internal Server Error'); | ||||
|     } | ||||
|     if (!ini_get('display_errors')) { | ||||
|         if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { | ||||
|             fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); | ||||
|         } elseif (!headers_sent()) { | ||||
|             echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; | ||||
|         } | ||||
|     } | ||||
|     trigger_error( | ||||
|         'Composer detected issues in your platform: ' . implode(' ', $issues), | ||||
|         E_USER_ERROR | ||||
|     ); | ||||
| } | ||||
							
								
								
									
										20
									
								
								vendor/myclabs/deep-copy/LICENSE
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/myclabs/deep-copy/LICENSE
									
									
									
									
										vendored
									
									
								
							| @@ -1,20 +0,0 @@ | ||||
| The MIT License (MIT) | ||||
|  | ||||
| Copyright (c) 2013 My C-Sense | ||||
|  | ||||
| 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. | ||||
							
								
								
									
										406
									
								
								vendor/myclabs/deep-copy/README.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										406
									
								
								vendor/myclabs/deep-copy/README.md
									
									
									
									
										vendored
									
									
								
							| @@ -1,406 +0,0 @@ | ||||
| # DeepCopy | ||||
|  | ||||
| DeepCopy helps you create deep copies (clones) of your objects. It is designed to handle cycles in the association graph. | ||||
|  | ||||
| [](https://packagist.org/packages/myclabs/deep-copy) | ||||
| [](https://github.com/myclabs/DeepCopy/actions/workflows/ci.yaml) | ||||
|  | ||||
| ## Table of Contents | ||||
|  | ||||
| 1. [How](#how) | ||||
| 1. [Why](#why) | ||||
|     1. [Using simply `clone`](#using-simply-clone) | ||||
|     1. [Overriding `__clone()`](#overriding-__clone) | ||||
|     1. [With `DeepCopy`](#with-deepcopy) | ||||
| 1. [How it works](#how-it-works) | ||||
| 1. [Going further](#going-further) | ||||
|     1. [Matchers](#matchers) | ||||
|         1. [Property name](#property-name) | ||||
|         1. [Specific property](#specific-property) | ||||
|         1. [Type](#type) | ||||
|     1. [Filters](#filters) | ||||
|         1. [`SetNullFilter`](#setnullfilter-filter) | ||||
|         1. [`KeepFilter`](#keepfilter-filter) | ||||
|         1. [`DoctrineCollectionFilter`](#doctrinecollectionfilter-filter) | ||||
|         1. [`DoctrineEmptyCollectionFilter`](#doctrineemptycollectionfilter-filter) | ||||
|         1. [`DoctrineProxyFilter`](#doctrineproxyfilter-filter) | ||||
|         1. [`ReplaceFilter`](#replacefilter-type-filter) | ||||
|         1. [`ShallowCopyFilter`](#shallowcopyfilter-type-filter) | ||||
| 1. [Edge cases](#edge-cases) | ||||
| 1. [Contributing](#contributing) | ||||
|     1. [Tests](#tests) | ||||
|  | ||||
|  | ||||
| ## How? | ||||
|  | ||||
| Install with Composer: | ||||
|  | ||||
| ``` | ||||
| composer require myclabs/deep-copy | ||||
| ``` | ||||
|  | ||||
| Use it: | ||||
|  | ||||
| ```php | ||||
| use DeepCopy\DeepCopy; | ||||
|  | ||||
| $copier = new DeepCopy(); | ||||
| $myCopy = $copier->copy($myObject); | ||||
| ``` | ||||
|  | ||||
|  | ||||
| ## Why? | ||||
|  | ||||
| - How do you create copies of your objects? | ||||
|  | ||||
| ```php | ||||
| $myCopy = clone $myObject; | ||||
| ``` | ||||
|  | ||||
| - How do you create **deep** copies of your objects (i.e. copying also all the objects referenced in the properties)? | ||||
|  | ||||
| You use [`__clone()`](http://www.php.net/manual/en/language.oop5.cloning.php#object.clone) and implement the behavior | ||||
| yourself. | ||||
|  | ||||
| - But how do you handle **cycles** in the association graph? | ||||
|  | ||||
| Now you're in for a big mess :( | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| ### Using simply `clone` | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| ### Overriding `__clone()` | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| ### With `DeepCopy` | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| ## How it works | ||||
|  | ||||
| DeepCopy recursively traverses all the object's properties and clones them. To avoid cloning the same object twice it | ||||
| keeps a hash map of all instances and thus preserves the object graph. | ||||
|  | ||||
| To use it: | ||||
|  | ||||
| ```php | ||||
| use function DeepCopy\deep_copy; | ||||
|  | ||||
| $copy = deep_copy($var); | ||||
| ``` | ||||
|  | ||||
| Alternatively, you can create your own `DeepCopy` instance to configure it differently for example: | ||||
|  | ||||
| ```php | ||||
| use DeepCopy\DeepCopy; | ||||
|  | ||||
| $copier = new DeepCopy(true); | ||||
|  | ||||
| $copy = $copier->copy($var); | ||||
| ``` | ||||
|  | ||||
| You may want to roll your own deep copy function: | ||||
|  | ||||
| ```php | ||||
| namespace Acme; | ||||
|  | ||||
| use DeepCopy\DeepCopy; | ||||
|  | ||||
| function deep_copy($var) | ||||
| { | ||||
|     static $copier = null; | ||||
|      | ||||
|     if (null === $copier) { | ||||
|         $copier = new DeepCopy(true); | ||||
|     } | ||||
|      | ||||
|     return $copier->copy($var); | ||||
| } | ||||
| ``` | ||||
|  | ||||
|  | ||||
| ## Going further | ||||
|  | ||||
| You can add filters to customize the copy process. | ||||
|  | ||||
| The method to add a filter is `DeepCopy\DeepCopy::addFilter($filter, $matcher)`, | ||||
| with `$filter` implementing `DeepCopy\Filter\Filter` | ||||
| and `$matcher` implementing `DeepCopy\Matcher\Matcher`. | ||||
|  | ||||
| We provide some generic filters and matchers. | ||||
|  | ||||
|  | ||||
| ### Matchers | ||||
|  | ||||
|   - `DeepCopy\Matcher` applies on a object attribute. | ||||
|   - `DeepCopy\TypeMatcher` applies on any element found in graph, including array elements. | ||||
|  | ||||
|  | ||||
| #### Property name | ||||
|  | ||||
| The `PropertyNameMatcher` will match a property by its name: | ||||
|  | ||||
| ```php | ||||
| use DeepCopy\Matcher\PropertyNameMatcher; | ||||
|  | ||||
| // Will apply a filter to any property of any objects named "id" | ||||
| $matcher = new PropertyNameMatcher('id'); | ||||
| ``` | ||||
|  | ||||
|  | ||||
| #### Specific property | ||||
|  | ||||
| The `PropertyMatcher` will match a specific property of a specific class: | ||||
|  | ||||
| ```php | ||||
| use DeepCopy\Matcher\PropertyMatcher; | ||||
|  | ||||
| // Will apply a filter to the property "id" of any objects of the class "MyClass" | ||||
| $matcher = new PropertyMatcher('MyClass', 'id'); | ||||
| ``` | ||||
|  | ||||
|  | ||||
| #### Type | ||||
|  | ||||
| The `TypeMatcher` will match any element by its type (instance of a class or any value that could be parameter of | ||||
| [gettype()](http://php.net/manual/en/function.gettype.php) function): | ||||
|  | ||||
| ```php | ||||
| use DeepCopy\TypeMatcher\TypeMatcher; | ||||
|  | ||||
| // Will apply a filter to any object that is an instance of Doctrine\Common\Collections\Collection | ||||
| $matcher = new TypeMatcher('Doctrine\Common\Collections\Collection'); | ||||
| ``` | ||||
|  | ||||
|  | ||||
| ### Filters | ||||
|  | ||||
| - `DeepCopy\Filter` applies a transformation to the object attribute matched by `DeepCopy\Matcher` | ||||
| - `DeepCopy\TypeFilter` applies a transformation to any element matched by `DeepCopy\TypeMatcher` | ||||
|  | ||||
| By design, matching a filter will stop the chain of filters (i.e. the next ones will not be applied). | ||||
| Using the ([`ChainableFilter`](#chainablefilter-filter)) won't stop the chain of filters. | ||||
|  | ||||
|  | ||||
| #### `SetNullFilter` (filter) | ||||
|  | ||||
| Let's say for example that you are copying a database record (or a Doctrine entity), so you want the copy not to have | ||||
| any ID: | ||||
|  | ||||
| ```php | ||||
| use DeepCopy\DeepCopy; | ||||
| use DeepCopy\Filter\SetNullFilter; | ||||
| use DeepCopy\Matcher\PropertyNameMatcher; | ||||
|  | ||||
| $object = MyClass::load(123); | ||||
| echo $object->id; // 123 | ||||
|  | ||||
| $copier = new DeepCopy(); | ||||
| $copier->addFilter(new SetNullFilter(), new PropertyNameMatcher('id')); | ||||
|  | ||||
| $copy = $copier->copy($object); | ||||
|  | ||||
| echo $copy->id; // null | ||||
| ``` | ||||
|  | ||||
|  | ||||
| #### `KeepFilter` (filter) | ||||
|  | ||||
| If you want a property to remain untouched (for example, an association to an object): | ||||
|  | ||||
| ```php | ||||
| use DeepCopy\DeepCopy; | ||||
| use DeepCopy\Filter\KeepFilter; | ||||
| use DeepCopy\Matcher\PropertyMatcher; | ||||
|  | ||||
| $copier = new DeepCopy(); | ||||
| $copier->addFilter(new KeepFilter(), new PropertyMatcher('MyClass', 'category')); | ||||
|  | ||||
| $copy = $copier->copy($object); | ||||
| // $copy->category has not been touched | ||||
| ``` | ||||
|  | ||||
|  | ||||
| #### `ChainableFilter` (filter) | ||||
|  | ||||
| If you use cloning on proxy classes, you might want to apply two filters for: | ||||
| 1. loading the data | ||||
| 2. applying a transformation | ||||
|  | ||||
| You can use the `ChainableFilter` as a decorator of the proxy loader filter, which won't stop the chain of filters (i.e.  | ||||
| the next ones may be applied). | ||||
|  | ||||
|  | ||||
| ```php | ||||
| use DeepCopy\DeepCopy; | ||||
| use DeepCopy\Filter\ChainableFilter; | ||||
| use DeepCopy\Filter\Doctrine\DoctrineProxyFilter; | ||||
| use DeepCopy\Filter\SetNullFilter; | ||||
| use DeepCopy\Matcher\Doctrine\DoctrineProxyMatcher; | ||||
| use DeepCopy\Matcher\PropertyNameMatcher; | ||||
|  | ||||
| $copier = new DeepCopy(); | ||||
| $copier->addFilter(new ChainableFilter(new DoctrineProxyFilter()), new DoctrineProxyMatcher()); | ||||
| $copier->addFilter(new SetNullFilter(), new PropertyNameMatcher('id')); | ||||
|  | ||||
| $copy = $copier->copy($object); | ||||
|  | ||||
| echo $copy->id; // null | ||||
| ``` | ||||
|  | ||||
|  | ||||
| #### `DoctrineCollectionFilter` (filter) | ||||
|  | ||||
| If you use Doctrine and want to copy an entity, you will need to use the `DoctrineCollectionFilter`: | ||||
|  | ||||
| ```php | ||||
| use DeepCopy\DeepCopy; | ||||
| use DeepCopy\Filter\Doctrine\DoctrineCollectionFilter; | ||||
| use DeepCopy\Matcher\PropertyTypeMatcher; | ||||
|  | ||||
| $copier = new DeepCopy(); | ||||
| $copier->addFilter(new DoctrineCollectionFilter(), new PropertyTypeMatcher('Doctrine\Common\Collections\Collection')); | ||||
|  | ||||
| $copy = $copier->copy($object); | ||||
| ``` | ||||
|  | ||||
|  | ||||
| #### `DoctrineEmptyCollectionFilter` (filter) | ||||
|  | ||||
| If you use Doctrine and want to copy an entity who contains a `Collection` that you want to be reset, you can use the | ||||
| `DoctrineEmptyCollectionFilter` | ||||
|  | ||||
| ```php | ||||
| use DeepCopy\DeepCopy; | ||||
| use DeepCopy\Filter\Doctrine\DoctrineEmptyCollectionFilter; | ||||
| use DeepCopy\Matcher\PropertyMatcher; | ||||
|  | ||||
| $copier = new DeepCopy(); | ||||
| $copier->addFilter(new DoctrineEmptyCollectionFilter(), new PropertyMatcher('MyClass', 'myProperty')); | ||||
|  | ||||
| $copy = $copier->copy($object); | ||||
|  | ||||
| // $copy->myProperty will return an empty collection | ||||
| ``` | ||||
|  | ||||
|  | ||||
| #### `DoctrineProxyFilter` (filter) | ||||
|  | ||||
| If you use Doctrine and use cloning on lazy loaded entities, you might encounter errors mentioning missing fields on a | ||||
| Doctrine proxy class (...\\\_\_CG\_\_\Proxy). | ||||
| You can use the `DoctrineProxyFilter` to load the actual entity behind the Doctrine proxy class. | ||||
| **Make sure, though, to put this as one of your very first filters in the filter chain so that the entity is loaded | ||||
| before other filters are applied!** | ||||
| We recommend to decorate the `DoctrineProxyFilter` with the `ChainableFilter` to allow applying other filters to the | ||||
| cloned lazy loaded entities. | ||||
|  | ||||
| ```php | ||||
| use DeepCopy\DeepCopy; | ||||
| use DeepCopy\Filter\Doctrine\DoctrineProxyFilter; | ||||
| use DeepCopy\Matcher\Doctrine\DoctrineProxyMatcher; | ||||
|  | ||||
| $copier = new DeepCopy(); | ||||
| $copier->addFilter(new ChainableFilter(new DoctrineProxyFilter()), new DoctrineProxyMatcher()); | ||||
|  | ||||
| $copy = $copier->copy($object); | ||||
|  | ||||
| // $copy should now contain a clone of all entities, including those that were not yet fully loaded. | ||||
| ``` | ||||
|  | ||||
|  | ||||
| #### `ReplaceFilter` (type filter) | ||||
|  | ||||
| 1. If you want to replace the value of a property: | ||||
|  | ||||
| ```php | ||||
| use DeepCopy\DeepCopy; | ||||
| use DeepCopy\Filter\ReplaceFilter; | ||||
| use DeepCopy\Matcher\PropertyMatcher; | ||||
|  | ||||
| $copier = new DeepCopy(); | ||||
| $callback = function ($currentValue) { | ||||
|   return $currentValue . ' (copy)' | ||||
| }; | ||||
| $copier->addFilter(new ReplaceFilter($callback), new PropertyMatcher('MyClass', 'title')); | ||||
|  | ||||
| $copy = $copier->copy($object); | ||||
|  | ||||
| // $copy->title will contain the data returned by the callback, e.g. 'The title (copy)' | ||||
| ``` | ||||
|  | ||||
| 2. If you want to replace whole element: | ||||
|  | ||||
| ```php | ||||
| use DeepCopy\DeepCopy; | ||||
| use DeepCopy\TypeFilter\ReplaceFilter; | ||||
| use DeepCopy\TypeMatcher\TypeMatcher; | ||||
|  | ||||
| $copier = new DeepCopy(); | ||||
| $callback = function (MyClass $myClass) { | ||||
|   return get_class($myClass); | ||||
| }; | ||||
| $copier->addTypeFilter(new ReplaceFilter($callback), new TypeMatcher('MyClass')); | ||||
|  | ||||
| $copy = $copier->copy([new MyClass, 'some string', new MyClass]); | ||||
|  | ||||
| // $copy will contain ['MyClass', 'some string', 'MyClass'] | ||||
| ``` | ||||
|  | ||||
|  | ||||
| The `$callback` parameter of the `ReplaceFilter` constructor accepts any PHP callable. | ||||
|  | ||||
|  | ||||
| #### `ShallowCopyFilter` (type filter) | ||||
|  | ||||
| Stop *DeepCopy* from recursively copying element, using standard `clone` instead: | ||||
|  | ||||
| ```php | ||||
| use DeepCopy\DeepCopy; | ||||
| use DeepCopy\TypeFilter\ShallowCopyFilter; | ||||
| use DeepCopy\TypeMatcher\TypeMatcher; | ||||
| use Mockery as m; | ||||
|  | ||||
| $this->deepCopy = new DeepCopy(); | ||||
| $this->deepCopy->addTypeFilter( | ||||
| 	new ShallowCopyFilter, | ||||
| 	new TypeMatcher(m\MockInterface::class) | ||||
| ); | ||||
|  | ||||
| $myServiceWithMocks = new MyService(m::mock(MyDependency1::class), m::mock(MyDependency2::class)); | ||||
| // All mocks will be just cloned, not deep copied | ||||
| ``` | ||||
|  | ||||
|  | ||||
| ## Edge cases | ||||
|  | ||||
| The following structures cannot be deep-copied with PHP Reflection. As a result they are shallow cloned and filters are | ||||
| not applied. There is two ways for you to handle them: | ||||
|  | ||||
| - Implement your own `__clone()` method | ||||
| - Use a filter with a type matcher | ||||
|  | ||||
|  | ||||
| ## Contributing | ||||
|  | ||||
| DeepCopy is distributed under the MIT license. | ||||
|  | ||||
|  | ||||
| ### Tests | ||||
|  | ||||
| Running the tests is simple: | ||||
|  | ||||
| ```php | ||||
| vendor/bin/phpunit | ||||
| ``` | ||||
|  | ||||
| ### Support | ||||
|  | ||||
| Get professional support via [the Tidelift Subscription](https://tidelift.com/subscription/pkg/packagist-myclabs-deep-copy?utm_source=packagist-myclabs-deep-copy&utm_medium=referral&utm_campaign=readme). | ||||
							
								
								
									
										43
									
								
								vendor/myclabs/deep-copy/composer.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										43
									
								
								vendor/myclabs/deep-copy/composer.json
									
									
									
									
										vendored
									
									
								
							| @@ -1,43 +0,0 @@ | ||||
| { | ||||
|     "name": "myclabs/deep-copy", | ||||
|     "description": "Create deep copies (clones) of your objects", | ||||
|     "license": "MIT", | ||||
|     "type": "library", | ||||
|     "keywords": [ | ||||
|         "clone", | ||||
|         "copy", | ||||
|         "duplicate", | ||||
|         "object", | ||||
|         "object graph" | ||||
|     ], | ||||
|     "require": { | ||||
|         "php": "^7.1 || ^8.0" | ||||
|     }, | ||||
|     "require-dev": { | ||||
|         "doctrine/collections": "^1.6.8", | ||||
|         "doctrine/common": "^2.13.3 || ^3.2.2", | ||||
|         "phpspec/prophecy": "^1.10", | ||||
|         "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" | ||||
|     }, | ||||
|     "conflict": { | ||||
|         "doctrine/collections": "<1.6.8", | ||||
|         "doctrine/common": "<2.13.3 || >=3 <3.2.2" | ||||
|     }, | ||||
|     "autoload": { | ||||
|         "psr-4": { | ||||
|             "DeepCopy\\": "src/DeepCopy/" | ||||
|         }, | ||||
|         "files": [ | ||||
|             "src/DeepCopy/deep_copy.php" | ||||
|         ] | ||||
|     }, | ||||
|     "autoload-dev": { | ||||
|         "psr-4": { | ||||
|             "DeepCopyTest\\": "tests/DeepCopyTest/", | ||||
|             "DeepCopy\\": "fixtures/" | ||||
|         } | ||||
|     }, | ||||
|     "config": { | ||||
|         "sort-packages": true | ||||
|     } | ||||
| } | ||||
							
								
								
									
										316
									
								
								vendor/myclabs/deep-copy/src/DeepCopy/DeepCopy.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										316
									
								
								vendor/myclabs/deep-copy/src/DeepCopy/DeepCopy.php
									
									
									
									
										vendored
									
									
								
							| @@ -1,316 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy; | ||||
|  | ||||
| use ArrayObject; | ||||
| use DateInterval; | ||||
| use DatePeriod; | ||||
| use DateTimeInterface; | ||||
| use DateTimeZone; | ||||
| use DeepCopy\Exception\CloneException; | ||||
| use DeepCopy\Filter\ChainableFilter; | ||||
| use DeepCopy\Filter\Filter; | ||||
| use DeepCopy\Matcher\Matcher; | ||||
| use DeepCopy\Reflection\ReflectionHelper; | ||||
| use DeepCopy\TypeFilter\Date\DateIntervalFilter; | ||||
| use DeepCopy\TypeFilter\Date\DatePeriodFilter; | ||||
| use DeepCopy\TypeFilter\Spl\ArrayObjectFilter; | ||||
| use DeepCopy\TypeFilter\Spl\SplDoublyLinkedListFilter; | ||||
| use DeepCopy\TypeFilter\TypeFilter; | ||||
| use DeepCopy\TypeMatcher\TypeMatcher; | ||||
| use ReflectionObject; | ||||
| use ReflectionProperty; | ||||
| use SplDoublyLinkedList; | ||||
|  | ||||
| /** | ||||
|  * @final | ||||
|  */ | ||||
| class DeepCopy | ||||
| { | ||||
|     /** | ||||
|      * @var object[] List of objects copied. | ||||
|      */ | ||||
|     private $hashMap = []; | ||||
|  | ||||
|     /** | ||||
|      * Filters to apply. | ||||
|      * | ||||
|      * @var array Array of ['filter' => Filter, 'matcher' => Matcher] pairs. | ||||
|      */ | ||||
|     private $filters = []; | ||||
|  | ||||
|     /** | ||||
|      * Type Filters to apply. | ||||
|      * | ||||
|      * @var array Array of ['filter' => Filter, 'matcher' => Matcher] pairs. | ||||
|      */ | ||||
|     private $typeFilters = []; | ||||
|  | ||||
|     /** | ||||
|      * @var bool | ||||
|      */ | ||||
|     private $skipUncloneable = false; | ||||
|  | ||||
|     /** | ||||
|      * @var bool | ||||
|      */ | ||||
|     private $useCloneMethod; | ||||
|  | ||||
|     /** | ||||
|      * @param bool $useCloneMethod   If set to true, when an object implements the __clone() function, it will be used | ||||
|      *                               instead of the regular deep cloning. | ||||
|      */ | ||||
|     public function __construct($useCloneMethod = false) | ||||
|     { | ||||
|         $this->useCloneMethod = $useCloneMethod; | ||||
|  | ||||
|         $this->addTypeFilter(new ArrayObjectFilter($this), new TypeMatcher(ArrayObject::class)); | ||||
|         $this->addTypeFilter(new DateIntervalFilter(), new TypeMatcher(DateInterval::class)); | ||||
|         $this->addTypeFilter(new DatePeriodFilter(), new TypeMatcher(DatePeriod::class)); | ||||
|         $this->addTypeFilter(new SplDoublyLinkedListFilter($this), new TypeMatcher(SplDoublyLinkedList::class)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * If enabled, will not throw an exception when coming across an uncloneable property. | ||||
|      * | ||||
|      * @param $skipUncloneable | ||||
|      * | ||||
|      * @return $this | ||||
|      */ | ||||
|     public function skipUncloneable($skipUncloneable = true) | ||||
|     { | ||||
|         $this->skipUncloneable = $skipUncloneable; | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Deep copies the given object. | ||||
|      * | ||||
|      * @param mixed $object | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     public function copy($object) | ||||
|     { | ||||
|         $this->hashMap = []; | ||||
|  | ||||
|         return $this->recursiveCopy($object); | ||||
|     } | ||||
|  | ||||
|     public function addFilter(Filter $filter, Matcher $matcher) | ||||
|     { | ||||
|         $this->filters[] = [ | ||||
|             'matcher' => $matcher, | ||||
|             'filter'  => $filter, | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     public function prependFilter(Filter $filter, Matcher $matcher) | ||||
|     { | ||||
|         array_unshift($this->filters, [ | ||||
|             'matcher' => $matcher, | ||||
|             'filter'  => $filter, | ||||
|         ]); | ||||
|     } | ||||
|  | ||||
|     public function addTypeFilter(TypeFilter $filter, TypeMatcher $matcher) | ||||
|     { | ||||
|         $this->typeFilters[] = [ | ||||
|             'matcher' => $matcher, | ||||
|             'filter'  => $filter, | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     private function recursiveCopy($var) | ||||
|     { | ||||
|         // Matches Type Filter | ||||
|         if ($filter = $this->getFirstMatchedTypeFilter($this->typeFilters, $var)) { | ||||
|             return $filter->apply($var); | ||||
|         } | ||||
|  | ||||
|         // Resource | ||||
|         if (is_resource($var)) { | ||||
|             return $var; | ||||
|         } | ||||
|  | ||||
|         // Array | ||||
|         if (is_array($var)) { | ||||
|             return $this->copyArray($var); | ||||
|         } | ||||
|  | ||||
|         // Scalar | ||||
|         if (! is_object($var)) { | ||||
|             return $var; | ||||
|         } | ||||
|  | ||||
|         // Enum | ||||
|         if (PHP_VERSION_ID >= 80100 && enum_exists(get_class($var))) { | ||||
|             return $var; | ||||
|         } | ||||
|  | ||||
|         // Object | ||||
|         return $this->copyObject($var); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Copy an array | ||||
|      * @param array $array | ||||
|      * @return array | ||||
|      */ | ||||
|     private function copyArray(array $array) | ||||
|     { | ||||
|         foreach ($array as $key => $value) { | ||||
|             $array[$key] = $this->recursiveCopy($value); | ||||
|         } | ||||
|  | ||||
|         return $array; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Copies an object. | ||||
|      * | ||||
|      * @param object $object | ||||
|      * | ||||
|      * @throws CloneException | ||||
|      * | ||||
|      * @return object | ||||
|      */ | ||||
|     private function copyObject($object) | ||||
|     { | ||||
|         $objectHash = spl_object_hash($object); | ||||
|  | ||||
|         if (isset($this->hashMap[$objectHash])) { | ||||
|             return $this->hashMap[$objectHash]; | ||||
|         } | ||||
|  | ||||
|         $reflectedObject = new ReflectionObject($object); | ||||
|         $isCloneable = $reflectedObject->isCloneable(); | ||||
|  | ||||
|         if (false === $isCloneable) { | ||||
|             if ($this->skipUncloneable) { | ||||
|                 $this->hashMap[$objectHash] = $object; | ||||
|  | ||||
|                 return $object; | ||||
|             } | ||||
|  | ||||
|             throw new CloneException( | ||||
|                 sprintf( | ||||
|                     'The class "%s" is not cloneable.', | ||||
|                     $reflectedObject->getName() | ||||
|                 ) | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         $newObject = clone $object; | ||||
|         $this->hashMap[$objectHash] = $newObject; | ||||
|  | ||||
|         if ($this->useCloneMethod && $reflectedObject->hasMethod('__clone')) { | ||||
|             return $newObject; | ||||
|         } | ||||
|  | ||||
|         if ($newObject instanceof DateTimeInterface || $newObject instanceof DateTimeZone) { | ||||
|             return $newObject; | ||||
|         } | ||||
|  | ||||
|         foreach (ReflectionHelper::getProperties($reflectedObject) as $property) { | ||||
|             $this->copyObjectProperty($newObject, $property); | ||||
|         } | ||||
|  | ||||
|         return $newObject; | ||||
|     } | ||||
|  | ||||
|     private function copyObjectProperty($object, ReflectionProperty $property) | ||||
|     { | ||||
|         // Ignore static properties | ||||
|         if ($property->isStatic()) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // Ignore readonly properties | ||||
|         if (method_exists($property, 'isReadOnly') && $property->isReadOnly()) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // Apply the filters | ||||
|         foreach ($this->filters as $item) { | ||||
|             /** @var Matcher $matcher */ | ||||
|             $matcher = $item['matcher']; | ||||
|             /** @var Filter $filter */ | ||||
|             $filter = $item['filter']; | ||||
|  | ||||
|             if ($matcher->matches($object, $property->getName())) { | ||||
|                 $filter->apply( | ||||
|                     $object, | ||||
|                     $property->getName(), | ||||
|                     function ($object) { | ||||
|                         return $this->recursiveCopy($object); | ||||
|                     } | ||||
|                 ); | ||||
|  | ||||
|                 if ($filter instanceof ChainableFilter) { | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 // If a filter matches, we stop processing this property | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         $property->setAccessible(true); | ||||
|  | ||||
|         // Ignore uninitialized properties (for PHP >7.4) | ||||
|         if (method_exists($property, 'isInitialized') && !$property->isInitialized($object)) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         $propertyValue = $property->getValue($object); | ||||
|  | ||||
|         // Copy the property | ||||
|         $property->setValue($object, $this->recursiveCopy($propertyValue)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns first filter that matches variable, `null` if no such filter found. | ||||
|      * | ||||
|      * @param array $filterRecords Associative array with 2 members: 'filter' with value of type {@see TypeFilter} and | ||||
|      *                             'matcher' with value of type {@see TypeMatcher} | ||||
|      * @param mixed $var | ||||
|      * | ||||
|      * @return TypeFilter|null | ||||
|      */ | ||||
|     private function getFirstMatchedTypeFilter(array $filterRecords, $var) | ||||
|     { | ||||
|         $matched = $this->first( | ||||
|             $filterRecords, | ||||
|             function (array $record) use ($var) { | ||||
|                 /* @var TypeMatcher $matcher */ | ||||
|                 $matcher = $record['matcher']; | ||||
|  | ||||
|                 return $matcher->matches($var); | ||||
|             } | ||||
|         ); | ||||
|  | ||||
|         return isset($matched) ? $matched['filter'] : null; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns first element that matches predicate, `null` if no such element found. | ||||
|      * | ||||
|      * @param array    $elements Array of ['filter' => Filter, 'matcher' => Matcher] pairs. | ||||
|      * @param callable $predicate Predicate arguments are: element. | ||||
|      * | ||||
|      * @return array|null Associative array with 2 members: 'filter' with value of type {@see TypeFilter} and 'matcher' | ||||
|      *                    with value of type {@see TypeMatcher} or `null`. | ||||
|      */ | ||||
|     private function first(array $elements, callable $predicate) | ||||
|     { | ||||
|         foreach ($elements as $element) { | ||||
|             if (call_user_func($predicate, $element)) { | ||||
|                 return $element; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return null; | ||||
|     } | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy\Exception; | ||||
|  | ||||
| use UnexpectedValueException; | ||||
|  | ||||
| class CloneException extends UnexpectedValueException | ||||
| { | ||||
| }  | ||||
| @@ -1,9 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy\Exception; | ||||
|  | ||||
| use ReflectionException; | ||||
|  | ||||
| class PropertyException extends ReflectionException | ||||
| { | ||||
| } | ||||
| @@ -1,24 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy\Filter; | ||||
|  | ||||
| /** | ||||
|  * Defines a decorator filter that will not stop the chain of filters. | ||||
|  */ | ||||
| class ChainableFilter implements Filter | ||||
| { | ||||
|     /** | ||||
|      * @var Filter | ||||
|      */ | ||||
|     protected $filter; | ||||
|  | ||||
|     public function __construct(Filter $filter) | ||||
|     { | ||||
|         $this->filter = $filter; | ||||
|     } | ||||
|  | ||||
|     public function apply($object, $property, $objectCopier) | ||||
|     { | ||||
|         $this->filter->apply($object, $property, $objectCopier); | ||||
|     } | ||||
| } | ||||
| @@ -1,33 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy\Filter\Doctrine; | ||||
|  | ||||
| use DeepCopy\Filter\Filter; | ||||
| use DeepCopy\Reflection\ReflectionHelper; | ||||
|  | ||||
| /** | ||||
|  * @final | ||||
|  */ | ||||
| class DoctrineCollectionFilter implements Filter | ||||
| { | ||||
|     /** | ||||
|      * Copies the object property doctrine collection. | ||||
|      * | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function apply($object, $property, $objectCopier) | ||||
|     { | ||||
|         $reflectionProperty = ReflectionHelper::getProperty($object, $property); | ||||
|  | ||||
|         $reflectionProperty->setAccessible(true); | ||||
|         $oldCollection = $reflectionProperty->getValue($object); | ||||
|  | ||||
|         $newCollection = $oldCollection->map( | ||||
|             function ($item) use ($objectCopier) { | ||||
|                 return $objectCopier($item); | ||||
|             } | ||||
|         ); | ||||
|  | ||||
|         $reflectionProperty->setValue($object, $newCollection); | ||||
|     } | ||||
| } | ||||
| @@ -1,28 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy\Filter\Doctrine; | ||||
|  | ||||
| use DeepCopy\Filter\Filter; | ||||
| use DeepCopy\Reflection\ReflectionHelper; | ||||
| use Doctrine\Common\Collections\ArrayCollection; | ||||
|  | ||||
| /** | ||||
|  * @final | ||||
|  */ | ||||
| class DoctrineEmptyCollectionFilter implements Filter | ||||
| { | ||||
|     /** | ||||
|      * Sets the object property to an empty doctrine collection. | ||||
|      * | ||||
|      * @param object   $object | ||||
|      * @param string   $property | ||||
|      * @param callable $objectCopier | ||||
|      */ | ||||
|     public function apply($object, $property, $objectCopier) | ||||
|     { | ||||
|         $reflectionProperty = ReflectionHelper::getProperty($object, $property); | ||||
|         $reflectionProperty->setAccessible(true); | ||||
|  | ||||
|         $reflectionProperty->setValue($object, new ArrayCollection()); | ||||
|     } | ||||
| }  | ||||
| @@ -1,22 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy\Filter\Doctrine; | ||||
|  | ||||
| use DeepCopy\Filter\Filter; | ||||
|  | ||||
| /** | ||||
|  * @final | ||||
|  */ | ||||
| class DoctrineProxyFilter implements Filter | ||||
| { | ||||
|     /** | ||||
|      * Triggers the magic method __load() on a Doctrine Proxy class to load the | ||||
|      * actual entity from the database. | ||||
|      * | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function apply($object, $property, $objectCopier) | ||||
|     { | ||||
|         $object->__load(); | ||||
|     } | ||||
| } | ||||
| @@ -1,18 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy\Filter; | ||||
|  | ||||
| /** | ||||
|  * Filter to apply to a property while copying an object | ||||
|  */ | ||||
| interface Filter | ||||
| { | ||||
|     /** | ||||
|      * Applies the filter to the object. | ||||
|      * | ||||
|      * @param object   $object | ||||
|      * @param string   $property | ||||
|      * @param callable $objectCopier | ||||
|      */ | ||||
|     public function apply($object, $property, $objectCopier); | ||||
| } | ||||
| @@ -1,16 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy\Filter; | ||||
|  | ||||
| class KeepFilter implements Filter | ||||
| { | ||||
|     /** | ||||
|      * Keeps the value of the object property. | ||||
|      * | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function apply($object, $property, $objectCopier) | ||||
|     { | ||||
|         // Nothing to do | ||||
|     } | ||||
| } | ||||
| @@ -1,39 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy\Filter; | ||||
|  | ||||
| use DeepCopy\Reflection\ReflectionHelper; | ||||
|  | ||||
| /** | ||||
|  * @final | ||||
|  */ | ||||
| class ReplaceFilter implements Filter | ||||
| { | ||||
|     /** | ||||
|      * @var callable | ||||
|      */ | ||||
|     protected $callback; | ||||
|  | ||||
|     /** | ||||
|      * @param callable $callable Will be called to get the new value for each property to replace | ||||
|      */ | ||||
|     public function __construct(callable $callable) | ||||
|     { | ||||
|         $this->callback = $callable; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Replaces the object property by the result of the callback called with the object property. | ||||
|      * | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function apply($object, $property, $objectCopier) | ||||
|     { | ||||
|         $reflectionProperty = ReflectionHelper::getProperty($object, $property); | ||||
|         $reflectionProperty->setAccessible(true); | ||||
|  | ||||
|         $value = call_user_func($this->callback, $reflectionProperty->getValue($object)); | ||||
|  | ||||
|         $reflectionProperty->setValue($object, $value); | ||||
|     } | ||||
| } | ||||
| @@ -1,24 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy\Filter; | ||||
|  | ||||
| use DeepCopy\Reflection\ReflectionHelper; | ||||
|  | ||||
| /** | ||||
|  * @final | ||||
|  */ | ||||
| class SetNullFilter implements Filter | ||||
| { | ||||
|     /** | ||||
|      * Sets the object property to null. | ||||
|      * | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function apply($object, $property, $objectCopier) | ||||
|     { | ||||
|         $reflectionProperty = ReflectionHelper::getProperty($object, $property); | ||||
|  | ||||
|         $reflectionProperty->setAccessible(true); | ||||
|         $reflectionProperty->setValue($object, null); | ||||
|     } | ||||
| } | ||||
| @@ -1,22 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy\Matcher\Doctrine; | ||||
|  | ||||
| use DeepCopy\Matcher\Matcher; | ||||
| use Doctrine\Persistence\Proxy; | ||||
|  | ||||
| /** | ||||
|  * @final | ||||
|  */ | ||||
| class DoctrineProxyMatcher implements Matcher | ||||
| { | ||||
|     /** | ||||
|      * Matches a Doctrine Proxy class. | ||||
|      * | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function matches($object, $property) | ||||
|     { | ||||
|         return $object instanceof Proxy; | ||||
|     } | ||||
| } | ||||
| @@ -1,14 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy\Matcher; | ||||
|  | ||||
| interface Matcher | ||||
| { | ||||
|     /** | ||||
|      * @param object $object | ||||
|      * @param string $property | ||||
|      * | ||||
|      * @return boolean | ||||
|      */ | ||||
|     public function matches($object, $property); | ||||
| } | ||||
| @@ -1,39 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy\Matcher; | ||||
|  | ||||
| /** | ||||
|  * @final | ||||
|  */ | ||||
| class PropertyMatcher implements Matcher | ||||
| { | ||||
|     /** | ||||
|      * @var string | ||||
|      */ | ||||
|     private $class; | ||||
|  | ||||
|     /** | ||||
|      * @var string | ||||
|      */ | ||||
|     private $property; | ||||
|  | ||||
|     /** | ||||
|      * @param string $class    Class name | ||||
|      * @param string $property Property name | ||||
|      */ | ||||
|     public function __construct($class, $property) | ||||
|     { | ||||
|         $this->class = $class; | ||||
|         $this->property = $property; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Matches a specific property of a specific class. | ||||
|      * | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function matches($object, $property) | ||||
|     { | ||||
|         return ($object instanceof $this->class) && $property == $this->property; | ||||
|     } | ||||
| } | ||||
| @@ -1,32 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy\Matcher; | ||||
|  | ||||
| /** | ||||
|  * @final | ||||
|  */ | ||||
| class PropertyNameMatcher implements Matcher | ||||
| { | ||||
|     /** | ||||
|      * @var string | ||||
|      */ | ||||
|     private $property; | ||||
|  | ||||
|     /** | ||||
|      * @param string $property Property name | ||||
|      */ | ||||
|     public function __construct($property) | ||||
|     { | ||||
|         $this->property = $property; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Matches a property by its name. | ||||
|      * | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function matches($object, $property) | ||||
|     { | ||||
|         return $property == $this->property; | ||||
|     } | ||||
| } | ||||
| @@ -1,52 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy\Matcher; | ||||
|  | ||||
| use DeepCopy\Reflection\ReflectionHelper; | ||||
| use ReflectionException; | ||||
|  | ||||
| /** | ||||
|  * Matches a property by its type. | ||||
|  * | ||||
|  * It is recommended to use {@see DeepCopy\TypeFilter\TypeFilter} instead, as it applies on all occurrences | ||||
|  * of given type in copied context (eg. array elements), not just on object properties. | ||||
|  * | ||||
|  * @final | ||||
|  */ | ||||
| class PropertyTypeMatcher implements Matcher | ||||
| { | ||||
|     /** | ||||
|      * @var string | ||||
|      */ | ||||
|     private $propertyType; | ||||
|  | ||||
|     /** | ||||
|      * @param string $propertyType Property type | ||||
|      */ | ||||
|     public function __construct($propertyType) | ||||
|     { | ||||
|         $this->propertyType = $propertyType; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function matches($object, $property) | ||||
|     { | ||||
|         try { | ||||
|             $reflectionProperty = ReflectionHelper::getProperty($object, $property); | ||||
|         } catch (ReflectionException $exception) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         $reflectionProperty->setAccessible(true); | ||||
|  | ||||
|         // Uninitialized properties (for PHP >7.4) | ||||
|         if (method_exists($reflectionProperty, 'isInitialized') && !$reflectionProperty->isInitialized($object)) { | ||||
|             // null instanceof $this->propertyType | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         return $reflectionProperty->getValue($object) instanceof $this->propertyType; | ||||
|     } | ||||
| } | ||||
| @@ -1,78 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy\Reflection; | ||||
|  | ||||
| use DeepCopy\Exception\PropertyException; | ||||
| use ReflectionClass; | ||||
| use ReflectionException; | ||||
| use ReflectionObject; | ||||
| use ReflectionProperty; | ||||
|  | ||||
| class ReflectionHelper | ||||
| { | ||||
|     /** | ||||
|      * Retrieves all properties (including private ones), from object and all its ancestors. | ||||
|      * | ||||
|      * Standard \ReflectionClass->getProperties() does not return private properties from ancestor classes. | ||||
|      * | ||||
|      * @author muratyaman@gmail.com | ||||
|      * @see http://php.net/manual/en/reflectionclass.getproperties.php | ||||
|      * | ||||
|      * @param ReflectionClass $ref | ||||
|      * | ||||
|      * @return ReflectionProperty[] | ||||
|      */ | ||||
|     public static function getProperties(ReflectionClass $ref) | ||||
|     { | ||||
|         $props = $ref->getProperties(); | ||||
|         $propsArr = array(); | ||||
|  | ||||
|         foreach ($props as $prop) { | ||||
|             $propertyName = $prop->getName(); | ||||
|             $propsArr[$propertyName] = $prop; | ||||
|         } | ||||
|  | ||||
|         if ($parentClass = $ref->getParentClass()) { | ||||
|             $parentPropsArr = self::getProperties($parentClass); | ||||
|             foreach ($propsArr as $key => $property) { | ||||
|                 $parentPropsArr[$key] = $property; | ||||
|             } | ||||
|  | ||||
|             return $parentPropsArr; | ||||
|         } | ||||
|  | ||||
|         return $propsArr; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Retrieves property by name from object and all its ancestors. | ||||
|      * | ||||
|      * @param object|string $object | ||||
|      * @param string $name | ||||
|      * | ||||
|      * @throws PropertyException | ||||
|      * @throws ReflectionException | ||||
|      * | ||||
|      * @return ReflectionProperty | ||||
|      */ | ||||
|     public static function getProperty($object, $name) | ||||
|     { | ||||
|         $reflection = is_object($object) ? new ReflectionObject($object) : new ReflectionClass($object); | ||||
|  | ||||
|         if ($reflection->hasProperty($name)) { | ||||
|             return $reflection->getProperty($name); | ||||
|         } | ||||
|  | ||||
|         if ($parentClass = $reflection->getParentClass()) { | ||||
|             return self::getProperty($parentClass->getName(), $name); | ||||
|         } | ||||
|  | ||||
|         throw new PropertyException( | ||||
|             sprintf( | ||||
|                 'The class "%s" doesn\'t have a property with the given name: "%s".', | ||||
|                 is_object($object) ? get_class($object) : $object, | ||||
|                 $name | ||||
|             ) | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| @@ -1,33 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy\TypeFilter\Date; | ||||
|  | ||||
| use DateInterval; | ||||
| use DeepCopy\TypeFilter\TypeFilter; | ||||
|  | ||||
| /** | ||||
|  * @final | ||||
|  * | ||||
|  * @deprecated Will be removed in 2.0. This filter will no longer be necessary in PHP 7.1+. | ||||
|  */ | ||||
| class DateIntervalFilter implements TypeFilter | ||||
| { | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      * | ||||
|      * @param DateInterval $element | ||||
|      * | ||||
|      * @see http://news.php.net/php.bugs/205076 | ||||
|      */ | ||||
|     public function apply($element) | ||||
|     { | ||||
|         $copy = new DateInterval('P0D'); | ||||
|  | ||||
|         foreach ($element as $propertyName => $propertyValue) { | ||||
|             $copy->{$propertyName} = $propertyValue; | ||||
|         } | ||||
|  | ||||
|         return $copy; | ||||
|     } | ||||
| } | ||||
| @@ -1,42 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy\TypeFilter\Date; | ||||
|  | ||||
| use DatePeriod; | ||||
| use DeepCopy\TypeFilter\TypeFilter; | ||||
|  | ||||
| /** | ||||
|  * @final | ||||
|  */ | ||||
| class DatePeriodFilter implements TypeFilter | ||||
| { | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      * | ||||
|      * @param DatePeriod $element | ||||
|      * | ||||
|      * @see http://news.php.net/php.bugs/205076 | ||||
|      */ | ||||
|     public function apply($element) | ||||
|     { | ||||
|         $options = 0; | ||||
|         if (PHP_VERSION_ID >= 80200 && $element->include_end_date) { | ||||
|             $options |= DatePeriod::INCLUDE_END_DATE; | ||||
|         } | ||||
|         if (!$element->include_start_date) { | ||||
|             $options |= DatePeriod::EXCLUDE_START_DATE; | ||||
|         } | ||||
|  | ||||
|         if ($element->getEndDate()) { | ||||
|             return new DatePeriod($element->getStartDate(), $element->getDateInterval(), $element->getEndDate(), $options); | ||||
|         } | ||||
|  | ||||
|         if (PHP_VERSION_ID >= 70217) { | ||||
|             $recurrences = $element->getRecurrences(); | ||||
|         } else { | ||||
|             $recurrences = $element->recurrences - $element->include_start_date; | ||||
|         } | ||||
|  | ||||
|         return new DatePeriod($element->getStartDate(), $element->getDateInterval(), $recurrences, $options); | ||||
|     } | ||||
| } | ||||
| @@ -1,30 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy\TypeFilter; | ||||
|  | ||||
| /** | ||||
|  * @final | ||||
|  */ | ||||
| class ReplaceFilter implements TypeFilter | ||||
| { | ||||
|     /** | ||||
|      * @var callable | ||||
|      */ | ||||
|     protected $callback; | ||||
|  | ||||
|     /** | ||||
|      * @param callable $callable Will be called to get the new value for each element to replace | ||||
|      */ | ||||
|     public function __construct(callable $callable) | ||||
|     { | ||||
|         $this->callback = $callable; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function apply($element) | ||||
|     { | ||||
|         return call_user_func($this->callback, $element); | ||||
|     } | ||||
| } | ||||
| @@ -1,17 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy\TypeFilter; | ||||
|  | ||||
| /** | ||||
|  * @final | ||||
|  */ | ||||
| class ShallowCopyFilter implements TypeFilter | ||||
| { | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function apply($element) | ||||
|     { | ||||
|         return clone $element; | ||||
|     } | ||||
| } | ||||
| @@ -1,36 +0,0 @@ | ||||
| <?php | ||||
| namespace DeepCopy\TypeFilter\Spl; | ||||
|  | ||||
| use DeepCopy\DeepCopy; | ||||
| use DeepCopy\TypeFilter\TypeFilter; | ||||
|  | ||||
| /** | ||||
|  * In PHP 7.4 the storage of an ArrayObject isn't returned as | ||||
|  * ReflectionProperty. So we deep copy its array copy. | ||||
|  */ | ||||
| final class ArrayObjectFilter implements TypeFilter | ||||
| { | ||||
|     /** | ||||
|      * @var DeepCopy | ||||
|      */ | ||||
|     private $copier; | ||||
|  | ||||
|     public function __construct(DeepCopy $copier) | ||||
|     { | ||||
|         $this->copier = $copier; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function apply($arrayObject) | ||||
|     { | ||||
|         $clone = clone $arrayObject; | ||||
|         foreach ($arrayObject->getArrayCopy() as $k => $v) { | ||||
|             $clone->offsetSet($k, $this->copier->copy($v)); | ||||
|         } | ||||
|  | ||||
|         return $clone; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -1,10 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy\TypeFilter\Spl; | ||||
|  | ||||
| /** | ||||
|  * @deprecated Use {@see SplDoublyLinkedListFilter} instead. | ||||
|  */ | ||||
| class SplDoublyLinkedList extends SplDoublyLinkedListFilter | ||||
| { | ||||
| } | ||||
| @@ -1,51 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy\TypeFilter\Spl; | ||||
|  | ||||
| use Closure; | ||||
| use DeepCopy\DeepCopy; | ||||
| use DeepCopy\TypeFilter\TypeFilter; | ||||
| use SplDoublyLinkedList; | ||||
|  | ||||
| /** | ||||
|  * @final | ||||
|  */ | ||||
| class SplDoublyLinkedListFilter implements TypeFilter | ||||
| { | ||||
|     private $copier; | ||||
|  | ||||
|     public function __construct(DeepCopy $copier) | ||||
|     { | ||||
|         $this->copier = $copier; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * {@inheritdoc} | ||||
|      */ | ||||
|     public function apply($element) | ||||
|     { | ||||
|         $newElement = clone $element; | ||||
|  | ||||
|         $copy = $this->createCopyClosure(); | ||||
|  | ||||
|         return $copy($newElement); | ||||
|     } | ||||
|  | ||||
|     private function createCopyClosure() | ||||
|     { | ||||
|         $copier = $this->copier; | ||||
|  | ||||
|         $copy = function (SplDoublyLinkedList $list) use ($copier) { | ||||
|             // Replace each element in the list with a deep copy of itself | ||||
|             for ($i = 1; $i <= $list->count(); $i++) { | ||||
|                 $copy = $copier->recursiveCopy($list->shift()); | ||||
|  | ||||
|                 $list->push($copy); | ||||
|             } | ||||
|  | ||||
|             return $list; | ||||
|         }; | ||||
|  | ||||
|         return Closure::bind($copy, null, DeepCopy::class); | ||||
|     } | ||||
| } | ||||
| @@ -1,13 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy\TypeFilter; | ||||
|  | ||||
| interface TypeFilter | ||||
| { | ||||
|     /** | ||||
|      * Applies the filter to the object. | ||||
|      * | ||||
|      * @param mixed $element | ||||
|      */ | ||||
|     public function apply($element); | ||||
| } | ||||
| @@ -1,29 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy\TypeMatcher; | ||||
|  | ||||
| class TypeMatcher | ||||
| { | ||||
|     /** | ||||
|      * @var string | ||||
|      */ | ||||
|     private $type; | ||||
|  | ||||
|     /** | ||||
|      * @param string $type | ||||
|      */ | ||||
|     public function __construct($type) | ||||
|     { | ||||
|         $this->type = $type; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param mixed $element | ||||
|      * | ||||
|      * @return boolean | ||||
|      */ | ||||
|     public function matches($element) | ||||
|     { | ||||
|         return is_object($element) ? is_a($element, $this->type) : gettype($element) === $this->type; | ||||
|     } | ||||
| } | ||||
| @@ -1,20 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| namespace DeepCopy; | ||||
|  | ||||
| use function function_exists; | ||||
|  | ||||
| if (false === function_exists('DeepCopy\deep_copy')) { | ||||
|     /** | ||||
|      * Deep copies the given value. | ||||
|      * | ||||
|      * @param mixed $value | ||||
|      * @param bool  $useCloneMethod | ||||
|      * | ||||
|      * @return mixed | ||||
|      */ | ||||
|     function deep_copy($value, $useCloneMethod = false) | ||||
|     { | ||||
|         return (new DeepCopy($useCloneMethod))->copy($value); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										29
									
								
								vendor/nikic/php-parser/LICENSE
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								vendor/nikic/php-parser/LICENSE
									
									
									
									
										vendored
									
									
								
							| @@ -1,29 +0,0 @@ | ||||
| BSD 3-Clause License | ||||
|  | ||||
| Copyright (c) 2011, Nikita Popov | ||||
| All rights reserved. | ||||
|  | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are met: | ||||
|  | ||||
| 1. Redistributions of source code must retain the above copyright notice, this | ||||
|    list of conditions and the following disclaimer. | ||||
|  | ||||
| 2. 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. | ||||
|  | ||||
| 3. Neither the name of the copyright holder 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 HOLDER 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. | ||||
							
								
								
									
										233
									
								
								vendor/nikic/php-parser/README.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										233
									
								
								vendor/nikic/php-parser/README.md
									
									
									
									
										vendored
									
									
								
							| @@ -1,233 +0,0 @@ | ||||
| PHP Parser | ||||
| ========== | ||||
|  | ||||
| [](https://coveralls.io/github/nikic/PHP-Parser?branch=master) | ||||
|  | ||||
| This is a PHP parser written in PHP. Its purpose is to simplify static code analysis and | ||||
| manipulation. | ||||
|  | ||||
| [**Documentation for version 5.x**][doc_master] (current; for running on PHP >= 7.4; for parsing PHP 7.0 to PHP 8.4, with limited support for parsing PHP 5.x). | ||||
|  | ||||
| [Documentation for version 4.x][doc_4_x] (supported; for running on PHP >= 7.0; for parsing PHP 5.2 to PHP 8.3). | ||||
|  | ||||
| Features | ||||
| -------- | ||||
|  | ||||
| The main features provided by this library are: | ||||
|  | ||||
|  * Parsing 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. | ||||
|    * 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 | ||||
| <?php | ||||
| use PhpParser\Error; | ||||
| use PhpParser\NodeDumper; | ||||
| use PhpParser\ParserFactory; | ||||
|  | ||||
| $code = <<<'CODE' | ||||
| <?php | ||||
|  | ||||
| function test($foo) | ||||
| { | ||||
|     var_dump($foo); | ||||
| } | ||||
| CODE; | ||||
|  | ||||
| $parser = (new ParserFactory())->createForNewestSupportedVersion(); | ||||
| 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( | ||||
|         attrGroups: array( | ||||
|         ) | ||||
|         byRef: false | ||||
|         name: Identifier( | ||||
|             name: test | ||||
|         ) | ||||
|         params: array( | ||||
|             0: Param( | ||||
|                 attrGroups: array( | ||||
|                 ) | ||||
|                 flags: 0 | ||||
|                 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( | ||||
|                         name: var_dump | ||||
|                     ) | ||||
|                     args: array( | ||||
|                         0: Arg( | ||||
|                             name: null | ||||
|                             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( | ||||
|         attrGroups: array( | ||||
|         ) | ||||
|         byRef: false | ||||
|         name: Identifier( | ||||
|             name: test | ||||
|         ) | ||||
|         params: array( | ||||
|             0: Param( | ||||
|                 attrGroups: array( | ||||
|                 ) | ||||
|                 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 | ||||
| <?php | ||||
|  | ||||
| function test($foo) | ||||
| { | ||||
| } | ||||
| ``` | ||||
|  | ||||
| For a more comprehensive introduction, see the documentation. | ||||
|  | ||||
| Documentation | ||||
| ------------- | ||||
|  | ||||
|  1. [Introduction](doc/0_Introduction.markdown) | ||||
|  2. [Usage of basic components](doc/2_Usage_of_basic_components.markdown) | ||||
|  | ||||
| Component documentation: | ||||
|  | ||||
|  * [Walking the AST](doc/component/Walking_the_AST.markdown) | ||||
|    * Node visitors | ||||
|    * Modifying the AST from a visitor | ||||
|    * Short-circuiting traversals | ||||
|    * Interleaved visitors | ||||
|    * Simple node finding API | ||||
|    * Parent and sibling references | ||||
|  * [Name resolution](doc/component/Name_resolution.markdown) | ||||
|    * Name resolver options | ||||
|    * Name resolution context | ||||
|  * [Pretty printing](doc/component/Pretty_printing.markdown) | ||||
|    * Converting AST back to PHP code | ||||
|    * Customizing formatting | ||||
|    * Formatting-preserving code transformations | ||||
|  * [AST builders](doc/component/AST_builders.markdown) | ||||
|    * Fluent builders for AST nodes | ||||
|  * [Lexer](doc/component/Lexer.markdown) | ||||
|    * Emulation | ||||
|    * Tokens, positions and attributes | ||||
|  * [Error handling](doc/component/Error_handling.markdown) | ||||
|    * Column information for errors | ||||
|    * Error recovery (parsing of syntactically incorrect code) | ||||
|  * [Constant expression evaluation](doc/component/Constant_expression_evaluation.markdown) | ||||
|    * Evaluating constant/property/etc initializers | ||||
|    * Handling errors and unsupported expressions | ||||
|  * [JSON representation](doc/component/JSON_representation.markdown) | ||||
|    * JSON encoding and decoding of ASTs | ||||
|  * [Performance](doc/component/Performance.markdown) | ||||
|    * Disabling Xdebug | ||||
|    * Reusing objects | ||||
|    * Garbage collection impact | ||||
|  * [Frequently asked questions](doc/component/FAQ.markdown) | ||||
|    * Parent and sibling references | ||||
|  | ||||
|  [doc_3_x]: https://github.com/nikic/PHP-Parser/tree/3.x/doc | ||||
|  [doc_4_x]: https://github.com/nikic/PHP-Parser/tree/4.x/doc | ||||
|  [doc_master]: https://github.com/nikic/PHP-Parser/tree/master/doc | ||||
							
								
								
									
										206
									
								
								vendor/nikic/php-parser/bin/php-parse
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										206
									
								
								vendor/nikic/php-parser/bin/php-parse
									
									
									
									
										vendored
									
									
								
							| @@ -1,206 +0,0 @@ | ||||
| #!/usr/bin/env php | ||||
| <?php | ||||
|  | ||||
| foreach ([__DIR__ . '/../../../autoload.php', __DIR__ . '/../vendor/autoload.php'] as $file) { | ||||
|     if (file_exists($file)) { | ||||
|         require $file; | ||||
|         break; | ||||
|     } | ||||
| } | ||||
|  | ||||
| ini_set('xdebug.max_nesting_level', 3000); | ||||
|  | ||||
| // Disable Xdebug var_dump() output truncation | ||||
| ini_set('xdebug.var_display_max_children', -1); | ||||
| ini_set('xdebug.var_display_max_data', -1); | ||||
| ini_set('xdebug.var_display_max_depth', -1); | ||||
|  | ||||
| list($operations, $files, $attributes) = parseArgs($argv); | ||||
|  | ||||
| /* Dump nodes by default */ | ||||
| if (empty($operations)) { | ||||
|     $operations[] = 'dump'; | ||||
| } | ||||
|  | ||||
| if (empty($files)) { | ||||
|     showHelp("Must specify at least one file."); | ||||
| } | ||||
|  | ||||
| $parser = (new PhpParser\ParserFactory())->createForVersion($attributes['version']); | ||||
| $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 ($file === '-') { | ||||
|         $code = file_get_contents('php://stdin'); | ||||
|         fwrite(STDERR, "====> Stdin:\n"); | ||||
|     } else if (strpos($file, '<?php') === 0) { | ||||
|         $code = $file; | ||||
|         fwrite(STDERR, "====> 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, <<<'OUTPUT' | ||||
| Usage: php-parse [operations] file1.php [file2.php ...] | ||||
|    or: php-parse [operations] "<?php code" | ||||
| Turn PHP source code into an abstract syntax tree. | ||||
|  | ||||
| Operations is a list of the following options (--dump by default): | ||||
|  | ||||
|     -d, --dump              Dump nodes using NodeDumper | ||||
|     -p, --pretty-print      Pretty print file using PrettyPrinter\Standard | ||||
|     -j, --json-dump         Print json_encode() result | ||||
|         --var-dump          var_dump() nodes (for exact structure) | ||||
|     -N, --resolve-names     Resolve names using NodeVisitor\NameResolver | ||||
|     -c, --with-column-info  Show column-numbers for errors (if available) | ||||
|     -P, --with-positions    Show positions in node dumps | ||||
|     -r, --with-recovery     Use parsing with error recovery | ||||
|         --version=VERSION   Target specific PHP version (default: newest) | ||||
|     -h, --help              Display this page | ||||
|  | ||||
| Example: | ||||
|     php-parse -d -p -N -d file.php | ||||
|  | ||||
|     Dumps nodes, pretty prints them, then resolves names and dumps them again. | ||||
|  | ||||
|  | ||||
| OUTPUT | ||||
|     ); | ||||
|     exit($error ? 1 : 0); | ||||
| } | ||||
|  | ||||
| function parseArgs($args) { | ||||
|     $operations = []; | ||||
|     $files = []; | ||||
|     $attributes = [ | ||||
|         'with-column-info' => false, | ||||
|         'with-positions' => false, | ||||
|         'with-recovery' => false, | ||||
|         'version' => PhpParser\PhpVersion::getNewestSupported(), | ||||
|     ]; | ||||
|  | ||||
|     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 (preg_match('/^--version=(.*)$/', $arg, $matches)) { | ||||
|                     $attributes['version'] = PhpParser\PhpVersion::fromString($matches[1]); | ||||
|                 } elseif ($arg[0] === '-' && \strlen($arg[0]) > 1) { | ||||
|                     showHelp("Invalid operation $arg."); | ||||
|                 } else { | ||||
|                     $files[] = $arg; | ||||
|                 } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return [$operations, $files, $attributes]; | ||||
| } | ||||
							
								
								
									
										43
									
								
								vendor/nikic/php-parser/composer.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										43
									
								
								vendor/nikic/php-parser/composer.json
									
									
									
									
										vendored
									
									
								
							| @@ -1,43 +0,0 @@ | ||||
| { | ||||
|     "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.4", | ||||
|         "ext-tokenizer": "*", | ||||
|         "ext-json": "*", | ||||
|         "ext-ctype": "*" | ||||
|     }, | ||||
|     "require-dev": { | ||||
|         "phpunit/phpunit": "^9.0", | ||||
|         "ircmaxell/php-yacc": "^0.0.7" | ||||
|     }, | ||||
|     "extra": { | ||||
|         "branch-alias": { | ||||
|             "dev-master": "5.0-dev" | ||||
|         } | ||||
|     }, | ||||
|     "autoload": { | ||||
|         "psr-4": { | ||||
|             "PhpParser\\": "lib/PhpParser" | ||||
|         } | ||||
|     }, | ||||
|     "autoload-dev": { | ||||
|         "psr-4": { | ||||
|             "PhpParser\\": "test/PhpParser/" | ||||
|         } | ||||
|     }, | ||||
|     "bin": [ | ||||
|         "bin/php-parse" | ||||
|     ] | ||||
| } | ||||
| @@ -1,12 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser; | ||||
|  | ||||
| interface Builder { | ||||
|     /** | ||||
|      * Returns the built node. | ||||
|      * | ||||
|      * @return Node The built node | ||||
|      */ | ||||
|     public function getNode(): Node; | ||||
| } | ||||
| @@ -1,150 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Builder; | ||||
|  | ||||
| use PhpParser; | ||||
| use PhpParser\BuilderHelpers; | ||||
| use PhpParser\Modifiers; | ||||
| use PhpParser\Node; | ||||
| use PhpParser\Node\Const_; | ||||
| use PhpParser\Node\Identifier; | ||||
| use PhpParser\Node\Stmt; | ||||
|  | ||||
| class ClassConst implements PhpParser\Builder { | ||||
|     protected int $flags = 0; | ||||
|     /** @var array<string, mixed> */ | ||||
|     protected array $attributes = []; | ||||
|     /** @var list<Const_> */ | ||||
|     protected array $constants = []; | ||||
|  | ||||
|     /** @var list<Node\AttributeGroup> */ | ||||
|     protected array $attributeGroups = []; | ||||
|     /** @var Identifier|Node\Name|Node\ComplexType|null */ | ||||
|     protected ?Node $type = null; | ||||
|  | ||||
|     /** | ||||
|      * Creates a class constant builder | ||||
|      * | ||||
|      * @param string|Identifier $name Name | ||||
|      * @param Node\Expr|bool|null|int|float|string|array|\UnitEnum $value Value | ||||
|      */ | ||||
|     public function __construct($name, $value) { | ||||
|         $this->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|\UnitEnum $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, Modifiers::PUBLIC); | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Makes the constant protected. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function makeProtected() { | ||||
|         $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED); | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Makes the constant private. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function makePrivate() { | ||||
|         $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE); | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Makes the constant final. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function makeFinal() { | ||||
|         $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::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 | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| @@ -1,151 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Builder; | ||||
|  | ||||
| use PhpParser; | ||||
| use PhpParser\BuilderHelpers; | ||||
| use PhpParser\Modifiers; | ||||
| use PhpParser\Node; | ||||
| use PhpParser\Node\Name; | ||||
| use PhpParser\Node\Stmt; | ||||
|  | ||||
| class Class_ extends Declaration { | ||||
|     protected string $name; | ||||
|     protected ?Name $extends = null; | ||||
|     /** @var list<Name> */ | ||||
|     protected array $implements = []; | ||||
|     protected int $flags = 0; | ||||
|     /** @var list<Stmt\TraitUse> */ | ||||
|     protected array $uses = []; | ||||
|     /** @var list<Stmt\ClassConst> */ | ||||
|     protected array $constants = []; | ||||
|     /** @var list<Stmt\Property> */ | ||||
|     protected array $properties = []; | ||||
|     /** @var list<Stmt\ClassMethod> */ | ||||
|     protected array $methods = []; | ||||
|     /** @var list<Node\AttributeGroup> */ | ||||
|     protected array $attributeGroups = []; | ||||
|  | ||||
|     /** | ||||
|      * Creates a class builder. | ||||
|      * | ||||
|      * @param string $name Name of the class | ||||
|      */ | ||||
|     public function __construct(string $name) { | ||||
|         $this->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, Modifiers::ABSTRACT); | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Makes the class final. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function makeFinal() { | ||||
|         $this->flags = BuilderHelpers::addClassModifier($this->flags, Modifiers::FINAL); | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Makes the class readonly. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function makeReadonly() { | ||||
|         $this->flags = BuilderHelpers::addClassModifier($this->flags, Modifiers::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); | ||||
|  | ||||
|         if ($stmt instanceof Stmt\Property) { | ||||
|             $this->properties[] = $stmt; | ||||
|         } elseif ($stmt instanceof Stmt\ClassMethod) { | ||||
|             $this->methods[] = $stmt; | ||||
|         } elseif ($stmt instanceof Stmt\TraitUse) { | ||||
|             $this->uses[] = $stmt; | ||||
|         } elseif ($stmt instanceof Stmt\ClassConst) { | ||||
|             $this->constants[] = $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 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); | ||||
|     } | ||||
| } | ||||
| @@ -1,50 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Builder; | ||||
|  | ||||
| use PhpParser; | ||||
| use PhpParser\BuilderHelpers; | ||||
|  | ||||
| abstract class Declaration implements PhpParser\Builder { | ||||
|     /** @var array<string, mixed> */ | ||||
|     protected array $attributes = []; | ||||
|  | ||||
|     /** | ||||
|      * Adds a statement. | ||||
|      * | ||||
|      * @param PhpParser\Node\Stmt|PhpParser\Builder $stmt The statement to add | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     abstract public function addStmt($stmt); | ||||
|  | ||||
|     /** | ||||
|      * Adds multiple statements. | ||||
|      * | ||||
|      * @param (PhpParser\Node\Stmt|PhpParser\Builder)[] $stmts The statements to add | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function addStmts(array $stmts) { | ||||
|         foreach ($stmts as $stmt) { | ||||
|             $this->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; | ||||
|     } | ||||
| } | ||||
| @@ -1,86 +0,0 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Builder; | ||||
|  | ||||
| use PhpParser; | ||||
| use PhpParser\BuilderHelpers; | ||||
| use PhpParser\Node; | ||||
| use PhpParser\Node\Identifier; | ||||
| use PhpParser\Node\Stmt; | ||||
|  | ||||
| class EnumCase implements PhpParser\Builder { | ||||
|     /** @var Identifier|string */ | ||||
|     protected $name; | ||||
|     protected ?Node\Expr $value = null; | ||||
|     /** @var array<string, mixed> */ | ||||
|     protected array $attributes = []; | ||||
|  | ||||
|     /** @var list<Node\AttributeGroup> */ | ||||
|     protected array $attributeGroups = []; | ||||
|  | ||||
|     /** | ||||
|      * Creates an enum case builder. | ||||
|      * | ||||
|      * @param string|Identifier $name Name | ||||
|      */ | ||||
|     public function __construct($name) { | ||||
|         $this->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 | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| @@ -1,116 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Builder; | ||||
|  | ||||
| use PhpParser; | ||||
| use PhpParser\BuilderHelpers; | ||||
| use PhpParser\Node; | ||||
| use PhpParser\Node\Identifier; | ||||
| use PhpParser\Node\Name; | ||||
| use PhpParser\Node\Stmt; | ||||
|  | ||||
| class Enum_ extends Declaration { | ||||
|     protected string $name; | ||||
|     protected ?Identifier $scalarType = null; | ||||
|     /** @var list<Name> */ | ||||
|     protected array $implements = []; | ||||
|     /** @var list<Stmt\TraitUse> */ | ||||
|     protected array $uses = []; | ||||
|     /** @var list<Stmt\EnumCase> */ | ||||
|     protected array $enumCases = []; | ||||
|     /** @var list<Stmt\ClassConst> */ | ||||
|     protected array $constants = []; | ||||
|     /** @var list<Stmt\ClassMethod> */ | ||||
|     protected array $methods = []; | ||||
|     /** @var list<Node\AttributeGroup> */ | ||||
|     protected array $attributeGroups = []; | ||||
|  | ||||
|     /** | ||||
|      * Creates an enum builder. | ||||
|      * | ||||
|      * @param string $name Name of the enum | ||||
|      */ | ||||
|     public function __construct(string $name) { | ||||
|         $this->name = $name; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sets the scalar type. | ||||
|      * | ||||
|      * @param string|Identifier $scalarType | ||||
|      * | ||||
|      * @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); | ||||
|  | ||||
|         if ($stmt instanceof Stmt\EnumCase) { | ||||
|             $this->enumCases[] = $stmt; | ||||
|         } elseif ($stmt instanceof Stmt\ClassMethod) { | ||||
|             $this->methods[] = $stmt; | ||||
|         } elseif ($stmt instanceof Stmt\TraitUse) { | ||||
|             $this->uses[] = $stmt; | ||||
|         } elseif ($stmt instanceof Stmt\ClassConst) { | ||||
|             $this->constants[] = $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 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); | ||||
|     } | ||||
| } | ||||
| @@ -1,73 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Builder; | ||||
|  | ||||
| use PhpParser\BuilderHelpers; | ||||
| use PhpParser\Node; | ||||
|  | ||||
| abstract class FunctionLike extends Declaration { | ||||
|     protected bool $returnByRef = false; | ||||
|     /** @var Node\Param[] */ | ||||
|     protected array $params = []; | ||||
|  | ||||
|     /** @var Node\Identifier|Node\Name|Node\ComplexType|null */ | ||||
|     protected ?Node $returnType = null; | ||||
|  | ||||
|     /** | ||||
|      * Make the function return by reference. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function makeReturnByRef() { | ||||
|         $this->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 (Node\Param|Param)[] $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; | ||||
|     } | ||||
| } | ||||
| @@ -1,67 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Builder; | ||||
|  | ||||
| use PhpParser; | ||||
| use PhpParser\BuilderHelpers; | ||||
| use PhpParser\Node; | ||||
| use PhpParser\Node\Stmt; | ||||
|  | ||||
| class Function_ extends FunctionLike { | ||||
|     protected string $name; | ||||
|     /** @var list<Stmt> */ | ||||
|     protected array $stmts = []; | ||||
|  | ||||
|     /** @var list<Node\AttributeGroup> */ | ||||
|     protected array $attributeGroups = []; | ||||
|  | ||||
|     /** | ||||
|      * Creates a function builder. | ||||
|      * | ||||
|      * @param string $name Name of the function | ||||
|      */ | ||||
|     public function __construct(string $name) { | ||||
|         $this->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); | ||||
|     } | ||||
| } | ||||
| @@ -1,94 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Builder; | ||||
|  | ||||
| use PhpParser; | ||||
| use PhpParser\BuilderHelpers; | ||||
| use PhpParser\Node; | ||||
| use PhpParser\Node\Name; | ||||
| use PhpParser\Node\Stmt; | ||||
|  | ||||
| class Interface_ extends Declaration { | ||||
|     protected string $name; | ||||
|     /** @var list<Name> */ | ||||
|     protected array $extends = []; | ||||
|     /** @var list<Stmt\ClassConst> */ | ||||
|     protected array $constants = []; | ||||
|     /** @var list<Stmt\ClassMethod> */ | ||||
|     protected array $methods = []; | ||||
|     /** @var list<Node\AttributeGroup> */ | ||||
|     protected array $attributeGroups = []; | ||||
|  | ||||
|     /** | ||||
|      * Creates an interface builder. | ||||
|      * | ||||
|      * @param string $name Name of the interface | ||||
|      */ | ||||
|     public function __construct(string $name) { | ||||
|         $this->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); | ||||
|     } | ||||
| } | ||||
| @@ -1,147 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Builder; | ||||
|  | ||||
| use PhpParser; | ||||
| use PhpParser\BuilderHelpers; | ||||
| use PhpParser\Modifiers; | ||||
| use PhpParser\Node; | ||||
| use PhpParser\Node\Stmt; | ||||
|  | ||||
| class Method extends FunctionLike { | ||||
|     protected string $name; | ||||
|  | ||||
|     protected int $flags = 0; | ||||
|  | ||||
|     /** @var list<Stmt>|null */ | ||||
|     protected ?array $stmts = []; | ||||
|  | ||||
|     /** @var list<Node\AttributeGroup> */ | ||||
|     protected array $attributeGroups = []; | ||||
|  | ||||
|     /** | ||||
|      * Creates a method builder. | ||||
|      * | ||||
|      * @param string $name Name of the method | ||||
|      */ | ||||
|     public function __construct(string $name) { | ||||
|         $this->name = $name; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Makes the method public. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function makePublic() { | ||||
|         $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PUBLIC); | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Makes the method protected. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function makeProtected() { | ||||
|         $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED); | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Makes the method private. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function makePrivate() { | ||||
|         $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE); | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Makes the method static. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function makeStatic() { | ||||
|         $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::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, Modifiers::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, Modifiers::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); | ||||
|     } | ||||
| } | ||||
| @@ -1,45 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Builder; | ||||
|  | ||||
| use PhpParser; | ||||
| use PhpParser\BuilderHelpers; | ||||
| use PhpParser\Node; | ||||
| use PhpParser\Node\Stmt; | ||||
|  | ||||
| class Namespace_ extends Declaration { | ||||
|     private ?Node\Name $name; | ||||
|     /** @var Stmt[] */ | ||||
|     private array $stmts = []; | ||||
|  | ||||
|     /** | ||||
|      * Creates a namespace builder. | ||||
|      * | ||||
|      * @param Node\Name|string|null $name Name of the namespace | ||||
|      */ | ||||
|     public function __construct($name) { | ||||
|         $this->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); | ||||
|     } | ||||
| } | ||||
| @@ -1,171 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Builder; | ||||
|  | ||||
| use PhpParser; | ||||
| use PhpParser\BuilderHelpers; | ||||
| use PhpParser\Modifiers; | ||||
| use PhpParser\Node; | ||||
|  | ||||
| class Param implements PhpParser\Builder { | ||||
|     protected string $name; | ||||
|     protected ?Node\Expr $default = null; | ||||
|     /** @var Node\Identifier|Node\Name|Node\ComplexType|null */ | ||||
|     protected ?Node $type = null; | ||||
|     protected bool $byRef = false; | ||||
|     protected int $flags = 0; | ||||
|     protected bool $variadic = false; | ||||
|     /** @var list<Node\AttributeGroup> */ | ||||
|     protected array $attributeGroups = []; | ||||
|  | ||||
|     /** | ||||
|      * Creates a parameter builder. | ||||
|      * | ||||
|      * @param string $name Name of the parameter | ||||
|      */ | ||||
|     public function __construct(string $name) { | ||||
|         $this->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; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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, Modifiers::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, Modifiers::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, Modifiers::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, Modifiers::READONLY); | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gives the promoted property private(set) visibility. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function makePrivateSet() { | ||||
|         $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE_SET); | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gives the promoted property protected(set) visibility. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function makeProtectedSet() { | ||||
|         $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED_SET); | ||||
|  | ||||
|         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 | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| @@ -1,223 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Builder; | ||||
|  | ||||
| use PhpParser; | ||||
| use PhpParser\BuilderHelpers; | ||||
| use PhpParser\Modifiers; | ||||
| use PhpParser\Node; | ||||
| use PhpParser\Node\Identifier; | ||||
| use PhpParser\Node\Name; | ||||
| use PhpParser\Node\Stmt; | ||||
| use PhpParser\Node\ComplexType; | ||||
|  | ||||
| class Property implements PhpParser\Builder { | ||||
|     protected string $name; | ||||
|  | ||||
|     protected int $flags = 0; | ||||
|  | ||||
|     protected ?Node\Expr $default = null; | ||||
|     /** @var array<string, mixed> */ | ||||
|     protected array $attributes = []; | ||||
|     /** @var null|Identifier|Name|ComplexType */ | ||||
|     protected ?Node $type = null; | ||||
|     /** @var list<Node\AttributeGroup> */ | ||||
|     protected array $attributeGroups = []; | ||||
|     /** @var list<Node\PropertyHook> */ | ||||
|     protected array $hooks = []; | ||||
|  | ||||
|     /** | ||||
|      * Creates a property builder. | ||||
|      * | ||||
|      * @param string $name Name of the property | ||||
|      */ | ||||
|     public function __construct(string $name) { | ||||
|         $this->name = $name; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Makes the property public. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function makePublic() { | ||||
|         $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PUBLIC); | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Makes the property protected. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function makeProtected() { | ||||
|         $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED); | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Makes the property private. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function makePrivate() { | ||||
|         $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE); | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Makes the property static. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function makeStatic() { | ||||
|         $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::STATIC); | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Makes the property readonly. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function makeReadonly() { | ||||
|         $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::READONLY); | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Makes the property abstract. Requires at least one property hook to be specified as well. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function makeAbstract() { | ||||
|         $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::ABSTRACT); | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Makes the property final. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function makeFinal() { | ||||
|         $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::FINAL); | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gives the property private(set) visibility. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function makePrivateSet() { | ||||
|         $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE_SET); | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gives the property protected(set) visibility. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function makeProtectedSet() { | ||||
|         $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED_SET); | ||||
|  | ||||
|         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; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Adds a property hook. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function addHook(Node\PropertyHook $hook) { | ||||
|         $this->hooks[] = $hook; | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the built class node. | ||||
|      * | ||||
|      * @return Stmt\Property The built property node | ||||
|      */ | ||||
|     public function getNode(): PhpParser\Node { | ||||
|         if ($this->flags & Modifiers::ABSTRACT && !$this->hooks) { | ||||
|             throw new PhpParser\Error('Only hooked properties may be declared abstract'); | ||||
|         } | ||||
|  | ||||
|         return new Stmt\Property( | ||||
|             $this->flags !== 0 ? $this->flags : Modifiers::PUBLIC, | ||||
|             [ | ||||
|                 new Node\PropertyItem($this->name, $this->default) | ||||
|             ], | ||||
|             $this->attributes, | ||||
|             $this->type, | ||||
|             $this->attributeGroups, | ||||
|             $this->hooks | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| @@ -1,65 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Builder; | ||||
|  | ||||
| use PhpParser\Builder; | ||||
| use PhpParser\BuilderHelpers; | ||||
| use PhpParser\Node; | ||||
| use PhpParser\Node\Stmt; | ||||
|  | ||||
| class TraitUse implements Builder { | ||||
|     /** @var Node\Name[] */ | ||||
|     protected array $traits = []; | ||||
|     /** @var Stmt\TraitUseAdaptation[] */ | ||||
|     protected array $adaptations = []; | ||||
|  | ||||
|     /** | ||||
|      * Creates a trait use builder. | ||||
|      * | ||||
|      * @param Node\Name|string ...$traits Names of used traits | ||||
|      */ | ||||
|     public function __construct(...$traits) { | ||||
|         foreach ($traits as $trait) { | ||||
|             $this->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); | ||||
|     } | ||||
| } | ||||
| @@ -1,145 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Builder; | ||||
|  | ||||
| use PhpParser\Builder; | ||||
| use PhpParser\BuilderHelpers; | ||||
| use PhpParser\Modifiers; | ||||
| use PhpParser\Node; | ||||
| use PhpParser\Node\Stmt; | ||||
|  | ||||
| class TraitUseAdaptation implements Builder { | ||||
|     private const TYPE_UNDEFINED  = 0; | ||||
|     private const TYPE_ALIAS      = 1; | ||||
|     private const TYPE_PRECEDENCE = 2; | ||||
|  | ||||
|     protected int $type; | ||||
|     protected ?Node\Name $trait; | ||||
|     protected Node\Identifier $method; | ||||
|     protected ?int $modifier = null; | ||||
|     protected ?Node\Identifier $alias = null; | ||||
|     /** @var Node\Name[] */ | ||||
|     protected array $insteadof = []; | ||||
|  | ||||
|     /** | ||||
|      * Creates a trait use adaptation builder. | ||||
|      * | ||||
|      * @param Node\Name|string|null $trait Name of adapted trait | ||||
|      * @param Node\Identifier|string $method Name of adapted method | ||||
|      */ | ||||
|     public function __construct($trait, $method) { | ||||
|         $this->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 adapted 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 = BuilderHelpers::normalizeIdentifier($alias); | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sets adapted method public. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function makePublic() { | ||||
|         $this->setModifier(Modifiers::PUBLIC); | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sets adapted method protected. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function makeProtected() { | ||||
|         $this->setModifier(Modifiers::PROTECTED); | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sets adapted method private. | ||||
|      * | ||||
|      * @return $this The builder instance (for fluid interface) | ||||
|      */ | ||||
|     public function makePrivate() { | ||||
|         $this->setModifier(Modifiers::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): void { | ||||
|         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'); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,83 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Builder; | ||||
|  | ||||
| use PhpParser; | ||||
| use PhpParser\BuilderHelpers; | ||||
| use PhpParser\Node; | ||||
| use PhpParser\Node\Stmt; | ||||
|  | ||||
| class Trait_ extends Declaration { | ||||
|     protected string $name; | ||||
|     /** @var list<Stmt\TraitUse> */ | ||||
|     protected array $uses = []; | ||||
|     /** @var list<Stmt\ClassConst> */ | ||||
|     protected array $constants = []; | ||||
|     /** @var list<Stmt\Property> */ | ||||
|     protected array $properties = []; | ||||
|     /** @var list<Stmt\ClassMethod> */ | ||||
|     protected array $methods = []; | ||||
|     /** @var list<Node\AttributeGroup> */ | ||||
|     protected array $attributeGroups = []; | ||||
|  | ||||
|     /** | ||||
|      * Creates an interface builder. | ||||
|      * | ||||
|      * @param string $name Name of the interface | ||||
|      */ | ||||
|     public function __construct(string $name) { | ||||
|         $this->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; | ||||
|         } elseif ($stmt instanceof Stmt\ClassConst) { | ||||
|             $this->constants[] = $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->constants, $this->properties, $this->methods), | ||||
|                 'attrGroups' => $this->attributeGroups, | ||||
|             ], $this->attributes | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| @@ -1,49 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Builder; | ||||
|  | ||||
| use PhpParser\Builder; | ||||
| use PhpParser\BuilderHelpers; | ||||
| use PhpParser\Node; | ||||
| use PhpParser\Node\Stmt; | ||||
|  | ||||
| class Use_ implements Builder { | ||||
|     protected Node\Name $name; | ||||
|     /** @var Stmt\Use_::TYPE_* */ | ||||
|     protected int $type; | ||||
|     protected ?string $alias = null; | ||||
|  | ||||
|     /** | ||||
|      * Creates a name use (alias) builder. | ||||
|      * | ||||
|      * @param Node\Name|string $name Name of the entity (namespace, class, function, constant) to alias | ||||
|      * @param Stmt\Use_::TYPE_* $type One of the Stmt\Use_::TYPE_* constants | ||||
|      */ | ||||
|     public function __construct($name, int $type) { | ||||
|         $this->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 Node\UseItem($this->name, $this->alias) | ||||
|         ], $this->type); | ||||
|     } | ||||
| } | ||||
| @@ -1,375 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser; | ||||
|  | ||||
| use PhpParser\Node\Arg; | ||||
| use PhpParser\Node\Expr; | ||||
| use PhpParser\Node\Expr\BinaryOp\Concat; | ||||
| use PhpParser\Node\Identifier; | ||||
| use PhpParser\Node\Name; | ||||
| use PhpParser\Node\Scalar\String_; | ||||
| use PhpParser\Node\Stmt\Use_; | ||||
|  | ||||
| class BuilderFactory { | ||||
|     /** | ||||
|      * Creates an attribute node. | ||||
|      * | ||||
|      * @param string|Name $name Name of the attribute | ||||
|      * @param array $args Attribute named arguments | ||||
|      */ | ||||
|     public function attribute($name, array $args = []): Node\Attribute { | ||||
|         return new Node\Attribute( | ||||
|             BuilderHelpers::normalizeName($name), | ||||
|             $this->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 created 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 created 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|\UnitEnum $value $value | ||||
|      */ | ||||
|     public function val($value): Expr { | ||||
|         return BuilderHelpers::normalizeValue($value); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creates variable node. | ||||
|      * | ||||
|      * @param string|Expr $name Name | ||||
|      */ | ||||
|     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 list<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 | ||||
|      */ | ||||
|     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 | ||||
|      */ | ||||
|     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 | ||||
|      */ | ||||
|     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 | ||||
|      */ | ||||
|     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 | ||||
|      */ | ||||
|     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 | ||||
|      */ | ||||
|     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 | ||||
|      */ | ||||
|     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 | ||||
|      */ | ||||
|     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 | ||||
|      */ | ||||
|     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'); | ||||
|     } | ||||
| } | ||||
| @@ -1,338 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser; | ||||
|  | ||||
| use PhpParser\Node\ComplexType; | ||||
| use PhpParser\Node\Expr; | ||||
| use PhpParser\Node\Identifier; | ||||
| use PhpParser\Node\Name; | ||||
| use PhpParser\Node\Name\FullyQualified; | ||||
| use PhpParser\Node\NullableType; | ||||
| use PhpParser\Node\Scalar; | ||||
| use PhpParser\Node\Stmt; | ||||
|  | ||||
| /** | ||||
|  * This class defines helpers used in the implementation of builders. Don't use it directly. | ||||
|  * | ||||
|  * @internal | ||||
|  */ | ||||
| final class BuilderHelpers { | ||||
|     /** | ||||
|      * Normalizes a node: Converts builder objects to nodes. | ||||
|      * | ||||
|      * @param Node|Builder $node The node to normalize | ||||
|      * | ||||
|      * @return Node The normalized node | ||||
|      */ | ||||
|     public static function normalizeNode($node): Node { | ||||
|         if ($node instanceof Builder) { | ||||
|             return $node->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|\UnitEnum $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\Int_($value); | ||||
|         } | ||||
|  | ||||
|         if (is_float($value)) { | ||||
|             return new Scalar\Float_($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 Node\ArrayItem( | ||||
|                         self::normalizeValue($itemValue) | ||||
|                     ); | ||||
|                 } else { | ||||
|                     $lastKey = null; | ||||
|                     $items[] = new Node\ArrayItem( | ||||
|                         self::normalizeValue($itemValue), | ||||
|                         self::normalizeValue($itemKey) | ||||
|                     ); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             return new Expr\Array_($items); | ||||
|         } | ||||
|  | ||||
|         if ($value instanceof \UnitEnum) { | ||||
|             return new Expr\ClassConstFetch(new FullyQualified(\get_class($value)), new Identifier($value->name)); | ||||
|         } | ||||
|  | ||||
|         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 { | ||||
|         Modifiers::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 { | ||||
|         Modifiers::verifyClassModifier($existingModifiers, $modifierToSet); | ||||
|         return $existingModifiers | $modifierToSet; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										209
									
								
								vendor/nikic/php-parser/lib/PhpParser/Comment.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										209
									
								
								vendor/nikic/php-parser/lib/PhpParser/Comment.php
									
									
									
									
										vendored
									
									
								
							| @@ -1,209 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser; | ||||
|  | ||||
| class Comment implements \JsonSerializable { | ||||
|     protected string $text; | ||||
|     protected int $startLine; | ||||
|     protected int $startFilePos; | ||||
|     protected int $startTokenPos; | ||||
|     protected int $endLine; | ||||
|     protected int $endFilePos; | ||||
|     protected int $endTokenPos; | ||||
|  | ||||
|     /** | ||||
|      * Constructs a comment node. | ||||
|      * | ||||
|      * @param string $text Comment text (including comment delimiters like /*) | ||||
|      * @param int $startLine Line number the comment started on | ||||
|      * @param int $startFilePos File offset the comment started on | ||||
|      * @param int $startTokenPos Token offset the comment started on | ||||
|      */ | ||||
|     public function __construct( | ||||
|         string $text, | ||||
|         int $startLine = -1, int $startFilePos = -1, int $startTokenPos = -1, | ||||
|         int $endLine = -1, int $endFilePos = -1, int $endTokenPos = -1 | ||||
|     ) { | ||||
|         $this->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) | ||||
|      * @phpstan-return -1|positive-int | ||||
|      */ | ||||
|     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) | ||||
|      * @phpstan-return -1|positive-int | ||||
|      */ | ||||
|     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 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 leading whitespace on the first line, but with leading whitespace | ||||
|      * on all subsequent lines. | ||||
|      * | ||||
|      * Additionally, this normalizes CRLF newlines to LF newlines. | ||||
|      */ | ||||
|     public function getReformattedText(): string { | ||||
|         $text = str_replace("\r\n", "\n", $this->text); | ||||
|         $newlinePos = strpos($text, "\n"); | ||||
|         if (false === $newlinePos) { | ||||
|             // Single line comments don't need further processing | ||||
|             return $text; | ||||
|         } | ||||
|         if (preg_match('(^.*(?:\n\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', ' *', $text); | ||||
|         } | ||||
|         if (preg_match('(^/\*\*?\s*\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); | ||||
|         } | ||||
|         if (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 = \PHP_INT_MAX; | ||||
|         foreach ($lines as $line) { | ||||
|             preg_match('(^\s*)', $line, $matches); | ||||
|             $prefixLen = strlen($matches[0]); | ||||
|             if ($prefixLen < $shortestPrefixLen) { | ||||
|                 $shortestPrefixLen = $prefixLen; | ||||
|             } | ||||
|         } | ||||
|         return $shortestPrefixLen; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @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, | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
| @@ -1,6 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Comment; | ||||
|  | ||||
| class Doc extends \PhpParser\Comment { | ||||
| } | ||||
| @@ -1,6 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser; | ||||
|  | ||||
| class ConstExprEvaluationException extends \Exception { | ||||
| } | ||||
| @@ -1,234 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser; | ||||
|  | ||||
| use PhpParser\Node\Expr; | ||||
| use PhpParser\Node\Scalar; | ||||
|  | ||||
| use function array_merge; | ||||
|  | ||||
| /** | ||||
|  * Evaluates constant expressions. | ||||
|  * | ||||
|  * This evaluator is able to evaluate all constant expressions (as defined by PHP), which can be | ||||
|  * evaluated without further context. If a subexpression is not of this type, a user-provided | ||||
|  * fallback evaluator is invoked. To support all constant expressions that are also supported by | ||||
|  * PHP (and not already handled by this class), the fallback evaluator must be able to handle the | ||||
|  * following node types: | ||||
|  * | ||||
|  *  * All Scalar\MagicConst\* nodes. | ||||
|  *  * Expr\ConstFetch nodes. Only null/false/true are already handled by this class. | ||||
|  *  * Expr\ClassConstFetch nodes. | ||||
|  * | ||||
|  * The fallback evaluator should throw ConstExprEvaluationException for nodes it cannot evaluate. | ||||
|  * | ||||
|  * The evaluation is dependent on runtime configuration in two respects: Firstly, floating | ||||
|  * point to string conversions are affected by the precision ini setting. Secondly, they are also | ||||
|  * affected by the LC_NUMERIC locale. | ||||
|  */ | ||||
| class ConstExprEvaluator { | ||||
|     /** @var callable|null */ | ||||
|     private $fallbackEvaluator; | ||||
|  | ||||
|     /** | ||||
|      * Create a constant expression evaluator. | ||||
|      * | ||||
|      * The provided fallback evaluator is invoked whenever a subexpression cannot be evaluated. See | ||||
|      * class doc comment for more information. | ||||
|      * | ||||
|      * @param callable|null $fallbackEvaluator To call if subexpression cannot be evaluated | ||||
|      */ | ||||
|     public function __construct(?callable $fallbackEvaluator = null) { | ||||
|         $this->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); | ||||
|     } | ||||
|  | ||||
|     /** @return mixed */ | ||||
|     private function evaluate(Expr $expr) { | ||||
|         if ($expr instanceof Scalar\Int_ | ||||
|             || $expr instanceof Scalar\Float_ | ||||
|             || $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 { | ||||
|         $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; | ||||
|     } | ||||
|  | ||||
|     /** @return mixed */ | ||||
|     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); | ||||
|     } | ||||
|  | ||||
|     /** @return mixed */ | ||||
|     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'); | ||||
|     } | ||||
|  | ||||
|     /** @return mixed */ | ||||
|     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); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										173
									
								
								vendor/nikic/php-parser/lib/PhpParser/Error.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										173
									
								
								vendor/nikic/php-parser/lib/PhpParser/Error.php
									
									
									
									
										vendored
									
									
								
							| @@ -1,173 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser; | ||||
|  | ||||
| class Error extends \RuntimeException { | ||||
|     protected string $rawMessage; | ||||
|     /** @var array<string, mixed> */ | ||||
|     protected array $attributes; | ||||
|  | ||||
|     /** | ||||
|      * Creates an Exception signifying a parse error. | ||||
|      * | ||||
|      * @param string $message Error message | ||||
|      * @param array<string, mixed> $attributes Attributes of node/token where error occurred | ||||
|      */ | ||||
|     public function __construct(string $message, array $attributes = []) { | ||||
|         $this->rawMessage = $message; | ||||
|         $this->attributes = $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 | ||||
|      * @phpstan-return -1|positive-int | ||||
|      */ | ||||
|     public function getStartLine(): int { | ||||
|         return $this->attributes['startLine'] ?? -1; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gets the line the error ends in. | ||||
|      * | ||||
|      * @return int Error end line | ||||
|      * @phpstan-return -1|positive-int | ||||
|      */ | ||||
|     public function getEndLine(): int { | ||||
|         return $this->attributes['endLine'] ?? -1; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Gets the attributes of the node/token the error occurred at. | ||||
|      * | ||||
|      * @return array<string, mixed> | ||||
|      */ | ||||
|     public function getAttributes(): array { | ||||
|         return $this->attributes; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sets the attributes of the node/token the error occurred at. | ||||
|      * | ||||
|      * @param array<string, mixed> $attributes | ||||
|      */ | ||||
|     public function setAttributes(array $attributes): void { | ||||
|         $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): void { | ||||
|         $this->rawMessage = $message; | ||||
|         $this->updateMessage(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sets the line the error starts in. | ||||
|      * | ||||
|      * @param int $line Error start line | ||||
|      */ | ||||
|     public function setStartLine(int $line): void { | ||||
|         $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. | ||||
|      */ | ||||
|     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 | ||||
|      */ | ||||
|     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 | ||||
|      */ | ||||
|     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(): void { | ||||
|         $this->message = $this->rawMessage; | ||||
|  | ||||
|         if (-1 === $this->getStartLine()) { | ||||
|             $this->message .= ' on unknown line'; | ||||
|         } else { | ||||
|             $this->message .= ' on line ' . $this->getStartLine(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,12 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser; | ||||
|  | ||||
| interface ErrorHandler { | ||||
|     /** | ||||
|      * Handle an error generated during lexing, parsing or some other operation. | ||||
|      * | ||||
|      * @param Error $error The error that needs to be handled | ||||
|      */ | ||||
|     public function handleError(Error $error): void; | ||||
| } | ||||
| @@ -1,43 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\ErrorHandler; | ||||
|  | ||||
| use PhpParser\Error; | ||||
| use PhpParser\ErrorHandler; | ||||
|  | ||||
| /** | ||||
|  * Error handler that collects all errors into an array. | ||||
|  * | ||||
|  * This allows graceful handling of errors. | ||||
|  */ | ||||
| class Collecting implements ErrorHandler { | ||||
|     /** @var Error[] Collected errors */ | ||||
|     private array $errors = []; | ||||
|  | ||||
|     public function handleError(Error $error): void { | ||||
|         $this->errors[] = $error; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get collected errors. | ||||
|      * | ||||
|      * @return Error[] | ||||
|      */ | ||||
|     public function getErrors(): array { | ||||
|         return $this->errors; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Check whether there are any errors. | ||||
|      */ | ||||
|     public function hasErrors(): bool { | ||||
|         return !empty($this->errors); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Reset/clear collected errors. | ||||
|      */ | ||||
|     public function clearErrors(): void { | ||||
|         $this->errors = []; | ||||
|     } | ||||
| } | ||||
| @@ -1,17 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\ErrorHandler; | ||||
|  | ||||
| use PhpParser\Error; | ||||
| use PhpParser\ErrorHandler; | ||||
|  | ||||
| /** | ||||
|  * Error handler that handles all errors by throwing them. | ||||
|  * | ||||
|  * This is the default strategy used by all components. | ||||
|  */ | ||||
| class Throwing implements ErrorHandler { | ||||
|     public function handleError(Error $error): void { | ||||
|         throw $error; | ||||
|     } | ||||
| } | ||||
| @@ -1,31 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Internal; | ||||
|  | ||||
| /** | ||||
|  * @internal | ||||
|  */ | ||||
| class DiffElem { | ||||
|     public const TYPE_KEEP = 0; | ||||
|     public const TYPE_REMOVE = 1; | ||||
|     public const TYPE_ADD = 2; | ||||
|     public const TYPE_REPLACE = 3; | ||||
|  | ||||
|     /** @var int One of the TYPE_* constants */ | ||||
|     public int $type; | ||||
|     /** @var mixed Is null for add operations */ | ||||
|     public $old; | ||||
|     /** @var mixed Is null for remove operations */ | ||||
|     public $new; | ||||
|  | ||||
|     /** | ||||
|      * @param int $type One of the TYPE_* constants | ||||
|      * @param mixed $old Is null for add operations | ||||
|      * @param mixed $new Is null for remove operations | ||||
|      */ | ||||
|     public function __construct(int $type, $old, $new) { | ||||
|         $this->type = $type; | ||||
|         $this->old = $old; | ||||
|         $this->new = $new; | ||||
|     } | ||||
| } | ||||
| @@ -1,178 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Internal; | ||||
|  | ||||
| /** | ||||
|  * Implements the Myers diff algorithm. | ||||
|  * | ||||
|  * Myers, Eugene W. "An O (ND) difference algorithm and its variations." | ||||
|  * Algorithmica 1.1 (1986): 251-266. | ||||
|  * | ||||
|  * @template T | ||||
|  * @internal | ||||
|  */ | ||||
| class Differ { | ||||
|     /** @var callable(T, T): bool */ | ||||
|     private $isEqual; | ||||
|  | ||||
|     /** | ||||
|      * Create differ over the given equality relation. | ||||
|      * | ||||
|      * @param callable(T, T): bool $isEqual Equality relation | ||||
|      */ | ||||
|     public function __construct(callable $isEqual) { | ||||
|         $this->isEqual = $isEqual; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Calculate diff (edit script) from $old to $new. | ||||
|      * | ||||
|      * @param T[] $old Original array | ||||
|      * @param T[] $new New array | ||||
|      * | ||||
|      * @return DiffElem[] Diff (edit script) | ||||
|      */ | ||||
|     public function diff(array $old, array $new): array { | ||||
|         $old = \array_values($old); | ||||
|         $new = \array_values($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 T[] $old Original array | ||||
|      * @param T[] $new New array | ||||
|      * | ||||
|      * @return DiffElem[] Diff (edit script), including replace operations | ||||
|      */ | ||||
|     public function diffWithReplacements(array $old, array $new): array { | ||||
|         return $this->coalesceReplacements($this->diff($old, $new)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param T[] $old | ||||
|      * @param T[] $new | ||||
|      * @return array{array<int, array<int, int>>, int, int} | ||||
|      */ | ||||
|     private function calculateTrace(array $old, array $new): array { | ||||
|         $n = \count($old); | ||||
|         $m = \count($new); | ||||
|         $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)($old[$x], $new[$y])) { | ||||
|                     $x++; | ||||
|                     $y++; | ||||
|                 } | ||||
|  | ||||
|                 $v[$k] = $x; | ||||
|                 if ($x >= $n && $y >= $m) { | ||||
|                     return [$trace, $x, $y]; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         throw new \Exception('Should not happen'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param array<int, array<int, int>> $trace | ||||
|      * @param T[] $old | ||||
|      * @param T[] $new | ||||
|      * @return DiffElem[] | ||||
|      */ | ||||
|     private function extractDiff(array $trace, int $x, int $y, array $old, array $new): array { | ||||
|         $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, $old[$x - 1], $new[$y - 1]); | ||||
|                 $x--; | ||||
|                 $y--; | ||||
|             } | ||||
|  | ||||
|             if ($d === 0) { | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             while ($x > $prevX) { | ||||
|                 $result[] = new DiffElem(DiffElem::TYPE_REMOVE, $old[$x - 1], null); | ||||
|                 $x--; | ||||
|             } | ||||
|  | ||||
|             while ($y > $prevY) { | ||||
|                 $result[] = new DiffElem(DiffElem::TYPE_ADD, null, $new[$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): array { | ||||
|         $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; | ||||
|     } | ||||
| } | ||||
| @@ -1,71 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Internal; | ||||
|  | ||||
| use PhpParser\Node; | ||||
| use PhpParser\Node\Expr; | ||||
|  | ||||
| /** | ||||
|  * This node is used internally by the format-preserving pretty printer to print anonymous classes. | ||||
|  * | ||||
|  * The normal anonymous class structure violates assumptions about the order of token offsets. | ||||
|  * Namely, the constructor arguments are part of the Expr\New_ node and follow the class node, even | ||||
|  * though they are actually interleaved with them. This special node type is used temporarily to | ||||
|  * restore a sane token offset order. | ||||
|  * | ||||
|  * @internal | ||||
|  */ | ||||
| class PrintableNewAnonClassNode extends Expr { | ||||
|     /** @var Node\AttributeGroup[] PHP attribute groups */ | ||||
|     public array $attrGroups; | ||||
|     /** @var int Modifiers */ | ||||
|     public int $flags; | ||||
|     /** @var (Node\Arg|Node\VariadicPlaceholder)[] Arguments */ | ||||
|     public array $args; | ||||
|     /** @var null|Node\Name Name of extended class */ | ||||
|     public ?Node\Name $extends; | ||||
|     /** @var Node\Name[] Names of implemented interfaces */ | ||||
|     public array $implements; | ||||
|     /** @var Node\Stmt[] Statements */ | ||||
|     public array $stmts; | ||||
|  | ||||
|     /** | ||||
|      * @param Node\AttributeGroup[] $attrGroups PHP attribute groups | ||||
|      * @param (Node\Arg|Node\VariadicPlaceholder)[] $args Arguments | ||||
|      * @param Node\Name|null $extends Name of extended class | ||||
|      * @param Node\Name[] $implements Names of implemented interfaces | ||||
|      * @param Node\Stmt[] $stmts Statements | ||||
|      * @param array<string, mixed> $attributes Attributes | ||||
|      */ | ||||
|     public function __construct( | ||||
|         array $attrGroups, int $flags, array $args, ?Node\Name $extends, array $implements, | ||||
|         array $stmts, array $attributes | ||||
|     ) { | ||||
|         parent::__construct($attributes); | ||||
|         $this->attrGroups = $attrGroups; | ||||
|         $this->flags = $flags; | ||||
|         $this->args = $args; | ||||
|         $this->extends = $extends; | ||||
|         $this->implements = $implements; | ||||
|         $this->stmts = $stmts; | ||||
|     } | ||||
|  | ||||
|     public static function fromNewNode(Expr\New_ $newNode): self { | ||||
|         $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']; | ||||
|     } | ||||
| } | ||||
| @@ -1,237 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Internal; | ||||
|  | ||||
| if (\PHP_VERSION_ID >= 80000) { | ||||
|     class TokenPolyfill extends \PhpToken { | ||||
|     } | ||||
|     return; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This is a polyfill for the PhpToken class introduced in PHP 8.0. We do not actually polyfill | ||||
|  * PhpToken, because composer might end up picking a different polyfill implementation, which does | ||||
|  * not meet our requirements. | ||||
|  * | ||||
|  * @internal | ||||
|  */ | ||||
| class TokenPolyfill { | ||||
|     /** @var int The ID of the token. Either a T_* constant of a character code < 256. */ | ||||
|     public int $id; | ||||
|     /** @var string The textual content of the token. */ | ||||
|     public string $text; | ||||
|     /** @var int The 1-based starting line of the token (or -1 if unknown). */ | ||||
|     public int $line; | ||||
|     /** @var int The 0-based starting position of the token (or -1 if unknown). */ | ||||
|     public int $pos; | ||||
|  | ||||
|     /** @var array<int, bool> Tokens ignored by the PHP parser. */ | ||||
|     private const IGNORABLE_TOKENS = [ | ||||
|         \T_WHITESPACE => true, | ||||
|         \T_COMMENT => true, | ||||
|         \T_DOC_COMMENT => true, | ||||
|         \T_OPEN_TAG => true, | ||||
|     ]; | ||||
|  | ||||
|     /** @var array<int, bool> Tokens that may be part of a T_NAME_* identifier. */ | ||||
|     private static array $identifierTokens; | ||||
|  | ||||
|     /** | ||||
|      * Create a Token with the given ID and text, as well optional line and position information. | ||||
|      */ | ||||
|     final public function __construct(int $id, string $text, int $line = -1, int $pos = -1) { | ||||
|         $this->id = $id; | ||||
|         $this->text = $text; | ||||
|         $this->line = $line; | ||||
|         $this->pos = $pos; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get the name of the token. For single-char tokens this will be the token character. | ||||
|      * Otherwise it will be a T_* style name, or null if the token ID is unknown. | ||||
|      */ | ||||
|     public function getTokenName(): ?string { | ||||
|         if ($this->id < 256) { | ||||
|             return \chr($this->id); | ||||
|         } | ||||
|  | ||||
|         $name = token_name($this->id); | ||||
|         return $name === 'UNKNOWN' ? null : $name; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Check whether the token is of the given kind. The kind may be either an integer that matches | ||||
|      * the token ID, a string that matches the token text, or an array of integers/strings. In the | ||||
|      * latter case, the function returns true if any of the kinds in the array match. | ||||
|      * | ||||
|      * @param int|string|(int|string)[] $kind | ||||
|      */ | ||||
|     public function is($kind): bool { | ||||
|         if (\is_int($kind)) { | ||||
|             return $this->id === $kind; | ||||
|         } | ||||
|         if (\is_string($kind)) { | ||||
|             return $this->text === $kind; | ||||
|         } | ||||
|         if (\is_array($kind)) { | ||||
|             foreach ($kind as $entry) { | ||||
|                 if (\is_int($entry)) { | ||||
|                     if ($this->id === $entry) { | ||||
|                         return true; | ||||
|                     } | ||||
|                 } elseif (\is_string($entry)) { | ||||
|                     if ($this->text === $entry) { | ||||
|                         return true; | ||||
|                     } | ||||
|                 } else { | ||||
|                     throw new \TypeError( | ||||
|                         'Argument #1 ($kind) must only have elements of type string|int, ' . | ||||
|                         gettype($entry) . ' given'); | ||||
|                 } | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
|         throw new \TypeError( | ||||
|             'Argument #1 ($kind) must be of type string|int|array, ' .gettype($kind) . ' given'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Check whether this token would be ignored by the PHP parser. Returns true for T_WHITESPACE, | ||||
|      * T_COMMENT, T_DOC_COMMENT and T_OPEN_TAG, and false for everything else. | ||||
|      */ | ||||
|     public function isIgnorable(): bool { | ||||
|         return isset(self::IGNORABLE_TOKENS[$this->id]); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Return the textual content of the token. | ||||
|      */ | ||||
|     public function __toString(): string { | ||||
|         return $this->text; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Tokenize the given source code and return an array of tokens. | ||||
|      * | ||||
|      * This performs certain canonicalizations to match the PHP 8.0 token format: | ||||
|      *  * Bad characters are represented using T_BAD_CHARACTER rather than omitted. | ||||
|      *  * T_COMMENT does not include trailing newlines, instead the newline is part of a following | ||||
|      *    T_WHITESPACE token. | ||||
|      *  * Namespaced names are represented using T_NAME_* tokens. | ||||
|      * | ||||
|      * @return static[] | ||||
|      */ | ||||
|     public static function tokenize(string $code, int $flags = 0): array { | ||||
|         self::init(); | ||||
|  | ||||
|         $tokens = []; | ||||
|         $line = 1; | ||||
|         $pos = 0; | ||||
|         $origTokens = \token_get_all($code, $flags); | ||||
|  | ||||
|         $numTokens = \count($origTokens); | ||||
|         for ($i = 0; $i < $numTokens; $i++) { | ||||
|             $token = $origTokens[$i]; | ||||
|             if (\is_string($token)) { | ||||
|                 if (\strlen($token) === 2) { | ||||
|                     // b" and B" are tokenized as single-char tokens, even though they aren't. | ||||
|                     $tokens[] = new static(\ord('"'), $token, $line, $pos); | ||||
|                     $pos += 2; | ||||
|                 } else { | ||||
|                     $tokens[] = new static(\ord($token), $token, $line, $pos); | ||||
|                     $pos++; | ||||
|                 } | ||||
|             } else { | ||||
|                 $id = $token[0]; | ||||
|                 $text = $token[1]; | ||||
|  | ||||
|                 // Emulate PHP 8.0 comment format, which does not include trailing whitespace anymore. | ||||
|                 if ($id === \T_COMMENT && \substr($text, 0, 2) !== '/*' && | ||||
|                     \preg_match('/(\r\n|\n|\r)$/D', $text, $matches) | ||||
|                 ) { | ||||
|                     $trailingNewline = $matches[0]; | ||||
|                     $text = \substr($text, 0, -\strlen($trailingNewline)); | ||||
|                     $tokens[] = new static($id, $text, $line, $pos); | ||||
|                     $pos += \strlen($text); | ||||
|  | ||||
|                     if ($i + 1 < $numTokens && $origTokens[$i + 1][0] === \T_WHITESPACE) { | ||||
|                         // Move trailing newline into following T_WHITESPACE token, if it already exists. | ||||
|                         $origTokens[$i + 1][1] = $trailingNewline . $origTokens[$i + 1][1]; | ||||
|                         $origTokens[$i + 1][2]--; | ||||
|                     } else { | ||||
|                         // Otherwise, we need to create a new T_WHITESPACE token. | ||||
|                         $tokens[] = new static(\T_WHITESPACE, $trailingNewline, $line, $pos); | ||||
|                         $line++; | ||||
|                         $pos += \strlen($trailingNewline); | ||||
|                     } | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 // Emulate PHP 8.0 T_NAME_* tokens, by combining sequences of T_NS_SEPARATOR and | ||||
|                 // T_STRING into a single token. | ||||
|                 if (($id === \T_NS_SEPARATOR || isset(self::$identifierTokens[$id]))) { | ||||
|                     $newText = $text; | ||||
|                     $lastWasSeparator = $id === \T_NS_SEPARATOR; | ||||
|                     for ($j = $i + 1; $j < $numTokens; $j++) { | ||||
|                         if ($lastWasSeparator) { | ||||
|                             if (!isset(self::$identifierTokens[$origTokens[$j][0]])) { | ||||
|                                 break; | ||||
|                             } | ||||
|                             $lastWasSeparator = false; | ||||
|                         } else { | ||||
|                             if ($origTokens[$j][0] !== \T_NS_SEPARATOR) { | ||||
|                                 break; | ||||
|                             } | ||||
|                             $lastWasSeparator = true; | ||||
|                         } | ||||
|                         $newText .= $origTokens[$j][1]; | ||||
|                     } | ||||
|                     if ($lastWasSeparator) { | ||||
|                         // Trailing separator is not part of the name. | ||||
|                         $j--; | ||||
|                         $newText = \substr($newText, 0, -1); | ||||
|                     } | ||||
|                     if ($j > $i + 1) { | ||||
|                         if ($id === \T_NS_SEPARATOR) { | ||||
|                             $id = \T_NAME_FULLY_QUALIFIED; | ||||
|                         } elseif ($id === \T_NAMESPACE) { | ||||
|                             $id = \T_NAME_RELATIVE; | ||||
|                         } else { | ||||
|                             $id = \T_NAME_QUALIFIED; | ||||
|                         } | ||||
|                         $tokens[] = new static($id, $newText, $line, $pos); | ||||
|                         $pos += \strlen($newText); | ||||
|                         $i = $j - 1; | ||||
|                         continue; | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 $tokens[] = new static($id, $text, $line, $pos); | ||||
|                 $line += \substr_count($text, "\n"); | ||||
|                 $pos += \strlen($text); | ||||
|             } | ||||
|         } | ||||
|         return $tokens; | ||||
|     } | ||||
|  | ||||
|     /** Initialize private static state needed by tokenize(). */ | ||||
|     private static function init(): void { | ||||
|         if (isset(self::$identifierTokens)) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // Based on semi_reserved production. | ||||
|         self::$identifierTokens = \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); | ||||
|     } | ||||
| } | ||||
| @@ -1,282 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Internal; | ||||
|  | ||||
| use PhpParser\Token; | ||||
|  | ||||
| /** | ||||
|  * Provides operations on token streams, for use by pretty printer. | ||||
|  * | ||||
|  * @internal | ||||
|  */ | ||||
| class TokenStream { | ||||
|     /** @var Token[] Tokens (in PhpToken::tokenize() format) */ | ||||
|     private array $tokens; | ||||
|     /** @var int[] Map from position to indentation */ | ||||
|     private array $indentMap; | ||||
|  | ||||
|     /** | ||||
|      * Create token stream instance. | ||||
|      * | ||||
|      * @param Token[] $tokens Tokens in PhpToken::tokenize() format | ||||
|      */ | ||||
|     public function __construct(array $tokens, int $tabWidth) { | ||||
|         $this->tokens = $tokens; | ||||
|         $this->indentMap = $this->calcIndentMap($tabWidth); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Whether the given position is immediately surrounded by parenthesis. | ||||
|      * | ||||
|      * @param int $startPos Start position | ||||
|      * @param int $endPos End position | ||||
|      */ | ||||
|     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 | ||||
|      */ | ||||
|     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--) { | ||||
|             $token = $tokens[$pos]; | ||||
|             if ($token->is($expectedTokenType)) { | ||||
|                 return true; | ||||
|             } | ||||
|             if (!$token->isIgnorable()) { | ||||
|                 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 ($c = \count($tokens); $pos < $c; $pos++) { | ||||
|             $token = $tokens[$pos]; | ||||
|             if ($token->is($expectedTokenType)) { | ||||
|                 return true; | ||||
|             } | ||||
|             if (!$token->isIgnorable()) { | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     /** @param int|string|(int|string)[] $skipTokenType */ | ||||
|     public function skipLeft(int $pos, $skipTokenType): int { | ||||
|         $tokens = $this->tokens; | ||||
|  | ||||
|         $pos = $this->skipLeftWhitespace($pos); | ||||
|         if ($skipTokenType === \T_WHITESPACE) { | ||||
|             return $pos; | ||||
|         } | ||||
|  | ||||
|         if (!$tokens[$pos]->is($skipTokenType)) { | ||||
|             // Shouldn't happen. The skip token MUST be there | ||||
|             throw new \Exception('Encountered unexpected token'); | ||||
|         } | ||||
|         $pos--; | ||||
|  | ||||
|         return $this->skipLeftWhitespace($pos); | ||||
|     } | ||||
|  | ||||
|     /** @param int|string|(int|string)[] $skipTokenType */ | ||||
|     public function skipRight(int $pos, $skipTokenType): int { | ||||
|         $tokens = $this->tokens; | ||||
|  | ||||
|         $pos = $this->skipRightWhitespace($pos); | ||||
|         if ($skipTokenType === \T_WHITESPACE) { | ||||
|             return $pos; | ||||
|         } | ||||
|  | ||||
|         if (!$tokens[$pos]->is($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): int { | ||||
|         $tokens = $this->tokens; | ||||
|         for (; $pos >= 0; $pos--) { | ||||
|             if (!$tokens[$pos]->isIgnorable()) { | ||||
|                 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): int { | ||||
|         $tokens = $this->tokens; | ||||
|         for ($count = \count($tokens); $pos < $count; $pos++) { | ||||
|             if (!$tokens[$pos]->isIgnorable()) { | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         return $pos; | ||||
|     } | ||||
|  | ||||
|     /** @param int|string|(int|string)[] $findTokenType */ | ||||
|     public function findRight(int $pos, $findTokenType): int { | ||||
|         $tokens = $this->tokens; | ||||
|         for ($count = \count($tokens); $pos < $count; $pos++) { | ||||
|             if ($tokens[$pos]->is($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): bool { | ||||
|         $tokens = $this->tokens; | ||||
|         for ($pos = $startPos; $pos < $endPos; $pos++) { | ||||
|             if ($tokens[$pos]->is($tokenType)) { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     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]; | ||||
|             $id = $token->id; | ||||
|             $text = $token->text; | ||||
|             if ($id === \T_CONSTANT_ENCAPSED_STRING || $id === \T_ENCAPSED_AND_WHITESPACE) { | ||||
|                 $result .= $text; | ||||
|             } else { | ||||
|                 // TODO Handle non-space indentation | ||||
|                 if ($indent < 0) { | ||||
|                     $result .= str_replace("\n" . str_repeat(" ", -$indent), "\n", $text); | ||||
|                 } elseif ($indent > 0) { | ||||
|                     $result .= str_replace("\n", "\n" . str_repeat(" ", $indent), $text); | ||||
|                 } else { | ||||
|                     $result .= $text; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return $result; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Precalculate the indentation at every token position. | ||||
|      * | ||||
|      * @return int[] Token position to indentation map | ||||
|      */ | ||||
|     private function calcIndentMap(int $tabWidth): array { | ||||
|         $indentMap = []; | ||||
|         $indent = 0; | ||||
|         foreach ($this->tokens as $i => $token) { | ||||
|             $indentMap[] = $indent; | ||||
|  | ||||
|             if ($token->id === \T_WHITESPACE) { | ||||
|                 $content = $token->text; | ||||
|                 $newlinePos = \strrpos($content, "\n"); | ||||
|                 if (false !== $newlinePos) { | ||||
|                     $indent = $this->getIndent(\substr($content, $newlinePos + 1), $tabWidth); | ||||
|                 } elseif ($i === 1 && $this->tokens[0]->id === \T_OPEN_TAG && | ||||
|                           $this->tokens[0]->text[\strlen($this->tokens[0]->text) - 1] === "\n") { | ||||
|                     // Special case: Newline at the end of opening tag followed by whitespace. | ||||
|                     $indent = $this->getIndent($content, $tabWidth); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Add a sentinel for one past end of the file | ||||
|         $indentMap[] = $indent; | ||||
|  | ||||
|         return $indentMap; | ||||
|     } | ||||
|  | ||||
|     private function getIndent(string $ws, int $tabWidth): int { | ||||
|         $spaces = \substr_count($ws, " "); | ||||
|         $tabs = \substr_count($ws, "\t"); | ||||
|         assert(\strlen($ws) === $spaces + $tabs); | ||||
|         return $spaces + $tabs * $tabWidth; | ||||
|     } | ||||
| } | ||||
| @@ -1,108 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser; | ||||
|  | ||||
| class JsonDecoder { | ||||
|     /** @var \ReflectionClass<Node>[] Node type to reflection class map */ | ||||
|     private array $reflectionClassCache; | ||||
|  | ||||
|     /** @return mixed */ | ||||
|     public function decode(string $json) { | ||||
|         $value = json_decode($json, true); | ||||
|         if (json_last_error()) { | ||||
|             throw new \RuntimeException('JSON decoding error: ' . json_last_error_msg()); | ||||
|         } | ||||
|  | ||||
|         return $this->decodeRecursive($value); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param mixed $value | ||||
|      * @return mixed | ||||
|      */ | ||||
|     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); | ||||
|         $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 | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** @return \ReflectionClass<Node> */ | ||||
|     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]; | ||||
|     } | ||||
|  | ||||
|     /** @return class-string<Node> */ | ||||
|     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\""); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										116
									
								
								vendor/nikic/php-parser/lib/PhpParser/Lexer.php
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										116
									
								
								vendor/nikic/php-parser/lib/PhpParser/Lexer.php
									
									
									
									
										vendored
									
									
								
							| @@ -1,116 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser; | ||||
|  | ||||
| require __DIR__ . '/compatibility_tokens.php'; | ||||
|  | ||||
| class Lexer { | ||||
|     /** | ||||
|      * Tokenize the provided source code. | ||||
|      * | ||||
|      * The token array is in the same format as provided by the PhpToken::tokenize() method in | ||||
|      * PHP 8.0. The tokens are instances of PhpParser\Token, to abstract over a polyfill | ||||
|      * implementation in earlier PHP version. | ||||
|      * | ||||
|      * The token array is terminated by a sentinel token with token ID 0. | ||||
|      * The token array does not discard any tokens (i.e. whitespace and comments are included). | ||||
|      * The token position attributes are against this token array. | ||||
|      * | ||||
|      * @param string $code The source code to tokenize. | ||||
|      * @param ErrorHandler|null $errorHandler Error handler to use for lexing errors. Defaults to | ||||
|      *                                        ErrorHandler\Throwing. | ||||
|      * @return Token[] Tokens | ||||
|      */ | ||||
|     public function tokenize(string $code, ?ErrorHandler $errorHandler = null): array { | ||||
|         if (null === $errorHandler) { | ||||
|             $errorHandler = new ErrorHandler\Throwing(); | ||||
|         } | ||||
|  | ||||
|         $scream = ini_set('xdebug.scream', '0'); | ||||
|  | ||||
|         $tokens = @Token::tokenize($code); | ||||
|         $this->postprocessTokens($tokens, $errorHandler); | ||||
|  | ||||
|         if (false !== $scream) { | ||||
|             ini_set('xdebug.scream', $scream); | ||||
|         } | ||||
|  | ||||
|         return $tokens; | ||||
|     } | ||||
|  | ||||
|     private function handleInvalidCharacter(Token $token, ErrorHandler $errorHandler): void { | ||||
|         $chr = $token->text; | ||||
|         if ($chr === "\0") { | ||||
|             // 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) | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         $errorHandler->handleError(new Error($errorMsg, [ | ||||
|             'startLine' => $token->line, | ||||
|             'endLine' => $token->line, | ||||
|             'startFilePos' => $token->pos, | ||||
|             'endFilePos' => $token->pos, | ||||
|         ])); | ||||
|     } | ||||
|  | ||||
|     private function isUnterminatedComment(Token $token): bool { | ||||
|         return $token->is([\T_COMMENT, \T_DOC_COMMENT]) | ||||
|             && substr($token->text, 0, 2) === '/*' | ||||
|             && substr($token->text, -2) !== '*/'; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param list<Token> $tokens | ||||
|      */ | ||||
|     protected function postprocessTokens(array &$tokens, ErrorHandler $errorHandler): void { | ||||
|         // This function reports errors (bad characters and unterminated comments) in the token | ||||
|         // array, and performs certain canonicalizations: | ||||
|         //  * 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. | ||||
|         //  * Add a sentinel token with ID 0. | ||||
|  | ||||
|         $numTokens = \count($tokens); | ||||
|         if ($numTokens === 0) { | ||||
|             // Empty input edge case: Just add the sentinel token. | ||||
|             $tokens[] = new Token(0, "\0", 1, 0); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         for ($i = 0; $i < $numTokens; $i++) { | ||||
|             $token = $tokens[$i]; | ||||
|             if ($token->id === \T_BAD_CHARACTER) { | ||||
|                 $this->handleInvalidCharacter($token, $errorHandler); | ||||
|             } | ||||
|  | ||||
|             if ($token->id === \ord('&')) { | ||||
|                 $next = $i + 1; | ||||
|                 while (isset($tokens[$next]) && $tokens[$next]->id === \T_WHITESPACE) { | ||||
|                     $next++; | ||||
|                 } | ||||
|                 $followedByVarOrVarArg = isset($tokens[$next]) && | ||||
|                     $tokens[$next]->is([\T_VARIABLE, \T_ELLIPSIS]); | ||||
|                 $token->id = $followedByVarOrVarArg | ||||
|                     ? \T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG | ||||
|                     : \T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Check for unterminated comment | ||||
|         $lastToken = $tokens[$numTokens - 1]; | ||||
|         if ($this->isUnterminatedComment($lastToken)) { | ||||
|             $errorHandler->handleError(new Error('Unterminated comment', [ | ||||
|                 'startLine' => $lastToken->line, | ||||
|                 'endLine' => $lastToken->getEndLine(), | ||||
|                 'startFilePos' => $lastToken->pos, | ||||
|                 'endFilePos' => $lastToken->getEndPos(), | ||||
|             ])); | ||||
|         } | ||||
|  | ||||
|         // Add sentinel token. | ||||
|         $tokens[] = new Token(0, "\0", $lastToken->getEndLine(), $lastToken->getEndPos()); | ||||
|     } | ||||
| } | ||||
| @@ -1,226 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Lexer; | ||||
|  | ||||
| use PhpParser\Error; | ||||
| use PhpParser\ErrorHandler; | ||||
| use PhpParser\Lexer; | ||||
| use PhpParser\Lexer\TokenEmulator\AsymmetricVisibilityTokenEmulator; | ||||
| use PhpParser\Lexer\TokenEmulator\AttributeEmulator; | ||||
| use PhpParser\Lexer\TokenEmulator\EnumTokenEmulator; | ||||
| use PhpParser\Lexer\TokenEmulator\ExplicitOctalEmulator; | ||||
| use PhpParser\Lexer\TokenEmulator\MatchTokenEmulator; | ||||
| use PhpParser\Lexer\TokenEmulator\NullsafeTokenEmulator; | ||||
| use PhpParser\Lexer\TokenEmulator\PropertyTokenEmulator; | ||||
| use PhpParser\Lexer\TokenEmulator\ReadonlyFunctionTokenEmulator; | ||||
| use PhpParser\Lexer\TokenEmulator\ReadonlyTokenEmulator; | ||||
| use PhpParser\Lexer\TokenEmulator\ReverseEmulator; | ||||
| use PhpParser\Lexer\TokenEmulator\TokenEmulator; | ||||
| use PhpParser\PhpVersion; | ||||
| use PhpParser\Token; | ||||
|  | ||||
| class Emulative extends Lexer { | ||||
|     /** @var array{int, string, string}[] Patches used to reverse changes introduced in the code */ | ||||
|     private array $patches = []; | ||||
|  | ||||
|     /** @var list<TokenEmulator> */ | ||||
|     private array $emulators = []; | ||||
|  | ||||
|     private PhpVersion $targetPhpVersion; | ||||
|  | ||||
|     private PhpVersion $hostPhpVersion; | ||||
|  | ||||
|     /** | ||||
|      * @param PhpVersion|null $phpVersion PHP version to emulate. Defaults to newest supported. | ||||
|      */ | ||||
|     public function __construct(?PhpVersion $phpVersion = null) { | ||||
|         $this->targetPhpVersion = $phpVersion ?? PhpVersion::getNewestSupported(); | ||||
|         $this->hostPhpVersion = PhpVersion::getHostVersion(); | ||||
|  | ||||
|         $emulators = [ | ||||
|             new MatchTokenEmulator(), | ||||
|             new NullsafeTokenEmulator(), | ||||
|             new AttributeEmulator(), | ||||
|             new EnumTokenEmulator(), | ||||
|             new ReadonlyTokenEmulator(), | ||||
|             new ExplicitOctalEmulator(), | ||||
|             new ReadonlyFunctionTokenEmulator(), | ||||
|             new PropertyTokenEmulator(), | ||||
|             new AsymmetricVisibilityTokenEmulator(), | ||||
|         ]; | ||||
|  | ||||
|         // 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; | ||||
|             } elseif ($this->isReverseEmulationNeeded($emulatorPhpVersion)) { | ||||
|                 $this->emulators[] = new ReverseEmulator($emulator); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public function tokenize(string $code, ?ErrorHandler $errorHandler = null): array { | ||||
|         $emulators = array_filter($this->emulators, function ($emulator) use ($code) { | ||||
|             return $emulator->isEmulationNeeded($code); | ||||
|         }); | ||||
|  | ||||
|         if (empty($emulators)) { | ||||
|             // Nothing to emulate, yay | ||||
|             return parent::tokenize($code, $errorHandler); | ||||
|         } | ||||
|  | ||||
|         if ($errorHandler === null) { | ||||
|             $errorHandler = new ErrorHandler\Throwing(); | ||||
|         } | ||||
|  | ||||
|         $this->patches = []; | ||||
|         foreach ($emulators as $emulator) { | ||||
|             $code = $emulator->preprocessCode($code, $this->patches); | ||||
|         } | ||||
|  | ||||
|         $collector = new ErrorHandler\Collecting(); | ||||
|         $tokens = parent::tokenize($code, $collector); | ||||
|         $this->sortPatches(); | ||||
|         $tokens = $this->fixupTokens($tokens); | ||||
|  | ||||
|         $errors = $collector->getErrors(); | ||||
|         if (!empty($errors)) { | ||||
|             $this->fixupErrors($errors); | ||||
|             foreach ($errors as $error) { | ||||
|                 $errorHandler->handleError($error); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         foreach ($emulators as $emulator) { | ||||
|             $tokens = $emulator->emulate($code, $tokens); | ||||
|         } | ||||
|  | ||||
|         return $tokens; | ||||
|     } | ||||
|  | ||||
|     private function isForwardEmulationNeeded(PhpVersion $emulatorPhpVersion): bool { | ||||
|         return $this->hostPhpVersion->older($emulatorPhpVersion) | ||||
|             && $this->targetPhpVersion->newerOrEqual($emulatorPhpVersion); | ||||
|     } | ||||
|  | ||||
|     private function isReverseEmulationNeeded(PhpVersion $emulatorPhpVersion): bool { | ||||
|         return $this->hostPhpVersion->newerOrEqual($emulatorPhpVersion) | ||||
|             && $this->targetPhpVersion->older($emulatorPhpVersion); | ||||
|     } | ||||
|  | ||||
|     private function sortPatches(): void { | ||||
|         // 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]; | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param list<Token> $tokens | ||||
|      * @return list<Token> | ||||
|      */ | ||||
|     private function fixupTokens(array $tokens): array { | ||||
|         if (\count($this->patches) === 0) { | ||||
|             return $tokens; | ||||
|         } | ||||
|  | ||||
|         // 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 | ||||
|         $posDelta = 0; | ||||
|         $lineDelta = 0; | ||||
|         for ($i = 0, $c = \count($tokens); $i < $c; $i++) { | ||||
|             $token = $tokens[$i]; | ||||
|             $pos = $token->pos; | ||||
|             $token->pos += $posDelta; | ||||
|             $token->line += $lineDelta; | ||||
|             $localPosDelta = 0; | ||||
|             $len = \strlen($token->text); | ||||
|             while ($patchPos >= $pos && $patchPos < $pos + $len) { | ||||
|                 $patchTextLen = \strlen($patchText); | ||||
|                 if ($patchType === 'remove') { | ||||
|                     if ($patchPos === $pos && $patchTextLen === $len) { | ||||
|                         // Remove token entirely | ||||
|                         array_splice($tokens, $i, 1, []); | ||||
|                         $i--; | ||||
|                         $c--; | ||||
|                     } else { | ||||
|                         // Remove from token string | ||||
|                         $token->text = substr_replace( | ||||
|                             $token->text, '', $patchPos - $pos + $localPosDelta, $patchTextLen | ||||
|                         ); | ||||
|                         $localPosDelta -= $patchTextLen; | ||||
|                     } | ||||
|                     $lineDelta -= \substr_count($patchText, "\n"); | ||||
|                 } elseif ($patchType === 'add') { | ||||
|                     // Insert into the token string | ||||
|                     $token->text = substr_replace( | ||||
|                         $token->text, $patchText, $patchPos - $pos + $localPosDelta, 0 | ||||
|                     ); | ||||
|                     $localPosDelta += $patchTextLen; | ||||
|                     $lineDelta += \substr_count($patchText, "\n"); | ||||
|                 } elseif ($patchType === 'replace') { | ||||
|                     // Replace inside the token string | ||||
|                     $token->text = substr_replace( | ||||
|                         $token->text, $patchText, $patchPos - $pos + $localPosDelta, $patchTextLen | ||||
|                     ); | ||||
|                 } else { | ||||
|                     assert(false); | ||||
|                 } | ||||
|  | ||||
|                 // Fetch the next patch | ||||
|                 $patchIdx++; | ||||
|                 if ($patchIdx >= \count($this->patches)) { | ||||
|                     // No more patches. However, we still need to adjust position. | ||||
|                     $patchPos = \PHP_INT_MAX; | ||||
|                     break; | ||||
|                 } | ||||
|  | ||||
|                 list($patchPos, $patchType, $patchText) = $this->patches[$patchIdx]; | ||||
|             } | ||||
|  | ||||
|             $posDelta += $localPosDelta; | ||||
|         } | ||||
|         return $tokens; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Fixup line and position information in errors. | ||||
|      * | ||||
|      * @param Error[] $errors | ||||
|      */ | ||||
|     private function fixupErrors(array $errors): void { | ||||
|         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"); | ||||
|                 } elseif ($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); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,93 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Lexer\TokenEmulator; | ||||
|  | ||||
| use PhpParser\PhpVersion; | ||||
| use PhpParser\Token; | ||||
|  | ||||
| final class AsymmetricVisibilityTokenEmulator extends TokenEmulator { | ||||
|     public function getPhpVersion(): PhpVersion { | ||||
|         return PhpVersion::fromComponents(8, 4); | ||||
|     } | ||||
|     public function isEmulationNeeded(string $code): bool { | ||||
|         $code = strtolower($code); | ||||
|         return strpos($code, 'public(set)') !== false || | ||||
|             strpos($code, 'protected(set)') !== false || | ||||
|             strpos($code, 'private(set)') !== false; | ||||
|     } | ||||
|  | ||||
|     public function emulate(string $code, array $tokens): array { | ||||
|         $map = [ | ||||
|             \T_PUBLIC => \T_PUBLIC_SET, | ||||
|             \T_PROTECTED => \T_PROTECTED_SET, | ||||
|             \T_PRIVATE => \T_PRIVATE_SET, | ||||
|         ]; | ||||
|         for ($i = 0, $c = count($tokens); $i < $c; ++$i) { | ||||
|             $token = $tokens[$i]; | ||||
|             if (isset($map[$token->id]) && $i + 3 < $c && $tokens[$i + 1]->text === '(' && | ||||
|                 $tokens[$i + 2]->id === \T_STRING && \strtolower($tokens[$i + 2]->text) === 'set' && | ||||
|                 $tokens[$i + 3]->text === ')' && | ||||
|                 $this->isKeywordContext($tokens, $i) | ||||
|             ) { | ||||
|                 array_splice($tokens, $i, 4, [ | ||||
|                     new Token( | ||||
|                         $map[$token->id], $token->text . '(' . $tokens[$i + 2]->text . ')', | ||||
|                         $token->line, $token->pos), | ||||
|                 ]); | ||||
|                 $c -= 3; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $tokens; | ||||
|     } | ||||
|  | ||||
|     public function reverseEmulate(string $code, array $tokens): array { | ||||
|         $reverseMap = [ | ||||
|             \T_PUBLIC_SET => \T_PUBLIC, | ||||
|             \T_PROTECTED_SET => \T_PROTECTED, | ||||
|             \T_PRIVATE_SET => \T_PRIVATE, | ||||
|         ]; | ||||
|         for ($i = 0, $c = count($tokens); $i < $c; ++$i) { | ||||
|             $token = $tokens[$i]; | ||||
|             if (isset($reverseMap[$token->id]) && | ||||
|                 \preg_match('/(public|protected|private)\((set)\)/i', $token->text, $matches) | ||||
|             ) { | ||||
|                 [, $modifier, $set] = $matches; | ||||
|                 $modifierLen = \strlen($modifier); | ||||
|                 array_splice($tokens, $i, 1, [ | ||||
|                     new Token($reverseMap[$token->id], $modifier, $token->line, $token->pos), | ||||
|                     new Token(\ord('('), '(', $token->line, $token->pos + $modifierLen), | ||||
|                     new Token(\T_STRING, $set, $token->line, $token->pos + $modifierLen + 1), | ||||
|                     new Token(\ord(')'), ')', $token->line, $token->pos + $modifierLen + 4), | ||||
|                 ]); | ||||
|                 $i += 3; | ||||
|                 $c += 3; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $tokens; | ||||
|     } | ||||
|  | ||||
|     /** @param Token[] $tokens */ | ||||
|     protected function isKeywordContext(array $tokens, int $pos): bool { | ||||
|         $prevToken = $this->getPreviousNonSpaceToken($tokens, $pos); | ||||
|         if ($prevToken === null) { | ||||
|             return false; | ||||
|         } | ||||
|         return $prevToken->id !== \T_OBJECT_OPERATOR | ||||
|             && $prevToken->id !== \T_NULLSAFE_OBJECT_OPERATOR; | ||||
|     } | ||||
|  | ||||
|     /** @param Token[] $tokens */ | ||||
|     private function getPreviousNonSpaceToken(array $tokens, int $start): ?Token { | ||||
|         for ($i = $start - 1; $i >= 0; --$i) { | ||||
|             if ($tokens[$i]->id === T_WHITESPACE) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             return $tokens[$i]; | ||||
|         } | ||||
|  | ||||
|         return null; | ||||
|     } | ||||
| } | ||||
| @@ -1,49 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Lexer\TokenEmulator; | ||||
|  | ||||
| use PhpParser\PhpVersion; | ||||
| use PhpParser\Token; | ||||
|  | ||||
| final class AttributeEmulator extends TokenEmulator { | ||||
|     public function getPhpVersion(): PhpVersion { | ||||
|         return PhpVersion::fromComponents(8, 0); | ||||
|     } | ||||
|  | ||||
|     public function isEmulationNeeded(string $code): bool { | ||||
|         return strpos($code, '#[') !== 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. | ||||
|         for ($i = 0, $c = count($tokens); $i < $c; ++$i) { | ||||
|             $token = $tokens[$i]; | ||||
|             if ($token->text === '#' && isset($tokens[$i + 1]) && $tokens[$i + 1]->text === '[') { | ||||
|                 array_splice($tokens, $i, 2, [ | ||||
|                     new Token(\T_ATTRIBUTE, '#[', $token->line, $token->pos), | ||||
|                 ]); | ||||
|                 $c--; | ||||
|                 continue; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $tokens; | ||||
|     } | ||||
|  | ||||
|     public function reverseEmulate(string $code, array $tokens): array { | ||||
|         // TODO | ||||
|         return $tokens; | ||||
|     } | ||||
|  | ||||
|     public function preprocessCode(string $code, array &$patches): string { | ||||
|         $pos = 0; | ||||
|         while (false !== $pos = strpos($code, '#[', $pos)) { | ||||
|             // Replace #[ with %[ | ||||
|             $code[$pos] = '%'; | ||||
|             $patches[] = [$pos, 'replace', '#']; | ||||
|             $pos += 2; | ||||
|         } | ||||
|         return $code; | ||||
|     } | ||||
| } | ||||
| @@ -1,26 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Lexer\TokenEmulator; | ||||
|  | ||||
| use PhpParser\PhpVersion; | ||||
|  | ||||
| final class EnumTokenEmulator extends KeywordEmulator { | ||||
|     public function getPhpVersion(): PhpVersion { | ||||
|         return PhpVersion::fromComponents(8, 1); | ||||
|     } | ||||
|  | ||||
|     public function getKeywordString(): string { | ||||
|         return 'enum'; | ||||
|     } | ||||
|  | ||||
|     public function getKeywordToken(): int { | ||||
|         return \T_ENUM; | ||||
|     } | ||||
|  | ||||
|     protected function isKeywordContext(array $tokens, int $pos): bool { | ||||
|         return parent::isKeywordContext($tokens, $pos) | ||||
|             && isset($tokens[$pos + 2]) | ||||
|             && $tokens[$pos + 1]->id === \T_WHITESPACE | ||||
|             && $tokens[$pos + 2]->id === \T_STRING; | ||||
|     } | ||||
| } | ||||
| @@ -1,45 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Lexer\TokenEmulator; | ||||
|  | ||||
| use PhpParser\PhpVersion; | ||||
| use PhpParser\Token; | ||||
|  | ||||
| class ExplicitOctalEmulator extends TokenEmulator { | ||||
|     public function getPhpVersion(): PhpVersion { | ||||
|         return PhpVersion::fromComponents(8, 1); | ||||
|     } | ||||
|  | ||||
|     public function isEmulationNeeded(string $code): bool { | ||||
|         return strpos($code, '0o') !== false || strpos($code, '0O') !== false; | ||||
|     } | ||||
|  | ||||
|     public function emulate(string $code, array $tokens): array { | ||||
|         for ($i = 0, $c = count($tokens); $i < $c; ++$i) { | ||||
|             $token = $tokens[$i]; | ||||
|             if ($token->id == \T_LNUMBER && $token->text === '0' && | ||||
|                 isset($tokens[$i + 1]) && $tokens[$i + 1]->id == \T_STRING && | ||||
|                 preg_match('/[oO][0-7]+(?:_[0-7]+)*/', $tokens[$i + 1]->text) | ||||
|             ) { | ||||
|                 $tokenKind = $this->resolveIntegerOrFloatToken($tokens[$i + 1]->text); | ||||
|                 array_splice($tokens, $i, 2, [ | ||||
|                     new Token($tokenKind, '0' . $tokens[$i + 1]->text, $token->line, $token->pos), | ||||
|                 ]); | ||||
|                 $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; | ||||
|     } | ||||
| } | ||||
| @@ -1,60 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Lexer\TokenEmulator; | ||||
|  | ||||
| use PhpParser\Token; | ||||
|  | ||||
| abstract class KeywordEmulator extends TokenEmulator { | ||||
|     abstract public function getKeywordString(): string; | ||||
|     abstract public function getKeywordToken(): int; | ||||
|  | ||||
|     public function isEmulationNeeded(string $code): bool { | ||||
|         return strpos(strtolower($code), $this->getKeywordString()) !== false; | ||||
|     } | ||||
|  | ||||
|     /** @param Token[] $tokens */ | ||||
|     protected function isKeywordContext(array $tokens, int $pos): bool { | ||||
|         $prevToken = $this->getPreviousNonSpaceToken($tokens, $pos); | ||||
|         if ($prevToken === null) { | ||||
|             return false; | ||||
|         } | ||||
|         return $prevToken->id !== \T_OBJECT_OPERATOR | ||||
|             && $prevToken->id !== \T_NULLSAFE_OBJECT_OPERATOR; | ||||
|     } | ||||
|  | ||||
|     public function emulate(string $code, array $tokens): array { | ||||
|         $keywordString = $this->getKeywordString(); | ||||
|         foreach ($tokens as $i => $token) { | ||||
|             if ($token->id === T_STRING && strtolower($token->text) === $keywordString | ||||
|                     && $this->isKeywordContext($tokens, $i)) { | ||||
|                 $token->id = $this->getKeywordToken(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $tokens; | ||||
|     } | ||||
|  | ||||
|     /** @param Token[] $tokens */ | ||||
|     private function getPreviousNonSpaceToken(array $tokens, int $start): ?Token { | ||||
|         for ($i = $start - 1; $i >= 0; --$i) { | ||||
|             if ($tokens[$i]->id === T_WHITESPACE) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             return $tokens[$i]; | ||||
|         } | ||||
|  | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     public function reverseEmulate(string $code, array $tokens): array { | ||||
|         $keywordToken = $this->getKeywordToken(); | ||||
|         foreach ($tokens as $token) { | ||||
|             if ($token->id === $keywordToken) { | ||||
|                 $token->id = \T_STRING; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $tokens; | ||||
|     } | ||||
| } | ||||
| @@ -1,19 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Lexer\TokenEmulator; | ||||
|  | ||||
| use PhpParser\PhpVersion; | ||||
|  | ||||
| final class MatchTokenEmulator extends KeywordEmulator { | ||||
|     public function getPhpVersion(): PhpVersion { | ||||
|         return PhpVersion::fromComponents(8, 0); | ||||
|     } | ||||
|  | ||||
|     public function getKeywordString(): string { | ||||
|         return 'match'; | ||||
|     } | ||||
|  | ||||
|     public function getKeywordToken(): int { | ||||
|         return \T_MATCH; | ||||
|     } | ||||
| } | ||||
| @@ -1,60 +0,0 @@ | ||||
| <?php declare(strict_types=1); | ||||
|  | ||||
| namespace PhpParser\Lexer\TokenEmulator; | ||||
|  | ||||
| use PhpParser\PhpVersion; | ||||
| use PhpParser\Token; | ||||
|  | ||||
| final class NullsafeTokenEmulator extends TokenEmulator { | ||||
|     public function getPhpVersion(): PhpVersion { | ||||
|         return PhpVersion::fromComponents(8, 0); | ||||
|     } | ||||
|  | ||||
|     public function isEmulationNeeded(string $code): bool { | ||||
|         return strpos($code, '?->') !== 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 | ||||
|         for ($i = 0, $c = count($tokens); $i < $c; ++$i) { | ||||
|             $token = $tokens[$i]; | ||||
|             if ($token->text === '?' && isset($tokens[$i + 1]) && $tokens[$i + 1]->id === \T_OBJECT_OPERATOR) { | ||||
|                 array_splice($tokens, $i, 2, [ | ||||
|                     new Token(\T_NULLSAFE_OBJECT_OPERATOR, '?->', $token->line, $token->pos), | ||||
|                 ]); | ||||
|                 $c--; | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             // Handle ?-> inside encapsed string. | ||||
|             if ($token->id === \T_ENCAPSED_AND_WHITESPACE && isset($tokens[$i - 1]) | ||||
|                 && $tokens[$i - 1]->id === \T_VARIABLE | ||||
|                 && preg_match('/^\?->([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)/', $token->text, $matches) | ||||
|             ) { | ||||
|                 $replacement = [ | ||||
|                     new Token(\T_NULLSAFE_OBJECT_OPERATOR, '?->', $token->line, $token->pos), | ||||
|                     new Token(\T_STRING, $matches[1], $token->line, $token->pos + 3), | ||||
|                 ]; | ||||
|                 $matchLen = \strlen($matches[0]); | ||||
|                 if ($matchLen !== \strlen($token->text)) { | ||||
|                     $replacement[] = new Token( | ||||
|                         \T_ENCAPSED_AND_WHITESPACE, | ||||
|                         \substr($token->text, $matchLen), | ||||
|                         $token->line, $token->pos + $matchLen | ||||
|                     ); | ||||
|                 } | ||||
|                 array_splice($tokens, $i, 1, $replacement); | ||||
|                 $c += \count($replacement) - 1; | ||||
|                 continue; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $tokens; | ||||
|     } | ||||
|  | ||||
|     public function reverseEmulate(string $code, array $tokens): array { | ||||
|         // ?-> was not valid code previously, don't bother. | ||||
|         return $tokens; | ||||
|     } | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user