Updated Rector to commit 48228edf4647336d860ab24af7d4c62ea06c75a1

48228edf46 [config] include bootstrap files of extensions, to let rector know about types as well (#3380)
This commit is contained in:
Tomas Votruba 2023-02-14 15:08:14 +00:00
parent fc230fdbc6
commit bb73357927
37 changed files with 2159 additions and 52 deletions

View File

@ -0,0 +1,51 @@
<?php
declare (strict_types=1);
namespace Rector\NodeTypeResolver\DependencyInjection;
use PHPStan\ExtensionInstaller\GeneratedConfig;
use Rector\Core\Exception\ShouldNotHappenException;
use ReflectionClass;
/**
* @see \Rector\Tests\NodeTypeResolver\DependencyInjection\PHPStanExtensionsConfigResolverTest
*/
final class PHPStanExtensionsConfigResolver
{
/**
* @var string[]
*/
private $cachedExtensionConfigFiles = [];
/**
* @return string[]
*/
public function resolve() : array
{
// same logic as in PHPStan for extension installed - https://github.com/phpstan/phpstan-src/blob/5956ec4f6cd09c8d7db9466ed4e7f25706f37a43/src/Command/CommandHelper.php#L195-L222
if (!\class_exists(GeneratedConfig::class)) {
return [];
}
if ($this->cachedExtensionConfigFiles !== []) {
return $this->cachedExtensionConfigFiles;
}
$reflectionClass = new ReflectionClass(GeneratedConfig::class);
$generatedConfigClassFileName = $reflectionClass->getFileName();
if ($generatedConfigClassFileName === \false) {
throw new ShouldNotHappenException();
}
$generatedConfigDirectory = \dirname($generatedConfigClassFileName);
$extensionConfigFiles = [];
foreach (GeneratedConfig::EXTENSIONS as $extension) {
$fileNames = $extension['extra']['includes'] ?? [];
foreach ($fileNames as $fileName) {
$configFilePath = $generatedConfigDirectory . '/' . $extension['relative_install_path'] . '/' . $fileName;
$absoluteConfigFilePath = \realpath($configFilePath);
if (!\is_string($absoluteConfigFilePath)) {
continue;
}
$extensionConfigFiles[] = $absoluteConfigFilePath;
}
}
$this->cachedExtensionConfigFiles = $extensionConfigFiles;
return $extensionConfigFiles;
}
}

View File

@ -9,16 +9,13 @@ use PHPStan\Analyser\ScopeFactory;
use PHPStan\Dependency\DependencyResolver;
use PHPStan\DependencyInjection\Container;
use PHPStan\DependencyInjection\ContainerFactory;
use PHPStan\ExtensionInstaller\GeneratedConfig;
use PHPStan\File\FileHelper;
use PHPStan\Parser\Parser;
use PHPStan\PhpDoc\TypeNodeResolver;
use PHPStan\Reflection\ReflectionProvider;
use Rector\Core\Configuration\Option;
use Rector\Core\Configuration\Parameter\ParameterProvider;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocatorProvider\DynamicSourceLocatorProvider;
use ReflectionClass;
/**
* Factory so Symfony app can use services from PHPStan container
*/
@ -29,7 +26,7 @@ final class PHPStanServicesFactory
* @var \PHPStan\DependencyInjection\Container
*/
private $container;
public function __construct(ParameterProvider $parameterProvider)
public function __construct(ParameterProvider $parameterProvider, \Rector\NodeTypeResolver\DependencyInjection\PHPStanExtensionsConfigResolver $phpStanExtensionsConfigResolver)
{
$containerFactory = new ContainerFactory(\getcwd());
$additionalConfigFiles = [];
@ -39,7 +36,7 @@ final class PHPStanServicesFactory
$additionalConfigFiles[] = __DIR__ . '/../../../config/phpstan/static-reflection.neon';
$additionalConfigFiles[] = __DIR__ . '/../../../config/phpstan/better-infer.neon';
$additionalConfigFiles[] = __DIR__ . '/../../../config/phpstan/parser.neon';
$extensionConfigFiles = $this->resolveExtensionConfigs();
$extensionConfigFiles = $phpStanExtensionsConfigResolver->resolve();
$additionalConfigFiles = \array_merge($additionalConfigFiles, $extensionConfigFiles);
$existingAdditionalConfigFiles = \array_filter($additionalConfigFiles, 'file_exists');
$this->container = $containerFactory->create(\sys_get_temp_dir(), $existingAdditionalConfigFiles, []);
@ -107,32 +104,4 @@ final class PHPStanServicesFactory
{
return $this->container->getByType(DynamicSourceLocatorProvider::class);
}
/**
* @return string[]
*/
private function resolveExtensionConfigs() : array
{
// same logic as in PHPStan for extension installed - https://github.com/phpstan/phpstan-src/blob/5956ec4f6cd09c8d7db9466ed4e7f25706f37a43/src/Command/CommandHelper.php#L195-L222
if (!\class_exists(GeneratedConfig::class)) {
return [];
}
$reflectionClass = new ReflectionClass(GeneratedConfig::class);
$generatedConfigClassFileName = $reflectionClass->getFileName();
if ($generatedConfigClassFileName === \false) {
throw new ShouldNotHappenException();
}
$generatedConfigDirectory = \dirname($generatedConfigClassFileName);
$extensionConfigFiles = [];
foreach (GeneratedConfig::EXTENSIONS as $extension) {
$fileNames = $extension['extra']['includes'] ?? [];
foreach ($fileNames as $fileName) {
$configFilePath = $generatedConfigDirectory . '/' . $extension['relative_install_path'] . '/' . $fileName;
if (!\file_exists($configFilePath)) {
continue;
}
$extensionConfigFiles[] = $configFilePath;
}
}
return $extensionConfigFiles;
}
}

View File

@ -70,6 +70,7 @@ abstract class AbstractRectorTestCase extends \Rector\Testing\PHPUnit\AbstractTe
/** @var BootstrapFilesIncluder $bootstrapFilesIncluder */
$bootstrapFilesIncluder = $this->getService(BootstrapFilesIncluder::class);
$bootstrapFilesIncluder->includeBootstrapFiles();
$bootstrapFilesIncluder->includePHPStanExtensionsBoostrapFiles();
}
protected function tearDown() : void
{

View File

@ -19,12 +19,12 @@ final class VersionResolver
* @api
* @var string
*/
public const PACKAGE_VERSION = 'dffddb244ffe016e94446f00a1ac61daac900ca6';
public const PACKAGE_VERSION = '48228edf4647336d860ab24af7d4c62ea06c75a1';
/**
* @api
* @var string
*/
public const RELEASE_DATE = '2023-02-14 20:38:04';
public const RELEASE_DATE = '2023-02-14 15:03:31';
/**
* @var int
*/

View File

@ -3,14 +3,19 @@
declare (strict_types=1);
namespace Rector\Core\Autoloading;
use RectorPrefix202302\Nette\Neon\Neon;
use Rector\Core\Configuration\Option;
use Rector\Core\Configuration\Parameter\ParameterProvider;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\NodeTypeResolver\DependencyInjection\PHPStanExtensionsConfigResolver;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use SplFileInfo;
use Throwable;
use RectorPrefix202302\Webmozart\Assert\Assert;
/**
* @see \Rector\Core\Tests\Autoloading\BootstrapFilesIncluderTest
*/
final class BootstrapFilesIncluder
{
/**
@ -18,9 +23,23 @@ final class BootstrapFilesIncluder
* @var \Rector\Core\Configuration\Parameter\ParameterProvider
*/
private $parameterProvider;
public function __construct(ParameterProvider $parameterProvider)
/**
* @readonly
* @var \Rector\NodeTypeResolver\DependencyInjection\PHPStanExtensionsConfigResolver
*/
private $phpStanExtensionsConfigResolver;
public function __construct(ParameterProvider $parameterProvider, PHPStanExtensionsConfigResolver $phpStanExtensionsConfigResolver)
{
$this->parameterProvider = $parameterProvider;
$this->phpStanExtensionsConfigResolver = $phpStanExtensionsConfigResolver;
}
public function includePHPStanExtensionsBoostrapFiles() : void
{
$extensionConfigFiles = $this->phpStanExtensionsConfigResolver->resolve();
$absoluteBootstrapFilePaths = $this->resolveAbsoluteBootstrapFilePaths($extensionConfigFiles);
foreach ($absoluteBootstrapFilePaths as $absoluteBootstrapFilePath) {
$this->tryRequireFile($absoluteBootstrapFilePath);
}
}
/**
* Inspired by
@ -35,13 +54,42 @@ final class BootstrapFilesIncluder
if (!\is_file($bootstrapFile)) {
throw new ShouldNotHappenException(\sprintf('Bootstrap file "%s" does not exist.', $bootstrapFile));
}
try {
require_once $bootstrapFile;
} catch (Throwable $throwable) {
$errorMessage = \sprintf('"%s" thrown in "%s" on line %d while loading bootstrap file %s: %s', \get_class($throwable), $throwable->getFile(), $throwable->getLine(), $bootstrapFile, $throwable->getMessage());
throw new ShouldNotHappenException($errorMessage, $throwable->getCode(), $throwable);
$this->tryRequireFile($bootstrapFile);
}
$this->requireRectorStubs();
}
/**
* @param string[] $extensionConfigFiles
* @return string[]
*/
private function resolveAbsoluteBootstrapFilePaths(array $extensionConfigFiles) : array
{
$absoluteBootstrapFilePaths = [];
foreach ($extensionConfigFiles as $extensionConfigFile) {
$extensionConfigContents = Neon::decodeFile($extensionConfigFile);
$configDirectory = \dirname($extensionConfigFile);
$bootstrapFiles = $extensionConfigContents['parameters']['bootstrapFiles'] ?? [];
foreach ($bootstrapFiles as $bootstrapFile) {
$absoluteBootstrapFilePath = \realpath($configDirectory . '/' . $bootstrapFile);
if (!\is_string($absoluteBootstrapFilePath)) {
continue;
}
$absoluteBootstrapFilePaths[] = $absoluteBootstrapFilePath;
}
}
return $absoluteBootstrapFilePaths;
}
private function tryRequireFile(string $bootstrapFile) : void
{
try {
require_once $bootstrapFile;
} catch (Throwable $throwable) {
$errorMessage = \sprintf('"%s" thrown in "%s" on line %d while loading bootstrap file %s: %s', \get_class($throwable), $throwable->getFile(), $throwable->getLine(), $bootstrapFile, $throwable->getMessage());
throw new ShouldNotHappenException($errorMessage, $throwable->getCode(), $throwable);
}
}
private function requireRectorStubs() : void
{
$stubsRectorDirectory = \realpath(__DIR__ . '/../../stubs-rector');
if ($stubsRectorDirectory === \false) {
return;

View File

@ -22,6 +22,7 @@ final class RectorContainerFactory
/** @var BootstrapFilesIncluder $bootstrapFilesIncluder */
$bootstrapFilesIncluder = $container->get(BootstrapFilesIncluder::class);
$bootstrapFilesIncluder->includeBootstrapFiles();
$bootstrapFilesIncluder->includePHPStanExtensionsBoostrapFiles();
return $container;
}
/**

2
vendor/autoload.php vendored
View File

@ -22,4 +22,4 @@ if (PHP_VERSION_ID < 50600) {
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInitea4756fe54e6b2eb6dba86dfa54e1a9f::getLoader();
return ComposerAutoloaderInite0225503d6547de35721ddc00c747139::getLoader();

95
vendor/bin/neon-lint vendored Normal file
View File

@ -0,0 +1,95 @@
#!/usr/bin/env php
<?php
/**
* Proxy PHP file generated by Composer
*
* This file includes the referenced bin path (../nette/neon/bin/neon-lint)
* using a stream wrapper to prevent the shebang from being output on PHP<8
*
* @generated
*/
namespace RectorPrefix202302\Composer;
$GLOBALS['_composer_bin_dir'] = __DIR__;
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..' . '/autoload.php';
if (\PHP_VERSION_ID < 80000) {
if (!\class_exists('RectorPrefix202302\\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', 'RectorPrefix202302\\Composer\\BinProxyWrapper')) {
include "phpvfscomposer://" . __DIR__ . '/..' . '/nette/neon/bin/neon-lint';
exit(0);
}
}
include __DIR__ . '/..' . '/nette/neon/bin/neon-lint';

View File

@ -451,6 +451,25 @@ return array(
'RectorPrefix202302\\Nette\\Localization\\ITranslator' => $vendorDir . '/nette/utils/src/compatibility.php',
'RectorPrefix202302\\Nette\\Localization\\Translator' => $vendorDir . '/nette/utils/src/Translator.php',
'RectorPrefix202302\\Nette\\MemberAccessException' => $vendorDir . '/nette/utils/src/exceptions.php',
'RectorPrefix202302\\Nette\\Neon\\Decoder' => $vendorDir . '/nette/neon/src/Neon/Decoder.php',
'RectorPrefix202302\\Nette\\Neon\\Encoder' => $vendorDir . '/nette/neon/src/Neon/Encoder.php',
'RectorPrefix202302\\Nette\\Neon\\Entity' => $vendorDir . '/nette/neon/src/Neon/Entity.php',
'RectorPrefix202302\\Nette\\Neon\\Exception' => $vendorDir . '/nette/neon/src/Neon/Exception.php',
'RectorPrefix202302\\Nette\\Neon\\Lexer' => $vendorDir . '/nette/neon/src/Neon/Lexer.php',
'RectorPrefix202302\\Nette\\Neon\\Neon' => $vendorDir . '/nette/neon/src/Neon/Neon.php',
'RectorPrefix202302\\Nette\\Neon\\Node' => $vendorDir . '/nette/neon/src/Neon/Node.php',
'RectorPrefix202302\\Nette\\Neon\\Node\\ArrayItemNode' => $vendorDir . '/nette/neon/src/Neon/Node/ArrayItemNode.php',
'RectorPrefix202302\\Nette\\Neon\\Node\\ArrayNode' => $vendorDir . '/nette/neon/src/Neon/Node/ArrayNode.php',
'RectorPrefix202302\\Nette\\Neon\\Node\\BlockArrayNode' => $vendorDir . '/nette/neon/src/Neon/Node/BlockArrayNode.php',
'RectorPrefix202302\\Nette\\Neon\\Node\\EntityChainNode' => $vendorDir . '/nette/neon/src/Neon/Node/EntityChainNode.php',
'RectorPrefix202302\\Nette\\Neon\\Node\\EntityNode' => $vendorDir . '/nette/neon/src/Neon/Node/EntityNode.php',
'RectorPrefix202302\\Nette\\Neon\\Node\\InlineArrayNode' => $vendorDir . '/nette/neon/src/Neon/Node/InlineArrayNode.php',
'RectorPrefix202302\\Nette\\Neon\\Node\\LiteralNode' => $vendorDir . '/nette/neon/src/Neon/Node/LiteralNode.php',
'RectorPrefix202302\\Nette\\Neon\\Node\\StringNode' => $vendorDir . '/nette/neon/src/Neon/Node/StringNode.php',
'RectorPrefix202302\\Nette\\Neon\\Parser' => $vendorDir . '/nette/neon/src/Neon/Parser.php',
'RectorPrefix202302\\Nette\\Neon\\Token' => $vendorDir . '/nette/neon/src/Neon/Token.php',
'RectorPrefix202302\\Nette\\Neon\\TokenStream' => $vendorDir . '/nette/neon/src/Neon/TokenStream.php',
'RectorPrefix202302\\Nette\\Neon\\Traverser' => $vendorDir . '/nette/neon/src/Neon/Traverser.php',
'RectorPrefix202302\\Nette\\NotImplementedException' => $vendorDir . '/nette/utils/src/exceptions.php',
'RectorPrefix202302\\Nette\\NotSupportedException' => $vendorDir . '/nette/utils/src/exceptions.php',
'RectorPrefix202302\\Nette\\OutOfRangeException' => $vendorDir . '/nette/utils/src/exceptions.php',
@ -1946,6 +1965,7 @@ return array(
'Rector\\NodeRemoval\\NodeRemover' => $baseDir . '/packages/NodeRemoval/NodeRemover.php',
'Rector\\NodeTypeResolver\\Contract\\NodeTypeResolverInterface' => $baseDir . '/packages/NodeTypeResolver/Contract/NodeTypeResolverInterface.php',
'Rector\\NodeTypeResolver\\Contract\\SourceLocatorProviderInterface' => $baseDir . '/packages/NodeTypeResolver/Contract/SourceLocatorProviderInterface.php',
'Rector\\NodeTypeResolver\\DependencyInjection\\PHPStanExtensionsConfigResolver' => $baseDir . '/packages/NodeTypeResolver/DependencyInjection/PHPStanExtensionsConfigResolver.php',
'Rector\\NodeTypeResolver\\DependencyInjection\\PHPStanServicesFactory' => $baseDir . '/packages/NodeTypeResolver/DependencyInjection/PHPStanServicesFactory.php',
'Rector\\NodeTypeResolver\\MethodParameterTypeResolver' => $baseDir . '/packages/NodeTypeResolver/MethodParameterTypeResolver.php',
'Rector\\NodeTypeResolver\\NodeScopeAndMetadataDecorator' => $baseDir . '/packages/NodeTypeResolver/NodeScopeAndMetadataDecorator.php',

View File

@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
class ComposerAutoloaderInitea4756fe54e6b2eb6dba86dfa54e1a9f
class ComposerAutoloaderInite0225503d6547de35721ddc00c747139
{
private static $loader;
@ -22,17 +22,17 @@ class ComposerAutoloaderInitea4756fe54e6b2eb6dba86dfa54e1a9f
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInitea4756fe54e6b2eb6dba86dfa54e1a9f', 'loadClassLoader'), true, true);
spl_autoload_register(array('ComposerAutoloaderInite0225503d6547de35721ddc00c747139', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInitea4756fe54e6b2eb6dba86dfa54e1a9f', 'loadClassLoader'));
spl_autoload_unregister(array('ComposerAutoloaderInite0225503d6547de35721ddc00c747139', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInitea4756fe54e6b2eb6dba86dfa54e1a9f::getInitializer($loader));
call_user_func(\Composer\Autoload\ComposerStaticInite0225503d6547de35721ddc00c747139::getInitializer($loader));
$loader->setClassMapAuthoritative(true);
$loader->register(true);
$filesToLoad = \Composer\Autoload\ComposerStaticInitea4756fe54e6b2eb6dba86dfa54e1a9f::$files;
$filesToLoad = \Composer\Autoload\ComposerStaticInite0225503d6547de35721ddc00c747139::$files;
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;

View File

@ -4,7 +4,7 @@
namespace Composer\Autoload;
class ComposerStaticInitea4756fe54e6b2eb6dba86dfa54e1a9f
class ComposerStaticInite0225503d6547de35721ddc00c747139
{
public static $files = array (
'ad155f8f1cf0d418fe49e248db8c661b' => __DIR__ . '/..' . '/react/promise/src/functions_include.php',
@ -698,6 +698,25 @@ class ComposerStaticInitea4756fe54e6b2eb6dba86dfa54e1a9f
'RectorPrefix202302\\Nette\\Localization\\ITranslator' => __DIR__ . '/..' . '/nette/utils/src/compatibility.php',
'RectorPrefix202302\\Nette\\Localization\\Translator' => __DIR__ . '/..' . '/nette/utils/src/Translator.php',
'RectorPrefix202302\\Nette\\MemberAccessException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php',
'RectorPrefix202302\\Nette\\Neon\\Decoder' => __DIR__ . '/..' . '/nette/neon/src/Neon/Decoder.php',
'RectorPrefix202302\\Nette\\Neon\\Encoder' => __DIR__ . '/..' . '/nette/neon/src/Neon/Encoder.php',
'RectorPrefix202302\\Nette\\Neon\\Entity' => __DIR__ . '/..' . '/nette/neon/src/Neon/Entity.php',
'RectorPrefix202302\\Nette\\Neon\\Exception' => __DIR__ . '/..' . '/nette/neon/src/Neon/Exception.php',
'RectorPrefix202302\\Nette\\Neon\\Lexer' => __DIR__ . '/..' . '/nette/neon/src/Neon/Lexer.php',
'RectorPrefix202302\\Nette\\Neon\\Neon' => __DIR__ . '/..' . '/nette/neon/src/Neon/Neon.php',
'RectorPrefix202302\\Nette\\Neon\\Node' => __DIR__ . '/..' . '/nette/neon/src/Neon/Node.php',
'RectorPrefix202302\\Nette\\Neon\\Node\\ArrayItemNode' => __DIR__ . '/..' . '/nette/neon/src/Neon/Node/ArrayItemNode.php',
'RectorPrefix202302\\Nette\\Neon\\Node\\ArrayNode' => __DIR__ . '/..' . '/nette/neon/src/Neon/Node/ArrayNode.php',
'RectorPrefix202302\\Nette\\Neon\\Node\\BlockArrayNode' => __DIR__ . '/..' . '/nette/neon/src/Neon/Node/BlockArrayNode.php',
'RectorPrefix202302\\Nette\\Neon\\Node\\EntityChainNode' => __DIR__ . '/..' . '/nette/neon/src/Neon/Node/EntityChainNode.php',
'RectorPrefix202302\\Nette\\Neon\\Node\\EntityNode' => __DIR__ . '/..' . '/nette/neon/src/Neon/Node/EntityNode.php',
'RectorPrefix202302\\Nette\\Neon\\Node\\InlineArrayNode' => __DIR__ . '/..' . '/nette/neon/src/Neon/Node/InlineArrayNode.php',
'RectorPrefix202302\\Nette\\Neon\\Node\\LiteralNode' => __DIR__ . '/..' . '/nette/neon/src/Neon/Node/LiteralNode.php',
'RectorPrefix202302\\Nette\\Neon\\Node\\StringNode' => __DIR__ . '/..' . '/nette/neon/src/Neon/Node/StringNode.php',
'RectorPrefix202302\\Nette\\Neon\\Parser' => __DIR__ . '/..' . '/nette/neon/src/Neon/Parser.php',
'RectorPrefix202302\\Nette\\Neon\\Token' => __DIR__ . '/..' . '/nette/neon/src/Neon/Token.php',
'RectorPrefix202302\\Nette\\Neon\\TokenStream' => __DIR__ . '/..' . '/nette/neon/src/Neon/TokenStream.php',
'RectorPrefix202302\\Nette\\Neon\\Traverser' => __DIR__ . '/..' . '/nette/neon/src/Neon/Traverser.php',
'RectorPrefix202302\\Nette\\NotImplementedException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php',
'RectorPrefix202302\\Nette\\NotSupportedException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php',
'RectorPrefix202302\\Nette\\OutOfRangeException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php',
@ -2193,6 +2212,7 @@ class ComposerStaticInitea4756fe54e6b2eb6dba86dfa54e1a9f
'Rector\\NodeRemoval\\NodeRemover' => __DIR__ . '/../..' . '/packages/NodeRemoval/NodeRemover.php',
'Rector\\NodeTypeResolver\\Contract\\NodeTypeResolverInterface' => __DIR__ . '/../..' . '/packages/NodeTypeResolver/Contract/NodeTypeResolverInterface.php',
'Rector\\NodeTypeResolver\\Contract\\SourceLocatorProviderInterface' => __DIR__ . '/../..' . '/packages/NodeTypeResolver/Contract/SourceLocatorProviderInterface.php',
'Rector\\NodeTypeResolver\\DependencyInjection\\PHPStanExtensionsConfigResolver' => __DIR__ . '/../..' . '/packages/NodeTypeResolver/DependencyInjection/PHPStanExtensionsConfigResolver.php',
'Rector\\NodeTypeResolver\\DependencyInjection\\PHPStanServicesFactory' => __DIR__ . '/../..' . '/packages/NodeTypeResolver/DependencyInjection/PHPStanServicesFactory.php',
'Rector\\NodeTypeResolver\\MethodParameterTypeResolver' => __DIR__ . '/../..' . '/packages/NodeTypeResolver/MethodParameterTypeResolver.php',
'Rector\\NodeTypeResolver\\NodeScopeAndMetadataDecorator' => __DIR__ . '/../..' . '/packages/NodeTypeResolver/NodeScopeAndMetadataDecorator.php',
@ -3101,9 +3121,9 @@ class ComposerStaticInitea4756fe54e6b2eb6dba86dfa54e1a9f
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInitea4756fe54e6b2eb6dba86dfa54e1a9f::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitea4756fe54e6b2eb6dba86dfa54e1a9f::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInitea4756fe54e6b2eb6dba86dfa54e1a9f::$classMap;
$loader->prefixLengthsPsr4 = ComposerStaticInite0225503d6547de35721ddc00c747139::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInite0225503d6547de35721ddc00c747139::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInite0225503d6547de35721ddc00c747139::$classMap;
}, null, ClassLoader::class);
}

View File

@ -502,6 +502,77 @@
],
"install-path": "..\/fidry\/cpu-core-counter"
},
{
"name": "nette\/neon",
"version": "v3.4.0",
"version_normalized": "3.4.0.0",
"source": {
"type": "git",
"url": "https:\/\/github.com\/nette\/neon.git",
"reference": "372d945c156ee7f35c953339fb164538339e6283"
},
"dist": {
"type": "zip",
"url": "https:\/\/api.github.com\/repos\/nette\/neon\/zipball\/372d945c156ee7f35c953339fb164538339e6283",
"reference": "372d945c156ee7f35c953339fb164538339e6283",
"shasum": ""
},
"require": {
"ext-json": "*",
"php": ">=8.0 <8.3"
},
"require-dev": {
"nette\/tester": "^2.4",
"phpstan\/phpstan": "^1.0",
"tracy\/tracy": "^2.7"
},
"time": "2023-01-13T03:08:29+00:00",
"bin": [
"bin\/neon-lint"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.4-dev"
}
},
"installation-source": "dist",
"autoload": {
"classmap": [
"src\/"
]
},
"notification-url": "https:\/\/packagist.org\/downloads\/",
"license": [
"BSD-3-Clause",
"GPL-2.0-only",
"GPL-3.0-only"
],
"authors": [
{
"name": "David Grudl",
"homepage": "https:\/\/davidgrudl.com"
},
{
"name": "Nette Community",
"homepage": "https:\/\/nette.org\/contributors"
}
],
"description": "\ud83c\udf78 Nette NEON: encodes and decodes NEON file format.",
"homepage": "https:\/\/ne-on.org",
"keywords": [
"export",
"import",
"neon",
"nette",
"yaml"
],
"support": {
"issues": "https:\/\/github.com\/nette\/neon\/issues",
"source": "https:\/\/github.com\/nette\/neon\/tree\/v3.4.0"
},
"install-path": "..\/nette\/neon"
},
{
"name": "nette\/utils",
"version": "v3.2.9",

File diff suppressed because one or more lines are too long

72
vendor/nette/neon/bin/neon-lint vendored Normal file
View File

@ -0,0 +1,72 @@
#!/usr/bin/env php
<?php
declare (strict_types=1);
namespace RectorPrefix202302;
if (!(\is_file($file = __DIR__ . '/../vendor/autoload.php') && (include $file)) && !(\is_file($file = __DIR__ . '/../../../autoload.php') && (include $file))) {
\fwrite(\STDERR, "Install packages using Composer.\n");
exit(1);
}
if (\function_exists('pcntl_signal')) {
\pcntl_signal(\SIGINT, function () : void {
\pcntl_signal(\SIGINT, \SIG_DFL);
echo "Terminated\n";
exit(1);
});
} elseif (\function_exists('sapi_windows_set_ctrl_handler')) {
\sapi_windows_set_ctrl_handler(function () {
echo "Terminated\n";
exit(1);
});
}
\set_time_limit(0);
echo '
NEON linter
-----------
';
if ($argc < 2) {
echo "Usage: neon-lint <path>\n";
exit(1);
}
$ok = scanPath($argv[1]);
exit($ok ? 0 : 1);
function scanPath(string $path) : bool
{
echo "Scanning {$path}\n";
$it = new \RecursiveDirectoryIterator($path);
$it = new \RecursiveIteratorIterator($it, \RecursiveIteratorIterator::LEAVES_ONLY);
$it = new \RegexIterator($it, '~\\.neon$~');
$counter = 0;
$success = \true;
foreach ($it as $file) {
echo \str_pad(\str_repeat('.', $counter++ % 40), 40), "\r";
$success = lintFile((string) $file) && $success;
}
echo \str_pad('', 40), "\r";
echo "Done.\n";
return $success;
}
function lintFile(string $file) : bool
{
\set_error_handler(function (int $severity, string $message) use($file) {
if ($severity === \E_USER_DEPRECATED) {
\fwrite(\STDERR, "[DEPRECATED] {$file} {$message}\n");
return null;
}
return \false;
});
$s = \file_get_contents($file);
if (\substr($s, 0, 3) === "") {
\fwrite(\STDERR, "[WARNING] {$file} contains BOM\n");
$contents = \substr($s, 3);
}
try {
Nette\Neon\Neon::decode($s);
return \true;
} catch (Nette\Neon\Exception $e) {
\fwrite(\STDERR, "[ERROR] {$file} {$e->getMessage()}\n");
} finally {
\restore_error_handler();
}
return \false;
}

54
vendor/nette/neon/composer.json vendored Normal file
View File

@ -0,0 +1,54 @@
{
"name": "nette\/neon",
"description": "\ud83c\udf78 Nette NEON: encodes and decodes NEON file format.",
"keywords": [
"nette",
"neon",
"import",
"export",
"yaml"
],
"homepage": "https:\/\/ne-on.org",
"license": [
"BSD-3-Clause",
"GPL-2.0-only",
"GPL-3.0-only"
],
"authors": [
{
"name": "David Grudl",
"homepage": "https:\/\/davidgrudl.com"
},
{
"name": "Nette Community",
"homepage": "https:\/\/nette.org\/contributors"
}
],
"require": {
"php": ">=8.0 <8.3",
"ext-json": "*"
},
"require-dev": {
"nette\/tester": "^2.4",
"tracy\/tracy": "^2.7",
"phpstan\/phpstan": "^1.0"
},
"autoload": {
"classmap": [
"src\/"
]
},
"minimum-stability": "dev",
"bin": [
"bin\/neon-lint"
],
"scripts": {
"phpstan": "phpstan analyse",
"tester": "tester tests -s"
},
"extra": {
"branch-alias": {
"dev-master": "3.4-dev"
}
}
}

60
vendor/nette/neon/license.md vendored Normal file
View File

@ -0,0 +1,60 @@
Licenses
========
Good news! You may use Nette Framework under the terms of either
the New BSD License or the GNU General Public License (GPL) version 2 or 3.
The BSD License is recommended for most projects. It is easy to understand and it
places almost no restrictions on what you can do with the framework. If the GPL
fits better to your project, you can use the framework under this license.
You don't have to notify anyone which license you are using. You can freely
use Nette Framework in commercial projects as long as the copyright header
remains intact.
Please be advised that the name "Nette Framework" is a protected trademark and its
usage has some limitations. So please do not use word "Nette" in the name of your
project or top-level domain, and choose a name that stands on its own merits.
If your stuff is good, it will not take long to establish a reputation for yourselves.
New BSD License
---------------
Copyright (c) 2004, 2014 David Grudl (https://davidgrudl.com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of "Nette Framework" nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
This software is provided by the copyright holders and contributors "as is" and
any express or implied warranties, including, but not limited to, the implied
warranties of merchantability and fitness for a particular purpose are
disclaimed. In no event shall the copyright owner or contributors be liable for
any direct, indirect, incidental, special, exemplary, or consequential damages
(including, but not limited to, procurement of substitute goods or services;
loss of use, data, or profits; or business interruption) however caused and on
any theory of liability, whether in contract, strict liability, or tort
(including negligence or otherwise) arising in any way out of the use of this
software, even if advised of the possibility of such damage.
GNU General Public License
--------------------------
GPL licenses are very very long, so instead of including them here we offer
you URLs with full text:
- [GPL version 2](https://www.gnu.org/licenses/gpl-2.0.html)
- [GPL version 3](https://www.gnu.org/licenses/gpl-3.0.html)

41
vendor/nette/neon/phpstan-baseline.neon vendored Normal file
View File

@ -0,0 +1,41 @@
parameters:
ignoreErrors:
-
message: '#^Property Nette\\Neon\\Node\\EntityChainNode\:\:\$chain \(array\<Nette\\Neon\\Node\\EntityNode\>\) does not accept array\<Nette\\Neon\\Node\>\.$#'
count: 1
path: src/Neon/Encoder.php
-
message: '#^Unreachable statement \- code above always terminates\.$#'
count: 1
path: src/Neon/Node.php
-
message: '#^If condition is always true\.$#'
count: 1
path: src/Neon/Parser.php
-
message: '#^Left side of && is always true\.$#'
count: 1
path: src/Neon/Parser.php
-
message: '#^Parameter \#1 \$chain of class Nette\\Neon\\Node\\EntityChainNode constructor expects array\<Nette\\Neon\\Node\\EntityNode\>, array\<int, Nette\\Neon\\Node\> given\.$#'
count: 1
path: src/Neon/Parser.php
-
message: '#^Unreachable statement \- code above always terminates\.$#'
count: 1
path: src/Neon/Parser.php
-
message: '#^While loop condition is always false\.$#'
count: 2
path: src/Neon/Parser.php
-
message: '#^While loop condition is always true\.$#'
count: 1
path: src/Neon/Parser.php

490
vendor/nette/neon/readme.md vendored Normal file
View File

@ -0,0 +1,490 @@
[NEON](https://ne-on.org): Nette Object Notation
================================================
[![Downloads this Month](https://img.shields.io/packagist/dm/nette/neon.svg)](https://packagist.org/packages/nette/neon)
[![Tests](https://github.com/nette/neon/workflows/Tests/badge.svg?branch=master)](https://github.com/nette/neon/actions)
[![Coverage Status](https://coveralls.io/repos/github/nette/neon/badge.svg?branch=master)](https://coveralls.io/github/nette/neon?branch=master)
[![Latest Stable Version](https://poser.pugx.org/nette/neon/v/stable)](https://github.com/nette/neon/releases)
[![License](https://img.shields.io/badge/license-New%20BSD-blue.svg)](https://github.com/nette/neon/blob/master/license.md)
Introduction
============
NEON is a human-readable structured data format. In Nette, it is used for configuration files. It is also used for structured data such as settings, language translations, etc. [Try it on the sandbox](https://ne-on.org).
NEON stands for *Nette Object Notation*. It is less complex and ungainly than XML or JSON, but provides similar capabilities. It is very similar to YAML. The main advantage is that NEON has so-called [entities](#entities), thanks to which the configuration of DI services is so sexy. And allows tabs for indentation.
NEON is built from the ground up to be simple to use.
[Support Neon](https://github.com/sponsors/dg)
----------------------------------------------
Do you like NEON? Are you looking forward to the new features?
[![Buy me a coffee](https://files.nette.org/icons/donation-3.svg)](https://github.com/sponsors/dg)
Thank you!
Usage
=====
Install via Composer:
```
composer require nette/neon
```
It requires PHP version 8.0 up to 8.2. Documentation can be found on the [website](https://doc.nette.org/neon).
`Neon::encode()` returns `$value` converted to NEON. As the second parameter `$blockMode` you can pass true, which will create multiline output. The third parameter `$indentation` specifies the characters used for indentation (default is tab).
```php
use Nette\Neon\Neon;
$neon = Neon::encode($value); // Returns $value converted to NEON
$neon = Neon::encode($value, true); // Returns $value converted to multiline NEON
```
`Neon::decode()` converts given NEON to PHP value:
```php
$value = Neon::decode('hello: world'); // Returns an array ['hello' => 'world']
```
`Neon::decodeFile()` converts given NEON file to PHP value:
```php
$value = Neon::decodeFile('config.neon');
```
All methods throw `Nette\Neon\Exception` on error.
Integration
===========
- NetBeans (has built-in support)
- PhpStorm ([plugin](https://plugins.jetbrains.com/plugin/7060?pr))
- Visual Studio Code ([plugin](https://marketplace.visualstudio.com/items?itemName=Kasik96.latte))
- Sublime Text 3 ([plugin](https://github.com/FilipStryk/Nette-Latte-Neon-for-Sublime-Text-3))
- Sublime Text 2 ([plugin](https://github.com/Michal-Mikolas/Nette-package-for-Sublime-Text-2))
- [NEON for PHP](https://doc.nette.org/neon)
- [NEON for JavaScript](https://github.com/matej21/neon-js)
- [NEON for Python](https://github.com/paveldedik/neon-py).
You can check for syntax errors in Neon files using the `neon-lint` console command:
```shell
vendor/bin/neon-lint <path>
```
Syntax
======
A file written in NEON usually consists of a sequence or mapping.
Mappings
--------
Mapping is a set of key-value pairs, in PHP it would be called an associative array. Each pair is written as `key: value`, a space after `:` is required. The value can be anything: string, number, boolean, null, sequence, or other mapping.
```neon
street: 742 Evergreen Terrace
city: Springfield
country: USA
```
In PHP, the same structure would be written as:
```php
[ // PHP
'street' => '742 Evergreen Terrace',
'city' => 'Springfield',
'country' => 'USA',
]
```
This notation is called a block notation because all items are on a separate line and have the same indentation (none in this case). NEON also supports inline representation for mapping, which is enclosed in brackets, indentation plays no role, and the separator of each element is either a comma or a newline:
```neon
{street: 742 Evergreen Terrace, city: Springfield, country: USA}
```
This is the same written on multiple lines (indentation does not matter):
```neon
{
street: 742 Evergreen Terrace
city: Springfield, country: USA
}
```
Alternatively, `=` can be used instead of <code>: </code>, both in block and inline notation:
```neon
{street=742 Evergreen Terrace, city=Springfield, country=USA}
```
Sequences
---------
Sequences are indexed arrays in PHP. They are written as lines starting with the hyphen `-` followed by a space. Again, the value can be anything: string, number, boolean, null, sequence, or other mapping.
```neon
- Cat
- Dog
- Goldfish
```
In PHP, the same structure would be written as:
```php
[ // PHP
'Cat',
'Dog',
'Goldfish',
]
```
This notation is called a block notation because all items are on a separate line and have the same indentation (none in this case). NEON also supports inline representation for sequences, which is enclosed in brackets, indentation plays no role, and the separator of each element is either a comma or a newline:
```neon
[Cat, Dog, Goldfish]
```
This is the same written on multiple lines (indentation does not matter):
```neon
[
Cat, Dog
Goldfish
]
```
Hyphens cannot be used in an inline representation.
Combination
-----------
Values of mappings and sequences may be other mappings and sequences. The level of indentation plays a major role. In the following example, the hyphen used to indicate sequence items has a greater indent than the `pets` key, so the items become the value of the first line:
```neon
pets:
- Cat
- Dog
cars:
- Volvo
- Skoda
```
In PHP, the same structure would be written as:
```php
[ // PHP
'pets' => [
'Cat',
'Dog',
],
'cars' => [
'Volvo',
'Skoda',
],
]
```
It is possible to combine block and inline notation:
```neon
pets: [Cat, Dog]
cars: [
Volvo,
Skoda,
]
```
Block notation can no longer be used inside an inline notation, this does not work:
```neon
item: [
pets:
- Cat # THIS IS NOT POSSIBLE!!!
- Dog
]
```
Because PHP uses the same structure for mapping and sequences, that is, arrays, both can be merged. The indentation is the same this time:
```neon
- Cat
street: 742 Evergreen Terrace
- Goldfish
```
In PHP, the same structure would be written as:
```php
[ // PHP
'Cat',
'street' => '742 Evergreen Terrace',
'Goldfish',
]
```
Strings
-------
Strings in NEON can be enclosed in single or double quotes. But as you can see, they can also be without quotes.
```neon
- A unquoted string in NEON
- 'A singled-quoted string in NEON'
- "A double-quoted string in NEON"
```
If the string contains characters that can be confused with NEON syntax (hyphens, colons, etc.), it must be enclosed in quotation marks. We recommend using single quotes because they do not use escaping. If you need to enclose a quotation mark in such a string, double it:
```neon
'A single quote '' inside a single-quoted string'
```
Double quotes allow you to use escape sequences to write special characters using backslashes `\`. All escape sequences as in the JSON format are supported, plus `\_`, which is an non-breaking space, ie `\u00A0`.
```neon
- "\t \n \r \f \b \" \\ \/ \_"
- "\u00A9"
```
There are other cases where you need to enclose strings in quotation marks:
- they begin or end with spaces
- look like numbers, booleans, or null
- NEON would understand them as [dates](#dates)
Multiline strings
-----------------
A multiline string begins and ends with a triple quotation mark on separate lines. The indent of the first line is ignored for all lines:
```neon
'''
first line
second line
third line
'''
```
In PHP we would write the same as:
```php
"first line\n\tsecond line\nthird line" // PHP
```
Escaping sequences only work for strings enclosed in double quotes instead of apostrophes:
```neon
"""
Copyright \u00A9
"""
```
Numbers
-------
NEON understands numbers written in so-called scientific notation and also numbers in binary, octal and hexadecimal:
```neon
- 12 # an integer
- 12.3 # a float
- +1.2e-34 # an exponential number
- 0b11010 # binary number
- 0o666 # octal number
- 0x7A # hexa number
```
Nulls
-----
Null can be expressed in NEON by using `null` or by not specifying a value. Variants with a capital first or all uppercase letters are also allowed.
```neon
a: null
b:
```
Booleans
--------
Boolean values are expressed in NEON using `true` / `false` or `yes` / `no`. Variants with a capital first or all uppercase letters are also allowed.
```neon
[true, TRUE, True, false, yes, no]
```
Dates
-----
NEON uses the following formats to express data and automatically converts them to `DateTimeImmutable` objects:
```neon
- 2016-06-03 # date
- 2016-06-03 19:00:00 # date & time
- 2016-06-03 19:00:00.1234 # date & microtime
- 2016-06-03 19:00:00 +0200 # date & time & timezone
- 2016-06-03 19:00:00 +02:00 # date & time & timezone
```
Entities
--------
An entity is a structure that resembles a function call:
```neon
Column(type: int, nulls: yes)
```
In PHP, it is parsed as an object [Nette\Neon\Entity](https://api.nette.org/3.0/Nette/Neon/Entity.html):
```php
// PHP
new Nette\Neon\Entity('Column', ['type' => 'int', 'nulls' => true])
```
Entities can also be chained:
```neon
Column(type: int, nulls: yes) Field(id: 1)
```
Which is parsed in PHP as follows:
```php
// PHP
new Nette\Neon\Entity(Nette\Neon\Neon::Chain, [
new Nette\Neon\Entity('Column', ['type' => 'int', 'nulls' => true]),
new Nette\Neon\Entity('Field', ['id' => 1]),
])
```
Inside the parentheses, the rules for inline notation used for mapping and sequences apply, so it can be divided into several lines and it is not necessary to add commas:
```neon
Column(
type: int
nulls: yes
)
```
Comments
--------
Comments start with `#` and all of the following characters on the right are ignored:
```neon
# this line will be ignored by the interpreter
street: 742 Evergreen Terrace
city: Springfield # this is ignored too
country: USA
```
NEON versus JSON
================
JSON is a subset of NEON. Each JSON can therefore be parsed as NEON:
```neon
{
"php": {
"date.timezone": "Europe\/Prague",
"zlib.output_compression": true
},
"database": {
"driver": "mysql",
"username": "root",
"password": "beruska92"
},
"users": [
"Dave", "Kryten", "Rimmer"
]
}
```
What if we could omit quotes?
```neon
{
php: {
date.timezone: Europe/Prague,
zlib.output_compression: true
},
database: {
driver: mysql,
username: root,
password: beruska92
},
users: [
Dave, Kryten, Rimmer
]
}
```
How about braces and commas?
```neon
php:
date.timezone: Europe/Prague
zlib.output_compression: true
database:
driver: mysql
username: root
password: beruska92
users: [
Dave, Kryten, Rimmer
]
```
Are bullets more legible?
```neon
php:
date.timezone: Europe/Prague
zlib.output_compression: true
database:
driver: mysql
username: root
password: beruska92
users:
- Dave
- Kryten
- Rimmer
```
How about comments?
```neon
# my web application config
php:
date.timezone: Europe/Prague
zlib.output_compression: true # use gzip
database:
driver: mysql
username: root
password: beruska92
users:
- Dave
- Kryten
- Rimmer
```
You found NEON syntax!
If you like NEON, **[please make a donation now](https://github.com/sponsors/dg)**. Thank you!

32
vendor/nette/neon/src/Neon/Decoder.php vendored Normal file
View File

@ -0,0 +1,32 @@
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare (strict_types=1);
namespace RectorPrefix202302\Nette\Neon;
/**
* Parser for Nette Object Notation.
* @internal
*/
final class Decoder
{
/**
* Decodes a NEON string.
* @return mixed
*/
public function decode(string $input)
{
$node = $this->parseToNode($input);
return $node->toValue();
}
public function parseToNode(string $input) : Node
{
$lexer = new Lexer();
$parser = new Parser();
$tokens = $lexer->tokenize($input);
return $parser->parse($tokens);
}
}

86
vendor/nette/neon/src/Neon/Encoder.php vendored Normal file
View File

@ -0,0 +1,86 @@
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare (strict_types=1);
namespace RectorPrefix202302\Nette\Neon;
/**
* Converts value to NEON format.
* @internal
*/
final class Encoder
{
/** @deprecated */
public const BLOCK = \true;
/**
* @var bool
*/
public $blockMode = \false;
/**
* @var string
*/
public $indentation = "\t";
/**
* Returns the NEON representation of a value.
* @param mixed $val
*/
public function encode($val) : string
{
$node = $this->valueToNode($val, $this->blockMode);
return $node->toString();
}
/**
* @param mixed $val
*/
public function valueToNode($val, bool $blockMode = \false) : Node
{
if ($val instanceof \DateTimeInterface) {
return new Node\LiteralNode($val);
} elseif ($val instanceof Entity && $val->value === Neon::Chain) {
$node = new Node\EntityChainNode();
foreach ($val->attributes as $entity) {
$node->chain[] = $this->valueToNode($entity);
}
return $node;
} elseif ($val instanceof Entity) {
return new Node\EntityNode($this->valueToNode($val->value), $this->arrayToNodes($val->attributes));
} elseif (\is_object($val) || \is_array($val)) {
if ($blockMode) {
$node = new Node\BlockArrayNode();
} else {
$isList = \is_array($val) && (!$val || \array_keys($val) === \range(0, \count($val) - 1));
$node = new Node\InlineArrayNode($isList ? '[' : '{');
}
$node->items = $this->arrayToNodes($val, $blockMode);
return $node;
} elseif (\is_string($val) && Lexer::requiresDelimiters($val)) {
return new Node\StringNode($val);
} else {
return new Node\LiteralNode($val);
}
}
/** @return Node\ArrayItemNode[]
* @param mixed $val */
private function arrayToNodes($val, bool $blockMode = \false) : array
{
$res = [];
$counter = 0;
$hide = \true;
foreach ($val as $k => $v) {
$res[] = $item = new Node\ArrayItemNode();
$item->key = $hide && $k === $counter ? null : self::valueToNode($k);
$item->value = self::valueToNode($v, $blockMode);
if ($item->value instanceof Node\BlockArrayNode) {
$item->value->indentation = $this->indentation;
}
if ($hide && \is_int($k)) {
$hide = $k === $counter;
$counter = \max($k + 1, $counter);
}
}
return $res;
}
}

37
vendor/nette/neon/src/Neon/Entity.php vendored Normal file
View File

@ -0,0 +1,37 @@
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare (strict_types=1);
namespace RectorPrefix202302\Nette\Neon;
/**
* Representation of NEON entity 'foo(bar=1)'
*/
final class Entity extends \stdClass
{
/**
* @var mixed
*/
public $value;
/**
* @var mixed[]
*/
public $attributes = [];
/**
* @param mixed $value
*/
public function __construct($value, array $attributes = [])
{
$this->value = $value;
/** @var mixed[] */
$this->attributes = $attributes;
}
/** @param mixed[] $properties */
public static function __set_state(array $properties)
{
return new self($properties['value'], $properties['attributes']);
}
}

View File

@ -0,0 +1,15 @@
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare (strict_types=1);
namespace RectorPrefix202302\Nette\Neon;
/**
* The exception that indicates error of NEON processing.
*/
class Exception extends \Exception
{
}

68
vendor/nette/neon/src/Neon/Lexer.php vendored Normal file
View File

@ -0,0 +1,68 @@
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare (strict_types=1);
namespace RectorPrefix202302\Nette\Neon;
/** @internal */
final class Lexer
{
public const Patterns = [
// strings
Token::String => <<<'XX'
'''\n (?:(?: [^\n] | \n(?![\t ]*+''') )*+ \n)?[\t ]*+''' |
"""\n (?:(?: [^\n] | \n(?![\t ]*+""") )*+ \n)?[\t ]*+""" |
' (?: '' | [^'\n] )*+ ' |
" (?: \\. | [^"\\\n] )*+ "
XX
,
// literal / boolean / integer / float
Token::Literal => <<<'XX'
(?: [^#"',:=[\]{}()\n\t `-] | (?<!["']) [:-] [^"',=[\]{}()\n\t ] )
(?:
[^,:=\]})(\n\t ]++ |
:(?! [\n\t ,\]})] | $ ) |
[ \t]++ [^#,:=\]})(\n\t ]
)*+
XX
,
// punctuation
Token::Char => '[,:=[\\]{}()-]',
// comment
Token::Comment => '\\#.*+',
// new line
Token::Newline => '\\n++',
// whitespace
Token::Whitespace => '[\\t ]++',
];
public function tokenize(string $input) : TokenStream
{
$input = \str_replace("\r", '', $input);
$pattern = '~(' . \implode(')|(', self::Patterns) . ')~Amixu';
$res = \preg_match_all($pattern, $input, $matches, \PREG_SET_ORDER);
if ($res === \false) {
throw new Exception('Invalid UTF-8 sequence.');
}
$types = \array_keys(self::Patterns);
$offset = 0;
$tokens = [];
foreach ($matches as $match) {
$type = $types[\count($match) - 2];
$tokens[] = new Token($match[0], $type === Token::Char ? $match[0] : $type);
$offset += \strlen($match[0]);
}
$stream = new TokenStream($tokens);
if ($offset !== \strlen($input)) {
$s = \str_replace("\n", '\\n', \substr($input, $offset, 40));
$stream->error("Unexpected '{$s}'", \count($tokens));
}
return $stream;
}
public static function requiresDelimiters(string $s) : bool
{
return \preg_match('~[\\x00-\\x1F]|^[+-.]?\\d|^(true|false|yes|no|on|off|null)$~Di', $s) || !\preg_match('~^' . self::Patterns[Token::Literal] . '$~Dx', $s);
}
}

59
vendor/nette/neon/src/Neon/Neon.php vendored Normal file
View File

@ -0,0 +1,59 @@
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare (strict_types=1);
namespace RectorPrefix202302\Nette\Neon;
/**
* Simple parser & generator for Nette Object Notation.
* @see https://ne-on.org
*/
final class Neon
{
public const Chain = '!!chain';
/** @deprecated use Neon::Chain */
public const CHAIN = self::Chain;
/** @deprecated use parameter $blockMode */
public const BLOCK = Encoder::BLOCK;
/**
* Returns value converted to NEON.
* @param mixed $value
*/
public static function encode($value, bool $blockMode = \false, string $indentation = "\t") : string
{
$encoder = new Encoder();
$encoder->blockMode = $blockMode;
$encoder->indentation = $indentation;
return $encoder->encode($value);
}
/**
* Converts given NEON to PHP value.
* @return mixed
*/
public static function decode(string $input)
{
$decoder = new Decoder();
return $decoder->decode($input);
}
/**
* Converts given NEON file to PHP value.
* @return mixed
*/
public static function decodeFile(string $file)
{
$input = @\file_get_contents($file);
// @ is escalated to exception
if ($input === \false) {
$error = \preg_replace('#^\\w+\\(.*?\\): #', '', \error_get_last()['message'] ?? '');
throw new Exception("Unable to read file '{$file}'. {$error}");
}
if (\substr($input, 0, 3) === "") {
// BOM
$input = \substr($input, 3);
}
return self::decode($input);
}
}

41
vendor/nette/neon/src/Neon/Node.php vendored Normal file
View File

@ -0,0 +1,41 @@
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare (strict_types=1);
namespace RectorPrefix202302\Nette\Neon;
/**
* @implements \IteratorAggregate<Node>
*/
abstract class Node implements \IteratorAggregate
{
/**
* @var int|null
*/
public $startTokenPos;
/**
* @var int|null
*/
public $endTokenPos;
/**
* @var int|null
*/
public $startLine;
/**
* @var int|null
*/
public $endLine;
/**
* @return mixed
*/
public abstract function toValue();
public abstract function toString() : string;
public function &getIterator() : \Generator
{
return;
yield;
}
}

View File

@ -0,0 +1,75 @@
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare (strict_types=1);
namespace RectorPrefix202302\Nette\Neon\Node;
use RectorPrefix202302\Nette\Neon\Node;
/** @internal */
final class ArrayItemNode extends Node
{
/**
* @var \Nette\Neon\Node|null
*/
public $key;
/**
* @var \Nette\Neon\Node
*/
public $value;
/**
* @param self[] $items
* @return mixed[]
*/
public static function itemsToArray(array $items) : array
{
$res = [];
foreach ($items as $item) {
if ($item->key === null) {
$res[] = $item->value->toValue();
} else {
$res[(string) $item->key->toValue()] = $item->value->toValue();
}
}
return $res;
}
/** @param self[] $items */
public static function itemsToInlineString(array $items) : string
{
$res = '';
foreach ($items as $item) {
$res .= ($res === '' ? '' : ', ') . ($item->key ? $item->key->toString() . ': ' : '') . $item->value->toString();
}
return $res;
}
/** @param self[] $items */
public static function itemsToBlockString(array $items) : string
{
$res = '';
foreach ($items as $item) {
$v = $item->value->toString();
$res .= ($item->key ? $item->key->toString() . ':' : '-') . ($item->value instanceof BlockArrayNode && $item->value->items ? "\n" . $v . (\substr($v, -2, 1) === "\n" ? '' : "\n") : ' ' . $v . "\n");
}
return $res;
}
/**
* @return mixed
*/
public function toValue()
{
throw new \LogicException();
}
public function toString() : string
{
throw new \LogicException();
}
public function &getIterator() : \Generator
{
if ($this->key) {
(yield $this->key);
}
(yield $this->value);
}
}

View File

@ -0,0 +1,27 @@
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare (strict_types=1);
namespace RectorPrefix202302\Nette\Neon\Node;
use RectorPrefix202302\Nette\Neon\Node;
/** @internal */
abstract class ArrayNode extends Node
{
/** @var ArrayItemNode[] */
public $items = [];
/** @return mixed[] */
public function toValue() : array
{
return ArrayItemNode::itemsToArray($this->items);
}
public function &getIterator() : \Generator
{
foreach ($this->items as &$item) {
(yield $item);
}
}
}

View File

@ -0,0 +1,29 @@
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare (strict_types=1);
namespace RectorPrefix202302\Nette\Neon\Node;
/** @internal */
final class BlockArrayNode extends ArrayNode
{
/**
* @var string
*/
public $indentation = '';
public function __construct(string $indentation = '')
{
$this->indentation = $indentation;
}
public function toString() : string
{
if (\count($this->items) === 0) {
return '[]';
}
$res = ArrayItemNode::itemsToBlockString($this->items);
return \preg_replace('#^(?=.)#m', $this->indentation, $res);
}
}

View File

@ -0,0 +1,44 @@
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare (strict_types=1);
namespace RectorPrefix202302\Nette\Neon\Node;
use RectorPrefix202302\Nette\Neon;
use RectorPrefix202302\Nette\Neon\Node;
/** @internal */
final class EntityChainNode extends Node
{
/**
* @var mixed[]
*/
public $chain = [];
public function __construct(array $chain = [])
{
/** @var EntityNode[] */
$this->chain = $chain;
}
public function toValue() : Neon\Entity
{
$entities = [];
foreach ($this->chain as $item) {
$entities[] = $item->toValue();
}
return new Neon\Entity(Neon\Neon::Chain, $entities);
}
public function toString() : string
{
return \implode('', \array_map(function ($entity) {
return $entity->toString();
}, $this->chain));
}
public function &getIterator() : \Generator
{
foreach ($this->chain as &$item) {
(yield $item);
}
}
}

View File

@ -0,0 +1,44 @@
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare (strict_types=1);
namespace RectorPrefix202302\Nette\Neon\Node;
use RectorPrefix202302\Nette\Neon\Entity;
use RectorPrefix202302\Nette\Neon\Node;
/** @internal */
final class EntityNode extends Node
{
/**
* @var \Nette\Neon\Node
*/
public $value;
/**
* @var mixed[]
*/
public $attributes = [];
public function __construct(Node $value, array $attributes = [])
{
$this->value = $value;
/** @var ArrayItemNode[] */
$this->attributes = $attributes;
}
public function toValue() : Entity
{
return new Entity($this->value->toValue(), ArrayItemNode::itemsToArray($this->attributes));
}
public function toString() : string
{
return $this->value->toString() . '(' . ($this->attributes ? ArrayItemNode::itemsToInlineString($this->attributes) : '') . ')';
}
public function &getIterator() : \Generator
{
(yield $this->value);
foreach ($this->attributes as &$item) {
(yield $item);
}
}
}

View File

@ -0,0 +1,25 @@
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare (strict_types=1);
namespace RectorPrefix202302\Nette\Neon\Node;
/** @internal */
final class InlineArrayNode extends ArrayNode
{
/**
* @var string
*/
public $bracket;
public function __construct(string $bracket)
{
$this->bracket = $bracket;
}
public function toString() : string
{
return $this->bracket . ArrayItemNode::itemsToInlineString($this->items) . ['[' => ']', '{' => '}', '(' => ')'][$this->bracket];
}
}

View File

@ -0,0 +1,73 @@
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare (strict_types=1);
namespace RectorPrefix202302\Nette\Neon\Node;
use RectorPrefix202302\Nette\Neon\Node;
/** @internal */
final class LiteralNode extends Node
{
private const SimpleTypes = ['true' => \true, 'True' => \true, 'TRUE' => \true, 'yes' => \true, 'Yes' => \true, 'YES' => \true, 'false' => \false, 'False' => \false, 'FALSE' => \false, 'no' => \false, 'No' => \false, 'NO' => \false, 'null' => null, 'Null' => null, 'NULL' => null];
private const PatternDatetime = '#\\d\\d\\d\\d-\\d\\d?-\\d\\d?(?:(?:[Tt]| ++)\\d\\d?:\\d\\d:\\d\\d(?:\\.\\d*+)? *+(?:Z|[-+]\\d\\d?(?::?\\d\\d)?)?)?$#DA';
private const PatternHex = '#0x[0-9a-fA-F]++$#DA';
private const PatternOctal = '#0o[0-7]++$#DA';
private const PatternBinary = '#0b[0-1]++$#DA';
/**
* @var mixed
*/
public $value;
/**
* @param mixed $value
*/
public function __construct($value)
{
$this->value = $value;
}
/**
* @return mixed
*/
public function toValue()
{
return $this->value;
}
/**
* @return mixed
*/
public static function parse(string $value, bool $isKey = \false)
{
if (!$isKey && \array_key_exists($value, self::SimpleTypes)) {
return self::SimpleTypes[$value];
} elseif (\is_numeric($value)) {
return $value * 1;
} elseif (\preg_match(self::PatternHex, $value)) {
return \hexdec($value);
} elseif (\preg_match(self::PatternOctal, $value)) {
return \octdec($value);
} elseif (\preg_match(self::PatternBinary, $value)) {
return \bindec($value);
} elseif (!$isKey && \preg_match(self::PatternDatetime, $value)) {
return new \DateTimeImmutable($value);
} else {
return $value;
}
}
public function toString() : string
{
if ($this->value instanceof \DateTimeInterface) {
return $this->value->format('Y-m-d H:i:s O');
} elseif (\is_string($this->value)) {
return $this->value;
} elseif (\is_float($this->value)) {
$res = \json_encode($this->value);
return \strpos($res, '.') !== \false ? $res : $res . '.0';
} elseif (\is_int($this->value) || \is_bool($this->value) || $this->value === null) {
return \json_encode($this->value);
} else {
throw new \LogicException();
}
}
}

View File

@ -0,0 +1,76 @@
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare (strict_types=1);
namespace RectorPrefix202302\Nette\Neon\Node;
use RectorPrefix202302\Nette;
use RectorPrefix202302\Nette\Neon\Node;
/** @internal */
final class StringNode extends Node
{
private const EscapeSequences = ['t' => "\t", 'n' => "\n", 'r' => "\r", 'f' => "\f", 'b' => "\x08", '"' => '"', '\\' => '\\', '/' => '/', '_' => " "];
/**
* @var string
*/
public $value;
public function __construct(string $value)
{
$this->value = $value;
}
public function toValue() : string
{
return $this->value;
}
public static function parse(string $s) : string
{
if (\preg_match('#^...\\n++([\\t ]*+)#', $s, $m)) {
// multiline
$res = \substr($s, 3, -3);
$res = \str_replace("\n" . $m[1], "\n", $res);
$res = \preg_replace('#^\\n|\\n[\\t ]*+$#D', '', $res);
} else {
$res = \substr($s, 1, -1);
if ($s[0] === "'") {
$res = \str_replace("''", "'", $res);
}
}
if ($s[0] === "'") {
return $res;
}
return \preg_replace_callback('#\\\\(?:ud[89ab][0-9a-f]{2}\\\\ud[c-f][0-9a-f]{2}|u[0-9a-f]{4}|.)#i', function (array $m) : string {
$sq = $m[0];
if (isset(self::EscapeSequences[$sq[1]])) {
return self::EscapeSequences[$sq[1]];
} elseif ($sq[1] === 'u' && \strlen($sq) >= 6) {
if (\json_decode('"' . $sq . '"') !== null) {
throw new Nette\Neon\Exception("Invalid UTF-8 sequence {$sq}");
}
return \json_decode('"' . $sq . '"');
} else {
throw new Nette\Neon\Exception("Invalid escaping sequence {$sq}");
}
}, $res);
}
public function toString() : string
{
if (\strpos($this->value, "\n") === \false) {
return "'" . \str_replace("'", "''", $this->value) . "'";
} elseif (\preg_match('~\\n[\\t ]+\'{3}~', $this->value)) {
$s = \json_encode($this->value, \JSON_UNESCAPED_UNICODE | \JSON_UNESCAPED_SLASHES);
$s = \preg_replace_callback('#[^\\\\]|\\\\(.)#s', function ($m) {
return ['n' => "\n", 't' => "\t", '"' => '"'][$m[1] ?? ''] ?? $m[0];
}, \substr($s, 1, -1));
$s = \str_replace('"""', '""\\"', $s);
$delim = '"""';
} else {
$s = $this->value;
$delim = "'''";
}
$s = \preg_replace('#^(?=.)#m', "\t", $s);
return $delim . "\n" . $s . "\n" . $delim;
}
}

211
vendor/nette/neon/src/Neon/Parser.php vendored Normal file
View File

@ -0,0 +1,211 @@
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare (strict_types=1);
namespace RectorPrefix202302\Nette\Neon;
/** @internal */
final class Parser
{
/**
* @var \Nette\Neon\TokenStream
*/
private $tokens;
/** @var int[] */
private $posToLine = [];
public function parse(TokenStream $tokens) : Node
{
$this->tokens = $tokens;
$this->initLines();
while ($this->tokens->consume(Token::Newline)) {
}
$node = $this->parseBlock($this->tokens->getIndentation());
while ($this->tokens->consume(Token::Newline)) {
}
if ($this->tokens->isNext()) {
$this->tokens->error();
}
return $node;
}
private function parseBlock(string $indent, bool $onlyBullets = \false) : Node
{
$res = new Node\BlockArrayNode($indent);
$this->injectPos($res);
$keyCheck = [];
loop:
$item = new Node\ArrayItemNode();
$this->injectPos($item);
if ($this->tokens->consume('-')) {
// continue
} elseif (!$this->tokens->isNext() || $onlyBullets) {
return $res->items ? $res : $this->injectPos(new Node\LiteralNode(null));
} else {
$value = $this->parseValue();
if ($this->tokens->consume(':', '=')) {
$this->checkArrayKey($value, $keyCheck);
$item->key = $value;
} else {
if ($res->items) {
$this->tokens->error();
}
return $value;
}
}
$res->items[] = $item;
$item->value = new Node\LiteralNode(null);
$this->injectPos($item->value);
if ($this->tokens->consume(Token::Newline)) {
while ($this->tokens->consume(Token::Newline)) {
}
$nextIndent = $this->tokens->getIndentation();
if (\strncmp($nextIndent, $indent, \min(\strlen($nextIndent), \strlen($indent)))) {
$this->tokens->error('Invalid combination of tabs and spaces');
} elseif (\strlen($nextIndent) > \strlen($indent)) {
// open new block
$item->value = $this->parseBlock($nextIndent);
} elseif (\strlen($nextIndent) < \strlen($indent)) {
// close block
return $res;
} elseif ($item->key !== null && $this->tokens->isNext('-')) {
// special dash subblock
$item->value = $this->parseBlock($indent, \true);
}
} elseif ($item->key === null) {
$item->value = $this->parseBlock($indent . ' ');
// open new block after dash
} elseif ($this->tokens->isNext()) {
$item->value = $this->parseValue();
if ($this->tokens->isNext() && !$this->tokens->isNext(Token::Newline)) {
$this->tokens->error();
}
}
if ($item->value instanceof Node\BlockArrayNode) {
$item->value->indentation = \substr($item->value->indentation, \strlen($indent));
}
$this->injectPos($res, $res->startTokenPos, $item->value->endTokenPos);
$this->injectPos($item, $item->startTokenPos, $item->value->endTokenPos);
while ($this->tokens->consume(Token::Newline)) {
}
if (!$this->tokens->isNext()) {
return $res;
}
$nextIndent = $this->tokens->getIndentation();
if (\strncmp($nextIndent, $indent, \min(\strlen($nextIndent), \strlen($indent)))) {
$this->tokens->error('Invalid combination of tabs and spaces');
} elseif (\strlen($nextIndent) > \strlen($indent)) {
$this->tokens->error('Bad indentation');
} elseif (\strlen($nextIndent) < \strlen($indent)) {
// close block
return $res;
}
goto loop;
}
private function parseValue() : Node
{
if ($token = $this->tokens->consume(Token::String)) {
try {
$node = new Node\StringNode(Node\StringNode::parse($token->value));
$this->injectPos($node, $this->tokens->getPos() - 1);
} catch (Exception $e) {
$this->tokens->error($e->getMessage(), $this->tokens->getPos() - 1);
}
} elseif ($token = $this->tokens->consume(Token::Literal)) {
$pos = $this->tokens->getPos() - 1;
$node = new Node\LiteralNode(Node\LiteralNode::parse($token->value, $this->tokens->isNext(':', '=')));
$this->injectPos($node, $pos);
} elseif ($this->tokens->isNext('[', '(', '{')) {
$node = $this->parseBraces();
} else {
$this->tokens->error();
}
return $this->parseEntity($node);
}
private function parseEntity(Node $node) : Node
{
if (!$this->tokens->isNext('(')) {
return $node;
}
$attributes = $this->parseBraces();
$entities[] = $this->injectPos(new Node\EntityNode($node, $attributes->items), $node->startTokenPos, $attributes->endTokenPos);
while ($token = $this->tokens->consume(Token::Literal)) {
$valueNode = new Node\LiteralNode(Node\LiteralNode::parse($token->value));
$this->injectPos($valueNode, $this->tokens->getPos() - 1);
if ($this->tokens->isNext('(')) {
$attributes = $this->parseBraces();
$entities[] = $this->injectPos(new Node\EntityNode($valueNode, $attributes->items), $valueNode->startTokenPos, $attributes->endTokenPos);
} else {
$entities[] = $this->injectPos(new Node\EntityNode($valueNode), $valueNode->startTokenPos);
break;
}
}
return \count($entities) === 1 ? $entities[0] : $this->injectPos(new Node\EntityChainNode($entities), $node->startTokenPos, \end($entities)->endTokenPos);
}
private function parseBraces() : Node\InlineArrayNode
{
$token = $this->tokens->consume();
$endBrace = ['[' => ']', '{' => '}', '(' => ')'][$token->value];
$res = new Node\InlineArrayNode($token->value);
$this->injectPos($res, $this->tokens->getPos() - 1);
$keyCheck = [];
loop:
while ($this->tokens->consume(Token::Newline)) {
}
if ($this->tokens->consume($endBrace)) {
$this->injectPos($res, $res->startTokenPos, $this->tokens->getPos() - 1);
return $res;
}
$res->items[] = $item = new Node\ArrayItemNode();
$this->injectPos($item, $this->tokens->getPos());
$value = $this->parseValue();
if ($this->tokens->consume(':', '=')) {
$this->checkArrayKey($value, $keyCheck);
$item->key = $value;
$item->value = $this->tokens->isNext(Token::Newline, ',', $endBrace) ? $this->injectPos(new Node\LiteralNode(null), $this->tokens->getPos()) : $this->parseValue();
} else {
$item->value = $value;
}
$this->injectPos($item, $item->startTokenPos, $item->value->endTokenPos);
if ($this->tokens->consume(',', Token::Newline)) {
goto loop;
}
while ($this->tokens->consume(Token::Newline)) {
}
if (!$this->tokens->isNext($endBrace)) {
$this->tokens->error();
}
goto loop;
}
/** @param true[] $arr */
private function checkArrayKey(Node $key, array &$arr) : void
{
if (!$key instanceof Node\StringNode && !$key instanceof Node\LiteralNode || !\is_scalar($key->value)) {
$this->tokens->error('Unacceptable key', $key->startTokenPos);
}
$k = (string) $key->value;
if (\array_key_exists($k, $arr)) {
$this->tokens->error("Duplicated key '{$k}'", $key->startTokenPos);
}
$arr[$k] = \true;
}
private function injectPos(Node $node, int $start = null, int $end = null) : Node
{
$node->startTokenPos = $start ?? $this->tokens->getPos();
$node->startLine = $this->posToLine[$node->startTokenPos];
$node->endTokenPos = $end ?? $node->startTokenPos;
$node->endLine = $this->posToLine[$node->endTokenPos + 1] ?? \end($this->posToLine);
return $node;
}
private function initLines() : void
{
$this->posToLine = [];
$line = 1;
foreach ($this->tokens->getTokens() as $token) {
$this->posToLine[] = $line;
$line += \substr_count($token->value, "\n");
}
$this->posToLine[] = $line;
}
}

35
vendor/nette/neon/src/Neon/Token.php vendored Normal file
View File

@ -0,0 +1,35 @@
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare (strict_types=1);
namespace RectorPrefix202302\Nette\Neon;
/** @internal */
final class Token
{
public const String = 1;
public const Literal = 2;
public const Char = 0;
public const Comment = 3;
public const Newline = 4;
public const Whitespace = 5;
/**
* @var string
*/
public $value;
/**
* @var int|string
*/
public $type;
/**
* @param int|string $type
*/
public function __construct(string $value, $type)
{
$this->value = $value;
$this->type = $type;
}
}

View File

@ -0,0 +1,73 @@
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare (strict_types=1);
namespace RectorPrefix202302\Nette\Neon;
/** @internal */
final class TokenStream
{
/**
* @var int
*/
private $pos = 0;
/**
* @var mixed[]
*/
public $tokens;
public function __construct(array $tokens)
{
/** @var Token[] */
$this->tokens = $tokens;
}
public function getPos() : int
{
return $this->pos;
}
/** @return Token[] */
public function getTokens() : array
{
return $this->tokens;
}
/**
* @param int|string ...$types
*/
public function isNext(...$types) : bool
{
while (\in_array($this->tokens[$this->pos]->type ?? null, [Token::Comment, Token::Whitespace], \true)) {
$this->pos++;
}
return $types ? \in_array($this->tokens[$this->pos]->type ?? null, $types, \true) : isset($this->tokens[$this->pos]);
}
/**
* @param int|string ...$types
*/
public function consume(...$types) : ?Token
{
return $this->isNext(...$types) ? $this->tokens[$this->pos++] : null;
}
public function getIndentation() : string
{
return \in_array($this->tokens[$this->pos - 2]->type ?? null, [Token::Newline, null], \true) && ($this->tokens[$this->pos - 1]->type ?? null) === Token::Whitespace ? $this->tokens[$this->pos - 1]->value : '';
}
/** @return never */
public function error(?string $message = null, ?int $pos = null) : void
{
$pos = $pos ?? $this->pos;
$input = '';
foreach ($this->tokens as $i => $token) {
if ($i >= $pos) {
break;
}
$input .= $token->value;
}
$line = \substr_count($input, "\n") + 1;
$col = \strlen($input) - \strrpos("\n" . $input, "\n") + 1;
$token = $this->tokens[$pos] ?? null;
$message = $message ?? 'Unexpected ' . ($token === null ? 'end' : "'" . \str_replace("\n", '<new line>', \substr($this->tokens[$pos]->value, 0, 40)) . "'");
throw new Exception("{$message} on line {$line}, column {$col}.");
}
}

View File

@ -0,0 +1,64 @@
<?php
/**
* This file is part of the Nette Framework (https://nette.org)
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
*/
declare (strict_types=1);
namespace RectorPrefix202302\Nette\Neon;
/** @internal */
final class Traverser
{
public const DontTraverseChildren = 1;
public const StopTraversal = 2;
/** @var callable(Node): (Node|int|null)|null */
private $enter;
/** @var callable(Node): (Node|int|null)|null */
private $leave;
/** @var bool */
private $stop;
/**
* @param callable(Node): (Node|int|null)|null $enter
* @param callable(Node): (Node|int|null)|null $leave
*/
public function traverse(Node $node, ?callable $enter = null, ?callable $leave = null) : Node
{
$this->enter = $enter;
$this->leave = $leave;
$this->stop = \false;
return $this->traverseNode($node);
}
private function traverseNode(Node $node) : Node
{
$children = \true;
if ($this->enter) {
$res = ($this->enter)($node);
if ($res instanceof Node) {
$node = $res;
} elseif ($res === self::DontTraverseChildren) {
$children = \false;
} elseif ($res === self::StopTraversal) {
$this->stop = \true;
$children = \false;
}
}
if ($children) {
foreach ($node as &$subnode) {
$subnode = $this->traverseNode($subnode);
if ($this->stop) {
break;
}
}
}
if (!$this->stop && $this->leave) {
$res = ($this->leave)($node);
if ($res instanceof Node) {
$node = $res;
} elseif ($res === self::StopTraversal) {
$this->stop = \true;
}
}
return $node;
}
}